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