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 74146985Sthompsa * consider heterogenous bridges). 75146985Sthompsa */ 76146985Sthompsa 77146985Sthompsa#include <sys/cdefs.h> 78146985Sthompsa__FBSDID("$FreeBSD: stable/10/sys/net/if_bridge.c 324116 2017-09-30 10:16:15Z kp $"); 79146985Sthompsa 80146985Sthompsa#include "opt_inet.h" 81146985Sthompsa#include "opt_inet6.h" 82146985Sthompsa 83146985Sthompsa#include <sys/param.h> 84146985Sthompsa#include <sys/mbuf.h> 85146985Sthompsa#include <sys/malloc.h> 86146985Sthompsa#include <sys/protosw.h> 87146985Sthompsa#include <sys/systm.h> 88225380Sthompsa#include <sys/jail.h> 89146985Sthompsa#include <sys/time.h> 90146985Sthompsa#include <sys/socket.h> /* for net/if.h */ 91146985Sthompsa#include <sys/sockio.h> 92146985Sthompsa#include <sys/ctype.h> /* string functions */ 93146985Sthompsa#include <sys/kernel.h> 94146985Sthompsa#include <sys/random.h> 95160902Sthompsa#include <sys/syslog.h> 96146985Sthompsa#include <sys/sysctl.h> 97146985Sthompsa#include <vm/uma.h> 98146985Sthompsa#include <sys/module.h> 99164033Srwatson#include <sys/priv.h> 100146985Sthompsa#include <sys/proc.h> 101146985Sthompsa#include <sys/lock.h> 102146985Sthompsa#include <sys/mutex.h> 103146985Sthompsa 104146985Sthompsa#include <net/bpf.h> 105146985Sthompsa#include <net/if.h> 106146985Sthompsa#include <net/if_clone.h> 107146985Sthompsa#include <net/if_dl.h> 108146985Sthompsa#include <net/if_types.h> 109146985Sthompsa#include <net/if_var.h> 110146985Sthompsa#include <net/pfil.h> 111197952Sjulian#include <net/vnet.h> 112146985Sthompsa 113146985Sthompsa#include <netinet/in.h> /* for struct arpcom */ 114146985Sthompsa#include <netinet/in_systm.h> 115146985Sthompsa#include <netinet/in_var.h> 116146985Sthompsa#include <netinet/ip.h> 117146985Sthompsa#include <netinet/ip_var.h> 118146985Sthompsa#ifdef INET6 119146985Sthompsa#include <netinet/ip6.h> 120146985Sthompsa#include <netinet6/ip6_var.h> 121252511Shrs#include <netinet6/in6_ifattach.h> 122146985Sthompsa#endif 123193983Sbz#if defined(INET) || defined(INET6) 124159446Sthompsa#include <netinet/ip_carp.h> 125159446Sthompsa#endif 126146985Sthompsa#include <machine/in_cksum.h> 127146985Sthompsa#include <netinet/if_ether.h> /* for struct arpcom */ 128160703Sthompsa#include <net/bridgestp.h> 129146985Sthompsa#include <net/if_bridgevar.h> 130146985Sthompsa#include <net/if_llc.h> 131170681Sthompsa#include <net/if_vlan_var.h> 132146985Sthompsa 133146985Sthompsa#include <net/route.h> 134146985Sthompsa 135146985Sthompsa/* 136146985Sthompsa * Size of the route hash table. Must be a power of two. 137146985Sthompsa */ 138146985Sthompsa#ifndef BRIDGE_RTHASH_SIZE 139146985Sthompsa#define BRIDGE_RTHASH_SIZE 1024 140146985Sthompsa#endif 141146985Sthompsa 142146985Sthompsa#define BRIDGE_RTHASH_MASK (BRIDGE_RTHASH_SIZE - 1) 143146985Sthompsa 144146985Sthompsa/* 145232315Sthompsa * Default maximum number of addresses to cache. 146146985Sthompsa */ 147146985Sthompsa#ifndef BRIDGE_RTABLE_MAX 148232315Sthompsa#define BRIDGE_RTABLE_MAX 2000 149146985Sthompsa#endif 150146985Sthompsa 151146985Sthompsa/* 152146985Sthompsa * Timeout (in seconds) for entries learned dynamically. 153146985Sthompsa */ 154146985Sthompsa#ifndef BRIDGE_RTABLE_TIMEOUT 155146985Sthompsa#define BRIDGE_RTABLE_TIMEOUT (20 * 60) /* same as ARP */ 156146985Sthompsa#endif 157146985Sthompsa 158146985Sthompsa/* 159146985Sthompsa * Number of seconds between walks of the route list. 160146985Sthompsa */ 161146985Sthompsa#ifndef BRIDGE_RTABLE_PRUNE_PERIOD 162146985Sthompsa#define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60) 163146985Sthompsa#endif 164146985Sthompsa 165154336Sthompsa/* 166180220Sthompsa * List of capabilities to possibly mask on the member interface. 167154336Sthompsa */ 168304427Smav#define BRIDGE_IFCAPS_MASK (IFCAP_TOE|IFCAP_TSO|IFCAP_TXCSUM|\ 169304427Smav IFCAP_TXCSUM_IPV6) 170154336Sthompsa 171160769Sthompsa/* 172196519Sjfv * List of capabilities to strip 173196519Sjfv */ 174196519Sjfv#define BRIDGE_IFCAPS_STRIP IFCAP_LRO 175196519Sjfv 176196519Sjfv/* 177160769Sthompsa * Bridge interface list entry. 178160769Sthompsa */ 179160769Sthompsastruct bridge_iflist { 180160769Sthompsa LIST_ENTRY(bridge_iflist) bif_next; 181160769Sthompsa struct ifnet *bif_ifp; /* member if */ 182160769Sthompsa struct bstp_port bif_stp; /* STP state */ 183160769Sthompsa uint32_t bif_flags; /* member if flags */ 184180220Sthompsa int bif_savedcaps; /* saved capabilities */ 185173320Sthompsa uint32_t bif_addrmax; /* max # of addresses */ 186173320Sthompsa uint32_t bif_addrcnt; /* cur. # of addresses */ 187173320Sthompsa uint32_t bif_addrexceeded;/* # of address violations */ 188160769Sthompsa}; 189160769Sthompsa 190160769Sthompsa/* 191160769Sthompsa * Bridge route node. 192160769Sthompsa */ 193160769Sthompsastruct bridge_rtnode { 194160769Sthompsa LIST_ENTRY(bridge_rtnode) brt_hash; /* hash table linkage */ 195160769Sthompsa LIST_ENTRY(bridge_rtnode) brt_list; /* list linkage */ 196173320Sthompsa struct bridge_iflist *brt_dst; /* destination if */ 197160769Sthompsa unsigned long brt_expire; /* expiration time */ 198160769Sthompsa uint8_t brt_flags; /* address flags */ 199160769Sthompsa uint8_t brt_addr[ETHER_ADDR_LEN]; 200170681Sthompsa uint16_t brt_vlan; /* vlan id */ 201160769Sthompsa}; 202173320Sthompsa#define brt_ifp brt_dst->bif_ifp 203160769Sthompsa 204160769Sthompsa/* 205160769Sthompsa * Software state for each bridge. 206160769Sthompsa */ 207160769Sthompsastruct bridge_softc { 208160769Sthompsa struct ifnet *sc_ifp; /* make this an interface */ 209160769Sthompsa LIST_ENTRY(bridge_softc) sc_list; 210160769Sthompsa struct mtx sc_mtx; 211160769Sthompsa struct cv sc_cv; 212160769Sthompsa uint32_t sc_brtmax; /* max # of addresses */ 213160769Sthompsa uint32_t sc_brtcnt; /* cur. # of addresses */ 214160769Sthompsa uint32_t sc_brttimeout; /* rt timeout in seconds */ 215160769Sthompsa struct callout sc_brcallout; /* bridge callout */ 216160769Sthompsa uint32_t sc_iflist_ref; /* refcount for sc_iflist */ 217160769Sthompsa uint32_t sc_iflist_xcnt; /* refcount for sc_iflist */ 218160769Sthompsa LIST_HEAD(, bridge_iflist) sc_iflist; /* member interface list */ 219160769Sthompsa LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */ 220160769Sthompsa LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */ 221160769Sthompsa uint32_t sc_rthash_key; /* key for hash */ 222160769Sthompsa LIST_HEAD(, bridge_iflist) sc_spanlist; /* span ports list */ 223160769Sthompsa struct bstp_state sc_stp; /* STP state */ 224160867Sthompsa uint32_t sc_brtexceeded; /* # of cache drops */ 225188594Sthompsa struct ifnet *sc_ifaddr; /* member mac copied from */ 226180140Sphilip u_char sc_defaddr[6]; /* Default MAC address */ 227160769Sthompsa}; 228160769Sthompsa 229153494Sthompsastatic struct mtx bridge_list_mtx; 230153494Sthompsaeventhandler_tag bridge_detach_cookie = NULL; 231153494Sthompsa 232146985Sthompsaint bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; 233146985Sthompsa 234146985Sthompsauma_zone_t bridge_rtnode_zone; 235146985Sthompsa 236160195Ssamstatic int bridge_clone_create(struct if_clone *, int, caddr_t); 237151313Sthompsastatic void bridge_clone_destroy(struct ifnet *); 238146985Sthompsa 239151313Sthompsastatic int bridge_ioctl(struct ifnet *, u_long, caddr_t); 240180220Sthompsastatic void bridge_mutecaps(struct bridge_softc *); 241180220Sthompsastatic void bridge_set_ifcap(struct bridge_softc *, struct bridge_iflist *, 242180220Sthompsa int); 243153494Sthompsastatic void bridge_ifdetach(void *arg __unused, struct ifnet *); 244146985Sthompsastatic void bridge_init(void *); 245151313Sthompsastatic void bridge_dummynet(struct mbuf *, struct ifnet *); 246151313Sthompsastatic void bridge_stop(struct ifnet *, int); 247240071Sglebiusstatic int bridge_transmit(struct ifnet *, struct mbuf *); 248240071Sglebiusstatic void bridge_qflush(struct ifnet *); 249151313Sthompsastatic struct mbuf *bridge_input(struct ifnet *, struct mbuf *); 250151313Sthompsastatic int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *, 251151313Sthompsa struct rtentry *); 252240071Sglebiusstatic int bridge_enqueue(struct bridge_softc *, struct ifnet *, 253160769Sthompsa struct mbuf *); 254160769Sthompsastatic void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int); 255146985Sthompsa 256171678Sthompsastatic void bridge_forward(struct bridge_softc *, struct bridge_iflist *, 257171678Sthompsa struct mbuf *m); 258146985Sthompsa 259151313Sthompsastatic void bridge_timer(void *); 260146985Sthompsa 261151313Sthompsastatic void bridge_broadcast(struct bridge_softc *, struct ifnet *, 262151313Sthompsa struct mbuf *, int); 263153408Sthompsastatic void bridge_span(struct bridge_softc *, struct mbuf *); 264146985Sthompsa 265151313Sthompsastatic int bridge_rtupdate(struct bridge_softc *, const uint8_t *, 266170681Sthompsa uint16_t, struct bridge_iflist *, int, uint8_t); 267170681Sthompsastatic struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *, 268170681Sthompsa uint16_t); 269151313Sthompsastatic void bridge_rttrim(struct bridge_softc *); 270151313Sthompsastatic void bridge_rtage(struct bridge_softc *); 271151313Sthompsastatic void bridge_rtflush(struct bridge_softc *, int); 272170681Sthompsastatic int bridge_rtdaddr(struct bridge_softc *, const uint8_t *, 273170681Sthompsa uint16_t); 274146985Sthompsa 275241183Sthompsastatic void bridge_rtable_init(struct bridge_softc *); 276151313Sthompsastatic void bridge_rtable_fini(struct bridge_softc *); 277146985Sthompsa 278155143Sthompsastatic int bridge_rtnode_addr_cmp(const uint8_t *, const uint8_t *); 279151313Sthompsastatic struct bridge_rtnode *bridge_rtnode_lookup(struct bridge_softc *, 280170681Sthompsa const uint8_t *, uint16_t); 281151313Sthompsastatic int bridge_rtnode_insert(struct bridge_softc *, 282151313Sthompsa struct bridge_rtnode *); 283151313Sthompsastatic void bridge_rtnode_destroy(struct bridge_softc *, 284151313Sthompsa struct bridge_rtnode *); 285163863Sthompsastatic void bridge_rtable_expire(struct ifnet *, int); 286160902Sthompsastatic void bridge_state_change(struct ifnet *, int); 287146985Sthompsa 288151313Sthompsastatic struct bridge_iflist *bridge_lookup_member(struct bridge_softc *, 289151313Sthompsa const char *name); 290151313Sthompsastatic struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *, 291151313Sthompsa struct ifnet *ifp); 292151313Sthompsastatic void bridge_delete_member(struct bridge_softc *, 293151594Sthompsa struct bridge_iflist *, int); 294153494Sthompsastatic void bridge_delete_span(struct bridge_softc *, 295153494Sthompsa struct bridge_iflist *); 296146985Sthompsa 297151313Sthompsastatic int bridge_ioctl_add(struct bridge_softc *, void *); 298151313Sthompsastatic int bridge_ioctl_del(struct bridge_softc *, void *); 299151313Sthompsastatic int bridge_ioctl_gifflags(struct bridge_softc *, void *); 300151313Sthompsastatic int bridge_ioctl_sifflags(struct bridge_softc *, void *); 301151313Sthompsastatic int bridge_ioctl_scache(struct bridge_softc *, void *); 302151313Sthompsastatic int bridge_ioctl_gcache(struct bridge_softc *, void *); 303151313Sthompsastatic int bridge_ioctl_gifs(struct bridge_softc *, void *); 304151313Sthompsastatic int bridge_ioctl_rts(struct bridge_softc *, void *); 305151313Sthompsastatic int bridge_ioctl_saddr(struct bridge_softc *, void *); 306151313Sthompsastatic int bridge_ioctl_sto(struct bridge_softc *, void *); 307151313Sthompsastatic int bridge_ioctl_gto(struct bridge_softc *, void *); 308151313Sthompsastatic int bridge_ioctl_daddr(struct bridge_softc *, void *); 309151313Sthompsastatic int bridge_ioctl_flush(struct bridge_softc *, void *); 310151313Sthompsastatic int bridge_ioctl_gpri(struct bridge_softc *, void *); 311151313Sthompsastatic int bridge_ioctl_spri(struct bridge_softc *, void *); 312151313Sthompsastatic int bridge_ioctl_ght(struct bridge_softc *, void *); 313151313Sthompsastatic int bridge_ioctl_sht(struct bridge_softc *, void *); 314151313Sthompsastatic int bridge_ioctl_gfd(struct bridge_softc *, void *); 315151313Sthompsastatic int bridge_ioctl_sfd(struct bridge_softc *, void *); 316151313Sthompsastatic int bridge_ioctl_gma(struct bridge_softc *, void *); 317151313Sthompsastatic int bridge_ioctl_sma(struct bridge_softc *, void *); 318151313Sthompsastatic int bridge_ioctl_sifprio(struct bridge_softc *, void *); 319151313Sthompsastatic int bridge_ioctl_sifcost(struct bridge_softc *, void *); 320173320Sthompsastatic int bridge_ioctl_sifmaxaddr(struct bridge_softc *, void *); 321153408Sthompsastatic int bridge_ioctl_addspan(struct bridge_softc *, void *); 322153408Sthompsastatic int bridge_ioctl_delspan(struct bridge_softc *, void *); 323160867Sthompsastatic int bridge_ioctl_gbparam(struct bridge_softc *, void *); 324160867Sthompsastatic int bridge_ioctl_grte(struct bridge_softc *, void *); 325160867Sthompsastatic int bridge_ioctl_gifsstp(struct bridge_softc *, void *); 326163863Sthompsastatic int bridge_ioctl_sproto(struct bridge_softc *, void *); 327163863Sthompsastatic int bridge_ioctl_stxhc(struct bridge_softc *, void *); 328151313Sthompsastatic int bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *, 329151313Sthompsa int); 330151313Sthompsastatic int bridge_ip_checkbasic(struct mbuf **mp); 331158667Sthompsa#ifdef INET6 332151313Sthompsastatic int bridge_ip6_checkbasic(struct mbuf **mp); 333158667Sthompsa#endif /* INET6 */ 334306594Skpstatic int bridge_fragment(struct ifnet *, struct mbuf **mp, 335158140Sthompsa struct ether_header *, int, struct llc *); 336234487Sthompsastatic void bridge_linkstate(struct ifnet *ifp); 337236916Sthompsastatic void bridge_linkcheck(struct bridge_softc *sc); 338146985Sthompsa 339234487Sthompsaextern void (*bridge_linkstate_p)(struct ifnet *ifp); 340234487Sthompsa 341170681Sthompsa/* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */ 342170681Sthompsa#define VLANTAGOF(_m) \ 343170681Sthompsa (_m->m_flags & M_VLANTAG) ? EVL_VLANOFTAG(_m->m_pkthdr.ether_vtag) : 1 344170681Sthompsa 345167379Sthompsastatic struct bstp_cb_ops bridge_ops = { 346167379Sthompsa .bcb_state = bridge_state_change, 347167379Sthompsa .bcb_rtage = bridge_rtable_expire 348167379Sthompsa}; 349167379Sthompsa 350146985SthompsaSYSCTL_DECL(_net_link); 351227309Sedstatic SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW, 0, "Bridge"); 352146985Sthompsa 353153831Sthompsastatic int pfil_onlyip = 1; /* only pass IP[46] packets when pfil is enabled */ 354146985Sthompsastatic int pfil_bridge = 1; /* run pfil hooks on the bridge interface */ 355146985Sthompsastatic int pfil_member = 1; /* run pfil hooks on the member interface */ 356147111Sthompsastatic int pfil_ipfw = 0; /* layer2 filter with ipfw */ 357162561Sthompsastatic int pfil_ipfw_arp = 0; /* layer2 filter with ipfw */ 358172201Sthompsastatic int pfil_local_phys = 0; /* run pfil hooks on the physical interface for 359172201Sthompsa locally destined packets */ 360160902Sthompsastatic int log_stp = 0; /* log STP state changes */ 361182862Sthompsastatic int bridge_inherit_mac = 0; /* share MAC with first bridge member */ 362231130SpjdTUNABLE_INT("net.link.bridge.pfil_onlyip", &pfil_onlyip); 363153831SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_onlyip, CTLFLAG_RW, 364153831Sthompsa &pfil_onlyip, 0, "Only pass IP packets when pfil is enabled"); 365231130SpjdTUNABLE_INT("net.link.bridge.ipfw_arp", &pfil_ipfw_arp); 366162561SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, ipfw_arp, CTLFLAG_RW, 367162561Sthompsa &pfil_ipfw_arp, 0, "Filter ARP packets through IPFW layer2"); 368231130SpjdTUNABLE_INT("net.link.bridge.pfil_bridge", &pfil_bridge); 369146985SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_bridge, CTLFLAG_RW, 370146985Sthompsa &pfil_bridge, 0, "Packet filter on the bridge interface"); 371231130SpjdTUNABLE_INT("net.link.bridge.pfil_member", &pfil_member); 372146985SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_member, CTLFLAG_RW, 373146985Sthompsa &pfil_member, 0, "Packet filter on the member interface"); 374231130SpjdTUNABLE_INT("net.link.bridge.pfil_local_phys", &pfil_local_phys); 375172201SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_local_phys, CTLFLAG_RW, 376172201Sthompsa &pfil_local_phys, 0, 377172201Sthompsa "Packet filter on the physical interface for locally destined packets"); 378231130SpjdTUNABLE_INT("net.link.bridge.log_stp", &log_stp); 379160902SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, log_stp, CTLFLAG_RW, 380160902Sthompsa &log_stp, 0, "Log STP state changes"); 381231130SpjdTUNABLE_INT("net.link.bridge.inherit_mac", &bridge_inherit_mac); 382182862SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, inherit_mac, CTLFLAG_RW, 383182862Sthompsa &bridge_inherit_mac, 0, 384182862Sthompsa "Inherit MAC address from the first bridge member"); 385146985Sthompsa 386253751Shrsstatic VNET_DEFINE(int, allow_llz_overlap) = 0; 387253751Shrs#define V_allow_llz_overlap VNET(allow_llz_overlap) 388253751ShrsSYSCTL_VNET_INT(_net_link_bridge, OID_AUTO, allow_llz_overlap, CTLFLAG_RW, 389253751Shrs &VNET_NAME(allow_llz_overlap), 0, "Allow overlap of link-local scope " 390253751Shrs "zones of a bridge interface and the member interfaces"); 391253751Shrs 392146985Sthompsastruct bridge_control { 393146985Sthompsa int (*bc_func)(struct bridge_softc *, void *); 394146985Sthompsa int bc_argsize; 395146985Sthompsa int bc_flags; 396146985Sthompsa}; 397146985Sthompsa 398146985Sthompsa#define BC_F_COPYIN 0x01 /* copy arguments in */ 399146985Sthompsa#define BC_F_COPYOUT 0x02 /* copy arguments out */ 400146985Sthompsa#define BC_F_SUSER 0x04 /* do super-user check */ 401146985Sthompsa 402146985Sthompsaconst struct bridge_control bridge_control_table[] = { 403146985Sthompsa { bridge_ioctl_add, sizeof(struct ifbreq), 404146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 405146985Sthompsa { bridge_ioctl_del, sizeof(struct ifbreq), 406146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 407146985Sthompsa 408146985Sthompsa { bridge_ioctl_gifflags, sizeof(struct ifbreq), 409146985Sthompsa BC_F_COPYIN|BC_F_COPYOUT }, 410146985Sthompsa { bridge_ioctl_sifflags, sizeof(struct ifbreq), 411146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 412146985Sthompsa 413146985Sthompsa { bridge_ioctl_scache, sizeof(struct ifbrparam), 414146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 415146985Sthompsa { bridge_ioctl_gcache, sizeof(struct ifbrparam), 416146985Sthompsa BC_F_COPYOUT }, 417146985Sthompsa 418146985Sthompsa { bridge_ioctl_gifs, sizeof(struct ifbifconf), 419146985Sthompsa BC_F_COPYIN|BC_F_COPYOUT }, 420146985Sthompsa { bridge_ioctl_rts, sizeof(struct ifbaconf), 421146985Sthompsa BC_F_COPYIN|BC_F_COPYOUT }, 422146985Sthompsa 423146985Sthompsa { bridge_ioctl_saddr, sizeof(struct ifbareq), 424146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 425146985Sthompsa 426146985Sthompsa { bridge_ioctl_sto, sizeof(struct ifbrparam), 427146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 428146985Sthompsa { bridge_ioctl_gto, sizeof(struct ifbrparam), 429146985Sthompsa BC_F_COPYOUT }, 430146985Sthompsa 431146985Sthompsa { bridge_ioctl_daddr, sizeof(struct ifbareq), 432146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 433146985Sthompsa 434146985Sthompsa { bridge_ioctl_flush, sizeof(struct ifbreq), 435146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 436146985Sthompsa 437146985Sthompsa { bridge_ioctl_gpri, sizeof(struct ifbrparam), 438146985Sthompsa BC_F_COPYOUT }, 439146985Sthompsa { bridge_ioctl_spri, sizeof(struct ifbrparam), 440146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 441146985Sthompsa 442146985Sthompsa { bridge_ioctl_ght, sizeof(struct ifbrparam), 443146985Sthompsa BC_F_COPYOUT }, 444146985Sthompsa { bridge_ioctl_sht, sizeof(struct ifbrparam), 445146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 446146985Sthompsa 447146985Sthompsa { bridge_ioctl_gfd, sizeof(struct ifbrparam), 448146985Sthompsa BC_F_COPYOUT }, 449146985Sthompsa { bridge_ioctl_sfd, sizeof(struct ifbrparam), 450146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 451146985Sthompsa 452146985Sthompsa { bridge_ioctl_gma, sizeof(struct ifbrparam), 453146985Sthompsa BC_F_COPYOUT }, 454146985Sthompsa { bridge_ioctl_sma, sizeof(struct ifbrparam), 455146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 456146985Sthompsa 457146985Sthompsa { bridge_ioctl_sifprio, sizeof(struct ifbreq), 458146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 459146985Sthompsa 460146985Sthompsa { bridge_ioctl_sifcost, sizeof(struct ifbreq), 461146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 462153408Sthompsa 463153408Sthompsa { bridge_ioctl_addspan, sizeof(struct ifbreq), 464153408Sthompsa BC_F_COPYIN|BC_F_SUSER }, 465153408Sthompsa { bridge_ioctl_delspan, sizeof(struct ifbreq), 466153408Sthompsa BC_F_COPYIN|BC_F_SUSER }, 467160867Sthompsa 468160867Sthompsa { bridge_ioctl_gbparam, sizeof(struct ifbropreq), 469160867Sthompsa BC_F_COPYOUT }, 470160867Sthompsa 471160867Sthompsa { bridge_ioctl_grte, sizeof(struct ifbrparam), 472160867Sthompsa BC_F_COPYOUT }, 473160867Sthompsa 474160867Sthompsa { bridge_ioctl_gifsstp, sizeof(struct ifbpstpconf), 475164861Ssyrinx BC_F_COPYIN|BC_F_COPYOUT }, 476163863Sthompsa 477163863Sthompsa { bridge_ioctl_sproto, sizeof(struct ifbrparam), 478163863Sthompsa BC_F_COPYIN|BC_F_SUSER }, 479163863Sthompsa 480163863Sthompsa { bridge_ioctl_stxhc, sizeof(struct ifbrparam), 481163863Sthompsa BC_F_COPYIN|BC_F_SUSER }, 482173320Sthompsa 483173320Sthompsa { bridge_ioctl_sifmaxaddr, sizeof(struct ifbreq), 484173320Sthompsa BC_F_COPYIN|BC_F_SUSER }, 485173320Sthompsa 486146985Sthompsa}; 487146985Sthompsaconst int bridge_control_table_size = 488146985Sthompsa sizeof(bridge_control_table) / sizeof(bridge_control_table[0]); 489146985Sthompsa 490153494SthompsaLIST_HEAD(, bridge_softc) bridge_list; 491153494Sthompsa 492241610Sglebiusstatic struct if_clone *bridge_cloner; 493241610Sglebiusstatic const char bridge_name[] = "bridge"; 494146985Sthompsa 495146985Sthompsastatic int 496146985Sthompsabridge_modevent(module_t mod, int type, void *data) 497146985Sthompsa{ 498146985Sthompsa 499146985Sthompsa switch (type) { 500146985Sthompsa case MOD_LOAD: 501153494Sthompsa mtx_init(&bridge_list_mtx, "if_bridge list", NULL, MTX_DEF); 502241610Sglebius bridge_cloner = if_clone_simple(bridge_name, 503241610Sglebius bridge_clone_create, bridge_clone_destroy, 0); 504146985Sthompsa bridge_rtnode_zone = uma_zcreate("bridge_rtnode", 505146985Sthompsa sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL, 506146985Sthompsa UMA_ALIGN_PTR, 0); 507153494Sthompsa LIST_INIT(&bridge_list); 508146985Sthompsa bridge_input_p = bridge_input; 509146985Sthompsa bridge_output_p = bridge_output; 510147205Sthompsa bridge_dn_p = bridge_dummynet; 511234487Sthompsa bridge_linkstate_p = bridge_linkstate; 512153494Sthompsa bridge_detach_cookie = EVENTHANDLER_REGISTER( 513153494Sthompsa ifnet_departure_event, bridge_ifdetach, NULL, 514153494Sthompsa EVENTHANDLER_PRI_ANY); 515146985Sthompsa break; 516146985Sthompsa case MOD_UNLOAD: 517153494Sthompsa EVENTHANDLER_DEREGISTER(ifnet_departure_event, 518153494Sthompsa bridge_detach_cookie); 519241610Sglebius if_clone_detach(bridge_cloner); 520146985Sthompsa uma_zdestroy(bridge_rtnode_zone); 521146985Sthompsa bridge_input_p = NULL; 522146985Sthompsa bridge_output_p = NULL; 523147205Sthompsa bridge_dn_p = NULL; 524234487Sthompsa bridge_linkstate_p = NULL; 525153494Sthompsa mtx_destroy(&bridge_list_mtx); 526146985Sthompsa break; 527146985Sthompsa default: 528158667Sthompsa return (EOPNOTSUPP); 529146985Sthompsa } 530158667Sthompsa return (0); 531146985Sthompsa} 532146985Sthompsa 533146985Sthompsastatic moduledata_t bridge_mod = { 534153497Sthompsa "if_bridge", 535153497Sthompsa bridge_modevent, 536241394Skevlo 0 537146985Sthompsa}; 538146985Sthompsa 539146985SthompsaDECLARE_MODULE(if_bridge, bridge_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 540324116SkpMODULE_VERSION(if_bridge, 1); 541160730SthompsaMODULE_DEPEND(if_bridge, bridgestp, 1, 1, 1); 542146985Sthompsa 543147111Sthompsa/* 544244378Skevlo * handler for net.link.bridge.ipfw 545147111Sthompsa */ 546147111Sthompsastatic int 547147111Sthompsasysctl_pfil_ipfw(SYSCTL_HANDLER_ARGS) 548147111Sthompsa{ 549153497Sthompsa int enable = pfil_ipfw; 550153497Sthompsa int error; 551146985Sthompsa 552153497Sthompsa error = sysctl_handle_int(oidp, &enable, 0, req); 553153497Sthompsa enable = (enable) ? 1 : 0; 554147111Sthompsa 555153497Sthompsa if (enable != pfil_ipfw) { 556153497Sthompsa pfil_ipfw = enable; 557147111Sthompsa 558153497Sthompsa /* 559153497Sthompsa * Disable pfil so that ipfw doesnt run twice, if the user 560153497Sthompsa * really wants both then they can re-enable pfil_bridge and/or 561153831Sthompsa * pfil_member. Also allow non-ip packets as ipfw can filter by 562153831Sthompsa * layer2 type. 563153497Sthompsa */ 564153497Sthompsa if (pfil_ipfw) { 565153831Sthompsa pfil_onlyip = 0; 566153497Sthompsa pfil_bridge = 0; 567153497Sthompsa pfil_member = 0; 568153497Sthompsa } 569147111Sthompsa } 570147111Sthompsa 571158667Sthompsa return (error); 572147111Sthompsa} 573147111SthompsaSYSCTL_PROC(_net_link_bridge, OID_AUTO, ipfw, CTLTYPE_INT|CTLFLAG_RW, 574147111Sthompsa &pfil_ipfw, 0, &sysctl_pfil_ipfw, "I", "Layer2 filter with IPFW"); 575147111Sthompsa 576146985Sthompsa/* 577146985Sthompsa * bridge_clone_create: 578146985Sthompsa * 579146985Sthompsa * Create a new bridge instance. 580146985Sthompsa */ 581151313Sthompsastatic int 582160195Ssambridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) 583146985Sthompsa{ 584156238Sthompsa struct bridge_softc *sc, *sc2; 585156238Sthompsa struct ifnet *bifp, *ifp; 586225380Sthompsa int fb, retry; 587225380Sthompsa unsigned long hostid; 588146985Sthompsa 589146985Sthompsa sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 590147281Sthompsa ifp = sc->sc_ifp = if_alloc(IFT_ETHER); 591147281Sthompsa if (ifp == NULL) { 592147281Sthompsa free(sc, M_DEVBUF); 593147281Sthompsa return (ENOSPC); 594147281Sthompsa } 595146985Sthompsa 596166916Sthompsa BRIDGE_LOCK_INIT(sc); 597146985Sthompsa sc->sc_brtmax = BRIDGE_RTABLE_MAX; 598146985Sthompsa sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT; 599146985Sthompsa 600146985Sthompsa /* Initialize our routing table. */ 601146985Sthompsa bridge_rtable_init(sc); 602146985Sthompsa 603149253Sthompsa callout_init_mtx(&sc->sc_brcallout, &sc->sc_mtx, 0); 604146985Sthompsa 605146985Sthompsa LIST_INIT(&sc->sc_iflist); 606153408Sthompsa LIST_INIT(&sc->sc_spanlist); 607146985Sthompsa 608146985Sthompsa ifp->if_softc = sc; 609241610Sglebius if_initname(ifp, bridge_name, unit); 610161625Sthompsa ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 611146985Sthompsa ifp->if_ioctl = bridge_ioctl; 612240071Sglebius ifp->if_transmit = bridge_transmit; 613240071Sglebius ifp->if_qflush = bridge_qflush; 614146985Sthompsa ifp->if_init = bridge_init; 615146985Sthompsa ifp->if_type = IFT_BRIDGE; 616146985Sthompsa 617146985Sthompsa /* 618225380Sthompsa * Generate an ethernet address with a locally administered address. 619156238Sthompsa * 620156238Sthompsa * Since we are using random ethernet addresses for the bridge, it is 621156238Sthompsa * possible that we might have address collisions, so make sure that 622156238Sthompsa * this hardware address isn't already in use on another bridge. 623225380Sthompsa * The first try uses the hostid and falls back to arc4rand(). 624146985Sthompsa */ 625225380Sthompsa fb = 0; 626225380Sthompsa getcredhostid(curthread->td_ucred, &hostid); 627243669Spjd do { 628225380Sthompsa if (fb || hostid == 0) { 629225380Sthompsa arc4rand(sc->sc_defaddr, ETHER_ADDR_LEN, 1); 630225380Sthompsa sc->sc_defaddr[0] &= ~1;/* clear multicast bit */ 631225380Sthompsa sc->sc_defaddr[0] |= 2; /* set the LAA bit */ 632225380Sthompsa } else { 633225380Sthompsa sc->sc_defaddr[0] = 0x2; 634225380Sthompsa sc->sc_defaddr[1] = (hostid >> 24) & 0xff; 635225380Sthompsa sc->sc_defaddr[2] = (hostid >> 16) & 0xff; 636225380Sthompsa sc->sc_defaddr[3] = (hostid >> 8 ) & 0xff; 637225380Sthompsa sc->sc_defaddr[4] = hostid & 0xff; 638225380Sthompsa sc->sc_defaddr[5] = ifp->if_dunit & 0xff; 639225380Sthompsa } 640225380Sthompsa 641225380Sthompsa fb = 1; 642156238Sthompsa retry = 0; 643156238Sthompsa mtx_lock(&bridge_list_mtx); 644156238Sthompsa LIST_FOREACH(sc2, &bridge_list, sc_list) { 645156238Sthompsa bifp = sc2->sc_ifp; 646180140Sphilip if (memcmp(sc->sc_defaddr, 647243669Spjd IF_LLADDR(bifp), ETHER_ADDR_LEN) == 0) { 648156238Sthompsa retry = 1; 649243669Spjd break; 650243669Spjd } 651156238Sthompsa } 652156238Sthompsa mtx_unlock(&bridge_list_mtx); 653243669Spjd } while (retry == 1); 654146985Sthompsa 655167379Sthompsa bstp_attach(&sc->sc_stp, &bridge_ops); 656180140Sphilip ether_ifattach(ifp, sc->sc_defaddr); 657146985Sthompsa /* Now undo some of the damage... */ 658146985Sthompsa ifp->if_baudrate = 0; 659146985Sthompsa ifp->if_type = IFT_BRIDGE; 660146985Sthompsa 661153494Sthompsa mtx_lock(&bridge_list_mtx); 662153494Sthompsa LIST_INSERT_HEAD(&bridge_list, sc, sc_list); 663153494Sthompsa mtx_unlock(&bridge_list_mtx); 664153494Sthompsa 665146985Sthompsa return (0); 666146985Sthompsa} 667146985Sthompsa 668146985Sthompsa/* 669146985Sthompsa * bridge_clone_destroy: 670146985Sthompsa * 671146985Sthompsa * Destroy a bridge instance. 672146985Sthompsa */ 673151313Sthompsastatic void 674146985Sthompsabridge_clone_destroy(struct ifnet *ifp) 675146985Sthompsa{ 676146985Sthompsa struct bridge_softc *sc = ifp->if_softc; 677146985Sthompsa struct bridge_iflist *bif; 678146985Sthompsa 679146985Sthompsa BRIDGE_LOCK(sc); 680146985Sthompsa 681146985Sthompsa bridge_stop(ifp, 1); 682149522Sthompsa ifp->if_flags &= ~IFF_UP; 683146985Sthompsa 684146985Sthompsa while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL) 685151594Sthompsa bridge_delete_member(sc, bif, 0); 686146985Sthompsa 687153408Sthompsa while ((bif = LIST_FIRST(&sc->sc_spanlist)) != NULL) { 688153494Sthompsa bridge_delete_span(sc, bif); 689153408Sthompsa } 690153408Sthompsa 691146985Sthompsa BRIDGE_UNLOCK(sc); 692146985Sthompsa 693149253Sthompsa callout_drain(&sc->sc_brcallout); 694149253Sthompsa 695153494Sthompsa mtx_lock(&bridge_list_mtx); 696153494Sthompsa LIST_REMOVE(sc, sc_list); 697153494Sthompsa mtx_unlock(&bridge_list_mtx); 698153494Sthompsa 699160703Sthompsa bstp_detach(&sc->sc_stp); 700146985Sthompsa ether_ifdetach(ifp); 701227459Sbrooks if_free(ifp); 702146985Sthompsa 703146985Sthompsa /* Tear down the routing table. */ 704146985Sthompsa bridge_rtable_fini(sc); 705146985Sthompsa 706146985Sthompsa BRIDGE_LOCK_DESTROY(sc); 707146985Sthompsa free(sc, M_DEVBUF); 708146985Sthompsa} 709146985Sthompsa 710146985Sthompsa/* 711146985Sthompsa * bridge_ioctl: 712146985Sthompsa * 713146985Sthompsa * Handle a control request from the operator. 714146985Sthompsa */ 715151313Sthompsastatic int 716146985Sthompsabridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 717146985Sthompsa{ 718146985Sthompsa struct bridge_softc *sc = ifp->if_softc; 719203272Shrs struct ifreq *ifr = (struct ifreq *)data; 720203272Shrs struct bridge_iflist *bif; 721146985Sthompsa struct thread *td = curthread; 722146985Sthompsa union { 723146985Sthompsa struct ifbreq ifbreq; 724146985Sthompsa struct ifbifconf ifbifconf; 725146985Sthompsa struct ifbareq ifbareq; 726146985Sthompsa struct ifbaconf ifbaconf; 727146985Sthompsa struct ifbrparam ifbrparam; 728164653Sthompsa struct ifbropreq ifbropreq; 729146985Sthompsa } args; 730146985Sthompsa struct ifdrv *ifd = (struct ifdrv *) data; 731146985Sthompsa const struct bridge_control *bc; 732146985Sthompsa int error = 0; 733146985Sthompsa 734146985Sthompsa switch (cmd) { 735146985Sthompsa 736149829Sthompsa case SIOCADDMULTI: 737149829Sthompsa case SIOCDELMULTI: 738149829Sthompsa break; 739149829Sthompsa 740146985Sthompsa case SIOCGDRVSPEC: 741146985Sthompsa case SIOCSDRVSPEC: 742146985Sthompsa if (ifd->ifd_cmd >= bridge_control_table_size) { 743146985Sthompsa error = EINVAL; 744146985Sthompsa break; 745146985Sthompsa } 746146985Sthompsa bc = &bridge_control_table[ifd->ifd_cmd]; 747146985Sthompsa 748146985Sthompsa if (cmd == SIOCGDRVSPEC && 749146985Sthompsa (bc->bc_flags & BC_F_COPYOUT) == 0) { 750146985Sthompsa error = EINVAL; 751146985Sthompsa break; 752146985Sthompsa } 753146985Sthompsa else if (cmd == SIOCSDRVSPEC && 754146985Sthompsa (bc->bc_flags & BC_F_COPYOUT) != 0) { 755146985Sthompsa error = EINVAL; 756146985Sthompsa break; 757146985Sthompsa } 758146985Sthompsa 759146985Sthompsa if (bc->bc_flags & BC_F_SUSER) { 760164033Srwatson error = priv_check(td, PRIV_NET_BRIDGE); 761146985Sthompsa if (error) 762146985Sthompsa break; 763146985Sthompsa } 764146985Sthompsa 765146985Sthompsa if (ifd->ifd_len != bc->bc_argsize || 766146985Sthompsa ifd->ifd_len > sizeof(args)) { 767146985Sthompsa error = EINVAL; 768146985Sthompsa break; 769146985Sthompsa } 770146985Sthompsa 771158667Sthompsa bzero(&args, sizeof(args)); 772146985Sthompsa if (bc->bc_flags & BC_F_COPYIN) { 773146985Sthompsa error = copyin(ifd->ifd_data, &args, ifd->ifd_len); 774146985Sthompsa if (error) 775146985Sthompsa break; 776146985Sthompsa } 777146985Sthompsa 778171603Sthompsa BRIDGE_LOCK(sc); 779146985Sthompsa error = (*bc->bc_func)(sc, &args); 780171603Sthompsa BRIDGE_UNLOCK(sc); 781146985Sthompsa if (error) 782146985Sthompsa break; 783146985Sthompsa 784146985Sthompsa if (bc->bc_flags & BC_F_COPYOUT) 785146985Sthompsa error = copyout(&args, ifd->ifd_data, ifd->ifd_len); 786146985Sthompsa 787146985Sthompsa break; 788146985Sthompsa 789146985Sthompsa case SIOCSIFFLAGS: 790148887Srwatson if (!(ifp->if_flags & IFF_UP) && 791148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING)) { 792146985Sthompsa /* 793146985Sthompsa * If interface is marked down and it is running, 794146985Sthompsa * then stop and disable it. 795146985Sthompsa */ 796171603Sthompsa BRIDGE_LOCK(sc); 797146985Sthompsa bridge_stop(ifp, 1); 798171603Sthompsa BRIDGE_UNLOCK(sc); 799148887Srwatson } else if ((ifp->if_flags & IFF_UP) && 800148887Srwatson !(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 801146985Sthompsa /* 802146985Sthompsa * If interface is marked up and it is stopped, then 803146985Sthompsa * start it. 804146985Sthompsa */ 805147634Sthompsa (*ifp->if_init)(sc); 806146985Sthompsa } 807146985Sthompsa break; 808146985Sthompsa 809146985Sthompsa case SIOCSIFMTU: 810203272Shrs if (ifr->ifr_mtu < 576) { 811203272Shrs error = EINVAL; 812203272Shrs break; 813203272Shrs } 814203272Shrs if (LIST_EMPTY(&sc->sc_iflist)) { 815203272Shrs sc->sc_ifp->if_mtu = ifr->ifr_mtu; 816203272Shrs break; 817203272Shrs } 818203272Shrs BRIDGE_LOCK(sc); 819203272Shrs LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 820203272Shrs if (bif->bif_ifp->if_mtu != ifr->ifr_mtu) { 821203272Shrs log(LOG_NOTICE, "%s: invalid MTU: %lu(%s)" 822203272Shrs " != %d\n", sc->sc_ifp->if_xname, 823203272Shrs bif->bif_ifp->if_mtu, 824203272Shrs bif->bif_ifp->if_xname, ifr->ifr_mtu); 825203272Shrs error = EINVAL; 826203272Shrs break; 827203272Shrs } 828203272Shrs } 829203272Shrs if (!error) 830203272Shrs sc->sc_ifp->if_mtu = ifr->ifr_mtu; 831203272Shrs BRIDGE_UNLOCK(sc); 832146985Sthompsa break; 833146985Sthompsa default: 834153497Sthompsa /* 835146985Sthompsa * drop the lock as ether_ioctl() will call bridge_start() and 836146985Sthompsa * cause the lock to be recursed. 837146985Sthompsa */ 838146985Sthompsa error = ether_ioctl(ifp, cmd, data); 839146985Sthompsa break; 840146985Sthompsa } 841146985Sthompsa 842146985Sthompsa return (error); 843146985Sthompsa} 844146985Sthompsa 845146985Sthompsa/* 846154336Sthompsa * bridge_mutecaps: 847154336Sthompsa * 848154336Sthompsa * Clear or restore unwanted capabilities on the member interface 849154336Sthompsa */ 850154336Sthompsastatic void 851180220Sthompsabridge_mutecaps(struct bridge_softc *sc) 852154336Sthompsa{ 853180220Sthompsa struct bridge_iflist *bif; 854180220Sthompsa int enabled, mask; 855180220Sthompsa 856180220Sthompsa /* Initial bitmask of capabilities to test */ 857180220Sthompsa mask = BRIDGE_IFCAPS_MASK; 858180220Sthompsa 859180220Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 860180220Sthompsa /* Every member must support it or its disabled */ 861180220Sthompsa mask &= bif->bif_savedcaps; 862180220Sthompsa } 863180220Sthompsa 864313066Skp BRIDGE_XLOCK(sc); 865180220Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 866180220Sthompsa enabled = bif->bif_ifp->if_capenable; 867196519Sjfv enabled &= ~BRIDGE_IFCAPS_STRIP; 868180220Sthompsa /* strip off mask bits and enable them again if allowed */ 869180220Sthompsa enabled &= ~BRIDGE_IFCAPS_MASK; 870180220Sthompsa enabled |= mask; 871313066Skp BRIDGE_UNLOCK(sc); 872180220Sthompsa bridge_set_ifcap(sc, bif, enabled); 873313066Skp BRIDGE_LOCK(sc); 874180220Sthompsa } 875313066Skp BRIDGE_XDROP(sc); 876180220Sthompsa 877180220Sthompsa} 878180220Sthompsa 879180220Sthompsastatic void 880180220Sthompsabridge_set_ifcap(struct bridge_softc *sc, struct bridge_iflist *bif, int set) 881180220Sthompsa{ 882154336Sthompsa struct ifnet *ifp = bif->bif_ifp; 883154336Sthompsa struct ifreq ifr; 884154336Sthompsa int error; 885154336Sthompsa 886313066Skp BRIDGE_UNLOCK_ASSERT(sc); 887313066Skp 888158667Sthompsa bzero(&ifr, sizeof(ifr)); 889180220Sthompsa ifr.ifr_reqcap = set; 890154336Sthompsa 891180220Sthompsa if (ifp->if_capenable != set) { 892154336Sthompsa error = (*ifp->if_ioctl)(ifp, SIOCSIFCAP, (caddr_t)&ifr); 893180220Sthompsa if (error) 894180220Sthompsa if_printf(sc->sc_ifp, 895180220Sthompsa "error setting interface capabilities on %s\n", 896180220Sthompsa ifp->if_xname); 897154336Sthompsa } 898154336Sthompsa} 899154336Sthompsa 900154336Sthompsa/* 901146985Sthompsa * bridge_lookup_member: 902146985Sthompsa * 903146985Sthompsa * Lookup a bridge member interface. 904146985Sthompsa */ 905151345Sthompsastatic struct bridge_iflist * 906146985Sthompsabridge_lookup_member(struct bridge_softc *sc, const char *name) 907146985Sthompsa{ 908146985Sthompsa struct bridge_iflist *bif; 909146985Sthompsa struct ifnet *ifp; 910146985Sthompsa 911146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 912146985Sthompsa 913146985Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 914146985Sthompsa ifp = bif->bif_ifp; 915146985Sthompsa if (strcmp(ifp->if_xname, name) == 0) 916146985Sthompsa return (bif); 917146985Sthompsa } 918146985Sthompsa 919146985Sthompsa return (NULL); 920146985Sthompsa} 921146985Sthompsa 922146985Sthompsa/* 923146985Sthompsa * bridge_lookup_member_if: 924146985Sthompsa * 925146985Sthompsa * Lookup a bridge member interface by ifnet*. 926146985Sthompsa */ 927151345Sthompsastatic struct bridge_iflist * 928146985Sthompsabridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp) 929146985Sthompsa{ 930146985Sthompsa struct bridge_iflist *bif; 931146985Sthompsa 932146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 933146985Sthompsa 934146985Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 935146985Sthompsa if (bif->bif_ifp == member_ifp) 936146985Sthompsa return (bif); 937146985Sthompsa } 938146985Sthompsa 939146985Sthompsa return (NULL); 940146985Sthompsa} 941146985Sthompsa 942146985Sthompsa/* 943146985Sthompsa * bridge_delete_member: 944146985Sthompsa * 945146985Sthompsa * Delete the specified member interface. 946146985Sthompsa */ 947151313Sthompsastatic void 948151594Sthompsabridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif, 949151594Sthompsa int gone) 950146985Sthompsa{ 951146985Sthompsa struct ifnet *ifs = bif->bif_ifp; 952180140Sphilip struct ifnet *fif = NULL; 953146985Sthompsa 954146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 955146985Sthompsa 956160703Sthompsa if (bif->bif_flags & IFBIF_STP) 957164626Sthompsa bstp_disable(&bif->bif_stp); 958160703Sthompsa 959146985Sthompsa ifs->if_bridge = NULL; 960146985Sthompsa BRIDGE_XLOCK(sc); 961146985Sthompsa LIST_REMOVE(bif, bif_next); 962146985Sthompsa BRIDGE_XDROP(sc); 963146985Sthompsa 964180140Sphilip /* 965180140Sphilip * If removing the interface that gave the bridge its mac address, set 966180140Sphilip * the mac address of the bridge to the address of the next member, or 967180140Sphilip * to its default address if no members are left. 968180140Sphilip */ 969188594Sthompsa if (bridge_inherit_mac && sc->sc_ifaddr == ifs) { 970188594Sthompsa if (LIST_EMPTY(&sc->sc_iflist)) { 971180140Sphilip bcopy(sc->sc_defaddr, 972180140Sphilip IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); 973188594Sthompsa sc->sc_ifaddr = NULL; 974188594Sthompsa } else { 975180140Sphilip fif = LIST_FIRST(&sc->sc_iflist)->bif_ifp; 976180140Sphilip bcopy(IF_LLADDR(fif), 977180140Sphilip IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); 978188594Sthompsa sc->sc_ifaddr = fif; 979180140Sphilip } 980202588Sthompsa EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); 981180140Sphilip } 982180140Sphilip 983236916Sthompsa bridge_linkcheck(sc); 984180220Sthompsa bridge_mutecaps(sc); /* recalcuate now this interface is removed */ 985146985Sthompsa bridge_rtdelete(sc, ifs, IFBF_FLUSHALL); 986173320Sthompsa KASSERT(bif->bif_addrcnt == 0, 987173320Sthompsa ("%s: %d bridge routes referenced", __func__, bif->bif_addrcnt)); 988146985Sthompsa 989160901Sthompsa BRIDGE_UNLOCK(sc); 990191729Sthompsa if (!gone) { 991191729Sthompsa switch (ifs->if_type) { 992191729Sthompsa case IFT_ETHER: 993191729Sthompsa case IFT_L2VLAN: 994191729Sthompsa /* 995285016Skp * Take the interface out of promiscuous mode, but only 996285016Skp * if it was promiscuous in the first place. It might 997285016Skp * not be if we're in the bridge_ioctl_add() error path. 998191729Sthompsa */ 999285016Skp if (ifs->if_flags & IFF_PROMISC) 1000285016Skp (void) ifpromisc(ifs, 0); 1001191729Sthompsa break; 1002191729Sthompsa 1003191729Sthompsa case IFT_GIF: 1004191729Sthompsa break; 1005191729Sthompsa 1006191729Sthompsa default: 1007191729Sthompsa#ifdef DIAGNOSTIC 1008191729Sthompsa panic("bridge_delete_member: impossible"); 1009191729Sthompsa#endif 1010191729Sthompsa break; 1011191729Sthompsa } 1012191729Sthompsa /* reneable any interface capabilities */ 1013191729Sthompsa bridge_set_ifcap(sc, bif, bif->bif_savedcaps); 1014191729Sthompsa } 1015164626Sthompsa bstp_destroy(&bif->bif_stp); /* prepare to free */ 1016160901Sthompsa BRIDGE_LOCK(sc); 1017146985Sthompsa free(bif, M_DEVBUF); 1018146985Sthompsa} 1019146985Sthompsa 1020153494Sthompsa/* 1021153494Sthompsa * bridge_delete_span: 1022153494Sthompsa * 1023153494Sthompsa * Delete the specified span interface. 1024153494Sthompsa */ 1025153494Sthompsastatic void 1026153494Sthompsabridge_delete_span(struct bridge_softc *sc, struct bridge_iflist *bif) 1027153494Sthompsa{ 1028153494Sthompsa BRIDGE_LOCK_ASSERT(sc); 1029153494Sthompsa 1030153494Sthompsa KASSERT(bif->bif_ifp->if_bridge == NULL, 1031153494Sthompsa ("%s: not a span interface", __func__)); 1032153494Sthompsa 1033153494Sthompsa LIST_REMOVE(bif, bif_next); 1034153494Sthompsa free(bif, M_DEVBUF); 1035153494Sthompsa} 1036153494Sthompsa 1037151313Sthompsastatic int 1038146985Sthompsabridge_ioctl_add(struct bridge_softc *sc, void *arg) 1039146985Sthompsa{ 1040146985Sthompsa struct ifbreq *req = arg; 1041146985Sthompsa struct bridge_iflist *bif = NULL; 1042146985Sthompsa struct ifnet *ifs; 1043146985Sthompsa int error = 0; 1044146985Sthompsa 1045146985Sthompsa ifs = ifunit(req->ifbr_ifsname); 1046146985Sthompsa if (ifs == NULL) 1047146985Sthompsa return (ENOENT); 1048180220Sthompsa if (ifs->if_ioctl == NULL) /* must be supported */ 1049180220Sthompsa return (EINVAL); 1050146985Sthompsa 1051153408Sthompsa /* If it's in the span list, it can't be a member. */ 1052153408Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) 1053153408Sthompsa if (ifs == bif->bif_ifp) 1054153408Sthompsa return (EBUSY); 1055153408Sthompsa 1056146985Sthompsa if (ifs->if_bridge == sc) 1057146985Sthompsa return (EEXIST); 1058146985Sthompsa 1059146985Sthompsa if (ifs->if_bridge != NULL) 1060146985Sthompsa return (EBUSY); 1061146985Sthompsa 1062146985Sthompsa switch (ifs->if_type) { 1063146985Sthompsa case IFT_ETHER: 1064146985Sthompsa case IFT_L2VLAN: 1065153621Sthompsa case IFT_GIF: 1066191729Sthompsa /* permitted interface types */ 1067153621Sthompsa break; 1068146985Sthompsa default: 1069252511Shrs return (EINVAL); 1070146985Sthompsa } 1071146985Sthompsa 1072252511Shrs#ifdef INET6 1073252511Shrs /* 1074252511Shrs * Two valid inet6 addresses with link-local scope must not be 1075252511Shrs * on the parent interface and the member interfaces at the 1076252511Shrs * same time. This restriction is needed to prevent violation 1077252511Shrs * of link-local scope zone. Attempts to add a member 1078252511Shrs * interface which has inet6 addresses when the parent has 1079252511Shrs * inet6 triggers removal of all inet6 addresses on the member 1080252511Shrs * interface. 1081252511Shrs */ 1082252511Shrs 1083252511Shrs /* Check if the parent interface has a link-local scope addr. */ 1084253751Shrs if (V_allow_llz_overlap == 0 && 1085253751Shrs in6ifa_llaonifp(sc->sc_ifp) != NULL) { 1086252511Shrs /* 1087252511Shrs * If any, remove all inet6 addresses from the member 1088252511Shrs * interfaces. 1089252511Shrs */ 1090252511Shrs BRIDGE_XLOCK(sc); 1091252511Shrs LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 1092252511Shrs if (in6ifa_llaonifp(bif->bif_ifp)) { 1093252511Shrs BRIDGE_UNLOCK(sc); 1094252511Shrs in6_ifdetach(bif->bif_ifp); 1095252511Shrs BRIDGE_LOCK(sc); 1096252511Shrs if_printf(sc->sc_ifp, 1097252511Shrs "IPv6 addresses on %s have been removed " 1098252511Shrs "before adding it as a member to prevent " 1099252511Shrs "IPv6 address scope violation.\n", 1100252511Shrs bif->bif_ifp->if_xname); 1101252511Shrs } 1102252511Shrs } 1103252511Shrs BRIDGE_XDROP(sc); 1104252511Shrs if (in6ifa_llaonifp(ifs)) { 1105252511Shrs BRIDGE_UNLOCK(sc); 1106252511Shrs in6_ifdetach(ifs); 1107252511Shrs BRIDGE_LOCK(sc); 1108252511Shrs if_printf(sc->sc_ifp, 1109252511Shrs "IPv6 addresses on %s have been removed " 1110252511Shrs "before adding it as a member to prevent " 1111252511Shrs "IPv6 address scope violation.\n", 1112252511Shrs ifs->if_xname); 1113252511Shrs } 1114252511Shrs } 1115252511Shrs#endif 1116203272Shrs /* Allow the first Ethernet member to define the MTU */ 1117203272Shrs if (LIST_EMPTY(&sc->sc_iflist)) 1118203272Shrs sc->sc_ifp->if_mtu = ifs->if_mtu; 1119203272Shrs else if (sc->sc_ifp->if_mtu != ifs->if_mtu) { 1120203272Shrs if_printf(sc->sc_ifp, "invalid MTU: %lu(%s) != %lu\n", 1121203272Shrs ifs->if_mtu, ifs->if_xname, sc->sc_ifp->if_mtu); 1122252511Shrs return (EINVAL); 1123203272Shrs } 1124203272Shrs 1125252511Shrs bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO); 1126252511Shrs if (bif == NULL) 1127252511Shrs return (ENOMEM); 1128252511Shrs 1129252511Shrs bif->bif_ifp = ifs; 1130252511Shrs bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; 1131252511Shrs bif->bif_savedcaps = ifs->if_capenable; 1132252511Shrs 1133180140Sphilip /* 1134180140Sphilip * Assign the interface's MAC address to the bridge if it's the first 1135180140Sphilip * member and the MAC address of the bridge has not been changed from 1136180140Sphilip * the default randomly generated one. 1137180140Sphilip */ 1138182862Sthompsa if (bridge_inherit_mac && LIST_EMPTY(&sc->sc_iflist) && 1139188594Sthompsa !memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr, ETHER_ADDR_LEN)) { 1140180140Sphilip bcopy(IF_LLADDR(ifs), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); 1141188594Sthompsa sc->sc_ifaddr = ifs; 1142202588Sthompsa EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); 1143188594Sthompsa } 1144180140Sphilip 1145146985Sthompsa ifs->if_bridge = sc; 1146164626Sthompsa bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp); 1147146985Sthompsa /* 1148146985Sthompsa * XXX: XLOCK HERE!?! 1149146985Sthompsa * 1150146985Sthompsa * NOTE: insert_***HEAD*** should be safe for the traversals. 1151146985Sthompsa */ 1152146985Sthompsa LIST_INSERT_HEAD(&sc->sc_iflist, bif, bif_next); 1153146985Sthompsa 1154180220Sthompsa /* Set interface capabilities to the intersection set of all members */ 1155180220Sthompsa bridge_mutecaps(sc); 1156236916Sthompsa bridge_linkcheck(sc); 1157191729Sthompsa 1158234487Sthompsa /* Place the interface into promiscuous mode */ 1159191729Sthompsa switch (ifs->if_type) { 1160234487Sthompsa case IFT_ETHER: 1161234487Sthompsa case IFT_L2VLAN: 1162236916Sthompsa BRIDGE_UNLOCK(sc); 1163234487Sthompsa error = ifpromisc(ifs, 1); 1164236916Sthompsa BRIDGE_LOCK(sc); 1165234487Sthompsa break; 1166191729Sthompsa } 1167252511Shrs 1168285016Skp if (error) 1169191729Sthompsa bridge_delete_member(sc, bif, 0); 1170146985Sthompsa return (error); 1171146985Sthompsa} 1172146985Sthompsa 1173151313Sthompsastatic int 1174146985Sthompsabridge_ioctl_del(struct bridge_softc *sc, void *arg) 1175146985Sthompsa{ 1176146985Sthompsa struct ifbreq *req = arg; 1177146985Sthompsa struct bridge_iflist *bif; 1178146985Sthompsa 1179146985Sthompsa bif = bridge_lookup_member(sc, req->ifbr_ifsname); 1180146985Sthompsa if (bif == NULL) 1181146985Sthompsa return (ENOENT); 1182146985Sthompsa 1183151594Sthompsa bridge_delete_member(sc, bif, 0); 1184146985Sthompsa 1185146985Sthompsa return (0); 1186146985Sthompsa} 1187146985Sthompsa 1188151313Sthompsastatic int 1189146985Sthompsabridge_ioctl_gifflags(struct bridge_softc *sc, void *arg) 1190146985Sthompsa{ 1191146985Sthompsa struct ifbreq *req = arg; 1192146985Sthompsa struct bridge_iflist *bif; 1193163863Sthompsa struct bstp_port *bp; 1194146985Sthompsa 1195146985Sthompsa bif = bridge_lookup_member(sc, req->ifbr_ifsname); 1196146985Sthompsa if (bif == NULL) 1197146985Sthompsa return (ENOENT); 1198146985Sthompsa 1199163863Sthompsa bp = &bif->bif_stp; 1200146985Sthompsa req->ifbr_ifsflags = bif->bif_flags; 1201163863Sthompsa req->ifbr_state = bp->bp_state; 1202163863Sthompsa req->ifbr_priority = bp->bp_priority; 1203163863Sthompsa req->ifbr_path_cost = bp->bp_path_cost; 1204163863Sthompsa req->ifbr_portno = bif->bif_ifp->if_index & 0xfff; 1205163863Sthompsa req->ifbr_proto = bp->bp_protover; 1206163863Sthompsa req->ifbr_role = bp->bp_role; 1207163863Sthompsa req->ifbr_stpflags = bp->bp_flags; 1208173320Sthompsa req->ifbr_addrcnt = bif->bif_addrcnt; 1209173320Sthompsa req->ifbr_addrmax = bif->bif_addrmax; 1210173320Sthompsa req->ifbr_addrexceeded = bif->bif_addrexceeded; 1211146985Sthompsa 1212164653Sthompsa /* Copy STP state options as flags */ 1213164653Sthompsa if (bp->bp_operedge) 1214164653Sthompsa req->ifbr_ifsflags |= IFBIF_BSTP_EDGE; 1215164653Sthompsa if (bp->bp_flags & BSTP_PORT_AUTOEDGE) 1216164653Sthompsa req->ifbr_ifsflags |= IFBIF_BSTP_AUTOEDGE; 1217165105Sthompsa if (bp->bp_ptp_link) 1218165105Sthompsa req->ifbr_ifsflags |= IFBIF_BSTP_PTP; 1219165105Sthompsa if (bp->bp_flags & BSTP_PORT_AUTOPTP) 1220165105Sthompsa req->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP; 1221164880Ssyrinx if (bp->bp_flags & BSTP_PORT_ADMEDGE) 1222164880Ssyrinx req->ifbr_ifsflags |= IFBIF_BSTP_ADMEDGE; 1223164880Ssyrinx if (bp->bp_flags & BSTP_PORT_ADMCOST) 1224164880Ssyrinx req->ifbr_ifsflags |= IFBIF_BSTP_ADMCOST; 1225146985Sthompsa return (0); 1226146985Sthompsa} 1227146985Sthompsa 1228151313Sthompsastatic int 1229146985Sthompsabridge_ioctl_sifflags(struct bridge_softc *sc, void *arg) 1230146985Sthompsa{ 1231146985Sthompsa struct ifbreq *req = arg; 1232146985Sthompsa struct bridge_iflist *bif; 1233164653Sthompsa struct bstp_port *bp; 1234160703Sthompsa int error; 1235146985Sthompsa 1236146985Sthompsa bif = bridge_lookup_member(sc, req->ifbr_ifsname); 1237146985Sthompsa if (bif == NULL) 1238146985Sthompsa return (ENOENT); 1239164653Sthompsa bp = &bif->bif_stp; 1240146985Sthompsa 1241153408Sthompsa if (req->ifbr_ifsflags & IFBIF_SPAN) 1242153408Sthompsa /* SPAN is readonly */ 1243153408Sthompsa return (EINVAL); 1244153408Sthompsa 1245146985Sthompsa if (req->ifbr_ifsflags & IFBIF_STP) { 1246160703Sthompsa if ((bif->bif_flags & IFBIF_STP) == 0) { 1247164626Sthompsa error = bstp_enable(&bif->bif_stp); 1248160703Sthompsa if (error) 1249160703Sthompsa return (error); 1250146985Sthompsa } 1251160703Sthompsa } else { 1252160703Sthompsa if ((bif->bif_flags & IFBIF_STP) != 0) 1253164626Sthompsa bstp_disable(&bif->bif_stp); 1254146985Sthompsa } 1255146985Sthompsa 1256164653Sthompsa /* Pass on STP flags */ 1257164653Sthompsa bstp_set_edge(bp, req->ifbr_ifsflags & IFBIF_BSTP_EDGE ? 1 : 0); 1258164653Sthompsa bstp_set_autoedge(bp, req->ifbr_ifsflags & IFBIF_BSTP_AUTOEDGE ? 1 : 0); 1259165105Sthompsa bstp_set_ptp(bp, req->ifbr_ifsflags & IFBIF_BSTP_PTP ? 1 : 0); 1260165105Sthompsa bstp_set_autoptp(bp, req->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP ? 1 : 0); 1261146985Sthompsa 1262164653Sthompsa /* Save the bits relating to the bridge */ 1263164653Sthompsa bif->bif_flags = req->ifbr_ifsflags & IFBIFMASK; 1264164653Sthompsa 1265146985Sthompsa return (0); 1266146985Sthompsa} 1267146985Sthompsa 1268151313Sthompsastatic int 1269146985Sthompsabridge_ioctl_scache(struct bridge_softc *sc, void *arg) 1270146985Sthompsa{ 1271146985Sthompsa struct ifbrparam *param = arg; 1272146985Sthompsa 1273146985Sthompsa sc->sc_brtmax = param->ifbrp_csize; 1274146985Sthompsa bridge_rttrim(sc); 1275146985Sthompsa 1276146985Sthompsa return (0); 1277146985Sthompsa} 1278146985Sthompsa 1279151313Sthompsastatic int 1280146985Sthompsabridge_ioctl_gcache(struct bridge_softc *sc, void *arg) 1281146985Sthompsa{ 1282146985Sthompsa struct ifbrparam *param = arg; 1283146985Sthompsa 1284146985Sthompsa param->ifbrp_csize = sc->sc_brtmax; 1285146985Sthompsa 1286146985Sthompsa return (0); 1287146985Sthompsa} 1288146985Sthompsa 1289151313Sthompsastatic int 1290146985Sthompsabridge_ioctl_gifs(struct bridge_softc *sc, void *arg) 1291146985Sthompsa{ 1292146985Sthompsa struct ifbifconf *bifc = arg; 1293146985Sthompsa struct bridge_iflist *bif; 1294146985Sthompsa struct ifbreq breq; 1295171603Sthompsa char *buf, *outbuf; 1296171603Sthompsa int count, buflen, len, error = 0; 1297146985Sthompsa 1298146985Sthompsa count = 0; 1299146985Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) 1300146985Sthompsa count++; 1301153408Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) 1302153408Sthompsa count++; 1303146985Sthompsa 1304171603Sthompsa buflen = sizeof(breq) * count; 1305146985Sthompsa if (bifc->ifbic_len == 0) { 1306171603Sthompsa bifc->ifbic_len = buflen; 1307146985Sthompsa return (0); 1308146985Sthompsa } 1309171603Sthompsa BRIDGE_UNLOCK(sc); 1310171603Sthompsa outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); 1311171603Sthompsa BRIDGE_LOCK(sc); 1312146985Sthompsa 1313146985Sthompsa count = 0; 1314171603Sthompsa buf = outbuf; 1315171603Sthompsa len = min(bifc->ifbic_len, buflen); 1316158667Sthompsa bzero(&breq, sizeof(breq)); 1317146985Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 1318146985Sthompsa if (len < sizeof(breq)) 1319146985Sthompsa break; 1320146985Sthompsa 1321146985Sthompsa strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname, 1322146985Sthompsa sizeof(breq.ifbr_ifsname)); 1323164653Sthompsa /* Fill in the ifbreq structure */ 1324164653Sthompsa error = bridge_ioctl_gifflags(sc, &breq); 1325164653Sthompsa if (error) 1326164653Sthompsa break; 1327171603Sthompsa memcpy(buf, &breq, sizeof(breq)); 1328146985Sthompsa count++; 1329171603Sthompsa buf += sizeof(breq); 1330146985Sthompsa len -= sizeof(breq); 1331146985Sthompsa } 1332153408Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) { 1333153408Sthompsa if (len < sizeof(breq)) 1334153408Sthompsa break; 1335146985Sthompsa 1336153408Sthompsa strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname, 1337153408Sthompsa sizeof(breq.ifbr_ifsname)); 1338153408Sthompsa breq.ifbr_ifsflags = bif->bif_flags; 1339163863Sthompsa breq.ifbr_portno = bif->bif_ifp->if_index & 0xfff; 1340171603Sthompsa memcpy(buf, &breq, sizeof(breq)); 1341153408Sthompsa count++; 1342171603Sthompsa buf += sizeof(breq); 1343153408Sthompsa len -= sizeof(breq); 1344153408Sthompsa } 1345153408Sthompsa 1346171603Sthompsa BRIDGE_UNLOCK(sc); 1347146985Sthompsa bifc->ifbic_len = sizeof(breq) * count; 1348171603Sthompsa error = copyout(outbuf, bifc->ifbic_req, bifc->ifbic_len); 1349171603Sthompsa BRIDGE_LOCK(sc); 1350171603Sthompsa free(outbuf, M_TEMP); 1351146985Sthompsa return (error); 1352146985Sthompsa} 1353146985Sthompsa 1354151313Sthompsastatic int 1355146985Sthompsabridge_ioctl_rts(struct bridge_softc *sc, void *arg) 1356146985Sthompsa{ 1357146985Sthompsa struct ifbaconf *bac = arg; 1358146985Sthompsa struct bridge_rtnode *brt; 1359146985Sthompsa struct ifbareq bareq; 1360171603Sthompsa char *buf, *outbuf; 1361171603Sthompsa int count, buflen, len, error = 0; 1362146985Sthompsa 1363146985Sthompsa if (bac->ifbac_len == 0) 1364146985Sthompsa return (0); 1365146985Sthompsa 1366171603Sthompsa count = 0; 1367171603Sthompsa LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) 1368171603Sthompsa count++; 1369171603Sthompsa buflen = sizeof(bareq) * count; 1370171603Sthompsa 1371171603Sthompsa BRIDGE_UNLOCK(sc); 1372171603Sthompsa outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); 1373171603Sthompsa BRIDGE_LOCK(sc); 1374171603Sthompsa 1375171603Sthompsa count = 0; 1376171603Sthompsa buf = outbuf; 1377171603Sthompsa len = min(bac->ifbac_len, buflen); 1378158667Sthompsa bzero(&bareq, sizeof(bareq)); 1379146985Sthompsa LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { 1380146985Sthompsa if (len < sizeof(bareq)) 1381146985Sthompsa goto out; 1382146985Sthompsa strlcpy(bareq.ifba_ifsname, brt->brt_ifp->if_xname, 1383146985Sthompsa sizeof(bareq.ifba_ifsname)); 1384146985Sthompsa memcpy(bareq.ifba_dst, brt->brt_addr, sizeof(brt->brt_addr)); 1385170681Sthompsa bareq.ifba_vlan = brt->brt_vlan; 1386146985Sthompsa if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && 1387153976Sthompsa time_uptime < brt->brt_expire) 1388153976Sthompsa bareq.ifba_expire = brt->brt_expire - time_uptime; 1389146985Sthompsa else 1390146985Sthompsa bareq.ifba_expire = 0; 1391146985Sthompsa bareq.ifba_flags = brt->brt_flags; 1392146985Sthompsa 1393171603Sthompsa memcpy(buf, &bareq, sizeof(bareq)); 1394146985Sthompsa count++; 1395171603Sthompsa buf += sizeof(bareq); 1396146985Sthompsa len -= sizeof(bareq); 1397146985Sthompsa } 1398153497Sthompsaout: 1399171603Sthompsa BRIDGE_UNLOCK(sc); 1400146985Sthompsa bac->ifbac_len = sizeof(bareq) * count; 1401171603Sthompsa error = copyout(outbuf, bac->ifbac_req, bac->ifbac_len); 1402171603Sthompsa BRIDGE_LOCK(sc); 1403171603Sthompsa free(outbuf, M_TEMP); 1404146985Sthompsa return (error); 1405146985Sthompsa} 1406146985Sthompsa 1407151313Sthompsastatic int 1408146985Sthompsabridge_ioctl_saddr(struct bridge_softc *sc, void *arg) 1409146985Sthompsa{ 1410146985Sthompsa struct ifbareq *req = arg; 1411146985Sthompsa struct bridge_iflist *bif; 1412146985Sthompsa int error; 1413146985Sthompsa 1414146985Sthompsa bif = bridge_lookup_member(sc, req->ifba_ifsname); 1415146985Sthompsa if (bif == NULL) 1416146985Sthompsa return (ENOENT); 1417146985Sthompsa 1418170681Sthompsa error = bridge_rtupdate(sc, req->ifba_dst, req->ifba_vlan, bif, 1, 1419146985Sthompsa req->ifba_flags); 1420146985Sthompsa 1421146985Sthompsa return (error); 1422146985Sthompsa} 1423146985Sthompsa 1424151313Sthompsastatic int 1425146985Sthompsabridge_ioctl_sto(struct bridge_softc *sc, void *arg) 1426146985Sthompsa{ 1427146985Sthompsa struct ifbrparam *param = arg; 1428146985Sthompsa 1429146985Sthompsa sc->sc_brttimeout = param->ifbrp_ctime; 1430146985Sthompsa return (0); 1431146985Sthompsa} 1432146985Sthompsa 1433151313Sthompsastatic int 1434146985Sthompsabridge_ioctl_gto(struct bridge_softc *sc, void *arg) 1435146985Sthompsa{ 1436146985Sthompsa struct ifbrparam *param = arg; 1437146985Sthompsa 1438146985Sthompsa param->ifbrp_ctime = sc->sc_brttimeout; 1439146985Sthompsa return (0); 1440146985Sthompsa} 1441146985Sthompsa 1442151313Sthompsastatic int 1443146985Sthompsabridge_ioctl_daddr(struct bridge_softc *sc, void *arg) 1444146985Sthompsa{ 1445146985Sthompsa struct ifbareq *req = arg; 1446146985Sthompsa 1447170681Sthompsa return (bridge_rtdaddr(sc, req->ifba_dst, req->ifba_vlan)); 1448146985Sthompsa} 1449146985Sthompsa 1450151313Sthompsastatic int 1451146985Sthompsabridge_ioctl_flush(struct bridge_softc *sc, void *arg) 1452146985Sthompsa{ 1453146985Sthompsa struct ifbreq *req = arg; 1454146985Sthompsa 1455146985Sthompsa bridge_rtflush(sc, req->ifbr_ifsflags); 1456146985Sthompsa return (0); 1457146985Sthompsa} 1458146985Sthompsa 1459151313Sthompsastatic int 1460146985Sthompsabridge_ioctl_gpri(struct bridge_softc *sc, void *arg) 1461146985Sthompsa{ 1462146985Sthompsa struct ifbrparam *param = arg; 1463160703Sthompsa struct bstp_state *bs = &sc->sc_stp; 1464146985Sthompsa 1465160703Sthompsa param->ifbrp_prio = bs->bs_bridge_priority; 1466146985Sthompsa return (0); 1467146985Sthompsa} 1468146985Sthompsa 1469151313Sthompsastatic int 1470146985Sthompsabridge_ioctl_spri(struct bridge_softc *sc, void *arg) 1471146985Sthompsa{ 1472146985Sthompsa struct ifbrparam *param = arg; 1473146985Sthompsa 1474163863Sthompsa return (bstp_set_priority(&sc->sc_stp, param->ifbrp_prio)); 1475146985Sthompsa} 1476146985Sthompsa 1477151313Sthompsastatic int 1478146985Sthompsabridge_ioctl_ght(struct bridge_softc *sc, void *arg) 1479146985Sthompsa{ 1480146985Sthompsa struct ifbrparam *param = arg; 1481160703Sthompsa struct bstp_state *bs = &sc->sc_stp; 1482146985Sthompsa 1483163863Sthompsa param->ifbrp_hellotime = bs->bs_bridge_htime >> 8; 1484146985Sthompsa return (0); 1485146985Sthompsa} 1486146985Sthompsa 1487151313Sthompsastatic int 1488146985Sthompsabridge_ioctl_sht(struct bridge_softc *sc, void *arg) 1489146985Sthompsa{ 1490146985Sthompsa struct ifbrparam *param = arg; 1491146985Sthompsa 1492163863Sthompsa return (bstp_set_htime(&sc->sc_stp, param->ifbrp_hellotime)); 1493146985Sthompsa} 1494146985Sthompsa 1495151313Sthompsastatic int 1496146985Sthompsabridge_ioctl_gfd(struct bridge_softc *sc, void *arg) 1497146985Sthompsa{ 1498146985Sthompsa struct ifbrparam *param = arg; 1499160703Sthompsa struct bstp_state *bs = &sc->sc_stp; 1500146985Sthompsa 1501163863Sthompsa param->ifbrp_fwddelay = bs->bs_bridge_fdelay >> 8; 1502146985Sthompsa return (0); 1503146985Sthompsa} 1504146985Sthompsa 1505151313Sthompsastatic int 1506146985Sthompsabridge_ioctl_sfd(struct bridge_softc *sc, void *arg) 1507146985Sthompsa{ 1508146985Sthompsa struct ifbrparam *param = arg; 1509146985Sthompsa 1510163863Sthompsa return (bstp_set_fdelay(&sc->sc_stp, param->ifbrp_fwddelay)); 1511146985Sthompsa} 1512146985Sthompsa 1513151313Sthompsastatic int 1514146985Sthompsabridge_ioctl_gma(struct bridge_softc *sc, void *arg) 1515146985Sthompsa{ 1516146985Sthompsa struct ifbrparam *param = arg; 1517160703Sthompsa struct bstp_state *bs = &sc->sc_stp; 1518146985Sthompsa 1519160703Sthompsa param->ifbrp_maxage = bs->bs_bridge_max_age >> 8; 1520146985Sthompsa return (0); 1521146985Sthompsa} 1522146985Sthompsa 1523151313Sthompsastatic int 1524146985Sthompsabridge_ioctl_sma(struct bridge_softc *sc, void *arg) 1525146985Sthompsa{ 1526146985Sthompsa struct ifbrparam *param = arg; 1527146985Sthompsa 1528163863Sthompsa return (bstp_set_maxage(&sc->sc_stp, param->ifbrp_maxage)); 1529146985Sthompsa} 1530146985Sthompsa 1531151313Sthompsastatic int 1532146985Sthompsabridge_ioctl_sifprio(struct bridge_softc *sc, void *arg) 1533146985Sthompsa{ 1534146985Sthompsa struct ifbreq *req = arg; 1535146985Sthompsa struct bridge_iflist *bif; 1536146985Sthompsa 1537146985Sthompsa bif = bridge_lookup_member(sc, req->ifbr_ifsname); 1538146985Sthompsa if (bif == NULL) 1539146985Sthompsa return (ENOENT); 1540146985Sthompsa 1541163863Sthompsa return (bstp_set_port_priority(&bif->bif_stp, req->ifbr_priority)); 1542146985Sthompsa} 1543146985Sthompsa 1544151313Sthompsastatic int 1545146985Sthompsabridge_ioctl_sifcost(struct bridge_softc *sc, void *arg) 1546146985Sthompsa{ 1547146985Sthompsa struct ifbreq *req = arg; 1548146985Sthompsa struct bridge_iflist *bif; 1549146985Sthompsa 1550146985Sthompsa bif = bridge_lookup_member(sc, req->ifbr_ifsname); 1551146985Sthompsa if (bif == NULL) 1552146985Sthompsa return (ENOENT); 1553146985Sthompsa 1554163863Sthompsa return (bstp_set_path_cost(&bif->bif_stp, req->ifbr_path_cost)); 1555146985Sthompsa} 1556146985Sthompsa 1557153408Sthompsastatic int 1558173320Sthompsabridge_ioctl_sifmaxaddr(struct bridge_softc *sc, void *arg) 1559173320Sthompsa{ 1560173320Sthompsa struct ifbreq *req = arg; 1561173320Sthompsa struct bridge_iflist *bif; 1562173320Sthompsa 1563173320Sthompsa bif = bridge_lookup_member(sc, req->ifbr_ifsname); 1564173320Sthompsa if (bif == NULL) 1565173320Sthompsa return (ENOENT); 1566173320Sthompsa 1567173320Sthompsa bif->bif_addrmax = req->ifbr_addrmax; 1568173320Sthompsa return (0); 1569173320Sthompsa} 1570173320Sthompsa 1571173320Sthompsastatic int 1572153408Sthompsabridge_ioctl_addspan(struct bridge_softc *sc, void *arg) 1573153408Sthompsa{ 1574153408Sthompsa struct ifbreq *req = arg; 1575153408Sthompsa struct bridge_iflist *bif = NULL; 1576153408Sthompsa struct ifnet *ifs; 1577153408Sthompsa 1578153408Sthompsa ifs = ifunit(req->ifbr_ifsname); 1579153408Sthompsa if (ifs == NULL) 1580153408Sthompsa return (ENOENT); 1581153408Sthompsa 1582153408Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) 1583153408Sthompsa if (ifs == bif->bif_ifp) 1584153408Sthompsa return (EBUSY); 1585153408Sthompsa 1586153408Sthompsa if (ifs->if_bridge != NULL) 1587153408Sthompsa return (EBUSY); 1588153408Sthompsa 1589153408Sthompsa switch (ifs->if_type) { 1590153408Sthompsa case IFT_ETHER: 1591159807Sthompsa case IFT_GIF: 1592153408Sthompsa case IFT_L2VLAN: 1593153408Sthompsa break; 1594153408Sthompsa default: 1595153408Sthompsa return (EINVAL); 1596153408Sthompsa } 1597153408Sthompsa 1598153408Sthompsa bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO); 1599153408Sthompsa if (bif == NULL) 1600153408Sthompsa return (ENOMEM); 1601153408Sthompsa 1602153408Sthompsa bif->bif_ifp = ifs; 1603153408Sthompsa bif->bif_flags = IFBIF_SPAN; 1604153408Sthompsa 1605153408Sthompsa LIST_INSERT_HEAD(&sc->sc_spanlist, bif, bif_next); 1606153408Sthompsa 1607153408Sthompsa return (0); 1608153408Sthompsa} 1609153408Sthompsa 1610153408Sthompsastatic int 1611153408Sthompsabridge_ioctl_delspan(struct bridge_softc *sc, void *arg) 1612153408Sthompsa{ 1613153408Sthompsa struct ifbreq *req = arg; 1614153408Sthompsa struct bridge_iflist *bif; 1615153408Sthompsa struct ifnet *ifs; 1616153408Sthompsa 1617153408Sthompsa ifs = ifunit(req->ifbr_ifsname); 1618153408Sthompsa if (ifs == NULL) 1619153408Sthompsa return (ENOENT); 1620153408Sthompsa 1621153408Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) 1622153408Sthompsa if (ifs == bif->bif_ifp) 1623153408Sthompsa break; 1624153408Sthompsa 1625153408Sthompsa if (bif == NULL) 1626153408Sthompsa return (ENOENT); 1627153408Sthompsa 1628153494Sthompsa bridge_delete_span(sc, bif); 1629153408Sthompsa 1630153408Sthompsa return (0); 1631153408Sthompsa} 1632153408Sthompsa 1633160867Sthompsastatic int 1634160867Sthompsabridge_ioctl_gbparam(struct bridge_softc *sc, void *arg) 1635160867Sthompsa{ 1636160867Sthompsa struct ifbropreq *req = arg; 1637163863Sthompsa struct bstp_state *bs = &sc->sc_stp; 1638160867Sthompsa struct bstp_port *root_port; 1639160867Sthompsa 1640163863Sthompsa req->ifbop_maxage = bs->bs_bridge_max_age >> 8; 1641163863Sthompsa req->ifbop_hellotime = bs->bs_bridge_htime >> 8; 1642163863Sthompsa req->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8; 1643160867Sthompsa 1644163863Sthompsa root_port = bs->bs_root_port; 1645160867Sthompsa if (root_port == NULL) 1646160867Sthompsa req->ifbop_root_port = 0; 1647160867Sthompsa else 1648160867Sthompsa req->ifbop_root_port = root_port->bp_ifp->if_index; 1649160867Sthompsa 1650163863Sthompsa req->ifbop_holdcount = bs->bs_txholdcount; 1651163863Sthompsa req->ifbop_priority = bs->bs_bridge_priority; 1652163863Sthompsa req->ifbop_protocol = bs->bs_protover; 1653163863Sthompsa req->ifbop_root_path_cost = bs->bs_root_pv.pv_cost; 1654164653Sthompsa req->ifbop_bridgeid = bs->bs_bridge_pv.pv_dbridge_id; 1655163863Sthompsa req->ifbop_designated_root = bs->bs_root_pv.pv_root_id; 1656164653Sthompsa req->ifbop_designated_bridge = bs->bs_root_pv.pv_dbridge_id; 1657163863Sthompsa req->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec; 1658163863Sthompsa req->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec; 1659160867Sthompsa 1660160867Sthompsa return (0); 1661160867Sthompsa} 1662160867Sthompsa 1663160867Sthompsastatic int 1664160867Sthompsabridge_ioctl_grte(struct bridge_softc *sc, void *arg) 1665160867Sthompsa{ 1666160867Sthompsa struct ifbrparam *param = arg; 1667160867Sthompsa 1668160867Sthompsa param->ifbrp_cexceeded = sc->sc_brtexceeded; 1669160867Sthompsa return (0); 1670160867Sthompsa} 1671160867Sthompsa 1672160867Sthompsastatic int 1673160867Sthompsabridge_ioctl_gifsstp(struct bridge_softc *sc, void *arg) 1674160867Sthompsa{ 1675160867Sthompsa struct ifbpstpconf *bifstp = arg; 1676160867Sthompsa struct bridge_iflist *bif; 1677163863Sthompsa struct bstp_port *bp; 1678160867Sthompsa struct ifbpstpreq bpreq; 1679171603Sthompsa char *buf, *outbuf; 1680171603Sthompsa int count, buflen, len, error = 0; 1681160867Sthompsa 1682160867Sthompsa count = 0; 1683160867Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 1684160867Sthompsa if ((bif->bif_flags & IFBIF_STP) != 0) 1685160867Sthompsa count++; 1686160867Sthompsa } 1687160867Sthompsa 1688171603Sthompsa buflen = sizeof(bpreq) * count; 1689160867Sthompsa if (bifstp->ifbpstp_len == 0) { 1690171603Sthompsa bifstp->ifbpstp_len = buflen; 1691160867Sthompsa return (0); 1692160867Sthompsa } 1693160867Sthompsa 1694171603Sthompsa BRIDGE_UNLOCK(sc); 1695171603Sthompsa outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); 1696171603Sthompsa BRIDGE_LOCK(sc); 1697171603Sthompsa 1698160867Sthompsa count = 0; 1699171603Sthompsa buf = outbuf; 1700171603Sthompsa len = min(bifstp->ifbpstp_len, buflen); 1701160867Sthompsa bzero(&bpreq, sizeof(bpreq)); 1702160867Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 1703160867Sthompsa if (len < sizeof(bpreq)) 1704160867Sthompsa break; 1705160867Sthompsa 1706160867Sthompsa if ((bif->bif_flags & IFBIF_STP) == 0) 1707160867Sthompsa continue; 1708160867Sthompsa 1709163863Sthompsa bp = &bif->bif_stp; 1710163863Sthompsa bpreq.ifbp_portno = bif->bif_ifp->if_index & 0xfff; 1711163863Sthompsa bpreq.ifbp_fwd_trans = bp->bp_forward_transitions; 1712163863Sthompsa bpreq.ifbp_design_cost = bp->bp_desg_pv.pv_cost; 1713163863Sthompsa bpreq.ifbp_design_port = bp->bp_desg_pv.pv_port_id; 1714163863Sthompsa bpreq.ifbp_design_bridge = bp->bp_desg_pv.pv_dbridge_id; 1715163863Sthompsa bpreq.ifbp_design_root = bp->bp_desg_pv.pv_root_id; 1716160867Sthompsa 1717171603Sthompsa memcpy(buf, &bpreq, sizeof(bpreq)); 1718160867Sthompsa count++; 1719171603Sthompsa buf += sizeof(bpreq); 1720160867Sthompsa len -= sizeof(bpreq); 1721160867Sthompsa } 1722160867Sthompsa 1723171603Sthompsa BRIDGE_UNLOCK(sc); 1724160867Sthompsa bifstp->ifbpstp_len = sizeof(bpreq) * count; 1725171603Sthompsa error = copyout(outbuf, bifstp->ifbpstp_req, bifstp->ifbpstp_len); 1726171603Sthompsa BRIDGE_LOCK(sc); 1727171603Sthompsa free(outbuf, M_TEMP); 1728160867Sthompsa return (error); 1729160867Sthompsa} 1730160867Sthompsa 1731163863Sthompsastatic int 1732163863Sthompsabridge_ioctl_sproto(struct bridge_softc *sc, void *arg) 1733163863Sthompsa{ 1734163863Sthompsa struct ifbrparam *param = arg; 1735163863Sthompsa 1736163863Sthompsa return (bstp_set_protocol(&sc->sc_stp, param->ifbrp_proto)); 1737163863Sthompsa} 1738163863Sthompsa 1739163863Sthompsastatic int 1740163863Sthompsabridge_ioctl_stxhc(struct bridge_softc *sc, void *arg) 1741163863Sthompsa{ 1742163863Sthompsa struct ifbrparam *param = arg; 1743163863Sthompsa 1744163863Sthompsa return (bstp_set_holdcount(&sc->sc_stp, param->ifbrp_txhc)); 1745163863Sthompsa} 1746163863Sthompsa 1747146985Sthompsa/* 1748146985Sthompsa * bridge_ifdetach: 1749146985Sthompsa * 1750146985Sthompsa * Detach an interface from a bridge. Called when a member 1751146985Sthompsa * interface is detaching. 1752146985Sthompsa */ 1753151313Sthompsastatic void 1754153494Sthompsabridge_ifdetach(void *arg __unused, struct ifnet *ifp) 1755146985Sthompsa{ 1756146985Sthompsa struct bridge_softc *sc = ifp->if_bridge; 1757151594Sthompsa struct bridge_iflist *bif; 1758146985Sthompsa 1759248851Smarkj if (ifp->if_flags & IFF_RENAMING) 1760248851Smarkj return; 1761248851Smarkj 1762153494Sthompsa /* Check if the interface is a bridge member */ 1763153494Sthompsa if (sc != NULL) { 1764153494Sthompsa BRIDGE_LOCK(sc); 1765146985Sthompsa 1766153494Sthompsa bif = bridge_lookup_member_if(sc, ifp); 1767153494Sthompsa if (bif != NULL) 1768153494Sthompsa bridge_delete_member(sc, bif, 1); 1769153494Sthompsa 1770153494Sthompsa BRIDGE_UNLOCK(sc); 1771151594Sthompsa return; 1772153494Sthompsa } 1773146985Sthompsa 1774153494Sthompsa /* Check if the interface is a span port */ 1775153494Sthompsa mtx_lock(&bridge_list_mtx); 1776153494Sthompsa LIST_FOREACH(sc, &bridge_list, sc_list) { 1777153494Sthompsa BRIDGE_LOCK(sc); 1778153494Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) 1779153494Sthompsa if (ifp == bif->bif_ifp) { 1780153494Sthompsa bridge_delete_span(sc, bif); 1781153494Sthompsa break; 1782153494Sthompsa } 1783151594Sthompsa 1784153494Sthompsa BRIDGE_UNLOCK(sc); 1785153494Sthompsa } 1786153494Sthompsa mtx_unlock(&bridge_list_mtx); 1787146985Sthompsa} 1788146985Sthompsa 1789146985Sthompsa/* 1790146985Sthompsa * bridge_init: 1791146985Sthompsa * 1792146985Sthompsa * Initialize a bridge interface. 1793146985Sthompsa */ 1794146985Sthompsastatic void 1795146985Sthompsabridge_init(void *xsc) 1796146985Sthompsa{ 1797146985Sthompsa struct bridge_softc *sc = (struct bridge_softc *)xsc; 1798147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 1799146985Sthompsa 1800148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1801146985Sthompsa return; 1802146985Sthompsa 1803149253Sthompsa BRIDGE_LOCK(sc); 1804146985Sthompsa callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz, 1805146985Sthompsa bridge_timer, sc); 1806146985Sthompsa 1807148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1808160703Sthompsa bstp_init(&sc->sc_stp); /* Initialize Spanning Tree */ 1809160703Sthompsa 1810149064Sthompsa BRIDGE_UNLOCK(sc); 1811146985Sthompsa} 1812146985Sthompsa 1813146985Sthompsa/* 1814146985Sthompsa * bridge_stop: 1815146985Sthompsa * 1816146985Sthompsa * Stop the bridge interface. 1817146985Sthompsa */ 1818151313Sthompsastatic void 1819146985Sthompsabridge_stop(struct ifnet *ifp, int disable) 1820146985Sthompsa{ 1821146985Sthompsa struct bridge_softc *sc = ifp->if_softc; 1822146985Sthompsa 1823149064Sthompsa BRIDGE_LOCK_ASSERT(sc); 1824149064Sthompsa 1825148887Srwatson if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1826146985Sthompsa return; 1827146985Sthompsa 1828146985Sthompsa callout_stop(&sc->sc_brcallout); 1829160703Sthompsa bstp_stop(&sc->sc_stp); 1830146985Sthompsa 1831146985Sthompsa bridge_rtflush(sc, IFBF_FLUSHDYN); 1832146985Sthompsa 1833148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1834146985Sthompsa} 1835146985Sthompsa 1836146985Sthompsa/* 1837146985Sthompsa * bridge_enqueue: 1838146985Sthompsa * 1839146985Sthompsa * Enqueue a packet on a bridge member interface. 1840146985Sthompsa * 1841146985Sthompsa */ 1842240071Sglebiusstatic int 1843147786Sthompsabridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m) 1844146985Sthompsa{ 1845158140Sthompsa int len, err = 0; 1846146985Sthompsa short mflags; 1847158140Sthompsa struct mbuf *m0; 1848146985Sthompsa 1849159759Sthompsa /* We may be sending a fragment so traverse the mbuf */ 1850158140Sthompsa for (; m; m = m0) { 1851158140Sthompsa m0 = m->m_nextpkt; 1852158140Sthompsa m->m_nextpkt = NULL; 1853240971Sglebius len = m->m_pkthdr.len; 1854240971Sglebius mflags = m->m_flags; 1855172770Sthompsa 1856172770Sthompsa /* 1857172770Sthompsa * If underlying interface can not do VLAN tag insertion itself 1858172770Sthompsa * then attach a packet tag that holds it. 1859172770Sthompsa */ 1860172770Sthompsa if ((m->m_flags & M_VLANTAG) && 1861172770Sthompsa (dst_ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) { 1862172770Sthompsa m = ether_vlanencap(m, m->m_pkthdr.ether_vtag); 1863172770Sthompsa if (m == NULL) { 1864172770Sthompsa if_printf(dst_ifp, 1865172770Sthompsa "unable to prepend VLAN header\n"); 1866172770Sthompsa dst_ifp->if_oerrors++; 1867172770Sthompsa continue; 1868172770Sthompsa } 1869172770Sthompsa m->m_flags &= ~M_VLANTAG; 1870172770Sthompsa } 1871172770Sthompsa 1872306594Skp M_ASSERTPKTHDR(m); /* We shouldn't transmit mbuf without pkthdr */ 1873238355Semaste if ((err = dst_ifp->if_transmit(dst_ifp, m))) { 1874238355Semaste m_freem(m0); 1875240971Sglebius sc->sc_ifp->if_oerrors++; 1876238355Semaste break; 1877238355Semaste } 1878158140Sthompsa 1879147256Sbrooks sc->sc_ifp->if_opackets++; 1880147256Sbrooks sc->sc_ifp->if_obytes += len; 1881191603Ssam if (mflags & M_MCAST) 1882147256Sbrooks sc->sc_ifp->if_omcasts++; 1883146985Sthompsa } 1884240071Sglebius 1885240071Sglebius return (err); 1886146985Sthompsa} 1887146985Sthompsa 1888146985Sthompsa/* 1889147205Sthompsa * bridge_dummynet: 1890147205Sthompsa * 1891147205Sthompsa * Receive a queued packet from dummynet and pass it on to the output 1892147205Sthompsa * interface. 1893147205Sthompsa * 1894147205Sthompsa * The mbuf has the Ethernet header already attached. 1895147205Sthompsa */ 1896151313Sthompsastatic void 1897147205Sthompsabridge_dummynet(struct mbuf *m, struct ifnet *ifp) 1898147205Sthompsa{ 1899147205Sthompsa struct bridge_softc *sc; 1900147205Sthompsa 1901147205Sthompsa sc = ifp->if_bridge; 1902147205Sthompsa 1903147205Sthompsa /* 1904147205Sthompsa * The packet didnt originate from a member interface. This should only 1905147205Sthompsa * ever happen if a member interface is removed while packets are 1906147205Sthompsa * queued for it. 1907147205Sthompsa */ 1908147251Smlaier if (sc == NULL) { 1909147205Sthompsa m_freem(m); 1910147205Sthompsa return; 1911147251Smlaier } 1912147205Sthompsa 1913197952Sjulian if (PFIL_HOOKED(&V_inet_pfil_hook) 1914147786Sthompsa#ifdef INET6 1915197952Sjulian || PFIL_HOOKED(&V_inet6_pfil_hook) 1916147786Sthompsa#endif 1917147786Sthompsa ) { 1918147786Sthompsa if (bridge_pfil(&m, sc->sc_ifp, ifp, PFIL_OUT) != 0) 1919147786Sthompsa return; 1920147786Sthompsa if (m == NULL) 1921147786Sthompsa return; 1922147786Sthompsa } 1923147786Sthompsa 1924147786Sthompsa bridge_enqueue(sc, ifp, m); 1925147205Sthompsa} 1926147205Sthompsa 1927147205Sthompsa/* 1928146985Sthompsa * bridge_output: 1929146985Sthompsa * 1930146985Sthompsa * Send output from a bridge member interface. This 1931146985Sthompsa * performs the bridging function for locally originated 1932146985Sthompsa * packets. 1933146985Sthompsa * 1934146985Sthompsa * The mbuf has the Ethernet header already attached. We must 1935146985Sthompsa * enqueue or free the mbuf before returning. 1936146985Sthompsa */ 1937151313Sthompsastatic int 1938146985Sthompsabridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, 1939146985Sthompsa struct rtentry *rt) 1940146985Sthompsa{ 1941146985Sthompsa struct ether_header *eh; 1942146985Sthompsa struct ifnet *dst_if; 1943146985Sthompsa struct bridge_softc *sc; 1944170681Sthompsa uint16_t vlan; 1945146985Sthompsa 1946146985Sthompsa if (m->m_len < ETHER_HDR_LEN) { 1947146985Sthompsa m = m_pullup(m, ETHER_HDR_LEN); 1948146985Sthompsa if (m == NULL) 1949146985Sthompsa return (0); 1950146985Sthompsa } 1951146985Sthompsa 1952146985Sthompsa eh = mtod(m, struct ether_header *); 1953146985Sthompsa sc = ifp->if_bridge; 1954170681Sthompsa vlan = VLANTAGOF(m); 1955146985Sthompsa 1956146985Sthompsa BRIDGE_LOCK(sc); 1957146985Sthompsa 1958146985Sthompsa /* 1959146985Sthompsa * If bridge is down, but the original output interface is up, 1960146985Sthompsa * go ahead and send out that interface. Otherwise, the packet 1961146985Sthompsa * is dropped below. 1962146985Sthompsa */ 1963148887Srwatson if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1964146985Sthompsa dst_if = ifp; 1965146985Sthompsa goto sendunicast; 1966146985Sthompsa } 1967146985Sthompsa 1968146985Sthompsa /* 1969146985Sthompsa * If the packet is a multicast, or we don't know a better way to 1970146985Sthompsa * get there, send to all interfaces. 1971146985Sthompsa */ 1972146985Sthompsa if (ETHER_IS_MULTICAST(eh->ether_dhost)) 1973146985Sthompsa dst_if = NULL; 1974146985Sthompsa else 1975170681Sthompsa dst_if = bridge_rtlookup(sc, eh->ether_dhost, vlan); 1976146985Sthompsa if (dst_if == NULL) { 1977146985Sthompsa struct bridge_iflist *bif; 1978146985Sthompsa struct mbuf *mc; 1979146985Sthompsa int error = 0, used = 0; 1980146985Sthompsa 1981161401Sthompsa bridge_span(sc, m); 1982161401Sthompsa 1983146985Sthompsa BRIDGE_LOCK2REF(sc, error); 1984146985Sthompsa if (error) { 1985146985Sthompsa m_freem(m); 1986146985Sthompsa return (0); 1987146985Sthompsa } 1988153408Sthompsa 1989146985Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 1990146985Sthompsa dst_if = bif->bif_ifp; 1991153621Sthompsa 1992153621Sthompsa if (dst_if->if_type == IFT_GIF) 1993153621Sthompsa continue; 1994148887Srwatson if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) 1995146985Sthompsa continue; 1996146985Sthompsa 1997146985Sthompsa /* 1998146985Sthompsa * If this is not the original output interface, 1999146985Sthompsa * and the interface is participating in spanning 2000146985Sthompsa * tree, make sure the port is in a state that 2001146985Sthompsa * allows forwarding. 2002146985Sthompsa */ 2003163863Sthompsa if (dst_if != ifp && (bif->bif_flags & IFBIF_STP) && 2004163863Sthompsa bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) 2005163863Sthompsa continue; 2006146985Sthompsa 2007146985Sthompsa if (LIST_NEXT(bif, bif_next) == NULL) { 2008146985Sthompsa used = 1; 2009146985Sthompsa mc = m; 2010146985Sthompsa } else { 2011243882Sglebius mc = m_copypacket(m, M_NOWAIT); 2012146985Sthompsa if (mc == NULL) { 2013147256Sbrooks sc->sc_ifp->if_oerrors++; 2014146985Sthompsa continue; 2015146985Sthompsa } 2016146985Sthompsa } 2017146985Sthompsa 2018147786Sthompsa bridge_enqueue(sc, dst_if, mc); 2019146985Sthompsa } 2020146985Sthompsa if (used == 0) 2021146985Sthompsa m_freem(m); 2022146985Sthompsa BRIDGE_UNREF(sc); 2023146985Sthompsa return (0); 2024146985Sthompsa } 2025146985Sthompsa 2026153497Sthompsasendunicast: 2027146985Sthompsa /* 2028146985Sthompsa * XXX Spanning tree consideration here? 2029146985Sthompsa */ 2030146985Sthompsa 2031153408Sthompsa bridge_span(sc, m); 2032148887Srwatson if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) { 2033146985Sthompsa m_freem(m); 2034146985Sthompsa BRIDGE_UNLOCK(sc); 2035146985Sthompsa return (0); 2036146985Sthompsa } 2037146985Sthompsa 2038146985Sthompsa BRIDGE_UNLOCK(sc); 2039147786Sthompsa bridge_enqueue(sc, dst_if, m); 2040146985Sthompsa return (0); 2041146985Sthompsa} 2042146985Sthompsa 2043146985Sthompsa/* 2044240071Sglebius * bridge_transmit: 2045146985Sthompsa * 2046240071Sglebius * Do output on a bridge. 2047146985Sthompsa * 2048146985Sthompsa */ 2049240071Sglebiusstatic int 2050240071Sglebiusbridge_transmit(struct ifnet *ifp, struct mbuf *m) 2051146985Sthompsa{ 2052146985Sthompsa struct bridge_softc *sc; 2053242013Sglebius struct ether_header *eh; 2054242013Sglebius struct ifnet *dst_if; 2055240071Sglebius int error = 0; 2056146985Sthompsa 2057146985Sthompsa sc = ifp->if_softc; 2058146985Sthompsa 2059240071Sglebius ETHER_BPF_MTAP(ifp, m); 2060146985Sthompsa 2061242013Sglebius eh = mtod(m, struct ether_header *); 2062240071Sglebius 2063240071Sglebius BRIDGE_LOCK(sc); 2064242013Sglebius if (((m->m_flags & (M_BCAST|M_MCAST)) == 0) && 2065242013Sglebius (dst_if = bridge_rtlookup(sc, eh->ether_dhost, 1)) != NULL) { 2066240071Sglebius BRIDGE_UNLOCK(sc); 2067240071Sglebius error = bridge_enqueue(sc, dst_if, m); 2068240071Sglebius } else 2069240071Sglebius bridge_broadcast(sc, ifp, m, 0); 2070146985Sthompsa 2071240071Sglebius return (error); 2072240071Sglebius} 2073146985Sthompsa 2074240071Sglebius/* 2075240071Sglebius * The ifp->if_qflush entry point for if_bridge(4) is no-op. 2076240071Sglebius */ 2077240071Sglebiusstatic void 2078240071Sglebiusbridge_qflush(struct ifnet *ifp __unused) 2079240071Sglebius{ 2080146985Sthompsa} 2081146985Sthompsa 2082146985Sthompsa/* 2083146985Sthompsa * bridge_forward: 2084146985Sthompsa * 2085146985Sthompsa * The forwarding function of the bridge. 2086146985Sthompsa * 2087146985Sthompsa * NOTE: Releases the lock on return. 2088146985Sthompsa */ 2089151313Sthompsastatic void 2090171678Sthompsabridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif, 2091171678Sthompsa struct mbuf *m) 2092146985Sthompsa{ 2093171678Sthompsa struct bridge_iflist *dbif; 2094146985Sthompsa struct ifnet *src_if, *dst_if, *ifp; 2095146985Sthompsa struct ether_header *eh; 2096170681Sthompsa uint16_t vlan; 2097175419Sthompsa uint8_t *dst; 2098173320Sthompsa int error; 2099146985Sthompsa 2100146985Sthompsa src_if = m->m_pkthdr.rcvif; 2101147256Sbrooks ifp = sc->sc_ifp; 2102146985Sthompsa 2103174749Sthompsa ifp->if_ipackets++; 2104174749Sthompsa ifp->if_ibytes += m->m_pkthdr.len; 2105170681Sthompsa vlan = VLANTAGOF(m); 2106146985Sthompsa 2107171678Sthompsa if ((sbif->bif_flags & IFBIF_STP) && 2108174749Sthompsa sbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) 2109174749Sthompsa goto drop; 2110146985Sthompsa 2111146985Sthompsa eh = mtod(m, struct ether_header *); 2112175419Sthompsa dst = eh->ether_dhost; 2113146985Sthompsa 2114173320Sthompsa /* If the interface is learning, record the address. */ 2115173320Sthompsa if (sbif->bif_flags & IFBIF_LEARNING) { 2116173320Sthompsa error = bridge_rtupdate(sc, eh->ether_shost, vlan, 2117171678Sthompsa sbif, 0, IFBAF_DYNAMIC); 2118173320Sthompsa /* 2119173320Sthompsa * If the interface has addresses limits then deny any source 2120173320Sthompsa * that is not in the cache. 2121173320Sthompsa */ 2122174749Sthompsa if (error && sbif->bif_addrmax) 2123174749Sthompsa goto drop; 2124146985Sthompsa } 2125146985Sthompsa 2126171678Sthompsa if ((sbif->bif_flags & IFBIF_STP) != 0 && 2127174749Sthompsa sbif->bif_stp.bp_state == BSTP_IFSTATE_LEARNING) 2128174749Sthompsa goto drop; 2129146985Sthompsa 2130146985Sthompsa /* 2131146985Sthompsa * At this point, the port either doesn't participate 2132146985Sthompsa * in spanning tree or it is in the forwarding state. 2133146985Sthompsa */ 2134146985Sthompsa 2135146985Sthompsa /* 2136146985Sthompsa * If the packet is unicast, destined for someone on 2137146985Sthompsa * "this" side of the bridge, drop it. 2138146985Sthompsa */ 2139146985Sthompsa if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) { 2140175419Sthompsa dst_if = bridge_rtlookup(sc, dst, vlan); 2141174749Sthompsa if (src_if == dst_if) 2142174749Sthompsa goto drop; 2143146985Sthompsa } else { 2144175419Sthompsa /* 2145175419Sthompsa * Check if its a reserved multicast address, any address 2146175419Sthompsa * listed in 802.1D section 7.12.6 may not be forwarded by the 2147175419Sthompsa * bridge. 2148175419Sthompsa * This is currently 01-80-C2-00-00-00 to 01-80-C2-00-00-0F 2149175419Sthompsa */ 2150175419Sthompsa if (dst[0] == 0x01 && dst[1] == 0x80 && 2151175419Sthompsa dst[2] == 0xc2 && dst[3] == 0x00 && 2152175419Sthompsa dst[4] == 0x00 && dst[5] <= 0x0f) 2153175419Sthompsa goto drop; 2154175419Sthompsa 2155146985Sthompsa /* ...forward it to all interfaces. */ 2156174749Sthompsa ifp->if_imcasts++; 2157146985Sthompsa dst_if = NULL; 2158146985Sthompsa } 2159146985Sthompsa 2160156235Scsjp /* 2161156235Scsjp * If we have a destination interface which is a member of our bridge, 2162156235Scsjp * OR this is a unicast packet, push it through the bpf(4) machinery. 2163156235Scsjp * For broadcast or multicast packets, don't bother because it will 2164156235Scsjp * be reinjected into ether_input. We do this before we pass the packets 2165156235Scsjp * through the pfil(9) framework, as it is possible that pfil(9) will 2166156235Scsjp * drop the packet, or possibly modify it, making it difficult to debug 2167156235Scsjp * firewall issues on the bridge. 2168156235Scsjp */ 2169156235Scsjp if (dst_if != NULL || (m->m_flags & (M_BCAST | M_MCAST)) == 0) 2170172824Sthompsa ETHER_BPF_MTAP(ifp, m); 2171156235Scsjp 2172146985Sthompsa /* run the packet filter */ 2173197952Sjulian if (PFIL_HOOKED(&V_inet_pfil_hook) 2174147786Sthompsa#ifdef INET6 2175197952Sjulian || PFIL_HOOKED(&V_inet6_pfil_hook) 2176147786Sthompsa#endif 2177147786Sthompsa ) { 2178146985Sthompsa BRIDGE_UNLOCK(sc); 2179146985Sthompsa if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0) 2180146985Sthompsa return; 2181147786Sthompsa if (m == NULL) 2182147786Sthompsa return; 2183146985Sthompsa BRIDGE_LOCK(sc); 2184146985Sthompsa } 2185146985Sthompsa 2186146985Sthompsa if (dst_if == NULL) { 2187150837Sthompsa bridge_broadcast(sc, src_if, m, 1); 2188146985Sthompsa return; 2189146985Sthompsa } 2190146985Sthompsa 2191146985Sthompsa /* 2192146985Sthompsa * At this point, we're dealing with a unicast frame 2193146985Sthompsa * going to a different interface. 2194146985Sthompsa */ 2195174749Sthompsa if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) 2196174749Sthompsa goto drop; 2197174749Sthompsa 2198171678Sthompsa dbif = bridge_lookup_member_if(sc, dst_if); 2199174749Sthompsa if (dbif == NULL) 2200146985Sthompsa /* Not a member of the bridge (anymore?) */ 2201174749Sthompsa goto drop; 2202146985Sthompsa 2203171678Sthompsa /* Private segments can not talk to each other */ 2204174749Sthompsa if (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE) 2205174749Sthompsa goto drop; 2206146985Sthompsa 2207171678Sthompsa if ((dbif->bif_flags & IFBIF_STP) && 2208174749Sthompsa dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) 2209174749Sthompsa goto drop; 2210171678Sthompsa 2211146985Sthompsa BRIDGE_UNLOCK(sc); 2212147786Sthompsa 2213197952Sjulian if (PFIL_HOOKED(&V_inet_pfil_hook) 2214147786Sthompsa#ifdef INET6 2215197952Sjulian || PFIL_HOOKED(&V_inet6_pfil_hook) 2216147786Sthompsa#endif 2217147786Sthompsa ) { 2218174749Sthompsa if (bridge_pfil(&m, ifp, dst_if, PFIL_OUT) != 0) 2219147786Sthompsa return; 2220147786Sthompsa if (m == NULL) 2221147786Sthompsa return; 2222147786Sthompsa } 2223147786Sthompsa 2224147786Sthompsa bridge_enqueue(sc, dst_if, m); 2225174749Sthompsa return; 2226174749Sthompsa 2227174749Sthompsadrop: 2228174749Sthompsa BRIDGE_UNLOCK(sc); 2229174749Sthompsa m_freem(m); 2230146985Sthompsa} 2231146985Sthompsa 2232146985Sthompsa/* 2233146985Sthompsa * bridge_input: 2234146985Sthompsa * 2235146985Sthompsa * Receive input from a member interface. Queue the packet for 2236146985Sthompsa * bridging if it is not for us. 2237146985Sthompsa */ 2238151345Sthompsastatic struct mbuf * 2239146985Sthompsabridge_input(struct ifnet *ifp, struct mbuf *m) 2240146985Sthompsa{ 2241146985Sthompsa struct bridge_softc *sc = ifp->if_bridge; 2242164112Sthompsa struct bridge_iflist *bif, *bif2; 2243149829Sthompsa struct ifnet *bifp; 2244146985Sthompsa struct ether_header *eh; 2245149829Sthompsa struct mbuf *mc, *mc2; 2246170681Sthompsa uint16_t vlan; 2247173320Sthompsa int error; 2248146985Sthompsa 2249148887Srwatson if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 2250146985Sthompsa return (m); 2251146985Sthompsa 2252149829Sthompsa bifp = sc->sc_ifp; 2253170681Sthompsa vlan = VLANTAGOF(m); 2254149829Sthompsa 2255156235Scsjp /* 2256156235Scsjp * Implement support for bridge monitoring. If this flag has been 2257156235Scsjp * set on this interface, discard the packet once we push it through 2258156235Scsjp * the bpf(4) machinery, but before we do, increment the byte and 2259156235Scsjp * packet counters associated with this interface. 2260156235Scsjp */ 2261156235Scsjp if ((bifp->if_flags & IFF_MONITOR) != 0) { 2262156235Scsjp m->m_pkthdr.rcvif = bifp; 2263172824Sthompsa ETHER_BPF_MTAP(bifp, m); 2264156235Scsjp bifp->if_ipackets++; 2265156235Scsjp bifp->if_ibytes += m->m_pkthdr.len; 2266164002Scsjp m_freem(m); 2267156235Scsjp return (NULL); 2268156235Scsjp } 2269146985Sthompsa BRIDGE_LOCK(sc); 2270146985Sthompsa bif = bridge_lookup_member_if(sc, ifp); 2271146985Sthompsa if (bif == NULL) { 2272146985Sthompsa BRIDGE_UNLOCK(sc); 2273146985Sthompsa return (m); 2274146985Sthompsa } 2275146985Sthompsa 2276146985Sthompsa eh = mtod(m, struct ether_header *); 2277146985Sthompsa 2278153408Sthompsa bridge_span(sc, m); 2279153408Sthompsa 2280167722Sthompsa if (m->m_flags & (M_BCAST|M_MCAST)) { 2281146985Sthompsa /* Tap off 802.1D packets; they do not get forwarded. */ 2282146985Sthompsa if (memcmp(eh->ether_dhost, bstp_etheraddr, 2283146985Sthompsa ETHER_ADDR_LEN) == 0) { 2284232014Sthompsa bstp_input(&bif->bif_stp, ifp, m); /* consumes mbuf */ 2285232014Sthompsa BRIDGE_UNLOCK(sc); 2286232014Sthompsa return (NULL); 2287146985Sthompsa } 2288146985Sthompsa 2289163863Sthompsa if ((bif->bif_flags & IFBIF_STP) && 2290163863Sthompsa bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { 2291163863Sthompsa BRIDGE_UNLOCK(sc); 2292163863Sthompsa return (m); 2293146985Sthompsa } 2294146985Sthompsa 2295146985Sthompsa /* 2296146985Sthompsa * Make a deep copy of the packet and enqueue the copy 2297146985Sthompsa * for bridge processing; return the original packet for 2298146985Sthompsa * local processing. 2299146985Sthompsa */ 2300243882Sglebius mc = m_dup(m, M_NOWAIT); 2301146985Sthompsa if (mc == NULL) { 2302146985Sthompsa BRIDGE_UNLOCK(sc); 2303146985Sthompsa return (m); 2304146985Sthompsa } 2305146985Sthompsa 2306146985Sthompsa /* Perform the bridge forwarding function with the copy. */ 2307171678Sthompsa bridge_forward(sc, bif, mc); 2308146985Sthompsa 2309149829Sthompsa /* 2310149829Sthompsa * Reinject the mbuf as arriving on the bridge so we have a 2311149829Sthompsa * chance at claiming multicast packets. We can not loop back 2312149829Sthompsa * here from ether_input as a bridge is never a member of a 2313149829Sthompsa * bridge. 2314149829Sthompsa */ 2315149829Sthompsa KASSERT(bifp->if_bridge == NULL, 2316149829Sthompsa ("loop created in bridge_input")); 2317243882Sglebius mc2 = m_dup(m, M_NOWAIT); 2318149829Sthompsa if (mc2 != NULL) { 2319153458Sthompsa /* Keep the layer3 header aligned */ 2320153458Sthompsa int i = min(mc2->m_pkthdr.len, max_protohdr); 2321153458Sthompsa mc2 = m_copyup(mc2, i, ETHER_ALIGN); 2322153458Sthompsa } 2323153458Sthompsa if (mc2 != NULL) { 2324149829Sthompsa mc2->m_pkthdr.rcvif = bifp; 2325149829Sthompsa (*bifp->if_input)(bifp, mc2); 2326149829Sthompsa } 2327149829Sthompsa 2328146985Sthompsa /* Return the original packet for local processing. */ 2329146985Sthompsa return (m); 2330146985Sthompsa } 2331146985Sthompsa 2332163863Sthompsa if ((bif->bif_flags & IFBIF_STP) && 2333163863Sthompsa bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { 2334163863Sthompsa BRIDGE_UNLOCK(sc); 2335163863Sthompsa return (m); 2336146985Sthompsa } 2337146985Sthompsa 2338211157Swill#if (defined(INET) || defined(INET6)) 2339167683Srik# define OR_CARP_CHECK_WE_ARE_DST(iface) \ 2340167683Srik || ((iface)->if_carp \ 2341211193Swill && (*carp_forus_p)((iface), eh->ether_dhost)) 2342167683Srik# define OR_CARP_CHECK_WE_ARE_SRC(iface) \ 2343167683Srik || ((iface)->if_carp \ 2344211193Swill && (*carp_forus_p)((iface), eh->ether_shost)) 2345167683Srik#else 2346167683Srik# define OR_CARP_CHECK_WE_ARE_DST(iface) 2347167683Srik# define OR_CARP_CHECK_WE_ARE_SRC(iface) 2348167683Srik#endif 2349167683Srik 2350175432Sthompsa#ifdef INET6 2351175432Sthompsa# define OR_PFIL_HOOKED_INET6 \ 2352197952Sjulian || PFIL_HOOKED(&V_inet6_pfil_hook) 2353175432Sthompsa#else 2354175432Sthompsa# define OR_PFIL_HOOKED_INET6 2355175432Sthompsa#endif 2356175432Sthompsa 2357167683Srik#define GRAB_OUR_PACKETS(iface) \ 2358167683Srik if ((iface)->if_type == IFT_GIF) \ 2359167683Srik continue; \ 2360167683Srik /* It is destined for us. */ \ 2361167683Srik if (memcmp(IF_LLADDR((iface)), eh->ether_dhost, ETHER_ADDR_LEN) == 0 \ 2362167683Srik OR_CARP_CHECK_WE_ARE_DST((iface)) \ 2363167683Srik ) { \ 2364175432Sthompsa if ((iface)->if_type == IFT_BRIDGE) { \ 2365175432Sthompsa ETHER_BPF_MTAP(iface, m); \ 2366175432Sthompsa iface->if_ipackets++; \ 2367240971Sglebius iface->if_ibytes += m->m_pkthdr.len; \ 2368175432Sthompsa /* Filter on the physical interface. */ \ 2369175432Sthompsa if (pfil_local_phys && \ 2370197952Sjulian (PFIL_HOOKED(&V_inet_pfil_hook) \ 2371175432Sthompsa OR_PFIL_HOOKED_INET6)) { \ 2372175432Sthompsa if (bridge_pfil(&m, NULL, ifp, \ 2373175432Sthompsa PFIL_IN) != 0 || m == NULL) { \ 2374175432Sthompsa BRIDGE_UNLOCK(sc); \ 2375175432Sthompsa return (NULL); \ 2376175432Sthompsa } \ 2377248155Sglebius eh = mtod(m, struct ether_header *); \ 2378175432Sthompsa } \ 2379175432Sthompsa } \ 2380173320Sthompsa if (bif->bif_flags & IFBIF_LEARNING) { \ 2381173320Sthompsa error = bridge_rtupdate(sc, eh->ether_shost, \ 2382170681Sthompsa vlan, bif, 0, IFBAF_DYNAMIC); \ 2383173320Sthompsa if (error && bif->bif_addrmax) { \ 2384173320Sthompsa BRIDGE_UNLOCK(sc); \ 2385173320Sthompsa m_freem(m); \ 2386173320Sthompsa return (NULL); \ 2387173320Sthompsa } \ 2388173320Sthompsa } \ 2389167683Srik m->m_pkthdr.rcvif = iface; \ 2390167683Srik BRIDGE_UNLOCK(sc); \ 2391167683Srik return (m); \ 2392167683Srik } \ 2393167683Srik \ 2394167683Srik /* We just received a packet that we sent out. */ \ 2395167683Srik if (memcmp(IF_LLADDR((iface)), eh->ether_shost, ETHER_ADDR_LEN) == 0 \ 2396167683Srik OR_CARP_CHECK_WE_ARE_SRC((iface)) \ 2397167683Srik ) { \ 2398167683Srik BRIDGE_UNLOCK(sc); \ 2399167683Srik m_freem(m); \ 2400167683Srik return (NULL); \ 2401167683Srik } 2402167683Srik 2403146985Sthompsa /* 2404175432Sthompsa * Unicast. Make sure it's not for the bridge. 2405175432Sthompsa */ 2406175432Sthompsa do { GRAB_OUR_PACKETS(bifp) } while (0); 2407175432Sthompsa 2408175432Sthompsa /* 2409167683Srik * Give a chance for ifp at first priority. This will help when the 2410167683Srik * packet comes through the interface like VLAN's with the same MACs 2411167683Srik * on several interfaces from the same bridge. This also will save 2412167683Srik * some CPU cycles in case the destination interface and the input 2413167683Srik * interface (eq ifp) are the same. 2414146985Sthompsa */ 2415167683Srik do { GRAB_OUR_PACKETS(ifp) } while (0); 2416167683Srik 2417167683Srik /* Now check the all bridge members. */ 2418164112Sthompsa LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) { 2419167683Srik GRAB_OUR_PACKETS(bif2->bif_ifp) 2420146985Sthompsa } 2421146985Sthompsa 2422167683Srik#undef OR_CARP_CHECK_WE_ARE_DST 2423167683Srik#undef OR_CARP_CHECK_WE_ARE_SRC 2424175432Sthompsa#undef OR_PFIL_HOOKED_INET6 2425167683Srik#undef GRAB_OUR_PACKETS 2426167683Srik 2427146985Sthompsa /* Perform the bridge forwarding function. */ 2428171678Sthompsa bridge_forward(sc, bif, m); 2429146985Sthompsa 2430146985Sthompsa return (NULL); 2431146985Sthompsa} 2432146985Sthompsa 2433146985Sthompsa/* 2434146985Sthompsa * bridge_broadcast: 2435146985Sthompsa * 2436146985Sthompsa * Send a frame to all interfaces that are members of 2437146985Sthompsa * the bridge, except for the one on which the packet 2438146985Sthompsa * arrived. 2439146985Sthompsa * 2440146985Sthompsa * NOTE: Releases the lock on return. 2441146985Sthompsa */ 2442151313Sthompsastatic void 2443146985Sthompsabridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, 2444150837Sthompsa struct mbuf *m, int runfilt) 2445146985Sthompsa{ 2446171678Sthompsa struct bridge_iflist *dbif, *sbif; 2447146985Sthompsa struct mbuf *mc; 2448146985Sthompsa struct ifnet *dst_if; 2449157057Srik int error = 0, used = 0, i; 2450146985Sthompsa 2451171678Sthompsa sbif = bridge_lookup_member_if(sc, src_if); 2452171678Sthompsa 2453146985Sthompsa BRIDGE_LOCK2REF(sc, error); 2454146985Sthompsa if (error) { 2455146985Sthompsa m_freem(m); 2456146985Sthompsa return; 2457146985Sthompsa } 2458146985Sthompsa 2459147786Sthompsa /* Filter on the bridge interface before broadcasting */ 2460197952Sjulian if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook) 2461147786Sthompsa#ifdef INET6 2462197952Sjulian || PFIL_HOOKED(&V_inet6_pfil_hook) 2463147786Sthompsa#endif 2464150837Sthompsa )) { 2465147786Sthompsa if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0) 2466152393Sthompsa goto out; 2467147786Sthompsa if (m == NULL) 2468152393Sthompsa goto out; 2469147786Sthompsa } 2470147786Sthompsa 2471171678Sthompsa LIST_FOREACH(dbif, &sc->sc_iflist, bif_next) { 2472171678Sthompsa dst_if = dbif->bif_ifp; 2473146985Sthompsa if (dst_if == src_if) 2474146985Sthompsa continue; 2475146985Sthompsa 2476171678Sthompsa /* Private segments can not talk to each other */ 2477171678Sthompsa if (sbif && (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE)) 2478163863Sthompsa continue; 2479146985Sthompsa 2480171678Sthompsa if ((dbif->bif_flags & IFBIF_STP) && 2481171678Sthompsa dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) 2482171678Sthompsa continue; 2483171678Sthompsa 2484171678Sthompsa if ((dbif->bif_flags & IFBIF_DISCOVER) == 0 && 2485146985Sthompsa (m->m_flags & (M_BCAST|M_MCAST)) == 0) 2486146985Sthompsa continue; 2487146985Sthompsa 2488148887Srwatson if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) 2489146985Sthompsa continue; 2490146985Sthompsa 2491171678Sthompsa if (LIST_NEXT(dbif, bif_next) == NULL) { 2492146985Sthompsa mc = m; 2493146985Sthompsa used = 1; 2494146985Sthompsa } else { 2495243882Sglebius mc = m_dup(m, M_NOWAIT); 2496146985Sthompsa if (mc == NULL) { 2497147256Sbrooks sc->sc_ifp->if_oerrors++; 2498146985Sthompsa continue; 2499146985Sthompsa } 2500146985Sthompsa } 2501146985Sthompsa 2502147786Sthompsa /* 2503147786Sthompsa * Filter on the output interface. Pass a NULL bridge interface 2504153497Sthompsa * pointer so we do not redundantly filter on the bridge for 2505147786Sthompsa * each interface we broadcast on. 2506147786Sthompsa */ 2507197952Sjulian if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook) 2508147786Sthompsa#ifdef INET6 2509197952Sjulian || PFIL_HOOKED(&V_inet6_pfil_hook) 2510147786Sthompsa#endif 2511150837Sthompsa )) { 2512157057Srik if (used == 0) { 2513157057Srik /* Keep the layer3 header aligned */ 2514157057Srik i = min(mc->m_pkthdr.len, max_protohdr); 2515157057Srik mc = m_copyup(mc, i, ETHER_ALIGN); 2516157057Srik if (mc == NULL) { 2517157057Srik sc->sc_ifp->if_oerrors++; 2518157057Srik continue; 2519157057Srik } 2520157057Srik } 2521152392Sthompsa if (bridge_pfil(&mc, NULL, dst_if, PFIL_OUT) != 0) 2522152392Sthompsa continue; 2523152392Sthompsa if (mc == NULL) 2524152392Sthompsa continue; 2525147786Sthompsa } 2526151305Sthompsa 2527147786Sthompsa bridge_enqueue(sc, dst_if, mc); 2528146985Sthompsa } 2529146985Sthompsa if (used == 0) 2530146985Sthompsa m_freem(m); 2531146985Sthompsa 2532152393Sthompsaout: 2533146985Sthompsa BRIDGE_UNREF(sc); 2534146985Sthompsa} 2535146985Sthompsa 2536146985Sthompsa/* 2537153408Sthompsa * bridge_span: 2538153408Sthompsa * 2539153408Sthompsa * Duplicate a packet out one or more interfaces that are in span mode, 2540153408Sthompsa * the original mbuf is unmodified. 2541153408Sthompsa */ 2542153408Sthompsastatic void 2543153408Sthompsabridge_span(struct bridge_softc *sc, struct mbuf *m) 2544153408Sthompsa{ 2545153408Sthompsa struct bridge_iflist *bif; 2546153408Sthompsa struct ifnet *dst_if; 2547153408Sthompsa struct mbuf *mc; 2548153408Sthompsa 2549153408Sthompsa if (LIST_EMPTY(&sc->sc_spanlist)) 2550153408Sthompsa return; 2551153408Sthompsa 2552153408Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) { 2553153408Sthompsa dst_if = bif->bif_ifp; 2554158667Sthompsa 2555153408Sthompsa if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) 2556153408Sthompsa continue; 2557153408Sthompsa 2558243882Sglebius mc = m_copypacket(m, M_NOWAIT); 2559153408Sthompsa if (mc == NULL) { 2560153408Sthompsa sc->sc_ifp->if_oerrors++; 2561153408Sthompsa continue; 2562153408Sthompsa } 2563153408Sthompsa 2564153408Sthompsa bridge_enqueue(sc, dst_if, mc); 2565153408Sthompsa } 2566153408Sthompsa} 2567153408Sthompsa 2568153408Sthompsa/* 2569146985Sthompsa * bridge_rtupdate: 2570146985Sthompsa * 2571146985Sthompsa * Add a bridge routing entry. 2572146985Sthompsa */ 2573151313Sthompsastatic int 2574170681Sthompsabridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan, 2575164112Sthompsa struct bridge_iflist *bif, int setflags, uint8_t flags) 2576146985Sthompsa{ 2577146985Sthompsa struct bridge_rtnode *brt; 2578146985Sthompsa int error; 2579146985Sthompsa 2580146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2581146985Sthompsa 2582173320Sthompsa /* Check the source address is valid and not multicast. */ 2583173320Sthompsa if (ETHER_IS_MULTICAST(dst) || 2584173320Sthompsa (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 && 2585173320Sthompsa dst[3] == 0 && dst[4] == 0 && dst[5] == 0) != 0) 2586173320Sthompsa return (EINVAL); 2587173320Sthompsa 2588170681Sthompsa /* 802.1p frames map to vlan 1 */ 2589170681Sthompsa if (vlan == 0) 2590170681Sthompsa vlan = 1; 2591170681Sthompsa 2592146985Sthompsa /* 2593146985Sthompsa * A route for this destination might already exist. If so, 2594146985Sthompsa * update it, otherwise create a new one. 2595146985Sthompsa */ 2596170681Sthompsa if ((brt = bridge_rtnode_lookup(sc, dst, vlan)) == NULL) { 2597160867Sthompsa if (sc->sc_brtcnt >= sc->sc_brtmax) { 2598160867Sthompsa sc->sc_brtexceeded++; 2599146985Sthompsa return (ENOSPC); 2600160867Sthompsa } 2601173320Sthompsa /* Check per interface address limits (if enabled) */ 2602173320Sthompsa if (bif->bif_addrmax && bif->bif_addrcnt >= bif->bif_addrmax) { 2603173320Sthompsa bif->bif_addrexceeded++; 2604173320Sthompsa return (ENOSPC); 2605173320Sthompsa } 2606146985Sthompsa 2607146985Sthompsa /* 2608146985Sthompsa * Allocate a new bridge forwarding node, and 2609146985Sthompsa * initialize the expiration time and Ethernet 2610146985Sthompsa * address. 2611146985Sthompsa */ 2612146985Sthompsa brt = uma_zalloc(bridge_rtnode_zone, M_NOWAIT | M_ZERO); 2613146985Sthompsa if (brt == NULL) 2614146985Sthompsa return (ENOMEM); 2615146985Sthompsa 2616164112Sthompsa if (bif->bif_flags & IFBIF_STICKY) 2617164112Sthompsa brt->brt_flags = IFBAF_STICKY; 2618164112Sthompsa else 2619164112Sthompsa brt->brt_flags = IFBAF_DYNAMIC; 2620164112Sthompsa 2621146985Sthompsa memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN); 2622170681Sthompsa brt->brt_vlan = vlan; 2623146985Sthompsa 2624146985Sthompsa if ((error = bridge_rtnode_insert(sc, brt)) != 0) { 2625146985Sthompsa uma_zfree(bridge_rtnode_zone, brt); 2626146985Sthompsa return (error); 2627146985Sthompsa } 2628173320Sthompsa brt->brt_dst = bif; 2629173320Sthompsa bif->bif_addrcnt++; 2630146985Sthompsa } 2631146985Sthompsa 2632173320Sthompsa if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && 2633173320Sthompsa brt->brt_dst != bif) { 2634173320Sthompsa brt->brt_dst->bif_addrcnt--; 2635173320Sthompsa brt->brt_dst = bif; 2636173320Sthompsa brt->brt_dst->bif_addrcnt++; 2637173320Sthompsa } 2638173320Sthompsa 2639153979Sthompsa if ((flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) 2640153978Sthompsa brt->brt_expire = time_uptime + sc->sc_brttimeout; 2641153977Sthompsa if (setflags) 2642146985Sthompsa brt->brt_flags = flags; 2643146985Sthompsa 2644146985Sthompsa return (0); 2645146985Sthompsa} 2646146985Sthompsa 2647146985Sthompsa/* 2648146985Sthompsa * bridge_rtlookup: 2649146985Sthompsa * 2650146985Sthompsa * Lookup the destination interface for an address. 2651146985Sthompsa */ 2652151345Sthompsastatic struct ifnet * 2653170681Sthompsabridge_rtlookup(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan) 2654146985Sthompsa{ 2655146985Sthompsa struct bridge_rtnode *brt; 2656146985Sthompsa 2657146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2658146985Sthompsa 2659170681Sthompsa if ((brt = bridge_rtnode_lookup(sc, addr, vlan)) == NULL) 2660146985Sthompsa return (NULL); 2661146985Sthompsa 2662146985Sthompsa return (brt->brt_ifp); 2663146985Sthompsa} 2664146985Sthompsa 2665146985Sthompsa/* 2666146985Sthompsa * bridge_rttrim: 2667146985Sthompsa * 2668146985Sthompsa * Trim the routine table so that we have a number 2669146985Sthompsa * of routing entries less than or equal to the 2670146985Sthompsa * maximum number. 2671146985Sthompsa */ 2672151313Sthompsastatic void 2673146985Sthompsabridge_rttrim(struct bridge_softc *sc) 2674146985Sthompsa{ 2675146985Sthompsa struct bridge_rtnode *brt, *nbrt; 2676146985Sthompsa 2677146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2678146985Sthompsa 2679146985Sthompsa /* Make sure we actually need to do this. */ 2680146985Sthompsa if (sc->sc_brtcnt <= sc->sc_brtmax) 2681146985Sthompsa return; 2682146985Sthompsa 2683146985Sthompsa /* Force an aging cycle; this might trim enough addresses. */ 2684146985Sthompsa bridge_rtage(sc); 2685146985Sthompsa if (sc->sc_brtcnt <= sc->sc_brtmax) 2686146985Sthompsa return; 2687146985Sthompsa 2688163142Sthompsa LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { 2689146985Sthompsa if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { 2690146985Sthompsa bridge_rtnode_destroy(sc, brt); 2691146985Sthompsa if (sc->sc_brtcnt <= sc->sc_brtmax) 2692146985Sthompsa return; 2693146985Sthompsa } 2694146985Sthompsa } 2695146985Sthompsa} 2696146985Sthompsa 2697146985Sthompsa/* 2698146985Sthompsa * bridge_timer: 2699146985Sthompsa * 2700146985Sthompsa * Aging timer for the bridge. 2701146985Sthompsa */ 2702151313Sthompsastatic void 2703146985Sthompsabridge_timer(void *arg) 2704146985Sthompsa{ 2705146985Sthompsa struct bridge_softc *sc = arg; 2706146985Sthompsa 2707149253Sthompsa BRIDGE_LOCK_ASSERT(sc); 2708149253Sthompsa 2709146985Sthompsa bridge_rtage(sc); 2710146985Sthompsa 2711148887Srwatson if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) 2712146985Sthompsa callout_reset(&sc->sc_brcallout, 2713146985Sthompsa bridge_rtable_prune_period * hz, bridge_timer, sc); 2714146985Sthompsa} 2715146985Sthompsa 2716146985Sthompsa/* 2717146985Sthompsa * bridge_rtage: 2718146985Sthompsa * 2719146985Sthompsa * Perform an aging cycle. 2720146985Sthompsa */ 2721151313Sthompsastatic void 2722146985Sthompsabridge_rtage(struct bridge_softc *sc) 2723146985Sthompsa{ 2724146985Sthompsa struct bridge_rtnode *brt, *nbrt; 2725146985Sthompsa 2726146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2727146985Sthompsa 2728163142Sthompsa LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { 2729146985Sthompsa if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { 2730153976Sthompsa if (time_uptime >= brt->brt_expire) 2731146985Sthompsa bridge_rtnode_destroy(sc, brt); 2732146985Sthompsa } 2733146985Sthompsa } 2734146985Sthompsa} 2735146985Sthompsa 2736146985Sthompsa/* 2737146985Sthompsa * bridge_rtflush: 2738146985Sthompsa * 2739146985Sthompsa * Remove all dynamic addresses from the bridge. 2740146985Sthompsa */ 2741151313Sthompsastatic void 2742146985Sthompsabridge_rtflush(struct bridge_softc *sc, int full) 2743146985Sthompsa{ 2744146985Sthompsa struct bridge_rtnode *brt, *nbrt; 2745146985Sthompsa 2746146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2747146985Sthompsa 2748163142Sthompsa LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { 2749146985Sthompsa if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) 2750146985Sthompsa bridge_rtnode_destroy(sc, brt); 2751146985Sthompsa } 2752146985Sthompsa} 2753146985Sthompsa 2754146985Sthompsa/* 2755146985Sthompsa * bridge_rtdaddr: 2756146985Sthompsa * 2757146985Sthompsa * Remove an address from the table. 2758146985Sthompsa */ 2759151313Sthompsastatic int 2760170681Sthompsabridge_rtdaddr(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan) 2761146985Sthompsa{ 2762146985Sthompsa struct bridge_rtnode *brt; 2763170681Sthompsa int found = 0; 2764146985Sthompsa 2765146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2766146985Sthompsa 2767170681Sthompsa /* 2768170681Sthompsa * If vlan is zero then we want to delete for all vlans so the lookup 2769170681Sthompsa * may return more than one. 2770170681Sthompsa */ 2771170681Sthompsa while ((brt = bridge_rtnode_lookup(sc, addr, vlan)) != NULL) { 2772170681Sthompsa bridge_rtnode_destroy(sc, brt); 2773170681Sthompsa found = 1; 2774170681Sthompsa } 2775146985Sthompsa 2776170681Sthompsa return (found ? 0 : ENOENT); 2777146985Sthompsa} 2778146985Sthompsa 2779146985Sthompsa/* 2780146985Sthompsa * bridge_rtdelete: 2781146985Sthompsa * 2782146985Sthompsa * Delete routes to a speicifc member interface. 2783146985Sthompsa */ 2784160769Sthompsastatic void 2785146985Sthompsabridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int full) 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) { 2792153497Sthompsa if (brt->brt_ifp == ifp && (full || 2793146985Sthompsa (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)) 2794146985Sthompsa bridge_rtnode_destroy(sc, brt); 2795146985Sthompsa } 2796146985Sthompsa} 2797146985Sthompsa 2798146985Sthompsa/* 2799146985Sthompsa * bridge_rtable_init: 2800146985Sthompsa * 2801146985Sthompsa * Initialize the route table for this bridge. 2802146985Sthompsa */ 2803241183Sthompsastatic void 2804146985Sthompsabridge_rtable_init(struct bridge_softc *sc) 2805146985Sthompsa{ 2806146985Sthompsa int i; 2807146985Sthompsa 2808146985Sthompsa sc->sc_rthash = malloc(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE, 2809241183Sthompsa M_DEVBUF, M_WAITOK); 2810146985Sthompsa 2811146985Sthompsa for (i = 0; i < BRIDGE_RTHASH_SIZE; i++) 2812146985Sthompsa LIST_INIT(&sc->sc_rthash[i]); 2813146985Sthompsa 2814146985Sthompsa sc->sc_rthash_key = arc4random(); 2815146985Sthompsa LIST_INIT(&sc->sc_rtlist); 2816146985Sthompsa} 2817146985Sthompsa 2818146985Sthompsa/* 2819146985Sthompsa * bridge_rtable_fini: 2820146985Sthompsa * 2821146985Sthompsa * Deconstruct the route table for this bridge. 2822146985Sthompsa */ 2823151313Sthompsastatic void 2824146985Sthompsabridge_rtable_fini(struct bridge_softc *sc) 2825146985Sthompsa{ 2826146985Sthompsa 2827173320Sthompsa KASSERT(sc->sc_brtcnt == 0, 2828173320Sthompsa ("%s: %d bridge routes referenced", __func__, sc->sc_brtcnt)); 2829146985Sthompsa free(sc->sc_rthash, M_DEVBUF); 2830146985Sthompsa} 2831146985Sthompsa 2832146985Sthompsa/* 2833146985Sthompsa * The following hash function is adapted from "Hash Functions" by Bob Jenkins 2834146985Sthompsa * ("Algorithm Alley", Dr. Dobbs Journal, September 1997). 2835146985Sthompsa */ 2836146985Sthompsa#define mix(a, b, c) \ 2837146985Sthompsado { \ 2838146985Sthompsa a -= b; a -= c; a ^= (c >> 13); \ 2839146985Sthompsa b -= c; b -= a; b ^= (a << 8); \ 2840146985Sthompsa c -= a; c -= b; c ^= (b >> 13); \ 2841146985Sthompsa a -= b; a -= c; a ^= (c >> 12); \ 2842146985Sthompsa b -= c; b -= a; b ^= (a << 16); \ 2843146985Sthompsa c -= a; c -= b; c ^= (b >> 5); \ 2844146985Sthompsa a -= b; a -= c; a ^= (c >> 3); \ 2845146985Sthompsa b -= c; b -= a; b ^= (a << 10); \ 2846146985Sthompsa c -= a; c -= b; c ^= (b >> 15); \ 2847146985Sthompsa} while (/*CONSTCOND*/0) 2848146985Sthompsa 2849146985Sthompsastatic __inline uint32_t 2850146985Sthompsabridge_rthash(struct bridge_softc *sc, const uint8_t *addr) 2851146985Sthompsa{ 2852146985Sthompsa uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_rthash_key; 2853146985Sthompsa 2854146985Sthompsa b += addr[5] << 8; 2855146985Sthompsa b += addr[4]; 2856146985Sthompsa a += addr[3] << 24; 2857146985Sthompsa a += addr[2] << 16; 2858146985Sthompsa a += addr[1] << 8; 2859146985Sthompsa a += addr[0]; 2860146985Sthompsa 2861146985Sthompsa mix(a, b, c); 2862146985Sthompsa 2863146985Sthompsa return (c & BRIDGE_RTHASH_MASK); 2864146985Sthompsa} 2865146985Sthompsa 2866146985Sthompsa#undef mix 2867146985Sthompsa 2868155143Sthompsastatic int 2869155143Sthompsabridge_rtnode_addr_cmp(const uint8_t *a, const uint8_t *b) 2870155143Sthompsa{ 2871155143Sthompsa int i, d; 2872155143Sthompsa 2873155143Sthompsa for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) { 2874155143Sthompsa d = ((int)a[i]) - ((int)b[i]); 2875155143Sthompsa } 2876155143Sthompsa 2877155143Sthompsa return (d); 2878155143Sthompsa} 2879155143Sthompsa 2880146985Sthompsa/* 2881146985Sthompsa * bridge_rtnode_lookup: 2882146985Sthompsa * 2883170681Sthompsa * Look up a bridge route node for the specified destination. Compare the 2884170681Sthompsa * vlan id or if zero then just return the first match. 2885146985Sthompsa */ 2886151345Sthompsastatic struct bridge_rtnode * 2887170681Sthompsabridge_rtnode_lookup(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan) 2888146985Sthompsa{ 2889146985Sthompsa struct bridge_rtnode *brt; 2890146985Sthompsa uint32_t hash; 2891146985Sthompsa int dir; 2892146985Sthompsa 2893146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2894146985Sthompsa 2895146985Sthompsa hash = bridge_rthash(sc, addr); 2896146985Sthompsa LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) { 2897155143Sthompsa dir = bridge_rtnode_addr_cmp(addr, brt->brt_addr); 2898170681Sthompsa if (dir == 0 && (brt->brt_vlan == vlan || vlan == 0)) 2899146985Sthompsa return (brt); 2900146985Sthompsa if (dir > 0) 2901146985Sthompsa return (NULL); 2902146985Sthompsa } 2903146985Sthompsa 2904146985Sthompsa return (NULL); 2905146985Sthompsa} 2906146985Sthompsa 2907146985Sthompsa/* 2908146985Sthompsa * bridge_rtnode_insert: 2909146985Sthompsa * 2910146985Sthompsa * Insert the specified bridge node into the route table. We 2911146985Sthompsa * assume the entry is not already in the table. 2912146985Sthompsa */ 2913151313Sthompsastatic int 2914146985Sthompsabridge_rtnode_insert(struct bridge_softc *sc, struct bridge_rtnode *brt) 2915146985Sthompsa{ 2916146985Sthompsa struct bridge_rtnode *lbrt; 2917146985Sthompsa uint32_t hash; 2918146985Sthompsa int dir; 2919146985Sthompsa 2920146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2921146985Sthompsa 2922146985Sthompsa hash = bridge_rthash(sc, brt->brt_addr); 2923146985Sthompsa 2924146985Sthompsa lbrt = LIST_FIRST(&sc->sc_rthash[hash]); 2925146985Sthompsa if (lbrt == NULL) { 2926146985Sthompsa LIST_INSERT_HEAD(&sc->sc_rthash[hash], brt, brt_hash); 2927146985Sthompsa goto out; 2928146985Sthompsa } 2929146985Sthompsa 2930146985Sthompsa do { 2931155143Sthompsa dir = bridge_rtnode_addr_cmp(brt->brt_addr, lbrt->brt_addr); 2932170681Sthompsa if (dir == 0 && brt->brt_vlan == lbrt->brt_vlan) 2933146985Sthompsa return (EEXIST); 2934146985Sthompsa if (dir > 0) { 2935146985Sthompsa LIST_INSERT_BEFORE(lbrt, brt, brt_hash); 2936146985Sthompsa goto out; 2937146985Sthompsa } 2938146985Sthompsa if (LIST_NEXT(lbrt, brt_hash) == NULL) { 2939146985Sthompsa LIST_INSERT_AFTER(lbrt, brt, brt_hash); 2940146985Sthompsa goto out; 2941146985Sthompsa } 2942146985Sthompsa lbrt = LIST_NEXT(lbrt, brt_hash); 2943146985Sthompsa } while (lbrt != NULL); 2944146985Sthompsa 2945146985Sthompsa#ifdef DIAGNOSTIC 2946146985Sthompsa panic("bridge_rtnode_insert: impossible"); 2947146985Sthompsa#endif 2948146985Sthompsa 2949153497Sthompsaout: 2950146985Sthompsa LIST_INSERT_HEAD(&sc->sc_rtlist, brt, brt_list); 2951146985Sthompsa sc->sc_brtcnt++; 2952146985Sthompsa 2953146985Sthompsa return (0); 2954146985Sthompsa} 2955146985Sthompsa 2956146985Sthompsa/* 2957146985Sthompsa * bridge_rtnode_destroy: 2958146985Sthompsa * 2959146985Sthompsa * Destroy a bridge rtnode. 2960146985Sthompsa */ 2961151313Sthompsastatic void 2962146985Sthompsabridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt) 2963146985Sthompsa{ 2964146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2965146985Sthompsa 2966146985Sthompsa LIST_REMOVE(brt, brt_hash); 2967146985Sthompsa 2968146985Sthompsa LIST_REMOVE(brt, brt_list); 2969146985Sthompsa sc->sc_brtcnt--; 2970173320Sthompsa brt->brt_dst->bif_addrcnt--; 2971146985Sthompsa uma_zfree(bridge_rtnode_zone, brt); 2972146985Sthompsa} 2973146985Sthompsa 2974146985Sthompsa/* 2975163863Sthompsa * bridge_rtable_expire: 2976163863Sthompsa * 2977163863Sthompsa * Set the expiry time for all routes on an interface. 2978163863Sthompsa */ 2979163863Sthompsastatic void 2980163863Sthompsabridge_rtable_expire(struct ifnet *ifp, int age) 2981163863Sthompsa{ 2982163863Sthompsa struct bridge_softc *sc = ifp->if_bridge; 2983163863Sthompsa struct bridge_rtnode *brt; 2984163863Sthompsa 2985163863Sthompsa BRIDGE_LOCK(sc); 2986163863Sthompsa 2987163863Sthompsa /* 2988163863Sthompsa * If the age is zero then flush, otherwise set all the expiry times to 2989163863Sthompsa * age for the interface 2990163863Sthompsa */ 2991163863Sthompsa if (age == 0) 2992163863Sthompsa bridge_rtdelete(sc, ifp, IFBF_FLUSHDYN); 2993163863Sthompsa else { 2994163863Sthompsa LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { 2995163863Sthompsa /* Cap the expiry time to 'age' */ 2996163863Sthompsa if (brt->brt_ifp == ifp && 2997163863Sthompsa brt->brt_expire > time_uptime + age && 2998163863Sthompsa (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) 2999163863Sthompsa brt->brt_expire = time_uptime + age; 3000163863Sthompsa } 3001163863Sthompsa } 3002163863Sthompsa BRIDGE_UNLOCK(sc); 3003163863Sthompsa} 3004163863Sthompsa 3005163863Sthompsa/* 3006160902Sthompsa * bridge_state_change: 3007160902Sthompsa * 3008160902Sthompsa * Callback from the bridgestp code when a port changes states. 3009160902Sthompsa */ 3010160902Sthompsastatic void 3011160902Sthompsabridge_state_change(struct ifnet *ifp, int state) 3012160902Sthompsa{ 3013160902Sthompsa struct bridge_softc *sc = ifp->if_bridge; 3014160902Sthompsa static const char *stpstates[] = { 3015160902Sthompsa "disabled", 3016160902Sthompsa "listening", 3017160902Sthompsa "learning", 3018160902Sthompsa "forwarding", 3019160902Sthompsa "blocking", 3020163863Sthompsa "discarding" 3021160902Sthompsa }; 3022160902Sthompsa 3023160902Sthompsa if (log_stp) 3024160902Sthompsa log(LOG_NOTICE, "%s: state changed to %s on %s\n", 3025160902Sthompsa sc->sc_ifp->if_xname, stpstates[state], ifp->if_xname); 3026160902Sthompsa} 3027160902Sthompsa 3028160902Sthompsa/* 3029146985Sthompsa * Send bridge packets through pfil if they are one of the types pfil can deal 3030146985Sthompsa * with, or if they are ARP or REVARP. (pfil will pass ARP and REVARP without 3031147786Sthompsa * question.) If *bifp or *ifp are NULL then packet filtering is skipped for 3032147786Sthompsa * that interface. 3033146985Sthompsa */ 3034153497Sthompsastatic int 3035153497Sthompsabridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) 3036146985Sthompsa{ 3037158592Sdhartmei int snap, error, i, hlen; 3038146985Sthompsa struct ether_header *eh1, eh2; 3039146985Sthompsa struct ip *ip; 3040147665Sthompsa struct llc llc1; 3041146985Sthompsa u_int16_t ether_type; 3042146985Sthompsa 3043146985Sthompsa snap = 0; 3044146985Sthompsa error = -1; /* Default error if not error == 0 */ 3045147111Sthompsa 3046170139Sthompsa#if 0 3047157155Sthompsa /* we may return with the IP fields swapped, ensure its not shared */ 3048157155Sthompsa KASSERT(M_WRITABLE(*mp), ("%s: modifying a shared mbuf", __func__)); 3049170139Sthompsa#endif 3050157155Sthompsa 3051153831Sthompsa if (pfil_bridge == 0 && pfil_member == 0 && pfil_ipfw == 0) 3052158667Sthompsa return (0); /* filtering is disabled */ 3053153831Sthompsa 3054147111Sthompsa i = min((*mp)->m_pkthdr.len, max_protohdr); 3055147111Sthompsa if ((*mp)->m_len < i) { 3056147111Sthompsa *mp = m_pullup(*mp, i); 3057147111Sthompsa if (*mp == NULL) { 3058147111Sthompsa printf("%s: m_pullup failed\n", __func__); 3059158667Sthompsa return (-1); 3060147111Sthompsa } 3061147111Sthompsa } 3062147111Sthompsa 3063146985Sthompsa eh1 = mtod(*mp, struct ether_header *); 3064146985Sthompsa ether_type = ntohs(eh1->ether_type); 3065146985Sthompsa 3066146985Sthompsa /* 3067146985Sthompsa * Check for SNAP/LLC. 3068146985Sthompsa */ 3069146985Sthompsa if (ether_type < ETHERMTU) { 3070147665Sthompsa struct llc *llc2 = (struct llc *)(eh1 + 1); 3071146985Sthompsa 3072146985Sthompsa if ((*mp)->m_len >= ETHER_HDR_LEN + 8 && 3073147665Sthompsa llc2->llc_dsap == LLC_SNAP_LSAP && 3074147665Sthompsa llc2->llc_ssap == LLC_SNAP_LSAP && 3075147665Sthompsa llc2->llc_control == LLC_UI) { 3076147665Sthompsa ether_type = htons(llc2->llc_un.type_snap.ether_type); 3077146985Sthompsa snap = 1; 3078146985Sthompsa } 3079146985Sthompsa } 3080146985Sthompsa 3081162561Sthompsa /* 3082162561Sthompsa * If we're trying to filter bridge traffic, don't look at anything 3083162561Sthompsa * other than IP and ARP traffic. If the filter doesn't understand 3084162561Sthompsa * IPv6, don't allow IPv6 through the bridge either. This is lame 3085162561Sthompsa * since if we really wanted, say, an AppleTalk filter, we are hosed, 3086162561Sthompsa * but of course we don't have an AppleTalk filter to begin with. 3087162561Sthompsa * (Note that since pfil doesn't understand ARP it will pass *ALL* 3088162561Sthompsa * ARP traffic.) 3089162561Sthompsa */ 3090162561Sthompsa switch (ether_type) { 3091162561Sthompsa case ETHERTYPE_ARP: 3092162561Sthompsa case ETHERTYPE_REVARP: 3093162561Sthompsa if (pfil_ipfw_arp == 0) 3094162561Sthompsa return (0); /* Automatically pass */ 3095162561Sthompsa break; 3096162561Sthompsa 3097162561Sthompsa case ETHERTYPE_IP: 3098162561Sthompsa#ifdef INET6 3099162561Sthompsa case ETHERTYPE_IPV6: 3100162561Sthompsa#endif /* INET6 */ 3101162561Sthompsa break; 3102162561Sthompsa default: 3103162561Sthompsa /* 3104162561Sthompsa * Check to see if the user wants to pass non-ip 3105162561Sthompsa * packets, these will not be checked by pfil(9) and 3106162561Sthompsa * passed unconditionally so the default is to drop. 3107162561Sthompsa */ 3108162561Sthompsa if (pfil_onlyip) 3109162561Sthompsa goto bad; 3110162561Sthompsa } 3111162561Sthompsa 3112240099Smelifaro /* Run the packet through pfil before stripping link headers */ 3113240099Smelifaro if (PFIL_HOOKED(&V_link_pfil_hook) && pfil_ipfw != 0 && 3114240099Smelifaro dir == PFIL_OUT && ifp != NULL) { 3115240099Smelifaro 3116240099Smelifaro error = pfil_run_hooks(&V_link_pfil_hook, mp, ifp, dir, NULL); 3117240099Smelifaro 3118240099Smelifaro if (*mp == NULL || error != 0) /* packet consumed by filter */ 3119240099Smelifaro return (error); 3120240099Smelifaro } 3121240099Smelifaro 3122146985Sthompsa /* Strip off the Ethernet header and keep a copy. */ 3123146985Sthompsa m_copydata(*mp, 0, ETHER_HDR_LEN, (caddr_t) &eh2); 3124146985Sthompsa m_adj(*mp, ETHER_HDR_LEN); 3125146985Sthompsa 3126146985Sthompsa /* Strip off snap header, if present */ 3127146985Sthompsa if (snap) { 3128147665Sthompsa m_copydata(*mp, 0, sizeof(struct llc), (caddr_t) &llc1); 3129146985Sthompsa m_adj(*mp, sizeof(struct llc)); 3130146985Sthompsa } 3131146985Sthompsa 3132147744Sthompsa /* 3133147744Sthompsa * Check the IP header for alignment and errors 3134147744Sthompsa */ 3135147744Sthompsa if (dir == PFIL_IN) { 3136147744Sthompsa switch (ether_type) { 3137147744Sthompsa case ETHERTYPE_IP: 3138147744Sthompsa error = bridge_ip_checkbasic(mp); 3139147744Sthompsa break; 3140158667Sthompsa#ifdef INET6 3141147744Sthompsa case ETHERTYPE_IPV6: 3142147744Sthompsa error = bridge_ip6_checkbasic(mp); 3143147744Sthompsa break; 3144158667Sthompsa#endif /* INET6 */ 3145147744Sthompsa default: 3146147744Sthompsa error = 0; 3147147744Sthompsa } 3148147744Sthompsa if (error) 3149147744Sthompsa goto bad; 3150147744Sthompsa } 3151147744Sthompsa 3152147744Sthompsa error = 0; 3153147744Sthompsa 3154146985Sthompsa /* 3155162561Sthompsa * Run the packet through pfil 3156146985Sthompsa */ 3157158667Sthompsa switch (ether_type) { 3158158667Sthompsa case ETHERTYPE_IP: 3159146985Sthompsa /* 3160146985Sthompsa * Run pfil on the member interface and the bridge, both can 3161146985Sthompsa * be skipped by clearing pfil_member or pfil_bridge. 3162146985Sthompsa * 3163146985Sthompsa * Keep the order: 3164146985Sthompsa * in_if -> bridge_if -> out_if 3165146985Sthompsa */ 3166147786Sthompsa if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) 3167197952Sjulian error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp, 3168146985Sthompsa dir, NULL); 3169146985Sthompsa 3170147744Sthompsa if (*mp == NULL || error != 0) /* filter may consume */ 3171147205Sthompsa break; 3172147205Sthompsa 3173147786Sthompsa if (pfil_member && ifp != NULL) 3174197952Sjulian error = pfil_run_hooks(&V_inet_pfil_hook, mp, ifp, 3175146985Sthompsa dir, NULL); 3176146985Sthompsa 3177147744Sthompsa if (*mp == NULL || error != 0) /* filter may consume */ 3178147205Sthompsa break; 3179147205Sthompsa 3180147786Sthompsa if (pfil_bridge && dir == PFIL_IN && bifp != NULL) 3181197952Sjulian error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp, 3182146985Sthompsa dir, NULL); 3183146985Sthompsa 3184158140Sthompsa if (*mp == NULL || error != 0) /* filter may consume */ 3185158140Sthompsa break; 3186158140Sthompsa 3187158140Sthompsa /* check if we need to fragment the packet */ 3188306594Skp /* bridge_fragment generates a mbuf chain of packets */ 3189306594Skp /* that already include eth headers */ 3190158140Sthompsa if (pfil_member && ifp != NULL && dir == PFIL_OUT) { 3191158140Sthompsa i = (*mp)->m_pkthdr.len; 3192158140Sthompsa if (i > ifp->if_mtu) { 3193306594Skp error = bridge_fragment(ifp, mp, &eh2, snap, 3194158140Sthompsa &llc1); 3195158140Sthompsa return (error); 3196158140Sthompsa } 3197146985Sthompsa } 3198146985Sthompsa 3199241245Sglebius /* Recalculate the ip checksum. */ 3200158140Sthompsa ip = mtod(*mp, struct ip *); 3201158592Sdhartmei hlen = ip->ip_hl << 2; 3202158667Sthompsa if (hlen < sizeof(struct ip)) 3203158667Sthompsa goto bad; 3204158667Sthompsa if (hlen > (*mp)->m_len) { 3205158667Sthompsa if ((*mp = m_pullup(*mp, hlen)) == 0) 3206158667Sthompsa goto bad; 3207158667Sthompsa ip = mtod(*mp, struct ip *); 3208158667Sthompsa if (ip == NULL) 3209158667Sthompsa goto bad; 3210158667Sthompsa } 3211158667Sthompsa ip->ip_sum = 0; 3212158667Sthompsa if (hlen == sizeof(struct ip)) 3213158667Sthompsa ip->ip_sum = in_cksum_hdr(ip); 3214158667Sthompsa else 3215158667Sthompsa ip->ip_sum = in_cksum(*mp, hlen); 3216158140Sthompsa 3217146985Sthompsa break; 3218158667Sthompsa#ifdef INET6 3219158667Sthompsa case ETHERTYPE_IPV6: 3220147786Sthompsa if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) 3221197952Sjulian error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp, 3222147040Sthompsa dir, NULL); 3223147040Sthompsa 3224147744Sthompsa if (*mp == NULL || error != 0) /* filter may consume */ 3225147205Sthompsa break; 3226147205Sthompsa 3227147786Sthompsa if (pfil_member && ifp != NULL) 3228197952Sjulian error = pfil_run_hooks(&V_inet6_pfil_hook, mp, ifp, 3229146985Sthompsa dir, NULL); 3230147040Sthompsa 3231147744Sthompsa if (*mp == NULL || error != 0) /* filter may consume */ 3232147205Sthompsa break; 3233147205Sthompsa 3234147786Sthompsa if (pfil_bridge && dir == PFIL_IN && bifp != NULL) 3235197952Sjulian error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp, 3236147040Sthompsa dir, NULL); 3237146985Sthompsa break; 3238158667Sthompsa#endif 3239158667Sthompsa default: 3240162561Sthompsa error = 0; 3241146985Sthompsa break; 3242146985Sthompsa } 3243146985Sthompsa 3244146985Sthompsa if (*mp == NULL) 3245158667Sthompsa return (error); 3246146985Sthompsa if (error != 0) 3247146985Sthompsa goto bad; 3248146985Sthompsa 3249146985Sthompsa error = -1; 3250146985Sthompsa 3251146985Sthompsa /* 3252146985Sthompsa * Finally, put everything back the way it was and return 3253146985Sthompsa */ 3254146985Sthompsa if (snap) { 3255243882Sglebius M_PREPEND(*mp, sizeof(struct llc), M_NOWAIT); 3256146985Sthompsa if (*mp == NULL) 3257158667Sthompsa return (error); 3258147665Sthompsa bcopy(&llc1, mtod(*mp, caddr_t), sizeof(struct llc)); 3259146985Sthompsa } 3260146985Sthompsa 3261243882Sglebius M_PREPEND(*mp, ETHER_HDR_LEN, M_NOWAIT); 3262146985Sthompsa if (*mp == NULL) 3263158667Sthompsa return (error); 3264146985Sthompsa bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN); 3265146985Sthompsa 3266158667Sthompsa return (0); 3267146985Sthompsa 3268153497Sthompsabad: 3269146985Sthompsa m_freem(*mp); 3270146985Sthompsa *mp = NULL; 3271158667Sthompsa return (error); 3272146985Sthompsa} 3273146985Sthompsa 3274146985Sthompsa/* 3275146985Sthompsa * Perform basic checks on header size since 3276146985Sthompsa * pfil assumes ip_input has already processed 3277146985Sthompsa * it for it. Cut-and-pasted from ip_input.c. 3278146985Sthompsa * Given how simple the IPv6 version is, 3279146985Sthompsa * does the IPv4 version really need to be 3280146985Sthompsa * this complicated? 3281146985Sthompsa * 3282146985Sthompsa * XXX Should we update ipstat here, or not? 3283146985Sthompsa * XXX Right now we update ipstat but not 3284146985Sthompsa * XXX csum_counter. 3285146985Sthompsa */ 3286146985Sthompsastatic int 3287146985Sthompsabridge_ip_checkbasic(struct mbuf **mp) 3288146985Sthompsa{ 3289146985Sthompsa struct mbuf *m = *mp; 3290146985Sthompsa struct ip *ip; 3291146985Sthompsa int len, hlen; 3292146985Sthompsa u_short sum; 3293146985Sthompsa 3294146985Sthompsa if (*mp == NULL) 3295158667Sthompsa return (-1); 3296146985Sthompsa 3297147744Sthompsa if (IP_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) { 3298147744Sthompsa if ((m = m_copyup(m, sizeof(struct ip), 3299147744Sthompsa (max_linkhdr + 3) & ~3)) == NULL) { 3300147744Sthompsa /* XXXJRT new stat, please */ 3301196039Srwatson KMOD_IPSTAT_INC(ips_toosmall); 3302147744Sthompsa goto bad; 3303147744Sthompsa } 3304147744Sthompsa } else if (__predict_false(m->m_len < sizeof (struct ip))) { 3305146985Sthompsa if ((m = m_pullup(m, sizeof (struct ip))) == NULL) { 3306196039Srwatson KMOD_IPSTAT_INC(ips_toosmall); 3307146985Sthompsa goto bad; 3308146985Sthompsa } 3309146985Sthompsa } 3310146985Sthompsa ip = mtod(m, struct ip *); 3311146985Sthompsa if (ip == NULL) goto bad; 3312146985Sthompsa 3313146985Sthompsa if (ip->ip_v != IPVERSION) { 3314196039Srwatson KMOD_IPSTAT_INC(ips_badvers); 3315146985Sthompsa goto bad; 3316146985Sthompsa } 3317146985Sthompsa hlen = ip->ip_hl << 2; 3318146985Sthompsa if (hlen < sizeof(struct ip)) { /* minimum header length */ 3319196039Srwatson KMOD_IPSTAT_INC(ips_badhlen); 3320146985Sthompsa goto bad; 3321146985Sthompsa } 3322146985Sthompsa if (hlen > m->m_len) { 3323146985Sthompsa if ((m = m_pullup(m, hlen)) == 0) { 3324196039Srwatson KMOD_IPSTAT_INC(ips_badhlen); 3325146985Sthompsa goto bad; 3326146985Sthompsa } 3327146985Sthompsa ip = mtod(m, struct ip *); 3328146985Sthompsa if (ip == NULL) goto bad; 3329146985Sthompsa } 3330146985Sthompsa 3331146985Sthompsa if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { 3332146985Sthompsa sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); 3333146985Sthompsa } else { 3334146985Sthompsa if (hlen == sizeof(struct ip)) { 3335146985Sthompsa sum = in_cksum_hdr(ip); 3336146985Sthompsa } else { 3337146985Sthompsa sum = in_cksum(m, hlen); 3338146985Sthompsa } 3339146985Sthompsa } 3340146985Sthompsa if (sum) { 3341196039Srwatson KMOD_IPSTAT_INC(ips_badsum); 3342146985Sthompsa goto bad; 3343146985Sthompsa } 3344146985Sthompsa 3345146985Sthompsa /* Retrieve the packet length. */ 3346146985Sthompsa len = ntohs(ip->ip_len); 3347146985Sthompsa 3348146985Sthompsa /* 3349146985Sthompsa * Check for additional length bogosity 3350146985Sthompsa */ 3351146985Sthompsa if (len < hlen) { 3352196039Srwatson KMOD_IPSTAT_INC(ips_badlen); 3353146985Sthompsa goto bad; 3354146985Sthompsa } 3355146985Sthompsa 3356146985Sthompsa /* 3357146985Sthompsa * Check that the amount of data in the buffers 3358146985Sthompsa * is as at least much as the IP header would have us expect. 3359146985Sthompsa * Drop packet if shorter than we expect. 3360146985Sthompsa */ 3361146985Sthompsa if (m->m_pkthdr.len < len) { 3362196039Srwatson KMOD_IPSTAT_INC(ips_tooshort); 3363146985Sthompsa goto bad; 3364146985Sthompsa } 3365146985Sthompsa 3366146985Sthompsa /* Checks out, proceed */ 3367146985Sthompsa *mp = m; 3368158667Sthompsa return (0); 3369146985Sthompsa 3370153497Sthompsabad: 3371146985Sthompsa *mp = m; 3372158667Sthompsa return (-1); 3373146985Sthompsa} 3374146985Sthompsa 3375158667Sthompsa#ifdef INET6 3376146985Sthompsa/* 3377146985Sthompsa * Same as above, but for IPv6. 3378146985Sthompsa * Cut-and-pasted from ip6_input.c. 3379146985Sthompsa * XXX Should we update ip6stat, or not? 3380146985Sthompsa */ 3381146985Sthompsastatic int 3382146985Sthompsabridge_ip6_checkbasic(struct mbuf **mp) 3383146985Sthompsa{ 3384146985Sthompsa struct mbuf *m = *mp; 3385146985Sthompsa struct ip6_hdr *ip6; 3386146985Sthompsa 3387146985Sthompsa /* 3388146985Sthompsa * If the IPv6 header is not aligned, slurp it up into a new 3389146985Sthompsa * mbuf with space for link headers, in the event we forward 3390146985Sthompsa * it. Otherwise, if it is aligned, make sure the entire base 3391146985Sthompsa * IPv6 header is in the first mbuf of the chain. 3392147744Sthompsa */ 3393146985Sthompsa if (IP6_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) { 3394146985Sthompsa struct ifnet *inifp = m->m_pkthdr.rcvif; 3395146985Sthompsa if ((m = m_copyup(m, sizeof(struct ip6_hdr), 3396146985Sthompsa (max_linkhdr + 3) & ~3)) == NULL) { 3397147744Sthompsa /* XXXJRT new stat, please */ 3398249294Sae IP6STAT_INC(ip6s_toosmall); 3399146985Sthompsa in6_ifstat_inc(inifp, ifs6_in_hdrerr); 3400146985Sthompsa goto bad; 3401146985Sthompsa } 3402147744Sthompsa } else if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) { 3403146985Sthompsa struct ifnet *inifp = m->m_pkthdr.rcvif; 3404146985Sthompsa if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { 3405249294Sae IP6STAT_INC(ip6s_toosmall); 3406146985Sthompsa in6_ifstat_inc(inifp, ifs6_in_hdrerr); 3407146985Sthompsa goto bad; 3408146985Sthompsa } 3409146985Sthompsa } 3410146985Sthompsa 3411146985Sthompsa ip6 = mtod(m, struct ip6_hdr *); 3412146985Sthompsa 3413146985Sthompsa if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { 3414249294Sae IP6STAT_INC(ip6s_badvers); 3415146985Sthompsa in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); 3416146985Sthompsa goto bad; 3417146985Sthompsa } 3418146985Sthompsa 3419146985Sthompsa /* Checks out, proceed */ 3420146985Sthompsa *mp = m; 3421158667Sthompsa return (0); 3422146985Sthompsa 3423153497Sthompsabad: 3424146985Sthompsa *mp = m; 3425158667Sthompsa return (-1); 3426146985Sthompsa} 3427158667Sthompsa#endif /* INET6 */ 3428158140Sthompsa 3429158140Sthompsa/* 3430158140Sthompsa * bridge_fragment: 3431158140Sthompsa * 3432306594Skp * Fragment mbuf chain in multiple packets and prepend ethernet header. 3433158140Sthompsa */ 3434158140Sthompsastatic int 3435306594Skpbridge_fragment(struct ifnet *ifp, struct mbuf **mp, struct ether_header *eh, 3436158140Sthompsa int snap, struct llc *llc) 3437158140Sthompsa{ 3438306594Skp struct mbuf *m = *mp, *nextpkt = NULL, *mprev = NULL, *mcur = NULL; 3439158140Sthompsa struct ip *ip; 3440158140Sthompsa int error = -1; 3441158140Sthompsa 3442158140Sthompsa if (m->m_len < sizeof(struct ip) && 3443158140Sthompsa (m = m_pullup(m, sizeof(struct ip))) == NULL) 3444306594Skp goto dropit; 3445158140Sthompsa ip = mtod(m, struct ip *); 3446158140Sthompsa 3447242161Sglebius m->m_pkthdr.csum_flags |= CSUM_IP; 3448242161Sglebius error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist); 3449158140Sthompsa if (error) 3450306594Skp goto dropit; 3451158140Sthompsa 3452306594Skp /* 3453306594Skp * Walk the chain and re-add the Ethernet header for 3454306594Skp * each mbuf packet. 3455306594Skp */ 3456306594Skp for (mcur = m; mcur; mcur = mcur->m_nextpkt) { 3457306594Skp nextpkt = mcur->m_nextpkt; 3458306594Skp mcur->m_nextpkt = NULL; 3459306594Skp if (snap) { 3460306594Skp M_PREPEND(mcur, sizeof(struct llc), M_NOWAIT); 3461306594Skp if (mcur == NULL) { 3462158140Sthompsa error = ENOBUFS; 3463306594Skp if (mprev != NULL) 3464306594Skp mprev->m_nextpkt = nextpkt; 3465306594Skp goto dropit; 3466158140Sthompsa } 3467306594Skp bcopy(llc, mtod(mcur, caddr_t),sizeof(struct llc)); 3468306594Skp } 3469306594Skp 3470306594Skp M_PREPEND(mcur, ETHER_HDR_LEN, M_NOWAIT); 3471306594Skp if (mcur == NULL) { 3472306594Skp error = ENOBUFS; 3473306594Skp if (mprev != NULL) 3474306594Skp mprev->m_nextpkt = nextpkt; 3475306594Skp goto dropit; 3476306594Skp } 3477306594Skp bcopy(eh, mtod(mcur, caddr_t), ETHER_HDR_LEN); 3478306594Skp 3479306594Skp /* 3480306594Skp * The previous two M_PREPEND could have inserted one or two 3481306594Skp * mbufs in front so we have to update the previous packet's 3482306594Skp * m_nextpkt. 3483306594Skp */ 3484306594Skp mcur->m_nextpkt = nextpkt; 3485306594Skp if (mprev != NULL) 3486306594Skp mprev->m_nextpkt = mcur; 3487306594Skp else { 3488306594Skp /* The first mbuf in the original chain needs to be 3489306594Skp * updated. */ 3490306594Skp *mp = mcur; 3491306594Skp } 3492306594Skp mprev = mcur; 3493158140Sthompsa } 3494158140Sthompsa 3495306594Skp KMOD_IPSTAT_INC(ips_fragmented); 3496158140Sthompsa return (error); 3497158140Sthompsa 3498306594Skpdropit: 3499306594Skp for (mcur = *mp; mcur; mcur = m) { /* droping the full packet chain */ 3500306594Skp m = mcur->m_nextpkt; 3501306594Skp m_freem(mcur); 3502306594Skp } 3503158140Sthompsa return (error); 3504158140Sthompsa} 3505234487Sthompsa 3506234487Sthompsastatic void 3507234487Sthompsabridge_linkstate(struct ifnet *ifp) 3508234487Sthompsa{ 3509234487Sthompsa struct bridge_softc *sc = ifp->if_bridge; 3510236916Sthompsa struct bridge_iflist *bif; 3511234487Sthompsa 3512234487Sthompsa BRIDGE_LOCK(sc); 3513234487Sthompsa bif = bridge_lookup_member_if(sc, ifp); 3514234487Sthompsa if (bif == NULL) { 3515234487Sthompsa BRIDGE_UNLOCK(sc); 3516234487Sthompsa return; 3517234487Sthompsa } 3518236916Sthompsa bridge_linkcheck(sc); 3519236916Sthompsa BRIDGE_UNLOCK(sc); 3520236916Sthompsa 3521236916Sthompsa bstp_linkstate(&bif->bif_stp); 3522236916Sthompsa} 3523236916Sthompsa 3524236916Sthompsastatic void 3525236916Sthompsabridge_linkcheck(struct bridge_softc *sc) 3526236916Sthompsa{ 3527236916Sthompsa struct bridge_iflist *bif; 3528236916Sthompsa int new_link, hasls; 3529236916Sthompsa 3530236916Sthompsa BRIDGE_LOCK_ASSERT(sc); 3531234487Sthompsa new_link = LINK_STATE_DOWN; 3532234487Sthompsa hasls = 0; 3533234487Sthompsa /* Our link is considered up if at least one of our ports is active */ 3534236916Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 3535236916Sthompsa if (bif->bif_ifp->if_capabilities & IFCAP_LINKSTATE) 3536234487Sthompsa hasls++; 3537236916Sthompsa if (bif->bif_ifp->if_link_state == LINK_STATE_UP) { 3538234487Sthompsa new_link = LINK_STATE_UP; 3539234487Sthompsa break; 3540234487Sthompsa } 3541234487Sthompsa } 3542234487Sthompsa if (!LIST_EMPTY(&sc->sc_iflist) && !hasls) { 3543234487Sthompsa /* If no interfaces support link-state then we default to up */ 3544234487Sthompsa new_link = LINK_STATE_UP; 3545234487Sthompsa } 3546234487Sthompsa if_link_state_change(sc->sc_ifp, new_link); 3547234487Sthompsa} 3548