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;
1078 struct bridge_port *bp;
1080 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1081 bridge_update_all_ports();
1083 which = val->var.subs[sub - 1];
1088 if (which == LEAF_begemotBridgeBaseSpanEnabled ||
1089 which == LEAF_begemotBridgeBasePortStatus)
1091 if ((bp = bridge_port_index_get(&val->var, sub,
1093 return (SNMP_ERR_NOSUCHNAME);
1096 case SNMP_OP_GETNEXT:
1097 if (which == LEAF_begemotBridgeBaseSpanEnabled ||
1098 which == LEAF_begemotBridgeBasePortStatus)
1100 if ((bp = bridge_port_index_getnext(&val->var, sub,
1102 bridge_port_index_append(&val->var, sub, bp) < 0)
1103 return (SNMP_ERR_NOSUCHNAME);
1108 case LEAF_begemotBridgeBaseSpanEnabled:
1109 return (bridge_port_set_span_enable(ctx, val, sub));
1111 case LEAF_begemotBridgeBasePortStatus:
1112 return (bridge_port_set_status(ctx, val, sub));
1114 case LEAF_begemotBridgeBasePortPrivate:
1115 if ((bp = bridge_port_index_get(&val->var, sub,
1117 return (SNMP_ERR_NOSUCHNAME);
1118 if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
1119 return (SNMP_ERR_GENERR);
1120 ctx->scratch->int1 = bp->priv_set;
1121 return (bridge_port_set_private(bname, bp,
1124 case LEAF_begemotBridgeBasePort:
1125 case LEAF_begemotBridgeBasePortIfIndex:
1126 case LEAF_begemotBridgeBasePortDelayExceededDiscards:
1127 case LEAF_begemotBridgeBasePortMtuExceededDiscards:
1128 return (SNMP_ERR_NOT_WRITEABLE);
1132 case SNMP_OP_ROLLBACK:
1134 case LEAF_begemotBridgeBaseSpanEnabled:
1136 case LEAF_begemotBridgeBasePortStatus:
1137 return (bridge_port_rollback_status(ctx, val, sub));
1138 case LEAF_begemotBridgeBasePortPrivate:
1139 if ((bp = bridge_port_index_get(&val->var, sub,
1141 return (SNMP_ERR_GENERR);
1142 if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
1143 return (SNMP_ERR_GENERR);
1144 return (bridge_port_set_private(bname, bp,
1145 ctx->scratch->int1));
1147 return (SNMP_ERR_NOERROR);
1149 case SNMP_OP_COMMIT:
1150 if (which == LEAF_begemotBridgeBasePortStatus)
1151 return (bridge_port_commit_status(val, sub));
1153 return (SNMP_ERR_NOERROR);
1159 case LEAF_begemotBridgeBasePort:
1160 val->v.integer = bp->port_no;
1161 return (SNMP_ERR_NOERROR);
1163 case LEAF_begemotBridgeBasePortIfIndex:
1164 val->v.integer = bp->if_idx;
1165 return (SNMP_ERR_NOERROR);
1167 case LEAF_begemotBridgeBaseSpanEnabled:
1168 val->v.integer = bp->span_enable;
1169 return (SNMP_ERR_NOERROR);
1171 case LEAF_begemotBridgeBasePortDelayExceededDiscards:
1172 val->v.uint32 = bp->dly_ex_drops;
1173 return (SNMP_ERR_NOERROR);
1175 case LEAF_begemotBridgeBasePortMtuExceededDiscards:
1176 val->v.uint32 = bp->dly_mtu_drops;
1177 return (SNMP_ERR_NOERROR);
1179 case LEAF_begemotBridgeBasePortStatus:
1180 val->v.integer = bp->status;
1181 return (SNMP_ERR_NOERROR);
1183 case LEAF_begemotBridgeBasePortPrivate:
1184 val->v.integer = bp->priv_set;
1185 return (SNMP_ERR_NOERROR);
1192 op_begemot_stp_port(struct snmp_context *ctx, struct snmp_value *val,
1193 uint sub, uint iidx __unused, enum snmp_op op)
1195 struct bridge_port *bp;
1198 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1199 bridge_update_all_ports();
1203 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1204 return (SNMP_ERR_NOSUCHNAME);
1207 case SNMP_OP_GETNEXT:
1208 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1209 NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1210 return (SNMP_ERR_NOSUCHNAME);
1214 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1215 return (SNMP_ERR_NOSUCHNAME);
1216 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1217 return (SNMP_ERR_GENERR);
1219 switch (val->var.subs[sub - 1]) {
1220 case LEAF_begemotBridgeStpPortPriority:
1221 if (val->v.integer < 0 || val->v.integer > 255)
1222 return (SNMP_ERR_WRONG_VALUE);
1224 ctx->scratch->int1 = bp->priority;
1225 if (bridge_port_set_priority(b_name, bp,
1226 val->v.integer) < 0)
1227 return (SNMP_ERR_GENERR);
1228 return (SNMP_ERR_NOERROR);
1230 case LEAF_begemotBridgeStpPortEnable:
1231 if (val->v.integer !=
1232 begemotBridgeStpPortEnable_enabled ||
1234 begemotBridgeStpPortEnable_disabled)
1235 return (SNMP_ERR_WRONG_VALUE);
1237 ctx->scratch->int1 = bp->enable;
1238 if (bridge_port_set_stp_enable(b_name, bp,
1239 val->v.integer) < 0)
1240 return (SNMP_ERR_GENERR);
1241 return (SNMP_ERR_NOERROR);
1243 case LEAF_begemotBridgeStpPortPathCost:
1244 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
1245 val->v.integer > SNMP_PORT_MAX_PATHCOST)
1246 return (SNMP_ERR_WRONG_VALUE);
1248 ctx->scratch->int1 = bp->path_cost;
1249 if (bridge_port_set_path_cost(b_name, bp,
1250 val->v.integer) < 0)
1251 return (SNMP_ERR_GENERR);
1252 return (SNMP_ERR_NOERROR);
1254 case LEAF_begemotBridgeStpPort:
1255 case LEAF_begemotBridgeStpPortState:
1256 case LEAF_begemotBridgeStpPortDesignatedRoot:
1257 case LEAF_begemotBridgeStpPortDesignatedCost:
1258 case LEAF_begemotBridgeStpPortDesignatedBridge:
1259 case LEAF_begemotBridgeStpPortDesignatedPort:
1260 case LEAF_begemotBridgeStpPortForwardTransitions:
1261 return (SNMP_ERR_NOT_WRITEABLE);
1265 case SNMP_OP_ROLLBACK:
1266 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1267 (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1268 return (SNMP_ERR_GENERR);
1270 switch (val->var.subs[sub - 1]) {
1271 case LEAF_begemotBridgeStpPortPriority:
1272 bridge_port_set_priority(b_name, bp,
1273 ctx->scratch->int1);
1275 case LEAF_begemotBridgeStpPortEnable:
1276 bridge_port_set_stp_enable(b_name, bp,
1277 ctx->scratch->int1);
1279 case LEAF_begemotBridgeStpPortPathCost:
1280 bridge_port_set_path_cost(b_name, bp,
1281 ctx->scratch->int1);
1284 return (SNMP_ERR_NOERROR);
1286 case SNMP_OP_COMMIT:
1287 return (SNMP_ERR_NOERROR);
1292 switch (val->var.subs[sub - 1]) {
1293 case LEAF_begemotBridgeStpPort:
1294 val->v.integer = bp->port_no;
1295 return (SNMP_ERR_NOERROR);
1297 case LEAF_begemotBridgeStpPortPriority:
1298 val->v.integer = bp->priority;
1299 return (SNMP_ERR_NOERROR);
1301 case LEAF_begemotBridgeStpPortState:
1302 val->v.integer = bp->state;
1303 return (SNMP_ERR_NOERROR);
1305 case LEAF_begemotBridgeStpPortEnable:
1306 val->v.integer = bp->enable;
1307 return (SNMP_ERR_NOERROR);
1309 case LEAF_begemotBridgeStpPortPathCost:
1310 val->v.integer = bp->path_cost;
1311 return (SNMP_ERR_NOERROR);
1313 case LEAF_begemotBridgeStpPortDesignatedRoot:
1314 return (string_get(val, bp->design_root, SNMP_BRIDGE_ID_LEN));
1316 case LEAF_begemotBridgeStpPortDesignatedCost:
1317 val->v.integer = bp->design_cost;
1318 return (SNMP_ERR_NOERROR);
1320 case LEAF_begemotBridgeStpPortDesignatedBridge:
1321 return (string_get(val, bp->design_bridge, SNMP_BRIDGE_ID_LEN));
1323 case LEAF_begemotBridgeStpPortDesignatedPort:
1324 return (string_get(val, bp->design_port, 2));
1326 case LEAF_begemotBridgeStpPortForwardTransitions:
1327 val->v.uint32 = bp->fwd_trans;
1328 return (SNMP_ERR_NOERROR);
1335 op_begemot_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
1336 uint sub, uint iidx __unused, enum snmp_op op)
1338 struct bridge_port *bp;
1341 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1342 bridge_update_all_ports();
1346 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1347 return (SNMP_ERR_NOSUCHNAME);
1350 case SNMP_OP_GETNEXT:
1351 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1352 NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1353 return (SNMP_ERR_NOSUCHNAME);
1357 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1358 return (SNMP_ERR_NOSUCHNAME);
1359 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1360 return (SNMP_ERR_GENERR);
1362 switch (val->var.subs[sub - 1]) {
1363 case LEAF_begemotBridgeStpPortAdminEdgePort:
1364 if (val->v.integer != TruthValue_true &&
1365 val->v.integer != TruthValue_false)
1366 return (SNMP_ERR_WRONG_VALUE);
1368 ctx->scratch->int1 = bp->admin_edge;
1369 if (bridge_port_set_admin_edge(b_name, bp,
1370 val->v.integer) < 0)
1371 return (SNMP_ERR_GENERR);
1372 return (SNMP_ERR_NOERROR);
1374 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1375 if (val->v.integer < 0 || val->v.integer >
1376 StpPortAdminPointToPointType_auto)
1377 return (SNMP_ERR_WRONG_VALUE);
1379 ctx->scratch->int1 = bp->admin_ptp;
1380 if (bridge_port_set_admin_ptp(b_name, bp,
1381 val->v.integer) < 0)
1382 return (SNMP_ERR_GENERR);
1383 return (SNMP_ERR_NOERROR);
1385 case LEAF_begemotBridgeStpPortAdminPathCost:
1386 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
1387 val->v.integer > SNMP_PORT_MAX_PATHCOST)
1388 return (SNMP_ERR_WRONG_VALUE);
1390 ctx->scratch->int1 = bp->admin_path_cost;
1391 if (bridge_port_set_path_cost(b_name, bp,
1392 val->v.integer) < 0)
1393 return (SNMP_ERR_GENERR);
1394 return (SNMP_ERR_NOERROR);
1396 case LEAF_begemotBridgeStpPortProtocolMigration:
1397 case LEAF_begemotBridgeStpPortOperEdgePort:
1398 case LEAF_begemotBridgeStpPortOperPointToPoint:
1399 return (SNMP_ERR_NOT_WRITEABLE);
1403 case SNMP_OP_ROLLBACK:
1404 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1405 (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1406 return (SNMP_ERR_GENERR);
1408 switch (val->var.subs[sub - 1]) {
1409 case LEAF_begemotBridgeStpPortAdminEdgePort:
1410 bridge_port_set_admin_edge(b_name, bp,
1411 ctx->scratch->int1);
1413 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1414 bridge_port_set_admin_ptp(b_name, bp,
1415 ctx->scratch->int1);
1417 case LEAF_begemotBridgeStpPortAdminPathCost:
1418 bridge_port_set_path_cost(b_name, bp,
1419 ctx->scratch->int1);
1422 return (SNMP_ERR_NOERROR);
1424 case SNMP_OP_COMMIT:
1425 return (SNMP_ERR_NOERROR);
1430 switch (val->var.subs[sub - 1]) {
1431 case LEAF_begemotBridgeStpPortProtocolMigration:
1432 val->v.integer = bp->proto_migr;
1433 return (SNMP_ERR_NOERROR);
1435 case LEAF_begemotBridgeStpPortAdminEdgePort:
1436 val->v.integer = bp->admin_edge;
1437 return (SNMP_ERR_NOERROR);
1439 case LEAF_begemotBridgeStpPortOperEdgePort:
1440 val->v.integer = bp->oper_edge;
1441 return (SNMP_ERR_NOERROR);
1443 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1444 val->v.integer = bp->admin_ptp;
1445 return (SNMP_ERR_NOERROR);
1447 case LEAF_begemotBridgeStpPortOperPointToPoint:
1448 val->v.integer = bp->oper_ptp;
1449 return (SNMP_ERR_NOERROR);
1451 case LEAF_begemotBridgeStpPortAdminPathCost:
1452 val->v.integer = bp->admin_path_cost;
1453 return (SNMP_ERR_NOERROR);
1460 op_begemot_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
1461 uint sub, uint iidx __unused, enum snmp_op op)
1463 struct bridge_port *bp;
1465 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1466 bridge_update_all_ports();
1470 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1471 return (SNMP_ERR_NOSUCHNAME);
1474 case SNMP_OP_GETNEXT:
1475 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1476 NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1477 return (SNMP_ERR_NOSUCHNAME);
1481 return (SNMP_ERR_NOT_WRITEABLE);
1483 case SNMP_OP_ROLLBACK:
1484 case SNMP_OP_COMMIT:
1490 switch (val->var.subs[sub - 1]) {
1491 case LEAF_begemotBridgeTpPort:
1492 val->v.integer = bp->port_no;
1493 return (SNMP_ERR_NOERROR);
1495 case LEAF_begemotBridgeTpPortMaxInfo:
1496 val->v.integer = bp->max_info;
1497 return (SNMP_ERR_NOERROR);
1499 case LEAF_begemotBridgeTpPortInFrames:
1500 val->v.uint32 = bp->in_frames;
1501 return (SNMP_ERR_NOERROR);
1503 case LEAF_begemotBridgeTpPortOutFrames:
1504 val->v.uint32 = bp->out_frames;
1505 return (SNMP_ERR_NOERROR);
1507 case LEAF_begemotBridgeTpPortInDiscards:
1508 val->v.uint32 = bp->in_drops;
1509 return (SNMP_ERR_NOERROR);