bridge_sys.c revision 268351
1164410Ssyrinx/*-
2164410Ssyrinx * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
3164410Ssyrinx * All rights reserved.
4164410Ssyrinx *
5164410Ssyrinx * Redistribution and use in source and binary forms, with or without
6164410Ssyrinx * modification, are permitted provided that the following conditions
7164410Ssyrinx * are met:
8164410Ssyrinx * 1. Redistributions of source code must retain the above copyright
9164410Ssyrinx *    notice, this list of conditions and the following disclaimer.
10164410Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright
11164410Ssyrinx *    notice, this list of conditions and the following disclaimer in the
12164410Ssyrinx *    documentation and/or other materials provided with the distribution.
13164410Ssyrinx *
14164410Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15164410Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16164410Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17164410Ssyrinx * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18164410Ssyrinx * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19164410Ssyrinx * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20164410Ssyrinx * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21164410Ssyrinx * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22164410Ssyrinx * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23164410Ssyrinx * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24164410Ssyrinx * SUCH DAMAGE.
25164410Ssyrinx *
26164410Ssyrinx * Bridge MIB implementation for SNMPd.
27164410Ssyrinx * Bridge OS specific ioctls.
28164410Ssyrinx *
29164410Ssyrinx * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_sys.c 268351 2014-07-07 00:27:09Z marcel $
30164410Ssyrinx */
31164410Ssyrinx
32164410Ssyrinx#include <sys/ioctl.h>
33164410Ssyrinx#include <sys/param.h>
34164410Ssyrinx#include <sys/module.h>
35164410Ssyrinx#include <sys/linker.h>
36164410Ssyrinx#include <sys/socket.h>
37164410Ssyrinx#include <sys/sysctl.h>
38164410Ssyrinx
39164410Ssyrinx#include <net/bridgestp.h>
40164410Ssyrinx#include <net/ethernet.h>
41164410Ssyrinx#include <net/if.h>
42164410Ssyrinx#include <net/if_bridgevar.h>
43164410Ssyrinx#include <net/if_dl.h>
44164410Ssyrinx#include <net/if_mib.h>
45164410Ssyrinx#include <net/if_types.h>
46164410Ssyrinx#include <netinet/in.h>
47164410Ssyrinx
48164410Ssyrinx#include <errno.h>
49164410Ssyrinx#include <ifaddrs.h>
50164410Ssyrinx#include <stdarg.h>
51164410Ssyrinx#include <stdlib.h>
52164410Ssyrinx#include <stdio.h>
53164410Ssyrinx#include <string.h>
54164410Ssyrinx#include <syslog.h>
55164410Ssyrinx
56164410Ssyrinx#include <bsnmp/snmpmod.h>
57164410Ssyrinx#include <bsnmp/snmp_mibII.h>
58164410Ssyrinx
59164410Ssyrinx#include "bridge_tree.h"
60164410Ssyrinx#include "bridge_snmp.h"
61164410Ssyrinx
62164410Ssyrinxint sock = -1;
63164410Ssyrinx
64164410Ssyrinxint
65164410Ssyrinxbridge_ioctl_init(void)
66164410Ssyrinx{
67164410Ssyrinx	if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
68164410Ssyrinx		syslog(LOG_ERR, "cannot open socket : %s", strerror(errno));
69164410Ssyrinx		return (-1);
70164410Ssyrinx	}
71164410Ssyrinx
72164410Ssyrinx	return (0);
73164410Ssyrinx}
74164410Ssyrinx
75164410Ssyrinx/*
76164410Ssyrinx * Load the if_bridge.ko module in kernel if not already there.
77164410Ssyrinx */
78164410Ssyrinxint
79164410Ssyrinxbridge_kmod_load(void)
80164410Ssyrinx{
81164410Ssyrinx	int fileid, modid;
82164410Ssyrinx	const char mod_name[] = "if_bridge";
83164410Ssyrinx	struct module_stat mstat;
84164410Ssyrinx
85164410Ssyrinx	/* Scan files in kernel. */
86164410Ssyrinx	mstat.version = sizeof(struct module_stat);
87164410Ssyrinx	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
88164410Ssyrinx		/* Scan modules in file. */
89164410Ssyrinx		for (modid = kldfirstmod(fileid); modid > 0;
90164410Ssyrinx			modid = modfnext(modid)) {
91164410Ssyrinx
92164410Ssyrinx			if (modstat(modid, &mstat) < 0)
93164410Ssyrinx				continue;
94164410Ssyrinx
95164410Ssyrinx			if (strcmp(mod_name, mstat.name) == 0)
96164410Ssyrinx				return (0);
97164410Ssyrinx		}
98164410Ssyrinx	}
99164410Ssyrinx
100164410Ssyrinx	/* Not present - load it. */
101164410Ssyrinx	if (kldload(mod_name) < 0) {
102164410Ssyrinx		syslog(LOG_ERR, "failed to load %s kernel module", mod_name);
103164410Ssyrinx		return (-1);
104164410Ssyrinx	}
105164410Ssyrinx
106164410Ssyrinx	return (1);
107164410Ssyrinx}
108164410Ssyrinx
109164410Ssyrinx/************************************************************************
110164410Ssyrinx * Bridge interfaces.
111164410Ssyrinx */
112164410Ssyrinx
113164410Ssyrinx/*
114164410Ssyrinx * Convert the kernel uint64_t value for a bridge id
115164410Ssyrinx */
116164410Ssyrinxstatic void
117164410Ssyrinxsnmp_uint64_to_bridgeid(uint64_t id, bridge_id b_id)
118164410Ssyrinx{
119164410Ssyrinx	int i;
120164410Ssyrinx	u_char *o;
121164410Ssyrinx
122164410Ssyrinx	o = (u_char *) &id;
123164410Ssyrinx
124164410Ssyrinx	for (i = 0; i < SNMP_BRIDGE_ID_LEN; i++, o++)
125164410Ssyrinx		b_id[SNMP_BRIDGE_ID_LEN - i - 1] = *o;
126164410Ssyrinx}
127164410Ssyrinx
128164410Ssyrinx/*
129164410Ssyrinx * Fetch the bridge configuration parameters from the kernel excluding
130164410Ssyrinx * it's base MAC address.
131164410Ssyrinx */
132164410Ssyrinxstatic int
133164410Ssyrinxbridge_get_conf_param(struct bridge_if *bif)
134164410Ssyrinx{
135164410Ssyrinx	struct ifdrv ifd;
136164410Ssyrinx	struct ifbrparam b_param;
137164410Ssyrinx
138164410Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
139164410Ssyrinx	ifd.ifd_len = sizeof(b_param);
140164410Ssyrinx	ifd.ifd_data = &b_param;
141164410Ssyrinx
142164410Ssyrinx	/* Bridge priority. */
143164410Ssyrinx	ifd.ifd_cmd = BRDGGPRI;
144164410Ssyrinx	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
145164410Ssyrinx		syslog(LOG_ERR, "update bridge: ioctl(BRDGGPRI) failed: %s",
146164410Ssyrinx		    strerror(errno));
147164410Ssyrinx		return (-1);
148164410Ssyrinx	}
149164410Ssyrinx
150164410Ssyrinx	bif->priority = b_param.ifbrp_prio;
151164410Ssyrinx
152164410Ssyrinx	/* Configured max age. */
153164410Ssyrinx	ifd.ifd_cmd = BRDGGMA;
154164410Ssyrinx	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
155164410Ssyrinx		syslog(LOG_ERR, "update bridge: ioctl(BRDGGMA) failed: %s",
156164410Ssyrinx		    strerror(errno));
157164410Ssyrinx		return (-1);
158164410Ssyrinx	}
159164410Ssyrinx
160164410Ssyrinx	/* Centi-seconds. */
161164410Ssyrinx	bif->bridge_max_age = 100 * b_param.ifbrp_maxage;
162164410Ssyrinx
163164410Ssyrinx	/* Configured hello time. */
164164410Ssyrinx	ifd.ifd_cmd = BRDGGHT;
165164410Ssyrinx	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
166164410Ssyrinx		syslog(LOG_ERR, "update bridge: ioctl(BRDGGHT) failed: %s",
167164410Ssyrinx		    strerror(errno));
168164410Ssyrinx		return (-1);
169164410Ssyrinx	}
170164410Ssyrinx	bif->bridge_hello_time = 100 * b_param.ifbrp_hellotime;
171164410Ssyrinx
172164410Ssyrinx	/* Forward delay. */
173164410Ssyrinx	ifd.ifd_cmd = BRDGGFD;
174164410Ssyrinx	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
175164410Ssyrinx		syslog(LOG_ERR, "update bridge: ioctl(BRDGGFD) failed: %s",
176164410Ssyrinx		    strerror(errno));
177164410Ssyrinx		return (-1);
178164410Ssyrinx	}
179164410Ssyrinx	bif->bridge_fwd_delay = 100 * b_param.ifbrp_fwddelay;
180164410Ssyrinx
181164410Ssyrinx	/* Number of dropped addresses. */
182164410Ssyrinx	ifd.ifd_cmd = BRDGGRTE;
183164410Ssyrinx	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
184164410Ssyrinx		syslog(LOG_ERR, "update bridge: ioctl(BRDGGRTE) failed: %s",
185164410Ssyrinx		    strerror(errno));
186164410Ssyrinx		return (-1);
187164410Ssyrinx	}
188164410Ssyrinx	bif->lrnt_drops = b_param.ifbrp_cexceeded;
189164410Ssyrinx
190164410Ssyrinx	/* Address table timeout. */
191164410Ssyrinx	ifd.ifd_cmd = BRDGGTO;
192164410Ssyrinx	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
193164410Ssyrinx		syslog(LOG_ERR, "update bridge: ioctl(BRDGGTO) failed: %s",
194164410Ssyrinx		    strerror(errno));
195164410Ssyrinx		return (-1);
196164410Ssyrinx	}
197164410Ssyrinx	bif->age_time = b_param.ifbrp_ctime;
198164410Ssyrinx
199164410Ssyrinx	/* Address table size. */
200164410Ssyrinx	ifd.ifd_cmd = BRDGGCACHE;
201164410Ssyrinx	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
202164410Ssyrinx		syslog(LOG_ERR, "update bridge: ioctl(BRDGGCACHE) "
203164410Ssyrinx		    "failed: %s", strerror(errno));
204164410Ssyrinx		return (-1);
205164410Ssyrinx	}
206164410Ssyrinx	bif->max_addrs = b_param.ifbrp_csize;
207164410Ssyrinx
208164410Ssyrinx	return (0);
209164410Ssyrinx}
210164410Ssyrinx
211164410Ssyrinx/*
212164410Ssyrinx * Fetch the current bridge STP operational parameters.
213164410Ssyrinx * Returns: -1 - on error;
214164410Ssyrinx *	     0 - old TC time and Root Port values are same;
215164410Ssyrinx *	     1 - topologyChange notification should be sent;
216164410Ssyrinx *	     2 - newRoot notification should be sent.
217164410Ssyrinx */
218164410Ssyrinxint
219164410Ssyrinxbridge_get_op_param(struct bridge_if *bif)
220164410Ssyrinx{
221164410Ssyrinx	int new_root_send;
222164410Ssyrinx	struct ifdrv ifd;
223164410Ssyrinx	struct ifbropreq b_req;
224164410Ssyrinx
225164410Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
226164410Ssyrinx	ifd.ifd_len = sizeof(b_req);
227164410Ssyrinx	ifd.ifd_data = &b_req;
228164410Ssyrinx	ifd.ifd_cmd = BRDGPARAM;
229164410Ssyrinx
230164410Ssyrinx	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
231164410Ssyrinx		syslog(LOG_ERR, "update bridge: ioctl(BRDGPARAM) failed: %s",
232164410Ssyrinx		    strerror(errno));
233164410Ssyrinx		return (-1);
234164410Ssyrinx	}
235164410Ssyrinx
236164410Ssyrinx	bif->max_age = 100 * b_req.ifbop_maxage;
237164410Ssyrinx	bif->hello_time = 100 * b_req.ifbop_hellotime;
238164410Ssyrinx	bif->fwd_delay = 100 * b_req.ifbop_fwddelay;
239164997Ssyrinx	bif->stp_version = b_req.ifbop_protocol;
240164997Ssyrinx	bif->tx_hold_count = b_req.ifbop_holdcount;
241164410Ssyrinx
242164410Ssyrinx	if (b_req.ifbop_root_port == 0 &&
243164410Ssyrinx	    bif->root_port != b_req.ifbop_root_port)
244164410Ssyrinx		new_root_send = 2;
245164410Ssyrinx	else
246164410Ssyrinx		new_root_send = 0;
247164410Ssyrinx
248164410Ssyrinx	bif->root_port = b_req.ifbop_root_port;
249164410Ssyrinx	bif->root_cost = b_req.ifbop_root_path_cost;
250164410Ssyrinx	snmp_uint64_to_bridgeid(b_req.ifbop_designated_root,
251164410Ssyrinx	    bif->design_root);
252164410Ssyrinx
253164410Ssyrinx	if (bif->last_tc_time.tv_sec != b_req.ifbop_last_tc_time.tv_sec) {
254164410Ssyrinx		bif->top_changes++;
255164410Ssyrinx		bif->last_tc_time.tv_sec = b_req.ifbop_last_tc_time.tv_sec;
256164410Ssyrinx		bif->last_tc_time.tv_usec = b_req.ifbop_last_tc_time.tv_usec;
257164410Ssyrinx
258164410Ssyrinx		/*
259164410Ssyrinx		 * "The trap is not sent if a (begemotBridge)NewRoot
260164410Ssyrinx		 * trap is sent for the same transition."
261164410Ssyrinx		 */
262164410Ssyrinx		if (new_root_send == 0)
263164410Ssyrinx			return (1);
264164410Ssyrinx	}
265164410Ssyrinx
266164410Ssyrinx	return (new_root_send);
267164410Ssyrinx}
268164410Ssyrinx
269164410Ssyrinxint
270164410Ssyrinxbridge_getinfo_bif(struct bridge_if *bif)
271164410Ssyrinx{
272164410Ssyrinx	if (bridge_get_conf_param(bif) < 0)
273164410Ssyrinx		return (-1);
274164410Ssyrinx
275164410Ssyrinx	return (bridge_get_op_param(bif));
276164410Ssyrinx}
277164410Ssyrinx
278164410Ssyrinxint
279164410Ssyrinxbridge_set_priority(struct bridge_if *bif, int32_t priority)
280164410Ssyrinx{
281164410Ssyrinx	struct ifdrv ifd;
282164410Ssyrinx	struct ifbrparam b_param;
283164410Ssyrinx
284164410Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
285164410Ssyrinx	ifd.ifd_len = sizeof(b_param);
286164410Ssyrinx	ifd.ifd_data = &b_param;
287164410Ssyrinx	b_param.ifbrp_prio = (uint32_t) priority;
288164410Ssyrinx	ifd.ifd_cmd = BRDGSPRI;
289164410Ssyrinx
290164410Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
291164410Ssyrinx		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPRI) "
292164410Ssyrinx		    "failed: %s", strerror(errno));
293164410Ssyrinx		return (-1);
294164410Ssyrinx	}
295164410Ssyrinx
296164410Ssyrinx	/*
297164410Ssyrinx	 * Re-fetching the data from the driver after that might be a good
298164410Ssyrinx	 * idea, since changing our bridge's priority should invoke
299164410Ssyrinx	 * recalculation of the active spanning tree topology in the network.
300164410Ssyrinx	 */
301164410Ssyrinx	bif->priority = priority;
302164410Ssyrinx	return (0);
303164410Ssyrinx}
304164410Ssyrinx
305164410Ssyrinx/*
306164410Ssyrinx * Convert 1/100 of seconds to 1/256 of seconds.
307164410Ssyrinx * Timeout ::= TEXTUAL-CONVENTION.
308164410Ssyrinx * To convert a Timeout value into a value in units of
309164410Ssyrinx * 1/256 seconds, the following algorithm should be used:
310164410Ssyrinx *	b = floor( (n * 256) / 100)
311164997Ssyrinx * The conversion to 1/256 of a second happens in the kernel -
312164997Ssyrinx * just make sure we correctly convert the seconds to Timout
313164997Ssyrinx * and vice versa.
314164410Ssyrinx */
315164410Ssyrinxstatic uint32_t
316164997Ssyrinxsnmp_timeout2_sec(int32_t secs)
317164410Ssyrinx{
318164997Ssyrinx	return (secs / 100);
319164410Ssyrinx}
320164410Ssyrinx
321164410Ssyrinxint
322164410Ssyrinxbridge_set_maxage(struct bridge_if *bif, int32_t max_age)
323164410Ssyrinx{
324164410Ssyrinx	struct ifdrv ifd;
325164410Ssyrinx	struct ifbrparam b_param;
326164410Ssyrinx
327164410Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
328164410Ssyrinx	ifd.ifd_len = sizeof(b_param);
329164410Ssyrinx	ifd.ifd_data = &b_param;
330164997Ssyrinx	b_param.ifbrp_maxage = snmp_timeout2_sec(max_age);
331164410Ssyrinx	ifd.ifd_cmd = BRDGSMA;
332164410Ssyrinx
333164410Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
334164410Ssyrinx		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSMA) "
335164410Ssyrinx		    "failed: %s", strerror(errno));
336164410Ssyrinx		return (-1);
337164410Ssyrinx	}
338164410Ssyrinx
339164410Ssyrinx	bif->bridge_max_age = max_age;
340164410Ssyrinx	return (0);
341164410Ssyrinx}
342164410Ssyrinx
343164410Ssyrinxint
344164410Ssyrinxbridge_set_hello_time(struct bridge_if *bif, int32_t hello_time)
345164410Ssyrinx{
346164410Ssyrinx	struct ifdrv ifd;
347164410Ssyrinx	struct ifbrparam b_param;
348164410Ssyrinx
349164410Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
350164410Ssyrinx	ifd.ifd_len = sizeof(b_param);
351164410Ssyrinx	ifd.ifd_data = &b_param;
352164997Ssyrinx	b_param.ifbrp_hellotime = snmp_timeout2_sec(hello_time);
353164410Ssyrinx	ifd.ifd_cmd = BRDGSHT;
354164410Ssyrinx
355164410Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
356164410Ssyrinx		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSHT) "
357164410Ssyrinx		    "failed: %s", strerror(errno));
358164410Ssyrinx		return (-1);
359164410Ssyrinx	}
360164410Ssyrinx
361164410Ssyrinx	bif->bridge_hello_time = b_param.ifbrp_hellotime;
362164410Ssyrinx	return (0);
363164410Ssyrinx}
364164410Ssyrinx
365164410Ssyrinxint
366164410Ssyrinxbridge_set_forward_delay(struct bridge_if *bif, int32_t fwd_delay)
367164410Ssyrinx{
368164410Ssyrinx	struct ifdrv ifd;
369164410Ssyrinx	struct ifbrparam b_param;
370164410Ssyrinx
371164410Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
372164410Ssyrinx	ifd.ifd_len = sizeof(b_param);
373164410Ssyrinx	ifd.ifd_data = &b_param;
374164997Ssyrinx	b_param.ifbrp_fwddelay = snmp_timeout2_sec(fwd_delay);
375164410Ssyrinx	ifd.ifd_cmd = BRDGSFD;
376164410Ssyrinx
377164410Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
378164410Ssyrinx		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSFD) "
379164410Ssyrinx		    "failed: %s", strerror(errno));
380164410Ssyrinx		return (-1);
381164410Ssyrinx	}
382164410Ssyrinx
383164410Ssyrinx	bif->bridge_fwd_delay = b_param.ifbrp_fwddelay;
384164410Ssyrinx	return (0);
385164410Ssyrinx}
386164410Ssyrinx
387164410Ssyrinxint
388164410Ssyrinxbridge_set_aging_time(struct bridge_if *bif, int32_t age_time)
389164410Ssyrinx{
390164410Ssyrinx	struct ifdrv ifd;
391164410Ssyrinx	struct ifbrparam b_param;
392164410Ssyrinx
393164410Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
394164410Ssyrinx	ifd.ifd_len = sizeof(b_param);
395164410Ssyrinx	ifd.ifd_data = &b_param;
396164410Ssyrinx	b_param.ifbrp_ctime = (uint32_t) age_time;
397164410Ssyrinx	ifd.ifd_cmd = BRDGSTO;
398164410Ssyrinx
399164410Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
400164410Ssyrinx		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTO) "
401164410Ssyrinx		    "failed: %s", strerror(errno));
402164410Ssyrinx		return (-1);
403164410Ssyrinx	}
404164410Ssyrinx
405164410Ssyrinx	bif->age_time = age_time;
406164410Ssyrinx	return (0);
407164410Ssyrinx}
408164410Ssyrinx
409164410Ssyrinxint
410164410Ssyrinxbridge_set_max_cache(struct bridge_if *bif, int32_t max_cache)
411164410Ssyrinx{
412164410Ssyrinx	struct ifdrv ifd;
413164410Ssyrinx	struct ifbrparam b_param;
414164410Ssyrinx
415164410Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
416164410Ssyrinx	ifd.ifd_len = sizeof(b_param);
417164410Ssyrinx	ifd.ifd_data = &b_param;
418164410Ssyrinx	b_param.ifbrp_csize = max_cache;
419164410Ssyrinx	ifd.ifd_cmd = BRDGSCACHE;
420164410Ssyrinx
421164410Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
422164410Ssyrinx		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSCACHE) "
423164410Ssyrinx		    "failed: %s", strerror(errno));
424164410Ssyrinx		return (-1);
425164410Ssyrinx	}
426164410Ssyrinx
427164410Ssyrinx	bif->max_addrs = b_param.ifbrp_csize;
428164410Ssyrinx	return (0);
429164410Ssyrinx}
430164410Ssyrinx
431164997Ssyrinxint
432171791Ssyrinxbridge_set_tx_hold_count(struct bridge_if *bif, int32_t tx_hc)
433164997Ssyrinx{
434164997Ssyrinx	struct ifdrv ifd;
435164997Ssyrinx	struct ifbrparam b_param;
436164997Ssyrinx
437164997Ssyrinx	if (tx_hc < SNMP_BRIDGE_MIN_TXHC || tx_hc > SNMP_BRIDGE_MAX_TXHC)
438164997Ssyrinx		return (-1);
439164997Ssyrinx
440164997Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
441164997Ssyrinx	ifd.ifd_len = sizeof(b_param);
442164997Ssyrinx	ifd.ifd_data = &b_param;
443164997Ssyrinx	b_param.ifbrp_txhc = tx_hc;
444164997Ssyrinx	ifd.ifd_cmd = BRDGSTXHC;
445164997Ssyrinx
446164997Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
447164997Ssyrinx		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSTXHC) "
448164997Ssyrinx		    "failed: %s", strerror(errno));
449164997Ssyrinx		return (-1);
450164997Ssyrinx	}
451164997Ssyrinx
452164997Ssyrinx	bif->tx_hold_count = b_param.ifbrp_txhc;
453164997Ssyrinx	return (0);
454164997Ssyrinx}
455164997Ssyrinx
456164997Ssyrinxint
457171791Ssyrinxbridge_set_stp_version(struct bridge_if *bif, int32_t stp_proto)
458164997Ssyrinx{
459164997Ssyrinx	struct ifdrv ifd;
460164997Ssyrinx	struct ifbrparam b_param;
461164997Ssyrinx
462164997Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
463164997Ssyrinx	ifd.ifd_len = sizeof(b_param);
464164997Ssyrinx	ifd.ifd_data = &b_param;
465164997Ssyrinx	b_param.ifbrp_proto = stp_proto;
466164997Ssyrinx	ifd.ifd_cmd = BRDGSPROTO;
467164997Ssyrinx
468164997Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
469164997Ssyrinx		syslog(LOG_ERR, "set bridge param: ioctl(BRDGSPROTO) "
470164997Ssyrinx		    "failed: %s", strerror(errno));
471164997Ssyrinx		return (-1);
472164997Ssyrinx	}
473164997Ssyrinx
474164997Ssyrinx	bif->stp_version = b_param.ifbrp_proto;
475164997Ssyrinx	return (0);
476164997Ssyrinx}
477164997Ssyrinx
478164410Ssyrinx/*
479164410Ssyrinx * Set the bridge interface status to up/down.
480164410Ssyrinx */
481164410Ssyrinxint
482164410Ssyrinxbridge_set_if_up(const char* b_name, int8_t up)
483164410Ssyrinx{
484164410Ssyrinx	int	flags;
485164410Ssyrinx	struct ifreq ifr;
486164410Ssyrinx
487164410Ssyrinx	bzero(&ifr, sizeof(ifr));
488164410Ssyrinx	strcpy(ifr.ifr_name, b_name);
489164410Ssyrinx	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
490164410Ssyrinx		syslog(LOG_ERR, "set bridge up: ioctl(SIOCGIFFLAGS) "
491164410Ssyrinx		    "failed: %s", strerror(errno));
492164410Ssyrinx		return (-1);
493164410Ssyrinx	}
494164410Ssyrinx
495164410Ssyrinx	flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
496164410Ssyrinx	if (up == 1)
497164410Ssyrinx		flags |= IFF_UP;
498164410Ssyrinx	else
499164410Ssyrinx		flags &= ~IFF_UP;
500164410Ssyrinx
501164410Ssyrinx	ifr.ifr_flags = flags & 0xffff;
502164410Ssyrinx	ifr.ifr_flagshigh = flags >> 16;
503164410Ssyrinx	if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
504164410Ssyrinx		syslog(LOG_ERR, "set bridge up: ioctl(SIOCSIFFLAGS) "
505164410Ssyrinx		    "failed: %s", strerror(errno));
506164410Ssyrinx		return (-1);
507164410Ssyrinx	}
508164410Ssyrinx
509164410Ssyrinx	return (0);
510164410Ssyrinx}
511164410Ssyrinx
512164410Ssyrinxint
513164410Ssyrinxbridge_create(const char *b_name)
514164410Ssyrinx{
515164410Ssyrinx	char *new_name;
516164410Ssyrinx	struct ifreq ifr;
517164410Ssyrinx
518164410Ssyrinx	bzero(&ifr, sizeof(ifr));
519164410Ssyrinx	strcpy(ifr.ifr_name, b_name);
520164410Ssyrinx
521164410Ssyrinx	if (ioctl(sock, SIOCIFCREATE, &ifr) < 0) {
522164410Ssyrinx		syslog(LOG_ERR, "create bridge: ioctl(SIOCIFCREATE) "
523164410Ssyrinx		    "failed: %s", strerror(errno));
524164410Ssyrinx		return (-1);
525164410Ssyrinx	}
526164410Ssyrinx
527164410Ssyrinx	if (strcmp(b_name, ifr.ifr_name) == 0)
528164410Ssyrinx		return (0);
529164410Ssyrinx
530164410Ssyrinx	if ((new_name = strdup(b_name)) == NULL) {
531164410Ssyrinx		syslog(LOG_ERR, "create bridge: strdup() failed");
532164410Ssyrinx		return (-1);
533164410Ssyrinx	}
534164410Ssyrinx
535164410Ssyrinx	ifr.ifr_data = new_name;
536164410Ssyrinx	if (ioctl(sock, SIOCSIFNAME, (caddr_t) &ifr) < 0) {
537164410Ssyrinx		syslog(LOG_ERR, "create bridge: ioctl(SIOCSIFNAME) "
538164410Ssyrinx		    "failed: %s", strerror(errno));
539164410Ssyrinx		free(new_name);
540164410Ssyrinx		return (-1);
541164410Ssyrinx	}
542164410Ssyrinx
543164410Ssyrinx	return (0);
544164410Ssyrinx}
545164410Ssyrinx
546164410Ssyrinxint
547164410Ssyrinxbridge_destroy(const char *b_name)
548164410Ssyrinx{
549164410Ssyrinx	struct ifreq ifr;
550164410Ssyrinx
551164410Ssyrinx	bzero(&ifr, sizeof(ifr));
552164410Ssyrinx	strcpy(ifr.ifr_name, b_name);
553164410Ssyrinx
554164410Ssyrinx	if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) {
555164410Ssyrinx		syslog(LOG_ERR, "destroy bridge: ioctl(SIOCIFDESTROY) "
556164410Ssyrinx		    "failed: %s", strerror(errno));
557164410Ssyrinx		return (-1);
558164410Ssyrinx	}
559164410Ssyrinx
560164410Ssyrinx	return (0);
561164410Ssyrinx}
562164410Ssyrinx
563164410Ssyrinx/*
564164410Ssyrinx * Fetch the bridge base MAC address. Return pointer to the
565165642Sbz * buffer containing the MAC address, NULL on failure.
566164410Ssyrinx */
567164410Ssyrinxu_char *
568165642Sbzbridge_get_basemac(const char *bif_name, u_char *mac, size_t mlen)
569164410Ssyrinx{
570164410Ssyrinx	int len;
571164410Ssyrinx	char if_name[IFNAMSIZ];
572165642Sbz	struct ifaddrs *ifap, *ifa;
573165642Sbz	struct sockaddr_dl sdl;
574164410Ssyrinx
575165642Sbz	if (getifaddrs(&ifap) != 0) {
576164410Ssyrinx		syslog(LOG_ERR, "bridge get mac: getifaddrs() failed - %s",
577164410Ssyrinx		    strerror(errno));
578164410Ssyrinx		return (NULL);
579164410Ssyrinx	}
580164410Ssyrinx
581165642Sbz	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
582165642Sbz		if (ifa->ifa_addr->sa_family != AF_LINK)
583165642Sbz			continue;
584164410Ssyrinx
585165642Sbz		/*
586165642Sbz		 * Not just casting because of alignment constraints
587268351Smarcel		 * on sparc64.
588165642Sbz		 */
589165642Sbz		bcopy(ifa->ifa_addr, &sdl, sizeof(struct sockaddr_dl));
590165642Sbz
591165642Sbz		if (sdl.sdl_alen > mlen)
592165642Sbz			continue;
593165642Sbz
594165642Sbz		if ((len = sdl.sdl_nlen) >= IFNAMSIZ)
595164410Ssyrinx			len = IFNAMSIZ - 1;
596164410Ssyrinx
597165642Sbz		bcopy(sdl.sdl_data, if_name, len);
598164410Ssyrinx		if_name[len] = '\0';
599164410Ssyrinx
600165642Sbz		if (strcmp(bif_name, if_name) == 0) {
601165642Sbz			bcopy(sdl.sdl_data + sdl.sdl_nlen, mac, sdl.sdl_alen);
602164410Ssyrinx			freeifaddrs(ifap);
603164410Ssyrinx			return (mac);
604164410Ssyrinx		}
605164410Ssyrinx	}
606164410Ssyrinx
607164410Ssyrinx	freeifaddrs(ifap);
608164410Ssyrinx	return (NULL);
609164410Ssyrinx}
610164410Ssyrinx
611164410Ssyrinx/************************************************************************
612164410Ssyrinx * Bridge ports.
613164410Ssyrinx */
614164410Ssyrinx
615164410Ssyrinx/*
616164410Ssyrinx * Convert the kernel STP port state into
617164410Ssyrinx * the corresopnding enumerated type from SNMP Bridge MIB.
618164410Ssyrinx */
619164410Ssyrinxstatic int
620164410Ssyrinxstate2snmp_st(uint8_t ifbr_state)
621164410Ssyrinx{
622164410Ssyrinx	switch (ifbr_state) {
623164410Ssyrinx		case BSTP_IFSTATE_DISABLED:
624164410Ssyrinx			return (StpPortState_disabled);
625164410Ssyrinx		case BSTP_IFSTATE_LISTENING:
626164410Ssyrinx			return (StpPortState_listening);
627164410Ssyrinx		case BSTP_IFSTATE_LEARNING:
628164410Ssyrinx			return (StpPortState_learning);
629164410Ssyrinx		case BSTP_IFSTATE_FORWARDING:
630164410Ssyrinx			return (StpPortState_forwarding);
631164410Ssyrinx		case BSTP_IFSTATE_BLOCKING:
632164997Ssyrinx		case BSTP_IFSTATE_DISCARDING:
633164410Ssyrinx			return (StpPortState_blocking);
634164410Ssyrinx	}
635164410Ssyrinx
636164410Ssyrinx	return (StpPortState_broken);
637164410Ssyrinx}
638164410Ssyrinx
639164410Ssyrinx/*
640164410Ssyrinx * Fill in a bridge member information according to data polled from kernel.
641164410Ssyrinx */
642164410Ssyrinxstatic void
643164410Ssyrinxbridge_port_getinfo_conf(struct ifbreq *k_info, struct bridge_port *bp)
644164410Ssyrinx{
645164410Ssyrinx	bp->state = state2snmp_st(k_info->ifbr_state);
646164410Ssyrinx	bp->priority = k_info->ifbr_priority;
647164410Ssyrinx
648164410Ssyrinx	/*
649164410Ssyrinx	 * RFC 4188:
650164410Ssyrinx	 * "New implementations should support dot1dStpPortPathCost32.
651164410Ssyrinx	 * If the port path costs exceeds the maximum value of this
652164410Ssyrinx	 * object then this object should report the maximum value,
653164410Ssyrinx	 * namely 65535.  Applications should try to read the
654164410Ssyrinx	 * dot1dStpPortPathCost32 object if this object reports
655164410Ssyrinx	 * the maximum value."
656164410Ssyrinx	 */
657164410Ssyrinx
658164997Ssyrinx	if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMCOST)
659164997Ssyrinx		bp->admin_path_cost = k_info->ifbr_path_cost;
660164997Ssyrinx	else
661164997Ssyrinx		bp->admin_path_cost = 0;
662166493Ssyrinx
663164410Ssyrinx	bp->path_cost = k_info->ifbr_path_cost;
664164410Ssyrinx
665164410Ssyrinx	if (k_info->ifbr_ifsflags & IFBIF_STP)
666164410Ssyrinx		bp->enable = dot1dStpPortEnable_enabled;
667164410Ssyrinx	else
668164410Ssyrinx		bp->enable = dot1dStpPortEnable_disabled;
669164410Ssyrinx
670164410Ssyrinx	/* Begemot Bridge MIB only. */
671164410Ssyrinx	if (k_info->ifbr_ifsflags & IFBIF_SPAN)
672164410Ssyrinx		bp->span_enable = begemotBridgeBaseSpanEnabled_enabled;
673164410Ssyrinx	else
674164410Ssyrinx		bp->span_enable = begemotBridgeBaseSpanEnabled_disabled;
675164997Ssyrinx
676171791Ssyrinx	if (k_info->ifbr_ifsflags & IFBIF_PRIVATE)
677171791Ssyrinx		bp->priv_set = TruthValue_true;
678171791Ssyrinx	else
679171791Ssyrinx		bp->priv_set = TruthValue_false;
680171791Ssyrinx
681164997Ssyrinx	if (k_info->ifbr_ifsflags & IFBIF_BSTP_ADMEDGE)
682164997Ssyrinx		bp->admin_edge = TruthValue_true;
683164997Ssyrinx	else
684164997Ssyrinx		bp->admin_edge = TruthValue_false;
685164997Ssyrinx
686164997Ssyrinx	if (k_info->ifbr_ifsflags & IFBIF_BSTP_EDGE)
687164997Ssyrinx		bp->oper_edge = TruthValue_true;
688164997Ssyrinx	else
689164997Ssyrinx		bp->oper_edge = TruthValue_false;
690164997Ssyrinx
691165416Ssyrinx	if (k_info->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP) {
692165416Ssyrinx		bp->admin_ptp = StpPortAdminPointToPointType_auto;
693165416Ssyrinx		if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP)
694165416Ssyrinx			bp->oper_ptp = TruthValue_true;
695164997Ssyrinx		else
696165416Ssyrinx			bp->oper_ptp = TruthValue_false;
697165416Ssyrinx	} else if (k_info->ifbr_ifsflags & IFBIF_BSTP_PTP) {
698165416Ssyrinx		bp->admin_ptp = StpPortAdminPointToPointType_forceTrue;
699165416Ssyrinx		bp->oper_ptp = TruthValue_true;
700164997Ssyrinx	} else {
701165416Ssyrinx		bp->admin_ptp = StpPortAdminPointToPointType_forceFalse;
702165416Ssyrinx		bp->oper_ptp = TruthValue_false;
703164997Ssyrinx	}
704164410Ssyrinx}
705164410Ssyrinx
706164410Ssyrinx/*
707164410Ssyrinx * Fill in a bridge interface STP information according to
708164410Ssyrinx * data polled from kernel.
709164410Ssyrinx */
710164410Ssyrinxstatic void
711164410Ssyrinxbridge_port_getinfo_opstp(struct ifbpstpreq *bp_stp, struct bridge_port *bp)
712164410Ssyrinx{
713164410Ssyrinx	bp->enable = dot1dStpPortEnable_enabled;
714164410Ssyrinx	bp->fwd_trans = bp_stp->ifbp_fwd_trans;
715164410Ssyrinx	bp->design_cost = bp_stp->ifbp_design_cost;
716164410Ssyrinx	snmp_uint64_to_bridgeid(bp_stp->ifbp_design_root, bp->design_root);
717164410Ssyrinx	snmp_uint64_to_bridgeid(bp_stp->ifbp_design_bridge, bp->design_bridge);
718164410Ssyrinx	bcopy(&(bp_stp->ifbp_design_port), &(bp->design_port),
719164410Ssyrinx	    sizeof(uint16_t));
720164410Ssyrinx}
721164410Ssyrinx
722164410Ssyrinx/*
723164410Ssyrinx * Clear a bridge interface STP information.
724164410Ssyrinx */
725164410Ssyrinxstatic void
726164410Ssyrinxbridge_port_clearinfo_opstp(struct bridge_port *bp)
727164410Ssyrinx{
728164410Ssyrinx	if (bp->enable == dot1dStpPortEnable_enabled) {
729164410Ssyrinx		bp->design_cost = 0;
730164410Ssyrinx		bzero(&(bp->design_root), sizeof(bridge_id));
731164410Ssyrinx		bzero(&(bp->design_bridge), sizeof(bridge_id));
732164410Ssyrinx		bzero(&(bp->design_port), sizeof(port_id));
733164410Ssyrinx		bp->fwd_trans = 0;
734164410Ssyrinx	}
735164410Ssyrinx
736164410Ssyrinx	bp->enable = dot1dStpPortEnable_disabled;
737164410Ssyrinx}
738164410Ssyrinx
739164410Ssyrinx/*
740164410Ssyrinx * Set a bridge member priority.
741164410Ssyrinx */
742164410Ssyrinxint
743164410Ssyrinxbridge_port_set_priority(const char *bif_name, struct bridge_port *bp,
744164410Ssyrinx	int32_t priority)
745164410Ssyrinx{
746164410Ssyrinx	struct ifdrv ifd;
747164410Ssyrinx	struct ifbreq b_req;
748164410Ssyrinx
749164410Ssyrinx	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
750164410Ssyrinx	ifd.ifd_len = sizeof(b_req);
751164410Ssyrinx	ifd.ifd_data = &b_req;
752164410Ssyrinx	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
753164410Ssyrinx
754164410Ssyrinx	b_req.ifbr_priority = (uint8_t) priority;
755164410Ssyrinx	ifd.ifd_cmd = BRDGSIFPRIO;
756164410Ssyrinx
757164410Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
758164410Ssyrinx		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFPRIO) "
759164410Ssyrinx		    "failed: %s", bp->p_name, strerror(errno));
760164410Ssyrinx		return (-1);
761164410Ssyrinx	}
762164410Ssyrinx
763164410Ssyrinx	bp->priority = priority;
764164410Ssyrinx	return (0);
765164410Ssyrinx}
766164410Ssyrinx
767164410Ssyrinx/*
768164410Ssyrinx * Set a bridge member STP-enabled flag.
769164410Ssyrinx */
770164410Ssyrinxint
771164410Ssyrinxbridge_port_set_stp_enable(const char *bif_name, struct bridge_port *bp,
772164410Ssyrinx	uint32_t enable)
773164410Ssyrinx{
774164410Ssyrinx	struct ifdrv ifd;
775164410Ssyrinx	struct ifbreq b_req;
776164410Ssyrinx
777164410Ssyrinx	if (bp->enable == enable)
778164410Ssyrinx		return (0);
779164410Ssyrinx
780164410Ssyrinx	bzero(&b_req, sizeof(b_req));
781164410Ssyrinx	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
782164410Ssyrinx	ifd.ifd_len = sizeof(b_req);
783164410Ssyrinx	ifd.ifd_data = &b_req;
784164410Ssyrinx	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
785164410Ssyrinx	ifd.ifd_cmd = BRDGGIFFLGS;
786164410Ssyrinx
787164410Ssyrinx	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
788164410Ssyrinx		syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
789164410Ssyrinx		    "failed: %s", bp->p_name, strerror(errno));
790164410Ssyrinx		return (-1);
791164410Ssyrinx	}
792164410Ssyrinx
793164410Ssyrinx	if (enable == dot1dStpPortEnable_enabled)
794164410Ssyrinx		b_req.ifbr_ifsflags |= IFBIF_STP;
795164410Ssyrinx	else
796164410Ssyrinx		b_req.ifbr_ifsflags &= ~IFBIF_STP;
797164410Ssyrinx
798164410Ssyrinx	ifd.ifd_cmd = BRDGSIFFLGS;
799164410Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
800164410Ssyrinx		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
801164410Ssyrinx		    "failed: %s", bp->p_name, strerror(errno));
802164410Ssyrinx		return (-1);
803164410Ssyrinx	}
804164410Ssyrinx
805164410Ssyrinx	bp->enable = enable;
806164410Ssyrinx	return (0);
807164410Ssyrinx}
808164410Ssyrinx
809164410Ssyrinx/*
810164410Ssyrinx * Set a bridge member STP path cost.
811164410Ssyrinx */
812164410Ssyrinxint
813164410Ssyrinxbridge_port_set_path_cost(const char *bif_name, struct bridge_port *bp,
814164410Ssyrinx	int32_t path_cost)
815164410Ssyrinx{
816164410Ssyrinx	struct ifdrv ifd;
817164410Ssyrinx	struct ifbreq b_req;
818164410Ssyrinx
819164997Ssyrinx	if (path_cost < SNMP_PORT_MIN_PATHCOST ||
820164997Ssyrinx	    path_cost > SNMP_PORT_PATHCOST_OBSOLETE)
821164997Ssyrinx		return (-2);
822164410Ssyrinx
823164410Ssyrinx	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
824164410Ssyrinx	ifd.ifd_len = sizeof(b_req);
825164410Ssyrinx	ifd.ifd_data = &b_req;
826164410Ssyrinx	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
827164410Ssyrinx
828164997Ssyrinx	b_req.ifbr_path_cost = path_cost;
829164410Ssyrinx	ifd.ifd_cmd = BRDGSIFCOST;
830164410Ssyrinx
831164410Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
832164410Ssyrinx		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFCOST) "
833164410Ssyrinx		    "failed: %s", bp->p_name, strerror(errno));
834164410Ssyrinx		return (-1);
835164410Ssyrinx	}
836164410Ssyrinx
837164997Ssyrinx	bp->admin_path_cost = path_cost;
838164997Ssyrinx
839164410Ssyrinx	return (0);
840164410Ssyrinx}
841164410Ssyrinx
842164410Ssyrinx/*
843164997Ssyrinx * Set the PonitToPoint status of the link administratively.
844164997Ssyrinx */
845164997Ssyrinxint
846171791Ssyrinxbridge_port_set_admin_ptp(const char *bif_name, struct bridge_port *bp,
847171791Ssyrinx    uint32_t admin_ptp)
848164997Ssyrinx{
849164997Ssyrinx	struct ifdrv ifd;
850164997Ssyrinx	struct ifbreq b_req;
851164997Ssyrinx
852165416Ssyrinx	if (bp->admin_ptp == admin_ptp)
853164997Ssyrinx		return (0);
854164997Ssyrinx
855164997Ssyrinx	bzero(&b_req, sizeof(b_req));
856164997Ssyrinx	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
857164997Ssyrinx	ifd.ifd_len = sizeof(b_req);
858164997Ssyrinx	ifd.ifd_data = &b_req;
859164997Ssyrinx	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
860164997Ssyrinx	ifd.ifd_cmd = BRDGGIFFLGS;
861164997Ssyrinx
862164997Ssyrinx	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
863164997Ssyrinx		syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
864164997Ssyrinx		    "failed: %s", bp->p_name, strerror(errno));
865164997Ssyrinx		return (-1);
866164997Ssyrinx	}
867164997Ssyrinx
868165416Ssyrinx	switch (admin_ptp) {
869164997Ssyrinx		case StpPortAdminPointToPointType_forceTrue:
870165416Ssyrinx			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
871165416Ssyrinx			b_req.ifbr_ifsflags |= IFBIF_BSTP_PTP;
872164997Ssyrinx			break;
873164997Ssyrinx		case StpPortAdminPointToPointType_forceFalse:
874165416Ssyrinx			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOPTP;
875165416Ssyrinx			b_req.ifbr_ifsflags &= ~IFBIF_BSTP_PTP;
876164997Ssyrinx			break;
877164997Ssyrinx		case StpPortAdminPointToPointType_auto:
878165416Ssyrinx			b_req.ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
879164997Ssyrinx			break;
880164997Ssyrinx	}
881164997Ssyrinx
882164997Ssyrinx	ifd.ifd_cmd = BRDGSIFFLGS;
883164997Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
884164997Ssyrinx		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
885164997Ssyrinx		    "failed: %s", bp->p_name, strerror(errno));
886164997Ssyrinx		return (-1);
887164997Ssyrinx	}
888164997Ssyrinx
889165416Ssyrinx	bp->admin_ptp = admin_ptp;
890164997Ssyrinx	return (0);
891164997Ssyrinx}
892164997Ssyrinx
893164997Ssyrinx/*
894164997Ssyrinx * Set admin edge.
895164997Ssyrinx */
896164997Ssyrinxint
897171791Ssyrinxbridge_port_set_admin_edge(const char *bif_name, struct bridge_port *bp,
898171791Ssyrinx    uint32_t enable)
899164997Ssyrinx{
900164997Ssyrinx	struct ifdrv ifd;
901164997Ssyrinx	struct ifbreq b_req;
902164997Ssyrinx
903164997Ssyrinx	if (bp->admin_edge == enable)
904164997Ssyrinx		return (0);
905164997Ssyrinx
906164997Ssyrinx	bzero(&b_req, sizeof(b_req));
907164997Ssyrinx	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
908164997Ssyrinx	ifd.ifd_len = sizeof(b_req);
909164997Ssyrinx	ifd.ifd_data = &b_req;
910164997Ssyrinx	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
911164997Ssyrinx	ifd.ifd_cmd = BRDGGIFFLGS;
912164997Ssyrinx
913164997Ssyrinx	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
914164997Ssyrinx		syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
915164997Ssyrinx		    "failed: %s", bp->p_name, strerror(errno));
916164997Ssyrinx		return (-1);
917164997Ssyrinx	}
918164997Ssyrinx
919164997Ssyrinx	if (enable == TruthValue_true) {
920164997Ssyrinx		b_req.ifbr_ifsflags &= ~IFBIF_BSTP_AUTOEDGE;
921164997Ssyrinx		b_req.ifbr_ifsflags |= IFBIF_BSTP_EDGE;
922164997Ssyrinx	} else
923164997Ssyrinx		b_req.ifbr_ifsflags &= ~IFBIF_BSTP_EDGE;
924164997Ssyrinx
925164997Ssyrinx	ifd.ifd_cmd = BRDGSIFFLGS;
926164997Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
927164997Ssyrinx		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
928164997Ssyrinx		    "failed: %s", bp->p_name, strerror(errno));
929164997Ssyrinx		return (-1);
930164997Ssyrinx	}
931164997Ssyrinx
932164997Ssyrinx	bp->admin_edge = enable;
933166493Ssyrinx
934164997Ssyrinx	return (0);
935164997Ssyrinx}
936164997Ssyrinx
937164997Ssyrinx/*
938171791Ssyrinx * Set 'private' flag.
939171791Ssyrinx */
940171791Ssyrinxint
941171791Ssyrinxbridge_port_set_private(const char *bif_name, struct bridge_port *bp,
942171791Ssyrinx    uint32_t priv_set)
943171791Ssyrinx{
944171791Ssyrinx	struct ifdrv ifd;
945171791Ssyrinx	struct ifbreq b_req;
946171791Ssyrinx
947171791Ssyrinx	if (bp->priv_set == priv_set)
948171791Ssyrinx		return (0);
949171791Ssyrinx
950171791Ssyrinx	bzero(&b_req, sizeof(b_req));
951171791Ssyrinx	strlcpy(ifd.ifd_name, bif_name, sizeof(ifd.ifd_name));
952171791Ssyrinx	ifd.ifd_len = sizeof(b_req);
953171791Ssyrinx	ifd.ifd_data = &b_req;
954171791Ssyrinx	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
955171791Ssyrinx	ifd.ifd_cmd = BRDGGIFFLGS;
956171791Ssyrinx
957171791Ssyrinx	if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
958171791Ssyrinx		syslog(LOG_ERR, "get member %s param: ioctl(BRDGGIFFLGS) "
959171791Ssyrinx		    "failed: %s", bp->p_name, strerror(errno));
960171791Ssyrinx		return (-1);
961171791Ssyrinx	}
962171791Ssyrinx
963171791Ssyrinx	if (priv_set == TruthValue_true)
964171791Ssyrinx		b_req.ifbr_ifsflags |= IFBIF_PRIVATE;
965171791Ssyrinx	else if (priv_set == TruthValue_false)
966171791Ssyrinx		b_req.ifbr_ifsflags &= ~IFBIF_PRIVATE;
967171791Ssyrinx	else
968171791Ssyrinx		return (SNMP_ERR_WRONG_VALUE);
969171791Ssyrinx
970171791Ssyrinx	ifd.ifd_cmd = BRDGSIFFLGS;
971171791Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
972171791Ssyrinx		syslog(LOG_ERR, "set member %s param: ioctl(BRDGSIFFLGS) "
973171791Ssyrinx		    "failed: %s", bp->p_name, strerror(errno));
974171791Ssyrinx		return (-1);
975171791Ssyrinx	}
976171791Ssyrinx
977171791Ssyrinx	bp->priv_set = priv_set;
978171791Ssyrinx
979171791Ssyrinx	return (0);
980171791Ssyrinx}
981171791Ssyrinx
982171791Ssyrinx
983171791Ssyrinx/*
984164410Ssyrinx * Add a bridge member port.
985164410Ssyrinx */
986164410Ssyrinxint
987164410Ssyrinxbridge_port_addm(struct bridge_port *bp, const char *b_name)
988164410Ssyrinx{
989164410Ssyrinx	struct ifdrv ifd;
990164410Ssyrinx	struct ifbreq b_req;
991164410Ssyrinx
992164410Ssyrinx	bzero(&ifd, sizeof(ifd));
993164410Ssyrinx	bzero(&b_req, sizeof(b_req));
994164410Ssyrinx
995164410Ssyrinx	strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
996164410Ssyrinx	ifd.ifd_len = sizeof(b_req);
997164410Ssyrinx	ifd.ifd_data = &b_req;
998164410Ssyrinx	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
999164410Ssyrinx
1000164410Ssyrinx	if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1001164410Ssyrinx		ifd.ifd_cmd = BRDGADDS;
1002164410Ssyrinx	else
1003164410Ssyrinx		ifd.ifd_cmd = BRDGADD;
1004164410Ssyrinx
1005164410Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1006164410Ssyrinx		syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1007164410Ssyrinx		    bp->p_name,
1008164410Ssyrinx		    (ifd.ifd_cmd == BRDGADDS ? "BRDGADDS" : "BRDGADD"),
1009164410Ssyrinx		    strerror(errno));
1010164410Ssyrinx		return (-1);
1011164410Ssyrinx	}
1012164410Ssyrinx
1013164410Ssyrinx	return (0);
1014164410Ssyrinx}
1015164410Ssyrinx
1016164410Ssyrinx/*
1017164410Ssyrinx * Delete a bridge member port.
1018164410Ssyrinx */
1019164410Ssyrinxint
1020164410Ssyrinxbridge_port_delm(struct bridge_port *bp, const char *b_name)
1021164410Ssyrinx{
1022164410Ssyrinx	struct ifdrv ifd;
1023164410Ssyrinx	struct ifbreq b_req;
1024164410Ssyrinx
1025164410Ssyrinx	bzero(&ifd, sizeof(ifd));
1026164410Ssyrinx	bzero(&b_req, sizeof(b_req));
1027164410Ssyrinx
1028164410Ssyrinx	strlcpy(ifd.ifd_name, b_name, sizeof(ifd.ifd_name));
1029164410Ssyrinx	ifd.ifd_len = sizeof(b_req);
1030164410Ssyrinx	ifd.ifd_data = &b_req;
1031164410Ssyrinx	strlcpy(b_req.ifbr_ifsname, bp->p_name, sizeof(b_req.ifbr_ifsname));
1032164410Ssyrinx
1033164410Ssyrinx	if (bp->span_enable == begemotBridgeBaseSpanEnabled_enabled)
1034164410Ssyrinx		ifd.ifd_cmd = BRDGDELS;
1035164410Ssyrinx	else
1036164410Ssyrinx		ifd.ifd_cmd = BRDGDEL;
1037164410Ssyrinx
1038164410Ssyrinx	if (ioctl(sock, SIOCSDRVSPEC, &ifd) < 0) {
1039164410Ssyrinx		syslog(LOG_ERR, "%s - add member : ioctl(%s) failed: %s",
1040164410Ssyrinx		    bp->p_name,
1041164410Ssyrinx		    (ifd.ifd_cmd == BRDGDELS ? "BRDGDELS" : "BRDGDEL"),
1042164410Ssyrinx		    strerror(errno));
1043164410Ssyrinx		return (-1);
1044164410Ssyrinx	}
1045164410Ssyrinx
1046164410Ssyrinx	return (0);
1047164410Ssyrinx}
1048164410Ssyrinx
1049164410Ssyrinx/*
1050164410Ssyrinx * Fetch the bridge member list from kernel.
1051164410Ssyrinx * Return -1 on error, or buffer len if successful.
1052164410Ssyrinx */
1053164410Ssyrinxstatic int32_t
1054165642Sbzbridge_port_get_iflist(struct bridge_if *bif, struct ifbreq **buf)
1055164410Ssyrinx{
1056165642Sbz	int n = 128;
1057165642Sbz	uint32_t len;
1058165642Sbz	struct ifbreq *ninbuf;
1059164410Ssyrinx	struct ifbifconf ifbc;
1060164410Ssyrinx	struct ifdrv ifd;
1061164410Ssyrinx
1062164410Ssyrinx	*buf = NULL;
1063164410Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1064164410Ssyrinx	ifd.ifd_cmd = BRDGGIFS;
1065164410Ssyrinx	ifd.ifd_len = sizeof(ifbc);
1066164410Ssyrinx	ifd.ifd_data = &ifbc;
1067164410Ssyrinx
1068164410Ssyrinx	for ( ; ; ) {
1069165642Sbz		len = n * sizeof(struct ifbreq);
1070165642Sbz		if ((ninbuf = (struct ifbreq *)realloc(*buf, len)) == NULL) {
1071164410Ssyrinx			syslog(LOG_ERR, "get bridge member list: "
1072164410Ssyrinx			    "realloc failed: %s", strerror(errno));
1073164410Ssyrinx			free(*buf);
1074164410Ssyrinx			*buf = NULL;
1075164410Ssyrinx			return (-1);
1076164410Ssyrinx		}
1077164410Ssyrinx
1078164410Ssyrinx		ifbc.ifbic_len = len;
1079165642Sbz		ifbc.ifbic_req = *buf = ninbuf;
1080164410Ssyrinx
1081164410Ssyrinx		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1082164410Ssyrinx			syslog(LOG_ERR, "get bridge member list: ioctl "
1083164410Ssyrinx			    "(BRDGGIFS) failed: %s", strerror(errno));
1084164410Ssyrinx			free(*buf);
1085164410Ssyrinx			buf = NULL;
1086164410Ssyrinx			return (-1);
1087164410Ssyrinx		}
1088164410Ssyrinx
1089164410Ssyrinx		if ((ifbc.ifbic_len + sizeof(struct ifbreq)) < len)
1090164410Ssyrinx			break;
1091164410Ssyrinx
1092165642Sbz		n += 64;
1093164410Ssyrinx	}
1094164410Ssyrinx
1095164410Ssyrinx	return (ifbc.ifbic_len);
1096164410Ssyrinx}
1097164410Ssyrinx
1098164410Ssyrinx/*
1099164410Ssyrinx * Fetch the bridge STP member list from kernel.
1100164410Ssyrinx * Return -1 on error, or buffer len if successful.
1101164410Ssyrinx */
1102164410Ssyrinxstatic int32_t
1103165642Sbzbridge_port_get_ifstplist(struct bridge_if *bif, struct ifbpstpreq **buf)
1104164410Ssyrinx{
1105165642Sbz	int n = 128;
1106165642Sbz	uint32_t len;
1107165642Sbz	struct ifbpstpreq *ninbuf;
1108164410Ssyrinx	struct ifbpstpconf ifbstp;
1109164410Ssyrinx	struct ifdrv ifd;
1110164410Ssyrinx
1111164997Ssyrinx	*buf = NULL;
1112164410Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1113164410Ssyrinx	ifd.ifd_cmd = BRDGGIFSSTP;
1114164410Ssyrinx	ifd.ifd_len = sizeof(ifbstp);
1115164410Ssyrinx	ifd.ifd_data = &ifbstp;
1116164410Ssyrinx
1117164410Ssyrinx	for ( ; ; ) {
1118165642Sbz		len = n * sizeof(struct ifbpstpreq);
1119165642Sbz		if ((ninbuf = (struct ifbpstpreq *)
1120165642Sbz		    realloc(*buf, len)) == NULL) {
1121164410Ssyrinx			syslog(LOG_ERR, "get bridge STP ports list: "
1122164410Ssyrinx			    "realloc failed: %s", strerror(errno));
1123164410Ssyrinx			free(*buf);
1124164410Ssyrinx			*buf = NULL;
1125164410Ssyrinx			return (-1);
1126164410Ssyrinx		}
1127164410Ssyrinx
1128164410Ssyrinx		ifbstp.ifbpstp_len = len;
1129165642Sbz		ifbstp.ifbpstp_req = *buf = ninbuf;
1130164410Ssyrinx
1131164410Ssyrinx		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1132164410Ssyrinx			syslog(LOG_ERR, "get bridge STP ports list: ioctl "
1133164410Ssyrinx			    "(BRDGGIFSSTP) failed: %s", strerror(errno));
1134164410Ssyrinx			free(*buf);
1135164410Ssyrinx			buf = NULL;
1136164410Ssyrinx			return (-1);
1137164410Ssyrinx		}
1138164410Ssyrinx
1139164410Ssyrinx		if ((ifbstp.ifbpstp_len + sizeof(struct ifbpstpreq)) < len)
1140164410Ssyrinx			break;
1141164410Ssyrinx
1142165642Sbz		n += 64;
1143164410Ssyrinx	}
1144164410Ssyrinx
1145164410Ssyrinx	return (ifbstp.ifbpstp_len);
1146164410Ssyrinx}
1147164410Ssyrinx
1148164410Ssyrinx/*
1149164410Ssyrinx * Locate a bridge if STP params structure in a buffer.
1150164410Ssyrinx */
1151164410Ssyrinxstatic struct ifbpstpreq *
1152165642Sbzbridge_port_find_ifstplist(uint8_t port_no, struct ifbpstpreq *buf,
1153165642Sbz    uint32_t buf_len)
1154164410Ssyrinx{
1155164410Ssyrinx	uint32_t i;
1156164410Ssyrinx	struct ifbpstpreq *bstp;
1157164410Ssyrinx
1158165642Sbz	for (i = 0; i < buf_len / sizeof(struct ifbpstpreq); i++) {
1159165642Sbz		bstp = buf + i;
1160164410Ssyrinx		if (bstp->ifbp_portno == port_no)
1161164410Ssyrinx			return (bstp);
1162164410Ssyrinx	}
1163164410Ssyrinx
1164164410Ssyrinx	return (NULL);
1165164410Ssyrinx}
1166164410Ssyrinx
1167164410Ssyrinx/*
1168164410Ssyrinx * Read the initial info for all members of a bridge interface.
1169164410Ssyrinx * Returns the number of ports, 0 - if none, otherwise
1170228990Suqs * -1 if some other error occurred.
1171164410Ssyrinx */
1172164410Ssyrinxint
1173164410Ssyrinxbridge_getinfo_bif_ports(struct bridge_if *bif)
1174164410Ssyrinx{
1175164410Ssyrinx	uint32_t i;
1176164410Ssyrinx	int32_t buf_len;
1177165642Sbz	struct ifbreq *b_req_buf, *b_req;
1178165642Sbz	struct ifbpstpreq *bs_req_buf, *bs_req;
1179164410Ssyrinx	struct bridge_port *bp;
1180164410Ssyrinx	struct mibif *m_if;
1181164410Ssyrinx
1182165642Sbz	if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1183164410Ssyrinx		return (-1);
1184164410Ssyrinx
1185164410Ssyrinx	for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1186165642Sbz		b_req = b_req_buf + i;
1187164410Ssyrinx
1188164410Ssyrinx		if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) != NULL) {
1189164410Ssyrinx			/* Hopefully we will not fail here. */
1190164410Ssyrinx			if ((bp = bridge_new_port(m_if, bif)) != NULL) {
1191164410Ssyrinx				bp->status = RowStatus_active;
1192164410Ssyrinx				bridge_port_getinfo_conf(b_req, bp);
1193164410Ssyrinx				bridge_port_getinfo_mibif(m_if, bp);
1194164410Ssyrinx			}
1195164410Ssyrinx		} else {
1196164410Ssyrinx			syslog(LOG_ERR, "bridge member %s not present "
1197164410Ssyrinx			    "in mibII ifTable", b_req->ifbr_ifsname);
1198164410Ssyrinx		}
1199164410Ssyrinx	}
1200165642Sbz	free(b_req_buf);
1201164410Ssyrinx
1202165642Sbz	if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1203164410Ssyrinx		return (-1);
1204164410Ssyrinx
1205164410Ssyrinx	for (bp = bridge_port_bif_first(bif); bp != NULL;
1206164410Ssyrinx	    bp = bridge_port_bif_next(bp)) {
1207164410Ssyrinx		if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1208165642Sbz		    bs_req_buf, buf_len)) == NULL)
1209164410Ssyrinx			bridge_port_clearinfo_opstp(bp);
1210164410Ssyrinx		else
1211164410Ssyrinx			bridge_port_getinfo_opstp(bs_req, bp);
1212164410Ssyrinx	}
1213165642Sbz	free(bs_req_buf);
1214164410Ssyrinx
1215164410Ssyrinx	return (i);
1216164410Ssyrinx}
1217164410Ssyrinx
1218164410Ssyrinx/*
1219164410Ssyrinx * Update the information for the bridge interface members.
1220164410Ssyrinx */
1221164410Ssyrinxint
1222164410Ssyrinxbridge_update_memif(struct bridge_if *bif)
1223164410Ssyrinx{
1224164410Ssyrinx	int added, updated;
1225164410Ssyrinx	uint32_t i;
1226164410Ssyrinx	int32_t buf_len;
1227165642Sbz	struct ifbreq *b_req_buf, *b_req;
1228165642Sbz	struct ifbpstpreq *bs_req_buf, *bs_req;
1229164410Ssyrinx	struct bridge_port *bp, *bp_next;
1230164410Ssyrinx	struct mibif *m_if;
1231164410Ssyrinx
1232165642Sbz	if ((buf_len = bridge_port_get_iflist(bif, &b_req_buf)) < 0)
1233164410Ssyrinx		return (-1);
1234164410Ssyrinx
1235164410Ssyrinx	added = updated = 0;
1236164410Ssyrinx
1237164410Ssyrinx#define	BP_FOUND	0x01
1238164410Ssyrinx	for (i = 0; i < buf_len / sizeof(struct ifbreq); i++) {
1239165642Sbz		b_req = b_req_buf + i;
1240164410Ssyrinx
1241164410Ssyrinx		if ((m_if = mib_find_if_sys(b_req->ifbr_portno)) == NULL) {
1242164410Ssyrinx			syslog(LOG_ERR, "bridge member %s not present "
1243164410Ssyrinx			    "in mibII ifTable", b_req->ifbr_ifsname);
1244164410Ssyrinx			continue;
1245164410Ssyrinx		}
1246164410Ssyrinx
1247164410Ssyrinx		if ((bp = bridge_port_find(m_if->index, bif)) == NULL &&
1248164410Ssyrinx		    (bp = bridge_new_port(m_if, bif)) != NULL) {
1249164410Ssyrinx			bp->status = RowStatus_active;
1250164410Ssyrinx			added++;
1251164410Ssyrinx		}
1252164410Ssyrinx
1253164410Ssyrinx		if (bp != NULL) {
1254164410Ssyrinx			updated++;
1255164410Ssyrinx			bridge_port_getinfo_conf(b_req, bp);
1256164410Ssyrinx			bridge_port_getinfo_mibif(m_if, bp);
1257164410Ssyrinx			bp->flags |= BP_FOUND;
1258164410Ssyrinx		}
1259164410Ssyrinx	}
1260165642Sbz	free(b_req_buf);
1261164410Ssyrinx
1262164410Ssyrinx	/* Clean up list. */
1263164410Ssyrinx	for (bp = bridge_port_bif_first(bif); bp != NULL; bp = bp_next) {
1264164410Ssyrinx		bp_next  = bridge_port_bif_next(bp);
1265164410Ssyrinx
1266164410Ssyrinx		if ((bp->flags & BP_FOUND) == 0 &&
1267164410Ssyrinx		    bp->status == RowStatus_active)
1268164410Ssyrinx			bridge_port_remove(bp, bif);
1269164410Ssyrinx		else
1270164410Ssyrinx			bp->flags |= ~BP_FOUND;
1271164410Ssyrinx	}
1272164410Ssyrinx#undef	BP_FOUND
1273164410Ssyrinx
1274165642Sbz	if ((buf_len = bridge_port_get_ifstplist(bif, &bs_req_buf)) < 0)
1275164410Ssyrinx		return (-1);
1276164410Ssyrinx
1277164410Ssyrinx	for (bp = bridge_port_bif_first(bif); bp != NULL;
1278164410Ssyrinx	    bp = bridge_port_bif_next(bp)) {
1279164410Ssyrinx		if ((bs_req = bridge_port_find_ifstplist(bp->port_no,
1280165642Sbz		    bs_req_buf, buf_len)) == NULL)
1281164410Ssyrinx			bridge_port_clearinfo_opstp(bp);
1282164410Ssyrinx		else
1283164410Ssyrinx			bridge_port_getinfo_opstp(bs_req, bp);
1284164410Ssyrinx	}
1285165642Sbz	free(bs_req_buf);
1286164410Ssyrinx	bif->ports_age = time(NULL);
1287164410Ssyrinx
1288164410Ssyrinx	return (updated);
1289164410Ssyrinx}
1290164410Ssyrinx
1291164410Ssyrinx/************************************************************************
1292164410Ssyrinx * Bridge addresses.
1293164410Ssyrinx */
1294164410Ssyrinx
1295164410Ssyrinx/*
1296164410Ssyrinx * Update the bridge address info according to the polled data.
1297164410Ssyrinx */
1298164410Ssyrinxstatic void
1299164410Ssyrinxbridge_addrs_info_ifaddrlist(struct ifbareq *ifba, struct tp_entry *tpe)
1300164410Ssyrinx{
1301164410Ssyrinx	tpe->port_no = if_nametoindex(ifba->ifba_ifsname);
1302164410Ssyrinx
1303164410Ssyrinx	if ((ifba->ifba_flags & IFBAF_TYPEMASK) == IFBAF_STATIC)
1304164410Ssyrinx		tpe->status = TpFdbStatus_mgmt;
1305164410Ssyrinx	else
1306164410Ssyrinx		tpe->status = TpFdbStatus_learned;
1307164410Ssyrinx}
1308164410Ssyrinx
1309164410Ssyrinx/*
1310164410Ssyrinx * Read the bridge addresses from kernel.
1311164410Ssyrinx * Return -1 on error, or buffer len if successful.
1312164410Ssyrinx */
1313164410Ssyrinxstatic int32_t
1314165642Sbzbridge_addrs_getinfo_ifalist(struct bridge_if *bif, struct ifbareq **buf)
1315164410Ssyrinx{
1316165642Sbz	int n = 128;
1317165642Sbz	uint32_t len;
1318165642Sbz	struct ifbareq *ninbuf;
1319164410Ssyrinx	struct ifbaconf bac;
1320164410Ssyrinx	struct ifdrv ifd;
1321164410Ssyrinx
1322164410Ssyrinx	*buf = NULL;
1323164410Ssyrinx	strlcpy(ifd.ifd_name, bif->bif_name, IFNAMSIZ);
1324164410Ssyrinx	ifd.ifd_cmd = BRDGRTS;
1325164410Ssyrinx	ifd.ifd_len = sizeof(bac);
1326164410Ssyrinx	ifd.ifd_data = &bac;
1327164410Ssyrinx
1328164410Ssyrinx	for ( ; ; ) {
1329165642Sbz		len = n * sizeof(struct ifbareq);
1330165642Sbz		if ((ninbuf = (struct ifbareq *)realloc(*buf, len)) == NULL) {
1331164410Ssyrinx			syslog(LOG_ERR, "get bridge address list: "
1332164410Ssyrinx			    " realloc failed: %s", strerror(errno));
1333164410Ssyrinx			free(*buf);
1334164410Ssyrinx			*buf = NULL;
1335164410Ssyrinx			return (-1);
1336164410Ssyrinx		}
1337164410Ssyrinx
1338164410Ssyrinx		bac.ifbac_len = len;
1339165642Sbz		bac.ifbac_req = *buf = ninbuf;
1340164410Ssyrinx
1341164410Ssyrinx		if (ioctl(sock, SIOCGDRVSPEC, &ifd) < 0) {
1342164410Ssyrinx			syslog(LOG_ERR, "get bridge address list: "
1343164410Ssyrinx			    "ioctl(BRDGRTS) failed: %s", strerror(errno));
1344164410Ssyrinx			free(*buf);
1345164410Ssyrinx			buf = NULL;
1346164410Ssyrinx			return (-1);
1347164410Ssyrinx		}
1348164410Ssyrinx
1349164410Ssyrinx		if ((bac.ifbac_len + sizeof(struct ifbareq)) < len)
1350164410Ssyrinx			break;
1351164410Ssyrinx
1352165642Sbz		n += 64;
1353164410Ssyrinx	}
1354164410Ssyrinx
1355164410Ssyrinx	return (bac.ifbac_len);
1356164410Ssyrinx}
1357164410Ssyrinx
1358164410Ssyrinx/*
1359164410Ssyrinx * Read the initial info for all addresses on a bridge interface.
1360164410Ssyrinx * Returns the number of addresses, 0 - if none, otherwise
1361228990Suqs * -1 if some other error occurred.
1362164410Ssyrinx */
1363164410Ssyrinxint
1364164410Ssyrinxbridge_getinfo_bif_addrs(struct bridge_if *bif)
1365164410Ssyrinx{
1366164410Ssyrinx	uint32_t i;
1367164410Ssyrinx	int32_t buf_len;
1368165642Sbz	struct ifbareq *addr_req_buf, *addr_req;
1369164410Ssyrinx	struct tp_entry *te;
1370164410Ssyrinx
1371165642Sbz	if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1372164410Ssyrinx		return (-1);
1373164410Ssyrinx
1374164410Ssyrinx	for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1375165642Sbz		addr_req = addr_req_buf + i;
1376164410Ssyrinx
1377164410Ssyrinx		if ((te = bridge_new_addrs(addr_req->ifba_dst, bif)) != NULL)
1378164410Ssyrinx			bridge_addrs_info_ifaddrlist(addr_req, te);
1379164410Ssyrinx	}
1380164410Ssyrinx
1381165642Sbz	free(addr_req_buf);
1382164410Ssyrinx	return (i);
1383164410Ssyrinx}
1384164410Ssyrinx
1385164410Ssyrinx/*
1386164410Ssyrinx * Update the addresses for the bridge interface.
1387164410Ssyrinx */
1388164410Ssyrinxint
1389164410Ssyrinxbridge_update_addrs(struct bridge_if *bif)
1390164410Ssyrinx{
1391164410Ssyrinx	int added, updated;
1392164410Ssyrinx	uint32_t i;
1393164410Ssyrinx	int32_t buf_len;
1394164410Ssyrinx	struct tp_entry *te, *te_next;
1395165642Sbz	struct ifbareq *addr_req_buf, *addr_req;
1396164410Ssyrinx
1397165642Sbz	if ((buf_len = bridge_addrs_getinfo_ifalist(bif, &addr_req_buf)) < 0)
1398164410Ssyrinx		return (-1);
1399164410Ssyrinx
1400164410Ssyrinx	added = updated = 0;
1401164410Ssyrinx
1402164410Ssyrinx#define	BA_FOUND	0x01
1403164410Ssyrinx	for (i = 0; i < buf_len / sizeof(struct ifbareq); i++) {
1404165642Sbz		addr_req = addr_req_buf + i;
1405164410Ssyrinx
1406165642Sbz		if ((te = bridge_addrs_find(addr_req->ifba_dst, bif)) == NULL) {
1407164410Ssyrinx			added++;
1408164410Ssyrinx
1409165642Sbz			if ((te = bridge_new_addrs(addr_req->ifba_dst, bif))
1410164410Ssyrinx			    == NULL)
1411164410Ssyrinx				continue;
1412164410Ssyrinx		} else
1413164410Ssyrinx			updated++;
1414164410Ssyrinx
1415165642Sbz		bridge_addrs_info_ifaddrlist(addr_req, te);
1416164410Ssyrinx		te-> flags |= BA_FOUND;
1417164410Ssyrinx	}
1418165642Sbz	free(addr_req_buf);
1419164410Ssyrinx
1420164410Ssyrinx	for (te = bridge_addrs_bif_first(bif); te != NULL; te = te_next) {
1421164410Ssyrinx		te_next = bridge_addrs_bif_next(te);
1422164410Ssyrinx
1423164410Ssyrinx		if ((te-> flags & BA_FOUND) == 0)
1424164410Ssyrinx			bridge_addrs_remove(te, bif);
1425164410Ssyrinx		else
1426164410Ssyrinx			te-> flags &= ~BA_FOUND;
1427164410Ssyrinx	}
1428164410Ssyrinx#undef	BA_FOUND
1429164410Ssyrinx
1430164410Ssyrinx	bif->addrs_age = time(NULL);
1431164410Ssyrinx	return (updated + added);
1432164410Ssyrinx}
1433164410Ssyrinx
1434164410Ssyrinx/************************************************************************
1435164410Ssyrinx * Bridge packet filtering.
1436164410Ssyrinx */
1437164410Ssyrinxconst char bridge_sysctl[] = "net.link.bridge.";
1438164410Ssyrinx
1439164410Ssyrinxstatic struct {
1440164410Ssyrinx	int32_t val;
1441164410Ssyrinx	const char *name;
1442164410Ssyrinx} bridge_pf_sysctl[] = {
1443164410Ssyrinx	{ 1, "pfil_bridge" },
1444164410Ssyrinx	{ 1, "pfil_member" },
1445164410Ssyrinx	{ 1, "pfil_onlyip" },
1446164410Ssyrinx	{ 0, "ipfw" },
1447164410Ssyrinx};
1448164410Ssyrinx
1449164410Ssyrinxint32_t
1450164410Ssyrinxbridge_get_pfval(uint8_t which)
1451164410Ssyrinx{
1452164410Ssyrinx	if (which > sizeof(bridge_pf_sysctl) / sizeof(bridge_pf_sysctl[0])
1453164410Ssyrinx	    || which < 1)
1454164410Ssyrinx		return (-1);
1455164410Ssyrinx
1456164410Ssyrinx	return (bridge_pf_sysctl[which - 1].val);
1457164410Ssyrinx}
1458164410Ssyrinx
1459164410Ssyrinxint32_t
1460164410Ssyrinxbridge_do_pfctl(int32_t bridge_ctl, enum snmp_op op, int32_t *val)
1461164410Ssyrinx{
1462164410Ssyrinx	char mib_name[100];
1463164410Ssyrinx	int32_t i, s_i;
1464164410Ssyrinx	size_t len, s_len;
1465164410Ssyrinx
1466164410Ssyrinx	if (bridge_ctl >= LEAF_begemotBridgeLayer2PfStatus)
1467164410Ssyrinx		return (-2);
1468164410Ssyrinx
1469164410Ssyrinx	if (op == SNMP_OP_SET) {
1470164410Ssyrinx		s_i = *val;
1471164410Ssyrinx		s_len = sizeof(s_i);
1472164410Ssyrinx	} else
1473164410Ssyrinx		s_len = 0;
1474164410Ssyrinx
1475164410Ssyrinx        len = sizeof(i);
1476164410Ssyrinx
1477164410Ssyrinx	strcpy(mib_name, bridge_sysctl);
1478164410Ssyrinx
1479164410Ssyrinx	if (sysctlbyname(strcat(mib_name,
1480164410Ssyrinx	    bridge_pf_sysctl[bridge_ctl].name), &i, &len,
1481164410Ssyrinx	    (op == SNMP_OP_SET ? &s_i : NULL), s_len) == -1) {
1482164410Ssyrinx		syslog(LOG_ERR, "sysctl(%s%s) failed - %s", bridge_sysctl,
1483164410Ssyrinx		    bridge_pf_sysctl[bridge_ctl].name, strerror(errno));
1484164410Ssyrinx		return (-1);
1485164410Ssyrinx	}
1486164410Ssyrinx
1487164410Ssyrinx	bridge_pf_sysctl[bridge_ctl].val = i;
1488164410Ssyrinx	*val = i;
1489164410Ssyrinx
1490164410Ssyrinx	return (i);
1491164410Ssyrinx}
1492164410Ssyrinx
1493164410Ssyrinxvoid
1494164410Ssyrinxbridge_pf_dump(void)
1495164410Ssyrinx{
1496164410Ssyrinx	uint8_t i;
1497164410Ssyrinx
1498164410Ssyrinx	for (i = 0; i < sizeof(bridge_pf_sysctl) / sizeof(bridge_pf_sysctl[0]);
1499164410Ssyrinx	    i++) {
1500164410Ssyrinx		syslog(LOG_ERR, "%s%s = %d", bridge_sysctl,
1501164410Ssyrinx		    bridge_pf_sysctl[i].name, bridge_pf_sysctl[i].val);
1502164410Ssyrinx	}
1503164410Ssyrinx}
1504