1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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
26  * SUCH DAMAGE.
27  *
28  * Bridge MIB implementation for SNMPd.
29  * Bridge OS specific ioctls.
30  */
31 
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>
38 
39 #include <net/bridgestp.h>
40 #include <net/ethernet.h>
41 #include <net/if.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>
47 
48 #include <errno.h>
49 #include <ifaddrs.h>
50 #include <stdarg.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <syslog.h>
55 
56 #include <bsnmp/snmpmod.h>
57 #include <bsnmp/snmp_mibII.h>
58 
59 #define	SNMPTREE_TYPES
60 #include "bridge_tree.h"
61 #include "bridge_snmp.h"
62 
63 int sock = -1;
64 
65 int
66 bridge_ioctl_init(void)
67 {
68 	if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
69 		syslog(LOG_ERR, "cannot open socket : %s", strerror(errno));
70 		return (-1);
71 	}
72 
73 	return (0);
74 }
75 
76 /*
77  * Load the if_bridge.ko module in kernel if not already there.
78  */
79 int
80 bridge_kmod_load(void)
81 {
82 	int fileid, modid;
83 	const char mod_name[] = "if_bridge";
84 	struct module_stat mstat;
85 
86 	/* Scan files in kernel. */
87 	mstat.version = sizeof(struct module_stat);
88 	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
89 		/* Scan modules in file. */
90 		for (modid = kldfirstmod(fileid); modid > 0;
91 			modid = modfnext(modid)) {
92 
93 			if (modstat(modid, &mstat) < 0)
94 				continue;
95 
96 			if (strcmp(mod_name, mstat.name) == 0)
97 				return (0);
98 		}
99 	}
100 
101 	/* Not present - load it. */
102 	if (kldload(mod_name) < 0) {
103 		syslog(LOG_ERR, "failed to load %s kernel module", mod_name);
104 		return (-1);
105 	}
106 
107 	return (1);
108 }
109 
110 /************************************************************************
111  * Bridge interfaces.
112  */
113 
114 /*
115  * Convert the kernel uint64_t value for a bridge id
116  */
117 static void
118 snmp_uint64_to_bridgeid(uint64_t id, bridge_id b_id)
119 {
120 	int i;
121 	u_char *o;
122 
123 	o = (u_char *) &id;
124 
125 	for (i = 0; i < SNMP_BRIDGE_ID_LEN; i++, o++)
126 		b_id[SNMP_BRIDGE_ID_LEN - i - 1] = *o;
127 }
128 
129 /*
130  * Fetch the bridge configuration parameters from the kernel excluding
131  * it's base MAC address.
132  */
133 static int
134 bridge_get_conf_param(struct bridge_if *bif)
135 {
136 	struct ifdrv ifd;
137 	struct ifbrparam b_param;
138 
139 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
140 	ifd.ifd_len = sizeof(b_param);
141 	ifd.ifd_data = &b_param;
142 
143 	/* Bridge priority. */
144 	ifd.ifd_cmd = BRDGGPRI;
145 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
146 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGPRI) failed: %s",
147 		    strerror(errno));
148 		return (-1);
149 	}
150 
151 	bif->priority = b_param.ifbrp_prio;
152 
153 	/* Configured max age. */
154 	ifd.ifd_cmd = BRDGGMA;
155 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
156 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGMA) failed: %s",
157 		    strerror(errno));
158 		return (-1);
159 	}
160 
161 	/* Centi-seconds. */
162 	bif->bridge_max_age = 100 * b_param.ifbrp_maxage;
163 
164 	/* Configured hello time. */
165 	ifd.ifd_cmd = BRDGGHT;
166 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
167 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGHT) failed: %s",
168 		    strerror(errno));
169 		return (-1);
170 	}
171 	bif->bridge_hello_time = 100 * b_param.ifbrp_hellotime;
172 
173 	/* Forward delay. */
174 	ifd.ifd_cmd = BRDGGFD;
175 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
176 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGFD) failed: %s",
177 		    strerror(errno));
178 		return (-1);
179 	}
180 	bif->bridge_fwd_delay = 100 * b_param.ifbrp_fwddelay;
181 
182 	/* Number of dropped addresses. */
183 	ifd.ifd_cmd = BRDGGRTE;
184 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
185 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGRTE) failed: %s",
186 		    strerror(errno));
187 		return (-1);
188 	}
189 	bif->lrnt_drops = b_param.ifbrp_cexceeded;
190 
191 	/* Address table timeout. */
192 	ifd.ifd_cmd = BRDGGTO;
193 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
194 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGTO) failed: %s",
195 		    strerror(errno));
196 		return (-1);
197 	}
198 	bif->age_time = b_param.ifbrp_ctime;
199 
200 	/* Address table size. */
201 	ifd.ifd_cmd = BRDGGCACHE;
202 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
203 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGCACHE) "
204 		    "failed: %s", strerror(errno));
205 		return (-1);
206 	}
207 	bif->max_addrs = b_param.ifbrp_csize;
208 
209 	return (0);
210 }
211 
212 /*
213  * Fetch the current bridge STP operational parameters.
214  * Returns: -1 - on error;
215  *	     0 - old TC time and Root Port values are same;
216  *	     1 - topologyChange notification should be sent;
217  *	     2 - newRoot notification should be sent.
218  */
219 int
220 bridge_get_op_param(struct bridge_if *bif)
221 {
222 	int new_root_send;
223 	struct ifdrv ifd;
224 	struct ifbropreq b_req;
225 
226 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
227 	ifd.ifd_len = sizeof(b_req);
228 	ifd.ifd_data = &b_req;
229 	ifd.ifd_cmd = BRDGPARAM;
230 
231 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
232 		syslog(LOG_ERR, "update bridge: ioctl(BRDGPARAM) failed: %s",
233 		    strerror(errno));
234 		return (-1);
235 	}
236 
237 	bif->max_age = 100 * b_req.ifbop_maxage;
238 	bif->hello_time = 100 * b_req.ifbop_hellotime;
239 	bif->fwd_delay = 100 * b_req.ifbop_fwddelay;
240 	bif->stp_version = b_req.ifbop_protocol;
241 	bif->tx_hold_count = b_req.ifbop_holdcount;
242 
243 	if (b_req.ifbop_root_port == 0 &&
244 	    bif->root_port != b_req.ifbop_root_port)
245 		new_root_send = 2;
246 	else
247 		new_root_send = 0;
248 
249 	bif->root_port = b_req.ifbop_root_port;
250 	bif->root_cost = b_req.ifbop_root_path_cost;
251 	snmp_uint64_to_bridgeid(b_req.ifbop_designated_root,
252 	    bif->design_root);
253 
254 	if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) {
255 		bif->top_changes++;
256 		bif->last_tc_time.tv_sec = b_req.ifbop_last_tc_time.tv_sec;
257 		bif->last_tc_time.tv_usec = b_req.ifbop_last_tc_time.tv_usec;
258 
259 		/*
260 		 * "The trap is not sent if a (begemotBridge)NewRoot
261 		 * trap is sent for the same transition."
262 		 */
263 		if (new_root_send == 0)
264 			return (1);
265 	}
266 
267 	return (new_root_send);
268 }
269 
270 int
271 bridge_getinfo_bif(struct bridge_if *bif)
272 {
273 	if (bridge_get_conf_param(bif) < 0)
274 		return (-1);
275 
276 	return (bridge_get_op_param(bif));
277 }
278 
279 int
280 bridge_set_priority(struct bridge_if *bif, int32_t priority)
281 {
282 	struct ifdrv ifd;
283 	struct ifbrparam b_param;
284 
285 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
286 	ifd.ifd_len = sizeof(b_param);
287 	ifd.ifd_data = &b_param;
288 	b_param.ifbrp_prio = (uint32_t) priority;
289 	ifd.ifd_cmd = BRDGSPRI;
290 
291 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
292 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) "
293 		    "failed: %s", strerror(errno));
294 		return (-1);
295 	}
296 
297 	/*
298 	 * Re-fetching the data from the driver after that might be a good
299 	 * idea, since changing our bridge's priority should invoke
300 	 * recalculation of the active spanning tree topology in the network.
301 	 */
302 	bif->priority = priority;
303 	return (0);
304 }
305 
306 /*
307  * Convert 1/100 of seconds to 1/256 of seconds.
308  * Timeout ::= TEXTUAL-CONVENTION.
309  * To convert a Timeout value into a value in units of
310  * 1/256 seconds, the following algorithm should be used:
311  *	b = floor( (n * 256) / 100)
312  * The conversion to 1/256 of a second happens in the kernel -
313  * just make sure we correctly convert the seconds to Timeout
314  * and vice versa.
315  */
316 static uint32_t
317 snmp_timeout2_sec(int32_t secs)
318 {
319 	return (secs / 100);
320 }
321 
322 int
323 bridge_set_maxage(struct bridge_if *bif, int32_t max_age)
324 {
325 	struct ifdrv ifd;
326 	struct ifbrparam b_param;
327 
328 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
329 	ifd.ifd_len = sizeof(b_param);
330 	ifd.ifd_data = &b_param;
331 	b_param.ifbrp_maxage = snmp_timeout2_sec(max_age);
332 	ifd.ifd_cmd = BRDGSMA;
333 
334 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
335 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) "
336 		    "failed: %s", strerror(errno));
337 		return (-1);
338 	}
339 
340 	bif->bridge_max_age = max_age;
341 	return (0);
342 }
343 
344 int
345 bridge_set_hello_time(struct bridge_if *bif, int32_t hello_time)
346 {
347 	struct ifdrv ifd;
348 	struct ifbrparam b_param;
349 
350 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
351 	ifd.ifd_len = sizeof(b_param);
352 	ifd.ifd_data = &b_param;
353 	b_param.ifbrp_hellotime = snmp_timeout2_sec(hello_time);
354 	ifd.ifd_cmd = BRDGSHT;
355 
356 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
357 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) "
358 		    "failed: %s", strerror(errno));
359 		return (-1);
360 	}
361 
362 	bif->bridge_hello_time = b_param.ifbrp_hellotime;
363 	return (0);
364 }
365 
366 int
367 bridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay)
368 {
369 	struct ifdrv ifd;
370 	struct ifbrparam b_param;
371 
372 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
373 	ifd.ifd_len = sizeof(b_param);
374 	ifd.ifd_data = &b_param;
375 	b_param.ifbrp_fwddelay = snmp_timeout2_sec(fwd_delay);
376 	ifd.ifd_cmd = BRDGSFD;
377 
378 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
379 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) "
380 		    "failed: %s", strerror(errno));
381 		return (-1);
382 	}
383 
384 	bif->bridge_fwd_delay = b_param.ifbrp_fwddelay;
385 	return (0);
386 }
387 
388 int
389 bridge_set_aging_time(struct bridge_if *bif, int32_t age_time)
390 {
391 	struct ifdrv ifd;
392 	struct ifbrparam b_param;
393 
394 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
395 	ifd.ifd_len = sizeof(b_param);
396 	ifd.ifd_data = &b_param;
397 	b_param.ifbrp_ctime = (uint32_t) age_time;
398 	ifd.ifd_cmd = BRDGSTO;
399 
400 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
401 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) "
402 		    "failed: %s", strerror(errno));
403 		return (-1);
404 	}
405 
406 	bif->age_time = age_time;
407 	return (0);
408 }
409 
410 int
411 bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache)
412 {
413 	struct ifdrv ifd;
414 	struct ifbrparam b_param;
415 
416 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
417 	ifd.ifd_len = sizeof(b_param);
418 	ifd.ifd_data = &b_param;
419 	b_param.ifbrp_csize = max_cache;
420 	ifd.ifd_cmd = BRDGSCACHE;
421 
422 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
423 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) "
424 		    "failed: %s", strerror(errno));
425 		return (-1);
426 	}
427 
428 	bif->max_addrs = b_param.ifbrp_csize;
429 	return (0);
430 }
431 
432 int
433 bridge_set_tx_hold_count(struct bridge_if *bif, int32_t tx_hc)
434 {
435 	struct ifdrv ifd;
436 	struct ifbrparam b_param;
437 
438 	if (tx_hc < SNMP_BRIDGE_MIN_TXHC || tx_hc > SNMP_BRIDGE_MAX_TXHC)
439 		return (-1);
440 
441 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
442 	ifd.ifd_len = sizeof(b_param);
443 	ifd.ifd_data = &b_param;
444 	b_param.ifbrp_txhc = tx_hc;
445 	ifd.ifd_cmd = BRDGSTXHC;
446 
447 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
448 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTXHC) "
449 		    "failed: %s", strerror(errno));
450 		return (-1);
451 	}
452 
453 	bif->tx_hold_count = b_param.ifbrp_txhc;
454 	return (0);
455 }
456 
457 int
458 bridge_set_stp_version(struct bridge_if *bif, int32_t stp_proto)
459 {
460 	struct ifdrv ifd;
461 	struct ifbrparam b_param;
462 
463 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
464 	ifd.ifd_len = sizeof(b_param);
465 	ifd.ifd_data = &b_param;
466 	b_param.ifbrp_proto = stp_proto;
467 	ifd.ifd_cmd = BRDGSPROTO;
468 
469 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
470 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPROTO) "
471 		    "failed: %s", strerror(errno));
472 		return (-1);
473 	}
474 
475 	bif->stp_version = b_param.ifbrp_proto;
476 	return (0);
477 }
478 
479 /*
480  * Set the bridge interface status to up/down.
481  */
482 int
483 bridge_set_if_up(const char* b_name, int8_t up)
484 {
485 	int	flags;
486 	struct ifreq ifr;
487 
488 	bzero(&ifr, sizeof(ifr));
489 	strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
490 	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
491 		syslog(LOG_ERR, "set bridge up: ioctl(SIOCGIFFLAGS) "
492 		    "failed: %s", strerror(errno));
493 		return (-1);
494 	}
495 
496 	flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
497 	if (up == 1)
498 		flags |= IFF_UP;
499 	else
500 		flags &= ~IFF_UP;
501 
502 	ifr.ifr_flags = flags & 0xffff;
503 	ifr.ifr_flagshigh = flags >> 16;
504 	if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
505 		syslog(LOG_ERR, "set bridge up: ioctl(SIOCSIFFLAGS) "
506 		    "failed: %s", strerror(errno));
507 		return (-1);
508 	}
509 
510 	return (0);
511 }
512 
513 int
514 bridge_create(const char *b_name)
515 {
516 	char *new_name;
517 	struct ifreq ifr;
518 
519 	bzero(&ifr, sizeof(ifr));
520 	strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
521 
522 	if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) {
523 		syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) "
524 		    "failed: %s", strerror(errno));
525 		return (-1);
526 	}
527 
528 	if (strcmp(b_name, ifr.ifr_name) == 0)
529 		return (0);
530 
531 	if ((new_name = strdup(b_name)) == NULL) {
532 		syslog(LOG_ERR, "create bridge: strdup() failed");
533 		return (-1);
534 	}
535 
536 	ifr.ifr_data = new_name;
537 	if (ioctl(sock, SIOCSIFNAME, (caddr_t) &ifr) < 0) {
538 		syslog(LOG_ERR, "create bridge: ioctl(SIOCSIFNAME) "
539 		    "failed: %s", strerror(errno));
540 		free(new_name);
541 		return (-1);
542 	}
543 
544 	return (0);
545 }
546 
547 int
548 bridge_destroy(const char *b_name)
549 {
550 	struct ifreq ifr;
551 
552 	bzero(&ifr, sizeof(ifr));
553 	strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
554 
555 	if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) {
556 		syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) "
557 		    "failed: %s", strerror(errno));
558 		return (-1);
559 	}
560 
561 	return (0);
562 }
563 
564 /*
565  * Fetch the bridge base MAC address. Return pointer to the
566  * buffer containing the MAC address, NULL on failure.
567  */
568 u_char *
569 bridge_get_basemac(const char *bif_name, u_char *mac, size_t mlen)
570 {
571 	int len;
572 	char if_name[IFNAMSIZ];
573 	struct ifaddrs *ifap, *ifa;
574 	struct sockaddr_dl sdl;
575 
576 	if (getifaddrs(&ifap) != 0) {
577 		syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s",
578 		    strerror(errno));
579 		return (NULL);
580 	}
581 
582 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
583 		if (ifa->ifa_addr->sa_family != AF_LINK)
584 			continue;
585 
586 		/*
587 		 * Not just casting because of alignment constraints.
588 		 */
589 		bcopy(ifa->ifa_addr, &sdl, sizeof(struct sockaddr_dl));
590 
591 		if (sdl.sdl_alen > mlen)
592 			continue;
593 
594 		if ((len = sdl.sdl_nlen) >= IFNAMSIZ)
595 			len = IFNAMSIZ - 1;
596 
597 		bcopy(sdl.sdl_data, if_name, len);
598 		if_name[len] = '\0';
599 
600 		if (strcmp(bif_name, if_name) == 0) {
601 			bcopy(sdl.sdl_data + sdl.sdl_nlen, mac, sdl.sdl_alen);
602 			freeifaddrs(ifap);
603 			return (mac);
604 		}
605 	}
606 
607 	freeifaddrs(ifap);
608 	return (NULL);
609 }
610 
611 /************************************************************************
612  * Bridge ports.
613  */
614 
615 /*
616  * Convert the kernel STP port state into
617  * the corresopnding enumerated type from SNMP Bridge MIB.
618  */
619 static int
620 state2snmp_st(uint8_t ifbr_state)
621 {
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);
634 	}
635 
636 	return (StpPortState_broken);
637 }
638 
639 /*
640  * Fill in a bridge member information according to data polled from kernel.
641  */
642 static void
643 bridge_port_getinfo_conf(struct ifbreq *k_info, struct bridge_port *bp)
644 {
645 	bp->state = state2snmp_st(k_info->ifbr_state);
646 	bp->priority = k_info->ifbr_priority;
647 
648 	/*
649 	 * RFC 4188:
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."
656 	 */
657 
658 	if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMCOST)
659 		bp->admin_path_cost = k_info->ifbr_path_cost;
660 	else
661 		bp->admin_path_cost = 0;
662 
663 	bp->path_cost = k_info->ifbr_path_cost;
664 
665 	if (k_info->ifbr_ifsflags & IFBIF_STP)
666 		bp->enable = dot1dStpPortEnable_enabled;
667 	else
668 		bp->enable = dot1dStpPortEnable_disabled;
669 
670 	/* Begemot Bridge MIB only. */
671 	if (k_info->ifbr_ifsflags & IFBIF_SPAN)
672 		bp->span_enable = begemotBridgeBaseSpanEnabled_enabled;
673 	else
674 		bp->span_enable = begemotBridgeBaseSpanEnabled_disabled;
675 
676 	if (k_info->ifbr_ifsflags & IFBIF_PRIVATE)
677 		bp->priv_set = TruthValue_true;
678 	else
679 		bp->priv_set = TruthValue_false;
680 
681 	if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMEDGE)
682 		bp->admin_edge = TruthValue_true;
683 	else
684 		bp->admin_edge = TruthValue_false;
685 
686 	if (k_info->ifbr_ifsflags & IFBIF_BSTP_EDGE)
687 		bp->oper_edge = TruthValue_true;
688 	else
689 		bp->oper_edge = TruthValue_false;
690 
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;
695 		else
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;
700 	} else {
701 		bp->admin_ptp = StpPortAdminPointToPointType_forceFalse;
702 		bp->oper_ptp = TruthValue_false;
703 	}
704 }
705 
706 /*
707  * Fill in a bridge interface STP information according to
708  * data polled from kernel.
709  */
710 static void
711 bridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp)
712 {
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),
719 	    sizeof(uint16_t));
720 }
721 
722 /*
723  * Clear a bridge interface STP information.
724  */
725 static void
726 bridge_port_clearinfo_opstp(struct bridge_port *bp)
727 {
728 	if (bp->enable == dot1dStpPortEnable_enabled) {
729 		bp->design_cost = 0;
730 		bzero(&(bp->design_root), sizeof(bridge_id));
731 		bzero(&(bp->design_bridge), sizeof(bridge_id));
732 		bzero(&(bp->design_port), sizeof(port_id));
733 		bp->fwd_trans = 0;
734 	}
735 
736 	bp->enable = dot1dStpPortEnable_disabled;
737 }
738 
739 /*
740  * Set a bridge member priority.
741  */
742 int
743 bridge_port_set_priority(const char *bif_name, struct bridge_port *bp,
744 	int32_t priority)
745 {
746 	struct ifdrv ifd;
747 	struct ifbreq b_req;
748 
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));
753 
754 	b_req.ifbr_priority = (uint8_t) priority;
755 	ifd.ifd_cmd = BRDGSIFPRIO;
756 
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));
760 		return (-1);
761 	}
762 
763 	bp->priority = priority;
764 	return (0);
765 }
766 
767 /*
768  * Set a bridge member STP-enabled flag.
769  */
770 int
771 bridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp,
772 	uint32_t enable)
773 {
774 	struct ifdrv ifd;
775 	struct ifbreq b_req;
776 
777 	if (bp->enable == enable)
778 		return (0);
779 
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;
786 
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));
790 		return (-1);
791 	}
792 
793 	if (enable == dot1dStpPortEnable_enabled)
794 		b_req.ifbr_ifsflags |= IFBIF_STP;
795 	else
796 		b_req.ifbr_ifsflags &= ~IFBIF_STP;
797 
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));
802 		return (-1);
803 	}
804 
805 	bp->enable = enable;
806 	return (0);
807 }
808 
809 /*
810  * Set a bridge member STP path cost.
811  */
812 int
813 bridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp,
814 	int32_t path_cost)
815 {
816 	struct ifdrv ifd;
817 	struct ifbreq b_req;
818 
819 	if (path_cost < SNMP_PORT_MIN_PATHCOST ||
820 	    path_cost > SNMP_PORT_PATHCOST_OBSOLETE)
821 		return (-2);
822 
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));
827 
828 	b_req.ifbr_path_cost = path_cost;
829 	ifd.ifd_cmd = BRDGSIFCOST;
830 
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));
834 		return (-1);
835 	}
836 
837 	bp->admin_path_cost = path_cost;
838 
839 	return (0);
840 }
841 
842 /*
843  * Set the PonitToPoint status of the link administratively.
844  */
845 int
846 bridge_port_set_admin_ptp(const char *bif_name, struct bridge_port *bp,
847     uint32_t admin_ptp)
848 {
849 	struct ifdrv ifd;
850 	struct ifbreq b_req;
851 
852 	if (bp->admin_ptp == admin_ptp)
853 		return (0);
854 
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;
861 
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));
865 		return (-1);
866 	}
867 
868 	switch (admin_ptp) {
869 		case StpPortAdminPointToPointType_forceTrue:
870 			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
871 			b_req.ifbr_ifsflags |= IFBIF_BSTP_PTP;
872 			break;
873 		case StpPortAdminPointToPointType_forceFalse:
874 			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
875 			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_PTP;
876 			break;
877 		case StpPortAdminPointToPointType_auto:
878 			b_req.ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
879 			break;
880 	}
881 
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));
886 		return (-1);
887 	}
888 
889 	bp->admin_ptp = admin_ptp;
890 	return (0);
891 }
892 
893 /*
894  * Set admin edge.
895  */
896 int
897 bridge_port_set_admin_edge(const char *bif_name, struct bridge_port *bp,
898     uint32_t enable)
899 {
900 	struct ifdrv ifd;
901 	struct ifbreq b_req;
902 
903 	if (bp->admin_edge == enable)
904 		return (0);
905 
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;
912 
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));
916 		return (-1);
917 	}
918 
919 	if (enable == TruthValue_true) {
920 		b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOEDGE;
921 		b_req.ifbr_ifsflags |= IFBIF_BSTP_EDGE;
922 	} else
923 		b_req.ifbr_ifsflags &= ~IFBIF_BSTP_EDGE;
924 
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));
929 		return (-1);
930 	}
931 
932 	bp->admin_edge = enable;
933 
934 	return (0);
935 }
936 
937 /*
938  * Set 'private' flag.
939  */
940 int
941 bridge_port_set_private(const char *bif_name, struct bridge_port *bp,
942     uint32_t priv_set)
943 {
944 	struct ifdrv ifd;
945 	struct ifbreq b_req;
946 
947 	if (bp->priv_set == priv_set)
948 		return (0);
949 
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;
956 
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));
960 		return (-1);
961 	}
962 
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;
967 	else
968 		return (SNMP_ERR_WRONG_VALUE);
969 
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));
974 		return (-1);
975 	}
976 
977 	bp->priv_set = priv_set;
978 
979 	return (0);
980 }
981 
982 
983 /*
984  * Add a bridge member port.
985  */
986 int
987 bridge_port_addm(struct bridge_port *bp, const char *b_name)
988 {
989 	struct ifdrv ifd;
990 	struct ifbreq b_req;
991 
992 	bzero(&ifd, sizeof(ifd));
993 	bzero(&b_req, sizeof(b_req));
994 
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));
999 
1000 	if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1001 		ifd.ifd_cmd = BRDGADDS;
1002 	else
1003 		ifd.ifd_cmd = BRDGADD;
1004 
1005 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1006 		syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1007 		    bp->p_name,
1008 		    (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"),
1009 		    strerror(errno));
1010 		return (-1);
1011 	}
1012 
1013 	return (0);
1014 }
1015 
1016 /*
1017  * Delete a bridge member port.
1018  */
1019 int
1020 bridge_port_delm(struct bridge_port *bp, const char *b_name)
1021 {
1022 	struct ifdrv ifd;
1023 	struct ifbreq b_req;
1024 
1025 	bzero(&ifd, sizeof(ifd));
1026 	bzero(&b_req, sizeof(b_req));
1027 
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));
1032 
1033 	if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1034 		ifd.ifd_cmd = BRDGDELS;
1035 	else
1036 		ifd.ifd_cmd = BRDGDEL;
1037 
1038 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1039 		syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1040 		    bp->p_name,
1041 		    (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"),
1042 		    strerror(errno));
1043 		return (-1);
1044 	}
1045 
1046 	return (0);
1047 }
1048 
1049 /*
1050  * Fetch the bridge member list from kernel.
1051  * Return -1 on error, or buffer len if successful.
1052  */
1053 static int32_t
1054 bridge_port_get_iflist(struct bridge_if *bif, struct ifbreq **buf)
1055 {
1056 	int n = 128;
1057 	uint32_t len;
1058 	struct ifbreq *ninbuf;
1059 	struct ifbifconf ifbc;
1060 	struct ifdrv ifd;
1061 
1062 	*buf = NULL;
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;
1067 
1068 	for ( ; ; ) {
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));
1073 			free(*buf);
1074 			*buf = NULL;
1075 			return (-1);
1076 		}
1077 
1078 		ifbc.ifbic_len = len;
1079 		ifbc.ifbic_req = *buf = ninbuf;
1080 
1081 		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1082 			syslog(LOG_ERR, "get bridge member list: ioctl "
1083 			    "(BRDGGIFS) failed: %s", strerror(errno));
1084 			free(*buf);
1085 			buf = NULL;
1086 			return (-1);
1087 		}
1088 
1089 		if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len)
1090 			break;
1091 
1092 		n += 64;
1093 	}
1094 
1095 	return (ifbc.ifbic_len);
1096 }
1097 
1098 /*
1099  * Fetch the bridge STP member list from kernel.
1100  * Return -1 on error, or buffer len if successful.
1101  */
1102 static int32_t
1103 bridge_port_get_ifstplist(struct bridge_if *bif, struct ifbpstpreq **buf)
1104 {
1105 	int n = 128;
1106 	uint32_t len;
1107 	struct ifbpstpreq *ninbuf;
1108 	struct ifbpstpconf ifbstp;
1109 	struct ifdrv ifd;
1110 
1111 	*buf = NULL;
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;
1116 
1117 	for ( ; ; ) {
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));
1123 			free(*buf);
1124 			*buf = NULL;
1125 			return (-1);
1126 		}
1127 
1128 		ifbstp.ifbpstp_len = len;
1129 		ifbstp.ifbpstp_req = *buf = ninbuf;
1130 
1131 		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1132 			syslog(LOG_ERR, "get bridge STP ports list: ioctl "
1133 			    "(BRDGGIFSSTP) failed: %s", strerror(errno));
1134 			free(*buf);
1135 			buf = NULL;
1136 			return (-1);
1137 		}
1138 
1139 		if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len)
1140 			break;
1141 
1142 		n += 64;
1143 	}
1144 
1145 	return (ifbstp.ifbpstp_len);
1146 }
1147 
1148 /*
1149  * Locate a bridge if STP params structure in a buffer.
1150  */
1151 static struct ifbpstpreq *
1152 bridge_port_find_ifstplist(uint8_t port_no, struct ifbpstpreq *buf,
1153     uint32_t buf_len)
1154 {
1155 	uint32_t i;
1156 	struct ifbpstpreq *bstp;
1157 
1158 	for (i = 0; i < buf_len / sizeof(struct ifbpstpreq); i++) {
1159 		bstp = buf + i;
1160 		if (bstp->ifbp_portno == port_no)
1161 			return (bstp);
1162 	}
1163 
1164 	return (NULL);
1165 }
1166 
1167 /*
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 occurred.
1171  */
1172 int
1173 bridge_getinfo_bif_ports(struct bridge_if *bif)
1174 {
1175 	uint32_t i;
1176 	int32_t buf_len;
1177 	struct ifbreq *b_req_buf, *b_req;
1178 	struct ifbpstpreq *bs_req_buf, *bs_req;
1179 	struct bridge_port *bp;
1180 	struct mibif *m_if;
1181 
1182 	if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1183 		return (-1);
1184 
1185 	for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1186 		b_req = b_req_buf + i;
1187 
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);
1194 			}
1195 		} else {
1196 			syslog(LOG_ERR, "bridge member %s not present "
1197 			    "in mibII ifTable", b_req->ifbr_ifsname);
1198 		}
1199 	}
1200 	free(b_req_buf);
1201 
1202 	if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1203 		return (-1);
1204 
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);
1210 		else
1211 			bridge_port_getinfo_opstp(bs_req, bp);
1212 	}
1213 	free(bs_req_buf);
1214 
1215 	return (i);
1216 }
1217 
1218 /*
1219  * Update the information for the bridge interface members.
1220  */
1221 int
1222 bridge_update_memif(struct bridge_if *bif)
1223 {
1224 	int updated;
1225 	uint32_t i;
1226 	int32_t buf_len;
1227 	struct ifbreq *b_req_buf, *b_req;
1228 	struct ifbpstpreq *bs_req_buf, *bs_req;
1229 	struct bridge_port *bp, *bp_next;
1230 	struct mibif *m_if;
1231 
1232 	if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1233 		return (-1);
1234 
1235 	updated = 0;
1236 
1237 #define	BP_FOUND	0x01
1238 	for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1239 		b_req = b_req_buf + i;
1240 
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);
1244 			continue;
1245 		}
1246 
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;
1250 		}
1251 
1252 		if (bp != NULL) {
1253 			updated++;
1254 			bridge_port_getinfo_conf(b_req, bp);
1255 			bridge_port_getinfo_mibif(m_if, bp);
1256 			bp->flags |= BP_FOUND;
1257 		}
1258 	}
1259 	free(b_req_buf);
1260 
1261 	/* Clean up list. */
1262 	for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) {
1263 		bp_next  = bridge_port_bif_next(bp);
1264 
1265 		if ((bp->flags & BP_FOUND) == 0 &&
1266 		    bp->status == RowStatus_active)
1267 			bridge_port_remove(bp, bif);
1268 		else
1269 			bp->flags |= ~BP_FOUND;
1270 	}
1271 #undef	BP_FOUND
1272 
1273 	if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1274 		return (-1);
1275 
1276 	for (bp = bridge_port_bif_first(bif); bp != NULL;
1277 	    bp = bridge_port_bif_next(bp)) {
1278 		if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1279 		    bs_req_buf, buf_len)) == NULL)
1280 			bridge_port_clearinfo_opstp(bp);
1281 		else
1282 			bridge_port_getinfo_opstp(bs_req, bp);
1283 	}
1284 	free(bs_req_buf);
1285 	bif->ports_age = time(NULL);
1286 
1287 	return (updated);
1288 }
1289 
1290 /************************************************************************
1291  * Bridge addresses.
1292  */
1293 
1294 /*
1295  * Update the bridge address info according to the polled data.
1296  */
1297 static void
1298 bridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe)
1299 {
1300 	tpe->port_no = if_nametoindex(ifba->ifba_ifsname);
1301 
1302 	if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
1303 		tpe->status = TpFdbStatus_mgmt;
1304 	else
1305 		tpe->status = TpFdbStatus_learned;
1306 }
1307 
1308 /*
1309  * Read the bridge addresses from kernel.
1310  * Return -1 on error, or buffer len if successful.
1311  */
1312 static int32_t
1313 bridge_addrs_getinfo_ifalist(struct bridge_if *bif, struct ifbareq **buf)
1314 {
1315 	int n = 128;
1316 	uint32_t len;
1317 	struct ifbareq *ninbuf;
1318 	struct ifbaconf bac;
1319 	struct ifdrv ifd;
1320 
1321 	*buf = NULL;
1322 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1323 	ifd.ifd_cmd = BRDGRTS;
1324 	ifd.ifd_len = sizeof(bac);
1325 	ifd.ifd_data = &bac;
1326 
1327 	for ( ; ; ) {
1328 		len = n * sizeof(struct ifbareq);
1329 		if ((ninbuf = (struct ifbareq *)realloc(*buf, len)) == NULL) {
1330 			syslog(LOG_ERR, "get bridge address list: "
1331 			    " realloc failed: %s", strerror(errno));
1332 			free(*buf);
1333 			*buf = NULL;
1334 			return (-1);
1335 		}
1336 
1337 		bac.ifbac_len = len;
1338 		bac.ifbac_req = *buf = ninbuf;
1339 
1340 		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1341 			syslog(LOG_ERR, "get bridge address list: "
1342 			    "ioctl(BRDGRTS) failed: %s", strerror(errno));
1343 			free(*buf);
1344 			buf = NULL;
1345 			return (-1);
1346 		}
1347 
1348 		if ((bac.ifbac_len + sizeof(struct ifbareq)) < len)
1349 			break;
1350 
1351 		n += 64;
1352 	}
1353 
1354 	return (bac.ifbac_len);
1355 }
1356 
1357 /*
1358  * Read the initial info for all addresses on a bridge interface.
1359  * Returns the number of addresses, 0 - if none, otherwise
1360  * -1 if some other error occurred.
1361  */
1362 int
1363 bridge_getinfo_bif_addrs(struct bridge_if *bif)
1364 {
1365 	uint32_t i;
1366 	int32_t buf_len;
1367 	struct ifbareq *addr_req_buf, *addr_req;
1368 	struct tp_entry *te;
1369 
1370 	if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1371 		return (-1);
1372 
1373 	for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1374 		addr_req = addr_req_buf + i;
1375 
1376 		if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
1377 			bridge_addrs_info_ifaddrlist(addr_req, te);
1378 	}
1379 
1380 	free(addr_req_buf);
1381 	return (i);
1382 }
1383 
1384 /*
1385  * Update the addresses for the bridge interface.
1386  */
1387 int
1388 bridge_update_addrs(struct bridge_if *bif)
1389 {
1390 	int added, updated;
1391 	uint32_t i;
1392 	int32_t buf_len;
1393 	struct tp_entry *te, *te_next;
1394 	struct ifbareq *addr_req_buf, *addr_req;
1395 
1396 	if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1397 		return (-1);
1398 
1399 	added = updated = 0;
1400 
1401 #define	BA_FOUND	0x01
1402 	for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1403 		addr_req = addr_req_buf + i;
1404 
1405 		if ((te = bridge_addrs_find(addr_req->ifba_dst, bif)) == NULL) {
1406 			added++;
1407 
1408 			if ((te = bridge_new_addrs(addr_req->ifba_dst, bif))
1409 			    == NULL)
1410 				continue;
1411 		} else
1412 			updated++;
1413 
1414 		bridge_addrs_info_ifaddrlist(addr_req, te);
1415 		te-> flags |= BA_FOUND;
1416 	}
1417 	free(addr_req_buf);
1418 
1419 	for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) {
1420 		te_next = bridge_addrs_bif_next(te);
1421 
1422 		if ((te-> flags & BA_FOUND) == 0)
1423 			bridge_addrs_remove(te, bif);
1424 		else
1425 			te-> flags &= ~BA_FOUND;
1426 	}
1427 #undef	BA_FOUND
1428 
1429 	bif->addrs_age = time(NULL);
1430 	return (updated + added);
1431 }
1432 
1433 /************************************************************************
1434  * Bridge packet filtering.
1435  */
1436 const char bridge_sysctl[] = "net.link.bridge.";
1437 
1438 static struct {
1439 	int32_t val;
1440 	const char *name;
1441 } bridge_pf_sysctl[] = {
1442 	{ 1, "pfil_bridge" },
1443 	{ 1, "pfil_member" },
1444 	{ 1, "pfil_onlyip" },
1445 	{ 0, "ipfw" },
1446 };
1447 
1448 int32_t
1449 bridge_get_pfval(uint8_t which)
1450 {
1451 
1452 	if (which > nitems(bridge_pf_sysctl) || which < 1)
1453 		return (-1);
1454 
1455 	return (bridge_pf_sysctl[which - 1].val);
1456 }
1457 
1458 int32_t
1459 bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val)
1460 {
1461 	char *mib_oid;
1462 	size_t len, s_len;
1463 	int32_t i, s_i;
1464 
1465 	if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus)
1466 		return (-2);
1467 
1468 	if (op == SNMP_OP_SET) {
1469 		s_i = *val;
1470 		s_len = sizeof(s_i);
1471 	} else
1472 		s_len = 0;
1473 
1474 	len = sizeof(i);
1475 
1476 	asprintf(&mib_oid, "%s%s", bridge_sysctl,
1477 	    bridge_pf_sysctl[bridge_ctl].name);
1478 	if (mib_oid == NULL)
1479 		return (-1);
1480 
1481 	if (sysctlbyname(mib_oid, &i, &len, (op == SNMP_OP_SET ? &s_i : NULL),
1482 	    s_len) == -1) {
1483 		syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_oid,
1484 		    strerror(errno));
1485 		free(mib_oid);
1486 		return (-1);
1487 	}
1488 
1489 	bridge_pf_sysctl[bridge_ctl].val = i;
1490 	*val = i;
1491 
1492 	free(mib_oid);
1493 
1494 	return (i);
1495 }
1496 
1497 void
1498 bridge_pf_dump(void)
1499 {
1500 	uint8_t i;
1501 
1502 	for (i = 0; i < nitems(bridge_pf_sysctl); i++) {
1503 		syslog(LOG_ERR, "%s%s = %d", bridge_sysctl,
1504 		    bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val);
1505 	}
1506 }
1507