2 * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * Bridge MIB implementation for SNMPd.
32 #include <sys/queue.h>
33 #include <sys/socket.h>
34 #include <sys/types.h>
36 #include <net/ethernet.h>
38 #include <net/if_mib.h>
47 #include <bsnmp/snmpmod.h>
48 #include <bsnmp/snmp_mibII.h>
50 #include "bridge_tree.h"
51 #include "bridge_snmp.h"
53 TAILQ_HEAD(bridge_ports, bridge_port);
56 * Free the bridge base ports list.
59 bridge_ports_free(struct bridge_ports *headp)
61 struct bridge_port *bp;
63 while ((bp = TAILQ_FIRST(headp)) != NULL) {
64 TAILQ_REMOVE(headp, bp, b_p);
70 * Free the bridge base ports from the base ports list,
71 * members of a specified bridge interface only.
74 bridge_port_memif_free(struct bridge_ports *headp,
75 struct bridge_if *bif)
77 struct bridge_port *bp;
79 while (bif->f_bp != NULL && bif->sysindex == bif->f_bp->sysindex) {
80 bp = TAILQ_NEXT(bif->f_bp, b_p);
81 TAILQ_REMOVE(headp, bif->f_bp, b_p);
88 * Insert a port entry in the base port TAILQ starting to search
89 * for its place from the position of the first bridge port for the bridge
90 * interface. Update the first bridge port if neccessary.
93 bridge_port_insert_at(struct bridge_ports *headp,
94 struct bridge_port *bp, struct bridge_port **f_bp)
96 struct bridge_port *t1;
101 t1 != NULL && bp->sysindex == t1->sysindex;
102 t1 = TAILQ_NEXT(t1, b_p)) {
103 if (bp->if_idx < t1->if_idx) {
104 TAILQ_INSERT_BEFORE(t1, bp, b_p);
112 * Handle the case when our first port was actually the
113 * last element of the TAILQ.
116 TAILQ_INSERT_TAIL(headp, bp, b_p);
118 TAILQ_INSERT_BEFORE(t1, bp, b_p);
122 * Find a port entry's possition in the ports list according
123 * to it's parent bridge interface name. Returns a NULL if
124 * we should be at the TAILQ head, otherwise the entry after
125 * which we should be inserted.
127 static struct bridge_port *
128 bridge_port_find_pos(struct bridge_ports *headp, uint32_t b_idx)
131 struct bridge_port *t1;
133 if ((t1 = TAILQ_FIRST(headp)) == NULL ||
134 bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
137 t_idx = t1->sysindex;
139 for (t1 = TAILQ_NEXT(t1, b_p); t1 != NULL; t1 = TAILQ_NEXT(t1, b_p)) {
140 if (t1->sysindex != t_idx) {
141 if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
142 return (TAILQ_PREV(t1, bridge_ports, b_p));
144 t_idx = t1->sysindex;
149 t1 = TAILQ_LAST(headp, bridge_ports);
155 * Insert a bridge member interface in the ports TAILQ.
158 bridge_port_memif_insert(struct bridge_ports *headp,
159 struct bridge_port *bp, struct bridge_port **f_bp)
161 struct bridge_port *temp;
164 bridge_port_insert_at(headp, bp, f_bp);
166 temp = bridge_port_find_pos(headp, bp->sysindex);
169 TAILQ_INSERT_HEAD(headp, bp, b_p);
171 TAILQ_INSERT_AFTER(headp, temp, bp, b_p);
176 /* The global ports list. */
177 static struct bridge_ports bridge_ports = TAILQ_HEAD_INITIALIZER(bridge_ports);
178 static time_t ports_list_age;
181 bridge_ports_update_listage(void)
183 ports_list_age = time(NULL);
187 bridge_ports_fini(void)
189 bridge_ports_free(&bridge_ports);
193 bridge_members_free(struct bridge_if *bif)
195 bridge_port_memif_free(&bridge_ports, bif);
199 * Find the first port in the ports list.
201 static struct bridge_port *
202 bridge_port_first(void)
204 return (TAILQ_FIRST(&bridge_ports));
208 * Find the next port in the ports list.
210 static struct bridge_port *
211 bridge_port_next(struct bridge_port *bp)
213 return (TAILQ_NEXT(bp, b_p));
217 * Find the first member of the specified bridge interface.
220 bridge_port_bif_first(struct bridge_if *bif)
226 * Find the next member of the specified bridge interface.
229 bridge_port_bif_next(struct bridge_port *bp)
231 struct bridge_port *bp_next;
233 if ((bp_next = TAILQ_NEXT(bp, b_p)) == NULL ||
234 bp_next->sysindex != bp->sysindex)
241 * Remove a bridge port from the ports list.
244 bridge_port_remove(struct bridge_port *bp, struct bridge_if *bif)
247 bif->f_bp = bridge_port_bif_next(bp);
249 TAILQ_REMOVE(&bridge_ports, bp, b_p);
254 * Allocate memory for a new bridge port and insert it
255 * in the base ports list. Return a pointer to the port's
256 * structure in case we want to do anything else with it.
259 bridge_new_port(struct mibif *mif, struct bridge_if *bif)
261 struct bridge_port *bp;
263 if ((bp = (struct bridge_port *) malloc(sizeof(*bp))) == NULL) {
264 syslog(LOG_ERR, "bridge new member: failed: %s",
269 bzero(bp, sizeof(*bp));
271 bp->sysindex = bif->sysindex;
272 bp->if_idx = mif->index;
273 bp->port_no = mif->sysindex;
274 strlcpy(bp->p_name, mif->name, IFNAMSIZ);
275 bp->circuit = oid_zeroDotZero;
278 * Initialize all rstpMib specific values to false/default.
279 * These will be set to their true values later if the bridge
282 bp->proto_migr = TruthValue_false;
283 bp->admin_edge = TruthValue_false;
284 bp->oper_edge = TruthValue_false;
285 bp->oper_ptp = TruthValue_false;
286 bp->admin_ptp = StpPortAdminPointToPointType_auto;
288 bridge_port_memif_insert(&bridge_ports, bp, &(bif->f_bp));
294 * Update our info from the corresponding mibII interface info.
297 bridge_port_getinfo_mibif(struct mibif *m_if, struct bridge_port *bp)
299 bp->max_info = m_if->mib.ifmd_data.ifi_mtu;
300 bp->in_frames = m_if->mib.ifmd_data.ifi_ipackets;
301 bp->out_frames = m_if->mib.ifmd_data.ifi_opackets;
302 bp->in_drops = m_if->mib.ifmd_data.ifi_iqdrops;
306 * Find a port, whose SNMP's mibII ifIndex matches one of the ports,
307 * members of the specified bridge interface.
310 bridge_port_find(int32_t if_idx, struct bridge_if *bif)
312 struct bridge_port *bp;
314 for (bp = bif->f_bp; bp != NULL; bp = TAILQ_NEXT(bp, b_p)) {
315 if (bp->sysindex != bif->sysindex) {
320 if (bp->if_idx == if_idx)
328 bridge_ports_dump(struct bridge_if *bif)
330 struct bridge_port *bp;
332 for (bp = bridge_port_bif_first(bif); bp != NULL;
333 bp = bridge_port_bif_next(bp)) {
334 syslog(LOG_ERR, "memif - %s, index - %d",
335 bp->p_name, bp->port_no);
343 op_dot1d_base_port(struct snmp_context *c __unused, struct snmp_value *val,
344 uint sub, uint iidx __unused, enum snmp_op op)
346 struct bridge_if *bif;
347 struct bridge_port *bp;
349 if ((bif = bridge_get_default()) == NULL)
350 return (SNMP_ERR_NOSUCHNAME);
352 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
353 bridge_update_memif(bif) <= 0)
354 return (SNMP_ERR_NOSUCHNAME);
358 if (val->var.len - sub != 1)
359 return (SNMP_ERR_NOSUCHNAME);
360 if ((bp = bridge_port_find(val->var.subs[sub],
362 return (SNMP_ERR_NOSUCHNAME);
365 case SNMP_OP_GETNEXT:
366 if (val->var.len - sub == 0) {
367 if ((bp = bridge_port_bif_first(bif)) == NULL)
368 return (SNMP_ERR_NOSUCHNAME);
370 if ((bp = bridge_port_find(val->var.subs[sub],
372 (bp = bridge_port_bif_next(bp)) == NULL)
373 return (SNMP_ERR_NOSUCHNAME);
375 val->var.len = sub + 1;
376 val->var.subs[sub] = bp->port_no;
380 return (SNMP_ERR_NOT_WRITEABLE);
382 case SNMP_OP_ROLLBACK:
389 switch (val->var.subs[sub - 1]) {
390 case LEAF_dot1dBasePort:
391 val->v.integer = bp->port_no;
392 return (SNMP_ERR_NOERROR);
394 case LEAF_dot1dBasePortIfIndex:
395 val->v.integer = bp->if_idx;
396 return (SNMP_ERR_NOERROR);
398 case LEAF_dot1dBasePortCircuit:
399 val->v.oid = bp->circuit;
400 return (SNMP_ERR_NOERROR);
402 case LEAF_dot1dBasePortDelayExceededDiscards:
403 val->v.uint32 = bp->dly_ex_drops;
404 return (SNMP_ERR_NOERROR);
406 case LEAF_dot1dBasePortMtuExceededDiscards:
407 val->v.uint32 = bp->dly_mtu_drops;
408 return (SNMP_ERR_NOERROR);
415 op_dot1d_stp_port(struct snmp_context *ctx, struct snmp_value *val,
416 uint sub, uint iidx __unused, enum snmp_op op)
418 struct bridge_if *bif;
419 struct bridge_port *bp;
421 if ((bif = bridge_get_default()) == NULL)
422 return (SNMP_ERR_NOSUCHNAME);
424 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
425 bridge_update_memif(bif) <= 0)
426 return (SNMP_ERR_NOSUCHNAME);
430 if (val->var.len - sub != 1)
431 return (SNMP_ERR_NOSUCHNAME);
432 if ((bp = bridge_port_find(val->var.subs[sub],
434 return (SNMP_ERR_NOSUCHNAME);
437 case SNMP_OP_GETNEXT:
438 if (val->var.len - sub == 0) {
439 if ((bp = bridge_port_bif_first(bif)) == NULL)
440 return (SNMP_ERR_NOSUCHNAME);
442 if ((bp = bridge_port_find(val->var.subs[sub],
444 (bp = bridge_port_bif_next(bp)) == NULL)
445 return (SNMP_ERR_NOSUCHNAME);
447 val->var.len = sub + 1;
448 val->var.subs[sub] = bp->port_no;
452 if (val->var.len - sub != 1)
453 return (SNMP_ERR_NOSUCHNAME);
454 if ((bp = bridge_port_find(val->var.subs[sub],
456 return (SNMP_ERR_NOSUCHNAME);
458 switch (val->var.subs[sub - 1]) {
459 case LEAF_dot1dStpPortPriority:
460 if (val->v.integer < 0 || val->v.integer > 255)
461 return (SNMP_ERR_WRONG_VALUE);
463 ctx->scratch->int1 = bp->priority;
464 if (bridge_port_set_priority(bif->bif_name, bp,
466 return (SNMP_ERR_GENERR);
467 return (SNMP_ERR_NOERROR);
469 case LEAF_dot1dStpPortEnable:
470 if (val->v.integer != dot1dStpPortEnable_enabled &&
471 val->v.integer != dot1dStpPortEnable_disabled)
472 return (SNMP_ERR_WRONG_VALUE);
474 ctx->scratch->int1 = bp->enable;
475 if (bridge_port_set_stp_enable(bif->bif_name,
476 bp, val->v.integer) < 0)
477 return (SNMP_ERR_GENERR);
478 return (SNMP_ERR_NOERROR);
480 case LEAF_dot1dStpPortPathCost:
481 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
482 val->v.integer > SNMP_PORT_MAX_PATHCOST)
483 return (SNMP_ERR_WRONG_VALUE);
485 ctx->scratch->int1 = bp->path_cost;
486 if (bridge_port_set_path_cost(bif->bif_name, bp,
488 return (SNMP_ERR_GENERR);
489 return (SNMP_ERR_NOERROR);
491 case LEAF_dot1dStpPort:
492 case LEAF_dot1dStpPortState:
493 case LEAF_dot1dStpPortDesignatedRoot:
494 case LEAF_dot1dStpPortDesignatedCost:
495 case LEAF_dot1dStpPortDesignatedBridge:
496 case LEAF_dot1dStpPortDesignatedPort:
497 case LEAF_dot1dStpPortForwardTransitions:
498 return (SNMP_ERR_NOT_WRITEABLE);
502 case SNMP_OP_ROLLBACK:
503 if ((bp = bridge_port_find(val->var.subs[sub],
505 return (SNMP_ERR_GENERR);
506 switch (val->var.subs[sub - 1]) {
507 case LEAF_dot1dStpPortPriority:
508 bridge_port_set_priority(bif->bif_name, bp,
511 case LEAF_dot1dStpPortEnable:
512 bridge_port_set_stp_enable(bif->bif_name, bp,
515 case LEAF_dot1dStpPortPathCost:
516 bridge_port_set_path_cost(bif->bif_name, bp,
520 return (SNMP_ERR_NOERROR);
523 return (SNMP_ERR_NOERROR);
528 switch (val->var.subs[sub - 1]) {
529 case LEAF_dot1dStpPort:
530 val->v.integer = bp->port_no;
531 return (SNMP_ERR_NOERROR);
533 case LEAF_dot1dStpPortPriority:
534 val->v.integer = bp->priority;
535 return (SNMP_ERR_NOERROR);
537 case LEAF_dot1dStpPortState:
538 val->v.integer = bp->state;
539 return (SNMP_ERR_NOERROR);
541 case LEAF_dot1dStpPortEnable:
542 val->v.integer = bp->enable;
543 return (SNMP_ERR_NOERROR);
545 case LEAF_dot1dStpPortPathCost:
546 val->v.integer = bp->path_cost;
547 return (SNMP_ERR_NOERROR);
549 case LEAF_dot1dStpPortDesignatedRoot:
550 return (string_get(val, bp->design_root,
551 SNMP_BRIDGE_ID_LEN));
553 case LEAF_dot1dStpPortDesignatedCost:
554 val->v.integer = bp->design_cost;
555 return (SNMP_ERR_NOERROR);
557 case LEAF_dot1dStpPortDesignatedBridge:
558 return (string_get(val, bp->design_bridge,
559 SNMP_BRIDGE_ID_LEN));
561 case LEAF_dot1dStpPortDesignatedPort:
562 return (string_get(val, bp->design_port, 2));
564 case LEAF_dot1dStpPortForwardTransitions:
565 val->v.uint32 = bp->fwd_trans;
566 return (SNMP_ERR_NOERROR);
573 op_dot1d_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
574 uint sub, uint iidx __unused, enum snmp_op op)
576 struct bridge_if *bif;
577 struct bridge_port *bp;
579 if ((bif = bridge_get_default()) == NULL)
580 return (SNMP_ERR_NOSUCHNAME);
582 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
583 bridge_update_memif(bif) <= 0)
584 return (SNMP_ERR_NOSUCHNAME);
588 if (val->var.len - sub != 1)
589 return (SNMP_ERR_NOSUCHNAME);
590 if ((bp = bridge_port_find(val->var.subs[sub],
592 return (SNMP_ERR_NOSUCHNAME);
595 case SNMP_OP_GETNEXT:
596 if (val->var.len - sub == 0) {
597 if ((bp = bridge_port_bif_first(bif)) == NULL)
598 return (SNMP_ERR_NOSUCHNAME);
600 if ((bp = bridge_port_find(val->var.subs[sub],
602 (bp = bridge_port_bif_next(bp)) == NULL)
603 return (SNMP_ERR_NOSUCHNAME);
605 val->var.len = sub + 1;
606 val->var.subs[sub] = bp->port_no;
610 if (val->var.len - sub != 1)
611 return (SNMP_ERR_NOSUCHNAME);
612 if ((bp = bridge_port_find(val->var.subs[sub],
614 return (SNMP_ERR_NOSUCHNAME);
616 switch (val->var.subs[sub - 1]) {
617 case LEAF_dot1dStpPortAdminEdgePort:
618 if (val->v.integer != TruthValue_true &&
619 val->v.integer != TruthValue_false)
620 return (SNMP_ERR_WRONG_VALUE);
622 ctx->scratch->int1 = bp->admin_edge;
623 if (bridge_port_set_admin_edge(bif->bif_name, bp,
625 return (SNMP_ERR_GENERR);
626 return (SNMP_ERR_NOERROR);
628 case LEAF_dot1dStpPortAdminPointToPoint:
629 if (val->v.integer < 0 || val->v.integer >
630 StpPortAdminPointToPointType_auto)
631 return (SNMP_ERR_WRONG_VALUE);
633 ctx->scratch->int1 = bp->admin_ptp;
634 if (bridge_port_set_admin_ptp(bif->bif_name, bp,
636 return (SNMP_ERR_GENERR);
637 return (SNMP_ERR_NOERROR);
639 case LEAF_dot1dStpPortAdminPathCost:
640 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
641 val->v.integer > SNMP_PORT_MAX_PATHCOST)
642 return (SNMP_ERR_WRONG_VALUE);
644 ctx->scratch->int1 = bp->admin_path_cost;
645 if (bridge_port_set_path_cost(bif->bif_name, bp,
647 return (SNMP_ERR_GENERR);
648 return (SNMP_ERR_NOERROR);
650 case LEAF_dot1dStpPortProtocolMigration:
651 case LEAF_dot1dStpPortOperEdgePort:
652 case LEAF_dot1dStpPortOperPointToPoint:
653 return (SNMP_ERR_NOT_WRITEABLE);
657 case SNMP_OP_ROLLBACK:
658 if ((bp = bridge_port_find(val->var.subs[sub],
660 return (SNMP_ERR_GENERR);
662 switch (val->var.subs[sub - 1]) {
663 case LEAF_dot1dStpPortAdminEdgePort:
664 bridge_port_set_admin_edge(bif->bif_name, bp,
667 case LEAF_dot1dStpPortAdminPointToPoint:
668 bridge_port_set_admin_ptp(bif->bif_name, bp,
671 case LEAF_dot1dStpPortAdminPathCost:
672 bridge_port_set_path_cost(bif->bif_name, bp,
676 return (SNMP_ERR_NOERROR);
679 return (SNMP_ERR_NOERROR);
684 switch (val->var.subs[sub - 1]) {
685 case LEAF_dot1dStpPortProtocolMigration:
686 val->v.integer = bp->proto_migr;
687 return (SNMP_ERR_NOERROR);
689 case LEAF_dot1dStpPortAdminEdgePort:
690 val->v.integer = bp->admin_edge;
691 return (SNMP_ERR_NOERROR);
693 case LEAF_dot1dStpPortOperEdgePort:
694 val->v.integer = bp->oper_edge;
695 return (SNMP_ERR_NOERROR);
697 case LEAF_dot1dStpPortAdminPointToPoint:
698 val->v.integer = bp->admin_ptp;
699 return (SNMP_ERR_NOERROR);
701 case LEAF_dot1dStpPortOperPointToPoint:
702 val->v.integer = bp->oper_ptp;
703 return (SNMP_ERR_NOERROR);
705 case LEAF_dot1dStpPortAdminPathCost:
706 val->v.integer = bp->admin_path_cost;
707 return (SNMP_ERR_NOERROR);
714 op_dot1d_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
715 uint sub, uint iidx __unused, enum snmp_op op)
717 struct bridge_if *bif;
718 struct bridge_port *bp;
720 if ((bif = bridge_get_default()) == NULL)
721 return (SNMP_ERR_NOSUCHNAME);
723 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
724 bridge_update_memif(bif) <= 0)
725 return (SNMP_ERR_NOSUCHNAME);
729 if (val->var.len - sub != 1)
730 return (SNMP_ERR_NOSUCHNAME);
731 if ((bp = bridge_port_find(val->var.subs[sub],
733 return (SNMP_ERR_NOSUCHNAME);
736 case SNMP_OP_GETNEXT:
737 if (val->var.len - sub == 0) {
738 if ((bp = bridge_port_bif_first(bif)) == NULL)
739 return (SNMP_ERR_NOSUCHNAME);
741 if ((bp = bridge_port_find(val->var.subs[sub],
743 (bp = bridge_port_bif_next(bp)) == NULL)
744 return (SNMP_ERR_NOSUCHNAME);
746 val->var.len = sub + 1;
747 val->var.subs[sub] = bp->port_no;
751 return (SNMP_ERR_NOT_WRITEABLE);
753 case SNMP_OP_ROLLBACK:
760 switch (val->var.subs[sub - 1]) {
761 case LEAF_dot1dTpPort:
762 val->v.integer = bp->port_no;
763 return (SNMP_ERR_NOERROR);
765 case LEAF_dot1dTpPortMaxInfo:
766 val->v.integer = bp->max_info;
767 return (SNMP_ERR_NOERROR);
769 case LEAF_dot1dTpPortInFrames:
770 val->v.uint32 = bp->in_frames;
771 return (SNMP_ERR_NOERROR);
773 case LEAF_dot1dTpPortOutFrames:
774 val->v.uint32 = bp->out_frames;
775 return (SNMP_ERR_NOERROR);
777 case LEAF_dot1dTpPortInDiscards:
778 val->v.uint32 = bp->in_drops;
779 return (SNMP_ERR_NOERROR);
786 * Private BEGEMOT-BRIDGE-MIB specifics.
790 * Construct a bridge port entry index.
793 bridge_port_index_append(struct asn_oid *oid, uint sub,
794 const struct bridge_port *bp)
799 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
802 oid->len = sub + strlen(b_name) + 1 + 1;
803 oid->subs[sub] = strlen(b_name);
805 for (i = 1; i <= strlen(b_name); i++)
806 oid->subs[sub + i] = b_name[i - 1];
808 oid->subs[sub + i] = bp->port_no;
814 * Get the port entry from an entry's index.
816 static struct bridge_port *
817 bridge_port_index_get(const struct asn_oid *oid, uint sub, int8_t status)
821 char bif_name[IFNAMSIZ];
822 struct bridge_if *bif;
823 struct bridge_port *bp;
825 if (oid->len - sub != oid->subs[sub] + 2 ||
826 oid->subs[sub] >= IFNAMSIZ)
829 for (i = 0; i < oid->subs[sub]; i++)
830 bif_name[i] = oid->subs[sub + i + 1];
833 port_no = oid->subs[sub + i + 1];
835 if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
838 if ((bp = bridge_port_find(port_no, bif)) == NULL ||
839 (status == 0 && bp->status != RowStatus_active))
846 * Get the next port entry from an entry's index.
848 static struct bridge_port *
849 bridge_port_index_getnext(const struct asn_oid *oid, uint sub, int8_t status)
853 char bif_name[IFNAMSIZ];
854 struct bridge_if *bif;
855 struct bridge_port *bp;
857 if (oid->len - sub == 0)
858 bp = bridge_port_first();
860 if (oid->len - sub != oid->subs[sub] + 2 ||
861 oid->subs[sub] >= IFNAMSIZ)
864 for (i = 0; i < oid->subs[sub]; i++)
865 bif_name[i] = oid->subs[sub + i + 1];
868 port_no = oid->subs[sub + i + 1];
870 if ((bif = bridge_if_find_ifname(bif_name)) == NULL ||
871 (bp = bridge_port_find(port_no, bif)) == NULL)
874 bp = bridge_port_next(bp);
881 if (bp->status == RowStatus_active)
883 bp = bridge_port_next(bp);
890 * Read the bridge name and port index from a ASN OID structure.
893 bridge_port_index_decode(const struct asn_oid *oid, uint sub,
894 char *b_name, int32_t *idx)
898 if (oid->len - sub != oid->subs[sub] + 2 ||
899 oid->subs[sub] >= IFNAMSIZ)
902 for (i = 0; i < oid->subs[sub]; i++)
903 b_name[i] = oid->subs[sub + i + 1];
906 *idx = oid->subs[sub + i + 1];
911 bridge_port_set_status(struct snmp_context *ctx,
912 struct snmp_value *val, uint sub)
915 char b_name[IFNAMSIZ];
916 struct bridge_if *bif;
917 struct bridge_port *bp;
920 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
921 return (SNMP_ERR_INCONS_VALUE);
923 if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
924 (mif = mib_find_if(if_idx)) == NULL)
925 return (SNMP_ERR_INCONS_VALUE);
927 bp = bridge_port_find(if_idx, bif);
929 switch (val->v.integer) {
930 case RowStatus_active:
932 return (SNMP_ERR_INCONS_VALUE);
934 if (bp->span_enable == 0)
935 return (SNMP_ERR_INCONS_VALUE);
937 ctx->scratch->int1 = bp->status;
938 bp->status = RowStatus_active;
941 case RowStatus_notInService:
942 if (bp == NULL || bp->span_enable == 0 ||
943 bp->status == RowStatus_active)
944 return (SNMP_ERR_INCONS_VALUE);
946 ctx->scratch->int1 = bp->status;
947 bp->status = RowStatus_notInService;
949 case RowStatus_notReady:
951 case RowStatus_createAndGo:
952 return (SNMP_ERR_INCONS_VALUE);
954 case RowStatus_createAndWait:
956 return (SNMP_ERR_INCONS_VALUE);
958 if ((bp = bridge_new_port(mif, bif)) == NULL)
959 return (SNMP_ERR_GENERR);
961 ctx->scratch->int1 = RowStatus_destroy;
962 bp->status = RowStatus_notReady;
965 case RowStatus_destroy:
967 return (SNMP_ERR_INCONS_VALUE);
969 ctx->scratch->int1 = bp->status;
970 bp->status = RowStatus_destroy;
974 return (SNMP_ERR_NOERROR);
978 bridge_port_rollback_status(struct snmp_context *ctx,
979 struct snmp_value *val, uint sub)
982 char b_name[IFNAMSIZ];
983 struct bridge_if *bif;
984 struct bridge_port *bp;
986 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
987 return (SNMP_ERR_GENERR);
989 if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
990 (bp = bridge_port_find(if_idx, bif)) == NULL)
991 return (SNMP_ERR_GENERR);
993 if (ctx->scratch->int1 == RowStatus_destroy)
994 bridge_port_remove(bp, bif);
996 bp->status = ctx->scratch->int1;
998 return (SNMP_ERR_NOERROR);
1002 bridge_port_commit_status(struct snmp_value *val, uint sub)
1005 char b_name[IFNAMSIZ];
1006 struct bridge_if *bif;
1007 struct bridge_port *bp;
1009 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
1010 return (SNMP_ERR_GENERR);
1012 if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
1013 (bp = bridge_port_find(if_idx, bif)) == NULL)
1014 return (SNMP_ERR_GENERR);
1016 switch (bp->status) {
1017 case RowStatus_active:
1018 if (bridge_port_addm(bp, b_name) < 0)
1019 return (SNMP_ERR_COMMIT_FAILED);
1022 case RowStatus_destroy:
1023 if (bridge_port_delm(bp, b_name) < 0)
1024 return (SNMP_ERR_COMMIT_FAILED);
1025 bridge_port_remove(bp, bif);
1029 return (SNMP_ERR_NOERROR);
1033 bridge_port_set_span_enable(struct snmp_context *ctx,
1034 struct snmp_value *val, uint sub)
1037 char b_name[IFNAMSIZ];
1038 struct bridge_if *bif;
1039 struct bridge_port *bp;
1042 if (val->v.integer != begemotBridgeBaseSpanEnabled_enabled &&
1043 val->v.integer != begemotBridgeBaseSpanEnabled_disabled)
1044 return (SNMP_ERR_BADVALUE);
1046 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
1047 return (SNMP_ERR_INCONS_VALUE);
1049 if ((bif = bridge_if_find_ifname(b_name)) == NULL)
1050 return (SNMP_ERR_INCONS_VALUE);
1052 if ((bp = bridge_port_find(if_idx, bif)) == NULL) {
1053 if ((mif = mib_find_if(if_idx)) == NULL)
1054 return (SNMP_ERR_INCONS_VALUE);
1056 if ((bp = bridge_new_port(mif, bif)) == NULL)
1057 return (SNMP_ERR_GENERR);
1059 ctx->scratch->int1 = RowStatus_destroy;
1060 } else if (bp->status == RowStatus_active) {
1061 return (SNMP_ERR_INCONS_VALUE);
1063 ctx->scratch->int1 = bp->status;
1066 bp->span_enable = val->v.integer;
1067 bp->status = RowStatus_notInService;
1069 return (SNMP_ERR_NOERROR);
1073 op_begemot_base_port(struct snmp_context *ctx, struct snmp_value *val,
1074 uint sub, uint iidx __unused, enum snmp_op op)
1076 int8_t status, which;
1077 struct bridge_port *bp;
1079 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1080 bridge_update_all_ports();
1082 which = val->var.subs[sub - 1];
1087 if (which == LEAF_begemotBridgeBaseSpanEnabled ||
1088 which == LEAF_begemotBridgeBasePortStatus)
1090 if ((bp = bridge_port_index_get(&val->var, sub,
1092 return (SNMP_ERR_NOSUCHNAME);
1095 case SNMP_OP_GETNEXT:
1096 if (which == LEAF_begemotBridgeBaseSpanEnabled ||
1097 which == LEAF_begemotBridgeBasePortStatus)
1099 if ((bp = bridge_port_index_getnext(&val->var, sub,
1101 bridge_port_index_append(&val->var, sub, bp) < 0)
1102 return (SNMP_ERR_NOSUCHNAME);
1107 case LEAF_begemotBridgeBaseSpanEnabled:
1108 return (bridge_port_set_span_enable(ctx, val, sub));
1110 case LEAF_begemotBridgeBasePortStatus:
1111 return (bridge_port_set_status(ctx, val, sub));
1113 case LEAF_begemotBridgeBasePort:
1114 case LEAF_begemotBridgeBasePortIfIndex:
1115 case LEAF_begemotBridgeBasePortDelayExceededDiscards:
1116 case LEAF_begemotBridgeBasePortMtuExceededDiscards:
1117 return (SNMP_ERR_NOT_WRITEABLE);
1121 case SNMP_OP_ROLLBACK:
1123 case LEAF_begemotBridgeBaseSpanEnabled:
1125 case LEAF_begemotBridgeBasePortStatus:
1126 return (bridge_port_rollback_status(ctx, val, sub));
1128 return (SNMP_ERR_NOERROR);
1130 case SNMP_OP_COMMIT:
1131 if (which == LEAF_begemotBridgeBasePortStatus)
1132 return (bridge_port_commit_status(val, sub));
1134 return (SNMP_ERR_NOERROR);
1140 case LEAF_begemotBridgeBasePort:
1141 val->v.integer = bp->port_no;
1142 return (SNMP_ERR_NOERROR);
1144 case LEAF_begemotBridgeBasePortIfIndex:
1145 val->v.integer = bp->if_idx;
1146 return (SNMP_ERR_NOERROR);
1148 case LEAF_begemotBridgeBaseSpanEnabled:
1149 val->v.integer = bp->span_enable;
1150 return (SNMP_ERR_NOERROR);
1152 case LEAF_begemotBridgeBasePortDelayExceededDiscards:
1153 val->v.uint32 = bp->dly_ex_drops;
1154 return (SNMP_ERR_NOERROR);
1156 case LEAF_begemotBridgeBasePortMtuExceededDiscards:
1157 val->v.uint32 = bp->dly_mtu_drops;
1158 return (SNMP_ERR_NOERROR);
1160 case LEAF_begemotBridgeBasePortStatus:
1161 val->v.integer = bp->status;
1162 return (SNMP_ERR_NOERROR);
1169 op_begemot_stp_port(struct snmp_context *ctx, struct snmp_value *val,
1170 uint sub, uint iidx __unused, enum snmp_op op)
1172 struct bridge_port *bp;
1175 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1176 bridge_update_all_ports();
1180 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1181 return (SNMP_ERR_NOSUCHNAME);
1184 case SNMP_OP_GETNEXT:
1185 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1186 NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1187 return (SNMP_ERR_NOSUCHNAME);
1191 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1192 return (SNMP_ERR_NOSUCHNAME);
1193 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1194 return (SNMP_ERR_GENERR);
1196 switch (val->var.subs[sub - 1]) {
1197 case LEAF_begemotBridgeStpPortPriority:
1198 if (val->v.integer < 0 || val->v.integer > 255)
1199 return (SNMP_ERR_WRONG_VALUE);
1201 ctx->scratch->int1 = bp->priority;
1202 if (bridge_port_set_priority(b_name, bp,
1203 val->v.integer) < 0)
1204 return (SNMP_ERR_GENERR);
1205 return (SNMP_ERR_NOERROR);
1207 case LEAF_begemotBridgeStpPortEnable:
1208 if (val->v.integer !=
1209 begemotBridgeStpPortEnable_enabled ||
1211 begemotBridgeStpPortEnable_disabled)
1212 return (SNMP_ERR_WRONG_VALUE);
1214 ctx->scratch->int1 = bp->enable;
1215 if (bridge_port_set_stp_enable(b_name, bp,
1216 val->v.integer) < 0)
1217 return (SNMP_ERR_GENERR);
1218 return (SNMP_ERR_NOERROR);
1220 case LEAF_begemotBridgeStpPortPathCost:
1221 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
1222 val->v.integer > SNMP_PORT_MAX_PATHCOST)
1223 return (SNMP_ERR_WRONG_VALUE);
1225 ctx->scratch->int1 = bp->path_cost;
1226 if (bridge_port_set_path_cost(b_name, bp,
1227 val->v.integer) < 0)
1228 return (SNMP_ERR_GENERR);
1229 return (SNMP_ERR_NOERROR);
1231 case LEAF_begemotBridgeStpPort:
1232 case LEAF_begemotBridgeStpPortState:
1233 case LEAF_begemotBridgeStpPortDesignatedRoot:
1234 case LEAF_begemotBridgeStpPortDesignatedCost:
1235 case LEAF_begemotBridgeStpPortDesignatedBridge:
1236 case LEAF_begemotBridgeStpPortDesignatedPort:
1237 case LEAF_begemotBridgeStpPortForwardTransitions:
1238 return (SNMP_ERR_NOT_WRITEABLE);
1242 case SNMP_OP_ROLLBACK:
1243 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1244 (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1245 return (SNMP_ERR_GENERR);
1247 switch (val->var.subs[sub - 1]) {
1248 case LEAF_begemotBridgeStpPortPriority:
1249 bridge_port_set_priority(b_name, bp,
1250 ctx->scratch->int1);
1252 case LEAF_begemotBridgeStpPortEnable:
1253 bridge_port_set_stp_enable(b_name, bp,
1254 ctx->scratch->int1);
1256 case LEAF_begemotBridgeStpPortPathCost:
1257 bridge_port_set_path_cost(b_name, bp,
1258 ctx->scratch->int1);
1261 return (SNMP_ERR_NOERROR);
1263 case SNMP_OP_COMMIT:
1264 return (SNMP_ERR_NOERROR);
1269 switch (val->var.subs[sub - 1]) {
1270 case LEAF_begemotBridgeStpPort:
1271 val->v.integer = bp->port_no;
1272 return (SNMP_ERR_NOERROR);
1274 case LEAF_begemotBridgeStpPortPriority:
1275 val->v.integer = bp->priority;
1276 return (SNMP_ERR_NOERROR);
1278 case LEAF_begemotBridgeStpPortState:
1279 val->v.integer = bp->state;
1280 return (SNMP_ERR_NOERROR);
1282 case LEAF_begemotBridgeStpPortEnable:
1283 val->v.integer = bp->enable;
1284 return (SNMP_ERR_NOERROR);
1286 case LEAF_begemotBridgeStpPortPathCost:
1287 val->v.integer = bp->path_cost;
1288 return (SNMP_ERR_NOERROR);
1290 case LEAF_begemotBridgeStpPortDesignatedRoot:
1291 return (string_get(val, bp->design_root, SNMP_BRIDGE_ID_LEN));
1293 case LEAF_begemotBridgeStpPortDesignatedCost:
1294 val->v.integer = bp->design_cost;
1295 return (SNMP_ERR_NOERROR);
1297 case LEAF_begemotBridgeStpPortDesignatedBridge:
1298 return (string_get(val, bp->design_bridge, SNMP_BRIDGE_ID_LEN));
1300 case LEAF_begemotBridgeStpPortDesignatedPort:
1301 return (string_get(val, bp->design_port, 2));
1303 case LEAF_begemotBridgeStpPortForwardTransitions:
1304 val->v.uint32 = bp->fwd_trans;
1305 return (SNMP_ERR_NOERROR);
1312 op_begemot_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
1313 uint sub, uint iidx __unused, enum snmp_op op)
1315 struct bridge_port *bp;
1318 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1319 bridge_update_all_ports();
1323 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1324 return (SNMP_ERR_NOSUCHNAME);
1327 case SNMP_OP_GETNEXT:
1328 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1329 NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1330 return (SNMP_ERR_NOSUCHNAME);
1334 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1335 return (SNMP_ERR_NOSUCHNAME);
1336 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1337 return (SNMP_ERR_GENERR);
1339 switch (val->var.subs[sub - 1]) {
1340 case LEAF_begemotBridgeStpPortAdminEdgePort:
1341 if (val->v.integer != TruthValue_true &&
1342 val->v.integer != TruthValue_false)
1343 return (SNMP_ERR_WRONG_VALUE);
1345 ctx->scratch->int1 = bp->admin_edge;
1346 if (bridge_port_set_admin_edge(b_name, bp,
1347 val->v.integer) < 0)
1348 return (SNMP_ERR_GENERR);
1349 return (SNMP_ERR_NOERROR);
1351 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1352 if (val->v.integer < 0 || val->v.integer >
1353 StpPortAdminPointToPointType_auto)
1354 return (SNMP_ERR_WRONG_VALUE);
1356 ctx->scratch->int1 = bp->admin_ptp;
1357 if (bridge_port_set_admin_ptp(b_name, bp,
1358 val->v.integer) < 0)
1359 return (SNMP_ERR_GENERR);
1360 return (SNMP_ERR_NOERROR);
1362 case LEAF_begemotBridgeStpPortAdminPathCost:
1363 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
1364 val->v.integer > SNMP_PORT_MAX_PATHCOST)
1365 return (SNMP_ERR_WRONG_VALUE);
1367 ctx->scratch->int1 = bp->admin_path_cost;
1368 if (bridge_port_set_path_cost(b_name, bp,
1369 val->v.integer) < 0)
1370 return (SNMP_ERR_GENERR);
1371 return (SNMP_ERR_NOERROR);
1373 case LEAF_begemotBridgeStpPortProtocolMigration:
1374 case LEAF_begemotBridgeStpPortOperEdgePort:
1375 case LEAF_begemotBridgeStpPortOperPointToPoint:
1376 return (SNMP_ERR_NOT_WRITEABLE);
1380 case SNMP_OP_ROLLBACK:
1381 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1382 (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1383 return (SNMP_ERR_GENERR);
1385 switch (val->var.subs[sub - 1]) {
1386 case LEAF_begemotBridgeStpPortAdminEdgePort:
1387 bridge_port_set_admin_edge(b_name, bp,
1388 ctx->scratch->int1);
1390 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1391 bridge_port_set_admin_ptp(b_name, bp,
1392 ctx->scratch->int1);
1394 case LEAF_begemotBridgeStpPortAdminPathCost:
1395 bridge_port_set_path_cost(b_name, bp,
1396 ctx->scratch->int1);
1399 return (SNMP_ERR_NOERROR);
1401 case SNMP_OP_COMMIT:
1402 return (SNMP_ERR_NOERROR);
1407 switch (val->var.subs[sub - 1]) {
1408 case LEAF_begemotBridgeStpPortProtocolMigration:
1409 val->v.integer = bp->proto_migr;
1410 return (SNMP_ERR_NOERROR);
1412 case LEAF_begemotBridgeStpPortAdminEdgePort:
1413 val->v.integer = bp->admin_edge;
1414 return (SNMP_ERR_NOERROR);
1416 case LEAF_begemotBridgeStpPortOperEdgePort:
1417 val->v.integer = bp->oper_edge;
1418 return (SNMP_ERR_NOERROR);
1420 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1421 val->v.integer = bp->admin_ptp;
1422 return (SNMP_ERR_NOERROR);
1424 case LEAF_begemotBridgeStpPortOperPointToPoint:
1425 val->v.integer = bp->oper_ptp;
1426 return (SNMP_ERR_NOERROR);
1428 case LEAF_begemotBridgeStpPortAdminPathCost:
1429 val->v.integer = bp->admin_path_cost;
1430 return (SNMP_ERR_NOERROR);
1437 op_begemot_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
1438 uint sub, uint iidx __unused, enum snmp_op op)
1440 struct bridge_port *bp;
1442 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1443 bridge_update_all_ports();
1447 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1448 return (SNMP_ERR_NOSUCHNAME);
1451 case SNMP_OP_GETNEXT:
1452 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1453 NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1454 return (SNMP_ERR_NOSUCHNAME);
1458 return (SNMP_ERR_NOT_WRITEABLE);
1460 case SNMP_OP_ROLLBACK:
1461 case SNMP_OP_COMMIT:
1467 switch (val->var.subs[sub - 1]) {
1468 case LEAF_begemotBridgeTpPort:
1469 val->v.integer = bp->port_no;
1470 return (SNMP_ERR_NOERROR);
1472 case LEAF_begemotBridgeTpPortMaxInfo:
1473 val->v.integer = bp->max_info;
1474 return (SNMP_ERR_NOERROR);
1476 case LEAF_begemotBridgeTpPortInFrames:
1477 val->v.uint32 = bp->in_frames;
1478 return (SNMP_ERR_NOERROR);
1480 case LEAF_begemotBridgeTpPortOutFrames:
1481 val->v.uint32 = bp->out_frames;
1482 return (SNMP_ERR_NOERROR);
1484 case LEAF_begemotBridgeTpPortInDiscards:
1485 val->v.uint32 = bp->in_drops;
1486 return (SNMP_ERR_NOERROR);