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.
29 * Bridge interface objects.
34 #include <sys/queue.h>
35 #include <sys/socket.h>
37 #include <sys/types.h>
39 #include <net/ethernet.h>
41 #include <net/if_mib.h>
42 #include <net/if_types.h>
50 #include <bsnmp/snmpmod.h>
51 #include <bsnmp/snmp_mibII.h>
53 #define SNMPTREE_TYPES
54 #include "bridge_tree.h"
55 #include "bridge_snmp.h"
56 #include "bridge_oid.h"
58 static const struct asn_oid oid_newRoot = OIDX_newRoot;
59 static const struct asn_oid oid_TopologyChange = OIDX_topologyChange;
60 static const struct asn_oid oid_begemotBrigeName = \
61 OIDX_begemotBridgeBaseName;
62 static const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot;
63 static const struct asn_oid oid_begemotTopologyChange = \
64 OIDX_begemotBridgeTopologyChange;
66 TAILQ_HEAD(bridge_ifs, bridge_if);
69 * Free the bridge interface list.
72 bridge_ifs_free(struct bridge_ifs *headp)
76 while ((b = TAILQ_FIRST(headp)) != NULL) {
77 TAILQ_REMOVE(headp, b, b_if);
83 * Insert an entry in the bridge interface TAILQ. Keep the
84 * TAILQ sorted by the bridge's interface name.
87 bridge_ifs_insert(struct bridge_ifs *headp,
90 struct bridge_if *temp;
92 if ((temp = TAILQ_FIRST(headp)) == NULL ||
93 strcmp(b->bif_name, temp->bif_name) < 0) {
94 TAILQ_INSERT_HEAD(headp, b, b_if);
98 TAILQ_FOREACH(temp, headp, b_if)
99 if(strcmp(b->bif_name, temp->bif_name) < 0)
100 TAILQ_INSERT_BEFORE(temp, b, b_if);
102 TAILQ_INSERT_TAIL(headp, b, b_if);
105 /* The global bridge interface list. */
106 static struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs);
107 static time_t bridge_list_age;
110 * Free the global list.
113 bridge_ifs_fini(void)
115 bridge_ifs_free(&bridge_ifs);
119 * Find a bridge interface entry by the bridge interface system index.
122 bridge_if_find_ifs(uint32_t sysindex)
126 TAILQ_FOREACH(b, &bridge_ifs, b_if)
127 if (b->sysindex == sysindex)
134 * Find a bridge interface entry by the bridge interface name.
137 bridge_if_find_ifname(const char *b_name)
141 TAILQ_FOREACH(b, &bridge_ifs, b_if)
142 if (strcmp(b_name, b->bif_name) == 0)
149 * Find a bridge name by the bridge interface system index.
152 bridge_if_find_name(uint32_t sysindex)
156 TAILQ_FOREACH(b, &bridge_ifs, b_if)
157 if (b->sysindex == sysindex)
158 return (b->bif_name);
164 * Given two bridge interfaces' system indexes, find their
165 * corresponding names and return the result of the name
166 * comparison. Returns:
173 bridge_compare_sysidx(uint32_t i1, uint32_t i2)
181 if ((b1 = bridge_if_find_name(i1)) == NULL) {
182 syslog(LOG_ERR, "Bridge interface %d does not exist", i1);
186 if ((b2 = bridge_if_find_name(i2)) == NULL) {
187 syslog(LOG_ERR, "Bridge interface %d does not exist", i2);
191 if ((c = strcmp(b1, b2)) < 0)
200 * Fetch the first bridge interface from the list.
203 bridge_first_bif(void)
205 return (TAILQ_FIRST(&bridge_ifs));
209 * Fetch the next bridge interface from the list.
212 bridge_next_bif(struct bridge_if *b_pr)
214 return (TAILQ_NEXT(b_pr, b_if));
218 * Create a new entry for a bridge interface and insert
221 static struct bridge_if *
222 bridge_new_bif(const char *bif_n, uint32_t sysindex, const u_char *physaddr)
224 struct bridge_if *bif;
226 if ((bif = (struct bridge_if *) malloc(sizeof(*bif)))== NULL) {
227 syslog(LOG_ERR, "bridge new interface failed: %s",
232 bzero(bif, sizeof(struct bridge_if));
233 strlcpy(bif->bif_name, bif_n, IFNAMSIZ);
234 bcopy(physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
235 bif->sysindex = sysindex;
236 bif->br_type = BaseType_transparent_only;
237 /* 1 - all bridges default hold time * 100 - centi-seconds */
238 bif->hold_time = 1 * 100;
239 bif->prot_spec = dot1dStpProtocolSpecification_ieee8021d;
240 bridge_ifs_insert(&bridge_ifs, bif);
246 * Remove a bridge interface from the list, freeing all it's ports
247 * and address entries.
250 bridge_remove_bif(struct bridge_if *bif)
252 bridge_members_free(bif);
253 bridge_addrs_free(bif);
254 TAILQ_REMOVE(&bridge_ifs, bif, b_if);
260 * Prepare the variable (bridge interface name) for the private
261 * begemot notifications.
263 static struct snmp_value*
264 bridge_basename_var(struct bridge_if *bif, struct snmp_value* b_val)
268 b_val->var = oid_begemotBrigeName;
269 b_val->var.subs[b_val->var.len++] = strlen(bif->bif_name);
271 if ((b_val->v.octetstring.octets = (u_char *)
272 malloc(strlen(bif->bif_name))) == NULL)
275 for (i = 0; i < strlen(bif->bif_name); i++)
276 b_val->var.subs[b_val->var.len++] = bif->bif_name[i];
278 b_val->v.octetstring.len = strlen(bif->bif_name);
279 bcopy(bif->bif_name, b_val->v.octetstring.octets,
280 strlen(bif->bif_name));
281 b_val->syntax = SNMP_SYNTAX_OCTETSTRING;
287 * Compare the values of the old and the new root port and
288 * send a new root notification, if they are not matching.
291 bridge_new_root(struct bridge_if *bif)
293 struct snmp_value bif_idx;
295 if (bridge_get_default() == bif)
296 snmp_send_trap(&oid_newRoot, (struct snmp_value *) NULL);
298 if (bridge_basename_var(bif, &bif_idx) == NULL)
301 snmp_send_trap(&oid_begemotTopologyChange,
302 &bif_idx, (struct snmp_value *) NULL);
306 * Compare the new and old topology change times and send a
307 * topology change notification if necessary.
310 bridge_top_change(struct bridge_if *bif)
312 struct snmp_value bif_idx;
314 if (bridge_get_default() == bif)
315 snmp_send_trap(&oid_TopologyChange,
316 (struct snmp_value *) NULL);
318 if (bridge_basename_var(bif, &bif_idx) == NULL)
321 snmp_send_trap(&oid_begemotNewRoot,
322 &bif_idx, (struct snmp_value *) NULL);
326 bridge_if_create(const char* b_name, int8_t up)
328 if (bridge_create(b_name) < 0)
331 if (up == 1 && (bridge_set_if_up(b_name, 1) < 0))
335 * Do not create a new bridge entry here -
336 * wait until the mibII module notifies us.
342 bridge_if_destroy(struct bridge_if *bif)
344 if (bridge_destroy(bif->bif_name) < 0)
347 bridge_remove_bif(bif);
353 * Calculate the timeticks since the last topology change.
356 bridge_get_time_since_tc(struct bridge_if *bif, uint32_t *ticks)
360 if (gettimeofday(&ct, NULL) < 0) {
361 syslog(LOG_ERR, "bridge get time since last TC:"
362 "gettimeofday failed: %s", strerror(errno));
366 if (ct.tv_usec - bif->last_tc_time.tv_usec < 0) {
368 ct.tv_usec += 1000000;
371 ct.tv_sec -= bif->last_tc_time.tv_sec;
372 ct.tv_usec -= bif->last_tc_time.tv_usec;
374 *ticks = ct.tv_sec * 100 + ct.tv_usec/10000;
380 * Update the info we have for a single bridge interface.
383 * 0, if the interface was deleted
384 * -1, error occurred while fetching the info from the kernel.
387 bridge_update_bif(struct bridge_if *bif)
391 /* Walk through the mibII interface list. */
392 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
393 if (strcmp(ifp->name, bif->bif_name) == 0)
397 /* Ops, we do not exist anymore. */
398 bridge_remove_bif(bif);
402 if (ifp->physaddr != NULL )
403 bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
405 bridge_get_basemac(bif->bif_name, bif->br_addr.octet,
408 if (ifp->mib.ifmd_flags & IFF_RUNNING)
409 bif->if_status = RowStatus_active;
411 bif->if_status = RowStatus_notInService;
413 switch (bridge_getinfo_bif(bif)) {
415 bridge_new_root(bif);
418 bridge_top_change(bif);
421 bridge_remove_bif(bif);
428 * The number of ports is accessible via SNMP -
429 * update the ports each time the bridge interface data
432 bif->num_ports = bridge_update_memif(bif);
433 bif->entry_age = time(NULL);
439 * Update all bridge interfaces' ports only -
440 * make sure each bridge interface exists first.
443 bridge_update_all_ports(void)
446 struct bridge_if *bif, *t_bif;
448 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
449 t_bif = bridge_next_bif(bif);
451 for (ifp = mib_first_if(); ifp != NULL;
452 ifp = mib_next_if(ifp))
453 if (strcmp(ifp->name, bif->bif_name) == 0)
457 bif->num_ports = bridge_update_memif(bif);
458 else /* Ops, we do not exist anymore. */
459 bridge_remove_bif(bif);
462 bridge_ports_update_listage();
466 * Update all addresses only.
469 bridge_update_all_addrs(void)
472 struct bridge_if *bif, *t_bif;
474 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
475 t_bif = bridge_next_bif(bif);
477 for (ifp = mib_first_if(); ifp != NULL;
478 ifp = mib_next_if(ifp))
479 if (strcmp(ifp->name, bif->bif_name) == 0)
483 bif->num_addrs = bridge_update_addrs(bif);
484 else /* Ops, we don't exist anymore. */
485 bridge_remove_bif(bif);
488 bridge_addrs_update_listage();
492 * Update only the bridge interfaces' data - skip addresses.
495 bridge_update_all_ifs(void)
497 struct bridge_if *bif, *t_bif;
499 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
500 t_bif = bridge_next_bif(bif);
501 bridge_update_bif(bif);
504 bridge_ports_update_listage();
505 bridge_list_age = time(NULL);
509 * Update all info we have for all bridges.
512 bridge_update_all(void *arg __unused)
514 struct bridge_if *bif, *t_bif;
516 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
517 t_bif = bridge_next_bif(bif);
518 if (bridge_update_bif(bif) <= 0)
521 /* Update our learnt addresses. */
522 bif->num_addrs = bridge_update_addrs(bif);
525 bridge_list_age = time(NULL);
526 bridge_ports_update_listage();
527 bridge_addrs_update_listage();
531 * Callback for polling our last topology change time -
532 * check whether we are root or whether a TC was detected once every
533 * 30 seconds, so that we can send the newRoot and TopologyChange traps
534 * on time. The rest of the data is polled only once every 5 min.
537 bridge_update_tc_time(void *arg __unused)
539 struct bridge_if *bif;
542 TAILQ_FOREACH(bif, &bridge_ifs, b_if) {
543 /* Walk through the mibII interface list. */
544 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
545 if (strcmp(ifp->name, bif->bif_name) == 0)
549 bridge_remove_bif(bif);
553 switch (bridge_get_op_param(bif)) {
555 bridge_new_root(bif);
558 bridge_top_change(bif);
565 * Callback for handling new bridge interface creation.
568 bridge_attach_newif(struct mibif *ifp)
570 u_char mac[ETHER_ADDR_LEN];
571 struct bridge_if *bif;
573 if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE)
576 /* Make sure it does not exist in our list. */
577 TAILQ_FOREACH(bif, &bridge_ifs, b_if)
578 if(strcmp(bif->bif_name, ifp->name) == 0) {
579 syslog(LOG_ERR, "bridge interface %s already "
580 "in list", bif->bif_name);
584 if (ifp->physaddr == NULL) {
585 if (bridge_get_basemac(ifp->name, mac, sizeof(mac)) == NULL) {
586 syslog(LOG_ERR, "bridge attach new %s failed - "
587 "no bridge mac address", ifp->name);
591 bcopy(ifp->physaddr, &mac, sizeof(mac));
593 if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, mac)) == NULL)
596 if (ifp->mib.ifmd_flags & IFF_RUNNING)
597 bif->if_status = RowStatus_active;
599 bif->if_status = RowStatus_notInService;
601 /* Skip sending notifications if the interface was just created. */
602 if (bridge_getinfo_bif(bif) < 0 ||
603 (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 ||
604 (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) {
605 bridge_remove_bif(bif);
609 /* Check whether we are the default bridge interface. */
610 if (strcmp(ifp->name, bridge_get_default_name()) == 0)
611 bridge_set_default(bif);
617 bridge_ifs_dump(void)
619 struct bridge_if *bif;
621 for (bif = bridge_first_bif(); bif != NULL;
622 bif = bridge_next_bif(bif)) {
623 syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name,
625 bridge_ports_dump(bif);
626 bridge_addrs_dump(bif);
634 op_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value,
635 uint sub, uint iidx __unused, enum snmp_op op)
637 struct bridge_if *bif;
639 if ((bif = bridge_get_default()) == NULL)
640 return (SNMP_ERR_NOSUCHNAME);
642 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
643 bridge_update_bif(bif) <= 0) /* It was just deleted. */
644 return (SNMP_ERR_NOSUCHNAME);
648 switch (value->var.subs[sub - 1]) {
649 case LEAF_dot1dBaseBridgeAddress:
650 return (string_get(value, bif->br_addr.octet,
652 case LEAF_dot1dBaseNumPorts:
653 value->v.integer = bif->num_ports;
654 return (SNMP_ERR_NOERROR);
655 case LEAF_dot1dBaseType:
656 value->v.integer = bif->br_type;
657 return (SNMP_ERR_NOERROR);
662 return (SNMP_ERR_NOT_WRITEABLE);
664 case SNMP_OP_GETNEXT:
665 case SNMP_OP_ROLLBACK:
674 op_dot1d_stp(struct snmp_context *ctx, struct snmp_value *val, uint sub,
675 uint iidx __unused, enum snmp_op op)
677 struct bridge_if *bif;
679 if ((bif = bridge_get_default()) == NULL)
680 return (SNMP_ERR_NOSUCHNAME);
682 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
683 bridge_update_bif(bif) <= 0) /* It was just deleted. */
684 return (SNMP_ERR_NOSUCHNAME);
688 switch (val->var.subs[sub - 1]) {
689 case LEAF_dot1dStpProtocolSpecification:
690 val->v.integer = bif->prot_spec;
691 return (SNMP_ERR_NOERROR);
693 case LEAF_dot1dStpPriority:
694 val->v.integer = bif->priority;
695 return (SNMP_ERR_NOERROR);
697 case LEAF_dot1dStpTimeSinceTopologyChange:
698 if (bridge_get_time_since_tc(bif,
699 &(val->v.uint32)) < 0)
700 return (SNMP_ERR_GENERR);
701 return (SNMP_ERR_NOERROR);
703 case LEAF_dot1dStpTopChanges:
704 val->v.uint32 = bif->top_changes;
705 return (SNMP_ERR_NOERROR);
707 case LEAF_dot1dStpDesignatedRoot:
708 return (string_get(val, bif->design_root,
709 SNMP_BRIDGE_ID_LEN));
711 case LEAF_dot1dStpRootCost:
712 val->v.integer = bif->root_cost;
713 return (SNMP_ERR_NOERROR);
715 case LEAF_dot1dStpRootPort:
716 val->v.integer = bif->root_port;
717 return (SNMP_ERR_NOERROR);
719 case LEAF_dot1dStpMaxAge:
720 val->v.integer = bif->max_age;
721 return (SNMP_ERR_NOERROR);
723 case LEAF_dot1dStpHelloTime:
724 val->v.integer = bif->hello_time;
725 return (SNMP_ERR_NOERROR);
727 case LEAF_dot1dStpHoldTime:
728 val->v.integer = bif->hold_time;
729 return (SNMP_ERR_NOERROR);
731 case LEAF_dot1dStpForwardDelay:
732 val->v.integer = bif->fwd_delay;
733 return (SNMP_ERR_NOERROR);
735 case LEAF_dot1dStpBridgeMaxAge:
736 val->v.integer = bif->bridge_max_age;
737 return (SNMP_ERR_NOERROR);
739 case LEAF_dot1dStpBridgeHelloTime:
740 val->v.integer = bif->bridge_hello_time;
741 return (SNMP_ERR_NOERROR);
743 case LEAF_dot1dStpBridgeForwardDelay:
744 val->v.integer = bif->bridge_fwd_delay;
745 return (SNMP_ERR_NOERROR);
747 case LEAF_dot1dStpVersion:
748 val->v.integer = bif->stp_version;
749 return (SNMP_ERR_NOERROR);
751 case LEAF_dot1dStpTxHoldCount:
752 val->v.integer = bif->tx_hold_count;
753 return (SNMP_ERR_NOERROR);
757 case SNMP_OP_GETNEXT:
761 switch (val->var.subs[sub - 1]) {
762 case LEAF_dot1dStpPriority:
763 if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
764 val->v.integer % 4096 != 0)
765 return (SNMP_ERR_WRONG_VALUE);
767 ctx->scratch->int1 = bif->priority;
768 if (bridge_set_priority(bif, val->v.integer) < 0)
769 return (SNMP_ERR_GENERR);
770 return (SNMP_ERR_NOERROR);
772 case LEAF_dot1dStpBridgeMaxAge:
773 if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
774 val->v.integer > SNMP_BRIDGE_MAX_MAGE)
775 return (SNMP_ERR_WRONG_VALUE);
777 ctx->scratch->int1 = bif->bridge_max_age;
778 if (bridge_set_maxage(bif, val->v.integer) < 0)
779 return (SNMP_ERR_GENERR);
780 return (SNMP_ERR_NOERROR);
782 case LEAF_dot1dStpBridgeHelloTime:
783 if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
784 val->v.integer > SNMP_BRIDGE_MAX_HTIME)
785 return (SNMP_ERR_WRONG_VALUE);
787 ctx->scratch->int1 = bif->bridge_hello_time;
788 if (bridge_set_hello_time(bif, val->v.integer) < 0)
789 return (SNMP_ERR_GENERR);
790 return (SNMP_ERR_NOERROR);
792 case LEAF_dot1dStpBridgeForwardDelay:
793 if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
794 val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
795 return (SNMP_ERR_WRONG_VALUE);
797 ctx->scratch->int1 = bif->bridge_fwd_delay;
798 if (bridge_set_forward_delay(bif, val->v.integer) < 0)
799 return (SNMP_ERR_GENERR);
800 return (SNMP_ERR_NOERROR);
802 case LEAF_dot1dStpVersion:
803 if (val->v.integer != dot1dStpVersion_stpCompatible &&
804 val->v.integer != dot1dStpVersion_rstp)
805 return (SNMP_ERR_WRONG_VALUE);
807 ctx->scratch->int1 = bif->stp_version;
808 if (bridge_set_stp_version(bif, val->v.integer) < 0)
809 return (SNMP_ERR_GENERR);
810 return (SNMP_ERR_NOERROR);
812 case LEAF_dot1dStpTxHoldCount:
813 if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
814 val->v.integer > SNMP_BRIDGE_MAX_TXHC)
815 return (SNMP_ERR_WRONG_VALUE);
817 ctx->scratch->int1 = bif->tx_hold_count;
818 if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
819 return (SNMP_ERR_GENERR);
820 return (SNMP_ERR_NOERROR);
822 case LEAF_dot1dStpProtocolSpecification:
823 case LEAF_dot1dStpTimeSinceTopologyChange:
824 case LEAF_dot1dStpTopChanges:
825 case LEAF_dot1dStpDesignatedRoot:
826 case LEAF_dot1dStpRootCost:
827 case LEAF_dot1dStpRootPort:
828 case LEAF_dot1dStpMaxAge:
829 case LEAF_dot1dStpHelloTime:
830 case LEAF_dot1dStpHoldTime:
831 case LEAF_dot1dStpForwardDelay:
832 return (SNMP_ERR_NOT_WRITEABLE);
836 case SNMP_OP_ROLLBACK:
837 switch (val->var.subs[sub - 1]) {
838 case LEAF_dot1dStpPriority:
839 bridge_set_priority(bif, ctx->scratch->int1);
841 case LEAF_dot1dStpBridgeMaxAge:
842 bridge_set_maxage(bif, ctx->scratch->int1);
844 case LEAF_dot1dStpBridgeHelloTime:
845 bridge_set_hello_time(bif, ctx->scratch->int1);
847 case LEAF_dot1dStpBridgeForwardDelay:
848 bridge_set_forward_delay(bif, ctx->scratch->int1);
850 case LEAF_dot1dStpVersion:
851 bridge_set_stp_version(bif, ctx->scratch->int1);
853 case LEAF_dot1dStpTxHoldCount:
854 bridge_set_tx_hold_count(bif, ctx->scratch->int1);
857 return (SNMP_ERR_NOERROR);
860 return (SNMP_ERR_NOERROR);
867 op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,
868 uint sub, uint iidx __unused, enum snmp_op op)
870 struct bridge_if *bif;
872 if ((bif = bridge_get_default()) == NULL)
873 return (SNMP_ERR_NOSUCHNAME);
875 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
876 bridge_update_bif(bif) <= 0) /* It was just deleted. */
877 return (SNMP_ERR_NOSUCHNAME);
881 switch (value->var.subs[sub - 1]) {
882 case LEAF_dot1dTpLearnedEntryDiscards:
883 value->v.uint32 = bif->lrnt_drops;
884 return (SNMP_ERR_NOERROR);
885 case LEAF_dot1dTpAgingTime:
886 value->v.integer = bif->age_time;
887 return (SNMP_ERR_NOERROR);
891 case SNMP_OP_GETNEXT:
895 switch (value->var.subs[sub - 1]) {
896 case LEAF_dot1dTpLearnedEntryDiscards:
897 return (SNMP_ERR_NOT_WRITEABLE);
899 case LEAF_dot1dTpAgingTime:
900 if (value->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
901 value->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
902 return (SNMP_ERR_WRONG_VALUE);
904 ctx->scratch->int1 = bif->age_time;
905 if (bridge_set_aging_time(bif, value->v.integer) < 0)
906 return (SNMP_ERR_GENERR);
907 return (SNMP_ERR_NOERROR);
911 case SNMP_OP_ROLLBACK:
912 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
913 bridge_set_aging_time(bif, ctx->scratch->int1);
914 return (SNMP_ERR_NOERROR);
917 return (SNMP_ERR_NOERROR);
924 * Private BEGEMOT-BRIDGE-MIB specifics.
928 * Get the bridge name from an OID index.
931 bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)
935 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
938 for (i = 0; i < oid->subs[sub]; i++)
939 b_name[i] = oid->subs[sub + i + 1];
946 bridge_if_index_append(struct asn_oid *oid, uint sub,
947 const struct bridge_if *bif)
951 oid->len = sub + strlen(bif->bif_name) + 1;
952 oid->subs[sub] = strlen(bif->bif_name);
954 for (i = 1; i <= strlen(bif->bif_name); i++)
955 oid->subs[sub + i] = bif->bif_name[i - 1];
958 static struct bridge_if *
959 bridge_if_index_get(const struct asn_oid *oid, uint sub)
962 char bif_name[IFNAMSIZ];
964 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
967 for (i = 0; i < oid->subs[sub]; i++)
968 bif_name[i] = oid->subs[sub + i + 1];
971 return (bridge_if_find_ifname(bif_name));
974 static struct bridge_if *
975 bridge_if_index_getnext(const struct asn_oid *oid, uint sub)
978 char bif_name[IFNAMSIZ];
979 struct bridge_if *bif;
981 if (oid->len - sub == 0)
982 return (bridge_first_bif());
984 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
987 for (i = 0; i < oid->subs[sub]; i++)
988 bif_name[i] = oid->subs[sub + i + 1];
991 if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
994 return (bridge_next_bif(bif));
998 bridge_set_if_status(struct snmp_context *ctx,
999 struct snmp_value *val, uint sub)
1001 struct bridge_if *bif;
1002 char bif_name[IFNAMSIZ];
1004 bif = bridge_if_index_get(&val->var, sub);
1006 switch (val->v.integer) {
1007 case RowStatus_active:
1009 return (SNMP_ERR_INCONS_VALUE);
1011 ctx->scratch->int1 = bif->if_status;
1013 switch (bif->if_status) {
1014 case RowStatus_active:
1015 return (SNMP_ERR_NOERROR);
1016 case RowStatus_notInService:
1017 if (bridge_set_if_up(bif->bif_name, 1) < 0)
1018 return (SNMP_ERR_GENERR);
1019 return (SNMP_ERR_NOERROR);
1023 return (SNMP_ERR_INCONS_VALUE);
1025 case RowStatus_notInService:
1027 return (SNMP_ERR_INCONS_VALUE);
1029 ctx->scratch->int1 = bif->if_status;
1031 switch (bif->if_status) {
1032 case RowStatus_active:
1033 if (bridge_set_if_up(bif->bif_name, 1) < 0)
1034 return (SNMP_ERR_GENERR);
1035 return (SNMP_ERR_NOERROR);
1036 case RowStatus_notInService:
1037 return (SNMP_ERR_NOERROR);
1041 return (SNMP_ERR_INCONS_VALUE);
1043 case RowStatus_notReady:
1044 return (SNMP_ERR_INCONS_VALUE);
1046 case RowStatus_createAndGo:
1048 return (SNMP_ERR_INCONS_VALUE);
1050 ctx->scratch->int1 = RowStatus_destroy;
1052 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1053 return (SNMP_ERR_BADVALUE);
1054 if (bridge_if_create(bif_name, 1) < 0)
1055 return (SNMP_ERR_GENERR);
1056 return (SNMP_ERR_NOERROR);
1058 case RowStatus_createAndWait:
1060 return (SNMP_ERR_INCONS_VALUE);
1062 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1063 return (SNMP_ERR_BADVALUE);
1065 ctx->scratch->int1 = RowStatus_destroy;
1067 if (bridge_if_create(bif_name, 0) < 0)
1068 return (SNMP_ERR_GENERR);
1069 return (SNMP_ERR_NOERROR);
1071 case RowStatus_destroy:
1073 return (SNMP_ERR_NOSUCHNAME);
1075 ctx->scratch->int1 = bif->if_status;
1076 bif->if_status = RowStatus_destroy;
1079 return (SNMP_ERR_NOERROR);
1083 bridge_rollback_if_status(struct snmp_context *ctx,
1084 struct snmp_value *val, uint sub)
1086 struct bridge_if *bif;
1088 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1089 return (SNMP_ERR_GENERR);
1091 switch (ctx->scratch->int1) {
1092 case RowStatus_destroy:
1093 bridge_if_destroy(bif);
1094 return (SNMP_ERR_NOERROR);
1096 case RowStatus_notInService:
1097 if (bif->if_status != ctx->scratch->int1)
1098 bridge_set_if_up(bif->bif_name, 0);
1099 bif->if_status = RowStatus_notInService;
1100 return (SNMP_ERR_NOERROR);
1102 case RowStatus_active:
1103 if (bif->if_status != ctx->scratch->int1)
1104 bridge_set_if_up(bif->bif_name, 1);
1105 bif->if_status = RowStatus_active;
1106 return (SNMP_ERR_NOERROR);
1113 bridge_commit_if_status(struct snmp_value *val, uint sub)
1115 struct bridge_if *bif;
1117 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1118 return (SNMP_ERR_GENERR);
1120 if (bif->if_status == RowStatus_destroy &&
1121 bridge_if_destroy(bif) < 0)
1122 return (SNMP_ERR_COMMIT_FAILED);
1124 return (SNMP_ERR_NOERROR);
1128 op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,
1129 uint sub, uint iidx __unused, enum snmp_op op)
1131 struct bridge_if *bif;
1133 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1134 bridge_update_all_ifs();
1138 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1139 return (SNMP_ERR_NOSUCHNAME);
1142 case SNMP_OP_GETNEXT:
1143 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1144 return (SNMP_ERR_NOSUCHNAME);
1145 bridge_if_index_append(&val->var, sub, bif);
1149 switch (val->var.subs[sub - 1]) {
1150 case LEAF_begemotBridgeBaseStatus:
1151 return (bridge_set_if_status(ctx, val, sub));
1152 case LEAF_begemotBridgeBaseName:
1153 case LEAF_begemotBridgeBaseAddress:
1154 case LEAF_begemotBridgeBaseNumPorts:
1155 case LEAF_begemotBridgeBaseType:
1156 return (SNMP_ERR_NOT_WRITEABLE);
1160 case SNMP_OP_ROLLBACK:
1161 return (bridge_rollback_if_status(ctx, val, sub));
1163 case SNMP_OP_COMMIT:
1164 return (bridge_commit_if_status(val, sub));
1169 switch (val->var.subs[sub - 1]) {
1170 case LEAF_begemotBridgeBaseName:
1171 return (string_get(val, bif->bif_name, -1));
1173 case LEAF_begemotBridgeBaseAddress:
1174 return (string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN));
1176 case LEAF_begemotBridgeBaseNumPorts:
1177 val->v.integer = bif->num_ports;
1178 return (SNMP_ERR_NOERROR);
1180 case LEAF_begemotBridgeBaseType:
1181 val->v.integer = bif->br_type;
1182 return (SNMP_ERR_NOERROR);
1184 case LEAF_begemotBridgeBaseStatus:
1185 val->v.integer = bif->if_status;
1186 return (SNMP_ERR_NOERROR);
1193 op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
1194 uint sub, uint iidx __unused, enum snmp_op op)
1196 struct bridge_if *bif;
1198 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1199 bridge_update_all_ifs();
1203 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1204 return (SNMP_ERR_NOSUCHNAME);
1207 case SNMP_OP_GETNEXT:
1208 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1209 return (SNMP_ERR_NOSUCHNAME);
1210 bridge_if_index_append(&val->var, sub, bif);
1214 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1215 return (SNMP_ERR_NOSUCHNAME);
1217 switch (val->var.subs[sub - 1]) {
1218 case LEAF_begemotBridgeStpPriority:
1219 if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
1220 val->v.integer % 4096 != 0)
1221 return (SNMP_ERR_WRONG_VALUE);
1223 ctx->scratch->int1 = bif->priority;
1224 if (bridge_set_priority(bif, val->v.integer) < 0)
1225 return (SNMP_ERR_GENERR);
1226 return (SNMP_ERR_NOERROR);
1228 case LEAF_begemotBridgeStpBridgeMaxAge:
1229 if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
1230 val->v.integer > SNMP_BRIDGE_MAX_MAGE)
1231 return (SNMP_ERR_WRONG_VALUE);
1233 ctx->scratch->int1 = bif->bridge_max_age;
1234 if (bridge_set_maxage(bif, val->v.integer) < 0)
1235 return (SNMP_ERR_GENERR);
1236 return (SNMP_ERR_NOERROR);
1238 case LEAF_begemotBridgeStpBridgeHelloTime:
1239 if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
1240 val->v.integer > SNMP_BRIDGE_MAX_HTIME)
1241 return (SNMP_ERR_WRONG_VALUE);
1243 ctx->scratch->int1 = bif->bridge_hello_time;
1244 if (bridge_set_hello_time(bif, val->v.integer) < 0)
1245 return (SNMP_ERR_GENERR);
1246 return (SNMP_ERR_NOERROR);
1248 case LEAF_begemotBridgeStpBridgeForwardDelay:
1249 if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
1250 val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
1251 return (SNMP_ERR_WRONG_VALUE);
1253 ctx->scratch->int1 = bif->bridge_fwd_delay;
1254 if (bridge_set_forward_delay(bif, val->v.integer) < 0)
1255 return (SNMP_ERR_GENERR);
1256 return (SNMP_ERR_NOERROR);
1258 case LEAF_begemotBridgeStpVersion:
1259 if (val->v.integer !=
1260 begemotBridgeStpVersion_stpCompatible &&
1261 val->v.integer != begemotBridgeStpVersion_rstp)
1262 return (SNMP_ERR_WRONG_VALUE);
1264 ctx->scratch->int1 = bif->stp_version;
1265 if (bridge_set_stp_version(bif, val->v.integer) < 0)
1266 return (SNMP_ERR_GENERR);
1267 return (SNMP_ERR_NOERROR);
1269 case LEAF_begemotBridgeStpTxHoldCount:
1270 if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
1271 val->v.integer > SNMP_BRIDGE_MAX_TXHC)
1272 return (SNMP_ERR_WRONG_VALUE);
1274 ctx->scratch->int1 = bif->tx_hold_count;
1275 if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
1276 return (SNMP_ERR_GENERR);
1277 return (SNMP_ERR_NOERROR);
1279 case LEAF_begemotBridgeStpProtocolSpecification:
1280 case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1281 case LEAF_begemotBridgeStpTopChanges:
1282 case LEAF_begemotBridgeStpDesignatedRoot:
1283 case LEAF_begemotBridgeStpRootCost:
1284 case LEAF_begemotBridgeStpRootPort:
1285 case LEAF_begemotBridgeStpMaxAge:
1286 case LEAF_begemotBridgeStpHelloTime:
1287 case LEAF_begemotBridgeStpHoldTime:
1288 case LEAF_begemotBridgeStpForwardDelay:
1289 return (SNMP_ERR_NOT_WRITEABLE);
1293 case SNMP_OP_ROLLBACK:
1294 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1295 return (SNMP_ERR_NOSUCHNAME);
1297 switch (val->var.subs[sub - 1]) {
1298 case LEAF_begemotBridgeStpPriority:
1299 bridge_set_priority(bif, ctx->scratch->int1);
1302 case LEAF_begemotBridgeStpBridgeMaxAge:
1303 bridge_set_maxage(bif, ctx->scratch->int1);
1306 case LEAF_begemotBridgeStpBridgeHelloTime:
1307 bridge_set_hello_time(bif, ctx->scratch->int1);
1310 case LEAF_begemotBridgeStpBridgeForwardDelay:
1311 bridge_set_forward_delay(bif, ctx->scratch->int1);
1314 case LEAF_begemotBridgeStpVersion:
1315 bridge_set_stp_version(bif, ctx->scratch->int1);
1318 case LEAF_begemotBridgeStpTxHoldCount:
1319 bridge_set_tx_hold_count(bif, ctx->scratch->int1);
1322 return (SNMP_ERR_NOERROR);
1324 case SNMP_OP_COMMIT:
1325 return (SNMP_ERR_NOERROR);
1330 switch (val->var.subs[sub - 1]) {
1331 case LEAF_begemotBridgeStpProtocolSpecification:
1332 val->v.integer = bif->prot_spec;
1333 return (SNMP_ERR_NOERROR);
1335 case LEAF_begemotBridgeStpPriority:
1336 val->v.integer = bif->priority;
1337 return (SNMP_ERR_NOERROR);
1339 case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1340 if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
1341 return (SNMP_ERR_GENERR);
1342 return (SNMP_ERR_NOERROR);
1344 case LEAF_begemotBridgeStpTopChanges:
1345 val->v.uint32 = bif->top_changes;
1346 return (SNMP_ERR_NOERROR);
1348 case LEAF_begemotBridgeStpDesignatedRoot:
1349 return (string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN));
1351 case LEAF_begemotBridgeStpRootCost:
1352 val->v.integer = bif->root_cost;
1353 return (SNMP_ERR_NOERROR);
1355 case LEAF_begemotBridgeStpRootPort:
1356 val->v.integer = bif->root_port;
1357 return (SNMP_ERR_NOERROR);
1359 case LEAF_begemotBridgeStpMaxAge:
1360 val->v.integer = bif->max_age;
1361 return (SNMP_ERR_NOERROR);
1363 case LEAF_begemotBridgeStpHelloTime:
1364 val->v.integer = bif->hello_time;
1365 return (SNMP_ERR_NOERROR);
1367 case LEAF_begemotBridgeStpHoldTime:
1368 val->v.integer = bif->hold_time;
1369 return (SNMP_ERR_NOERROR);
1371 case LEAF_begemotBridgeStpForwardDelay:
1372 val->v.integer = bif->fwd_delay;
1373 return (SNMP_ERR_NOERROR);
1375 case LEAF_begemotBridgeStpBridgeMaxAge:
1376 val->v.integer = bif->bridge_max_age;
1377 return (SNMP_ERR_NOERROR);
1379 case LEAF_begemotBridgeStpBridgeHelloTime:
1380 val->v.integer = bif->bridge_hello_time;
1381 return (SNMP_ERR_NOERROR);
1383 case LEAF_begemotBridgeStpBridgeForwardDelay:
1384 val->v.integer = bif->bridge_fwd_delay;
1385 return (SNMP_ERR_NOERROR);
1387 case LEAF_begemotBridgeStpVersion:
1388 val->v.integer = bif->stp_version;
1389 return (SNMP_ERR_NOERROR);
1391 case LEAF_begemotBridgeStpTxHoldCount:
1392 val->v.integer = bif->tx_hold_count;
1393 return (SNMP_ERR_NOERROR);
1400 op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
1401 uint sub, uint iidx __unused, enum snmp_op op)
1403 struct bridge_if *bif;
1405 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1406 bridge_update_all_ifs();
1410 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1411 return (SNMP_ERR_NOSUCHNAME);
1414 case SNMP_OP_GETNEXT:
1415 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1416 return (SNMP_ERR_NOSUCHNAME);
1417 bridge_if_index_append(&val->var, sub, bif);
1421 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1422 return (SNMP_ERR_NOSUCHNAME);
1424 switch (val->var.subs[sub - 1]) {
1425 case LEAF_begemotBridgeTpAgingTime:
1426 if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
1427 val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
1428 return (SNMP_ERR_WRONG_VALUE);
1430 ctx->scratch->int1 = bif->age_time;
1431 if (bridge_set_aging_time(bif, val->v.integer) < 0)
1432 return (SNMP_ERR_GENERR);
1433 return (SNMP_ERR_NOERROR);
1435 case LEAF_begemotBridgeTpMaxAddresses:
1436 ctx->scratch->int1 = bif->max_addrs;
1437 if (bridge_set_max_cache(bif, val->v.integer) < 0)
1438 return (SNMP_ERR_GENERR);
1439 return (SNMP_ERR_NOERROR);
1441 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1442 return (SNMP_ERR_NOT_WRITEABLE);
1446 case SNMP_OP_ROLLBACK:
1447 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1448 return (SNMP_ERR_GENERR);
1450 switch (val->var.subs[sub - 1]) {
1451 case LEAF_begemotBridgeTpAgingTime:
1452 bridge_set_aging_time(bif, ctx->scratch->int1);
1455 case LEAF_begemotBridgeTpMaxAddresses:
1456 bridge_set_max_cache(bif, ctx->scratch->int1);
1459 return (SNMP_ERR_NOERROR);
1461 case SNMP_OP_COMMIT:
1462 return (SNMP_ERR_NOERROR);
1467 switch (val->var.subs[sub - 1]) {
1468 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1469 val->v.uint32 = bif->lrnt_drops;
1470 return (SNMP_ERR_NOERROR);
1472 case LEAF_begemotBridgeTpAgingTime:
1473 val->v.integer = bif->age_time;
1474 return (SNMP_ERR_NOERROR);
1476 case LEAF_begemotBridgeTpMaxAddresses:
1477 val->v.integer = bif->max_addrs;
1478 return (SNMP_ERR_NOERROR);