1ac93838fSSimon Schubert /*
2ac93838fSSimon Schubert * Copyright 2001 Wasabi Systems, Inc.
3ac93838fSSimon Schubert * All rights reserved.
4ac93838fSSimon Schubert *
5ac93838fSSimon Schubert * Written by Jason R. Thorpe for Wasabi Systems, Inc.
6ac93838fSSimon Schubert *
7ac93838fSSimon Schubert * Redistribution and use in source and binary forms, with or without
8ac93838fSSimon Schubert * modification, are permitted provided that the following conditions
9ac93838fSSimon Schubert * are met:
10ac93838fSSimon Schubert * 1. Redistributions of source code must retain the above copyright
11ac93838fSSimon Schubert * notice, this list of conditions and the following disclaimer.
12ac93838fSSimon Schubert * 2. Redistributions in binary form must reproduce the above copyright
13ac93838fSSimon Schubert * notice, this list of conditions and the following disclaimer in the
14ac93838fSSimon Schubert * documentation and/or other materials provided with the distribution.
15ac93838fSSimon Schubert * 3. All advertising materials mentioning features or use of this software
16ac93838fSSimon Schubert * must display the following acknowledgement:
17ac93838fSSimon Schubert * This product includes software developed for the NetBSD Project by
18ac93838fSSimon Schubert * Wasabi Systems, Inc.
19ac93838fSSimon Schubert * 4. The name of Wasabi Systems, Inc. may not be used to endorse
20ac93838fSSimon Schubert * or promote products derived from this software without specific prior
21ac93838fSSimon Schubert * written permission.
22ac93838fSSimon Schubert *
23ac93838fSSimon Schubert * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
24ac93838fSSimon Schubert * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25ac93838fSSimon Schubert * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26ac93838fSSimon Schubert * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
27ac93838fSSimon Schubert * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28ac93838fSSimon Schubert * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29ac93838fSSimon Schubert * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30ac93838fSSimon Schubert * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31ac93838fSSimon Schubert * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32ac93838fSSimon Schubert * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33ac93838fSSimon Schubert * POSSIBILITY OF SUCH DAMAGE.
34ac93838fSSimon Schubert */
35ac93838fSSimon Schubert
36ac93838fSSimon Schubert /*
37ac93838fSSimon Schubert * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
38ac93838fSSimon Schubert * All rights reserved.
39ac93838fSSimon Schubert *
40ac93838fSSimon Schubert * Redistribution and use in source and binary forms, with or without
41ac93838fSSimon Schubert * modification, are permitted provided that the following conditions
42ac93838fSSimon Schubert * are met:
43ac93838fSSimon Schubert * 1. Redistributions of source code must retain the above copyright
44ac93838fSSimon Schubert * notice, this list of conditions and the following disclaimer.
45ac93838fSSimon Schubert * 2. Redistributions in binary form must reproduce the above copyright
46ac93838fSSimon Schubert * notice, this list of conditions and the following disclaimer in the
47ac93838fSSimon Schubert * documentation and/or other materials provided with the distribution.
48ac93838fSSimon Schubert * 3. All advertising materials mentioning features or use of this software
49ac93838fSSimon Schubert * must display the following acknowledgement:
50ac93838fSSimon Schubert * This product includes software developed by Jason L. Wright
51ac93838fSSimon Schubert * 4. The name of the author may not be used to endorse or promote products
52ac93838fSSimon Schubert * derived from this software without specific prior written permission.
53ac93838fSSimon Schubert *
54ac93838fSSimon Schubert * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
55ac93838fSSimon Schubert * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
56ac93838fSSimon Schubert * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
57ac93838fSSimon Schubert * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
58ac93838fSSimon Schubert * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
59ac93838fSSimon Schubert * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
60ac93838fSSimon Schubert * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61ac93838fSSimon Schubert * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
62ac93838fSSimon Schubert * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
63ac93838fSSimon Schubert * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
64ac93838fSSimon Schubert * POSSIBILITY OF SUCH DAMAGE.
65ac93838fSSimon Schubert *
66ac93838fSSimon Schubert * $OpenBSD: if_bridge.c,v 1.60 2001/06/15 03:38:33 itojun Exp $
67ac93838fSSimon Schubert * $NetBSD: if_bridge.c,v 1.31 2005/06/01 19:45:34 jdc Exp $
68ac93838fSSimon Schubert * $FreeBSD: src/sys/net/if_bridge.c,v 1.26 2005/10/13 23:05:55 thompsa Exp $
69ac93838fSSimon Schubert */
70ac93838fSSimon Schubert
71ac93838fSSimon Schubert /*
72ac93838fSSimon Schubert * Network interface bridge support.
73ac93838fSSimon Schubert *
74ac93838fSSimon Schubert * TODO:
75ac93838fSSimon Schubert *
76ac93838fSSimon Schubert * - Currently only supports Ethernet-like interfaces (Ethernet,
77ac93838fSSimon Schubert * 802.11, VLANs on Ethernet, etc.) Figure out a nice way
78ac93838fSSimon Schubert * to bridge other types of interfaces (FDDI-FDDI, and maybe
79ac93838fSSimon Schubert * consider heterogenous bridges).
804394693cSSepherosa Ziehau *
814394693cSSepherosa Ziehau *
824394693cSSepherosa Ziehau * Bridge's route information is duplicated to each CPUs:
834394693cSSepherosa Ziehau *
844394693cSSepherosa Ziehau * CPU0 CPU1 CPU2 CPU3
854394693cSSepherosa Ziehau * +-----------+ +-----------+ +-----------+ +-----------+
864394693cSSepherosa Ziehau * | rtnode | | rtnode | | rtnode | | rtnode |
874394693cSSepherosa Ziehau * | | | | | | | |
884394693cSSepherosa Ziehau * | dst eaddr | | dst eaddr | | dst eaddr | | dst eaddr |
894394693cSSepherosa Ziehau * +-----------+ +-----------+ +-----------+ +-----------+
904394693cSSepherosa Ziehau * | | | |
914394693cSSepherosa Ziehau * | | | |
924394693cSSepherosa Ziehau * | | +----------+ | |
934394693cSSepherosa Ziehau * | | | rtinfo | | |
944394693cSSepherosa Ziehau * | +---->| |<---+ |
954394693cSSepherosa Ziehau * | | flags | |
964394693cSSepherosa Ziehau * +-------------->| timeout |<-------------+
974394693cSSepherosa Ziehau * | dst_ifp |
984394693cSSepherosa Ziehau * +----------+
994394693cSSepherosa Ziehau *
1004394693cSSepherosa Ziehau * We choose to put timeout and dst_ifp into shared part, so updating
1014394693cSSepherosa Ziehau * them will be cheaper than using message forwarding. Also there is
1024394693cSSepherosa Ziehau * not need to use spinlock to protect the updating: timeout and dst_ifp
1034394693cSSepherosa Ziehau * is not related and specific field's updating order has no importance.
1044394693cSSepherosa Ziehau * The cache pollution by the share part should not be heavy: in a stable
1054394693cSSepherosa Ziehau * setup, dst_ifp probably will be not changed in rtnode's life time,
1064394693cSSepherosa Ziehau * while timeout is refreshed once per second; most of the time, timeout
1074394693cSSepherosa Ziehau * and dst_ifp are read-only accessed.
1084394693cSSepherosa Ziehau *
1094394693cSSepherosa Ziehau *
1104394693cSSepherosa Ziehau * Bridge route information installation on bridge_input path:
1114394693cSSepherosa Ziehau *
1124394693cSSepherosa Ziehau * CPU0 CPU1 CPU2 CPU3
1134394693cSSepherosa Ziehau *
1148fc51cdeSSepherosa Ziehau * netisr2
1154394693cSSepherosa Ziehau * |
1164394693cSSepherosa Ziehau * alloc nmsg
1174394693cSSepherosa Ziehau * snd nmsg |
1184394693cSSepherosa Ziehau * w/o rtinfo |
1198fc51cdeSSepherosa Ziehau * netisr0<-----------------------+
1204394693cSSepherosa Ziehau * | :
1214394693cSSepherosa Ziehau * lookup dst :
1224394693cSSepherosa Ziehau * rtnode exists?(Y)free nmsg :
1234394693cSSepherosa Ziehau * |(N) :
1248fc51cdeSSepherosa Ziehau * | :
1258fc51cdeSSepherosa Ziehau * alloc rtinfo :
1268fc51cdeSSepherosa Ziehau * alloc rtnode :
1278fc51cdeSSepherosa Ziehau * install rtnode :
1288fc51cdeSSepherosa Ziehau * | :
1298fc51cdeSSepherosa Ziehau * +---------->netisr1 :
1308fc51cdeSSepherosa Ziehau * : fwd nmsg | :
1318fc51cdeSSepherosa Ziehau * : w/ rtinfo | :
1328fc51cdeSSepherosa Ziehau * : | :
1338fc51cdeSSepherosa Ziehau * : | :
1348fc51cdeSSepherosa Ziehau * alloc rtnode :
1358fc51cdeSSepherosa Ziehau * (w/ nmsg's rtinfo) :
1368fc51cdeSSepherosa Ziehau * install rtnode :
1378fc51cdeSSepherosa Ziehau * | :
1388fc51cdeSSepherosa Ziehau * +----------->|
1394394693cSSepherosa Ziehau * : fwd nmsg |
1404394693cSSepherosa Ziehau * : w/ rtinfo |
1414394693cSSepherosa Ziehau * : |
1428fc51cdeSSepherosa Ziehau * : same as netisr1
1434394693cSSepherosa Ziehau * |
1448fc51cdeSSepherosa Ziehau * +---------->netisr3
1454394693cSSepherosa Ziehau * : fwd nmsg |
1464394693cSSepherosa Ziehau * : w/ rtinfo |
1474394693cSSepherosa Ziehau * : |
1488fc51cdeSSepherosa Ziehau * : same as netisr1
1494394693cSSepherosa Ziehau * free nmsg
1504394693cSSepherosa Ziehau * :
1514394693cSSepherosa Ziehau * :
1524394693cSSepherosa Ziehau *
1538fc51cdeSSepherosa Ziehau * The netmsgs forwarded between netisr2 are allocated with
1548fc51cdeSSepherosa Ziehau * (M_WAITOK|M_NULLOK), so it will not fail under most cases (route
1558fc51cdeSSepherosa Ziehau * information is too precious to be not installed :). Since multiple
1568fc51cdeSSepherosa Ziehau * netisrs may try to install route information for the same dst eaddr,
1578fc51cdeSSepherosa Ziehau * we look up route information in netisr0. However, this looking up
1588fc51cdeSSepherosa Ziehau * only need to be performed on netisr0, which is the start point of
1598fc51cdeSSepherosa Ziehau * the route information installation process.
1604394693cSSepherosa Ziehau *
1614394693cSSepherosa Ziehau *
1624394693cSSepherosa Ziehau * Bridge route information deleting/flushing:
1634394693cSSepherosa Ziehau *
1644394693cSSepherosa Ziehau * CPU0 CPU1 CPU2 CPU3
1654394693cSSepherosa Ziehau *
1664394693cSSepherosa Ziehau * netisr0
1674394693cSSepherosa Ziehau * |
1684394693cSSepherosa Ziehau * find suitable rtnodes,
1694394693cSSepherosa Ziehau * mark their rtinfo dead
1704394693cSSepherosa Ziehau * |
1718fc51cdeSSepherosa Ziehau * | domsg <-------------------------------------------+
1728fc51cdeSSepherosa Ziehau * : delete rtnodes | replymsg
1738fc51cdeSSepherosa Ziehau * : w/ dead rtinfo |
1748fc51cdeSSepherosa Ziehau * : |
1758fc51cdeSSepherosa Ziehau * : fwdmsg fwdmsg fwdmsg |
1768fc51cdeSSepherosa Ziehau * :----------> netisr1 --------> netisr2 --------> netisr3
1778fc51cdeSSepherosa Ziehau * delete rtnodes delete rtnodes delete rtnodes
1788fc51cdeSSepherosa Ziehau * w/ dead rtinfo w/ dead rtinfo w/ dead rtinfo
1794394693cSSepherosa Ziehau * free dead rtinfos
1804394693cSSepherosa Ziehau *
1814394693cSSepherosa Ziehau * All deleting/flushing operations are serialized by netisr0, so each
1824394693cSSepherosa Ziehau * operation only reaps the route information marked dead by itself.
1834394693cSSepherosa Ziehau *
1844394693cSSepherosa Ziehau *
1854394693cSSepherosa Ziehau * Bridge route information adding/deleting/flushing:
1864394693cSSepherosa Ziehau * Since all operation is serialized by the fixed message flow between
1878fc51cdeSSepherosa Ziehau * netisrs, it is not possible to create corrupted per-cpu route
1884394693cSSepherosa Ziehau * information.
18980ed9a26SSepherosa Ziehau *
19080ed9a26SSepherosa Ziehau *
19180ed9a26SSepherosa Ziehau *
1928fc51cdeSSepherosa Ziehau * XXX This no longer applies.
19380ed9a26SSepherosa Ziehau * Percpu member interface list iteration with blocking operation:
19480ed9a26SSepherosa Ziehau * Since one bridge could only delete one member interface at a time and
19580ed9a26SSepherosa Ziehau * the deleted member interface is not freed after netmsg_service_sync(),
19680ed9a26SSepherosa Ziehau * following way is used to make sure that even if the certain member
19780ed9a26SSepherosa Ziehau * interface is ripped from the percpu list during the blocking operation,
19880ed9a26SSepherosa Ziehau * the iteration still could keep going:
19980ed9a26SSepherosa Ziehau *
20070d9a675SMatthew Dillon * TAILQ_FOREACH_MUTABLE(bif, sc->sc_iflists[mycpuid], bif_next, nbif) {
20180ed9a26SSepherosa Ziehau * blocking operation;
20280ed9a26SSepherosa Ziehau * blocking operation;
20380ed9a26SSepherosa Ziehau * ...
20480ed9a26SSepherosa Ziehau * ...
20580ed9a26SSepherosa Ziehau * if (nbif != NULL && !nbif->bif_onlist) {
20680ed9a26SSepherosa Ziehau * KKASSERT(bif->bif_onlist);
20770d9a675SMatthew Dillon * nbif = TAILQ_NEXT(bif, bif_next);
20880ed9a26SSepherosa Ziehau * }
20980ed9a26SSepherosa Ziehau * }
21080ed9a26SSepherosa Ziehau *
21180ed9a26SSepherosa Ziehau * As mentioned above only one member interface could be unlinked from the
21280ed9a26SSepherosa Ziehau * percpu member interface list, so either bif or nbif may be not on the list,
21380ed9a26SSepherosa Ziehau * but _not_ both. To keep the list iteration, we don't care about bif, but
21480ed9a26SSepherosa Ziehau * only nbif. Since removed member interface will only be freed after we
21580ed9a26SSepherosa Ziehau * finish our work, it is safe to access any field in an unlinked bif (here
21680ed9a26SSepherosa Ziehau * bif_onlist). If nbif is no longer on the list, then bif must be on the
21780ed9a26SSepherosa Ziehau * list, so we change nbif to the next element of bif and keep going.
218ac93838fSSimon Schubert */
219ac93838fSSimon Schubert
220ac93838fSSimon Schubert #include "opt_inet.h"
221ac93838fSSimon Schubert #include "opt_inet6.h"
222ac93838fSSimon Schubert
223ac93838fSSimon Schubert #include <sys/param.h>
224ac93838fSSimon Schubert #include <sys/mbuf.h>
225ac93838fSSimon Schubert #include <sys/malloc.h>
226ac93838fSSimon Schubert #include <sys/protosw.h>
227ac93838fSSimon Schubert #include <sys/systm.h>
228ac93838fSSimon Schubert #include <sys/time.h>
229ac93838fSSimon Schubert #include <sys/socket.h> /* for net/if.h */
230ac93838fSSimon Schubert #include <sys/sockio.h>
231ac93838fSSimon Schubert #include <sys/ctype.h> /* string functions */
232ac93838fSSimon Schubert #include <sys/kernel.h>
233ac93838fSSimon Schubert #include <sys/random.h>
234ac93838fSSimon Schubert #include <sys/sysctl.h>
235ac93838fSSimon Schubert #include <sys/module.h>
236ac93838fSSimon Schubert #include <sys/proc.h>
2372b3f93eaSMatthew Dillon #include <sys/caps.h>
238ac93838fSSimon Schubert #include <sys/lock.h>
239ac93838fSSimon Schubert #include <sys/thread.h>
240ac93838fSSimon Schubert #include <sys/thread2.h>
241ac93838fSSimon Schubert #include <sys/mpipe.h>
242ac93838fSSimon Schubert
243ac93838fSSimon Schubert #include <net/bpf.h>
244ac93838fSSimon Schubert #include <net/if.h>
245ac93838fSSimon Schubert #include <net/if_dl.h>
246ac93838fSSimon Schubert #include <net/if_types.h>
247ac93838fSSimon Schubert #include <net/if_var.h>
248ac93838fSSimon Schubert #include <net/pfil.h>
249ac93838fSSimon Schubert #include <net/ifq_var.h>
25065a24520SSepherosa Ziehau #include <net/if_clone.h>
251ac93838fSSimon Schubert
252ac93838fSSimon Schubert #include <netinet/in.h> /* for struct arpcom */
253ac93838fSSimon Schubert #include <netinet/in_systm.h>
254ac93838fSSimon Schubert #include <netinet/in_var.h>
255ac93838fSSimon Schubert #include <netinet/ip.h>
256ac93838fSSimon Schubert #include <netinet/ip_var.h>
257ac93838fSSimon Schubert #ifdef INET6
258ac93838fSSimon Schubert #include <netinet/ip6.h>
259ac93838fSSimon Schubert #include <netinet6/ip6_var.h>
260ac93838fSSimon Schubert #endif
261ac93838fSSimon Schubert #include <netinet/if_ether.h> /* for struct arpcom */
262ac93838fSSimon Schubert #include <net/bridge/if_bridgevar.h>
263ac93838fSSimon Schubert #include <net/if_llc.h>
264ecd27a4cSSepherosa Ziehau #include <net/netmsg2.h>
2655337421cSSepherosa Ziehau #include <net/netisr2.h>
266ac93838fSSimon Schubert
267ac93838fSSimon Schubert #include <net/route.h>
268ac93838fSSimon Schubert #include <sys/in_cksum.h>
269ac93838fSSimon Schubert
270ac93838fSSimon Schubert /*
271ac93838fSSimon Schubert * Size of the route hash table. Must be a power of two.
272ac93838fSSimon Schubert */
273ac93838fSSimon Schubert #ifndef BRIDGE_RTHASH_SIZE
274ac93838fSSimon Schubert #define BRIDGE_RTHASH_SIZE 1024
275ac93838fSSimon Schubert #endif
276ac93838fSSimon Schubert
277ac93838fSSimon Schubert #define BRIDGE_RTHASH_MASK (BRIDGE_RTHASH_SIZE - 1)
278ac93838fSSimon Schubert
279ac93838fSSimon Schubert /*
280ac93838fSSimon Schubert * Maximum number of addresses to cache.
281ac93838fSSimon Schubert */
282ac93838fSSimon Schubert #ifndef BRIDGE_RTABLE_MAX
2839c3d6b2bSMatthew Dillon #define BRIDGE_RTABLE_MAX 4096
284ac93838fSSimon Schubert #endif
285ac93838fSSimon Schubert
286ac93838fSSimon Schubert /*
287ac93838fSSimon Schubert * Spanning tree defaults.
288ac93838fSSimon Schubert */
289ac93838fSSimon Schubert #define BSTP_DEFAULT_MAX_AGE (20 * 256)
290ac93838fSSimon Schubert #define BSTP_DEFAULT_HELLO_TIME (2 * 256)
291ac93838fSSimon Schubert #define BSTP_DEFAULT_FORWARD_DELAY (15 * 256)
292ac93838fSSimon Schubert #define BSTP_DEFAULT_HOLD_TIME (1 * 256)
293ac93838fSSimon Schubert #define BSTP_DEFAULT_BRIDGE_PRIORITY 0x8000
294ac93838fSSimon Schubert #define BSTP_DEFAULT_PORT_PRIORITY 0x80
295ac93838fSSimon Schubert #define BSTP_DEFAULT_PATH_COST 55
296ac93838fSSimon Schubert
297ac93838fSSimon Schubert /*
298ac93838fSSimon Schubert * Timeout (in seconds) for entries learned dynamically.
299ac93838fSSimon Schubert */
300ac93838fSSimon Schubert #ifndef BRIDGE_RTABLE_TIMEOUT
301ac93838fSSimon Schubert #define BRIDGE_RTABLE_TIMEOUT (20 * 60) /* same as ARP */
302ac93838fSSimon Schubert #endif
303ac93838fSSimon Schubert
304ac93838fSSimon Schubert /*
305ac93838fSSimon Schubert * Number of seconds between walks of the route list.
306ac93838fSSimon Schubert */
307ac93838fSSimon Schubert #ifndef BRIDGE_RTABLE_PRUNE_PERIOD
308ac93838fSSimon Schubert #define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60)
309ac93838fSSimon Schubert #endif
310ac93838fSSimon Schubert
311d217f5e5SScott Ullrich /*
312d217f5e5SScott Ullrich * List of capabilities to mask on the member interface.
313d217f5e5SScott Ullrich */
3141c070daaSSepherosa Ziehau #define BRIDGE_IFCAPS_MASK (IFCAP_TXCSUM | IFCAP_TSO)
315d217f5e5SScott Ullrich
3164394693cSSepherosa Ziehau typedef int (*bridge_ctl_t)(struct bridge_softc *, void *);
3174394693cSSepherosa Ziehau
3184394693cSSepherosa Ziehau struct netmsg_brctl {
319002c1265SMatthew Dillon struct netmsg_base base;
3204394693cSSepherosa Ziehau bridge_ctl_t bc_func;
3214394693cSSepherosa Ziehau struct bridge_softc *bc_sc;
3224394693cSSepherosa Ziehau void *bc_arg;
3234394693cSSepherosa Ziehau };
3244394693cSSepherosa Ziehau
3254394693cSSepherosa Ziehau struct netmsg_brsaddr {
326002c1265SMatthew Dillon struct netmsg_base base;
3274394693cSSepherosa Ziehau struct bridge_softc *br_softc;
3284394693cSSepherosa Ziehau struct ifnet *br_dst_if;
3294394693cSSepherosa Ziehau struct bridge_rtinfo *br_rtinfo;
3304394693cSSepherosa Ziehau int br_setflags;
3314394693cSSepherosa Ziehau uint8_t br_dst[ETHER_ADDR_LEN];
3324394693cSSepherosa Ziehau uint8_t br_flags;
3334394693cSSepherosa Ziehau };
3344394693cSSepherosa Ziehau
3358f7b13efSSepherosa Ziehau struct netmsg_braddbif {
336002c1265SMatthew Dillon struct netmsg_base base;
3378f7b13efSSepherosa Ziehau struct bridge_softc *br_softc;
3388f7b13efSSepherosa Ziehau struct bridge_ifinfo *br_bif_info;
3398f7b13efSSepherosa Ziehau struct ifnet *br_bif_ifp;
3408f7b13efSSepherosa Ziehau };
3418f7b13efSSepherosa Ziehau
3428f7b13efSSepherosa Ziehau struct netmsg_brdelbif {
343002c1265SMatthew Dillon struct netmsg_base base;
3448f7b13efSSepherosa Ziehau struct bridge_softc *br_softc;
3458f7b13efSSepherosa Ziehau struct bridge_ifinfo *br_bif_info;
3468f7b13efSSepherosa Ziehau struct bridge_iflist_head *br_bif_list;
3478f7b13efSSepherosa Ziehau };
3488f7b13efSSepherosa Ziehau
3498f7b13efSSepherosa Ziehau struct netmsg_brsflags {
350002c1265SMatthew Dillon struct netmsg_base base;
3518f7b13efSSepherosa Ziehau struct bridge_softc *br_softc;
3528f7b13efSSepherosa Ziehau struct bridge_ifinfo *br_bif_info;
3538f7b13efSSepherosa Ziehau uint32_t br_bif_flags;
3548f7b13efSSepherosa Ziehau };
3558f7b13efSSepherosa Ziehau
356d217f5e5SScott Ullrich eventhandler_tag bridge_detach_cookie = NULL;
357d217f5e5SScott Ullrich
358ac93838fSSimon Schubert extern struct mbuf *(*bridge_input_p)(struct ifnet *, struct mbuf *);
359eb366364SSepherosa Ziehau extern int (*bridge_output_p)(struct ifnet *, struct mbuf *);
360ac93838fSSimon Schubert extern void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
36170d9a675SMatthew Dillon extern struct ifnet *(*bridge_interface_p)(void *if_bridge);
362ac93838fSSimon Schubert
363d217f5e5SScott Ullrich static int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD;
364ac93838fSSimon Schubert
365bb54c3a2SAaron LI static int bridge_clone_create(struct if_clone *, int, caddr_t, caddr_t);
366a7e9152eSSepherosa Ziehau static int bridge_clone_destroy(struct ifnet *);
367ac93838fSSimon Schubert
368d217f5e5SScott Ullrich static int bridge_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
3698f7b13efSSepherosa Ziehau static void bridge_mutecaps(struct bridge_ifinfo *, struct ifnet *, int);
3708f7b13efSSepherosa Ziehau static void bridge_ifdetach(void *, struct ifnet *);
371ac93838fSSimon Schubert static void bridge_init(void *);
37270d9a675SMatthew Dillon static int bridge_from_us(struct bridge_softc *, struct ether_header *);
373867cc45aSSepherosa Ziehau static void bridge_stop(struct ifnet *);
374f0a26983SSepherosa Ziehau static void bridge_start(struct ifnet *, struct ifaltq_subque *);
375d217f5e5SScott Ullrich static struct mbuf *bridge_input(struct ifnet *, struct mbuf *);
376eb366364SSepherosa Ziehau static int bridge_output(struct ifnet *, struct mbuf *);
37770d9a675SMatthew Dillon static struct ifnet *bridge_interface(void *if_bridge);
378ac93838fSSimon Schubert
379d217f5e5SScott Ullrich static void bridge_forward(struct bridge_softc *, struct mbuf *m);
380ac93838fSSimon Schubert
381002c1265SMatthew Dillon static void bridge_timer_handler(netmsg_t);
382d217f5e5SScott Ullrich static void bridge_timer(void *);
383ac93838fSSimon Schubert
384137aa7b3SSepherosa Ziehau static void bridge_start_bcast(struct bridge_softc *, struct mbuf *);
385d217f5e5SScott Ullrich static void bridge_broadcast(struct bridge_softc *, struct ifnet *,
386137aa7b3SSepherosa Ziehau struct mbuf *);
387d217f5e5SScott Ullrich static void bridge_span(struct bridge_softc *, struct mbuf *);
388ac93838fSSimon Schubert
389d217f5e5SScott Ullrich static int bridge_rtupdate(struct bridge_softc *, const uint8_t *,
3904394693cSSepherosa Ziehau struct ifnet *, uint8_t);
391d217f5e5SScott Ullrich static struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *);
3924394693cSSepherosa Ziehau static void bridge_rtreap(struct bridge_softc *);
39330ced003SSepherosa Ziehau static void bridge_rtreap_async(struct bridge_softc *);
394d217f5e5SScott Ullrich static void bridge_rttrim(struct bridge_softc *);
3954394693cSSepherosa Ziehau static int bridge_rtage_finddead(struct bridge_softc *);
396d217f5e5SScott Ullrich static void bridge_rtage(struct bridge_softc *);
397d217f5e5SScott Ullrich static void bridge_rtflush(struct bridge_softc *, int);
398d217f5e5SScott Ullrich static int bridge_rtdaddr(struct bridge_softc *, const uint8_t *);
3994394693cSSepherosa Ziehau static int bridge_rtsaddr(struct bridge_softc *, const uint8_t *,
4004394693cSSepherosa Ziehau struct ifnet *, uint8_t);
4014394693cSSepherosa Ziehau static void bridge_rtmsg_sync(struct bridge_softc *sc);
402002c1265SMatthew Dillon static void bridge_rtreap_handler(netmsg_t);
403002c1265SMatthew Dillon static void bridge_rtinstall_handler(netmsg_t);
4044394693cSSepherosa Ziehau static int bridge_rtinstall_oncpu(struct bridge_softc *, const uint8_t *,
4054394693cSSepherosa Ziehau struct ifnet *, int, uint8_t, struct bridge_rtinfo **);
406ac93838fSSimon Schubert
4074394693cSSepherosa Ziehau static void bridge_rtable_init(struct bridge_softc *);
408d217f5e5SScott Ullrich static void bridge_rtable_fini(struct bridge_softc *);
409ac93838fSSimon Schubert
410d217f5e5SScott Ullrich static int bridge_rtnode_addr_cmp(const uint8_t *, const uint8_t *);
411d217f5e5SScott Ullrich static struct bridge_rtnode *bridge_rtnode_lookup(struct bridge_softc *,
412ac93838fSSimon Schubert const uint8_t *);
4134394693cSSepherosa Ziehau static void bridge_rtnode_insert(struct bridge_softc *,
414d217f5e5SScott Ullrich struct bridge_rtnode *);
415d217f5e5SScott Ullrich static void bridge_rtnode_destroy(struct bridge_softc *,
416d217f5e5SScott Ullrich struct bridge_rtnode *);
417ac93838fSSimon Schubert
418d217f5e5SScott Ullrich static struct bridge_iflist *bridge_lookup_member(struct bridge_softc *,
419ac93838fSSimon Schubert const char *name);
420d217f5e5SScott Ullrich static struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *,
421ac93838fSSimon Schubert struct ifnet *ifp);
4228f7b13efSSepherosa Ziehau static struct bridge_iflist *bridge_lookup_member_ifinfo(struct bridge_softc *,
4238f7b13efSSepherosa Ziehau struct bridge_ifinfo *);
424d217f5e5SScott Ullrich static void bridge_delete_member(struct bridge_softc *,
425d217f5e5SScott Ullrich struct bridge_iflist *, int);
426d217f5e5SScott Ullrich static void bridge_delete_span(struct bridge_softc *,
427d217f5e5SScott Ullrich struct bridge_iflist *);
428ac93838fSSimon Schubert
4290b326f64SSepherosa Ziehau static int bridge_control(struct bridge_softc *, u_long,
4300b326f64SSepherosa Ziehau bridge_ctl_t, void *);
431d71129d9SSepherosa Ziehau static int bridge_ioctl_init(struct bridge_softc *, void *);
432d71129d9SSepherosa Ziehau static int bridge_ioctl_stop(struct bridge_softc *, void *);
433d217f5e5SScott Ullrich static int bridge_ioctl_add(struct bridge_softc *, void *);
434d217f5e5SScott Ullrich static int bridge_ioctl_del(struct bridge_softc *, void *);
43570d9a675SMatthew Dillon static void bridge_ioctl_fillflags(struct bridge_softc *sc,
43670d9a675SMatthew Dillon struct bridge_iflist *bif, struct ifbreq *req);
437d217f5e5SScott Ullrich static int bridge_ioctl_gifflags(struct bridge_softc *, void *);
438d217f5e5SScott Ullrich static int bridge_ioctl_sifflags(struct bridge_softc *, void *);
439d217f5e5SScott Ullrich static int bridge_ioctl_scache(struct bridge_softc *, void *);
440d217f5e5SScott Ullrich static int bridge_ioctl_gcache(struct bridge_softc *, void *);
441d217f5e5SScott Ullrich static int bridge_ioctl_gifs(struct bridge_softc *, void *);
442d217f5e5SScott Ullrich static int bridge_ioctl_rts(struct bridge_softc *, void *);
443d217f5e5SScott Ullrich static int bridge_ioctl_saddr(struct bridge_softc *, void *);
444d217f5e5SScott Ullrich static int bridge_ioctl_sto(struct bridge_softc *, void *);
445d217f5e5SScott Ullrich static int bridge_ioctl_gto(struct bridge_softc *, void *);
446d217f5e5SScott Ullrich static int bridge_ioctl_daddr(struct bridge_softc *, void *);
447d217f5e5SScott Ullrich static int bridge_ioctl_flush(struct bridge_softc *, void *);
448d217f5e5SScott Ullrich static int bridge_ioctl_gpri(struct bridge_softc *, void *);
449d217f5e5SScott Ullrich static int bridge_ioctl_spri(struct bridge_softc *, void *);
4509b42fdc9SMatthew Dillon static int bridge_ioctl_reinit(struct bridge_softc *, void *);
451d217f5e5SScott Ullrich static int bridge_ioctl_ght(struct bridge_softc *, void *);
452d217f5e5SScott Ullrich static int bridge_ioctl_sht(struct bridge_softc *, void *);
453d217f5e5SScott Ullrich static int bridge_ioctl_gfd(struct bridge_softc *, void *);
454d217f5e5SScott Ullrich static int bridge_ioctl_sfd(struct bridge_softc *, void *);
455d217f5e5SScott Ullrich static int bridge_ioctl_gma(struct bridge_softc *, void *);
456d217f5e5SScott Ullrich static int bridge_ioctl_sma(struct bridge_softc *, void *);
457d217f5e5SScott Ullrich static int bridge_ioctl_sifprio(struct bridge_softc *, void *);
458d217f5e5SScott Ullrich static int bridge_ioctl_sifcost(struct bridge_softc *, void *);
459d217f5e5SScott Ullrich static int bridge_ioctl_addspan(struct bridge_softc *, void *);
460d217f5e5SScott Ullrich static int bridge_ioctl_delspan(struct bridge_softc *, void *);
4611e858374SMatthew Dillon static int bridge_ioctl_sifbondwght(struct bridge_softc *, void *);
462d217f5e5SScott Ullrich static int bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *,
463d217f5e5SScott Ullrich int);
464ac93838fSSimon Schubert static int bridge_ip_checkbasic(struct mbuf **mp);
465ac93838fSSimon Schubert #ifdef INET6
466ac93838fSSimon Schubert static int bridge_ip6_checkbasic(struct mbuf **mp);
467ac93838fSSimon Schubert #endif /* INET6 */
468d217f5e5SScott Ullrich static int bridge_fragment(struct ifnet *, struct mbuf *,
469d217f5e5SScott Ullrich struct ether_header *, int, struct llc *);
470002c1265SMatthew Dillon static void bridge_enqueue_handler(netmsg_t);
47170d9a675SMatthew Dillon static void bridge_handoff(struct bridge_softc *, struct ifnet *,
47270d9a675SMatthew Dillon struct mbuf *, int);
473ac93838fSSimon Schubert
474002c1265SMatthew Dillon static void bridge_del_bif_handler(netmsg_t);
475002c1265SMatthew Dillon static void bridge_add_bif_handler(netmsg_t);
4768f7b13efSSepherosa Ziehau static void bridge_del_bif(struct bridge_softc *, struct bridge_ifinfo *,
4778f7b13efSSepherosa Ziehau struct bridge_iflist_head *);
4788f7b13efSSepherosa Ziehau static void bridge_add_bif(struct bridge_softc *, struct bridge_ifinfo *,
4798f7b13efSSepherosa Ziehau struct ifnet *);
4808f7b13efSSepherosa Ziehau
481ac93838fSSimon Schubert SYSCTL_DECL(_net_link);
482ac93838fSSimon Schubert SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW, 0, "Bridge");
483ac93838fSSimon Schubert
484d217f5e5SScott Ullrich static int pfil_onlyip = 1; /* only pass IP[46] packets when pfil is enabled */
485ac93838fSSimon Schubert static int pfil_bridge = 1; /* run pfil hooks on the bridge interface */
486ac93838fSSimon Schubert static int pfil_member = 1; /* run pfil hooks on the member interface */
48770d9a675SMatthew Dillon static int bridge_debug;
488d217f5e5SScott Ullrich SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_onlyip, CTLFLAG_RW,
489d217f5e5SScott Ullrich &pfil_onlyip, 0, "Only pass IP packets when pfil is enabled");
490ac93838fSSimon Schubert SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_bridge, CTLFLAG_RW,
491ac93838fSSimon Schubert &pfil_bridge, 0, "Packet filter on the bridge interface");
492ac93838fSSimon Schubert SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_member, CTLFLAG_RW,
493ac93838fSSimon Schubert &pfil_member, 0, "Packet filter on the member interface");
49470d9a675SMatthew Dillon SYSCTL_INT(_net_link_bridge, OID_AUTO, debug, CTLFLAG_RW,
49570d9a675SMatthew Dillon &bridge_debug, 0, "Bridge debug mode");
496ac93838fSSimon Schubert
4972d4d3c93SSepherosa Ziehau struct bridge_control_arg {
4982d4d3c93SSepherosa Ziehau union {
4992d4d3c93SSepherosa Ziehau struct ifbreq ifbreq;
5002d4d3c93SSepherosa Ziehau struct ifbifconf ifbifconf;
5012d4d3c93SSepherosa Ziehau struct ifbareq ifbareq;
5022d4d3c93SSepherosa Ziehau struct ifbaconf ifbaconf;
5032d4d3c93SSepherosa Ziehau struct ifbrparam ifbrparam;
5042d4d3c93SSepherosa Ziehau } bca_u;
5052d4d3c93SSepherosa Ziehau int bca_len;
5062d4d3c93SSepherosa Ziehau void *bca_uptr;
5072d4d3c93SSepherosa Ziehau void *bca_kptr;
5082d4d3c93SSepherosa Ziehau };
5092d4d3c93SSepherosa Ziehau
510ac93838fSSimon Schubert struct bridge_control {
51123cf9e67SSepherosa Ziehau bridge_ctl_t bc_func;
512ac93838fSSimon Schubert int bc_argsize;
513ac93838fSSimon Schubert int bc_flags;
514ac93838fSSimon Schubert };
515ac93838fSSimon Schubert
516ac93838fSSimon Schubert #define BC_F_COPYIN 0x01 /* copy arguments in */
517ac93838fSSimon Schubert #define BC_F_COPYOUT 0x02 /* copy arguments out */
518ac93838fSSimon Schubert #define BC_F_SUSER 0x04 /* do super-user check */
519ac93838fSSimon Schubert
520ac93838fSSimon Schubert const struct bridge_control bridge_control_table[] = {
521ac93838fSSimon Schubert { bridge_ioctl_add, sizeof(struct ifbreq),
522ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
523ac93838fSSimon Schubert { bridge_ioctl_del, sizeof(struct ifbreq),
524ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
525ac93838fSSimon Schubert
526ac93838fSSimon Schubert { bridge_ioctl_gifflags, sizeof(struct ifbreq),
527ac93838fSSimon Schubert BC_F_COPYIN|BC_F_COPYOUT },
528ac93838fSSimon Schubert { bridge_ioctl_sifflags, sizeof(struct ifbreq),
529ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
530ac93838fSSimon Schubert
531ac93838fSSimon Schubert { bridge_ioctl_scache, sizeof(struct ifbrparam),
532ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
533ac93838fSSimon Schubert { bridge_ioctl_gcache, sizeof(struct ifbrparam),
534ac93838fSSimon Schubert BC_F_COPYOUT },
535ac93838fSSimon Schubert
536ac93838fSSimon Schubert { bridge_ioctl_gifs, sizeof(struct ifbifconf),
537ac93838fSSimon Schubert BC_F_COPYIN|BC_F_COPYOUT },
538ac93838fSSimon Schubert { bridge_ioctl_rts, sizeof(struct ifbaconf),
539ac93838fSSimon Schubert BC_F_COPYIN|BC_F_COPYOUT },
540ac93838fSSimon Schubert
541ac93838fSSimon Schubert { bridge_ioctl_saddr, sizeof(struct ifbareq),
542ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
543ac93838fSSimon Schubert
544ac93838fSSimon Schubert { bridge_ioctl_sto, sizeof(struct ifbrparam),
545ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
546ac93838fSSimon Schubert { bridge_ioctl_gto, sizeof(struct ifbrparam),
547ac93838fSSimon Schubert BC_F_COPYOUT },
548ac93838fSSimon Schubert
549ac93838fSSimon Schubert { bridge_ioctl_daddr, sizeof(struct ifbareq),
550ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
551ac93838fSSimon Schubert
552ac93838fSSimon Schubert { bridge_ioctl_flush, sizeof(struct ifbreq),
553ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
554ac93838fSSimon Schubert
555ac93838fSSimon Schubert { bridge_ioctl_gpri, sizeof(struct ifbrparam),
556ac93838fSSimon Schubert BC_F_COPYOUT },
557ac93838fSSimon Schubert { bridge_ioctl_spri, sizeof(struct ifbrparam),
558ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
559ac93838fSSimon Schubert
560ac93838fSSimon Schubert { bridge_ioctl_ght, sizeof(struct ifbrparam),
561ac93838fSSimon Schubert BC_F_COPYOUT },
562ac93838fSSimon Schubert { bridge_ioctl_sht, sizeof(struct ifbrparam),
563ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
564ac93838fSSimon Schubert
565ac93838fSSimon Schubert { bridge_ioctl_gfd, sizeof(struct ifbrparam),
566ac93838fSSimon Schubert BC_F_COPYOUT },
567ac93838fSSimon Schubert { bridge_ioctl_sfd, sizeof(struct ifbrparam),
568ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
569ac93838fSSimon Schubert
570ac93838fSSimon Schubert { bridge_ioctl_gma, sizeof(struct ifbrparam),
571ac93838fSSimon Schubert BC_F_COPYOUT },
572ac93838fSSimon Schubert { bridge_ioctl_sma, sizeof(struct ifbrparam),
573ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
574ac93838fSSimon Schubert
575ac93838fSSimon Schubert { bridge_ioctl_sifprio, sizeof(struct ifbreq),
576ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
577ac93838fSSimon Schubert
578ac93838fSSimon Schubert { bridge_ioctl_sifcost, sizeof(struct ifbreq),
579ac93838fSSimon Schubert BC_F_COPYIN|BC_F_SUSER },
580d217f5e5SScott Ullrich
581d217f5e5SScott Ullrich { bridge_ioctl_addspan, sizeof(struct ifbreq),
582d217f5e5SScott Ullrich BC_F_COPYIN|BC_F_SUSER },
583d217f5e5SScott Ullrich { bridge_ioctl_delspan, sizeof(struct ifbreq),
584d217f5e5SScott Ullrich BC_F_COPYIN|BC_F_SUSER },
5851e858374SMatthew Dillon
5861e858374SMatthew Dillon { bridge_ioctl_sifbondwght, sizeof(struct ifbreq),
5871e858374SMatthew Dillon BC_F_COPYIN|BC_F_SUSER },
5881e858374SMatthew Dillon
589ac93838fSSimon Schubert };
590c157ff7aSSascha Wildner static const int bridge_control_table_size = NELEM(bridge_control_table);
591ac93838fSSimon Schubert
592ac93838fSSimon Schubert LIST_HEAD(, bridge_softc) bridge_list;
593ac93838fSSimon Schubert
594ac93838fSSimon Schubert struct if_clone bridge_cloner = IF_CLONE_INITIALIZER("bridge",
595ac93838fSSimon Schubert bridge_clone_create,
596ac93838fSSimon Schubert bridge_clone_destroy, 0, IF_MAXUNIT);
597ac93838fSSimon Schubert
598ac93838fSSimon Schubert static int
bridge_modevent(module_t mod,int type,void * data)599ac93838fSSimon Schubert bridge_modevent(module_t mod, int type, void *data)
600ac93838fSSimon Schubert {
601ac93838fSSimon Schubert switch (type) {
602ac93838fSSimon Schubert case MOD_LOAD:
603ac93838fSSimon Schubert LIST_INIT(&bridge_list);
604ac93838fSSimon Schubert if_clone_attach(&bridge_cloner);
605ac93838fSSimon Schubert bridge_input_p = bridge_input;
606e1d2145dSSepherosa Ziehau bridge_output_p = bridge_output;
60770d9a675SMatthew Dillon bridge_interface_p = bridge_interface;
608d217f5e5SScott Ullrich bridge_detach_cookie = EVENTHANDLER_REGISTER(
609d217f5e5SScott Ullrich ifnet_detach_event, bridge_ifdetach, NULL,
610d217f5e5SScott Ullrich EVENTHANDLER_PRI_ANY);
611122df98fSSascha Wildner #if 0 /* notyet */
612ac93838fSSimon Schubert bstp_linkstate_p = bstp_linkstate;
613ac93838fSSimon Schubert #endif
614ac93838fSSimon Schubert break;
615ac93838fSSimon Schubert case MOD_UNLOAD:
616ac93838fSSimon Schubert if (!LIST_EMPTY(&bridge_list))
617d217f5e5SScott Ullrich return (EBUSY);
618d217f5e5SScott Ullrich EVENTHANDLER_DEREGISTER(ifnet_detach_event,
619d217f5e5SScott Ullrich bridge_detach_cookie);
620ac93838fSSimon Schubert if_clone_detach(&bridge_cloner);
621ac93838fSSimon Schubert bridge_input_p = NULL;
622ac93838fSSimon Schubert bridge_output_p = NULL;
62370d9a675SMatthew Dillon bridge_interface_p = NULL;
624122df98fSSascha Wildner #if 0 /* notyet */
625ac93838fSSimon Schubert bstp_linkstate_p = NULL;
626ac93838fSSimon Schubert #endif
627ac93838fSSimon Schubert break;
628ac93838fSSimon Schubert default:
629d217f5e5SScott Ullrich return (EOPNOTSUPP);
630ac93838fSSimon Schubert }
631d217f5e5SScott Ullrich return (0);
632ac93838fSSimon Schubert }
633ac93838fSSimon Schubert
634ac93838fSSimon Schubert static moduledata_t bridge_mod = {
635ac93838fSSimon Schubert "if_bridge",
636ac93838fSSimon Schubert bridge_modevent,
637ac93838fSSimon Schubert 0
638ac93838fSSimon Schubert };
639ac93838fSSimon Schubert
640ac93838fSSimon Schubert DECLARE_MODULE(if_bridge, bridge_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
641ac93838fSSimon Schubert
642e6720526SMatthew Dillon /*#define BRIDGE_DEBUG_ENABLE*/
643e6720526SMatthew Dillon #ifdef BRIDGE_DEBUG_ENABLE
644e6720526SMatthew Dillon
645e6720526SMatthew Dillon static void
BRIDGE_DEBUG(const char * str,struct ifnet * src_if,struct ifnet * dst_if,struct mbuf * m)646e6720526SMatthew Dillon BRIDGE_DEBUG(const char *str, struct ifnet *src_if, struct ifnet *dst_if,
647e6720526SMatthew Dillon struct mbuf *m)
648e6720526SMatthew Dillon {
649e6720526SMatthew Dillon if ((bridge_debug & 2) == 0)
650e6720526SMatthew Dillon return;
651e6720526SMatthew Dillon
652e6720526SMatthew Dillon if (str)
653e6720526SMatthew Dillon kprintf("%s", str);
654e6720526SMatthew Dillon if (src_if)
655e6720526SMatthew Dillon kprintf(" src={%s,%s%d}",
656e6720526SMatthew Dillon src_if->if_xname, src_if->if_dname, src_if->if_dunit);
657e6720526SMatthew Dillon if (dst_if)
658e6720526SMatthew Dillon kprintf(" dst={%s,%s%d}",
659e6720526SMatthew Dillon dst_if->if_xname, dst_if->if_dname, dst_if->if_dunit);
660e6720526SMatthew Dillon if (m) {
661e6720526SMatthew Dillon struct ether_header *eh;
662e6720526SMatthew Dillon struct ip *ip;
663e6720526SMatthew Dillon
664e6720526SMatthew Dillon eh = mtod(m, struct ether_header *);
665e6720526SMatthew Dillon
666e6720526SMatthew Dillon kprintf(" %02x:%02x:%02x:%02x:%02x:%02x "
667e6720526SMatthew Dillon "%02x:%02x:%02x:%02x:%02x:%02x type %04x ",
668e6720526SMatthew Dillon eh->ether_dhost[0],
669e6720526SMatthew Dillon eh->ether_dhost[1],
670e6720526SMatthew Dillon eh->ether_dhost[2],
671e6720526SMatthew Dillon eh->ether_dhost[3],
672e6720526SMatthew Dillon eh->ether_dhost[4],
673e6720526SMatthew Dillon eh->ether_dhost[5],
674e6720526SMatthew Dillon eh->ether_shost[0],
675e6720526SMatthew Dillon eh->ether_shost[1],
676e6720526SMatthew Dillon eh->ether_shost[2],
677e6720526SMatthew Dillon eh->ether_shost[3],
678e6720526SMatthew Dillon eh->ether_shost[4],
679e6720526SMatthew Dillon eh->ether_shost[5],
680e6720526SMatthew Dillon eh->ether_type);
681e6720526SMatthew Dillon ip = (void *)(eh + 1);
682e6720526SMatthew Dillon kprintf("%u.%u.%u.%u -> %u.%u.%u.%u",
683e6720526SMatthew Dillon (uint8_t)(ip->ip_src.s_addr >> 24),
684e6720526SMatthew Dillon (uint8_t)(ip->ip_src.s_addr >> 16),
685e6720526SMatthew Dillon (uint8_t)(ip->ip_src.s_addr >> 8),
686e6720526SMatthew Dillon (uint8_t)(ip->ip_src.s_addr),
687e6720526SMatthew Dillon (uint8_t)(ip->ip_dst.s_addr >> 24),
688e6720526SMatthew Dillon (uint8_t)(ip->ip_dst.s_addr >> 16),
689e6720526SMatthew Dillon (uint8_t)(ip->ip_dst.s_addr >> 8),
690e6720526SMatthew Dillon (uint8_t)(ip->ip_dst.s_addr));
691e6720526SMatthew Dillon kprintf("\n");
692e6720526SMatthew Dillon }
693e6720526SMatthew Dillon }
694e6720526SMatthew Dillon
695e6720526SMatthew Dillon #else
696e6720526SMatthew Dillon
697e6720526SMatthew Dillon #define BRIDGE_DEBUG(ctl, sif, dif, m)
698e6720526SMatthew Dillon
699e6720526SMatthew Dillon #endif
700ac93838fSSimon Schubert
701ac93838fSSimon Schubert /*
702ac93838fSSimon Schubert * bridge_clone_create:
703ac93838fSSimon Schubert *
704ac93838fSSimon Schubert * Create a new bridge instance.
705ac93838fSSimon Schubert */
706d217f5e5SScott Ullrich static int
bridge_clone_create(struct if_clone * ifc,int unit,caddr_t params __unused,caddr_t data __unused)707bb54c3a2SAaron LI bridge_clone_create(struct if_clone *ifc, int unit,
708bb54c3a2SAaron LI caddr_t params __unused, caddr_t data __unused)
709ac93838fSSimon Schubert {
710ac93838fSSimon Schubert struct bridge_softc *sc;
711ac93838fSSimon Schubert struct ifnet *ifp;
712ac93838fSSimon Schubert u_char eaddr[6];
713d76dd5c7SSepherosa Ziehau int cpu, rnd;
714ac93838fSSimon Schubert
715efda3bd0SMatthew Dillon sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
716ac93838fSSimon Schubert ifp = sc->sc_ifp = &sc->sc_if;
717ac93838fSSimon Schubert
718ac93838fSSimon Schubert sc->sc_brtmax = BRIDGE_RTABLE_MAX;
719ac93838fSSimon Schubert sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT;
720ac93838fSSimon Schubert sc->sc_bridge_max_age = BSTP_DEFAULT_MAX_AGE;
721ac93838fSSimon Schubert sc->sc_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME;
722ac93838fSSimon Schubert sc->sc_bridge_forward_delay = BSTP_DEFAULT_FORWARD_DELAY;
723ac93838fSSimon Schubert sc->sc_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
724ac93838fSSimon Schubert sc->sc_hold_time = BSTP_DEFAULT_HOLD_TIME;
725ac93838fSSimon Schubert
726ac93838fSSimon Schubert /* Initialize our routing table. */
727ac93838fSSimon Schubert bridge_rtable_init(sc);
728ac93838fSSimon Schubert
729f51d3bbeSSepherosa Ziehau callout_init_mp(&sc->sc_brcallout);
73048e7b118SMatthew Dillon netmsg_init(&sc->sc_brtimemsg, NULL, &netisr_adone_rport,
731b95665d8SSepherosa Ziehau MSGF_DROPABLE, bridge_timer_handler);
732002c1265SMatthew Dillon sc->sc_brtimemsg.lmsg.u.ms_resultp = sc;
733e9d22060SSepherosa Ziehau
734f51d3bbeSSepherosa Ziehau callout_init_mp(&sc->sc_bstpcallout);
73548e7b118SMatthew Dillon netmsg_init(&sc->sc_bstptimemsg, NULL, &netisr_adone_rport,
736b95665d8SSepherosa Ziehau MSGF_DROPABLE, bstp_tick_handler);
737002c1265SMatthew Dillon sc->sc_bstptimemsg.lmsg.u.ms_resultp = sc;
738ac93838fSSimon Schubert
7398f7b13efSSepherosa Ziehau /* Initialize per-cpu member iface lists */
740fddbe7b3SSepherosa Ziehau sc->sc_iflists = kmalloc(sizeof(*sc->sc_iflists) * netisr_ncpus,
7418f7b13efSSepherosa Ziehau M_DEVBUF, M_WAITOK);
742fddbe7b3SSepherosa Ziehau for (cpu = 0; cpu < netisr_ncpus; ++cpu)
74370d9a675SMatthew Dillon TAILQ_INIT(&sc->sc_iflists[cpu]);
7448f7b13efSSepherosa Ziehau
74570d9a675SMatthew Dillon TAILQ_INIT(&sc->sc_spanlist);
746ac93838fSSimon Schubert
747ac93838fSSimon Schubert ifp->if_softc = sc;
748ac93838fSSimon Schubert if_initname(ifp, ifc->ifc_name, unit);
749ac93838fSSimon Schubert ifp->if_mtu = ETHERMTU;
750444b1a86SMatthew Dillon ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_ISBRIDGE;
751ac93838fSSimon Schubert ifp->if_ioctl = bridge_ioctl;
752ac93838fSSimon Schubert ifp->if_start = bridge_start;
753ac93838fSSimon Schubert ifp->if_init = bridge_init;
75470d9a675SMatthew Dillon ifp->if_type = IFT_ETHER;
755ac93838fSSimon Schubert ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
756ac93838fSSimon Schubert ifq_set_ready(&ifp->if_snd);
757ac93838fSSimon Schubert ifp->if_hdrlen = ETHER_HDR_LEN;
758ac93838fSSimon Schubert
759ac93838fSSimon Schubert /*
760ac93838fSSimon Schubert * Generate a random ethernet address and use the private AC:DE:48
761ac93838fSSimon Schubert * OUI code.
762ac93838fSSimon Schubert */
763d76dd5c7SSepherosa Ziehau rnd = karc4random();
764d217f5e5SScott Ullrich bcopy(&rnd, &eaddr[0], 4); /* ETHER_ADDR_LEN == 6 */
7650ced1954SMatthew Dillon rnd = karc4random();
766ac93838fSSimon Schubert bcopy(&rnd, &eaddr[2], 4); /* ETHER_ADDR_LEN == 6 */
767d76dd5c7SSepherosa Ziehau
768d217f5e5SScott Ullrich eaddr[0] &= ~1; /* clear multicast bit */
769d217f5e5SScott Ullrich eaddr[0] |= 2; /* set the LAA bit */
770ac93838fSSimon Schubert
771ac93838fSSimon Schubert ether_ifattach(ifp, eaddr, NULL);
772ac93838fSSimon Schubert /* Now undo some of the damage... */
773ac93838fSSimon Schubert ifp->if_baudrate = 0;
77470d9a675SMatthew Dillon /*ifp->if_type = IFT_BRIDGE;*/
775ac93838fSSimon Schubert
776ac308789SSepherosa Ziehau crit_enter(); /* XXX MP */
777ac93838fSSimon Schubert LIST_INSERT_HEAD(&bridge_list, sc, sc_list);
778ac93838fSSimon Schubert crit_exit();
779ac93838fSSimon Schubert
780ac93838fSSimon Schubert return (0);
781ac93838fSSimon Schubert }
782ac93838fSSimon Schubert
78334db64a6SSepherosa Ziehau static void
bridge_delete_dispatch(netmsg_t msg)784002c1265SMatthew Dillon bridge_delete_dispatch(netmsg_t msg)
78534db64a6SSepherosa Ziehau {
786002c1265SMatthew Dillon struct bridge_softc *sc = msg->lmsg.u.ms_resultp;
78734db64a6SSepherosa Ziehau struct ifnet *bifp = sc->sc_ifp;
78834db64a6SSepherosa Ziehau struct bridge_iflist *bif;
78934db64a6SSepherosa Ziehau
790a3dd34d2SSepherosa Ziehau ifnet_serialize_all(bifp);
79134db64a6SSepherosa Ziehau
79270d9a675SMatthew Dillon while ((bif = TAILQ_FIRST(&sc->sc_iflists[mycpuid])) != NULL)
79334db64a6SSepherosa Ziehau bridge_delete_member(sc, bif, 0);
79434db64a6SSepherosa Ziehau
79570d9a675SMatthew Dillon while ((bif = TAILQ_FIRST(&sc->sc_spanlist)) != NULL)
79634db64a6SSepherosa Ziehau bridge_delete_span(sc, bif);
79734db64a6SSepherosa Ziehau
798a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(bifp);
79934db64a6SSepherosa Ziehau
800002c1265SMatthew Dillon lwkt_replymsg(&msg->lmsg, 0);
80134db64a6SSepherosa Ziehau }
80234db64a6SSepherosa Ziehau
803ac93838fSSimon Schubert /*
804ac93838fSSimon Schubert * bridge_clone_destroy:
805ac93838fSSimon Schubert *
806ac93838fSSimon Schubert * Destroy a bridge instance.
807ac93838fSSimon Schubert */
808a7e9152eSSepherosa Ziehau static int
bridge_clone_destroy(struct ifnet * ifp)809ac93838fSSimon Schubert bridge_clone_destroy(struct ifnet *ifp)
810ac93838fSSimon Schubert {
811ac93838fSSimon Schubert struct bridge_softc *sc = ifp->if_softc;
812002c1265SMatthew Dillon struct netmsg_base msg;
813ac93838fSSimon Schubert
814a3dd34d2SSepherosa Ziehau ifnet_serialize_all(ifp);
815ac93838fSSimon Schubert
816867cc45aSSepherosa Ziehau bridge_stop(ifp);
817ac93838fSSimon Schubert ifp->if_flags &= ~IFF_UP;
818ac93838fSSimon Schubert
819a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(ifp);
820ac93838fSSimon Schubert
821002c1265SMatthew Dillon netmsg_init(&msg, NULL, &curthread->td_msgport,
82248e7b118SMatthew Dillon 0, bridge_delete_dispatch);
823002c1265SMatthew Dillon msg.lmsg.u.ms_resultp = sc;
824002c1265SMatthew Dillon lwkt_domsg(BRIDGE_CFGPORT, &msg.lmsg, 0);
82534db64a6SSepherosa Ziehau
82634db64a6SSepherosa Ziehau crit_enter(); /* XXX MP */
827ac93838fSSimon Schubert LIST_REMOVE(sc, sc_list);
828ac93838fSSimon Schubert crit_exit();
829ac93838fSSimon Schubert
830ac93838fSSimon Schubert ether_ifdetach(ifp);
831ac93838fSSimon Schubert
832ac93838fSSimon Schubert /* Tear down the routing table. */
833ac93838fSSimon Schubert bridge_rtable_fini(sc);
834ac93838fSSimon Schubert
8358f7b13efSSepherosa Ziehau /* Free per-cpu member iface lists */
8368f7b13efSSepherosa Ziehau kfree(sc->sc_iflists, M_DEVBUF);
8378f7b13efSSepherosa Ziehau
838efda3bd0SMatthew Dillon kfree(sc, M_DEVBUF);
839a7e9152eSSepherosa Ziehau
840a7e9152eSSepherosa Ziehau return 0;
841ac93838fSSimon Schubert }
842ac93838fSSimon Schubert
843ac93838fSSimon Schubert /*
844ac93838fSSimon Schubert * bridge_ioctl:
845ac93838fSSimon Schubert *
846ac93838fSSimon Schubert * Handle a control request from the operator.
847ac93838fSSimon Schubert */
848d217f5e5SScott Ullrich static int
bridge_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data,struct ucred * cr)849ac93838fSSimon Schubert bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
850ac93838fSSimon Schubert {
851ac93838fSSimon Schubert struct bridge_softc *sc = ifp->if_softc;
8522d4d3c93SSepherosa Ziehau struct bridge_control_arg args;
853ac93838fSSimon Schubert struct ifdrv *ifd = (struct ifdrv *) data;
854ac93838fSSimon Schubert const struct bridge_control *bc;
855ac93838fSSimon Schubert int error = 0;
856ac93838fSSimon Schubert
8572c9effcfSSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp);
858ac93838fSSimon Schubert
859867cc45aSSepherosa Ziehau switch (cmd) {
860ac93838fSSimon Schubert case SIOCADDMULTI:
861ac93838fSSimon Schubert case SIOCDELMULTI:
862ac93838fSSimon Schubert break;
863ac93838fSSimon Schubert
864ac93838fSSimon Schubert case SIOCGDRVSPEC:
865ac93838fSSimon Schubert case SIOCSDRVSPEC:
866ac93838fSSimon Schubert if (ifd->ifd_cmd >= bridge_control_table_size) {
867ac93838fSSimon Schubert error = EINVAL;
868ac93838fSSimon Schubert break;
869ac93838fSSimon Schubert }
870ac93838fSSimon Schubert bc = &bridge_control_table[ifd->ifd_cmd];
871ac93838fSSimon Schubert
872ac93838fSSimon Schubert if (cmd == SIOCGDRVSPEC &&
873ac93838fSSimon Schubert (bc->bc_flags & BC_F_COPYOUT) == 0) {
874ac93838fSSimon Schubert error = EINVAL;
875ac93838fSSimon Schubert break;
876867cc45aSSepherosa Ziehau } else if (cmd == SIOCSDRVSPEC &&
8772d4d3c93SSepherosa Ziehau (bc->bc_flags & BC_F_COPYOUT)) {
878ac93838fSSimon Schubert error = EINVAL;
879ac93838fSSimon Schubert break;
880ac93838fSSimon Schubert }
881ac93838fSSimon Schubert
882ac93838fSSimon Schubert if (bc->bc_flags & BC_F_SUSER) {
8832b3f93eaSMatthew Dillon error = caps_priv_check(cr, SYSCAP_RESTRICTEDROOT |
8842b3f93eaSMatthew Dillon __SYSCAP_NULLCRED);
885ac93838fSSimon Schubert if (error)
886ac93838fSSimon Schubert break;
887ac93838fSSimon Schubert }
888ac93838fSSimon Schubert
889ac93838fSSimon Schubert if (ifd->ifd_len != bc->bc_argsize ||
8902d4d3c93SSepherosa Ziehau ifd->ifd_len > sizeof(args.bca_u)) {
891ac93838fSSimon Schubert error = EINVAL;
892ac93838fSSimon Schubert break;
893ac93838fSSimon Schubert }
894ac93838fSSimon Schubert
89560d8d1d3SJeffrey Hsu memset(&args, 0, sizeof(args));
896ac93838fSSimon Schubert if (bc->bc_flags & BC_F_COPYIN) {
8972d4d3c93SSepherosa Ziehau error = copyin(ifd->ifd_data, &args.bca_u,
8982d4d3c93SSepherosa Ziehau ifd->ifd_len);
899ac93838fSSimon Schubert if (error)
900ac93838fSSimon Schubert break;
901ac93838fSSimon Schubert }
902ac93838fSSimon Schubert
9030b326f64SSepherosa Ziehau error = bridge_control(sc, cmd, bc->bc_func, &args);
9042d4d3c93SSepherosa Ziehau if (error) {
9052d4d3c93SSepherosa Ziehau KKASSERT(args.bca_len == 0 && args.bca_kptr == NULL);
906ac93838fSSimon Schubert break;
9072d4d3c93SSepherosa Ziehau }
908ac93838fSSimon Schubert
9092d4d3c93SSepherosa Ziehau if (bc->bc_flags & BC_F_COPYOUT) {
910ac93838fSSimon Schubert error = copyout(&args, ifd->ifd_data, ifd->ifd_len);
9112d4d3c93SSepherosa Ziehau if (args.bca_len != 0) {
9122d4d3c93SSepherosa Ziehau KKASSERT(args.bca_kptr != NULL);
9132d4d3c93SSepherosa Ziehau if (!error) {
9142d4d3c93SSepherosa Ziehau error = copyout(args.bca_kptr,
9152d4d3c93SSepherosa Ziehau args.bca_uptr, args.bca_len);
9162d4d3c93SSepherosa Ziehau }
9172d4d3c93SSepherosa Ziehau kfree(args.bca_kptr, M_TEMP);
9182d4d3c93SSepherosa Ziehau } else {
9192d4d3c93SSepherosa Ziehau KKASSERT(args.bca_kptr == NULL);
9202d4d3c93SSepherosa Ziehau }
9212d4d3c93SSepherosa Ziehau } else {
9222d4d3c93SSepherosa Ziehau KKASSERT(args.bca_len == 0 && args.bca_kptr == NULL);
9232d4d3c93SSepherosa Ziehau }
924ac93838fSSimon Schubert break;
925ac93838fSSimon Schubert
926ac93838fSSimon Schubert case SIOCSIFFLAGS:
927ac93838fSSimon Schubert if (!(ifp->if_flags & IFF_UP) &&
928ac93838fSSimon Schubert (ifp->if_flags & IFF_RUNNING)) {
929ac93838fSSimon Schubert /*
930ac93838fSSimon Schubert * If interface is marked down and it is running,
931867cc45aSSepherosa Ziehau * then stop it.
932ac93838fSSimon Schubert */
933867cc45aSSepherosa Ziehau bridge_stop(ifp);
934ac93838fSSimon Schubert } else if ((ifp->if_flags & IFF_UP) &&
935ac93838fSSimon Schubert !(ifp->if_flags & IFF_RUNNING)) {
936ac93838fSSimon Schubert /*
937ac93838fSSimon Schubert * If interface is marked up and it is stopped, then
938ac93838fSSimon Schubert * start it.
939ac93838fSSimon Schubert */
940867cc45aSSepherosa Ziehau ifp->if_init(sc);
941ac93838fSSimon Schubert }
9429b42fdc9SMatthew Dillon
9439b42fdc9SMatthew Dillon /*
9449b42fdc9SMatthew Dillon * If running and link flag state change we have to
9459b42fdc9SMatthew Dillon * reinitialize as well.
9469b42fdc9SMatthew Dillon */
9479b42fdc9SMatthew Dillon if ((ifp->if_flags & IFF_RUNNING) &&
9489b42fdc9SMatthew Dillon (ifp->if_flags & (IFF_LINK0|IFF_LINK1|IFF_LINK2)) !=
9499b42fdc9SMatthew Dillon sc->sc_copy_flags) {
9509b42fdc9SMatthew Dillon sc->sc_copy_flags = ifp->if_flags &
9519b42fdc9SMatthew Dillon (IFF_LINK0|IFF_LINK1|IFF_LINK2);
9529b42fdc9SMatthew Dillon bridge_control(sc, 0, bridge_ioctl_reinit, NULL);
9539b42fdc9SMatthew Dillon }
9549b42fdc9SMatthew Dillon
955ac93838fSSimon Schubert break;
956ac93838fSSimon Schubert
957ac93838fSSimon Schubert case SIOCSIFMTU:
958ac93838fSSimon Schubert /* Do not allow the MTU to be changed on the bridge */
959ac93838fSSimon Schubert error = EINVAL;
960ac93838fSSimon Schubert break;
961ac93838fSSimon Schubert
962ac93838fSSimon Schubert default:
963ac93838fSSimon Schubert error = ether_ioctl(ifp, cmd, data);
964ac93838fSSimon Schubert break;
965ac93838fSSimon Schubert }
966ac93838fSSimon Schubert return (error);
967ac93838fSSimon Schubert }
968ac93838fSSimon Schubert
969ac93838fSSimon Schubert /*
970d217f5e5SScott Ullrich * bridge_mutecaps:
971d217f5e5SScott Ullrich *
972d217f5e5SScott Ullrich * Clear or restore unwanted capabilities on the member interface
973d217f5e5SScott Ullrich */
974d217f5e5SScott Ullrich static void
bridge_mutecaps(struct bridge_ifinfo * bif_info,struct ifnet * ifp,int mute)9758f7b13efSSepherosa Ziehau bridge_mutecaps(struct bridge_ifinfo *bif_info, struct ifnet *ifp, int mute)
976d217f5e5SScott Ullrich {
977d217f5e5SScott Ullrich struct ifreq ifr;
978d217f5e5SScott Ullrich
979d217f5e5SScott Ullrich if (ifp->if_ioctl == NULL)
980d217f5e5SScott Ullrich return;
981d217f5e5SScott Ullrich
982d217f5e5SScott Ullrich bzero(&ifr, sizeof(ifr));
983d217f5e5SScott Ullrich ifr.ifr_reqcap = ifp->if_capenable;
984d217f5e5SScott Ullrich
985d217f5e5SScott Ullrich if (mute) {
986d217f5e5SScott Ullrich /* mask off and save capabilities */
9878f7b13efSSepherosa Ziehau bif_info->bifi_mutecap = ifr.ifr_reqcap & BRIDGE_IFCAPS_MASK;
9888f7b13efSSepherosa Ziehau if (bif_info->bifi_mutecap != 0)
989d217f5e5SScott Ullrich ifr.ifr_reqcap &= ~BRIDGE_IFCAPS_MASK;
99068b979e7SSepherosa Ziehau } else {
991d217f5e5SScott Ullrich /* restore muted capabilities */
9928f7b13efSSepherosa Ziehau ifr.ifr_reqcap |= bif_info->bifi_mutecap;
99368b979e7SSepherosa Ziehau }
994d217f5e5SScott Ullrich
9958f7b13efSSepherosa Ziehau if (bif_info->bifi_mutecap != 0) {
996a3dd34d2SSepherosa Ziehau ifnet_serialize_all(ifp);
997859da660SSepherosa Ziehau ifp->if_ioctl(ifp, SIOCSIFCAP, (caddr_t)&ifr, NULL);
998a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(ifp);
999d217f5e5SScott Ullrich }
1000d217f5e5SScott Ullrich }
1001d217f5e5SScott Ullrich
1002d217f5e5SScott Ullrich /*
1003ac93838fSSimon Schubert * bridge_lookup_member:
1004ac93838fSSimon Schubert *
1005ac93838fSSimon Schubert * Lookup a bridge member interface.
1006ac93838fSSimon Schubert */
1007d217f5e5SScott Ullrich static struct bridge_iflist *
bridge_lookup_member(struct bridge_softc * sc,const char * name)1008ac93838fSSimon Schubert bridge_lookup_member(struct bridge_softc *sc, const char *name)
1009ac93838fSSimon Schubert {
1010ac93838fSSimon Schubert struct bridge_iflist *bif;
1011ac93838fSSimon Schubert
101270d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
10138f7b13efSSepherosa Ziehau if (strcmp(bif->bif_ifp->if_xname, name) == 0)
1014ac93838fSSimon Schubert return (bif);
1015ac93838fSSimon Schubert }
1016ac93838fSSimon Schubert return (NULL);
1017ac93838fSSimon Schubert }
1018ac93838fSSimon Schubert
1019ac93838fSSimon Schubert /*
1020ac93838fSSimon Schubert * bridge_lookup_member_if:
1021ac93838fSSimon Schubert *
1022ac93838fSSimon Schubert * Lookup a bridge member interface by ifnet*.
1023ac93838fSSimon Schubert */
1024d217f5e5SScott Ullrich static struct bridge_iflist *
bridge_lookup_member_if(struct bridge_softc * sc,struct ifnet * member_ifp)1025ac93838fSSimon Schubert bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp)
1026ac93838fSSimon Schubert {
1027ac93838fSSimon Schubert struct bridge_iflist *bif;
1028ac93838fSSimon Schubert
102970d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
1030ac93838fSSimon Schubert if (bif->bif_ifp == member_ifp)
1031ac93838fSSimon Schubert return (bif);
1032ac93838fSSimon Schubert }
10338f7b13efSSepherosa Ziehau return (NULL);
10348f7b13efSSepherosa Ziehau }
1035ac93838fSSimon Schubert
10368f7b13efSSepherosa Ziehau /*
10378f7b13efSSepherosa Ziehau * bridge_lookup_member_ifinfo:
10388f7b13efSSepherosa Ziehau *
10398f7b13efSSepherosa Ziehau * Lookup a bridge member interface by bridge_ifinfo.
10408f7b13efSSepherosa Ziehau */
10418f7b13efSSepherosa Ziehau static struct bridge_iflist *
bridge_lookup_member_ifinfo(struct bridge_softc * sc,struct bridge_ifinfo * bif_info)10428f7b13efSSepherosa Ziehau bridge_lookup_member_ifinfo(struct bridge_softc *sc,
10438f7b13efSSepherosa Ziehau struct bridge_ifinfo *bif_info)
10448f7b13efSSepherosa Ziehau {
10458f7b13efSSepherosa Ziehau struct bridge_iflist *bif;
10468f7b13efSSepherosa Ziehau
104770d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
10488f7b13efSSepherosa Ziehau if (bif->bif_info == bif_info)
10498f7b13efSSepherosa Ziehau return (bif);
10508f7b13efSSepherosa Ziehau }
1051ac93838fSSimon Schubert return (NULL);
1052ac93838fSSimon Schubert }
1053ac93838fSSimon Schubert
1054ac93838fSSimon Schubert /*
1055ac93838fSSimon Schubert * bridge_delete_member:
1056ac93838fSSimon Schubert *
1057ac93838fSSimon Schubert * Delete the specified member interface.
1058ac93838fSSimon Schubert */
1059d217f5e5SScott Ullrich static void
bridge_delete_member(struct bridge_softc * sc,struct bridge_iflist * bif,int gone)1060d217f5e5SScott Ullrich bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
1061d217f5e5SScott Ullrich int gone)
1062ac93838fSSimon Schubert {
1063ac93838fSSimon Schubert struct ifnet *ifs = bif->bif_ifp;
1064bdfc79d0SSepherosa Ziehau struct ifnet *bifp = sc->sc_ifp;
10658f7b13efSSepherosa Ziehau struct bridge_ifinfo *bif_info = bif->bif_info;
10668f7b13efSSepherosa Ziehau struct bridge_iflist_head saved_bifs;
1067bdfc79d0SSepherosa Ziehau
10682c9effcfSSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(bifp);
10698f7b13efSSepherosa Ziehau KKASSERT(bif_info != NULL);
1070bdfc79d0SSepherosa Ziehau
1071bdfc79d0SSepherosa Ziehau ifs->if_bridge = NULL;
1072297c8124SSepherosa Ziehau
1073297c8124SSepherosa Ziehau /*
1074297c8124SSepherosa Ziehau * Release bridge interface's serializer:
1075297c8124SSepherosa Ziehau * - To avoid possible dead lock.
10768f7b13efSSepherosa Ziehau * - Various sync operation will block the current thread.
1077297c8124SSepherosa Ziehau */
1078a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(bifp);
1079297c8124SSepherosa Ziehau
1080d217f5e5SScott Ullrich if (!gone) {
1081ac93838fSSimon Schubert switch (ifs->if_type) {
1082ac93838fSSimon Schubert case IFT_ETHER:
1083ac93838fSSimon Schubert case IFT_L2VLAN:
1084ac93838fSSimon Schubert /*
1085ac93838fSSimon Schubert * Take the interface out of promiscuous mode.
1086ac93838fSSimon Schubert */
1087bdfc79d0SSepherosa Ziehau ifpromisc(ifs, 0);
10888f7b13efSSepherosa Ziehau bridge_mutecaps(bif_info, ifs, 0);
1089ac93838fSSimon Schubert break;
1090ac93838fSSimon Schubert
1091ac93838fSSimon Schubert case IFT_GIF:
1092ac93838fSSimon Schubert break;
1093ac93838fSSimon Schubert
1094ac93838fSSimon Schubert default:
1095ac93838fSSimon Schubert panic("bridge_delete_member: impossible");
1096ac93838fSSimon Schubert break;
1097ac93838fSSimon Schubert }
1098d217f5e5SScott Ullrich }
1099ac93838fSSimon Schubert
11008f7b13efSSepherosa Ziehau /*
11018f7b13efSSepherosa Ziehau * Remove bifs from percpu linked list.
11028f7b13efSSepherosa Ziehau *
11038f7b13efSSepherosa Ziehau * Removed bifs are not freed immediately, instead,
11048f7b13efSSepherosa Ziehau * they are saved in saved_bifs. They will be freed
11058f7b13efSSepherosa Ziehau * after we make sure that no one is accessing them,
11068f7b13efSSepherosa Ziehau * i.e. after following netmsg_service_sync()
11078f7b13efSSepherosa Ziehau */
110870d9a675SMatthew Dillon TAILQ_INIT(&saved_bifs);
11098f7b13efSSepherosa Ziehau bridge_del_bif(sc, bif_info, &saved_bifs);
11108f7b13efSSepherosa Ziehau
11118f7b13efSSepherosa Ziehau /*
11128f7b13efSSepherosa Ziehau * Make sure that all protocol threads:
11138f7b13efSSepherosa Ziehau * o see 'ifs' if_bridge is changed
11148f7b13efSSepherosa Ziehau * o know that bif is removed from the percpu linked list
11158f7b13efSSepherosa Ziehau */
11168f7b13efSSepherosa Ziehau netmsg_service_sync();
11178f7b13efSSepherosa Ziehau
11188f7b13efSSepherosa Ziehau /*
11198f7b13efSSepherosa Ziehau * Free the removed bifs
11208f7b13efSSepherosa Ziehau */
112170d9a675SMatthew Dillon KKASSERT(!TAILQ_EMPTY(&saved_bifs));
112270d9a675SMatthew Dillon while ((bif = TAILQ_FIRST(&saved_bifs)) != NULL) {
112370d9a675SMatthew Dillon TAILQ_REMOVE(&saved_bifs, bif, bif_next);
11248f7b13efSSepherosa Ziehau kfree(bif, M_DEVBUF);
11258f7b13efSSepherosa Ziehau }
11268f7b13efSSepherosa Ziehau
11274394693cSSepherosa Ziehau /* See the comment in bridge_ioctl_stop() */
11284394693cSSepherosa Ziehau bridge_rtmsg_sync(sc);
112930ced003SSepherosa Ziehau bridge_rtdelete(sc, ifs, IFBF_FLUSHALL | IFBF_FLUSHSYNC);
11304394693cSSepherosa Ziehau
1131a3dd34d2SSepherosa Ziehau ifnet_serialize_all(bifp);
1132297c8124SSepherosa Ziehau
11338f7b13efSSepherosa Ziehau if (bifp->if_flags & IFF_RUNNING)
1134ac93838fSSimon Schubert bstp_initialization(sc);
11358f7b13efSSepherosa Ziehau
11368f7b13efSSepherosa Ziehau /*
11378f7b13efSSepherosa Ziehau * Free the bif_info after bstp_initialization(), so that
11388f7b13efSSepherosa Ziehau * bridge_softc.sc_root_port will not reference a dangling
11398f7b13efSSepherosa Ziehau * pointer.
11408f7b13efSSepherosa Ziehau */
11418f7b13efSSepherosa Ziehau kfree(bif_info, M_DEVBUF);
1142ac93838fSSimon Schubert }
1143ac93838fSSimon Schubert
1144d217f5e5SScott Ullrich /*
1145d217f5e5SScott Ullrich * bridge_delete_span:
1146d217f5e5SScott Ullrich *
1147d217f5e5SScott Ullrich * Delete the specified span interface.
1148d217f5e5SScott Ullrich */
1149d217f5e5SScott Ullrich static void
bridge_delete_span(struct bridge_softc * sc,struct bridge_iflist * bif)1150d217f5e5SScott Ullrich bridge_delete_span(struct bridge_softc *sc, struct bridge_iflist *bif)
1151d217f5e5SScott Ullrich {
1152d217f5e5SScott Ullrich KASSERT(bif->bif_ifp->if_bridge == NULL,
1153d217f5e5SScott Ullrich ("%s: not a span interface", __func__));
1154d217f5e5SScott Ullrich
115570d9a675SMatthew Dillon TAILQ_REMOVE(&sc->sc_iflists[mycpuid], bif, bif_next);
1156efda3bd0SMatthew Dillon kfree(bif, M_DEVBUF);
1157d217f5e5SScott Ullrich }
1158d217f5e5SScott Ullrich
1159d217f5e5SScott Ullrich static int
bridge_ioctl_init(struct bridge_softc * sc,void * arg __unused)1160d71129d9SSepherosa Ziehau bridge_ioctl_init(struct bridge_softc *sc, void *arg __unused)
1161d71129d9SSepherosa Ziehau {
1162d71129d9SSepherosa Ziehau struct ifnet *ifp = sc->sc_ifp;
1163d71129d9SSepherosa Ziehau
1164d71129d9SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING)
1165d71129d9SSepherosa Ziehau return 0;
1166d71129d9SSepherosa Ziehau
1167d71129d9SSepherosa Ziehau callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz,
1168d71129d9SSepherosa Ziehau bridge_timer, sc);
1169d71129d9SSepherosa Ziehau
1170d71129d9SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING;
1171d71129d9SSepherosa Ziehau bstp_initialization(sc);
1172d71129d9SSepherosa Ziehau return 0;
1173d71129d9SSepherosa Ziehau }
1174d71129d9SSepherosa Ziehau
1175d71129d9SSepherosa Ziehau static int
bridge_ioctl_stop(struct bridge_softc * sc,void * arg __unused)1176d71129d9SSepherosa Ziehau bridge_ioctl_stop(struct bridge_softc *sc, void *arg __unused)
1177d71129d9SSepherosa Ziehau {
1178d71129d9SSepherosa Ziehau struct ifnet *ifp = sc->sc_ifp;
1179d71129d9SSepherosa Ziehau
1180d71129d9SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0)
1181d71129d9SSepherosa Ziehau return 0;
1182d71129d9SSepherosa Ziehau
1183d71129d9SSepherosa Ziehau callout_stop(&sc->sc_brcallout);
1184e9d22060SSepherosa Ziehau
1185e9d22060SSepherosa Ziehau crit_enter();
11866999cd81SMatthew Dillon lwkt_dropmsg(&sc->sc_brtimemsg.lmsg);
1187e9d22060SSepherosa Ziehau crit_exit();
1188e9d22060SSepherosa Ziehau
1189d71129d9SSepherosa Ziehau bstp_stop(sc);
1190d71129d9SSepherosa Ziehau
1191d71129d9SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING;
1192d71129d9SSepherosa Ziehau
1193a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(ifp);
11944394693cSSepherosa Ziehau
11954394693cSSepherosa Ziehau /* Let everyone know that we are stopped */
11964394693cSSepherosa Ziehau netmsg_service_sync();
11974394693cSSepherosa Ziehau
11984394693cSSepherosa Ziehau /*
11994394693cSSepherosa Ziehau * Sync ifnetX msgports in the order we forward rtnode
12004394693cSSepherosa Ziehau * installation message. This is used to make sure that
12014394693cSSepherosa Ziehau * all rtnode installation messages sent by bridge_rtupdate()
12024394693cSSepherosa Ziehau * during above netmsg_service_sync() are flushed.
12034394693cSSepherosa Ziehau */
12044394693cSSepherosa Ziehau bridge_rtmsg_sync(sc);
120530ced003SSepherosa Ziehau bridge_rtflush(sc, IFBF_FLUSHDYN | IFBF_FLUSHSYNC);
12064394693cSSepherosa Ziehau
1207a3dd34d2SSepherosa Ziehau ifnet_serialize_all(ifp);
1208d71129d9SSepherosa Ziehau return 0;
1209d71129d9SSepherosa Ziehau }
1210d71129d9SSepherosa Ziehau
1211d71129d9SSepherosa Ziehau static int
bridge_ioctl_add(struct bridge_softc * sc,void * arg)1212ac93838fSSimon Schubert bridge_ioctl_add(struct bridge_softc *sc, void *arg)
1213ac93838fSSimon Schubert {
1214ac93838fSSimon Schubert struct ifbreq *req = arg;
12158f7b13efSSepherosa Ziehau struct bridge_iflist *bif;
12168f7b13efSSepherosa Ziehau struct bridge_ifinfo *bif_info;
121768b979e7SSepherosa Ziehau struct ifnet *ifs, *bifp;
1218ac93838fSSimon Schubert int error = 0;
1219ac93838fSSimon Schubert
122068b979e7SSepherosa Ziehau bifp = sc->sc_ifp;
12212c9effcfSSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(bifp);
122268b979e7SSepherosa Ziehau
1223b4051e25SSepherosa Ziehau ifs = ifunit_netisr(req->ifbr_ifsname);
1224ac93838fSSimon Schubert if (ifs == NULL)
1225ac93838fSSimon Schubert return (ENOENT);
1226ac93838fSSimon Schubert
1227d217f5e5SScott Ullrich /* If it's in the span list, it can't be a member. */
122870d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
1229d217f5e5SScott Ullrich if (ifs == bif->bif_ifp)
1230d217f5e5SScott Ullrich return (EBUSY);
1231d217f5e5SScott Ullrich
1232d217f5e5SScott Ullrich /* Allow the first Ethernet member to define the MTU */
1233d217f5e5SScott Ullrich if (ifs->if_type != IFT_GIF) {
123470d9a675SMatthew Dillon if (TAILQ_EMPTY(&sc->sc_iflists[mycpuid])) {
123568b979e7SSepherosa Ziehau bifp->if_mtu = ifs->if_mtu;
123668b979e7SSepherosa Ziehau } else if (bifp->if_mtu != ifs->if_mtu) {
123768b979e7SSepherosa Ziehau if_printf(bifp, "invalid MTU for %s\n", ifs->if_xname);
1238ac93838fSSimon Schubert return (EINVAL);
1239ac93838fSSimon Schubert }
1240d217f5e5SScott Ullrich }
1241ac93838fSSimon Schubert
1242ac93838fSSimon Schubert if (ifs->if_bridge == sc)
1243ac93838fSSimon Schubert return (EEXIST);
1244ac93838fSSimon Schubert
1245ac93838fSSimon Schubert if (ifs->if_bridge != NULL)
1246ac93838fSSimon Schubert return (EBUSY);
1247ac93838fSSimon Schubert
12488f7b13efSSepherosa Ziehau bif_info = kmalloc(sizeof(*bif_info), M_DEVBUF, M_WAITOK | M_ZERO);
12498f7b13efSSepherosa Ziehau bif_info->bifi_priority = BSTP_DEFAULT_PORT_PRIORITY;
12508f7b13efSSepherosa Ziehau bif_info->bifi_path_cost = BSTP_DEFAULT_PATH_COST;
12518f7b13efSSepherosa Ziehau bif_info->bifi_ifp = ifs;
12521e858374SMatthew Dillon bif_info->bifi_bond_weight = 1;
12538f7b13efSSepherosa Ziehau
12548f7b13efSSepherosa Ziehau /*
12558f7b13efSSepherosa Ziehau * Release bridge interface's serializer:
12568f7b13efSSepherosa Ziehau * - To avoid possible dead lock.
12578f7b13efSSepherosa Ziehau * - Various sync operation will block the current thread.
12588f7b13efSSepherosa Ziehau */
1259a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(bifp);
1260d217f5e5SScott Ullrich
1261ac93838fSSimon Schubert switch (ifs->if_type) {
1262ac93838fSSimon Schubert case IFT_ETHER:
1263ac93838fSSimon Schubert case IFT_L2VLAN:
1264ac93838fSSimon Schubert /*
1265ac93838fSSimon Schubert * Place the interface into promiscuous mode.
1266ac93838fSSimon Schubert */
1267ac93838fSSimon Schubert error = ifpromisc(ifs, 1);
126868b979e7SSepherosa Ziehau if (error) {
1269a3dd34d2SSepherosa Ziehau ifnet_serialize_all(bifp);
1270ac93838fSSimon Schubert goto out;
127168b979e7SSepherosa Ziehau }
12728f7b13efSSepherosa Ziehau bridge_mutecaps(bif_info, ifs, 1);
1273ac93838fSSimon Schubert break;
1274ac93838fSSimon Schubert
1275ac93838fSSimon Schubert case IFT_GIF: /* :^) */
1276ac93838fSSimon Schubert break;
1277ac93838fSSimon Schubert
1278ac93838fSSimon Schubert default:
1279ac93838fSSimon Schubert error = EINVAL;
1280a3dd34d2SSepherosa Ziehau ifnet_serialize_all(bifp);
1281ac93838fSSimon Schubert goto out;
1282ac93838fSSimon Schubert }
1283ac93838fSSimon Schubert
12848f7b13efSSepherosa Ziehau /*
12858f7b13efSSepherosa Ziehau * Add bifs to percpu linked lists
12868f7b13efSSepherosa Ziehau */
12878f7b13efSSepherosa Ziehau bridge_add_bif(sc, bif_info, ifs);
12888f7b13efSSepherosa Ziehau
1289a3dd34d2SSepherosa Ziehau ifnet_serialize_all(bifp);
1290ac93838fSSimon Schubert
129168b979e7SSepherosa Ziehau if (bifp->if_flags & IFF_RUNNING)
1292ac93838fSSimon Schubert bstp_initialization(sc);
1293ac93838fSSimon Schubert else
1294ac93838fSSimon Schubert bstp_stop(sc);
1295ac93838fSSimon Schubert
129668b979e7SSepherosa Ziehau /*
129768b979e7SSepherosa Ziehau * Everything has been setup, so let the member interface
129868b979e7SSepherosa Ziehau * deliver packets to this bridge on its input/output path.
129968b979e7SSepherosa Ziehau */
130068b979e7SSepherosa Ziehau ifs->if_bridge = sc;
1301ac93838fSSimon Schubert out:
1302ac93838fSSimon Schubert if (error) {
13038f7b13efSSepherosa Ziehau if (bif_info != NULL)
13048f7b13efSSepherosa Ziehau kfree(bif_info, M_DEVBUF);
1305ac93838fSSimon Schubert }
1306ac93838fSSimon Schubert return (error);
1307ac93838fSSimon Schubert }
1308ac93838fSSimon Schubert
1309d217f5e5SScott Ullrich static int
bridge_ioctl_del(struct bridge_softc * sc,void * arg)1310ac93838fSSimon Schubert bridge_ioctl_del(struct bridge_softc *sc, void *arg)
1311ac93838fSSimon Schubert {
1312ac93838fSSimon Schubert struct ifbreq *req = arg;
1313ac93838fSSimon Schubert struct bridge_iflist *bif;
1314ac93838fSSimon Schubert
1315ac93838fSSimon Schubert bif = bridge_lookup_member(sc, req->ifbr_ifsname);
1316ac93838fSSimon Schubert if (bif == NULL)
1317ac93838fSSimon Schubert return (ENOENT);
1318ac93838fSSimon Schubert
1319d217f5e5SScott Ullrich bridge_delete_member(sc, bif, 0);
1320ac93838fSSimon Schubert
1321ac93838fSSimon Schubert return (0);
1322ac93838fSSimon Schubert }
1323ac93838fSSimon Schubert
1324d217f5e5SScott Ullrich static int
bridge_ioctl_gifflags(struct bridge_softc * sc,void * arg)1325ac93838fSSimon Schubert bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg)
1326ac93838fSSimon Schubert {
1327ac93838fSSimon Schubert struct ifbreq *req = arg;
1328ac93838fSSimon Schubert struct bridge_iflist *bif;
1329ac93838fSSimon Schubert
1330ac93838fSSimon Schubert bif = bridge_lookup_member(sc, req->ifbr_ifsname);
1331ac93838fSSimon Schubert if (bif == NULL)
1332ac93838fSSimon Schubert return (ENOENT);
133370d9a675SMatthew Dillon bridge_ioctl_fillflags(sc, bif, req);
133470d9a675SMatthew Dillon return (0);
133570d9a675SMatthew Dillon }
1336ac93838fSSimon Schubert
133770d9a675SMatthew Dillon static void
bridge_ioctl_fillflags(struct bridge_softc * sc,struct bridge_iflist * bif,struct ifbreq * req)133870d9a675SMatthew Dillon bridge_ioctl_fillflags(struct bridge_softc *sc, struct bridge_iflist *bif,
133970d9a675SMatthew Dillon struct ifbreq *req)
134070d9a675SMatthew Dillon {
1341ac93838fSSimon Schubert req->ifbr_ifsflags = bif->bif_flags;
1342ac93838fSSimon Schubert req->ifbr_state = bif->bif_state;
1343ac93838fSSimon Schubert req->ifbr_priority = bif->bif_priority;
1344ac93838fSSimon Schubert req->ifbr_path_cost = bif->bif_path_cost;
13451e858374SMatthew Dillon req->ifbr_bond_weight = bif->bif_bond_weight;
1346ac93838fSSimon Schubert req->ifbr_portno = bif->bif_ifp->if_index & 0xff;
134770d9a675SMatthew Dillon if (bif->bif_flags & IFBIF_STP) {
134870d9a675SMatthew Dillon req->ifbr_peer_root = bif->bif_peer_root;
134970d9a675SMatthew Dillon req->ifbr_peer_bridge = bif->bif_peer_bridge;
135070d9a675SMatthew Dillon req->ifbr_peer_cost = bif->bif_peer_cost;
135170d9a675SMatthew Dillon req->ifbr_peer_port = bif->bif_peer_port;
135270d9a675SMatthew Dillon if (bstp_supersedes_port_info(sc, bif)) {
135370d9a675SMatthew Dillon req->ifbr_designated_root = bif->bif_peer_root;
135470d9a675SMatthew Dillon req->ifbr_designated_bridge = bif->bif_peer_bridge;
135570d9a675SMatthew Dillon req->ifbr_designated_cost = bif->bif_peer_cost;
135670d9a675SMatthew Dillon req->ifbr_designated_port = bif->bif_peer_port;
135770d9a675SMatthew Dillon } else {
135870d9a675SMatthew Dillon req->ifbr_designated_root = sc->sc_bridge_id;
135970d9a675SMatthew Dillon req->ifbr_designated_bridge = sc->sc_bridge_id;
136070d9a675SMatthew Dillon req->ifbr_designated_cost = bif->bif_path_cost +
136170d9a675SMatthew Dillon bif->bif_peer_cost;
136270d9a675SMatthew Dillon req->ifbr_designated_port = bif->bif_port_id;
136370d9a675SMatthew Dillon }
136470d9a675SMatthew Dillon } else {
136570d9a675SMatthew Dillon req->ifbr_peer_root = 0;
136670d9a675SMatthew Dillon req->ifbr_peer_bridge = 0;
136770d9a675SMatthew Dillon req->ifbr_peer_cost = 0;
136870d9a675SMatthew Dillon req->ifbr_peer_port = 0;
136970d9a675SMatthew Dillon req->ifbr_designated_root = 0;
137070d9a675SMatthew Dillon req->ifbr_designated_bridge = 0;
137170d9a675SMatthew Dillon req->ifbr_designated_cost = 0;
137270d9a675SMatthew Dillon req->ifbr_designated_port = 0;
137370d9a675SMatthew Dillon }
1374ac93838fSSimon Schubert }
1375ac93838fSSimon Schubert
1376d217f5e5SScott Ullrich static int
bridge_ioctl_sifflags(struct bridge_softc * sc,void * arg)1377ac93838fSSimon Schubert bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg)
1378ac93838fSSimon Schubert {
1379ac93838fSSimon Schubert struct ifbreq *req = arg;
1380ac93838fSSimon Schubert struct bridge_iflist *bif;
13818f7b13efSSepherosa Ziehau struct ifnet *bifp = sc->sc_ifp;
1382ac93838fSSimon Schubert
1383ac93838fSSimon Schubert bif = bridge_lookup_member(sc, req->ifbr_ifsname);
1384ac93838fSSimon Schubert if (bif == NULL)
1385ac93838fSSimon Schubert return (ENOENT);
1386ac93838fSSimon Schubert
13878f7b13efSSepherosa Ziehau if (req->ifbr_ifsflags & IFBIF_SPAN) {
1388d217f5e5SScott Ullrich /* SPAN is readonly */
1389d217f5e5SScott Ullrich return (EINVAL);
13908f7b13efSSepherosa Ziehau }
1391d217f5e5SScott Ullrich
1392ac93838fSSimon Schubert if (req->ifbr_ifsflags & IFBIF_STP) {
1393ac93838fSSimon Schubert switch (bif->bif_ifp->if_type) {
1394ac93838fSSimon Schubert case IFT_ETHER:
1395ac93838fSSimon Schubert /* These can do spanning tree. */
1396ac93838fSSimon Schubert break;
1397ac93838fSSimon Schubert
1398ac93838fSSimon Schubert default:
1399ac93838fSSimon Schubert /* Nothing else can. */
1400ac93838fSSimon Schubert return (EINVAL);
1401ac93838fSSimon Schubert }
1402ac93838fSSimon Schubert }
1403ac93838fSSimon Schubert
140470d9a675SMatthew Dillon bif->bif_flags = (bif->bif_flags & IFBIF_KEEPMASK) |
140570d9a675SMatthew Dillon (req->ifbr_ifsflags & ~IFBIF_KEEPMASK);
14068f7b13efSSepherosa Ziehau if (bifp->if_flags & IFF_RUNNING)
1407ac93838fSSimon Schubert bstp_initialization(sc);
1408ac93838fSSimon Schubert
1409ac93838fSSimon Schubert return (0);
1410ac93838fSSimon Schubert }
1411ac93838fSSimon Schubert
1412d217f5e5SScott Ullrich static int
bridge_ioctl_scache(struct bridge_softc * sc,void * arg)1413ac93838fSSimon Schubert bridge_ioctl_scache(struct bridge_softc *sc, void *arg)
1414ac93838fSSimon Schubert {
1415ac93838fSSimon Schubert struct ifbrparam *param = arg;
14164394693cSSepherosa Ziehau struct ifnet *ifp = sc->sc_ifp;
1417ac93838fSSimon Schubert
1418ac93838fSSimon Schubert sc->sc_brtmax = param->ifbrp_csize;
14194394693cSSepherosa Ziehau
1420a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(ifp);
1421ac93838fSSimon Schubert bridge_rttrim(sc);
1422a3dd34d2SSepherosa Ziehau ifnet_serialize_all(ifp);
1423ac93838fSSimon Schubert
1424ac93838fSSimon Schubert return (0);
1425ac93838fSSimon Schubert }
1426ac93838fSSimon Schubert
1427d217f5e5SScott Ullrich static int
bridge_ioctl_gcache(struct bridge_softc * sc,void * arg)1428ac93838fSSimon Schubert bridge_ioctl_gcache(struct bridge_softc *sc, void *arg)
1429ac93838fSSimon Schubert {
1430ac93838fSSimon Schubert struct ifbrparam *param = arg;
1431ac93838fSSimon Schubert
1432ac93838fSSimon Schubert param->ifbrp_csize = sc->sc_brtmax;
1433ac93838fSSimon Schubert
1434ac93838fSSimon Schubert return (0);
1435ac93838fSSimon Schubert }
1436ac93838fSSimon Schubert
1437d217f5e5SScott Ullrich static int
bridge_ioctl_gifs(struct bridge_softc * sc,void * arg)1438ac93838fSSimon Schubert bridge_ioctl_gifs(struct bridge_softc *sc, void *arg)
1439ac93838fSSimon Schubert {
14402d4d3c93SSepherosa Ziehau struct bridge_control_arg *bc_arg = arg;
1441ac93838fSSimon Schubert struct ifbifconf *bifc = arg;
1442ac93838fSSimon Schubert struct bridge_iflist *bif;
14432d4d3c93SSepherosa Ziehau struct ifbreq *breq;
14442d4d3c93SSepherosa Ziehau int count, len;
1445ac93838fSSimon Schubert
1446ac93838fSSimon Schubert count = 0;
144770d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next)
1448ac93838fSSimon Schubert count++;
144970d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
1450d217f5e5SScott Ullrich count++;
1451ac93838fSSimon Schubert
1452ac93838fSSimon Schubert if (bifc->ifbic_len == 0) {
14532d4d3c93SSepherosa Ziehau bifc->ifbic_len = sizeof(*breq) * count;
14542d4d3c93SSepherosa Ziehau return 0;
14552d4d3c93SSepherosa Ziehau } else if (count == 0 || bifc->ifbic_len < sizeof(*breq)) {
14562d4d3c93SSepherosa Ziehau bifc->ifbic_len = 0;
14572d4d3c93SSepherosa Ziehau return 0;
1458ac93838fSSimon Schubert }
1459ac93838fSSimon Schubert
14602d4d3c93SSepherosa Ziehau len = min(bifc->ifbic_len, sizeof(*breq) * count);
14612d4d3c93SSepherosa Ziehau KKASSERT(len >= sizeof(*breq));
14622d4d3c93SSepherosa Ziehau
1463d15c1fc9SSepherosa Ziehau breq = kmalloc(len, M_TEMP, M_WAITOK | M_NULLOK | M_ZERO);
14642d4d3c93SSepherosa Ziehau if (breq == NULL) {
14652d4d3c93SSepherosa Ziehau bifc->ifbic_len = 0;
14662d4d3c93SSepherosa Ziehau return ENOMEM;
14672d4d3c93SSepherosa Ziehau }
14682d4d3c93SSepherosa Ziehau bc_arg->bca_kptr = breq;
14692d4d3c93SSepherosa Ziehau
1470ac93838fSSimon Schubert count = 0;
147170d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
14722d4d3c93SSepherosa Ziehau if (len < sizeof(*breq))
1473ac93838fSSimon Schubert break;
1474ac93838fSSimon Schubert
14752d4d3c93SSepherosa Ziehau strlcpy(breq->ifbr_ifsname, bif->bif_ifp->if_xname,
14762d4d3c93SSepherosa Ziehau sizeof(breq->ifbr_ifsname));
147770d9a675SMatthew Dillon bridge_ioctl_fillflags(sc, bif, breq);
14782d4d3c93SSepherosa Ziehau breq++;
1479ac93838fSSimon Schubert count++;
14802d4d3c93SSepherosa Ziehau len -= sizeof(*breq);
1481ac93838fSSimon Schubert }
148270d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) {
14832d4d3c93SSepherosa Ziehau if (len < sizeof(*breq))
1484d217f5e5SScott Ullrich break;
1485d217f5e5SScott Ullrich
14862d4d3c93SSepherosa Ziehau strlcpy(breq->ifbr_ifsname, bif->bif_ifp->if_xname,
14872d4d3c93SSepherosa Ziehau sizeof(breq->ifbr_ifsname));
14882d4d3c93SSepherosa Ziehau breq->ifbr_ifsflags = bif->bif_flags;
14892d4d3c93SSepherosa Ziehau breq->ifbr_portno = bif->bif_ifp->if_index & 0xff;
14902d4d3c93SSepherosa Ziehau breq++;
1491d217f5e5SScott Ullrich count++;
14922d4d3c93SSepherosa Ziehau len -= sizeof(*breq);
1493d217f5e5SScott Ullrich }
1494ac93838fSSimon Schubert
14952d4d3c93SSepherosa Ziehau bifc->ifbic_len = sizeof(*breq) * count;
14962d4d3c93SSepherosa Ziehau KKASSERT(bifc->ifbic_len > 0);
14972d4d3c93SSepherosa Ziehau
14982d4d3c93SSepherosa Ziehau bc_arg->bca_len = bifc->ifbic_len;
14992d4d3c93SSepherosa Ziehau bc_arg->bca_uptr = bifc->ifbic_req;
15002d4d3c93SSepherosa Ziehau return 0;
1501ac93838fSSimon Schubert }
1502ac93838fSSimon Schubert
1503d217f5e5SScott Ullrich static int
bridge_ioctl_rts(struct bridge_softc * sc,void * arg)1504ac93838fSSimon Schubert bridge_ioctl_rts(struct bridge_softc *sc, void *arg)
1505ac93838fSSimon Schubert {
15062d4d3c93SSepherosa Ziehau struct bridge_control_arg *bc_arg = arg;
1507ac93838fSSimon Schubert struct ifbaconf *bac = arg;
1508ac93838fSSimon Schubert struct bridge_rtnode *brt;
15092d4d3c93SSepherosa Ziehau struct ifbareq *bareq;
15102d4d3c93SSepherosa Ziehau int count, len;
1511ac93838fSSimon Schubert
15122d4d3c93SSepherosa Ziehau count = 0;
15134394693cSSepherosa Ziehau LIST_FOREACH(brt, &sc->sc_rtlists[mycpuid], brt_list)
15142d4d3c93SSepherosa Ziehau count++;
1515ac93838fSSimon Schubert
15162d4d3c93SSepherosa Ziehau if (bac->ifbac_len == 0) {
15172d4d3c93SSepherosa Ziehau bac->ifbac_len = sizeof(*bareq) * count;
15182d4d3c93SSepherosa Ziehau return 0;
15192d4d3c93SSepherosa Ziehau } else if (count == 0 || bac->ifbac_len < sizeof(*bareq)) {
15202d4d3c93SSepherosa Ziehau bac->ifbac_len = 0;
15212d4d3c93SSepherosa Ziehau return 0;
15222d4d3c93SSepherosa Ziehau }
15232d4d3c93SSepherosa Ziehau
15242d4d3c93SSepherosa Ziehau len = min(bac->ifbac_len, sizeof(*bareq) * count);
15252d4d3c93SSepherosa Ziehau KKASSERT(len >= sizeof(*bareq));
15262d4d3c93SSepherosa Ziehau
1527d15c1fc9SSepherosa Ziehau bareq = kmalloc(len, M_TEMP, M_WAITOK | M_NULLOK | M_ZERO);
15282d4d3c93SSepherosa Ziehau if (bareq == NULL) {
15292d4d3c93SSepherosa Ziehau bac->ifbac_len = 0;
15302d4d3c93SSepherosa Ziehau return ENOMEM;
15312d4d3c93SSepherosa Ziehau }
15322d4d3c93SSepherosa Ziehau bc_arg->bca_kptr = bareq;
15332d4d3c93SSepherosa Ziehau
15342d4d3c93SSepherosa Ziehau count = 0;
15354394693cSSepherosa Ziehau LIST_FOREACH(brt, &sc->sc_rtlists[mycpuid], brt_list) {
15364394693cSSepherosa Ziehau struct bridge_rtinfo *bri = brt->brt_info;
1537cec73927SMatthew Dillon time_t expire;
15384394693cSSepherosa Ziehau
15392d4d3c93SSepherosa Ziehau if (len < sizeof(*bareq))
15402d4d3c93SSepherosa Ziehau break;
15412d4d3c93SSepherosa Ziehau
15424394693cSSepherosa Ziehau strlcpy(bareq->ifba_ifsname, bri->bri_ifp->if_xname,
15432d4d3c93SSepherosa Ziehau sizeof(bareq->ifba_ifsname));
15442d4d3c93SSepherosa Ziehau memcpy(bareq->ifba_dst, brt->brt_addr, sizeof(brt->brt_addr));
15454394693cSSepherosa Ziehau expire = bri->bri_expire;
15464394693cSSepherosa Ziehau if ((bri->bri_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC &&
1547cec73927SMatthew Dillon time_uptime < expire)
1548cec73927SMatthew Dillon bareq->ifba_expire = expire - time_uptime;
1549ac93838fSSimon Schubert else
15502d4d3c93SSepherosa Ziehau bareq->ifba_expire = 0;
15514394693cSSepherosa Ziehau bareq->ifba_flags = bri->bri_flags;
15522d4d3c93SSepherosa Ziehau bareq++;
1553ac93838fSSimon Schubert count++;
15542d4d3c93SSepherosa Ziehau len -= sizeof(*bareq);
1555ac93838fSSimon Schubert }
15562d4d3c93SSepherosa Ziehau
15572d4d3c93SSepherosa Ziehau bac->ifbac_len = sizeof(*bareq) * count;
15582d4d3c93SSepherosa Ziehau KKASSERT(bac->ifbac_len > 0);
15592d4d3c93SSepherosa Ziehau
15602d4d3c93SSepherosa Ziehau bc_arg->bca_len = bac->ifbac_len;
15612d4d3c93SSepherosa Ziehau bc_arg->bca_uptr = bac->ifbac_req;
15622d4d3c93SSepherosa Ziehau return 0;
1563ac93838fSSimon Schubert }
1564ac93838fSSimon Schubert
1565d217f5e5SScott Ullrich static int
bridge_ioctl_saddr(struct bridge_softc * sc,void * arg)1566ac93838fSSimon Schubert bridge_ioctl_saddr(struct bridge_softc *sc, void *arg)
1567ac93838fSSimon Schubert {
1568ac93838fSSimon Schubert struct ifbareq *req = arg;
1569ac93838fSSimon Schubert struct bridge_iflist *bif;
15704394693cSSepherosa Ziehau struct ifnet *ifp = sc->sc_ifp;
1571ac93838fSSimon Schubert int error;
1572ac93838fSSimon Schubert
15732c9effcfSSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp);
15744394693cSSepherosa Ziehau
1575ac93838fSSimon Schubert bif = bridge_lookup_member(sc, req->ifba_ifsname);
1576ac93838fSSimon Schubert if (bif == NULL)
1577ac93838fSSimon Schubert return (ENOENT);
1578ac93838fSSimon Schubert
1579a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(ifp);
15804394693cSSepherosa Ziehau error = bridge_rtsaddr(sc, req->ifba_dst, bif->bif_ifp,
1581ac93838fSSimon Schubert req->ifba_flags);
1582a3dd34d2SSepherosa Ziehau ifnet_serialize_all(ifp);
1583ac93838fSSimon Schubert return (error);
1584ac93838fSSimon Schubert }
1585ac93838fSSimon Schubert
1586d217f5e5SScott Ullrich static int
bridge_ioctl_sto(struct bridge_softc * sc,void * arg)1587ac93838fSSimon Schubert bridge_ioctl_sto(struct bridge_softc *sc, void *arg)
1588ac93838fSSimon Schubert {
1589ac93838fSSimon Schubert struct ifbrparam *param = arg;
1590ac93838fSSimon Schubert
1591ac93838fSSimon Schubert sc->sc_brttimeout = param->ifbrp_ctime;
1592ac93838fSSimon Schubert
1593ac93838fSSimon Schubert return (0);
1594ac93838fSSimon Schubert }
1595ac93838fSSimon Schubert
1596d217f5e5SScott Ullrich static int
bridge_ioctl_gto(struct bridge_softc * sc,void * arg)1597ac93838fSSimon Schubert bridge_ioctl_gto(struct bridge_softc *sc, void *arg)
1598ac93838fSSimon Schubert {
1599ac93838fSSimon Schubert struct ifbrparam *param = arg;
1600ac93838fSSimon Schubert
1601ac93838fSSimon Schubert param->ifbrp_ctime = sc->sc_brttimeout;
1602ac93838fSSimon Schubert
1603ac93838fSSimon Schubert return (0);
1604ac93838fSSimon Schubert }
1605ac93838fSSimon Schubert
1606d217f5e5SScott Ullrich static int
bridge_ioctl_daddr(struct bridge_softc * sc,void * arg)1607ac93838fSSimon Schubert bridge_ioctl_daddr(struct bridge_softc *sc, void *arg)
1608ac93838fSSimon Schubert {
1609ac93838fSSimon Schubert struct ifbareq *req = arg;
16104394693cSSepherosa Ziehau struct ifnet *ifp = sc->sc_ifp;
16114394693cSSepherosa Ziehau int error;
1612ac93838fSSimon Schubert
1613a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(ifp);
16144394693cSSepherosa Ziehau error = bridge_rtdaddr(sc, req->ifba_dst);
1615a3dd34d2SSepherosa Ziehau ifnet_serialize_all(ifp);
16164394693cSSepherosa Ziehau return error;
1617ac93838fSSimon Schubert }
1618ac93838fSSimon Schubert
1619d217f5e5SScott Ullrich static int
bridge_ioctl_flush(struct bridge_softc * sc,void * arg)1620ac93838fSSimon Schubert bridge_ioctl_flush(struct bridge_softc *sc, void *arg)
1621ac93838fSSimon Schubert {
1622ac93838fSSimon Schubert struct ifbreq *req = arg;
16234394693cSSepherosa Ziehau struct ifnet *ifp = sc->sc_ifp;
1624ac93838fSSimon Schubert
1625a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(ifp);
162630ced003SSepherosa Ziehau bridge_rtflush(sc, req->ifbr_ifsflags | IFBF_FLUSHSYNC);
1627a3dd34d2SSepherosa Ziehau ifnet_serialize_all(ifp);
1628ac93838fSSimon Schubert
1629ac93838fSSimon Schubert return (0);
1630ac93838fSSimon Schubert }
1631ac93838fSSimon Schubert
1632d217f5e5SScott Ullrich static int
bridge_ioctl_gpri(struct bridge_softc * sc,void * arg)1633ac93838fSSimon Schubert bridge_ioctl_gpri(struct bridge_softc *sc, void *arg)
1634ac93838fSSimon Schubert {
1635ac93838fSSimon Schubert struct ifbrparam *param = arg;
1636ac93838fSSimon Schubert
1637ac93838fSSimon Schubert param->ifbrp_prio = sc->sc_bridge_priority;
1638ac93838fSSimon Schubert
1639ac93838fSSimon Schubert return (0);
1640ac93838fSSimon Schubert }
1641ac93838fSSimon Schubert
1642d217f5e5SScott Ullrich static int
bridge_ioctl_spri(struct bridge_softc * sc,void * arg)1643ac93838fSSimon Schubert bridge_ioctl_spri(struct bridge_softc *sc, void *arg)
1644ac93838fSSimon Schubert {
1645ac93838fSSimon Schubert struct ifbrparam *param = arg;
1646ac93838fSSimon Schubert
1647ac93838fSSimon Schubert sc->sc_bridge_priority = param->ifbrp_prio;
1648ac93838fSSimon Schubert
1649ac93838fSSimon Schubert if (sc->sc_ifp->if_flags & IFF_RUNNING)
1650ac93838fSSimon Schubert bstp_initialization(sc);
1651ac93838fSSimon Schubert
1652ac93838fSSimon Schubert return (0);
1653ac93838fSSimon Schubert }
1654ac93838fSSimon Schubert
1655d217f5e5SScott Ullrich static int
bridge_ioctl_reinit(struct bridge_softc * sc,void * arg __unused)16569b42fdc9SMatthew Dillon bridge_ioctl_reinit(struct bridge_softc *sc, void *arg __unused)
16579b42fdc9SMatthew Dillon {
16589b42fdc9SMatthew Dillon if (sc->sc_ifp->if_flags & IFF_RUNNING)
16599b42fdc9SMatthew Dillon bstp_initialization(sc);
16609b42fdc9SMatthew Dillon return (0);
16619b42fdc9SMatthew Dillon }
16629b42fdc9SMatthew Dillon
16639b42fdc9SMatthew Dillon static int
bridge_ioctl_ght(struct bridge_softc * sc,void * arg)1664ac93838fSSimon Schubert bridge_ioctl_ght(struct bridge_softc *sc, void *arg)
1665ac93838fSSimon Schubert {
1666ac93838fSSimon Schubert struct ifbrparam *param = arg;
1667ac93838fSSimon Schubert
1668ac93838fSSimon Schubert param->ifbrp_hellotime = sc->sc_bridge_hello_time >> 8;
1669ac93838fSSimon Schubert
1670ac93838fSSimon Schubert return (0);
1671ac93838fSSimon Schubert }
1672ac93838fSSimon Schubert
1673d217f5e5SScott Ullrich static int
bridge_ioctl_sht(struct bridge_softc * sc,void * arg)1674ac93838fSSimon Schubert bridge_ioctl_sht(struct bridge_softc *sc, void *arg)
1675ac93838fSSimon Schubert {
1676ac93838fSSimon Schubert struct ifbrparam *param = arg;
1677ac93838fSSimon Schubert
1678ac93838fSSimon Schubert if (param->ifbrp_hellotime == 0)
1679ac93838fSSimon Schubert return (EINVAL);
1680ac93838fSSimon Schubert sc->sc_bridge_hello_time = param->ifbrp_hellotime << 8;
1681ac93838fSSimon Schubert
1682ac93838fSSimon Schubert if (sc->sc_ifp->if_flags & IFF_RUNNING)
1683ac93838fSSimon Schubert bstp_initialization(sc);
1684ac93838fSSimon Schubert
1685ac93838fSSimon Schubert return (0);
1686ac93838fSSimon Schubert }
1687ac93838fSSimon Schubert
1688d217f5e5SScott Ullrich static int
bridge_ioctl_gfd(struct bridge_softc * sc,void * arg)1689ac93838fSSimon Schubert bridge_ioctl_gfd(struct bridge_softc *sc, void *arg)
1690ac93838fSSimon Schubert {
1691ac93838fSSimon Schubert struct ifbrparam *param = arg;
1692ac93838fSSimon Schubert
1693ac93838fSSimon Schubert param->ifbrp_fwddelay = sc->sc_bridge_forward_delay >> 8;
1694ac93838fSSimon Schubert
1695ac93838fSSimon Schubert return (0);
1696ac93838fSSimon Schubert }
1697ac93838fSSimon Schubert
1698d217f5e5SScott Ullrich static int
bridge_ioctl_sfd(struct bridge_softc * sc,void * arg)1699ac93838fSSimon Schubert bridge_ioctl_sfd(struct bridge_softc *sc, void *arg)
1700ac93838fSSimon Schubert {
1701ac93838fSSimon Schubert struct ifbrparam *param = arg;
1702ac93838fSSimon Schubert
1703ac93838fSSimon Schubert if (param->ifbrp_fwddelay == 0)
1704ac93838fSSimon Schubert return (EINVAL);
1705ac93838fSSimon Schubert sc->sc_bridge_forward_delay = param->ifbrp_fwddelay << 8;
1706ac93838fSSimon Schubert
1707ac93838fSSimon Schubert if (sc->sc_ifp->if_flags & IFF_RUNNING)
1708ac93838fSSimon Schubert bstp_initialization(sc);
1709ac93838fSSimon Schubert
1710ac93838fSSimon Schubert return (0);
1711ac93838fSSimon Schubert }
1712ac93838fSSimon Schubert
1713d217f5e5SScott Ullrich static int
bridge_ioctl_gma(struct bridge_softc * sc,void * arg)1714ac93838fSSimon Schubert bridge_ioctl_gma(struct bridge_softc *sc, void *arg)
1715ac93838fSSimon Schubert {
1716ac93838fSSimon Schubert struct ifbrparam *param = arg;
1717ac93838fSSimon Schubert
1718ac93838fSSimon Schubert param->ifbrp_maxage = sc->sc_bridge_max_age >> 8;
1719ac93838fSSimon Schubert
1720ac93838fSSimon Schubert return (0);
1721ac93838fSSimon Schubert }
1722ac93838fSSimon Schubert
1723d217f5e5SScott Ullrich static int
bridge_ioctl_sma(struct bridge_softc * sc,void * arg)1724ac93838fSSimon Schubert bridge_ioctl_sma(struct bridge_softc *sc, void *arg)
1725ac93838fSSimon Schubert {
1726ac93838fSSimon Schubert struct ifbrparam *param = arg;
1727ac93838fSSimon Schubert
1728ac93838fSSimon Schubert if (param->ifbrp_maxage == 0)
1729ac93838fSSimon Schubert return (EINVAL);
1730ac93838fSSimon Schubert sc->sc_bridge_max_age = param->ifbrp_maxage << 8;
1731ac93838fSSimon Schubert
1732ac93838fSSimon Schubert if (sc->sc_ifp->if_flags & IFF_RUNNING)
1733ac93838fSSimon Schubert bstp_initialization(sc);
1734ac93838fSSimon Schubert
1735ac93838fSSimon Schubert return (0);
1736ac93838fSSimon Schubert }
1737ac93838fSSimon Schubert
1738d217f5e5SScott Ullrich static int
bridge_ioctl_sifprio(struct bridge_softc * sc,void * arg)1739ac93838fSSimon Schubert bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg)
1740ac93838fSSimon Schubert {
1741ac93838fSSimon Schubert struct ifbreq *req = arg;
1742ac93838fSSimon Schubert struct bridge_iflist *bif;
1743ac93838fSSimon Schubert
1744ac93838fSSimon Schubert bif = bridge_lookup_member(sc, req->ifbr_ifsname);
1745ac93838fSSimon Schubert if (bif == NULL)
1746ac93838fSSimon Schubert return (ENOENT);
1747ac93838fSSimon Schubert
1748ac93838fSSimon Schubert bif->bif_priority = req->ifbr_priority;
1749ac93838fSSimon Schubert
1750ac93838fSSimon Schubert if (sc->sc_ifp->if_flags & IFF_RUNNING)
1751ac93838fSSimon Schubert bstp_initialization(sc);
1752ac93838fSSimon Schubert
1753ac93838fSSimon Schubert return (0);
1754ac93838fSSimon Schubert }
1755ac93838fSSimon Schubert
1756d217f5e5SScott Ullrich static int
bridge_ioctl_sifcost(struct bridge_softc * sc,void * arg)1757ac93838fSSimon Schubert bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg)
1758ac93838fSSimon Schubert {
1759ac93838fSSimon Schubert struct ifbreq *req = arg;
1760ac93838fSSimon Schubert struct bridge_iflist *bif;
1761ac93838fSSimon Schubert
1762ac93838fSSimon Schubert bif = bridge_lookup_member(sc, req->ifbr_ifsname);
1763ac93838fSSimon Schubert if (bif == NULL)
1764ac93838fSSimon Schubert return (ENOENT);
1765ac93838fSSimon Schubert
1766ac93838fSSimon Schubert bif->bif_path_cost = req->ifbr_path_cost;
1767ac93838fSSimon Schubert
1768ac93838fSSimon Schubert if (sc->sc_ifp->if_flags & IFF_RUNNING)
1769ac93838fSSimon Schubert bstp_initialization(sc);
1770ac93838fSSimon Schubert
1771ac93838fSSimon Schubert return (0);
1772ac93838fSSimon Schubert }
1773ac93838fSSimon Schubert
1774d217f5e5SScott Ullrich static int
bridge_ioctl_sifbondwght(struct bridge_softc * sc,void * arg)17751e858374SMatthew Dillon bridge_ioctl_sifbondwght(struct bridge_softc *sc, void *arg)
17761e858374SMatthew Dillon {
17771e858374SMatthew Dillon struct ifbreq *req = arg;
17781e858374SMatthew Dillon struct bridge_iflist *bif;
17791e858374SMatthew Dillon
17801e858374SMatthew Dillon bif = bridge_lookup_member(sc, req->ifbr_ifsname);
17811e858374SMatthew Dillon if (bif == NULL)
17821e858374SMatthew Dillon return (ENOENT);
17831e858374SMatthew Dillon
17841e858374SMatthew Dillon bif->bif_bond_weight = req->ifbr_bond_weight;
17851e858374SMatthew Dillon
17861e858374SMatthew Dillon /* no reinit needed */
17871e858374SMatthew Dillon
17881e858374SMatthew Dillon return (0);
17891e858374SMatthew Dillon }
17901e858374SMatthew Dillon
17911e858374SMatthew Dillon static int
bridge_ioctl_addspan(struct bridge_softc * sc,void * arg)1792d217f5e5SScott Ullrich bridge_ioctl_addspan(struct bridge_softc *sc, void *arg)
1793d217f5e5SScott Ullrich {
1794d217f5e5SScott Ullrich struct ifbreq *req = arg;
17958f7b13efSSepherosa Ziehau struct bridge_iflist *bif;
1796d217f5e5SScott Ullrich struct ifnet *ifs;
179770d9a675SMatthew Dillon struct bridge_ifinfo *bif_info;
1798d217f5e5SScott Ullrich
1799b4051e25SSepherosa Ziehau ifs = ifunit_netisr(req->ifbr_ifsname);
1800d217f5e5SScott Ullrich if (ifs == NULL)
1801d217f5e5SScott Ullrich return (ENOENT);
1802d217f5e5SScott Ullrich
180370d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
1804d217f5e5SScott Ullrich if (ifs == bif->bif_ifp)
1805d217f5e5SScott Ullrich return (EBUSY);
1806d217f5e5SScott Ullrich
1807d217f5e5SScott Ullrich if (ifs->if_bridge != NULL)
1808d217f5e5SScott Ullrich return (EBUSY);
1809d217f5e5SScott Ullrich
1810d217f5e5SScott Ullrich switch (ifs->if_type) {
1811d217f5e5SScott Ullrich case IFT_ETHER:
1812d217f5e5SScott Ullrich case IFT_GIF:
1813d217f5e5SScott Ullrich case IFT_L2VLAN:
1814d217f5e5SScott Ullrich break;
1815d76dd5c7SSepherosa Ziehau
1816d217f5e5SScott Ullrich default:
1817d217f5e5SScott Ullrich return (EINVAL);
1818d217f5e5SScott Ullrich }
1819d217f5e5SScott Ullrich
182070d9a675SMatthew Dillon /*
182170d9a675SMatthew Dillon * bif_info is needed for bif_flags
182270d9a675SMatthew Dillon */
182370d9a675SMatthew Dillon bif_info = kmalloc(sizeof(*bif_info), M_DEVBUF, M_WAITOK | M_ZERO);
182470d9a675SMatthew Dillon bif_info->bifi_ifp = ifs;
182570d9a675SMatthew Dillon
18266676e111SThomas E. Spanjaard bif = kmalloc(sizeof(*bif), M_DEVBUF, M_WAITOK | M_ZERO);
1827d217f5e5SScott Ullrich bif->bif_ifp = ifs;
182870d9a675SMatthew Dillon bif->bif_info = bif_info;
1829d217f5e5SScott Ullrich bif->bif_flags = IFBIF_SPAN;
18308f7b13efSSepherosa Ziehau /* NOTE: span bif does not need bridge_ifinfo */
1831d217f5e5SScott Ullrich
183270d9a675SMatthew Dillon TAILQ_INSERT_HEAD(&sc->sc_spanlist, bif, bif_next);
1833d217f5e5SScott Ullrich
1834d895303bSSepherosa Ziehau sc->sc_span = 1;
1835d895303bSSepherosa Ziehau
1836d217f5e5SScott Ullrich return (0);
1837d217f5e5SScott Ullrich }
1838d217f5e5SScott Ullrich
1839d217f5e5SScott Ullrich static int
bridge_ioctl_delspan(struct bridge_softc * sc,void * arg)1840d217f5e5SScott Ullrich bridge_ioctl_delspan(struct bridge_softc *sc, void *arg)
1841d217f5e5SScott Ullrich {
1842d217f5e5SScott Ullrich struct ifbreq *req = arg;
1843d217f5e5SScott Ullrich struct bridge_iflist *bif;
1844d217f5e5SScott Ullrich struct ifnet *ifs;
1845d217f5e5SScott Ullrich
1846b4051e25SSepherosa Ziehau ifs = ifunit_netisr(req->ifbr_ifsname);
1847d217f5e5SScott Ullrich if (ifs == NULL)
1848d217f5e5SScott Ullrich return (ENOENT);
1849d217f5e5SScott Ullrich
185070d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
1851d217f5e5SScott Ullrich if (ifs == bif->bif_ifp)
1852d217f5e5SScott Ullrich break;
1853d217f5e5SScott Ullrich
1854d217f5e5SScott Ullrich if (bif == NULL)
1855d217f5e5SScott Ullrich return (ENOENT);
1856d217f5e5SScott Ullrich
1857d217f5e5SScott Ullrich bridge_delete_span(sc, bif);
1858d217f5e5SScott Ullrich
185970d9a675SMatthew Dillon if (TAILQ_EMPTY(&sc->sc_spanlist))
1860d895303bSSepherosa Ziehau sc->sc_span = 0;
1861d895303bSSepherosa Ziehau
1862d217f5e5SScott Ullrich return (0);
1863d217f5e5SScott Ullrich }
1864d217f5e5SScott Ullrich
1865d217f5e5SScott Ullrich static void
bridge_ifdetach_dispatch(netmsg_t msg)1866002c1265SMatthew Dillon bridge_ifdetach_dispatch(netmsg_t msg)
1867ac93838fSSimon Schubert {
1868ac308789SSepherosa Ziehau struct ifnet *ifp, *bifp;
1869ac308789SSepherosa Ziehau struct bridge_softc *sc;
1870d217f5e5SScott Ullrich struct bridge_iflist *bif;
1871ac308789SSepherosa Ziehau
1872002c1265SMatthew Dillon ifp = msg->lmsg.u.ms_resultp;
1873ac308789SSepherosa Ziehau sc = ifp->if_bridge;
1874ac93838fSSimon Schubert
1875d217f5e5SScott Ullrich /* Check if the interface is a bridge member */
1876d217f5e5SScott Ullrich if (sc != NULL) {
1877bdfc79d0SSepherosa Ziehau bifp = sc->sc_ifp;
1878bdfc79d0SSepherosa Ziehau
1879a3dd34d2SSepherosa Ziehau ifnet_serialize_all(bifp);
1880d217f5e5SScott Ullrich
1881d217f5e5SScott Ullrich bif = bridge_lookup_member_if(sc, ifp);
1882ac308789SSepherosa Ziehau if (bif != NULL) {
1883d217f5e5SScott Ullrich bridge_delete_member(sc, bif, 1);
1884ac308789SSepherosa Ziehau } else {
1885ac308789SSepherosa Ziehau /* XXX Why bif will be NULL? */
1886ac308789SSepherosa Ziehau }
1887d217f5e5SScott Ullrich
1888a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(bifp);
1889ac308789SSepherosa Ziehau goto reply;
1890d217f5e5SScott Ullrich }
1891d217f5e5SScott Ullrich
1892ac308789SSepherosa Ziehau crit_enter(); /* XXX MP */
1893ac308789SSepherosa Ziehau
1894d217f5e5SScott Ullrich /* Check if the interface is a span port */
1895d217f5e5SScott Ullrich LIST_FOREACH(sc, &bridge_list, sc_list) {
1896bdfc79d0SSepherosa Ziehau bifp = sc->sc_ifp;
1897bdfc79d0SSepherosa Ziehau
1898a3dd34d2SSepherosa Ziehau ifnet_serialize_all(bifp);
1899bdfc79d0SSepherosa Ziehau
190070d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
1901d217f5e5SScott Ullrich if (ifp == bif->bif_ifp) {
1902d217f5e5SScott Ullrich bridge_delete_span(sc, bif);
1903d217f5e5SScott Ullrich break;
1904d217f5e5SScott Ullrich }
1905bdfc79d0SSepherosa Ziehau
1906a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(bifp);
1907d217f5e5SScott Ullrich }
1908ac308789SSepherosa Ziehau
1909ac308789SSepherosa Ziehau crit_exit();
1910ac308789SSepherosa Ziehau
1911ac308789SSepherosa Ziehau reply:
1912002c1265SMatthew Dillon lwkt_replymsg(&msg->lmsg, 0);
1913ac308789SSepherosa Ziehau }
1914ac308789SSepherosa Ziehau
1915ac308789SSepherosa Ziehau /*
1916ac308789SSepherosa Ziehau * bridge_ifdetach:
1917ac308789SSepherosa Ziehau *
1918ac308789SSepherosa Ziehau * Detach an interface from a bridge. Called when a member
1919ac308789SSepherosa Ziehau * interface is detaching.
1920ac308789SSepherosa Ziehau */
1921ac308789SSepherosa Ziehau static void
bridge_ifdetach(void * arg __unused,struct ifnet * ifp)1922ac308789SSepherosa Ziehau bridge_ifdetach(void *arg __unused, struct ifnet *ifp)
1923ac308789SSepherosa Ziehau {
1924002c1265SMatthew Dillon struct netmsg_base msg;
1925ac308789SSepherosa Ziehau
1926002c1265SMatthew Dillon netmsg_init(&msg, NULL, &curthread->td_msgport,
192748e7b118SMatthew Dillon 0, bridge_ifdetach_dispatch);
1928002c1265SMatthew Dillon msg.lmsg.u.ms_resultp = ifp;
1929ac308789SSepherosa Ziehau
1930002c1265SMatthew Dillon lwkt_domsg(BRIDGE_CFGPORT, &msg.lmsg, 0);
1931ac93838fSSimon Schubert }
1932ac93838fSSimon Schubert
1933ac93838fSSimon Schubert /*
1934ac93838fSSimon Schubert * bridge_init:
1935ac93838fSSimon Schubert *
1936ac93838fSSimon Schubert * Initialize a bridge interface.
1937ac93838fSSimon Schubert */
1938ac93838fSSimon Schubert static void
bridge_init(void * xsc)1939ac93838fSSimon Schubert bridge_init(void *xsc)
1940ac93838fSSimon Schubert {
1941d71129d9SSepherosa Ziehau bridge_control(xsc, SIOCSIFFLAGS, bridge_ioctl_init, NULL);
1942ac93838fSSimon Schubert }
1943ac93838fSSimon Schubert
1944ac93838fSSimon Schubert /*
1945ac93838fSSimon Schubert * bridge_stop:
1946ac93838fSSimon Schubert *
1947ac93838fSSimon Schubert * Stop the bridge interface.
1948ac93838fSSimon Schubert */
1949d217f5e5SScott Ullrich static void
bridge_stop(struct ifnet * ifp)1950867cc45aSSepherosa Ziehau bridge_stop(struct ifnet *ifp)
1951ac93838fSSimon Schubert {
1952d71129d9SSepherosa Ziehau bridge_control(ifp->if_softc, SIOCSIFFLAGS, bridge_ioctl_stop, NULL);
1953ac93838fSSimon Schubert }
1954ac93838fSSimon Schubert
1955ac93838fSSimon Schubert /*
195670d9a675SMatthew Dillon * Returns TRUE if the packet is being sent 'from us'... from our bridge
195770d9a675SMatthew Dillon * interface or from any member of our bridge interface. This is used
195870d9a675SMatthew Dillon * later on to force the MAC to be the MAC of our bridge interface.
195970d9a675SMatthew Dillon */
196070d9a675SMatthew Dillon static int
bridge_from_us(struct bridge_softc * sc,struct ether_header * eh)196170d9a675SMatthew Dillon bridge_from_us(struct bridge_softc *sc, struct ether_header *eh)
196270d9a675SMatthew Dillon {
196370d9a675SMatthew Dillon struct bridge_iflist *bif;
196470d9a675SMatthew Dillon
196570d9a675SMatthew Dillon if (memcmp(eh->ether_shost, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN) == 0)
196670d9a675SMatthew Dillon return (1);
196770d9a675SMatthew Dillon
196870d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
196970d9a675SMatthew Dillon if (memcmp(eh->ether_shost, IF_LLADDR(bif->bif_ifp),
1970e6720526SMatthew Dillon ETHER_ADDR_LEN) == 0)
1971e6720526SMatthew Dillon {
197270d9a675SMatthew Dillon return (1);
197370d9a675SMatthew Dillon }
197470d9a675SMatthew Dillon }
197570d9a675SMatthew Dillon return (0);
197670d9a675SMatthew Dillon }
197770d9a675SMatthew Dillon
197870d9a675SMatthew Dillon /*
1979ac93838fSSimon Schubert * bridge_enqueue:
1980ac93838fSSimon Schubert *
1981ac93838fSSimon Schubert * Enqueue a packet on a bridge member interface.
1982ac93838fSSimon Schubert *
1983ac93838fSSimon Schubert */
1984708a3bfaSSepherosa Ziehau void
bridge_enqueue(struct ifnet * dst_ifp,struct mbuf * m)1985708a3bfaSSepherosa Ziehau bridge_enqueue(struct ifnet *dst_ifp, struct mbuf *m)
1986ac93838fSSimon Schubert {
1987137aa7b3SSepherosa Ziehau struct netmsg_packet *nmp;
1988137aa7b3SSepherosa Ziehau
198986989f49SMatthew Dillon mbuftrackid(m, 64);
199086989f49SMatthew Dillon
1991137aa7b3SSepherosa Ziehau nmp = &m->m_hdr.mh_netmsg;
1992002c1265SMatthew Dillon netmsg_init(&nmp->base, NULL, &netisr_apanic_rport,
199348e7b118SMatthew Dillon 0, bridge_enqueue_handler);
1994137aa7b3SSepherosa Ziehau nmp->nm_packet = m;
1995002c1265SMatthew Dillon nmp->base.lmsg.u.ms_resultp = dst_ifp;
1996137aa7b3SSepherosa Ziehau
19973a51da79SSepherosa Ziehau lwkt_sendmsg_oncpu(netisr_cpuport(mycpuid), &nmp->base.lmsg);
1998ac93838fSSimon Schubert }
1999ac93838fSSimon Schubert
2000ac93838fSSimon Schubert /*
200186989f49SMatthew Dillon * After looking up dst_if in our forwarding table we still have to
200286989f49SMatthew Dillon * deal with channel bonding. Find the best interface in the bonding set.
200386989f49SMatthew Dillon */
200486989f49SMatthew Dillon static struct ifnet *
bridge_select_unicast(struct bridge_softc * sc,struct ifnet * dst_if,int from_blocking,struct mbuf * m)200586989f49SMatthew Dillon bridge_select_unicast(struct bridge_softc *sc, struct ifnet *dst_if,
200686989f49SMatthew Dillon int from_blocking, struct mbuf *m)
200786989f49SMatthew Dillon {
2008e6720526SMatthew Dillon struct bridge_iflist *bif, *alt_bif, *nbif;
2009e6720526SMatthew Dillon int alt_priority, alt_count;
2010e6720526SMatthew Dillon uint8_t alt_state;
201186989f49SMatthew Dillon
201286989f49SMatthew Dillon /*
201386989f49SMatthew Dillon * Unicast, kinda replicates the output side of bridge_output().
201486989f49SMatthew Dillon *
201586989f49SMatthew Dillon * Even though this is a uni-cast packet we may have to select
201686989f49SMatthew Dillon * an interface from a bonding set.
201786989f49SMatthew Dillon */
201886989f49SMatthew Dillon bif = bridge_lookup_member_if(sc, dst_if);
201986989f49SMatthew Dillon if (bif == NULL) {
202086989f49SMatthew Dillon /* Not a member of the bridge (anymore?) */
202186989f49SMatthew Dillon return NULL;
202286989f49SMatthew Dillon }
202386989f49SMatthew Dillon
202486989f49SMatthew Dillon /*
2025e6720526SMatthew Dillon * Send directly if the interface is not part of the spanning
2026e6720526SMatthew Dillon * tree.
2027e6720526SMatthew Dillon */
2028e6720526SMatthew Dillon if ((bif->bif_flags & IFBIF_STP) == 0) {
2029e6720526SMatthew Dillon goto sendunicast;
2030e6720526SMatthew Dillon }
2031e6720526SMatthew Dillon
2032e6720526SMatthew Dillon /*
203386989f49SMatthew Dillon * If STP is enabled on the target we are an equal opportunity
203486989f49SMatthew Dillon * employer and do not necessarily output to dst_if. Instead
203586989f49SMatthew Dillon * scan available links with the same MAC as the current dst_if
203686989f49SMatthew Dillon * and choose the best one.
203786989f49SMatthew Dillon *
2038e6720526SMatthew Dillon * We also need to do this because arp or other cached entries might
2039e6720526SMatthew Dillon * be tagged to the wrong port after a fail-over. We don't want to
2040e6720526SMatthew Dillon * route packets to dead ports when perfectly good ones exist.
204186989f49SMatthew Dillon *
2042e6720526SMatthew Dillon * If LINK2 is set on the bridge, any interfaces in the same bonding
2043e6720526SMatthew Dillon * set as dst_if with the same priority will be round-robined. If
2044e6720526SMatthew Dillon * different priorities, only the highest priority is chosen. In
2045e6720526SMatthew Dillon * this case links in a STP FORWARDING or BONDED state are allowed
2046e6720526SMatthew Dillon * for unicast packets.
204786989f49SMatthew Dillon */
2048e6720526SMatthew Dillon alt_state = BSTP_IFSTATE_LEARNING;
2049e6720526SMatthew Dillon alt_bif = NULL;
205086989f49SMatthew Dillon alt_priority = 0;
2051e6720526SMatthew Dillon alt_count = 0;
205286989f49SMatthew Dillon
2053e6720526SMatthew Dillon TAILQ_FOREACH_MUTABLE(bif, &sc->sc_iflists[mycpuid], bif_next, nbif) {
205486989f49SMatthew Dillon /*
2055e6720526SMatthew Dillon * Ignore interfaces not in the same bonding set as dst_if
2056e6720526SMatthew Dillon * or which are not running.
205786989f49SMatthew Dillon */
2058e6720526SMatthew Dillon if (memcmp(IF_LLADDR(bif->bif_ifp), IF_LLADDR(dst_if),
2059e6720526SMatthew Dillon ETHER_ADDR_LEN) != 0)
2060e6720526SMatthew Dillon {
206186989f49SMatthew Dillon continue;
206286989f49SMatthew Dillon }
206386989f49SMatthew Dillon
206486989f49SMatthew Dillon if ((bif->bif_ifp->if_flags & IFF_RUNNING) == 0)
206586989f49SMatthew Dillon continue;
206686989f49SMatthew Dillon
206786989f49SMatthew Dillon /*
206886989f49SMatthew Dillon * NOTE: We allow tranmissions through a BLOCKING
206986989f49SMatthew Dillon * or LEARNING interface only as a last resort.
207086989f49SMatthew Dillon * We DISALLOW both cases if the receiving
207186989f49SMatthew Dillon *
207286989f49SMatthew Dillon * NOTE: If we send a packet through a learning
207386989f49SMatthew Dillon * interface the receiving end (if also in
207486989f49SMatthew Dillon * LEARNING) will throw it away, so this is
207586989f49SMatthew Dillon * the ultimate last resort.
207686989f49SMatthew Dillon */
207786989f49SMatthew Dillon switch(bif->bif_state) {
207886989f49SMatthew Dillon case BSTP_IFSTATE_LEARNING:
207986989f49SMatthew Dillon if (from_blocking == 0 &&
2080e6720526SMatthew Dillon alt_state == BSTP_IFSTATE_LEARNING &&
2081e6720526SMatthew Dillon bif->bif_priority > alt_priority)
2082e6720526SMatthew Dillon {
208386989f49SMatthew Dillon alt_priority = bif->bif_priority;
2084e6720526SMatthew Dillon alt_bif = bif;
208586989f49SMatthew Dillon }
2086e6720526SMatthew Dillon break;
2087e6720526SMatthew Dillon case BSTP_IFSTATE_BLOCKING:
2088e6720526SMatthew Dillon if (from_blocking == 0 &&
2089e6720526SMatthew Dillon (alt_state == BSTP_IFSTATE_LEARNING ||
2090e6720526SMatthew Dillon (alt_state == BSTP_IFSTATE_BLOCKING &&
2091e6720526SMatthew Dillon bif->bif_priority > alt_priority)))
2092e6720526SMatthew Dillon {
2093e6720526SMatthew Dillon alt_state = BSTP_IFSTATE_BLOCKING;
2094e6720526SMatthew Dillon alt_priority = bif->bif_priority;
2095e6720526SMatthew Dillon alt_bif = bif;
2096e6720526SMatthew Dillon }
2097e6720526SMatthew Dillon break;
209886989f49SMatthew Dillon case BSTP_IFSTATE_L1BLOCKING:
209986989f49SMatthew Dillon case BSTP_IFSTATE_LISTENING:
210086989f49SMatthew Dillon case BSTP_IFSTATE_DISABLED:
210186989f49SMatthew Dillon break;
2102e6720526SMatthew Dillon default:
2103e6720526SMatthew Dillon /*
2104e6720526SMatthew Dillon * Select the best interface in the FORWARDING
2105e6720526SMatthew Dillon * set (or BONDING, but there shouldn't be any
2106e6720526SMatthew Dillon * when LINK2 is not set).
2107e6720526SMatthew Dillon */
2108e6720526SMatthew Dillon if (alt_state != BSTP_IFSTATE_BONDED ||
2109e6720526SMatthew Dillon bif->bif_priority > alt_priority)
2110e6720526SMatthew Dillon {
2111e6720526SMatthew Dillon alt_state = BSTP_IFSTATE_BONDED;
2112e6720526SMatthew Dillon alt_priority = bif->bif_priority;
2113e6720526SMatthew Dillon alt_bif = bif;
2114e6720526SMatthew Dillon alt_count = 0;
2115e6720526SMatthew Dillon } else if (alt_state == BSTP_IFSTATE_BONDED &&
2116e6720526SMatthew Dillon bif->bif_priority == alt_priority)
2117e6720526SMatthew Dillon {
2118e6720526SMatthew Dillon /*
2119e6720526SMatthew Dillon * Round-robin
2120e6720526SMatthew Dillon */
2121e6720526SMatthew Dillon ++alt_count;
2122e6720526SMatthew Dillon }
2123e6720526SMatthew Dillon break;
2124e6720526SMatthew Dillon }
212586989f49SMatthew Dillon }
212686989f49SMatthew Dillon
212786989f49SMatthew Dillon /*
2128e6720526SMatthew Dillon * If bonding is enabled (LINK2) and there were multiple interfaces
2129e6720526SMatthew Dillon * at the selected priority level, count packets and switch the
2130e6720526SMatthew Dillon * output interface.
2131e6720526SMatthew Dillon *
2132e6720526SMatthew Dillon * XXX need to use the toepliz hash or something like that instead
2133e6720526SMatthew Dillon * of a dumb packet round-robin.
213486989f49SMatthew Dillon */
2135e6720526SMatthew Dillon if (alt_count && (sc->sc_ifp->if_flags & IFF_LINK2)) {
2136e6720526SMatthew Dillon if (++alt_bif->bif_bond_count >= alt_bif->bif_bond_weight) {
2137e6720526SMatthew Dillon alt_bif->bif_bond_count = 0;
213886989f49SMatthew Dillon TAILQ_REMOVE(&sc->sc_iflists[mycpuid],
2139e6720526SMatthew Dillon alt_bif, bif_next);
214086989f49SMatthew Dillon TAILQ_INSERT_TAIL(
214186989f49SMatthew Dillon &sc->sc_iflists[mycpuid],
2142e6720526SMatthew Dillon alt_bif, bif_next);
214386989f49SMatthew Dillon }
214486989f49SMatthew Dillon }
214586989f49SMatthew Dillon
214686989f49SMatthew Dillon /*
2147e6720526SMatthew Dillon * After loop, alt_if is the interface we selected. alt_if can
2148e6720526SMatthew Dillon * be NULL.
214986989f49SMatthew Dillon */
2150e6720526SMatthew Dillon if (alt_bif)
2151e6720526SMatthew Dillon dst_if = alt_bif->bif_ifp;
215286989f49SMatthew Dillon
2153e6720526SMatthew Dillon sendunicast:
215486989f49SMatthew Dillon /*
215586989f49SMatthew Dillon * At this point, we're dealing with a unicast frame
215686989f49SMatthew Dillon * going to a different interface.
215786989f49SMatthew Dillon */
215886989f49SMatthew Dillon if ((dst_if->if_flags & IFF_RUNNING) == 0)
215986989f49SMatthew Dillon dst_if = NULL;
216086989f49SMatthew Dillon return (dst_if);
216186989f49SMatthew Dillon }
216286989f49SMatthew Dillon
216386989f49SMatthew Dillon
216486989f49SMatthew Dillon /*
2165e6720526SMatthew Dillon * bridge_output
2166ac93838fSSimon Schubert *
2167e6720526SMatthew Dillon * Issue locally originated (not forwarded) packet to the bridge. ifp
2168e6720526SMatthew Dillon * is the nominal interface the system route table is trying to send
2169e6720526SMatthew Dillon * it to, but we get here because that interface is part of the bridge
2170e6720526SMatthew Dillon * so really the packet is being sent to the whole bridge.
2171ac93838fSSimon Schubert *
2172ac93838fSSimon Schubert * The mbuf has the Ethernet header already attached. We must
2173ac93838fSSimon Schubert * enqueue or free the mbuf before returning.
2174ac93838fSSimon Schubert */
2175a18eb4b7SSepherosa Ziehau static int
bridge_output(struct ifnet * ifp,struct mbuf * m)2176eb366364SSepherosa Ziehau bridge_output(struct ifnet *ifp, struct mbuf *m)
2177ac93838fSSimon Schubert {
217889ea766dSSepherosa Ziehau struct bridge_softc *sc = ifp->if_bridge;
21793677aae9SMatthew Dillon struct bridge_iflist *bif, *nbif;
2180ac93838fSSimon Schubert struct ether_header *eh;
21811e858374SMatthew Dillon struct ifnet *dst_if, *alt_if, *bifp;
21824ee4f753SMatthew Dillon int from_us;
21831e858374SMatthew Dillon int alt_priority;
2184e6720526SMatthew Dillon uint8_t alt_state;
2185e6720526SMatthew Dillon struct mbuf *mc;
2186e6720526SMatthew Dillon int used;
2187e6720526SMatthew Dillon int found;
2188ac93838fSSimon Schubert
21892c9effcfSSepherosa Ziehau ASSERT_IFNET_NOT_SERIALIZED_ALL(ifp);
21905204e13cSSepherosa Ziehau ASSERT_NETISR_NCPUS(mycpuid);
219186989f49SMatthew Dillon mbuftrackid(m, 65);
2192ac93838fSSimon Schubert
219389ea766dSSepherosa Ziehau /*
219489ea766dSSepherosa Ziehau * Make sure that we are still a member of a bridge interface.
219589ea766dSSepherosa Ziehau */
219689ea766dSSepherosa Ziehau if (sc == NULL) {
219789ea766dSSepherosa Ziehau m_freem(m);
219889ea766dSSepherosa Ziehau return (0);
219989ea766dSSepherosa Ziehau }
2200137aa7b3SSepherosa Ziehau bifp = sc->sc_ifp;
220189ea766dSSepherosa Ziehau
220270d9a675SMatthew Dillon /*
220370d9a675SMatthew Dillon * Acquire header
220470d9a675SMatthew Dillon */
2205ac93838fSSimon Schubert if (m->m_len < ETHER_HDR_LEN) {
2206ac93838fSSimon Schubert m = m_pullup(m, ETHER_HDR_LEN);
220770d9a675SMatthew Dillon if (m == NULL) {
2208d40991efSSepherosa Ziehau IFNET_STAT_INC(bifp, oerrors, 1);
2209ac93838fSSimon Schubert return (0);
2210ac93838fSSimon Schubert }
221170d9a675SMatthew Dillon }
2212ac93838fSSimon Schubert eh = mtod(m, struct ether_header *);
221370d9a675SMatthew Dillon from_us = bridge_from_us(sc, eh);
2214be02a6a0SMatthew Dillon
2215be02a6a0SMatthew Dillon /*
2216ac93838fSSimon Schubert * If bridge is down, but the original output interface is up,
2217ac93838fSSimon Schubert * go ahead and send out that interface. Otherwise, the packet
2218ac93838fSSimon Schubert * is dropped below.
2219ac93838fSSimon Schubert */
2220137aa7b3SSepherosa Ziehau if ((bifp->if_flags & IFF_RUNNING) == 0) {
2221ac93838fSSimon Schubert dst_if = ifp;
2222ac93838fSSimon Schubert goto sendunicast;
2223ac93838fSSimon Schubert }
2224ac93838fSSimon Schubert
2225ac93838fSSimon Schubert /*
2226e6720526SMatthew Dillon * If the packet is a broadcast or multicast, or we don't know a better
2227e6720526SMatthew Dillon * way to get there, send to all interfaces except the originating one.
2228ac93838fSSimon Schubert */
2229ac93838fSSimon Schubert if (ETHER_IS_MULTICAST(eh->ether_dhost))
2230ac93838fSSimon Schubert dst_if = NULL;
2231ac93838fSSimon Schubert else
2232ac93838fSSimon Schubert dst_if = bridge_rtlookup(sc, eh->ether_dhost);
223370d9a675SMatthew Dillon
2234e6720526SMatthew Dillon if (dst_if)
2235e6720526SMatthew Dillon goto sendunicast;
2236e6720526SMatthew Dillon
2237e6720526SMatthew Dillon used = 0;
2238e6720526SMatthew Dillon found = 0;
2239ac93838fSSimon Schubert
2240d895303bSSepherosa Ziehau if (sc->sc_span)
2241d217f5e5SScott Ullrich bridge_span(sc, m);
2242d217f5e5SScott Ullrich
22431e858374SMatthew Dillon alt_if = NULL;
22441e858374SMatthew Dillon alt_priority = 0;
2245e6720526SMatthew Dillon alt_state = BSTP_IFSTATE_LEARNING;
2246e6720526SMatthew Dillon
2247e6720526SMatthew Dillon TAILQ_FOREACH_MUTABLE(bif, &sc->sc_iflists[mycpuid], bif_next, nbif) {
2248ac93838fSSimon Schubert dst_if = bif->bif_ifp;
22491e858374SMatthew Dillon
2250e6720526SMatthew Dillon /*
2251e6720526SMatthew Dillon * Ignore interfaces marked down
2252e6720526SMatthew Dillon *
2253e6720526SMatthew Dillon * NOTE: Since the packet is originated on the machine, the
2254e6720526SMatthew Dillon * original interface the system tried to send it to
2255e6720526SMatthew Dillon * (ifp), which is part of the bridge, is not treated
2256e6720526SMatthew Dillon * specially verses other interfaces on the bridge.
2257e6720526SMatthew Dillon */
2258ac93838fSSimon Schubert if ((dst_if->if_flags & IFF_RUNNING) == 0)
2259ac93838fSSimon Schubert continue;
2260ac93838fSSimon Schubert
2261ac93838fSSimon Schubert /*
2262e6720526SMatthew Dillon * Issue to all FORWARDING STP-enabled interfaces and
2263e6720526SMatthew Dillon * to all non-STP interfaces. Keep track of a possible
2264e6720526SMatthew Dillon * backup to a BONDED, BLOCKING, or LEARNING interfaces
2265e6720526SMatthew Dillon * (in that priority) in case no other interfaces are found.
2266ac93838fSSimon Schubert */
2267e6720526SMatthew Dillon if (bif->bif_flags & IFBIF_STP) {
2268ac93838fSSimon Schubert switch (bif->bif_state) {
22691e858374SMatthew Dillon case BSTP_IFSTATE_BONDED:
2270e6720526SMatthew Dillon if (alt_state != BSTP_IFSTATE_BONDED ||
2271e6720526SMatthew Dillon bif->bif_priority > alt_priority)
2272e6720526SMatthew Dillon {
2273e6720526SMatthew Dillon alt_state = BSTP_IFSTATE_BONDED;
2274e6720526SMatthew Dillon alt_priority = bif->bif_priority;
22751e858374SMatthew Dillon alt_if = bif->bif_ifp;
22761e858374SMatthew Dillon }
22771e858374SMatthew Dillon continue;
2278ac93838fSSimon Schubert case BSTP_IFSTATE_BLOCKING:
2279e6720526SMatthew Dillon if (alt_state == BSTP_IFSTATE_LEARNING ||
2280e6720526SMatthew Dillon (alt_state == BSTP_IFSTATE_BLOCKING &&
2281e6720526SMatthew Dillon bif->bif_priority > alt_priority))
2282e6720526SMatthew Dillon {
2283e6720526SMatthew Dillon alt_state = BSTP_IFSTATE_BLOCKING;
2284e6720526SMatthew Dillon alt_priority = bif->bif_priority;
22851e858374SMatthew Dillon alt_if = bif->bif_ifp;
22861e858374SMatthew Dillon }
22871e858374SMatthew Dillon continue;
22881e858374SMatthew Dillon case BSTP_IFSTATE_LEARNING:
2289e6720526SMatthew Dillon if (alt_state == BSTP_IFSTATE_LEARNING &&
2290e6720526SMatthew Dillon bif->bif_priority > alt_priority)
2291e6720526SMatthew Dillon {
2292e6720526SMatthew Dillon alt_priority = bif->bif_priority;
22931e858374SMatthew Dillon alt_if = bif->bif_ifp;
22941e858374SMatthew Dillon }
22951e858374SMatthew Dillon continue;
22961e858374SMatthew Dillon case BSTP_IFSTATE_L1BLOCKING:
2297ac93838fSSimon Schubert case BSTP_IFSTATE_LISTENING:
2298ac93838fSSimon Schubert case BSTP_IFSTATE_DISABLED:
2299e6720526SMatthew Dillon /*
2300e6720526SMatthew Dillon * Ignore interfaces in these states
2301e6720526SMatthew Dillon */
2302ac93838fSSimon Schubert continue;
23031e858374SMatthew Dillon default:
23041e858374SMatthew Dillon /* FORWARDING */
23051e858374SMatthew Dillon break;
2306ac93838fSSimon Schubert }
2307ac93838fSSimon Schubert }
2308ac93838fSSimon Schubert
2309e6720526SMatthew Dillon /*
2310e6720526SMatthew Dillon * Copy the packet to dstif
2311e6720526SMatthew Dillon */
23121e858374SMatthew Dillon KKASSERT(used == 0);
231370d9a675SMatthew Dillon if (TAILQ_NEXT(bif, bif_next) == NULL) {
2314ac93838fSSimon Schubert used = 1;
2315ac93838fSSimon Schubert mc = m;
2316ac93838fSSimon Schubert } else {
2317b5523eacSSascha Wildner mc = m_copypacket(m, M_NOWAIT);
2318ac93838fSSimon Schubert if (mc == NULL) {
2319d40991efSSepherosa Ziehau IFNET_STAT_INC(bifp, oerrors, 1);
2320ac93838fSSimon Schubert continue;
2321ac93838fSSimon Schubert }
2322ac93838fSSimon Schubert }
23234ee4f753SMatthew Dillon
23244ee4f753SMatthew Dillon /*
23254ee4f753SMatthew Dillon * If the packet is 'from' us override ether_shost.
23264ee4f753SMatthew Dillon */
232770d9a675SMatthew Dillon bridge_handoff(sc, dst_if, mc, from_us);
23281e858374SMatthew Dillon found = 1;
2329137aa7b3SSepherosa Ziehau
2330137aa7b3SSepherosa Ziehau if (nbif != NULL && !nbif->bif_onlist) {
2331137aa7b3SSepherosa Ziehau KKASSERT(bif->bif_onlist);
233270d9a675SMatthew Dillon nbif = TAILQ_NEXT(bif, bif_next);
2333137aa7b3SSepherosa Ziehau }
2334ac93838fSSimon Schubert }
23351e858374SMatthew Dillon
23361e858374SMatthew Dillon /*
23371e858374SMatthew Dillon * If we couldn't find anything use the backup interface
23381e858374SMatthew Dillon * if we have one.
23391e858374SMatthew Dillon */
23401e858374SMatthew Dillon if (found == 0 && alt_if) {
23411e858374SMatthew Dillon KKASSERT(used == 0);
23421e858374SMatthew Dillon mc = m;
23431e858374SMatthew Dillon used = 1;
23441e858374SMatthew Dillon bridge_handoff(sc, alt_if, mc, from_us);
23451e858374SMatthew Dillon }
23461e858374SMatthew Dillon
2347ac93838fSSimon Schubert if (used == 0)
2348ac93838fSSimon Schubert m_freem(m);
2349ad8c8b44SSepherosa Ziehau return (0);
2350ac93838fSSimon Schubert
235186989f49SMatthew Dillon /*
235286989f49SMatthew Dillon * Unicast
235386989f49SMatthew Dillon */
2354ac93838fSSimon Schubert sendunicast:
235586989f49SMatthew Dillon dst_if = bridge_select_unicast(sc, dst_if, 0, m);
23563677aae9SMatthew Dillon
2357d895303bSSepherosa Ziehau if (sc->sc_span)
2358d217f5e5SScott Ullrich bridge_span(sc, m);
235986989f49SMatthew Dillon if (dst_if == NULL)
2360ac93838fSSimon Schubert m_freem(m);
2361ad8c8b44SSepherosa Ziehau else
236270d9a675SMatthew Dillon bridge_handoff(sc, dst_if, m, from_us);
2363ac93838fSSimon Schubert return (0);
2364ac93838fSSimon Schubert }
2365ac93838fSSimon Schubert
2366ac93838fSSimon Schubert /*
236770d9a675SMatthew Dillon * Returns the bridge interface associated with an ifc.
236870d9a675SMatthew Dillon * Pass ifp->if_bridge (must not be NULL). Used by the ARP
236970d9a675SMatthew Dillon * code to supply the bridge for the is-at info, making
237070d9a675SMatthew Dillon * the bridge responsible for matching local addresses.
237170d9a675SMatthew Dillon *
237270d9a675SMatthew Dillon * Without this the ARP code will supply bridge member interfaces
237370d9a675SMatthew Dillon * for the is-at which makes it difficult the bridge to fail-over
2374e41e076dSMatthew Dillon * interfaces (among other things).
237570d9a675SMatthew Dillon */
237670d9a675SMatthew Dillon static struct ifnet *
bridge_interface(void * if_bridge)237770d9a675SMatthew Dillon bridge_interface(void *if_bridge)
237870d9a675SMatthew Dillon {
237970d9a675SMatthew Dillon struct bridge_softc *sc = if_bridge;
238070d9a675SMatthew Dillon return (sc->sc_ifp);
238170d9a675SMatthew Dillon }
238270d9a675SMatthew Dillon
238370d9a675SMatthew Dillon /*
2384ac93838fSSimon Schubert * bridge_start:
2385ac93838fSSimon Schubert *
2386ac93838fSSimon Schubert * Start output on a bridge.
2387ac93838fSSimon Schubert */
2388d217f5e5SScott Ullrich static void
bridge_start(struct ifnet * ifp,struct ifaltq_subque * ifsq)2389f0a26983SSepherosa Ziehau bridge_start(struct ifnet *ifp, struct ifaltq_subque *ifsq)
2390ac93838fSSimon Schubert {
2391867cc45aSSepherosa Ziehau struct bridge_softc *sc = ifp->if_softc;
2392ac93838fSSimon Schubert
2393f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);
2394bfefe4a6SSepherosa Ziehau ASSERT_ALTQ_SQ_SERIALIZED_HW(ifsq);
23955204e13cSSepherosa Ziehau ASSERT_NETISR_NCPUS(mycpuid);
2396ac93838fSSimon Schubert
2397f0a26983SSepherosa Ziehau ifsq_set_oactive(ifsq);
2398ac93838fSSimon Schubert for (;;) {
2399867cc45aSSepherosa Ziehau struct ifnet *dst_if = NULL;
2400867cc45aSSepherosa Ziehau struct ether_header *eh;
2401867cc45aSSepherosa Ziehau struct mbuf *m;
2402867cc45aSSepherosa Ziehau
2403ac9843a1SSepherosa Ziehau m = ifsq_dequeue(ifsq);
2404867cc45aSSepherosa Ziehau if (m == NULL)
2405ac93838fSSimon Schubert break;
240686989f49SMatthew Dillon mbuftrackid(m, 75);
2407867cc45aSSepherosa Ziehau
2408867cc45aSSepherosa Ziehau if (m->m_len < sizeof(*eh)) {
2409867cc45aSSepherosa Ziehau m = m_pullup(m, sizeof(*eh));
2410867cc45aSSepherosa Ziehau if (m == NULL) {
2411d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1);
2412867cc45aSSepherosa Ziehau continue;
2413867cc45aSSepherosa Ziehau }
2414867cc45aSSepherosa Ziehau }
2415867cc45aSSepherosa Ziehau eh = mtod(m, struct ether_header *);
2416867cc45aSSepherosa Ziehau
2417ac93838fSSimon Schubert BPF_MTAP(ifp, m);
2418d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1);
2419ac93838fSSimon Schubert
2420867cc45aSSepherosa Ziehau if ((m->m_flags & (M_BCAST|M_MCAST)) == 0)
2421ac93838fSSimon Schubert dst_if = bridge_rtlookup(sc, eh->ether_dhost);
2422ac93838fSSimon Schubert
242386989f49SMatthew Dillon /*
242486989f49SMatthew Dillon * Multicast or broadcast
242586989f49SMatthew Dillon */
242686989f49SMatthew Dillon if (dst_if == NULL) {
2427137aa7b3SSepherosa Ziehau bridge_start_bcast(sc, m);
242886989f49SMatthew Dillon continue;
242986989f49SMatthew Dillon }
243086989f49SMatthew Dillon
243186989f49SMatthew Dillon /*
243286989f49SMatthew Dillon * Unicast
243386989f49SMatthew Dillon */
243486989f49SMatthew Dillon dst_if = bridge_select_unicast(sc, dst_if, 0, m);
243586989f49SMatthew Dillon
243686989f49SMatthew Dillon if (dst_if == NULL)
243786989f49SMatthew Dillon m_freem(m);
2438ac93838fSSimon Schubert else
2439708a3bfaSSepherosa Ziehau bridge_enqueue(dst_if, m);
2440ac93838fSSimon Schubert }
2441f0a26983SSepherosa Ziehau ifsq_clr_oactive(ifsq);
2442ac93838fSSimon Schubert }
2443ac93838fSSimon Schubert
2444ac93838fSSimon Schubert /*
2445ac93838fSSimon Schubert * bridge_forward:
2446ac93838fSSimon Schubert *
24474ee4f753SMatthew Dillon * Forward packets received on a bridge interface via the input
24484ee4f753SMatthew Dillon * path.
24494ee4f753SMatthew Dillon *
24501e858374SMatthew Dillon * This implements the forwarding function of the bridge.
2451ac93838fSSimon Schubert */
2452d217f5e5SScott Ullrich static void
bridge_forward(struct bridge_softc * sc,struct mbuf * m)2453ac93838fSSimon Schubert bridge_forward(struct bridge_softc *sc, struct mbuf *m)
2454ac93838fSSimon Schubert {
245586989f49SMatthew Dillon struct bridge_iflist *bif;
245686989f49SMatthew Dillon struct ifnet *src_if, *dst_if, *ifp;
2457ac93838fSSimon Schubert struct ether_header *eh;
24581e858374SMatthew Dillon int from_blocking;
2459ac93838fSSimon Schubert
246086989f49SMatthew Dillon mbuftrackid(m, 66);
2461ac93838fSSimon Schubert src_if = m->m_pkthdr.rcvif;
2462ac93838fSSimon Schubert ifp = sc->sc_ifp;
2463ac93838fSSimon Schubert
24642c9effcfSSepherosa Ziehau ASSERT_IFNET_NOT_SERIALIZED_ALL(ifp);
2465ac93838fSSimon Schubert
24667b944190SMatthew Dillon /*
24677b944190SMatthew Dillon * packet coming in on the bridge is also going out on the bridge,
24687b944190SMatthew Dillon * but ether code won't adjust output stats for the bridge because
24697b944190SMatthew Dillon * we are changing the interface to something else.
24707b944190SMatthew Dillon */
24717b944190SMatthew Dillon IFNET_STAT_INC(ifp, opackets, 1);
24727b944190SMatthew Dillon IFNET_STAT_INC(ifp, obytes, m->m_pkthdr.len);
2473ac93838fSSimon Schubert
2474ac93838fSSimon Schubert /*
2475ac93838fSSimon Schubert * Look up the bridge_iflist.
2476ac93838fSSimon Schubert */
2477ac93838fSSimon Schubert bif = bridge_lookup_member_if(sc, src_if);
2478ac93838fSSimon Schubert if (bif == NULL) {
2479ac93838fSSimon Schubert /* Interface is not a bridge member (anymore?) */
2480ac93838fSSimon Schubert m_freem(m);
2481ac93838fSSimon Schubert return;
2482ac93838fSSimon Schubert }
2483ac93838fSSimon Schubert
24841e858374SMatthew Dillon /*
24851e858374SMatthew Dillon * In spanning tree mode receiving a packet from an interface
24861e858374SMatthew Dillon * in a BLOCKING state is allowed, it could be a member of last
24871e858374SMatthew Dillon * resort from the sender's point of view, but forwarding it is
24881e858374SMatthew Dillon * not allowed.
24891e858374SMatthew Dillon *
24901e858374SMatthew Dillon * The sender's spanning tree will eventually sync up and the
24911e858374SMatthew Dillon * sender will go into a BLOCKING state too (but this still may be
24921e858374SMatthew Dillon * an interface of last resort during state changes).
24931e858374SMatthew Dillon */
2494ac93838fSSimon Schubert if (bif->bif_flags & IFBIF_STP) {
2495ac93838fSSimon Schubert switch (bif->bif_state) {
249670d9a675SMatthew Dillon case BSTP_IFSTATE_L1BLOCKING:
2497ac93838fSSimon Schubert case BSTP_IFSTATE_LISTENING:
2498ac93838fSSimon Schubert case BSTP_IFSTATE_DISABLED:
2499ac93838fSSimon Schubert m_freem(m);
2500ac93838fSSimon Schubert return;
250170d9a675SMatthew Dillon default:
25021e858374SMatthew Dillon /* learning, blocking, bonded, forwarding */
250370d9a675SMatthew Dillon break;
2504ac93838fSSimon Schubert }
25051e858374SMatthew Dillon from_blocking = (bif->bif_state == BSTP_IFSTATE_BLOCKING);
2506ab002640SMatthew Dillon } else {
2507ab002640SMatthew Dillon from_blocking = 0;
2508ab002640SMatthew Dillon }
2509ac93838fSSimon Schubert
2510ac93838fSSimon Schubert eh = mtod(m, struct ether_header *);
2511ac93838fSSimon Schubert
2512ac93838fSSimon Schubert /*
2513ac93838fSSimon Schubert * If the interface is learning, and the source
2514ac93838fSSimon Schubert * address is valid and not multicast, record
2515ac93838fSSimon Schubert * the address.
2516ac93838fSSimon Schubert */
2517ac93838fSSimon Schubert if ((bif->bif_flags & IFBIF_LEARNING) != 0 &&
25181e858374SMatthew Dillon from_blocking == 0 &&
2519ac93838fSSimon Schubert ETHER_IS_MULTICAST(eh->ether_shost) == 0 &&
2520ac93838fSSimon Schubert (eh->ether_shost[0] == 0 &&
2521ac93838fSSimon Schubert eh->ether_shost[1] == 0 &&
2522ac93838fSSimon Schubert eh->ether_shost[2] == 0 &&
2523ac93838fSSimon Schubert eh->ether_shost[3] == 0 &&
2524ac93838fSSimon Schubert eh->ether_shost[4] == 0 &&
2525e6720526SMatthew Dillon eh->ether_shost[5] == 0) == 0)
2526e6720526SMatthew Dillon {
25274394693cSSepherosa Ziehau bridge_rtupdate(sc, eh->ether_shost, src_if, IFBAF_DYNAMIC);
252870d9a675SMatthew Dillon }
2529ac93838fSSimon Schubert
25301e858374SMatthew Dillon /*
25311e858374SMatthew Dillon * Don't forward from an interface in the listening or learning
25321e858374SMatthew Dillon * state. That is, in the learning state we learn information
25331e858374SMatthew Dillon * but we throw away the packets.
25341e858374SMatthew Dillon *
25351e858374SMatthew Dillon * We let through packets on interfaces in the blocking state.
25361e858374SMatthew Dillon * The blocking state is applicable to the send side, not the
25371e858374SMatthew Dillon * receive side.
25381e858374SMatthew Dillon */
2539ac93838fSSimon Schubert if ((bif->bif_flags & IFBIF_STP) != 0 &&
25401e858374SMatthew Dillon (bif->bif_state == BSTP_IFSTATE_LISTENING ||
25411e858374SMatthew Dillon bif->bif_state == BSTP_IFSTATE_LEARNING)) {
2542ac93838fSSimon Schubert m_freem(m);
2543ecd27a4cSSepherosa Ziehau return;
2544ac93838fSSimon Schubert }
2545ac93838fSSimon Schubert
2546ac93838fSSimon Schubert /*
2547ac93838fSSimon Schubert * At this point, the port either doesn't participate
2548ac93838fSSimon Schubert * in spanning tree or it is in the forwarding state.
2549ac93838fSSimon Schubert */
2550ac93838fSSimon Schubert
2551ac93838fSSimon Schubert /*
2552ac93838fSSimon Schubert * If the packet is unicast, destined for someone on
2553ac93838fSSimon Schubert * "this" side of the bridge, drop it.
25545c76f1ffSMatthew Dillon *
25555c76f1ffSMatthew Dillon * src_if implies the entire bonding set so we have to compare MAC
25565c76f1ffSMatthew Dillon * addresses and not just if pointers.
2557ac93838fSSimon Schubert */
2558ac93838fSSimon Schubert if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) {
2559ac93838fSSimon Schubert dst_if = bridge_rtlookup(sc, eh->ether_dhost);
25605c76f1ffSMatthew Dillon if (dst_if && memcmp(IF_LLADDR(src_if), IF_LLADDR(dst_if),
25615c76f1ffSMatthew Dillon ETHER_ADDR_LEN) == 0) {
2562ac93838fSSimon Schubert m_freem(m);
2563ecd27a4cSSepherosa Ziehau return;
2564ac93838fSSimon Schubert }
2565ac93838fSSimon Schubert } else {
2566ac93838fSSimon Schubert /* ...forward it to all interfaces. */
2567d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, imcasts, 1);
2568ac93838fSSimon Schubert dst_if = NULL;
2569ac93838fSSimon Schubert }
2570ac93838fSSimon Schubert
25711e858374SMatthew Dillon /*
25721e858374SMatthew Dillon * Brodcast if we do not have forwarding information. However, if
25731e858374SMatthew Dillon * we received the packet on a blocking interface we do not do this
25741e858374SMatthew Dillon * (unless you really want to blow up your network).
25751e858374SMatthew Dillon */
2576ecd27a4cSSepherosa Ziehau if (dst_if == NULL) {
25771e858374SMatthew Dillon if (from_blocking)
25781e858374SMatthew Dillon m_freem(m);
25791e858374SMatthew Dillon else
2580137aa7b3SSepherosa Ziehau bridge_broadcast(sc, src_if, m);
2581ecd27a4cSSepherosa Ziehau return;
2582ecd27a4cSSepherosa Ziehau }
2583ecd27a4cSSepherosa Ziehau
258486989f49SMatthew Dillon dst_if = bridge_select_unicast(sc, dst_if, from_blocking, m);
2585ecd27a4cSSepherosa Ziehau
258686989f49SMatthew Dillon if (dst_if == NULL) {
2587ecd27a4cSSepherosa Ziehau m_freem(m);
2588ecd27a4cSSepherosa Ziehau return;
2589ecd27a4cSSepherosa Ziehau }
2590ecd27a4cSSepherosa Ziehau
2591ac93838fSSimon Schubert if (inet_pfil_hook.ph_hashooks > 0
2592ac93838fSSimon Schubert #ifdef INET6
2593ac93838fSSimon Schubert || inet6_pfil_hook.ph_hashooks > 0
2594ac93838fSSimon Schubert #endif
2595ac93838fSSimon Schubert ) {
2596ac93838fSSimon Schubert if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0)
2597137aa7b3SSepherosa Ziehau return;
2598ac93838fSSimon Schubert if (m == NULL)
2599137aa7b3SSepherosa Ziehau return;
2600ac93838fSSimon Schubert
2601ecd27a4cSSepherosa Ziehau if (bridge_pfil(&m, ifp, dst_if, PFIL_OUT) != 0)
2602137aa7b3SSepherosa Ziehau return;
2603ac93838fSSimon Schubert if (m == NULL)
2604137aa7b3SSepherosa Ziehau return;
2605ac93838fSSimon Schubert }
260670d9a675SMatthew Dillon bridge_handoff(sc, dst_if, m, 0);
2607ac93838fSSimon Schubert }
2608ac93838fSSimon Schubert
2609ac93838fSSimon Schubert /*
2610ac93838fSSimon Schubert * bridge_input:
2611ac93838fSSimon Schubert *
2612ac93838fSSimon Schubert * Receive input from a member interface. Queue the packet for
2613ac93838fSSimon Schubert * bridging if it is not for us.
2614ac93838fSSimon Schubert */
2615a18eb4b7SSepherosa Ziehau static struct mbuf *
bridge_input(struct ifnet * ifp,struct mbuf * m)2616ac93838fSSimon Schubert bridge_input(struct ifnet *ifp, struct mbuf *m)
2617ac93838fSSimon Schubert {
2618ac93838fSSimon Schubert struct bridge_softc *sc = ifp->if_bridge;
2619ac93838fSSimon Schubert struct bridge_iflist *bif;
26203ce67233SSepherosa Ziehau struct ifnet *bifp, *new_ifp;
2621ac93838fSSimon Schubert struct ether_header *eh;
2622ac93838fSSimon Schubert struct mbuf *mc, *mc2;
2623ac93838fSSimon Schubert
26242c9effcfSSepherosa Ziehau ASSERT_IFNET_NOT_SERIALIZED_ALL(ifp);
26255204e13cSSepherosa Ziehau ASSERT_NETISR_NCPUS(mycpuid);
262686989f49SMatthew Dillon mbuftrackid(m, 67);
2627137aa7b3SSepherosa Ziehau
262889ea766dSSepherosa Ziehau /*
262989ea766dSSepherosa Ziehau * Make sure that we are still a member of a bridge interface.
263089ea766dSSepherosa Ziehau */
263189ea766dSSepherosa Ziehau if (sc == NULL)
263289ea766dSSepherosa Ziehau return m;
263389ea766dSSepherosa Ziehau
26343ce67233SSepherosa Ziehau new_ifp = NULL;
2635ac93838fSSimon Schubert bifp = sc->sc_ifp;
26363ce67233SSepherosa Ziehau
2637ac91a939SSepherosa Ziehau if ((bifp->if_flags & IFF_RUNNING) == 0)
2638ac93838fSSimon Schubert goto out;
2639ac93838fSSimon Schubert
26403a593c54SMatthew Dillon /*
26413a593c54SMatthew Dillon * Implement support for bridge monitoring. If this flag has been
26423a593c54SMatthew Dillon * set on this interface, discard the packet once we push it through
26430f6ada01SSepherosa Ziehau * the bpf(4) machinery, but before we do, increment various counters
26440f6ada01SSepherosa Ziehau * associated with this bridge.
26453a593c54SMatthew Dillon */
26460f6ada01SSepherosa Ziehau if (bifp->if_flags & IFF_MONITOR) {
26477b944190SMatthew Dillon /*
26487b944190SMatthew Dillon * Change input interface to this bridge
26497b944190SMatthew Dillon *
26507b944190SMatthew Dillon * Update bridge's ifnet statistics
26517b944190SMatthew Dillon */
26523a593c54SMatthew Dillon m->m_pkthdr.rcvif = bifp;
26530f6ada01SSepherosa Ziehau
26543a593c54SMatthew Dillon BPF_MTAP(bifp, m);
2655d40991efSSepherosa Ziehau IFNET_STAT_INC(bifp, ipackets, 1);
2656d40991efSSepherosa Ziehau IFNET_STAT_INC(bifp, ibytes, m->m_pkthdr.len);
26570f6ada01SSepherosa Ziehau if (m->m_flags & (M_MCAST | M_BCAST))
2658d40991efSSepherosa Ziehau IFNET_STAT_INC(bifp, imcasts, 1);
26590f6ada01SSepherosa Ziehau
26603a593c54SMatthew Dillon m_freem(m);
2661ac91a939SSepherosa Ziehau m = NULL;
26623a593c54SMatthew Dillon goto out;
26633a593c54SMatthew Dillon }
26643a593c54SMatthew Dillon
2665be02a6a0SMatthew Dillon /*
2666be02a6a0SMatthew Dillon * Handle the ether_header
2667b7441d0cSMatthew Dillon *
2668b7441d0cSMatthew Dillon * In all cases if the packet is destined for us via our MAC
2669b7441d0cSMatthew Dillon * we must clear BRIDGE_MBUF_TAGGED to ensure that we don't
2670b7441d0cSMatthew Dillon * repeat the source MAC out the same interface.
267170d9a675SMatthew Dillon *
267270d9a675SMatthew Dillon * This first test against our bridge MAC is the fast-path.
267370d9a675SMatthew Dillon *
267470d9a675SMatthew Dillon * NOTE! The bridge interface can serve as an endpoint for
267570d9a675SMatthew Dillon * communication but normally there are no IPs associated
267670d9a675SMatthew Dillon * with it so you cannot route through it. Instead what
267770d9a675SMatthew Dillon * you do is point your default route *THROUGH* the bridge
267870d9a675SMatthew Dillon * to the actual default router for one of the bridged spaces.
267970d9a675SMatthew Dillon *
268070d9a675SMatthew Dillon * Another possibility is to put all your IP specifications
268170d9a675SMatthew Dillon * on the bridge instead of on the individual interfaces. If
268270d9a675SMatthew Dillon * you do this it should be possible to use the bridge as an
268370d9a675SMatthew Dillon * end point and route (rather than switch) through it using
268470d9a675SMatthew Dillon * the default route or ipfw forwarding rules.
2685be02a6a0SMatthew Dillon */
268670d9a675SMatthew Dillon
268770d9a675SMatthew Dillon /*
268870d9a675SMatthew Dillon * Acquire header
268970d9a675SMatthew Dillon */
269070d9a675SMatthew Dillon if (m->m_len < ETHER_HDR_LEN) {
269170d9a675SMatthew Dillon m = m_pullup(m, ETHER_HDR_LEN);
269270d9a675SMatthew Dillon if (m == NULL)
269370d9a675SMatthew Dillon goto out;
269470d9a675SMatthew Dillon }
2695ac93838fSSimon Schubert eh = mtod(m, struct ether_header *);
2696be02a6a0SMatthew Dillon m->m_pkthdr.fw_flags |= BRIDGE_MBUF_TAGGED;
2697b4e5a107SSepherosa Ziehau bcopy(eh->ether_shost, m->m_pkthdr.ether_br_shost, ETHER_ADDR_LEN);
2698ac93838fSSimon Schubert
269970d9a675SMatthew Dillon if ((bridge_debug & 1) &&
270070d9a675SMatthew Dillon (ntohs(eh->ether_type) == ETHERTYPE_ARP ||
270170d9a675SMatthew Dillon ntohs(eh->ether_type) == ETHERTYPE_REVARP)) {
270270d9a675SMatthew Dillon kprintf("%02x:%02x:%02x:%02x:%02x:%02x "
270370d9a675SMatthew Dillon "%02x:%02x:%02x:%02x:%02x:%02x type %04x "
270470d9a675SMatthew Dillon "lla %02x:%02x:%02x:%02x:%02x:%02x\n",
270570d9a675SMatthew Dillon eh->ether_dhost[0],
270670d9a675SMatthew Dillon eh->ether_dhost[1],
270770d9a675SMatthew Dillon eh->ether_dhost[2],
270870d9a675SMatthew Dillon eh->ether_dhost[3],
270970d9a675SMatthew Dillon eh->ether_dhost[4],
271070d9a675SMatthew Dillon eh->ether_dhost[5],
271170d9a675SMatthew Dillon eh->ether_shost[0],
271270d9a675SMatthew Dillon eh->ether_shost[1],
271370d9a675SMatthew Dillon eh->ether_shost[2],
271470d9a675SMatthew Dillon eh->ether_shost[3],
271570d9a675SMatthew Dillon eh->ether_shost[4],
271670d9a675SMatthew Dillon eh->ether_shost[5],
271770d9a675SMatthew Dillon eh->ether_type,
271870d9a675SMatthew Dillon ((u_char *)IF_LLADDR(bifp))[0],
271970d9a675SMatthew Dillon ((u_char *)IF_LLADDR(bifp))[1],
272070d9a675SMatthew Dillon ((u_char *)IF_LLADDR(bifp))[2],
272170d9a675SMatthew Dillon ((u_char *)IF_LLADDR(bifp))[3],
272270d9a675SMatthew Dillon ((u_char *)IF_LLADDR(bifp))[4],
272370d9a675SMatthew Dillon ((u_char *)IF_LLADDR(bifp))[5]
272470d9a675SMatthew Dillon );
272570d9a675SMatthew Dillon }
272670d9a675SMatthew Dillon
27273ce67233SSepherosa Ziehau /*
27283ce67233SSepherosa Ziehau * If the packet is for us, set the packets source as the
27293ce67233SSepherosa Ziehau * bridge, and return the packet back to ifnet.if_input for
27303ce67233SSepherosa Ziehau * local processing.
27313ce67233SSepherosa Ziehau */
27324a3d58b6SMatthew Dillon if (memcmp(eh->ether_dhost, IF_LLADDR(bifp), ETHER_ADDR_LEN) == 0) {
27334a3d58b6SMatthew Dillon /*
27344a3d58b6SMatthew Dillon * We must still record the source interface in our
27354a3d58b6SMatthew Dillon * addr cache, otherwise our bridge won't know where
27364a3d58b6SMatthew Dillon * to send responses and will broadcast them.
27374a3d58b6SMatthew Dillon */
27384a3d58b6SMatthew Dillon bif = bridge_lookup_member_if(sc, ifp);
27394a3d58b6SMatthew Dillon if ((bif->bif_flags & IFBIF_LEARNING) &&
27404a3d58b6SMatthew Dillon ((bif->bif_flags & IFBIF_STP) == 0 ||
2741ab7bc350SMatthew Dillon bif->bif_state != BSTP_IFSTATE_BLOCKING))
2742ab7bc350SMatthew Dillon {
27434a3d58b6SMatthew Dillon bridge_rtupdate(sc, eh->ether_shost,
27444a3d58b6SMatthew Dillon ifp, IFBAF_DYNAMIC);
27454a3d58b6SMatthew Dillon }
27464a3d58b6SMatthew Dillon
27474a3d58b6SMatthew Dillon /*
27484a3d58b6SMatthew Dillon * Perform pfil hooks.
27494a3d58b6SMatthew Dillon */
2750b7441d0cSMatthew Dillon m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED;
27513ce67233SSepherosa Ziehau KASSERT(bifp->if_bridge == NULL,
27523ce67233SSepherosa Ziehau ("loop created in bridge_input"));
275302b0fa02SMatthew Dillon if (pfil_member != 0) {
275402b0fa02SMatthew Dillon if (inet_pfil_hook.ph_hashooks > 0
275502b0fa02SMatthew Dillon #ifdef INET6
275602b0fa02SMatthew Dillon || inet6_pfil_hook.ph_hashooks > 0
275702b0fa02SMatthew Dillon #endif
275802b0fa02SMatthew Dillon ) {
275902b0fa02SMatthew Dillon if (bridge_pfil(&m, NULL, ifp, PFIL_IN) != 0)
276002b0fa02SMatthew Dillon goto out;
276102b0fa02SMatthew Dillon if (m == NULL)
276202b0fa02SMatthew Dillon goto out;
276302b0fa02SMatthew Dillon }
276402b0fa02SMatthew Dillon }
27654a3d58b6SMatthew Dillon
27664a3d58b6SMatthew Dillon /*
27674a3d58b6SMatthew Dillon * Set new_ifp and skip to the end. This will trigger code
27684a3d58b6SMatthew Dillon * to reinput the packet and run it into our stack.
27694a3d58b6SMatthew Dillon */
27703ce67233SSepherosa Ziehau new_ifp = bifp;
27713ce67233SSepherosa Ziehau goto out;
27723ce67233SSepherosa Ziehau }
27733ce67233SSepherosa Ziehau
2774f94bb7f0SSimon Schubert /*
2775f94bb7f0SSimon Schubert * Tap all packets arriving on the bridge, no matter if
2776f94bb7f0SSimon Schubert * they are local destinations or not. In is in.
27777b944190SMatthew Dillon *
27787b944190SMatthew Dillon * Update bridge's ifnet statistics
2779f94bb7f0SSimon Schubert */
2780f94bb7f0SSimon Schubert BPF_MTAP(bifp, m);
27817b944190SMatthew Dillon IFNET_STAT_INC(bifp, ipackets, 1);
27827b944190SMatthew Dillon IFNET_STAT_INC(bifp, ibytes, m->m_pkthdr.len);
27837b944190SMatthew Dillon if (m->m_flags & (M_MCAST | M_BCAST))
27847b944190SMatthew Dillon IFNET_STAT_INC(bifp, imcasts, 1);
2785f94bb7f0SSimon Schubert
27863ce67233SSepherosa Ziehau bif = bridge_lookup_member_if(sc, ifp);
27873ce67233SSepherosa Ziehau if (bif == NULL)
2788ac93838fSSimon Schubert goto out;
2789ac93838fSSimon Schubert
2790d895303bSSepherosa Ziehau if (sc->sc_span)
2791d217f5e5SScott Ullrich bridge_span(sc, m);
2792d217f5e5SScott Ullrich
2793f581b688SSepherosa Ziehau if (m->m_flags & (M_BCAST | M_MCAST)) {
279470d9a675SMatthew Dillon /*
279570d9a675SMatthew Dillon * Tap off 802.1D packets; they do not get forwarded.
279670d9a675SMatthew Dillon */
2797ac93838fSSimon Schubert if (memcmp(eh->ether_dhost, bstp_etheraddr,
2798ac93838fSSimon Schubert ETHER_ADDR_LEN) == 0) {
2799a3dd34d2SSepherosa Ziehau ifnet_serialize_all(bifp);
2800b2417333SSepherosa Ziehau bstp_input(sc, bif, m);
2801a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(bifp);
2802137aa7b3SSepherosa Ziehau
2803b2417333SSepherosa Ziehau /* m is freed by bstp_input */
2804b2417333SSepherosa Ziehau m = NULL;
2805ac93838fSSimon Schubert goto out;
2806ac93838fSSimon Schubert }
2807ac93838fSSimon Schubert
280870d9a675SMatthew Dillon /*
280970d9a675SMatthew Dillon * Other than 802.11d packets, ignore packets if the
281070d9a675SMatthew Dillon * interface is not in a good state.
28111e858374SMatthew Dillon *
28121e858374SMatthew Dillon * NOTE: Broadcast/mcast packets received on a blocking or
28131e858374SMatthew Dillon * learning interface are allowed for local processing.
28141e858374SMatthew Dillon *
28151e858374SMatthew Dillon * The sending side of a blocked port will stop
28161e858374SMatthew Dillon * transmitting when a better alternative is found.
28171e858374SMatthew Dillon * However, later on we will disallow the forwarding
28181e858374SMatthew Dillon * of bcast/mcsat packets over a blocking interface.
281970d9a675SMatthew Dillon */
2820ac93838fSSimon Schubert if (bif->bif_flags & IFBIF_STP) {
2821ac93838fSSimon Schubert switch (bif->bif_state) {
28223677aae9SMatthew Dillon case BSTP_IFSTATE_L1BLOCKING:
2823ac93838fSSimon Schubert case BSTP_IFSTATE_LISTENING:
2824ac93838fSSimon Schubert case BSTP_IFSTATE_DISABLED:
2825ac93838fSSimon Schubert goto out;
28261e858374SMatthew Dillon default:
28271e858374SMatthew Dillon /* blocking, learning, bonded, forwarding */
28281e858374SMatthew Dillon break;
2829ac93838fSSimon Schubert }
2830ac93838fSSimon Schubert }
2831ac93838fSSimon Schubert
2832ac93838fSSimon Schubert /*
2833ac93838fSSimon Schubert * Make a deep copy of the packet and enqueue the copy
2834ac93838fSSimon Schubert * for bridge processing; return the original packet for
2835ac93838fSSimon Schubert * local processing.
2836ac93838fSSimon Schubert */
2837b5523eacSSascha Wildner mc = m_dup(m, M_NOWAIT);
2838ac93838fSSimon Schubert if (mc == NULL)
2839ac93838fSSimon Schubert goto out;
2840ac93838fSSimon Schubert
28411e858374SMatthew Dillon /*
28421e858374SMatthew Dillon * It's just too dangerous to allow bcast/mcast over a
28431e858374SMatthew Dillon * blocked interface, eventually the network will sort
28441e858374SMatthew Dillon * itself out and a better path will be found.
28451e858374SMatthew Dillon */
28461e858374SMatthew Dillon if ((bif->bif_flags & IFBIF_STP) == 0 ||
2847e6720526SMatthew Dillon bif->bif_state != BSTP_IFSTATE_BLOCKING)
2848e6720526SMatthew Dillon {
2849ac93838fSSimon Schubert bridge_forward(sc, mc);
28501e858374SMatthew Dillon }
2851ac93838fSSimon Schubert
2852ac93838fSSimon Schubert /*
2853ac93838fSSimon Schubert * Reinject the mbuf as arriving on the bridge so we have a
2854ac93838fSSimon Schubert * chance at claiming multicast packets. We can not loop back
2855ac93838fSSimon Schubert * here from ether_input as a bridge is never a member of a
2856ac93838fSSimon Schubert * bridge.
2857ac93838fSSimon Schubert */
2858ac93838fSSimon Schubert KASSERT(bifp->if_bridge == NULL,
2859ac93838fSSimon Schubert ("loop created in bridge_input"));
2860b5523eacSSascha Wildner mc2 = m_dup(m, M_NOWAIT);
2861d217f5e5SScott Ullrich #ifdef notyet
2862d217f5e5SScott Ullrich if (mc2 != NULL) {
2863d217f5e5SScott Ullrich /* Keep the layer3 header aligned */
2864d217f5e5SScott Ullrich int i = min(mc2->m_pkthdr.len, max_protohdr);
2865d217f5e5SScott Ullrich mc2 = m_copyup(mc2, i, ETHER_ALIGN);
2866d217f5e5SScott Ullrich }
2867d217f5e5SScott Ullrich #endif
2868ac93838fSSimon Schubert if (mc2 != NULL) {
2869137aa7b3SSepherosa Ziehau /*
28704ee4f753SMatthew Dillon * Don't tap to bpf(4) again; we have already done
28714ee4f753SMatthew Dillon * the tapping.
28724ee4f753SMatthew Dillon *
28734ee4f753SMatthew Dillon * Leave m_pkthdr.rcvif alone, so ARP replies are
28744ee4f753SMatthew Dillon * processed as coming in on the correct interface.
2875b7441d0cSMatthew Dillon *
2876b7441d0cSMatthew Dillon * Clear the bridge flag for local processing in
2877b7441d0cSMatthew Dillon * case the packet gets routed.
2878137aa7b3SSepherosa Ziehau */
2879b7441d0cSMatthew Dillon mc2->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED;
288070d9a675SMatthew Dillon ether_reinput_oncpu(bifp, mc2, 0);
2881ac93838fSSimon Schubert }
2882ac93838fSSimon Schubert
2883ac93838fSSimon Schubert /* Return the original packet for local processing. */
2884ac93838fSSimon Schubert goto out;
2885ac93838fSSimon Schubert }
2886ac93838fSSimon Schubert
288770d9a675SMatthew Dillon /*
288870d9a675SMatthew Dillon * Input of a unicast packet. We have to allow unicast packets
28891e858374SMatthew Dillon * input from links in the BLOCKING state as this might be an
28901e858374SMatthew Dillon * interface of last resort.
289170d9a675SMatthew Dillon *
289270d9a675SMatthew Dillon * NOTE: We explicitly ignore normal packets received on a link
289370d9a675SMatthew Dillon * in the BLOCKING state. The point of being in that state
289470d9a675SMatthew Dillon * is to avoid getting duplicate packets.
289570d9a675SMatthew Dillon *
289670d9a675SMatthew Dillon * HOWEVER, if LINK2 is set the normal spanning tree code
289770d9a675SMatthew Dillon * will mark an interface BLOCKING to avoid multi-cast/broadcast
289870d9a675SMatthew Dillon * loops. Unicast packets CAN still loop if we allow the
289970d9a675SMatthew Dillon * case (hence we only do it in LINK2), but it isn't quite as
290070d9a675SMatthew Dillon * bad as a broadcast packet looping.
290170d9a675SMatthew Dillon */
2902ac93838fSSimon Schubert if (bif->bif_flags & IFBIF_STP) {
2903ac93838fSSimon Schubert switch (bif->bif_state) {
290470d9a675SMatthew Dillon case BSTP_IFSTATE_L1BLOCKING:
2905ac93838fSSimon Schubert case BSTP_IFSTATE_LISTENING:
2906ac93838fSSimon Schubert case BSTP_IFSTATE_DISABLED:
2907ac93838fSSimon Schubert goto out;
290870d9a675SMatthew Dillon default:
29091e858374SMatthew Dillon /* blocking, bonded, forwarding, learning */
291070d9a675SMatthew Dillon break;
2911ac93838fSSimon Schubert }
2912ac93838fSSimon Schubert }
2913ac93838fSSimon Schubert
2914ac93838fSSimon Schubert /*
2915ac93838fSSimon Schubert * Unicast. Make sure it's not for us.
29168f7b13efSSepherosa Ziehau *
29178f7b13efSSepherosa Ziehau * This loop is MPSAFE; the only blocking operation (bridge_rtupdate)
29188f7b13efSSepherosa Ziehau * is followed by breaking out of the loop.
2919ac93838fSSimon Schubert */
292070d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
2921ac93838fSSimon Schubert if (bif->bif_ifp->if_type != IFT_ETHER)
2922ac93838fSSimon Schubert continue;
29233ce67233SSepherosa Ziehau
29244ee4f753SMatthew Dillon /*
292570d9a675SMatthew Dillon * It is destined for an interface linked to the bridge.
292670d9a675SMatthew Dillon * We want the bridge itself to take care of link level
292770d9a675SMatthew Dillon * forwarding to member interfaces so reinput on the bridge.
292870d9a675SMatthew Dillon * i.e. if you ping an IP on a target interface associated
292970d9a675SMatthew Dillon * with the bridge, the arp is-at response should indicate
293070d9a675SMatthew Dillon * the bridge MAC.
29311e858374SMatthew Dillon *
29321e858374SMatthew Dillon * Only update our addr list when learning if the port
29331e858374SMatthew Dillon * is not in a blocking state. If it is we still allow
29341e858374SMatthew Dillon * the packet but we do not try to learn from it.
29354ee4f753SMatthew Dillon */
2936ac93838fSSimon Schubert if (memcmp(IF_LLADDR(bif->bif_ifp), eh->ether_dhost,
2937ac93838fSSimon Schubert ETHER_ADDR_LEN) == 0) {
2938ecd27a4cSSepherosa Ziehau if (bif->bif_ifp != ifp) {
2939ecd27a4cSSepherosa Ziehau /* XXX loop prevention */
29400899cb3eSSepherosa Ziehau m->m_flags |= M_ETHER_BRIDGED;
2941ecd27a4cSSepherosa Ziehau }
29421e858374SMatthew Dillon if ((bif->bif_flags & IFBIF_LEARNING) &&
2943ab002640SMatthew Dillon ((bif->bif_flags & IFBIF_STP) == 0 ||
2944ab002640SMatthew Dillon bif->bif_state != BSTP_IFSTATE_BLOCKING)) {
29458f7b13efSSepherosa Ziehau bridge_rtupdate(sc, eh->ether_shost,
29468f7b13efSSepherosa Ziehau ifp, IFBAF_DYNAMIC);
29478f7b13efSSepherosa Ziehau }
294870d9a675SMatthew Dillon new_ifp = bifp; /* not bif->bif_ifp */
2949b7441d0cSMatthew Dillon m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED;
2950ac93838fSSimon Schubert goto out;
2951ac93838fSSimon Schubert }
2952ac93838fSSimon Schubert
295370d9a675SMatthew Dillon /*
295470d9a675SMatthew Dillon * Ignore received packets that were sent by us.
295570d9a675SMatthew Dillon */
2956ac93838fSSimon Schubert if (memcmp(IF_LLADDR(bif->bif_ifp), eh->ether_shost,
2957ac93838fSSimon Schubert ETHER_ADDR_LEN) == 0) {
2958ac93838fSSimon Schubert m_freem(m);
2959ac93838fSSimon Schubert m = NULL;
2960ac93838fSSimon Schubert goto out;
2961ac93838fSSimon Schubert }
2962ac93838fSSimon Schubert }
2963ac93838fSSimon Schubert
29641e858374SMatthew Dillon /*
29651e858374SMatthew Dillon * It isn't for us.
29661e858374SMatthew Dillon *
29671e858374SMatthew Dillon * Perform the bridge forwarding function, but disallow bridging
29681e858374SMatthew Dillon * to interfaces in the blocking state if the packet came in on
29691e858374SMatthew Dillon * an interface in the blocking state.
29704a3d58b6SMatthew Dillon *
29714a3d58b6SMatthew Dillon * (bridge_forward also updates the addr cache).
29721e858374SMatthew Dillon */
2973ac93838fSSimon Schubert bridge_forward(sc, m);
2974ac93838fSSimon Schubert m = NULL;
29754ee4f753SMatthew Dillon
29764ee4f753SMatthew Dillon /*
297770d9a675SMatthew Dillon * ether_reinput_oncpu() will reprocess rcvif as
297870d9a675SMatthew Dillon * coming from new_ifp (since we do not specify
297970d9a675SMatthew Dillon * REINPUT_KEEPRCVIF).
29804ee4f753SMatthew Dillon */
2981ac93838fSSimon Schubert out:
29823ce67233SSepherosa Ziehau if (new_ifp != NULL) {
2983b7441d0cSMatthew Dillon /*
2984b7441d0cSMatthew Dillon * Clear the bridge flag for local processing in
2985b7441d0cSMatthew Dillon * case the packet gets routed.
2986b7441d0cSMatthew Dillon */
298770d9a675SMatthew Dillon ether_reinput_oncpu(new_ifp, m, REINPUT_RUNBPF);
29883ce67233SSepherosa Ziehau m = NULL;
29893ce67233SSepherosa Ziehau }
2990d217f5e5SScott Ullrich return (m);
2991ac93838fSSimon Schubert }
2992ac93838fSSimon Schubert
2993ac93838fSSimon Schubert /*
2994137aa7b3SSepherosa Ziehau * bridge_start_bcast:
2995137aa7b3SSepherosa Ziehau *
2996137aa7b3SSepherosa Ziehau * Broadcast the packet sent from bridge to all member
2997137aa7b3SSepherosa Ziehau * interfaces.
2998137aa7b3SSepherosa Ziehau * This is a simplified version of bridge_broadcast(), however,
2999137aa7b3SSepherosa Ziehau * this function expects caller to hold bridge's serializer.
3000137aa7b3SSepherosa Ziehau */
3001137aa7b3SSepherosa Ziehau static void
bridge_start_bcast(struct bridge_softc * sc,struct mbuf * m)3002137aa7b3SSepherosa Ziehau bridge_start_bcast(struct bridge_softc *sc, struct mbuf *m)
3003137aa7b3SSepherosa Ziehau {
3004137aa7b3SSepherosa Ziehau struct bridge_iflist *bif;
3005137aa7b3SSepherosa Ziehau struct mbuf *mc;
30061e858374SMatthew Dillon struct ifnet *dst_if, *alt_if, *bifp;
3007137aa7b3SSepherosa Ziehau int used = 0;
30081e858374SMatthew Dillon int found = 0;
30091e858374SMatthew Dillon int alt_priority;
3010137aa7b3SSepherosa Ziehau
301186989f49SMatthew Dillon mbuftrackid(m, 68);
3012137aa7b3SSepherosa Ziehau bifp = sc->sc_ifp;
30132c9effcfSSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(bifp);
3014137aa7b3SSepherosa Ziehau
3015137aa7b3SSepherosa Ziehau /*
3016137aa7b3SSepherosa Ziehau * Following loop is MPSAFE; nothing is blocking
3017137aa7b3SSepherosa Ziehau * in the loop body.
30181e858374SMatthew Dillon *
30191e858374SMatthew Dillon * NOTE: We transmit through an member in the BLOCKING state only
30201e858374SMatthew Dillon * as a last resort.
3021137aa7b3SSepherosa Ziehau */
30221e858374SMatthew Dillon alt_if = NULL;
30231e858374SMatthew Dillon alt_priority = 0;
30241e858374SMatthew Dillon
302570d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
3026137aa7b3SSepherosa Ziehau dst_if = bif->bif_ifp;
3027137aa7b3SSepherosa Ziehau
3028137aa7b3SSepherosa Ziehau if (bif->bif_flags & IFBIF_STP) {
3029137aa7b3SSepherosa Ziehau switch (bif->bif_state) {
3030137aa7b3SSepherosa Ziehau case BSTP_IFSTATE_BLOCKING:
30311e858374SMatthew Dillon if (bif->bif_priority > alt_priority) {
30321e858374SMatthew Dillon alt_priority = bif->bif_priority;
30331e858374SMatthew Dillon alt_if = bif->bif_ifp;
30341e858374SMatthew Dillon }
30351e858374SMatthew Dillon /* fall through */
30361e858374SMatthew Dillon case BSTP_IFSTATE_L1BLOCKING:
3037137aa7b3SSepherosa Ziehau case BSTP_IFSTATE_DISABLED:
3038137aa7b3SSepherosa Ziehau continue;
30391e858374SMatthew Dillon default:
30401e858374SMatthew Dillon /* listening, learning, bonded, forwarding */
30411e858374SMatthew Dillon break;
3042137aa7b3SSepherosa Ziehau }
3043137aa7b3SSepherosa Ziehau }
3044137aa7b3SSepherosa Ziehau
3045137aa7b3SSepherosa Ziehau if ((bif->bif_flags & IFBIF_DISCOVER) == 0 &&
3046137aa7b3SSepherosa Ziehau (m->m_flags & (M_BCAST|M_MCAST)) == 0)
3047137aa7b3SSepherosa Ziehau continue;
3048137aa7b3SSepherosa Ziehau
3049137aa7b3SSepherosa Ziehau if ((dst_if->if_flags & IFF_RUNNING) == 0)
3050137aa7b3SSepherosa Ziehau continue;
3051137aa7b3SSepherosa Ziehau
305270d9a675SMatthew Dillon if (TAILQ_NEXT(bif, bif_next) == NULL) {
3053137aa7b3SSepherosa Ziehau mc = m;
3054137aa7b3SSepherosa Ziehau used = 1;
3055137aa7b3SSepherosa Ziehau } else {
3056b5523eacSSascha Wildner mc = m_copypacket(m, M_NOWAIT);
3057137aa7b3SSepherosa Ziehau if (mc == NULL) {
3058d40991efSSepherosa Ziehau IFNET_STAT_INC(bifp, oerrors, 1);
3059137aa7b3SSepherosa Ziehau continue;
3060137aa7b3SSepherosa Ziehau }
3061137aa7b3SSepherosa Ziehau }
30621e858374SMatthew Dillon found = 1;
3063137aa7b3SSepherosa Ziehau bridge_enqueue(dst_if, mc);
3064137aa7b3SSepherosa Ziehau }
30651e858374SMatthew Dillon
30661e858374SMatthew Dillon if (found == 0 && alt_if) {
30671e858374SMatthew Dillon KKASSERT(used == 0);
30681e858374SMatthew Dillon mc = m;
30691e858374SMatthew Dillon used = 1;
30701e858374SMatthew Dillon bridge_enqueue(alt_if, mc);
30711e858374SMatthew Dillon }
30721e858374SMatthew Dillon
3073137aa7b3SSepherosa Ziehau if (used == 0)
3074137aa7b3SSepherosa Ziehau m_freem(m);
3075137aa7b3SSepherosa Ziehau }
3076137aa7b3SSepherosa Ziehau
3077137aa7b3SSepherosa Ziehau /*
3078ac93838fSSimon Schubert * bridge_broadcast:
3079ac93838fSSimon Schubert *
3080e6720526SMatthew Dillon * Send a frame to all interfaces that are members of the bridge, except
3081e6720526SMatthew Dillon * for the one on which the packet arrived.
3082ac93838fSSimon Schubert */
3083d217f5e5SScott Ullrich static void
bridge_broadcast(struct bridge_softc * sc,struct ifnet * src_if,struct mbuf * m)3084e6720526SMatthew Dillon bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, struct mbuf *m)
3085ac93838fSSimon Schubert {
3086137aa7b3SSepherosa Ziehau struct bridge_iflist *bif, *nbif;
30874ee4f753SMatthew Dillon struct ether_header *eh;
3088ac93838fSSimon Schubert struct mbuf *mc;
30891e858374SMatthew Dillon struct ifnet *dst_if, *alt_if, *bifp;
30901e858374SMatthew Dillon int used;
30911e858374SMatthew Dillon int found;
30921e858374SMatthew Dillon int alt_priority;
30934ee4f753SMatthew Dillon int from_us;
3094e6720526SMatthew Dillon uint8_t alt_state;
3095ac93838fSSimon Schubert
309686989f49SMatthew Dillon mbuftrackid(m, 69);
3097ecd27a4cSSepherosa Ziehau bifp = sc->sc_ifp;
30982c9effcfSSepherosa Ziehau ASSERT_IFNET_NOT_SERIALIZED_ALL(bifp);
3099ecd27a4cSSepherosa Ziehau
31004ee4f753SMatthew Dillon eh = mtod(m, struct ether_header *);
310170d9a675SMatthew Dillon from_us = bridge_from_us(sc, eh);
31024ee4f753SMatthew Dillon
3103137aa7b3SSepherosa Ziehau if (inet_pfil_hook.ph_hashooks > 0
3104ac93838fSSimon Schubert #ifdef INET6
3105ac93838fSSimon Schubert || inet6_pfil_hook.ph_hashooks > 0
3106ac93838fSSimon Schubert #endif
3107e6720526SMatthew Dillon )
3108e6720526SMatthew Dillon {
3109137aa7b3SSepherosa Ziehau if (bridge_pfil(&m, bifp, src_if, PFIL_IN) != 0)
3110137aa7b3SSepherosa Ziehau return;
3111137aa7b3SSepherosa Ziehau if (m == NULL)
3112137aa7b3SSepherosa Ziehau return;
3113ecd27a4cSSepherosa Ziehau
3114ecd27a4cSSepherosa Ziehau /* Filter on the bridge interface before broadcasting */
3115ecd27a4cSSepherosa Ziehau if (bridge_pfil(&m, bifp, NULL, PFIL_OUT) != 0)
3116137aa7b3SSepherosa Ziehau return;
3117ac93838fSSimon Schubert if (m == NULL)
3118ac93838fSSimon Schubert return;
3119ac93838fSSimon Schubert }
3120ac93838fSSimon Schubert
3121e6720526SMatthew Dillon alt_state = BSTP_IFSTATE_LEARNING;
31224090d6ffSSascha Wildner alt_if = NULL;
31231e858374SMatthew Dillon alt_priority = 0;
31241e858374SMatthew Dillon found = 0;
31251e858374SMatthew Dillon used = 0;
31261e858374SMatthew Dillon
312770d9a675SMatthew Dillon TAILQ_FOREACH_MUTABLE(bif, &sc->sc_iflists[mycpuid], bif_next, nbif) {
3128ac93838fSSimon Schubert dst_if = bif->bif_ifp;
3129ac93838fSSimon Schubert
31301e858374SMatthew Dillon if ((dst_if->if_flags & IFF_RUNNING) == 0)
31311e858374SMatthew Dillon continue;
31321e858374SMatthew Dillon
31331e858374SMatthew Dillon /*
31345c76f1ffSMatthew Dillon * Don't bounce the packet out the same interface it came
31355c76f1ffSMatthew Dillon * in on. We have to test MAC addresses because a packet
31365c76f1ffSMatthew Dillon * can come in a bonded interface and we don't want it to
31375c76f1ffSMatthew Dillon * be echod out the forwarding interface for the same bonding
31385c76f1ffSMatthew Dillon * set.
31395c76f1ffSMatthew Dillon */
3140e6720526SMatthew Dillon if (src_if &&
3141e6720526SMatthew Dillon memcmp(IF_LLADDR(src_if), IF_LLADDR(dst_if),
3142e6720526SMatthew Dillon ETHER_ADDR_LEN) == 0)
3143e6720526SMatthew Dillon {
31445c76f1ffSMatthew Dillon continue;
31455c76f1ffSMatthew Dillon }
31465c76f1ffSMatthew Dillon
31475c76f1ffSMatthew Dillon /*
31481e858374SMatthew Dillon * Generally speaking we only broadcast through forwarding
31491e858374SMatthew Dillon * interfaces. If no interfaces are available we select
31501e858374SMatthew Dillon * a BONDED, BLOCKING, or LEARNING interface to forward
31511e858374SMatthew Dillon * through.
31521e858374SMatthew Dillon */
3153ac93838fSSimon Schubert if (bif->bif_flags & IFBIF_STP) {
3154ac93838fSSimon Schubert switch (bif->bif_state) {
3155e6720526SMatthew Dillon case BSTP_IFSTATE_LEARNING:
3156e6720526SMatthew Dillon if (alt_state == BSTP_IFSTATE_LEARNING &&
3157e6720526SMatthew Dillon bif->bif_priority > alt_priority)
3158e6720526SMatthew Dillon {
3159e6720526SMatthew Dillon alt_priority = bif->bif_priority;
31601e858374SMatthew Dillon alt_if = bif->bif_ifp;
31611e858374SMatthew Dillon }
3162ac93838fSSimon Schubert continue;
31631e858374SMatthew Dillon case BSTP_IFSTATE_BLOCKING:
3164e6720526SMatthew Dillon if (alt_state == BSTP_IFSTATE_LEARNING ||
3165e6720526SMatthew Dillon (alt_state == BSTP_IFSTATE_BLOCKING &&
3166e6720526SMatthew Dillon bif->bif_priority > alt_priority))
3167e6720526SMatthew Dillon {
3168e6720526SMatthew Dillon alt_state = BSTP_IFSTATE_BLOCKING;
3169e6720526SMatthew Dillon alt_priority = bif->bif_priority;
31701e858374SMatthew Dillon alt_if = bif->bif_ifp;
31711e858374SMatthew Dillon }
31721e858374SMatthew Dillon continue;
3173e6720526SMatthew Dillon case BSTP_IFSTATE_BONDED:
3174e6720526SMatthew Dillon if (alt_state != BSTP_IFSTATE_BONDED ||
3175e6720526SMatthew Dillon bif->bif_priority > alt_priority)
3176e6720526SMatthew Dillon {
3177e6720526SMatthew Dillon alt_state = BSTP_IFSTATE_BONDED;
31781e858374SMatthew Dillon alt_priority = bif->bif_priority;
31791e858374SMatthew Dillon alt_if = bif->bif_ifp;
31801e858374SMatthew Dillon }
31811e858374SMatthew Dillon continue;
31821e858374SMatthew Dillon case BSTP_IFSTATE_L1BLOCKING:
31831e858374SMatthew Dillon case BSTP_IFSTATE_DISABLED:
31841e858374SMatthew Dillon case BSTP_IFSTATE_LISTENING:
31851e858374SMatthew Dillon continue;
31861e858374SMatthew Dillon default:
31871e858374SMatthew Dillon /* forwarding */
31881e858374SMatthew Dillon break;
3189ac93838fSSimon Schubert }
3190ac93838fSSimon Schubert }
3191ac93838fSSimon Schubert
3192e6720526SMatthew Dillon /*
3193e6720526SMatthew Dillon * FORWARDING
3194e6720526SMatthew Dillon */
3195ac93838fSSimon Schubert if ((bif->bif_flags & IFBIF_DISCOVER) == 0 &&
3196e6720526SMatthew Dillon (m->m_flags & (M_BCAST|M_MCAST)) == 0)
3197e6720526SMatthew Dillon {
3198ac93838fSSimon Schubert continue;
31991e858374SMatthew Dillon }
3200ac93838fSSimon Schubert
3201e6720526SMatthew Dillon /*
3202e6720526SMatthew Dillon * Last interface in list?
3203e6720526SMatthew Dillon */
320470d9a675SMatthew Dillon if (TAILQ_NEXT(bif, bif_next) == NULL) {
3205ac93838fSSimon Schubert mc = m;
3206ac93838fSSimon Schubert used = 1;
3207ac93838fSSimon Schubert } else {
3208b5523eacSSascha Wildner mc = m_copypacket(m, M_NOWAIT);
3209ac93838fSSimon Schubert if (mc == NULL) {
3210d40991efSSepherosa Ziehau IFNET_STAT_INC(sc->sc_ifp, oerrors, 1);
3211ac93838fSSimon Schubert continue;
3212ac93838fSSimon Schubert }
3213ac93838fSSimon Schubert }
32141e858374SMatthew Dillon found = 1;
3215137aa7b3SSepherosa Ziehau
3216137aa7b3SSepherosa Ziehau /*
3217137aa7b3SSepherosa Ziehau * Filter on the output interface. Pass a NULL bridge
3218137aa7b3SSepherosa Ziehau * interface pointer so we do not redundantly filter on
3219137aa7b3SSepherosa Ziehau * the bridge for each interface we broadcast on.
3220137aa7b3SSepherosa Ziehau */
3221137aa7b3SSepherosa Ziehau if (inet_pfil_hook.ph_hashooks > 0
3222137aa7b3SSepherosa Ziehau #ifdef INET6
3223137aa7b3SSepherosa Ziehau || inet6_pfil_hook.ph_hashooks > 0
3224137aa7b3SSepherosa Ziehau #endif
3225e6720526SMatthew Dillon )
3226e6720526SMatthew Dillon {
3227137aa7b3SSepherosa Ziehau if (bridge_pfil(&mc, NULL, dst_if, PFIL_OUT) != 0)
3228137aa7b3SSepherosa Ziehau continue;
3229137aa7b3SSepherosa Ziehau if (mc == NULL)
3230137aa7b3SSepherosa Ziehau continue;
3231137aa7b3SSepherosa Ziehau }
323270d9a675SMatthew Dillon bridge_handoff(sc, dst_if, mc, from_us);
3233137aa7b3SSepherosa Ziehau
3234137aa7b3SSepherosa Ziehau if (nbif != NULL && !nbif->bif_onlist) {
3235137aa7b3SSepherosa Ziehau KKASSERT(bif->bif_onlist);
323670d9a675SMatthew Dillon nbif = TAILQ_NEXT(bif, bif_next);
3237137aa7b3SSepherosa Ziehau }
3238ac93838fSSimon Schubert }
32391e858374SMatthew Dillon
32401e858374SMatthew Dillon if (found == 0 && alt_if) {
32411e858374SMatthew Dillon KKASSERT(used == 0);
32421e858374SMatthew Dillon mc = m;
32431e858374SMatthew Dillon used = 1;
32441e858374SMatthew Dillon bridge_enqueue(alt_if, mc);
32451e858374SMatthew Dillon }
32461e858374SMatthew Dillon
3247ac93838fSSimon Schubert if (used == 0)
3248ac93838fSSimon Schubert m_freem(m);
3249ac93838fSSimon Schubert }
3250ac93838fSSimon Schubert
3251ac93838fSSimon Schubert /*
3252d217f5e5SScott Ullrich * bridge_span:
3253d217f5e5SScott Ullrich *
3254d217f5e5SScott Ullrich * Duplicate a packet out one or more interfaces that are in span mode,
3255d217f5e5SScott Ullrich * the original mbuf is unmodified.
3256d217f5e5SScott Ullrich */
3257d217f5e5SScott Ullrich static void
bridge_span(struct bridge_softc * sc,struct mbuf * m)3258d217f5e5SScott Ullrich bridge_span(struct bridge_softc *sc, struct mbuf *m)
3259d217f5e5SScott Ullrich {
3260d217f5e5SScott Ullrich struct bridge_iflist *bif;
3261137aa7b3SSepherosa Ziehau struct ifnet *dst_if, *bifp;
3262d217f5e5SScott Ullrich struct mbuf *mc;
3263d217f5e5SScott Ullrich
326486989f49SMatthew Dillon mbuftrackid(m, 70);
3265137aa7b3SSepherosa Ziehau bifp = sc->sc_ifp;
3266a3dd34d2SSepherosa Ziehau ifnet_serialize_all(bifp);
3267137aa7b3SSepherosa Ziehau
326870d9a675SMatthew Dillon TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) {
3269d217f5e5SScott Ullrich dst_if = bif->bif_ifp;
3270d217f5e5SScott Ullrich
3271d217f5e5SScott Ullrich if ((dst_if->if_flags & IFF_RUNNING) == 0)
3272d217f5e5SScott Ullrich continue;
3273d217f5e5SScott Ullrich
3274b5523eacSSascha Wildner mc = m_copypacket(m, M_NOWAIT);
3275d217f5e5SScott Ullrich if (mc == NULL) {
3276d40991efSSepherosa Ziehau IFNET_STAT_INC(sc->sc_ifp, oerrors, 1);
3277d217f5e5SScott Ullrich continue;
3278d217f5e5SScott Ullrich }
3279708a3bfaSSepherosa Ziehau bridge_enqueue(dst_if, mc);
3280d217f5e5SScott Ullrich }
3281137aa7b3SSepherosa Ziehau
3282a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(bifp);
3283d217f5e5SScott Ullrich }
3284d217f5e5SScott Ullrich
32854394693cSSepherosa Ziehau static void
bridge_rtmsg_sync_handler(netmsg_t msg)3286002c1265SMatthew Dillon bridge_rtmsg_sync_handler(netmsg_t msg)
32874394693cSSepherosa Ziehau {
3288fddbe7b3SSepherosa Ziehau netisr_forwardmsg(&msg->base, mycpuid + 1);
32894394693cSSepherosa Ziehau }
32904394693cSSepherosa Ziehau
32914394693cSSepherosa Ziehau static void
bridge_rtmsg_sync(struct bridge_softc * sc)32924394693cSSepherosa Ziehau bridge_rtmsg_sync(struct bridge_softc *sc)
32934394693cSSepherosa Ziehau {
3294002c1265SMatthew Dillon struct netmsg_base msg;
32954394693cSSepherosa Ziehau
32962c9effcfSSepherosa Ziehau ASSERT_IFNET_NOT_SERIALIZED_ALL(sc->sc_ifp);
32974394693cSSepherosa Ziehau
3298deae8bb6SSepherosa Ziehau /* XXX use netmsg_service_sync */
3299002c1265SMatthew Dillon netmsg_init(&msg, NULL, &curthread->td_msgport,
330048e7b118SMatthew Dillon 0, bridge_rtmsg_sync_handler);
3301deae8bb6SSepherosa Ziehau netisr_domsg(&msg, 0);
33024394693cSSepherosa Ziehau }
33034394693cSSepherosa Ziehau
33044394693cSSepherosa Ziehau static __inline void
bridge_rtinfo_update(struct bridge_rtinfo * bri,struct ifnet * dst_if,int setflags,uint8_t flags,uint32_t timeo)33054394693cSSepherosa Ziehau bridge_rtinfo_update(struct bridge_rtinfo *bri, struct ifnet *dst_if,
33064394693cSSepherosa Ziehau int setflags, uint8_t flags, uint32_t timeo)
33074394693cSSepherosa Ziehau {
33084394693cSSepherosa Ziehau if ((bri->bri_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC &&
33094394693cSSepherosa Ziehau bri->bri_ifp != dst_if)
33104394693cSSepherosa Ziehau bri->bri_ifp = dst_if;
33114394693cSSepherosa Ziehau if ((flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC &&
3312cec73927SMatthew Dillon bri->bri_expire != time_uptime + timeo)
3313cec73927SMatthew Dillon bri->bri_expire = time_uptime + timeo;
33144394693cSSepherosa Ziehau if (setflags)
33154394693cSSepherosa Ziehau bri->bri_flags = flags;
33164394693cSSepherosa Ziehau }
33174394693cSSepherosa Ziehau
33184394693cSSepherosa Ziehau static int
bridge_rtinstall_oncpu(struct bridge_softc * sc,const uint8_t * dst,struct ifnet * dst_if,int setflags,uint8_t flags,struct bridge_rtinfo ** bri0)33194394693cSSepherosa Ziehau bridge_rtinstall_oncpu(struct bridge_softc *sc, const uint8_t *dst,
33204394693cSSepherosa Ziehau struct ifnet *dst_if, int setflags, uint8_t flags,
33214394693cSSepherosa Ziehau struct bridge_rtinfo **bri0)
33224394693cSSepherosa Ziehau {
33234394693cSSepherosa Ziehau struct bridge_rtnode *brt;
33244394693cSSepherosa Ziehau struct bridge_rtinfo *bri;
33254394693cSSepherosa Ziehau
33264394693cSSepherosa Ziehau if (mycpuid == 0) {
33274394693cSSepherosa Ziehau brt = bridge_rtnode_lookup(sc, dst);
33284394693cSSepherosa Ziehau if (brt != NULL) {
33294394693cSSepherosa Ziehau /*
33304394693cSSepherosa Ziehau * rtnode for 'dst' already exists. We inform the
33314394693cSSepherosa Ziehau * caller about this by leaving bri0 as NULL. The
33324394693cSSepherosa Ziehau * caller will terminate the intallation upon getting
33334394693cSSepherosa Ziehau * NULL bri0. However, we still need to update the
33344394693cSSepherosa Ziehau * rtinfo.
33354394693cSSepherosa Ziehau */
33364394693cSSepherosa Ziehau KKASSERT(*bri0 == NULL);
33374394693cSSepherosa Ziehau
33384394693cSSepherosa Ziehau /* Update rtinfo */
33394394693cSSepherosa Ziehau bridge_rtinfo_update(brt->brt_info, dst_if, setflags,
33404394693cSSepherosa Ziehau flags, sc->sc_brttimeout);
33414394693cSSepherosa Ziehau return 0;
33424394693cSSepherosa Ziehau }
33434394693cSSepherosa Ziehau
33444394693cSSepherosa Ziehau /*
33454394693cSSepherosa Ziehau * We only need to check brtcnt on CPU0, since if limit
33464394693cSSepherosa Ziehau * is to be exceeded, ENOSPC is returned. Caller knows
33474394693cSSepherosa Ziehau * this and will terminate the installation.
33484394693cSSepherosa Ziehau */
33494394693cSSepherosa Ziehau if (sc->sc_brtcnt >= sc->sc_brtmax)
33504394693cSSepherosa Ziehau return ENOSPC;
33514394693cSSepherosa Ziehau
33524394693cSSepherosa Ziehau KKASSERT(*bri0 == NULL);
33534394693cSSepherosa Ziehau bri = kmalloc(sizeof(struct bridge_rtinfo), M_DEVBUF,
33544394693cSSepherosa Ziehau M_WAITOK | M_ZERO);
33554394693cSSepherosa Ziehau *bri0 = bri;
33564394693cSSepherosa Ziehau
33574394693cSSepherosa Ziehau /* Setup rtinfo */
33584394693cSSepherosa Ziehau bri->bri_flags = IFBAF_DYNAMIC;
33594394693cSSepherosa Ziehau bridge_rtinfo_update(bri, dst_if, setflags, flags,
33604394693cSSepherosa Ziehau sc->sc_brttimeout);
33614394693cSSepherosa Ziehau } else {
33624394693cSSepherosa Ziehau bri = *bri0;
33634394693cSSepherosa Ziehau KKASSERT(bri != NULL);
33644394693cSSepherosa Ziehau }
33654394693cSSepherosa Ziehau
33664394693cSSepherosa Ziehau brt = kmalloc(sizeof(struct bridge_rtnode), M_DEVBUF,
33674394693cSSepherosa Ziehau M_WAITOK | M_ZERO);
33684394693cSSepherosa Ziehau memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN);
33694394693cSSepherosa Ziehau brt->brt_info = bri;
3370e41e076dSMatthew Dillon atomic_add_int(&bri->bri_refs, 1);
33714394693cSSepherosa Ziehau
33724394693cSSepherosa Ziehau bridge_rtnode_insert(sc, brt);
33734394693cSSepherosa Ziehau return 0;
33744394693cSSepherosa Ziehau }
33754394693cSSepherosa Ziehau
33764394693cSSepherosa Ziehau static void
bridge_rtinstall_handler(netmsg_t msg)3377002c1265SMatthew Dillon bridge_rtinstall_handler(netmsg_t msg)
33784394693cSSepherosa Ziehau {
3379002c1265SMatthew Dillon struct netmsg_brsaddr *brmsg = (struct netmsg_brsaddr *)msg;
33804394693cSSepherosa Ziehau int error;
33814394693cSSepherosa Ziehau
33824394693cSSepherosa Ziehau error = bridge_rtinstall_oncpu(brmsg->br_softc,
33834394693cSSepherosa Ziehau brmsg->br_dst, brmsg->br_dst_if,
33844394693cSSepherosa Ziehau brmsg->br_setflags, brmsg->br_flags,
33854394693cSSepherosa Ziehau &brmsg->br_rtinfo);
33864394693cSSepherosa Ziehau if (error) {
33874394693cSSepherosa Ziehau KKASSERT(mycpuid == 0 && brmsg->br_rtinfo == NULL);
3388deae8bb6SSepherosa Ziehau netisr_replymsg(&brmsg->base, error);
33894394693cSSepherosa Ziehau return;
33904394693cSSepherosa Ziehau } else if (brmsg->br_rtinfo == NULL) {
33914394693cSSepherosa Ziehau /* rtnode already exists for 'dst' */
33924394693cSSepherosa Ziehau KKASSERT(mycpuid == 0);
3393deae8bb6SSepherosa Ziehau netisr_replymsg(&brmsg->base, 0);
33944394693cSSepherosa Ziehau return;
33954394693cSSepherosa Ziehau }
3396fddbe7b3SSepherosa Ziehau netisr_forwardmsg(&brmsg->base, mycpuid + 1);
33974394693cSSepherosa Ziehau }
33984394693cSSepherosa Ziehau
3399d217f5e5SScott Ullrich /*
3400ac93838fSSimon Schubert * bridge_rtupdate:
3401ac93838fSSimon Schubert *
34024394693cSSepherosa Ziehau * Add/Update a bridge routing entry.
3403ac93838fSSimon Schubert */
3404d217f5e5SScott Ullrich static int
bridge_rtupdate(struct bridge_softc * sc,const uint8_t * dst,struct ifnet * dst_if,uint8_t flags)3405ac93838fSSimon Schubert bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst,
34064394693cSSepherosa Ziehau struct ifnet *dst_if, uint8_t flags)
3407ac93838fSSimon Schubert {
3408ac93838fSSimon Schubert struct bridge_rtnode *brt;
3409ac93838fSSimon Schubert
3410ac93838fSSimon Schubert /*
3411ac93838fSSimon Schubert * A route for this destination might already exist. If so,
3412ac93838fSSimon Schubert * update it, otherwise create a new one.
3413ac93838fSSimon Schubert */
3414ac93838fSSimon Schubert if ((brt = bridge_rtnode_lookup(sc, dst)) == NULL) {
34154394693cSSepherosa Ziehau struct netmsg_brsaddr *brmsg;
34164394693cSSepherosa Ziehau
3417ac93838fSSimon Schubert if (sc->sc_brtcnt >= sc->sc_brtmax)
34184394693cSSepherosa Ziehau return ENOSPC;
3419ac93838fSSimon Schubert
34204394693cSSepherosa Ziehau brmsg = kmalloc(sizeof(*brmsg), M_LWKTMSG, M_WAITOK | M_NULLOK);
34214394693cSSepherosa Ziehau if (brmsg == NULL)
34224394693cSSepherosa Ziehau return ENOMEM;
3423ac93838fSSimon Schubert
3424002c1265SMatthew Dillon netmsg_init(&brmsg->base, NULL, &netisr_afree_rport,
342548e7b118SMatthew Dillon 0, bridge_rtinstall_handler);
34264394693cSSepherosa Ziehau memcpy(brmsg->br_dst, dst, ETHER_ADDR_LEN);
34274394693cSSepherosa Ziehau brmsg->br_dst_if = dst_if;
34284394693cSSepherosa Ziehau brmsg->br_flags = flags;
34294394693cSSepherosa Ziehau brmsg->br_setflags = 0;
34304394693cSSepherosa Ziehau brmsg->br_softc = sc;
34314394693cSSepherosa Ziehau brmsg->br_rtinfo = NULL;
3432ac93838fSSimon Schubert
3433deae8bb6SSepherosa Ziehau netisr_sendmsg(&brmsg->base, 0);
34344394693cSSepherosa Ziehau return 0;
3435ac93838fSSimon Schubert }
34364394693cSSepherosa Ziehau bridge_rtinfo_update(brt->brt_info, dst_if, 0, flags,
34374394693cSSepherosa Ziehau sc->sc_brttimeout);
34384394693cSSepherosa Ziehau return 0;
3439ac93838fSSimon Schubert }
3440ac93838fSSimon Schubert
34414394693cSSepherosa Ziehau static int
bridge_rtsaddr(struct bridge_softc * sc,const uint8_t * dst,struct ifnet * dst_if,uint8_t flags)34424394693cSSepherosa Ziehau bridge_rtsaddr(struct bridge_softc *sc, const uint8_t *dst,
34434394693cSSepherosa Ziehau struct ifnet *dst_if, uint8_t flags)
34444394693cSSepherosa Ziehau {
34454394693cSSepherosa Ziehau struct netmsg_brsaddr brmsg;
3446ac93838fSSimon Schubert
34472c9effcfSSepherosa Ziehau ASSERT_IFNET_NOT_SERIALIZED_ALL(sc->sc_ifp);
34484394693cSSepherosa Ziehau
3449002c1265SMatthew Dillon netmsg_init(&brmsg.base, NULL, &curthread->td_msgport,
345048e7b118SMatthew Dillon 0, bridge_rtinstall_handler);
34514394693cSSepherosa Ziehau memcpy(brmsg.br_dst, dst, ETHER_ADDR_LEN);
34524394693cSSepherosa Ziehau brmsg.br_dst_if = dst_if;
34534394693cSSepherosa Ziehau brmsg.br_flags = flags;
34544394693cSSepherosa Ziehau brmsg.br_setflags = 1;
34554394693cSSepherosa Ziehau brmsg.br_softc = sc;
34564394693cSSepherosa Ziehau brmsg.br_rtinfo = NULL;
34574394693cSSepherosa Ziehau
3458deae8bb6SSepherosa Ziehau return netisr_domsg(&brmsg.base, 0);
3459ac93838fSSimon Schubert }
3460ac93838fSSimon Schubert
3461ac93838fSSimon Schubert /*
3462ac93838fSSimon Schubert * bridge_rtlookup:
3463ac93838fSSimon Schubert *
3464ac93838fSSimon Schubert * Lookup the destination interface for an address.
3465ac93838fSSimon Schubert */
3466d217f5e5SScott Ullrich static struct ifnet *
bridge_rtlookup(struct bridge_softc * sc,const uint8_t * addr)3467ac93838fSSimon Schubert bridge_rtlookup(struct bridge_softc *sc, const uint8_t *addr)
3468ac93838fSSimon Schubert {
3469ac93838fSSimon Schubert struct bridge_rtnode *brt;
3470ac93838fSSimon Schubert
3471ac93838fSSimon Schubert if ((brt = bridge_rtnode_lookup(sc, addr)) == NULL)
34724394693cSSepherosa Ziehau return NULL;
34734394693cSSepherosa Ziehau return brt->brt_info->bri_ifp;
34744394693cSSepherosa Ziehau }
3475ac93838fSSimon Schubert
34764394693cSSepherosa Ziehau static void
bridge_rtreap_handler(netmsg_t msg)3477002c1265SMatthew Dillon bridge_rtreap_handler(netmsg_t msg)
34784394693cSSepherosa Ziehau {
3479002c1265SMatthew Dillon struct bridge_softc *sc = msg->lmsg.u.ms_resultp;
34804394693cSSepherosa Ziehau struct bridge_rtnode *brt, *nbrt;
34814394693cSSepherosa Ziehau
34824394693cSSepherosa Ziehau LIST_FOREACH_MUTABLE(brt, &sc->sc_rtlists[mycpuid], brt_list, nbrt) {
34834394693cSSepherosa Ziehau if (brt->brt_info->bri_dead)
34844394693cSSepherosa Ziehau bridge_rtnode_destroy(sc, brt);
34854394693cSSepherosa Ziehau }
3486fddbe7b3SSepherosa Ziehau netisr_forwardmsg(&msg->base, mycpuid + 1);
34874394693cSSepherosa Ziehau }
34884394693cSSepherosa Ziehau
34894394693cSSepherosa Ziehau static void
bridge_rtreap(struct bridge_softc * sc)34904394693cSSepherosa Ziehau bridge_rtreap(struct bridge_softc *sc)
34914394693cSSepherosa Ziehau {
3492002c1265SMatthew Dillon struct netmsg_base msg;
34934394693cSSepherosa Ziehau
34942c9effcfSSepherosa Ziehau ASSERT_IFNET_NOT_SERIALIZED_ALL(sc->sc_ifp);
34954394693cSSepherosa Ziehau
3496002c1265SMatthew Dillon netmsg_init(&msg, NULL, &curthread->td_msgport,
349748e7b118SMatthew Dillon 0, bridge_rtreap_handler);
3498002c1265SMatthew Dillon msg.lmsg.u.ms_resultp = sc;
34994394693cSSepherosa Ziehau
3500deae8bb6SSepherosa Ziehau netisr_domsg(&msg, 0);
3501ac93838fSSimon Schubert }
3502ac93838fSSimon Schubert
350330ced003SSepherosa Ziehau static void
bridge_rtreap_async(struct bridge_softc * sc)350430ced003SSepherosa Ziehau bridge_rtreap_async(struct bridge_softc *sc)
350530ced003SSepherosa Ziehau {
3506002c1265SMatthew Dillon struct netmsg_base *msg;
350730ced003SSepherosa Ziehau
3508002c1265SMatthew Dillon msg = kmalloc(sizeof(*msg), M_LWKTMSG, M_WAITOK);
350930ced003SSepherosa Ziehau
3510002c1265SMatthew Dillon netmsg_init(msg, NULL, &netisr_afree_rport,
351148e7b118SMatthew Dillon 0, bridge_rtreap_handler);
3512002c1265SMatthew Dillon msg->lmsg.u.ms_resultp = sc;
351330ced003SSepherosa Ziehau
3514deae8bb6SSepherosa Ziehau netisr_sendmsg(msg, 0);
351530ced003SSepherosa Ziehau }
351630ced003SSepherosa Ziehau
3517ac93838fSSimon Schubert /*
3518ac93838fSSimon Schubert * bridge_rttrim:
3519ac93838fSSimon Schubert *
3520ac93838fSSimon Schubert * Trim the routine table so that we have a number
3521ac93838fSSimon Schubert * of routing entries less than or equal to the
3522ac93838fSSimon Schubert * maximum number.
3523ac93838fSSimon Schubert */
3524d217f5e5SScott Ullrich static void
bridge_rttrim(struct bridge_softc * sc)3525ac93838fSSimon Schubert bridge_rttrim(struct bridge_softc *sc)
3526ac93838fSSimon Schubert {
35274394693cSSepherosa Ziehau struct bridge_rtnode *brt;
35284394693cSSepherosa Ziehau int dead;
35294394693cSSepherosa Ziehau
35302c9effcfSSepherosa Ziehau ASSERT_IFNET_NOT_SERIALIZED_ALL(sc->sc_ifp);
3531ac93838fSSimon Schubert
3532ac93838fSSimon Schubert /* Make sure we actually need to do this. */
3533ac93838fSSimon Schubert if (sc->sc_brtcnt <= sc->sc_brtmax)
3534ac93838fSSimon Schubert return;
3535ac93838fSSimon Schubert
35364394693cSSepherosa Ziehau /*
35374394693cSSepherosa Ziehau * Find out how many rtnodes are dead
35384394693cSSepherosa Ziehau */
35394394693cSSepherosa Ziehau dead = bridge_rtage_finddead(sc);
35404394693cSSepherosa Ziehau KKASSERT(dead <= sc->sc_brtcnt);
3541ac93838fSSimon Schubert
35424394693cSSepherosa Ziehau if (sc->sc_brtcnt - dead <= sc->sc_brtmax) {
35434394693cSSepherosa Ziehau /* Enough dead rtnodes are found */
35444394693cSSepherosa Ziehau bridge_rtreap(sc);
3545ac93838fSSimon Schubert return;
3546ac93838fSSimon Schubert }
35474394693cSSepherosa Ziehau
35484394693cSSepherosa Ziehau /*
35494394693cSSepherosa Ziehau * Kill some dynamic rtnodes to meet the brtmax
35504394693cSSepherosa Ziehau */
35514394693cSSepherosa Ziehau LIST_FOREACH(brt, &sc->sc_rtlists[mycpuid], brt_list) {
35524394693cSSepherosa Ziehau struct bridge_rtinfo *bri = brt->brt_info;
35534394693cSSepherosa Ziehau
35544394693cSSepherosa Ziehau if (bri->bri_dead) {
35554394693cSSepherosa Ziehau /*
35564394693cSSepherosa Ziehau * We have counted this rtnode in
35574394693cSSepherosa Ziehau * bridge_rtage_finddead()
35584394693cSSepherosa Ziehau */
35594394693cSSepherosa Ziehau continue;
3560ac93838fSSimon Schubert }
35614394693cSSepherosa Ziehau
35624394693cSSepherosa Ziehau if ((bri->bri_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
35634394693cSSepherosa Ziehau bri->bri_dead = 1;
35644394693cSSepherosa Ziehau ++dead;
35654394693cSSepherosa Ziehau KKASSERT(dead <= sc->sc_brtcnt);
35664394693cSSepherosa Ziehau
35674394693cSSepherosa Ziehau if (sc->sc_brtcnt - dead <= sc->sc_brtmax) {
35684394693cSSepherosa Ziehau /* Enough rtnodes are collected */
35694394693cSSepherosa Ziehau break;
35704394693cSSepherosa Ziehau }
35714394693cSSepherosa Ziehau }
35724394693cSSepherosa Ziehau }
35734394693cSSepherosa Ziehau if (dead)
35744394693cSSepherosa Ziehau bridge_rtreap(sc);
3575ac93838fSSimon Schubert }
3576ac93838fSSimon Schubert
3577ac93838fSSimon Schubert /*
3578ac93838fSSimon Schubert * bridge_timer:
3579ac93838fSSimon Schubert *
3580ac93838fSSimon Schubert * Aging timer for the bridge.
3581ac93838fSSimon Schubert */
3582d217f5e5SScott Ullrich static void
bridge_timer(void * arg)3583ac93838fSSimon Schubert bridge_timer(void *arg)
3584ac93838fSSimon Schubert {
3585ac93838fSSimon Schubert struct bridge_softc *sc = arg;
3586002c1265SMatthew Dillon struct netmsg_base *msg;
3587e9d22060SSepherosa Ziehau
3588e9d22060SSepherosa Ziehau KKASSERT(mycpuid == BRIDGE_CFGCPU);
3589e9d22060SSepherosa Ziehau
3590e9d22060SSepherosa Ziehau crit_enter();
3591e9d22060SSepherosa Ziehau
3592e9d22060SSepherosa Ziehau if (callout_pending(&sc->sc_brcallout) ||
3593e9d22060SSepherosa Ziehau !callout_active(&sc->sc_brcallout)) {
3594e9d22060SSepherosa Ziehau crit_exit();
3595e9d22060SSepherosa Ziehau return;
3596e9d22060SSepherosa Ziehau }
3597e9d22060SSepherosa Ziehau callout_deactivate(&sc->sc_brcallout);
3598e9d22060SSepherosa Ziehau
3599002c1265SMatthew Dillon msg = &sc->sc_brtimemsg;
3600002c1265SMatthew Dillon KKASSERT(msg->lmsg.ms_flags & MSGF_DONE);
36013a51da79SSepherosa Ziehau lwkt_sendmsg_oncpu(BRIDGE_CFGPORT, &msg->lmsg);
3602e9d22060SSepherosa Ziehau
3603e9d22060SSepherosa Ziehau crit_exit();
3604e9d22060SSepherosa Ziehau }
3605e9d22060SSepherosa Ziehau
3606e9d22060SSepherosa Ziehau static void
bridge_timer_handler(netmsg_t msg)3607002c1265SMatthew Dillon bridge_timer_handler(netmsg_t msg)
3608e9d22060SSepherosa Ziehau {
3609002c1265SMatthew Dillon struct bridge_softc *sc = msg->lmsg.u.ms_resultp;
3610e9d22060SSepherosa Ziehau
3611e9d22060SSepherosa Ziehau KKASSERT(&curthread->td_msgport == BRIDGE_CFGPORT);
3612e9d22060SSepherosa Ziehau
3613e9d22060SSepherosa Ziehau crit_enter();
3614e9d22060SSepherosa Ziehau /* Reply ASAP */
3615002c1265SMatthew Dillon lwkt_replymsg(&msg->lmsg, 0);
3616e9d22060SSepherosa Ziehau crit_exit();
3617ac93838fSSimon Schubert
3618ac93838fSSimon Schubert bridge_rtage(sc);
3619e9d22060SSepherosa Ziehau if (sc->sc_ifp->if_flags & IFF_RUNNING) {
3620ac93838fSSimon Schubert callout_reset(&sc->sc_brcallout,
3621ac93838fSSimon Schubert bridge_rtable_prune_period * hz, bridge_timer, sc);
3622e9d22060SSepherosa Ziehau }
36234394693cSSepherosa Ziehau }
3624ac93838fSSimon Schubert
36254394693cSSepherosa Ziehau static int
bridge_rtage_finddead(struct bridge_softc * sc)36264394693cSSepherosa Ziehau bridge_rtage_finddead(struct bridge_softc *sc)
36274394693cSSepherosa Ziehau {
36284394693cSSepherosa Ziehau struct bridge_rtnode *brt;
36294394693cSSepherosa Ziehau int dead = 0;
36304394693cSSepherosa Ziehau
36314394693cSSepherosa Ziehau LIST_FOREACH(brt, &sc->sc_rtlists[mycpuid], brt_list) {
36324394693cSSepherosa Ziehau struct bridge_rtinfo *bri = brt->brt_info;
36334394693cSSepherosa Ziehau
36344394693cSSepherosa Ziehau if ((bri->bri_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC &&
3635cec73927SMatthew Dillon time_uptime >= bri->bri_expire) {
36364394693cSSepherosa Ziehau bri->bri_dead = 1;
36374394693cSSepherosa Ziehau ++dead;
36384394693cSSepherosa Ziehau KKASSERT(dead <= sc->sc_brtcnt);
36394394693cSSepherosa Ziehau }
36404394693cSSepherosa Ziehau }
36414394693cSSepherosa Ziehau return dead;
3642ac93838fSSimon Schubert }
3643ac93838fSSimon Schubert
3644ac93838fSSimon Schubert /*
3645ac93838fSSimon Schubert * bridge_rtage:
3646ac93838fSSimon Schubert *
3647ac93838fSSimon Schubert * Perform an aging cycle.
3648ac93838fSSimon Schubert */
3649d217f5e5SScott Ullrich static void
bridge_rtage(struct bridge_softc * sc)3650ac93838fSSimon Schubert bridge_rtage(struct bridge_softc *sc)
3651ac93838fSSimon Schubert {
36522c9effcfSSepherosa Ziehau ASSERT_IFNET_NOT_SERIALIZED_ALL(sc->sc_ifp);
3653ac93838fSSimon Schubert
36544394693cSSepherosa Ziehau if (bridge_rtage_finddead(sc))
36554394693cSSepherosa Ziehau bridge_rtreap(sc);
3656ac93838fSSimon Schubert }
3657ac93838fSSimon Schubert
3658ac93838fSSimon Schubert /*
3659ac93838fSSimon Schubert * bridge_rtflush:
3660ac93838fSSimon Schubert *
3661ac93838fSSimon Schubert * Remove all dynamic addresses from the bridge.
3662ac93838fSSimon Schubert */
3663d217f5e5SScott Ullrich static void
bridge_rtflush(struct bridge_softc * sc,int bf)366430ced003SSepherosa Ziehau bridge_rtflush(struct bridge_softc *sc, int bf)
3665ac93838fSSimon Schubert {
36664394693cSSepherosa Ziehau struct bridge_rtnode *brt;
36674394693cSSepherosa Ziehau int reap;
3668ac93838fSSimon Schubert
36694394693cSSepherosa Ziehau reap = 0;
36704394693cSSepherosa Ziehau LIST_FOREACH(brt, &sc->sc_rtlists[mycpuid], brt_list) {
36714394693cSSepherosa Ziehau struct bridge_rtinfo *bri = brt->brt_info;
36724394693cSSepherosa Ziehau
367330ced003SSepherosa Ziehau if ((bf & IFBF_FLUSHALL) ||
36744394693cSSepherosa Ziehau (bri->bri_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
36754394693cSSepherosa Ziehau bri->bri_dead = 1;
36764394693cSSepherosa Ziehau reap = 1;
3677ac93838fSSimon Schubert }
3678ac93838fSSimon Schubert }
367930ced003SSepherosa Ziehau if (reap) {
368030ced003SSepherosa Ziehau if (bf & IFBF_FLUSHSYNC)
36814394693cSSepherosa Ziehau bridge_rtreap(sc);
368230ced003SSepherosa Ziehau else
368330ced003SSepherosa Ziehau bridge_rtreap_async(sc);
368430ced003SSepherosa Ziehau }
36854394693cSSepherosa Ziehau }
3686ac93838fSSimon Schubert
3687ac93838fSSimon Schubert /*
3688ac93838fSSimon Schubert * bridge_rtdaddr:
3689ac93838fSSimon Schubert *
3690ac93838fSSimon Schubert * Remove an address from the table.
3691ac93838fSSimon Schubert */
3692d217f5e5SScott Ullrich static int
bridge_rtdaddr(struct bridge_softc * sc,const uint8_t * addr)3693ac93838fSSimon Schubert bridge_rtdaddr(struct bridge_softc *sc, const uint8_t *addr)
3694ac93838fSSimon Schubert {
3695ac93838fSSimon Schubert struct bridge_rtnode *brt;
3696ac93838fSSimon Schubert
36972c9effcfSSepherosa Ziehau ASSERT_IFNET_NOT_SERIALIZED_ALL(sc->sc_ifp);
36984394693cSSepherosa Ziehau
3699ac93838fSSimon Schubert if ((brt = bridge_rtnode_lookup(sc, addr)) == NULL)
3700ac93838fSSimon Schubert return (ENOENT);
3701ac93838fSSimon Schubert
37024394693cSSepherosa Ziehau /* TODO: add a cheaper delete operation */
37034394693cSSepherosa Ziehau brt->brt_info->bri_dead = 1;
37044394693cSSepherosa Ziehau bridge_rtreap(sc);
3705ac93838fSSimon Schubert return (0);
3706ac93838fSSimon Schubert }
3707ac93838fSSimon Schubert
3708ac93838fSSimon Schubert /*
3709ac93838fSSimon Schubert * bridge_rtdelete:
3710ac93838fSSimon Schubert *
3711ac93838fSSimon Schubert * Delete routes to a speicifc member interface.
3712ac93838fSSimon Schubert */
3713ac93838fSSimon Schubert void
bridge_rtdelete(struct bridge_softc * sc,struct ifnet * ifp,int bf)371430ced003SSepherosa Ziehau bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int bf)
3715ac93838fSSimon Schubert {
37164394693cSSepherosa Ziehau struct bridge_rtnode *brt;
37174394693cSSepherosa Ziehau int reap;
3718ac93838fSSimon Schubert
37194394693cSSepherosa Ziehau reap = 0;
37204394693cSSepherosa Ziehau LIST_FOREACH(brt, &sc->sc_rtlists[mycpuid], brt_list) {
37214394693cSSepherosa Ziehau struct bridge_rtinfo *bri = brt->brt_info;
37224394693cSSepherosa Ziehau
37234394693cSSepherosa Ziehau if (bri->bri_ifp == ifp &&
372430ced003SSepherosa Ziehau ((bf & IFBF_FLUSHALL) ||
37254394693cSSepherosa Ziehau (bri->bri_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)) {
37264394693cSSepherosa Ziehau bri->bri_dead = 1;
37274394693cSSepherosa Ziehau reap = 1;
3728ac93838fSSimon Schubert }
3729ac93838fSSimon Schubert }
373030ced003SSepherosa Ziehau if (reap) {
373130ced003SSepherosa Ziehau if (bf & IFBF_FLUSHSYNC)
37324394693cSSepherosa Ziehau bridge_rtreap(sc);
373330ced003SSepherosa Ziehau else
373430ced003SSepherosa Ziehau bridge_rtreap_async(sc);
373530ced003SSepherosa Ziehau }
37364394693cSSepherosa Ziehau }
3737ac93838fSSimon Schubert
3738ac93838fSSimon Schubert /*
3739ac93838fSSimon Schubert * bridge_rtable_init:
3740ac93838fSSimon Schubert *
3741ac93838fSSimon Schubert * Initialize the route table for this bridge.
3742ac93838fSSimon Schubert */
37434394693cSSepherosa Ziehau static void
bridge_rtable_init(struct bridge_softc * sc)3744ac93838fSSimon Schubert bridge_rtable_init(struct bridge_softc *sc)
3745ac93838fSSimon Schubert {
37464394693cSSepherosa Ziehau int cpu;
37474394693cSSepherosa Ziehau
37484394693cSSepherosa Ziehau /*
37494394693cSSepherosa Ziehau * Initialize per-cpu hash tables
37504394693cSSepherosa Ziehau */
3751fddbe7b3SSepherosa Ziehau sc->sc_rthashs = kmalloc(sizeof(*sc->sc_rthashs) * netisr_ncpus,
37524394693cSSepherosa Ziehau M_DEVBUF, M_WAITOK);
3753fddbe7b3SSepherosa Ziehau for (cpu = 0; cpu < netisr_ncpus; ++cpu) {
3754ac93838fSSimon Schubert int i;
3755ac93838fSSimon Schubert
37564394693cSSepherosa Ziehau sc->sc_rthashs[cpu] =
37574394693cSSepherosa Ziehau kmalloc(sizeof(struct bridge_rtnode_head) * BRIDGE_RTHASH_SIZE,
3758d217f5e5SScott Ullrich M_DEVBUF, M_WAITOK);
3759ac93838fSSimon Schubert
3760ac93838fSSimon Schubert for (i = 0; i < BRIDGE_RTHASH_SIZE; i++)
37614394693cSSepherosa Ziehau LIST_INIT(&sc->sc_rthashs[cpu][i]);
37624394693cSSepherosa Ziehau }
37630ced1954SMatthew Dillon sc->sc_rthash_key = karc4random();
3764ac93838fSSimon Schubert
37654394693cSSepherosa Ziehau /*
37664394693cSSepherosa Ziehau * Initialize per-cpu lists
37674394693cSSepherosa Ziehau */
3768fddbe7b3SSepherosa Ziehau sc->sc_rtlists =
3769fddbe7b3SSepherosa Ziehau kmalloc(sizeof(struct bridge_rtnode_head) * netisr_ncpus,
37704394693cSSepherosa Ziehau M_DEVBUF, M_WAITOK);
3771fddbe7b3SSepherosa Ziehau for (cpu = 0; cpu < netisr_ncpus; ++cpu)
37724394693cSSepherosa Ziehau LIST_INIT(&sc->sc_rtlists[cpu]);
3773ac93838fSSimon Schubert }
3774ac93838fSSimon Schubert
3775ac93838fSSimon Schubert /*
3776ac93838fSSimon Schubert * bridge_rtable_fini:
3777ac93838fSSimon Schubert *
3778ac93838fSSimon Schubert * Deconstruct the route table for this bridge.
3779ac93838fSSimon Schubert */
3780d217f5e5SScott Ullrich static void
bridge_rtable_fini(struct bridge_softc * sc)3781ac93838fSSimon Schubert bridge_rtable_fini(struct bridge_softc *sc)
3782ac93838fSSimon Schubert {
37834394693cSSepherosa Ziehau int cpu;
3784ac93838fSSimon Schubert
37854394693cSSepherosa Ziehau /*
37864394693cSSepherosa Ziehau * Free per-cpu hash tables
37874394693cSSepherosa Ziehau */
3788fddbe7b3SSepherosa Ziehau for (cpu = 0; cpu < netisr_ncpus; ++cpu)
37894394693cSSepherosa Ziehau kfree(sc->sc_rthashs[cpu], M_DEVBUF);
37904394693cSSepherosa Ziehau kfree(sc->sc_rthashs, M_DEVBUF);
37914394693cSSepherosa Ziehau
37924394693cSSepherosa Ziehau /*
37934394693cSSepherosa Ziehau * Free per-cpu lists
37944394693cSSepherosa Ziehau */
37954394693cSSepherosa Ziehau kfree(sc->sc_rtlists, M_DEVBUF);
3796ac93838fSSimon Schubert }
3797ac93838fSSimon Schubert
3798ac93838fSSimon Schubert /*
3799ac93838fSSimon Schubert * The following hash function is adapted from "Hash Functions" by Bob Jenkins
3800ac93838fSSimon Schubert * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
3801ac93838fSSimon Schubert */
3802ac93838fSSimon Schubert #define mix(a, b, c) \
3803ac93838fSSimon Schubert do { \
3804ac93838fSSimon Schubert a -= b; a -= c; a ^= (c >> 13); \
3805ac93838fSSimon Schubert b -= c; b -= a; b ^= (a << 8); \
3806ac93838fSSimon Schubert c -= a; c -= b; c ^= (b >> 13); \
3807ac93838fSSimon Schubert a -= b; a -= c; a ^= (c >> 12); \
3808ac93838fSSimon Schubert b -= c; b -= a; b ^= (a << 16); \
3809ac93838fSSimon Schubert c -= a; c -= b; c ^= (b >> 5); \
3810ac93838fSSimon Schubert a -= b; a -= c; a ^= (c >> 3); \
3811ac93838fSSimon Schubert b -= c; b -= a; b ^= (a << 10); \
3812ac93838fSSimon Schubert c -= a; c -= b; c ^= (b >> 15); \
3813ac93838fSSimon Schubert } while (/*CONSTCOND*/0)
3814ac93838fSSimon Schubert
3815ac93838fSSimon Schubert static __inline uint32_t
bridge_rthash(struct bridge_softc * sc,const uint8_t * addr)3816ac93838fSSimon Schubert bridge_rthash(struct bridge_softc *sc, const uint8_t *addr)
3817ac93838fSSimon Schubert {
3818ac93838fSSimon Schubert uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_rthash_key;
3819ac93838fSSimon Schubert
3820ac93838fSSimon Schubert b += addr[5] << 8;
3821ac93838fSSimon Schubert b += addr[4];
3822ac93838fSSimon Schubert a += addr[3] << 24;
3823ac93838fSSimon Schubert a += addr[2] << 16;
3824ac93838fSSimon Schubert a += addr[1] << 8;
3825ac93838fSSimon Schubert a += addr[0];
3826ac93838fSSimon Schubert
3827ac93838fSSimon Schubert mix(a, b, c);
3828ac93838fSSimon Schubert
3829ac93838fSSimon Schubert return (c & BRIDGE_RTHASH_MASK);
3830ac93838fSSimon Schubert }
3831ac93838fSSimon Schubert
3832ac93838fSSimon Schubert #undef mix
3833ac93838fSSimon Schubert
3834d217f5e5SScott Ullrich static int
bridge_rtnode_addr_cmp(const uint8_t * a,const uint8_t * b)3835d217f5e5SScott Ullrich bridge_rtnode_addr_cmp(const uint8_t *a, const uint8_t *b)
3836d217f5e5SScott Ullrich {
3837d217f5e5SScott Ullrich int i, d;
3838d217f5e5SScott Ullrich
3839d217f5e5SScott Ullrich for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) {
3840d217f5e5SScott Ullrich d = ((int)a[i]) - ((int)b[i]);
3841d217f5e5SScott Ullrich }
3842d217f5e5SScott Ullrich
3843d217f5e5SScott Ullrich return (d);
3844d217f5e5SScott Ullrich }
3845d217f5e5SScott Ullrich
3846ac93838fSSimon Schubert /*
3847ac93838fSSimon Schubert * bridge_rtnode_lookup:
3848ac93838fSSimon Schubert *
3849ac93838fSSimon Schubert * Look up a bridge route node for the specified destination.
3850ac93838fSSimon Schubert */
3851d217f5e5SScott Ullrich static struct bridge_rtnode *
bridge_rtnode_lookup(struct bridge_softc * sc,const uint8_t * addr)3852ac93838fSSimon Schubert bridge_rtnode_lookup(struct bridge_softc *sc, const uint8_t *addr)
3853ac93838fSSimon Schubert {
3854ac93838fSSimon Schubert struct bridge_rtnode *brt;
3855ac93838fSSimon Schubert uint32_t hash;
3856ac93838fSSimon Schubert int dir;
3857ac93838fSSimon Schubert
3858ac93838fSSimon Schubert hash = bridge_rthash(sc, addr);
38594394693cSSepherosa Ziehau LIST_FOREACH(brt, &sc->sc_rthashs[mycpuid][hash], brt_hash) {
3860d217f5e5SScott Ullrich dir = bridge_rtnode_addr_cmp(addr, brt->brt_addr);
3861ac93838fSSimon Schubert if (dir == 0)
3862ac93838fSSimon Schubert return (brt);
3863ac93838fSSimon Schubert if (dir > 0)
3864ac93838fSSimon Schubert return (NULL);
3865ac93838fSSimon Schubert }
3866ac93838fSSimon Schubert
3867ac93838fSSimon Schubert return (NULL);
3868ac93838fSSimon Schubert }
3869ac93838fSSimon Schubert
3870ac93838fSSimon Schubert /*
3871ac93838fSSimon Schubert * bridge_rtnode_insert:
3872ac93838fSSimon Schubert *
38734394693cSSepherosa Ziehau * Insert the specified bridge node into the route table.
38744394693cSSepherosa Ziehau * Caller has to make sure that rtnode does not exist.
3875ac93838fSSimon Schubert */
38764394693cSSepherosa Ziehau static void
bridge_rtnode_insert(struct bridge_softc * sc,struct bridge_rtnode * brt)3877ac93838fSSimon Schubert bridge_rtnode_insert(struct bridge_softc *sc, struct bridge_rtnode *brt)
3878ac93838fSSimon Schubert {
3879ac93838fSSimon Schubert struct bridge_rtnode *lbrt;
3880ac93838fSSimon Schubert uint32_t hash;
3881ac93838fSSimon Schubert int dir;
3882ac93838fSSimon Schubert
3883ac93838fSSimon Schubert hash = bridge_rthash(sc, brt->brt_addr);
3884ac93838fSSimon Schubert
38854394693cSSepherosa Ziehau lbrt = LIST_FIRST(&sc->sc_rthashs[mycpuid][hash]);
3886ac93838fSSimon Schubert if (lbrt == NULL) {
388770d9a675SMatthew Dillon LIST_INSERT_HEAD(&sc->sc_rthashs[mycpuid][hash],
388870d9a675SMatthew Dillon brt, brt_hash);
3889ac93838fSSimon Schubert goto out;
3890ac93838fSSimon Schubert }
3891ac93838fSSimon Schubert
3892ac93838fSSimon Schubert do {
3893d217f5e5SScott Ullrich dir = bridge_rtnode_addr_cmp(brt->brt_addr, lbrt->brt_addr);
3894ed20d0e3SSascha Wildner KASSERT(dir != 0, ("rtnode already exist"));
38954394693cSSepherosa Ziehau
3896ac93838fSSimon Schubert if (dir > 0) {
3897ac93838fSSimon Schubert LIST_INSERT_BEFORE(lbrt, brt, brt_hash);
3898ac93838fSSimon Schubert goto out;
3899ac93838fSSimon Schubert }
3900ac93838fSSimon Schubert if (LIST_NEXT(lbrt, brt_hash) == NULL) {
3901ac93838fSSimon Schubert LIST_INSERT_AFTER(lbrt, brt, brt_hash);
3902ac93838fSSimon Schubert goto out;
3903ac93838fSSimon Schubert }
3904ac93838fSSimon Schubert lbrt = LIST_NEXT(lbrt, brt_hash);
3905ac93838fSSimon Schubert } while (lbrt != NULL);
3906ac93838fSSimon Schubert
3907ed20d0e3SSascha Wildner panic("no suitable position found for rtnode");
3908ac93838fSSimon Schubert out:
39094394693cSSepherosa Ziehau LIST_INSERT_HEAD(&sc->sc_rtlists[mycpuid], brt, brt_list);
39104394693cSSepherosa Ziehau if (mycpuid == 0) {
39114394693cSSepherosa Ziehau /*
39124394693cSSepherosa Ziehau * Update the brtcnt.
39134394693cSSepherosa Ziehau * We only need to do it once and we do it on CPU0.
39144394693cSSepherosa Ziehau */
3915ac93838fSSimon Schubert sc->sc_brtcnt++;
39164394693cSSepherosa Ziehau }
3917ac93838fSSimon Schubert }
3918ac93838fSSimon Schubert
3919ac93838fSSimon Schubert /*
3920ac93838fSSimon Schubert * bridge_rtnode_destroy:
3921ac93838fSSimon Schubert *
3922ac93838fSSimon Schubert * Destroy a bridge rtnode.
3923ac93838fSSimon Schubert */
3924d217f5e5SScott Ullrich static void
bridge_rtnode_destroy(struct bridge_softc * sc,struct bridge_rtnode * brt)3925ac93838fSSimon Schubert bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt)
3926ac93838fSSimon Schubert {
3927e41e076dSMatthew Dillon struct bridge_rtinfo *bri;
3928e41e076dSMatthew Dillon
3929ac93838fSSimon Schubert LIST_REMOVE(brt, brt_hash);
3930ac93838fSSimon Schubert LIST_REMOVE(brt, brt_list);
39314394693cSSepherosa Ziehau
3932e41e076dSMatthew Dillon bri = brt->brt_info;
3933e41e076dSMatthew Dillon
3934e41e076dSMatthew Dillon /*
3935e41e076dSMatthew Dillon * The bri_dead flag can be set asynchronously and catch some gc's
3936e41e076dSMatthew Dillon * in the middle, don't free bri until all references have actually
3937e41e076dSMatthew Dillon * gone away.
3938e41e076dSMatthew Dillon */
3939e41e076dSMatthew Dillon if (atomic_fetchadd_int(&bri->bri_refs, -1) == 1) {
39404394693cSSepherosa Ziehau /* Free rtinfo associated with rtnode on the last cpu */
3941e41e076dSMatthew Dillon kfree(bri, M_DEVBUF);
3942e41e076dSMatthew Dillon brt->brt_info = NULL; /* safety */
39434394693cSSepherosa Ziehau }
3944efda3bd0SMatthew Dillon kfree(brt, M_DEVBUF);
39454394693cSSepherosa Ziehau
39464394693cSSepherosa Ziehau if (mycpuid == 0) {
39474394693cSSepherosa Ziehau /* Update brtcnt only on CPU0 */
39484394693cSSepherosa Ziehau sc->sc_brtcnt--;
39494394693cSSepherosa Ziehau }
3950ac93838fSSimon Schubert }
3951ac93838fSSimon Schubert
39522303c7deSSepherosa Ziehau static __inline int
bridge_post_pfil(struct mbuf * m)39532303c7deSSepherosa Ziehau bridge_post_pfil(struct mbuf *m)
39542303c7deSSepherosa Ziehau {
39552303c7deSSepherosa Ziehau if (m->m_pkthdr.fw_flags & IPFORWARD_MBUF_TAGGED)
39562303c7deSSepherosa Ziehau return EOPNOTSUPP;
39572303c7deSSepherosa Ziehau
39582303c7deSSepherosa Ziehau /* Not yet */
39592303c7deSSepherosa Ziehau if (m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED)
39602303c7deSSepherosa Ziehau return EOPNOTSUPP;
39612303c7deSSepherosa Ziehau
39622303c7deSSepherosa Ziehau return 0;
39632303c7deSSepherosa Ziehau }
39642303c7deSSepherosa Ziehau
3965ac93838fSSimon Schubert /*
3966ac93838fSSimon Schubert * Send bridge packets through pfil if they are one of the types pfil can deal
3967ac93838fSSimon Schubert * with, or if they are ARP or REVARP. (pfil will pass ARP and REVARP without
3968ac93838fSSimon Schubert * question.) If *bifp or *ifp are NULL then packet filtering is skipped for
3969ac93838fSSimon Schubert * that interface.
3970ac93838fSSimon Schubert */
39713bf25ce1SSascha Wildner static int
bridge_pfil(struct mbuf ** mp,struct ifnet * bifp,struct ifnet * ifp,int dir)39723bf25ce1SSascha Wildner bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
3973ac93838fSSimon Schubert {
3974d217f5e5SScott Ullrich int snap, error, i, hlen;
3975ac93838fSSimon Schubert struct ether_header *eh1, eh2;
3976ac93838fSSimon Schubert struct ip *ip;
3977ac93838fSSimon Schubert struct llc llc1;
3978ac93838fSSimon Schubert u_int16_t ether_type;
3979ac93838fSSimon Schubert
3980ac93838fSSimon Schubert snap = 0;
3981ac93838fSSimon Schubert error = -1; /* Default error if not error == 0 */
3982ac93838fSSimon Schubert
3983d217f5e5SScott Ullrich if (pfil_bridge == 0 && pfil_member == 0)
3984d217f5e5SScott Ullrich return (0); /* filtering is disabled */
3985d217f5e5SScott Ullrich
3986ac93838fSSimon Schubert i = min((*mp)->m_pkthdr.len, max_protohdr);
3987ac93838fSSimon Schubert if ((*mp)->m_len < i) {
3988ac93838fSSimon Schubert *mp = m_pullup(*mp, i);
3989ac93838fSSimon Schubert if (*mp == NULL) {
39904b1cf444SSascha Wildner kprintf("%s: m_pullup failed\n", __func__);
3991d217f5e5SScott Ullrich return (-1);
3992ac93838fSSimon Schubert }
3993ac93838fSSimon Schubert }
3994ac93838fSSimon Schubert
3995ac93838fSSimon Schubert eh1 = mtod(*mp, struct ether_header *);
3996ac93838fSSimon Schubert ether_type = ntohs(eh1->ether_type);
3997ac93838fSSimon Schubert
3998ac93838fSSimon Schubert /*
3999ac93838fSSimon Schubert * Check for SNAP/LLC.
4000ac93838fSSimon Schubert */
4001ac93838fSSimon Schubert if (ether_type < ETHERMTU) {
4002ac93838fSSimon Schubert struct llc *llc2 = (struct llc *)(eh1 + 1);
4003ac93838fSSimon Schubert
4004ac93838fSSimon Schubert if ((*mp)->m_len >= ETHER_HDR_LEN + 8 &&
4005ac93838fSSimon Schubert llc2->llc_dsap == LLC_SNAP_LSAP &&
4006ac93838fSSimon Schubert llc2->llc_ssap == LLC_SNAP_LSAP &&
4007ac93838fSSimon Schubert llc2->llc_control == LLC_UI) {
4008ac93838fSSimon Schubert ether_type = htons(llc2->llc_un.type_snap.ether_type);
4009ac93838fSSimon Schubert snap = 1;
4010ac93838fSSimon Schubert }
4011ac93838fSSimon Schubert }
4012ac93838fSSimon Schubert
4013ac93838fSSimon Schubert /*
4014ac93838fSSimon Schubert * If we're trying to filter bridge traffic, don't look at anything
4015ac93838fSSimon Schubert * other than IP and ARP traffic. If the filter doesn't understand
4016ac93838fSSimon Schubert * IPv6, don't allow IPv6 through the bridge either. This is lame
4017ac93838fSSimon Schubert * since if we really wanted, say, an AppleTalk filter, we are hosed,
4018ac93838fSSimon Schubert * but of course we don't have an AppleTalk filter to begin with.
4019ac93838fSSimon Schubert * (Note that since pfil doesn't understand ARP it will pass *ALL*
4020ac93838fSSimon Schubert * ARP traffic.)
4021ac93838fSSimon Schubert */
4022ac93838fSSimon Schubert switch (ether_type) {
4023ac93838fSSimon Schubert case ETHERTYPE_ARP:
4024ac93838fSSimon Schubert case ETHERTYPE_REVARP:
4025d217f5e5SScott Ullrich return (0); /* Automatically pass */
4026d76dd5c7SSepherosa Ziehau
4027ac93838fSSimon Schubert case ETHERTYPE_IP:
4028ac93838fSSimon Schubert #ifdef INET6
4029ac93838fSSimon Schubert case ETHERTYPE_IPV6:
4030ac93838fSSimon Schubert #endif /* INET6 */
4031ac93838fSSimon Schubert break;
4032d76dd5c7SSepherosa Ziehau
4033ac93838fSSimon Schubert default:
4034d217f5e5SScott Ullrich /*
4035d217f5e5SScott Ullrich * Check to see if the user wants to pass non-ip
4036d76dd5c7SSepherosa Ziehau * packets, these will not be checked by pfil(9)
4037d76dd5c7SSepherosa Ziehau * and passed unconditionally so the default is to drop.
4038d217f5e5SScott Ullrich */
4039d217f5e5SScott Ullrich if (pfil_onlyip)
4040ac93838fSSimon Schubert goto bad;
4041ac93838fSSimon Schubert }
4042ac93838fSSimon Schubert
4043ac93838fSSimon Schubert /* Strip off the Ethernet header and keep a copy. */
4044*05d02a38SAaron LI m_copydata(*mp, 0, ETHER_HDR_LEN, &eh2);
4045ac93838fSSimon Schubert m_adj(*mp, ETHER_HDR_LEN);
4046ac93838fSSimon Schubert
4047ac93838fSSimon Schubert /* Strip off snap header, if present */
4048ac93838fSSimon Schubert if (snap) {
4049*05d02a38SAaron LI m_copydata(*mp, 0, sizeof(struct llc), &llc1);
4050ac93838fSSimon Schubert m_adj(*mp, sizeof(struct llc));
4051ac93838fSSimon Schubert }
4052ac93838fSSimon Schubert
4053ac93838fSSimon Schubert /*
4054ac93838fSSimon Schubert * Check the IP header for alignment and errors
4055ac93838fSSimon Schubert */
4056ac93838fSSimon Schubert if (dir == PFIL_IN) {
4057ac93838fSSimon Schubert switch (ether_type) {
4058ac93838fSSimon Schubert case ETHERTYPE_IP:
4059ac93838fSSimon Schubert error = bridge_ip_checkbasic(mp);
4060ac93838fSSimon Schubert break;
4061ac93838fSSimon Schubert #ifdef INET6
4062ac93838fSSimon Schubert case ETHERTYPE_IPV6:
4063ac93838fSSimon Schubert error = bridge_ip6_checkbasic(mp);
4064ac93838fSSimon Schubert break;
4065ac93838fSSimon Schubert #endif /* INET6 */
4066ac93838fSSimon Schubert default:
4067ac93838fSSimon Schubert error = 0;
4068ac93838fSSimon Schubert }
4069ac93838fSSimon Schubert if (error)
4070ac93838fSSimon Schubert goto bad;
4071ac93838fSSimon Schubert }
4072ac93838fSSimon Schubert
4073ac93838fSSimon Schubert error = 0;
4074ac93838fSSimon Schubert
4075ac93838fSSimon Schubert /*
4076ac93838fSSimon Schubert * Run the packet through pfil
4077ac93838fSSimon Schubert */
4078d76dd5c7SSepherosa Ziehau switch (ether_type) {
4079ac93838fSSimon Schubert case ETHERTYPE_IP:
4080ac93838fSSimon Schubert /*
4081ac93838fSSimon Schubert * Run pfil on the member interface and the bridge, both can
4082ac93838fSSimon Schubert * be skipped by clearing pfil_member or pfil_bridge.
4083ac93838fSSimon Schubert *
4084ac93838fSSimon Schubert * Keep the order:
4085ac93838fSSimon Schubert * in_if -> bridge_if -> out_if
4086ac93838fSSimon Schubert */
40872303c7deSSepherosa Ziehau if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) {
40882303c7deSSepherosa Ziehau error = pfil_run_hooks(&inet_pfil_hook, mp, bifp, dir);
4089ac93838fSSimon Schubert if (*mp == NULL || error != 0) /* filter may consume */
4090ac93838fSSimon Schubert break;
40912303c7deSSepherosa Ziehau error = bridge_post_pfil(*mp);
40922303c7deSSepherosa Ziehau if (error)
40932303c7deSSepherosa Ziehau break;
40942303c7deSSepherosa Ziehau }
4095ac93838fSSimon Schubert
40962303c7deSSepherosa Ziehau if (pfil_member && ifp != NULL) {
40972303c7deSSepherosa Ziehau error = pfil_run_hooks(&inet_pfil_hook, mp, ifp, dir);
4098ac93838fSSimon Schubert if (*mp == NULL || error != 0) /* filter may consume */
4099ac93838fSSimon Schubert break;
41002303c7deSSepherosa Ziehau error = bridge_post_pfil(*mp);
41012303c7deSSepherosa Ziehau if (error)
41022303c7deSSepherosa Ziehau break;
41032303c7deSSepherosa Ziehau }
4104ac93838fSSimon Schubert
41052303c7deSSepherosa Ziehau if (pfil_bridge && dir == PFIL_IN && bifp != NULL) {
41062303c7deSSepherosa Ziehau error = pfil_run_hooks(&inet_pfil_hook, mp, bifp, dir);
4107d217f5e5SScott Ullrich if (*mp == NULL || error != 0) /* filter may consume */
4108d217f5e5SScott Ullrich break;
41092303c7deSSepherosa Ziehau error = bridge_post_pfil(*mp);
41102303c7deSSepherosa Ziehau if (error)
41112303c7deSSepherosa Ziehau break;
41122303c7deSSepherosa Ziehau }
4113d217f5e5SScott Ullrich
4114d217f5e5SScott Ullrich /* check if we need to fragment the packet */
4115d217f5e5SScott Ullrich if (pfil_member && ifp != NULL && dir == PFIL_OUT) {
4116d217f5e5SScott Ullrich i = (*mp)->m_pkthdr.len;
4117d217f5e5SScott Ullrich if (i > ifp->if_mtu) {
4118d217f5e5SScott Ullrich error = bridge_fragment(ifp, *mp, &eh2, snap,
4119d217f5e5SScott Ullrich &llc1);
4120d217f5e5SScott Ullrich return (error);
4121d217f5e5SScott Ullrich }
4122d217f5e5SScott Ullrich }
4123d217f5e5SScott Ullrich
4124d217f5e5SScott Ullrich /* Recalculate the ip checksum and restore byte ordering */
4125ac93838fSSimon Schubert ip = mtod(*mp, struct ip *);
4126d217f5e5SScott Ullrich hlen = ip->ip_hl << 2;
4127d217f5e5SScott Ullrich if (hlen < sizeof(struct ip))
4128d217f5e5SScott Ullrich goto bad;
4129d217f5e5SScott Ullrich if (hlen > (*mp)->m_len) {
41304090d6ffSSascha Wildner if ((*mp = m_pullup(*mp, hlen)) == NULL)
4131d217f5e5SScott Ullrich goto bad;
4132d217f5e5SScott Ullrich ip = mtod(*mp, struct ip *);
4133d217f5e5SScott Ullrich if (ip == NULL)
4134d217f5e5SScott Ullrich goto bad;
4135d217f5e5SScott Ullrich }
4136d217f5e5SScott Ullrich ip->ip_sum = 0;
4137d217f5e5SScott Ullrich if (hlen == sizeof(struct ip))
4138d217f5e5SScott Ullrich ip->ip_sum = in_cksum_hdr(ip);
4139d217f5e5SScott Ullrich else
4140d217f5e5SScott Ullrich ip->ip_sum = in_cksum(*mp, hlen);
4141ac93838fSSimon Schubert
4142ac93838fSSimon Schubert break;
4143ac93838fSSimon Schubert #ifdef INET6
4144ac93838fSSimon Schubert case ETHERTYPE_IPV6:
4145ac93838fSSimon Schubert if (pfil_bridge && dir == PFIL_OUT && bifp != NULL)
4146ac93838fSSimon Schubert error = pfil_run_hooks(&inet6_pfil_hook, mp, bifp,
4147ac93838fSSimon Schubert dir);
4148ac93838fSSimon Schubert
4149ac93838fSSimon Schubert if (*mp == NULL || error != 0) /* filter may consume */
4150ac93838fSSimon Schubert break;
4151ac93838fSSimon Schubert
4152ac93838fSSimon Schubert if (pfil_member && ifp != NULL)
4153ac93838fSSimon Schubert error = pfil_run_hooks(&inet6_pfil_hook, mp, ifp,
4154ac93838fSSimon Schubert dir);
4155ac93838fSSimon Schubert
4156ac93838fSSimon Schubert if (*mp == NULL || error != 0) /* filter may consume */
4157ac93838fSSimon Schubert break;
4158ac93838fSSimon Schubert
4159ac93838fSSimon Schubert if (pfil_bridge && dir == PFIL_IN && bifp != NULL)
4160ac93838fSSimon Schubert error = pfil_run_hooks(&inet6_pfil_hook, mp, bifp,
4161ac93838fSSimon Schubert dir);
4162ac93838fSSimon Schubert break;
4163ac93838fSSimon Schubert #endif
4164ac93838fSSimon Schubert default:
4165ac93838fSSimon Schubert error = 0;
4166ac93838fSSimon Schubert break;
4167ac93838fSSimon Schubert }
4168ac93838fSSimon Schubert
4169ac93838fSSimon Schubert if (*mp == NULL)
4170d217f5e5SScott Ullrich return (error);
4171ac93838fSSimon Schubert if (error != 0)
4172ac93838fSSimon Schubert goto bad;
4173ac93838fSSimon Schubert
4174ac93838fSSimon Schubert error = -1;
4175ac93838fSSimon Schubert
4176ac93838fSSimon Schubert /*
4177ac93838fSSimon Schubert * Finally, put everything back the way it was and return
4178ac93838fSSimon Schubert */
4179ac93838fSSimon Schubert if (snap) {
4180b5523eacSSascha Wildner M_PREPEND(*mp, sizeof(struct llc), M_NOWAIT);
4181ac93838fSSimon Schubert if (*mp == NULL)
4182d217f5e5SScott Ullrich return (error);
4183ac93838fSSimon Schubert bcopy(&llc1, mtod(*mp, caddr_t), sizeof(struct llc));
4184ac93838fSSimon Schubert }
4185ac93838fSSimon Schubert
4186b5523eacSSascha Wildner M_PREPEND(*mp, ETHER_HDR_LEN, M_NOWAIT);
4187ac93838fSSimon Schubert if (*mp == NULL)
4188d217f5e5SScott Ullrich return (error);
4189ac93838fSSimon Schubert bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN);
4190ac93838fSSimon Schubert
4191d217f5e5SScott Ullrich return (0);
4192ac93838fSSimon Schubert
4193ac93838fSSimon Schubert bad:
4194ac93838fSSimon Schubert m_freem(*mp);
4195ac93838fSSimon Schubert *mp = NULL;
4196d217f5e5SScott Ullrich return (error);
4197ac93838fSSimon Schubert }
4198ac93838fSSimon Schubert
4199ac93838fSSimon Schubert /*
4200ac93838fSSimon Schubert * Perform basic checks on header size since
4201ac93838fSSimon Schubert * pfil assumes ip_input has already processed
4202ac93838fSSimon Schubert * it for it. Cut-and-pasted from ip_input.c.
4203ac93838fSSimon Schubert * Given how simple the IPv6 version is,
4204ac93838fSSimon Schubert * does the IPv4 version really need to be
4205ac93838fSSimon Schubert * this complicated?
4206ac93838fSSimon Schubert *
4207ac93838fSSimon Schubert * XXX Should we update ipstat here, or not?
4208ac93838fSSimon Schubert * XXX Right now we update ipstat but not
4209ac93838fSSimon Schubert * XXX csum_counter.
4210ac93838fSSimon Schubert */
4211ac93838fSSimon Schubert static int
bridge_ip_checkbasic(struct mbuf ** mp)4212ac93838fSSimon Schubert bridge_ip_checkbasic(struct mbuf **mp)
4213ac93838fSSimon Schubert {
4214ac93838fSSimon Schubert struct mbuf *m = *mp;
4215ac93838fSSimon Schubert struct ip *ip;
4216ac93838fSSimon Schubert int len, hlen;
4217ac93838fSSimon Schubert u_short sum;
4218ac93838fSSimon Schubert
4219ac93838fSSimon Schubert if (*mp == NULL)
4220d217f5e5SScott Ullrich return (-1);
4221122df98fSSascha Wildner #if 0 /* notyet */
4222ac93838fSSimon Schubert if (IP_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) {
4223ac93838fSSimon Schubert if ((m = m_copyup(m, sizeof(struct ip),
4224ac93838fSSimon Schubert (max_linkhdr + 3) & ~3)) == NULL) {
4225ac93838fSSimon Schubert /* XXXJRT new stat, please */
4226ac93838fSSimon Schubert ipstat.ips_toosmall++;
4227ac93838fSSimon Schubert goto bad;
4228ac93838fSSimon Schubert }
4229ac93838fSSimon Schubert } else
4230ac93838fSSimon Schubert #endif
4231ac93838fSSimon Schubert #ifndef __predict_false
4232ac93838fSSimon Schubert #define __predict_false(x) x
4233ac93838fSSimon Schubert #endif
4234ac93838fSSimon Schubert if (__predict_false(m->m_len < sizeof (struct ip))) {
4235ac93838fSSimon Schubert if ((m = m_pullup(m, sizeof (struct ip))) == NULL) {
4236ac93838fSSimon Schubert ipstat.ips_toosmall++;
4237ac93838fSSimon Schubert goto bad;
4238ac93838fSSimon Schubert }
4239ac93838fSSimon Schubert }
4240ac93838fSSimon Schubert ip = mtod(m, struct ip *);
4241ac93838fSSimon Schubert if (ip == NULL) goto bad;
4242ac93838fSSimon Schubert
4243ac93838fSSimon Schubert if (ip->ip_v != IPVERSION) {
4244ac93838fSSimon Schubert ipstat.ips_badvers++;
4245ac93838fSSimon Schubert goto bad;
4246ac93838fSSimon Schubert }
4247ac93838fSSimon Schubert hlen = ip->ip_hl << 2;
4248ac93838fSSimon Schubert if (hlen < sizeof(struct ip)) { /* minimum header length */
4249ac93838fSSimon Schubert ipstat.ips_badhlen++;
4250ac93838fSSimon Schubert goto bad;
4251ac93838fSSimon Schubert }
4252ac93838fSSimon Schubert if (hlen > m->m_len) {
42534090d6ffSSascha Wildner if ((m = m_pullup(m, hlen)) == NULL) {
4254ac93838fSSimon Schubert ipstat.ips_badhlen++;
4255ac93838fSSimon Schubert goto bad;
4256ac93838fSSimon Schubert }
4257ac93838fSSimon Schubert ip = mtod(m, struct ip *);
4258ac93838fSSimon Schubert if (ip == NULL) goto bad;
4259ac93838fSSimon Schubert }
4260ac93838fSSimon Schubert
4261ac93838fSSimon Schubert if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
4262ac93838fSSimon Schubert sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
4263ac93838fSSimon Schubert } else {
4264ac93838fSSimon Schubert if (hlen == sizeof(struct ip)) {
4265ac93838fSSimon Schubert sum = in_cksum_hdr(ip);
4266ac93838fSSimon Schubert } else {
4267ac93838fSSimon Schubert sum = in_cksum(m, hlen);
4268ac93838fSSimon Schubert }
4269ac93838fSSimon Schubert }
4270ac93838fSSimon Schubert if (sum) {
4271ac93838fSSimon Schubert ipstat.ips_badsum++;
4272ac93838fSSimon Schubert goto bad;
4273ac93838fSSimon Schubert }
4274ac93838fSSimon Schubert
4275ac93838fSSimon Schubert /* Retrieve the packet length. */
4276ac93838fSSimon Schubert len = ntohs(ip->ip_len);
4277ac93838fSSimon Schubert
4278ac93838fSSimon Schubert /*
4279ac93838fSSimon Schubert * Check for additional length bogosity
4280ac93838fSSimon Schubert */
4281ac93838fSSimon Schubert if (len < hlen) {
4282ac93838fSSimon Schubert ipstat.ips_badlen++;
4283ac93838fSSimon Schubert goto bad;
4284ac93838fSSimon Schubert }
4285ac93838fSSimon Schubert
4286ac93838fSSimon Schubert /*
4287ac93838fSSimon Schubert * Check that the amount of data in the buffers
4288ac93838fSSimon Schubert * is as at least much as the IP header would have us expect.
4289ac93838fSSimon Schubert * Drop packet if shorter than we expect.
4290ac93838fSSimon Schubert */
4291ac93838fSSimon Schubert if (m->m_pkthdr.len < len) {
4292ac93838fSSimon Schubert ipstat.ips_tooshort++;
4293ac93838fSSimon Schubert goto bad;
4294ac93838fSSimon Schubert }
4295ac93838fSSimon Schubert
4296ac93838fSSimon Schubert /* Checks out, proceed */
4297ac93838fSSimon Schubert *mp = m;
4298d217f5e5SScott Ullrich return (0);
4299ac93838fSSimon Schubert
4300ac93838fSSimon Schubert bad:
4301ac93838fSSimon Schubert *mp = m;
4302d217f5e5SScott Ullrich return (-1);
4303ac93838fSSimon Schubert }
4304ac93838fSSimon Schubert
4305ac93838fSSimon Schubert #ifdef INET6
4306ac93838fSSimon Schubert /*
4307ac93838fSSimon Schubert * Same as above, but for IPv6.
4308ac93838fSSimon Schubert * Cut-and-pasted from ip6_input.c.
4309ac93838fSSimon Schubert * XXX Should we update ip6stat, or not?
4310ac93838fSSimon Schubert */
4311ac93838fSSimon Schubert static int
bridge_ip6_checkbasic(struct mbuf ** mp)4312ac93838fSSimon Schubert bridge_ip6_checkbasic(struct mbuf **mp)
4313ac93838fSSimon Schubert {
4314ac93838fSSimon Schubert struct mbuf *m = *mp;
4315ac93838fSSimon Schubert struct ip6_hdr *ip6;
4316ac93838fSSimon Schubert
4317ac93838fSSimon Schubert /*
4318ac93838fSSimon Schubert * If the IPv6 header is not aligned, slurp it up into a new
4319ac93838fSSimon Schubert * mbuf with space for link headers, in the event we forward
4320ac93838fSSimon Schubert * it. Otherwise, if it is aligned, make sure the entire base
4321ac93838fSSimon Schubert * IPv6 header is in the first mbuf of the chain.
4322ac93838fSSimon Schubert */
4323122df98fSSascha Wildner #if 0 /* notyet */
4324ac93838fSSimon Schubert if (IP6_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) {
4325ac93838fSSimon Schubert struct ifnet *inifp = m->m_pkthdr.rcvif;
4326ac93838fSSimon Schubert if ((m = m_copyup(m, sizeof(struct ip6_hdr),
4327ac93838fSSimon Schubert (max_linkhdr + 3) & ~3)) == NULL) {
4328ac93838fSSimon Schubert /* XXXJRT new stat, please */
4329ac93838fSSimon Schubert ip6stat.ip6s_toosmall++;
4330ac93838fSSimon Schubert in6_ifstat_inc(inifp, ifs6_in_hdrerr);
4331ac93838fSSimon Schubert goto bad;
4332ac93838fSSimon Schubert }
4333ac93838fSSimon Schubert } else
4334ac93838fSSimon Schubert #endif
4335ac93838fSSimon Schubert if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) {
4336ac93838fSSimon Schubert struct ifnet *inifp = m->m_pkthdr.rcvif;
4337ac93838fSSimon Schubert if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
4338ac93838fSSimon Schubert ip6stat.ip6s_toosmall++;
4339ac93838fSSimon Schubert in6_ifstat_inc(inifp, ifs6_in_hdrerr);
4340ac93838fSSimon Schubert goto bad;
4341ac93838fSSimon Schubert }
4342ac93838fSSimon Schubert }
4343ac93838fSSimon Schubert
4344ac93838fSSimon Schubert ip6 = mtod(m, struct ip6_hdr *);
4345ac93838fSSimon Schubert
4346ac93838fSSimon Schubert if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
4347ac93838fSSimon Schubert ip6stat.ip6s_badvers++;
4348ac93838fSSimon Schubert in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
4349ac93838fSSimon Schubert goto bad;
4350ac93838fSSimon Schubert }
4351ac93838fSSimon Schubert
4352ac93838fSSimon Schubert /* Checks out, proceed */
4353ac93838fSSimon Schubert *mp = m;
4354d217f5e5SScott Ullrich return (0);
4355ac93838fSSimon Schubert
4356ac93838fSSimon Schubert bad:
4357ac93838fSSimon Schubert *mp = m;
4358d217f5e5SScott Ullrich return (-1);
4359ac93838fSSimon Schubert }
4360ac93838fSSimon Schubert #endif /* INET6 */
4361d217f5e5SScott Ullrich
4362d217f5e5SScott Ullrich /*
4363d217f5e5SScott Ullrich * bridge_fragment:
4364d217f5e5SScott Ullrich *
4365d217f5e5SScott Ullrich * Return a fragmented mbuf chain.
4366d217f5e5SScott Ullrich */
4367d217f5e5SScott Ullrich static int
bridge_fragment(struct ifnet * ifp,struct mbuf * m,struct ether_header * eh,int snap,struct llc * llc)4368d217f5e5SScott Ullrich bridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh,
4369d217f5e5SScott Ullrich int snap, struct llc *llc)
4370d217f5e5SScott Ullrich {
4371d217f5e5SScott Ullrich struct mbuf *m0;
4372d217f5e5SScott Ullrich struct ip *ip;
4373d217f5e5SScott Ullrich int error = -1;
4374d217f5e5SScott Ullrich
4375d217f5e5SScott Ullrich if (m->m_len < sizeof(struct ip) &&
4376d217f5e5SScott Ullrich (m = m_pullup(m, sizeof(struct ip))) == NULL)
4377d217f5e5SScott Ullrich goto out;
4378d217f5e5SScott Ullrich ip = mtod(m, struct ip *);
4379d217f5e5SScott Ullrich
4380d217f5e5SScott Ullrich error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist,
4381d217f5e5SScott Ullrich CSUM_DELAY_IP);
4382d217f5e5SScott Ullrich if (error)
4383d217f5e5SScott Ullrich goto out;
4384d217f5e5SScott Ullrich
4385d217f5e5SScott Ullrich /* walk the chain and re-add the Ethernet header */
4386d217f5e5SScott Ullrich for (m0 = m; m0; m0 = m0->m_nextpkt) {
4387d217f5e5SScott Ullrich if (error == 0) {
4388d217f5e5SScott Ullrich if (snap) {
4389b5523eacSSascha Wildner M_PREPEND(m0, sizeof(struct llc), M_NOWAIT);
4390d217f5e5SScott Ullrich if (m0 == NULL) {
4391d217f5e5SScott Ullrich error = ENOBUFS;
4392d217f5e5SScott Ullrich continue;
4393d217f5e5SScott Ullrich }
4394d217f5e5SScott Ullrich bcopy(llc, mtod(m0, caddr_t),
4395d217f5e5SScott Ullrich sizeof(struct llc));
4396d217f5e5SScott Ullrich }
4397b5523eacSSascha Wildner M_PREPEND(m0, ETHER_HDR_LEN, M_NOWAIT);
4398d217f5e5SScott Ullrich if (m0 == NULL) {
4399d217f5e5SScott Ullrich error = ENOBUFS;
4400d217f5e5SScott Ullrich continue;
4401d217f5e5SScott Ullrich }
4402d217f5e5SScott Ullrich bcopy(eh, mtod(m0, caddr_t), ETHER_HDR_LEN);
4403d217f5e5SScott Ullrich } else
4404d217f5e5SScott Ullrich m_freem(m);
4405d217f5e5SScott Ullrich }
4406d217f5e5SScott Ullrich
4407d217f5e5SScott Ullrich if (error == 0)
4408d217f5e5SScott Ullrich ipstat.ips_fragmented++;
4409d217f5e5SScott Ullrich
4410d217f5e5SScott Ullrich return (error);
4411d217f5e5SScott Ullrich
4412d217f5e5SScott Ullrich out:
4413d217f5e5SScott Ullrich if (m != NULL)
4414d217f5e5SScott Ullrich m_freem(m);
4415d217f5e5SScott Ullrich return (error);
4416d217f5e5SScott Ullrich }
4417ecd27a4cSSepherosa Ziehau
4418ecd27a4cSSepherosa Ziehau static void
bridge_enqueue_handler(netmsg_t msg)4419002c1265SMatthew Dillon bridge_enqueue_handler(netmsg_t msg)
4420ecd27a4cSSepherosa Ziehau {
4421ecd27a4cSSepherosa Ziehau struct netmsg_packet *nmp;
4422ecd27a4cSSepherosa Ziehau struct ifnet *dst_ifp;
4423ecd27a4cSSepherosa Ziehau struct mbuf *m;
4424ecd27a4cSSepherosa Ziehau
4425002c1265SMatthew Dillon nmp = &msg->packet;
4426ecd27a4cSSepherosa Ziehau m = nmp->nm_packet;
4427002c1265SMatthew Dillon dst_ifp = nmp->base.lmsg.u.ms_resultp;
442886989f49SMatthew Dillon mbuftrackid(m, 71);
4429ecd27a4cSSepherosa Ziehau
443070d9a675SMatthew Dillon bridge_handoff(dst_ifp->if_bridge, dst_ifp, m, 1);
4431ecd27a4cSSepherosa Ziehau }
4432ecd27a4cSSepherosa Ziehau
4433ecd27a4cSSepherosa Ziehau static void
bridge_handoff(struct bridge_softc * sc,struct ifnet * dst_ifp,struct mbuf * m,int from_us)443470d9a675SMatthew Dillon bridge_handoff(struct bridge_softc *sc, struct ifnet *dst_ifp,
443570d9a675SMatthew Dillon struct mbuf *m, int from_us)
4436ecd27a4cSSepherosa Ziehau {
4437ecd27a4cSSepherosa Ziehau struct mbuf *m0;
44384ee4f753SMatthew Dillon struct ifnet *bifp;
44394ee4f753SMatthew Dillon
444070d9a675SMatthew Dillon bifp = sc->sc_ifp;
444186989f49SMatthew Dillon mbuftrackid(m, 72);
4442ecd27a4cSSepherosa Ziehau
4443ecd27a4cSSepherosa Ziehau /* We may be sending a fragment so traverse the mbuf */
4444ecd27a4cSSepherosa Ziehau for (; m; m = m0) {
4445ecd27a4cSSepherosa Ziehau struct altq_pktattr pktattr;
4446ecd27a4cSSepherosa Ziehau
4447ecd27a4cSSepherosa Ziehau m0 = m->m_nextpkt;
4448ecd27a4cSSepherosa Ziehau m->m_nextpkt = NULL;
4449ecd27a4cSSepherosa Ziehau
44504ee4f753SMatthew Dillon /*
44514ee4f753SMatthew Dillon * If being sent from our host override ether_shost
445270d9a675SMatthew Dillon * with the bridge MAC. This is mandatory for ARP
445370d9a675SMatthew Dillon * so things don't get confused. In particular we
445470d9a675SMatthew Dillon * don't want ARPs to get associated with link interfaces
445570d9a675SMatthew Dillon * under the bridge which might or might not stay valid.
44564ee4f753SMatthew Dillon *
4457b7441d0cSMatthew Dillon * Also override ether_shost when relaying a packet out
4458b7441d0cSMatthew Dillon * the same interface it came in on, due to multi-homed
4459b7441d0cSMatthew Dillon * addresses & default routes, otherwise switches will
4460b7441d0cSMatthew Dillon * get very confused.
4461b7441d0cSMatthew Dillon *
4462b7441d0cSMatthew Dillon * Otherwise if we are in transparent mode.
44634ee4f753SMatthew Dillon */
4464b7441d0cSMatthew Dillon if (from_us || m->m_pkthdr.rcvif == dst_ifp) {
44654ee4f753SMatthew Dillon m_copyback(m,
44664ee4f753SMatthew Dillon offsetof(struct ether_header, ether_shost),
446770d9a675SMatthew Dillon ETHER_ADDR_LEN, IF_LLADDR(sc->sc_ifp));
44684ee4f753SMatthew Dillon } else if ((bifp->if_flags & IFF_LINK0) &&
44694ee4f753SMatthew Dillon (m->m_pkthdr.fw_flags & BRIDGE_MBUF_TAGGED)) {
44704ee4f753SMatthew Dillon m_copyback(m,
44714ee4f753SMatthew Dillon offsetof(struct ether_header, ether_shost),
44724ee4f753SMatthew Dillon ETHER_ADDR_LEN,
4473b4e5a107SSepherosa Ziehau m->m_pkthdr.ether_br_shost);
447470d9a675SMatthew Dillon } /* else retain shost */
44754ee4f753SMatthew Dillon
4476ecd27a4cSSepherosa Ziehau if (ifq_is_enabled(&dst_ifp->if_snd))
4477ecd27a4cSSepherosa Ziehau altq_etherclassify(&dst_ifp->if_snd, m, &pktattr);
4478ecd27a4cSSepherosa Ziehau
4479137aa7b3SSepherosa Ziehau ifq_dispatch(dst_ifp, m, &pktattr);
4480ecd27a4cSSepherosa Ziehau }
4481ecd27a4cSSepherosa Ziehau }
448223cf9e67SSepherosa Ziehau
448323cf9e67SSepherosa Ziehau static void
bridge_control_dispatch(netmsg_t msg)4484002c1265SMatthew Dillon bridge_control_dispatch(netmsg_t msg)
448523cf9e67SSepherosa Ziehau {
4486002c1265SMatthew Dillon struct netmsg_brctl *bc_msg = (struct netmsg_brctl *)msg;
448723cf9e67SSepherosa Ziehau struct ifnet *bifp = bc_msg->bc_sc->sc_ifp;
448823cf9e67SSepherosa Ziehau int error;
448923cf9e67SSepherosa Ziehau
4490a3dd34d2SSepherosa Ziehau ifnet_serialize_all(bifp);
449123cf9e67SSepherosa Ziehau error = bc_msg->bc_func(bc_msg->bc_sc, bc_msg->bc_arg);
4492a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(bifp);
449323cf9e67SSepherosa Ziehau
4494002c1265SMatthew Dillon lwkt_replymsg(&bc_msg->base.lmsg, error);
449523cf9e67SSepherosa Ziehau }
449623cf9e67SSepherosa Ziehau
449723cf9e67SSepherosa Ziehau static int
bridge_control(struct bridge_softc * sc,u_long cmd,bridge_ctl_t bc_func,void * bc_arg)44980b326f64SSepherosa Ziehau bridge_control(struct bridge_softc *sc, u_long cmd,
44990b326f64SSepherosa Ziehau bridge_ctl_t bc_func, void *bc_arg)
450023cf9e67SSepherosa Ziehau {
450123cf9e67SSepherosa Ziehau struct ifnet *bifp = sc->sc_ifp;
45024394693cSSepherosa Ziehau struct netmsg_brctl bc_msg;
45030b326f64SSepherosa Ziehau int error;
450423cf9e67SSepherosa Ziehau
45052c9effcfSSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(bifp);
45060b326f64SSepherosa Ziehau
450723cf9e67SSepherosa Ziehau bzero(&bc_msg, sizeof(bc_msg));
450823cf9e67SSepherosa Ziehau
4509002c1265SMatthew Dillon netmsg_init(&bc_msg.base, NULL, &curthread->td_msgport,
451048e7b118SMatthew Dillon 0, bridge_control_dispatch);
451123cf9e67SSepherosa Ziehau bc_msg.bc_func = bc_func;
451223cf9e67SSepherosa Ziehau bc_msg.bc_sc = sc;
451323cf9e67SSepherosa Ziehau bc_msg.bc_arg = bc_arg;
451423cf9e67SSepherosa Ziehau
4515a3dd34d2SSepherosa Ziehau ifnet_deserialize_all(bifp);
4516002c1265SMatthew Dillon error = lwkt_domsg(BRIDGE_CFGPORT, &bc_msg.base.lmsg, 0);
4517a3dd34d2SSepherosa Ziehau ifnet_serialize_all(bifp);
4518d752e606SSepherosa Ziehau return error;
451923cf9e67SSepherosa Ziehau }
45208f7b13efSSepherosa Ziehau
45218f7b13efSSepherosa Ziehau static void
bridge_add_bif_handler(netmsg_t msg)4522002c1265SMatthew Dillon bridge_add_bif_handler(netmsg_t msg)
45238f7b13efSSepherosa Ziehau {
4524002c1265SMatthew Dillon struct netmsg_braddbif *amsg = (struct netmsg_braddbif *)msg;
45258f7b13efSSepherosa Ziehau struct bridge_softc *sc;
45268f7b13efSSepherosa Ziehau struct bridge_iflist *bif;
45278f7b13efSSepherosa Ziehau
45288f7b13efSSepherosa Ziehau sc = amsg->br_softc;
45298f7b13efSSepherosa Ziehau
45308f7b13efSSepherosa Ziehau bif = kmalloc(sizeof(*bif), M_DEVBUF, M_WAITOK | M_ZERO);
45318f7b13efSSepherosa Ziehau bif->bif_ifp = amsg->br_bif_ifp;
45328f7b13efSSepherosa Ziehau bif->bif_onlist = 1;
45338f7b13efSSepherosa Ziehau bif->bif_info = amsg->br_bif_info;
45348f7b13efSSepherosa Ziehau
453570d9a675SMatthew Dillon /*
453670d9a675SMatthew Dillon * runs through bif_info
453770d9a675SMatthew Dillon */
453870d9a675SMatthew Dillon bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
453970d9a675SMatthew Dillon
454070d9a675SMatthew Dillon TAILQ_INSERT_HEAD(&sc->sc_iflists[mycpuid], bif, bif_next);
45418f7b13efSSepherosa Ziehau
4542fddbe7b3SSepherosa Ziehau netisr_forwardmsg(&amsg->base, mycpuid + 1);
45438f7b13efSSepherosa Ziehau }
45448f7b13efSSepherosa Ziehau
45458f7b13efSSepherosa Ziehau static void
bridge_add_bif(struct bridge_softc * sc,struct bridge_ifinfo * bif_info,struct ifnet * ifp)45468f7b13efSSepherosa Ziehau bridge_add_bif(struct bridge_softc *sc, struct bridge_ifinfo *bif_info,
45478f7b13efSSepherosa Ziehau struct ifnet *ifp)
45488f7b13efSSepherosa Ziehau {
45498f7b13efSSepherosa Ziehau struct netmsg_braddbif amsg;
45508f7b13efSSepherosa Ziehau
45512c9effcfSSepherosa Ziehau ASSERT_IFNET_NOT_SERIALIZED_ALL(sc->sc_ifp);
45528f7b13efSSepherosa Ziehau
4553002c1265SMatthew Dillon netmsg_init(&amsg.base, NULL, &curthread->td_msgport,
455448e7b118SMatthew Dillon 0, bridge_add_bif_handler);
45558f7b13efSSepherosa Ziehau amsg.br_softc = sc;
45568f7b13efSSepherosa Ziehau amsg.br_bif_info = bif_info;
45578f7b13efSSepherosa Ziehau amsg.br_bif_ifp = ifp;
45588f7b13efSSepherosa Ziehau
4559deae8bb6SSepherosa Ziehau netisr_domsg(&amsg.base, 0);
45608f7b13efSSepherosa Ziehau }
45618f7b13efSSepherosa Ziehau
45628f7b13efSSepherosa Ziehau static void
bridge_del_bif_handler(netmsg_t msg)4563002c1265SMatthew Dillon bridge_del_bif_handler(netmsg_t msg)
45648f7b13efSSepherosa Ziehau {
4565002c1265SMatthew Dillon struct netmsg_brdelbif *dmsg = (struct netmsg_brdelbif *)msg;
45668f7b13efSSepherosa Ziehau struct bridge_softc *sc;
45678f7b13efSSepherosa Ziehau struct bridge_iflist *bif;
45688f7b13efSSepherosa Ziehau
45698f7b13efSSepherosa Ziehau sc = dmsg->br_softc;
45708f7b13efSSepherosa Ziehau
45718f7b13efSSepherosa Ziehau /*
45728f7b13efSSepherosa Ziehau * Locate the bif associated with the br_bif_info
45738f7b13efSSepherosa Ziehau * on the current CPU
45748f7b13efSSepherosa Ziehau */
45758f7b13efSSepherosa Ziehau bif = bridge_lookup_member_ifinfo(sc, dmsg->br_bif_info);
45768f7b13efSSepherosa Ziehau KKASSERT(bif != NULL && bif->bif_onlist);
45778f7b13efSSepherosa Ziehau
45788f7b13efSSepherosa Ziehau /* Remove the bif from the current CPU's iflist */
45798f7b13efSSepherosa Ziehau bif->bif_onlist = 0;
458070d9a675SMatthew Dillon TAILQ_REMOVE(dmsg->br_bif_list, bif, bif_next);
45818f7b13efSSepherosa Ziehau
45828f7b13efSSepherosa Ziehau /* Save the removed bif for later freeing */
458370d9a675SMatthew Dillon TAILQ_INSERT_HEAD(dmsg->br_bif_list, bif, bif_next);
45848f7b13efSSepherosa Ziehau
4585fddbe7b3SSepherosa Ziehau netisr_forwardmsg(&dmsg->base, mycpuid + 1);
45868f7b13efSSepherosa Ziehau }
45878f7b13efSSepherosa Ziehau
45888f7b13efSSepherosa Ziehau static void
bridge_del_bif(struct bridge_softc * sc,struct bridge_ifinfo * bif_info,struct bridge_iflist_head * saved_bifs)45898f7b13efSSepherosa Ziehau bridge_del_bif(struct bridge_softc *sc, struct bridge_ifinfo *bif_info,
45908f7b13efSSepherosa Ziehau struct bridge_iflist_head *saved_bifs)
45918f7b13efSSepherosa Ziehau {
45928f7b13efSSepherosa Ziehau struct netmsg_brdelbif dmsg;
45938f7b13efSSepherosa Ziehau
45942c9effcfSSepherosa Ziehau ASSERT_IFNET_NOT_SERIALIZED_ALL(sc->sc_ifp);
45958f7b13efSSepherosa Ziehau
4596002c1265SMatthew Dillon netmsg_init(&dmsg.base, NULL, &curthread->td_msgport,
459748e7b118SMatthew Dillon 0, bridge_del_bif_handler);
45988f7b13efSSepherosa Ziehau dmsg.br_softc = sc;
45998f7b13efSSepherosa Ziehau dmsg.br_bif_info = bif_info;
46008f7b13efSSepherosa Ziehau dmsg.br_bif_list = saved_bifs;
46018f7b13efSSepherosa Ziehau
4602deae8bb6SSepherosa Ziehau netisr_domsg(&dmsg.base, 0);
46038f7b13efSSepherosa Ziehau }
4604