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 #include "bridge_tree.h"
54 #include "bridge_snmp.h"
55 #include "bridge_oid.h"
57 static const struct asn_oid oid_newRoot = OIDX_newRoot;
58 static const struct asn_oid oid_TopologyChange = OIDX_topologyChange;
59 static const struct asn_oid oid_begemotBrigeName = \
60 OIDX_begemotBridgeBaseName;
61 static const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot;
62 static const struct asn_oid oid_begemotTopologyChange = \
63 OIDX_begemotBridgeTopologyChange;
65 TAILQ_HEAD(bridge_ifs, bridge_if);
68 * Free the bridge interface list.
71 bridge_ifs_free(struct bridge_ifs *headp)
75 while ((b = TAILQ_FIRST(headp)) != NULL) {
76 TAILQ_REMOVE(headp, b, b_if);
82 * Insert an entry in the bridge interface TAILQ. Keep the
83 * TAILQ sorted by the bridge's interface name.
86 bridge_ifs_insert(struct bridge_ifs *headp,
89 struct bridge_if *temp;
91 if ((temp = TAILQ_FIRST(headp)) == NULL ||
92 strcmp(b->bif_name, temp->bif_name) < 0) {
93 TAILQ_INSERT_HEAD(headp, b, b_if);
97 TAILQ_FOREACH(temp, headp, b_if)
98 if(strcmp(b->bif_name, temp->bif_name) < 0)
99 TAILQ_INSERT_BEFORE(temp, b, b_if);
101 TAILQ_INSERT_TAIL(headp, b, b_if);
104 /* The global bridge interface list. */
105 static struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs);
106 static time_t bridge_list_age;
109 * Free the global list.
112 bridge_ifs_fini(void)
114 bridge_ifs_free(&bridge_ifs);
118 * Find a bridge interface entry by the bridge interface system index.
121 bridge_if_find_ifs(uint32_t sysindex)
125 TAILQ_FOREACH(b, &bridge_ifs, b_if)
126 if (b->sysindex == sysindex)
133 * Find a bridge interface entry by the bridge interface name.
136 bridge_if_find_ifname(const char *b_name)
140 TAILQ_FOREACH(b, &bridge_ifs, b_if)
141 if (strcmp(b_name, b->bif_name) == 0)
148 * Find a bridge name by the bridge interface system index.
151 bridge_if_find_name(uint32_t sysindex)
155 TAILQ_FOREACH(b, &bridge_ifs, b_if)
156 if (b->sysindex == sysindex)
157 return (b->bif_name);
163 * Given two bridge interfaces' system indexes, find their
164 * corresponding names and return the result of the name
165 * comparison. Returns:
172 bridge_compare_sysidx(uint32_t i1, uint32_t i2)
180 if ((b1 = bridge_if_find_name(i1)) == NULL) {
181 syslog(LOG_ERR, "Bridge interface %d does not exist", i1);
185 if ((b2 = bridge_if_find_name(i2)) == NULL) {
186 syslog(LOG_ERR, "Bridge interface %d does not exist", i2);
190 if ((c = strcmp(b1, b2)) < 0)
199 * Fetch the first bridge interface from the list.
202 bridge_first_bif(void)
204 return (TAILQ_FIRST(&bridge_ifs));
208 * Fetch the next bridge interface from the list.
211 bridge_next_bif(struct bridge_if *b_pr)
213 return (TAILQ_NEXT(b_pr, b_if));
217 * Create a new entry for a bridge interface and insert
220 static struct bridge_if *
221 bridge_new_bif(const char *bif_n, uint32_t sysindex, const u_char *physaddr)
223 struct bridge_if *bif;
225 if ((bif = (struct bridge_if *) malloc(sizeof(*bif)))== NULL) {
226 syslog(LOG_ERR, "bridge new interface failed: %s",
231 bzero(bif, sizeof(struct bridge_if));
232 strlcpy(bif->bif_name, bif_n, IFNAMSIZ);
233 bcopy(physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
234 bif->sysindex = sysindex;
235 bif->br_type = BaseType_transparent_only;
236 /* 1 - all bridges default hold time * 100 - centi-seconds */
237 bif->hold_time = 1 * 100;
238 bif->prot_spec = dot1dStpProtocolSpecification_ieee8021d;
239 bridge_ifs_insert(&bridge_ifs, bif);
245 * Remove a bridge interface from the list, freeing all it's ports
246 * and address entries.
249 bridge_remove_bif(struct bridge_if *bif)
251 bridge_members_free(bif);
252 bridge_addrs_free(bif);
253 TAILQ_REMOVE(&bridge_ifs, bif, b_if);
259 * Prepare the variable (bridge interface name) for the private
260 * begemot notifications.
262 static struct snmp_value*
263 bridge_basename_var(struct bridge_if *bif, struct snmp_value* b_val)
267 b_val->var = oid_begemotBrigeName;
268 b_val->var.subs[b_val->var.len++] = strlen(bif->bif_name);
270 if ((b_val->v.octetstring.octets = (u_char *)
271 malloc(strlen(bif->bif_name))) == NULL)
274 for (i = 0; i < strlen(bif->bif_name); i++)
275 b_val->var.subs[b_val->var.len++] = bif->bif_name[i];
277 b_val->v.octetstring.len = strlen(bif->bif_name);
278 bcopy(bif->bif_name, b_val->v.octetstring.octets,
279 strlen(bif->bif_name));
280 b_val->syntax = SNMP_SYNTAX_OCTETSTRING;
286 * Compare the values of the old and the new root port and
287 * send a new root notification, if they are not matching.
290 bridge_new_root(struct bridge_if *bif)
292 struct snmp_value bif_idx;
294 if (bridge_get_default() == bif)
295 snmp_send_trap(&oid_newRoot, (struct snmp_value *) NULL);
297 if (bridge_basename_var(bif, &bif_idx) == NULL)
300 snmp_send_trap(&oid_begemotTopologyChange,
301 &bif_idx, (struct snmp_value *) NULL);
305 * Compare the new and old topology change times and send a
306 * topology change notification if necessary.
309 bridge_top_change(struct bridge_if *bif)
311 struct snmp_value bif_idx;
313 if (bridge_get_default() == bif)
314 snmp_send_trap(&oid_TopologyChange,
315 (struct snmp_value *) NULL);
317 if (bridge_basename_var(bif, &bif_idx) == NULL)
320 snmp_send_trap(&oid_begemotNewRoot,
321 &bif_idx, (struct snmp_value *) NULL);
325 bridge_if_create(const char* b_name, int8_t up)
327 if (bridge_create(b_name) < 0)
330 if (up == 1 && (bridge_set_if_up(b_name, 1) < 0))
334 * Do not create a new bridge entry here -
335 * wait until the mibII module notifies us.
341 bridge_if_destroy(struct bridge_if *bif)
343 if (bridge_destroy(bif->bif_name) < 0)
346 bridge_remove_bif(bif);
352 * Calculate the timeticks since the last topology change.
355 bridge_get_time_since_tc(struct bridge_if *bif, uint32_t *ticks)
359 if (gettimeofday(&ct, NULL) < 0) {
360 syslog(LOG_ERR, "bridge get time since last TC:"
361 "gettimeofday failed: %s", strerror(errno));
365 if (ct.tv_usec - bif->last_tc_time.tv_usec < 0) {
367 ct.tv_usec += 1000000;
370 ct.tv_sec -= bif->last_tc_time.tv_sec;
371 ct.tv_usec -= bif->last_tc_time.tv_usec;
373 *ticks = ct.tv_sec * 100 + ct.tv_usec/10000;
379 * Update the info we have for a single bridge interface.
382 * 0, if the interface was deleted
383 * -1, error occurred while fetching the info from the kernel.
386 bridge_update_bif(struct bridge_if *bif)
390 /* Walk through the mibII interface list. */
391 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
392 if (strcmp(ifp->name, bif->bif_name) == 0)
396 /* Ops, we do not exist anymore. */
397 bridge_remove_bif(bif);
401 if (ifp->physaddr != NULL )
402 bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
404 bridge_get_basemac(bif->bif_name, bif->br_addr.octet,
407 if (ifp->mib.ifmd_flags & IFF_RUNNING)
408 bif->if_status = RowStatus_active;
410 bif->if_status = RowStatus_notInService;
412 switch (bridge_getinfo_bif(bif)) {
414 bridge_new_root(bif);
417 bridge_top_change(bif);
420 bridge_remove_bif(bif);
427 * The number of ports is accessible via SNMP -
428 * update the ports each time the bridge interface data
431 bif->num_ports = bridge_update_memif(bif);
432 bif->entry_age = time(NULL);
438 * Update all bridge interfaces' ports only -
439 * make sure each bridge interface exists first.
442 bridge_update_all_ports(void)
445 struct bridge_if *bif, *t_bif;
447 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
448 t_bif = bridge_next_bif(bif);
450 for (ifp = mib_first_if(); ifp != NULL;
451 ifp = mib_next_if(ifp))
452 if (strcmp(ifp->name, bif->bif_name) == 0)
456 bif->num_ports = bridge_update_memif(bif);
457 else /* Ops, we do not exist anymore. */
458 bridge_remove_bif(bif);
461 bridge_ports_update_listage();
465 * Update all addresses only.
468 bridge_update_all_addrs(void)
471 struct bridge_if *bif, *t_bif;
473 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
474 t_bif = bridge_next_bif(bif);
476 for (ifp = mib_first_if(); ifp != NULL;
477 ifp = mib_next_if(ifp))
478 if (strcmp(ifp->name, bif->bif_name) == 0)
482 bif->num_addrs = bridge_update_addrs(bif);
483 else /* Ops, we don't exist anymore. */
484 bridge_remove_bif(bif);
487 bridge_addrs_update_listage();
491 * Update only the bridge interfaces' data - skip addresses.
494 bridge_update_all_ifs(void)
496 struct bridge_if *bif, *t_bif;
498 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
499 t_bif = bridge_next_bif(bif);
500 bridge_update_bif(bif);
503 bridge_ports_update_listage();
504 bridge_list_age = time(NULL);
508 * Update all info we have for all bridges.
511 bridge_update_all(void *arg __unused)
513 struct bridge_if *bif, *t_bif;
515 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
516 t_bif = bridge_next_bif(bif);
517 if (bridge_update_bif(bif) <= 0)
520 /* Update our learnt addresses. */
521 bif->num_addrs = bridge_update_addrs(bif);
524 bridge_list_age = time(NULL);
525 bridge_ports_update_listage();
526 bridge_addrs_update_listage();
530 * Callback for polling our last topology change time -
531 * check whether we are root or whether a TC was detected once every
532 * 30 seconds, so that we can send the newRoot and TopologyChange traps
533 * on time. The rest of the data is polled only once every 5 min.
536 bridge_update_tc_time(void *arg __unused)
538 struct bridge_if *bif;
541 TAILQ_FOREACH(bif, &bridge_ifs, b_if) {
542 /* Walk through the mibII interface list. */
543 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
544 if (strcmp(ifp->name, bif->bif_name) == 0)
548 bridge_remove_bif(bif);
552 switch (bridge_get_op_param(bif)) {
554 bridge_new_root(bif);
557 bridge_top_change(bif);
564 * Callback for handling new bridge interface creation.
567 bridge_attach_newif(struct mibif *ifp)
569 u_char mac[ETHER_ADDR_LEN];
570 struct bridge_if *bif;
572 if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE)
575 /* Make sure it does not exist in our list. */
576 TAILQ_FOREACH(bif, &bridge_ifs, b_if)
577 if(strcmp(bif->bif_name, ifp->name) == 0) {
578 syslog(LOG_ERR, "bridge interface %s already "
579 "in list", bif->bif_name);
583 if (ifp->physaddr == NULL) {
584 if (bridge_get_basemac(ifp->name, mac, sizeof(mac)) == NULL) {
585 syslog(LOG_ERR, "bridge attach new %s failed - "
586 "no bridge mac address", ifp->name);
590 bcopy(ifp->physaddr, &mac, sizeof(mac));
592 if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, mac)) == NULL)
595 if (ifp->mib.ifmd_flags & IFF_RUNNING)
596 bif->if_status = RowStatus_active;
598 bif->if_status = RowStatus_notInService;
600 /* Skip sending notifications if the interface was just created. */
601 if (bridge_getinfo_bif(bif) < 0 ||
602 (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 ||
603 (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) {
604 bridge_remove_bif(bif);
608 /* Check whether we are the default bridge interface. */
609 if (strcmp(ifp->name, bridge_get_default_name()) == 0)
610 bridge_set_default(bif);
616 bridge_ifs_dump(void)
618 struct bridge_if *bif;
620 for (bif = bridge_first_bif(); bif != NULL;
621 bif = bridge_next_bif(bif)) {
622 syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name,
624 bridge_ports_dump(bif);
625 bridge_addrs_dump(bif);
633 op_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value,
634 uint sub, uint iidx __unused, enum snmp_op op)
636 struct bridge_if *bif;
638 if ((bif = bridge_get_default()) == NULL)
639 return (SNMP_ERR_NOSUCHNAME);
641 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
642 bridge_update_bif(bif) <= 0) /* It was just deleted. */
643 return (SNMP_ERR_NOSUCHNAME);
647 switch (value->var.subs[sub - 1]) {
648 case LEAF_dot1dBaseBridgeAddress:
649 return (string_get(value, bif->br_addr.octet,
651 case LEAF_dot1dBaseNumPorts:
652 value->v.integer = bif->num_ports;
653 return (SNMP_ERR_NOERROR);
654 case LEAF_dot1dBaseType:
655 value->v.integer = bif->br_type;
656 return (SNMP_ERR_NOERROR);
661 return (SNMP_ERR_NOT_WRITEABLE);
663 case SNMP_OP_GETNEXT:
664 case SNMP_OP_ROLLBACK:
673 op_dot1d_stp(struct snmp_context *ctx, struct snmp_value *val, uint sub,
674 uint iidx __unused, enum snmp_op op)
676 struct bridge_if *bif;
678 if ((bif = bridge_get_default()) == NULL)
679 return (SNMP_ERR_NOSUCHNAME);
681 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
682 bridge_update_bif(bif) <= 0) /* It was just deleted. */
683 return (SNMP_ERR_NOSUCHNAME);
687 switch (val->var.subs[sub - 1]) {
688 case LEAF_dot1dStpProtocolSpecification:
689 val->v.integer = bif->prot_spec;
690 return (SNMP_ERR_NOERROR);
692 case LEAF_dot1dStpPriority:
693 val->v.integer = bif->priority;
694 return (SNMP_ERR_NOERROR);
696 case LEAF_dot1dStpTimeSinceTopologyChange:
697 if (bridge_get_time_since_tc(bif,
698 &(val->v.uint32)) < 0)
699 return (SNMP_ERR_GENERR);
700 return (SNMP_ERR_NOERROR);
702 case LEAF_dot1dStpTopChanges:
703 val->v.uint32 = bif->top_changes;
704 return (SNMP_ERR_NOERROR);
706 case LEAF_dot1dStpDesignatedRoot:
707 return (string_get(val, bif->design_root,
708 SNMP_BRIDGE_ID_LEN));
710 case LEAF_dot1dStpRootCost:
711 val->v.integer = bif->root_cost;
712 return (SNMP_ERR_NOERROR);
714 case LEAF_dot1dStpRootPort:
715 val->v.integer = bif->root_port;
716 return (SNMP_ERR_NOERROR);
718 case LEAF_dot1dStpMaxAge:
719 val->v.integer = bif->max_age;
720 return (SNMP_ERR_NOERROR);
722 case LEAF_dot1dStpHelloTime:
723 val->v.integer = bif->hello_time;
724 return (SNMP_ERR_NOERROR);
726 case LEAF_dot1dStpHoldTime:
727 val->v.integer = bif->hold_time;
728 return (SNMP_ERR_NOERROR);
730 case LEAF_dot1dStpForwardDelay:
731 val->v.integer = bif->fwd_delay;
732 return (SNMP_ERR_NOERROR);
734 case LEAF_dot1dStpBridgeMaxAge:
735 val->v.integer = bif->bridge_max_age;
736 return (SNMP_ERR_NOERROR);
738 case LEAF_dot1dStpBridgeHelloTime:
739 val->v.integer = bif->bridge_hello_time;
740 return (SNMP_ERR_NOERROR);
742 case LEAF_dot1dStpBridgeForwardDelay:
743 val->v.integer = bif->bridge_fwd_delay;
744 return (SNMP_ERR_NOERROR);
746 case LEAF_dot1dStpVersion:
747 val->v.integer = bif->stp_version;
748 return (SNMP_ERR_NOERROR);
750 case LEAF_dot1dStpTxHoldCount:
751 val->v.integer = bif->tx_hold_count;
752 return (SNMP_ERR_NOERROR);
756 case SNMP_OP_GETNEXT:
760 switch (val->var.subs[sub - 1]) {
761 case LEAF_dot1dStpPriority:
762 if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
763 val->v.integer % 4096 != 0)
764 return (SNMP_ERR_WRONG_VALUE);
766 ctx->scratch->int1 = bif->priority;
767 if (bridge_set_priority(bif, val->v.integer) < 0)
768 return (SNMP_ERR_GENERR);
769 return (SNMP_ERR_NOERROR);
771 case LEAF_dot1dStpBridgeMaxAge:
772 if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
773 val->v.integer > SNMP_BRIDGE_MAX_MAGE)
774 return (SNMP_ERR_WRONG_VALUE);
776 ctx->scratch->int1 = bif->bridge_max_age;
777 if (bridge_set_maxage(bif, val->v.integer) < 0)
778 return (SNMP_ERR_GENERR);
779 return (SNMP_ERR_NOERROR);
781 case LEAF_dot1dStpBridgeHelloTime:
782 if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
783 val->v.integer > SNMP_BRIDGE_MAX_HTIME)
784 return (SNMP_ERR_WRONG_VALUE);
786 ctx->scratch->int1 = bif->bridge_hello_time;
787 if (bridge_set_hello_time(bif, val->v.integer) < 0)
788 return (SNMP_ERR_GENERR);
789 return (SNMP_ERR_NOERROR);
791 case LEAF_dot1dStpBridgeForwardDelay:
792 if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
793 val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
794 return (SNMP_ERR_WRONG_VALUE);
796 ctx->scratch->int1 = bif->bridge_fwd_delay;
797 if (bridge_set_forward_delay(bif, val->v.integer) < 0)
798 return (SNMP_ERR_GENERR);
799 return (SNMP_ERR_NOERROR);
801 case LEAF_dot1dStpVersion:
802 if (val->v.integer != dot1dStpVersion_stpCompatible &&
803 val->v.integer != dot1dStpVersion_rstp)
804 return (SNMP_ERR_WRONG_VALUE);
806 ctx->scratch->int1 = bif->stp_version;
807 if (bridge_set_stp_version(bif, val->v.integer) < 0)
808 return (SNMP_ERR_GENERR);
809 return (SNMP_ERR_NOERROR);
811 case LEAF_dot1dStpTxHoldCount:
812 if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
813 val->v.integer > SNMP_BRIDGE_MAX_TXHC)
814 return (SNMP_ERR_WRONG_VALUE);
816 ctx->scratch->int1 = bif->tx_hold_count;
817 if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
818 return (SNMP_ERR_GENERR);
819 return (SNMP_ERR_NOERROR);
821 case LEAF_dot1dStpProtocolSpecification:
822 case LEAF_dot1dStpTimeSinceTopologyChange:
823 case LEAF_dot1dStpTopChanges:
824 case LEAF_dot1dStpDesignatedRoot:
825 case LEAF_dot1dStpRootCost:
826 case LEAF_dot1dStpRootPort:
827 case LEAF_dot1dStpMaxAge:
828 case LEAF_dot1dStpHelloTime:
829 case LEAF_dot1dStpHoldTime:
830 case LEAF_dot1dStpForwardDelay:
831 return (SNMP_ERR_NOT_WRITEABLE);
835 case SNMP_OP_ROLLBACK:
836 switch (val->var.subs[sub - 1]) {
837 case LEAF_dot1dStpPriority:
838 bridge_set_priority(bif, ctx->scratch->int1);
840 case LEAF_dot1dStpBridgeMaxAge:
841 bridge_set_maxage(bif, ctx->scratch->int1);
843 case LEAF_dot1dStpBridgeHelloTime:
844 bridge_set_hello_time(bif, ctx->scratch->int1);
846 case LEAF_dot1dStpBridgeForwardDelay:
847 bridge_set_forward_delay(bif, ctx->scratch->int1);
849 case LEAF_dot1dStpVersion:
850 bridge_set_stp_version(bif, ctx->scratch->int1);
852 case LEAF_dot1dStpTxHoldCount:
853 bridge_set_tx_hold_count(bif, ctx->scratch->int1);
856 return (SNMP_ERR_NOERROR);
859 return (SNMP_ERR_NOERROR);
866 op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,
867 uint sub, uint iidx __unused, enum snmp_op op)
869 struct bridge_if *bif;
871 if ((bif = bridge_get_default()) == NULL)
872 return (SNMP_ERR_NOSUCHNAME);
874 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
875 bridge_update_bif(bif) <= 0) /* It was just deleted. */
876 return (SNMP_ERR_NOSUCHNAME);
880 switch (value->var.subs[sub - 1]) {
881 case LEAF_dot1dTpLearnedEntryDiscards:
882 value->v.uint32 = bif->lrnt_drops;
883 return (SNMP_ERR_NOERROR);
884 case LEAF_dot1dTpAgingTime:
885 value->v.integer = bif->age_time;
886 return (SNMP_ERR_NOERROR);
890 case SNMP_OP_GETNEXT:
894 switch (value->var.subs[sub - 1]) {
895 case LEAF_dot1dTpLearnedEntryDiscards:
896 return (SNMP_ERR_NOT_WRITEABLE);
898 case LEAF_dot1dTpAgingTime:
899 if (value->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
900 value->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
901 return (SNMP_ERR_WRONG_VALUE);
903 ctx->scratch->int1 = bif->age_time;
904 if (bridge_set_aging_time(bif, value->v.integer) < 0)
905 return (SNMP_ERR_GENERR);
906 return (SNMP_ERR_NOERROR);
910 case SNMP_OP_ROLLBACK:
911 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
912 bridge_set_aging_time(bif, ctx->scratch->int1);
913 return (SNMP_ERR_NOERROR);
916 return (SNMP_ERR_NOERROR);
923 * Private BEGEMOT-BRIDGE-MIB specifics.
927 * Get the bridge name from an OID index.
930 bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)
934 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
937 for (i = 0; i < oid->subs[sub]; i++)
938 b_name[i] = oid->subs[sub + i + 1];
945 bridge_if_index_append(struct asn_oid *oid, uint sub,
946 const struct bridge_if *bif)
950 oid->len = sub + strlen(bif->bif_name) + 1;
951 oid->subs[sub] = strlen(bif->bif_name);
953 for (i = 1; i <= strlen(bif->bif_name); i++)
954 oid->subs[sub + i] = bif->bif_name[i - 1];
957 static struct bridge_if *
958 bridge_if_index_get(const struct asn_oid *oid, uint sub)
961 char bif_name[IFNAMSIZ];
963 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
966 for (i = 0; i < oid->subs[sub]; i++)
967 bif_name[i] = oid->subs[sub + i + 1];
970 return (bridge_if_find_ifname(bif_name));
973 static struct bridge_if *
974 bridge_if_index_getnext(const struct asn_oid *oid, uint sub)
977 char bif_name[IFNAMSIZ];
978 struct bridge_if *bif;
980 if (oid->len - sub == 0)
981 return (bridge_first_bif());
983 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
986 for (i = 0; i < oid->subs[sub]; i++)
987 bif_name[i] = oid->subs[sub + i + 1];
990 if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
993 return (bridge_next_bif(bif));
997 bridge_set_if_status(struct snmp_context *ctx,
998 struct snmp_value *val, uint sub)
1000 struct bridge_if *bif;
1001 char bif_name[IFNAMSIZ];
1003 bif = bridge_if_index_get(&val->var, sub);
1005 switch (val->v.integer) {
1006 case RowStatus_active:
1008 return (SNMP_ERR_INCONS_VALUE);
1010 ctx->scratch->int1 = bif->if_status;
1012 switch (bif->if_status) {
1013 case RowStatus_active:
1014 return (SNMP_ERR_NOERROR);
1015 case RowStatus_notInService:
1016 if (bridge_set_if_up(bif->bif_name, 1) < 0)
1017 return (SNMP_ERR_GENERR);
1018 return (SNMP_ERR_NOERROR);
1022 return (SNMP_ERR_INCONS_VALUE);
1024 case RowStatus_notInService:
1026 return (SNMP_ERR_INCONS_VALUE);
1028 ctx->scratch->int1 = bif->if_status;
1030 switch (bif->if_status) {
1031 case RowStatus_active:
1032 if (bridge_set_if_up(bif->bif_name, 1) < 0)
1033 return (SNMP_ERR_GENERR);
1034 return (SNMP_ERR_NOERROR);
1035 case RowStatus_notInService:
1036 return (SNMP_ERR_NOERROR);
1040 return (SNMP_ERR_INCONS_VALUE);
1042 case RowStatus_notReady:
1043 return (SNMP_ERR_INCONS_VALUE);
1045 case RowStatus_createAndGo:
1047 return (SNMP_ERR_INCONS_VALUE);
1049 ctx->scratch->int1 = RowStatus_destroy;
1051 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1052 return (SNMP_ERR_BADVALUE);
1053 if (bridge_if_create(bif_name, 1) < 0)
1054 return (SNMP_ERR_GENERR);
1055 return (SNMP_ERR_NOERROR);
1057 case RowStatus_createAndWait:
1059 return (SNMP_ERR_INCONS_VALUE);
1061 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1062 return (SNMP_ERR_BADVALUE);
1064 ctx->scratch->int1 = RowStatus_destroy;
1066 if (bridge_if_create(bif_name, 0) < 0)
1067 return (SNMP_ERR_GENERR);
1068 return (SNMP_ERR_NOERROR);
1070 case RowStatus_destroy:
1072 return (SNMP_ERR_NOSUCHNAME);
1074 ctx->scratch->int1 = bif->if_status;
1075 bif->if_status = RowStatus_destroy;
1078 return (SNMP_ERR_NOERROR);
1082 bridge_rollback_if_status(struct snmp_context *ctx,
1083 struct snmp_value *val, uint sub)
1085 struct bridge_if *bif;
1087 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1088 return (SNMP_ERR_GENERR);
1090 switch (ctx->scratch->int1) {
1091 case RowStatus_destroy:
1092 bridge_if_destroy(bif);
1093 return (SNMP_ERR_NOERROR);
1095 case RowStatus_notInService:
1096 if (bif->if_status != ctx->scratch->int1)
1097 bridge_set_if_up(bif->bif_name, 0);
1098 bif->if_status = RowStatus_notInService;
1099 return (SNMP_ERR_NOERROR);
1101 case RowStatus_active:
1102 if (bif->if_status != ctx->scratch->int1)
1103 bridge_set_if_up(bif->bif_name, 1);
1104 bif->if_status = RowStatus_active;
1105 return (SNMP_ERR_NOERROR);
1112 bridge_commit_if_status(struct snmp_value *val, uint sub)
1114 struct bridge_if *bif;
1116 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1117 return (SNMP_ERR_GENERR);
1119 if (bif->if_status == RowStatus_destroy &&
1120 bridge_if_destroy(bif) < 0)
1121 return (SNMP_ERR_COMMIT_FAILED);
1123 return (SNMP_ERR_NOERROR);
1127 op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,
1128 uint sub, uint iidx __unused, enum snmp_op op)
1130 struct bridge_if *bif;
1132 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1133 bridge_update_all_ifs();
1137 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1138 return (SNMP_ERR_NOSUCHNAME);
1141 case SNMP_OP_GETNEXT:
1142 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1143 return (SNMP_ERR_NOSUCHNAME);
1144 bridge_if_index_append(&val->var, sub, bif);
1148 switch (val->var.subs[sub - 1]) {
1149 case LEAF_begemotBridgeBaseStatus:
1150 return (bridge_set_if_status(ctx, val, sub));
1151 case LEAF_begemotBridgeBaseName:
1152 case LEAF_begemotBridgeBaseAddress:
1153 case LEAF_begemotBridgeBaseNumPorts:
1154 case LEAF_begemotBridgeBaseType:
1155 return (SNMP_ERR_NOT_WRITEABLE);
1159 case SNMP_OP_ROLLBACK:
1160 return (bridge_rollback_if_status(ctx, val, sub));
1162 case SNMP_OP_COMMIT:
1163 return (bridge_commit_if_status(val, sub));
1168 switch (val->var.subs[sub - 1]) {
1169 case LEAF_begemotBridgeBaseName:
1170 return (string_get(val, bif->bif_name, -1));
1172 case LEAF_begemotBridgeBaseAddress:
1173 return (string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN));
1175 case LEAF_begemotBridgeBaseNumPorts:
1176 val->v.integer = bif->num_ports;
1177 return (SNMP_ERR_NOERROR);
1179 case LEAF_begemotBridgeBaseType:
1180 val->v.integer = bif->br_type;
1181 return (SNMP_ERR_NOERROR);
1183 case LEAF_begemotBridgeBaseStatus:
1184 val->v.integer = bif->if_status;
1185 return (SNMP_ERR_NOERROR);
1192 op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
1193 uint sub, uint iidx __unused, enum snmp_op op)
1195 struct bridge_if *bif;
1197 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1198 bridge_update_all_ifs();
1202 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1203 return (SNMP_ERR_NOSUCHNAME);
1206 case SNMP_OP_GETNEXT:
1207 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1208 return (SNMP_ERR_NOSUCHNAME);
1209 bridge_if_index_append(&val->var, sub, bif);
1213 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1214 return (SNMP_ERR_NOSUCHNAME);
1216 switch (val->var.subs[sub - 1]) {
1217 case LEAF_begemotBridgeStpPriority:
1218 if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
1219 val->v.integer % 4096 != 0)
1220 return (SNMP_ERR_WRONG_VALUE);
1222 ctx->scratch->int1 = bif->priority;
1223 if (bridge_set_priority(bif, val->v.integer) < 0)
1224 return (SNMP_ERR_GENERR);
1225 return (SNMP_ERR_NOERROR);
1227 case LEAF_begemotBridgeStpBridgeMaxAge:
1228 if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
1229 val->v.integer > SNMP_BRIDGE_MAX_MAGE)
1230 return (SNMP_ERR_WRONG_VALUE);
1232 ctx->scratch->int1 = bif->bridge_max_age;
1233 if (bridge_set_maxage(bif, val->v.integer) < 0)
1234 return (SNMP_ERR_GENERR);
1235 return (SNMP_ERR_NOERROR);
1237 case LEAF_begemotBridgeStpBridgeHelloTime:
1238 if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
1239 val->v.integer > SNMP_BRIDGE_MAX_HTIME)
1240 return (SNMP_ERR_WRONG_VALUE);
1242 ctx->scratch->int1 = bif->bridge_hello_time;
1243 if (bridge_set_hello_time(bif, val->v.integer) < 0)
1244 return (SNMP_ERR_GENERR);
1245 return (SNMP_ERR_NOERROR);
1247 case LEAF_begemotBridgeStpBridgeForwardDelay:
1248 if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
1249 val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
1250 return (SNMP_ERR_WRONG_VALUE);
1252 ctx->scratch->int1 = bif->bridge_fwd_delay;
1253 if (bridge_set_forward_delay(bif, val->v.integer) < 0)
1254 return (SNMP_ERR_GENERR);
1255 return (SNMP_ERR_NOERROR);
1257 case LEAF_begemotBridgeStpVersion:
1258 if (val->v.integer !=
1259 begemotBridgeStpVersion_stpCompatible &&
1260 val->v.integer != begemotBridgeStpVersion_rstp)
1261 return (SNMP_ERR_WRONG_VALUE);
1263 ctx->scratch->int1 = bif->stp_version;
1264 if (bridge_set_stp_version(bif, val->v.integer) < 0)
1265 return (SNMP_ERR_GENERR);
1266 return (SNMP_ERR_NOERROR);
1268 case LEAF_begemotBridgeStpTxHoldCount:
1269 if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
1270 val->v.integer > SNMP_BRIDGE_MAX_TXHC)
1271 return (SNMP_ERR_WRONG_VALUE);
1273 ctx->scratch->int1 = bif->tx_hold_count;
1274 if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
1275 return (SNMP_ERR_GENERR);
1276 return (SNMP_ERR_NOERROR);
1278 case LEAF_begemotBridgeStpProtocolSpecification:
1279 case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1280 case LEAF_begemotBridgeStpTopChanges:
1281 case LEAF_begemotBridgeStpDesignatedRoot:
1282 case LEAF_begemotBridgeStpRootCost:
1283 case LEAF_begemotBridgeStpRootPort:
1284 case LEAF_begemotBridgeStpMaxAge:
1285 case LEAF_begemotBridgeStpHelloTime:
1286 case LEAF_begemotBridgeStpHoldTime:
1287 case LEAF_begemotBridgeStpForwardDelay:
1288 return (SNMP_ERR_NOT_WRITEABLE);
1292 case SNMP_OP_ROLLBACK:
1293 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1294 return (SNMP_ERR_NOSUCHNAME);
1296 switch (val->var.subs[sub - 1]) {
1297 case LEAF_begemotBridgeStpPriority:
1298 bridge_set_priority(bif, ctx->scratch->int1);
1301 case LEAF_begemotBridgeStpBridgeMaxAge:
1302 bridge_set_maxage(bif, ctx->scratch->int1);
1305 case LEAF_begemotBridgeStpBridgeHelloTime:
1306 bridge_set_hello_time(bif, ctx->scratch->int1);
1309 case LEAF_begemotBridgeStpBridgeForwardDelay:
1310 bridge_set_forward_delay(bif, ctx->scratch->int1);
1313 case LEAF_begemotBridgeStpVersion:
1314 bridge_set_stp_version(bif, ctx->scratch->int1);
1317 case LEAF_begemotBridgeStpTxHoldCount:
1318 bridge_set_tx_hold_count(bif, ctx->scratch->int1);
1321 return (SNMP_ERR_NOERROR);
1323 case SNMP_OP_COMMIT:
1324 return (SNMP_ERR_NOERROR);
1329 switch (val->var.subs[sub - 1]) {
1330 case LEAF_begemotBridgeStpProtocolSpecification:
1331 val->v.integer = bif->prot_spec;
1332 return (SNMP_ERR_NOERROR);
1334 case LEAF_begemotBridgeStpPriority:
1335 val->v.integer = bif->priority;
1336 return (SNMP_ERR_NOERROR);
1338 case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1339 if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
1340 return (SNMP_ERR_GENERR);
1341 return (SNMP_ERR_NOERROR);
1343 case LEAF_begemotBridgeStpTopChanges:
1344 val->v.uint32 = bif->top_changes;
1345 return (SNMP_ERR_NOERROR);
1347 case LEAF_begemotBridgeStpDesignatedRoot:
1348 return (string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN));
1350 case LEAF_begemotBridgeStpRootCost:
1351 val->v.integer = bif->root_cost;
1352 return (SNMP_ERR_NOERROR);
1354 case LEAF_begemotBridgeStpRootPort:
1355 val->v.integer = bif->root_port;
1356 return (SNMP_ERR_NOERROR);
1358 case LEAF_begemotBridgeStpMaxAge:
1359 val->v.integer = bif->max_age;
1360 return (SNMP_ERR_NOERROR);
1362 case LEAF_begemotBridgeStpHelloTime:
1363 val->v.integer = bif->hello_time;
1364 return (SNMP_ERR_NOERROR);
1366 case LEAF_begemotBridgeStpHoldTime:
1367 val->v.integer = bif->hold_time;
1368 return (SNMP_ERR_NOERROR);
1370 case LEAF_begemotBridgeStpForwardDelay:
1371 val->v.integer = bif->fwd_delay;
1372 return (SNMP_ERR_NOERROR);
1374 case LEAF_begemotBridgeStpBridgeMaxAge:
1375 val->v.integer = bif->bridge_max_age;
1376 return (SNMP_ERR_NOERROR);
1378 case LEAF_begemotBridgeStpBridgeHelloTime:
1379 val->v.integer = bif->bridge_hello_time;
1380 return (SNMP_ERR_NOERROR);
1382 case LEAF_begemotBridgeStpBridgeForwardDelay:
1383 val->v.integer = bif->bridge_fwd_delay;
1384 return (SNMP_ERR_NOERROR);
1386 case LEAF_begemotBridgeStpVersion:
1387 val->v.integer = bif->stp_version;
1388 return (SNMP_ERR_NOERROR);
1390 case LEAF_begemotBridgeStpTxHoldCount:
1391 val->v.integer = bif->tx_hold_count;
1392 return (SNMP_ERR_NOERROR);
1399 op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
1400 uint sub, uint iidx __unused, enum snmp_op op)
1402 struct bridge_if *bif;
1404 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1405 bridge_update_all_ifs();
1409 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1410 return (SNMP_ERR_NOSUCHNAME);
1413 case SNMP_OP_GETNEXT:
1414 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1415 return (SNMP_ERR_NOSUCHNAME);
1416 bridge_if_index_append(&val->var, sub, bif);
1420 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1421 return (SNMP_ERR_NOSUCHNAME);
1423 switch (val->var.subs[sub - 1]) {
1424 case LEAF_begemotBridgeTpAgingTime:
1425 if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
1426 val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
1427 return (SNMP_ERR_WRONG_VALUE);
1429 ctx->scratch->int1 = bif->age_time;
1430 if (bridge_set_aging_time(bif, val->v.integer) < 0)
1431 return (SNMP_ERR_GENERR);
1432 return (SNMP_ERR_NOERROR);
1434 case LEAF_begemotBridgeTpMaxAddresses:
1435 ctx->scratch->int1 = bif->max_addrs;
1436 if (bridge_set_max_cache(bif, val->v.integer) < 0)
1437 return (SNMP_ERR_GENERR);
1438 return (SNMP_ERR_NOERROR);
1440 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1441 return (SNMP_ERR_NOT_WRITEABLE);
1445 case SNMP_OP_ROLLBACK:
1446 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1447 return (SNMP_ERR_GENERR);
1449 switch (val->var.subs[sub - 1]) {
1450 case LEAF_begemotBridgeTpAgingTime:
1451 bridge_set_aging_time(bif, ctx->scratch->int1);
1454 case LEAF_begemotBridgeTpMaxAddresses:
1455 bridge_set_max_cache(bif, ctx->scratch->int1);
1458 return (SNMP_ERR_NOERROR);
1460 case SNMP_OP_COMMIT:
1461 return (SNMP_ERR_NOERROR);
1466 switch (val->var.subs[sub - 1]) {
1467 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1468 val->v.uint32 = bif->lrnt_drops;
1469 return (SNMP_ERR_NOERROR);
1471 case LEAF_begemotBridgeTpAgingTime:
1472 val->v.integer = bif->age_time;
1473 return (SNMP_ERR_NOERROR);
1475 case LEAF_begemotBridgeTpMaxAddresses:
1476 val->v.integer = bif->max_addrs;
1477 return (SNMP_ERR_NOERROR);