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