1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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  * $FreeBSD$
32  */
33 
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>
40 
41 #include <net/bridgestp.h>
42 #include <net/ethernet.h>
43 #include <net/if.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>
49 
50 #include <errno.h>
51 #include <ifaddrs.h>
52 #include <stdarg.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <syslog.h>
57 
58 #include <bsnmp/snmpmod.h>
59 #include <bsnmp/snmp_mibII.h>
60 
61 #define	SNMPTREE_TYPES
62 #include "bridge_tree.h"
63 #include "bridge_snmp.h"
64 
65 int sock = -1;
66 
67 int
68 bridge_ioctl_init(void)
69 {
70 	if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
71 		syslog(LOG_ERR, "cannot open socket : %s", strerror(errno));
72 		return (-1);
73 	}
74 
75 	return (0);
76 }
77 
78 /*
79  * Load the if_bridge.ko module in kernel if not already there.
80  */
81 int
82 bridge_kmod_load(void)
83 {
84 	int fileid, modid;
85 	const char mod_name[] = "if_bridge";
86 	struct module_stat mstat;
87 
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)) {
94 
95 			if (modstat(modid, &mstat) < 0)
96 				continue;
97 
98 			if (strcmp(mod_name, mstat.name) == 0)
99 				return (0);
100 		}
101 	}
102 
103 	/* Not present - load it. */
104 	if (kldload(mod_name) < 0) {
105 		syslog(LOG_ERR, "failed to load %s kernel module", mod_name);
106 		return (-1);
107 	}
108 
109 	return (1);
110 }
111 
112 /************************************************************************
113  * Bridge interfaces.
114  */
115 
116 /*
117  * Convert the kernel uint64_t value for a bridge id
118  */
119 static void
120 snmp_uint64_to_bridgeid(uint64_t id, bridge_id b_id)
121 {
122 	int i;
123 	u_char *o;
124 
125 	o = (u_char *) &id;
126 
127 	for (i = 0; i < SNMP_BRIDGE_ID_LEN; i++, o++)
128 		b_id[SNMP_BRIDGE_ID_LEN - i - 1] = *o;
129 }
130 
131 /*
132  * Fetch the bridge configuration parameters from the kernel excluding
133  * it's base MAC address.
134  */
135 static int
136 bridge_get_conf_param(struct bridge_if *bif)
137 {
138 	struct ifdrv ifd;
139 	struct ifbrparam b_param;
140 
141 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
142 	ifd.ifd_len = sizeof(b_param);
143 	ifd.ifd_data = &b_param;
144 
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",
149 		    strerror(errno));
150 		return (-1);
151 	}
152 
153 	bif->priority = b_param.ifbrp_prio;
154 
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",
159 		    strerror(errno));
160 		return (-1);
161 	}
162 
163 	/* Centi-seconds. */
164 	bif->bridge_max_age = 100 * b_param.ifbrp_maxage;
165 
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",
170 		    strerror(errno));
171 		return (-1);
172 	}
173 	bif->bridge_hello_time = 100 * b_param.ifbrp_hellotime;
174 
175 	/* Forward delay. */
176 	ifd.ifd_cmd = BRDGGFD;
177 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
178 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGFD) failed: %s",
179 		    strerror(errno));
180 		return (-1);
181 	}
182 	bif->bridge_fwd_delay = 100 * b_param.ifbrp_fwddelay;
183 
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",
188 		    strerror(errno));
189 		return (-1);
190 	}
191 	bif->lrnt_drops = b_param.ifbrp_cexceeded;
192 
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",
197 		    strerror(errno));
198 		return (-1);
199 	}
200 	bif->age_time = b_param.ifbrp_ctime;
201 
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));
207 		return (-1);
208 	}
209 	bif->max_addrs = b_param.ifbrp_csize;
210 
211 	return (0);
212 }
213 
214 /*
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.
220  */
221 int
222 bridge_get_op_param(struct bridge_if *bif)
223 {
224 	int new_root_send;
225 	struct ifdrv ifd;
226 	struct ifbropreq b_req;
227 
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;
232 
233 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
234 		syslog(LOG_ERR, "update bridge: ioctl(BRDGPARAM) failed: %s",
235 		    strerror(errno));
236 		return (-1);
237 	}
238 
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;
244 
245 	if (b_req.ifbop_root_port == 0 &&
246 	    bif->root_port != b_req.ifbop_root_port)
247 		new_root_send = 2;
248 	else
249 		new_root_send = 0;
250 
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,
254 	    bif->design_root);
255 
256 	if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) {
257 		bif->top_changes++;
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;
260 
261 		/*
262 		 * "The trap is not sent if a (begemotBridge)NewRoot
263 		 * trap is sent for the same transition."
264 		 */
265 		if (new_root_send == 0)
266 			return (1);
267 	}
268 
269 	return (new_root_send);
270 }
271 
272 int
273 bridge_getinfo_bif(struct bridge_if *bif)
274 {
275 	if (bridge_get_conf_param(bif) < 0)
276 		return (-1);
277 
278 	return (bridge_get_op_param(bif));
279 }
280 
281 int
282 bridge_set_priority(struct bridge_if *bif, int32_t priority)
283 {
284 	struct ifdrv ifd;
285 	struct ifbrparam b_param;
286 
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;
292 
293 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
294 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) "
295 		    "failed: %s", strerror(errno));
296 		return (-1);
297 	}
298 
299 	/*
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.
303 	 */
304 	bif->priority = priority;
305 	return (0);
306 }
307 
308 /*
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
316  * and vice versa.
317  */
318 static uint32_t
319 snmp_timeout2_sec(int32_t secs)
320 {
321 	return (secs / 100);
322 }
323 
324 int
325 bridge_set_maxage(struct bridge_if *bif, int32_t max_age)
326 {
327 	struct ifdrv ifd;
328 	struct ifbrparam b_param;
329 
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;
335 
336 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
337 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) "
338 		    "failed: %s", strerror(errno));
339 		return (-1);
340 	}
341 
342 	bif->bridge_max_age = max_age;
343 	return (0);
344 }
345 
346 int
347 bridge_set_hello_time(struct bridge_if *bif, int32_t hello_time)
348 {
349 	struct ifdrv ifd;
350 	struct ifbrparam b_param;
351 
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;
357 
358 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
359 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) "
360 		    "failed: %s", strerror(errno));
361 		return (-1);
362 	}
363 
364 	bif->bridge_hello_time = b_param.ifbrp_hellotime;
365 	return (0);
366 }
367 
368 int
369 bridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay)
370 {
371 	struct ifdrv ifd;
372 	struct ifbrparam b_param;
373 
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;
379 
380 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
381 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) "
382 		    "failed: %s", strerror(errno));
383 		return (-1);
384 	}
385 
386 	bif->bridge_fwd_delay = b_param.ifbrp_fwddelay;
387 	return (0);
388 }
389 
390 int
391 bridge_set_aging_time(struct bridge_if *bif, int32_t age_time)
392 {
393 	struct ifdrv ifd;
394 	struct ifbrparam b_param;
395 
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;
401 
402 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
403 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) "
404 		    "failed: %s", strerror(errno));
405 		return (-1);
406 	}
407 
408 	bif->age_time = age_time;
409 	return (0);
410 }
411 
412 int
413 bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache)
414 {
415 	struct ifdrv ifd;
416 	struct ifbrparam b_param;
417 
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;
423 
424 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
425 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) "
426 		    "failed: %s", strerror(errno));
427 		return (-1);
428 	}
429 
430 	bif->max_addrs = b_param.ifbrp_csize;
431 	return (0);
432 }
433 
434 int
435 bridge_set_tx_hold_count(struct bridge_if *bif, int32_t tx_hc)
436 {
437 	struct ifdrv ifd;
438 	struct ifbrparam b_param;
439 
440 	if (tx_hc < SNMP_BRIDGE_MIN_TXHC || tx_hc > SNMP_BRIDGE_MAX_TXHC)
441 		return (-1);
442 
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;
448 
449 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
450 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTXHC) "
451 		    "failed: %s", strerror(errno));
452 		return (-1);
453 	}
454 
455 	bif->tx_hold_count = b_param.ifbrp_txhc;
456 	return (0);
457 }
458 
459 int
460 bridge_set_stp_version(struct bridge_if *bif, int32_t stp_proto)
461 {
462 	struct ifdrv ifd;
463 	struct ifbrparam b_param;
464 
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;
470 
471 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
472 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPROTO) "
473 		    "failed: %s", strerror(errno));
474 		return (-1);
475 	}
476 
477 	bif->stp_version = b_param.ifbrp_proto;
478 	return (0);
479 }
480 
481 /*
482  * Set the bridge interface status to up/down.
483  */
484 int
485 bridge_set_if_up(const char* b_name, int8_t up)
486 {
487 	int	flags;
488 	struct ifreq ifr;
489 
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));
495 		return (-1);
496 	}
497 
498 	flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
499 	if (up == 1)
500 		flags |= IFF_UP;
501 	else
502 		flags &= ~IFF_UP;
503 
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));
509 		return (-1);
510 	}
511 
512 	return (0);
513 }
514 
515 int
516 bridge_create(const char *b_name)
517 {
518 	char *new_name;
519 	struct ifreq ifr;
520 
521 	bzero(&ifr, sizeof(ifr));
522 	strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
523 
524 	if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) {
525 		syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) "
526 		    "failed: %s", strerror(errno));
527 		return (-1);
528 	}
529 
530 	if (strcmp(b_name, ifr.ifr_name) == 0)
531 		return (0);
532 
533 	if ((new_name = strdup(b_name)) == NULL) {
534 		syslog(LOG_ERR, "create bridge: strdup() failed");
535 		return (-1);
536 	}
537 
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));
542 		free(new_name);
543 		return (-1);
544 	}
545 
546 	return (0);
547 }
548 
549 int
550 bridge_destroy(const char *b_name)
551 {
552 	struct ifreq ifr;
553 
554 	bzero(&ifr, sizeof(ifr));
555 	strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_name));
556 
557 	if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) {
558 		syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) "
559 		    "failed: %s", strerror(errno));
560 		return (-1);
561 	}
562 
563 	return (0);
564 }
565 
566 /*
567  * Fetch the bridge base MAC address. Return pointer to the
568  * buffer containing the MAC address, NULL on failure.
569  */
570 u_char *
571 bridge_get_basemac(const char *bif_name, u_char *mac, size_t mlen)
572 {
573 	int len;
574 	char if_name[IFNAMSIZ];
575 	struct ifaddrs *ifap, *ifa;
576 	struct sockaddr_dl sdl;
577 
578 	if (getifaddrs(&ifap) != 0) {
579 		syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s",
580 		    strerror(errno));
581 		return (NULL);
582 	}
583 
584 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
585 		if (ifa->ifa_addr->sa_family != AF_LINK)
586 			continue;
587 
588 		/*
589 		 * Not just casting because of alignment constraints
590 		 * on sparc64.
591 		 */
592 		bcopy(ifa->ifa_addr, &sdl, sizeof(struct sockaddr_dl));
593 
594 		if (sdl.sdl_alen > mlen)
595 			continue;
596 
597 		if ((len = sdl.sdl_nlen) >= IFNAMSIZ)
598 			len = IFNAMSIZ - 1;
599 
600 		bcopy(sdl.sdl_data, if_name, len);
601 		if_name[len] = '\0';
602 
603 		if (strcmp(bif_name, if_name) == 0) {
604 			bcopy(sdl.sdl_data + sdl.sdl_nlen, mac, sdl.sdl_alen);
605 			freeifaddrs(ifap);
606 			return (mac);
607 		}
608 	}
609 
610 	freeifaddrs(ifap);
611 	return (NULL);
612 }
613 
614 /************************************************************************
615  * Bridge ports.
616  */
617 
618 /*
619  * Convert the kernel STP port state into
620  * the corresopnding enumerated type from SNMP Bridge MIB.
621  */
622 static int
623 state2snmp_st(uint8_t ifbr_state)
624 {
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);
637 	}
638 
639 	return (StpPortState_broken);
640 }
641 
642 /*
643  * Fill in a bridge member information according to data polled from kernel.
644  */
645 static void
646 bridge_port_getinfo_conf(struct ifbreq *k_info, struct bridge_port *bp)
647 {
648 	bp->state = state2snmp_st(k_info->ifbr_state);
649 	bp->priority = k_info->ifbr_priority;
650 
651 	/*
652 	 * RFC 4188:
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."
659 	 */
660 
661 	if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMCOST)
662 		bp->admin_path_cost = k_info->ifbr_path_cost;
663 	else
664 		bp->admin_path_cost = 0;
665 
666 	bp->path_cost = k_info->ifbr_path_cost;
667 
668 	if (k_info->ifbr_ifsflags & IFBIF_STP)
669 		bp->enable = dot1dStpPortEnable_enabled;
670 	else
671 		bp->enable = dot1dStpPortEnable_disabled;
672 
673 	/* Begemot Bridge MIB only. */
674 	if (k_info->ifbr_ifsflags & IFBIF_SPAN)
675 		bp->span_enable = begemotBridgeBaseSpanEnabled_enabled;
676 	else
677 		bp->span_enable = begemotBridgeBaseSpanEnabled_disabled;
678 
679 	if (k_info->ifbr_ifsflags & IFBIF_PRIVATE)
680 		bp->priv_set = TruthValue_true;
681 	else
682 		bp->priv_set = TruthValue_false;
683 
684 	if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMEDGE)
685 		bp->admin_edge = TruthValue_true;
686 	else
687 		bp->admin_edge = TruthValue_false;
688 
689 	if (k_info->ifbr_ifsflags & IFBIF_BSTP_EDGE)
690 		bp->oper_edge = TruthValue_true;
691 	else
692 		bp->oper_edge = TruthValue_false;
693 
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;
698 		else
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;
703 	} else {
704 		bp->admin_ptp = StpPortAdminPointToPointType_forceFalse;
705 		bp->oper_ptp = TruthValue_false;
706 	}
707 }
708 
709 /*
710  * Fill in a bridge interface STP information according to
711  * data polled from kernel.
712  */
713 static void
714 bridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp)
715 {
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),
722 	    sizeof(uint16_t));
723 }
724 
725 /*
726  * Clear a bridge interface STP information.
727  */
728 static void
729 bridge_port_clearinfo_opstp(struct bridge_port *bp)
730 {
731 	if (bp->enable == dot1dStpPortEnable_enabled) {
732 		bp->design_cost = 0;
733 		bzero(&(bp->design_root), sizeof(bridge_id));
734 		bzero(&(bp->design_bridge), sizeof(bridge_id));
735 		bzero(&(bp->design_port), sizeof(port_id));
736 		bp->fwd_trans = 0;
737 	}
738 
739 	bp->enable = dot1dStpPortEnable_disabled;
740 }
741 
742 /*
743  * Set a bridge member priority.
744  */
745 int
746 bridge_port_set_priority(const char *bif_name, struct bridge_port *bp,
747 	int32_t priority)
748 {
749 	struct ifdrv ifd;
750 	struct ifbreq b_req;
751 
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));
756 
757 	b_req.ifbr_priority = (uint8_t) priority;
758 	ifd.ifd_cmd = BRDGSIFPRIO;
759 
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));
763 		return (-1);
764 	}
765 
766 	bp->priority = priority;
767 	return (0);
768 }
769 
770 /*
771  * Set a bridge member STP-enabled flag.
772  */
773 int
774 bridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp,
775 	uint32_t enable)
776 {
777 	struct ifdrv ifd;
778 	struct ifbreq b_req;
779 
780 	if (bp->enable == enable)
781 		return (0);
782 
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;
789 
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));
793 		return (-1);
794 	}
795 
796 	if (enable == dot1dStpPortEnable_enabled)
797 		b_req.ifbr_ifsflags |= IFBIF_STP;
798 	else
799 		b_req.ifbr_ifsflags &= ~IFBIF_STP;
800 
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));
805 		return (-1);
806 	}
807 
808 	bp->enable = enable;
809 	return (0);
810 }
811 
812 /*
813  * Set a bridge member STP path cost.
814  */
815 int
816 bridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp,
817 	int32_t path_cost)
818 {
819 	struct ifdrv ifd;
820 	struct ifbreq b_req;
821 
822 	if (path_cost < SNMP_PORT_MIN_PATHCOST ||
823 	    path_cost > SNMP_PORT_PATHCOST_OBSOLETE)
824 		return (-2);
825 
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));
830 
831 	b_req.ifbr_path_cost = path_cost;
832 	ifd.ifd_cmd = BRDGSIFCOST;
833 
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));
837 		return (-1);
838 	}
839 
840 	bp->admin_path_cost = path_cost;
841 
842 	return (0);
843 }
844 
845 /*
846  * Set the PonitToPoint status of the link administratively.
847  */
848 int
849 bridge_port_set_admin_ptp(const char *bif_name, struct bridge_port *bp,
850     uint32_t admin_ptp)
851 {
852 	struct ifdrv ifd;
853 	struct ifbreq b_req;
854 
855 	if (bp->admin_ptp == admin_ptp)
856 		return (0);
857 
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;
864 
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));
868 		return (-1);
869 	}
870 
871 	switch (admin_ptp) {
872 		case StpPortAdminPointToPointType_forceTrue:
873 			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
874 			b_req.ifbr_ifsflags |= IFBIF_BSTP_PTP;
875 			break;
876 		case StpPortAdminPointToPointType_forceFalse:
877 			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
878 			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_PTP;
879 			break;
880 		case StpPortAdminPointToPointType_auto:
881 			b_req.ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
882 			break;
883 	}
884 
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));
889 		return (-1);
890 	}
891 
892 	bp->admin_ptp = admin_ptp;
893 	return (0);
894 }
895 
896 /*
897  * Set admin edge.
898  */
899 int
900 bridge_port_set_admin_edge(const char *bif_name, struct bridge_port *bp,
901     uint32_t enable)
902 {
903 	struct ifdrv ifd;
904 	struct ifbreq b_req;
905 
906 	if (bp->admin_edge == enable)
907 		return (0);
908 
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;
915 
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));
919 		return (-1);
920 	}
921 
922 	if (enable == TruthValue_true) {
923 		b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOEDGE;
924 		b_req.ifbr_ifsflags |= IFBIF_BSTP_EDGE;
925 	} else
926 		b_req.ifbr_ifsflags &= ~IFBIF_BSTP_EDGE;
927 
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));
932 		return (-1);
933 	}
934 
935 	bp->admin_edge = enable;
936 
937 	return (0);
938 }
939 
940 /*
941  * Set 'private' flag.
942  */
943 int
944 bridge_port_set_private(const char *bif_name, struct bridge_port *bp,
945     uint32_t priv_set)
946 {
947 	struct ifdrv ifd;
948 	struct ifbreq b_req;
949 
950 	if (bp->priv_set == priv_set)
951 		return (0);
952 
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;
959 
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));
963 		return (-1);
964 	}
965 
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;
970 	else
971 		return (SNMP_ERR_WRONG_VALUE);
972 
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));
977 		return (-1);
978 	}
979 
980 	bp->priv_set = priv_set;
981 
982 	return (0);
983 }
984 
985 
986 /*
987  * Add a bridge member port.
988  */
989 int
990 bridge_port_addm(struct bridge_port *bp, const char *b_name)
991 {
992 	struct ifdrv ifd;
993 	struct ifbreq b_req;
994 
995 	bzero(&ifd, sizeof(ifd));
996 	bzero(&b_req, sizeof(b_req));
997 
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));
1002 
1003 	if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1004 		ifd.ifd_cmd = BRDGADDS;
1005 	else
1006 		ifd.ifd_cmd = BRDGADD;
1007 
1008 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1009 		syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1010 		    bp->p_name,
1011 		    (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"),
1012 		    strerror(errno));
1013 		return (-1);
1014 	}
1015 
1016 	return (0);
1017 }
1018 
1019 /*
1020  * Delete a bridge member port.
1021  */
1022 int
1023 bridge_port_delm(struct bridge_port *bp, const char *b_name)
1024 {
1025 	struct ifdrv ifd;
1026 	struct ifbreq b_req;
1027 
1028 	bzero(&ifd, sizeof(ifd));
1029 	bzero(&b_req, sizeof(b_req));
1030 
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));
1035 
1036 	if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1037 		ifd.ifd_cmd = BRDGDELS;
1038 	else
1039 		ifd.ifd_cmd = BRDGDEL;
1040 
1041 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1042 		syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1043 		    bp->p_name,
1044 		    (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"),
1045 		    strerror(errno));
1046 		return (-1);
1047 	}
1048 
1049 	return (0);
1050 }
1051 
1052 /*
1053  * Fetch the bridge member list from kernel.
1054  * Return -1 on error, or buffer len if successful.
1055  */
1056 static int32_t
1057 bridge_port_get_iflist(struct bridge_if *bif, struct ifbreq **buf)
1058 {
1059 	int n = 128;
1060 	uint32_t len;
1061 	struct ifbreq *ninbuf;
1062 	struct ifbifconf ifbc;
1063 	struct ifdrv ifd;
1064 
1065 	*buf = NULL;
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;
1070 
1071 	for ( ; ; ) {
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));
1076 			free(*buf);
1077 			*buf = NULL;
1078 			return (-1);
1079 		}
1080 
1081 		ifbc.ifbic_len = len;
1082 		ifbc.ifbic_req = *buf = ninbuf;
1083 
1084 		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1085 			syslog(LOG_ERR, "get bridge member list: ioctl "
1086 			    "(BRDGGIFS) failed: %s", strerror(errno));
1087 			free(*buf);
1088 			buf = NULL;
1089 			return (-1);
1090 		}
1091 
1092 		if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len)
1093 			break;
1094 
1095 		n += 64;
1096 	}
1097 
1098 	return (ifbc.ifbic_len);
1099 }
1100 
1101 /*
1102  * Fetch the bridge STP member list from kernel.
1103  * Return -1 on error, or buffer len if successful.
1104  */
1105 static int32_t
1106 bridge_port_get_ifstplist(struct bridge_if *bif, struct ifbpstpreq **buf)
1107 {
1108 	int n = 128;
1109 	uint32_t len;
1110 	struct ifbpstpreq *ninbuf;
1111 	struct ifbpstpconf ifbstp;
1112 	struct ifdrv ifd;
1113 
1114 	*buf = NULL;
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;
1119 
1120 	for ( ; ; ) {
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));
1126 			free(*buf);
1127 			*buf = NULL;
1128 			return (-1);
1129 		}
1130 
1131 		ifbstp.ifbpstp_len = len;
1132 		ifbstp.ifbpstp_req = *buf = ninbuf;
1133 
1134 		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1135 			syslog(LOG_ERR, "get bridge STP ports list: ioctl "
1136 			    "(BRDGGIFSSTP) failed: %s", strerror(errno));
1137 			free(*buf);
1138 			buf = NULL;
1139 			return (-1);
1140 		}
1141 
1142 		if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len)
1143 			break;
1144 
1145 		n += 64;
1146 	}
1147 
1148 	return (ifbstp.ifbpstp_len);
1149 }
1150 
1151 /*
1152  * Locate a bridge if STP params structure in a buffer.
1153  */
1154 static struct ifbpstpreq *
1155 bridge_port_find_ifstplist(uint8_t port_no, struct ifbpstpreq *buf,
1156     uint32_t buf_len)
1157 {
1158 	uint32_t i;
1159 	struct ifbpstpreq *bstp;
1160 
1161 	for (i = 0; i < buf_len / sizeof(struct ifbpstpreq); i++) {
1162 		bstp = buf + i;
1163 		if (bstp->ifbp_portno == port_no)
1164 			return (bstp);
1165 	}
1166 
1167 	return (NULL);
1168 }
1169 
1170 /*
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.
1174  */
1175 int
1176 bridge_getinfo_bif_ports(struct bridge_if *bif)
1177 {
1178 	uint32_t i;
1179 	int32_t buf_len;
1180 	struct ifbreq *b_req_buf, *b_req;
1181 	struct ifbpstpreq *bs_req_buf, *bs_req;
1182 	struct bridge_port *bp;
1183 	struct mibif *m_if;
1184 
1185 	if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1186 		return (-1);
1187 
1188 	for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1189 		b_req = b_req_buf + i;
1190 
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);
1197 			}
1198 		} else {
1199 			syslog(LOG_ERR, "bridge member %s not present "
1200 			    "in mibII ifTable", b_req->ifbr_ifsname);
1201 		}
1202 	}
1203 	free(b_req_buf);
1204 
1205 	if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1206 		return (-1);
1207 
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);
1213 		else
1214 			bridge_port_getinfo_opstp(bs_req, bp);
1215 	}
1216 	free(bs_req_buf);
1217 
1218 	return (i);
1219 }
1220 
1221 /*
1222  * Update the information for the bridge interface members.
1223  */
1224 int
1225 bridge_update_memif(struct bridge_if *bif)
1226 {
1227 	int added, updated;
1228 	uint32_t i;
1229 	int32_t buf_len;
1230 	struct ifbreq *b_req_buf, *b_req;
1231 	struct ifbpstpreq *bs_req_buf, *bs_req;
1232 	struct bridge_port *bp, *bp_next;
1233 	struct mibif *m_if;
1234 
1235 	if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1236 		return (-1);
1237 
1238 	added = updated = 0;
1239 
1240 #define	BP_FOUND	0x01
1241 	for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1242 		b_req = b_req_buf + i;
1243 
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);
1247 			continue;
1248 		}
1249 
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;
1253 			added++;
1254 		}
1255 
1256 		if (bp != NULL) {
1257 			updated++;
1258 			bridge_port_getinfo_conf(b_req, bp);
1259 			bridge_port_getinfo_mibif(m_if, bp);
1260 			bp->flags |= BP_FOUND;
1261 		}
1262 	}
1263 	free(b_req_buf);
1264 
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);
1268 
1269 		if ((bp->flags & BP_FOUND) == 0 &&
1270 		    bp->status == RowStatus_active)
1271 			bridge_port_remove(bp, bif);
1272 		else
1273 			bp->flags |= ~BP_FOUND;
1274 	}
1275 #undef	BP_FOUND
1276 
1277 	if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1278 		return (-1);
1279 
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);
1285 		else
1286 			bridge_port_getinfo_opstp(bs_req, bp);
1287 	}
1288 	free(bs_req_buf);
1289 	bif->ports_age = time(NULL);
1290 
1291 	return (updated);
1292 }
1293 
1294 /************************************************************************
1295  * Bridge addresses.
1296  */
1297 
1298 /*
1299  * Update the bridge address info according to the polled data.
1300  */
1301 static void
1302 bridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe)
1303 {
1304 	tpe->port_no = if_nametoindex(ifba->ifba_ifsname);
1305 
1306 	if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
1307 		tpe->status = TpFdbStatus_mgmt;
1308 	else
1309 		tpe->status = TpFdbStatus_learned;
1310 }
1311 
1312 /*
1313  * Read the bridge addresses from kernel.
1314  * Return -1 on error, or buffer len if successful.
1315  */
1316 static int32_t
1317 bridge_addrs_getinfo_ifalist(struct bridge_if *bif, struct ifbareq **buf)
1318 {
1319 	int n = 128;
1320 	uint32_t len;
1321 	struct ifbareq *ninbuf;
1322 	struct ifbaconf bac;
1323 	struct ifdrv ifd;
1324 
1325 	*buf = NULL;
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;
1330 
1331 	for ( ; ; ) {
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));
1336 			free(*buf);
1337 			*buf = NULL;
1338 			return (-1);
1339 		}
1340 
1341 		bac.ifbac_len = len;
1342 		bac.ifbac_req = *buf = ninbuf;
1343 
1344 		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1345 			syslog(LOG_ERR, "get bridge address list: "
1346 			    "ioctl(BRDGRTS) failed: %s", strerror(errno));
1347 			free(*buf);
1348 			buf = NULL;
1349 			return (-1);
1350 		}
1351 
1352 		if ((bac.ifbac_len + sizeof(struct ifbareq)) < len)
1353 			break;
1354 
1355 		n += 64;
1356 	}
1357 
1358 	return (bac.ifbac_len);
1359 }
1360 
1361 /*
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.
1365  */
1366 int
1367 bridge_getinfo_bif_addrs(struct bridge_if *bif)
1368 {
1369 	uint32_t i;
1370 	int32_t buf_len;
1371 	struct ifbareq *addr_req_buf, *addr_req;
1372 	struct tp_entry *te;
1373 
1374 	if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1375 		return (-1);
1376 
1377 	for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1378 		addr_req = addr_req_buf + i;
1379 
1380 		if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
1381 			bridge_addrs_info_ifaddrlist(addr_req, te);
1382 	}
1383 
1384 	free(addr_req_buf);
1385 	return (i);
1386 }
1387 
1388 /*
1389  * Update the addresses for the bridge interface.
1390  */
1391 int
1392 bridge_update_addrs(struct bridge_if *bif)
1393 {
1394 	int added, updated;
1395 	uint32_t i;
1396 	int32_t buf_len;
1397 	struct tp_entry *te, *te_next;
1398 	struct ifbareq *addr_req_buf, *addr_req;
1399 
1400 	if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1401 		return (-1);
1402 
1403 	added = updated = 0;
1404 
1405 #define	BA_FOUND	0x01
1406 	for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1407 		addr_req = addr_req_buf + i;
1408 
1409 		if ((te = bridge_addrs_find(addr_req->ifba_dst, bif)) == NULL) {
1410 			added++;
1411 
1412 			if ((te = bridge_new_addrs(addr_req->ifba_dst, bif))
1413 			    == NULL)
1414 				continue;
1415 		} else
1416 			updated++;
1417 
1418 		bridge_addrs_info_ifaddrlist(addr_req, te);
1419 		te-> flags |= BA_FOUND;
1420 	}
1421 	free(addr_req_buf);
1422 
1423 	for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) {
1424 		te_next = bridge_addrs_bif_next(te);
1425 
1426 		if ((te-> flags & BA_FOUND) == 0)
1427 			bridge_addrs_remove(te, bif);
1428 		else
1429 			te-> flags &= ~BA_FOUND;
1430 	}
1431 #undef	BA_FOUND
1432 
1433 	bif->addrs_age = time(NULL);
1434 	return (updated + added);
1435 }
1436 
1437 /************************************************************************
1438  * Bridge packet filtering.
1439  */
1440 const char bridge_sysctl[] = "net.link.bridge.";
1441 
1442 static struct {
1443 	int32_t val;
1444 	const char *name;
1445 } bridge_pf_sysctl[] = {
1446 	{ 1, "pfil_bridge" },
1447 	{ 1, "pfil_member" },
1448 	{ 1, "pfil_onlyip" },
1449 	{ 0, "ipfw" },
1450 };
1451 
1452 int32_t
1453 bridge_get_pfval(uint8_t which)
1454 {
1455 
1456 	if (which > nitems(bridge_pf_sysctl) || which < 1)
1457 		return (-1);
1458 
1459 	return (bridge_pf_sysctl[which - 1].val);
1460 }
1461 
1462 int32_t
1463 bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val)
1464 {
1465 	char *mib_oid;
1466 	size_t len, s_len;
1467 	int32_t i, s_i;
1468 
1469 	if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus)
1470 		return (-2);
1471 
1472 	if (op == SNMP_OP_SET) {
1473 		s_i = *val;
1474 		s_len = sizeof(s_i);
1475 	} else
1476 		s_len = 0;
1477 
1478 	len = sizeof(i);
1479 
1480 	asprintf(&mib_oid, "%s%s", bridge_sysctl,
1481 	    bridge_pf_sysctl[bridge_ctl].name);
1482 	if (mib_oid == NULL)
1483 		return (-1);
1484 
1485 	if (sysctlbyname(mib_oid, &i, &len, (op == SNMP_OP_SET ? &s_i : NULL),
1486 	    s_len) == -1) {
1487 		syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_oid,
1488 		    strerror(errno));
1489 		free(mib_oid);
1490 		return (-1);
1491 	}
1492 
1493 	bridge_pf_sysctl[bridge_ctl].val = i;
1494 	*val = i;
1495 
1496 	free(mib_oid);
1497 
1498 	return (i);
1499 }
1500 
1501 void
1502 bridge_pf_dump(void)
1503 {
1504 	uint8_t i;
1505 
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);
1509 	}
1510 }
1511