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 OS specific ioctls.
34 #include <sys/ioctl.h>
35 #include <sys/param.h>
36 #include <sys/module.h>
37 #include <sys/linker.h>
38 #include <sys/socket.h>
39 #include <sys/sysctl.h>
41 #include <net/bridgestp.h>
42 #include <net/ethernet.h>
44 #include <net/if_bridgevar.h>
45 #include <net/if_dl.h>
46 #include <net/if_mib.h>
47 #include <net/if_types.h>
48 #include <netinet/in.h>
58 #include <bsnmp/snmpmod.h>
59 #include <bsnmp/snmp_mibII.h>
61 #define SNMPTREE_TYPES
62 #include "bridge_tree.h"
63 #include "bridge_snmp.h"
68 bridge_ioctl_init(void)
70 if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
71 syslog(LOG_ERR, "cannot open socket : %s", strerror(errno));
79 * Load the if_bridge.ko module in kernel if not already there.
82 bridge_kmod_load(void)
85 const char mod_name[] = "if_bridge";
86 struct module_stat mstat;
88 /* Scan files in kernel. */
89 mstat.version = sizeof(struct module_stat);
90 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
91 /* Scan modules in file. */
92 for (modid = kldfirstmod(fileid); modid > 0;
93 modid = modfnext(modid)) {
95 if (modstat(modid, &mstat) < 0)
98 if (strcmp(mod_name, mstat.name) == 0)
103 /* Not present - load it. */
104 if (kldload(mod_name) < 0) {
105 syslog(LOG_ERR, "failed to load %s kernel module", mod_name);
112 /************************************************************************
117 * Convert the kernel uint64_t value for a bridge id
120 snmp_uint64_to_bridgeid(uint64_t id, bridge_id b_id)
127 for (i = 0; i < SNMP_BRIDGE_ID_LEN; i++, o++)
128 b_id[SNMP_BRIDGE_ID_LEN - i - 1] = *o;
132 * Fetch the bridge configuration parameters from the kernel excluding
133 * it's base MAC address.
136 bridge_get_conf_param(struct bridge_if *bif)
139 struct ifbrparam b_param;
141 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
142 ifd.ifd_len = sizeof(b_param);
143 ifd.ifd_data = &b_param;
145 /* Bridge priority. */
146 ifd.ifd_cmd = BRDGGPRI;
147 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
148 syslog(LOG_ERR, "update bridge: ioctl(BRDGGPRI) failed: %s",
153 bif->priority = b_param.ifbrp_prio;
155 /* Configured max age. */
156 ifd.ifd_cmd = BRDGGMA;
157 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
158 syslog(LOG_ERR, "update bridge: ioctl(BRDGGMA) failed: %s",
164 bif->bridge_max_age = 100 * b_param.ifbrp_maxage;
166 /* Configured hello time. */
167 ifd.ifd_cmd = BRDGGHT;
168 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
169 syslog(LOG_ERR, "update bridge: ioctl(BRDGGHT) failed: %s",
173 bif->bridge_hello_time = 100 * b_param.ifbrp_hellotime;
176 ifd.ifd_cmd = BRDGGFD;
177 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
178 syslog(LOG_ERR, "update bridge: ioctl(BRDGGFD) failed: %s",
182 bif->bridge_fwd_delay = 100 * b_param.ifbrp_fwddelay;
184 /* Number of dropped addresses. */
185 ifd.ifd_cmd = BRDGGRTE;
186 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
187 syslog(LOG_ERR, "update bridge: ioctl(BRDGGRTE) failed: %s",
191 bif->lrnt_drops = b_param.ifbrp_cexceeded;
193 /* Address table timeout. */
194 ifd.ifd_cmd = BRDGGTO;
195 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
196 syslog(LOG_ERR, "update bridge: ioctl(BRDGGTO) failed: %s",
200 bif->age_time = b_param.ifbrp_ctime;
202 /* Address table size. */
203 ifd.ifd_cmd = BRDGGCACHE;
204 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
205 syslog(LOG_ERR, "update bridge: ioctl(BRDGGCACHE) "
206 "failed: %s", strerror(errno));
209 bif->max_addrs = b_param.ifbrp_csize;
215 * Fetch the current bridge STP operational parameters.
216 * Returns: -1 - on error;
217 * 0 - old TC time and Root Port values are same;
218 * 1 - topologyChange notification should be sent;
219 * 2 - newRoot notification should be sent.
222 bridge_get_op_param(struct bridge_if *bif)
226 struct ifbropreq b_req;
228 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
229 ifd.ifd_len = sizeof(b_req);
230 ifd.ifd_data = &b_req;
231 ifd.ifd_cmd = BRDGPARAM;
233 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
234 syslog(LOG_ERR, "update bridge: ioctl(BRDGPARAM) failed: %s",
239 bif->max_age = 100 * b_req.ifbop_maxage;
240 bif->hello_time = 100 * b_req.ifbop_hellotime;
241 bif->fwd_delay = 100 * b_req.ifbop_fwddelay;
242 bif->stp_version = b_req.ifbop_protocol;
243 bif->tx_hold_count = b_req.ifbop_holdcount;
245 if (b_req.ifbop_root_port == 0 &&
246 bif->root_port != b_req.ifbop_root_port)
251 bif->root_port = b_req.ifbop_root_port;
252 bif->root_cost = b_req.ifbop_root_path_cost;
253 snmp_uint64_to_bridgeid(b_req.ifbop_designated_root,
256 if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) {
258 bif->last_tc_time.tv_sec = b_req.ifbop_last_tc_time.tv_sec;
259 bif->last_tc_time.tv_usec = b_req.ifbop_last_tc_time.tv_usec;
262 * "The trap is not sent if a (begemotBridge)NewRoot
263 * trap is sent for the same transition."
265 if (new_root_send == 0)
269 return (new_root_send);
273 bridge_getinfo_bif(struct bridge_if *bif)
275 if (bridge_get_conf_param(bif) < 0)
278 return (bridge_get_op_param(bif));
282 bridge_set_priority(struct bridge_if *bif, int32_t priority)
285 struct ifbrparam b_param;
287 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
288 ifd.ifd_len = sizeof(b_param);
289 ifd.ifd_data = &b_param;
290 b_param.ifbrp_prio = (uint32_t) priority;
291 ifd.ifd_cmd = BRDGSPRI;
293 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
294 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) "
295 "failed: %s", strerror(errno));
300 * Re-fetching the data from the driver after that might be a good
301 * idea, since changing our bridge's priority should invoke
302 * recalculation of the active spanning tree topology in the network.
304 bif->priority = priority;
309 * Convert 1/100 of seconds to 1/256 of seconds.
310 * Timeout ::= TEXTUAL-CONVENTION.
311 * To convert a Timeout value into a value in units of
312 * 1/256 seconds, the following algorithm should be used:
313 * b = floor( (n * 256) / 100)
314 * The conversion to 1/256 of a second happens in the kernel -
315 * just make sure we correctly convert the seconds to Timout
319 snmp_timeout2_sec(int32_t secs)
325 bridge_set_maxage(struct bridge_if *bif, int32_t max_age)
328 struct ifbrparam b_param;
330 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
331 ifd.ifd_len = sizeof(b_param);
332 ifd.ifd_data = &b_param;
333 b_param.ifbrp_maxage = snmp_timeout2_sec(max_age);
334 ifd.ifd_cmd = BRDGSMA;
336 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
337 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) "
338 "failed: %s", strerror(errno));
342 bif->bridge_max_age = max_age;
347 bridge_set_hello_time(struct bridge_if *bif, int32_t hello_time)
350 struct ifbrparam b_param;
352 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
353 ifd.ifd_len = sizeof(b_param);
354 ifd.ifd_data = &b_param;
355 b_param.ifbrp_hellotime = snmp_timeout2_sec(hello_time);
356 ifd.ifd_cmd = BRDGSHT;
358 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
359 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) "
360 "failed: %s", strerror(errno));
364 bif->bridge_hello_time = b_param.ifbrp_hellotime;
369 bridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay)
372 struct ifbrparam b_param;
374 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
375 ifd.ifd_len = sizeof(b_param);
376 ifd.ifd_data = &b_param;
377 b_param.ifbrp_fwddelay = snmp_timeout2_sec(fwd_delay);
378 ifd.ifd_cmd = BRDGSFD;
380 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
381 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) "
382 "failed: %s", strerror(errno));
386 bif->bridge_fwd_delay = b_param.ifbrp_fwddelay;
391 bridge_set_aging_time(struct bridge_if *bif, int32_t age_time)
394 struct ifbrparam b_param;
396 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
397 ifd.ifd_len = sizeof(b_param);
398 ifd.ifd_data = &b_param;
399 b_param.ifbrp_ctime = (uint32_t) age_time;
400 ifd.ifd_cmd = BRDGSTO;
402 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
403 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) "
404 "failed: %s", strerror(errno));
408 bif->age_time = age_time;
413 bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache)
416 struct ifbrparam b_param;
418 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
419 ifd.ifd_len = sizeof(b_param);
420 ifd.ifd_data = &b_param;
421 b_param.ifbrp_csize = max_cache;
422 ifd.ifd_cmd = BRDGSCACHE;
424 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
425 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) "
426 "failed: %s", strerror(errno));
430 bif->max_addrs = b_param.ifbrp_csize;
435 bridge_set_tx_hold_count(struct bridge_if *bif, int32_t tx_hc)
438 struct ifbrparam b_param;
440 if (tx_hc < SNMP_BRIDGE_MIN_TXHC || tx_hc > SNMP_BRIDGE_MAX_TXHC)
443 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
444 ifd.ifd_len = sizeof(b_param);
445 ifd.ifd_data = &b_param;
446 b_param.ifbrp_txhc = tx_hc;
447 ifd.ifd_cmd = BRDGSTXHC;
449 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
450 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTXHC) "
451 "failed: %s", strerror(errno));
455 bif->tx_hold_count = b_param.ifbrp_txhc;
460 bridge_set_stp_version(struct bridge_if *bif, int32_t stp_proto)
463 struct ifbrparam b_param;
465 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
466 ifd.ifd_len = sizeof(b_param);
467 ifd.ifd_data = &b_param;
468 b_param.ifbrp_proto = stp_proto;
469 ifd.ifd_cmd = BRDGSPROTO;
471 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
472 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPROTO) "
473 "failed: %s", strerror(errno));
477 bif->stp_version = b_param.ifbrp_proto;
482 * Set the bridge interface status to up/down.
485 bridge_set_if_up(const char* b_name, int8_t up)
490 bzero(&ifr, sizeof(ifr));
491 strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
492 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
493 syslog(LOG_ERR, "set bridge up: ioctl(SIOCGIFFLAGS) "
494 "failed: %s", strerror(errno));
498 flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
504 ifr.ifr_flags = flags & 0xffff;
505 ifr.ifr_flagshigh = flags >> 16;
506 if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
507 syslog(LOG_ERR, "set bridge up: ioctl(SIOCSIFFLAGS) "
508 "failed: %s", strerror(errno));
516 bridge_create(const char *b_name)
521 bzero(&ifr, sizeof(ifr));
522 strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
524 if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) {
525 syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) "
526 "failed: %s", strerror(errno));
530 if (strcmp(b_name, ifr.ifr_name) == 0)
533 if ((new_name = strdup(b_name)) == NULL) {
534 syslog(LOG_ERR, "create bridge: strdup() failed");
538 ifr.ifr_data = new_name;
539 if (ioctl(sock, SIOCSIFNAME, (caddr_t) &ifr) < 0) {
540 syslog(LOG_ERR, "create bridge: ioctl(SIOCSIFNAME) "
541 "failed: %s", strerror(errno));
550 bridge_destroy(const char *b_name)
554 bzero(&ifr, sizeof(ifr));
555 strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
557 if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) {
558 syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) "
559 "failed: %s", strerror(errno));
567 * Fetch the bridge base MAC address. Return pointer to the
568 * buffer containing the MAC address, NULL on failure.
571 bridge_get_basemac(const char *bif_name, u_char *mac, size_t mlen)
574 char if_name[IFNAMSIZ];
575 struct ifaddrs *ifap, *ifa;
576 struct sockaddr_dl sdl;
578 if (getifaddrs(&ifap) != 0) {
579 syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s",
584 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
585 if (ifa->ifa_addr->sa_family != AF_LINK)
589 * Not just casting because of alignment constraints
592 bcopy(ifa->ifa_addr, &sdl, sizeof(struct sockaddr_dl));
594 if (sdl.sdl_alen > mlen)
597 if ((len = sdl.sdl_nlen) >= IFNAMSIZ)
600 bcopy(sdl.sdl_data, if_name, len);
603 if (strcmp(bif_name, if_name) == 0) {
604 bcopy(sdl.sdl_data + sdl.sdl_nlen, mac, sdl.sdl_alen);
614 /************************************************************************
619 * Convert the kernel STP port state into
620 * the corresopnding enumerated type from SNMP Bridge MIB.
623 state2snmp_st(uint8_t ifbr_state)
625 switch (ifbr_state) {
626 case BSTP_IFSTATE_DISABLED:
627 return (StpPortState_disabled);
628 case BSTP_IFSTATE_LISTENING:
629 return (StpPortState_listening);
630 case BSTP_IFSTATE_LEARNING:
631 return (StpPortState_learning);
632 case BSTP_IFSTATE_FORWARDING:
633 return (StpPortState_forwarding);
634 case BSTP_IFSTATE_BLOCKING:
635 case BSTP_IFSTATE_DISCARDING:
636 return (StpPortState_blocking);
639 return (StpPortState_broken);
643 * Fill in a bridge member information according to data polled from kernel.
646 bridge_port_getinfo_conf(struct ifbreq *k_info, struct bridge_port *bp)
648 bp->state = state2snmp_st(k_info->ifbr_state);
649 bp->priority = k_info->ifbr_priority;
653 * "New implementations should support dot1dStpPortPathCost32.
654 * If the port path costs exceeds the maximum value of this
655 * object then this object should report the maximum value,
656 * namely 65535. Applications should try to read the
657 * dot1dStpPortPathCost32 object if this object reports
658 * the maximum value."
661 if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMCOST)
662 bp->admin_path_cost = k_info->ifbr_path_cost;
664 bp->admin_path_cost = 0;
666 bp->path_cost = k_info->ifbr_path_cost;
668 if (k_info->ifbr_ifsflags & IFBIF_STP)
669 bp->enable = dot1dStpPortEnable_enabled;
671 bp->enable = dot1dStpPortEnable_disabled;
673 /* Begemot Bridge MIB only. */
674 if (k_info->ifbr_ifsflags & IFBIF_SPAN)
675 bp->span_enable = begemotBridgeBaseSpanEnabled_enabled;
677 bp->span_enable = begemotBridgeBaseSpanEnabled_disabled;
679 if (k_info->ifbr_ifsflags & IFBIF_PRIVATE)
680 bp->priv_set = TruthValue_true;
682 bp->priv_set = TruthValue_false;
684 if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMEDGE)
685 bp->admin_edge = TruthValue_true;
687 bp->admin_edge = TruthValue_false;
689 if (k_info->ifbr_ifsflags & IFBIF_BSTP_EDGE)
690 bp->oper_edge = TruthValue_true;
692 bp->oper_edge = TruthValue_false;
694 if (k_info->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP) {
695 bp->admin_ptp = StpPortAdminPointToPointType_auto;
696 if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP)
697 bp->oper_ptp = TruthValue_true;
699 bp->oper_ptp = TruthValue_false;
700 } else if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP) {
701 bp->admin_ptp = StpPortAdminPointToPointType_forceTrue;
702 bp->oper_ptp = TruthValue_true;
704 bp->admin_ptp = StpPortAdminPointToPointType_forceFalse;
705 bp->oper_ptp = TruthValue_false;
710 * Fill in a bridge interface STP information according to
711 * data polled from kernel.
714 bridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp)
716 bp->enable = dot1dStpPortEnable_enabled;
717 bp->fwd_trans = bp_stp->ifbp_fwd_trans;
718 bp->design_cost = bp_stp->ifbp_design_cost;
719 snmp_uint64_to_bridgeid(bp_stp->ifbp_design_root, bp->design_root);
720 snmp_uint64_to_bridgeid(bp_stp->ifbp_design_bridge, bp->design_bridge);
721 bcopy(&(bp_stp->ifbp_design_port), &(bp->design_port),
726 * Clear a bridge interface STP information.
729 bridge_port_clearinfo_opstp(struct bridge_port *bp)
731 if (bp->enable == dot1dStpPortEnable_enabled) {
733 bzero(&(bp->design_root), sizeof(bridge_id));
734 bzero(&(bp->design_bridge), sizeof(bridge_id));
735 bzero(&(bp->design_port), sizeof(port_id));
739 bp->enable = dot1dStpPortEnable_disabled;
743 * Set a bridge member priority.
746 bridge_port_set_priority(const char *bif_name, struct bridge_port *bp,
752 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
753 ifd.ifd_len = sizeof(b_req);
754 ifd.ifd_data = &b_req;
755 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
757 b_req.ifbr_priority = (uint8_t) priority;
758 ifd.ifd_cmd = BRDGSIFPRIO;
760 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
761 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFPRIO) "
762 "failed: %s", bp->p_name, strerror(errno));
766 bp->priority = priority;
771 * Set a bridge member STP-enabled flag.
774 bridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp,
780 if (bp->enable == enable)
783 bzero(&b_req, sizeof(b_req));
784 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
785 ifd.ifd_len = sizeof(b_req);
786 ifd.ifd_data = &b_req;
787 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
788 ifd.ifd_cmd = BRDGGIFFLGS;
790 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
791 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
792 "failed: %s", bp->p_name, strerror(errno));
796 if (enable == dot1dStpPortEnable_enabled)
797 b_req.ifbr_ifsflags |= IFBIF_STP;
799 b_req.ifbr_ifsflags &= ~IFBIF_STP;
801 ifd.ifd_cmd = BRDGSIFFLGS;
802 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
803 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
804 "failed: %s", bp->p_name, strerror(errno));
813 * Set a bridge member STP path cost.
816 bridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp,
822 if (path_cost < SNMP_PORT_MIN_PATHCOST ||
823 path_cost > SNMP_PORT_PATHCOST_OBSOLETE)
826 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
827 ifd.ifd_len = sizeof(b_req);
828 ifd.ifd_data = &b_req;
829 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
831 b_req.ifbr_path_cost = path_cost;
832 ifd.ifd_cmd = BRDGSIFCOST;
834 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
835 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFCOST) "
836 "failed: %s", bp->p_name, strerror(errno));
840 bp->admin_path_cost = path_cost;
846 * Set the PonitToPoint status of the link administratively.
849 bridge_port_set_admin_ptp(const char *bif_name, struct bridge_port *bp,
855 if (bp->admin_ptp == admin_ptp)
858 bzero(&b_req, sizeof(b_req));
859 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
860 ifd.ifd_len = sizeof(b_req);
861 ifd.ifd_data = &b_req;
862 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
863 ifd.ifd_cmd = BRDGGIFFLGS;
865 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
866 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
867 "failed: %s", bp->p_name, strerror(errno));
872 case StpPortAdminPointToPointType_forceTrue:
873 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
874 b_req.ifbr_ifsflags |= IFBIF_BSTP_PTP;
876 case StpPortAdminPointToPointType_forceFalse:
877 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
878 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_PTP;
880 case StpPortAdminPointToPointType_auto:
881 b_req.ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
885 ifd.ifd_cmd = BRDGSIFFLGS;
886 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
887 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
888 "failed: %s", bp->p_name, strerror(errno));
892 bp->admin_ptp = admin_ptp;
900 bridge_port_set_admin_edge(const char *bif_name, struct bridge_port *bp,
906 if (bp->admin_edge == enable)
909 bzero(&b_req, sizeof(b_req));
910 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
911 ifd.ifd_len = sizeof(b_req);
912 ifd.ifd_data = &b_req;
913 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
914 ifd.ifd_cmd = BRDGGIFFLGS;
916 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
917 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
918 "failed: %s", bp->p_name, strerror(errno));
922 if (enable == TruthValue_true) {
923 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOEDGE;
924 b_req.ifbr_ifsflags |= IFBIF_BSTP_EDGE;
926 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_EDGE;
928 ifd.ifd_cmd = BRDGSIFFLGS;
929 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
930 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
931 "failed: %s", bp->p_name, strerror(errno));
935 bp->admin_edge = enable;
941 * Set 'private' flag.
944 bridge_port_set_private(const char *bif_name, struct bridge_port *bp,
950 if (bp->priv_set == priv_set)
953 bzero(&b_req, sizeof(b_req));
954 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
955 ifd.ifd_len = sizeof(b_req);
956 ifd.ifd_data = &b_req;
957 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
958 ifd.ifd_cmd = BRDGGIFFLGS;
960 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
961 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
962 "failed: %s", bp->p_name, strerror(errno));
966 if (priv_set == TruthValue_true)
967 b_req.ifbr_ifsflags |= IFBIF_PRIVATE;
968 else if (priv_set == TruthValue_false)
969 b_req.ifbr_ifsflags &= ~IFBIF_PRIVATE;
971 return (SNMP_ERR_WRONG_VALUE);
973 ifd.ifd_cmd = BRDGSIFFLGS;
974 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
975 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
976 "failed: %s", bp->p_name, strerror(errno));
980 bp->priv_set = priv_set;
987 * Add a bridge member port.
990 bridge_port_addm(struct bridge_port *bp, const char *b_name)
995 bzero(&ifd, sizeof(ifd));
996 bzero(&b_req, sizeof(b_req));
998 strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
999 ifd.ifd_len = sizeof(b_req);
1000 ifd.ifd_data = &b_req;
1001 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
1003 if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1004 ifd.ifd_cmd = BRDGADDS;
1006 ifd.ifd_cmd = BRDGADD;
1008 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1009 syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1011 (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"),
1020 * Delete a bridge member port.
1023 bridge_port_delm(struct bridge_port *bp, const char *b_name)
1026 struct ifbreq b_req;
1028 bzero(&ifd, sizeof(ifd));
1029 bzero(&b_req, sizeof(b_req));
1031 strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
1032 ifd.ifd_len = sizeof(b_req);
1033 ifd.ifd_data = &b_req;
1034 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
1036 if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1037 ifd.ifd_cmd = BRDGDELS;
1039 ifd.ifd_cmd = BRDGDEL;
1041 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1042 syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1044 (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"),
1053 * Fetch the bridge member list from kernel.
1054 * Return -1 on error, or buffer len if successful.
1057 bridge_port_get_iflist(struct bridge_if *bif, struct ifbreq **buf)
1061 struct ifbreq *ninbuf;
1062 struct ifbifconf ifbc;
1066 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1067 ifd.ifd_cmd = BRDGGIFS;
1068 ifd.ifd_len = sizeof(ifbc);
1069 ifd.ifd_data = &ifbc;
1072 len = n * sizeof(struct ifbreq);
1073 if ((ninbuf = (struct ifbreq *)realloc(*buf, len)) == NULL) {
1074 syslog(LOG_ERR, "get bridge member list: "
1075 "realloc failed: %s", strerror(errno));
1081 ifbc.ifbic_len = len;
1082 ifbc.ifbic_req = *buf = ninbuf;
1084 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1085 syslog(LOG_ERR, "get bridge member list: ioctl "
1086 "(BRDGGIFS) failed: %s", strerror(errno));
1092 if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len)
1098 return (ifbc.ifbic_len);
1102 * Fetch the bridge STP member list from kernel.
1103 * Return -1 on error, or buffer len if successful.
1106 bridge_port_get_ifstplist(struct bridge_if *bif, struct ifbpstpreq **buf)
1110 struct ifbpstpreq *ninbuf;
1111 struct ifbpstpconf ifbstp;
1115 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1116 ifd.ifd_cmd = BRDGGIFSSTP;
1117 ifd.ifd_len = sizeof(ifbstp);
1118 ifd.ifd_data = &ifbstp;
1121 len = n * sizeof(struct ifbpstpreq);
1122 if ((ninbuf = (struct ifbpstpreq *)
1123 realloc(*buf, len)) == NULL) {
1124 syslog(LOG_ERR, "get bridge STP ports list: "
1125 "realloc failed: %s", strerror(errno));
1131 ifbstp.ifbpstp_len = len;
1132 ifbstp.ifbpstp_req = *buf = ninbuf;
1134 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1135 syslog(LOG_ERR, "get bridge STP ports list: ioctl "
1136 "(BRDGGIFSSTP) failed: %s", strerror(errno));
1142 if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len)
1148 return (ifbstp.ifbpstp_len);
1152 * Locate a bridge if STP params structure in a buffer.
1154 static struct ifbpstpreq *
1155 bridge_port_find_ifstplist(uint8_t port_no, struct ifbpstpreq *buf,
1159 struct ifbpstpreq *bstp;
1161 for (i = 0; i < buf_len / sizeof(struct ifbpstpreq); i++) {
1163 if (bstp->ifbp_portno == port_no)
1171 * Read the initial info for all members of a bridge interface.
1172 * Returns the number of ports, 0 - if none, otherwise
1173 * -1 if some other error occurred.
1176 bridge_getinfo_bif_ports(struct bridge_if *bif)
1180 struct ifbreq *b_req_buf, *b_req;
1181 struct ifbpstpreq *bs_req_buf, *bs_req;
1182 struct bridge_port *bp;
1185 if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1188 for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1189 b_req = b_req_buf + i;
1191 if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) != NULL) {
1192 /* Hopefully we will not fail here. */
1193 if ((bp = bridge_new_port(m_if, bif)) != NULL) {
1194 bp->status = RowStatus_active;
1195 bridge_port_getinfo_conf(b_req, bp);
1196 bridge_port_getinfo_mibif(m_if, bp);
1199 syslog(LOG_ERR, "bridge member %s not present "
1200 "in mibII ifTable", b_req->ifbr_ifsname);
1205 if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1208 for (bp = bridge_port_bif_first(bif); bp != NULL;
1209 bp = bridge_port_bif_next(bp)) {
1210 if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1211 bs_req_buf, buf_len)) == NULL)
1212 bridge_port_clearinfo_opstp(bp);
1214 bridge_port_getinfo_opstp(bs_req, bp);
1222 * Update the information for the bridge interface members.
1225 bridge_update_memif(struct bridge_if *bif)
1230 struct ifbreq *b_req_buf, *b_req;
1231 struct ifbpstpreq *bs_req_buf, *bs_req;
1232 struct bridge_port *bp, *bp_next;
1235 if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1238 added = updated = 0;
1240 #define BP_FOUND 0x01
1241 for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1242 b_req = b_req_buf + i;
1244 if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) == NULL) {
1245 syslog(LOG_ERR, "bridge member %s not present "
1246 "in mibII ifTable", b_req->ifbr_ifsname);
1250 if ((bp = bridge_port_find(m_if->index, bif)) == NULL &&
1251 (bp = bridge_new_port(m_if, bif)) != NULL) {
1252 bp->status = RowStatus_active;
1258 bridge_port_getinfo_conf(b_req, bp);
1259 bridge_port_getinfo_mibif(m_if, bp);
1260 bp->flags |= BP_FOUND;
1265 /* Clean up list. */
1266 for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) {
1267 bp_next = bridge_port_bif_next(bp);
1269 if ((bp->flags & BP_FOUND) == 0 &&
1270 bp->status == RowStatus_active)
1271 bridge_port_remove(bp, bif);
1273 bp->flags |= ~BP_FOUND;
1277 if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1280 for (bp = bridge_port_bif_first(bif); bp != NULL;
1281 bp = bridge_port_bif_next(bp)) {
1282 if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1283 bs_req_buf, buf_len)) == NULL)
1284 bridge_port_clearinfo_opstp(bp);
1286 bridge_port_getinfo_opstp(bs_req, bp);
1289 bif->ports_age = time(NULL);
1294 /************************************************************************
1299 * Update the bridge address info according to the polled data.
1302 bridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe)
1304 tpe->port_no = if_nametoindex(ifba->ifba_ifsname);
1306 if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
1307 tpe->status = TpFdbStatus_mgmt;
1309 tpe->status = TpFdbStatus_learned;
1313 * Read the bridge addresses from kernel.
1314 * Return -1 on error, or buffer len if successful.
1317 bridge_addrs_getinfo_ifalist(struct bridge_if *bif, struct ifbareq **buf)
1321 struct ifbareq *ninbuf;
1322 struct ifbaconf bac;
1326 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1327 ifd.ifd_cmd = BRDGRTS;
1328 ifd.ifd_len = sizeof(bac);
1329 ifd.ifd_data = &bac;
1332 len = n * sizeof(struct ifbareq);
1333 if ((ninbuf = (struct ifbareq *)realloc(*buf, len)) == NULL) {
1334 syslog(LOG_ERR, "get bridge address list: "
1335 " realloc failed: %s", strerror(errno));
1341 bac.ifbac_len = len;
1342 bac.ifbac_req = *buf = ninbuf;
1344 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1345 syslog(LOG_ERR, "get bridge address list: "
1346 "ioctl(BRDGRTS) failed: %s", strerror(errno));
1352 if ((bac.ifbac_len + sizeof(struct ifbareq)) < len)
1358 return (bac.ifbac_len);
1362 * Read the initial info for all addresses on a bridge interface.
1363 * Returns the number of addresses, 0 - if none, otherwise
1364 * -1 if some other error occurred.
1367 bridge_getinfo_bif_addrs(struct bridge_if *bif)
1371 struct ifbareq *addr_req_buf, *addr_req;
1372 struct tp_entry *te;
1374 if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1377 for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1378 addr_req = addr_req_buf + i;
1380 if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
1381 bridge_addrs_info_ifaddrlist(addr_req, te);
1389 * Update the addresses for the bridge interface.
1392 bridge_update_addrs(struct bridge_if *bif)
1397 struct tp_entry *te, *te_next;
1398 struct ifbareq *addr_req_buf, *addr_req;
1400 if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1403 added = updated = 0;
1405 #define BA_FOUND 0x01
1406 for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1407 addr_req = addr_req_buf + i;
1409 if ((te = bridge_addrs_find(addr_req->ifba_dst, bif)) == NULL) {
1412 if ((te = bridge_new_addrs(addr_req->ifba_dst, bif))
1418 bridge_addrs_info_ifaddrlist(addr_req, te);
1419 te-> flags |= BA_FOUND;
1423 for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) {
1424 te_next = bridge_addrs_bif_next(te);
1426 if ((te-> flags & BA_FOUND) == 0)
1427 bridge_addrs_remove(te, bif);
1429 te-> flags &= ~BA_FOUND;
1433 bif->addrs_age = time(NULL);
1434 return (updated + added);
1437 /************************************************************************
1438 * Bridge packet filtering.
1440 const char bridge_sysctl[] = "net.link.bridge.";
1445 } bridge_pf_sysctl[] = {
1446 { 1, "pfil_bridge" },
1447 { 1, "pfil_member" },
1448 { 1, "pfil_onlyip" },
1453 bridge_get_pfval(uint8_t which)
1456 if (which > nitems(bridge_pf_sysctl) || which < 1)
1459 return (bridge_pf_sysctl[which - 1].val);
1463 bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val)
1469 if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus)
1472 if (op == SNMP_OP_SET) {
1474 s_len = sizeof(s_i);
1480 asprintf(&mib_oid, "%s%s", bridge_sysctl,
1481 bridge_pf_sysctl[bridge_ctl].name);
1482 if (mib_oid == NULL)
1485 if (sysctlbyname(mib_oid, &i, &len, (op == SNMP_OP_SET ? &s_i : NULL),
1487 syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_oid,
1493 bridge_pf_sysctl[bridge_ctl].val = i;
1502 bridge_pf_dump(void)
1506 for (i = 0; i < nitems(bridge_pf_sysctl); i++) {
1507 syslog(LOG_ERR, "%s%s = %d", bridge_sysctl,
1508 bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val);