xref: /freebsd/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c (revision f0a75d274af375d15b97b830966b99a02b7db911)
1 /*-
2  * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * Bridge MIB implementation for SNMPd.
27  * Bridge OS specific ioctls.
28  *
29  * $FreeBSD$
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 #include "bridge_tree.h"
60 #include "bridge_snmp.h"
61 
62 int sock = -1;
63 
64 int
65 bridge_ioctl_init(void)
66 {
67 	if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
68 		syslog(LOG_ERR, "cannot open socket : %s", strerror(errno));
69 		return (-1);
70 	}
71 
72 	return (0);
73 }
74 
75 /*
76  * Load the if_bridge.ko module in kernel if not already there.
77  */
78 int
79 bridge_kmod_load(void)
80 {
81 	int fileid, modid;
82 	const char mod_name[] = "if_bridge";
83 	struct module_stat mstat;
84 
85 	/* Scan files in kernel. */
86 	mstat.version = sizeof(struct module_stat);
87 	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
88 		/* Scan modules in file. */
89 		for (modid = kldfirstmod(fileid); modid > 0;
90 			modid = modfnext(modid)) {
91 
92 			if (modstat(modid, &mstat) < 0)
93 				continue;
94 
95 			if (strcmp(mod_name, mstat.name) == 0)
96 				return (0);
97 		}
98 	}
99 
100 	/* Not present - load it. */
101 	if (kldload(mod_name) < 0) {
102 		syslog(LOG_ERR, "failed to load %s kernel module", mod_name);
103 		return (-1);
104 	}
105 
106 	return (1);
107 }
108 
109 /************************************************************************
110  * Bridge interfaces.
111  */
112 
113 /*
114  * Convert the kernel uint64_t value for a bridge id
115  */
116 static void
117 snmp_uint64_to_bridgeid(uint64_t id, bridge_id b_id)
118 {
119 	int i;
120 	u_char *o;
121 
122 	o = (u_char *) &id;
123 
124 	for (i = 0; i < SNMP_BRIDGE_ID_LEN; i++, o++)
125 		b_id[SNMP_BRIDGE_ID_LEN - i - 1] = *o;
126 }
127 
128 /*
129  * Fetch the bridge configuration parameters from the kernel excluding
130  * it's base MAC address.
131  */
132 static int
133 bridge_get_conf_param(struct bridge_if *bif)
134 {
135 	struct ifdrv ifd;
136 	struct ifbrparam b_param;
137 
138 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
139 	ifd.ifd_len = sizeof(b_param);
140 	ifd.ifd_data = &b_param;
141 
142 	/* Bridge priority. */
143 	ifd.ifd_cmd = BRDGGPRI;
144 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
145 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGPRI) failed: %s",
146 		    strerror(errno));
147 		return (-1);
148 	}
149 
150 	bif->priority = b_param.ifbrp_prio;
151 
152 	/* Configured max age. */
153 	ifd.ifd_cmd = BRDGGMA;
154 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
155 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGMA) failed: %s",
156 		    strerror(errno));
157 		return (-1);
158 	}
159 
160 	/* Centi-seconds. */
161 	bif->bridge_max_age = 100 * b_param.ifbrp_maxage;
162 
163 	/* Configured hello time. */
164 	ifd.ifd_cmd = BRDGGHT;
165 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
166 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGHT) failed: %s",
167 		    strerror(errno));
168 		return (-1);
169 	}
170 	bif->bridge_hello_time = 100 * b_param.ifbrp_hellotime;
171 
172 	/* Forward delay. */
173 	ifd.ifd_cmd = BRDGGFD;
174 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
175 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGFD) failed: %s",
176 		    strerror(errno));
177 		return (-1);
178 	}
179 	bif->bridge_fwd_delay = 100 * b_param.ifbrp_fwddelay;
180 
181 	/* Number of dropped addresses. */
182 	ifd.ifd_cmd = BRDGGRTE;
183 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
184 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGRTE) failed: %s",
185 		    strerror(errno));
186 		return (-1);
187 	}
188 	bif->lrnt_drops = b_param.ifbrp_cexceeded;
189 
190 	/* Address table timeout. */
191 	ifd.ifd_cmd = BRDGGTO;
192 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
193 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGTO) failed: %s",
194 		    strerror(errno));
195 		return (-1);
196 	}
197 	bif->age_time = b_param.ifbrp_ctime;
198 
199 	/* Address table size. */
200 	ifd.ifd_cmd = BRDGGCACHE;
201 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
202 		syslog(LOG_ERR, "update bridge: ioctl(BRDGGCACHE) "
203 		    "failed: %s", strerror(errno));
204 		return (-1);
205 	}
206 	bif->max_addrs = b_param.ifbrp_csize;
207 
208 	return (0);
209 }
210 
211 /*
212  * Fetch the current bridge STP operational parameters.
213  * Returns: -1 - on error;
214  *	     0 - old TC time and Root Port values are same;
215  *	     1 - topologyChange notification should be sent;
216  *	     2 - newRoot notification should be sent.
217  */
218 int
219 bridge_get_op_param(struct bridge_if *bif)
220 {
221 	int new_root_send;
222 	struct ifdrv ifd;
223 	struct ifbropreq b_req;
224 
225 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
226 	ifd.ifd_len = sizeof(b_req);
227 	ifd.ifd_data = &b_req;
228 	ifd.ifd_cmd = BRDGPARAM;
229 
230 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
231 		syslog(LOG_ERR, "update bridge: ioctl(BRDGPARAM) failed: %s",
232 		    strerror(errno));
233 		return (-1);
234 	}
235 
236 	bif->max_age = 100 * b_req.ifbop_maxage;
237 	bif->hello_time = 100 * b_req.ifbop_hellotime;
238 	bif->fwd_delay = 100 * b_req.ifbop_fwddelay;
239 	bif->stp_version = b_req.ifbop_protocol;
240 	bif->tx_hold_count = b_req.ifbop_holdcount;
241 
242 	if (b_req.ifbop_root_port == 0 &&
243 	    bif->root_port != b_req.ifbop_root_port)
244 		new_root_send = 2;
245 	else
246 		new_root_send = 0;
247 
248 	bif->root_port = b_req.ifbop_root_port;
249 	bif->root_cost = b_req.ifbop_root_path_cost;
250 	snmp_uint64_to_bridgeid(b_req.ifbop_designated_root,
251 	    bif->design_root);
252 
253 	if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) {
254 		bif->top_changes++;
255 		bif->last_tc_time.tv_sec = b_req.ifbop_last_tc_time.tv_sec;
256 		bif->last_tc_time.tv_usec = b_req.ifbop_last_tc_time.tv_usec;
257 
258 		/*
259 		 * "The trap is not sent if a (begemotBridge)NewRoot
260 		 * trap is sent for the same transition."
261 		 */
262 		if (new_root_send == 0)
263 			return (1);
264 	}
265 
266 	return (new_root_send);
267 }
268 
269 int
270 bridge_getinfo_bif(struct bridge_if *bif)
271 {
272 	if (bridge_get_conf_param(bif) < 0)
273 		return (-1);
274 
275 	return (bridge_get_op_param(bif));
276 }
277 
278 int
279 bridge_set_priority(struct bridge_if *bif, int32_t priority)
280 {
281 	struct ifdrv ifd;
282 	struct ifbrparam b_param;
283 
284 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
285 	ifd.ifd_len = sizeof(b_param);
286 	ifd.ifd_data = &b_param;
287 	b_param.ifbrp_prio = (uint32_t) priority;
288 	ifd.ifd_cmd = BRDGSPRI;
289 
290 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
291 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) "
292 		    "failed: %s", strerror(errno));
293 		return (-1);
294 	}
295 
296 	/*
297 	 * Re-fetching the data from the driver after that might be a good
298 	 * idea, since changing our bridge's priority should invoke
299 	 * recalculation of the active spanning tree topology in the network.
300 	 */
301 	bif->priority = priority;
302 	return (0);
303 }
304 
305 /*
306  * Convert 1/100 of seconds to 1/256 of seconds.
307  * Timeout ::= TEXTUAL-CONVENTION.
308  * To convert a Timeout value into a value in units of
309  * 1/256 seconds, the following algorithm should be used:
310  *	b = floor( (n * 256) / 100)
311  * The conversion to 1/256 of a second happens in the kernel -
312  * just make sure we correctly convert the seconds to Timout
313  * and vice versa.
314  */
315 static uint32_t
316 snmp_timeout2_sec(int32_t secs)
317 {
318 	return (secs / 100);
319 }
320 
321 int
322 bridge_set_maxage(struct bridge_if *bif, int32_t max_age)
323 {
324 	struct ifdrv ifd;
325 	struct ifbrparam b_param;
326 
327 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
328 	ifd.ifd_len = sizeof(b_param);
329 	ifd.ifd_data = &b_param;
330 	b_param.ifbrp_maxage = snmp_timeout2_sec(max_age);
331 	ifd.ifd_cmd = BRDGSMA;
332 
333 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
334 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) "
335 		    "failed: %s", strerror(errno));
336 		return (-1);
337 	}
338 
339 	bif->bridge_max_age = max_age;
340 	return (0);
341 }
342 
343 int
344 bridge_set_hello_time(struct bridge_if *bif, int32_t hello_time)
345 {
346 	struct ifdrv ifd;
347 	struct ifbrparam b_param;
348 
349 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
350 	ifd.ifd_len = sizeof(b_param);
351 	ifd.ifd_data = &b_param;
352 	b_param.ifbrp_hellotime = snmp_timeout2_sec(hello_time);
353 	ifd.ifd_cmd = BRDGSHT;
354 
355 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
356 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) "
357 		    "failed: %s", strerror(errno));
358 		return (-1);
359 	}
360 
361 	bif->bridge_hello_time = b_param.ifbrp_hellotime;
362 	return (0);
363 }
364 
365 int
366 bridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay)
367 {
368 	struct ifdrv ifd;
369 	struct ifbrparam b_param;
370 
371 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
372 	ifd.ifd_len = sizeof(b_param);
373 	ifd.ifd_data = &b_param;
374 	b_param.ifbrp_fwddelay = snmp_timeout2_sec(fwd_delay);
375 	ifd.ifd_cmd = BRDGSFD;
376 
377 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
378 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) "
379 		    "failed: %s", strerror(errno));
380 		return (-1);
381 	}
382 
383 	bif->bridge_fwd_delay = b_param.ifbrp_fwddelay;
384 	return (0);
385 }
386 
387 int
388 bridge_set_aging_time(struct bridge_if *bif, int32_t age_time)
389 {
390 	struct ifdrv ifd;
391 	struct ifbrparam b_param;
392 
393 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
394 	ifd.ifd_len = sizeof(b_param);
395 	ifd.ifd_data = &b_param;
396 	b_param.ifbrp_ctime = (uint32_t) age_time;
397 	ifd.ifd_cmd = BRDGSTO;
398 
399 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
400 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) "
401 		    "failed: %s", strerror(errno));
402 		return (-1);
403 	}
404 
405 	bif->age_time = age_time;
406 	return (0);
407 }
408 
409 int
410 bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache)
411 {
412 	struct ifdrv ifd;
413 	struct ifbrparam b_param;
414 
415 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
416 	ifd.ifd_len = sizeof(b_param);
417 	ifd.ifd_data = &b_param;
418 	b_param.ifbrp_csize = max_cache;
419 	ifd.ifd_cmd = BRDGSCACHE;
420 
421 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
422 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) "
423 		    "failed: %s", strerror(errno));
424 		return (-1);
425 	}
426 
427 	bif->max_addrs = b_param.ifbrp_csize;
428 	return (0);
429 }
430 
431 int
432 bridge_set_tx_hold_count(struct bridge_if *bif __unused,
433     int32_t tx_hc __unused)
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 __unused,
459     int32_t stp_proto __unused)
460 {
461 	struct ifdrv ifd;
462 	struct ifbrparam b_param;
463 
464 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
465 	ifd.ifd_len = sizeof(b_param);
466 	ifd.ifd_data = &b_param;
467 	b_param.ifbrp_proto = stp_proto;
468 	ifd.ifd_cmd = BRDGSPROTO;
469 
470 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
471 		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPROTO) "
472 		    "failed: %s", strerror(errno));
473 		return (-1);
474 	}
475 
476 	bif->stp_version = b_param.ifbrp_proto;
477 	return (0);
478 }
479 
480 /*
481  * Set the bridge interface status to up/down.
482  */
483 int
484 bridge_set_if_up(const char* b_name, int8_t up)
485 {
486 	int	flags;
487 	struct ifreq ifr;
488 
489 	bzero(&ifr, sizeof(ifr));
490 	strcpy(ifr.ifr_name, b_name);
491 	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
492 		syslog(LOG_ERR, "set bridge up: ioctl(SIOCGIFFLAGS) "
493 		    "failed: %s", strerror(errno));
494 		return (-1);
495 	}
496 
497 	flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
498 	if (up == 1)
499 		flags |= IFF_UP;
500 	else
501 		flags &= ~IFF_UP;
502 
503 	ifr.ifr_flags = flags & 0xffff;
504 	ifr.ifr_flagshigh = flags >> 16;
505 	if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
506 		syslog(LOG_ERR, "set bridge up: ioctl(SIOCSIFFLAGS) "
507 		    "failed: %s", strerror(errno));
508 		return (-1);
509 	}
510 
511 	return (0);
512 }
513 
514 int
515 bridge_create(const char *b_name)
516 {
517 	char *new_name;
518 	struct ifreq ifr;
519 
520 	bzero(&ifr, sizeof(ifr));
521 	strcpy(ifr.ifr_name, b_name);
522 
523 	if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) {
524 		syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) "
525 		    "failed: %s", strerror(errno));
526 		return (-1);
527 	}
528 
529 	if (strcmp(b_name, ifr.ifr_name) == 0)
530 		return (0);
531 
532 	if ((new_name = strdup(b_name)) == NULL) {
533 		syslog(LOG_ERR, "create bridge: strdup() failed");
534 		return (-1);
535 	}
536 
537 	ifr.ifr_data = new_name;
538 	if (ioctl(sock, SIOCSIFNAME, (caddr_t) &ifr) < 0) {
539 		syslog(LOG_ERR, "create bridge: ioctl(SIOCSIFNAME) "
540 		    "failed: %s", strerror(errno));
541 		free(new_name);
542 		return (-1);
543 	}
544 
545 	return (0);
546 }
547 
548 int
549 bridge_destroy(const char *b_name)
550 {
551 	struct ifreq ifr;
552 
553 	bzero(&ifr, sizeof(ifr));
554 	strcpy(ifr.ifr_name, b_name);
555 
556 	if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) {
557 		syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) "
558 		    "failed: %s", strerror(errno));
559 		return (-1);
560 	}
561 
562 	return (0);
563 }
564 
565 /*
566  * Fetch the bridge base MAC address. Return pointer to the
567  * buffer containing the MAC address, NULL on failure.
568  */
569 u_char *
570 bridge_get_basemac(const char *bif_name, u_char *mac, size_t mlen)
571 {
572 	int len;
573 	char if_name[IFNAMSIZ];
574 	struct ifaddrs *ifap, *ifa;
575 	struct sockaddr_dl sdl;
576 
577 	if (getifaddrs(&ifap) != 0) {
578 		syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s",
579 		    strerror(errno));
580 		return (NULL);
581 	}
582 
583 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
584 		if (ifa->ifa_addr->sa_family != AF_LINK)
585 			continue;
586 
587 		/*
588 		 * Not just casting because of alignment constraints
589 		 * on sparc64 and ia64.
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_BSTP_ADMEDGE)
679 		bp->admin_edge = TruthValue_true;
680 	else
681 		bp->admin_edge = TruthValue_false;
682 
683 	if (k_info->ifbr_ifsflags & IFBIF_BSTP_EDGE)
684 		bp->oper_edge = TruthValue_true;
685 	else
686 		bp->oper_edge = TruthValue_false;
687 
688 	if (k_info->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP) {
689 		bp->admin_ptp = StpPortAdminPointToPointType_auto;
690 		if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP)
691 			bp->oper_ptp = TruthValue_true;
692 		else
693 			bp->oper_ptp = TruthValue_false;
694 	} else if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP) {
695 		bp->admin_ptp = StpPortAdminPointToPointType_forceTrue;
696 		bp->oper_ptp = TruthValue_true;
697 	} else {
698 		bp->admin_ptp = StpPortAdminPointToPointType_forceFalse;
699 		bp->oper_ptp = TruthValue_false;
700 	}
701 }
702 
703 /*
704  * Fill in a bridge interface STP information according to
705  * data polled from kernel.
706  */
707 static void
708 bridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp)
709 {
710 	bp->enable = dot1dStpPortEnable_enabled;
711 	bp->fwd_trans = bp_stp->ifbp_fwd_trans;
712 	bp->design_cost = bp_stp->ifbp_design_cost;
713 	snmp_uint64_to_bridgeid(bp_stp->ifbp_design_root, bp->design_root);
714 	snmp_uint64_to_bridgeid(bp_stp->ifbp_design_bridge, bp->design_bridge);
715 	bcopy(&(bp_stp->ifbp_design_port), &(bp->design_port),
716 	    sizeof(uint16_t));
717 }
718 
719 /*
720  * Clear a bridge interface STP information.
721  */
722 static void
723 bridge_port_clearinfo_opstp(struct bridge_port *bp)
724 {
725 	if (bp->enable == dot1dStpPortEnable_enabled) {
726 		bp->design_cost = 0;
727 		bzero(&(bp->design_root), sizeof(bridge_id));
728 		bzero(&(bp->design_bridge), sizeof(bridge_id));
729 		bzero(&(bp->design_port), sizeof(port_id));
730 		bp->fwd_trans = 0;
731 	}
732 
733 	bp->enable = dot1dStpPortEnable_disabled;
734 }
735 
736 /*
737  * Set a bridge member priority.
738  */
739 int
740 bridge_port_set_priority(const char *bif_name, struct bridge_port *bp,
741 	int32_t priority)
742 {
743 	struct ifdrv ifd;
744 	struct ifbreq b_req;
745 
746 	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
747 	ifd.ifd_len = sizeof(b_req);
748 	ifd.ifd_data = &b_req;
749 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
750 
751 	b_req.ifbr_priority = (uint8_t) priority;
752 	ifd.ifd_cmd = BRDGSIFPRIO;
753 
754 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
755 		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFPRIO) "
756 		    "failed: %s", bp->p_name, strerror(errno));
757 		return (-1);
758 	}
759 
760 	bp->priority = priority;
761 	return (0);
762 }
763 
764 /*
765  * Set a bridge member STP-enabled flag.
766  */
767 int
768 bridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp,
769 	uint32_t enable)
770 {
771 	struct ifdrv ifd;
772 	struct ifbreq b_req;
773 
774 	if (bp->enable == enable)
775 		return (0);
776 
777 	bzero(&b_req, sizeof(b_req));
778 	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
779 	ifd.ifd_len = sizeof(b_req);
780 	ifd.ifd_data = &b_req;
781 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
782 	ifd.ifd_cmd = BRDGGIFFLGS;
783 
784 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
785 		syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
786 		    "failed: %s", bp->p_name, strerror(errno));
787 		return (-1);
788 	}
789 
790 	if (enable == dot1dStpPortEnable_enabled)
791 		b_req.ifbr_ifsflags |= IFBIF_STP;
792 	else
793 		b_req.ifbr_ifsflags &= ~IFBIF_STP;
794 
795 	ifd.ifd_cmd = BRDGSIFFLGS;
796 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
797 		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
798 		    "failed: %s", bp->p_name, strerror(errno));
799 		return (-1);
800 	}
801 
802 	bp->enable = enable;
803 	return (0);
804 }
805 
806 /*
807  * Set a bridge member STP path cost.
808  */
809 int
810 bridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp,
811 	int32_t path_cost)
812 {
813 	struct ifdrv ifd;
814 	struct ifbreq b_req;
815 
816 	if (path_cost < SNMP_PORT_MIN_PATHCOST ||
817 	    path_cost > SNMP_PORT_PATHCOST_OBSOLETE)
818 		return (-2);
819 
820 	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
821 	ifd.ifd_len = sizeof(b_req);
822 	ifd.ifd_data = &b_req;
823 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
824 
825 	b_req.ifbr_path_cost = path_cost;
826 	ifd.ifd_cmd = BRDGSIFCOST;
827 
828 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
829 		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFCOST) "
830 		    "failed: %s", bp->p_name, strerror(errno));
831 		return (-1);
832 	}
833 
834 	bp->admin_path_cost = path_cost;
835 
836 	return (0);
837 }
838 
839 /*
840  * Set the PonitToPoint status of the link administratively.
841  */
842 int
843 bridge_port_set_admin_ptp(const char *bif_name __unused,
844     struct bridge_port *bp __unused, uint32_t admin_ptp __unused)
845 {
846 	struct ifdrv ifd;
847 	struct ifbreq b_req;
848 
849 	if (bp->admin_ptp == admin_ptp)
850 		return (0);
851 
852 	bzero(&b_req, sizeof(b_req));
853 	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
854 	ifd.ifd_len = sizeof(b_req);
855 	ifd.ifd_data = &b_req;
856 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
857 	ifd.ifd_cmd = BRDGGIFFLGS;
858 
859 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
860 		syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
861 		    "failed: %s", bp->p_name, strerror(errno));
862 		return (-1);
863 	}
864 
865 	switch (admin_ptp) {
866 		case StpPortAdminPointToPointType_forceTrue:
867 			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
868 			b_req.ifbr_ifsflags |= IFBIF_BSTP_PTP;
869 			break;
870 		case StpPortAdminPointToPointType_forceFalse:
871 			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
872 			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_PTP;
873 			break;
874 		case StpPortAdminPointToPointType_auto:
875 			b_req.ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
876 			break;
877 	}
878 
879 	ifd.ifd_cmd = BRDGSIFFLGS;
880 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
881 		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
882 		    "failed: %s", bp->p_name, strerror(errno));
883 		return (-1);
884 	}
885 
886 	bp->admin_ptp = admin_ptp;
887 	return (0);
888 }
889 
890 /*
891  * Set admin edge.
892  */
893 int
894 bridge_port_set_admin_edge(const char *bif_name __unused,
895     struct bridge_port *bp __unused, uint32_t enable __unused)
896 {
897 	struct ifdrv ifd;
898 	struct ifbreq b_req;
899 
900 	if (bp->admin_edge == enable)
901 		return (0);
902 
903 	bzero(&b_req, sizeof(b_req));
904 	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
905 	ifd.ifd_len = sizeof(b_req);
906 	ifd.ifd_data = &b_req;
907 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
908 	ifd.ifd_cmd = BRDGGIFFLGS;
909 
910 	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
911 		syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
912 		    "failed: %s", bp->p_name, strerror(errno));
913 		return (-1);
914 	}
915 
916 	if (enable == TruthValue_true) {
917 		b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOEDGE;
918 		b_req.ifbr_ifsflags |= IFBIF_BSTP_EDGE;
919 	} else
920 		b_req.ifbr_ifsflags &= ~IFBIF_BSTP_EDGE;
921 
922 	ifd.ifd_cmd = BRDGSIFFLGS;
923 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
924 		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
925 		    "failed: %s", bp->p_name, strerror(errno));
926 		return (-1);
927 	}
928 
929 	bp->admin_edge = enable;
930 
931 	return (0);
932 }
933 
934 /*
935  * Add a bridge member port.
936  */
937 int
938 bridge_port_addm(struct bridge_port *bp, const char *b_name)
939 {
940 	struct ifdrv ifd;
941 	struct ifbreq b_req;
942 
943 	bzero(&ifd, sizeof(ifd));
944 	bzero(&b_req, sizeof(b_req));
945 
946 	strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
947 	ifd.ifd_len = sizeof(b_req);
948 	ifd.ifd_data = &b_req;
949 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
950 
951 	if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
952 		ifd.ifd_cmd = BRDGADDS;
953 	else
954 		ifd.ifd_cmd = BRDGADD;
955 
956 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
957 		syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
958 		    bp->p_name,
959 		    (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"),
960 		    strerror(errno));
961 		return (-1);
962 	}
963 
964 	return (0);
965 }
966 
967 /*
968  * Delete a bridge member port.
969  */
970 int
971 bridge_port_delm(struct bridge_port *bp, const char *b_name)
972 {
973 	struct ifdrv ifd;
974 	struct ifbreq b_req;
975 
976 	bzero(&ifd, sizeof(ifd));
977 	bzero(&b_req, sizeof(b_req));
978 
979 	strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
980 	ifd.ifd_len = sizeof(b_req);
981 	ifd.ifd_data = &b_req;
982 	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
983 
984 	if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
985 		ifd.ifd_cmd = BRDGDELS;
986 	else
987 		ifd.ifd_cmd = BRDGDEL;
988 
989 	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
990 		syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
991 		    bp->p_name,
992 		    (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"),
993 		    strerror(errno));
994 		return (-1);
995 	}
996 
997 	return (0);
998 }
999 
1000 /*
1001  * Fetch the bridge member list from kernel.
1002  * Return -1 on error, or buffer len if successful.
1003  */
1004 static int32_t
1005 bridge_port_get_iflist(struct bridge_if *bif, struct ifbreq **buf)
1006 {
1007 	int n = 128;
1008 	uint32_t len;
1009 	struct ifbreq *ninbuf;
1010 	struct ifbifconf ifbc;
1011 	struct ifdrv ifd;
1012 
1013 	*buf = NULL;
1014 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1015 	ifd.ifd_cmd = BRDGGIFS;
1016 	ifd.ifd_len = sizeof(ifbc);
1017 	ifd.ifd_data = &ifbc;
1018 
1019 	for ( ; ; ) {
1020 		len = n * sizeof(struct ifbreq);
1021 		if ((ninbuf = (struct ifbreq *)realloc(*buf, len)) == NULL) {
1022 			syslog(LOG_ERR, "get bridge member list: "
1023 			    "realloc failed: %s", strerror(errno));
1024 			free(*buf);
1025 			*buf = NULL;
1026 			return (-1);
1027 		}
1028 
1029 		ifbc.ifbic_len = len;
1030 		ifbc.ifbic_req = *buf = ninbuf;
1031 
1032 		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1033 			syslog(LOG_ERR, "get bridge member list: ioctl "
1034 			    "(BRDGGIFS) failed: %s", strerror(errno));
1035 			free(*buf);
1036 			buf = NULL;
1037 			return (-1);
1038 		}
1039 
1040 		if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len)
1041 			break;
1042 
1043 		n += 64;
1044 	}
1045 
1046 	return (ifbc.ifbic_len);
1047 }
1048 
1049 /*
1050  * Fetch the bridge STP member list from kernel.
1051  * Return -1 on error, or buffer len if successful.
1052  */
1053 static int32_t
1054 bridge_port_get_ifstplist(struct bridge_if *bif, struct ifbpstpreq **buf)
1055 {
1056 	int n = 128;
1057 	uint32_t len;
1058 	struct ifbpstpreq *ninbuf;
1059 	struct ifbpstpconf ifbstp;
1060 	struct ifdrv ifd;
1061 
1062 	*buf = NULL;
1063 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1064 	ifd.ifd_cmd = BRDGGIFSSTP;
1065 	ifd.ifd_len = sizeof(ifbstp);
1066 	ifd.ifd_data = &ifbstp;
1067 
1068 	for ( ; ; ) {
1069 		len = n * sizeof(struct ifbpstpreq);
1070 		if ((ninbuf = (struct ifbpstpreq *)
1071 		    realloc(*buf, len)) == NULL) {
1072 			syslog(LOG_ERR, "get bridge STP ports list: "
1073 			    "realloc failed: %s", strerror(errno));
1074 			free(*buf);
1075 			*buf = NULL;
1076 			return (-1);
1077 		}
1078 
1079 		ifbstp.ifbpstp_len = len;
1080 		ifbstp.ifbpstp_req = *buf = ninbuf;
1081 
1082 		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1083 			syslog(LOG_ERR, "get bridge STP ports list: ioctl "
1084 			    "(BRDGGIFSSTP) failed: %s", strerror(errno));
1085 			free(*buf);
1086 			buf = NULL;
1087 			return (-1);
1088 		}
1089 
1090 		if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len)
1091 			break;
1092 
1093 		n += 64;
1094 	}
1095 
1096 	return (ifbstp.ifbpstp_len);
1097 }
1098 
1099 /*
1100  * Locate a bridge if STP params structure in a buffer.
1101  */
1102 static struct ifbpstpreq *
1103 bridge_port_find_ifstplist(uint8_t port_no, struct ifbpstpreq *buf,
1104     uint32_t buf_len)
1105 {
1106 	uint32_t i;
1107 	struct ifbpstpreq *bstp;
1108 
1109 	for (i = 0; i < buf_len / sizeof(struct ifbpstpreq); i++) {
1110 		bstp = buf + i;
1111 		if (bstp->ifbp_portno == port_no)
1112 			return (bstp);
1113 	}
1114 
1115 	return (NULL);
1116 }
1117 
1118 /*
1119  * Read the initial info for all members of a bridge interface.
1120  * Returns the number of ports, 0 - if none, otherwise
1121  * -1 if some other error occured.
1122  */
1123 int
1124 bridge_getinfo_bif_ports(struct bridge_if *bif)
1125 {
1126 	uint32_t i;
1127 	int32_t buf_len;
1128 	struct ifbreq *b_req_buf, *b_req;
1129 	struct ifbpstpreq *bs_req_buf, *bs_req;
1130 	struct bridge_port *bp;
1131 	struct mibif *m_if;
1132 
1133 	if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1134 		return (-1);
1135 
1136 	for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1137 		b_req = b_req_buf + i;
1138 
1139 		if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) != NULL) {
1140 			/* Hopefully we will not fail here. */
1141 			if ((bp = bridge_new_port(m_if, bif)) != NULL) {
1142 				bp->status = RowStatus_active;
1143 				bridge_port_getinfo_conf(b_req, bp);
1144 				bridge_port_getinfo_mibif(m_if, bp);
1145 			}
1146 		} else {
1147 			syslog(LOG_ERR, "bridge member %s not present "
1148 			    "in mibII ifTable", b_req->ifbr_ifsname);
1149 		}
1150 	}
1151 	free(b_req_buf);
1152 
1153 	if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1154 		return (-1);
1155 
1156 	for (bp = bridge_port_bif_first(bif); bp != NULL;
1157 	    bp = bridge_port_bif_next(bp)) {
1158 		if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1159 		    bs_req_buf, buf_len)) == NULL)
1160 			bridge_port_clearinfo_opstp(bp);
1161 		else
1162 			bridge_port_getinfo_opstp(bs_req, bp);
1163 	}
1164 	free(bs_req_buf);
1165 
1166 	return (i);
1167 }
1168 
1169 /*
1170  * Update the information for the bridge interface members.
1171  */
1172 int
1173 bridge_update_memif(struct bridge_if *bif)
1174 {
1175 	int added, updated;
1176 	uint32_t i;
1177 	int32_t buf_len;
1178 	struct ifbreq *b_req_buf, *b_req;
1179 	struct ifbpstpreq *bs_req_buf, *bs_req;
1180 	struct bridge_port *bp, *bp_next;
1181 	struct mibif *m_if;
1182 
1183 	if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1184 		return (-1);
1185 
1186 	added = updated = 0;
1187 
1188 #define	BP_FOUND	0x01
1189 	for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1190 		b_req = b_req_buf + i;
1191 
1192 		if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) == NULL) {
1193 			syslog(LOG_ERR, "bridge member %s not present "
1194 			    "in mibII ifTable", b_req->ifbr_ifsname);
1195 			continue;
1196 		}
1197 
1198 		if ((bp = bridge_port_find(m_if->index, bif)) == NULL &&
1199 		    (bp = bridge_new_port(m_if, bif)) != NULL) {
1200 			bp->status = RowStatus_active;
1201 			added++;
1202 		}
1203 
1204 		if (bp != NULL) {
1205 			updated++;
1206 			bridge_port_getinfo_conf(b_req, bp);
1207 			bridge_port_getinfo_mibif(m_if, bp);
1208 			bp->flags |= BP_FOUND;
1209 		}
1210 	}
1211 	free(b_req_buf);
1212 
1213 	/* Clean up list. */
1214 	for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) {
1215 		bp_next  = bridge_port_bif_next(bp);
1216 
1217 		if ((bp->flags & BP_FOUND) == 0 &&
1218 		    bp->status == RowStatus_active)
1219 			bridge_port_remove(bp, bif);
1220 		else
1221 			bp->flags |= ~BP_FOUND;
1222 	}
1223 #undef	BP_FOUND
1224 
1225 	if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1226 		return (-1);
1227 
1228 	for (bp = bridge_port_bif_first(bif); bp != NULL;
1229 	    bp = bridge_port_bif_next(bp)) {
1230 		if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1231 		    bs_req_buf, buf_len)) == NULL)
1232 			bridge_port_clearinfo_opstp(bp);
1233 		else
1234 			bridge_port_getinfo_opstp(bs_req, bp);
1235 	}
1236 	free(bs_req_buf);
1237 	bif->ports_age = time(NULL);
1238 
1239 	return (updated);
1240 }
1241 
1242 /************************************************************************
1243  * Bridge addresses.
1244  */
1245 
1246 /*
1247  * Update the bridge address info according to the polled data.
1248  */
1249 static void
1250 bridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe)
1251 {
1252 	tpe->port_no = if_nametoindex(ifba->ifba_ifsname);
1253 
1254 	if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
1255 		tpe->status = TpFdbStatus_mgmt;
1256 	else
1257 		tpe->status = TpFdbStatus_learned;
1258 }
1259 
1260 /*
1261  * Read the bridge addresses from kernel.
1262  * Return -1 on error, or buffer len if successful.
1263  */
1264 static int32_t
1265 bridge_addrs_getinfo_ifalist(struct bridge_if *bif, struct ifbareq **buf)
1266 {
1267 	int n = 128;
1268 	uint32_t len;
1269 	struct ifbareq *ninbuf;
1270 	struct ifbaconf bac;
1271 	struct ifdrv ifd;
1272 
1273 	*buf = NULL;
1274 	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1275 	ifd.ifd_cmd = BRDGRTS;
1276 	ifd.ifd_len = sizeof(bac);
1277 	ifd.ifd_data = &bac;
1278 
1279 	for ( ; ; ) {
1280 		len = n * sizeof(struct ifbareq);
1281 		if ((ninbuf = (struct ifbareq *)realloc(*buf, len)) == NULL) {
1282 			syslog(LOG_ERR, "get bridge address list: "
1283 			    " realloc failed: %s", strerror(errno));
1284 			free(*buf);
1285 			*buf = NULL;
1286 			return (-1);
1287 		}
1288 
1289 		bac.ifbac_len = len;
1290 		bac.ifbac_req = *buf = ninbuf;
1291 
1292 		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1293 			syslog(LOG_ERR, "get bridge address list: "
1294 			    "ioctl(BRDGRTS) failed: %s", strerror(errno));
1295 			free(*buf);
1296 			buf = NULL;
1297 			return (-1);
1298 		}
1299 
1300 		if ((bac.ifbac_len + sizeof(struct ifbareq)) < len)
1301 			break;
1302 
1303 		n += 64;
1304 	}
1305 
1306 	return (bac.ifbac_len);
1307 }
1308 
1309 /*
1310  * Read the initial info for all addresses on a bridge interface.
1311  * Returns the number of addresses, 0 - if none, otherwise
1312  * -1 if some other error occured.
1313  */
1314 int
1315 bridge_getinfo_bif_addrs(struct bridge_if *bif)
1316 {
1317 	uint32_t i;
1318 	int32_t buf_len;
1319 	struct ifbareq *addr_req_buf, *addr_req;
1320 	struct tp_entry *te;
1321 
1322 	if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1323 		return (-1);
1324 
1325 	for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1326 		addr_req = addr_req_buf + i;
1327 
1328 		if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
1329 			bridge_addrs_info_ifaddrlist(addr_req, te);
1330 	}
1331 
1332 	free(addr_req_buf);
1333 	return (i);
1334 }
1335 
1336 /*
1337  * Update the addresses for the bridge interface.
1338  */
1339 int
1340 bridge_update_addrs(struct bridge_if *bif)
1341 {
1342 	int added, updated;
1343 	uint32_t i;
1344 	int32_t buf_len;
1345 	struct tp_entry *te, *te_next;
1346 	struct ifbareq *addr_req_buf, *addr_req;
1347 
1348 	if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1349 		return (-1);
1350 
1351 	added = updated = 0;
1352 
1353 #define	BA_FOUND	0x01
1354 	for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1355 		addr_req = addr_req_buf + i;
1356 
1357 		if ((te = bridge_addrs_find(addr_req->ifba_dst, bif)) == NULL) {
1358 			added++;
1359 
1360 			if ((te = bridge_new_addrs(addr_req->ifba_dst, bif))
1361 			    == NULL)
1362 				continue;
1363 		} else
1364 			updated++;
1365 
1366 		bridge_addrs_info_ifaddrlist(addr_req, te);
1367 		te-> flags |= BA_FOUND;
1368 	}
1369 	free(addr_req_buf);
1370 
1371 	for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) {
1372 		te_next = bridge_addrs_bif_next(te);
1373 
1374 		if ((te-> flags & BA_FOUND) == 0)
1375 			bridge_addrs_remove(te, bif);
1376 		else
1377 			te-> flags &= ~BA_FOUND;
1378 	}
1379 #undef	BA_FOUND
1380 
1381 	bif->addrs_age = time(NULL);
1382 	return (updated + added);
1383 }
1384 
1385 /************************************************************************
1386  * Bridge packet filtering.
1387  */
1388 const char bridge_sysctl[] = "net.link.bridge.";
1389 
1390 static struct {
1391 	int32_t val;
1392 	const char *name;
1393 } bridge_pf_sysctl[] = {
1394 	{ 1, "pfil_bridge" },
1395 	{ 1, "pfil_member" },
1396 	{ 1, "pfil_onlyip" },
1397 	{ 0, "ipfw" },
1398 };
1399 
1400 int32_t
1401 bridge_get_pfval(uint8_t which)
1402 {
1403 	if (which > sizeof(bridge_pf_sysctl) / sizeof(bridge_pf_sysctl[0])
1404 	    || which < 1)
1405 		return (-1);
1406 
1407 	return (bridge_pf_sysctl[which - 1].val);
1408 }
1409 
1410 int32_t
1411 bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val)
1412 {
1413 	char mib_name[100];
1414 	int32_t i, s_i;
1415 	size_t len, s_len;
1416 
1417 	if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus)
1418 		return (-2);
1419 
1420 	if (op == SNMP_OP_SET) {
1421 		s_i = *val;
1422 		s_len = sizeof(s_i);
1423 	} else
1424 		s_len = 0;
1425 
1426         len = sizeof(i);
1427 
1428 	strcpy(mib_name, bridge_sysctl);
1429 
1430 	if (sysctlbyname(strcat(mib_name,
1431 	    bridge_pf_sysctl[bridge_ctl].name), &i, &len,
1432 	    (op == SNMP_OP_SET ? &s_i : NULL), s_len) == -1) {
1433 		syslog(LOG_ERR, "sysctl(%s%s) failed - %s", bridge_sysctl,
1434 		    bridge_pf_sysctl[bridge_ctl].name, strerror(errno));
1435 		return (-1);
1436 	}
1437 
1438 	bridge_pf_sysctl[bridge_ctl].val = i;
1439 	*val = i;
1440 
1441 	return (i);
1442 }
1443 
1444 void
1445 bridge_pf_dump(void)
1446 {
1447 	uint8_t i;
1448 
1449 	for (i = 0; i < sizeof(bridge_pf_sysctl) / sizeof(bridge_pf_sysctl[0]);
1450 	    i++) {
1451 		syslog(LOG_ERR, "%s%s = %d", bridge_sysctl,
1452 		    bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val);
1453 	}
1454 }
1455