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
65int sock = -1;
66
67int
68bridge_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 */
81int
82bridge_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 */
119static void
120snmp_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 */
135static int
136bridge_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 */
221int
222bridge_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
272int
273bridge_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
281int
282bridge_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 */
318static uint32_t
319snmp_timeout2_sec(int32_t secs)
320{
321	return (secs / 100);
322}
323
324int
325bridge_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
346int
347bridge_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
368int
369bridge_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
390int
391bridge_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
412int
413bridge_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
434int
435bridge_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
459int
460bridge_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 */
484int
485bridge_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
515int
516bridge_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
549int
550bridge_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 */
570u_char *
571bridge_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 */
621static int
622state2snmp_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 */
644static void
645bridge_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 */
712static void
713bridge_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 */
727static void
728bridge_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 */
744int
745bridge_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 */
772int
773bridge_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 */
814int
815bridge_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 */
847int
848bridge_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 */
898int
899bridge_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 */
942int
943bridge_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 */
988int
989bridge_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 */
1021int
1022bridge_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 */
1055static int32_t
1056bridge_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 */
1104static int32_t
1105bridge_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 */
1153static struct ifbpstpreq *
1154bridge_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 */
1174int
1175bridge_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 */
1223int
1224bridge_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 */
1300static void
1301bridge_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 */
1315static int32_t
1316bridge_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 */
1365int
1366bridge_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 */
1390int
1391bridge_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 */
1439const char bridge_sysctl[] = "net.link.bridge.";
1440
1441static 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
1451int32_t
1452bridge_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
1461int32_t
1462bridge_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
1500void
1501bridge_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