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 OS specific ioctls.
32 #include <sys/ioctl.h>
33 #include <sys/param.h>
34 #include <sys/module.h>
35 #include <sys/linker.h>
36 #include <sys/socket.h>
37 #include <sys/sysctl.h>
39 #include <net/bridgestp.h>
40 #include <net/ethernet.h>
42 #include <net/if_bridgevar.h>
43 #include <net/if_dl.h>
44 #include <net/if_mib.h>
45 #include <net/if_types.h>
46 #include <netinet/in.h>
56 #include <bsnmp/snmpmod.h>
57 #include <bsnmp/snmp_mibII.h>
59 #include "bridge_tree.h"
60 #include "bridge_snmp.h"
65 bridge_ioctl_init(void)
67 if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
68 syslog(LOG_ERR, "cannot open socket : %s", strerror(errno));
76 * Load the if_bridge.ko module in kernel if not already there.
79 bridge_kmod_load(void)
82 const char mod_name[] = "if_bridge";
83 struct module_stat mstat;
85 /* Scan files in kernel. */
86 mstat.version = sizeof(struct module_stat);
87 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
88 /* Scan modules in file. */
89 for (modid = kldfirstmod(fileid); modid > 0;
90 modid = modfnext(modid)) {
92 if (modstat(modid, &mstat) < 0)
95 if (strcmp(mod_name, mstat.name) == 0)
100 /* Not present - load it. */
101 if (kldload(mod_name) < 0) {
102 syslog(LOG_ERR, "failed to load %s kernel module", mod_name);
109 /************************************************************************
114 * Convert the kernel uint64_t value for a bridge id
117 snmp_uint64_to_bridgeid(uint64_t id, bridge_id b_id)
124 for (i = 0; i < SNMP_BRIDGE_ID_LEN; i++, o++)
125 b_id[SNMP_BRIDGE_ID_LEN - i - 1] = *o;
129 * Fetch the bridge configuration parameters from the kernel excluding
130 * it's base MAC address.
133 bridge_get_conf_param(struct bridge_if *bif)
136 struct ifbrparam b_param;
138 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
139 ifd.ifd_len = sizeof(b_param);
140 ifd.ifd_data = &b_param;
142 /* Bridge priority. */
143 ifd.ifd_cmd = BRDGGPRI;
144 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
145 syslog(LOG_ERR, "update bridge: ioctl(BRDGGPRI) failed: %s",
150 bif->priority = b_param.ifbrp_prio;
152 /* Configured max age. */
153 ifd.ifd_cmd = BRDGGMA;
154 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
155 syslog(LOG_ERR, "update bridge: ioctl(BRDGGMA) failed: %s",
161 bif->bridge_max_age = 100 * b_param.ifbrp_maxage;
163 /* Configured hello time. */
164 ifd.ifd_cmd = BRDGGHT;
165 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
166 syslog(LOG_ERR, "update bridge: ioctl(BRDGGHT) failed: %s",
170 bif->bridge_hello_time = 100 * b_param.ifbrp_hellotime;
173 ifd.ifd_cmd = BRDGGFD;
174 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
175 syslog(LOG_ERR, "update bridge: ioctl(BRDGGFD) failed: %s",
179 bif->bridge_fwd_delay = 100 * b_param.ifbrp_fwddelay;
181 /* Number of dropped addresses. */
182 ifd.ifd_cmd = BRDGGRTE;
183 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
184 syslog(LOG_ERR, "update bridge: ioctl(BRDGGRTE) failed: %s",
188 bif->lrnt_drops = b_param.ifbrp_cexceeded;
190 /* Address table timeout. */
191 ifd.ifd_cmd = BRDGGTO;
192 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
193 syslog(LOG_ERR, "update bridge: ioctl(BRDGGTO) failed: %s",
197 bif->age_time = b_param.ifbrp_ctime;
199 /* Address table size. */
200 ifd.ifd_cmd = BRDGGCACHE;
201 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
202 syslog(LOG_ERR, "update bridge: ioctl(BRDGGCACHE) "
203 "failed: %s", strerror(errno));
206 bif->max_addrs = b_param.ifbrp_csize;
212 * Fetch the current bridge STP operational parameters.
213 * Returns: -1 - on error;
214 * 0 - old TC time and Root Port values are same;
215 * 1 - topologyChange notification should be sent;
216 * 2 - newRoot notification should be sent.
219 bridge_get_op_param(struct bridge_if *bif)
223 struct ifbropreq b_req;
225 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
226 ifd.ifd_len = sizeof(b_req);
227 ifd.ifd_data = &b_req;
228 ifd.ifd_cmd = BRDGPARAM;
230 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
231 syslog(LOG_ERR, "update bridge: ioctl(BRDGPARAM) failed: %s",
236 bif->max_age = 100 * b_req.ifbop_maxage;
237 bif->hello_time = 100 * b_req.ifbop_hellotime;
238 bif->fwd_delay = 100 * b_req.ifbop_fwddelay;
239 bif->stp_version = b_req.ifbop_protocol;
240 bif->tx_hold_count = b_req.ifbop_holdcount;
242 if (b_req.ifbop_root_port == 0 &&
243 bif->root_port != b_req.ifbop_root_port)
248 bif->root_port = b_req.ifbop_root_port;
249 bif->root_cost = b_req.ifbop_root_path_cost;
250 snmp_uint64_to_bridgeid(b_req.ifbop_designated_root,
253 if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) {
255 bif->last_tc_time.tv_sec = b_req.ifbop_last_tc_time.tv_sec;
256 bif->last_tc_time.tv_usec = b_req.ifbop_last_tc_time.tv_usec;
259 * "The trap is not sent if a (begemotBridge)NewRoot
260 * trap is sent for the same transition."
262 if (new_root_send == 0)
266 return (new_root_send);
270 bridge_getinfo_bif(struct bridge_if *bif)
272 if (bridge_get_conf_param(bif) < 0)
275 return (bridge_get_op_param(bif));
279 bridge_set_priority(struct bridge_if *bif, int32_t priority)
282 struct ifbrparam b_param;
284 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
285 ifd.ifd_len = sizeof(b_param);
286 ifd.ifd_data = &b_param;
287 b_param.ifbrp_prio = (uint32_t) priority;
288 ifd.ifd_cmd = BRDGSPRI;
290 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
291 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) "
292 "failed: %s", strerror(errno));
297 * Re-fetching the data from the driver after that might be a good
298 * idea, since changing our bridge's priority should invoke
299 * recalculation of the active spanning tree topology in the network.
301 bif->priority = priority;
306 * Convert 1/100 of seconds to 1/256 of seconds.
307 * Timeout ::= TEXTUAL-CONVENTION.
308 * To convert a Timeout value into a value in units of
309 * 1/256 seconds, the following algorithm should be used:
310 * b = floor( (n * 256) / 100)
311 * The conversion to 1/256 of a second happens in the kernel -
312 * just make sure we correctly convert the seconds to Timout
316 snmp_timeout2_sec(int32_t secs)
322 bridge_set_maxage(struct bridge_if *bif, int32_t max_age)
325 struct ifbrparam b_param;
327 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
328 ifd.ifd_len = sizeof(b_param);
329 ifd.ifd_data = &b_param;
330 b_param.ifbrp_maxage = snmp_timeout2_sec(max_age);
331 ifd.ifd_cmd = BRDGSMA;
333 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
334 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) "
335 "failed: %s", strerror(errno));
339 bif->bridge_max_age = max_age;
344 bridge_set_hello_time(struct bridge_if *bif, int32_t hello_time)
347 struct ifbrparam b_param;
349 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
350 ifd.ifd_len = sizeof(b_param);
351 ifd.ifd_data = &b_param;
352 b_param.ifbrp_hellotime = snmp_timeout2_sec(hello_time);
353 ifd.ifd_cmd = BRDGSHT;
355 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
356 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) "
357 "failed: %s", strerror(errno));
361 bif->bridge_hello_time = b_param.ifbrp_hellotime;
366 bridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay)
369 struct ifbrparam b_param;
371 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
372 ifd.ifd_len = sizeof(b_param);
373 ifd.ifd_data = &b_param;
374 b_param.ifbrp_fwddelay = snmp_timeout2_sec(fwd_delay);
375 ifd.ifd_cmd = BRDGSFD;
377 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
378 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) "
379 "failed: %s", strerror(errno));
383 bif->bridge_fwd_delay = b_param.ifbrp_fwddelay;
388 bridge_set_aging_time(struct bridge_if *bif, int32_t age_time)
391 struct ifbrparam b_param;
393 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
394 ifd.ifd_len = sizeof(b_param);
395 ifd.ifd_data = &b_param;
396 b_param.ifbrp_ctime = (uint32_t) age_time;
397 ifd.ifd_cmd = BRDGSTO;
399 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
400 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) "
401 "failed: %s", strerror(errno));
405 bif->age_time = age_time;
410 bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache)
413 struct ifbrparam b_param;
415 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
416 ifd.ifd_len = sizeof(b_param);
417 ifd.ifd_data = &b_param;
418 b_param.ifbrp_csize = max_cache;
419 ifd.ifd_cmd = BRDGSCACHE;
421 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
422 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) "
423 "failed: %s", strerror(errno));
427 bif->max_addrs = b_param.ifbrp_csize;
432 bridge_set_tx_hold_count(struct bridge_if *bif, int32_t tx_hc)
435 struct ifbrparam b_param;
437 if (tx_hc < SNMP_BRIDGE_MIN_TXHC || tx_hc > SNMP_BRIDGE_MAX_TXHC)
440 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
441 ifd.ifd_len = sizeof(b_param);
442 ifd.ifd_data = &b_param;
443 b_param.ifbrp_txhc = tx_hc;
444 ifd.ifd_cmd = BRDGSTXHC;
446 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
447 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTXHC) "
448 "failed: %s", strerror(errno));
452 bif->tx_hold_count = b_param.ifbrp_txhc;
457 bridge_set_stp_version(struct bridge_if *bif, int32_t stp_proto)
460 struct ifbrparam b_param;
462 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
463 ifd.ifd_len = sizeof(b_param);
464 ifd.ifd_data = &b_param;
465 b_param.ifbrp_proto = stp_proto;
466 ifd.ifd_cmd = BRDGSPROTO;
468 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
469 syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPROTO) "
470 "failed: %s", strerror(errno));
474 bif->stp_version = b_param.ifbrp_proto;
479 * Set the bridge interface status to up/down.
482 bridge_set_if_up(const char* b_name, int8_t up)
487 bzero(&ifr, sizeof(ifr));
488 strcpy(ifr.ifr_name, b_name);
489 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
490 syslog(LOG_ERR, "set bridge up: ioctl(SIOCGIFFLAGS) "
491 "failed: %s", strerror(errno));
495 flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
501 ifr.ifr_flags = flags & 0xffff;
502 ifr.ifr_flagshigh = flags >> 16;
503 if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
504 syslog(LOG_ERR, "set bridge up: ioctl(SIOCSIFFLAGS) "
505 "failed: %s", strerror(errno));
513 bridge_create(const char *b_name)
518 bzero(&ifr, sizeof(ifr));
519 strcpy(ifr.ifr_name, b_name);
521 if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) {
522 syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) "
523 "failed: %s", strerror(errno));
527 if (strcmp(b_name, ifr.ifr_name) == 0)
530 if ((new_name = strdup(b_name)) == NULL) {
531 syslog(LOG_ERR, "create bridge: strdup() failed");
535 ifr.ifr_data = new_name;
536 if (ioctl(sock, SIOCSIFNAME, (caddr_t) &ifr) < 0) {
537 syslog(LOG_ERR, "create bridge: ioctl(SIOCSIFNAME) "
538 "failed: %s", strerror(errno));
547 bridge_destroy(const char *b_name)
551 bzero(&ifr, sizeof(ifr));
552 strcpy(ifr.ifr_name, b_name);
554 if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) {
555 syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) "
556 "failed: %s", strerror(errno));
564 * Fetch the bridge base MAC address. Return pointer to the
565 * buffer containing the MAC address, NULL on failure.
568 bridge_get_basemac(const char *bif_name, u_char *mac, size_t mlen)
571 char if_name[IFNAMSIZ];
572 struct ifaddrs *ifap, *ifa;
573 struct sockaddr_dl sdl;
575 if (getifaddrs(&ifap) != 0) {
576 syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s",
581 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
582 if (ifa->ifa_addr->sa_family != AF_LINK)
586 * Not just casting because of alignment constraints
587 * on sparc64 and ia64.
589 bcopy(ifa->ifa_addr, &sdl, sizeof(struct sockaddr_dl));
591 if (sdl.sdl_alen > mlen)
594 if ((len = sdl.sdl_nlen) >= IFNAMSIZ)
597 bcopy(sdl.sdl_data, if_name, len);
600 if (strcmp(bif_name, if_name) == 0) {
601 bcopy(sdl.sdl_data + sdl.sdl_nlen, mac, sdl.sdl_alen);
611 /************************************************************************
616 * Convert the kernel STP port state into
617 * the corresopnding enumerated type from SNMP Bridge MIB.
620 state2snmp_st(uint8_t ifbr_state)
622 switch (ifbr_state) {
623 case BSTP_IFSTATE_DISABLED:
624 return (StpPortState_disabled);
625 case BSTP_IFSTATE_LISTENING:
626 return (StpPortState_listening);
627 case BSTP_IFSTATE_LEARNING:
628 return (StpPortState_learning);
629 case BSTP_IFSTATE_FORWARDING:
630 return (StpPortState_forwarding);
631 case BSTP_IFSTATE_BLOCKING:
632 case BSTP_IFSTATE_DISCARDING:
633 return (StpPortState_blocking);
636 return (StpPortState_broken);
640 * Fill in a bridge member information according to data polled from kernel.
643 bridge_port_getinfo_conf(struct ifbreq *k_info, struct bridge_port *bp)
645 bp->state = state2snmp_st(k_info->ifbr_state);
646 bp->priority = k_info->ifbr_priority;
650 * "New implementations should support dot1dStpPortPathCost32.
651 * If the port path costs exceeds the maximum value of this
652 * object then this object should report the maximum value,
653 * namely 65535. Applications should try to read the
654 * dot1dStpPortPathCost32 object if this object reports
655 * the maximum value."
658 if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMCOST)
659 bp->admin_path_cost = k_info->ifbr_path_cost;
661 bp->admin_path_cost = 0;
663 bp->path_cost = k_info->ifbr_path_cost;
665 if (k_info->ifbr_ifsflags & IFBIF_STP)
666 bp->enable = dot1dStpPortEnable_enabled;
668 bp->enable = dot1dStpPortEnable_disabled;
670 /* Begemot Bridge MIB only. */
671 if (k_info->ifbr_ifsflags & IFBIF_SPAN)
672 bp->span_enable = begemotBridgeBaseSpanEnabled_enabled;
674 bp->span_enable = begemotBridgeBaseSpanEnabled_disabled;
676 if (k_info->ifbr_ifsflags & IFBIF_PRIVATE)
677 bp->priv_set = TruthValue_true;
679 bp->priv_set = TruthValue_false;
681 if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMEDGE)
682 bp->admin_edge = TruthValue_true;
684 bp->admin_edge = TruthValue_false;
686 if (k_info->ifbr_ifsflags & IFBIF_BSTP_EDGE)
687 bp->oper_edge = TruthValue_true;
689 bp->oper_edge = TruthValue_false;
691 if (k_info->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP) {
692 bp->admin_ptp = StpPortAdminPointToPointType_auto;
693 if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP)
694 bp->oper_ptp = TruthValue_true;
696 bp->oper_ptp = TruthValue_false;
697 } else if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP) {
698 bp->admin_ptp = StpPortAdminPointToPointType_forceTrue;
699 bp->oper_ptp = TruthValue_true;
701 bp->admin_ptp = StpPortAdminPointToPointType_forceFalse;
702 bp->oper_ptp = TruthValue_false;
707 * Fill in a bridge interface STP information according to
708 * data polled from kernel.
711 bridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp)
713 bp->enable = dot1dStpPortEnable_enabled;
714 bp->fwd_trans = bp_stp->ifbp_fwd_trans;
715 bp->design_cost = bp_stp->ifbp_design_cost;
716 snmp_uint64_to_bridgeid(bp_stp->ifbp_design_root, bp->design_root);
717 snmp_uint64_to_bridgeid(bp_stp->ifbp_design_bridge, bp->design_bridge);
718 bcopy(&(bp_stp->ifbp_design_port), &(bp->design_port),
723 * Clear a bridge interface STP information.
726 bridge_port_clearinfo_opstp(struct bridge_port *bp)
728 if (bp->enable == dot1dStpPortEnable_enabled) {
730 bzero(&(bp->design_root), sizeof(bridge_id));
731 bzero(&(bp->design_bridge), sizeof(bridge_id));
732 bzero(&(bp->design_port), sizeof(port_id));
736 bp->enable = dot1dStpPortEnable_disabled;
740 * Set a bridge member priority.
743 bridge_port_set_priority(const char *bif_name, struct bridge_port *bp,
749 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
750 ifd.ifd_len = sizeof(b_req);
751 ifd.ifd_data = &b_req;
752 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
754 b_req.ifbr_priority = (uint8_t) priority;
755 ifd.ifd_cmd = BRDGSIFPRIO;
757 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
758 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFPRIO) "
759 "failed: %s", bp->p_name, strerror(errno));
763 bp->priority = priority;
768 * Set a bridge member STP-enabled flag.
771 bridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp,
777 if (bp->enable == enable)
780 bzero(&b_req, sizeof(b_req));
781 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
782 ifd.ifd_len = sizeof(b_req);
783 ifd.ifd_data = &b_req;
784 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
785 ifd.ifd_cmd = BRDGGIFFLGS;
787 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
788 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
789 "failed: %s", bp->p_name, strerror(errno));
793 if (enable == dot1dStpPortEnable_enabled)
794 b_req.ifbr_ifsflags |= IFBIF_STP;
796 b_req.ifbr_ifsflags &= ~IFBIF_STP;
798 ifd.ifd_cmd = BRDGSIFFLGS;
799 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
800 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
801 "failed: %s", bp->p_name, strerror(errno));
810 * Set a bridge member STP path cost.
813 bridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp,
819 if (path_cost < SNMP_PORT_MIN_PATHCOST ||
820 path_cost > SNMP_PORT_PATHCOST_OBSOLETE)
823 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
824 ifd.ifd_len = sizeof(b_req);
825 ifd.ifd_data = &b_req;
826 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
828 b_req.ifbr_path_cost = path_cost;
829 ifd.ifd_cmd = BRDGSIFCOST;
831 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
832 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFCOST) "
833 "failed: %s", bp->p_name, strerror(errno));
837 bp->admin_path_cost = path_cost;
843 * Set the PonitToPoint status of the link administratively.
846 bridge_port_set_admin_ptp(const char *bif_name, struct bridge_port *bp,
852 if (bp->admin_ptp == admin_ptp)
855 bzero(&b_req, sizeof(b_req));
856 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
857 ifd.ifd_len = sizeof(b_req);
858 ifd.ifd_data = &b_req;
859 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
860 ifd.ifd_cmd = BRDGGIFFLGS;
862 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
863 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
864 "failed: %s", bp->p_name, strerror(errno));
869 case StpPortAdminPointToPointType_forceTrue:
870 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
871 b_req.ifbr_ifsflags |= IFBIF_BSTP_PTP;
873 case StpPortAdminPointToPointType_forceFalse:
874 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
875 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_PTP;
877 case StpPortAdminPointToPointType_auto:
878 b_req.ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
882 ifd.ifd_cmd = BRDGSIFFLGS;
883 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
884 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
885 "failed: %s", bp->p_name, strerror(errno));
889 bp->admin_ptp = admin_ptp;
897 bridge_port_set_admin_edge(const char *bif_name, struct bridge_port *bp,
903 if (bp->admin_edge == enable)
906 bzero(&b_req, sizeof(b_req));
907 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
908 ifd.ifd_len = sizeof(b_req);
909 ifd.ifd_data = &b_req;
910 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
911 ifd.ifd_cmd = BRDGGIFFLGS;
913 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
914 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
915 "failed: %s", bp->p_name, strerror(errno));
919 if (enable == TruthValue_true) {
920 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOEDGE;
921 b_req.ifbr_ifsflags |= IFBIF_BSTP_EDGE;
923 b_req.ifbr_ifsflags &= ~IFBIF_BSTP_EDGE;
925 ifd.ifd_cmd = BRDGSIFFLGS;
926 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
927 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
928 "failed: %s", bp->p_name, strerror(errno));
932 bp->admin_edge = enable;
938 * Set 'private' flag.
941 bridge_port_set_private(const char *bif_name, struct bridge_port *bp,
947 if (bp->priv_set == priv_set)
950 bzero(&b_req, sizeof(b_req));
951 strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
952 ifd.ifd_len = sizeof(b_req);
953 ifd.ifd_data = &b_req;
954 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
955 ifd.ifd_cmd = BRDGGIFFLGS;
957 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
958 syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
959 "failed: %s", bp->p_name, strerror(errno));
963 if (priv_set == TruthValue_true)
964 b_req.ifbr_ifsflags |= IFBIF_PRIVATE;
965 else if (priv_set == TruthValue_false)
966 b_req.ifbr_ifsflags &= ~IFBIF_PRIVATE;
968 return (SNMP_ERR_WRONG_VALUE);
970 ifd.ifd_cmd = BRDGSIFFLGS;
971 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
972 syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
973 "failed: %s", bp->p_name, strerror(errno));
977 bp->priv_set = priv_set;
984 * Add a bridge member port.
987 bridge_port_addm(struct bridge_port *bp, const char *b_name)
992 bzero(&ifd, sizeof(ifd));
993 bzero(&b_req, sizeof(b_req));
995 strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
996 ifd.ifd_len = sizeof(b_req);
997 ifd.ifd_data = &b_req;
998 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
1000 if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1001 ifd.ifd_cmd = BRDGADDS;
1003 ifd.ifd_cmd = BRDGADD;
1005 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1006 syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1008 (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"),
1017 * Delete a bridge member port.
1020 bridge_port_delm(struct bridge_port *bp, const char *b_name)
1023 struct ifbreq b_req;
1025 bzero(&ifd, sizeof(ifd));
1026 bzero(&b_req, sizeof(b_req));
1028 strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
1029 ifd.ifd_len = sizeof(b_req);
1030 ifd.ifd_data = &b_req;
1031 strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
1033 if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1034 ifd.ifd_cmd = BRDGDELS;
1036 ifd.ifd_cmd = BRDGDEL;
1038 if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1039 syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1041 (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"),
1050 * Fetch the bridge member list from kernel.
1051 * Return -1 on error, or buffer len if successful.
1054 bridge_port_get_iflist(struct bridge_if *bif, struct ifbreq **buf)
1058 struct ifbreq *ninbuf;
1059 struct ifbifconf ifbc;
1063 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1064 ifd.ifd_cmd = BRDGGIFS;
1065 ifd.ifd_len = sizeof(ifbc);
1066 ifd.ifd_data = &ifbc;
1069 len = n * sizeof(struct ifbreq);
1070 if ((ninbuf = (struct ifbreq *)realloc(*buf, len)) == NULL) {
1071 syslog(LOG_ERR, "get bridge member list: "
1072 "realloc failed: %s", strerror(errno));
1078 ifbc.ifbic_len = len;
1079 ifbc.ifbic_req = *buf = ninbuf;
1081 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1082 syslog(LOG_ERR, "get bridge member list: ioctl "
1083 "(BRDGGIFS) failed: %s", strerror(errno));
1089 if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len)
1095 return (ifbc.ifbic_len);
1099 * Fetch the bridge STP member list from kernel.
1100 * Return -1 on error, or buffer len if successful.
1103 bridge_port_get_ifstplist(struct bridge_if *bif, struct ifbpstpreq **buf)
1107 struct ifbpstpreq *ninbuf;
1108 struct ifbpstpconf ifbstp;
1112 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1113 ifd.ifd_cmd = BRDGGIFSSTP;
1114 ifd.ifd_len = sizeof(ifbstp);
1115 ifd.ifd_data = &ifbstp;
1118 len = n * sizeof(struct ifbpstpreq);
1119 if ((ninbuf = (struct ifbpstpreq *)
1120 realloc(*buf, len)) == NULL) {
1121 syslog(LOG_ERR, "get bridge STP ports list: "
1122 "realloc failed: %s", strerror(errno));
1128 ifbstp.ifbpstp_len = len;
1129 ifbstp.ifbpstp_req = *buf = ninbuf;
1131 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1132 syslog(LOG_ERR, "get bridge STP ports list: ioctl "
1133 "(BRDGGIFSSTP) failed: %s", strerror(errno));
1139 if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len)
1145 return (ifbstp.ifbpstp_len);
1149 * Locate a bridge if STP params structure in a buffer.
1151 static struct ifbpstpreq *
1152 bridge_port_find_ifstplist(uint8_t port_no, struct ifbpstpreq *buf,
1156 struct ifbpstpreq *bstp;
1158 for (i = 0; i < buf_len / sizeof(struct ifbpstpreq); i++) {
1160 if (bstp->ifbp_portno == port_no)
1168 * Read the initial info for all members of a bridge interface.
1169 * Returns the number of ports, 0 - if none, otherwise
1170 * -1 if some other error occured.
1173 bridge_getinfo_bif_ports(struct bridge_if *bif)
1177 struct ifbreq *b_req_buf, *b_req;
1178 struct ifbpstpreq *bs_req_buf, *bs_req;
1179 struct bridge_port *bp;
1182 if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1185 for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1186 b_req = b_req_buf + i;
1188 if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) != NULL) {
1189 /* Hopefully we will not fail here. */
1190 if ((bp = bridge_new_port(m_if, bif)) != NULL) {
1191 bp->status = RowStatus_active;
1192 bridge_port_getinfo_conf(b_req, bp);
1193 bridge_port_getinfo_mibif(m_if, bp);
1196 syslog(LOG_ERR, "bridge member %s not present "
1197 "in mibII ifTable", b_req->ifbr_ifsname);
1202 if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1205 for (bp = bridge_port_bif_first(bif); bp != NULL;
1206 bp = bridge_port_bif_next(bp)) {
1207 if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1208 bs_req_buf, buf_len)) == NULL)
1209 bridge_port_clearinfo_opstp(bp);
1211 bridge_port_getinfo_opstp(bs_req, bp);
1219 * Update the information for the bridge interface members.
1222 bridge_update_memif(struct bridge_if *bif)
1227 struct ifbreq *b_req_buf, *b_req;
1228 struct ifbpstpreq *bs_req_buf, *bs_req;
1229 struct bridge_port *bp, *bp_next;
1232 if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1235 added = updated = 0;
1237 #define BP_FOUND 0x01
1238 for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1239 b_req = b_req_buf + i;
1241 if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) == NULL) {
1242 syslog(LOG_ERR, "bridge member %s not present "
1243 "in mibII ifTable", b_req->ifbr_ifsname);
1247 if ((bp = bridge_port_find(m_if->index, bif)) == NULL &&
1248 (bp = bridge_new_port(m_if, bif)) != NULL) {
1249 bp->status = RowStatus_active;
1255 bridge_port_getinfo_conf(b_req, bp);
1256 bridge_port_getinfo_mibif(m_if, bp);
1257 bp->flags |= BP_FOUND;
1262 /* Clean up list. */
1263 for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) {
1264 bp_next = bridge_port_bif_next(bp);
1266 if ((bp->flags & BP_FOUND) == 0 &&
1267 bp->status == RowStatus_active)
1268 bridge_port_remove(bp, bif);
1270 bp->flags |= ~BP_FOUND;
1274 if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1277 for (bp = bridge_port_bif_first(bif); bp != NULL;
1278 bp = bridge_port_bif_next(bp)) {
1279 if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1280 bs_req_buf, buf_len)) == NULL)
1281 bridge_port_clearinfo_opstp(bp);
1283 bridge_port_getinfo_opstp(bs_req, bp);
1286 bif->ports_age = time(NULL);
1291 /************************************************************************
1296 * Update the bridge address info according to the polled data.
1299 bridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe)
1301 tpe->port_no = if_nametoindex(ifba->ifba_ifsname);
1303 if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
1304 tpe->status = TpFdbStatus_mgmt;
1306 tpe->status = TpFdbStatus_learned;
1310 * Read the bridge addresses from kernel.
1311 * Return -1 on error, or buffer len if successful.
1314 bridge_addrs_getinfo_ifalist(struct bridge_if *bif, struct ifbareq **buf)
1318 struct ifbareq *ninbuf;
1319 struct ifbaconf bac;
1323 strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1324 ifd.ifd_cmd = BRDGRTS;
1325 ifd.ifd_len = sizeof(bac);
1326 ifd.ifd_data = &bac;
1329 len = n * sizeof(struct ifbareq);
1330 if ((ninbuf = (struct ifbareq *)realloc(*buf, len)) == NULL) {
1331 syslog(LOG_ERR, "get bridge address list: "
1332 " realloc failed: %s", strerror(errno));
1338 bac.ifbac_len = len;
1339 bac.ifbac_req = *buf = ninbuf;
1341 if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1342 syslog(LOG_ERR, "get bridge address list: "
1343 "ioctl(BRDGRTS) failed: %s", strerror(errno));
1349 if ((bac.ifbac_len + sizeof(struct ifbareq)) < len)
1355 return (bac.ifbac_len);
1359 * Read the initial info for all addresses on a bridge interface.
1360 * Returns the number of addresses, 0 - if none, otherwise
1361 * -1 if some other error occured.
1364 bridge_getinfo_bif_addrs(struct bridge_if *bif)
1368 struct ifbareq *addr_req_buf, *addr_req;
1369 struct tp_entry *te;
1371 if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1374 for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1375 addr_req = addr_req_buf + i;
1377 if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
1378 bridge_addrs_info_ifaddrlist(addr_req, te);
1386 * Update the addresses for the bridge interface.
1389 bridge_update_addrs(struct bridge_if *bif)
1394 struct tp_entry *te, *te_next;
1395 struct ifbareq *addr_req_buf, *addr_req;
1397 if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1400 added = updated = 0;
1402 #define BA_FOUND 0x01
1403 for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1404 addr_req = addr_req_buf + i;
1406 if ((te = bridge_addrs_find(addr_req->ifba_dst, bif)) == NULL) {
1409 if ((te = bridge_new_addrs(addr_req->ifba_dst, bif))
1415 bridge_addrs_info_ifaddrlist(addr_req, te);
1416 te-> flags |= BA_FOUND;
1420 for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) {
1421 te_next = bridge_addrs_bif_next(te);
1423 if ((te-> flags & BA_FOUND) == 0)
1424 bridge_addrs_remove(te, bif);
1426 te-> flags &= ~BA_FOUND;
1430 bif->addrs_age = time(NULL);
1431 return (updated + added);
1434 /************************************************************************
1435 * Bridge packet filtering.
1437 const char bridge_sysctl[] = "net.link.bridge.";
1442 } bridge_pf_sysctl[] = {
1443 { 1, "pfil_bridge" },
1444 { 1, "pfil_member" },
1445 { 1, "pfil_onlyip" },
1450 bridge_get_pfval(uint8_t which)
1452 if (which > sizeof(bridge_pf_sysctl) / sizeof(bridge_pf_sysctl[0])
1456 return (bridge_pf_sysctl[which - 1].val);
1460 bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val)
1466 if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus)
1469 if (op == SNMP_OP_SET) {
1471 s_len = sizeof(s_i);
1477 strcpy(mib_name, bridge_sysctl);
1479 if (sysctlbyname(strcat(mib_name,
1480 bridge_pf_sysctl[bridge_ctl].name), &i, &len,
1481 (op == SNMP_OP_SET ? &s_i : NULL), s_len) == -1) {
1482 syslog(LOG_ERR, "sysctl(%s%s) failed - %s", bridge_sysctl,
1483 bridge_pf_sysctl[bridge_ctl].name, strerror(errno));
1487 bridge_pf_sysctl[bridge_ctl].val = i;
1494 bridge_pf_dump(void)
1498 for (i = 0; i < sizeof(bridge_pf_sysctl) / sizeof(bridge_pf_sysctl[0]);
1500 syslog(LOG_ERR, "%s%s = %d", bridge_sysctl,
1501 bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val);