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 #include "bridge_tree.h"
53 #include "bridge_snmp.h"
55 TAILQ_HEAD(bridge_ports, bridge_port);
58 * Free the bridge base ports list.
61 bridge_ports_free(struct bridge_ports *headp)
63 struct bridge_port *bp;
65 while ((bp = TAILQ_FIRST(headp)) != NULL) {
66 TAILQ_REMOVE(headp, bp, b_p);
72 * Free the bridge base ports from the base ports list,
73 * members of a specified bridge interface only.
76 bridge_port_memif_free(struct bridge_ports *headp,
77 struct bridge_if *bif)
79 struct bridge_port *bp;
81 while (bif->f_bp != NULL && bif->sysindex == bif->f_bp->sysindex) {
82 bp = TAILQ_NEXT(bif->f_bp, b_p);
83 TAILQ_REMOVE(headp, bif->f_bp, b_p);
90 * Insert a port entry in the base port TAILQ starting to search
91 * for its place from the position of the first bridge port for the bridge
92 * interface. Update the first bridge port if necessary.
95 bridge_port_insert_at(struct bridge_ports *headp,
96 struct bridge_port *bp, struct bridge_port **f_bp)
98 struct bridge_port *t1;
100 assert(f_bp != NULL);
103 t1 != NULL && bp->sysindex == t1->sysindex;
104 t1 = TAILQ_NEXT(t1, b_p)) {
105 if (bp->if_idx < t1->if_idx) {
106 TAILQ_INSERT_BEFORE(t1, bp, b_p);
114 * Handle the case when our first port was actually the
115 * last element of the TAILQ.
118 TAILQ_INSERT_TAIL(headp, bp, b_p);
120 TAILQ_INSERT_BEFORE(t1, bp, b_p);
124 * Find a port entry's position in the ports list according
125 * to it's parent bridge interface name. Returns a NULL if
126 * we should be at the TAILQ head, otherwise the entry after
127 * which we should be inserted.
129 static struct bridge_port *
130 bridge_port_find_pos(struct bridge_ports *headp, uint32_t b_idx)
133 struct bridge_port *t1;
135 if ((t1 = TAILQ_FIRST(headp)) == NULL ||
136 bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
139 t_idx = t1->sysindex;
141 for (t1 = TAILQ_NEXT(t1, b_p); t1 != NULL; t1 = TAILQ_NEXT(t1, b_p)) {
142 if (t1->sysindex != t_idx) {
143 if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
144 return (TAILQ_PREV(t1, bridge_ports, b_p));
146 t_idx = t1->sysindex;
151 t1 = TAILQ_LAST(headp, bridge_ports);
157 * Insert a bridge member interface in the ports TAILQ.
160 bridge_port_memif_insert(struct bridge_ports *headp,
161 struct bridge_port *bp, struct bridge_port **f_bp)
163 struct bridge_port *temp;
166 bridge_port_insert_at(headp, bp, f_bp);
168 temp = bridge_port_find_pos(headp, bp->sysindex);
171 TAILQ_INSERT_HEAD(headp, bp, b_p);
173 TAILQ_INSERT_AFTER(headp, temp, bp, b_p);
178 /* The global ports list. */
179 static struct bridge_ports bridge_ports = TAILQ_HEAD_INITIALIZER(bridge_ports);
180 static time_t ports_list_age;
183 bridge_ports_update_listage(void)
185 ports_list_age = time(NULL);
189 bridge_ports_fini(void)
191 bridge_ports_free(&bridge_ports);
195 bridge_members_free(struct bridge_if *bif)
197 bridge_port_memif_free(&bridge_ports, bif);
201 * Find the first port in the ports list.
203 static struct bridge_port *
204 bridge_port_first(void)
206 return (TAILQ_FIRST(&bridge_ports));
210 * Find the next port in the ports list.
212 static struct bridge_port *
213 bridge_port_next(struct bridge_port *bp)
215 return (TAILQ_NEXT(bp, b_p));
219 * Find the first member of the specified bridge interface.
222 bridge_port_bif_first(struct bridge_if *bif)
228 * Find the next member of the specified bridge interface.
231 bridge_port_bif_next(struct bridge_port *bp)
233 struct bridge_port *bp_next;
235 if ((bp_next = TAILQ_NEXT(bp, b_p)) == NULL ||
236 bp_next->sysindex != bp->sysindex)
243 * Remove a bridge port from the ports list.
246 bridge_port_remove(struct bridge_port *bp, struct bridge_if *bif)
249 bif->f_bp = bridge_port_bif_next(bp);
251 TAILQ_REMOVE(&bridge_ports, bp, b_p);
256 * Allocate memory for a new bridge port and insert it
257 * in the base ports list. Return a pointer to the port's
258 * structure in case we want to do anything else with it.
261 bridge_new_port(struct mibif *mif, struct bridge_if *bif)
263 struct bridge_port *bp;
265 if ((bp = (struct bridge_port *) malloc(sizeof(*bp))) == NULL) {
266 syslog(LOG_ERR, "bridge new member: failed: %s",
271 bzero(bp, sizeof(*bp));
273 bp->sysindex = bif->sysindex;
274 bp->if_idx = mif->index;
275 bp->port_no = mif->sysindex;
276 strlcpy(bp->p_name, mif->name, IFNAMSIZ);
277 bp->circuit = oid_zeroDotZero;
280 * Initialize all rstpMib specific values to false/default.
281 * These will be set to their true values later if the bridge
284 bp->proto_migr = TruthValue_false;
285 bp->admin_edge = TruthValue_false;
286 bp->oper_edge = TruthValue_false;
287 bp->oper_ptp = TruthValue_false;
288 bp->admin_ptp = StpPortAdminPointToPointType_auto;
290 bridge_port_memif_insert(&bridge_ports, bp, &(bif->f_bp));
296 * Update our info from the corresponding mibII interface info.
299 bridge_port_getinfo_mibif(struct mibif *m_if, struct bridge_port *bp)
301 bp->max_info = m_if->mib.ifmd_data.ifi_mtu;
302 bp->in_frames = m_if->mib.ifmd_data.ifi_ipackets;
303 bp->out_frames = m_if->mib.ifmd_data.ifi_opackets;
304 bp->in_drops = m_if->mib.ifmd_data.ifi_iqdrops;
308 * Find a port, whose SNMP's mibII ifIndex matches one of the ports,
309 * members of the specified bridge interface.
312 bridge_port_find(int32_t if_idx, struct bridge_if *bif)
314 struct bridge_port *bp;
316 for (bp = bif->f_bp; bp != NULL; bp = TAILQ_NEXT(bp, b_p)) {
317 if (bp->sysindex != bif->sysindex) {
322 if (bp->if_idx == if_idx)
330 bridge_ports_dump(struct bridge_if *bif)
332 struct bridge_port *bp;
334 for (bp = bridge_port_bif_first(bif); bp != NULL;
335 bp = bridge_port_bif_next(bp)) {
336 syslog(LOG_ERR, "memif - %s, index - %d",
337 bp->p_name, bp->port_no);
345 op_dot1d_base_port(struct snmp_context *c __unused, struct snmp_value *val,
346 uint sub, uint iidx __unused, enum snmp_op op)
348 struct bridge_if *bif;
349 struct bridge_port *bp;
351 if ((bif = bridge_get_default()) == NULL)
352 return (SNMP_ERR_NOSUCHNAME);
354 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
355 bridge_update_memif(bif) <= 0)
356 return (SNMP_ERR_NOSUCHNAME);
360 if (val->var.len - sub != 1)
361 return (SNMP_ERR_NOSUCHNAME);
362 if ((bp = bridge_port_find(val->var.subs[sub],
364 return (SNMP_ERR_NOSUCHNAME);
367 case SNMP_OP_GETNEXT:
368 if (val->var.len - sub == 0) {
369 if ((bp = bridge_port_bif_first(bif)) == NULL)
370 return (SNMP_ERR_NOSUCHNAME);
372 if ((bp = bridge_port_find(val->var.subs[sub],
374 (bp = bridge_port_bif_next(bp)) == NULL)
375 return (SNMP_ERR_NOSUCHNAME);
377 val->var.len = sub + 1;
378 val->var.subs[sub] = bp->port_no;
382 return (SNMP_ERR_NOT_WRITEABLE);
384 case SNMP_OP_ROLLBACK:
391 switch (val->var.subs[sub - 1]) {
392 case LEAF_dot1dBasePort:
393 val->v.integer = bp->port_no;
394 return (SNMP_ERR_NOERROR);
396 case LEAF_dot1dBasePortIfIndex:
397 val->v.integer = bp->if_idx;
398 return (SNMP_ERR_NOERROR);
400 case LEAF_dot1dBasePortCircuit:
401 val->v.oid = bp->circuit;
402 return (SNMP_ERR_NOERROR);
404 case LEAF_dot1dBasePortDelayExceededDiscards:
405 val->v.uint32 = bp->dly_ex_drops;
406 return (SNMP_ERR_NOERROR);
408 case LEAF_dot1dBasePortMtuExceededDiscards:
409 val->v.uint32 = bp->dly_mtu_drops;
410 return (SNMP_ERR_NOERROR);
417 op_dot1d_stp_port(struct snmp_context *ctx, struct snmp_value *val,
418 uint sub, uint iidx __unused, enum snmp_op op)
420 struct bridge_if *bif;
421 struct bridge_port *bp;
423 if ((bif = bridge_get_default()) == NULL)
424 return (SNMP_ERR_NOSUCHNAME);
426 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
427 bridge_update_memif(bif) <= 0)
428 return (SNMP_ERR_NOSUCHNAME);
432 if (val->var.len - sub != 1)
433 return (SNMP_ERR_NOSUCHNAME);
434 if ((bp = bridge_port_find(val->var.subs[sub],
436 return (SNMP_ERR_NOSUCHNAME);
439 case SNMP_OP_GETNEXT:
440 if (val->var.len - sub == 0) {
441 if ((bp = bridge_port_bif_first(bif)) == NULL)
442 return (SNMP_ERR_NOSUCHNAME);
444 if ((bp = bridge_port_find(val->var.subs[sub],
446 (bp = bridge_port_bif_next(bp)) == NULL)
447 return (SNMP_ERR_NOSUCHNAME);
449 val->var.len = sub + 1;
450 val->var.subs[sub] = bp->port_no;
454 if (val->var.len - sub != 1)
455 return (SNMP_ERR_NOSUCHNAME);
456 if ((bp = bridge_port_find(val->var.subs[sub],
458 return (SNMP_ERR_NOSUCHNAME);
460 switch (val->var.subs[sub - 1]) {
461 case LEAF_dot1dStpPortPriority:
462 if (val->v.integer < 0 || val->v.integer > 255)
463 return (SNMP_ERR_WRONG_VALUE);
465 ctx->scratch->int1 = bp->priority;
466 if (bridge_port_set_priority(bif->bif_name, bp,
468 return (SNMP_ERR_GENERR);
469 return (SNMP_ERR_NOERROR);
471 case LEAF_dot1dStpPortEnable:
472 if (val->v.integer != dot1dStpPortEnable_enabled &&
473 val->v.integer != dot1dStpPortEnable_disabled)
474 return (SNMP_ERR_WRONG_VALUE);
476 ctx->scratch->int1 = bp->enable;
477 if (bridge_port_set_stp_enable(bif->bif_name,
478 bp, val->v.integer) < 0)
479 return (SNMP_ERR_GENERR);
480 return (SNMP_ERR_NOERROR);
482 case LEAF_dot1dStpPortPathCost:
483 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
484 val->v.integer > SNMP_PORT_MAX_PATHCOST)
485 return (SNMP_ERR_WRONG_VALUE);
487 ctx->scratch->int1 = bp->path_cost;
488 if (bridge_port_set_path_cost(bif->bif_name, bp,
490 return (SNMP_ERR_GENERR);
491 return (SNMP_ERR_NOERROR);
493 case LEAF_dot1dStpPort:
494 case LEAF_dot1dStpPortState:
495 case LEAF_dot1dStpPortDesignatedRoot:
496 case LEAF_dot1dStpPortDesignatedCost:
497 case LEAF_dot1dStpPortDesignatedBridge:
498 case LEAF_dot1dStpPortDesignatedPort:
499 case LEAF_dot1dStpPortForwardTransitions:
500 return (SNMP_ERR_NOT_WRITEABLE);
504 case SNMP_OP_ROLLBACK:
505 if ((bp = bridge_port_find(val->var.subs[sub],
507 return (SNMP_ERR_GENERR);
508 switch (val->var.subs[sub - 1]) {
509 case LEAF_dot1dStpPortPriority:
510 bridge_port_set_priority(bif->bif_name, bp,
513 case LEAF_dot1dStpPortEnable:
514 bridge_port_set_stp_enable(bif->bif_name, bp,
517 case LEAF_dot1dStpPortPathCost:
518 bridge_port_set_path_cost(bif->bif_name, bp,
522 return (SNMP_ERR_NOERROR);
525 return (SNMP_ERR_NOERROR);
530 switch (val->var.subs[sub - 1]) {
531 case LEAF_dot1dStpPort:
532 val->v.integer = bp->port_no;
533 return (SNMP_ERR_NOERROR);
535 case LEAF_dot1dStpPortPriority:
536 val->v.integer = bp->priority;
537 return (SNMP_ERR_NOERROR);
539 case LEAF_dot1dStpPortState:
540 val->v.integer = bp->state;
541 return (SNMP_ERR_NOERROR);
543 case LEAF_dot1dStpPortEnable:
544 val->v.integer = bp->enable;
545 return (SNMP_ERR_NOERROR);
547 case LEAF_dot1dStpPortPathCost:
548 val->v.integer = bp->path_cost;
549 return (SNMP_ERR_NOERROR);
551 case LEAF_dot1dStpPortDesignatedRoot:
552 return (string_get(val, bp->design_root,
553 SNMP_BRIDGE_ID_LEN));
555 case LEAF_dot1dStpPortDesignatedCost:
556 val->v.integer = bp->design_cost;
557 return (SNMP_ERR_NOERROR);
559 case LEAF_dot1dStpPortDesignatedBridge:
560 return (string_get(val, bp->design_bridge,
561 SNMP_BRIDGE_ID_LEN));
563 case LEAF_dot1dStpPortDesignatedPort:
564 return (string_get(val, bp->design_port, 2));
566 case LEAF_dot1dStpPortForwardTransitions:
567 val->v.uint32 = bp->fwd_trans;
568 return (SNMP_ERR_NOERROR);
575 op_dot1d_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
576 uint sub, uint iidx __unused, enum snmp_op op)
578 struct bridge_if *bif;
579 struct bridge_port *bp;
581 if ((bif = bridge_get_default()) == NULL)
582 return (SNMP_ERR_NOSUCHNAME);
584 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
585 bridge_update_memif(bif) <= 0)
586 return (SNMP_ERR_NOSUCHNAME);
590 if (val->var.len - sub != 1)
591 return (SNMP_ERR_NOSUCHNAME);
592 if ((bp = bridge_port_find(val->var.subs[sub],
594 return (SNMP_ERR_NOSUCHNAME);
597 case SNMP_OP_GETNEXT:
598 if (val->var.len - sub == 0) {
599 if ((bp = bridge_port_bif_first(bif)) == NULL)
600 return (SNMP_ERR_NOSUCHNAME);
602 if ((bp = bridge_port_find(val->var.subs[sub],
604 (bp = bridge_port_bif_next(bp)) == NULL)
605 return (SNMP_ERR_NOSUCHNAME);
607 val->var.len = sub + 1;
608 val->var.subs[sub] = bp->port_no;
612 if (val->var.len - sub != 1)
613 return (SNMP_ERR_NOSUCHNAME);
614 if ((bp = bridge_port_find(val->var.subs[sub],
616 return (SNMP_ERR_NOSUCHNAME);
618 switch (val->var.subs[sub - 1]) {
619 case LEAF_dot1dStpPortAdminEdgePort:
620 if (val->v.integer != TruthValue_true &&
621 val->v.integer != TruthValue_false)
622 return (SNMP_ERR_WRONG_VALUE);
624 ctx->scratch->int1 = bp->admin_edge;
625 if (bridge_port_set_admin_edge(bif->bif_name, bp,
627 return (SNMP_ERR_GENERR);
628 return (SNMP_ERR_NOERROR);
630 case LEAF_dot1dStpPortAdminPointToPoint:
631 if (val->v.integer < 0 || val->v.integer >
632 StpPortAdminPointToPointType_auto)
633 return (SNMP_ERR_WRONG_VALUE);
635 ctx->scratch->int1 = bp->admin_ptp;
636 if (bridge_port_set_admin_ptp(bif->bif_name, bp,
638 return (SNMP_ERR_GENERR);
639 return (SNMP_ERR_NOERROR);
641 case LEAF_dot1dStpPortAdminPathCost:
642 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
643 val->v.integer > SNMP_PORT_MAX_PATHCOST)
644 return (SNMP_ERR_WRONG_VALUE);
646 ctx->scratch->int1 = bp->admin_path_cost;
647 if (bridge_port_set_path_cost(bif->bif_name, bp,
649 return (SNMP_ERR_GENERR);
650 return (SNMP_ERR_NOERROR);
652 case LEAF_dot1dStpPortProtocolMigration:
653 case LEAF_dot1dStpPortOperEdgePort:
654 case LEAF_dot1dStpPortOperPointToPoint:
655 return (SNMP_ERR_NOT_WRITEABLE);
659 case SNMP_OP_ROLLBACK:
660 if ((bp = bridge_port_find(val->var.subs[sub],
662 return (SNMP_ERR_GENERR);
664 switch (val->var.subs[sub - 1]) {
665 case LEAF_dot1dStpPortAdminEdgePort:
666 bridge_port_set_admin_edge(bif->bif_name, bp,
669 case LEAF_dot1dStpPortAdminPointToPoint:
670 bridge_port_set_admin_ptp(bif->bif_name, bp,
673 case LEAF_dot1dStpPortAdminPathCost:
674 bridge_port_set_path_cost(bif->bif_name, bp,
678 return (SNMP_ERR_NOERROR);
681 return (SNMP_ERR_NOERROR);
686 switch (val->var.subs[sub - 1]) {
687 case LEAF_dot1dStpPortProtocolMigration:
688 val->v.integer = bp->proto_migr;
689 return (SNMP_ERR_NOERROR);
691 case LEAF_dot1dStpPortAdminEdgePort:
692 val->v.integer = bp->admin_edge;
693 return (SNMP_ERR_NOERROR);
695 case LEAF_dot1dStpPortOperEdgePort:
696 val->v.integer = bp->oper_edge;
697 return (SNMP_ERR_NOERROR);
699 case LEAF_dot1dStpPortAdminPointToPoint:
700 val->v.integer = bp->admin_ptp;
701 return (SNMP_ERR_NOERROR);
703 case LEAF_dot1dStpPortOperPointToPoint:
704 val->v.integer = bp->oper_ptp;
705 return (SNMP_ERR_NOERROR);
707 case LEAF_dot1dStpPortAdminPathCost:
708 val->v.integer = bp->admin_path_cost;
709 return (SNMP_ERR_NOERROR);
716 op_dot1d_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
717 uint sub, uint iidx __unused, enum snmp_op op)
719 struct bridge_if *bif;
720 struct bridge_port *bp;
722 if ((bif = bridge_get_default()) == NULL)
723 return (SNMP_ERR_NOSUCHNAME);
725 if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
726 bridge_update_memif(bif) <= 0)
727 return (SNMP_ERR_NOSUCHNAME);
731 if (val->var.len - sub != 1)
732 return (SNMP_ERR_NOSUCHNAME);
733 if ((bp = bridge_port_find(val->var.subs[sub],
735 return (SNMP_ERR_NOSUCHNAME);
738 case SNMP_OP_GETNEXT:
739 if (val->var.len - sub == 0) {
740 if ((bp = bridge_port_bif_first(bif)) == NULL)
741 return (SNMP_ERR_NOSUCHNAME);
743 if ((bp = bridge_port_find(val->var.subs[sub],
745 (bp = bridge_port_bif_next(bp)) == NULL)
746 return (SNMP_ERR_NOSUCHNAME);
748 val->var.len = sub + 1;
749 val->var.subs[sub] = bp->port_no;
753 return (SNMP_ERR_NOT_WRITEABLE);
755 case SNMP_OP_ROLLBACK:
762 switch (val->var.subs[sub - 1]) {
763 case LEAF_dot1dTpPort:
764 val->v.integer = bp->port_no;
765 return (SNMP_ERR_NOERROR);
767 case LEAF_dot1dTpPortMaxInfo:
768 val->v.integer = bp->max_info;
769 return (SNMP_ERR_NOERROR);
771 case LEAF_dot1dTpPortInFrames:
772 val->v.uint32 = bp->in_frames;
773 return (SNMP_ERR_NOERROR);
775 case LEAF_dot1dTpPortOutFrames:
776 val->v.uint32 = bp->out_frames;
777 return (SNMP_ERR_NOERROR);
779 case LEAF_dot1dTpPortInDiscards:
780 val->v.uint32 = bp->in_drops;
781 return (SNMP_ERR_NOERROR);
788 * Private BEGEMOT-BRIDGE-MIB specifics.
792 * Construct a bridge port entry index.
795 bridge_port_index_append(struct asn_oid *oid, uint sub,
796 const struct bridge_port *bp)
801 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
804 oid->len = sub + strlen(b_name) + 1 + 1;
805 oid->subs[sub] = strlen(b_name);
807 for (i = 1; i <= strlen(b_name); i++)
808 oid->subs[sub + i] = b_name[i - 1];
810 oid->subs[sub + i] = bp->port_no;
816 * Get the port entry from an entry's index.
818 static struct bridge_port *
819 bridge_port_index_get(const struct asn_oid *oid, uint sub, int8_t status)
823 char bif_name[IFNAMSIZ];
824 struct bridge_if *bif;
825 struct bridge_port *bp;
827 if (oid->len - sub != oid->subs[sub] + 2 ||
828 oid->subs[sub] >= IFNAMSIZ)
831 for (i = 0; i < oid->subs[sub]; i++)
832 bif_name[i] = oid->subs[sub + i + 1];
835 port_no = oid->subs[sub + i + 1];
837 if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
840 if ((bp = bridge_port_find(port_no, bif)) == NULL ||
841 (status == 0 && bp->status != RowStatus_active))
848 * Get the next port entry from an entry's index.
850 static struct bridge_port *
851 bridge_port_index_getnext(const struct asn_oid *oid, uint sub, int8_t status)
855 char bif_name[IFNAMSIZ];
856 struct bridge_if *bif;
857 struct bridge_port *bp;
859 if (oid->len - sub == 0)
860 bp = bridge_port_first();
862 if (oid->len - sub != oid->subs[sub] + 2 ||
863 oid->subs[sub] >= IFNAMSIZ)
866 for (i = 0; i < oid->subs[sub]; i++)
867 bif_name[i] = oid->subs[sub + i + 1];
870 port_no = oid->subs[sub + i + 1];
872 if ((bif = bridge_if_find_ifname(bif_name)) == NULL ||
873 (bp = bridge_port_find(port_no, bif)) == NULL)
876 bp = bridge_port_next(bp);
883 if (bp->status == RowStatus_active)
885 bp = bridge_port_next(bp);
892 * Read the bridge name and port index from a ASN OID structure.
895 bridge_port_index_decode(const struct asn_oid *oid, uint sub,
896 char *b_name, int32_t *idx)
900 if (oid->len - sub != oid->subs[sub] + 2 ||
901 oid->subs[sub] >= IFNAMSIZ)
904 for (i = 0; i < oid->subs[sub]; i++)
905 b_name[i] = oid->subs[sub + i + 1];
908 *idx = oid->subs[sub + i + 1];
913 bridge_port_set_status(struct snmp_context *ctx,
914 struct snmp_value *val, uint sub)
917 char b_name[IFNAMSIZ];
918 struct bridge_if *bif;
919 struct bridge_port *bp;
922 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
923 return (SNMP_ERR_INCONS_VALUE);
925 if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
926 (mif = mib_find_if(if_idx)) == NULL)
927 return (SNMP_ERR_INCONS_VALUE);
929 bp = bridge_port_find(if_idx, bif);
931 switch (val->v.integer) {
932 case RowStatus_active:
934 return (SNMP_ERR_INCONS_VALUE);
936 if (bp->span_enable == 0)
937 return (SNMP_ERR_INCONS_VALUE);
939 ctx->scratch->int1 = bp->status;
940 bp->status = RowStatus_active;
943 case RowStatus_notInService:
944 if (bp == NULL || bp->span_enable == 0 ||
945 bp->status == RowStatus_active)
946 return (SNMP_ERR_INCONS_VALUE);
948 ctx->scratch->int1 = bp->status;
949 bp->status = RowStatus_notInService;
951 case RowStatus_notReady:
953 case RowStatus_createAndGo:
954 return (SNMP_ERR_INCONS_VALUE);
956 case RowStatus_createAndWait:
958 return (SNMP_ERR_INCONS_VALUE);
960 if ((bp = bridge_new_port(mif, bif)) == NULL)
961 return (SNMP_ERR_GENERR);
963 ctx->scratch->int1 = RowStatus_destroy;
964 bp->status = RowStatus_notReady;
967 case RowStatus_destroy:
969 return (SNMP_ERR_INCONS_VALUE);
971 ctx->scratch->int1 = bp->status;
972 bp->status = RowStatus_destroy;
976 return (SNMP_ERR_NOERROR);
980 bridge_port_rollback_status(struct snmp_context *ctx,
981 struct snmp_value *val, uint sub)
984 char b_name[IFNAMSIZ];
985 struct bridge_if *bif;
986 struct bridge_port *bp;
988 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
989 return (SNMP_ERR_GENERR);
991 if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
992 (bp = bridge_port_find(if_idx, bif)) == NULL)
993 return (SNMP_ERR_GENERR);
995 if (ctx->scratch->int1 == RowStatus_destroy)
996 bridge_port_remove(bp, bif);
998 bp->status = ctx->scratch->int1;
1000 return (SNMP_ERR_NOERROR);
1004 bridge_port_commit_status(struct snmp_value *val, uint sub)
1007 char b_name[IFNAMSIZ];
1008 struct bridge_if *bif;
1009 struct bridge_port *bp;
1011 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
1012 return (SNMP_ERR_GENERR);
1014 if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
1015 (bp = bridge_port_find(if_idx, bif)) == NULL)
1016 return (SNMP_ERR_GENERR);
1018 switch (bp->status) {
1019 case RowStatus_active:
1020 if (bridge_port_addm(bp, b_name) < 0)
1021 return (SNMP_ERR_COMMIT_FAILED);
1024 case RowStatus_destroy:
1025 if (bridge_port_delm(bp, b_name) < 0)
1026 return (SNMP_ERR_COMMIT_FAILED);
1027 bridge_port_remove(bp, bif);
1031 return (SNMP_ERR_NOERROR);
1035 bridge_port_set_span_enable(struct snmp_context *ctx,
1036 struct snmp_value *val, uint sub)
1039 char b_name[IFNAMSIZ];
1040 struct bridge_if *bif;
1041 struct bridge_port *bp;
1044 if (val->v.integer != begemotBridgeBaseSpanEnabled_enabled &&
1045 val->v.integer != begemotBridgeBaseSpanEnabled_disabled)
1046 return (SNMP_ERR_BADVALUE);
1048 if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
1049 return (SNMP_ERR_INCONS_VALUE);
1051 if ((bif = bridge_if_find_ifname(b_name)) == NULL)
1052 return (SNMP_ERR_INCONS_VALUE);
1054 if ((bp = bridge_port_find(if_idx, bif)) == NULL) {
1055 if ((mif = mib_find_if(if_idx)) == NULL)
1056 return (SNMP_ERR_INCONS_VALUE);
1058 if ((bp = bridge_new_port(mif, bif)) == NULL)
1059 return (SNMP_ERR_GENERR);
1061 ctx->scratch->int1 = RowStatus_destroy;
1062 } else if (bp->status == RowStatus_active) {
1063 return (SNMP_ERR_INCONS_VALUE);
1065 ctx->scratch->int1 = bp->status;
1068 bp->span_enable = val->v.integer;
1069 bp->status = RowStatus_notInService;
1071 return (SNMP_ERR_NOERROR);
1075 op_begemot_base_port(struct snmp_context *ctx, struct snmp_value *val,
1076 uint sub, uint iidx __unused, enum snmp_op op)
1078 int8_t status, which;
1080 struct bridge_port *bp;
1082 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1083 bridge_update_all_ports();
1085 which = val->var.subs[sub - 1];
1090 if (which == LEAF_begemotBridgeBaseSpanEnabled ||
1091 which == LEAF_begemotBridgeBasePortStatus)
1093 if ((bp = bridge_port_index_get(&val->var, sub,
1095 return (SNMP_ERR_NOSUCHNAME);
1098 case SNMP_OP_GETNEXT:
1099 if (which == LEAF_begemotBridgeBaseSpanEnabled ||
1100 which == LEAF_begemotBridgeBasePortStatus)
1102 if ((bp = bridge_port_index_getnext(&val->var, sub,
1104 bridge_port_index_append(&val->var, sub, bp) < 0)
1105 return (SNMP_ERR_NOSUCHNAME);
1110 case LEAF_begemotBridgeBaseSpanEnabled:
1111 return (bridge_port_set_span_enable(ctx, val, sub));
1113 case LEAF_begemotBridgeBasePortStatus:
1114 return (bridge_port_set_status(ctx, val, sub));
1116 case LEAF_begemotBridgeBasePortPrivate:
1117 if ((bp = bridge_port_index_get(&val->var, sub,
1119 return (SNMP_ERR_NOSUCHNAME);
1120 if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
1121 return (SNMP_ERR_GENERR);
1122 ctx->scratch->int1 = bp->priv_set;
1123 return (bridge_port_set_private(bname, bp,
1126 case LEAF_begemotBridgeBasePort:
1127 case LEAF_begemotBridgeBasePortIfIndex:
1128 case LEAF_begemotBridgeBasePortDelayExceededDiscards:
1129 case LEAF_begemotBridgeBasePortMtuExceededDiscards:
1130 return (SNMP_ERR_NOT_WRITEABLE);
1134 case SNMP_OP_ROLLBACK:
1136 case LEAF_begemotBridgeBaseSpanEnabled:
1138 case LEAF_begemotBridgeBasePortStatus:
1139 return (bridge_port_rollback_status(ctx, val, sub));
1140 case LEAF_begemotBridgeBasePortPrivate:
1141 if ((bp = bridge_port_index_get(&val->var, sub,
1143 return (SNMP_ERR_GENERR);
1144 if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
1145 return (SNMP_ERR_GENERR);
1146 return (bridge_port_set_private(bname, bp,
1147 ctx->scratch->int1));
1149 return (SNMP_ERR_NOERROR);
1151 case SNMP_OP_COMMIT:
1152 if (which == LEAF_begemotBridgeBasePortStatus)
1153 return (bridge_port_commit_status(val, sub));
1155 return (SNMP_ERR_NOERROR);
1161 case LEAF_begemotBridgeBasePort:
1162 val->v.integer = bp->port_no;
1163 return (SNMP_ERR_NOERROR);
1165 case LEAF_begemotBridgeBasePortIfIndex:
1166 val->v.integer = bp->if_idx;
1167 return (SNMP_ERR_NOERROR);
1169 case LEAF_begemotBridgeBaseSpanEnabled:
1170 val->v.integer = bp->span_enable;
1171 return (SNMP_ERR_NOERROR);
1173 case LEAF_begemotBridgeBasePortDelayExceededDiscards:
1174 val->v.uint32 = bp->dly_ex_drops;
1175 return (SNMP_ERR_NOERROR);
1177 case LEAF_begemotBridgeBasePortMtuExceededDiscards:
1178 val->v.uint32 = bp->dly_mtu_drops;
1179 return (SNMP_ERR_NOERROR);
1181 case LEAF_begemotBridgeBasePortStatus:
1182 val->v.integer = bp->status;
1183 return (SNMP_ERR_NOERROR);
1185 case LEAF_begemotBridgeBasePortPrivate:
1186 val->v.integer = bp->priv_set;
1187 return (SNMP_ERR_NOERROR);
1194 op_begemot_stp_port(struct snmp_context *ctx, struct snmp_value *val,
1195 uint sub, uint iidx __unused, enum snmp_op op)
1197 struct bridge_port *bp;
1200 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1201 bridge_update_all_ports();
1205 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1206 return (SNMP_ERR_NOSUCHNAME);
1209 case SNMP_OP_GETNEXT:
1210 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1211 NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1212 return (SNMP_ERR_NOSUCHNAME);
1216 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1217 return (SNMP_ERR_NOSUCHNAME);
1218 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1219 return (SNMP_ERR_GENERR);
1221 switch (val->var.subs[sub - 1]) {
1222 case LEAF_begemotBridgeStpPortPriority:
1223 if (val->v.integer < 0 || val->v.integer > 255)
1224 return (SNMP_ERR_WRONG_VALUE);
1226 ctx->scratch->int1 = bp->priority;
1227 if (bridge_port_set_priority(b_name, bp,
1228 val->v.integer) < 0)
1229 return (SNMP_ERR_GENERR);
1230 return (SNMP_ERR_NOERROR);
1232 case LEAF_begemotBridgeStpPortEnable:
1233 if (val->v.integer !=
1234 begemotBridgeStpPortEnable_enabled ||
1236 begemotBridgeStpPortEnable_disabled)
1237 return (SNMP_ERR_WRONG_VALUE);
1239 ctx->scratch->int1 = bp->enable;
1240 if (bridge_port_set_stp_enable(b_name, bp,
1241 val->v.integer) < 0)
1242 return (SNMP_ERR_GENERR);
1243 return (SNMP_ERR_NOERROR);
1245 case LEAF_begemotBridgeStpPortPathCost:
1246 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
1247 val->v.integer > SNMP_PORT_MAX_PATHCOST)
1248 return (SNMP_ERR_WRONG_VALUE);
1250 ctx->scratch->int1 = bp->path_cost;
1251 if (bridge_port_set_path_cost(b_name, bp,
1252 val->v.integer) < 0)
1253 return (SNMP_ERR_GENERR);
1254 return (SNMP_ERR_NOERROR);
1256 case LEAF_begemotBridgeStpPort:
1257 case LEAF_begemotBridgeStpPortState:
1258 case LEAF_begemotBridgeStpPortDesignatedRoot:
1259 case LEAF_begemotBridgeStpPortDesignatedCost:
1260 case LEAF_begemotBridgeStpPortDesignatedBridge:
1261 case LEAF_begemotBridgeStpPortDesignatedPort:
1262 case LEAF_begemotBridgeStpPortForwardTransitions:
1263 return (SNMP_ERR_NOT_WRITEABLE);
1267 case SNMP_OP_ROLLBACK:
1268 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1269 (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1270 return (SNMP_ERR_GENERR);
1272 switch (val->var.subs[sub - 1]) {
1273 case LEAF_begemotBridgeStpPortPriority:
1274 bridge_port_set_priority(b_name, bp,
1275 ctx->scratch->int1);
1277 case LEAF_begemotBridgeStpPortEnable:
1278 bridge_port_set_stp_enable(b_name, bp,
1279 ctx->scratch->int1);
1281 case LEAF_begemotBridgeStpPortPathCost:
1282 bridge_port_set_path_cost(b_name, bp,
1283 ctx->scratch->int1);
1286 return (SNMP_ERR_NOERROR);
1288 case SNMP_OP_COMMIT:
1289 return (SNMP_ERR_NOERROR);
1294 switch (val->var.subs[sub - 1]) {
1295 case LEAF_begemotBridgeStpPort:
1296 val->v.integer = bp->port_no;
1297 return (SNMP_ERR_NOERROR);
1299 case LEAF_begemotBridgeStpPortPriority:
1300 val->v.integer = bp->priority;
1301 return (SNMP_ERR_NOERROR);
1303 case LEAF_begemotBridgeStpPortState:
1304 val->v.integer = bp->state;
1305 return (SNMP_ERR_NOERROR);
1307 case LEAF_begemotBridgeStpPortEnable:
1308 val->v.integer = bp->enable;
1309 return (SNMP_ERR_NOERROR);
1311 case LEAF_begemotBridgeStpPortPathCost:
1312 val->v.integer = bp->path_cost;
1313 return (SNMP_ERR_NOERROR);
1315 case LEAF_begemotBridgeStpPortDesignatedRoot:
1316 return (string_get(val, bp->design_root, SNMP_BRIDGE_ID_LEN));
1318 case LEAF_begemotBridgeStpPortDesignatedCost:
1319 val->v.integer = bp->design_cost;
1320 return (SNMP_ERR_NOERROR);
1322 case LEAF_begemotBridgeStpPortDesignatedBridge:
1323 return (string_get(val, bp->design_bridge, SNMP_BRIDGE_ID_LEN));
1325 case LEAF_begemotBridgeStpPortDesignatedPort:
1326 return (string_get(val, bp->design_port, 2));
1328 case LEAF_begemotBridgeStpPortForwardTransitions:
1329 val->v.uint32 = bp->fwd_trans;
1330 return (SNMP_ERR_NOERROR);
1337 op_begemot_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
1338 uint sub, uint iidx __unused, enum snmp_op op)
1340 struct bridge_port *bp;
1343 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1344 bridge_update_all_ports();
1348 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1349 return (SNMP_ERR_NOSUCHNAME);
1352 case SNMP_OP_GETNEXT:
1353 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1354 NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1355 return (SNMP_ERR_NOSUCHNAME);
1359 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1360 return (SNMP_ERR_NOSUCHNAME);
1361 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1362 return (SNMP_ERR_GENERR);
1364 switch (val->var.subs[sub - 1]) {
1365 case LEAF_begemotBridgeStpPortAdminEdgePort:
1366 if (val->v.integer != TruthValue_true &&
1367 val->v.integer != TruthValue_false)
1368 return (SNMP_ERR_WRONG_VALUE);
1370 ctx->scratch->int1 = bp->admin_edge;
1371 if (bridge_port_set_admin_edge(b_name, bp,
1372 val->v.integer) < 0)
1373 return (SNMP_ERR_GENERR);
1374 return (SNMP_ERR_NOERROR);
1376 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1377 if (val->v.integer < 0 || val->v.integer >
1378 StpPortAdminPointToPointType_auto)
1379 return (SNMP_ERR_WRONG_VALUE);
1381 ctx->scratch->int1 = bp->admin_ptp;
1382 if (bridge_port_set_admin_ptp(b_name, bp,
1383 val->v.integer) < 0)
1384 return (SNMP_ERR_GENERR);
1385 return (SNMP_ERR_NOERROR);
1387 case LEAF_begemotBridgeStpPortAdminPathCost:
1388 if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
1389 val->v.integer > SNMP_PORT_MAX_PATHCOST)
1390 return (SNMP_ERR_WRONG_VALUE);
1392 ctx->scratch->int1 = bp->admin_path_cost;
1393 if (bridge_port_set_path_cost(b_name, bp,
1394 val->v.integer) < 0)
1395 return (SNMP_ERR_GENERR);
1396 return (SNMP_ERR_NOERROR);
1398 case LEAF_begemotBridgeStpPortProtocolMigration:
1399 case LEAF_begemotBridgeStpPortOperEdgePort:
1400 case LEAF_begemotBridgeStpPortOperPointToPoint:
1401 return (SNMP_ERR_NOT_WRITEABLE);
1405 case SNMP_OP_ROLLBACK:
1406 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1407 (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1408 return (SNMP_ERR_GENERR);
1410 switch (val->var.subs[sub - 1]) {
1411 case LEAF_begemotBridgeStpPortAdminEdgePort:
1412 bridge_port_set_admin_edge(b_name, bp,
1413 ctx->scratch->int1);
1415 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1416 bridge_port_set_admin_ptp(b_name, bp,
1417 ctx->scratch->int1);
1419 case LEAF_begemotBridgeStpPortAdminPathCost:
1420 bridge_port_set_path_cost(b_name, bp,
1421 ctx->scratch->int1);
1424 return (SNMP_ERR_NOERROR);
1426 case SNMP_OP_COMMIT:
1427 return (SNMP_ERR_NOERROR);
1432 switch (val->var.subs[sub - 1]) {
1433 case LEAF_begemotBridgeStpPortProtocolMigration:
1434 val->v.integer = bp->proto_migr;
1435 return (SNMP_ERR_NOERROR);
1437 case LEAF_begemotBridgeStpPortAdminEdgePort:
1438 val->v.integer = bp->admin_edge;
1439 return (SNMP_ERR_NOERROR);
1441 case LEAF_begemotBridgeStpPortOperEdgePort:
1442 val->v.integer = bp->oper_edge;
1443 return (SNMP_ERR_NOERROR);
1445 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1446 val->v.integer = bp->admin_ptp;
1447 return (SNMP_ERR_NOERROR);
1449 case LEAF_begemotBridgeStpPortOperPointToPoint:
1450 val->v.integer = bp->oper_ptp;
1451 return (SNMP_ERR_NOERROR);
1453 case LEAF_begemotBridgeStpPortAdminPathCost:
1454 val->v.integer = bp->admin_path_cost;
1455 return (SNMP_ERR_NOERROR);
1462 op_begemot_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
1463 uint sub, uint iidx __unused, enum snmp_op op)
1465 struct bridge_port *bp;
1467 if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1468 bridge_update_all_ports();
1472 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1473 return (SNMP_ERR_NOSUCHNAME);
1476 case SNMP_OP_GETNEXT:
1477 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1478 NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1479 return (SNMP_ERR_NOSUCHNAME);
1483 return (SNMP_ERR_NOT_WRITEABLE);
1485 case SNMP_OP_ROLLBACK:
1486 case SNMP_OP_COMMIT:
1492 switch (val->var.subs[sub - 1]) {
1493 case LEAF_begemotBridgeTpPort:
1494 val->v.integer = bp->port_no;
1495 return (SNMP_ERR_NOERROR);
1497 case LEAF_begemotBridgeTpPortMaxInfo:
1498 val->v.integer = bp->max_info;
1499 return (SNMP_ERR_NOERROR);
1501 case LEAF_begemotBridgeTpPortInFrames:
1502 val->v.uint32 = bp->in_frames;
1503 return (SNMP_ERR_NOERROR);
1505 case LEAF_begemotBridgeTpPortOutFrames:
1506 val->v.uint32 = bp->out_frames;
1507 return (SNMP_ERR_NOERROR);
1509 case LEAF_begemotBridgeTpPortInDiscards:
1510 val->v.uint32 = bp->in_drops;
1511 return (SNMP_ERR_NOERROR);