2 * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * Bridge MIB implementation for SNMPd.
27 * Bridge interface objects.
32 #include <sys/queue.h>
33 #include <sys/socket.h>
35 #include <sys/types.h>
37 #include <net/ethernet.h>
39 #include <net/if_mib.h>
40 #include <net/if_types.h>
48 #include <bsnmp/snmpmod.h>
49 #include <bsnmp/snmp_mibII.h>
51 #include "bridge_tree.h"
52 #include "bridge_snmp.h"
53 #include "bridge_oid.h"
55 static const struct asn_oid oid_newRoot = OIDX_newRoot;
56 static const struct asn_oid oid_TopologyChange = OIDX_topologyChange;
57 static const struct asn_oid oid_begemotBrigeName = \
58 OIDX_begemotBridgeBaseName;
59 static const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot;
60 static const struct asn_oid oid_begemotTopologyChange = \
61 OIDX_begemotBridgeTopologyChange;
63 TAILQ_HEAD(bridge_ifs, bridge_if);
66 * Free the bridge interface list.
69 bridge_ifs_free(struct bridge_ifs *headp)
73 while ((b = TAILQ_FIRST(headp)) != NULL) {
74 TAILQ_REMOVE(headp, b, b_if);
80 * Insert an entry in the bridge interface TAILQ. Keep the
81 * TAILQ sorted by the bridge's interface name.
84 bridge_ifs_insert(struct bridge_ifs *headp,
87 struct bridge_if *temp;
89 if ((temp = TAILQ_FIRST(headp)) == NULL ||
90 strcmp(b->bif_name, temp->bif_name) < 0) {
91 TAILQ_INSERT_HEAD(headp, b, b_if);
95 TAILQ_FOREACH(temp, headp, b_if)
96 if(strcmp(b->bif_name, temp->bif_name) < 0)
97 TAILQ_INSERT_BEFORE(temp, b, b_if);
99 TAILQ_INSERT_TAIL(headp, b, b_if);
102 /* The global bridge interface list. */
103 static struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs);
104 static time_t bridge_list_age;
107 * Free the global list.
110 bridge_ifs_fini(void)
112 bridge_ifs_free(&bridge_ifs);
116 * Find a bridge interface entry by the bridge interface system index.
119 bridge_if_find_ifs(uint32_t sysindex)
123 TAILQ_FOREACH(b, &bridge_ifs, b_if)
124 if (b->sysindex == sysindex)
131 * Find a bridge interface entry by the bridge interface name.
134 bridge_if_find_ifname(const char *b_name)
138 TAILQ_FOREACH(b, &bridge_ifs, b_if)
139 if (strcmp(b_name, b->bif_name) == 0)
146 * Find a bridge name by the bridge interface system index.
149 bridge_if_find_name(uint32_t sysindex)
153 TAILQ_FOREACH(b, &bridge_ifs, b_if)
154 if (b->sysindex == sysindex)
155 return (b->bif_name);
161 * Given two bridge interfaces' system indexes, find their
162 * corresponding names and return the result of the name
163 * comparison. Returns:
170 bridge_compare_sysidx(uint32_t i1, uint32_t i2)
178 if ((b1 = bridge_if_find_name(i1)) == NULL) {
179 syslog(LOG_ERR, "Bridge interface %d does not exist", i1);
183 if ((b2 = bridge_if_find_name(i2)) == NULL) {
184 syslog(LOG_ERR, "Bridge interface %d does not exist", i2);
188 if ((c = strcmp(b1, b2)) < 0)
197 * Fetch the first bridge interface from the list.
200 bridge_first_bif(void)
202 return (TAILQ_FIRST(&bridge_ifs));
206 * Fetch the next bridge interface from the list.
209 bridge_next_bif(struct bridge_if *b_pr)
211 return (TAILQ_NEXT(b_pr, b_if));
215 * Create a new entry for a bridge interface and insert
218 static struct bridge_if *
219 bridge_new_bif(const char *bif_n, uint32_t sysindex, const u_char *physaddr)
221 struct bridge_if *bif;
223 if ((bif = (struct bridge_if *) malloc(sizeof(*bif)))== NULL) {
224 syslog(LOG_ERR, "bridge new interface failed: %s",
229 bzero(bif, sizeof(struct bridge_if));
230 strlcpy(bif->bif_name, bif_n, IFNAMSIZ);
231 bcopy(physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
232 bif->sysindex = sysindex;
233 bif->br_type = BaseType_transparent_only;
234 /* 1 - all bridges default hold time * 100 - centi-seconds */
235 bif->hold_time = 1 * 100;
236 bif->prot_spec = dot1dStpProtocolSpecification_ieee8021d;
237 bridge_ifs_insert(&bridge_ifs, bif);
243 * Remove a bridge interface from the list, freeing all it's ports
244 * and address entries.
247 bridge_remove_bif(struct bridge_if *bif)
249 bridge_members_free(bif);
250 bridge_addrs_free(bif);
251 TAILQ_REMOVE(&bridge_ifs, bif, b_if);
257 * Prepare the variable (bridge interface name) for the private
258 * begemot notifications.
260 static struct snmp_value*
261 bridge_basename_var(struct bridge_if *bif, struct snmp_value* b_val)
265 b_val->var = oid_begemotBrigeName;
266 b_val->var.subs[b_val->var.len++] = strlen(bif->bif_name);
268 if ((b_val->v.octetstring.octets = (u_char *)
269 malloc(strlen(bif->bif_name))) == NULL)
272 for (i = 0; i < strlen(bif->bif_name); i++)
273 b_val->var.subs[b_val->var.len++] = bif->bif_name[i];
275 b_val->v.octetstring.len = strlen(bif->bif_name);
276 bcopy(bif->bif_name, b_val->v.octetstring.octets,
277 strlen(bif->bif_name));
278 b_val->syntax = SNMP_SYNTAX_OCTETSTRING;
284 * Compare the values of the old and the new root port and
285 * send a new root notification, if they are not matching.
288 bridge_new_root(struct bridge_if *bif)
290 struct snmp_value bif_idx;
292 if (bridge_get_default() == bif)
293 snmp_send_trap(&oid_newRoot, (struct snmp_value *) NULL);
295 if (bridge_basename_var(bif, &bif_idx) == NULL)
298 snmp_send_trap(&oid_begemotTopologyChange,
299 &bif_idx, (struct snmp_value *) NULL);
303 * Compare the new and old topology change times and send a
304 * topology change notification if necessary.
307 bridge_top_change(struct bridge_if *bif)
309 struct snmp_value bif_idx;
311 if (bridge_get_default() == bif)
312 snmp_send_trap(&oid_TopologyChange,
313 (struct snmp_value *) NULL);
315 if (bridge_basename_var(bif, &bif_idx) == NULL)
318 snmp_send_trap(&oid_begemotNewRoot,
319 &bif_idx, (struct snmp_value *) NULL);
323 bridge_if_create(const char* b_name, int8_t up)
325 if (bridge_create(b_name) < 0)
328 if (up == 1 && (bridge_set_if_up(b_name, 1) < 0))
332 * Do not create a new bridge entry here -
333 * wait until the mibII module notifies us.
339 bridge_if_destroy(struct bridge_if *bif)
341 if (bridge_destroy(bif->bif_name) < 0)
344 bridge_remove_bif(bif);
350 * Calculate the timeticks since the last topology change.
353 bridge_get_time_since_tc(struct bridge_if *bif, uint32_t *ticks)
357 if (gettimeofday(&ct, NULL) < 0) {
358 syslog(LOG_ERR, "bridge get time since last TC:"
359 "getttimeofday failed: %s", strerror(errno));
363 if (ct.tv_usec - bif->last_tc_time.tv_usec < 0) {
365 ct.tv_usec += 1000000;
368 ct.tv_sec -= bif->last_tc_time.tv_sec;
369 ct.tv_usec -= bif->last_tc_time.tv_usec;
371 *ticks = ct.tv_sec * 100 + ct.tv_usec/10000;
377 * Update the info we have for a single bridge interface.
380 * 0, if the interface was deleted
381 * -1, error occured while fetching the info from the kernel.
384 bridge_update_bif(struct bridge_if *bif)
388 /* Walk through the mibII interface list. */
389 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
390 if (strcmp(ifp->name, bif->bif_name) == 0)
394 /* Ops, we do not exist anymore. */
395 bridge_remove_bif(bif);
399 if (ifp->physaddr != NULL )
400 bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN);
402 bridge_get_basemac(bif->bif_name, bif->br_addr.octet,
405 if (ifp->mib.ifmd_flags & IFF_RUNNING)
406 bif->if_status = RowStatus_active;
408 bif->if_status = RowStatus_notInService;
410 switch (bridge_getinfo_bif(bif)) {
412 bridge_new_root(bif);
415 bridge_top_change(bif);
418 bridge_remove_bif(bif);
425 * The number of ports is accessible via SNMP -
426 * update the ports each time the bridge interface data
429 bif->num_ports = bridge_update_memif(bif);
430 bif->entry_age = time(NULL);
436 * Update all bridge interfaces' ports only -
437 * make sure each bridge interface exists first.
440 bridge_update_all_ports(void)
443 struct bridge_if *bif, *t_bif;
445 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
446 t_bif = bridge_next_bif(bif);
448 for (ifp = mib_first_if(); ifp != NULL;
449 ifp = mib_next_if(ifp))
450 if (strcmp(ifp->name, bif->bif_name) == 0)
454 bif->num_ports = bridge_update_memif(bif);
455 else /* Ops, we do not exist anymore. */
456 bridge_remove_bif(bif);
459 bridge_ports_update_listage();
463 * Update all addresses only.
466 bridge_update_all_addrs(void)
469 struct bridge_if *bif, *t_bif;
471 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
472 t_bif = bridge_next_bif(bif);
474 for (ifp = mib_first_if(); ifp != NULL;
475 ifp = mib_next_if(ifp))
476 if (strcmp(ifp->name, bif->bif_name) == 0)
480 bif->num_addrs = bridge_update_addrs(bif);
481 else /* Ops, we don't exist anymore. */
482 bridge_remove_bif(bif);
485 bridge_addrs_update_listage();
489 * Update only the bridge interfaces' data - skip addresses.
492 bridge_update_all_ifs(void)
494 struct bridge_if *bif, *t_bif;
496 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
497 t_bif = bridge_next_bif(bif);
498 bridge_update_bif(bif);
501 bridge_ports_update_listage();
502 bridge_list_age = time(NULL);
506 * Update all info we have for all bridges.
509 bridge_update_all(void *arg __unused)
511 struct bridge_if *bif, *t_bif;
513 for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) {
514 t_bif = bridge_next_bif(bif);
515 if (bridge_update_bif(bif) <= 0)
518 /* Update our learnt addresses. */
519 bif->num_addrs = bridge_update_addrs(bif);
522 bridge_list_age = time(NULL);
523 bridge_ports_update_listage();
524 bridge_addrs_update_listage();
528 * Callback for polling our last topology change time -
529 * check whether we are root or whether a TC was detected once every
530 * 30 seconds, so that we can send the newRoot and TopologyChange traps
531 * on time. The rest of the data is polled only once every 5 min.
534 bridge_update_tc_time(void *arg __unused)
536 struct bridge_if *bif;
539 TAILQ_FOREACH(bif, &bridge_ifs, b_if) {
540 /* Walk through the mibII interface list. */
541 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
542 if (strcmp(ifp->name, bif->bif_name) == 0)
546 bridge_remove_bif(bif);
550 switch (bridge_get_op_param(bif)) {
552 bridge_new_root(bif);
555 bridge_top_change(bif);
562 * Callback for handling new bridge interface creation.
565 bridge_attach_newif(struct mibif *ifp)
567 u_char mac[ETHER_ADDR_LEN];
568 struct bridge_if *bif;
570 if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE)
573 /* Make sure it does not exist in our list. */
574 TAILQ_FOREACH(bif, &bridge_ifs, b_if)
575 if(strcmp(bif->bif_name, ifp->name) == 0) {
576 syslog(LOG_ERR, "bridge interface %s already "
577 "in list", bif->bif_name);
581 if (ifp->physaddr == NULL) {
582 if (bridge_get_basemac(ifp->name, mac, sizeof(mac)) == NULL) {
583 syslog(LOG_ERR, "bridge attach new %s failed - "
584 "no bridge mac address", ifp->name);
588 bcopy(ifp->physaddr, &mac, sizeof(mac));
590 if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, mac)) == NULL)
593 if (ifp->mib.ifmd_flags & IFF_RUNNING)
594 bif->if_status = RowStatus_active;
596 bif->if_status = RowStatus_notInService;
598 /* Skip sending notifications if the interface was just created. */
599 if (bridge_getinfo_bif(bif) < 0 ||
600 (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 ||
601 (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) {
602 bridge_remove_bif(bif);
606 /* Check whether we are the default bridge interface. */
607 if (strcmp(ifp->name, bridge_get_default_name()) == 0)
608 bridge_set_default(bif);
614 bridge_ifs_dump(void)
616 struct bridge_if *bif;
618 for (bif = bridge_first_bif(); bif != NULL;
619 bif = bridge_next_bif(bif)) {
620 syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name,
622 bridge_ports_dump(bif);
623 bridge_addrs_dump(bif);
631 op_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value,
632 uint sub, uint iidx __unused, enum snmp_op op)
634 struct bridge_if *bif;
636 if ((bif = bridge_get_default()) == NULL)
637 return (SNMP_ERR_NOSUCHNAME);
639 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
640 bridge_update_bif(bif) <= 0) /* It was just deleted. */
641 return (SNMP_ERR_NOSUCHNAME);
645 switch (value->var.subs[sub - 1]) {
646 case LEAF_dot1dBaseBridgeAddress:
647 return (string_get(value, bif->br_addr.octet,
649 case LEAF_dot1dBaseNumPorts:
650 value->v.integer = bif->num_ports;
651 return (SNMP_ERR_NOERROR);
652 case LEAF_dot1dBaseType:
653 value->v.integer = bif->br_type;
654 return (SNMP_ERR_NOERROR);
659 return (SNMP_ERR_NOT_WRITEABLE);
661 case SNMP_OP_GETNEXT:
662 case SNMP_OP_ROLLBACK:
671 op_dot1d_stp(struct snmp_context *ctx, struct snmp_value *val, uint sub,
672 uint iidx __unused, enum snmp_op op)
674 struct bridge_if *bif;
676 if ((bif = bridge_get_default()) == NULL)
677 return (SNMP_ERR_NOSUCHNAME);
679 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
680 bridge_update_bif(bif) <= 0) /* It was just deleted. */
681 return (SNMP_ERR_NOSUCHNAME);
685 switch (val->var.subs[sub - 1]) {
686 case LEAF_dot1dStpProtocolSpecification:
687 val->v.integer = bif->prot_spec;
688 return (SNMP_ERR_NOERROR);
690 case LEAF_dot1dStpPriority:
691 val->v.integer = bif->priority;
692 return (SNMP_ERR_NOERROR);
694 case LEAF_dot1dStpTimeSinceTopologyChange:
695 if (bridge_get_time_since_tc(bif,
696 &(val->v.uint32)) < 0)
697 return (SNMP_ERR_GENERR);
698 return (SNMP_ERR_NOERROR);
700 case LEAF_dot1dStpTopChanges:
701 val->v.uint32 = bif->top_changes;
702 return (SNMP_ERR_NOERROR);
704 case LEAF_dot1dStpDesignatedRoot:
705 return (string_get(val, bif->design_root,
706 SNMP_BRIDGE_ID_LEN));
708 case LEAF_dot1dStpRootCost:
709 val->v.integer = bif->root_cost;
710 return (SNMP_ERR_NOERROR);
712 case LEAF_dot1dStpRootPort:
713 val->v.integer = bif->root_port;
714 return (SNMP_ERR_NOERROR);
716 case LEAF_dot1dStpMaxAge:
717 val->v.integer = bif->max_age;
718 return (SNMP_ERR_NOERROR);
720 case LEAF_dot1dStpHelloTime:
721 val->v.integer = bif->hello_time;
722 return (SNMP_ERR_NOERROR);
724 case LEAF_dot1dStpHoldTime:
725 val->v.integer = bif->hold_time;
726 return (SNMP_ERR_NOERROR);
728 case LEAF_dot1dStpForwardDelay:
729 val->v.integer = bif->fwd_delay;
730 return (SNMP_ERR_NOERROR);
732 case LEAF_dot1dStpBridgeMaxAge:
733 val->v.integer = bif->bridge_max_age;
734 return (SNMP_ERR_NOERROR);
736 case LEAF_dot1dStpBridgeHelloTime:
737 val->v.integer = bif->bridge_hello_time;
738 return (SNMP_ERR_NOERROR);
740 case LEAF_dot1dStpBridgeForwardDelay:
741 val->v.integer = bif->bridge_fwd_delay;
742 return (SNMP_ERR_NOERROR);
744 case LEAF_dot1dStpVersion:
745 val->v.integer = bif->stp_version;
746 return (SNMP_ERR_NOERROR);
748 case LEAF_dot1dStpTxHoldCount:
749 val->v.integer = bif->tx_hold_count;
750 return (SNMP_ERR_NOERROR);
754 case SNMP_OP_GETNEXT:
758 switch (val->var.subs[sub - 1]) {
759 case LEAF_dot1dStpPriority:
760 if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
761 val->v.integer % 4096 != 0)
762 return (SNMP_ERR_WRONG_VALUE);
764 ctx->scratch->int1 = bif->priority;
765 if (bridge_set_priority(bif, val->v.integer) < 0)
766 return (SNMP_ERR_GENERR);
767 return (SNMP_ERR_NOERROR);
769 case LEAF_dot1dStpBridgeMaxAge:
770 if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
771 val->v.integer > SNMP_BRIDGE_MAX_MAGE)
772 return (SNMP_ERR_WRONG_VALUE);
774 ctx->scratch->int1 = bif->bridge_max_age;
775 if (bridge_set_maxage(bif, val->v.integer) < 0)
776 return (SNMP_ERR_GENERR);
777 return (SNMP_ERR_NOERROR);
779 case LEAF_dot1dStpBridgeHelloTime:
780 if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
781 val->v.integer > SNMP_BRIDGE_MAX_HTIME)
782 return (SNMP_ERR_WRONG_VALUE);
784 ctx->scratch->int1 = bif->bridge_hello_time;
785 if (bridge_set_hello_time(bif, val->v.integer) < 0)
786 return (SNMP_ERR_GENERR);
787 return (SNMP_ERR_NOERROR);
789 case LEAF_dot1dStpBridgeForwardDelay:
790 if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
791 val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
792 return (SNMP_ERR_WRONG_VALUE);
794 ctx->scratch->int1 = bif->bridge_fwd_delay;
795 if (bridge_set_forward_delay(bif, val->v.integer) < 0)
796 return (SNMP_ERR_GENERR);
797 return (SNMP_ERR_NOERROR);
799 case LEAF_dot1dStpVersion:
800 if (val->v.integer != dot1dStpVersion_stpCompatible &&
801 val->v.integer != dot1dStpVersion_rstp)
802 return (SNMP_ERR_WRONG_VALUE);
804 ctx->scratch->int1 = bif->stp_version;
805 if (bridge_set_stp_version(bif, val->v.integer) < 0)
806 return (SNMP_ERR_GENERR);
807 return (SNMP_ERR_NOERROR);
809 case LEAF_dot1dStpTxHoldCount:
810 if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
811 val->v.integer > SNMP_BRIDGE_MAX_TXHC)
812 return (SNMP_ERR_WRONG_VALUE);
814 ctx->scratch->int1 = bif->tx_hold_count;
815 if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
816 return (SNMP_ERR_GENERR);
817 return (SNMP_ERR_NOERROR);
819 case LEAF_dot1dStpProtocolSpecification:
820 case LEAF_dot1dStpTimeSinceTopologyChange:
821 case LEAF_dot1dStpTopChanges:
822 case LEAF_dot1dStpDesignatedRoot:
823 case LEAF_dot1dStpRootCost:
824 case LEAF_dot1dStpRootPort:
825 case LEAF_dot1dStpMaxAge:
826 case LEAF_dot1dStpHelloTime:
827 case LEAF_dot1dStpHoldTime:
828 case LEAF_dot1dStpForwardDelay:
829 return (SNMP_ERR_NOT_WRITEABLE);
833 case SNMP_OP_ROLLBACK:
834 switch (val->var.subs[sub - 1]) {
835 case LEAF_dot1dStpPriority:
836 bridge_set_priority(bif, ctx->scratch->int1);
838 case LEAF_dot1dStpBridgeMaxAge:
839 bridge_set_maxage(bif, ctx->scratch->int1);
841 case LEAF_dot1dStpBridgeHelloTime:
842 bridge_set_hello_time(bif, ctx->scratch->int1);
844 case LEAF_dot1dStpBridgeForwardDelay:
845 bridge_set_forward_delay(bif, ctx->scratch->int1);
847 case LEAF_dot1dStpVersion:
848 bridge_set_stp_version(bif, ctx->scratch->int1);
850 case LEAF_dot1dStpTxHoldCount:
851 bridge_set_tx_hold_count(bif, ctx->scratch->int1);
854 return (SNMP_ERR_NOERROR);
857 return (SNMP_ERR_NOERROR);
864 op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value,
865 uint sub, uint iidx __unused, enum snmp_op op)
867 struct bridge_if *bif;
869 if ((bif = bridge_get_default()) == NULL)
870 return (SNMP_ERR_NOSUCHNAME);
872 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() &&
873 bridge_update_bif(bif) <= 0) /* It was just deleted. */
874 return (SNMP_ERR_NOSUCHNAME);
878 switch (value->var.subs[sub - 1]) {
879 case LEAF_dot1dTpLearnedEntryDiscards:
880 value->v.uint32 = bif->lrnt_drops;
881 return (SNMP_ERR_NOERROR);
882 case LEAF_dot1dTpAgingTime:
883 value->v.integer = bif->age_time;
884 return (SNMP_ERR_NOERROR);
888 case SNMP_OP_GETNEXT:
892 switch (value->var.subs[sub - 1]) {
893 case LEAF_dot1dTpLearnedEntryDiscards:
894 return (SNMP_ERR_NOT_WRITEABLE);
896 case LEAF_dot1dTpAgingTime:
897 if (value->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
898 value->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
899 return (SNMP_ERR_WRONG_VALUE);
901 ctx->scratch->int1 = bif->age_time;
902 if (bridge_set_aging_time(bif, value->v.integer) < 0)
903 return (SNMP_ERR_GENERR);
904 return (SNMP_ERR_NOERROR);
908 case SNMP_OP_ROLLBACK:
909 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime)
910 bridge_set_aging_time(bif, ctx->scratch->int1);
911 return (SNMP_ERR_NOERROR);
914 return (SNMP_ERR_NOERROR);
921 * Private BEGEMOT-BRIDGE-MIB specifics.
925 * Get the bridge name from an OID index.
928 bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name)
932 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
935 for (i = 0; i < oid->subs[sub]; i++)
936 b_name[i] = oid->subs[sub + i + 1];
943 bridge_if_index_append(struct asn_oid *oid, uint sub,
944 const struct bridge_if *bif)
948 oid->len = sub + strlen(bif->bif_name) + 1;
949 oid->subs[sub] = strlen(bif->bif_name);
951 for (i = 1; i <= strlen(bif->bif_name); i++)
952 oid->subs[sub + i] = bif->bif_name[i - 1];
955 static struct bridge_if *
956 bridge_if_index_get(const struct asn_oid *oid, uint sub)
959 char bif_name[IFNAMSIZ];
961 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
964 for (i = 0; i < oid->subs[sub]; i++)
965 bif_name[i] = oid->subs[sub + i + 1];
968 return (bridge_if_find_ifname(bif_name));
971 static struct bridge_if *
972 bridge_if_index_getnext(const struct asn_oid *oid, uint sub)
975 char bif_name[IFNAMSIZ];
976 struct bridge_if *bif;
978 if (oid->len - sub == 0)
979 return (bridge_first_bif());
981 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
984 for (i = 0; i < oid->subs[sub]; i++)
985 bif_name[i] = oid->subs[sub + i + 1];
988 if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
991 return (bridge_next_bif(bif));
995 bridge_set_if_status(struct snmp_context *ctx,
996 struct snmp_value *val, uint sub)
998 struct bridge_if *bif;
999 char bif_name[IFNAMSIZ];
1001 bif = bridge_if_index_get(&val->var, sub);
1003 switch (val->v.integer) {
1004 case RowStatus_active:
1006 return (SNMP_ERR_INCONS_VALUE);
1008 ctx->scratch->int1 = bif->if_status;
1010 switch (bif->if_status) {
1011 case RowStatus_active:
1012 return (SNMP_ERR_NOERROR);
1013 case RowStatus_notInService:
1014 if (bridge_set_if_up(bif->bif_name, 1) < 0)
1015 return (SNMP_ERR_GENERR);
1016 return (SNMP_ERR_NOERROR);
1020 return (SNMP_ERR_INCONS_VALUE);
1022 case RowStatus_notInService:
1024 return (SNMP_ERR_INCONS_VALUE);
1026 ctx->scratch->int1 = bif->if_status;
1028 switch (bif->if_status) {
1029 case RowStatus_active:
1030 if (bridge_set_if_up(bif->bif_name, 1) < 0)
1031 return (SNMP_ERR_GENERR);
1032 return (SNMP_ERR_NOERROR);
1033 case RowStatus_notInService:
1034 return (SNMP_ERR_NOERROR);
1038 return (SNMP_ERR_INCONS_VALUE);
1040 case RowStatus_notReady:
1041 return (SNMP_ERR_INCONS_VALUE);
1043 case RowStatus_createAndGo:
1045 return (SNMP_ERR_INCONS_VALUE);
1047 ctx->scratch->int1 = RowStatus_destroy;
1049 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1050 return (SNMP_ERR_BADVALUE);
1051 if (bridge_if_create(bif_name, 1) < 0)
1052 return (SNMP_ERR_GENERR);
1053 return (SNMP_ERR_NOERROR);
1055 case RowStatus_createAndWait:
1057 return (SNMP_ERR_INCONS_VALUE);
1059 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL)
1060 return (SNMP_ERR_BADVALUE);
1062 ctx->scratch->int1 = RowStatus_destroy;
1064 if (bridge_if_create(bif_name, 0) < 0)
1065 return (SNMP_ERR_GENERR);
1066 return (SNMP_ERR_NOERROR);
1068 case RowStatus_destroy:
1070 return (SNMP_ERR_NOSUCHNAME);
1072 ctx->scratch->int1 = bif->if_status;
1073 bif->if_status = RowStatus_destroy;
1076 return (SNMP_ERR_NOERROR);
1080 bridge_rollback_if_status(struct snmp_context *ctx,
1081 struct snmp_value *val, uint sub)
1083 struct bridge_if *bif;
1085 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1086 return (SNMP_ERR_GENERR);
1088 switch (ctx->scratch->int1) {
1089 case RowStatus_destroy:
1090 bridge_if_destroy(bif);
1091 return (SNMP_ERR_NOERROR);
1093 case RowStatus_notInService:
1094 if (bif->if_status != ctx->scratch->int1)
1095 bridge_set_if_up(bif->bif_name, 0);
1096 bif->if_status = RowStatus_notInService;
1097 return (SNMP_ERR_NOERROR);
1099 case RowStatus_active:
1100 if (bif->if_status != ctx->scratch->int1)
1101 bridge_set_if_up(bif->bif_name, 1);
1102 bif->if_status = RowStatus_active;
1103 return (SNMP_ERR_NOERROR);
1110 bridge_commit_if_status(struct snmp_value *val, uint sub)
1112 struct bridge_if *bif;
1114 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1115 return (SNMP_ERR_GENERR);
1117 if (bif->if_status == RowStatus_destroy &&
1118 bridge_if_destroy(bif) < 0)
1119 return (SNMP_ERR_COMMIT_FAILED);
1121 return (SNMP_ERR_NOERROR);
1125 op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val,
1126 uint sub, uint iidx __unused, enum snmp_op op)
1128 struct bridge_if *bif;
1130 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1131 bridge_update_all_ifs();
1135 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1136 return (SNMP_ERR_NOSUCHNAME);
1139 case SNMP_OP_GETNEXT:
1140 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1141 return (SNMP_ERR_NOSUCHNAME);
1142 bridge_if_index_append(&val->var, sub, bif);
1146 switch (val->var.subs[sub - 1]) {
1147 case LEAF_begemotBridgeBaseStatus:
1148 return (bridge_set_if_status(ctx, val, sub));
1149 case LEAF_begemotBridgeBaseName:
1150 case LEAF_begemotBridgeBaseAddress:
1151 case LEAF_begemotBridgeBaseNumPorts:
1152 case LEAF_begemotBridgeBaseType:
1153 return (SNMP_ERR_NOT_WRITEABLE);
1157 case SNMP_OP_ROLLBACK:
1158 return (bridge_rollback_if_status(ctx, val, sub));
1160 case SNMP_OP_COMMIT:
1161 return (bridge_commit_if_status(val, sub));
1166 switch (val->var.subs[sub - 1]) {
1167 case LEAF_begemotBridgeBaseName:
1168 return (string_get(val, bif->bif_name, -1));
1170 case LEAF_begemotBridgeBaseAddress:
1171 return (string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN));
1173 case LEAF_begemotBridgeBaseNumPorts:
1174 val->v.integer = bif->num_ports;
1175 return (SNMP_ERR_NOERROR);
1177 case LEAF_begemotBridgeBaseType:
1178 val->v.integer = bif->br_type;
1179 return (SNMP_ERR_NOERROR);
1181 case LEAF_begemotBridgeBaseStatus:
1182 val->v.integer = bif->if_status;
1183 return (SNMP_ERR_NOERROR);
1190 op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val,
1191 uint sub, uint iidx __unused, enum snmp_op op)
1193 struct bridge_if *bif;
1195 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1196 bridge_update_all_ifs();
1200 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1201 return (SNMP_ERR_NOSUCHNAME);
1204 case SNMP_OP_GETNEXT:
1205 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1206 return (SNMP_ERR_NOSUCHNAME);
1207 bridge_if_index_append(&val->var, sub, bif);
1211 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1212 return (SNMP_ERR_NOSUCHNAME);
1214 switch (val->var.subs[sub - 1]) {
1215 case LEAF_begemotBridgeStpPriority:
1216 if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY ||
1217 val->v.integer % 4096 != 0)
1218 return (SNMP_ERR_WRONG_VALUE);
1220 ctx->scratch->int1 = bif->priority;
1221 if (bridge_set_priority(bif, val->v.integer) < 0)
1222 return (SNMP_ERR_GENERR);
1223 return (SNMP_ERR_NOERROR);
1225 case LEAF_begemotBridgeStpBridgeMaxAge:
1226 if (val->v.integer < SNMP_BRIDGE_MIN_MAGE ||
1227 val->v.integer > SNMP_BRIDGE_MAX_MAGE)
1228 return (SNMP_ERR_WRONG_VALUE);
1230 ctx->scratch->int1 = bif->bridge_max_age;
1231 if (bridge_set_maxage(bif, val->v.integer) < 0)
1232 return (SNMP_ERR_GENERR);
1233 return (SNMP_ERR_NOERROR);
1235 case LEAF_begemotBridgeStpBridgeHelloTime:
1236 if (val->v.integer < SNMP_BRIDGE_MIN_HTIME ||
1237 val->v.integer > SNMP_BRIDGE_MAX_HTIME)
1238 return (SNMP_ERR_WRONG_VALUE);
1240 ctx->scratch->int1 = bif->bridge_hello_time;
1241 if (bridge_set_hello_time(bif, val->v.integer) < 0)
1242 return (SNMP_ERR_GENERR);
1243 return (SNMP_ERR_NOERROR);
1245 case LEAF_begemotBridgeStpBridgeForwardDelay:
1246 if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY ||
1247 val->v.integer > SNMP_BRIDGE_MAX_FDELAY)
1248 return (SNMP_ERR_WRONG_VALUE);
1250 ctx->scratch->int1 = bif->bridge_fwd_delay;
1251 if (bridge_set_forward_delay(bif, val->v.integer) < 0)
1252 return (SNMP_ERR_GENERR);
1253 return (SNMP_ERR_NOERROR);
1255 case LEAF_begemotBridgeStpVersion:
1256 if (val->v.integer !=
1257 begemotBridgeStpVersion_stpCompatible &&
1258 val->v.integer != begemotBridgeStpVersion_rstp)
1259 return (SNMP_ERR_WRONG_VALUE);
1261 ctx->scratch->int1 = bif->stp_version;
1262 if (bridge_set_stp_version(bif, val->v.integer) < 0)
1263 return (SNMP_ERR_GENERR);
1264 return (SNMP_ERR_NOERROR);
1266 case LEAF_begemotBridgeStpTxHoldCount:
1267 if (val->v.integer < SNMP_BRIDGE_MIN_TXHC ||
1268 val->v.integer > SNMP_BRIDGE_MAX_TXHC)
1269 return (SNMP_ERR_WRONG_VALUE);
1271 ctx->scratch->int1 = bif->tx_hold_count;
1272 if (bridge_set_tx_hold_count(bif, val->v.integer) < 0)
1273 return (SNMP_ERR_GENERR);
1274 return (SNMP_ERR_NOERROR);
1276 case LEAF_begemotBridgeStpProtocolSpecification:
1277 case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1278 case LEAF_begemotBridgeStpTopChanges:
1279 case LEAF_begemotBridgeStpDesignatedRoot:
1280 case LEAF_begemotBridgeStpRootCost:
1281 case LEAF_begemotBridgeStpRootPort:
1282 case LEAF_begemotBridgeStpMaxAge:
1283 case LEAF_begemotBridgeStpHelloTime:
1284 case LEAF_begemotBridgeStpHoldTime:
1285 case LEAF_begemotBridgeStpForwardDelay:
1286 return (SNMP_ERR_NOT_WRITEABLE);
1290 case SNMP_OP_ROLLBACK:
1291 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1292 return (SNMP_ERR_NOSUCHNAME);
1294 switch (val->var.subs[sub - 1]) {
1295 case LEAF_begemotBridgeStpPriority:
1296 bridge_set_priority(bif, ctx->scratch->int1);
1299 case LEAF_begemotBridgeStpBridgeMaxAge:
1300 bridge_set_maxage(bif, ctx->scratch->int1);
1303 case LEAF_begemotBridgeStpBridgeHelloTime:
1304 bridge_set_hello_time(bif, ctx->scratch->int1);
1307 case LEAF_begemotBridgeStpBridgeForwardDelay:
1308 bridge_set_forward_delay(bif, ctx->scratch->int1);
1311 case LEAF_begemotBridgeStpVersion:
1312 bridge_set_stp_version(bif, ctx->scratch->int1);
1315 case LEAF_begemotBridgeStpTxHoldCount:
1316 bridge_set_tx_hold_count(bif, ctx->scratch->int1);
1319 return (SNMP_ERR_NOERROR);
1321 case SNMP_OP_COMMIT:
1322 return (SNMP_ERR_NOERROR);
1327 switch (val->var.subs[sub - 1]) {
1328 case LEAF_begemotBridgeStpProtocolSpecification:
1329 val->v.integer = bif->prot_spec;
1330 return (SNMP_ERR_NOERROR);
1332 case LEAF_begemotBridgeStpPriority:
1333 val->v.integer = bif->priority;
1334 return (SNMP_ERR_NOERROR);
1336 case LEAF_begemotBridgeStpTimeSinceTopologyChange:
1337 if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0)
1338 return (SNMP_ERR_GENERR);
1339 return (SNMP_ERR_NOERROR);
1341 case LEAF_begemotBridgeStpTopChanges:
1342 val->v.uint32 = bif->top_changes;
1343 return (SNMP_ERR_NOERROR);
1345 case LEAF_begemotBridgeStpDesignatedRoot:
1346 return (string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN));
1348 case LEAF_begemotBridgeStpRootCost:
1349 val->v.integer = bif->root_cost;
1350 return (SNMP_ERR_NOERROR);
1352 case LEAF_begemotBridgeStpRootPort:
1353 val->v.integer = bif->root_port;
1354 return (SNMP_ERR_NOERROR);
1356 case LEAF_begemotBridgeStpMaxAge:
1357 val->v.integer = bif->max_age;
1358 return (SNMP_ERR_NOERROR);
1360 case LEAF_begemotBridgeStpHelloTime:
1361 val->v.integer = bif->hello_time;
1362 return (SNMP_ERR_NOERROR);
1364 case LEAF_begemotBridgeStpHoldTime:
1365 val->v.integer = bif->hold_time;
1366 return (SNMP_ERR_NOERROR);
1368 case LEAF_begemotBridgeStpForwardDelay:
1369 val->v.integer = bif->fwd_delay;
1370 return (SNMP_ERR_NOERROR);
1372 case LEAF_begemotBridgeStpBridgeMaxAge:
1373 val->v.integer = bif->bridge_max_age;
1374 return (SNMP_ERR_NOERROR);
1376 case LEAF_begemotBridgeStpBridgeHelloTime:
1377 val->v.integer = bif->bridge_hello_time;
1378 return (SNMP_ERR_NOERROR);
1380 case LEAF_begemotBridgeStpBridgeForwardDelay:
1381 val->v.integer = bif->bridge_fwd_delay;
1382 return (SNMP_ERR_NOERROR);
1384 case LEAF_begemotBridgeStpVersion:
1385 val->v.integer = bif->stp_version;
1386 return (SNMP_ERR_NOERROR);
1388 case LEAF_begemotBridgeStpTxHoldCount:
1389 val->v.integer = bif->tx_hold_count;
1390 return (SNMP_ERR_NOERROR);
1397 op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val,
1398 uint sub, uint iidx __unused, enum snmp_op op)
1400 struct bridge_if *bif;
1402 if (time(NULL) - bridge_list_age > bridge_get_data_maxage())
1403 bridge_update_all_ifs();
1407 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1408 return (SNMP_ERR_NOSUCHNAME);
1411 case SNMP_OP_GETNEXT:
1412 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL)
1413 return (SNMP_ERR_NOSUCHNAME);
1414 bridge_if_index_append(&val->var, sub, bif);
1418 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1419 return (SNMP_ERR_NOSUCHNAME);
1421 switch (val->var.subs[sub - 1]) {
1422 case LEAF_begemotBridgeTpAgingTime:
1423 if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME ||
1424 val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME)
1425 return (SNMP_ERR_WRONG_VALUE);
1427 ctx->scratch->int1 = bif->age_time;
1428 if (bridge_set_aging_time(bif, val->v.integer) < 0)
1429 return (SNMP_ERR_GENERR);
1430 return (SNMP_ERR_NOERROR);
1432 case LEAF_begemotBridgeTpMaxAddresses:
1433 ctx->scratch->int1 = bif->max_addrs;
1434 if (bridge_set_max_cache(bif, val->v.integer) < 0)
1435 return (SNMP_ERR_GENERR);
1436 return (SNMP_ERR_NOERROR);
1438 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1439 return (SNMP_ERR_NOT_WRITEABLE);
1443 case SNMP_OP_ROLLBACK:
1444 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL)
1445 return (SNMP_ERR_GENERR);
1447 switch (val->var.subs[sub - 1]) {
1448 case LEAF_begemotBridgeTpAgingTime:
1449 bridge_set_aging_time(bif, ctx->scratch->int1);
1452 case LEAF_begemotBridgeTpMaxAddresses:
1453 bridge_set_max_cache(bif, ctx->scratch->int1);
1456 return (SNMP_ERR_NOERROR);
1458 case SNMP_OP_COMMIT:
1459 return (SNMP_ERR_NOERROR);
1464 switch (val->var.subs[sub - 1]) {
1465 case LEAF_begemotBridgeTpLearnedEntryDiscards:
1466 val->v.uint32 = bif->lrnt_drops;
1467 return (SNMP_ERR_NOERROR);
1469 case LEAF_begemotBridgeTpAgingTime:
1470 val->v.integer = bif->age_time;
1471 return (SNMP_ERR_NOERROR);
1473 case LEAF_begemotBridgeTpMaxAddresses:
1474 val->v.integer = bif->max_addrs;
1475 return (SNMP_ERR_NOERROR);