2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * Bridge MIB implementation for SNMPd.
34 #include <sys/queue.h>
35 #include <sys/socket.h>
36 #include <sys/types.h>
38 #include <net/ethernet.h>
40 #include <net/if_mib.h>
49 #include <bsnmp/snmpmod.h>
50 #include <bsnmp/snmp_mibII.h>
52 #define SNMPTREE_TYPES
53 #include "bridge_tree.h"
54 #include "bridge_snmp.h"
56 TAILQ_HEAD(bridge_ports, bridge_port);
59 * Free the bridge base ports list.
62 bridge_ports_free(struct bridge_ports *headp)
64 struct bridge_port *bp;
66 while ((bp = TAILQ_FIRST(headp)) != NULL) {
67 TAILQ_REMOVE(headp, bp, b_p);
73 * Free the bridge base ports from the base ports list,
74 * members of a specified bridge interface only.
77 bridge_port_memif_free(struct bridge_ports *headp,
78 struct bridge_if *bif)
80 struct bridge_port *bp;
82 while (bif->f_bp != NULL && bif->sysindex == bif->f_bp->sysindex) {
83 bp = TAILQ_NEXT(bif->f_bp, b_p);
84 TAILQ_REMOVE(headp, bif->f_bp, b_p);
91 * Insert a port entry in the base port TAILQ starting to search
92 * for its place from the position of the first bridge port for the bridge
93 * interface. Update the first bridge port if necessary.
96 bridge_port_insert_at(struct bridge_ports *headp,
97 struct bridge_port *bp, struct bridge_port **f_bp)
99 struct bridge_port *t1;
101 assert(f_bp != NULL);
104 t1 != NULL && bp->sysindex == t1->sysindex;
105 t1 = TAILQ_NEXT(t1, b_p)) {
106 if (bp->if_idx < t1->if_idx) {
107 TAILQ_INSERT_BEFORE(t1, bp, b_p);
115 * Handle the case when our first port was actually the
116 * last element of the TAILQ.
119 TAILQ_INSERT_TAIL(headp, bp, b_p);
121 TAILQ_INSERT_BEFORE(t1, bp, b_p);
125 * Find a port entry's position in the ports list according
126 * to it's parent bridge interface name. Returns a NULL if
127 * we should be at the TAILQ head, otherwise the entry after
128 * which we should be inserted.
130 static struct bridge_port *
131 bridge_port_find_pos(struct bridge_ports *headp, uint32_t b_idx)
134 struct bridge_port *t1;
136 if ((t1 = TAILQ_FIRST(headp)) == NULL ||
137 bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
140 t_idx = t1->sysindex;
142 for (t1 = TAILQ_NEXT(t1, b_p); t1 != NULL; t1 = TAILQ_NEXT(t1, b_p)) {
143 if (t1->sysindex != t_idx) {
144 if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
145 return (TAILQ_PREV(t1, bridge_ports, b_p));
147 t_idx = t1->sysindex;
152 t1 = TAILQ_LAST(headp, bridge_ports);
158 * Insert a bridge member interface in the ports TAILQ.
161 bridge_port_memif_insert(struct bridge_ports *headp,
162 struct bridge_port *bp, struct bridge_port **f_bp)
164 struct bridge_port *temp;
167 bridge_port_insert_at(headp, bp, f_bp);
169 temp = bridge_port_find_pos(headp, bp->sysindex);
172 TAILQ_INSERT_HEAD(headp, bp, b_p);
174 TAILQ_INSERT_AFTER(headp, temp, bp, b_p);
179 /* The global ports list. */
180 static struct bridge_ports bridge_ports = TAILQ_HEAD_INITIALIZER(bridge_ports);
181 static time_t ports_list_age;
184 bridge_ports_update_listage(void)
186 ports_list_age = time(NULL);
190 bridge_ports_fini(void)
192 bridge_ports_free(&bridge_ports);
196 bridge_members_free(struct bridge_if *bif)
198 bridge_port_memif_free(&bridge_ports, bif);
202 * Find the first port in the ports list.
204 static struct bridge_port *
205 bridge_port_first(void)
207 return (TAILQ_FIRST(&bridge_ports));
211 * Find the next port in the ports list.
213 static struct bridge_port *
214 bridge_port_next(struct bridge_port *bp)
216 return (TAILQ_NEXT(bp, b_p));
220 * Find the first member of the specified bridge interface.
223 bridge_port_bif_first(struct bridge_if *bif)
229 * Find the next member of the specified bridge interface.
232 bridge_port_bif_next(struct bridge_port *bp)
234 struct bridge_port *bp_next;
236 if ((bp_next = TAILQ_NEXT(bp, b_p)) == NULL ||
237 bp_next->sysindex != bp->sysindex)
244 * Remove a bridge port from the ports list.
247 bridge_port_remove(struct bridge_port *bp, struct bridge_if *bif)
250 bif->f_bp = bridge_port_bif_next(bp);
252 TAILQ_REMOVE(&bridge_ports, bp, b_p);
257 * Allocate memory for a new bridge port and insert it
258 * in the base ports list. Return a pointer to the port's
259 * structure in case we want to do anything else with it.
262 bridge_new_port(struct mibif *mif, struct bridge_if *bif)
264 struct bridge_port *bp;
266 if ((bp = (struct bridge_port *) malloc(sizeof(*bp))) == NULL) {
267 syslog(LOG_ERR, "bridge new member: failed: %s",
272 bzero(bp, sizeof(*bp));
274 bp->sysindex = bif->sysindex;
275 bp->if_idx = mif->index;
276 bp->port_no = mif->sysindex;
277 strlcpy(bp->p_name, mif->name, IFNAMSIZ);
278 bp->circuit = oid_zeroDotZero;
281 * Initialize all rstpMib specific values to false/default.
282 * These will be set to their true values later if the bridge
285 bp->proto_migr = TruthValue_false;
286 bp->admin_edge = TruthValue_false;
287 bp->oper_edge = TruthValue_false;
288 bp->oper_ptp = TruthValue_false;
289 bp->admin_ptp = StpPortAdminPointToPointType_auto;
291 bridge_port_memif_insert(&bridge_ports, bp, &(bif->f_bp));
297 * Update our info from the corresponding mibII interface info.
300 bridge_port_getinfo_mibif(struct mibif *m_if, struct bridge_port *bp)
302 bp->max_info = m_if->mib.ifmd_data.ifi_mtu;
303 bp->in_frames = m_if->mib.ifmd_data.ifi_ipackets;
304 bp->out_frames = m_if->mib.ifmd_data.ifi_opackets;
305 bp->in_drops = m_if->mib.ifmd_data.ifi_iqdrops;
309 * Find a port, whose SNMP's mibII ifIndex matches one of the ports,
310 * members of the specified bridge interface.
313 bridge_port_find(int32_t if_idx, struct bridge_if *bif)
315 struct bridge_port *bp;
317 for (bp = bif->f_bp; bp != NULL; bp = TAILQ_NEXT(bp, b_p)) {
318 if (bp->sysindex != bif->sysindex) {
323 if (bp->if_idx == if_idx)
331 bridge_ports_dump(struct bridge_if *bif)
333 struct bridge_port *bp;
335 for (bp = bridge_port_bif_first(bif); bp != NULL;
336 bp = bridge_port_bif_next(bp)) {
337 syslog(LOG_ERR, "memif - %s, index - %d",
338 bp->p_name, bp->port_no);
346 op_dot1d_base_port(struct snmp_context *c __unused, struct snmp_value *val,
347 uint sub, uint iidx __unused, enum snmp_op op)
349 struct bridge_if *bif;
350 struct bridge_port *bp;
352 if ((bif = bridge_get_default()) == NULL)
353 return (SNMP_ERR_NOSUCHNAME);
355 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
356 bridge_update_memif(bif) <= 0)
357 return (SNMP_ERR_NOSUCHNAME);
361 if (val->var.len - sub != 1)
362 return (SNMP_ERR_NOSUCHNAME);
363 if ((bp = bridge_port_find(val->var.subs[sub],
365 return (SNMP_ERR_NOSUCHNAME);
368 case SNMP_OP_GETNEXT:
369 if (val->var.len - sub == 0) {
370 if ((bp = bridge_port_bif_first(bif)) == NULL)
371 return (SNMP_ERR_NOSUCHNAME);
373 if ((bp = bridge_port_find(val->var.subs[sub],
375 (bp = bridge_port_bif_next(bp)) == NULL)
376 return (SNMP_ERR_NOSUCHNAME);
378 val->var.len = sub + 1;
379 val->var.subs[sub] = bp->port_no;
383 return (SNMP_ERR_NOT_WRITEABLE);
385 case SNMP_OP_ROLLBACK:
392 switch (val->var.subs[sub - 1]) {
393 case LEAF_dot1dBasePort:
394 val->v.integer = bp->port_no;
395 return (SNMP_ERR_NOERROR);
397 case LEAF_dot1dBasePortIfIndex:
398 val->v.integer = bp->if_idx;
399 return (SNMP_ERR_NOERROR);
401 case LEAF_dot1dBasePortCircuit:
402 val->v.oid = bp->circuit;
403 return (SNMP_ERR_NOERROR);
405 case LEAF_dot1dBasePortDelayExceededDiscards:
406 val->v.uint32 = bp->dly_ex_drops;
407 return (SNMP_ERR_NOERROR);
409 case LEAF_dot1dBasePortMtuExceededDiscards:
410 val->v.uint32 = bp->dly_mtu_drops;
411 return (SNMP_ERR_NOERROR);
418 op_dot1d_stp_port(struct snmp_context *ctx, struct snmp_value *val,
419 uint sub, uint iidx __unused, enum snmp_op op)
421 struct bridge_if *bif;
422 struct bridge_port *bp;
424 if ((bif = bridge_get_default()) == NULL)
425 return (SNMP_ERR_NOSUCHNAME);
427 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
428 bridge_update_memif(bif) <= 0)
429 return (SNMP_ERR_NOSUCHNAME);
433 if (val->var.len - sub != 1)
434 return (SNMP_ERR_NOSUCHNAME);
435 if ((bp = bridge_port_find(val->var.subs[sub],
437 return (SNMP_ERR_NOSUCHNAME);
440 case SNMP_OP_GETNEXT:
441 if (val->var.len - sub == 0) {
442 if ((bp = bridge_port_bif_first(bif)) == NULL)
443 return (SNMP_ERR_NOSUCHNAME);
445 if ((bp = bridge_port_find(val->var.subs[sub],
447 (bp = bridge_port_bif_next(bp)) == NULL)
448 return (SNMP_ERR_NOSUCHNAME);
450 val->var.len = sub + 1;
451 val->var.subs[sub] = bp->port_no;
455 if (val->var.len - sub != 1)
456 return (SNMP_ERR_NOSUCHNAME);
457 if ((bp = bridge_port_find(val->var.subs[sub],
459 return (SNMP_ERR_NOSUCHNAME);
461 switch (val->var.subs[sub - 1]) {
462 case LEAF_dot1dStpPortPriority:
463 if (val->v.integer < 0 || val->v.integer > 255)
464 return (SNMP_ERR_WRONG_VALUE);
466 ctx->scratch->int1 = bp->priority;
467 if (bridge_port_set_priority(bif->bif_name, bp,
469 return (SNMP_ERR_GENERR);
470 return (SNMP_ERR_NOERROR);
472 case LEAF_dot1dStpPortEnable:
473 if (val->v.integer != dot1dStpPortEnable_enabled &&
474 val->v.integer != dot1dStpPortEnable_disabled)
475 return (SNMP_ERR_WRONG_VALUE);
477 ctx->scratch->int1 = bp->enable;
478 if (bridge_port_set_stp_enable(bif->bif_name,
479 bp, val->v.integer) < 0)
480 return (SNMP_ERR_GENERR);
481 return (SNMP_ERR_NOERROR);
483 case LEAF_dot1dStpPortPathCost:
484 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
485 val->v.integer > SNMP_PORT_MAX_PATHCOST)
486 return (SNMP_ERR_WRONG_VALUE);
488 ctx->scratch->int1 = bp->path_cost;
489 if (bridge_port_set_path_cost(bif->bif_name, bp,
491 return (SNMP_ERR_GENERR);
492 return (SNMP_ERR_NOERROR);
494 case LEAF_dot1dStpPort:
495 case LEAF_dot1dStpPortState:
496 case LEAF_dot1dStpPortDesignatedRoot:
497 case LEAF_dot1dStpPortDesignatedCost:
498 case LEAF_dot1dStpPortDesignatedBridge:
499 case LEAF_dot1dStpPortDesignatedPort:
500 case LEAF_dot1dStpPortForwardTransitions:
501 return (SNMP_ERR_NOT_WRITEABLE);
505 case SNMP_OP_ROLLBACK:
506 if ((bp = bridge_port_find(val->var.subs[sub],
508 return (SNMP_ERR_GENERR);
509 switch (val->var.subs[sub - 1]) {
510 case LEAF_dot1dStpPortPriority:
511 bridge_port_set_priority(bif->bif_name, bp,
514 case LEAF_dot1dStpPortEnable:
515 bridge_port_set_stp_enable(bif->bif_name, bp,
518 case LEAF_dot1dStpPortPathCost:
519 bridge_port_set_path_cost(bif->bif_name, bp,
523 return (SNMP_ERR_NOERROR);
526 return (SNMP_ERR_NOERROR);
531 switch (val->var.subs[sub - 1]) {
532 case LEAF_dot1dStpPort:
533 val->v.integer = bp->port_no;
534 return (SNMP_ERR_NOERROR);
536 case LEAF_dot1dStpPortPriority:
537 val->v.integer = bp->priority;
538 return (SNMP_ERR_NOERROR);
540 case LEAF_dot1dStpPortState:
541 val->v.integer = bp->state;
542 return (SNMP_ERR_NOERROR);
544 case LEAF_dot1dStpPortEnable:
545 val->v.integer = bp->enable;
546 return (SNMP_ERR_NOERROR);
548 case LEAF_dot1dStpPortPathCost:
549 val->v.integer = bp->path_cost;
550 return (SNMP_ERR_NOERROR);
552 case LEAF_dot1dStpPortDesignatedRoot:
553 return (string_get(val, bp->design_root,
554 SNMP_BRIDGE_ID_LEN));
556 case LEAF_dot1dStpPortDesignatedCost:
557 val->v.integer = bp->design_cost;
558 return (SNMP_ERR_NOERROR);
560 case LEAF_dot1dStpPortDesignatedBridge:
561 return (string_get(val, bp->design_bridge,
562 SNMP_BRIDGE_ID_LEN));
564 case LEAF_dot1dStpPortDesignatedPort:
565 return (string_get(val, bp->design_port, 2));
567 case LEAF_dot1dStpPortForwardTransitions:
568 val->v.uint32 = bp->fwd_trans;
569 return (SNMP_ERR_NOERROR);
576 op_dot1d_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
577 uint sub, uint iidx __unused, enum snmp_op op)
579 struct bridge_if *bif;
580 struct bridge_port *bp;
582 if ((bif = bridge_get_default()) == NULL)
583 return (SNMP_ERR_NOSUCHNAME);
585 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
586 bridge_update_memif(bif) <= 0)
587 return (SNMP_ERR_NOSUCHNAME);
591 if (val->var.len - sub != 1)
592 return (SNMP_ERR_NOSUCHNAME);
593 if ((bp = bridge_port_find(val->var.subs[sub],
595 return (SNMP_ERR_NOSUCHNAME);
598 case SNMP_OP_GETNEXT:
599 if (val->var.len - sub == 0) {
600 if ((bp = bridge_port_bif_first(bif)) == NULL)
601 return (SNMP_ERR_NOSUCHNAME);
603 if ((bp = bridge_port_find(val->var.subs[sub],
605 (bp = bridge_port_bif_next(bp)) == NULL)
606 return (SNMP_ERR_NOSUCHNAME);
608 val->var.len = sub + 1;
609 val->var.subs[sub] = bp->port_no;
613 if (val->var.len - sub != 1)
614 return (SNMP_ERR_NOSUCHNAME);
615 if ((bp = bridge_port_find(val->var.subs[sub],
617 return (SNMP_ERR_NOSUCHNAME);
619 switch (val->var.subs[sub - 1]) {
620 case LEAF_dot1dStpPortAdminEdgePort:
621 if (val->v.integer != TruthValue_true &&
622 val->v.integer != TruthValue_false)
623 return (SNMP_ERR_WRONG_VALUE);
625 ctx->scratch->int1 = bp->admin_edge;
626 if (bridge_port_set_admin_edge(bif->bif_name, bp,
628 return (SNMP_ERR_GENERR);
629 return (SNMP_ERR_NOERROR);
631 case LEAF_dot1dStpPortAdminPointToPoint:
632 if (val->v.integer < 0 || val->v.integer >
633 StpPortAdminPointToPointType_auto)
634 return (SNMP_ERR_WRONG_VALUE);
636 ctx->scratch->int1 = bp->admin_ptp;
637 if (bridge_port_set_admin_ptp(bif->bif_name, bp,
639 return (SNMP_ERR_GENERR);
640 return (SNMP_ERR_NOERROR);
642 case LEAF_dot1dStpPortAdminPathCost:
643 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
644 val->v.integer > SNMP_PORT_MAX_PATHCOST)
645 return (SNMP_ERR_WRONG_VALUE);
647 ctx->scratch->int1 = bp->admin_path_cost;
648 if (bridge_port_set_path_cost(bif->bif_name, bp,
650 return (SNMP_ERR_GENERR);
651 return (SNMP_ERR_NOERROR);
653 case LEAF_dot1dStpPortProtocolMigration:
654 case LEAF_dot1dStpPortOperEdgePort:
655 case LEAF_dot1dStpPortOperPointToPoint:
656 return (SNMP_ERR_NOT_WRITEABLE);
660 case SNMP_OP_ROLLBACK:
661 if ((bp = bridge_port_find(val->var.subs[sub],
663 return (SNMP_ERR_GENERR);
665 switch (val->var.subs[sub - 1]) {
666 case LEAF_dot1dStpPortAdminEdgePort:
667 bridge_port_set_admin_edge(bif->bif_name, bp,
670 case LEAF_dot1dStpPortAdminPointToPoint:
671 bridge_port_set_admin_ptp(bif->bif_name, bp,
674 case LEAF_dot1dStpPortAdminPathCost:
675 bridge_port_set_path_cost(bif->bif_name, bp,
679 return (SNMP_ERR_NOERROR);
682 return (SNMP_ERR_NOERROR);
687 switch (val->var.subs[sub - 1]) {
688 case LEAF_dot1dStpPortProtocolMigration:
689 val->v.integer = bp->proto_migr;
690 return (SNMP_ERR_NOERROR);
692 case LEAF_dot1dStpPortAdminEdgePort:
693 val->v.integer = bp->admin_edge;
694 return (SNMP_ERR_NOERROR);
696 case LEAF_dot1dStpPortOperEdgePort:
697 val->v.integer = bp->oper_edge;
698 return (SNMP_ERR_NOERROR);
700 case LEAF_dot1dStpPortAdminPointToPoint:
701 val->v.integer = bp->admin_ptp;
702 return (SNMP_ERR_NOERROR);
704 case LEAF_dot1dStpPortOperPointToPoint:
705 val->v.integer = bp->oper_ptp;
706 return (SNMP_ERR_NOERROR);
708 case LEAF_dot1dStpPortAdminPathCost:
709 val->v.integer = bp->admin_path_cost;
710 return (SNMP_ERR_NOERROR);
717 op_dot1d_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
718 uint sub, uint iidx __unused, enum snmp_op op)
720 struct bridge_if *bif;
721 struct bridge_port *bp;
723 if ((bif = bridge_get_default()) == NULL)
724 return (SNMP_ERR_NOSUCHNAME);
726 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
727 bridge_update_memif(bif) <= 0)
728 return (SNMP_ERR_NOSUCHNAME);
732 if (val->var.len - sub != 1)
733 return (SNMP_ERR_NOSUCHNAME);
734 if ((bp = bridge_port_find(val->var.subs[sub],
736 return (SNMP_ERR_NOSUCHNAME);
739 case SNMP_OP_GETNEXT:
740 if (val->var.len - sub == 0) {
741 if ((bp = bridge_port_bif_first(bif)) == NULL)
742 return (SNMP_ERR_NOSUCHNAME);
744 if ((bp = bridge_port_find(val->var.subs[sub],
746 (bp = bridge_port_bif_next(bp)) == NULL)
747 return (SNMP_ERR_NOSUCHNAME);
749 val->var.len = sub + 1;
750 val->var.subs[sub] = bp->port_no;
754 return (SNMP_ERR_NOT_WRITEABLE);
756 case SNMP_OP_ROLLBACK:
763 switch (val->var.subs[sub - 1]) {
764 case LEAF_dot1dTpPort:
765 val->v.integer = bp->port_no;
766 return (SNMP_ERR_NOERROR);
768 case LEAF_dot1dTpPortMaxInfo:
769 val->v.integer = bp->max_info;
770 return (SNMP_ERR_NOERROR);
772 case LEAF_dot1dTpPortInFrames:
773 val->v.uint32 = bp->in_frames;
774 return (SNMP_ERR_NOERROR);
776 case LEAF_dot1dTpPortOutFrames:
777 val->v.uint32 = bp->out_frames;
778 return (SNMP_ERR_NOERROR);
780 case LEAF_dot1dTpPortInDiscards:
781 val->v.uint32 = bp->in_drops;
782 return (SNMP_ERR_NOERROR);
789 * Private BEGEMOT-BRIDGE-MIB specifics.
793 * Construct a bridge port entry index.
796 bridge_port_index_append(struct asn_oid *oid, uint sub,
797 const struct bridge_port *bp)
802 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
805 oid->len = sub + strlen(b_name) + 1 + 1;
806 oid->subs[sub] = strlen(b_name);
808 for (i = 1; i <= strlen(b_name); i++)
809 oid->subs[sub + i] = b_name[i - 1];
811 oid->subs[sub + i] = bp->port_no;
817 * Get the port entry from an entry's index.
819 static struct bridge_port *
820 bridge_port_index_get(const struct asn_oid *oid, uint sub, int8_t status)
824 char bif_name[IFNAMSIZ];
825 struct bridge_if *bif;
826 struct bridge_port *bp;
828 if (oid->len - sub != oid->subs[sub] + 2 ||
829 oid->subs[sub] >= IFNAMSIZ)
832 for (i = 0; i < oid->subs[sub]; i++)
833 bif_name[i] = oid->subs[sub + i + 1];
836 port_no = oid->subs[sub + i + 1];
838 if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
841 if ((bp = bridge_port_find(port_no, bif)) == NULL ||
842 (status == 0 && bp->status != RowStatus_active))
849 * Get the next port entry from an entry's index.
851 static struct bridge_port *
852 bridge_port_index_getnext(const struct asn_oid *oid, uint sub, int8_t status)
856 char bif_name[IFNAMSIZ];
857 struct bridge_if *bif;
858 struct bridge_port *bp;
860 if (oid->len - sub == 0)
861 bp = bridge_port_first();
863 if (oid->len - sub != oid->subs[sub] + 2 ||
864 oid->subs[sub] >= IFNAMSIZ)
867 for (i = 0; i < oid->subs[sub]; i++)
868 bif_name[i] = oid->subs[sub + i + 1];
871 port_no = oid->subs[sub + i + 1];
873 if ((bif = bridge_if_find_ifname(bif_name)) == NULL ||
874 (bp = bridge_port_find(port_no, bif)) == NULL)
877 bp = bridge_port_next(bp);
884 if (bp->status == RowStatus_active)
886 bp = bridge_port_next(bp);
893 * Read the bridge name and port index from a ASN OID structure.
896 bridge_port_index_decode(const struct asn_oid *oid, uint sub,
897 char *b_name, int32_t *idx)
901 if (oid->len - sub != oid->subs[sub] + 2 ||
902 oid->subs[sub] >= IFNAMSIZ)
905 for (i = 0; i < oid->subs[sub]; i++)
906 b_name[i] = oid->subs[sub + i + 1];
909 *idx = oid->subs[sub + i + 1];
914 bridge_port_set_status(struct snmp_context *ctx,
915 struct snmp_value *val, uint sub)
918 char b_name[IFNAMSIZ];
919 struct bridge_if *bif;
920 struct bridge_port *bp;
923 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
924 return (SNMP_ERR_INCONS_VALUE);
926 if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
927 (mif = mib_find_if(if_idx)) == NULL)
928 return (SNMP_ERR_INCONS_VALUE);
930 bp = bridge_port_find(if_idx, bif);
932 switch (val->v.integer) {
933 case RowStatus_active:
935 return (SNMP_ERR_INCONS_VALUE);
937 if (bp->span_enable == 0)
938 return (SNMP_ERR_INCONS_VALUE);
940 ctx->scratch->int1 = bp->status;
941 bp->status = RowStatus_active;
944 case RowStatus_notInService:
945 if (bp == NULL || bp->span_enable == 0 ||
946 bp->status == RowStatus_active)
947 return (SNMP_ERR_INCONS_VALUE);
949 ctx->scratch->int1 = bp->status;
950 bp->status = RowStatus_notInService;
952 case RowStatus_notReady:
954 case RowStatus_createAndGo:
955 return (SNMP_ERR_INCONS_VALUE);
957 case RowStatus_createAndWait:
959 return (SNMP_ERR_INCONS_VALUE);
961 if ((bp = bridge_new_port(mif, bif)) == NULL)
962 return (SNMP_ERR_GENERR);
964 ctx->scratch->int1 = RowStatus_destroy;
965 bp->status = RowStatus_notReady;
968 case RowStatus_destroy:
970 return (SNMP_ERR_INCONS_VALUE);
972 ctx->scratch->int1 = bp->status;
973 bp->status = RowStatus_destroy;
977 return (SNMP_ERR_NOERROR);
981 bridge_port_rollback_status(struct snmp_context *ctx,
982 struct snmp_value *val, uint sub)
985 char b_name[IFNAMSIZ];
986 struct bridge_if *bif;
987 struct bridge_port *bp;
989 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
990 return (SNMP_ERR_GENERR);
992 if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
993 (bp = bridge_port_find(if_idx, bif)) == NULL)
994 return (SNMP_ERR_GENERR);
996 if (ctx->scratch->int1 == RowStatus_destroy)
997 bridge_port_remove(bp, bif);
999 bp->status = ctx->scratch->int1;
1001 return (SNMP_ERR_NOERROR);
1005 bridge_port_commit_status(struct snmp_value *val, uint sub)
1008 char b_name[IFNAMSIZ];
1009 struct bridge_if *bif;
1010 struct bridge_port *bp;
1012 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
1013 return (SNMP_ERR_GENERR);
1015 if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
1016 (bp = bridge_port_find(if_idx, bif)) == NULL)
1017 return (SNMP_ERR_GENERR);
1019 switch (bp->status) {
1020 case RowStatus_active:
1021 if (bridge_port_addm(bp, b_name) < 0)
1022 return (SNMP_ERR_COMMIT_FAILED);
1025 case RowStatus_destroy:
1026 if (bridge_port_delm(bp, b_name) < 0)
1027 return (SNMP_ERR_COMMIT_FAILED);
1028 bridge_port_remove(bp, bif);
1032 return (SNMP_ERR_NOERROR);
1036 bridge_port_set_span_enable(struct snmp_context *ctx,
1037 struct snmp_value *val, uint sub)
1040 char b_name[IFNAMSIZ];
1041 struct bridge_if *bif;
1042 struct bridge_port *bp;
1045 if (val->v.integer != begemotBridgeBaseSpanEnabled_enabled &&
1046 val->v.integer != begemotBridgeBaseSpanEnabled_disabled)
1047 return (SNMP_ERR_BADVALUE);
1049 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
1050 return (SNMP_ERR_INCONS_VALUE);
1052 if ((bif = bridge_if_find_ifname(b_name)) == NULL)
1053 return (SNMP_ERR_INCONS_VALUE);
1055 if ((bp = bridge_port_find(if_idx, bif)) == NULL) {
1056 if ((mif = mib_find_if(if_idx)) == NULL)
1057 return (SNMP_ERR_INCONS_VALUE);
1059 if ((bp = bridge_new_port(mif, bif)) == NULL)
1060 return (SNMP_ERR_GENERR);
1062 ctx->scratch->int1 = RowStatus_destroy;
1063 } else if (bp->status == RowStatus_active) {
1064 return (SNMP_ERR_INCONS_VALUE);
1066 ctx->scratch->int1 = bp->status;
1069 bp->span_enable = val->v.integer;
1070 bp->status = RowStatus_notInService;
1072 return (SNMP_ERR_NOERROR);
1076 op_begemot_base_port(struct snmp_context *ctx, struct snmp_value *val,
1077 uint sub, uint iidx __unused, enum snmp_op op)
1079 int8_t status, which;
1081 struct bridge_port *bp;
1083 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1084 bridge_update_all_ports();
1086 which = val->var.subs[sub - 1];
1091 if (which == LEAF_begemotBridgeBaseSpanEnabled ||
1092 which == LEAF_begemotBridgeBasePortStatus)
1094 if ((bp = bridge_port_index_get(&val->var, sub,
1096 return (SNMP_ERR_NOSUCHNAME);
1099 case SNMP_OP_GETNEXT:
1100 if (which == LEAF_begemotBridgeBaseSpanEnabled ||
1101 which == LEAF_begemotBridgeBasePortStatus)
1103 if ((bp = bridge_port_index_getnext(&val->var, sub,
1105 bridge_port_index_append(&val->var, sub, bp) < 0)
1106 return (SNMP_ERR_NOSUCHNAME);
1111 case LEAF_begemotBridgeBaseSpanEnabled:
1112 return (bridge_port_set_span_enable(ctx, val, sub));
1114 case LEAF_begemotBridgeBasePortStatus:
1115 return (bridge_port_set_status(ctx, val, sub));
1117 case LEAF_begemotBridgeBasePortPrivate:
1118 if ((bp = bridge_port_index_get(&val->var, sub,
1120 return (SNMP_ERR_NOSUCHNAME);
1121 if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
1122 return (SNMP_ERR_GENERR);
1123 ctx->scratch->int1 = bp->priv_set;
1124 return (bridge_port_set_private(bname, bp,
1127 case LEAF_begemotBridgeBasePort:
1128 case LEAF_begemotBridgeBasePortIfIndex:
1129 case LEAF_begemotBridgeBasePortDelayExceededDiscards:
1130 case LEAF_begemotBridgeBasePortMtuExceededDiscards:
1131 return (SNMP_ERR_NOT_WRITEABLE);
1135 case SNMP_OP_ROLLBACK:
1137 case LEAF_begemotBridgeBaseSpanEnabled:
1139 case LEAF_begemotBridgeBasePortStatus:
1140 return (bridge_port_rollback_status(ctx, val, sub));
1141 case LEAF_begemotBridgeBasePortPrivate:
1142 if ((bp = bridge_port_index_get(&val->var, sub,
1144 return (SNMP_ERR_GENERR);
1145 if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
1146 return (SNMP_ERR_GENERR);
1147 return (bridge_port_set_private(bname, bp,
1148 ctx->scratch->int1));
1150 return (SNMP_ERR_NOERROR);
1152 case SNMP_OP_COMMIT:
1153 if (which == LEAF_begemotBridgeBasePortStatus)
1154 return (bridge_port_commit_status(val, sub));
1156 return (SNMP_ERR_NOERROR);
1162 case LEAF_begemotBridgeBasePort:
1163 val->v.integer = bp->port_no;
1164 return (SNMP_ERR_NOERROR);
1166 case LEAF_begemotBridgeBasePortIfIndex:
1167 val->v.integer = bp->if_idx;
1168 return (SNMP_ERR_NOERROR);
1170 case LEAF_begemotBridgeBaseSpanEnabled:
1171 val->v.integer = bp->span_enable;
1172 return (SNMP_ERR_NOERROR);
1174 case LEAF_begemotBridgeBasePortDelayExceededDiscards:
1175 val->v.uint32 = bp->dly_ex_drops;
1176 return (SNMP_ERR_NOERROR);
1178 case LEAF_begemotBridgeBasePortMtuExceededDiscards:
1179 val->v.uint32 = bp->dly_mtu_drops;
1180 return (SNMP_ERR_NOERROR);
1182 case LEAF_begemotBridgeBasePortStatus:
1183 val->v.integer = bp->status;
1184 return (SNMP_ERR_NOERROR);
1186 case LEAF_begemotBridgeBasePortPrivate:
1187 val->v.integer = bp->priv_set;
1188 return (SNMP_ERR_NOERROR);
1195 op_begemot_stp_port(struct snmp_context *ctx, struct snmp_value *val,
1196 uint sub, uint iidx __unused, enum snmp_op op)
1198 struct bridge_port *bp;
1201 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1202 bridge_update_all_ports();
1206 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1207 return (SNMP_ERR_NOSUCHNAME);
1210 case SNMP_OP_GETNEXT:
1211 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1212 NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1213 return (SNMP_ERR_NOSUCHNAME);
1217 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1218 return (SNMP_ERR_NOSUCHNAME);
1219 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1220 return (SNMP_ERR_GENERR);
1222 switch (val->var.subs[sub - 1]) {
1223 case LEAF_begemotBridgeStpPortPriority:
1224 if (val->v.integer < 0 || val->v.integer > 255)
1225 return (SNMP_ERR_WRONG_VALUE);
1227 ctx->scratch->int1 = bp->priority;
1228 if (bridge_port_set_priority(b_name, bp,
1229 val->v.integer) < 0)
1230 return (SNMP_ERR_GENERR);
1231 return (SNMP_ERR_NOERROR);
1233 case LEAF_begemotBridgeStpPortEnable:
1234 if (val->v.integer !=
1235 begemotBridgeStpPortEnable_enabled ||
1237 begemotBridgeStpPortEnable_disabled)
1238 return (SNMP_ERR_WRONG_VALUE);
1240 ctx->scratch->int1 = bp->enable;
1241 if (bridge_port_set_stp_enable(b_name, bp,
1242 val->v.integer) < 0)
1243 return (SNMP_ERR_GENERR);
1244 return (SNMP_ERR_NOERROR);
1246 case LEAF_begemotBridgeStpPortPathCost:
1247 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
1248 val->v.integer > SNMP_PORT_MAX_PATHCOST)
1249 return (SNMP_ERR_WRONG_VALUE);
1251 ctx->scratch->int1 = bp->path_cost;
1252 if (bridge_port_set_path_cost(b_name, bp,
1253 val->v.integer) < 0)
1254 return (SNMP_ERR_GENERR);
1255 return (SNMP_ERR_NOERROR);
1257 case LEAF_begemotBridgeStpPort:
1258 case LEAF_begemotBridgeStpPortState:
1259 case LEAF_begemotBridgeStpPortDesignatedRoot:
1260 case LEAF_begemotBridgeStpPortDesignatedCost:
1261 case LEAF_begemotBridgeStpPortDesignatedBridge:
1262 case LEAF_begemotBridgeStpPortDesignatedPort:
1263 case LEAF_begemotBridgeStpPortForwardTransitions:
1264 return (SNMP_ERR_NOT_WRITEABLE);
1268 case SNMP_OP_ROLLBACK:
1269 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1270 (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1271 return (SNMP_ERR_GENERR);
1273 switch (val->var.subs[sub - 1]) {
1274 case LEAF_begemotBridgeStpPortPriority:
1275 bridge_port_set_priority(b_name, bp,
1276 ctx->scratch->int1);
1278 case LEAF_begemotBridgeStpPortEnable:
1279 bridge_port_set_stp_enable(b_name, bp,
1280 ctx->scratch->int1);
1282 case LEAF_begemotBridgeStpPortPathCost:
1283 bridge_port_set_path_cost(b_name, bp,
1284 ctx->scratch->int1);
1287 return (SNMP_ERR_NOERROR);
1289 case SNMP_OP_COMMIT:
1290 return (SNMP_ERR_NOERROR);
1295 switch (val->var.subs[sub - 1]) {
1296 case LEAF_begemotBridgeStpPort:
1297 val->v.integer = bp->port_no;
1298 return (SNMP_ERR_NOERROR);
1300 case LEAF_begemotBridgeStpPortPriority:
1301 val->v.integer = bp->priority;
1302 return (SNMP_ERR_NOERROR);
1304 case LEAF_begemotBridgeStpPortState:
1305 val->v.integer = bp->state;
1306 return (SNMP_ERR_NOERROR);
1308 case LEAF_begemotBridgeStpPortEnable:
1309 val->v.integer = bp->enable;
1310 return (SNMP_ERR_NOERROR);
1312 case LEAF_begemotBridgeStpPortPathCost:
1313 val->v.integer = bp->path_cost;
1314 return (SNMP_ERR_NOERROR);
1316 case LEAF_begemotBridgeStpPortDesignatedRoot:
1317 return (string_get(val, bp->design_root, SNMP_BRIDGE_ID_LEN));
1319 case LEAF_begemotBridgeStpPortDesignatedCost:
1320 val->v.integer = bp->design_cost;
1321 return (SNMP_ERR_NOERROR);
1323 case LEAF_begemotBridgeStpPortDesignatedBridge:
1324 return (string_get(val, bp->design_bridge, SNMP_BRIDGE_ID_LEN));
1326 case LEAF_begemotBridgeStpPortDesignatedPort:
1327 return (string_get(val, bp->design_port, 2));
1329 case LEAF_begemotBridgeStpPortForwardTransitions:
1330 val->v.uint32 = bp->fwd_trans;
1331 return (SNMP_ERR_NOERROR);
1338 op_begemot_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
1339 uint sub, uint iidx __unused, enum snmp_op op)
1341 struct bridge_port *bp;
1344 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1345 bridge_update_all_ports();
1349 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1350 return (SNMP_ERR_NOSUCHNAME);
1353 case SNMP_OP_GETNEXT:
1354 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1355 NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1356 return (SNMP_ERR_NOSUCHNAME);
1360 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1361 return (SNMP_ERR_NOSUCHNAME);
1362 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1363 return (SNMP_ERR_GENERR);
1365 switch (val->var.subs[sub - 1]) {
1366 case LEAF_begemotBridgeStpPortAdminEdgePort:
1367 if (val->v.integer != TruthValue_true &&
1368 val->v.integer != TruthValue_false)
1369 return (SNMP_ERR_WRONG_VALUE);
1371 ctx->scratch->int1 = bp->admin_edge;
1372 if (bridge_port_set_admin_edge(b_name, bp,
1373 val->v.integer) < 0)
1374 return (SNMP_ERR_GENERR);
1375 return (SNMP_ERR_NOERROR);
1377 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1378 if (val->v.integer < 0 || val->v.integer >
1379 StpPortAdminPointToPointType_auto)
1380 return (SNMP_ERR_WRONG_VALUE);
1382 ctx->scratch->int1 = bp->admin_ptp;
1383 if (bridge_port_set_admin_ptp(b_name, bp,
1384 val->v.integer) < 0)
1385 return (SNMP_ERR_GENERR);
1386 return (SNMP_ERR_NOERROR);
1388 case LEAF_begemotBridgeStpPortAdminPathCost:
1389 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
1390 val->v.integer > SNMP_PORT_MAX_PATHCOST)
1391 return (SNMP_ERR_WRONG_VALUE);
1393 ctx->scratch->int1 = bp->admin_path_cost;
1394 if (bridge_port_set_path_cost(b_name, bp,
1395 val->v.integer) < 0)
1396 return (SNMP_ERR_GENERR);
1397 return (SNMP_ERR_NOERROR);
1399 case LEAF_begemotBridgeStpPortProtocolMigration:
1400 case LEAF_begemotBridgeStpPortOperEdgePort:
1401 case LEAF_begemotBridgeStpPortOperPointToPoint:
1402 return (SNMP_ERR_NOT_WRITEABLE);
1406 case SNMP_OP_ROLLBACK:
1407 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1408 (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1409 return (SNMP_ERR_GENERR);
1411 switch (val->var.subs[sub - 1]) {
1412 case LEAF_begemotBridgeStpPortAdminEdgePort:
1413 bridge_port_set_admin_edge(b_name, bp,
1414 ctx->scratch->int1);
1416 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1417 bridge_port_set_admin_ptp(b_name, bp,
1418 ctx->scratch->int1);
1420 case LEAF_begemotBridgeStpPortAdminPathCost:
1421 bridge_port_set_path_cost(b_name, bp,
1422 ctx->scratch->int1);
1425 return (SNMP_ERR_NOERROR);
1427 case SNMP_OP_COMMIT:
1428 return (SNMP_ERR_NOERROR);
1433 switch (val->var.subs[sub - 1]) {
1434 case LEAF_begemotBridgeStpPortProtocolMigration:
1435 val->v.integer = bp->proto_migr;
1436 return (SNMP_ERR_NOERROR);
1438 case LEAF_begemotBridgeStpPortAdminEdgePort:
1439 val->v.integer = bp->admin_edge;
1440 return (SNMP_ERR_NOERROR);
1442 case LEAF_begemotBridgeStpPortOperEdgePort:
1443 val->v.integer = bp->oper_edge;
1444 return (SNMP_ERR_NOERROR);
1446 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1447 val->v.integer = bp->admin_ptp;
1448 return (SNMP_ERR_NOERROR);
1450 case LEAF_begemotBridgeStpPortOperPointToPoint:
1451 val->v.integer = bp->oper_ptp;
1452 return (SNMP_ERR_NOERROR);
1454 case LEAF_begemotBridgeStpPortAdminPathCost:
1455 val->v.integer = bp->admin_path_cost;
1456 return (SNMP_ERR_NOERROR);
1463 op_begemot_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
1464 uint sub, uint iidx __unused, enum snmp_op op)
1466 struct bridge_port *bp;
1468 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1469 bridge_update_all_ports();
1473 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1474 return (SNMP_ERR_NOSUCHNAME);
1477 case SNMP_OP_GETNEXT:
1478 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1479 NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1480 return (SNMP_ERR_NOSUCHNAME);
1484 return (SNMP_ERR_NOT_WRITEABLE);
1486 case SNMP_OP_ROLLBACK:
1487 case SNMP_OP_COMMIT:
1493 switch (val->var.subs[sub - 1]) {
1494 case LEAF_begemotBridgeTpPort:
1495 val->v.integer = bp->port_no;
1496 return (SNMP_ERR_NOERROR);
1498 case LEAF_begemotBridgeTpPortMaxInfo:
1499 val->v.integer = bp->max_info;
1500 return (SNMP_ERR_NOERROR);
1502 case LEAF_begemotBridgeTpPortInFrames:
1503 val->v.uint32 = bp->in_frames;
1504 return (SNMP_ERR_NOERROR);
1506 case LEAF_begemotBridgeTpPortOutFrames:
1507 val->v.uint32 = bp->out_frames;
1508 return (SNMP_ERR_NOERROR);
1510 case LEAF_begemotBridgeTpPortInDiscards:
1511 val->v.uint32 = bp->in_drops;
1512 return (SNMP_ERR_NOERROR);