bridge_sys.c revision 164410
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: head/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c 164410 2006-11-19 15:42:48Z syrinx $
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#if __FreeBSD_version > 700018
40#include <net/bridgestp.h>
41#endif
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
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	/* Sanity check. */
285	if (priority > SNMP_BRIDGE_MAX_PRIORITY || priority % 4096 != 0)
286		return (-1);
287
288	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
289	ifd.ifd_len = sizeof(b_param);
290	ifd.ifd_data = &b_param;
291	b_param.ifbrp_prio = (uint32_t) priority;
292	ifd.ifd_cmd = BRDGSPRI;
293
294	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
295		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) "
296		    "failed: %s", strerror(errno));
297		return (-1);
298	}
299
300	/*
301	 * Re-fetching the data from the driver after that might be a good
302	 * idea, since changing our bridge's priority should invoke
303	 * recalculation of the active spanning tree topology in the network.
304	 */
305	bif->priority = priority;
306	return (0);
307}
308
309/*
310 * Convert 1/100 of seconds to 1/256 of seconds.
311 * Timeout ::= TEXTUAL-CONVENTION.
312 * To convert a Timeout value into a value in units of
313 * 1/256 seconds, the following algorithm should be used:
314 *	b = floor( (n * 256) / 100)
315 */
316static uint32_t
317snmp_hundred_secs2_256(int32_t h_secs)
318{
319	return ((h_secs * 256) / 100);
320}
321
322int
323bridge_set_maxage(struct bridge_if *bif, int32_t max_age)
324{
325	struct ifdrv ifd;
326	struct ifbrparam b_param;
327
328	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
329	ifd.ifd_len = sizeof(b_param);
330	ifd.ifd_data = &b_param;
331	b_param.ifbrp_maxage = (uint32_t) max_age;
332	ifd.ifd_cmd = BRDGSMA;
333
334	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
335		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) "
336		    "failed: %s", strerror(errno));
337		return (-1);
338	}
339
340	bif->bridge_max_age = max_age;
341	return (0);
342}
343
344int
345bridge_set_hello_time(struct bridge_if *bif, int32_t hello_time)
346{
347	struct ifdrv ifd;
348	struct ifbrparam b_param;
349
350	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
351	ifd.ifd_len = sizeof(b_param);
352	ifd.ifd_data = &b_param;
353	b_param.ifbrp_hellotime = snmp_hundred_secs2_256(hello_time);
354	ifd.ifd_cmd = BRDGSHT;
355
356	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
357		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) "
358		    "failed: %s", strerror(errno));
359		return (-1);
360	}
361
362	bif->bridge_hello_time = b_param.ifbrp_hellotime;
363	return (0);
364}
365
366int
367bridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay)
368{
369	struct ifdrv ifd;
370	struct ifbrparam b_param;
371
372	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
373	ifd.ifd_len = sizeof(b_param);
374	ifd.ifd_data = &b_param;
375	b_param.ifbrp_fwddelay = snmp_hundred_secs2_256(fwd_delay);
376	ifd.ifd_cmd = BRDGSFD;
377
378	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
379		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) "
380		    "failed: %s", strerror(errno));
381		return (-1);
382	}
383
384	bif->bridge_fwd_delay = b_param.ifbrp_fwddelay;
385	return (0);
386}
387
388int
389bridge_set_aging_time(struct bridge_if *bif, int32_t age_time)
390{
391	struct ifdrv ifd;
392	struct ifbrparam b_param;
393
394	/* Sanity check. */
395	if (age_time < SNMP_BRIDGE_MIN_AGE_TIME ||
396	    age_time > SNMP_BRIDGE_MAX_AGE_TIME)
397		return (-1);
398
399	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
400	ifd.ifd_len = sizeof(b_param);
401	ifd.ifd_data = &b_param;
402	b_param.ifbrp_ctime = (uint32_t) age_time;
403	ifd.ifd_cmd = BRDGSTO;
404
405	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
406		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) "
407		    "failed: %s", strerror(errno));
408		return (-1);
409	}
410
411	bif->age_time = age_time;
412	return (0);
413}
414
415int
416bridge_set_max_cache(struct bridge_if *bif, int32_t max_cache)
417{
418	struct ifdrv ifd;
419	struct ifbrparam b_param;
420
421	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
422	ifd.ifd_len = sizeof(b_param);
423	ifd.ifd_data = &b_param;
424	b_param.ifbrp_csize = max_cache;
425	ifd.ifd_cmd = BRDGSCACHE;
426
427	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
428		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) "
429		    "failed: %s", strerror(errno));
430		return (-1);
431	}
432
433	bif->max_addrs = b_param.ifbrp_csize;
434	return (0);
435}
436
437/*
438 * Set the bridge interface status to up/down.
439 */
440int
441bridge_set_if_up(const char* b_name, int8_t up)
442{
443	int	flags;
444	struct ifreq ifr;
445
446	bzero(&ifr, sizeof(ifr));
447	strcpy(ifr.ifr_name, b_name);
448	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
449		syslog(LOG_ERR, "set bridge up: ioctl(SIOCGIFFLAGS) "
450		    "failed: %s", strerror(errno));
451		return (-1);
452	}
453
454	flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
455	if (up == 1)
456		flags |= IFF_UP;
457	else
458		flags &= ~IFF_UP;
459
460	ifr.ifr_flags = flags & 0xffff;
461	ifr.ifr_flagshigh = flags >> 16;
462	if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
463		syslog(LOG_ERR, "set bridge up: ioctl(SIOCSIFFLAGS) "
464		    "failed: %s", strerror(errno));
465		return (-1);
466	}
467
468	return (0);
469}
470
471int
472bridge_create(const char *b_name)
473{
474	char *new_name;
475	struct ifreq ifr;
476
477	bzero(&ifr, sizeof(ifr));
478	strcpy(ifr.ifr_name, b_name);
479
480	if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) {
481		syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) "
482		    "failed: %s", strerror(errno));
483		return (-1);
484	}
485
486	if (strcmp(b_name, ifr.ifr_name) == 0)
487		return (0);
488
489	if ((new_name = strdup(b_name)) == NULL) {
490		syslog(LOG_ERR, "create bridge: strdup() failed");
491		return (-1);
492	}
493
494	ifr.ifr_data = new_name;
495	if (ioctl(sock, SIOCSIFNAME, (caddr_t) &ifr) < 0) {
496		syslog(LOG_ERR, "create bridge: ioctl(SIOCSIFNAME) "
497		    "failed: %s", strerror(errno));
498		free(new_name);
499		return (-1);
500	}
501
502	return (0);
503}
504
505int
506bridge_destroy(const char *b_name)
507{
508	struct ifreq ifr;
509
510	bzero(&ifr, sizeof(ifr));
511	strcpy(ifr.ifr_name, b_name);
512
513	if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) {
514		syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) "
515		    "failed: %s", strerror(errno));
516		return (-1);
517	}
518
519	return (0);
520}
521
522/*
523 * Fetch the bridge base MAC address. Return pointer to the
524 * buffer containing the mac address, NULL on failure.
525 */
526u_char *
527bridge_get_basemac(const char *bif_name, u_char *mac)
528{
529	int len;
530	char if_name[IFNAMSIZ];
531	struct ifaddrs *ifap, *tmp;
532	struct sockaddr_dl *sdl;
533
534	if (getifaddrs(&ifap) < 0) {
535		syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s",
536		    strerror(errno));
537		return (NULL);
538	}
539
540	for (tmp = ifap; tmp != NULL; tmp = tmp->ifa_next) {
541		sdl = (struct sockaddr_dl *) tmp->ifa_addr;
542
543		if ((len = sdl->sdl_nlen) >= IFNAMSIZ)
544			len = IFNAMSIZ - 1;
545
546		bcopy(sdl->sdl_data, if_name, len);
547		if_name[len] = '\0';
548
549		if (sdl->sdl_family == AF_LINK && !strncmp(bif_name,
550		    if_name, strlen(bif_name))) {
551			bcopy(sdl->sdl_data + sdl->sdl_nlen, mac,
552			     ETHER_ADDR_LEN);
553			freeifaddrs(ifap);
554			return (mac);
555		}
556	}
557
558	freeifaddrs(ifap);
559	return (NULL);
560}
561
562/************************************************************************
563 * Bridge ports.
564 */
565
566/*
567 * Convert the kernel STP port state into
568 * the corresopnding enumerated type from SNMP Bridge MIB.
569 */
570static int
571state2snmp_st(uint8_t ifbr_state)
572{
573	switch (ifbr_state) {
574		case BSTP_IFSTATE_DISABLED:
575			return (StpPortState_disabled);
576		case BSTP_IFSTATE_LISTENING:
577			return (StpPortState_listening);
578		case BSTP_IFSTATE_LEARNING:
579			return (StpPortState_learning);
580		case BSTP_IFSTATE_FORWARDING:
581			return (StpPortState_forwarding);
582		case BSTP_IFSTATE_BLOCKING:
583			return (StpPortState_blocking);
584	}
585
586	return (StpPortState_broken);
587}
588
589/*
590 * Fill in a bridge member information according to data polled from kernel.
591 */
592static void
593bridge_port_getinfo_conf(struct ifbreq *k_info, struct bridge_port *bp)
594{
595	bp->state = state2snmp_st(k_info->ifbr_state);
596	bp->priority = k_info->ifbr_priority;
597
598	/*
599	 * RFC 4188:
600	 * "New implementations should support dot1dStpPortPathCost32.
601	 * If the port path costs exceeds the maximum value of this
602	 * object then this object should report the maximum value,
603	 * namely 65535.  Applications should try to read the
604	 * dot1dStpPortPathCost32 object if this object reports
605	 * the maximum value."
606	 */
607
608#if 0
609	/*
610	 * Kernel variable is a 32-bit integer but the ioctl supports
611	 * only getting/setting a 8-bit value.
612	 */
613
614	if (k_info->ifbr_path_cost > SNMP_PORT_PATHCOST_OBSOLETE) {
615		bp->path_cost = SNMP_PORT_PATHCOST_OBSOLETE;
616		bp->path_cost32 = k_info->ifbr_path_cost;
617	} else
618
619		bp->path_cost = bp->path_cost32 = k_info->ifbr_path_cost;
620#endif
621
622	bp->path_cost = k_info->ifbr_path_cost;
623
624	if (k_info->ifbr_ifsflags & IFBIF_STP)
625		bp->enable = dot1dStpPortEnable_enabled;
626	else
627		bp->enable = dot1dStpPortEnable_disabled;
628
629	/* Begemot Bridge MIB only. */
630	if (k_info->ifbr_ifsflags & IFBIF_SPAN)
631		bp->span_enable = begemotBridgeBaseSpanEnabled_enabled;
632	else
633		bp->span_enable = begemotBridgeBaseSpanEnabled_disabled;
634}
635
636/*
637 * Fill in a bridge interface STP information according to
638 * data polled from kernel.
639 */
640static void
641bridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp)
642{
643	bp->enable = dot1dStpPortEnable_enabled;
644	bp->fwd_trans = bp_stp->ifbp_fwd_trans;
645	bp->design_cost = bp_stp->ifbp_design_cost;
646	snmp_uint64_to_bridgeid(bp_stp->ifbp_design_root, bp->design_root);
647	snmp_uint64_to_bridgeid(bp_stp->ifbp_design_bridge, bp->design_bridge);
648	bcopy(&(bp_stp->ifbp_design_port), &(bp->design_port),
649	    sizeof(uint16_t));
650}
651
652/*
653 * Clear a bridge interface STP information.
654 */
655static void
656bridge_port_clearinfo_opstp(struct bridge_port *bp)
657{
658	if (bp->enable == dot1dStpPortEnable_enabled) {
659		bp->design_cost = 0;
660		bzero(&(bp->design_root), sizeof(bridge_id));
661		bzero(&(bp->design_bridge), sizeof(bridge_id));
662		bzero(&(bp->design_port), sizeof(port_id));
663		bp->fwd_trans = 0;
664	}
665
666	bp->enable = dot1dStpPortEnable_disabled;
667}
668
669/*
670 * Set a bridge member priority.
671 */
672int
673bridge_port_set_priority(const char *bif_name, struct bridge_port *bp,
674	int32_t priority)
675{
676	struct ifdrv ifd;
677	struct ifbreq b_req;
678
679	if (priority < 0 || priority > 255)
680		return (-2);
681
682	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
683	ifd.ifd_len = sizeof(b_req);
684	ifd.ifd_data = &b_req;
685	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
686
687	b_req.ifbr_priority = (uint8_t) priority;
688	ifd.ifd_cmd = BRDGSIFPRIO;
689
690	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
691		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFPRIO) "
692		    "failed: %s", bp->p_name, strerror(errno));
693		return (-1);
694	}
695
696	bp->priority = priority;
697	return (0);
698}
699
700/*
701 * Set a bridge member STP-enabled flag.
702 */
703int
704bridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp,
705	uint32_t enable)
706{
707	struct ifdrv ifd;
708	struct ifbreq b_req;
709
710	if (bp->enable == enable)
711		return (0);
712
713	if (enable != dot1dStpPortEnable_enabled &&
714	    enable != dot1dStpPortEnable_disabled)
715		return (-2);
716
717	bzero(&b_req, sizeof(b_req));
718	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
719	ifd.ifd_len = sizeof(b_req);
720	ifd.ifd_data = &b_req;
721	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
722	ifd.ifd_cmd = BRDGGIFFLGS;
723
724	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
725		syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
726		    "failed: %s", bp->p_name, strerror(errno));
727		return (-1);
728	}
729
730	if (enable == dot1dStpPortEnable_enabled)
731		b_req.ifbr_ifsflags |= IFBIF_STP;
732	else
733		b_req.ifbr_ifsflags &= ~IFBIF_STP;
734
735	ifd.ifd_cmd = BRDGSIFFLGS;
736	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
737		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
738		    "failed: %s", bp->p_name, strerror(errno));
739		return (-1);
740	}
741
742	bp->enable = enable;
743	return (0);
744}
745
746/*
747 * Set a bridge member STP path cost.
748 */
749int
750bridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp,
751	int32_t path_cost)
752{
753	struct ifdrv ifd;
754	struct ifbreq b_req;
755
756	if (path_cost > SNMP_PORT_PATHCOST_OBSOLETE)
757		return (-2);
758
759	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
760	ifd.ifd_len = sizeof(b_req);
761	ifd.ifd_data = &b_req;
762	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
763
764	b_req.ifbr_path_cost = (uint16_t) path_cost;
765	ifd.ifd_cmd = BRDGSIFCOST;
766
767	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
768		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFCOST) "
769		    "failed: %s", bp->p_name, strerror(errno));
770		return (-1);
771	}
772
773	bp->path_cost = path_cost;
774	return (0);
775}
776
777/*
778 * Add a bridge member port.
779 */
780int
781bridge_port_addm(struct bridge_port *bp, const char *b_name)
782{
783	struct ifdrv ifd;
784	struct ifbreq b_req;
785
786	bzero(&ifd, sizeof(ifd));
787	bzero(&b_req, sizeof(b_req));
788
789	strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
790	ifd.ifd_len = sizeof(b_req);
791	ifd.ifd_data = &b_req;
792	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
793
794	if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
795		ifd.ifd_cmd = BRDGADDS;
796	else
797		ifd.ifd_cmd = BRDGADD;
798
799	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
800		syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
801		    bp->p_name,
802		    (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"),
803		    strerror(errno));
804		return (-1);
805	}
806
807	return (0);
808}
809
810/*
811 * Delete a bridge member port.
812 */
813int
814bridge_port_delm(struct bridge_port *bp, const char *b_name)
815{
816	struct ifdrv ifd;
817	struct ifbreq b_req;
818
819	bzero(&ifd, sizeof(ifd));
820	bzero(&b_req, sizeof(b_req));
821
822	strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
823	ifd.ifd_len = sizeof(b_req);
824	ifd.ifd_data = &b_req;
825	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
826
827	if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
828		ifd.ifd_cmd = BRDGDELS;
829	else
830		ifd.ifd_cmd = BRDGDEL;
831
832	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
833		syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
834		    bp->p_name,
835		    (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"),
836		    strerror(errno));
837		return (-1);
838	}
839
840	return (0);
841}
842
843/*
844 * Fetch the bridge member list from kernel.
845 * Return -1 on error, or buffer len if successful.
846 */
847static int32_t
848bridge_port_get_iflist(struct bridge_if *bif, char **buf)
849{
850	uint32_t len = 8192; /* ??? */
851	char *ninbuf;
852	struct ifbifconf ifbc;
853	struct ifdrv ifd;
854
855	*buf = NULL;
856	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
857	ifd.ifd_cmd = BRDGGIFS;
858	ifd.ifd_len = sizeof(ifbc);
859	ifd.ifd_data = &ifbc;
860
861	for ( ; ; ) {
862		if ((ninbuf = realloc(*buf, len) /* ??? */) == NULL) {
863			syslog(LOG_ERR, "get bridge member list: "
864			    "realloc failed: %s", strerror(errno));
865			free(*buf);
866			*buf = NULL;
867			return (-1);
868		}
869
870		ifbc.ifbic_len = len;
871		ifbc.ifbic_buf = *buf = ninbuf;
872
873		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
874			syslog(LOG_ERR, "get bridge member list: ioctl "
875			    "(BRDGGIFS) failed: %s", strerror(errno));
876			free(*buf);
877			buf = NULL;
878			return (-1);
879		}
880
881		if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len)
882			break;
883
884		len += 8192;
885	}
886
887	return (ifbc.ifbic_len);
888}
889
890/*
891 * Fetch the bridge STP member list from kernel.
892 * Return -1 on error, or buffer len if successful.
893 */
894static int32_t
895bridge_port_get_ifstplist(struct bridge_if *bif, char **buf)
896{
897	uint32_t len = 8192; /* ??? */
898	char *ninbuf;
899	struct ifbpstpconf ifbstp;
900	struct ifdrv ifd;
901
902	*buf = NULL;
903	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
904	ifd.ifd_cmd = BRDGGIFSSTP;
905	ifd.ifd_len = sizeof(ifbstp);
906	ifd.ifd_data = &ifbstp;
907
908	for ( ; ; ) {
909		if ((ninbuf = realloc(*buf, len) /* ??? */) == NULL) {
910			syslog(LOG_ERR, "get bridge STP ports list: "
911			    "realloc failed: %s", strerror(errno));
912			free(*buf);
913			*buf = NULL;
914			return (-1);
915		}
916
917		ifbstp.ifbpstp_len = len;
918		ifbstp.ifbpstp_buf = *buf = ninbuf;
919
920		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
921			syslog(LOG_ERR, "get bridge STP ports list: ioctl "
922			    "(BRDGGIFSSTP) failed: %s", strerror(errno));
923			free(*buf);
924			buf = NULL;
925			return (-1);
926		}
927
928		if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len)
929			break;
930
931		len += 8192;
932	}
933
934	return (ifbstp.ifbpstp_len);
935}
936
937/*
938 * Locate a bridge if STP params structure in a buffer.
939 */
940static struct ifbpstpreq *
941bridge_port_find_ifstplist(uint8_t port_no, char *buf, uint32_t buf_len)
942{
943	uint32_t i;
944	struct ifbpstpreq *bstp;
945
946	for (i = 0; i < buf_len / sizeof(*bstp); i++) {
947		bstp =  (struct ifbpstpreq *) buf + i;
948		if (bstp->ifbp_portno == port_no)
949			return (bstp);
950	}
951
952	return (NULL);
953}
954
955/*
956 * Read the initial info for all members of a bridge interface.
957 * Returns the number of ports, 0 - if none, otherwise
958 * -1 if some other error occured.
959 */
960int
961bridge_getinfo_bif_ports(struct bridge_if *bif)
962{
963	uint32_t i;
964	int32_t buf_len;
965	char *mem_buf;
966	struct ifbreq *b_req;
967	struct ifbpstpreq *bs_req;
968	struct bridge_port *bp;
969	struct mibif *m_if;
970
971	if ((buf_len = bridge_port_get_iflist(bif, &mem_buf)) < 0)
972		return (-1);
973
974	for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
975		b_req = (struct ifbreq *) mem_buf + i;
976
977		if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) != NULL) {
978			/* Hopefully we will not fail here. */
979			if ((bp = bridge_new_port(m_if, bif)) != NULL) {
980				bp->status = RowStatus_active;
981				bridge_port_getinfo_conf(b_req, bp);
982				bridge_port_getinfo_mibif(m_if, bp);
983			}
984		} else {
985			syslog(LOG_ERR, "bridge member %s not present "
986			    "in mibII ifTable", b_req->ifbr_ifsname);
987		}
988	}
989	free(mem_buf);
990
991	if ((buf_len = bridge_port_get_ifstplist(bif, &mem_buf)) < 0)
992		return (-1);
993
994	for (bp = bridge_port_bif_first(bif); bp != NULL;
995	    bp = bridge_port_bif_next(bp)) {
996		if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
997		    mem_buf, buf_len)) == NULL)
998			bridge_port_clearinfo_opstp(bp);
999		else
1000			bridge_port_getinfo_opstp(bs_req, bp);
1001	}
1002	free(mem_buf);
1003
1004	return (i);
1005}
1006
1007/*
1008 * Update the information for the bridge interface members.
1009 */
1010int
1011bridge_update_memif(struct bridge_if *bif)
1012{
1013	int added, updated;
1014	uint32_t i;
1015	int32_t buf_len;
1016	char *if_buf;
1017	struct ifbreq *b_req;
1018	struct ifbpstpreq *bs_req;
1019	struct bridge_port *bp, *bp_next;
1020	struct mibif *m_if;
1021
1022	if ((buf_len = bridge_port_get_iflist(bif, &if_buf)) < 0)
1023		return (-1);
1024
1025	added = updated = 0;
1026
1027#define	BP_FOUND	0x01
1028	for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1029		b_req = (struct ifbreq *) if_buf + i;
1030
1031		if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) == NULL) {
1032			syslog(LOG_ERR, "bridge member %s not present "
1033			    "in mibII ifTable", b_req->ifbr_ifsname);
1034			continue;
1035		}
1036
1037		if ((bp = bridge_port_find(m_if->index, bif)) == NULL &&
1038		    (bp = bridge_new_port(m_if, bif)) != NULL) {
1039			bp->status = RowStatus_active;
1040			added++;
1041		}
1042
1043		if (bp != NULL) {
1044			updated++;
1045			bridge_port_getinfo_conf(b_req, bp);
1046			bridge_port_getinfo_mibif(m_if, bp);
1047			bp->flags |= BP_FOUND;
1048		}
1049	}
1050	free(if_buf);
1051
1052	/* Clean up list. */
1053	for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) {
1054		bp_next  = bridge_port_bif_next(bp);
1055
1056		if ((bp->flags & BP_FOUND) == 0 &&
1057		    bp->status == RowStatus_active)
1058			bridge_port_remove(bp, bif);
1059		else
1060			bp->flags |= ~BP_FOUND;
1061	}
1062#undef	BP_FOUND
1063
1064	if ((buf_len = bridge_port_get_ifstplist(bif, &if_buf)) < 0)
1065		return (-1);
1066
1067	for (bp = bridge_port_bif_first(bif); bp != NULL;
1068	    bp = bridge_port_bif_next(bp)) {
1069		if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1070		    if_buf, buf_len)) == NULL)
1071			bridge_port_clearinfo_opstp(bp);
1072		else
1073			bridge_port_getinfo_opstp(bs_req, bp);
1074	}
1075	free(if_buf);
1076	bif->ports_age = time(NULL);
1077
1078	return (updated);
1079}
1080
1081/************************************************************************
1082 * Bridge addresses.
1083 */
1084
1085/*
1086 * Update the bridge address info according to the polled data.
1087 */
1088static void
1089bridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe)
1090{
1091	tpe->port_no = if_nametoindex(ifba->ifba_ifsname);
1092
1093	if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
1094		tpe->status = TpFdbStatus_mgmt;
1095	else
1096		tpe->status = TpFdbStatus_learned;
1097}
1098
1099/*
1100 * Read the bridge addresses from kernel.
1101 * Return -1 on error, or buffer len if successful.
1102 */
1103static int32_t
1104bridge_addrs_getinfo_ifalist(struct bridge_if *bif, char **buf)
1105{
1106	uint32_t len = 8192; /* ??? */
1107	char *ninbuf;
1108	struct ifbaconf bac;
1109	struct ifdrv ifd;
1110
1111	*buf = NULL;
1112	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1113	ifd.ifd_cmd = BRDGRTS;
1114	ifd.ifd_len = sizeof(bac);
1115	ifd.ifd_data = &bac;
1116
1117	for ( ; ; ) {
1118		if ((ninbuf = realloc(*buf, len) /* ??? */) == NULL) {
1119			syslog(LOG_ERR, "get bridge address list: "
1120			    " realloc failed: %s", strerror(errno));
1121			free(*buf);
1122			*buf = NULL;
1123			return (-1);
1124		}
1125
1126		bac.ifbac_len = len;
1127		bac.ifbac_buf = *buf = ninbuf;
1128
1129		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1130			syslog(LOG_ERR, "get bridge address list: "
1131			    "ioctl(BRDGRTS) failed: %s", strerror(errno));
1132			free(*buf);
1133			buf = NULL;
1134			return (-1);
1135		}
1136
1137		if ((bac.ifbac_len + sizeof(struct ifbareq)) < len)
1138			break;
1139
1140		len += 8192;
1141	}
1142
1143	return (bac.ifbac_len);
1144}
1145
1146/*
1147 * Read the initial info for all addresses on a bridge interface.
1148 * Returns the number of addresses, 0 - if none, otherwise
1149 * -1 if some other error occured.
1150 */
1151int
1152bridge_getinfo_bif_addrs(struct bridge_if *bif)
1153{
1154	uint32_t i;
1155	int32_t buf_len;
1156	char *addr_buf;
1157	struct ifbareq *addr_req;
1158	struct tp_entry *te;
1159
1160	if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_buf)) < 0)
1161		return (-1);
1162
1163	for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1164		addr_req = (struct ifbareq *) addr_buf + i;
1165
1166		if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
1167			bridge_addrs_info_ifaddrlist(addr_req, te);
1168	}
1169
1170	free(addr_buf);
1171	return (i);
1172}
1173
1174/*
1175 * Update the addresses for the bridge interface.
1176 */
1177int
1178bridge_update_addrs(struct bridge_if *bif)
1179{
1180	int added, updated;
1181	uint32_t i;
1182	int32_t buf_len;
1183	char *ifbad_buf;
1184	struct tp_entry *te, *te_next;
1185	struct ifbareq *a_req;
1186
1187	if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &ifbad_buf)) < 0)
1188		return (-1);
1189
1190	added = updated = 0;
1191
1192#define	BA_FOUND	0x01
1193	for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1194		a_req = (struct ifbareq *) ifbad_buf + i;
1195
1196		if ((te = bridge_addrs_find(a_req->ifba_dst, bif)) == NULL) {
1197			added++;
1198
1199			if ((te = bridge_new_addrs(a_req->ifba_dst, bif))
1200			    == NULL)
1201				continue;
1202		} else
1203			updated++;
1204
1205		bridge_addrs_info_ifaddrlist(a_req, te);
1206		te-> flags |= BA_FOUND;
1207	}
1208	free(ifbad_buf);
1209
1210	for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) {
1211		te_next = bridge_addrs_bif_next(te);
1212
1213		if ((te-> flags & BA_FOUND) == 0)
1214			bridge_addrs_remove(te, bif);
1215		else
1216			te-> flags &= ~BA_FOUND;
1217	}
1218#undef	BA_FOUND
1219
1220	bif->addrs_age = time(NULL);
1221	return (updated + added);
1222}
1223
1224/************************************************************************
1225 * Bridge packet filtering.
1226 */
1227const char bridge_sysctl[] = "net.link.bridge.";
1228
1229static struct {
1230	int32_t val;
1231	const char *name;
1232} bridge_pf_sysctl[] = {
1233	{ 1, "pfil_bridge" },
1234	{ 1, "pfil_member" },
1235	{ 1, "pfil_onlyip" },
1236	{ 0, "ipfw" },
1237};
1238
1239int32_t
1240bridge_get_pfval(uint8_t which)
1241{
1242	if (which > sizeof(bridge_pf_sysctl) / sizeof(bridge_pf_sysctl[0])
1243	    || which < 1)
1244		return (-1);
1245
1246	return (bridge_pf_sysctl[which - 1].val);
1247}
1248
1249int32_t
1250bridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val)
1251{
1252	char mib_name[100];
1253	int32_t i, s_i;
1254	size_t len, s_len;
1255
1256	if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus)
1257		return (-2);
1258
1259	if (op == SNMP_OP_SET) {
1260		s_i = *val;
1261		s_len = sizeof(s_i);
1262	} else
1263		s_len = 0;
1264
1265        len = sizeof(i);
1266
1267	strcpy(mib_name, bridge_sysctl);
1268
1269	if (sysctlbyname(strcat(mib_name,
1270	    bridge_pf_sysctl[bridge_ctl].name), &i, &len,
1271	    (op == SNMP_OP_SET ? &s_i : NULL), s_len) == -1) {
1272		syslog(LOG_ERR, "sysctl(%s%s) failed - %s", bridge_sysctl,
1273		    bridge_pf_sysctl[bridge_ctl].name, strerror(errno));
1274		return (-1);
1275	}
1276
1277	bridge_pf_sysctl[bridge_ctl].val = i;
1278	*val = i;
1279
1280	return (i);
1281}
1282
1283void
1284bridge_pf_dump(void)
1285{
1286	uint8_t i;
1287
1288	for (i = 0; i < sizeof(bridge_pf_sysctl) / sizeof(bridge_pf_sysctl[0]);
1289	    i++) {
1290		syslog(LOG_ERR, "%s%s = %d", bridge_sysctl,
1291		    bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val);
1292	}
1293}
1294