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 		 */
591 		bcopy(ifa->ifa_addr, &sdl, sizeof(struct sockaddr_dl));
592 
593 		if (sdl.sdl_alen > mlen)
594 			continue;
595 
596 		if ((len = sdl.sdl_nlen) >= IFNAMSIZ)
597 			len = IFNAMSIZ - 1;
598 
599 		bcopy(sdl.sdl_data, if_name, len);
600 		if_name[len] = '\0';
601 
602 		if (strcmp(bif_name, if_name) == 0) {
603 			bcopy(sdl.sdl_data + sdl.sdl_nlen, mac, sdl.sdl_alen);
604 			freeifaddrs(ifap);
605 			return (mac);
606 		}
607 	}
608 
609 	freeifaddrs(ifap);
610 	return (NULL);
611 }
612 
613 /************************************************************************
614  * Bridge ports.
615  */
616 
617 /*
618  * Convert the kernel STP port state into
619  * the corresopnding enumerated type from SNMP Bridge MIB.
620  */
621 static int
622 state2snmp_st(uint8_t ifbr_state)
623 {
624 	switch (ifbr_state) {
625 		case BSTP_IFSTATE_DISABLED:
626 			return (StpPortState_disabled);
627 		case BSTP_IFSTATE_LISTENING:
628 			return (StpPortState_listening);
629 		case BSTP_IFSTATE_LEARNING:
630 			return (StpPortState_learning);
631 		case BSTP_IFSTATE_FORWARDING:
632 			return (StpPortState_forwarding);
633 		case BSTP_IFSTATE_BLOCKING:
634 		case BSTP_IFSTATE_DISCARDING:
635 			return (StpPortState_blocking);
636 	}
637 
638 	return (StpPortState_broken);
639 }
640 
641 /*
642  * Fill in a bridge member information according to data polled from kernel.
643  */
644 static void
645 bridge_port_getinfo_conf(struct ifbreq *k_info, struct bridge_port *bp)
646 {
647 	bp->state = state2snmp_st(k_info->ifbr_state);
648 	bp->priority = k_info->ifbr_priority;
649 
650 	/*
651 	 * RFC 4188:
652 	 * "New implementations should support dot1dStpPortPathCost32.
653 	 * If the port path costs exceeds the maximum value of this
654 	 * object then this object should report the maximum value,
655 	 * namely 65535.  Applications should try to read the
656 	 * dot1dStpPortPathCost32 object if this object reports
657 	 * the maximum value."
658 	 */
659 
660 	if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMCOST)
661 		bp->admin_path_cost = k_info->ifbr_path_cost;
662 	else
663 		bp->admin_path_cost = 0;
664 
665 	bp->path_cost = k_info->ifbr_path_cost;
666 
667 	if (k_info->ifbr_ifsflags & IFBIF_STP)
668 		bp->enable = dot1dStpPortEnable_enabled;
669 	else
670 		bp->enable = dot1dStpPortEnable_disabled;
671 
672 	/* Begemot Bridge MIB only. */
673 	if (k_info->ifbr_ifsflags & IFBIF_SPAN)
674 		bp->span_enable = begemotBridgeBaseSpanEnabled_enabled;
675 	else
676 		bp->span_enable = begemotBridgeBaseSpanEnabled_disabled;
677 
678 	if (k_info->ifbr_ifsflags & IFBIF_PRIVATE)
679 		bp->priv_set = TruthValue_true;
680 	else
681 		bp->priv_set = TruthValue_false;
682 
683 	if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMEDGE)
684 		bp->admin_edge = TruthValue_true;
685 	else
686 		bp->admin_edge = TruthValue_false;
687 
688 	if (k_info->ifbr_ifsflags & IFBIF_BSTP_EDGE)
689 		bp->oper_edge = TruthValue_true;
690 	else
691 		bp->oper_edge = TruthValue_false;
692 
693 	if (k_info->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP) {
694 		bp->admin_ptp = StpPortAdminPointToPointType_auto;
695 		if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP)
696 			bp->oper_ptp = TruthValue_true;
697 		else
698 			bp->oper_ptp = TruthValue_false;
699 	} else if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP) {
700 		bp->admin_ptp = StpPortAdminPointToPointType_forceTrue;
701 		bp->oper_ptp = TruthValue_true;
702 	} else {
703 		bp->admin_ptp = StpPortAdminPointToPointType_forceFalse;
704 		bp->oper_ptp = TruthValue_false;
705 	}
706 }
707 
708 /*
709  * Fill in a bridge interface STP information according to
710  * data polled from kernel.
711  */
712 static void
713 bridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp)
714 {
715 	bp->enable = dot1dStpPortEnable_enabled;
716 	bp->fwd_trans = bp_stp->ifbp_fwd_trans;
717 	bp->design_cost = bp_stp->ifbp_design_cost;
718 	snmp_uint64_to_bridgeid(bp_stp->ifbp_design_root, bp->design_root);
719 	snmp_uint64_to_bridgeid(bp_stp->ifbp_design_bridge, bp->design_bridge);
720 	bcopy(&(bp_stp->ifbp_design_port), &(bp->design_port),
721 	    sizeof(uint16_t));
722 }
723 
724 /*
725  * Clear a bridge interface STP information.
726  */
727 static void
728 bridge_port_clearinfo_opstp(struct bridge_port *bp)
729 {
730 	if (bp->enable == dot1dStpPortEnable_enabled) {
731 		bp->design_cost = 0;
732 		bzero(&(bp->design_root), sizeof(bridge_id));
733 		bzero(&(bp->design_bridge), sizeof(bridge_id));
734 		bzero(&(bp->design_port), sizeof(port_id));
735 		bp->fwd_trans = 0;
736 	}
737 
738 	bp->enable = dot1dStpPortEnable_disabled;
739 }
740 
741 /*
742  * Set a bridge member priority.
743  */
744 int
745 bridge_port_set_priority(const char *bif_name, struct bridge_port *bp,
746 	int32_t priority)
747 {
748 	struct ifdrv ifd;
749 	struct ifbreq b_req;
750 
751 	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
752 	ifd.ifd_len = sizeof(b_req);
753 	ifd.ifd_data = &b_req;
754 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
755 
756 	b_req.ifbr_priority = (uint8_t) priority;
757 	ifd.ifd_cmd = BRDGSIFPRIO;
758 
759 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
760 		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFPRIO) "
761 		    "failed: %s", bp->p_name, strerror(errno));
762 		return (-1);
763 	}
764 
765 	bp->priority = priority;
766 	return (0);
767 }
768 
769 /*
770  * Set a bridge member STP-enabled flag.
771  */
772 int
773 bridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp,
774 	uint32_t enable)
775 {
776 	struct ifdrv ifd;
777 	struct ifbreq b_req;
778 
779 	if (bp->enable == enable)
780 		return (0);
781 
782 	bzero(&b_req, sizeof(b_req));
783 	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
784 	ifd.ifd_len = sizeof(b_req);
785 	ifd.ifd_data = &b_req;
786 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
787 	ifd.ifd_cmd = BRDGGIFFLGS;
788 
789 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
790 		syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
791 		    "failed: %s", bp->p_name, strerror(errno));
792 		return (-1);
793 	}
794 
795 	if (enable == dot1dStpPortEnable_enabled)
796 		b_req.ifbr_ifsflags |= IFBIF_STP;
797 	else
798 		b_req.ifbr_ifsflags &= ~IFBIF_STP;
799 
800 	ifd.ifd_cmd = BRDGSIFFLGS;
801 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
802 		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
803 		    "failed: %s", bp->p_name, strerror(errno));
804 		return (-1);
805 	}
806 
807 	bp->enable = enable;
808 	return (0);
809 }
810 
811 /*
812  * Set a bridge member STP path cost.
813  */
814 int
815 bridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp,
816 	int32_t path_cost)
817 {
818 	struct ifdrv ifd;
819 	struct ifbreq b_req;
820 
821 	if (path_cost < SNMP_PORT_MIN_PATHCOST ||
822 	    path_cost > SNMP_PORT_PATHCOST_OBSOLETE)
823 		return (-2);
824 
825 	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
826 	ifd.ifd_len = sizeof(b_req);
827 	ifd.ifd_data = &b_req;
828 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
829 
830 	b_req.ifbr_path_cost = path_cost;
831 	ifd.ifd_cmd = BRDGSIFCOST;
832 
833 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
834 		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFCOST) "
835 		    "failed: %s", bp->p_name, strerror(errno));
836 		return (-1);
837 	}
838 
839 	bp->admin_path_cost = path_cost;
840 
841 	return (0);
842 }
843 
844 /*
845  * Set the PonitToPoint status of the link administratively.
846  */
847 int
848 bridge_port_set_admin_ptp(const char *bif_name, struct bridge_port *bp,
849     uint32_t admin_ptp)
850 {
851 	struct ifdrv ifd;
852 	struct ifbreq b_req;
853 
854 	if (bp->admin_ptp == admin_ptp)
855 		return (0);
856 
857 	bzero(&b_req, sizeof(b_req));
858 	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
859 	ifd.ifd_len = sizeof(b_req);
860 	ifd.ifd_data = &b_req;
861 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
862 	ifd.ifd_cmd = BRDGGIFFLGS;
863 
864 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
865 		syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
866 		    "failed: %s", bp->p_name, strerror(errno));
867 		return (-1);
868 	}
869 
870 	switch (admin_ptp) {
871 		case StpPortAdminPointToPointType_forceTrue:
872 			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
873 			b_req.ifbr_ifsflags |= IFBIF_BSTP_PTP;
874 			break;
875 		case StpPortAdminPointToPointType_forceFalse:
876 			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
877 			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_PTP;
878 			break;
879 		case StpPortAdminPointToPointType_auto:
880 			b_req.ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
881 			break;
882 	}
883 
884 	ifd.ifd_cmd = BRDGSIFFLGS;
885 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
886 		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
887 		    "failed: %s", bp->p_name, strerror(errno));
888 		return (-1);
889 	}
890 
891 	bp->admin_ptp = admin_ptp;
892 	return (0);
893 }
894 
895 /*
896  * Set admin edge.
897  */
898 int
899 bridge_port_set_admin_edge(const char *bif_name, struct bridge_port *bp,
900     uint32_t enable)
901 {
902 	struct ifdrv ifd;
903 	struct ifbreq b_req;
904 
905 	if (bp->admin_edge == enable)
906 		return (0);
907 
908 	bzero(&b_req, sizeof(b_req));
909 	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
910 	ifd.ifd_len = sizeof(b_req);
911 	ifd.ifd_data = &b_req;
912 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
913 	ifd.ifd_cmd = BRDGGIFFLGS;
914 
915 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
916 		syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
917 		    "failed: %s", bp->p_name, strerror(errno));
918 		return (-1);
919 	}
920 
921 	if (enable == TruthValue_true) {
922 		b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOEDGE;
923 		b_req.ifbr_ifsflags |= IFBIF_BSTP_EDGE;
924 	} else
925 		b_req.ifbr_ifsflags &= ~IFBIF_BSTP_EDGE;
926 
927 	ifd.ifd_cmd = BRDGSIFFLGS;
928 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
929 		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
930 		    "failed: %s", bp->p_name, strerror(errno));
931 		return (-1);
932 	}
933 
934 	bp->admin_edge = enable;
935 
936 	return (0);
937 }
938 
939 /*
940  * Set 'private' flag.
941  */
942 int
943 bridge_port_set_private(const char *bif_name, struct bridge_port *bp,
944     uint32_t priv_set)
945 {
946 	struct ifdrv ifd;
947 	struct ifbreq b_req;
948 
949 	if (bp->priv_set == priv_set)
950 		return (0);
951 
952 	bzero(&b_req, sizeof(b_req));
953 	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
954 	ifd.ifd_len = sizeof(b_req);
955 	ifd.ifd_data = &b_req;
956 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
957 	ifd.ifd_cmd = BRDGGIFFLGS;
958 
959 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
960 		syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
961 		    "failed: %s", bp->p_name, strerror(errno));
962 		return (-1);
963 	}
964 
965 	if (priv_set == TruthValue_true)
966 		b_req.ifbr_ifsflags |= IFBIF_PRIVATE;
967 	else if (priv_set == TruthValue_false)
968 		b_req.ifbr_ifsflags &= ~IFBIF_PRIVATE;
969 	else
970 		return (SNMP_ERR_WRONG_VALUE);
971 
972 	ifd.ifd_cmd = BRDGSIFFLGS;
973 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
974 		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
975 		    "failed: %s", bp->p_name, strerror(errno));
976 		return (-1);
977 	}
978 
979 	bp->priv_set = priv_set;
980 
981 	return (0);
982 }
983 
984 
985 /*
986  * Add a bridge member port.
987  */
988 int
989 bridge_port_addm(struct bridge_port *bp, const char *b_name)
990 {
991 	struct ifdrv ifd;
992 	struct ifbreq b_req;
993 
994 	bzero(&ifd, sizeof(ifd));
995 	bzero(&b_req, sizeof(b_req));
996 
997 	strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
998 	ifd.ifd_len = sizeof(b_req);
999 	ifd.ifd_data = &b_req;
1000 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
1001 
1002 	if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1003 		ifd.ifd_cmd = BRDGADDS;
1004 	else
1005 		ifd.ifd_cmd = BRDGADD;
1006 
1007 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1008 		syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1009 		    bp->p_name,
1010 		    (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"),
1011 		    strerror(errno));
1012 		return (-1);
1013 	}
1014 
1015 	return (0);
1016 }
1017 
1018 /*
1019  * Delete a bridge member port.
1020  */
1021 int
1022 bridge_port_delm(struct bridge_port *bp, const char *b_name)
1023 {
1024 	struct ifdrv ifd;
1025 	struct ifbreq b_req;
1026 
1027 	bzero(&ifd, sizeof(ifd));
1028 	bzero(&b_req, sizeof(b_req));
1029 
1030 	strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
1031 	ifd.ifd_len = sizeof(b_req);
1032 	ifd.ifd_data = &b_req;
1033 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
1034 
1035 	if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1036 		ifd.ifd_cmd = BRDGDELS;
1037 	else
1038 		ifd.ifd_cmd = BRDGDEL;
1039 
1040 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1041 		syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1042 		    bp->p_name,
1043 		    (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"),
1044 		    strerror(errno));
1045 		return (-1);
1046 	}
1047 
1048 	return (0);
1049 }
1050 
1051 /*
1052  * Fetch the bridge member list from kernel.
1053  * Return -1 on error, or buffer len if successful.
1054  */
1055 static int32_t
1056 bridge_port_get_iflist(struct bridge_if *bif, struct ifbreq **buf)
1057 {
1058 	int n = 128;
1059 	uint32_t len;
1060 	struct ifbreq *ninbuf;
1061 	struct ifbifconf ifbc;
1062 	struct ifdrv ifd;
1063 
1064 	*buf = NULL;
1065 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1066 	ifd.ifd_cmd = BRDGGIFS;
1067 	ifd.ifd_len = sizeof(ifbc);
1068 	ifd.ifd_data = &ifbc;
1069 
1070 	for ( ; ; ) {
1071 		len = n * sizeof(struct ifbreq);
1072 		if ((ninbuf = (struct ifbreq *)realloc(*buf, len)) == NULL) {
1073 			syslog(LOG_ERR, "get bridge member list: "
1074 			    "realloc failed: %s", strerror(errno));
1075 			free(*buf);
1076 			*buf = NULL;
1077 			return (-1);
1078 		}
1079 
1080 		ifbc.ifbic_len = len;
1081 		ifbc.ifbic_req = *buf = ninbuf;
1082 
1083 		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1084 			syslog(LOG_ERR, "get bridge member list: ioctl "
1085 			    "(BRDGGIFS) failed: %s", strerror(errno));
1086 			free(*buf);
1087 			buf = NULL;
1088 			return (-1);
1089 		}
1090 
1091 		if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len)
1092 			break;
1093 
1094 		n += 64;
1095 	}
1096 
1097 	return (ifbc.ifbic_len);
1098 }
1099 
1100 /*
1101  * Fetch the bridge STP member list from kernel.
1102  * Return -1 on error, or buffer len if successful.
1103  */
1104 static int32_t
1105 bridge_port_get_ifstplist(struct bridge_if *bif, struct ifbpstpreq **buf)
1106 {
1107 	int n = 128;
1108 	uint32_t len;
1109 	struct ifbpstpreq *ninbuf;
1110 	struct ifbpstpconf ifbstp;
1111 	struct ifdrv ifd;
1112 
1113 	*buf = NULL;
1114 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1115 	ifd.ifd_cmd = BRDGGIFSSTP;
1116 	ifd.ifd_len = sizeof(ifbstp);
1117 	ifd.ifd_data = &ifbstp;
1118 
1119 	for ( ; ; ) {
1120 		len = n * sizeof(struct ifbpstpreq);
1121 		if ((ninbuf = (struct ifbpstpreq *)
1122 		    realloc(*buf, len)) == NULL) {
1123 			syslog(LOG_ERR, "get bridge STP ports list: "
1124 			    "realloc failed: %s", strerror(errno));
1125 			free(*buf);
1126 			*buf = NULL;
1127 			return (-1);
1128 		}
1129 
1130 		ifbstp.ifbpstp_len = len;
1131 		ifbstp.ifbpstp_req = *buf = ninbuf;
1132 
1133 		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1134 			syslog(LOG_ERR, "get bridge STP ports list: ioctl "
1135 			    "(BRDGGIFSSTP) failed: %s", strerror(errno));
1136 			free(*buf);
1137 			buf = NULL;
1138 			return (-1);
1139 		}
1140 
1141 		if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len)
1142 			break;
1143 
1144 		n += 64;
1145 	}
1146 
1147 	return (ifbstp.ifbpstp_len);
1148 }
1149 
1150 /*
1151  * Locate a bridge if STP params structure in a buffer.
1152  */
1153 static struct ifbpstpreq *
1154 bridge_port_find_ifstplist(uint8_t port_no, struct ifbpstpreq *buf,
1155     uint32_t buf_len)
1156 {
1157 	uint32_t i;
1158 	struct ifbpstpreq *bstp;
1159 
1160 	for (i = 0; i < buf_len / sizeof(struct ifbpstpreq); i++) {
1161 		bstp = buf + i;
1162 		if (bstp->ifbp_portno == port_no)
1163 			return (bstp);
1164 	}
1165 
1166 	return (NULL);
1167 }
1168 
1169 /*
1170  * Read the initial info for all members of a bridge interface.
1171  * Returns the number of ports, 0 - if none, otherwise
1172  * -1 if some other error occurred.
1173  */
1174 int
1175 bridge_getinfo_bif_ports(struct bridge_if *bif)
1176 {
1177 	uint32_t i;
1178 	int32_t buf_len;
1179 	struct ifbreq *b_req_buf, *b_req;
1180 	struct ifbpstpreq *bs_req_buf, *bs_req;
1181 	struct bridge_port *bp;
1182 	struct mibif *m_if;
1183 
1184 	if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1185 		return (-1);
1186 
1187 	for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1188 		b_req = b_req_buf + i;
1189 
1190 		if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) != NULL) {
1191 			/* Hopefully we will not fail here. */
1192 			if ((bp = bridge_new_port(m_if, bif)) != NULL) {
1193 				bp->status = RowStatus_active;
1194 				bridge_port_getinfo_conf(b_req, bp);
1195 				bridge_port_getinfo_mibif(m_if, bp);
1196 			}
1197 		} else {
1198 			syslog(LOG_ERR, "bridge member %s not present "
1199 			    "in mibII ifTable", b_req->ifbr_ifsname);
1200 		}
1201 	}
1202 	free(b_req_buf);
1203 
1204 	if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1205 		return (-1);
1206 
1207 	for (bp = bridge_port_bif_first(bif); bp != NULL;
1208 	    bp = bridge_port_bif_next(bp)) {
1209 		if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1210 		    bs_req_buf, buf_len)) == NULL)
1211 			bridge_port_clearinfo_opstp(bp);
1212 		else
1213 			bridge_port_getinfo_opstp(bs_req, bp);
1214 	}
1215 	free(bs_req_buf);
1216 
1217 	return (i);
1218 }
1219 
1220 /*
1221  * Update the information for the bridge interface members.
1222  */
1223 int
1224 bridge_update_memif(struct bridge_if *bif)
1225 {
1226 	int added, updated;
1227 	uint32_t i;
1228 	int32_t buf_len;
1229 	struct ifbreq *b_req_buf, *b_req;
1230 	struct ifbpstpreq *bs_req_buf, *bs_req;
1231 	struct bridge_port *bp, *bp_next;
1232 	struct mibif *m_if;
1233 
1234 	if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1235 		return (-1);
1236 
1237 	added = updated = 0;
1238 
1239 #define	BP_FOUND	0x01
1240 	for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1241 		b_req = b_req_buf + i;
1242 
1243 		if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) == NULL) {
1244 			syslog(LOG_ERR, "bridge member %s not present "
1245 			    "in mibII ifTable", b_req->ifbr_ifsname);
1246 			continue;
1247 		}
1248 
1249 		if ((bp = bridge_port_find(m_if->index, bif)) == NULL &&
1250 		    (bp = bridge_new_port(m_if, bif)) != NULL) {
1251 			bp->status = RowStatus_active;
1252 			added++;
1253 		}
1254 
1255 		if (bp != NULL) {
1256 			updated++;
1257 			bridge_port_getinfo_conf(b_req, bp);
1258 			bridge_port_getinfo_mibif(m_if, bp);
1259 			bp->flags |= BP_FOUND;
1260 		}
1261 	}
1262 	free(b_req_buf);
1263 
1264 	/* Clean up list. */
1265 	for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) {
1266 		bp_next  = bridge_port_bif_next(bp);
1267 
1268 		if ((bp->flags & BP_FOUND) == 0 &&
1269 		    bp->status == RowStatus_active)
1270 			bridge_port_remove(bp, bif);
1271 		else
1272 			bp->flags |= ~BP_FOUND;
1273 	}
1274 #undef	BP_FOUND
1275 
1276 	if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1277 		return (-1);
1278 
1279 	for (bp = bridge_port_bif_first(bif); bp != NULL;
1280 	    bp = bridge_port_bif_next(bp)) {
1281 		if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1282 		    bs_req_buf, buf_len)) == NULL)
1283 			bridge_port_clearinfo_opstp(bp);
1284 		else
1285 			bridge_port_getinfo_opstp(bs_req, bp);
1286 	}
1287 	free(bs_req_buf);
1288 	bif->ports_age = time(NULL);
1289 
1290 	return (updated);
1291 }
1292 
1293 /************************************************************************
1294  * Bridge addresses.
1295  */
1296 
1297 /*
1298  * Update the bridge address info according to the polled data.
1299  */
1300 static void
1301 bridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe)
1302 {
1303 	tpe->port_no = if_nametoindex(ifba->ifba_ifsname);
1304 
1305 	if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
1306 		tpe->status = TpFdbStatus_mgmt;
1307 	else
1308 		tpe->status = TpFdbStatus_learned;
1309 }
1310 
1311 /*
1312  * Read the bridge addresses from kernel.
1313  * Return -1 on error, or buffer len if successful.
1314  */
1315 static int32_t
1316 bridge_addrs_getinfo_ifalist(struct bridge_if *bif, struct ifbareq **buf)
1317 {
1318 	int n = 128;
1319 	uint32_t len;
1320 	struct ifbareq *ninbuf;
1321 	struct ifbaconf bac;
1322 	struct ifdrv ifd;
1323 
1324 	*buf = NULL;
1325 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1326 	ifd.ifd_cmd = BRDGRTS;
1327 	ifd.ifd_len = sizeof(bac);
1328 	ifd.ifd_data = &bac;
1329 
1330 	for ( ; ; ) {
1331 		len = n * sizeof(struct ifbareq);
1332 		if ((ninbuf = (struct ifbareq *)realloc(*buf, len)) == NULL) {
1333 			syslog(LOG_ERR, "get bridge address list: "
1334 			    " realloc failed: %s", strerror(errno));
1335 			free(*buf);
1336 			*buf = NULL;
1337 			return (-1);
1338 		}
1339 
1340 		bac.ifbac_len = len;
1341 		bac.ifbac_req = *buf = ninbuf;
1342 
1343 		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1344 			syslog(LOG_ERR, "get bridge address list: "
1345 			    "ioctl(BRDGRTS) failed: %s", strerror(errno));
1346 			free(*buf);
1347 			buf = NULL;
1348 			return (-1);
1349 		}
1350 
1351 		if ((bac.ifbac_len + sizeof(struct ifbareq)) < len)
1352 			break;
1353 
1354 		n += 64;
1355 	}
1356 
1357 	return (bac.ifbac_len);
1358 }
1359 
1360 /*
1361  * Read the initial info for all addresses on a bridge interface.
1362  * Returns the number of addresses, 0 - if none, otherwise
1363  * -1 if some other error occurred.
1364  */
1365 int
1366 bridge_getinfo_bif_addrs(struct bridge_if *bif)
1367 {
1368 	uint32_t i;
1369 	int32_t buf_len;
1370 	struct ifbareq *addr_req_buf, *addr_req;
1371 	struct tp_entry *te;
1372 
1373 	if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1374 		return (-1);
1375 
1376 	for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1377 		addr_req = addr_req_buf + i;
1378 
1379 		if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
1380 			bridge_addrs_info_ifaddrlist(addr_req, te);
1381 	}
1382 
1383 	free(addr_req_buf);
1384 	return (i);
1385 }
1386 
1387 /*
1388  * Update the addresses for the bridge interface.
1389  */
1390 int
1391 bridge_update_addrs(struct bridge_if *bif)
1392 {
1393 	int added, updated;
1394 	uint32_t i;
1395 	int32_t buf_len;
1396 	struct tp_entry *te, *te_next;
1397 	struct ifbareq *addr_req_buf, *addr_req;
1398 
1399 	if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1400 		return (-1);
1401 
1402 	added = updated = 0;
1403 
1404 #define	BA_FOUND	0x01
1405 	for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1406 		addr_req = addr_req_buf + i;
1407 
1408 		if ((te = bridge_addrs_find(addr_req->ifba_dst, bif)) == NULL) {
1409 			added++;
1410 
1411 			if ((te = bridge_new_addrs(addr_req->ifba_dst, bif))
1412 			    == NULL)
1413 				continue;
1414 		} else
1415 			updated++;
1416 
1417 		bridge_addrs_info_ifaddrlist(addr_req, te);
1418 		te-> flags |= BA_FOUND;
1419 	}
1420 	free(addr_req_buf);
1421 
1422 	for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) {
1423 		te_next = bridge_addrs_bif_next(te);
1424 
1425 		if ((te-> flags & BA_FOUND) == 0)
1426 			bridge_addrs_remove(te, bif);
1427 		else
1428 			te-> flags &= ~BA_FOUND;
1429 	}
1430 #undef	BA_FOUND
1431 
1432 	bif->addrs_age = time(NULL);
1433 	return (updated + added);
1434 }
1435 
1436 /************************************************************************
1437  * Bridge packet filtering.
1438  */
1439 const char bridge_sysctl[] = "net.link.bridge.";
1440 
1441 static struct {
1442 	int32_t val;
1443 	const char *name;
1444 } bridge_pf_sysctl[] = {
1445 	{ 1, "pfil_bridge" },
1446 	{ 1, "pfil_member" },
1447 	{ 1, "pfil_onlyip" },
1448 	{ 0, "ipfw" },
1449 };
1450 
1451 int32_t
1452 bridge_get_pfval(uint8_t which)
1453 {
1454 
1455 	if (which > nitems(bridge_pf_sysctl) || which < 1)
1456 		return (-1);
1457 
1458 	return (bridge_pf_sysctl[which - 1].val);
1459 }
1460 
1461 int32_t
1462 bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val)
1463 {
1464 	char *mib_oid;
1465 	size_t len, s_len;
1466 	int32_t i, s_i;
1467 
1468 	if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus)
1469 		return (-2);
1470 
1471 	if (op == SNMP_OP_SET) {
1472 		s_i = *val;
1473 		s_len = sizeof(s_i);
1474 	} else
1475 		s_len = 0;
1476 
1477 	len = sizeof(i);
1478 
1479 	asprintf(&mib_oid, "%s%s", bridge_sysctl,
1480 	    bridge_pf_sysctl[bridge_ctl].name);
1481 	if (mib_oid == NULL)
1482 		return (-1);
1483 
1484 	if (sysctlbyname(mib_oid, &i, &len, (op == SNMP_OP_SET ? &s_i : NULL),
1485 	    s_len) == -1) {
1486 		syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_oid,
1487 		    strerror(errno));
1488 		free(mib_oid);
1489 		return (-1);
1490 	}
1491 
1492 	bridge_pf_sysctl[bridge_ctl].val = i;
1493 	*val = i;
1494 
1495 	free(mib_oid);
1496 
1497 	return (i);
1498 }
1499 
1500 void
1501 bridge_pf_dump(void)
1502 {
1503 	uint8_t i;
1504 
1505 	for (i = 0; i < nitems(bridge_pf_sysctl); i++) {
1506 		syslog(LOG_ERR, "%s%s = %d", bridge_sysctl,
1507 		    bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val);
1508 	}
1509 }
1510