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: stable/11/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c 330449 2018-03-05 07:26:05Z eadler $
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#include "bridge_tree.h"
62#include "bridge_snmp.h"
63
64int sock = -1;
65
66int
67bridge_ioctl_init(void)
68{
69	if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
70		syslog(LOG_ERR, "cannot open socket : %s", strerror(errno));
71		return (-1);
72	}
73
74	return (0);
75}
76
77/*
78 * Load the if_bridge.ko module in kernel if not already there.
79 */
80int
81bridge_kmod_load(void)
82{
83	int fileid, modid;
84	const char mod_name[] = "if_bridge";
85	struct module_stat mstat;
86
87	/* Scan files in kernel. */
88	mstat.version = sizeof(struct module_stat);
89	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
90		/* Scan modules in file. */
91		for (modid = kldfirstmod(fileid); modid > 0;
92			modid = modfnext(modid)) {
93
94			if (modstat(modid, &mstat) < 0)
95				continue;
96
97			if (strcmp(mod_name, mstat.name) == 0)
98				return (0);
99		}
100	}
101
102	/* Not present - load it. */
103	if (kldload(mod_name) < 0) {
104		syslog(LOG_ERR, "failed to load %s kernel module", mod_name);
105		return (-1);
106	}
107
108	return (1);
109}
110
111/************************************************************************
112 * Bridge interfaces.
113 */
114
115/*
116 * Convert the kernel uint64_t value for a bridge id
117 */
118static void
119snmp_uint64_to_bridgeid(uint64_t id, bridge_id b_id)
120{
121	int i;
122	u_char *o;
123
124	o = (u_char *) &id;
125
126	for (i = 0; i < SNMP_BRIDGE_ID_LEN; i++, o++)
127		b_id[SNMP_BRIDGE_ID_LEN - i - 1] = *o;
128}
129
130/*
131 * Fetch the bridge configuration parameters from the kernel excluding
132 * it's base MAC address.
133 */
134static int
135bridge_get_conf_param(struct bridge_if *bif)
136{
137	struct ifdrv ifd;
138	struct ifbrparam b_param;
139
140	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
141	ifd.ifd_len = sizeof(b_param);
142	ifd.ifd_data = &b_param;
143
144	/* Bridge priority. */
145	ifd.ifd_cmd = BRDGGPRI;
146	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
147		syslog(LOG_ERR, "update bridge: ioctl(BRDGGPRI) failed: %s",
148		    strerror(errno));
149		return (-1);
150	}
151
152	bif->priority = b_param.ifbrp_prio;
153
154	/* Configured max age. */
155	ifd.ifd_cmd = BRDGGMA;
156	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
157		syslog(LOG_ERR, "update bridge: ioctl(BRDGGMA) failed: %s",
158		    strerror(errno));
159		return (-1);
160	}
161
162	/* Centi-seconds. */
163	bif->bridge_max_age = 100 * b_param.ifbrp_maxage;
164
165	/* Configured hello time. */
166	ifd.ifd_cmd = BRDGGHT;
167	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
168		syslog(LOG_ERR, "update bridge: ioctl(BRDGGHT) failed: %s",
169		    strerror(errno));
170		return (-1);
171	}
172	bif->bridge_hello_time = 100 * b_param.ifbrp_hellotime;
173
174	/* Forward delay. */
175	ifd.ifd_cmd = BRDGGFD;
176	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
177		syslog(LOG_ERR, "update bridge: ioctl(BRDGGFD) failed: %s",
178		    strerror(errno));
179		return (-1);
180	}
181	bif->bridge_fwd_delay = 100 * b_param.ifbrp_fwddelay;
182
183	/* Number of dropped addresses. */
184	ifd.ifd_cmd = BRDGGRTE;
185	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
186		syslog(LOG_ERR, "update bridge: ioctl(BRDGGRTE) failed: %s",
187		    strerror(errno));
188		return (-1);
189	}
190	bif->lrnt_drops = b_param.ifbrp_cexceeded;
191
192	/* Address table timeout. */
193	ifd.ifd_cmd = BRDGGTO;
194	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
195		syslog(LOG_ERR, "update bridge: ioctl(BRDGGTO) failed: %s",
196		    strerror(errno));
197		return (-1);
198	}
199	bif->age_time = b_param.ifbrp_ctime;
200
201	/* Address table size. */
202	ifd.ifd_cmd = BRDGGCACHE;
203	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
204		syslog(LOG_ERR, "update bridge: ioctl(BRDGGCACHE) "
205		    "failed: %s", strerror(errno));
206		return (-1);
207	}
208	bif->max_addrs = b_param.ifbrp_csize;
209
210	return (0);
211}
212
213/*
214 * Fetch the current bridge STP operational parameters.
215 * Returns: -1 - on error;
216 *	     0 - old TC time and Root Port values are same;
217 *	     1 - topologyChange notification should be sent;
218 *	     2 - newRoot notification should be sent.
219 */
220int
221bridge_get_op_param(struct bridge_if *bif)
222{
223	int new_root_send;
224	struct ifdrv ifd;
225	struct ifbropreq b_req;
226
227	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
228	ifd.ifd_len = sizeof(b_req);
229	ifd.ifd_data = &b_req;
230	ifd.ifd_cmd = BRDGPARAM;
231
232	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
233		syslog(LOG_ERR, "update bridge: ioctl(BRDGPARAM) failed: %s",
234		    strerror(errno));
235		return (-1);
236	}
237
238	bif->max_age = 100 * b_req.ifbop_maxage;
239	bif->hello_time = 100 * b_req.ifbop_hellotime;
240	bif->fwd_delay = 100 * b_req.ifbop_fwddelay;
241	bif->stp_version = b_req.ifbop_protocol;
242	bif->tx_hold_count = b_req.ifbop_holdcount;
243
244	if (b_req.ifbop_root_port == 0 &&
245	    bif->root_port != b_req.ifbop_root_port)
246		new_root_send = 2;
247	else
248		new_root_send = 0;
249
250	bif->root_port = b_req.ifbop_root_port;
251	bif->root_cost = b_req.ifbop_root_path_cost;
252	snmp_uint64_to_bridgeid(b_req.ifbop_designated_root,
253	    bif->design_root);
254
255	if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) {
256		bif->top_changes++;
257		bif->last_tc_time.tv_sec = b_req.ifbop_last_tc_time.tv_sec;
258		bif->last_tc_time.tv_usec = b_req.ifbop_last_tc_time.tv_usec;
259
260		/*
261		 * "The trap is not sent if a (begemotBridge)NewRoot
262		 * trap is sent for the same transition."
263		 */
264		if (new_root_send == 0)
265			return (1);
266	}
267
268	return (new_root_send);
269}
270
271int
272bridge_getinfo_bif(struct bridge_if *bif)
273{
274	if (bridge_get_conf_param(bif) < 0)
275		return (-1);
276
277	return (bridge_get_op_param(bif));
278}
279
280int
281bridge_set_priority(struct bridge_if *bif, int32_t priority)
282{
283	struct ifdrv ifd;
284	struct ifbrparam b_param;
285
286	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
287	ifd.ifd_len = sizeof(b_param);
288	ifd.ifd_data = &b_param;
289	b_param.ifbrp_prio = (uint32_t) priority;
290	ifd.ifd_cmd = BRDGSPRI;
291
292	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
293		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) "
294		    "failed: %s", strerror(errno));
295		return (-1);
296	}
297
298	/*
299	 * Re-fetching the data from the driver after that might be a good
300	 * idea, since changing our bridge's priority should invoke
301	 * recalculation of the active spanning tree topology in the network.
302	 */
303	bif->priority = priority;
304	return (0);
305}
306
307/*
308 * Convert 1/100 of seconds to 1/256 of seconds.
309 * Timeout ::= TEXTUAL-CONVENTION.
310 * To convert a Timeout value into a value in units of
311 * 1/256 seconds, the following algorithm should be used:
312 *	b = floor( (n * 256) / 100)
313 * The conversion to 1/256 of a second happens in the kernel -
314 * just make sure we correctly convert the seconds to Timout
315 * and vice versa.
316 */
317static uint32_t
318snmp_timeout2_sec(int32_t secs)
319{
320	return (secs / 100);
321}
322
323int
324bridge_set_maxage(struct bridge_if *bif, int32_t max_age)
325{
326	struct ifdrv ifd;
327	struct ifbrparam b_param;
328
329	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
330	ifd.ifd_len = sizeof(b_param);
331	ifd.ifd_data = &b_param;
332	b_param.ifbrp_maxage = snmp_timeout2_sec(max_age);
333	ifd.ifd_cmd = BRDGSMA;
334
335	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
336		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) "
337		    "failed: %s", strerror(errno));
338		return (-1);
339	}
340
341	bif->bridge_max_age = max_age;
342	return (0);
343}
344
345int
346bridge_set_hello_time(struct bridge_if *bif, int32_t hello_time)
347{
348	struct ifdrv ifd;
349	struct ifbrparam b_param;
350
351	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
352	ifd.ifd_len = sizeof(b_param);
353	ifd.ifd_data = &b_param;
354	b_param.ifbrp_hellotime = snmp_timeout2_sec(hello_time);
355	ifd.ifd_cmd = BRDGSHT;
356
357	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
358		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) "
359		    "failed: %s", strerror(errno));
360		return (-1);
361	}
362
363	bif->bridge_hello_time = b_param.ifbrp_hellotime;
364	return (0);
365}
366
367int
368bridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay)
369{
370	struct ifdrv ifd;
371	struct ifbrparam b_param;
372
373	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
374	ifd.ifd_len = sizeof(b_param);
375	ifd.ifd_data = &b_param;
376	b_param.ifbrp_fwddelay = snmp_timeout2_sec(fwd_delay);
377	ifd.ifd_cmd = BRDGSFD;
378
379	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
380		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) "
381		    "failed: %s", strerror(errno));
382		return (-1);
383	}
384
385	bif->bridge_fwd_delay = b_param.ifbrp_fwddelay;
386	return (0);
387}
388
389int
390bridge_set_aging_time(struct bridge_if *bif, int32_t age_time)
391{
392	struct ifdrv ifd;
393	struct ifbrparam b_param;
394
395	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
396	ifd.ifd_len = sizeof(b_param);
397	ifd.ifd_data = &b_param;
398	b_param.ifbrp_ctime = (uint32_t) age_time;
399	ifd.ifd_cmd = BRDGSTO;
400
401	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
402		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) "
403		    "failed: %s", strerror(errno));
404		return (-1);
405	}
406
407	bif->age_time = age_time;
408	return (0);
409}
410
411int
412bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache)
413{
414	struct ifdrv ifd;
415	struct ifbrparam b_param;
416
417	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
418	ifd.ifd_len = sizeof(b_param);
419	ifd.ifd_data = &b_param;
420	b_param.ifbrp_csize = max_cache;
421	ifd.ifd_cmd = BRDGSCACHE;
422
423	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
424		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) "
425		    "failed: %s", strerror(errno));
426		return (-1);
427	}
428
429	bif->max_addrs = b_param.ifbrp_csize;
430	return (0);
431}
432
433int
434bridge_set_tx_hold_count(struct bridge_if *bif, int32_t tx_hc)
435{
436	struct ifdrv ifd;
437	struct ifbrparam b_param;
438
439	if (tx_hc < SNMP_BRIDGE_MIN_TXHC || tx_hc > SNMP_BRIDGE_MAX_TXHC)
440		return (-1);
441
442	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
443	ifd.ifd_len = sizeof(b_param);
444	ifd.ifd_data = &b_param;
445	b_param.ifbrp_txhc = tx_hc;
446	ifd.ifd_cmd = BRDGSTXHC;
447
448	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
449		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTXHC) "
450		    "failed: %s", strerror(errno));
451		return (-1);
452	}
453
454	bif->tx_hold_count = b_param.ifbrp_txhc;
455	return (0);
456}
457
458int
459bridge_set_stp_version(struct bridge_if *bif, int32_t stp_proto)
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 */
483int
484bridge_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	strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_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
514int
515bridge_create(const char *b_name)
516{
517	char *new_name;
518	struct ifreq ifr;
519
520	bzero(&ifr, sizeof(ifr));
521	strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_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
548int
549bridge_destroy(const char *b_name)
550{
551	struct ifreq ifr;
552
553	bzero(&ifr, sizeof(ifr));
554	strlcpy(ifr.ifr_name, b_name, sizeof(ifr.ifr_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 */
569u_char *
570bridge_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.
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