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