1147665Sthompsa/*	$NetBSD: if_bridge.c,v 1.31 2005/06/01 19:45:34 jdc Exp $	*/
2146985Sthompsa
3146985Sthompsa/*
4146985Sthompsa * Copyright 2001 Wasabi Systems, Inc.
5146985Sthompsa * All rights reserved.
6146985Sthompsa *
7146985Sthompsa * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8146985Sthompsa *
9146985Sthompsa * Redistribution and use in source and binary forms, with or without
10146985Sthompsa * modification, are permitted provided that the following conditions
11146985Sthompsa * are met:
12146985Sthompsa * 1. Redistributions of source code must retain the above copyright
13146985Sthompsa *    notice, this list of conditions and the following disclaimer.
14146985Sthompsa * 2. Redistributions in binary form must reproduce the above copyright
15146985Sthompsa *    notice, this list of conditions and the following disclaimer in the
16146985Sthompsa *    documentation and/or other materials provided with the distribution.
17146985Sthompsa * 3. All advertising materials mentioning features or use of this software
18146985Sthompsa *    must display the following acknowledgement:
19146985Sthompsa *	This product includes software developed for the NetBSD Project by
20146985Sthompsa *	Wasabi Systems, Inc.
21146985Sthompsa * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22146985Sthompsa *    or promote products derived from this software without specific prior
23146985Sthompsa *    written permission.
24146985Sthompsa *
25146985Sthompsa * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26146985Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27146985Sthompsa * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28146985Sthompsa * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29146985Sthompsa * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30146985Sthompsa * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31146985Sthompsa * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32146985Sthompsa * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33146985Sthompsa * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34146985Sthompsa * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35146985Sthompsa * POSSIBILITY OF SUCH DAMAGE.
36146985Sthompsa */
37146985Sthompsa
38146985Sthompsa/*
39146985Sthompsa * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
40146985Sthompsa * All rights reserved.
41146985Sthompsa *
42146985Sthompsa * Redistribution and use in source and binary forms, with or without
43146985Sthompsa * modification, are permitted provided that the following conditions
44146985Sthompsa * are met:
45146985Sthompsa * 1. Redistributions of source code must retain the above copyright
46146985Sthompsa *    notice, this list of conditions and the following disclaimer.
47146985Sthompsa * 2. Redistributions in binary form must reproduce the above copyright
48146985Sthompsa *    notice, this list of conditions and the following disclaimer in the
49146985Sthompsa *    documentation and/or other materials provided with the distribution.
50146985Sthompsa *
51146985Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
52146985Sthompsa * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
53146985Sthompsa * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
54146985Sthompsa * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
55146985Sthompsa * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
56146985Sthompsa * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
57146985Sthompsa * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58146985Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
59146985Sthompsa * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
60146985Sthompsa * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61146985Sthompsa * POSSIBILITY OF SUCH DAMAGE.
62146985Sthompsa *
63146985Sthompsa * OpenBSD: if_bridge.c,v 1.60 2001/06/15 03:38:33 itojun Exp
64146985Sthompsa */
65146985Sthompsa
66146985Sthompsa/*
67146985Sthompsa * Network interface bridge support.
68146985Sthompsa *
69146985Sthompsa * TODO:
70146985Sthompsa *
71146985Sthompsa *	- Currently only supports Ethernet-like interfaces (Ethernet,
72146985Sthompsa *	  802.11, VLANs on Ethernet, etc.)  Figure out a nice way
73146985Sthompsa *	  to bridge other types of interfaces (FDDI-FDDI, and maybe
74298995Spfg *	  consider heterogeneous bridges).
75146985Sthompsa */
76146985Sthompsa
77146985Sthompsa#include <sys/cdefs.h>
78146985Sthompsa__FBSDID("$FreeBSD: stable/11/sys/net/if_bridge.c 346783 2019-04-27 04:39:41Z kevans $");
79146985Sthompsa
80146985Sthompsa#include "opt_inet.h"
81146985Sthompsa#include "opt_inet6.h"
82146985Sthompsa
83146985Sthompsa#include <sys/param.h>
84257241Sglebius#include <sys/eventhandler.h>
85146985Sthompsa#include <sys/mbuf.h>
86146985Sthompsa#include <sys/malloc.h>
87146985Sthompsa#include <sys/protosw.h>
88146985Sthompsa#include <sys/systm.h>
89225380Sthompsa#include <sys/jail.h>
90146985Sthompsa#include <sys/time.h>
91146985Sthompsa#include <sys/socket.h> /* for net/if.h */
92146985Sthompsa#include <sys/sockio.h>
93146985Sthompsa#include <sys/ctype.h>  /* string functions */
94146985Sthompsa#include <sys/kernel.h>
95146985Sthompsa#include <sys/random.h>
96160902Sthompsa#include <sys/syslog.h>
97146985Sthompsa#include <sys/sysctl.h>
98146985Sthompsa#include <vm/uma.h>
99146985Sthompsa#include <sys/module.h>
100164033Srwatson#include <sys/priv.h>
101146985Sthompsa#include <sys/proc.h>
102146985Sthompsa#include <sys/lock.h>
103146985Sthompsa#include <sys/mutex.h>
104146985Sthompsa
105146985Sthompsa#include <net/bpf.h>
106146985Sthompsa#include <net/if.h>
107146985Sthompsa#include <net/if_clone.h>
108146985Sthompsa#include <net/if_dl.h>
109146985Sthompsa#include <net/if_types.h>
110146985Sthompsa#include <net/if_var.h>
111146985Sthompsa#include <net/pfil.h>
112197952Sjulian#include <net/vnet.h>
113146985Sthompsa
114274231Sglebius#include <netinet/in.h>
115146985Sthompsa#include <netinet/in_systm.h>
116146985Sthompsa#include <netinet/in_var.h>
117146985Sthompsa#include <netinet/ip.h>
118146985Sthompsa#include <netinet/ip_var.h>
119146985Sthompsa#ifdef INET6
120146985Sthompsa#include <netinet/ip6.h>
121146985Sthompsa#include <netinet6/ip6_var.h>
122252511Shrs#include <netinet6/in6_ifattach.h>
123146985Sthompsa#endif
124193983Sbz#if defined(INET) || defined(INET6)
125159446Sthompsa#include <netinet/ip_carp.h>
126159446Sthompsa#endif
127146985Sthompsa#include <machine/in_cksum.h>
128274231Sglebius#include <netinet/if_ether.h>
129160703Sthompsa#include <net/bridgestp.h>
130146985Sthompsa#include <net/if_bridgevar.h>
131146985Sthompsa#include <net/if_llc.h>
132170681Sthompsa#include <net/if_vlan_var.h>
133146985Sthompsa
134146985Sthompsa#include <net/route.h>
135146985Sthompsa
136146985Sthompsa/*
137146985Sthompsa * Size of the route hash table.  Must be a power of two.
138146985Sthompsa */
139146985Sthompsa#ifndef BRIDGE_RTHASH_SIZE
140146985Sthompsa#define	BRIDGE_RTHASH_SIZE		1024
141146985Sthompsa#endif
142146985Sthompsa
143146985Sthompsa#define	BRIDGE_RTHASH_MASK		(BRIDGE_RTHASH_SIZE - 1)
144146985Sthompsa
145146985Sthompsa/*
146232315Sthompsa * Default maximum number of addresses to cache.
147146985Sthompsa */
148146985Sthompsa#ifndef BRIDGE_RTABLE_MAX
149232315Sthompsa#define	BRIDGE_RTABLE_MAX		2000
150146985Sthompsa#endif
151146985Sthompsa
152146985Sthompsa/*
153146985Sthompsa * Timeout (in seconds) for entries learned dynamically.
154146985Sthompsa */
155146985Sthompsa#ifndef BRIDGE_RTABLE_TIMEOUT
156146985Sthompsa#define	BRIDGE_RTABLE_TIMEOUT		(20 * 60)	/* same as ARP */
157146985Sthompsa#endif
158146985Sthompsa
159146985Sthompsa/*
160146985Sthompsa * Number of seconds between walks of the route list.
161146985Sthompsa */
162146985Sthompsa#ifndef BRIDGE_RTABLE_PRUNE_PERIOD
163146985Sthompsa#define	BRIDGE_RTABLE_PRUNE_PERIOD	(5 * 60)
164146985Sthompsa#endif
165146985Sthompsa
166154336Sthompsa/*
167180220Sthompsa * List of capabilities to possibly mask on the member interface.
168154336Sthompsa */
169304426Smav#define	BRIDGE_IFCAPS_MASK		(IFCAP_TOE|IFCAP_TSO|IFCAP_TXCSUM|\
170304426Smav					 IFCAP_TXCSUM_IPV6)
171154336Sthompsa
172160769Sthompsa/*
173196519Sjfv * List of capabilities to strip
174196519Sjfv */
175196519Sjfv#define	BRIDGE_IFCAPS_STRIP		IFCAP_LRO
176196519Sjfv
177196519Sjfv/*
178160769Sthompsa * Bridge interface list entry.
179160769Sthompsa */
180160769Sthompsastruct bridge_iflist {
181160769Sthompsa	LIST_ENTRY(bridge_iflist) bif_next;
182160769Sthompsa	struct ifnet		*bif_ifp;	/* member if */
183160769Sthompsa	struct bstp_port	bif_stp;	/* STP state */
184160769Sthompsa	uint32_t		bif_flags;	/* member if flags */
185180220Sthompsa	int			bif_savedcaps;	/* saved capabilities */
186173320Sthompsa	uint32_t		bif_addrmax;	/* max # of addresses */
187173320Sthompsa	uint32_t		bif_addrcnt;	/* cur. # of addresses */
188173320Sthompsa	uint32_t		bif_addrexceeded;/* # of address violations */
189160769Sthompsa};
190160769Sthompsa
191160769Sthompsa/*
192160769Sthompsa * Bridge route node.
193160769Sthompsa */
194160769Sthompsastruct bridge_rtnode {
195160769Sthompsa	LIST_ENTRY(bridge_rtnode) brt_hash;	/* hash table linkage */
196160769Sthompsa	LIST_ENTRY(bridge_rtnode) brt_list;	/* list linkage */
197173320Sthompsa	struct bridge_iflist	*brt_dst;	/* destination if */
198160769Sthompsa	unsigned long		brt_expire;	/* expiration time */
199160769Sthompsa	uint8_t			brt_flags;	/* address flags */
200160769Sthompsa	uint8_t			brt_addr[ETHER_ADDR_LEN];
201170681Sthompsa	uint16_t		brt_vlan;	/* vlan id */
202160769Sthompsa};
203173320Sthompsa#define	brt_ifp			brt_dst->bif_ifp
204160769Sthompsa
205160769Sthompsa/*
206160769Sthompsa * Software state for each bridge.
207160769Sthompsa */
208160769Sthompsastruct bridge_softc {
209160769Sthompsa	struct ifnet		*sc_ifp;	/* make this an interface */
210160769Sthompsa	LIST_ENTRY(bridge_softc) sc_list;
211160769Sthompsa	struct mtx		sc_mtx;
212160769Sthompsa	struct cv		sc_cv;
213160769Sthompsa	uint32_t		sc_brtmax;	/* max # of addresses */
214160769Sthompsa	uint32_t		sc_brtcnt;	/* cur. # of addresses */
215160769Sthompsa	uint32_t		sc_brttimeout;	/* rt timeout in seconds */
216160769Sthompsa	struct callout		sc_brcallout;	/* bridge callout */
217160769Sthompsa	uint32_t		sc_iflist_ref;	/* refcount for sc_iflist */
218160769Sthompsa	uint32_t		sc_iflist_xcnt;	/* refcount for sc_iflist */
219160769Sthompsa	LIST_HEAD(, bridge_iflist) sc_iflist;	/* member interface list */
220160769Sthompsa	LIST_HEAD(, bridge_rtnode) *sc_rthash;	/* our forwarding table */
221160769Sthompsa	LIST_HEAD(, bridge_rtnode) sc_rtlist;	/* list version of above */
222160769Sthompsa	uint32_t		sc_rthash_key;	/* key for hash */
223160769Sthompsa	LIST_HEAD(, bridge_iflist) sc_spanlist;	/* span ports list */
224160769Sthompsa	struct bstp_state	sc_stp;		/* STP state */
225160867Sthompsa	uint32_t		sc_brtexceeded;	/* # of cache drops */
226188594Sthompsa	struct ifnet		*sc_ifaddr;	/* member mac copied from */
227346783Skevans	struct ether_addr	sc_defaddr;	/* Default MAC address */
228160769Sthompsa};
229160769Sthompsa
230272568Shrsstatic VNET_DEFINE(struct mtx, bridge_list_mtx);
231272568Shrs#define	V_bridge_list_mtx	VNET(bridge_list_mtx)
232278766Shrsstatic eventhandler_tag bridge_detach_cookie;
233153494Sthompsa
234146985Sthompsaint	bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD;
235146985Sthompsa
236346300Skevansstatic VNET_DEFINE(uma_zone_t, bridge_rtnode_zone);
237346300Skevans#define	V_bridge_rtnode_zone	VNET(bridge_rtnode_zone)
238146985Sthompsa
239160195Ssamstatic int	bridge_clone_create(struct if_clone *, int, caddr_t);
240151313Sthompsastatic void	bridge_clone_destroy(struct ifnet *);
241146985Sthompsa
242151313Sthompsastatic int	bridge_ioctl(struct ifnet *, u_long, caddr_t);
243180220Sthompsastatic void	bridge_mutecaps(struct bridge_softc *);
244180220Sthompsastatic void	bridge_set_ifcap(struct bridge_softc *, struct bridge_iflist *,
245180220Sthompsa		    int);
246153494Sthompsastatic void	bridge_ifdetach(void *arg __unused, struct ifnet *);
247146985Sthompsastatic void	bridge_init(void *);
248151313Sthompsastatic void	bridge_dummynet(struct mbuf *, struct ifnet *);
249151313Sthompsastatic void	bridge_stop(struct ifnet *, int);
250240071Sglebiusstatic int	bridge_transmit(struct ifnet *, struct mbuf *);
251240071Sglebiusstatic void	bridge_qflush(struct ifnet *);
252151313Sthompsastatic struct mbuf *bridge_input(struct ifnet *, struct mbuf *);
253151313Sthompsastatic int	bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *,
254151313Sthompsa		    struct rtentry *);
255240071Sglebiusstatic int	bridge_enqueue(struct bridge_softc *, struct ifnet *,
256160769Sthompsa		    struct mbuf *);
257160769Sthompsastatic void	bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int);
258146985Sthompsa
259171678Sthompsastatic void	bridge_forward(struct bridge_softc *, struct bridge_iflist *,
260171678Sthompsa		    struct mbuf *m);
261146985Sthompsa
262151313Sthompsastatic void	bridge_timer(void *);
263146985Sthompsa
264151313Sthompsastatic void	bridge_broadcast(struct bridge_softc *, struct ifnet *,
265151313Sthompsa		    struct mbuf *, int);
266153408Sthompsastatic void	bridge_span(struct bridge_softc *, struct mbuf *);
267146985Sthompsa
268151313Sthompsastatic int	bridge_rtupdate(struct bridge_softc *, const uint8_t *,
269170681Sthompsa		    uint16_t, struct bridge_iflist *, int, uint8_t);
270170681Sthompsastatic struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *,
271170681Sthompsa		    uint16_t);
272151313Sthompsastatic void	bridge_rttrim(struct bridge_softc *);
273151313Sthompsastatic void	bridge_rtage(struct bridge_softc *);
274151313Sthompsastatic void	bridge_rtflush(struct bridge_softc *, int);
275170681Sthompsastatic int	bridge_rtdaddr(struct bridge_softc *, const uint8_t *,
276170681Sthompsa		    uint16_t);
277146985Sthompsa
278241183Sthompsastatic void	bridge_rtable_init(struct bridge_softc *);
279151313Sthompsastatic void	bridge_rtable_fini(struct bridge_softc *);
280146985Sthompsa
281155143Sthompsastatic int	bridge_rtnode_addr_cmp(const uint8_t *, const uint8_t *);
282151313Sthompsastatic struct bridge_rtnode *bridge_rtnode_lookup(struct bridge_softc *,
283170681Sthompsa		    const uint8_t *, uint16_t);
284151313Sthompsastatic int	bridge_rtnode_insert(struct bridge_softc *,
285151313Sthompsa		    struct bridge_rtnode *);
286151313Sthompsastatic void	bridge_rtnode_destroy(struct bridge_softc *,
287151313Sthompsa		    struct bridge_rtnode *);
288163863Sthompsastatic void	bridge_rtable_expire(struct ifnet *, int);
289160902Sthompsastatic void	bridge_state_change(struct ifnet *, int);
290146985Sthompsa
291151313Sthompsastatic struct bridge_iflist *bridge_lookup_member(struct bridge_softc *,
292151313Sthompsa		    const char *name);
293151313Sthompsastatic struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *,
294151313Sthompsa		    struct ifnet *ifp);
295151313Sthompsastatic void	bridge_delete_member(struct bridge_softc *,
296151594Sthompsa		    struct bridge_iflist *, int);
297153494Sthompsastatic void	bridge_delete_span(struct bridge_softc *,
298153494Sthompsa		    struct bridge_iflist *);
299146985Sthompsa
300151313Sthompsastatic int	bridge_ioctl_add(struct bridge_softc *, void *);
301151313Sthompsastatic int	bridge_ioctl_del(struct bridge_softc *, void *);
302151313Sthompsastatic int	bridge_ioctl_gifflags(struct bridge_softc *, void *);
303151313Sthompsastatic int	bridge_ioctl_sifflags(struct bridge_softc *, void *);
304151313Sthompsastatic int	bridge_ioctl_scache(struct bridge_softc *, void *);
305151313Sthompsastatic int	bridge_ioctl_gcache(struct bridge_softc *, void *);
306151313Sthompsastatic int	bridge_ioctl_gifs(struct bridge_softc *, void *);
307151313Sthompsastatic int	bridge_ioctl_rts(struct bridge_softc *, void *);
308151313Sthompsastatic int	bridge_ioctl_saddr(struct bridge_softc *, void *);
309151313Sthompsastatic int	bridge_ioctl_sto(struct bridge_softc *, void *);
310151313Sthompsastatic int	bridge_ioctl_gto(struct bridge_softc *, void *);
311151313Sthompsastatic int	bridge_ioctl_daddr(struct bridge_softc *, void *);
312151313Sthompsastatic int	bridge_ioctl_flush(struct bridge_softc *, void *);
313151313Sthompsastatic int	bridge_ioctl_gpri(struct bridge_softc *, void *);
314151313Sthompsastatic int	bridge_ioctl_spri(struct bridge_softc *, void *);
315151313Sthompsastatic int	bridge_ioctl_ght(struct bridge_softc *, void *);
316151313Sthompsastatic int	bridge_ioctl_sht(struct bridge_softc *, void *);
317151313Sthompsastatic int	bridge_ioctl_gfd(struct bridge_softc *, void *);
318151313Sthompsastatic int	bridge_ioctl_sfd(struct bridge_softc *, void *);
319151313Sthompsastatic int	bridge_ioctl_gma(struct bridge_softc *, void *);
320151313Sthompsastatic int	bridge_ioctl_sma(struct bridge_softc *, void *);
321151313Sthompsastatic int	bridge_ioctl_sifprio(struct bridge_softc *, void *);
322151313Sthompsastatic int	bridge_ioctl_sifcost(struct bridge_softc *, void *);
323173320Sthompsastatic int	bridge_ioctl_sifmaxaddr(struct bridge_softc *, void *);
324153408Sthompsastatic int	bridge_ioctl_addspan(struct bridge_softc *, void *);
325153408Sthompsastatic int	bridge_ioctl_delspan(struct bridge_softc *, void *);
326160867Sthompsastatic int	bridge_ioctl_gbparam(struct bridge_softc *, void *);
327160867Sthompsastatic int	bridge_ioctl_grte(struct bridge_softc *, void *);
328160867Sthompsastatic int	bridge_ioctl_gifsstp(struct bridge_softc *, void *);
329163863Sthompsastatic int	bridge_ioctl_sproto(struct bridge_softc *, void *);
330163863Sthompsastatic int	bridge_ioctl_stxhc(struct bridge_softc *, void *);
331151313Sthompsastatic int	bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *,
332151313Sthompsa		    int);
333151313Sthompsastatic int	bridge_ip_checkbasic(struct mbuf **mp);
334158667Sthompsa#ifdef INET6
335151313Sthompsastatic int	bridge_ip6_checkbasic(struct mbuf **mp);
336158667Sthompsa#endif /* INET6 */
337306593Skpstatic int	bridge_fragment(struct ifnet *, struct mbuf **mp,
338158140Sthompsa		    struct ether_header *, int, struct llc *);
339234487Sthompsastatic void	bridge_linkstate(struct ifnet *ifp);
340236916Sthompsastatic void	bridge_linkcheck(struct bridge_softc *sc);
341146985Sthompsa
342234487Sthompsaextern void (*bridge_linkstate_p)(struct ifnet *ifp);
343234487Sthompsa
344170681Sthompsa/* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */
345170681Sthompsa#define	VLANTAGOF(_m)	\
346170681Sthompsa    (_m->m_flags & M_VLANTAG) ? EVL_VLANOFTAG(_m->m_pkthdr.ether_vtag) : 1
347170681Sthompsa
348167379Sthompsastatic struct bstp_cb_ops bridge_ops = {
349167379Sthompsa	.bcb_state = bridge_state_change,
350167379Sthompsa	.bcb_rtage = bridge_rtable_expire
351167379Sthompsa};
352167379Sthompsa
353146985SthompsaSYSCTL_DECL(_net_link);
354227309Sedstatic SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW, 0, "Bridge");
355146985Sthompsa
356272568Shrs/* only pass IP[46] packets when pfil is enabled */
357272568Shrsstatic VNET_DEFINE(int, pfil_onlyip) = 1;
358272568Shrs#define	V_pfil_onlyip	VNET(pfil_onlyip)
359272568ShrsSYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_onlyip,
360272568Shrs    CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(pfil_onlyip), 0,
361272568Shrs    "Only pass IP packets when pfil is enabled");
362272568Shrs
363272568Shrs/* run pfil hooks on the bridge interface */
364272568Shrsstatic VNET_DEFINE(int, pfil_bridge) = 1;
365272568Shrs#define	V_pfil_bridge	VNET(pfil_bridge)
366272568ShrsSYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_bridge,
367272568Shrs    CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(pfil_bridge), 0,
368272568Shrs    "Packet filter on the bridge interface");
369272568Shrs
370272568Shrs/* layer2 filter with ipfw */
371272568Shrsstatic VNET_DEFINE(int, pfil_ipfw);
372272568Shrs#define	V_pfil_ipfw	VNET(pfil_ipfw)
373272568Shrs
374272568Shrs/* layer2 ARP filter with ipfw */
375272568Shrsstatic VNET_DEFINE(int, pfil_ipfw_arp);
376272568Shrs#define	V_pfil_ipfw_arp	VNET(pfil_ipfw_arp)
377272568ShrsSYSCTL_INT(_net_link_bridge, OID_AUTO, ipfw_arp,
378272568Shrs    CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(pfil_ipfw_arp), 0,
379272568Shrs    "Filter ARP packets through IPFW layer2");
380272568Shrs
381272568Shrs/* run pfil hooks on the member interface */
382272568Shrsstatic VNET_DEFINE(int, pfil_member) = 1;
383272568Shrs#define	V_pfil_member	VNET(pfil_member)
384272568ShrsSYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_member,
385272568Shrs    CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(pfil_member), 0,
386272568Shrs    "Packet filter on the member interface");
387272568Shrs
388272568Shrs/* run pfil hooks on the physical interface for locally destined packets */
389272568Shrsstatic VNET_DEFINE(int, pfil_local_phys);
390272568Shrs#define	V_pfil_local_phys	VNET(pfil_local_phys)
391272568ShrsSYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_local_phys,
392272568Shrs    CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(pfil_local_phys), 0,
393172201Sthompsa    "Packet filter on the physical interface for locally destined packets");
394272568Shrs
395272568Shrs/* log STP state changes */
396272568Shrsstatic VNET_DEFINE(int, log_stp);
397272568Shrs#define	V_log_stp	VNET(log_stp)
398272568ShrsSYSCTL_INT(_net_link_bridge, OID_AUTO, log_stp,
399272568Shrs    CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(log_stp), 0,
400272568Shrs    "Log STP state changes");
401272568Shrs
402272568Shrs/* share MAC with first bridge member */
403272568Shrsstatic VNET_DEFINE(int, bridge_inherit_mac);
404272568Shrs#define	V_bridge_inherit_mac	VNET(bridge_inherit_mac)
405272568ShrsSYSCTL_INT(_net_link_bridge, OID_AUTO, inherit_mac,
406272568Shrs    CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(bridge_inherit_mac), 0,
407182862Sthompsa    "Inherit MAC address from the first bridge member");
408146985Sthompsa
409253751Shrsstatic VNET_DEFINE(int, allow_llz_overlap) = 0;
410253751Shrs#define	V_allow_llz_overlap	VNET(allow_llz_overlap)
411274225SglebiusSYSCTL_INT(_net_link_bridge, OID_AUTO, allow_llz_overlap,
412274225Sglebius    CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(allow_llz_overlap), 0,
413272568Shrs    "Allow overlap of link-local scope "
414253751Shrs    "zones of a bridge interface and the member interfaces");
415253751Shrs
416146985Sthompsastruct bridge_control {
417146985Sthompsa	int	(*bc_func)(struct bridge_softc *, void *);
418146985Sthompsa	int	bc_argsize;
419146985Sthompsa	int	bc_flags;
420146985Sthompsa};
421146985Sthompsa
422146985Sthompsa#define	BC_F_COPYIN		0x01	/* copy arguments in */
423146985Sthompsa#define	BC_F_COPYOUT		0x02	/* copy arguments out */
424146985Sthompsa#define	BC_F_SUSER		0x04	/* do super-user check */
425146985Sthompsa
426146985Sthompsaconst struct bridge_control bridge_control_table[] = {
427146985Sthompsa	{ bridge_ioctl_add,		sizeof(struct ifbreq),
428146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
429146985Sthompsa	{ bridge_ioctl_del,		sizeof(struct ifbreq),
430146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
431146985Sthompsa
432146985Sthompsa	{ bridge_ioctl_gifflags,	sizeof(struct ifbreq),
433146985Sthompsa	  BC_F_COPYIN|BC_F_COPYOUT },
434146985Sthompsa	{ bridge_ioctl_sifflags,	sizeof(struct ifbreq),
435146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
436146985Sthompsa
437146985Sthompsa	{ bridge_ioctl_scache,		sizeof(struct ifbrparam),
438146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
439146985Sthompsa	{ bridge_ioctl_gcache,		sizeof(struct ifbrparam),
440146985Sthompsa	  BC_F_COPYOUT },
441146985Sthompsa
442146985Sthompsa	{ bridge_ioctl_gifs,		sizeof(struct ifbifconf),
443146985Sthompsa	  BC_F_COPYIN|BC_F_COPYOUT },
444146985Sthompsa	{ bridge_ioctl_rts,		sizeof(struct ifbaconf),
445146985Sthompsa	  BC_F_COPYIN|BC_F_COPYOUT },
446146985Sthompsa
447146985Sthompsa	{ bridge_ioctl_saddr,		sizeof(struct ifbareq),
448146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
449146985Sthompsa
450146985Sthompsa	{ bridge_ioctl_sto,		sizeof(struct ifbrparam),
451146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
452146985Sthompsa	{ bridge_ioctl_gto,		sizeof(struct ifbrparam),
453146985Sthompsa	  BC_F_COPYOUT },
454146985Sthompsa
455146985Sthompsa	{ bridge_ioctl_daddr,		sizeof(struct ifbareq),
456146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
457146985Sthompsa
458146985Sthompsa	{ bridge_ioctl_flush,		sizeof(struct ifbreq),
459146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
460146985Sthompsa
461146985Sthompsa	{ bridge_ioctl_gpri,		sizeof(struct ifbrparam),
462146985Sthompsa	  BC_F_COPYOUT },
463146985Sthompsa	{ bridge_ioctl_spri,		sizeof(struct ifbrparam),
464146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
465146985Sthompsa
466146985Sthompsa	{ bridge_ioctl_ght,		sizeof(struct ifbrparam),
467146985Sthompsa	  BC_F_COPYOUT },
468146985Sthompsa	{ bridge_ioctl_sht,		sizeof(struct ifbrparam),
469146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
470146985Sthompsa
471146985Sthompsa	{ bridge_ioctl_gfd,		sizeof(struct ifbrparam),
472146985Sthompsa	  BC_F_COPYOUT },
473146985Sthompsa	{ bridge_ioctl_sfd,		sizeof(struct ifbrparam),
474146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
475146985Sthompsa
476146985Sthompsa	{ bridge_ioctl_gma,		sizeof(struct ifbrparam),
477146985Sthompsa	  BC_F_COPYOUT },
478146985Sthompsa	{ bridge_ioctl_sma,		sizeof(struct ifbrparam),
479146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
480146985Sthompsa
481146985Sthompsa	{ bridge_ioctl_sifprio,		sizeof(struct ifbreq),
482146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
483146985Sthompsa
484146985Sthompsa	{ bridge_ioctl_sifcost,		sizeof(struct ifbreq),
485146985Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
486153408Sthompsa
487153408Sthompsa	{ bridge_ioctl_addspan,		sizeof(struct ifbreq),
488153408Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
489153408Sthompsa	{ bridge_ioctl_delspan,		sizeof(struct ifbreq),
490153408Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
491160867Sthompsa
492160867Sthompsa	{ bridge_ioctl_gbparam,		sizeof(struct ifbropreq),
493160867Sthompsa	  BC_F_COPYOUT },
494160867Sthompsa
495160867Sthompsa	{ bridge_ioctl_grte,		sizeof(struct ifbrparam),
496160867Sthompsa	  BC_F_COPYOUT },
497160867Sthompsa
498160867Sthompsa	{ bridge_ioctl_gifsstp,		sizeof(struct ifbpstpconf),
499164861Ssyrinx	  BC_F_COPYIN|BC_F_COPYOUT },
500163863Sthompsa
501163863Sthompsa	{ bridge_ioctl_sproto,		sizeof(struct ifbrparam),
502163863Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
503163863Sthompsa
504163863Sthompsa	{ bridge_ioctl_stxhc,		sizeof(struct ifbrparam),
505163863Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
506173320Sthompsa
507173320Sthompsa	{ bridge_ioctl_sifmaxaddr,	sizeof(struct ifbreq),
508173320Sthompsa	  BC_F_COPYIN|BC_F_SUSER },
509173320Sthompsa
510146985Sthompsa};
511272568Shrsconst int bridge_control_table_size = nitems(bridge_control_table);
512146985Sthompsa
513272568Shrsstatic VNET_DEFINE(LIST_HEAD(, bridge_softc), bridge_list);
514272568Shrs#define	V_bridge_list	VNET(bridge_list)
515272568Shrs#define	BRIDGE_LIST_LOCK_INIT(x)	mtx_init(&V_bridge_list_mtx,	\
516272568Shrs					    "if_bridge list", NULL, MTX_DEF)
517272568Shrs#define	BRIDGE_LIST_LOCK_DESTROY(x)	mtx_destroy(&V_bridge_list_mtx)
518272568Shrs#define	BRIDGE_LIST_LOCK(x)		mtx_lock(&V_bridge_list_mtx)
519272568Shrs#define	BRIDGE_LIST_UNLOCK(x)		mtx_unlock(&V_bridge_list_mtx)
520153494Sthompsa
521272568Shrsstatic VNET_DEFINE(struct if_clone *, bridge_cloner);
522272568Shrs#define	V_bridge_cloner	VNET(bridge_cloner)
523272568Shrs
524241610Sglebiusstatic const char bridge_name[] = "bridge";
525146985Sthompsa
526272568Shrsstatic void
527272568Shrsvnet_bridge_init(const void *unused __unused)
528272568Shrs{
529272568Shrs
530346300Skevans	V_bridge_rtnode_zone = uma_zcreate("bridge_rtnode",
531346300Skevans	    sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL,
532346300Skevans	    UMA_ALIGN_PTR, 0);
533272568Shrs	BRIDGE_LIST_LOCK_INIT();
534272568Shrs	LIST_INIT(&V_bridge_list);
535272568Shrs	V_bridge_cloner = if_clone_simple(bridge_name,
536272568Shrs	    bridge_clone_create, bridge_clone_destroy, 0);
537272568Shrs}
538272568ShrsVNET_SYSINIT(vnet_bridge_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
539272568Shrs    vnet_bridge_init, NULL);
540272568Shrs
541272568Shrsstatic void
542272568Shrsvnet_bridge_uninit(const void *unused __unused)
543272568Shrs{
544272568Shrs
545272568Shrs	if_clone_detach(V_bridge_cloner);
546278766Shrs	V_bridge_cloner = NULL;
547272568Shrs	BRIDGE_LIST_LOCK_DESTROY();
548346300Skevans	uma_zdestroy(V_bridge_rtnode_zone);
549272568Shrs}
550302054SbzVNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
551272568Shrs    vnet_bridge_uninit, NULL);
552272568Shrs
553146985Sthompsastatic int
554146985Sthompsabridge_modevent(module_t mod, int type, void *data)
555146985Sthompsa{
556146985Sthompsa
557146985Sthompsa	switch (type) {
558146985Sthompsa	case MOD_LOAD:
559146985Sthompsa		bridge_input_p = bridge_input;
560146985Sthompsa		bridge_output_p = bridge_output;
561147205Sthompsa		bridge_dn_p = bridge_dummynet;
562234487Sthompsa		bridge_linkstate_p = bridge_linkstate;
563153494Sthompsa		bridge_detach_cookie = EVENTHANDLER_REGISTER(
564153494Sthompsa		    ifnet_departure_event, bridge_ifdetach, NULL,
565153494Sthompsa		    EVENTHANDLER_PRI_ANY);
566146985Sthompsa		break;
567146985Sthompsa	case MOD_UNLOAD:
568153494Sthompsa		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
569153494Sthompsa		    bridge_detach_cookie);
570146985Sthompsa		bridge_input_p = NULL;
571146985Sthompsa		bridge_output_p = NULL;
572147205Sthompsa		bridge_dn_p = NULL;
573234487Sthompsa		bridge_linkstate_p = NULL;
574146985Sthompsa		break;
575146985Sthompsa	default:
576158667Sthompsa		return (EOPNOTSUPP);
577146985Sthompsa	}
578158667Sthompsa	return (0);
579146985Sthompsa}
580146985Sthompsa
581146985Sthompsastatic moduledata_t bridge_mod = {
582153497Sthompsa	"if_bridge",
583153497Sthompsa	bridge_modevent,
584241394Skevlo	0
585146985Sthompsa};
586146985Sthompsa
587146985SthompsaDECLARE_MODULE(if_bridge, bridge_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
588324115SkpMODULE_VERSION(if_bridge, 1);
589160730SthompsaMODULE_DEPEND(if_bridge, bridgestp, 1, 1, 1);
590146985Sthompsa
591147111Sthompsa/*
592244378Skevlo * handler for net.link.bridge.ipfw
593147111Sthompsa */
594147111Sthompsastatic int
595147111Sthompsasysctl_pfil_ipfw(SYSCTL_HANDLER_ARGS)
596147111Sthompsa{
597272568Shrs	int enable = V_pfil_ipfw;
598153497Sthompsa	int error;
599146985Sthompsa
600153497Sthompsa	error = sysctl_handle_int(oidp, &enable, 0, req);
601272568Shrs	enable &= 1;
602147111Sthompsa
603272568Shrs	if (enable != V_pfil_ipfw) {
604272568Shrs		V_pfil_ipfw = enable;
605147111Sthompsa
606153497Sthompsa		/*
607153497Sthompsa		 * Disable pfil so that ipfw doesnt run twice, if the user
608153497Sthompsa		 * really wants both then they can re-enable pfil_bridge and/or
609153831Sthompsa		 * pfil_member. Also allow non-ip packets as ipfw can filter by
610153831Sthompsa		 * layer2 type.
611153497Sthompsa		 */
612272568Shrs		if (V_pfil_ipfw) {
613272568Shrs			V_pfil_onlyip = 0;
614272568Shrs			V_pfil_bridge = 0;
615272568Shrs			V_pfil_member = 0;
616153497Sthompsa		}
617147111Sthompsa	}
618147111Sthompsa
619158667Sthompsa	return (error);
620147111Sthompsa}
621272568ShrsSYSCTL_PROC(_net_link_bridge, OID_AUTO, ipfw,
622272568Shrs    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_VNET,
623272568Shrs    &VNET_NAME(pfil_ipfw), 0, &sysctl_pfil_ipfw, "I",
624272568Shrs    "Layer2 filter with IPFW");
625147111Sthompsa
626146985Sthompsa/*
627146985Sthompsa * bridge_clone_create:
628146985Sthompsa *
629146985Sthompsa *	Create a new bridge instance.
630146985Sthompsa */
631151313Sthompsastatic int
632160195Ssambridge_clone_create(struct if_clone *ifc, int unit, caddr_t params)
633146985Sthompsa{
634156238Sthompsa	struct bridge_softc *sc, *sc2;
635156238Sthompsa	struct ifnet *bifp, *ifp;
636225380Sthompsa	int fb, retry;
637225380Sthompsa	unsigned long hostid;
638146985Sthompsa
639146985Sthompsa	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
640147281Sthompsa	ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
641147281Sthompsa	if (ifp == NULL) {
642147281Sthompsa		free(sc, M_DEVBUF);
643147281Sthompsa		return (ENOSPC);
644147281Sthompsa	}
645146985Sthompsa
646166916Sthompsa	BRIDGE_LOCK_INIT(sc);
647146985Sthompsa	sc->sc_brtmax = BRIDGE_RTABLE_MAX;
648146985Sthompsa	sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT;
649146985Sthompsa
650146985Sthompsa	/* Initialize our routing table. */
651146985Sthompsa	bridge_rtable_init(sc);
652146985Sthompsa
653149253Sthompsa	callout_init_mtx(&sc->sc_brcallout, &sc->sc_mtx, 0);
654146985Sthompsa
655146985Sthompsa	LIST_INIT(&sc->sc_iflist);
656153408Sthompsa	LIST_INIT(&sc->sc_spanlist);
657146985Sthompsa
658146985Sthompsa	ifp->if_softc = sc;
659241610Sglebius	if_initname(ifp, bridge_name, unit);
660161625Sthompsa	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
661146985Sthompsa	ifp->if_ioctl = bridge_ioctl;
662240071Sglebius	ifp->if_transmit = bridge_transmit;
663240071Sglebius	ifp->if_qflush = bridge_qflush;
664146985Sthompsa	ifp->if_init = bridge_init;
665146985Sthompsa	ifp->if_type = IFT_BRIDGE;
666146985Sthompsa
667146985Sthompsa	/*
668225380Sthompsa	 * Generate an ethernet address with a locally administered address.
669156238Sthompsa	 *
670156238Sthompsa	 * Since we are using random ethernet addresses for the bridge, it is
671156238Sthompsa	 * possible that we might have address collisions, so make sure that
672156238Sthompsa	 * this hardware address isn't already in use on another bridge.
673225380Sthompsa	 * The first try uses the hostid and falls back to arc4rand().
674146985Sthompsa	 */
675225380Sthompsa	fb = 0;
676225380Sthompsa	getcredhostid(curthread->td_ucred, &hostid);
677243669Spjd	do {
678225380Sthompsa		if (fb || hostid == 0) {
679346783Skevans			ether_gen_addr(ifp, &sc->sc_defaddr);
680225380Sthompsa		} else {
681346783Skevans			sc->sc_defaddr.octet[0] = 0x2;
682346783Skevans			sc->sc_defaddr.octet[1] = (hostid >> 24) & 0xff;
683346783Skevans			sc->sc_defaddr.octet[2] = (hostid >> 16) & 0xff;
684346783Skevans			sc->sc_defaddr.octet[3] = (hostid >> 8 ) & 0xff;
685346783Skevans			sc->sc_defaddr.octet[4] =  hostid        & 0xff;
686346783Skevans			sc->sc_defaddr.octet[5] = ifp->if_dunit & 0xff;
687225380Sthompsa		}
688225380Sthompsa
689225380Sthompsa		fb = 1;
690156238Sthompsa		retry = 0;
691272568Shrs		BRIDGE_LIST_LOCK();
692272568Shrs		LIST_FOREACH(sc2, &V_bridge_list, sc_list) {
693156238Sthompsa			bifp = sc2->sc_ifp;
694346783Skevans			if (memcmp(sc->sc_defaddr.octet,
695243669Spjd			    IF_LLADDR(bifp), ETHER_ADDR_LEN) == 0) {
696156238Sthompsa				retry = 1;
697243669Spjd				break;
698243669Spjd			}
699156238Sthompsa		}
700272568Shrs		BRIDGE_LIST_UNLOCK();
701243669Spjd	} while (retry == 1);
702146985Sthompsa
703167379Sthompsa	bstp_attach(&sc->sc_stp, &bridge_ops);
704346783Skevans	ether_ifattach(ifp, sc->sc_defaddr.octet);
705146985Sthompsa	/* Now undo some of the damage... */
706146985Sthompsa	ifp->if_baudrate = 0;
707146985Sthompsa	ifp->if_type = IFT_BRIDGE;
708146985Sthompsa
709272568Shrs	BRIDGE_LIST_LOCK();
710272568Shrs	LIST_INSERT_HEAD(&V_bridge_list, sc, sc_list);
711272568Shrs	BRIDGE_LIST_UNLOCK();
712153494Sthompsa
713146985Sthompsa	return (0);
714146985Sthompsa}
715146985Sthompsa
716146985Sthompsa/*
717146985Sthompsa * bridge_clone_destroy:
718146985Sthompsa *
719146985Sthompsa *	Destroy a bridge instance.
720146985Sthompsa */
721151313Sthompsastatic void
722146985Sthompsabridge_clone_destroy(struct ifnet *ifp)
723146985Sthompsa{
724146985Sthompsa	struct bridge_softc *sc = ifp->if_softc;
725146985Sthompsa	struct bridge_iflist *bif;
726146985Sthompsa
727146985Sthompsa	BRIDGE_LOCK(sc);
728146985Sthompsa
729146985Sthompsa	bridge_stop(ifp, 1);
730149522Sthompsa	ifp->if_flags &= ~IFF_UP;
731146985Sthompsa
732146985Sthompsa	while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL)
733151594Sthompsa		bridge_delete_member(sc, bif, 0);
734146985Sthompsa
735153408Sthompsa	while ((bif = LIST_FIRST(&sc->sc_spanlist)) != NULL) {
736153494Sthompsa		bridge_delete_span(sc, bif);
737153408Sthompsa	}
738153408Sthompsa
739346300Skevans	/* Tear down the routing table. */
740346300Skevans	bridge_rtable_fini(sc);
741346300Skevans
742146985Sthompsa	BRIDGE_UNLOCK(sc);
743146985Sthompsa
744149253Sthompsa	callout_drain(&sc->sc_brcallout);
745149253Sthompsa
746272568Shrs	BRIDGE_LIST_LOCK();
747153494Sthompsa	LIST_REMOVE(sc, sc_list);
748272568Shrs	BRIDGE_LIST_UNLOCK();
749153494Sthompsa
750160703Sthompsa	bstp_detach(&sc->sc_stp);
751146985Sthompsa	ether_ifdetach(ifp);
752227459Sbrooks	if_free(ifp);
753146985Sthompsa
754146985Sthompsa	BRIDGE_LOCK_DESTROY(sc);
755146985Sthompsa	free(sc, M_DEVBUF);
756146985Sthompsa}
757146985Sthompsa
758146985Sthompsa/*
759146985Sthompsa * bridge_ioctl:
760146985Sthompsa *
761146985Sthompsa *	Handle a control request from the operator.
762146985Sthompsa */
763151313Sthompsastatic int
764146985Sthompsabridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
765146985Sthompsa{
766146985Sthompsa	struct bridge_softc *sc = ifp->if_softc;
767203272Shrs	struct ifreq *ifr = (struct ifreq *)data;
768203272Shrs	struct bridge_iflist *bif;
769146985Sthompsa	struct thread *td = curthread;
770146985Sthompsa	union {
771146985Sthompsa		struct ifbreq ifbreq;
772146985Sthompsa		struct ifbifconf ifbifconf;
773146985Sthompsa		struct ifbareq ifbareq;
774146985Sthompsa		struct ifbaconf ifbaconf;
775146985Sthompsa		struct ifbrparam ifbrparam;
776164653Sthompsa		struct ifbropreq ifbropreq;
777146985Sthompsa	} args;
778146985Sthompsa	struct ifdrv *ifd = (struct ifdrv *) data;
779146985Sthompsa	const struct bridge_control *bc;
780146985Sthompsa	int error = 0;
781146985Sthompsa
782146985Sthompsa	switch (cmd) {
783146985Sthompsa
784149829Sthompsa	case SIOCADDMULTI:
785149829Sthompsa	case SIOCDELMULTI:
786149829Sthompsa		break;
787149829Sthompsa
788146985Sthompsa	case SIOCGDRVSPEC:
789146985Sthompsa	case SIOCSDRVSPEC:
790146985Sthompsa		if (ifd->ifd_cmd >= bridge_control_table_size) {
791146985Sthompsa			error = EINVAL;
792146985Sthompsa			break;
793146985Sthompsa		}
794146985Sthompsa		bc = &bridge_control_table[ifd->ifd_cmd];
795146985Sthompsa
796146985Sthompsa		if (cmd == SIOCGDRVSPEC &&
797146985Sthompsa		    (bc->bc_flags & BC_F_COPYOUT) == 0) {
798146985Sthompsa			error = EINVAL;
799146985Sthompsa			break;
800146985Sthompsa		}
801146985Sthompsa		else if (cmd == SIOCSDRVSPEC &&
802146985Sthompsa		    (bc->bc_flags & BC_F_COPYOUT) != 0) {
803146985Sthompsa			error = EINVAL;
804146985Sthompsa			break;
805146985Sthompsa		}
806146985Sthompsa
807146985Sthompsa		if (bc->bc_flags & BC_F_SUSER) {
808164033Srwatson			error = priv_check(td, PRIV_NET_BRIDGE);
809146985Sthompsa			if (error)
810146985Sthompsa				break;
811146985Sthompsa		}
812146985Sthompsa
813146985Sthompsa		if (ifd->ifd_len != bc->bc_argsize ||
814146985Sthompsa		    ifd->ifd_len > sizeof(args)) {
815146985Sthompsa			error = EINVAL;
816146985Sthompsa			break;
817146985Sthompsa		}
818146985Sthompsa
819158667Sthompsa		bzero(&args, sizeof(args));
820146985Sthompsa		if (bc->bc_flags & BC_F_COPYIN) {
821146985Sthompsa			error = copyin(ifd->ifd_data, &args, ifd->ifd_len);
822146985Sthompsa			if (error)
823146985Sthompsa				break;
824146985Sthompsa		}
825146985Sthompsa
826171603Sthompsa		BRIDGE_LOCK(sc);
827146985Sthompsa		error = (*bc->bc_func)(sc, &args);
828171603Sthompsa		BRIDGE_UNLOCK(sc);
829146985Sthompsa		if (error)
830146985Sthompsa			break;
831146985Sthompsa
832146985Sthompsa		if (bc->bc_flags & BC_F_COPYOUT)
833146985Sthompsa			error = copyout(&args, ifd->ifd_data, ifd->ifd_len);
834146985Sthompsa
835146985Sthompsa		break;
836146985Sthompsa
837146985Sthompsa	case SIOCSIFFLAGS:
838148887Srwatson		if (!(ifp->if_flags & IFF_UP) &&
839148887Srwatson		    (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
840146985Sthompsa			/*
841146985Sthompsa			 * If interface is marked down and it is running,
842146985Sthompsa			 * then stop and disable it.
843146985Sthompsa			 */
844171603Sthompsa			BRIDGE_LOCK(sc);
845146985Sthompsa			bridge_stop(ifp, 1);
846171603Sthompsa			BRIDGE_UNLOCK(sc);
847148887Srwatson		} else if ((ifp->if_flags & IFF_UP) &&
848148887Srwatson		    !(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
849146985Sthompsa			/*
850146985Sthompsa			 * If interface is marked up and it is stopped, then
851146985Sthompsa			 * start it.
852146985Sthompsa			 */
853147634Sthompsa			(*ifp->if_init)(sc);
854146985Sthompsa		}
855146985Sthompsa		break;
856146985Sthompsa
857146985Sthompsa	case SIOCSIFMTU:
858203272Shrs		if (ifr->ifr_mtu < 576) {
859203272Shrs			error = EINVAL;
860203272Shrs			break;
861203272Shrs		}
862203272Shrs		if (LIST_EMPTY(&sc->sc_iflist)) {
863203272Shrs			sc->sc_ifp->if_mtu = ifr->ifr_mtu;
864203272Shrs			break;
865203272Shrs		}
866203272Shrs		BRIDGE_LOCK(sc);
867203272Shrs		LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
868203272Shrs			if (bif->bif_ifp->if_mtu != ifr->ifr_mtu) {
869263102Sglebius				log(LOG_NOTICE, "%s: invalid MTU: %u(%s)"
870203272Shrs				    " != %d\n", sc->sc_ifp->if_xname,
871203272Shrs				    bif->bif_ifp->if_mtu,
872203272Shrs				    bif->bif_ifp->if_xname, ifr->ifr_mtu);
873203272Shrs				error = EINVAL;
874203272Shrs				break;
875203272Shrs			}
876203272Shrs		}
877203272Shrs		if (!error)
878203272Shrs			sc->sc_ifp->if_mtu = ifr->ifr_mtu;
879203272Shrs		BRIDGE_UNLOCK(sc);
880146985Sthompsa		break;
881146985Sthompsa	default:
882153497Sthompsa		/*
883146985Sthompsa		 * drop the lock as ether_ioctl() will call bridge_start() and
884146985Sthompsa		 * cause the lock to be recursed.
885146985Sthompsa		 */
886146985Sthompsa		error = ether_ioctl(ifp, cmd, data);
887146985Sthompsa		break;
888146985Sthompsa	}
889146985Sthompsa
890146985Sthompsa	return (error);
891146985Sthompsa}
892146985Sthompsa
893146985Sthompsa/*
894154336Sthompsa * bridge_mutecaps:
895154336Sthompsa *
896154336Sthompsa *	Clear or restore unwanted capabilities on the member interface
897154336Sthompsa */
898154336Sthompsastatic void
899180220Sthompsabridge_mutecaps(struct bridge_softc *sc)
900154336Sthompsa{
901180220Sthompsa	struct bridge_iflist *bif;
902180220Sthompsa	int enabled, mask;
903180220Sthompsa
904180220Sthompsa	/* Initial bitmask of capabilities to test */
905180220Sthompsa	mask = BRIDGE_IFCAPS_MASK;
906180220Sthompsa
907180220Sthompsa	LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
908180220Sthompsa		/* Every member must support it or its disabled */
909180220Sthompsa		mask &= bif->bif_savedcaps;
910180220Sthompsa	}
911180220Sthompsa
912313050Skp	BRIDGE_XLOCK(sc);
913180220Sthompsa	LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
914180220Sthompsa		enabled = bif->bif_ifp->if_capenable;
915196519Sjfv		enabled &= ~BRIDGE_IFCAPS_STRIP;
916180220Sthompsa		/* strip off mask bits and enable them again if allowed */
917180220Sthompsa		enabled &= ~BRIDGE_IFCAPS_MASK;
918180220Sthompsa		enabled |= mask;
919313050Skp		BRIDGE_UNLOCK(sc);
920180220Sthompsa		bridge_set_ifcap(sc, bif, enabled);
921313050Skp		BRIDGE_LOCK(sc);
922180220Sthompsa	}
923313050Skp	BRIDGE_XDROP(sc);
924180220Sthompsa
925180220Sthompsa}
926180220Sthompsa
927180220Sthompsastatic void
928180220Sthompsabridge_set_ifcap(struct bridge_softc *sc, struct bridge_iflist *bif, int set)
929180220Sthompsa{
930154336Sthompsa	struct ifnet *ifp = bif->bif_ifp;
931154336Sthompsa	struct ifreq ifr;
932346767Smav	int error, mask, stuck;
933154336Sthompsa
934313050Skp	BRIDGE_UNLOCK_ASSERT(sc);
935313050Skp
936158667Sthompsa	bzero(&ifr, sizeof(ifr));
937180220Sthompsa	ifr.ifr_reqcap = set;
938154336Sthompsa
939180220Sthompsa	if (ifp->if_capenable != set) {
940154336Sthompsa		error = (*ifp->if_ioctl)(ifp, SIOCSIFCAP, (caddr_t)&ifr);
941180220Sthompsa		if (error)
942180220Sthompsa			if_printf(sc->sc_ifp,
943346766Smav			    "error setting capabilities on %s: %d\n",
944346766Smav			    ifp->if_xname, error);
945346767Smav		mask = BRIDGE_IFCAPS_MASK | BRIDGE_IFCAPS_STRIP;
946346767Smav		stuck = ifp->if_capenable & mask & ~set;
947346767Smav		if (stuck != 0)
948346766Smav			if_printf(sc->sc_ifp,
949346766Smav			    "can't disable some capabilities on %s: 0x%x\n",
950346767Smav			    ifp->if_xname, stuck);
951154336Sthompsa	}
952154336Sthompsa}
953154336Sthompsa
954154336Sthompsa/*
955146985Sthompsa * bridge_lookup_member:
956146985Sthompsa *
957146985Sthompsa *	Lookup a bridge member interface.
958146985Sthompsa */
959151345Sthompsastatic struct bridge_iflist *
960146985Sthompsabridge_lookup_member(struct bridge_softc *sc, const char *name)
961146985Sthompsa{
962146985Sthompsa	struct bridge_iflist *bif;
963146985Sthompsa	struct ifnet *ifp;
964146985Sthompsa
965146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
966146985Sthompsa
967146985Sthompsa	LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
968146985Sthompsa		ifp = bif->bif_ifp;
969146985Sthompsa		if (strcmp(ifp->if_xname, name) == 0)
970146985Sthompsa			return (bif);
971146985Sthompsa	}
972146985Sthompsa
973146985Sthompsa	return (NULL);
974146985Sthompsa}
975146985Sthompsa
976146985Sthompsa/*
977146985Sthompsa * bridge_lookup_member_if:
978146985Sthompsa *
979146985Sthompsa *	Lookup a bridge member interface by ifnet*.
980146985Sthompsa */
981151345Sthompsastatic struct bridge_iflist *
982146985Sthompsabridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp)
983146985Sthompsa{
984146985Sthompsa	struct bridge_iflist *bif;
985146985Sthompsa
986146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
987146985Sthompsa
988146985Sthompsa	LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
989146985Sthompsa		if (bif->bif_ifp == member_ifp)
990146985Sthompsa			return (bif);
991146985Sthompsa	}
992146985Sthompsa
993146985Sthompsa	return (NULL);
994146985Sthompsa}
995146985Sthompsa
996146985Sthompsa/*
997146985Sthompsa * bridge_delete_member:
998146985Sthompsa *
999146985Sthompsa *	Delete the specified member interface.
1000146985Sthompsa */
1001151313Sthompsastatic void
1002151594Sthompsabridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
1003151594Sthompsa    int gone)
1004146985Sthompsa{
1005146985Sthompsa	struct ifnet *ifs = bif->bif_ifp;
1006180140Sphilip	struct ifnet *fif = NULL;
1007146985Sthompsa
1008146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
1009146985Sthompsa
1010160703Sthompsa	if (bif->bif_flags & IFBIF_STP)
1011164626Sthompsa		bstp_disable(&bif->bif_stp);
1012160703Sthompsa
1013146985Sthompsa	ifs->if_bridge = NULL;
1014146985Sthompsa	BRIDGE_XLOCK(sc);
1015146985Sthompsa	LIST_REMOVE(bif, bif_next);
1016146985Sthompsa	BRIDGE_XDROP(sc);
1017146985Sthompsa
1018180140Sphilip	/*
1019180140Sphilip	 * If removing the interface that gave the bridge its mac address, set
1020180140Sphilip	 * the mac address of the bridge to the address of the next member, or
1021180140Sphilip	 * to its default address if no members are left.
1022180140Sphilip	 */
1023272568Shrs	if (V_bridge_inherit_mac && sc->sc_ifaddr == ifs) {
1024188594Sthompsa		if (LIST_EMPTY(&sc->sc_iflist)) {
1025346783Skevans			bcopy(&sc->sc_defaddr,
1026180140Sphilip			    IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
1027188594Sthompsa			sc->sc_ifaddr = NULL;
1028188594Sthompsa		} else {
1029180140Sphilip			fif = LIST_FIRST(&sc->sc_iflist)->bif_ifp;
1030180140Sphilip			bcopy(IF_LLADDR(fif),
1031180140Sphilip			    IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
1032188594Sthompsa			sc->sc_ifaddr = fif;
1033180140Sphilip		}
1034202588Sthompsa		EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
1035180140Sphilip	}
1036180140Sphilip
1037236916Sthompsa	bridge_linkcheck(sc);
1038180220Sthompsa	bridge_mutecaps(sc);	/* recalcuate now this interface is removed */
1039146985Sthompsa	bridge_rtdelete(sc, ifs, IFBF_FLUSHALL);
1040173320Sthompsa	KASSERT(bif->bif_addrcnt == 0,
1041173320Sthompsa	    ("%s: %d bridge routes referenced", __func__, bif->bif_addrcnt));
1042146985Sthompsa
1043160901Sthompsa	BRIDGE_UNLOCK(sc);
1044191729Sthompsa	if (!gone) {
1045191729Sthompsa		switch (ifs->if_type) {
1046191729Sthompsa		case IFT_ETHER:
1047191729Sthompsa		case IFT_L2VLAN:
1048191729Sthompsa			/*
1049284348Skp			 * Take the interface out of promiscuous mode, but only
1050284348Skp			 * if it was promiscuous in the first place. It might
1051284348Skp			 * not be if we're in the bridge_ioctl_add() error path.
1052191729Sthompsa			 */
1053284348Skp			if (ifs->if_flags & IFF_PROMISC)
1054284348Skp				(void) ifpromisc(ifs, 0);
1055191729Sthompsa			break;
1056191729Sthompsa
1057191729Sthompsa		case IFT_GIF:
1058191729Sthompsa			break;
1059191729Sthompsa
1060191729Sthompsa		default:
1061191729Sthompsa#ifdef DIAGNOSTIC
1062191729Sthompsa			panic("bridge_delete_member: impossible");
1063191729Sthompsa#endif
1064191729Sthompsa			break;
1065191729Sthompsa		}
1066191729Sthompsa		/* reneable any interface capabilities */
1067191729Sthompsa		bridge_set_ifcap(sc, bif, bif->bif_savedcaps);
1068191729Sthompsa	}
1069164626Sthompsa	bstp_destroy(&bif->bif_stp);	/* prepare to free */
1070160901Sthompsa	BRIDGE_LOCK(sc);
1071146985Sthompsa	free(bif, M_DEVBUF);
1072146985Sthompsa}
1073146985Sthompsa
1074153494Sthompsa/*
1075153494Sthompsa * bridge_delete_span:
1076153494Sthompsa *
1077153494Sthompsa *	Delete the specified span interface.
1078153494Sthompsa */
1079153494Sthompsastatic void
1080153494Sthompsabridge_delete_span(struct bridge_softc *sc, struct bridge_iflist *bif)
1081153494Sthompsa{
1082153494Sthompsa	BRIDGE_LOCK_ASSERT(sc);
1083153494Sthompsa
1084153494Sthompsa	KASSERT(bif->bif_ifp->if_bridge == NULL,
1085153494Sthompsa	    ("%s: not a span interface", __func__));
1086153494Sthompsa
1087153494Sthompsa	LIST_REMOVE(bif, bif_next);
1088153494Sthompsa	free(bif, M_DEVBUF);
1089153494Sthompsa}
1090153494Sthompsa
1091151313Sthompsastatic int
1092146985Sthompsabridge_ioctl_add(struct bridge_softc *sc, void *arg)
1093146985Sthompsa{
1094146985Sthompsa	struct ifbreq *req = arg;
1095146985Sthompsa	struct bridge_iflist *bif = NULL;
1096146985Sthompsa	struct ifnet *ifs;
1097146985Sthompsa	int error = 0;
1098146985Sthompsa
1099146985Sthompsa	ifs = ifunit(req->ifbr_ifsname);
1100146985Sthompsa	if (ifs == NULL)
1101146985Sthompsa		return (ENOENT);
1102180220Sthompsa	if (ifs->if_ioctl == NULL)	/* must be supported */
1103180220Sthompsa		return (EINVAL);
1104146985Sthompsa
1105153408Sthompsa	/* If it's in the span list, it can't be a member. */
1106153408Sthompsa	LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
1107153408Sthompsa		if (ifs == bif->bif_ifp)
1108153408Sthompsa			return (EBUSY);
1109153408Sthompsa
1110146985Sthompsa	if (ifs->if_bridge == sc)
1111146985Sthompsa		return (EEXIST);
1112146985Sthompsa
1113146985Sthompsa	if (ifs->if_bridge != NULL)
1114146985Sthompsa		return (EBUSY);
1115146985Sthompsa
1116146985Sthompsa	switch (ifs->if_type) {
1117146985Sthompsa	case IFT_ETHER:
1118146985Sthompsa	case IFT_L2VLAN:
1119153621Sthompsa	case IFT_GIF:
1120191729Sthompsa		/* permitted interface types */
1121153621Sthompsa		break;
1122146985Sthompsa	default:
1123252511Shrs		return (EINVAL);
1124146985Sthompsa	}
1125146985Sthompsa
1126252511Shrs#ifdef INET6
1127252511Shrs	/*
1128252511Shrs	 * Two valid inet6 addresses with link-local scope must not be
1129252511Shrs	 * on the parent interface and the member interfaces at the
1130252511Shrs	 * same time.  This restriction is needed to prevent violation
1131252511Shrs	 * of link-local scope zone.  Attempts to add a member
1132252511Shrs	 * interface which has inet6 addresses when the parent has
1133252511Shrs	 * inet6 triggers removal of all inet6 addresses on the member
1134252511Shrs	 * interface.
1135252511Shrs	 */
1136252511Shrs
1137252511Shrs	/* Check if the parent interface has a link-local scope addr. */
1138253751Shrs	if (V_allow_llz_overlap == 0 &&
1139253751Shrs	    in6ifa_llaonifp(sc->sc_ifp) != NULL) {
1140252511Shrs		/*
1141252511Shrs		 * If any, remove all inet6 addresses from the member
1142252511Shrs		 * interfaces.
1143252511Shrs		 */
1144252511Shrs		BRIDGE_XLOCK(sc);
1145252511Shrs		LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
1146252511Shrs 			if (in6ifa_llaonifp(bif->bif_ifp)) {
1147252511Shrs				BRIDGE_UNLOCK(sc);
1148252511Shrs				in6_ifdetach(bif->bif_ifp);
1149252511Shrs				BRIDGE_LOCK(sc);
1150252511Shrs				if_printf(sc->sc_ifp,
1151252511Shrs				    "IPv6 addresses on %s have been removed "
1152252511Shrs				    "before adding it as a member to prevent "
1153252511Shrs				    "IPv6 address scope violation.\n",
1154252511Shrs				    bif->bif_ifp->if_xname);
1155252511Shrs			}
1156252511Shrs		}
1157252511Shrs		BRIDGE_XDROP(sc);
1158252511Shrs		if (in6ifa_llaonifp(ifs)) {
1159252511Shrs			BRIDGE_UNLOCK(sc);
1160252511Shrs			in6_ifdetach(ifs);
1161252511Shrs			BRIDGE_LOCK(sc);
1162252511Shrs			if_printf(sc->sc_ifp,
1163252511Shrs			    "IPv6 addresses on %s have been removed "
1164252511Shrs			    "before adding it as a member to prevent "
1165252511Shrs			    "IPv6 address scope violation.\n",
1166252511Shrs			    ifs->if_xname);
1167252511Shrs		}
1168252511Shrs	}
1169252511Shrs#endif
1170203272Shrs	/* Allow the first Ethernet member to define the MTU */
1171203272Shrs	if (LIST_EMPTY(&sc->sc_iflist))
1172203272Shrs		sc->sc_ifp->if_mtu = ifs->if_mtu;
1173203272Shrs	else if (sc->sc_ifp->if_mtu != ifs->if_mtu) {
1174263102Sglebius		if_printf(sc->sc_ifp, "invalid MTU: %u(%s) != %u\n",
1175203272Shrs		    ifs->if_mtu, ifs->if_xname, sc->sc_ifp->if_mtu);
1176252511Shrs		return (EINVAL);
1177203272Shrs	}
1178203272Shrs
1179252511Shrs	bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO);
1180252511Shrs	if (bif == NULL)
1181252511Shrs		return (ENOMEM);
1182252511Shrs
1183252511Shrs	bif->bif_ifp = ifs;
1184252511Shrs	bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
1185252511Shrs	bif->bif_savedcaps = ifs->if_capenable;
1186252511Shrs
1187180140Sphilip	/*
1188180140Sphilip	 * Assign the interface's MAC address to the bridge if it's the first
1189180140Sphilip	 * member and the MAC address of the bridge has not been changed from
1190180140Sphilip	 * the default randomly generated one.
1191180140Sphilip	 */
1192272568Shrs	if (V_bridge_inherit_mac && LIST_EMPTY(&sc->sc_iflist) &&
1193346783Skevans	    !memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr.octet, ETHER_ADDR_LEN)) {
1194180140Sphilip		bcopy(IF_LLADDR(ifs), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
1195188594Sthompsa		sc->sc_ifaddr = ifs;
1196202588Sthompsa		EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
1197188594Sthompsa	}
1198180140Sphilip
1199146985Sthompsa	ifs->if_bridge = sc;
1200164626Sthompsa	bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp);
1201146985Sthompsa	/*
1202146985Sthompsa	 * XXX: XLOCK HERE!?!
1203146985Sthompsa	 *
1204146985Sthompsa	 * NOTE: insert_***HEAD*** should be safe for the traversals.
1205146985Sthompsa	 */
1206146985Sthompsa	LIST_INSERT_HEAD(&sc->sc_iflist, bif, bif_next);
1207146985Sthompsa
1208180220Sthompsa	/* Set interface capabilities to the intersection set of all members */
1209180220Sthompsa	bridge_mutecaps(sc);
1210236916Sthompsa	bridge_linkcheck(sc);
1211191729Sthompsa
1212234487Sthompsa	/* Place the interface into promiscuous mode */
1213191729Sthompsa	switch (ifs->if_type) {
1214234487Sthompsa		case IFT_ETHER:
1215234487Sthompsa		case IFT_L2VLAN:
1216236916Sthompsa			BRIDGE_UNLOCK(sc);
1217234487Sthompsa			error = ifpromisc(ifs, 1);
1218236916Sthompsa			BRIDGE_LOCK(sc);
1219234487Sthompsa			break;
1220191729Sthompsa	}
1221252511Shrs
1222284348Skp	if (error)
1223191729Sthompsa		bridge_delete_member(sc, bif, 0);
1224146985Sthompsa	return (error);
1225146985Sthompsa}
1226146985Sthompsa
1227151313Sthompsastatic int
1228146985Sthompsabridge_ioctl_del(struct bridge_softc *sc, void *arg)
1229146985Sthompsa{
1230146985Sthompsa	struct ifbreq *req = arg;
1231146985Sthompsa	struct bridge_iflist *bif;
1232146985Sthompsa
1233146985Sthompsa	bif = bridge_lookup_member(sc, req->ifbr_ifsname);
1234146985Sthompsa	if (bif == NULL)
1235146985Sthompsa		return (ENOENT);
1236146985Sthompsa
1237151594Sthompsa	bridge_delete_member(sc, bif, 0);
1238146985Sthompsa
1239146985Sthompsa	return (0);
1240146985Sthompsa}
1241146985Sthompsa
1242151313Sthompsastatic int
1243146985Sthompsabridge_ioctl_gifflags(struct bridge_softc *sc, void *arg)
1244146985Sthompsa{
1245146985Sthompsa	struct ifbreq *req = arg;
1246146985Sthompsa	struct bridge_iflist *bif;
1247163863Sthompsa	struct bstp_port *bp;
1248146985Sthompsa
1249146985Sthompsa	bif = bridge_lookup_member(sc, req->ifbr_ifsname);
1250146985Sthompsa	if (bif == NULL)
1251146985Sthompsa		return (ENOENT);
1252146985Sthompsa
1253163863Sthompsa	bp = &bif->bif_stp;
1254146985Sthompsa	req->ifbr_ifsflags = bif->bif_flags;
1255163863Sthompsa	req->ifbr_state = bp->bp_state;
1256163863Sthompsa	req->ifbr_priority = bp->bp_priority;
1257163863Sthompsa	req->ifbr_path_cost = bp->bp_path_cost;
1258163863Sthompsa	req->ifbr_portno = bif->bif_ifp->if_index & 0xfff;
1259163863Sthompsa	req->ifbr_proto = bp->bp_protover;
1260163863Sthompsa	req->ifbr_role = bp->bp_role;
1261163863Sthompsa	req->ifbr_stpflags = bp->bp_flags;
1262173320Sthompsa	req->ifbr_addrcnt = bif->bif_addrcnt;
1263173320Sthompsa	req->ifbr_addrmax = bif->bif_addrmax;
1264173320Sthompsa	req->ifbr_addrexceeded = bif->bif_addrexceeded;
1265146985Sthompsa
1266164653Sthompsa	/* Copy STP state options as flags */
1267164653Sthompsa	if (bp->bp_operedge)
1268164653Sthompsa		req->ifbr_ifsflags |= IFBIF_BSTP_EDGE;
1269164653Sthompsa	if (bp->bp_flags & BSTP_PORT_AUTOEDGE)
1270164653Sthompsa		req->ifbr_ifsflags |= IFBIF_BSTP_AUTOEDGE;
1271165105Sthompsa	if (bp->bp_ptp_link)
1272165105Sthompsa		req->ifbr_ifsflags |= IFBIF_BSTP_PTP;
1273165105Sthompsa	if (bp->bp_flags & BSTP_PORT_AUTOPTP)
1274165105Sthompsa		req->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
1275164880Ssyrinx	if (bp->bp_flags & BSTP_PORT_ADMEDGE)
1276164880Ssyrinx		req->ifbr_ifsflags |= IFBIF_BSTP_ADMEDGE;
1277164880Ssyrinx	if (bp->bp_flags & BSTP_PORT_ADMCOST)
1278164880Ssyrinx		req->ifbr_ifsflags |= IFBIF_BSTP_ADMCOST;
1279146985Sthompsa	return (0);
1280146985Sthompsa}
1281146985Sthompsa
1282151313Sthompsastatic int
1283146985Sthompsabridge_ioctl_sifflags(struct bridge_softc *sc, void *arg)
1284146985Sthompsa{
1285146985Sthompsa	struct ifbreq *req = arg;
1286146985Sthompsa	struct bridge_iflist *bif;
1287164653Sthompsa	struct bstp_port *bp;
1288160703Sthompsa	int error;
1289146985Sthompsa
1290146985Sthompsa	bif = bridge_lookup_member(sc, req->ifbr_ifsname);
1291146985Sthompsa	if (bif == NULL)
1292146985Sthompsa		return (ENOENT);
1293164653Sthompsa	bp = &bif->bif_stp;
1294146985Sthompsa
1295153408Sthompsa	if (req->ifbr_ifsflags & IFBIF_SPAN)
1296153408Sthompsa		/* SPAN is readonly */
1297153408Sthompsa		return (EINVAL);
1298153408Sthompsa
1299146985Sthompsa	if (req->ifbr_ifsflags & IFBIF_STP) {
1300160703Sthompsa		if ((bif->bif_flags & IFBIF_STP) == 0) {
1301164626Sthompsa			error = bstp_enable(&bif->bif_stp);
1302160703Sthompsa			if (error)
1303160703Sthompsa				return (error);
1304146985Sthompsa		}
1305160703Sthompsa	} else {
1306160703Sthompsa		if ((bif->bif_flags & IFBIF_STP) != 0)
1307164626Sthompsa			bstp_disable(&bif->bif_stp);
1308146985Sthompsa	}
1309146985Sthompsa
1310164653Sthompsa	/* Pass on STP flags */
1311164653Sthompsa	bstp_set_edge(bp, req->ifbr_ifsflags & IFBIF_BSTP_EDGE ? 1 : 0);
1312164653Sthompsa	bstp_set_autoedge(bp, req->ifbr_ifsflags & IFBIF_BSTP_AUTOEDGE ? 1 : 0);
1313165105Sthompsa	bstp_set_ptp(bp, req->ifbr_ifsflags & IFBIF_BSTP_PTP ? 1 : 0);
1314165105Sthompsa	bstp_set_autoptp(bp, req->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP ? 1 : 0);
1315146985Sthompsa
1316164653Sthompsa	/* Save the bits relating to the bridge */
1317164653Sthompsa	bif->bif_flags = req->ifbr_ifsflags & IFBIFMASK;
1318164653Sthompsa
1319146985Sthompsa	return (0);
1320146985Sthompsa}
1321146985Sthompsa
1322151313Sthompsastatic int
1323146985Sthompsabridge_ioctl_scache(struct bridge_softc *sc, void *arg)
1324146985Sthompsa{
1325146985Sthompsa	struct ifbrparam *param = arg;
1326146985Sthompsa
1327146985Sthompsa	sc->sc_brtmax = param->ifbrp_csize;
1328146985Sthompsa	bridge_rttrim(sc);
1329146985Sthompsa
1330146985Sthompsa	return (0);
1331146985Sthompsa}
1332146985Sthompsa
1333151313Sthompsastatic int
1334146985Sthompsabridge_ioctl_gcache(struct bridge_softc *sc, void *arg)
1335146985Sthompsa{
1336146985Sthompsa	struct ifbrparam *param = arg;
1337146985Sthompsa
1338146985Sthompsa	param->ifbrp_csize = sc->sc_brtmax;
1339146985Sthompsa
1340146985Sthompsa	return (0);
1341146985Sthompsa}
1342146985Sthompsa
1343151313Sthompsastatic int
1344146985Sthompsabridge_ioctl_gifs(struct bridge_softc *sc, void *arg)
1345146985Sthompsa{
1346146985Sthompsa	struct ifbifconf *bifc = arg;
1347146985Sthompsa	struct bridge_iflist *bif;
1348146985Sthompsa	struct ifbreq breq;
1349171603Sthompsa	char *buf, *outbuf;
1350171603Sthompsa	int count, buflen, len, error = 0;
1351146985Sthompsa
1352146985Sthompsa	count = 0;
1353146985Sthompsa	LIST_FOREACH(bif, &sc->sc_iflist, bif_next)
1354146985Sthompsa		count++;
1355153408Sthompsa	LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
1356153408Sthompsa		count++;
1357146985Sthompsa
1358171603Sthompsa	buflen = sizeof(breq) * count;
1359146985Sthompsa	if (bifc->ifbic_len == 0) {
1360171603Sthompsa		bifc->ifbic_len = buflen;
1361146985Sthompsa		return (0);
1362146985Sthompsa	}
1363171603Sthompsa	BRIDGE_UNLOCK(sc);
1364171603Sthompsa	outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
1365171603Sthompsa	BRIDGE_LOCK(sc);
1366146985Sthompsa
1367146985Sthompsa	count = 0;
1368171603Sthompsa	buf = outbuf;
1369171603Sthompsa	len = min(bifc->ifbic_len, buflen);
1370158667Sthompsa	bzero(&breq, sizeof(breq));
1371146985Sthompsa	LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
1372146985Sthompsa		if (len < sizeof(breq))
1373146985Sthompsa			break;
1374146985Sthompsa
1375146985Sthompsa		strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname,
1376146985Sthompsa		    sizeof(breq.ifbr_ifsname));
1377164653Sthompsa		/* Fill in the ifbreq structure */
1378164653Sthompsa		error = bridge_ioctl_gifflags(sc, &breq);
1379164653Sthompsa		if (error)
1380164653Sthompsa			break;
1381171603Sthompsa		memcpy(buf, &breq, sizeof(breq));
1382146985Sthompsa		count++;
1383171603Sthompsa		buf += sizeof(breq);
1384146985Sthompsa		len -= sizeof(breq);
1385146985Sthompsa	}
1386153408Sthompsa	LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) {
1387153408Sthompsa		if (len < sizeof(breq))
1388153408Sthompsa			break;
1389146985Sthompsa
1390153408Sthompsa		strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname,
1391153408Sthompsa		    sizeof(breq.ifbr_ifsname));
1392153408Sthompsa		breq.ifbr_ifsflags = bif->bif_flags;
1393163863Sthompsa		breq.ifbr_portno = bif->bif_ifp->if_index & 0xfff;
1394171603Sthompsa		memcpy(buf, &breq, sizeof(breq));
1395153408Sthompsa		count++;
1396171603Sthompsa		buf += sizeof(breq);
1397153408Sthompsa		len -= sizeof(breq);
1398153408Sthompsa	}
1399153408Sthompsa
1400171603Sthompsa	BRIDGE_UNLOCK(sc);
1401146985Sthompsa	bifc->ifbic_len = sizeof(breq) * count;
1402171603Sthompsa	error = copyout(outbuf, bifc->ifbic_req, bifc->ifbic_len);
1403171603Sthompsa	BRIDGE_LOCK(sc);
1404171603Sthompsa	free(outbuf, M_TEMP);
1405146985Sthompsa	return (error);
1406146985Sthompsa}
1407146985Sthompsa
1408151313Sthompsastatic int
1409146985Sthompsabridge_ioctl_rts(struct bridge_softc *sc, void *arg)
1410146985Sthompsa{
1411146985Sthompsa	struct ifbaconf *bac = arg;
1412146985Sthompsa	struct bridge_rtnode *brt;
1413146985Sthompsa	struct ifbareq bareq;
1414171603Sthompsa	char *buf, *outbuf;
1415171603Sthompsa	int count, buflen, len, error = 0;
1416146985Sthompsa
1417146985Sthompsa	if (bac->ifbac_len == 0)
1418146985Sthompsa		return (0);
1419146985Sthompsa
1420171603Sthompsa	count = 0;
1421171603Sthompsa	LIST_FOREACH(brt, &sc->sc_rtlist, brt_list)
1422171603Sthompsa		count++;
1423171603Sthompsa	buflen = sizeof(bareq) * count;
1424171603Sthompsa
1425171603Sthompsa	BRIDGE_UNLOCK(sc);
1426171603Sthompsa	outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
1427171603Sthompsa	BRIDGE_LOCK(sc);
1428171603Sthompsa
1429171603Sthompsa	count = 0;
1430171603Sthompsa	buf = outbuf;
1431171603Sthompsa	len = min(bac->ifbac_len, buflen);
1432158667Sthompsa	bzero(&bareq, sizeof(bareq));
1433146985Sthompsa	LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) {
1434146985Sthompsa		if (len < sizeof(bareq))
1435146985Sthompsa			goto out;
1436146985Sthompsa		strlcpy(bareq.ifba_ifsname, brt->brt_ifp->if_xname,
1437146985Sthompsa		    sizeof(bareq.ifba_ifsname));
1438146985Sthompsa		memcpy(bareq.ifba_dst, brt->brt_addr, sizeof(brt->brt_addr));
1439170681Sthompsa		bareq.ifba_vlan = brt->brt_vlan;
1440146985Sthompsa		if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC &&
1441153976Sthompsa				time_uptime < brt->brt_expire)
1442153976Sthompsa			bareq.ifba_expire = brt->brt_expire - time_uptime;
1443146985Sthompsa		else
1444146985Sthompsa			bareq.ifba_expire = 0;
1445146985Sthompsa		bareq.ifba_flags = brt->brt_flags;
1446146985Sthompsa
1447171603Sthompsa		memcpy(buf, &bareq, sizeof(bareq));
1448146985Sthompsa		count++;
1449171603Sthompsa		buf += sizeof(bareq);
1450146985Sthompsa		len -= sizeof(bareq);
1451146985Sthompsa	}
1452153497Sthompsaout:
1453171603Sthompsa	BRIDGE_UNLOCK(sc);
1454146985Sthompsa	bac->ifbac_len = sizeof(bareq) * count;
1455171603Sthompsa	error = copyout(outbuf, bac->ifbac_req, bac->ifbac_len);
1456171603Sthompsa	BRIDGE_LOCK(sc);
1457171603Sthompsa	free(outbuf, M_TEMP);
1458146985Sthompsa	return (error);
1459146985Sthompsa}
1460146985Sthompsa
1461151313Sthompsastatic int
1462146985Sthompsabridge_ioctl_saddr(struct bridge_softc *sc, void *arg)
1463146985Sthompsa{
1464146985Sthompsa	struct ifbareq *req = arg;
1465146985Sthompsa	struct bridge_iflist *bif;
1466146985Sthompsa	int error;
1467146985Sthompsa
1468146985Sthompsa	bif = bridge_lookup_member(sc, req->ifba_ifsname);
1469146985Sthompsa	if (bif == NULL)
1470146985Sthompsa		return (ENOENT);
1471146985Sthompsa
1472170681Sthompsa	error = bridge_rtupdate(sc, req->ifba_dst, req->ifba_vlan, bif, 1,
1473146985Sthompsa	    req->ifba_flags);
1474146985Sthompsa
1475146985Sthompsa	return (error);
1476146985Sthompsa}
1477146985Sthompsa
1478151313Sthompsastatic int
1479146985Sthompsabridge_ioctl_sto(struct bridge_softc *sc, void *arg)
1480146985Sthompsa{
1481146985Sthompsa	struct ifbrparam *param = arg;
1482146985Sthompsa
1483146985Sthompsa	sc->sc_brttimeout = param->ifbrp_ctime;
1484146985Sthompsa	return (0);
1485146985Sthompsa}
1486146985Sthompsa
1487151313Sthompsastatic int
1488146985Sthompsabridge_ioctl_gto(struct bridge_softc *sc, void *arg)
1489146985Sthompsa{
1490146985Sthompsa	struct ifbrparam *param = arg;
1491146985Sthompsa
1492146985Sthompsa	param->ifbrp_ctime = sc->sc_brttimeout;
1493146985Sthompsa	return (0);
1494146985Sthompsa}
1495146985Sthompsa
1496151313Sthompsastatic int
1497146985Sthompsabridge_ioctl_daddr(struct bridge_softc *sc, void *arg)
1498146985Sthompsa{
1499146985Sthompsa	struct ifbareq *req = arg;
1500146985Sthompsa
1501170681Sthompsa	return (bridge_rtdaddr(sc, req->ifba_dst, req->ifba_vlan));
1502146985Sthompsa}
1503146985Sthompsa
1504151313Sthompsastatic int
1505146985Sthompsabridge_ioctl_flush(struct bridge_softc *sc, void *arg)
1506146985Sthompsa{
1507146985Sthompsa	struct ifbreq *req = arg;
1508146985Sthompsa
1509146985Sthompsa	bridge_rtflush(sc, req->ifbr_ifsflags);
1510146985Sthompsa	return (0);
1511146985Sthompsa}
1512146985Sthompsa
1513151313Sthompsastatic int
1514146985Sthompsabridge_ioctl_gpri(struct bridge_softc *sc, void *arg)
1515146985Sthompsa{
1516146985Sthompsa	struct ifbrparam *param = arg;
1517160703Sthompsa	struct bstp_state *bs = &sc->sc_stp;
1518146985Sthompsa
1519160703Sthompsa	param->ifbrp_prio = bs->bs_bridge_priority;
1520146985Sthompsa	return (0);
1521146985Sthompsa}
1522146985Sthompsa
1523151313Sthompsastatic int
1524146985Sthompsabridge_ioctl_spri(struct bridge_softc *sc, void *arg)
1525146985Sthompsa{
1526146985Sthompsa	struct ifbrparam *param = arg;
1527146985Sthompsa
1528163863Sthompsa	return (bstp_set_priority(&sc->sc_stp, param->ifbrp_prio));
1529146985Sthompsa}
1530146985Sthompsa
1531151313Sthompsastatic int
1532146985Sthompsabridge_ioctl_ght(struct bridge_softc *sc, void *arg)
1533146985Sthompsa{
1534146985Sthompsa	struct ifbrparam *param = arg;
1535160703Sthompsa	struct bstp_state *bs = &sc->sc_stp;
1536146985Sthompsa
1537163863Sthompsa	param->ifbrp_hellotime = bs->bs_bridge_htime >> 8;
1538146985Sthompsa	return (0);
1539146985Sthompsa}
1540146985Sthompsa
1541151313Sthompsastatic int
1542146985Sthompsabridge_ioctl_sht(struct bridge_softc *sc, void *arg)
1543146985Sthompsa{
1544146985Sthompsa	struct ifbrparam *param = arg;
1545146985Sthompsa
1546163863Sthompsa	return (bstp_set_htime(&sc->sc_stp, param->ifbrp_hellotime));
1547146985Sthompsa}
1548146985Sthompsa
1549151313Sthompsastatic int
1550146985Sthompsabridge_ioctl_gfd(struct bridge_softc *sc, void *arg)
1551146985Sthompsa{
1552146985Sthompsa	struct ifbrparam *param = arg;
1553160703Sthompsa	struct bstp_state *bs = &sc->sc_stp;
1554146985Sthompsa
1555163863Sthompsa	param->ifbrp_fwddelay = bs->bs_bridge_fdelay >> 8;
1556146985Sthompsa	return (0);
1557146985Sthompsa}
1558146985Sthompsa
1559151313Sthompsastatic int
1560146985Sthompsabridge_ioctl_sfd(struct bridge_softc *sc, void *arg)
1561146985Sthompsa{
1562146985Sthompsa	struct ifbrparam *param = arg;
1563146985Sthompsa
1564163863Sthompsa	return (bstp_set_fdelay(&sc->sc_stp, param->ifbrp_fwddelay));
1565146985Sthompsa}
1566146985Sthompsa
1567151313Sthompsastatic int
1568146985Sthompsabridge_ioctl_gma(struct bridge_softc *sc, void *arg)
1569146985Sthompsa{
1570146985Sthompsa	struct ifbrparam *param = arg;
1571160703Sthompsa	struct bstp_state *bs = &sc->sc_stp;
1572146985Sthompsa
1573160703Sthompsa	param->ifbrp_maxage = bs->bs_bridge_max_age >> 8;
1574146985Sthompsa	return (0);
1575146985Sthompsa}
1576146985Sthompsa
1577151313Sthompsastatic int
1578146985Sthompsabridge_ioctl_sma(struct bridge_softc *sc, void *arg)
1579146985Sthompsa{
1580146985Sthompsa	struct ifbrparam *param = arg;
1581146985Sthompsa
1582163863Sthompsa	return (bstp_set_maxage(&sc->sc_stp, param->ifbrp_maxage));
1583146985Sthompsa}
1584146985Sthompsa
1585151313Sthompsastatic int
1586146985Sthompsabridge_ioctl_sifprio(struct bridge_softc *sc, void *arg)
1587146985Sthompsa{
1588146985Sthompsa	struct ifbreq *req = arg;
1589146985Sthompsa	struct bridge_iflist *bif;
1590146985Sthompsa
1591146985Sthompsa	bif = bridge_lookup_member(sc, req->ifbr_ifsname);
1592146985Sthompsa	if (bif == NULL)
1593146985Sthompsa		return (ENOENT);
1594146985Sthompsa
1595163863Sthompsa	return (bstp_set_port_priority(&bif->bif_stp, req->ifbr_priority));
1596146985Sthompsa}
1597146985Sthompsa
1598151313Sthompsastatic int
1599146985Sthompsabridge_ioctl_sifcost(struct bridge_softc *sc, void *arg)
1600146985Sthompsa{
1601146985Sthompsa	struct ifbreq *req = arg;
1602146985Sthompsa	struct bridge_iflist *bif;
1603146985Sthompsa
1604146985Sthompsa	bif = bridge_lookup_member(sc, req->ifbr_ifsname);
1605146985Sthompsa	if (bif == NULL)
1606146985Sthompsa		return (ENOENT);
1607146985Sthompsa
1608163863Sthompsa	return (bstp_set_path_cost(&bif->bif_stp, req->ifbr_path_cost));
1609146985Sthompsa}
1610146985Sthompsa
1611153408Sthompsastatic int
1612173320Sthompsabridge_ioctl_sifmaxaddr(struct bridge_softc *sc, void *arg)
1613173320Sthompsa{
1614173320Sthompsa	struct ifbreq *req = arg;
1615173320Sthompsa	struct bridge_iflist *bif;
1616173320Sthompsa
1617173320Sthompsa	bif = bridge_lookup_member(sc, req->ifbr_ifsname);
1618173320Sthompsa	if (bif == NULL)
1619173320Sthompsa		return (ENOENT);
1620173320Sthompsa
1621173320Sthompsa	bif->bif_addrmax = req->ifbr_addrmax;
1622173320Sthompsa	return (0);
1623173320Sthompsa}
1624173320Sthompsa
1625173320Sthompsastatic int
1626153408Sthompsabridge_ioctl_addspan(struct bridge_softc *sc, void *arg)
1627153408Sthompsa{
1628153408Sthompsa	struct ifbreq *req = arg;
1629153408Sthompsa	struct bridge_iflist *bif = NULL;
1630153408Sthompsa	struct ifnet *ifs;
1631153408Sthompsa
1632153408Sthompsa	ifs = ifunit(req->ifbr_ifsname);
1633153408Sthompsa	if (ifs == NULL)
1634153408Sthompsa		return (ENOENT);
1635153408Sthompsa
1636153408Sthompsa	LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
1637153408Sthompsa		if (ifs == bif->bif_ifp)
1638153408Sthompsa			return (EBUSY);
1639153408Sthompsa
1640153408Sthompsa	if (ifs->if_bridge != NULL)
1641153408Sthompsa		return (EBUSY);
1642153408Sthompsa
1643153408Sthompsa	switch (ifs->if_type) {
1644153408Sthompsa		case IFT_ETHER:
1645159807Sthompsa		case IFT_GIF:
1646153408Sthompsa		case IFT_L2VLAN:
1647153408Sthompsa			break;
1648153408Sthompsa		default:
1649153408Sthompsa			return (EINVAL);
1650153408Sthompsa	}
1651153408Sthompsa
1652153408Sthompsa	bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO);
1653153408Sthompsa	if (bif == NULL)
1654153408Sthompsa		return (ENOMEM);
1655153408Sthompsa
1656153408Sthompsa	bif->bif_ifp = ifs;
1657153408Sthompsa	bif->bif_flags = IFBIF_SPAN;
1658153408Sthompsa
1659153408Sthompsa	LIST_INSERT_HEAD(&sc->sc_spanlist, bif, bif_next);
1660153408Sthompsa
1661153408Sthompsa	return (0);
1662153408Sthompsa}
1663153408Sthompsa
1664153408Sthompsastatic int
1665153408Sthompsabridge_ioctl_delspan(struct bridge_softc *sc, void *arg)
1666153408Sthompsa{
1667153408Sthompsa	struct ifbreq *req = arg;
1668153408Sthompsa	struct bridge_iflist *bif;
1669153408Sthompsa	struct ifnet *ifs;
1670153408Sthompsa
1671153408Sthompsa	ifs = ifunit(req->ifbr_ifsname);
1672153408Sthompsa	if (ifs == NULL)
1673153408Sthompsa		return (ENOENT);
1674153408Sthompsa
1675153408Sthompsa	LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
1676153408Sthompsa		if (ifs == bif->bif_ifp)
1677153408Sthompsa			break;
1678153408Sthompsa
1679153408Sthompsa	if (bif == NULL)
1680153408Sthompsa		return (ENOENT);
1681153408Sthompsa
1682153494Sthompsa	bridge_delete_span(sc, bif);
1683153408Sthompsa
1684153408Sthompsa	return (0);
1685153408Sthompsa}
1686153408Sthompsa
1687160867Sthompsastatic int
1688160867Sthompsabridge_ioctl_gbparam(struct bridge_softc *sc, void *arg)
1689160867Sthompsa{
1690160867Sthompsa	struct ifbropreq *req = arg;
1691163863Sthompsa	struct bstp_state *bs = &sc->sc_stp;
1692160867Sthompsa	struct bstp_port *root_port;
1693160867Sthompsa
1694163863Sthompsa	req->ifbop_maxage = bs->bs_bridge_max_age >> 8;
1695163863Sthompsa	req->ifbop_hellotime = bs->bs_bridge_htime >> 8;
1696163863Sthompsa	req->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8;
1697160867Sthompsa
1698163863Sthompsa	root_port = bs->bs_root_port;
1699160867Sthompsa	if (root_port == NULL)
1700160867Sthompsa		req->ifbop_root_port = 0;
1701160867Sthompsa	else
1702160867Sthompsa		req->ifbop_root_port = root_port->bp_ifp->if_index;
1703160867Sthompsa
1704163863Sthompsa	req->ifbop_holdcount = bs->bs_txholdcount;
1705163863Sthompsa	req->ifbop_priority = bs->bs_bridge_priority;
1706163863Sthompsa	req->ifbop_protocol = bs->bs_protover;
1707163863Sthompsa	req->ifbop_root_path_cost = bs->bs_root_pv.pv_cost;
1708164653Sthompsa	req->ifbop_bridgeid = bs->bs_bridge_pv.pv_dbridge_id;
1709163863Sthompsa	req->ifbop_designated_root = bs->bs_root_pv.pv_root_id;
1710164653Sthompsa	req->ifbop_designated_bridge = bs->bs_root_pv.pv_dbridge_id;
1711163863Sthompsa	req->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec;
1712163863Sthompsa	req->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec;
1713160867Sthompsa
1714160867Sthompsa	return (0);
1715160867Sthompsa}
1716160867Sthompsa
1717160867Sthompsastatic int
1718160867Sthompsabridge_ioctl_grte(struct bridge_softc *sc, void *arg)
1719160867Sthompsa{
1720160867Sthompsa	struct ifbrparam *param = arg;
1721160867Sthompsa
1722160867Sthompsa	param->ifbrp_cexceeded = sc->sc_brtexceeded;
1723160867Sthompsa	return (0);
1724160867Sthompsa}
1725160867Sthompsa
1726160867Sthompsastatic int
1727160867Sthompsabridge_ioctl_gifsstp(struct bridge_softc *sc, void *arg)
1728160867Sthompsa{
1729160867Sthompsa	struct ifbpstpconf *bifstp = arg;
1730160867Sthompsa	struct bridge_iflist *bif;
1731163863Sthompsa	struct bstp_port *bp;
1732160867Sthompsa	struct ifbpstpreq bpreq;
1733171603Sthompsa	char *buf, *outbuf;
1734171603Sthompsa	int count, buflen, len, error = 0;
1735160867Sthompsa
1736160867Sthompsa	count = 0;
1737160867Sthompsa	LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
1738160867Sthompsa		if ((bif->bif_flags & IFBIF_STP) != 0)
1739160867Sthompsa			count++;
1740160867Sthompsa	}
1741160867Sthompsa
1742171603Sthompsa	buflen = sizeof(bpreq) * count;
1743160867Sthompsa	if (bifstp->ifbpstp_len == 0) {
1744171603Sthompsa		bifstp->ifbpstp_len = buflen;
1745160867Sthompsa		return (0);
1746160867Sthompsa	}
1747160867Sthompsa
1748171603Sthompsa	BRIDGE_UNLOCK(sc);
1749171603Sthompsa	outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
1750171603Sthompsa	BRIDGE_LOCK(sc);
1751171603Sthompsa
1752160867Sthompsa	count = 0;
1753171603Sthompsa	buf = outbuf;
1754171603Sthompsa	len = min(bifstp->ifbpstp_len, buflen);
1755160867Sthompsa	bzero(&bpreq, sizeof(bpreq));
1756160867Sthompsa	LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
1757160867Sthompsa		if (len < sizeof(bpreq))
1758160867Sthompsa			break;
1759160867Sthompsa
1760160867Sthompsa		if ((bif->bif_flags & IFBIF_STP) == 0)
1761160867Sthompsa			continue;
1762160867Sthompsa
1763163863Sthompsa		bp = &bif->bif_stp;
1764163863Sthompsa		bpreq.ifbp_portno = bif->bif_ifp->if_index & 0xfff;
1765163863Sthompsa		bpreq.ifbp_fwd_trans = bp->bp_forward_transitions;
1766163863Sthompsa		bpreq.ifbp_design_cost = bp->bp_desg_pv.pv_cost;
1767163863Sthompsa		bpreq.ifbp_design_port = bp->bp_desg_pv.pv_port_id;
1768163863Sthompsa		bpreq.ifbp_design_bridge = bp->bp_desg_pv.pv_dbridge_id;
1769163863Sthompsa		bpreq.ifbp_design_root = bp->bp_desg_pv.pv_root_id;
1770160867Sthompsa
1771171603Sthompsa		memcpy(buf, &bpreq, sizeof(bpreq));
1772160867Sthompsa		count++;
1773171603Sthompsa		buf += sizeof(bpreq);
1774160867Sthompsa		len -= sizeof(bpreq);
1775160867Sthompsa	}
1776160867Sthompsa
1777171603Sthompsa	BRIDGE_UNLOCK(sc);
1778160867Sthompsa	bifstp->ifbpstp_len = sizeof(bpreq) * count;
1779171603Sthompsa	error = copyout(outbuf, bifstp->ifbpstp_req, bifstp->ifbpstp_len);
1780171603Sthompsa	BRIDGE_LOCK(sc);
1781171603Sthompsa	free(outbuf, M_TEMP);
1782160867Sthompsa	return (error);
1783160867Sthompsa}
1784160867Sthompsa
1785163863Sthompsastatic int
1786163863Sthompsabridge_ioctl_sproto(struct bridge_softc *sc, void *arg)
1787163863Sthompsa{
1788163863Sthompsa	struct ifbrparam *param = arg;
1789163863Sthompsa
1790163863Sthompsa	return (bstp_set_protocol(&sc->sc_stp, param->ifbrp_proto));
1791163863Sthompsa}
1792163863Sthompsa
1793163863Sthompsastatic int
1794163863Sthompsabridge_ioctl_stxhc(struct bridge_softc *sc, void *arg)
1795163863Sthompsa{
1796163863Sthompsa	struct ifbrparam *param = arg;
1797163863Sthompsa
1798163863Sthompsa	return (bstp_set_holdcount(&sc->sc_stp, param->ifbrp_txhc));
1799163863Sthompsa}
1800163863Sthompsa
1801146985Sthompsa/*
1802146985Sthompsa * bridge_ifdetach:
1803146985Sthompsa *
1804146985Sthompsa *	Detach an interface from a bridge.  Called when a member
1805146985Sthompsa *	interface is detaching.
1806146985Sthompsa */
1807151313Sthompsastatic void
1808153494Sthompsabridge_ifdetach(void *arg __unused, struct ifnet *ifp)
1809146985Sthompsa{
1810146985Sthompsa	struct bridge_softc *sc = ifp->if_bridge;
1811151594Sthompsa	struct bridge_iflist *bif;
1812146985Sthompsa
1813248851Smarkj	if (ifp->if_flags & IFF_RENAMING)
1814248851Smarkj		return;
1815278766Shrs	if (V_bridge_cloner == NULL) {
1816278766Shrs		/*
1817278766Shrs		 * This detach handler can be called after
1818278766Shrs		 * vnet_bridge_uninit().  Just return in that case.
1819278766Shrs		 */
1820278766Shrs		return;
1821278766Shrs	}
1822153494Sthompsa	/* Check if the interface is a bridge member */
1823153494Sthompsa	if (sc != NULL) {
1824153494Sthompsa		BRIDGE_LOCK(sc);
1825146985Sthompsa
1826153494Sthompsa		bif = bridge_lookup_member_if(sc, ifp);
1827153494Sthompsa		if (bif != NULL)
1828153494Sthompsa			bridge_delete_member(sc, bif, 1);
1829153494Sthompsa
1830153494Sthompsa		BRIDGE_UNLOCK(sc);
1831151594Sthompsa		return;
1832153494Sthompsa	}
1833146985Sthompsa
1834153494Sthompsa	/* Check if the interface is a span port */
1835272568Shrs	BRIDGE_LIST_LOCK();
1836272568Shrs	LIST_FOREACH(sc, &V_bridge_list, sc_list) {
1837153494Sthompsa		BRIDGE_LOCK(sc);
1838153494Sthompsa		LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
1839153494Sthompsa			if (ifp == bif->bif_ifp) {
1840153494Sthompsa				bridge_delete_span(sc, bif);
1841153494Sthompsa				break;
1842153494Sthompsa			}
1843151594Sthompsa
1844153494Sthompsa		BRIDGE_UNLOCK(sc);
1845153494Sthompsa	}
1846272568Shrs	BRIDGE_LIST_UNLOCK();
1847146985Sthompsa}
1848146985Sthompsa
1849146985Sthompsa/*
1850146985Sthompsa * bridge_init:
1851146985Sthompsa *
1852146985Sthompsa *	Initialize a bridge interface.
1853146985Sthompsa */
1854146985Sthompsastatic void
1855146985Sthompsabridge_init(void *xsc)
1856146985Sthompsa{
1857146985Sthompsa	struct bridge_softc *sc = (struct bridge_softc *)xsc;
1858147256Sbrooks	struct ifnet *ifp = sc->sc_ifp;
1859146985Sthompsa
1860148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1861146985Sthompsa		return;
1862146985Sthompsa
1863149253Sthompsa	BRIDGE_LOCK(sc);
1864146985Sthompsa	callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz,
1865146985Sthompsa	    bridge_timer, sc);
1866146985Sthompsa
1867148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1868160703Sthompsa	bstp_init(&sc->sc_stp);		/* Initialize Spanning Tree */
1869160703Sthompsa
1870149064Sthompsa	BRIDGE_UNLOCK(sc);
1871146985Sthompsa}
1872146985Sthompsa
1873146985Sthompsa/*
1874146985Sthompsa * bridge_stop:
1875146985Sthompsa *
1876146985Sthompsa *	Stop the bridge interface.
1877146985Sthompsa */
1878151313Sthompsastatic void
1879146985Sthompsabridge_stop(struct ifnet *ifp, int disable)
1880146985Sthompsa{
1881146985Sthompsa	struct bridge_softc *sc = ifp->if_softc;
1882146985Sthompsa
1883149064Sthompsa	BRIDGE_LOCK_ASSERT(sc);
1884149064Sthompsa
1885148887Srwatson	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1886146985Sthompsa		return;
1887146985Sthompsa
1888146985Sthompsa	callout_stop(&sc->sc_brcallout);
1889160703Sthompsa	bstp_stop(&sc->sc_stp);
1890146985Sthompsa
1891146985Sthompsa	bridge_rtflush(sc, IFBF_FLUSHDYN);
1892146985Sthompsa
1893148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1894146985Sthompsa}
1895146985Sthompsa
1896146985Sthompsa/*
1897146985Sthompsa * bridge_enqueue:
1898146985Sthompsa *
1899146985Sthompsa *	Enqueue a packet on a bridge member interface.
1900146985Sthompsa *
1901146985Sthompsa */
1902240071Sglebiusstatic int
1903147786Sthompsabridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m)
1904146985Sthompsa{
1905158140Sthompsa	int len, err = 0;
1906146985Sthompsa	short mflags;
1907158140Sthompsa	struct mbuf *m0;
1908146985Sthompsa
1909159759Sthompsa	/* We may be sending a fragment so traverse the mbuf */
1910158140Sthompsa	for (; m; m = m0) {
1911158140Sthompsa		m0 = m->m_nextpkt;
1912158140Sthompsa		m->m_nextpkt = NULL;
1913240971Sglebius		len = m->m_pkthdr.len;
1914240971Sglebius		mflags = m->m_flags;
1915172770Sthompsa
1916172770Sthompsa		/*
1917172770Sthompsa		 * If underlying interface can not do VLAN tag insertion itself
1918172770Sthompsa		 * then attach a packet tag that holds it.
1919172770Sthompsa		 */
1920172770Sthompsa		if ((m->m_flags & M_VLANTAG) &&
1921172770Sthompsa		    (dst_ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) {
1922172770Sthompsa			m = ether_vlanencap(m, m->m_pkthdr.ether_vtag);
1923172770Sthompsa			if (m == NULL) {
1924172770Sthompsa				if_printf(dst_ifp,
1925172770Sthompsa				    "unable to prepend VLAN header\n");
1926271867Sglebius				if_inc_counter(dst_ifp, IFCOUNTER_OERRORS, 1);
1927172770Sthompsa				continue;
1928172770Sthompsa			}
1929172770Sthompsa			m->m_flags &= ~M_VLANTAG;
1930172770Sthompsa		}
1931172770Sthompsa
1932306593Skp		M_ASSERTPKTHDR(m); /* We shouldn't transmit mbuf without pkthdr */
1933238355Semaste		if ((err = dst_ifp->if_transmit(dst_ifp, m))) {
1934238355Semaste			m_freem(m0);
1935271867Sglebius			if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1);
1936238355Semaste			break;
1937238355Semaste		}
1938158140Sthompsa
1939271867Sglebius		if_inc_counter(sc->sc_ifp, IFCOUNTER_OPACKETS, 1);
1940271867Sglebius		if_inc_counter(sc->sc_ifp, IFCOUNTER_OBYTES, len);
1941191603Ssam		if (mflags & M_MCAST)
1942271867Sglebius			if_inc_counter(sc->sc_ifp, IFCOUNTER_OMCASTS, 1);
1943146985Sthompsa	}
1944240071Sglebius
1945240071Sglebius	return (err);
1946146985Sthompsa}
1947146985Sthompsa
1948146985Sthompsa/*
1949147205Sthompsa * bridge_dummynet:
1950147205Sthompsa *
1951147205Sthompsa * 	Receive a queued packet from dummynet and pass it on to the output
1952147205Sthompsa * 	interface.
1953147205Sthompsa *
1954147205Sthompsa *	The mbuf has the Ethernet header already attached.
1955147205Sthompsa */
1956151313Sthompsastatic void
1957147205Sthompsabridge_dummynet(struct mbuf *m, struct ifnet *ifp)
1958147205Sthompsa{
1959147205Sthompsa	struct bridge_softc *sc;
1960147205Sthompsa
1961147205Sthompsa	sc = ifp->if_bridge;
1962147205Sthompsa
1963147205Sthompsa	/*
1964147205Sthompsa	 * The packet didnt originate from a member interface. This should only
1965147205Sthompsa	 * ever happen if a member interface is removed while packets are
1966147205Sthompsa	 * queued for it.
1967147205Sthompsa	 */
1968147251Smlaier	if (sc == NULL) {
1969147205Sthompsa		m_freem(m);
1970147205Sthompsa		return;
1971147251Smlaier	}
1972147205Sthompsa
1973197952Sjulian	if (PFIL_HOOKED(&V_inet_pfil_hook)
1974147786Sthompsa#ifdef INET6
1975197952Sjulian	    || PFIL_HOOKED(&V_inet6_pfil_hook)
1976147786Sthompsa#endif
1977147786Sthompsa	    ) {
1978147786Sthompsa		if (bridge_pfil(&m, sc->sc_ifp, ifp, PFIL_OUT) != 0)
1979147786Sthompsa			return;
1980147786Sthompsa		if (m == NULL)
1981147786Sthompsa			return;
1982147786Sthompsa	}
1983147786Sthompsa
1984147786Sthompsa	bridge_enqueue(sc, ifp, m);
1985147205Sthompsa}
1986147205Sthompsa
1987147205Sthompsa/*
1988146985Sthompsa * bridge_output:
1989146985Sthompsa *
1990146985Sthompsa *	Send output from a bridge member interface.  This
1991146985Sthompsa *	performs the bridging function for locally originated
1992146985Sthompsa *	packets.
1993146985Sthompsa *
1994146985Sthompsa *	The mbuf has the Ethernet header already attached.  We must
1995146985Sthompsa *	enqueue or free the mbuf before returning.
1996146985Sthompsa */
1997151313Sthompsastatic int
1998146985Sthompsabridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
1999146985Sthompsa    struct rtentry *rt)
2000146985Sthompsa{
2001146985Sthompsa	struct ether_header *eh;
2002146985Sthompsa	struct ifnet *dst_if;
2003146985Sthompsa	struct bridge_softc *sc;
2004170681Sthompsa	uint16_t vlan;
2005146985Sthompsa
2006146985Sthompsa	if (m->m_len < ETHER_HDR_LEN) {
2007146985Sthompsa		m = m_pullup(m, ETHER_HDR_LEN);
2008146985Sthompsa		if (m == NULL)
2009146985Sthompsa			return (0);
2010146985Sthompsa	}
2011146985Sthompsa
2012146985Sthompsa	eh = mtod(m, struct ether_header *);
2013146985Sthompsa	sc = ifp->if_bridge;
2014170681Sthompsa	vlan = VLANTAGOF(m);
2015146985Sthompsa
2016146985Sthompsa	BRIDGE_LOCK(sc);
2017146985Sthompsa
2018146985Sthompsa	/*
2019146985Sthompsa	 * If bridge is down, but the original output interface is up,
2020146985Sthompsa	 * go ahead and send out that interface.  Otherwise, the packet
2021146985Sthompsa	 * is dropped below.
2022146985Sthompsa	 */
2023148887Srwatson	if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
2024146985Sthompsa		dst_if = ifp;
2025146985Sthompsa		goto sendunicast;
2026146985Sthompsa	}
2027146985Sthompsa
2028146985Sthompsa	/*
2029146985Sthompsa	 * If the packet is a multicast, or we don't know a better way to
2030146985Sthompsa	 * get there, send to all interfaces.
2031146985Sthompsa	 */
2032146985Sthompsa	if (ETHER_IS_MULTICAST(eh->ether_dhost))
2033146985Sthompsa		dst_if = NULL;
2034146985Sthompsa	else
2035170681Sthompsa		dst_if = bridge_rtlookup(sc, eh->ether_dhost, vlan);
2036146985Sthompsa	if (dst_if == NULL) {
2037146985Sthompsa		struct bridge_iflist *bif;
2038146985Sthompsa		struct mbuf *mc;
2039146985Sthompsa		int error = 0, used = 0;
2040146985Sthompsa
2041161401Sthompsa		bridge_span(sc, m);
2042161401Sthompsa
2043146985Sthompsa		BRIDGE_LOCK2REF(sc, error);
2044146985Sthompsa		if (error) {
2045146985Sthompsa			m_freem(m);
2046146985Sthompsa			return (0);
2047146985Sthompsa		}
2048153408Sthompsa
2049146985Sthompsa		LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
2050146985Sthompsa			dst_if = bif->bif_ifp;
2051153621Sthompsa
2052153621Sthompsa			if (dst_if->if_type == IFT_GIF)
2053153621Sthompsa				continue;
2054148887Srwatson			if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0)
2055146985Sthompsa				continue;
2056146985Sthompsa
2057146985Sthompsa			/*
2058146985Sthompsa			 * If this is not the original output interface,
2059146985Sthompsa			 * and the interface is participating in spanning
2060146985Sthompsa			 * tree, make sure the port is in a state that
2061146985Sthompsa			 * allows forwarding.
2062146985Sthompsa			 */
2063163863Sthompsa			if (dst_if != ifp && (bif->bif_flags & IFBIF_STP) &&
2064163863Sthompsa			    bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING)
2065163863Sthompsa				continue;
2066146985Sthompsa
2067146985Sthompsa			if (LIST_NEXT(bif, bif_next) == NULL) {
2068146985Sthompsa				used = 1;
2069146985Sthompsa				mc = m;
2070146985Sthompsa			} else {
2071243882Sglebius				mc = m_copypacket(m, M_NOWAIT);
2072146985Sthompsa				if (mc == NULL) {
2073271867Sglebius					if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1);
2074146985Sthompsa					continue;
2075146985Sthompsa				}
2076146985Sthompsa			}
2077146985Sthompsa
2078147786Sthompsa			bridge_enqueue(sc, dst_if, mc);
2079146985Sthompsa		}
2080146985Sthompsa		if (used == 0)
2081146985Sthompsa			m_freem(m);
2082146985Sthompsa		BRIDGE_UNREF(sc);
2083146985Sthompsa		return (0);
2084146985Sthompsa	}
2085146985Sthompsa
2086153497Sthompsasendunicast:
2087146985Sthompsa	/*
2088146985Sthompsa	 * XXX Spanning tree consideration here?
2089146985Sthompsa	 */
2090146985Sthompsa
2091153408Sthompsa	bridge_span(sc, m);
2092148887Srwatson	if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) {
2093146985Sthompsa		m_freem(m);
2094146985Sthompsa		BRIDGE_UNLOCK(sc);
2095146985Sthompsa		return (0);
2096146985Sthompsa	}
2097146985Sthompsa
2098146985Sthompsa	BRIDGE_UNLOCK(sc);
2099147786Sthompsa	bridge_enqueue(sc, dst_if, m);
2100146985Sthompsa	return (0);
2101146985Sthompsa}
2102146985Sthompsa
2103146985Sthompsa/*
2104240071Sglebius * bridge_transmit:
2105146985Sthompsa *
2106240071Sglebius *	Do output on a bridge.
2107146985Sthompsa *
2108146985Sthompsa */
2109240071Sglebiusstatic int
2110240071Sglebiusbridge_transmit(struct ifnet *ifp, struct mbuf *m)
2111146985Sthompsa{
2112146985Sthompsa	struct bridge_softc *sc;
2113242013Sglebius	struct ether_header *eh;
2114242013Sglebius	struct ifnet *dst_if;
2115240071Sglebius	int error = 0;
2116146985Sthompsa
2117146985Sthompsa	sc = ifp->if_softc;
2118146985Sthompsa
2119240071Sglebius	ETHER_BPF_MTAP(ifp, m);
2120146985Sthompsa
2121242013Sglebius	eh = mtod(m, struct ether_header *);
2122240071Sglebius
2123240071Sglebius	BRIDGE_LOCK(sc);
2124242013Sglebius	if (((m->m_flags & (M_BCAST|M_MCAST)) == 0) &&
2125242013Sglebius	    (dst_if = bridge_rtlookup(sc, eh->ether_dhost, 1)) != NULL) {
2126240071Sglebius		BRIDGE_UNLOCK(sc);
2127240071Sglebius		error = bridge_enqueue(sc, dst_if, m);
2128240071Sglebius	} else
2129240071Sglebius		bridge_broadcast(sc, ifp, m, 0);
2130146985Sthompsa
2131240071Sglebius	return (error);
2132240071Sglebius}
2133146985Sthompsa
2134240071Sglebius/*
2135240071Sglebius * The ifp->if_qflush entry point for if_bridge(4) is no-op.
2136240071Sglebius */
2137240071Sglebiusstatic void
2138240071Sglebiusbridge_qflush(struct ifnet *ifp __unused)
2139240071Sglebius{
2140146985Sthompsa}
2141146985Sthompsa
2142146985Sthompsa/*
2143146985Sthompsa * bridge_forward:
2144146985Sthompsa *
2145146985Sthompsa *	The forwarding function of the bridge.
2146146985Sthompsa *
2147146985Sthompsa *	NOTE: Releases the lock on return.
2148146985Sthompsa */
2149151313Sthompsastatic void
2150171678Sthompsabridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif,
2151171678Sthompsa    struct mbuf *m)
2152146985Sthompsa{
2153171678Sthompsa	struct bridge_iflist *dbif;
2154146985Sthompsa	struct ifnet *src_if, *dst_if, *ifp;
2155146985Sthompsa	struct ether_header *eh;
2156170681Sthompsa	uint16_t vlan;
2157175419Sthompsa	uint8_t *dst;
2158173320Sthompsa	int error;
2159146985Sthompsa
2160146985Sthompsa	src_if = m->m_pkthdr.rcvif;
2161147256Sbrooks	ifp = sc->sc_ifp;
2162146985Sthompsa
2163271867Sglebius	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
2164271867Sglebius	if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
2165170681Sthompsa	vlan = VLANTAGOF(m);
2166146985Sthompsa
2167171678Sthompsa	if ((sbif->bif_flags & IFBIF_STP) &&
2168174749Sthompsa	    sbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING)
2169174749Sthompsa		goto drop;
2170146985Sthompsa
2171146985Sthompsa	eh = mtod(m, struct ether_header *);
2172175419Sthompsa	dst = eh->ether_dhost;
2173146985Sthompsa
2174173320Sthompsa	/* If the interface is learning, record the address. */
2175173320Sthompsa	if (sbif->bif_flags & IFBIF_LEARNING) {
2176173320Sthompsa		error = bridge_rtupdate(sc, eh->ether_shost, vlan,
2177171678Sthompsa		    sbif, 0, IFBAF_DYNAMIC);
2178173320Sthompsa		/*
2179173320Sthompsa		 * If the interface has addresses limits then deny any source
2180173320Sthompsa		 * that is not in the cache.
2181173320Sthompsa		 */
2182174749Sthompsa		if (error && sbif->bif_addrmax)
2183174749Sthompsa			goto drop;
2184146985Sthompsa	}
2185146985Sthompsa
2186171678Sthompsa	if ((sbif->bif_flags & IFBIF_STP) != 0 &&
2187174749Sthompsa	    sbif->bif_stp.bp_state == BSTP_IFSTATE_LEARNING)
2188174749Sthompsa		goto drop;
2189146985Sthompsa
2190146985Sthompsa	/*
2191146985Sthompsa	 * At this point, the port either doesn't participate
2192146985Sthompsa	 * in spanning tree or it is in the forwarding state.
2193146985Sthompsa	 */
2194146985Sthompsa
2195146985Sthompsa	/*
2196146985Sthompsa	 * If the packet is unicast, destined for someone on
2197146985Sthompsa	 * "this" side of the bridge, drop it.
2198146985Sthompsa	 */
2199146985Sthompsa	if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) {
2200175419Sthompsa		dst_if = bridge_rtlookup(sc, dst, vlan);
2201174749Sthompsa		if (src_if == dst_if)
2202174749Sthompsa			goto drop;
2203146985Sthompsa	} else {
2204175419Sthompsa		/*
2205175419Sthompsa		 * Check if its a reserved multicast address, any address
2206175419Sthompsa		 * listed in 802.1D section 7.12.6 may not be forwarded by the
2207175419Sthompsa		 * bridge.
2208175419Sthompsa		 * This is currently 01-80-C2-00-00-00 to 01-80-C2-00-00-0F
2209175419Sthompsa		 */
2210175419Sthompsa		if (dst[0] == 0x01 && dst[1] == 0x80 &&
2211175419Sthompsa		    dst[2] == 0xc2 && dst[3] == 0x00 &&
2212175419Sthompsa		    dst[4] == 0x00 && dst[5] <= 0x0f)
2213175419Sthompsa			goto drop;
2214175419Sthompsa
2215146985Sthompsa		/* ...forward it to all interfaces. */
2216271867Sglebius		if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1);
2217146985Sthompsa		dst_if = NULL;
2218146985Sthompsa	}
2219146985Sthompsa
2220156235Scsjp	/*
2221156235Scsjp	 * If we have a destination interface which is a member of our bridge,
2222156235Scsjp	 * OR this is a unicast packet, push it through the bpf(4) machinery.
2223156235Scsjp	 * For broadcast or multicast packets, don't bother because it will
2224156235Scsjp	 * be reinjected into ether_input. We do this before we pass the packets
2225156235Scsjp	 * through the pfil(9) framework, as it is possible that pfil(9) will
2226156235Scsjp	 * drop the packet, or possibly modify it, making it difficult to debug
2227156235Scsjp	 * firewall issues on the bridge.
2228156235Scsjp	 */
2229156235Scsjp	if (dst_if != NULL || (m->m_flags & (M_BCAST | M_MCAST)) == 0)
2230172824Sthompsa		ETHER_BPF_MTAP(ifp, m);
2231156235Scsjp
2232146985Sthompsa	/* run the packet filter */
2233197952Sjulian	if (PFIL_HOOKED(&V_inet_pfil_hook)
2234147786Sthompsa#ifdef INET6
2235197952Sjulian	    || PFIL_HOOKED(&V_inet6_pfil_hook)
2236147786Sthompsa#endif
2237147786Sthompsa	    ) {
2238146985Sthompsa		BRIDGE_UNLOCK(sc);
2239146985Sthompsa		if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0)
2240146985Sthompsa			return;
2241147786Sthompsa		if (m == NULL)
2242147786Sthompsa			return;
2243146985Sthompsa		BRIDGE_LOCK(sc);
2244146985Sthompsa	}
2245146985Sthompsa
2246146985Sthompsa	if (dst_if == NULL) {
2247150837Sthompsa		bridge_broadcast(sc, src_if, m, 1);
2248146985Sthompsa		return;
2249146985Sthompsa	}
2250146985Sthompsa
2251146985Sthompsa	/*
2252146985Sthompsa	 * At this point, we're dealing with a unicast frame
2253146985Sthompsa	 * going to a different interface.
2254146985Sthompsa	 */
2255174749Sthompsa	if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0)
2256174749Sthompsa		goto drop;
2257174749Sthompsa
2258171678Sthompsa	dbif = bridge_lookup_member_if(sc, dst_if);
2259174749Sthompsa	if (dbif == NULL)
2260146985Sthompsa		/* Not a member of the bridge (anymore?) */
2261174749Sthompsa		goto drop;
2262146985Sthompsa
2263171678Sthompsa	/* Private segments can not talk to each other */
2264174749Sthompsa	if (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE)
2265174749Sthompsa		goto drop;
2266146985Sthompsa
2267171678Sthompsa	if ((dbif->bif_flags & IFBIF_STP) &&
2268174749Sthompsa	    dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING)
2269174749Sthompsa		goto drop;
2270171678Sthompsa
2271146985Sthompsa	BRIDGE_UNLOCK(sc);
2272147786Sthompsa
2273197952Sjulian	if (PFIL_HOOKED(&V_inet_pfil_hook)
2274147786Sthompsa#ifdef INET6
2275197952Sjulian	    || PFIL_HOOKED(&V_inet6_pfil_hook)
2276147786Sthompsa#endif
2277147786Sthompsa	    ) {
2278174749Sthompsa		if (bridge_pfil(&m, ifp, dst_if, PFIL_OUT) != 0)
2279147786Sthompsa			return;
2280147786Sthompsa		if (m == NULL)
2281147786Sthompsa			return;
2282147786Sthompsa	}
2283147786Sthompsa
2284147786Sthompsa	bridge_enqueue(sc, dst_if, m);
2285174749Sthompsa	return;
2286174749Sthompsa
2287174749Sthompsadrop:
2288174749Sthompsa	BRIDGE_UNLOCK(sc);
2289174749Sthompsa	m_freem(m);
2290146985Sthompsa}
2291146985Sthompsa
2292146985Sthompsa/*
2293146985Sthompsa * bridge_input:
2294146985Sthompsa *
2295146985Sthompsa *	Receive input from a member interface.  Queue the packet for
2296146985Sthompsa *	bridging if it is not for us.
2297146985Sthompsa */
2298151345Sthompsastatic struct mbuf *
2299146985Sthompsabridge_input(struct ifnet *ifp, struct mbuf *m)
2300146985Sthompsa{
2301146985Sthompsa	struct bridge_softc *sc = ifp->if_bridge;
2302164112Sthompsa	struct bridge_iflist *bif, *bif2;
2303149829Sthompsa	struct ifnet *bifp;
2304146985Sthompsa	struct ether_header *eh;
2305149829Sthompsa	struct mbuf *mc, *mc2;
2306170681Sthompsa	uint16_t vlan;
2307173320Sthompsa	int error;
2308146985Sthompsa
2309148887Srwatson	if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
2310146985Sthompsa		return (m);
2311146985Sthompsa
2312149829Sthompsa	bifp = sc->sc_ifp;
2313170681Sthompsa	vlan = VLANTAGOF(m);
2314149829Sthompsa
2315156235Scsjp	/*
2316156235Scsjp	 * Implement support for bridge monitoring. If this flag has been
2317156235Scsjp	 * set on this interface, discard the packet once we push it through
2318156235Scsjp	 * the bpf(4) machinery, but before we do, increment the byte and
2319156235Scsjp	 * packet counters associated with this interface.
2320156235Scsjp	 */
2321156235Scsjp	if ((bifp->if_flags & IFF_MONITOR) != 0) {
2322156235Scsjp		m->m_pkthdr.rcvif  = bifp;
2323172824Sthompsa		ETHER_BPF_MTAP(bifp, m);
2324271867Sglebius		if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1);
2325271867Sglebius		if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
2326164002Scsjp		m_freem(m);
2327156235Scsjp		return (NULL);
2328156235Scsjp	}
2329146985Sthompsa	BRIDGE_LOCK(sc);
2330146985Sthompsa	bif = bridge_lookup_member_if(sc, ifp);
2331146985Sthompsa	if (bif == NULL) {
2332146985Sthompsa		BRIDGE_UNLOCK(sc);
2333146985Sthompsa		return (m);
2334146985Sthompsa	}
2335146985Sthompsa
2336146985Sthompsa	eh = mtod(m, struct ether_header *);
2337146985Sthompsa
2338153408Sthompsa	bridge_span(sc, m);
2339153408Sthompsa
2340167722Sthompsa	if (m->m_flags & (M_BCAST|M_MCAST)) {
2341146985Sthompsa		/* Tap off 802.1D packets; they do not get forwarded. */
2342146985Sthompsa		if (memcmp(eh->ether_dhost, bstp_etheraddr,
2343146985Sthompsa		    ETHER_ADDR_LEN) == 0) {
2344232014Sthompsa			bstp_input(&bif->bif_stp, ifp, m); /* consumes mbuf */
2345232014Sthompsa			BRIDGE_UNLOCK(sc);
2346232014Sthompsa			return (NULL);
2347146985Sthompsa		}
2348146985Sthompsa
2349163863Sthompsa		if ((bif->bif_flags & IFBIF_STP) &&
2350163863Sthompsa		    bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
2351163863Sthompsa			BRIDGE_UNLOCK(sc);
2352163863Sthompsa			return (m);
2353146985Sthompsa		}
2354146985Sthompsa
2355146985Sthompsa		/*
2356146985Sthompsa		 * Make a deep copy of the packet and enqueue the copy
2357146985Sthompsa		 * for bridge processing; return the original packet for
2358146985Sthompsa		 * local processing.
2359146985Sthompsa		 */
2360243882Sglebius		mc = m_dup(m, M_NOWAIT);
2361146985Sthompsa		if (mc == NULL) {
2362146985Sthompsa			BRIDGE_UNLOCK(sc);
2363146985Sthompsa			return (m);
2364146985Sthompsa		}
2365146985Sthompsa
2366146985Sthompsa		/* Perform the bridge forwarding function with the copy. */
2367171678Sthompsa		bridge_forward(sc, bif, mc);
2368146985Sthompsa
2369149829Sthompsa		/*
2370149829Sthompsa		 * Reinject the mbuf as arriving on the bridge so we have a
2371149829Sthompsa		 * chance at claiming multicast packets. We can not loop back
2372149829Sthompsa		 * here from ether_input as a bridge is never a member of a
2373149829Sthompsa		 * bridge.
2374149829Sthompsa		 */
2375149829Sthompsa		KASSERT(bifp->if_bridge == NULL,
2376149829Sthompsa		    ("loop created in bridge_input"));
2377243882Sglebius		mc2 = m_dup(m, M_NOWAIT);
2378149829Sthompsa		if (mc2 != NULL) {
2379153458Sthompsa			/* Keep the layer3 header aligned */
2380153458Sthompsa			int i = min(mc2->m_pkthdr.len, max_protohdr);
2381153458Sthompsa			mc2 = m_copyup(mc2, i, ETHER_ALIGN);
2382153458Sthompsa		}
2383153458Sthompsa		if (mc2 != NULL) {
2384149829Sthompsa			mc2->m_pkthdr.rcvif = bifp;
2385149829Sthompsa			(*bifp->if_input)(bifp, mc2);
2386149829Sthompsa		}
2387149829Sthompsa
2388146985Sthompsa		/* Return the original packet for local processing. */
2389146985Sthompsa		return (m);
2390146985Sthompsa	}
2391146985Sthompsa
2392163863Sthompsa	if ((bif->bif_flags & IFBIF_STP) &&
2393163863Sthompsa	    bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
2394163863Sthompsa		BRIDGE_UNLOCK(sc);
2395163863Sthompsa		return (m);
2396146985Sthompsa	}
2397146985Sthompsa
2398211157Swill#if (defined(INET) || defined(INET6))
2399167683Srik#   define OR_CARP_CHECK_WE_ARE_DST(iface) \
2400167683Srik	|| ((iface)->if_carp \
2401211193Swill	    && (*carp_forus_p)((iface), eh->ether_dhost))
2402167683Srik#   define OR_CARP_CHECK_WE_ARE_SRC(iface) \
2403167683Srik	|| ((iface)->if_carp \
2404211193Swill	    && (*carp_forus_p)((iface), eh->ether_shost))
2405167683Srik#else
2406167683Srik#   define OR_CARP_CHECK_WE_ARE_DST(iface)
2407167683Srik#   define OR_CARP_CHECK_WE_ARE_SRC(iface)
2408167683Srik#endif
2409167683Srik
2410175432Sthompsa#ifdef INET6
2411175432Sthompsa#   define OR_PFIL_HOOKED_INET6 \
2412197952Sjulian	|| PFIL_HOOKED(&V_inet6_pfil_hook)
2413175432Sthompsa#else
2414175432Sthompsa#   define OR_PFIL_HOOKED_INET6
2415175432Sthompsa#endif
2416175432Sthompsa
2417167683Srik#define GRAB_OUR_PACKETS(iface) \
2418167683Srik	if ((iface)->if_type == IFT_GIF) \
2419167683Srik		continue; \
2420167683Srik	/* It is destined for us. */ \
2421167683Srik	if (memcmp(IF_LLADDR((iface)), eh->ether_dhost,  ETHER_ADDR_LEN) == 0 \
2422167683Srik	    OR_CARP_CHECK_WE_ARE_DST((iface))				\
2423167683Srik	    ) {								\
2424175432Sthompsa		if ((iface)->if_type == IFT_BRIDGE) {			\
2425175432Sthompsa			ETHER_BPF_MTAP(iface, m);			\
2426271867Sglebius			if_inc_counter(iface, IFCOUNTER_IPACKETS, 1);				\
2427271867Sglebius			if_inc_counter(iface, IFCOUNTER_IBYTES, m->m_pkthdr.len);		\
2428175432Sthompsa			/* Filter on the physical interface. */		\
2429272568Shrs			if (V_pfil_local_phys &&			\
2430197952Sjulian			    (PFIL_HOOKED(&V_inet_pfil_hook)		\
2431175432Sthompsa			     OR_PFIL_HOOKED_INET6)) {			\
2432175432Sthompsa				if (bridge_pfil(&m, NULL, ifp,		\
2433175432Sthompsa				    PFIL_IN) != 0 || m == NULL) {	\
2434175432Sthompsa					BRIDGE_UNLOCK(sc);		\
2435175432Sthompsa					return (NULL);			\
2436175432Sthompsa				}					\
2437248155Sglebius				eh = mtod(m, struct ether_header *);	\
2438175432Sthompsa			}						\
2439175432Sthompsa		}							\
2440173320Sthompsa		if (bif->bif_flags & IFBIF_LEARNING) {			\
2441173320Sthompsa			error = bridge_rtupdate(sc, eh->ether_shost,	\
2442170681Sthompsa			    vlan, bif, 0, IFBAF_DYNAMIC);		\
2443173320Sthompsa			if (error && bif->bif_addrmax) {		\
2444173320Sthompsa				BRIDGE_UNLOCK(sc);			\
2445173320Sthompsa				m_freem(m);				\
2446173320Sthompsa				return (NULL);				\
2447173320Sthompsa			}						\
2448173320Sthompsa		}							\
2449167683Srik		m->m_pkthdr.rcvif = iface;				\
2450167683Srik		BRIDGE_UNLOCK(sc);					\
2451167683Srik		return (m);						\
2452167683Srik	}								\
2453167683Srik									\
2454167683Srik	/* We just received a packet that we sent out. */		\
2455167683Srik	if (memcmp(IF_LLADDR((iface)), eh->ether_shost, ETHER_ADDR_LEN) == 0 \
2456167683Srik	    OR_CARP_CHECK_WE_ARE_SRC((iface))			\
2457167683Srik	    ) {								\
2458167683Srik		BRIDGE_UNLOCK(sc);					\
2459167683Srik		m_freem(m);						\
2460167683Srik		return (NULL);						\
2461167683Srik	}
2462167683Srik
2463146985Sthompsa	/*
2464175432Sthompsa	 * Unicast.  Make sure it's not for the bridge.
2465175432Sthompsa	 */
2466175432Sthompsa	do { GRAB_OUR_PACKETS(bifp) } while (0);
2467175432Sthompsa
2468175432Sthompsa	/*
2469167683Srik	 * Give a chance for ifp at first priority. This will help when	the
2470167683Srik	 * packet comes through the interface like VLAN's with the same MACs
2471167683Srik	 * on several interfaces from the same bridge. This also will save
2472167683Srik	 * some CPU cycles in case the destination interface and the input
2473167683Srik	 * interface (eq ifp) are the same.
2474146985Sthompsa	 */
2475167683Srik	do { GRAB_OUR_PACKETS(ifp) } while (0);
2476167683Srik
2477167683Srik	/* Now check the all bridge members. */
2478164112Sthompsa	LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) {
2479167683Srik		GRAB_OUR_PACKETS(bif2->bif_ifp)
2480146985Sthompsa	}
2481146985Sthompsa
2482167683Srik#undef OR_CARP_CHECK_WE_ARE_DST
2483167683Srik#undef OR_CARP_CHECK_WE_ARE_SRC
2484175432Sthompsa#undef OR_PFIL_HOOKED_INET6
2485167683Srik#undef GRAB_OUR_PACKETS
2486167683Srik
2487146985Sthompsa	/* Perform the bridge forwarding function. */
2488171678Sthompsa	bridge_forward(sc, bif, m);
2489146985Sthompsa
2490146985Sthompsa	return (NULL);
2491146985Sthompsa}
2492146985Sthompsa
2493146985Sthompsa/*
2494146985Sthompsa * bridge_broadcast:
2495146985Sthompsa *
2496146985Sthompsa *	Send a frame to all interfaces that are members of
2497146985Sthompsa *	the bridge, except for the one on which the packet
2498146985Sthompsa *	arrived.
2499146985Sthompsa *
2500146985Sthompsa *	NOTE: Releases the lock on return.
2501146985Sthompsa */
2502151313Sthompsastatic void
2503146985Sthompsabridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
2504150837Sthompsa    struct mbuf *m, int runfilt)
2505146985Sthompsa{
2506171678Sthompsa	struct bridge_iflist *dbif, *sbif;
2507146985Sthompsa	struct mbuf *mc;
2508146985Sthompsa	struct ifnet *dst_if;
2509157057Srik	int error = 0, used = 0, i;
2510146985Sthompsa
2511171678Sthompsa	sbif = bridge_lookup_member_if(sc, src_if);
2512171678Sthompsa
2513146985Sthompsa	BRIDGE_LOCK2REF(sc, error);
2514146985Sthompsa	if (error) {
2515146985Sthompsa		m_freem(m);
2516146985Sthompsa		return;
2517146985Sthompsa	}
2518146985Sthompsa
2519147786Sthompsa	/* Filter on the bridge interface before broadcasting */
2520197952Sjulian	if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook)
2521147786Sthompsa#ifdef INET6
2522197952Sjulian	    || PFIL_HOOKED(&V_inet6_pfil_hook)
2523147786Sthompsa#endif
2524150837Sthompsa	    )) {
2525147786Sthompsa		if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0)
2526152393Sthompsa			goto out;
2527147786Sthompsa		if (m == NULL)
2528152393Sthompsa			goto out;
2529147786Sthompsa	}
2530147786Sthompsa
2531171678Sthompsa	LIST_FOREACH(dbif, &sc->sc_iflist, bif_next) {
2532171678Sthompsa		dst_if = dbif->bif_ifp;
2533146985Sthompsa		if (dst_if == src_if)
2534146985Sthompsa			continue;
2535146985Sthompsa
2536171678Sthompsa		/* Private segments can not talk to each other */
2537171678Sthompsa		if (sbif && (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE))
2538163863Sthompsa			continue;
2539146985Sthompsa
2540171678Sthompsa		if ((dbif->bif_flags & IFBIF_STP) &&
2541171678Sthompsa		    dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING)
2542171678Sthompsa			continue;
2543171678Sthompsa
2544171678Sthompsa		if ((dbif->bif_flags & IFBIF_DISCOVER) == 0 &&
2545146985Sthompsa		    (m->m_flags & (M_BCAST|M_MCAST)) == 0)
2546146985Sthompsa			continue;
2547146985Sthompsa
2548148887Srwatson		if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0)
2549146985Sthompsa			continue;
2550146985Sthompsa
2551171678Sthompsa		if (LIST_NEXT(dbif, bif_next) == NULL) {
2552146985Sthompsa			mc = m;
2553146985Sthompsa			used = 1;
2554146985Sthompsa		} else {
2555243882Sglebius			mc = m_dup(m, M_NOWAIT);
2556146985Sthompsa			if (mc == NULL) {
2557271867Sglebius				if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1);
2558146985Sthompsa				continue;
2559146985Sthompsa			}
2560146985Sthompsa		}
2561146985Sthompsa
2562147786Sthompsa		/*
2563147786Sthompsa		 * Filter on the output interface. Pass a NULL bridge interface
2564153497Sthompsa		 * pointer so we do not redundantly filter on the bridge for
2565147786Sthompsa		 * each interface we broadcast on.
2566147786Sthompsa		 */
2567197952Sjulian		if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook)
2568147786Sthompsa#ifdef INET6
2569197952Sjulian		    || PFIL_HOOKED(&V_inet6_pfil_hook)
2570147786Sthompsa#endif
2571150837Sthompsa		    )) {
2572157057Srik			if (used == 0) {
2573157057Srik				/* Keep the layer3 header aligned */
2574157057Srik				i = min(mc->m_pkthdr.len, max_protohdr);
2575157057Srik				mc = m_copyup(mc, i, ETHER_ALIGN);
2576157057Srik				if (mc == NULL) {
2577271867Sglebius					if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1);
2578157057Srik					continue;
2579157057Srik				}
2580157057Srik			}
2581152392Sthompsa			if (bridge_pfil(&mc, NULL, dst_if, PFIL_OUT) != 0)
2582152392Sthompsa				continue;
2583152392Sthompsa			if (mc == NULL)
2584152392Sthompsa				continue;
2585147786Sthompsa		}
2586151305Sthompsa
2587147786Sthompsa		bridge_enqueue(sc, dst_if, mc);
2588146985Sthompsa	}
2589146985Sthompsa	if (used == 0)
2590146985Sthompsa		m_freem(m);
2591146985Sthompsa
2592152393Sthompsaout:
2593146985Sthompsa	BRIDGE_UNREF(sc);
2594146985Sthompsa}
2595146985Sthompsa
2596146985Sthompsa/*
2597153408Sthompsa * bridge_span:
2598153408Sthompsa *
2599153408Sthompsa *	Duplicate a packet out one or more interfaces that are in span mode,
2600153408Sthompsa *	the original mbuf is unmodified.
2601153408Sthompsa */
2602153408Sthompsastatic void
2603153408Sthompsabridge_span(struct bridge_softc *sc, struct mbuf *m)
2604153408Sthompsa{
2605153408Sthompsa	struct bridge_iflist *bif;
2606153408Sthompsa	struct ifnet *dst_if;
2607153408Sthompsa	struct mbuf *mc;
2608153408Sthompsa
2609153408Sthompsa	if (LIST_EMPTY(&sc->sc_spanlist))
2610153408Sthompsa		return;
2611153408Sthompsa
2612153408Sthompsa	LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) {
2613153408Sthompsa		dst_if = bif->bif_ifp;
2614158667Sthompsa
2615153408Sthompsa		if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0)
2616153408Sthompsa			continue;
2617153408Sthompsa
2618243882Sglebius		mc = m_copypacket(m, M_NOWAIT);
2619153408Sthompsa		if (mc == NULL) {
2620271867Sglebius			if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1);
2621153408Sthompsa			continue;
2622153408Sthompsa		}
2623153408Sthompsa
2624153408Sthompsa		bridge_enqueue(sc, dst_if, mc);
2625153408Sthompsa	}
2626153408Sthompsa}
2627153408Sthompsa
2628153408Sthompsa/*
2629146985Sthompsa * bridge_rtupdate:
2630146985Sthompsa *
2631146985Sthompsa *	Add a bridge routing entry.
2632146985Sthompsa */
2633151313Sthompsastatic int
2634170681Sthompsabridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan,
2635164112Sthompsa    struct bridge_iflist *bif, int setflags, uint8_t flags)
2636146985Sthompsa{
2637146985Sthompsa	struct bridge_rtnode *brt;
2638146985Sthompsa	int error;
2639146985Sthompsa
2640146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
2641146985Sthompsa
2642173320Sthompsa	/* Check the source address is valid and not multicast. */
2643173320Sthompsa	if (ETHER_IS_MULTICAST(dst) ||
2644173320Sthompsa	    (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
2645173320Sthompsa	     dst[3] == 0 && dst[4] == 0 && dst[5] == 0) != 0)
2646173320Sthompsa		return (EINVAL);
2647173320Sthompsa
2648170681Sthompsa	/* 802.1p frames map to vlan 1 */
2649170681Sthompsa	if (vlan == 0)
2650170681Sthompsa		vlan = 1;
2651170681Sthompsa
2652146985Sthompsa	/*
2653146985Sthompsa	 * A route for this destination might already exist.  If so,
2654146985Sthompsa	 * update it, otherwise create a new one.
2655146985Sthompsa	 */
2656170681Sthompsa	if ((brt = bridge_rtnode_lookup(sc, dst, vlan)) == NULL) {
2657160867Sthompsa		if (sc->sc_brtcnt >= sc->sc_brtmax) {
2658160867Sthompsa			sc->sc_brtexceeded++;
2659146985Sthompsa			return (ENOSPC);
2660160867Sthompsa		}
2661173320Sthompsa		/* Check per interface address limits (if enabled) */
2662173320Sthompsa		if (bif->bif_addrmax && bif->bif_addrcnt >= bif->bif_addrmax) {
2663173320Sthompsa			bif->bif_addrexceeded++;
2664173320Sthompsa			return (ENOSPC);
2665173320Sthompsa		}
2666146985Sthompsa
2667146985Sthompsa		/*
2668146985Sthompsa		 * Allocate a new bridge forwarding node, and
2669146985Sthompsa		 * initialize the expiration time and Ethernet
2670146985Sthompsa		 * address.
2671146985Sthompsa		 */
2672346300Skevans		brt = uma_zalloc(V_bridge_rtnode_zone, M_NOWAIT | M_ZERO);
2673146985Sthompsa		if (brt == NULL)
2674146985Sthompsa			return (ENOMEM);
2675146985Sthompsa
2676164112Sthompsa		if (bif->bif_flags & IFBIF_STICKY)
2677164112Sthompsa			brt->brt_flags = IFBAF_STICKY;
2678164112Sthompsa		else
2679164112Sthompsa			brt->brt_flags = IFBAF_DYNAMIC;
2680164112Sthompsa
2681146985Sthompsa		memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN);
2682170681Sthompsa		brt->brt_vlan = vlan;
2683146985Sthompsa
2684146985Sthompsa		if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
2685346300Skevans			uma_zfree(V_bridge_rtnode_zone, brt);
2686146985Sthompsa			return (error);
2687146985Sthompsa		}
2688173320Sthompsa		brt->brt_dst = bif;
2689173320Sthompsa		bif->bif_addrcnt++;
2690146985Sthompsa	}
2691146985Sthompsa
2692173320Sthompsa	if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC &&
2693173320Sthompsa	    brt->brt_dst != bif) {
2694173320Sthompsa		brt->brt_dst->bif_addrcnt--;
2695173320Sthompsa		brt->brt_dst = bif;
2696173320Sthompsa		brt->brt_dst->bif_addrcnt++;
2697173320Sthompsa	}
2698173320Sthompsa
2699153979Sthompsa	if ((flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
2700153978Sthompsa		brt->brt_expire = time_uptime + sc->sc_brttimeout;
2701153977Sthompsa	if (setflags)
2702146985Sthompsa		brt->brt_flags = flags;
2703146985Sthompsa
2704146985Sthompsa	return (0);
2705146985Sthompsa}
2706146985Sthompsa
2707146985Sthompsa/*
2708146985Sthompsa * bridge_rtlookup:
2709146985Sthompsa *
2710146985Sthompsa *	Lookup the destination interface for an address.
2711146985Sthompsa */
2712151345Sthompsastatic struct ifnet *
2713170681Sthompsabridge_rtlookup(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan)
2714146985Sthompsa{
2715146985Sthompsa	struct bridge_rtnode *brt;
2716146985Sthompsa
2717146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
2718146985Sthompsa
2719170681Sthompsa	if ((brt = bridge_rtnode_lookup(sc, addr, vlan)) == NULL)
2720146985Sthompsa		return (NULL);
2721146985Sthompsa
2722146985Sthompsa	return (brt->brt_ifp);
2723146985Sthompsa}
2724146985Sthompsa
2725146985Sthompsa/*
2726146985Sthompsa * bridge_rttrim:
2727146985Sthompsa *
2728146985Sthompsa *	Trim the routine table so that we have a number
2729146985Sthompsa *	of routing entries less than or equal to the
2730146985Sthompsa *	maximum number.
2731146985Sthompsa */
2732151313Sthompsastatic void
2733146985Sthompsabridge_rttrim(struct bridge_softc *sc)
2734146985Sthompsa{
2735146985Sthompsa	struct bridge_rtnode *brt, *nbrt;
2736146985Sthompsa
2737146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
2738146985Sthompsa
2739146985Sthompsa	/* Make sure we actually need to do this. */
2740146985Sthompsa	if (sc->sc_brtcnt <= sc->sc_brtmax)
2741146985Sthompsa		return;
2742146985Sthompsa
2743146985Sthompsa	/* Force an aging cycle; this might trim enough addresses. */
2744146985Sthompsa	bridge_rtage(sc);
2745146985Sthompsa	if (sc->sc_brtcnt <= sc->sc_brtmax)
2746146985Sthompsa		return;
2747146985Sthompsa
2748163142Sthompsa	LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
2749146985Sthompsa		if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
2750146985Sthompsa			bridge_rtnode_destroy(sc, brt);
2751146985Sthompsa			if (sc->sc_brtcnt <= sc->sc_brtmax)
2752146985Sthompsa				return;
2753146985Sthompsa		}
2754146985Sthompsa	}
2755146985Sthompsa}
2756146985Sthompsa
2757146985Sthompsa/*
2758146985Sthompsa * bridge_timer:
2759146985Sthompsa *
2760146985Sthompsa *	Aging timer for the bridge.
2761146985Sthompsa */
2762151313Sthompsastatic void
2763146985Sthompsabridge_timer(void *arg)
2764146985Sthompsa{
2765146985Sthompsa	struct bridge_softc *sc = arg;
2766146985Sthompsa
2767149253Sthompsa	BRIDGE_LOCK_ASSERT(sc);
2768149253Sthompsa
2769346300Skevans	/* Destruction of rtnodes requires a proper vnet context */
2770346300Skevans	CURVNET_SET(sc->sc_ifp->if_vnet);
2771146985Sthompsa	bridge_rtage(sc);
2772146985Sthompsa
2773148887Srwatson	if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
2774146985Sthompsa		callout_reset(&sc->sc_brcallout,
2775146985Sthompsa		    bridge_rtable_prune_period * hz, bridge_timer, sc);
2776346300Skevans	CURVNET_RESTORE();
2777146985Sthompsa}
2778146985Sthompsa
2779146985Sthompsa/*
2780146985Sthompsa * bridge_rtage:
2781146985Sthompsa *
2782146985Sthompsa *	Perform an aging cycle.
2783146985Sthompsa */
2784151313Sthompsastatic void
2785146985Sthompsabridge_rtage(struct bridge_softc *sc)
2786146985Sthompsa{
2787146985Sthompsa	struct bridge_rtnode *brt, *nbrt;
2788146985Sthompsa
2789146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
2790146985Sthompsa
2791163142Sthompsa	LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
2792146985Sthompsa		if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
2793153976Sthompsa			if (time_uptime >= brt->brt_expire)
2794146985Sthompsa				bridge_rtnode_destroy(sc, brt);
2795146985Sthompsa		}
2796146985Sthompsa	}
2797146985Sthompsa}
2798146985Sthompsa
2799146985Sthompsa/*
2800146985Sthompsa * bridge_rtflush:
2801146985Sthompsa *
2802146985Sthompsa *	Remove all dynamic addresses from the bridge.
2803146985Sthompsa */
2804151313Sthompsastatic void
2805146985Sthompsabridge_rtflush(struct bridge_softc *sc, int full)
2806146985Sthompsa{
2807146985Sthompsa	struct bridge_rtnode *brt, *nbrt;
2808146985Sthompsa
2809146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
2810146985Sthompsa
2811163142Sthompsa	LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
2812146985Sthompsa		if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
2813146985Sthompsa			bridge_rtnode_destroy(sc, brt);
2814146985Sthompsa	}
2815146985Sthompsa}
2816146985Sthompsa
2817146985Sthompsa/*
2818146985Sthompsa * bridge_rtdaddr:
2819146985Sthompsa *
2820146985Sthompsa *	Remove an address from the table.
2821146985Sthompsa */
2822151313Sthompsastatic int
2823170681Sthompsabridge_rtdaddr(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan)
2824146985Sthompsa{
2825146985Sthompsa	struct bridge_rtnode *brt;
2826170681Sthompsa	int found = 0;
2827146985Sthompsa
2828146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
2829146985Sthompsa
2830170681Sthompsa	/*
2831170681Sthompsa	 * If vlan is zero then we want to delete for all vlans so the lookup
2832170681Sthompsa	 * may return more than one.
2833170681Sthompsa	 */
2834170681Sthompsa	while ((brt = bridge_rtnode_lookup(sc, addr, vlan)) != NULL) {
2835170681Sthompsa		bridge_rtnode_destroy(sc, brt);
2836170681Sthompsa		found = 1;
2837170681Sthompsa	}
2838146985Sthompsa
2839170681Sthompsa	return (found ? 0 : ENOENT);
2840146985Sthompsa}
2841146985Sthompsa
2842146985Sthompsa/*
2843146985Sthompsa * bridge_rtdelete:
2844146985Sthompsa *
2845146985Sthompsa *	Delete routes to a speicifc member interface.
2846146985Sthompsa */
2847160769Sthompsastatic void
2848146985Sthompsabridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int full)
2849146985Sthompsa{
2850146985Sthompsa	struct bridge_rtnode *brt, *nbrt;
2851146985Sthompsa
2852146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
2853146985Sthompsa
2854163142Sthompsa	LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
2855153497Sthompsa		if (brt->brt_ifp == ifp && (full ||
2856146985Sthompsa			    (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC))
2857146985Sthompsa			bridge_rtnode_destroy(sc, brt);
2858146985Sthompsa	}
2859146985Sthompsa}
2860146985Sthompsa
2861146985Sthompsa/*
2862146985Sthompsa * bridge_rtable_init:
2863146985Sthompsa *
2864146985Sthompsa *	Initialize the route table for this bridge.
2865146985Sthompsa */
2866241183Sthompsastatic void
2867146985Sthompsabridge_rtable_init(struct bridge_softc *sc)
2868146985Sthompsa{
2869146985Sthompsa	int i;
2870146985Sthompsa
2871146985Sthompsa	sc->sc_rthash = malloc(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE,
2872241183Sthompsa	    M_DEVBUF, M_WAITOK);
2873146985Sthompsa
2874146985Sthompsa	for (i = 0; i < BRIDGE_RTHASH_SIZE; i++)
2875146985Sthompsa		LIST_INIT(&sc->sc_rthash[i]);
2876146985Sthompsa
2877146985Sthompsa	sc->sc_rthash_key = arc4random();
2878146985Sthompsa	LIST_INIT(&sc->sc_rtlist);
2879146985Sthompsa}
2880146985Sthompsa
2881146985Sthompsa/*
2882146985Sthompsa * bridge_rtable_fini:
2883146985Sthompsa *
2884146985Sthompsa *	Deconstruct the route table for this bridge.
2885146985Sthompsa */
2886151313Sthompsastatic void
2887146985Sthompsabridge_rtable_fini(struct bridge_softc *sc)
2888146985Sthompsa{
2889146985Sthompsa
2890173320Sthompsa	KASSERT(sc->sc_brtcnt == 0,
2891173320Sthompsa	    ("%s: %d bridge routes referenced", __func__, sc->sc_brtcnt));
2892146985Sthompsa	free(sc->sc_rthash, M_DEVBUF);
2893146985Sthompsa}
2894146985Sthompsa
2895146985Sthompsa/*
2896146985Sthompsa * The following hash function is adapted from "Hash Functions" by Bob Jenkins
2897146985Sthompsa * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
2898146985Sthompsa */
2899146985Sthompsa#define	mix(a, b, c)							\
2900146985Sthompsado {									\
2901146985Sthompsa	a -= b; a -= c; a ^= (c >> 13);					\
2902146985Sthompsa	b -= c; b -= a; b ^= (a << 8);					\
2903146985Sthompsa	c -= a; c -= b; c ^= (b >> 13);					\
2904146985Sthompsa	a -= b; a -= c; a ^= (c >> 12);					\
2905146985Sthompsa	b -= c; b -= a; b ^= (a << 16);					\
2906146985Sthompsa	c -= a; c -= b; c ^= (b >> 5);					\
2907146985Sthompsa	a -= b; a -= c; a ^= (c >> 3);					\
2908146985Sthompsa	b -= c; b -= a; b ^= (a << 10);					\
2909146985Sthompsa	c -= a; c -= b; c ^= (b >> 15);					\
2910146985Sthompsa} while (/*CONSTCOND*/0)
2911146985Sthompsa
2912146985Sthompsastatic __inline uint32_t
2913146985Sthompsabridge_rthash(struct bridge_softc *sc, const uint8_t *addr)
2914146985Sthompsa{
2915146985Sthompsa	uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_rthash_key;
2916146985Sthompsa
2917146985Sthompsa	b += addr[5] << 8;
2918146985Sthompsa	b += addr[4];
2919146985Sthompsa	a += addr[3] << 24;
2920146985Sthompsa	a += addr[2] << 16;
2921146985Sthompsa	a += addr[1] << 8;
2922146985Sthompsa	a += addr[0];
2923146985Sthompsa
2924146985Sthompsa	mix(a, b, c);
2925146985Sthompsa
2926146985Sthompsa	return (c & BRIDGE_RTHASH_MASK);
2927146985Sthompsa}
2928146985Sthompsa
2929146985Sthompsa#undef mix
2930146985Sthompsa
2931155143Sthompsastatic int
2932155143Sthompsabridge_rtnode_addr_cmp(const uint8_t *a, const uint8_t *b)
2933155143Sthompsa{
2934155143Sthompsa	int i, d;
2935155143Sthompsa
2936155143Sthompsa	for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) {
2937155143Sthompsa		d = ((int)a[i]) - ((int)b[i]);
2938155143Sthompsa	}
2939155143Sthompsa
2940155143Sthompsa	return (d);
2941155143Sthompsa}
2942155143Sthompsa
2943146985Sthompsa/*
2944146985Sthompsa * bridge_rtnode_lookup:
2945146985Sthompsa *
2946170681Sthompsa *	Look up a bridge route node for the specified destination. Compare the
2947170681Sthompsa *	vlan id or if zero then just return the first match.
2948146985Sthompsa */
2949151345Sthompsastatic struct bridge_rtnode *
2950170681Sthompsabridge_rtnode_lookup(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan)
2951146985Sthompsa{
2952146985Sthompsa	struct bridge_rtnode *brt;
2953146985Sthompsa	uint32_t hash;
2954146985Sthompsa	int dir;
2955146985Sthompsa
2956146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
2957146985Sthompsa
2958146985Sthompsa	hash = bridge_rthash(sc, addr);
2959146985Sthompsa	LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) {
2960155143Sthompsa		dir = bridge_rtnode_addr_cmp(addr, brt->brt_addr);
2961170681Sthompsa		if (dir == 0 && (brt->brt_vlan == vlan || vlan == 0))
2962146985Sthompsa			return (brt);
2963146985Sthompsa		if (dir > 0)
2964146985Sthompsa			return (NULL);
2965146985Sthompsa	}
2966146985Sthompsa
2967146985Sthompsa	return (NULL);
2968146985Sthompsa}
2969146985Sthompsa
2970146985Sthompsa/*
2971146985Sthompsa * bridge_rtnode_insert:
2972146985Sthompsa *
2973146985Sthompsa *	Insert the specified bridge node into the route table.  We
2974146985Sthompsa *	assume the entry is not already in the table.
2975146985Sthompsa */
2976151313Sthompsastatic int
2977146985Sthompsabridge_rtnode_insert(struct bridge_softc *sc, struct bridge_rtnode *brt)
2978146985Sthompsa{
2979146985Sthompsa	struct bridge_rtnode *lbrt;
2980146985Sthompsa	uint32_t hash;
2981146985Sthompsa	int dir;
2982146985Sthompsa
2983146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
2984146985Sthompsa
2985146985Sthompsa	hash = bridge_rthash(sc, brt->brt_addr);
2986146985Sthompsa
2987146985Sthompsa	lbrt = LIST_FIRST(&sc->sc_rthash[hash]);
2988146985Sthompsa	if (lbrt == NULL) {
2989146985Sthompsa		LIST_INSERT_HEAD(&sc->sc_rthash[hash], brt, brt_hash);
2990146985Sthompsa		goto out;
2991146985Sthompsa	}
2992146985Sthompsa
2993146985Sthompsa	do {
2994155143Sthompsa		dir = bridge_rtnode_addr_cmp(brt->brt_addr, lbrt->brt_addr);
2995170681Sthompsa		if (dir == 0 && brt->brt_vlan == lbrt->brt_vlan)
2996146985Sthompsa			return (EEXIST);
2997146985Sthompsa		if (dir > 0) {
2998146985Sthompsa			LIST_INSERT_BEFORE(lbrt, brt, brt_hash);
2999146985Sthompsa			goto out;
3000146985Sthompsa		}
3001146985Sthompsa		if (LIST_NEXT(lbrt, brt_hash) == NULL) {
3002146985Sthompsa			LIST_INSERT_AFTER(lbrt, brt, brt_hash);
3003146985Sthompsa			goto out;
3004146985Sthompsa		}
3005146985Sthompsa		lbrt = LIST_NEXT(lbrt, brt_hash);
3006146985Sthompsa	} while (lbrt != NULL);
3007146985Sthompsa
3008146985Sthompsa#ifdef DIAGNOSTIC
3009146985Sthompsa	panic("bridge_rtnode_insert: impossible");
3010146985Sthompsa#endif
3011146985Sthompsa
3012153497Sthompsaout:
3013146985Sthompsa	LIST_INSERT_HEAD(&sc->sc_rtlist, brt, brt_list);
3014146985Sthompsa	sc->sc_brtcnt++;
3015146985Sthompsa
3016146985Sthompsa	return (0);
3017146985Sthompsa}
3018146985Sthompsa
3019146985Sthompsa/*
3020146985Sthompsa * bridge_rtnode_destroy:
3021146985Sthompsa *
3022146985Sthompsa *	Destroy a bridge rtnode.
3023146985Sthompsa */
3024151313Sthompsastatic void
3025146985Sthompsabridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt)
3026146985Sthompsa{
3027146985Sthompsa	BRIDGE_LOCK_ASSERT(sc);
3028146985Sthompsa
3029146985Sthompsa	LIST_REMOVE(brt, brt_hash);
3030146985Sthompsa
3031146985Sthompsa	LIST_REMOVE(brt, brt_list);
3032146985Sthompsa	sc->sc_brtcnt--;
3033173320Sthompsa	brt->brt_dst->bif_addrcnt--;
3034346300Skevans	uma_zfree(V_bridge_rtnode_zone, brt);
3035146985Sthompsa}
3036146985Sthompsa
3037146985Sthompsa/*
3038163863Sthompsa * bridge_rtable_expire:
3039163863Sthompsa *
3040163863Sthompsa *	Set the expiry time for all routes on an interface.
3041163863Sthompsa */
3042163863Sthompsastatic void
3043163863Sthompsabridge_rtable_expire(struct ifnet *ifp, int age)
3044163863Sthompsa{
3045163863Sthompsa	struct bridge_softc *sc = ifp->if_bridge;
3046163863Sthompsa	struct bridge_rtnode *brt;
3047163863Sthompsa
3048346300Skevans	CURVNET_SET(ifp->if_vnet);
3049163863Sthompsa	BRIDGE_LOCK(sc);
3050163863Sthompsa
3051163863Sthompsa	/*
3052163863Sthompsa	 * If the age is zero then flush, otherwise set all the expiry times to
3053163863Sthompsa	 * age for the interface
3054163863Sthompsa	 */
3055163863Sthompsa	if (age == 0)
3056163863Sthompsa		bridge_rtdelete(sc, ifp, IFBF_FLUSHDYN);
3057163863Sthompsa	else {
3058163863Sthompsa		LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) {
3059163863Sthompsa			/* Cap the expiry time to 'age' */
3060163863Sthompsa			if (brt->brt_ifp == ifp &&
3061163863Sthompsa			    brt->brt_expire > time_uptime + age &&
3062163863Sthompsa			    (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
3063163863Sthompsa				brt->brt_expire = time_uptime + age;
3064163863Sthompsa		}
3065163863Sthompsa	}
3066163863Sthompsa	BRIDGE_UNLOCK(sc);
3067346300Skevans	CURVNET_RESTORE();
3068163863Sthompsa}
3069163863Sthompsa
3070163863Sthompsa/*
3071160902Sthompsa * bridge_state_change:
3072160902Sthompsa *
3073160902Sthompsa *	Callback from the bridgestp code when a port changes states.
3074160902Sthompsa */
3075160902Sthompsastatic void
3076160902Sthompsabridge_state_change(struct ifnet *ifp, int state)
3077160902Sthompsa{
3078160902Sthompsa	struct bridge_softc *sc = ifp->if_bridge;
3079160902Sthompsa	static const char *stpstates[] = {
3080160902Sthompsa		"disabled",
3081160902Sthompsa		"listening",
3082160902Sthompsa		"learning",
3083160902Sthompsa		"forwarding",
3084160902Sthompsa		"blocking",
3085163863Sthompsa		"discarding"
3086160902Sthompsa	};
3087160902Sthompsa
3088282806Shrs	CURVNET_SET(ifp->if_vnet);
3089272568Shrs	if (V_log_stp)
3090160902Sthompsa		log(LOG_NOTICE, "%s: state changed to %s on %s\n",
3091160902Sthompsa		    sc->sc_ifp->if_xname, stpstates[state], ifp->if_xname);
3092282806Shrs	CURVNET_RESTORE();
3093160902Sthompsa}
3094160902Sthompsa
3095160902Sthompsa/*
3096146985Sthompsa * Send bridge packets through pfil if they are one of the types pfil can deal
3097146985Sthompsa * with, or if they are ARP or REVARP.  (pfil will pass ARP and REVARP without
3098147786Sthompsa * question.) If *bifp or *ifp are NULL then packet filtering is skipped for
3099147786Sthompsa * that interface.
3100146985Sthompsa */
3101153497Sthompsastatic int
3102153497Sthompsabridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
3103146985Sthompsa{
3104158592Sdhartmei	int snap, error, i, hlen;
3105146985Sthompsa	struct ether_header *eh1, eh2;
3106146985Sthompsa	struct ip *ip;
3107147665Sthompsa	struct llc llc1;
3108146985Sthompsa	u_int16_t ether_type;
3109146985Sthompsa
3110146985Sthompsa	snap = 0;
3111146985Sthompsa	error = -1;	/* Default error if not error == 0 */
3112147111Sthompsa
3113170139Sthompsa#if 0
3114157155Sthompsa	/* we may return with the IP fields swapped, ensure its not shared */
3115157155Sthompsa	KASSERT(M_WRITABLE(*mp), ("%s: modifying a shared mbuf", __func__));
3116170139Sthompsa#endif
3117157155Sthompsa
3118272568Shrs	if (V_pfil_bridge == 0 && V_pfil_member == 0 && V_pfil_ipfw == 0)
3119158667Sthompsa		return (0); /* filtering is disabled */
3120153831Sthompsa
3121147111Sthompsa	i = min((*mp)->m_pkthdr.len, max_protohdr);
3122147111Sthompsa	if ((*mp)->m_len < i) {
3123147111Sthompsa	    *mp = m_pullup(*mp, i);
3124147111Sthompsa	    if (*mp == NULL) {
3125147111Sthompsa		printf("%s: m_pullup failed\n", __func__);
3126158667Sthompsa		return (-1);
3127147111Sthompsa	    }
3128147111Sthompsa	}
3129147111Sthompsa
3130146985Sthompsa	eh1 = mtod(*mp, struct ether_header *);
3131146985Sthompsa	ether_type = ntohs(eh1->ether_type);
3132146985Sthompsa
3133146985Sthompsa	/*
3134146985Sthompsa	 * Check for SNAP/LLC.
3135146985Sthompsa	 */
3136146985Sthompsa	if (ether_type < ETHERMTU) {
3137147665Sthompsa		struct llc *llc2 = (struct llc *)(eh1 + 1);
3138146985Sthompsa
3139146985Sthompsa		if ((*mp)->m_len >= ETHER_HDR_LEN + 8 &&
3140147665Sthompsa		    llc2->llc_dsap == LLC_SNAP_LSAP &&
3141147665Sthompsa		    llc2->llc_ssap == LLC_SNAP_LSAP &&
3142147665Sthompsa		    llc2->llc_control == LLC_UI) {
3143147665Sthompsa			ether_type = htons(llc2->llc_un.type_snap.ether_type);
3144146985Sthompsa			snap = 1;
3145146985Sthompsa		}
3146146985Sthompsa	}
3147146985Sthompsa
3148162561Sthompsa	/*
3149162561Sthompsa	 * If we're trying to filter bridge traffic, don't look at anything
3150162561Sthompsa	 * other than IP and ARP traffic.  If the filter doesn't understand
3151162561Sthompsa	 * IPv6, don't allow IPv6 through the bridge either.  This is lame
3152162561Sthompsa	 * since if we really wanted, say, an AppleTalk filter, we are hosed,
3153162561Sthompsa	 * but of course we don't have an AppleTalk filter to begin with.
3154162561Sthompsa	 * (Note that since pfil doesn't understand ARP it will pass *ALL*
3155162561Sthompsa	 * ARP traffic.)
3156162561Sthompsa	 */
3157162561Sthompsa	switch (ether_type) {
3158162561Sthompsa		case ETHERTYPE_ARP:
3159162561Sthompsa		case ETHERTYPE_REVARP:
3160272568Shrs			if (V_pfil_ipfw_arp == 0)
3161162561Sthompsa				return (0); /* Automatically pass */
3162162561Sthompsa			break;
3163162561Sthompsa
3164162561Sthompsa		case ETHERTYPE_IP:
3165162561Sthompsa#ifdef INET6
3166162561Sthompsa		case ETHERTYPE_IPV6:
3167162561Sthompsa#endif /* INET6 */
3168162561Sthompsa			break;
3169162561Sthompsa		default:
3170162561Sthompsa			/*
3171162561Sthompsa			 * Check to see if the user wants to pass non-ip
3172162561Sthompsa			 * packets, these will not be checked by pfil(9) and
3173162561Sthompsa			 * passed unconditionally so the default is to drop.
3174162561Sthompsa			 */
3175272568Shrs			if (V_pfil_onlyip)
3176162561Sthompsa				goto bad;
3177162561Sthompsa	}
3178162561Sthompsa
3179240099Smelifaro	/* Run the packet through pfil before stripping link headers */
3180272568Shrs	if (PFIL_HOOKED(&V_link_pfil_hook) && V_pfil_ipfw != 0 &&
3181240099Smelifaro			dir == PFIL_OUT && ifp != NULL) {
3182240099Smelifaro
3183332513Skp		error = pfil_run_hooks(&V_link_pfil_hook, mp, ifp, dir, 0,
3184332513Skp		    NULL);
3185240099Smelifaro
3186240099Smelifaro		if (*mp == NULL || error != 0) /* packet consumed by filter */
3187240099Smelifaro			return (error);
3188240099Smelifaro	}
3189240099Smelifaro
3190146985Sthompsa	/* Strip off the Ethernet header and keep a copy. */
3191146985Sthompsa	m_copydata(*mp, 0, ETHER_HDR_LEN, (caddr_t) &eh2);
3192146985Sthompsa	m_adj(*mp, ETHER_HDR_LEN);
3193146985Sthompsa
3194146985Sthompsa	/* Strip off snap header, if present */
3195146985Sthompsa	if (snap) {
3196147665Sthompsa		m_copydata(*mp, 0, sizeof(struct llc), (caddr_t) &llc1);
3197146985Sthompsa		m_adj(*mp, sizeof(struct llc));
3198146985Sthompsa	}
3199146985Sthompsa
3200147744Sthompsa	/*
3201147744Sthompsa	 * Check the IP header for alignment and errors
3202147744Sthompsa	 */
3203147744Sthompsa	if (dir == PFIL_IN) {
3204147744Sthompsa		switch (ether_type) {
3205147744Sthompsa			case ETHERTYPE_IP:
3206147744Sthompsa				error = bridge_ip_checkbasic(mp);
3207147744Sthompsa				break;
3208158667Sthompsa#ifdef INET6
3209147744Sthompsa			case ETHERTYPE_IPV6:
3210147744Sthompsa				error = bridge_ip6_checkbasic(mp);
3211147744Sthompsa				break;
3212158667Sthompsa#endif /* INET6 */
3213147744Sthompsa			default:
3214147744Sthompsa				error = 0;
3215147744Sthompsa		}
3216147744Sthompsa		if (error)
3217147744Sthompsa			goto bad;
3218147744Sthompsa	}
3219147744Sthompsa
3220147744Sthompsa	error = 0;
3221147744Sthompsa
3222146985Sthompsa	/*
3223162561Sthompsa	 * Run the packet through pfil
3224146985Sthompsa	 */
3225158667Sthompsa	switch (ether_type) {
3226158667Sthompsa	case ETHERTYPE_IP:
3227146985Sthompsa		/*
3228146985Sthompsa		 * Run pfil on the member interface and the bridge, both can
3229146985Sthompsa		 * be skipped by clearing pfil_member or pfil_bridge.
3230146985Sthompsa		 *
3231146985Sthompsa		 * Keep the order:
3232146985Sthompsa		 *   in_if -> bridge_if -> out_if
3233146985Sthompsa		 */
3234272568Shrs		if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL)
3235197952Sjulian			error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp,
3236332513Skp					dir, 0, NULL);
3237146985Sthompsa
3238147744Sthompsa		if (*mp == NULL || error != 0) /* filter may consume */
3239147205Sthompsa			break;
3240147205Sthompsa
3241272568Shrs		if (V_pfil_member && ifp != NULL)
3242197952Sjulian			error = pfil_run_hooks(&V_inet_pfil_hook, mp, ifp,
3243332513Skp					dir, 0, NULL);
3244146985Sthompsa
3245147744Sthompsa		if (*mp == NULL || error != 0) /* filter may consume */
3246147205Sthompsa			break;
3247147205Sthompsa
3248272568Shrs		if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL)
3249197952Sjulian			error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp,
3250332513Skp					dir, 0, NULL);
3251146985Sthompsa
3252158140Sthompsa		if (*mp == NULL || error != 0) /* filter may consume */
3253158140Sthompsa			break;
3254158140Sthompsa
3255158140Sthompsa		/* check if we need to fragment the packet */
3256306593Skp		/* bridge_fragment generates a mbuf chain of packets */
3257306593Skp		/* that already include eth headers */
3258272568Shrs		if (V_pfil_member && ifp != NULL && dir == PFIL_OUT) {
3259158140Sthompsa			i = (*mp)->m_pkthdr.len;
3260158140Sthompsa			if (i > ifp->if_mtu) {
3261306593Skp				error = bridge_fragment(ifp, mp, &eh2, snap,
3262158140Sthompsa					    &llc1);
3263158140Sthompsa				return (error);
3264158140Sthompsa			}
3265146985Sthompsa		}
3266146985Sthompsa
3267241245Sglebius		/* Recalculate the ip checksum. */
3268158140Sthompsa		ip = mtod(*mp, struct ip *);
3269158592Sdhartmei		hlen = ip->ip_hl << 2;
3270158667Sthompsa		if (hlen < sizeof(struct ip))
3271158667Sthompsa			goto bad;
3272158667Sthompsa		if (hlen > (*mp)->m_len) {
3273298075Spfg			if ((*mp = m_pullup(*mp, hlen)) == NULL)
3274158667Sthompsa				goto bad;
3275158667Sthompsa			ip = mtod(*mp, struct ip *);
3276158667Sthompsa			if (ip == NULL)
3277158667Sthompsa				goto bad;
3278158667Sthompsa		}
3279158667Sthompsa		ip->ip_sum = 0;
3280158667Sthompsa		if (hlen == sizeof(struct ip))
3281158667Sthompsa			ip->ip_sum = in_cksum_hdr(ip);
3282158667Sthompsa		else
3283158667Sthompsa			ip->ip_sum = in_cksum(*mp, hlen);
3284158140Sthompsa
3285146985Sthompsa		break;
3286158667Sthompsa#ifdef INET6
3287158667Sthompsa	case ETHERTYPE_IPV6:
3288272568Shrs		if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL)
3289197952Sjulian			error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp,
3290332513Skp					dir, 0, NULL);
3291147040Sthompsa
3292147744Sthompsa		if (*mp == NULL || error != 0) /* filter may consume */
3293147205Sthompsa			break;
3294147205Sthompsa
3295272568Shrs		if (V_pfil_member && ifp != NULL)
3296197952Sjulian			error = pfil_run_hooks(&V_inet6_pfil_hook, mp, ifp,
3297332513Skp					dir, 0, NULL);
3298147040Sthompsa
3299147744Sthompsa		if (*mp == NULL || error != 0) /* filter may consume */
3300147205Sthompsa			break;
3301147205Sthompsa
3302272568Shrs		if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL)
3303197952Sjulian			error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp,
3304332513Skp					dir, 0, NULL);
3305146985Sthompsa		break;
3306158667Sthompsa#endif
3307158667Sthompsa	default:
3308162561Sthompsa		error = 0;
3309146985Sthompsa		break;
3310146985Sthompsa	}
3311146985Sthompsa
3312146985Sthompsa	if (*mp == NULL)
3313158667Sthompsa		return (error);
3314146985Sthompsa	if (error != 0)
3315146985Sthompsa		goto bad;
3316146985Sthompsa
3317146985Sthompsa	error = -1;
3318146985Sthompsa
3319146985Sthompsa	/*
3320146985Sthompsa	 * Finally, put everything back the way it was and return
3321146985Sthompsa	 */
3322146985Sthompsa	if (snap) {
3323243882Sglebius		M_PREPEND(*mp, sizeof(struct llc), M_NOWAIT);
3324146985Sthompsa		if (*mp == NULL)
3325158667Sthompsa			return (error);
3326147665Sthompsa		bcopy(&llc1, mtod(*mp, caddr_t), sizeof(struct llc));
3327146985Sthompsa	}
3328146985Sthompsa
3329243882Sglebius	M_PREPEND(*mp, ETHER_HDR_LEN, M_NOWAIT);
3330146985Sthompsa	if (*mp == NULL)
3331158667Sthompsa		return (error);
3332146985Sthompsa	bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN);
3333146985Sthompsa
3334158667Sthompsa	return (0);
3335146985Sthompsa
3336153497Sthompsabad:
3337146985Sthompsa	m_freem(*mp);
3338146985Sthompsa	*mp = NULL;
3339158667Sthompsa	return (error);
3340146985Sthompsa}
3341146985Sthompsa
3342146985Sthompsa/*
3343146985Sthompsa * Perform basic checks on header size since
3344146985Sthompsa * pfil assumes ip_input has already processed
3345146985Sthompsa * it for it.  Cut-and-pasted from ip_input.c.
3346146985Sthompsa * Given how simple the IPv6 version is,
3347146985Sthompsa * does the IPv4 version really need to be
3348146985Sthompsa * this complicated?
3349146985Sthompsa *
3350146985Sthompsa * XXX Should we update ipstat here, or not?
3351146985Sthompsa * XXX Right now we update ipstat but not
3352146985Sthompsa * XXX csum_counter.
3353146985Sthompsa */
3354146985Sthompsastatic int
3355146985Sthompsabridge_ip_checkbasic(struct mbuf **mp)
3356146985Sthompsa{
3357146985Sthompsa	struct mbuf *m = *mp;
3358146985Sthompsa	struct ip *ip;
3359146985Sthompsa	int len, hlen;
3360146985Sthompsa	u_short sum;
3361146985Sthompsa
3362146985Sthompsa	if (*mp == NULL)
3363158667Sthompsa		return (-1);
3364146985Sthompsa
3365147744Sthompsa	if (IP_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) {
3366147744Sthompsa		if ((m = m_copyup(m, sizeof(struct ip),
3367147744Sthompsa			(max_linkhdr + 3) & ~3)) == NULL) {
3368147744Sthompsa			/* XXXJRT new stat, please */
3369196039Srwatson			KMOD_IPSTAT_INC(ips_toosmall);
3370147744Sthompsa			goto bad;
3371147744Sthompsa		}
3372147744Sthompsa	} else if (__predict_false(m->m_len < sizeof (struct ip))) {
3373146985Sthompsa		if ((m = m_pullup(m, sizeof (struct ip))) == NULL) {
3374196039Srwatson			KMOD_IPSTAT_INC(ips_toosmall);
3375146985Sthompsa			goto bad;
3376146985Sthompsa		}
3377146985Sthompsa	}
3378146985Sthompsa	ip = mtod(m, struct ip *);
3379146985Sthompsa	if (ip == NULL) goto bad;
3380146985Sthompsa
3381146985Sthompsa	if (ip->ip_v != IPVERSION) {
3382196039Srwatson		KMOD_IPSTAT_INC(ips_badvers);
3383146985Sthompsa		goto bad;
3384146985Sthompsa	}
3385146985Sthompsa	hlen = ip->ip_hl << 2;
3386146985Sthompsa	if (hlen < sizeof(struct ip)) { /* minimum header length */
3387196039Srwatson		KMOD_IPSTAT_INC(ips_badhlen);
3388146985Sthompsa		goto bad;
3389146985Sthompsa	}
3390146985Sthompsa	if (hlen > m->m_len) {
3391298075Spfg		if ((m = m_pullup(m, hlen)) == NULL) {
3392196039Srwatson			KMOD_IPSTAT_INC(ips_badhlen);
3393146985Sthompsa			goto bad;
3394146985Sthompsa		}
3395146985Sthompsa		ip = mtod(m, struct ip *);
3396146985Sthompsa		if (ip == NULL) goto bad;
3397146985Sthompsa	}
3398146985Sthompsa
3399146985Sthompsa	if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
3400146985Sthompsa		sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
3401146985Sthompsa	} else {
3402146985Sthompsa		if (hlen == sizeof(struct ip)) {
3403146985Sthompsa			sum = in_cksum_hdr(ip);
3404146985Sthompsa		} else {
3405146985Sthompsa			sum = in_cksum(m, hlen);
3406146985Sthompsa		}
3407146985Sthompsa	}
3408146985Sthompsa	if (sum) {
3409196039Srwatson		KMOD_IPSTAT_INC(ips_badsum);
3410146985Sthompsa		goto bad;
3411146985Sthompsa	}
3412146985Sthompsa
3413146985Sthompsa	/* Retrieve the packet length. */
3414146985Sthompsa	len = ntohs(ip->ip_len);
3415146985Sthompsa
3416146985Sthompsa	/*
3417146985Sthompsa	 * Check for additional length bogosity
3418146985Sthompsa	 */
3419146985Sthompsa	if (len < hlen) {
3420196039Srwatson		KMOD_IPSTAT_INC(ips_badlen);
3421146985Sthompsa		goto bad;
3422146985Sthompsa	}
3423146985Sthompsa
3424146985Sthompsa	/*
3425146985Sthompsa	 * Check that the amount of data in the buffers
3426146985Sthompsa	 * is as at least much as the IP header would have us expect.
3427146985Sthompsa	 * Drop packet if shorter than we expect.
3428146985Sthompsa	 */
3429146985Sthompsa	if (m->m_pkthdr.len < len) {
3430196039Srwatson		KMOD_IPSTAT_INC(ips_tooshort);
3431146985Sthompsa		goto bad;
3432146985Sthompsa	}
3433146985Sthompsa
3434146985Sthompsa	/* Checks out, proceed */
3435146985Sthompsa	*mp = m;
3436158667Sthompsa	return (0);
3437146985Sthompsa
3438153497Sthompsabad:
3439146985Sthompsa	*mp = m;
3440158667Sthompsa	return (-1);
3441146985Sthompsa}
3442146985Sthompsa
3443158667Sthompsa#ifdef INET6
3444146985Sthompsa/*
3445146985Sthompsa * Same as above, but for IPv6.
3446146985Sthompsa * Cut-and-pasted from ip6_input.c.
3447146985Sthompsa * XXX Should we update ip6stat, or not?
3448146985Sthompsa */
3449146985Sthompsastatic int
3450146985Sthompsabridge_ip6_checkbasic(struct mbuf **mp)
3451146985Sthompsa{
3452146985Sthompsa	struct mbuf *m = *mp;
3453146985Sthompsa	struct ip6_hdr *ip6;
3454146985Sthompsa
3455146985Sthompsa	/*
3456146985Sthompsa	 * If the IPv6 header is not aligned, slurp it up into a new
3457146985Sthompsa	 * mbuf with space for link headers, in the event we forward
3458146985Sthompsa	 * it.  Otherwise, if it is aligned, make sure the entire base
3459146985Sthompsa	 * IPv6 header is in the first mbuf of the chain.
3460147744Sthompsa	 */
3461146985Sthompsa	if (IP6_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) {
3462146985Sthompsa		struct ifnet *inifp = m->m_pkthdr.rcvif;
3463146985Sthompsa		if ((m = m_copyup(m, sizeof(struct ip6_hdr),
3464146985Sthompsa			    (max_linkhdr + 3) & ~3)) == NULL) {
3465147744Sthompsa			/* XXXJRT new stat, please */
3466249294Sae			IP6STAT_INC(ip6s_toosmall);
3467146985Sthompsa			in6_ifstat_inc(inifp, ifs6_in_hdrerr);
3468146985Sthompsa			goto bad;
3469146985Sthompsa		}
3470147744Sthompsa	} else if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) {
3471146985Sthompsa		struct ifnet *inifp = m->m_pkthdr.rcvif;
3472146985Sthompsa		if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
3473249294Sae			IP6STAT_INC(ip6s_toosmall);
3474146985Sthompsa			in6_ifstat_inc(inifp, ifs6_in_hdrerr);
3475146985Sthompsa			goto bad;
3476146985Sthompsa		}
3477146985Sthompsa	}
3478146985Sthompsa
3479146985Sthompsa	ip6 = mtod(m, struct ip6_hdr *);
3480146985Sthompsa
3481146985Sthompsa	if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
3482249294Sae		IP6STAT_INC(ip6s_badvers);
3483146985Sthompsa		in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
3484146985Sthompsa		goto bad;
3485146985Sthompsa	}
3486146985Sthompsa
3487146985Sthompsa	/* Checks out, proceed */
3488146985Sthompsa	*mp = m;
3489158667Sthompsa	return (0);
3490146985Sthompsa
3491153497Sthompsabad:
3492146985Sthompsa	*mp = m;
3493158667Sthompsa	return (-1);
3494146985Sthompsa}
3495158667Sthompsa#endif /* INET6 */
3496158140Sthompsa
3497158140Sthompsa/*
3498158140Sthompsa * bridge_fragment:
3499158140Sthompsa *
3500306593Skp *	Fragment mbuf chain in multiple packets and prepend ethernet header.
3501158140Sthompsa */
3502158140Sthompsastatic int
3503306593Skpbridge_fragment(struct ifnet *ifp, struct mbuf **mp, struct ether_header *eh,
3504158140Sthompsa    int snap, struct llc *llc)
3505158140Sthompsa{
3506306593Skp	struct mbuf *m = *mp, *nextpkt = NULL, *mprev = NULL, *mcur = NULL;
3507158140Sthompsa	struct ip *ip;
3508158140Sthompsa	int error = -1;
3509158140Sthompsa
3510158140Sthompsa	if (m->m_len < sizeof(struct ip) &&
3511158140Sthompsa	    (m = m_pullup(m, sizeof(struct ip))) == NULL)
3512306593Skp		goto dropit;
3513158140Sthompsa	ip = mtod(m, struct ip *);
3514158140Sthompsa
3515242161Sglebius	m->m_pkthdr.csum_flags |= CSUM_IP;
3516242161Sglebius	error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist);
3517158140Sthompsa	if (error)
3518306593Skp		goto dropit;
3519158140Sthompsa
3520306593Skp	/*
3521306593Skp	 * Walk the chain and re-add the Ethernet header for
3522306593Skp	 * each mbuf packet.
3523306593Skp	 */
3524306593Skp	for (mcur = m; mcur; mcur = mcur->m_nextpkt) {
3525306593Skp		nextpkt = mcur->m_nextpkt;
3526306593Skp		mcur->m_nextpkt = NULL;
3527306593Skp		if (snap) {
3528306593Skp			M_PREPEND(mcur, sizeof(struct llc), M_NOWAIT);
3529306593Skp			if (mcur == NULL) {
3530158140Sthompsa				error = ENOBUFS;
3531306593Skp				if (mprev != NULL)
3532306593Skp					mprev->m_nextpkt = nextpkt;
3533306593Skp				goto dropit;
3534158140Sthompsa			}
3535306593Skp			bcopy(llc, mtod(mcur, caddr_t),sizeof(struct llc));
3536306593Skp		}
3537306593Skp
3538306593Skp		M_PREPEND(mcur, ETHER_HDR_LEN, M_NOWAIT);
3539306593Skp		if (mcur == NULL) {
3540306593Skp			error = ENOBUFS;
3541306593Skp			if (mprev != NULL)
3542306593Skp				mprev->m_nextpkt = nextpkt;
3543306593Skp			goto dropit;
3544306593Skp		}
3545306593Skp		bcopy(eh, mtod(mcur, caddr_t), ETHER_HDR_LEN);
3546306593Skp
3547306593Skp		/*
3548306593Skp		 * The previous two M_PREPEND could have inserted one or two
3549306593Skp		 * mbufs in front so we have to update the previous packet's
3550306593Skp		 * m_nextpkt.
3551306593Skp		 */
3552306593Skp		mcur->m_nextpkt = nextpkt;
3553306593Skp		if (mprev != NULL)
3554306593Skp			mprev->m_nextpkt = mcur;
3555306593Skp		else {
3556306593Skp			/* The first mbuf in the original chain needs to be
3557306593Skp			 * updated. */
3558306593Skp			*mp = mcur;
3559306593Skp		}
3560306593Skp		mprev = mcur;
3561158140Sthompsa	}
3562158140Sthompsa
3563306593Skp	KMOD_IPSTAT_INC(ips_fragmented);
3564158140Sthompsa	return (error);
3565158140Sthompsa
3566306593Skpdropit:
3567306593Skp	for (mcur = *mp; mcur; mcur = m) { /* droping the full packet chain */
3568306593Skp		m = mcur->m_nextpkt;
3569306593Skp		m_freem(mcur);
3570306593Skp	}
3571158140Sthompsa	return (error);
3572158140Sthompsa}
3573234487Sthompsa
3574234487Sthompsastatic void
3575234487Sthompsabridge_linkstate(struct ifnet *ifp)
3576234487Sthompsa{
3577234487Sthompsa	struct bridge_softc *sc = ifp->if_bridge;
3578236916Sthompsa	struct bridge_iflist *bif;
3579234487Sthompsa
3580234487Sthompsa	BRIDGE_LOCK(sc);
3581234487Sthompsa	bif = bridge_lookup_member_if(sc, ifp);
3582234487Sthompsa	if (bif == NULL) {
3583234487Sthompsa		BRIDGE_UNLOCK(sc);
3584234487Sthompsa		return;
3585234487Sthompsa	}
3586236916Sthompsa	bridge_linkcheck(sc);
3587236916Sthompsa	BRIDGE_UNLOCK(sc);
3588236916Sthompsa
3589236916Sthompsa	bstp_linkstate(&bif->bif_stp);
3590236916Sthompsa}
3591236916Sthompsa
3592236916Sthompsastatic void
3593236916Sthompsabridge_linkcheck(struct bridge_softc *sc)
3594236916Sthompsa{
3595236916Sthompsa	struct bridge_iflist *bif;
3596236916Sthompsa	int new_link, hasls;
3597236916Sthompsa
3598236916Sthompsa	BRIDGE_LOCK_ASSERT(sc);
3599234487Sthompsa	new_link = LINK_STATE_DOWN;
3600234487Sthompsa	hasls = 0;
3601234487Sthompsa	/* Our link is considered up if at least one of our ports is active */
3602236916Sthompsa	LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
3603236916Sthompsa		if (bif->bif_ifp->if_capabilities & IFCAP_LINKSTATE)
3604234487Sthompsa			hasls++;
3605236916Sthompsa		if (bif->bif_ifp->if_link_state == LINK_STATE_UP) {
3606234487Sthompsa			new_link = LINK_STATE_UP;
3607234487Sthompsa			break;
3608234487Sthompsa		}
3609234487Sthompsa	}
3610234487Sthompsa	if (!LIST_EMPTY(&sc->sc_iflist) && !hasls) {
3611234487Sthompsa		/* If no interfaces support link-state then we default to up */
3612234487Sthompsa		new_link = LINK_STATE_UP;
3613234487Sthompsa	}
3614234487Sthompsa	if_link_state_change(sc->sc_ifp, new_link);
3615234487Sthompsa}
3616