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$"); 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> 103185895Szec#include <sys/rwlock.h> 104146985Sthompsa 105146985Sthompsa#include <net/bpf.h> 106146985Sthompsa#include <net/if.h> 107146985Sthompsa#include <net/if_clone.h> 108146985Sthompsa#include <net/if_dl.h> 109146985Sthompsa#include <net/if_types.h> 110146985Sthompsa#include <net/if_var.h> 111146985Sthompsa#include <net/pfil.h> 112197952Sjulian#include <net/vnet.h> 113146985Sthompsa 114146985Sthompsa#include <netinet/in.h> /* for struct arpcom */ 115146985Sthompsa#include <netinet/in_systm.h> 116146985Sthompsa#include <netinet/in_var.h> 117146985Sthompsa#include <netinet/ip.h> 118146985Sthompsa#include <netinet/ip_var.h> 119146985Sthompsa#ifdef INET6 120146985Sthompsa#include <netinet/ip6.h> 121146985Sthompsa#include <netinet6/ip6_var.h> 122253239Shrs#include <netinet6/in6_ifattach.h> 123146985Sthompsa#endif 124193983Sbz#if defined(INET) || defined(INET6) 125159446Sthompsa#include <netinet/ip_carp.h> 126159446Sthompsa#endif 127146985Sthompsa#include <machine/in_cksum.h> 128146985Sthompsa#include <netinet/if_ether.h> /* for struct arpcom */ 129160703Sthompsa#include <net/bridgestp.h> 130146985Sthompsa#include <net/if_bridgevar.h> 131146985Sthompsa#include <net/if_llc.h> 132170681Sthompsa#include <net/if_vlan_var.h> 133146985Sthompsa 134146985Sthompsa#include <net/route.h> 135146985Sthompsa#include <netinet/ip_fw.h> 136243401Sglebius#include <netpfil/ipfw/ip_fw_private.h> 137146985Sthompsa 138146985Sthompsa/* 139146985Sthompsa * Size of the route hash table. Must be a power of two. 140146985Sthompsa */ 141146985Sthompsa#ifndef BRIDGE_RTHASH_SIZE 142146985Sthompsa#define BRIDGE_RTHASH_SIZE 1024 143146985Sthompsa#endif 144146985Sthompsa 145146985Sthompsa#define BRIDGE_RTHASH_MASK (BRIDGE_RTHASH_SIZE - 1) 146146985Sthompsa 147146985Sthompsa/* 148233084Sbrueffer * Default maximum number of addresses to cache. 149146985Sthompsa */ 150146985Sthompsa#ifndef BRIDGE_RTABLE_MAX 151233084Sbrueffer#define BRIDGE_RTABLE_MAX 2000 152146985Sthompsa#endif 153146985Sthompsa 154146985Sthompsa/* 155146985Sthompsa * Timeout (in seconds) for entries learned dynamically. 156146985Sthompsa */ 157146985Sthompsa#ifndef BRIDGE_RTABLE_TIMEOUT 158146985Sthompsa#define BRIDGE_RTABLE_TIMEOUT (20 * 60) /* same as ARP */ 159146985Sthompsa#endif 160146985Sthompsa 161146985Sthompsa/* 162146985Sthompsa * Number of seconds between walks of the route list. 163146985Sthompsa */ 164146985Sthompsa#ifndef BRIDGE_RTABLE_PRUNE_PERIOD 165146985Sthompsa#define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60) 166146985Sthompsa#endif 167146985Sthompsa 168154336Sthompsa/* 169180220Sthompsa * List of capabilities to possibly mask on the member interface. 170154336Sthompsa */ 171180220Sthompsa#define BRIDGE_IFCAPS_MASK (IFCAP_TOE|IFCAP_TSO|IFCAP_TXCSUM) 172154336Sthompsa 173160769Sthompsa/* 174196519Sjfv * List of capabilities to strip 175196519Sjfv */ 176196519Sjfv#define BRIDGE_IFCAPS_STRIP IFCAP_LRO 177196519Sjfv 178196519Sjfv/* 179160769Sthompsa * Bridge interface list entry. 180160769Sthompsa */ 181160769Sthompsastruct bridge_iflist { 182160769Sthompsa LIST_ENTRY(bridge_iflist) bif_next; 183160769Sthompsa struct ifnet *bif_ifp; /* member if */ 184160769Sthompsa struct bstp_port bif_stp; /* STP state */ 185160769Sthompsa uint32_t bif_flags; /* member if flags */ 186180220Sthompsa int bif_savedcaps; /* saved capabilities */ 187173320Sthompsa uint32_t bif_addrmax; /* max # of addresses */ 188173320Sthompsa uint32_t bif_addrcnt; /* cur. # of addresses */ 189173320Sthompsa uint32_t bif_addrexceeded;/* # of address violations */ 190160769Sthompsa}; 191160769Sthompsa 192160769Sthompsa/* 193160769Sthompsa * Bridge route node. 194160769Sthompsa */ 195160769Sthompsastruct bridge_rtnode { 196160769Sthompsa LIST_ENTRY(bridge_rtnode) brt_hash; /* hash table linkage */ 197160769Sthompsa LIST_ENTRY(bridge_rtnode) brt_list; /* list linkage */ 198173320Sthompsa struct bridge_iflist *brt_dst; /* destination if */ 199160769Sthompsa unsigned long brt_expire; /* expiration time */ 200160769Sthompsa uint8_t brt_flags; /* address flags */ 201160769Sthompsa uint8_t brt_addr[ETHER_ADDR_LEN]; 202170681Sthompsa uint16_t brt_vlan; /* vlan id */ 203160769Sthompsa}; 204173320Sthompsa#define brt_ifp brt_dst->bif_ifp 205160769Sthompsa 206160769Sthompsa/* 207160769Sthompsa * Software state for each bridge. 208160769Sthompsa */ 209160769Sthompsastruct bridge_softc { 210160769Sthompsa struct ifnet *sc_ifp; /* make this an interface */ 211160769Sthompsa LIST_ENTRY(bridge_softc) sc_list; 212160769Sthompsa struct mtx sc_mtx; 213160769Sthompsa struct cv sc_cv; 214160769Sthompsa uint32_t sc_brtmax; /* max # of addresses */ 215160769Sthompsa uint32_t sc_brtcnt; /* cur. # of addresses */ 216160769Sthompsa uint32_t sc_brttimeout; /* rt timeout in seconds */ 217160769Sthompsa struct callout sc_brcallout; /* bridge callout */ 218160769Sthompsa uint32_t sc_iflist_ref; /* refcount for sc_iflist */ 219160769Sthompsa uint32_t sc_iflist_xcnt; /* refcount for sc_iflist */ 220160769Sthompsa LIST_HEAD(, bridge_iflist) sc_iflist; /* member interface list */ 221160769Sthompsa LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */ 222160769Sthompsa LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */ 223160769Sthompsa uint32_t sc_rthash_key; /* key for hash */ 224160769Sthompsa LIST_HEAD(, bridge_iflist) sc_spanlist; /* span ports list */ 225160769Sthompsa struct bstp_state sc_stp; /* STP state */ 226160867Sthompsa uint32_t sc_brtexceeded; /* # of cache drops */ 227188594Sthompsa struct ifnet *sc_ifaddr; /* member mac copied from */ 228180140Sphilip u_char sc_defaddr[6]; /* Default MAC address */ 229160769Sthompsa}; 230160769Sthompsa 231153494Sthompsastatic struct mtx bridge_list_mtx; 232153494Sthompsaeventhandler_tag bridge_detach_cookie = NULL; 233153494Sthompsa 234146985Sthompsaint bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; 235146985Sthompsa 236146985Sthompsauma_zone_t bridge_rtnode_zone; 237146985Sthompsa 238160195Ssamstatic int bridge_clone_create(struct if_clone *, int, caddr_t); 239151313Sthompsastatic void bridge_clone_destroy(struct ifnet *); 240146985Sthompsa 241151313Sthompsastatic int bridge_ioctl(struct ifnet *, u_long, caddr_t); 242180220Sthompsastatic void bridge_mutecaps(struct bridge_softc *); 243180220Sthompsastatic void bridge_set_ifcap(struct bridge_softc *, struct bridge_iflist *, 244180220Sthompsa int); 245153494Sthompsastatic void bridge_ifdetach(void *arg __unused, struct ifnet *); 246146985Sthompsastatic void bridge_init(void *); 247151313Sthompsastatic void bridge_dummynet(struct mbuf *, struct ifnet *); 248151313Sthompsastatic void bridge_stop(struct ifnet *, int); 249151313Sthompsastatic void bridge_start(struct ifnet *); 250151313Sthompsastatic struct mbuf *bridge_input(struct ifnet *, struct mbuf *); 251151313Sthompsastatic int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *, 252151313Sthompsa struct rtentry *); 253160769Sthompsastatic void bridge_enqueue(struct bridge_softc *, struct ifnet *, 254160769Sthompsa struct mbuf *); 255160769Sthompsastatic void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int); 256146985Sthompsa 257171678Sthompsastatic void bridge_forward(struct bridge_softc *, struct bridge_iflist *, 258171678Sthompsa struct mbuf *m); 259146985Sthompsa 260151313Sthompsastatic void bridge_timer(void *); 261146985Sthompsa 262151313Sthompsastatic void bridge_broadcast(struct bridge_softc *, struct ifnet *, 263151313Sthompsa struct mbuf *, int); 264153408Sthompsastatic void bridge_span(struct bridge_softc *, struct mbuf *); 265146985Sthompsa 266151313Sthompsastatic int bridge_rtupdate(struct bridge_softc *, const uint8_t *, 267170681Sthompsa uint16_t, struct bridge_iflist *, int, uint8_t); 268170681Sthompsastatic struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *, 269170681Sthompsa uint16_t); 270151313Sthompsastatic void bridge_rttrim(struct bridge_softc *); 271151313Sthompsastatic void bridge_rtage(struct bridge_softc *); 272151313Sthompsastatic void bridge_rtflush(struct bridge_softc *, int); 273170681Sthompsastatic int bridge_rtdaddr(struct bridge_softc *, const uint8_t *, 274170681Sthompsa uint16_t); 275146985Sthompsa 276151313Sthompsastatic int bridge_rtable_init(struct bridge_softc *); 277151313Sthompsastatic void bridge_rtable_fini(struct bridge_softc *); 278146985Sthompsa 279155143Sthompsastatic int bridge_rtnode_addr_cmp(const uint8_t *, const uint8_t *); 280151313Sthompsastatic struct bridge_rtnode *bridge_rtnode_lookup(struct bridge_softc *, 281170681Sthompsa const uint8_t *, uint16_t); 282151313Sthompsastatic int bridge_rtnode_insert(struct bridge_softc *, 283151313Sthompsa struct bridge_rtnode *); 284151313Sthompsastatic void bridge_rtnode_destroy(struct bridge_softc *, 285151313Sthompsa struct bridge_rtnode *); 286163863Sthompsastatic void bridge_rtable_expire(struct ifnet *, int); 287160902Sthompsastatic void bridge_state_change(struct ifnet *, int); 288146985Sthompsa 289151313Sthompsastatic struct bridge_iflist *bridge_lookup_member(struct bridge_softc *, 290151313Sthompsa const char *name); 291151313Sthompsastatic struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *, 292151313Sthompsa struct ifnet *ifp); 293151313Sthompsastatic void bridge_delete_member(struct bridge_softc *, 294151594Sthompsa struct bridge_iflist *, int); 295153494Sthompsastatic void bridge_delete_span(struct bridge_softc *, 296153494Sthompsa struct bridge_iflist *); 297146985Sthompsa 298151313Sthompsastatic int bridge_ioctl_add(struct bridge_softc *, void *); 299151313Sthompsastatic int bridge_ioctl_del(struct bridge_softc *, void *); 300151313Sthompsastatic int bridge_ioctl_gifflags(struct bridge_softc *, void *); 301151313Sthompsastatic int bridge_ioctl_sifflags(struct bridge_softc *, void *); 302151313Sthompsastatic int bridge_ioctl_scache(struct bridge_softc *, void *); 303151313Sthompsastatic int bridge_ioctl_gcache(struct bridge_softc *, void *); 304151313Sthompsastatic int bridge_ioctl_gifs(struct bridge_softc *, void *); 305151313Sthompsastatic int bridge_ioctl_rts(struct bridge_softc *, void *); 306151313Sthompsastatic int bridge_ioctl_saddr(struct bridge_softc *, void *); 307151313Sthompsastatic int bridge_ioctl_sto(struct bridge_softc *, void *); 308151313Sthompsastatic int bridge_ioctl_gto(struct bridge_softc *, void *); 309151313Sthompsastatic int bridge_ioctl_daddr(struct bridge_softc *, void *); 310151313Sthompsastatic int bridge_ioctl_flush(struct bridge_softc *, void *); 311151313Sthompsastatic int bridge_ioctl_gpri(struct bridge_softc *, void *); 312151313Sthompsastatic int bridge_ioctl_spri(struct bridge_softc *, void *); 313151313Sthompsastatic int bridge_ioctl_ght(struct bridge_softc *, void *); 314151313Sthompsastatic int bridge_ioctl_sht(struct bridge_softc *, void *); 315151313Sthompsastatic int bridge_ioctl_gfd(struct bridge_softc *, void *); 316151313Sthompsastatic int bridge_ioctl_sfd(struct bridge_softc *, void *); 317151313Sthompsastatic int bridge_ioctl_gma(struct bridge_softc *, void *); 318151313Sthompsastatic int bridge_ioctl_sma(struct bridge_softc *, void *); 319151313Sthompsastatic int bridge_ioctl_sifprio(struct bridge_softc *, void *); 320151313Sthompsastatic int bridge_ioctl_sifcost(struct bridge_softc *, void *); 321173320Sthompsastatic int bridge_ioctl_sifmaxaddr(struct bridge_softc *, void *); 322153408Sthompsastatic int bridge_ioctl_addspan(struct bridge_softc *, void *); 323153408Sthompsastatic int bridge_ioctl_delspan(struct bridge_softc *, void *); 324160867Sthompsastatic int bridge_ioctl_gbparam(struct bridge_softc *, void *); 325160867Sthompsastatic int bridge_ioctl_grte(struct bridge_softc *, void *); 326160867Sthompsastatic int bridge_ioctl_gifsstp(struct bridge_softc *, void *); 327163863Sthompsastatic int bridge_ioctl_sproto(struct bridge_softc *, void *); 328163863Sthompsastatic int bridge_ioctl_stxhc(struct bridge_softc *, void *); 329151313Sthompsastatic int bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *, 330151313Sthompsa int); 331151313Sthompsastatic int bridge_ip_checkbasic(struct mbuf **mp); 332158667Sthompsa#ifdef INET6 333151313Sthompsastatic int bridge_ip6_checkbasic(struct mbuf **mp); 334158667Sthompsa#endif /* INET6 */ 335158140Sthompsastatic int bridge_fragment(struct ifnet *, struct mbuf *, 336158140Sthompsa struct ether_header *, int, struct llc *); 337236051Sthompsastatic void bridge_linkstate(struct ifnet *ifp); 338237103Sthompsastatic void bridge_linkcheck(struct bridge_softc *sc); 339146985Sthompsa 340236051Sthompsaextern void (*bridge_linkstate_p)(struct ifnet *ifp); 341236051Sthompsa 342170681Sthompsa/* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */ 343170681Sthompsa#define VLANTAGOF(_m) \ 344170681Sthompsa (_m->m_flags & M_VLANTAG) ? EVL_VLANOFTAG(_m->m_pkthdr.ether_vtag) : 1 345170681Sthompsa 346167379Sthompsastatic struct bstp_cb_ops bridge_ops = { 347167379Sthompsa .bcb_state = bridge_state_change, 348167379Sthompsa .bcb_rtage = bridge_rtable_expire 349167379Sthompsa}; 350167379Sthompsa 351146985SthompsaSYSCTL_DECL(_net_link); 352248085Smariusstatic SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW, 0, "Bridge"); 353146985Sthompsa 354153831Sthompsastatic int pfil_onlyip = 1; /* only pass IP[46] packets when pfil is enabled */ 355146985Sthompsastatic int pfil_bridge = 1; /* run pfil hooks on the bridge interface */ 356146985Sthompsastatic int pfil_member = 1; /* run pfil hooks on the member interface */ 357147111Sthompsastatic int pfil_ipfw = 0; /* layer2 filter with ipfw */ 358162561Sthompsastatic int pfil_ipfw_arp = 0; /* layer2 filter with ipfw */ 359172201Sthompsastatic int pfil_local_phys = 0; /* run pfil hooks on the physical interface for 360172201Sthompsa locally destined packets */ 361160902Sthompsastatic int log_stp = 0; /* log STP state changes */ 362182862Sthompsastatic int bridge_inherit_mac = 0; /* share MAC with first bridge member */ 363236071SthompsaTUNABLE_INT("net.link.bridge.pfil_onlyip", &pfil_onlyip); 364153831SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_onlyip, CTLFLAG_RW, 365153831Sthompsa &pfil_onlyip, 0, "Only pass IP packets when pfil is enabled"); 366236071SthompsaTUNABLE_INT("net.link.bridge.ipfw_arp", &pfil_ipfw_arp); 367162561SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, ipfw_arp, CTLFLAG_RW, 368162561Sthompsa &pfil_ipfw_arp, 0, "Filter ARP packets through IPFW layer2"); 369236071SthompsaTUNABLE_INT("net.link.bridge.pfil_bridge", &pfil_bridge); 370146985SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_bridge, CTLFLAG_RW, 371146985Sthompsa &pfil_bridge, 0, "Packet filter on the bridge interface"); 372236071SthompsaTUNABLE_INT("net.link.bridge.pfil_member", &pfil_member); 373146985SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_member, CTLFLAG_RW, 374146985Sthompsa &pfil_member, 0, "Packet filter on the member interface"); 375236071SthompsaTUNABLE_INT("net.link.bridge.pfil_local_phys", &pfil_local_phys); 376172201SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_local_phys, CTLFLAG_RW, 377172201Sthompsa &pfil_local_phys, 0, 378172201Sthompsa "Packet filter on the physical interface for locally destined packets"); 379236071SthompsaTUNABLE_INT("net.link.bridge.log_stp", &log_stp); 380160902SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, log_stp, CTLFLAG_RW, 381160902Sthompsa &log_stp, 0, "Log STP state changes"); 382236071SthompsaTUNABLE_INT("net.link.bridge.inherit_mac", &bridge_inherit_mac); 383182862SthompsaSYSCTL_INT(_net_link_bridge, OID_AUTO, inherit_mac, CTLFLAG_RW, 384182862Sthompsa &bridge_inherit_mac, 0, 385182862Sthompsa "Inherit MAC address from the first bridge member"); 386146985Sthompsa 387253878Shrsstatic VNET_DEFINE(int, allow_llz_overlap) = 0; 388253878Shrs#define V_allow_llz_overlap VNET(allow_llz_overlap) 389253878ShrsSYSCTL_VNET_INT(_net_link_bridge, OID_AUTO, allow_llz_overlap, CTLFLAG_RW, 390253878Shrs &VNET_NAME(allow_llz_overlap), 0, "Allow overlap of link-local scope " 391253878Shrs "zones of a bridge interface and the member interfaces"); 392253878Shrs 393146985Sthompsastruct bridge_control { 394146985Sthompsa int (*bc_func)(struct bridge_softc *, void *); 395146985Sthompsa int bc_argsize; 396146985Sthompsa int bc_flags; 397146985Sthompsa}; 398146985Sthompsa 399146985Sthompsa#define BC_F_COPYIN 0x01 /* copy arguments in */ 400146985Sthompsa#define BC_F_COPYOUT 0x02 /* copy arguments out */ 401146985Sthompsa#define BC_F_SUSER 0x04 /* do super-user check */ 402146985Sthompsa 403146985Sthompsaconst struct bridge_control bridge_control_table[] = { 404146985Sthompsa { bridge_ioctl_add, sizeof(struct ifbreq), 405146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 406146985Sthompsa { bridge_ioctl_del, sizeof(struct ifbreq), 407146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 408146985Sthompsa 409146985Sthompsa { bridge_ioctl_gifflags, sizeof(struct ifbreq), 410146985Sthompsa BC_F_COPYIN|BC_F_COPYOUT }, 411146985Sthompsa { bridge_ioctl_sifflags, sizeof(struct ifbreq), 412146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 413146985Sthompsa 414146985Sthompsa { bridge_ioctl_scache, sizeof(struct ifbrparam), 415146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 416146985Sthompsa { bridge_ioctl_gcache, sizeof(struct ifbrparam), 417146985Sthompsa BC_F_COPYOUT }, 418146985Sthompsa 419146985Sthompsa { bridge_ioctl_gifs, sizeof(struct ifbifconf), 420146985Sthompsa BC_F_COPYIN|BC_F_COPYOUT }, 421146985Sthompsa { bridge_ioctl_rts, sizeof(struct ifbaconf), 422146985Sthompsa BC_F_COPYIN|BC_F_COPYOUT }, 423146985Sthompsa 424146985Sthompsa { bridge_ioctl_saddr, sizeof(struct ifbareq), 425146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 426146985Sthompsa 427146985Sthompsa { bridge_ioctl_sto, sizeof(struct ifbrparam), 428146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 429146985Sthompsa { bridge_ioctl_gto, sizeof(struct ifbrparam), 430146985Sthompsa BC_F_COPYOUT }, 431146985Sthompsa 432146985Sthompsa { bridge_ioctl_daddr, sizeof(struct ifbareq), 433146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 434146985Sthompsa 435146985Sthompsa { bridge_ioctl_flush, sizeof(struct ifbreq), 436146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 437146985Sthompsa 438146985Sthompsa { bridge_ioctl_gpri, sizeof(struct ifbrparam), 439146985Sthompsa BC_F_COPYOUT }, 440146985Sthompsa { bridge_ioctl_spri, sizeof(struct ifbrparam), 441146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 442146985Sthompsa 443146985Sthompsa { bridge_ioctl_ght, sizeof(struct ifbrparam), 444146985Sthompsa BC_F_COPYOUT }, 445146985Sthompsa { bridge_ioctl_sht, sizeof(struct ifbrparam), 446146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 447146985Sthompsa 448146985Sthompsa { bridge_ioctl_gfd, sizeof(struct ifbrparam), 449146985Sthompsa BC_F_COPYOUT }, 450146985Sthompsa { bridge_ioctl_sfd, sizeof(struct ifbrparam), 451146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 452146985Sthompsa 453146985Sthompsa { bridge_ioctl_gma, sizeof(struct ifbrparam), 454146985Sthompsa BC_F_COPYOUT }, 455146985Sthompsa { bridge_ioctl_sma, sizeof(struct ifbrparam), 456146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 457146985Sthompsa 458146985Sthompsa { bridge_ioctl_sifprio, sizeof(struct ifbreq), 459146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 460146985Sthompsa 461146985Sthompsa { bridge_ioctl_sifcost, sizeof(struct ifbreq), 462146985Sthompsa BC_F_COPYIN|BC_F_SUSER }, 463153408Sthompsa 464153408Sthompsa { bridge_ioctl_addspan, sizeof(struct ifbreq), 465153408Sthompsa BC_F_COPYIN|BC_F_SUSER }, 466153408Sthompsa { bridge_ioctl_delspan, sizeof(struct ifbreq), 467153408Sthompsa BC_F_COPYIN|BC_F_SUSER }, 468160867Sthompsa 469160867Sthompsa { bridge_ioctl_gbparam, sizeof(struct ifbropreq), 470160867Sthompsa BC_F_COPYOUT }, 471160867Sthompsa 472160867Sthompsa { bridge_ioctl_grte, sizeof(struct ifbrparam), 473160867Sthompsa BC_F_COPYOUT }, 474160867Sthompsa 475160867Sthompsa { bridge_ioctl_gifsstp, sizeof(struct ifbpstpconf), 476164861Ssyrinx BC_F_COPYIN|BC_F_COPYOUT }, 477163863Sthompsa 478163863Sthompsa { bridge_ioctl_sproto, sizeof(struct ifbrparam), 479163863Sthompsa BC_F_COPYIN|BC_F_SUSER }, 480163863Sthompsa 481163863Sthompsa { bridge_ioctl_stxhc, sizeof(struct ifbrparam), 482163863Sthompsa BC_F_COPYIN|BC_F_SUSER }, 483173320Sthompsa 484173320Sthompsa { bridge_ioctl_sifmaxaddr, sizeof(struct ifbreq), 485173320Sthompsa BC_F_COPYIN|BC_F_SUSER }, 486173320Sthompsa 487146985Sthompsa}; 488146985Sthompsaconst int bridge_control_table_size = 489146985Sthompsa sizeof(bridge_control_table) / sizeof(bridge_control_table[0]); 490146985Sthompsa 491153494SthompsaLIST_HEAD(, bridge_softc) bridge_list; 492153494Sthompsa 493146985SthompsaIFC_SIMPLE_DECLARE(bridge, 0); 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); 502146985Sthompsa if_clone_attach(&bridge_cloner); 503146985Sthompsa bridge_rtnode_zone = uma_zcreate("bridge_rtnode", 504146985Sthompsa sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL, 505146985Sthompsa UMA_ALIGN_PTR, 0); 506153494Sthompsa LIST_INIT(&bridge_list); 507146985Sthompsa bridge_input_p = bridge_input; 508146985Sthompsa bridge_output_p = bridge_output; 509147205Sthompsa bridge_dn_p = bridge_dummynet; 510236051Sthompsa bridge_linkstate_p = bridge_linkstate; 511153494Sthompsa bridge_detach_cookie = EVENTHANDLER_REGISTER( 512153494Sthompsa ifnet_departure_event, bridge_ifdetach, NULL, 513153494Sthompsa EVENTHANDLER_PRI_ANY); 514146985Sthompsa break; 515146985Sthompsa case MOD_UNLOAD: 516153494Sthompsa EVENTHANDLER_DEREGISTER(ifnet_departure_event, 517153494Sthompsa bridge_detach_cookie); 518146985Sthompsa if_clone_detach(&bridge_cloner); 519146985Sthompsa uma_zdestroy(bridge_rtnode_zone); 520146985Sthompsa bridge_input_p = NULL; 521146985Sthompsa bridge_output_p = NULL; 522147205Sthompsa bridge_dn_p = NULL; 523236051Sthompsa bridge_linkstate_p = NULL; 524153494Sthompsa mtx_destroy(&bridge_list_mtx); 525146985Sthompsa break; 526146985Sthompsa default: 527158667Sthompsa return (EOPNOTSUPP); 528146985Sthompsa } 529158667Sthompsa return (0); 530146985Sthompsa} 531146985Sthompsa 532146985Sthompsastatic moduledata_t bridge_mod = { 533153497Sthompsa "if_bridge", 534153497Sthompsa bridge_modevent, 535146985Sthompsa 0 536146985Sthompsa}; 537146985Sthompsa 538146985SthompsaDECLARE_MODULE(if_bridge, bridge_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 539160730SthompsaMODULE_DEPEND(if_bridge, bridgestp, 1, 1, 1); 540146985Sthompsa 541147111Sthompsa/* 542147111Sthompsa * handler for net.link.bridge.pfil_ipfw 543147111Sthompsa */ 544147111Sthompsastatic int 545147111Sthompsasysctl_pfil_ipfw(SYSCTL_HANDLER_ARGS) 546147111Sthompsa{ 547153497Sthompsa int enable = pfil_ipfw; 548153497Sthompsa int error; 549146985Sthompsa 550153497Sthompsa error = sysctl_handle_int(oidp, &enable, 0, req); 551153497Sthompsa enable = (enable) ? 1 : 0; 552147111Sthompsa 553153497Sthompsa if (enable != pfil_ipfw) { 554153497Sthompsa pfil_ipfw = enable; 555147111Sthompsa 556153497Sthompsa /* 557153497Sthompsa * Disable pfil so that ipfw doesnt run twice, if the user 558153497Sthompsa * really wants both then they can re-enable pfil_bridge and/or 559153831Sthompsa * pfil_member. Also allow non-ip packets as ipfw can filter by 560153831Sthompsa * layer2 type. 561153497Sthompsa */ 562153497Sthompsa if (pfil_ipfw) { 563153831Sthompsa pfil_onlyip = 0; 564153497Sthompsa pfil_bridge = 0; 565153497Sthompsa pfil_member = 0; 566153497Sthompsa } 567147111Sthompsa } 568147111Sthompsa 569158667Sthompsa return (error); 570147111Sthompsa} 571147111SthompsaSYSCTL_PROC(_net_link_bridge, OID_AUTO, ipfw, CTLTYPE_INT|CTLFLAG_RW, 572147111Sthompsa &pfil_ipfw, 0, &sysctl_pfil_ipfw, "I", "Layer2 filter with IPFW"); 573147111Sthompsa 574146985Sthompsa/* 575146985Sthompsa * bridge_clone_create: 576146985Sthompsa * 577146985Sthompsa * Create a new bridge instance. 578146985Sthompsa */ 579151313Sthompsastatic int 580160195Ssambridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) 581146985Sthompsa{ 582156238Sthompsa struct bridge_softc *sc, *sc2; 583156238Sthompsa struct ifnet *bifp, *ifp; 584225380Sthompsa int fb, retry; 585225380Sthompsa unsigned long hostid; 586146985Sthompsa 587146985Sthompsa sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 588147281Sthompsa ifp = sc->sc_ifp = if_alloc(IFT_ETHER); 589147281Sthompsa if (ifp == NULL) { 590147281Sthompsa free(sc, M_DEVBUF); 591147281Sthompsa return (ENOSPC); 592147281Sthompsa } 593146985Sthompsa 594166916Sthompsa BRIDGE_LOCK_INIT(sc); 595146985Sthompsa sc->sc_brtmax = BRIDGE_RTABLE_MAX; 596146985Sthompsa sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT; 597146985Sthompsa 598146985Sthompsa /* Initialize our routing table. */ 599146985Sthompsa bridge_rtable_init(sc); 600146985Sthompsa 601149253Sthompsa callout_init_mtx(&sc->sc_brcallout, &sc->sc_mtx, 0); 602146985Sthompsa 603146985Sthompsa LIST_INIT(&sc->sc_iflist); 604153408Sthompsa LIST_INIT(&sc->sc_spanlist); 605146985Sthompsa 606146985Sthompsa ifp->if_softc = sc; 607146985Sthompsa if_initname(ifp, ifc->ifc_name, unit); 608161625Sthompsa ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 609146985Sthompsa ifp->if_ioctl = bridge_ioctl; 610146985Sthompsa ifp->if_start = bridge_start; 611146985Sthompsa ifp->if_init = bridge_init; 612146985Sthompsa ifp->if_type = IFT_BRIDGE; 613146985Sthompsa IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 614146985Sthompsa ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 615146985Sthompsa IFQ_SET_READY(&ifp->if_snd); 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); 627156238Sthompsa for (retry = 1; retry != 0;) { 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, 647180140Sphilip IF_LLADDR(bifp), ETHER_ADDR_LEN) == 0) 648156238Sthompsa retry = 1; 649156238Sthompsa } 650156238Sthompsa mtx_unlock(&bridge_list_mtx); 651156238Sthompsa } 652146985Sthompsa 653167379Sthompsa bstp_attach(&sc->sc_stp, &bridge_ops); 654180140Sphilip ether_ifattach(ifp, sc->sc_defaddr); 655146985Sthompsa /* Now undo some of the damage... */ 656146985Sthompsa ifp->if_baudrate = 0; 657146985Sthompsa ifp->if_type = IFT_BRIDGE; 658146985Sthompsa 659153494Sthompsa mtx_lock(&bridge_list_mtx); 660153494Sthompsa LIST_INSERT_HEAD(&bridge_list, sc, sc_list); 661153494Sthompsa mtx_unlock(&bridge_list_mtx); 662153494Sthompsa 663146985Sthompsa return (0); 664146985Sthompsa} 665146985Sthompsa 666146985Sthompsa/* 667146985Sthompsa * bridge_clone_destroy: 668146985Sthompsa * 669146985Sthompsa * Destroy a bridge instance. 670146985Sthompsa */ 671151313Sthompsastatic void 672146985Sthompsabridge_clone_destroy(struct ifnet *ifp) 673146985Sthompsa{ 674146985Sthompsa struct bridge_softc *sc = ifp->if_softc; 675146985Sthompsa struct bridge_iflist *bif; 676146985Sthompsa 677146985Sthompsa BRIDGE_LOCK(sc); 678146985Sthompsa 679146985Sthompsa bridge_stop(ifp, 1); 680149522Sthompsa ifp->if_flags &= ~IFF_UP; 681146985Sthompsa 682146985Sthompsa while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL) 683151594Sthompsa bridge_delete_member(sc, bif, 0); 684146985Sthompsa 685153408Sthompsa while ((bif = LIST_FIRST(&sc->sc_spanlist)) != NULL) { 686153494Sthompsa bridge_delete_span(sc, bif); 687153408Sthompsa } 688153408Sthompsa 689146985Sthompsa BRIDGE_UNLOCK(sc); 690146985Sthompsa 691149253Sthompsa callout_drain(&sc->sc_brcallout); 692149253Sthompsa 693153494Sthompsa mtx_lock(&bridge_list_mtx); 694153494Sthompsa LIST_REMOVE(sc, sc_list); 695153494Sthompsa mtx_unlock(&bridge_list_mtx); 696153494Sthompsa 697160703Sthompsa bstp_detach(&sc->sc_stp); 698146985Sthompsa ether_ifdetach(ifp); 699147281Sthompsa if_free_type(ifp, IFT_ETHER); 700146985Sthompsa 701146985Sthompsa /* Tear down the routing table. */ 702146985Sthompsa bridge_rtable_fini(sc); 703146985Sthompsa 704146985Sthompsa BRIDGE_LOCK_DESTROY(sc); 705146985Sthompsa free(sc, M_DEVBUF); 706146985Sthompsa} 707146985Sthompsa 708146985Sthompsa/* 709146985Sthompsa * bridge_ioctl: 710146985Sthompsa * 711146985Sthompsa * Handle a control request from the operator. 712146985Sthompsa */ 713151313Sthompsastatic int 714146985Sthompsabridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 715146985Sthompsa{ 716146985Sthompsa struct bridge_softc *sc = ifp->if_softc; 717203272Shrs struct ifreq *ifr = (struct ifreq *)data; 718203272Shrs struct bridge_iflist *bif; 719146985Sthompsa struct thread *td = curthread; 720146985Sthompsa union { 721146985Sthompsa struct ifbreq ifbreq; 722146985Sthompsa struct ifbifconf ifbifconf; 723146985Sthompsa struct ifbareq ifbareq; 724146985Sthompsa struct ifbaconf ifbaconf; 725146985Sthompsa struct ifbrparam ifbrparam; 726164653Sthompsa struct ifbropreq ifbropreq; 727146985Sthompsa } args; 728146985Sthompsa struct ifdrv *ifd = (struct ifdrv *) data; 729146985Sthompsa const struct bridge_control *bc; 730146985Sthompsa int error = 0; 731146985Sthompsa 732146985Sthompsa switch (cmd) { 733146985Sthompsa 734149829Sthompsa case SIOCADDMULTI: 735149829Sthompsa case SIOCDELMULTI: 736149829Sthompsa break; 737149829Sthompsa 738146985Sthompsa case SIOCGDRVSPEC: 739146985Sthompsa case SIOCSDRVSPEC: 740146985Sthompsa if (ifd->ifd_cmd >= bridge_control_table_size) { 741146985Sthompsa error = EINVAL; 742146985Sthompsa break; 743146985Sthompsa } 744146985Sthompsa bc = &bridge_control_table[ifd->ifd_cmd]; 745146985Sthompsa 746146985Sthompsa if (cmd == SIOCGDRVSPEC && 747146985Sthompsa (bc->bc_flags & BC_F_COPYOUT) == 0) { 748146985Sthompsa error = EINVAL; 749146985Sthompsa break; 750146985Sthompsa } 751146985Sthompsa else if (cmd == SIOCSDRVSPEC && 752146985Sthompsa (bc->bc_flags & BC_F_COPYOUT) != 0) { 753146985Sthompsa error = EINVAL; 754146985Sthompsa break; 755146985Sthompsa } 756146985Sthompsa 757146985Sthompsa if (bc->bc_flags & BC_F_SUSER) { 758164033Srwatson error = priv_check(td, PRIV_NET_BRIDGE); 759146985Sthompsa if (error) 760146985Sthompsa break; 761146985Sthompsa } 762146985Sthompsa 763146985Sthompsa if (ifd->ifd_len != bc->bc_argsize || 764146985Sthompsa ifd->ifd_len > sizeof(args)) { 765146985Sthompsa error = EINVAL; 766146985Sthompsa break; 767146985Sthompsa } 768146985Sthompsa 769158667Sthompsa bzero(&args, sizeof(args)); 770146985Sthompsa if (bc->bc_flags & BC_F_COPYIN) { 771146985Sthompsa error = copyin(ifd->ifd_data, &args, ifd->ifd_len); 772146985Sthompsa if (error) 773146985Sthompsa break; 774146985Sthompsa } 775146985Sthompsa 776171603Sthompsa BRIDGE_LOCK(sc); 777146985Sthompsa error = (*bc->bc_func)(sc, &args); 778171603Sthompsa BRIDGE_UNLOCK(sc); 779146985Sthompsa if (error) 780146985Sthompsa break; 781146985Sthompsa 782146985Sthompsa if (bc->bc_flags & BC_F_COPYOUT) 783146985Sthompsa error = copyout(&args, ifd->ifd_data, ifd->ifd_len); 784146985Sthompsa 785146985Sthompsa break; 786146985Sthompsa 787146985Sthompsa case SIOCSIFFLAGS: 788148887Srwatson if (!(ifp->if_flags & IFF_UP) && 789148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING)) { 790146985Sthompsa /* 791146985Sthompsa * If interface is marked down and it is running, 792146985Sthompsa * then stop and disable it. 793146985Sthompsa */ 794171603Sthompsa BRIDGE_LOCK(sc); 795146985Sthompsa bridge_stop(ifp, 1); 796171603Sthompsa BRIDGE_UNLOCK(sc); 797148887Srwatson } else if ((ifp->if_flags & IFF_UP) && 798148887Srwatson !(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 799146985Sthompsa /* 800146985Sthompsa * If interface is marked up and it is stopped, then 801146985Sthompsa * start it. 802146985Sthompsa */ 803147634Sthompsa (*ifp->if_init)(sc); 804146985Sthompsa } 805146985Sthompsa break; 806146985Sthompsa 807146985Sthompsa case SIOCSIFMTU: 808203272Shrs if (ifr->ifr_mtu < 576) { 809203272Shrs error = EINVAL; 810203272Shrs break; 811203272Shrs } 812203272Shrs if (LIST_EMPTY(&sc->sc_iflist)) { 813203272Shrs sc->sc_ifp->if_mtu = ifr->ifr_mtu; 814203272Shrs break; 815203272Shrs } 816203272Shrs BRIDGE_LOCK(sc); 817203272Shrs LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 818203272Shrs if (bif->bif_ifp->if_mtu != ifr->ifr_mtu) { 819203272Shrs log(LOG_NOTICE, "%s: invalid MTU: %lu(%s)" 820203272Shrs " != %d\n", sc->sc_ifp->if_xname, 821203272Shrs bif->bif_ifp->if_mtu, 822203272Shrs bif->bif_ifp->if_xname, ifr->ifr_mtu); 823203272Shrs error = EINVAL; 824203272Shrs break; 825203272Shrs } 826203272Shrs } 827203272Shrs if (!error) 828203272Shrs sc->sc_ifp->if_mtu = ifr->ifr_mtu; 829203272Shrs BRIDGE_UNLOCK(sc); 830146985Sthompsa break; 831146985Sthompsa default: 832153497Sthompsa /* 833146985Sthompsa * drop the lock as ether_ioctl() will call bridge_start() and 834146985Sthompsa * cause the lock to be recursed. 835146985Sthompsa */ 836146985Sthompsa error = ether_ioctl(ifp, cmd, data); 837146985Sthompsa break; 838146985Sthompsa } 839146985Sthompsa 840146985Sthompsa return (error); 841146985Sthompsa} 842146985Sthompsa 843146985Sthompsa/* 844154336Sthompsa * bridge_mutecaps: 845154336Sthompsa * 846154336Sthompsa * Clear or restore unwanted capabilities on the member interface 847154336Sthompsa */ 848154336Sthompsastatic void 849180220Sthompsabridge_mutecaps(struct bridge_softc *sc) 850154336Sthompsa{ 851180220Sthompsa struct bridge_iflist *bif; 852180220Sthompsa int enabled, mask; 853180220Sthompsa 854180220Sthompsa /* Initial bitmask of capabilities to test */ 855180220Sthompsa mask = BRIDGE_IFCAPS_MASK; 856180220Sthompsa 857180220Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 858180220Sthompsa /* Every member must support it or its disabled */ 859180220Sthompsa mask &= bif->bif_savedcaps; 860180220Sthompsa } 861180220Sthompsa 862180220Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 863180220Sthompsa enabled = bif->bif_ifp->if_capenable; 864196519Sjfv enabled &= ~BRIDGE_IFCAPS_STRIP; 865180220Sthompsa /* strip off mask bits and enable them again if allowed */ 866180220Sthompsa enabled &= ~BRIDGE_IFCAPS_MASK; 867180220Sthompsa enabled |= mask; 868180220Sthompsa bridge_set_ifcap(sc, bif, enabled); 869180220Sthompsa } 870180220Sthompsa 871180220Sthompsa} 872180220Sthompsa 873180220Sthompsastatic void 874180220Sthompsabridge_set_ifcap(struct bridge_softc *sc, struct bridge_iflist *bif, int set) 875180220Sthompsa{ 876154336Sthompsa struct ifnet *ifp = bif->bif_ifp; 877154336Sthompsa struct ifreq ifr; 878154336Sthompsa int error; 879154336Sthompsa 880158667Sthompsa bzero(&ifr, sizeof(ifr)); 881180220Sthompsa ifr.ifr_reqcap = set; 882154336Sthompsa 883180220Sthompsa if (ifp->if_capenable != set) { 884154336Sthompsa error = (*ifp->if_ioctl)(ifp, SIOCSIFCAP, (caddr_t)&ifr); 885180220Sthompsa if (error) 886180220Sthompsa if_printf(sc->sc_ifp, 887180220Sthompsa "error setting interface capabilities on %s\n", 888180220Sthompsa ifp->if_xname); 889154336Sthompsa } 890154336Sthompsa} 891154336Sthompsa 892154336Sthompsa/* 893146985Sthompsa * bridge_lookup_member: 894146985Sthompsa * 895146985Sthompsa * Lookup a bridge member interface. 896146985Sthompsa */ 897151345Sthompsastatic struct bridge_iflist * 898146985Sthompsabridge_lookup_member(struct bridge_softc *sc, const char *name) 899146985Sthompsa{ 900146985Sthompsa struct bridge_iflist *bif; 901146985Sthompsa struct ifnet *ifp; 902146985Sthompsa 903146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 904146985Sthompsa 905146985Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 906146985Sthompsa ifp = bif->bif_ifp; 907146985Sthompsa if (strcmp(ifp->if_xname, name) == 0) 908146985Sthompsa return (bif); 909146985Sthompsa } 910146985Sthompsa 911146985Sthompsa return (NULL); 912146985Sthompsa} 913146985Sthompsa 914146985Sthompsa/* 915146985Sthompsa * bridge_lookup_member_if: 916146985Sthompsa * 917146985Sthompsa * Lookup a bridge member interface by ifnet*. 918146985Sthompsa */ 919151345Sthompsastatic struct bridge_iflist * 920146985Sthompsabridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp) 921146985Sthompsa{ 922146985Sthompsa struct bridge_iflist *bif; 923146985Sthompsa 924146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 925146985Sthompsa 926146985Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 927146985Sthompsa if (bif->bif_ifp == member_ifp) 928146985Sthompsa return (bif); 929146985Sthompsa } 930146985Sthompsa 931146985Sthompsa return (NULL); 932146985Sthompsa} 933146985Sthompsa 934146985Sthompsa/* 935146985Sthompsa * bridge_delete_member: 936146985Sthompsa * 937146985Sthompsa * Delete the specified member interface. 938146985Sthompsa */ 939151313Sthompsastatic void 940151594Sthompsabridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif, 941151594Sthompsa int gone) 942146985Sthompsa{ 943146985Sthompsa struct ifnet *ifs = bif->bif_ifp; 944180140Sphilip struct ifnet *fif = NULL; 945146985Sthompsa 946146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 947146985Sthompsa 948160703Sthompsa if (bif->bif_flags & IFBIF_STP) 949164626Sthompsa bstp_disable(&bif->bif_stp); 950160703Sthompsa 951146985Sthompsa ifs->if_bridge = NULL; 952146985Sthompsa BRIDGE_XLOCK(sc); 953146985Sthompsa LIST_REMOVE(bif, bif_next); 954146985Sthompsa BRIDGE_XDROP(sc); 955146985Sthompsa 956180140Sphilip /* 957180140Sphilip * If removing the interface that gave the bridge its mac address, set 958180140Sphilip * the mac address of the bridge to the address of the next member, or 959180140Sphilip * to its default address if no members are left. 960180140Sphilip */ 961188594Sthompsa if (bridge_inherit_mac && sc->sc_ifaddr == ifs) { 962188594Sthompsa if (LIST_EMPTY(&sc->sc_iflist)) { 963180140Sphilip bcopy(sc->sc_defaddr, 964180140Sphilip IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); 965188594Sthompsa sc->sc_ifaddr = NULL; 966188594Sthompsa } else { 967180140Sphilip fif = LIST_FIRST(&sc->sc_iflist)->bif_ifp; 968180140Sphilip bcopy(IF_LLADDR(fif), 969180140Sphilip IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); 970188594Sthompsa sc->sc_ifaddr = fif; 971180140Sphilip } 972202588Sthompsa EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); 973180140Sphilip } 974180140Sphilip 975237103Sthompsa bridge_linkcheck(sc); 976180220Sthompsa bridge_mutecaps(sc); /* recalcuate now this interface is removed */ 977146985Sthompsa bridge_rtdelete(sc, ifs, IFBF_FLUSHALL); 978173320Sthompsa KASSERT(bif->bif_addrcnt == 0, 979173320Sthompsa ("%s: %d bridge routes referenced", __func__, bif->bif_addrcnt)); 980146985Sthompsa 981160901Sthompsa BRIDGE_UNLOCK(sc); 982191729Sthompsa if (!gone) { 983191729Sthompsa switch (ifs->if_type) { 984191729Sthompsa case IFT_ETHER: 985191729Sthompsa case IFT_L2VLAN: 986191729Sthompsa /* 987191729Sthompsa * Take the interface out of promiscuous mode. 988191729Sthompsa */ 989191729Sthompsa (void) ifpromisc(ifs, 0); 990191729Sthompsa break; 991191729Sthompsa 992191729Sthompsa case IFT_GIF: 993191729Sthompsa break; 994191729Sthompsa 995191729Sthompsa default: 996191729Sthompsa#ifdef DIAGNOSTIC 997191729Sthompsa panic("bridge_delete_member: impossible"); 998191729Sthompsa#endif 999191729Sthompsa break; 1000191729Sthompsa } 1001191729Sthompsa /* reneable any interface capabilities */ 1002191729Sthompsa bridge_set_ifcap(sc, bif, bif->bif_savedcaps); 1003191729Sthompsa } 1004164626Sthompsa bstp_destroy(&bif->bif_stp); /* prepare to free */ 1005160901Sthompsa BRIDGE_LOCK(sc); 1006146985Sthompsa free(bif, M_DEVBUF); 1007146985Sthompsa} 1008146985Sthompsa 1009153494Sthompsa/* 1010153494Sthompsa * bridge_delete_span: 1011153494Sthompsa * 1012153494Sthompsa * Delete the specified span interface. 1013153494Sthompsa */ 1014153494Sthompsastatic void 1015153494Sthompsabridge_delete_span(struct bridge_softc *sc, struct bridge_iflist *bif) 1016153494Sthompsa{ 1017153494Sthompsa BRIDGE_LOCK_ASSERT(sc); 1018153494Sthompsa 1019153494Sthompsa KASSERT(bif->bif_ifp->if_bridge == NULL, 1020153494Sthompsa ("%s: not a span interface", __func__)); 1021153494Sthompsa 1022153494Sthompsa LIST_REMOVE(bif, bif_next); 1023153494Sthompsa free(bif, M_DEVBUF); 1024153494Sthompsa} 1025153494Sthompsa 1026151313Sthompsastatic int 1027146985Sthompsabridge_ioctl_add(struct bridge_softc *sc, void *arg) 1028146985Sthompsa{ 1029146985Sthompsa struct ifbreq *req = arg; 1030146985Sthompsa struct bridge_iflist *bif = NULL; 1031146985Sthompsa struct ifnet *ifs; 1032146985Sthompsa int error = 0; 1033146985Sthompsa 1034146985Sthompsa ifs = ifunit(req->ifbr_ifsname); 1035146985Sthompsa if (ifs == NULL) 1036146985Sthompsa return (ENOENT); 1037180220Sthompsa if (ifs->if_ioctl == NULL) /* must be supported */ 1038180220Sthompsa return (EINVAL); 1039146985Sthompsa 1040153408Sthompsa /* If it's in the span list, it can't be a member. */ 1041153408Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) 1042153408Sthompsa if (ifs == bif->bif_ifp) 1043153408Sthompsa return (EBUSY); 1044153408Sthompsa 1045146985Sthompsa if (ifs->if_bridge == sc) 1046146985Sthompsa return (EEXIST); 1047146985Sthompsa 1048146985Sthompsa if (ifs->if_bridge != NULL) 1049146985Sthompsa return (EBUSY); 1050146985Sthompsa 1051146985Sthompsa switch (ifs->if_type) { 1052146985Sthompsa case IFT_ETHER: 1053146985Sthompsa case IFT_L2VLAN: 1054153621Sthompsa case IFT_GIF: 1055191729Sthompsa /* permitted interface types */ 1056153621Sthompsa break; 1057146985Sthompsa default: 1058253239Shrs return (EINVAL); 1059146985Sthompsa } 1060146985Sthompsa 1061253239Shrs#ifdef INET6 1062253239Shrs /* 1063253239Shrs * Two valid inet6 addresses with link-local scope must not be 1064253239Shrs * on the parent interface and the member interfaces at the 1065253239Shrs * same time. This restriction is needed to prevent violation 1066253239Shrs * of link-local scope zone. Attempts to add a member 1067253239Shrs * interface which has inet6 addresses when the parent has 1068253239Shrs * inet6 triggers removal of all inet6 addresses on the member 1069253239Shrs * interface. 1070253239Shrs */ 1071253239Shrs 1072253239Shrs /* Check if the parent interface has a link-local scope addr. */ 1073253878Shrs if (V_allow_llz_overlap == 0 && 1074253878Shrs in6ifa_llaonifp(sc->sc_ifp) != NULL) { 1075253239Shrs /* 1076253239Shrs * If any, remove all inet6 addresses from the member 1077253239Shrs * interfaces. 1078253239Shrs */ 1079253239Shrs BRIDGE_XLOCK(sc); 1080253239Shrs LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 1081253239Shrs if (in6ifa_llaonifp(bif->bif_ifp)) { 1082253239Shrs BRIDGE_UNLOCK(sc); 1083253239Shrs in6_ifdetach(bif->bif_ifp); 1084253239Shrs BRIDGE_LOCK(sc); 1085253239Shrs if_printf(sc->sc_ifp, 1086253239Shrs "IPv6 addresses on %s have been removed " 1087253239Shrs "before adding it as a member to prevent " 1088253239Shrs "IPv6 address scope violation.\n", 1089253239Shrs bif->bif_ifp->if_xname); 1090253239Shrs } 1091253239Shrs } 1092253239Shrs BRIDGE_XDROP(sc); 1093253239Shrs if (in6ifa_llaonifp(ifs)) { 1094253239Shrs BRIDGE_UNLOCK(sc); 1095253239Shrs in6_ifdetach(ifs); 1096253239Shrs BRIDGE_LOCK(sc); 1097253239Shrs if_printf(sc->sc_ifp, 1098253239Shrs "IPv6 addresses on %s have been removed " 1099253239Shrs "before adding it as a member to prevent " 1100253239Shrs "IPv6 address scope violation.\n", 1101253239Shrs ifs->if_xname); 1102253239Shrs } 1103253239Shrs } 1104253239Shrs#endif 1105203272Shrs /* Allow the first Ethernet member to define the MTU */ 1106203272Shrs if (LIST_EMPTY(&sc->sc_iflist)) 1107203272Shrs sc->sc_ifp->if_mtu = ifs->if_mtu; 1108203272Shrs else if (sc->sc_ifp->if_mtu != ifs->if_mtu) { 1109203272Shrs if_printf(sc->sc_ifp, "invalid MTU: %lu(%s) != %lu\n", 1110203272Shrs ifs->if_mtu, ifs->if_xname, sc->sc_ifp->if_mtu); 1111253239Shrs return (EINVAL); 1112203272Shrs } 1113203272Shrs 1114253239Shrs bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO); 1115253239Shrs if (bif == NULL) 1116253239Shrs return (ENOMEM); 1117253239Shrs 1118253239Shrs bif->bif_ifp = ifs; 1119253239Shrs bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; 1120253239Shrs bif->bif_savedcaps = ifs->if_capenable; 1121253239Shrs 1122180140Sphilip /* 1123180140Sphilip * Assign the interface's MAC address to the bridge if it's the first 1124180140Sphilip * member and the MAC address of the bridge has not been changed from 1125180140Sphilip * the default randomly generated one. 1126180140Sphilip */ 1127182862Sthompsa if (bridge_inherit_mac && LIST_EMPTY(&sc->sc_iflist) && 1128188594Sthompsa !memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr, ETHER_ADDR_LEN)) { 1129180140Sphilip bcopy(IF_LLADDR(ifs), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); 1130188594Sthompsa sc->sc_ifaddr = ifs; 1131202588Sthompsa EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); 1132188594Sthompsa } 1133180140Sphilip 1134146985Sthompsa ifs->if_bridge = sc; 1135164626Sthompsa bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp); 1136146985Sthompsa /* 1137146985Sthompsa * XXX: XLOCK HERE!?! 1138146985Sthompsa * 1139146985Sthompsa * NOTE: insert_***HEAD*** should be safe for the traversals. 1140146985Sthompsa */ 1141146985Sthompsa LIST_INSERT_HEAD(&sc->sc_iflist, bif, bif_next); 1142146985Sthompsa 1143180220Sthompsa /* Set interface capabilities to the intersection set of all members */ 1144180220Sthompsa bridge_mutecaps(sc); 1145237103Sthompsa bridge_linkcheck(sc); 1146191729Sthompsa 1147236051Sthompsa /* Place the interface into promiscuous mode */ 1148191729Sthompsa switch (ifs->if_type) { 1149236051Sthompsa case IFT_ETHER: 1150236051Sthompsa case IFT_L2VLAN: 1151237103Sthompsa BRIDGE_UNLOCK(sc); 1152236051Sthompsa error = ifpromisc(ifs, 1); 1153237103Sthompsa BRIDGE_LOCK(sc); 1154236051Sthompsa break; 1155191729Sthompsa } 1156253239Shrs 1157253239Shrs if (error) { 1158191729Sthompsa bridge_delete_member(sc, bif, 0); 1159253239Shrs free(bif, M_DEVBUF); 1160146985Sthompsa } 1161146985Sthompsa return (error); 1162146985Sthompsa} 1163146985Sthompsa 1164151313Sthompsastatic int 1165146985Sthompsabridge_ioctl_del(struct bridge_softc *sc, void *arg) 1166146985Sthompsa{ 1167146985Sthompsa struct ifbreq *req = arg; 1168146985Sthompsa struct bridge_iflist *bif; 1169146985Sthompsa 1170146985Sthompsa bif = bridge_lookup_member(sc, req->ifbr_ifsname); 1171146985Sthompsa if (bif == NULL) 1172146985Sthompsa return (ENOENT); 1173146985Sthompsa 1174151594Sthompsa bridge_delete_member(sc, bif, 0); 1175146985Sthompsa 1176146985Sthompsa return (0); 1177146985Sthompsa} 1178146985Sthompsa 1179151313Sthompsastatic int 1180146985Sthompsabridge_ioctl_gifflags(struct bridge_softc *sc, void *arg) 1181146985Sthompsa{ 1182146985Sthompsa struct ifbreq *req = arg; 1183146985Sthompsa struct bridge_iflist *bif; 1184163863Sthompsa struct bstp_port *bp; 1185146985Sthompsa 1186146985Sthompsa bif = bridge_lookup_member(sc, req->ifbr_ifsname); 1187146985Sthompsa if (bif == NULL) 1188146985Sthompsa return (ENOENT); 1189146985Sthompsa 1190163863Sthompsa bp = &bif->bif_stp; 1191146985Sthompsa req->ifbr_ifsflags = bif->bif_flags; 1192163863Sthompsa req->ifbr_state = bp->bp_state; 1193163863Sthompsa req->ifbr_priority = bp->bp_priority; 1194163863Sthompsa req->ifbr_path_cost = bp->bp_path_cost; 1195163863Sthompsa req->ifbr_portno = bif->bif_ifp->if_index & 0xfff; 1196163863Sthompsa req->ifbr_proto = bp->bp_protover; 1197163863Sthompsa req->ifbr_role = bp->bp_role; 1198163863Sthompsa req->ifbr_stpflags = bp->bp_flags; 1199173320Sthompsa req->ifbr_addrcnt = bif->bif_addrcnt; 1200173320Sthompsa req->ifbr_addrmax = bif->bif_addrmax; 1201173320Sthompsa req->ifbr_addrexceeded = bif->bif_addrexceeded; 1202146985Sthompsa 1203164653Sthompsa /* Copy STP state options as flags */ 1204164653Sthompsa if (bp->bp_operedge) 1205164653Sthompsa req->ifbr_ifsflags |= IFBIF_BSTP_EDGE; 1206164653Sthompsa if (bp->bp_flags & BSTP_PORT_AUTOEDGE) 1207164653Sthompsa req->ifbr_ifsflags |= IFBIF_BSTP_AUTOEDGE; 1208165105Sthompsa if (bp->bp_ptp_link) 1209165105Sthompsa req->ifbr_ifsflags |= IFBIF_BSTP_PTP; 1210165105Sthompsa if (bp->bp_flags & BSTP_PORT_AUTOPTP) 1211165105Sthompsa req->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP; 1212164880Ssyrinx if (bp->bp_flags & BSTP_PORT_ADMEDGE) 1213164880Ssyrinx req->ifbr_ifsflags |= IFBIF_BSTP_ADMEDGE; 1214164880Ssyrinx if (bp->bp_flags & BSTP_PORT_ADMCOST) 1215164880Ssyrinx req->ifbr_ifsflags |= IFBIF_BSTP_ADMCOST; 1216146985Sthompsa return (0); 1217146985Sthompsa} 1218146985Sthompsa 1219151313Sthompsastatic int 1220146985Sthompsabridge_ioctl_sifflags(struct bridge_softc *sc, void *arg) 1221146985Sthompsa{ 1222146985Sthompsa struct ifbreq *req = arg; 1223146985Sthompsa struct bridge_iflist *bif; 1224164653Sthompsa struct bstp_port *bp; 1225160703Sthompsa int error; 1226146985Sthompsa 1227146985Sthompsa bif = bridge_lookup_member(sc, req->ifbr_ifsname); 1228146985Sthompsa if (bif == NULL) 1229146985Sthompsa return (ENOENT); 1230164653Sthompsa bp = &bif->bif_stp; 1231146985Sthompsa 1232153408Sthompsa if (req->ifbr_ifsflags & IFBIF_SPAN) 1233153408Sthompsa /* SPAN is readonly */ 1234153408Sthompsa return (EINVAL); 1235153408Sthompsa 1236146985Sthompsa if (req->ifbr_ifsflags & IFBIF_STP) { 1237160703Sthompsa if ((bif->bif_flags & IFBIF_STP) == 0) { 1238164626Sthompsa error = bstp_enable(&bif->bif_stp); 1239160703Sthompsa if (error) 1240160703Sthompsa return (error); 1241146985Sthompsa } 1242160703Sthompsa } else { 1243160703Sthompsa if ((bif->bif_flags & IFBIF_STP) != 0) 1244164626Sthompsa bstp_disable(&bif->bif_stp); 1245146985Sthompsa } 1246146985Sthompsa 1247164653Sthompsa /* Pass on STP flags */ 1248164653Sthompsa bstp_set_edge(bp, req->ifbr_ifsflags & IFBIF_BSTP_EDGE ? 1 : 0); 1249164653Sthompsa bstp_set_autoedge(bp, req->ifbr_ifsflags & IFBIF_BSTP_AUTOEDGE ? 1 : 0); 1250165105Sthompsa bstp_set_ptp(bp, req->ifbr_ifsflags & IFBIF_BSTP_PTP ? 1 : 0); 1251165105Sthompsa bstp_set_autoptp(bp, req->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP ? 1 : 0); 1252146985Sthompsa 1253164653Sthompsa /* Save the bits relating to the bridge */ 1254164653Sthompsa bif->bif_flags = req->ifbr_ifsflags & IFBIFMASK; 1255164653Sthompsa 1256146985Sthompsa return (0); 1257146985Sthompsa} 1258146985Sthompsa 1259151313Sthompsastatic int 1260146985Sthompsabridge_ioctl_scache(struct bridge_softc *sc, void *arg) 1261146985Sthompsa{ 1262146985Sthompsa struct ifbrparam *param = arg; 1263146985Sthompsa 1264146985Sthompsa sc->sc_brtmax = param->ifbrp_csize; 1265146985Sthompsa bridge_rttrim(sc); 1266146985Sthompsa 1267146985Sthompsa return (0); 1268146985Sthompsa} 1269146985Sthompsa 1270151313Sthompsastatic int 1271146985Sthompsabridge_ioctl_gcache(struct bridge_softc *sc, void *arg) 1272146985Sthompsa{ 1273146985Sthompsa struct ifbrparam *param = arg; 1274146985Sthompsa 1275146985Sthompsa param->ifbrp_csize = sc->sc_brtmax; 1276146985Sthompsa 1277146985Sthompsa return (0); 1278146985Sthompsa} 1279146985Sthompsa 1280151313Sthompsastatic int 1281146985Sthompsabridge_ioctl_gifs(struct bridge_softc *sc, void *arg) 1282146985Sthompsa{ 1283146985Sthompsa struct ifbifconf *bifc = arg; 1284146985Sthompsa struct bridge_iflist *bif; 1285146985Sthompsa struct ifbreq breq; 1286171603Sthompsa char *buf, *outbuf; 1287171603Sthompsa int count, buflen, len, error = 0; 1288146985Sthompsa 1289146985Sthompsa count = 0; 1290146985Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) 1291146985Sthompsa count++; 1292153408Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) 1293153408Sthompsa count++; 1294146985Sthompsa 1295171603Sthompsa buflen = sizeof(breq) * count; 1296146985Sthompsa if (bifc->ifbic_len == 0) { 1297171603Sthompsa bifc->ifbic_len = buflen; 1298146985Sthompsa return (0); 1299146985Sthompsa } 1300171603Sthompsa BRIDGE_UNLOCK(sc); 1301171603Sthompsa outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); 1302171603Sthompsa BRIDGE_LOCK(sc); 1303146985Sthompsa 1304146985Sthompsa count = 0; 1305171603Sthompsa buf = outbuf; 1306171603Sthompsa len = min(bifc->ifbic_len, buflen); 1307158667Sthompsa bzero(&breq, sizeof(breq)); 1308146985Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 1309146985Sthompsa if (len < sizeof(breq)) 1310146985Sthompsa break; 1311146985Sthompsa 1312146985Sthompsa strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname, 1313146985Sthompsa sizeof(breq.ifbr_ifsname)); 1314164653Sthompsa /* Fill in the ifbreq structure */ 1315164653Sthompsa error = bridge_ioctl_gifflags(sc, &breq); 1316164653Sthompsa if (error) 1317164653Sthompsa break; 1318171603Sthompsa memcpy(buf, &breq, sizeof(breq)); 1319146985Sthompsa count++; 1320171603Sthompsa buf += sizeof(breq); 1321146985Sthompsa len -= sizeof(breq); 1322146985Sthompsa } 1323153408Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) { 1324153408Sthompsa if (len < sizeof(breq)) 1325153408Sthompsa break; 1326146985Sthompsa 1327153408Sthompsa strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname, 1328153408Sthompsa sizeof(breq.ifbr_ifsname)); 1329153408Sthompsa breq.ifbr_ifsflags = bif->bif_flags; 1330163863Sthompsa breq.ifbr_portno = bif->bif_ifp->if_index & 0xfff; 1331171603Sthompsa memcpy(buf, &breq, sizeof(breq)); 1332153408Sthompsa count++; 1333171603Sthompsa buf += sizeof(breq); 1334153408Sthompsa len -= sizeof(breq); 1335153408Sthompsa } 1336153408Sthompsa 1337171603Sthompsa BRIDGE_UNLOCK(sc); 1338146985Sthompsa bifc->ifbic_len = sizeof(breq) * count; 1339171603Sthompsa error = copyout(outbuf, bifc->ifbic_req, bifc->ifbic_len); 1340171603Sthompsa BRIDGE_LOCK(sc); 1341171603Sthompsa free(outbuf, M_TEMP); 1342146985Sthompsa return (error); 1343146985Sthompsa} 1344146985Sthompsa 1345151313Sthompsastatic int 1346146985Sthompsabridge_ioctl_rts(struct bridge_softc *sc, void *arg) 1347146985Sthompsa{ 1348146985Sthompsa struct ifbaconf *bac = arg; 1349146985Sthompsa struct bridge_rtnode *brt; 1350146985Sthompsa struct ifbareq bareq; 1351171603Sthompsa char *buf, *outbuf; 1352171603Sthompsa int count, buflen, len, error = 0; 1353146985Sthompsa 1354146985Sthompsa if (bac->ifbac_len == 0) 1355146985Sthompsa return (0); 1356146985Sthompsa 1357171603Sthompsa count = 0; 1358171603Sthompsa LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) 1359171603Sthompsa count++; 1360171603Sthompsa buflen = sizeof(bareq) * count; 1361171603Sthompsa 1362171603Sthompsa BRIDGE_UNLOCK(sc); 1363171603Sthompsa outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); 1364171603Sthompsa BRIDGE_LOCK(sc); 1365171603Sthompsa 1366171603Sthompsa count = 0; 1367171603Sthompsa buf = outbuf; 1368171603Sthompsa len = min(bac->ifbac_len, buflen); 1369158667Sthompsa bzero(&bareq, sizeof(bareq)); 1370146985Sthompsa LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { 1371146985Sthompsa if (len < sizeof(bareq)) 1372146985Sthompsa goto out; 1373146985Sthompsa strlcpy(bareq.ifba_ifsname, brt->brt_ifp->if_xname, 1374146985Sthompsa sizeof(bareq.ifba_ifsname)); 1375146985Sthompsa memcpy(bareq.ifba_dst, brt->brt_addr, sizeof(brt->brt_addr)); 1376170681Sthompsa bareq.ifba_vlan = brt->brt_vlan; 1377146985Sthompsa if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && 1378153976Sthompsa time_uptime < brt->brt_expire) 1379153976Sthompsa bareq.ifba_expire = brt->brt_expire - time_uptime; 1380146985Sthompsa else 1381146985Sthompsa bareq.ifba_expire = 0; 1382146985Sthompsa bareq.ifba_flags = brt->brt_flags; 1383146985Sthompsa 1384171603Sthompsa memcpy(buf, &bareq, sizeof(bareq)); 1385146985Sthompsa count++; 1386171603Sthompsa buf += sizeof(bareq); 1387146985Sthompsa len -= sizeof(bareq); 1388146985Sthompsa } 1389153497Sthompsaout: 1390171603Sthompsa BRIDGE_UNLOCK(sc); 1391146985Sthompsa bac->ifbac_len = sizeof(bareq) * count; 1392171603Sthompsa error = copyout(outbuf, bac->ifbac_req, bac->ifbac_len); 1393171603Sthompsa BRIDGE_LOCK(sc); 1394171603Sthompsa free(outbuf, M_TEMP); 1395146985Sthompsa return (error); 1396146985Sthompsa} 1397146985Sthompsa 1398151313Sthompsastatic int 1399146985Sthompsabridge_ioctl_saddr(struct bridge_softc *sc, void *arg) 1400146985Sthompsa{ 1401146985Sthompsa struct ifbareq *req = arg; 1402146985Sthompsa struct bridge_iflist *bif; 1403146985Sthompsa int error; 1404146985Sthompsa 1405146985Sthompsa bif = bridge_lookup_member(sc, req->ifba_ifsname); 1406146985Sthompsa if (bif == NULL) 1407146985Sthompsa return (ENOENT); 1408146985Sthompsa 1409170681Sthompsa error = bridge_rtupdate(sc, req->ifba_dst, req->ifba_vlan, bif, 1, 1410146985Sthompsa req->ifba_flags); 1411146985Sthompsa 1412146985Sthompsa return (error); 1413146985Sthompsa} 1414146985Sthompsa 1415151313Sthompsastatic int 1416146985Sthompsabridge_ioctl_sto(struct bridge_softc *sc, void *arg) 1417146985Sthompsa{ 1418146985Sthompsa struct ifbrparam *param = arg; 1419146985Sthompsa 1420146985Sthompsa sc->sc_brttimeout = param->ifbrp_ctime; 1421146985Sthompsa return (0); 1422146985Sthompsa} 1423146985Sthompsa 1424151313Sthompsastatic int 1425146985Sthompsabridge_ioctl_gto(struct bridge_softc *sc, void *arg) 1426146985Sthompsa{ 1427146985Sthompsa struct ifbrparam *param = arg; 1428146985Sthompsa 1429146985Sthompsa param->ifbrp_ctime = sc->sc_brttimeout; 1430146985Sthompsa return (0); 1431146985Sthompsa} 1432146985Sthompsa 1433151313Sthompsastatic int 1434146985Sthompsabridge_ioctl_daddr(struct bridge_softc *sc, void *arg) 1435146985Sthompsa{ 1436146985Sthompsa struct ifbareq *req = arg; 1437146985Sthompsa 1438170681Sthompsa return (bridge_rtdaddr(sc, req->ifba_dst, req->ifba_vlan)); 1439146985Sthompsa} 1440146985Sthompsa 1441151313Sthompsastatic int 1442146985Sthompsabridge_ioctl_flush(struct bridge_softc *sc, void *arg) 1443146985Sthompsa{ 1444146985Sthompsa struct ifbreq *req = arg; 1445146985Sthompsa 1446146985Sthompsa bridge_rtflush(sc, req->ifbr_ifsflags); 1447146985Sthompsa return (0); 1448146985Sthompsa} 1449146985Sthompsa 1450151313Sthompsastatic int 1451146985Sthompsabridge_ioctl_gpri(struct bridge_softc *sc, void *arg) 1452146985Sthompsa{ 1453146985Sthompsa struct ifbrparam *param = arg; 1454160703Sthompsa struct bstp_state *bs = &sc->sc_stp; 1455146985Sthompsa 1456160703Sthompsa param->ifbrp_prio = bs->bs_bridge_priority; 1457146985Sthompsa return (0); 1458146985Sthompsa} 1459146985Sthompsa 1460151313Sthompsastatic int 1461146985Sthompsabridge_ioctl_spri(struct bridge_softc *sc, void *arg) 1462146985Sthompsa{ 1463146985Sthompsa struct ifbrparam *param = arg; 1464146985Sthompsa 1465163863Sthompsa return (bstp_set_priority(&sc->sc_stp, param->ifbrp_prio)); 1466146985Sthompsa} 1467146985Sthompsa 1468151313Sthompsastatic int 1469146985Sthompsabridge_ioctl_ght(struct bridge_softc *sc, void *arg) 1470146985Sthompsa{ 1471146985Sthompsa struct ifbrparam *param = arg; 1472160703Sthompsa struct bstp_state *bs = &sc->sc_stp; 1473146985Sthompsa 1474163863Sthompsa param->ifbrp_hellotime = bs->bs_bridge_htime >> 8; 1475146985Sthompsa return (0); 1476146985Sthompsa} 1477146985Sthompsa 1478151313Sthompsastatic int 1479146985Sthompsabridge_ioctl_sht(struct bridge_softc *sc, void *arg) 1480146985Sthompsa{ 1481146985Sthompsa struct ifbrparam *param = arg; 1482146985Sthompsa 1483163863Sthompsa return (bstp_set_htime(&sc->sc_stp, param->ifbrp_hellotime)); 1484146985Sthompsa} 1485146985Sthompsa 1486151313Sthompsastatic int 1487146985Sthompsabridge_ioctl_gfd(struct bridge_softc *sc, void *arg) 1488146985Sthompsa{ 1489146985Sthompsa struct ifbrparam *param = arg; 1490160703Sthompsa struct bstp_state *bs = &sc->sc_stp; 1491146985Sthompsa 1492163863Sthompsa param->ifbrp_fwddelay = bs->bs_bridge_fdelay >> 8; 1493146985Sthompsa return (0); 1494146985Sthompsa} 1495146985Sthompsa 1496151313Sthompsastatic int 1497146985Sthompsabridge_ioctl_sfd(struct bridge_softc *sc, void *arg) 1498146985Sthompsa{ 1499146985Sthompsa struct ifbrparam *param = arg; 1500146985Sthompsa 1501163863Sthompsa return (bstp_set_fdelay(&sc->sc_stp, param->ifbrp_fwddelay)); 1502146985Sthompsa} 1503146985Sthompsa 1504151313Sthompsastatic int 1505146985Sthompsabridge_ioctl_gma(struct bridge_softc *sc, void *arg) 1506146985Sthompsa{ 1507146985Sthompsa struct ifbrparam *param = arg; 1508160703Sthompsa struct bstp_state *bs = &sc->sc_stp; 1509146985Sthompsa 1510160703Sthompsa param->ifbrp_maxage = bs->bs_bridge_max_age >> 8; 1511146985Sthompsa return (0); 1512146985Sthompsa} 1513146985Sthompsa 1514151313Sthompsastatic int 1515146985Sthompsabridge_ioctl_sma(struct bridge_softc *sc, void *arg) 1516146985Sthompsa{ 1517146985Sthompsa struct ifbrparam *param = arg; 1518146985Sthompsa 1519163863Sthompsa return (bstp_set_maxage(&sc->sc_stp, param->ifbrp_maxage)); 1520146985Sthompsa} 1521146985Sthompsa 1522151313Sthompsastatic int 1523146985Sthompsabridge_ioctl_sifprio(struct bridge_softc *sc, void *arg) 1524146985Sthompsa{ 1525146985Sthompsa struct ifbreq *req = arg; 1526146985Sthompsa struct bridge_iflist *bif; 1527146985Sthompsa 1528146985Sthompsa bif = bridge_lookup_member(sc, req->ifbr_ifsname); 1529146985Sthompsa if (bif == NULL) 1530146985Sthompsa return (ENOENT); 1531146985Sthompsa 1532163863Sthompsa return (bstp_set_port_priority(&bif->bif_stp, req->ifbr_priority)); 1533146985Sthompsa} 1534146985Sthompsa 1535151313Sthompsastatic int 1536146985Sthompsabridge_ioctl_sifcost(struct bridge_softc *sc, void *arg) 1537146985Sthompsa{ 1538146985Sthompsa struct ifbreq *req = arg; 1539146985Sthompsa struct bridge_iflist *bif; 1540146985Sthompsa 1541146985Sthompsa bif = bridge_lookup_member(sc, req->ifbr_ifsname); 1542146985Sthompsa if (bif == NULL) 1543146985Sthompsa return (ENOENT); 1544146985Sthompsa 1545163863Sthompsa return (bstp_set_path_cost(&bif->bif_stp, req->ifbr_path_cost)); 1546146985Sthompsa} 1547146985Sthompsa 1548153408Sthompsastatic int 1549173320Sthompsabridge_ioctl_sifmaxaddr(struct bridge_softc *sc, void *arg) 1550173320Sthompsa{ 1551173320Sthompsa struct ifbreq *req = arg; 1552173320Sthompsa struct bridge_iflist *bif; 1553173320Sthompsa 1554173320Sthompsa bif = bridge_lookup_member(sc, req->ifbr_ifsname); 1555173320Sthompsa if (bif == NULL) 1556173320Sthompsa return (ENOENT); 1557173320Sthompsa 1558173320Sthompsa bif->bif_addrmax = req->ifbr_addrmax; 1559173320Sthompsa return (0); 1560173320Sthompsa} 1561173320Sthompsa 1562173320Sthompsastatic int 1563153408Sthompsabridge_ioctl_addspan(struct bridge_softc *sc, void *arg) 1564153408Sthompsa{ 1565153408Sthompsa struct ifbreq *req = arg; 1566153408Sthompsa struct bridge_iflist *bif = NULL; 1567153408Sthompsa struct ifnet *ifs; 1568153408Sthompsa 1569153408Sthompsa ifs = ifunit(req->ifbr_ifsname); 1570153408Sthompsa if (ifs == NULL) 1571153408Sthompsa return (ENOENT); 1572153408Sthompsa 1573153408Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) 1574153408Sthompsa if (ifs == bif->bif_ifp) 1575153408Sthompsa return (EBUSY); 1576153408Sthompsa 1577153408Sthompsa if (ifs->if_bridge != NULL) 1578153408Sthompsa return (EBUSY); 1579153408Sthompsa 1580153408Sthompsa switch (ifs->if_type) { 1581153408Sthompsa case IFT_ETHER: 1582159807Sthompsa case IFT_GIF: 1583153408Sthompsa case IFT_L2VLAN: 1584153408Sthompsa break; 1585153408Sthompsa default: 1586153408Sthompsa return (EINVAL); 1587153408Sthompsa } 1588153408Sthompsa 1589153408Sthompsa bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO); 1590153408Sthompsa if (bif == NULL) 1591153408Sthompsa return (ENOMEM); 1592153408Sthompsa 1593153408Sthompsa bif->bif_ifp = ifs; 1594153408Sthompsa bif->bif_flags = IFBIF_SPAN; 1595153408Sthompsa 1596153408Sthompsa LIST_INSERT_HEAD(&sc->sc_spanlist, bif, bif_next); 1597153408Sthompsa 1598153408Sthompsa return (0); 1599153408Sthompsa} 1600153408Sthompsa 1601153408Sthompsastatic int 1602153408Sthompsabridge_ioctl_delspan(struct bridge_softc *sc, void *arg) 1603153408Sthompsa{ 1604153408Sthompsa struct ifbreq *req = arg; 1605153408Sthompsa struct bridge_iflist *bif; 1606153408Sthompsa struct ifnet *ifs; 1607153408Sthompsa 1608153408Sthompsa ifs = ifunit(req->ifbr_ifsname); 1609153408Sthompsa if (ifs == NULL) 1610153408Sthompsa return (ENOENT); 1611153408Sthompsa 1612153408Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) 1613153408Sthompsa if (ifs == bif->bif_ifp) 1614153408Sthompsa break; 1615153408Sthompsa 1616153408Sthompsa if (bif == NULL) 1617153408Sthompsa return (ENOENT); 1618153408Sthompsa 1619153494Sthompsa bridge_delete_span(sc, bif); 1620153408Sthompsa 1621153408Sthompsa return (0); 1622153408Sthompsa} 1623153408Sthompsa 1624160867Sthompsastatic int 1625160867Sthompsabridge_ioctl_gbparam(struct bridge_softc *sc, void *arg) 1626160867Sthompsa{ 1627160867Sthompsa struct ifbropreq *req = arg; 1628163863Sthompsa struct bstp_state *bs = &sc->sc_stp; 1629160867Sthompsa struct bstp_port *root_port; 1630160867Sthompsa 1631163863Sthompsa req->ifbop_maxage = bs->bs_bridge_max_age >> 8; 1632163863Sthompsa req->ifbop_hellotime = bs->bs_bridge_htime >> 8; 1633163863Sthompsa req->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8; 1634160867Sthompsa 1635163863Sthompsa root_port = bs->bs_root_port; 1636160867Sthompsa if (root_port == NULL) 1637160867Sthompsa req->ifbop_root_port = 0; 1638160867Sthompsa else 1639160867Sthompsa req->ifbop_root_port = root_port->bp_ifp->if_index; 1640160867Sthompsa 1641163863Sthompsa req->ifbop_holdcount = bs->bs_txholdcount; 1642163863Sthompsa req->ifbop_priority = bs->bs_bridge_priority; 1643163863Sthompsa req->ifbop_protocol = bs->bs_protover; 1644163863Sthompsa req->ifbop_root_path_cost = bs->bs_root_pv.pv_cost; 1645164653Sthompsa req->ifbop_bridgeid = bs->bs_bridge_pv.pv_dbridge_id; 1646163863Sthompsa req->ifbop_designated_root = bs->bs_root_pv.pv_root_id; 1647164653Sthompsa req->ifbop_designated_bridge = bs->bs_root_pv.pv_dbridge_id; 1648163863Sthompsa req->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec; 1649163863Sthompsa req->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec; 1650160867Sthompsa 1651160867Sthompsa return (0); 1652160867Sthompsa} 1653160867Sthompsa 1654160867Sthompsastatic int 1655160867Sthompsabridge_ioctl_grte(struct bridge_softc *sc, void *arg) 1656160867Sthompsa{ 1657160867Sthompsa struct ifbrparam *param = arg; 1658160867Sthompsa 1659160867Sthompsa param->ifbrp_cexceeded = sc->sc_brtexceeded; 1660160867Sthompsa return (0); 1661160867Sthompsa} 1662160867Sthompsa 1663160867Sthompsastatic int 1664160867Sthompsabridge_ioctl_gifsstp(struct bridge_softc *sc, void *arg) 1665160867Sthompsa{ 1666160867Sthompsa struct ifbpstpconf *bifstp = arg; 1667160867Sthompsa struct bridge_iflist *bif; 1668163863Sthompsa struct bstp_port *bp; 1669160867Sthompsa struct ifbpstpreq bpreq; 1670171603Sthompsa char *buf, *outbuf; 1671171603Sthompsa int count, buflen, len, error = 0; 1672160867Sthompsa 1673160867Sthompsa count = 0; 1674160867Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 1675160867Sthompsa if ((bif->bif_flags & IFBIF_STP) != 0) 1676160867Sthompsa count++; 1677160867Sthompsa } 1678160867Sthompsa 1679171603Sthompsa buflen = sizeof(bpreq) * count; 1680160867Sthompsa if (bifstp->ifbpstp_len == 0) { 1681171603Sthompsa bifstp->ifbpstp_len = buflen; 1682160867Sthompsa return (0); 1683160867Sthompsa } 1684160867Sthompsa 1685171603Sthompsa BRIDGE_UNLOCK(sc); 1686171603Sthompsa outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); 1687171603Sthompsa BRIDGE_LOCK(sc); 1688171603Sthompsa 1689160867Sthompsa count = 0; 1690171603Sthompsa buf = outbuf; 1691171603Sthompsa len = min(bifstp->ifbpstp_len, buflen); 1692160867Sthompsa bzero(&bpreq, sizeof(bpreq)); 1693160867Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 1694160867Sthompsa if (len < sizeof(bpreq)) 1695160867Sthompsa break; 1696160867Sthompsa 1697160867Sthompsa if ((bif->bif_flags & IFBIF_STP) == 0) 1698160867Sthompsa continue; 1699160867Sthompsa 1700163863Sthompsa bp = &bif->bif_stp; 1701163863Sthompsa bpreq.ifbp_portno = bif->bif_ifp->if_index & 0xfff; 1702163863Sthompsa bpreq.ifbp_fwd_trans = bp->bp_forward_transitions; 1703163863Sthompsa bpreq.ifbp_design_cost = bp->bp_desg_pv.pv_cost; 1704163863Sthompsa bpreq.ifbp_design_port = bp->bp_desg_pv.pv_port_id; 1705163863Sthompsa bpreq.ifbp_design_bridge = bp->bp_desg_pv.pv_dbridge_id; 1706163863Sthompsa bpreq.ifbp_design_root = bp->bp_desg_pv.pv_root_id; 1707160867Sthompsa 1708171603Sthompsa memcpy(buf, &bpreq, sizeof(bpreq)); 1709160867Sthompsa count++; 1710171603Sthompsa buf += sizeof(bpreq); 1711160867Sthompsa len -= sizeof(bpreq); 1712160867Sthompsa } 1713160867Sthompsa 1714171603Sthompsa BRIDGE_UNLOCK(sc); 1715160867Sthompsa bifstp->ifbpstp_len = sizeof(bpreq) * count; 1716171603Sthompsa error = copyout(outbuf, bifstp->ifbpstp_req, bifstp->ifbpstp_len); 1717171603Sthompsa BRIDGE_LOCK(sc); 1718171603Sthompsa free(outbuf, M_TEMP); 1719160867Sthompsa return (error); 1720160867Sthompsa} 1721160867Sthompsa 1722163863Sthompsastatic int 1723163863Sthompsabridge_ioctl_sproto(struct bridge_softc *sc, void *arg) 1724163863Sthompsa{ 1725163863Sthompsa struct ifbrparam *param = arg; 1726163863Sthompsa 1727163863Sthompsa return (bstp_set_protocol(&sc->sc_stp, param->ifbrp_proto)); 1728163863Sthompsa} 1729163863Sthompsa 1730163863Sthompsastatic int 1731163863Sthompsabridge_ioctl_stxhc(struct bridge_softc *sc, void *arg) 1732163863Sthompsa{ 1733163863Sthompsa struct ifbrparam *param = arg; 1734163863Sthompsa 1735163863Sthompsa return (bstp_set_holdcount(&sc->sc_stp, param->ifbrp_txhc)); 1736163863Sthompsa} 1737163863Sthompsa 1738146985Sthompsa/* 1739146985Sthompsa * bridge_ifdetach: 1740146985Sthompsa * 1741146985Sthompsa * Detach an interface from a bridge. Called when a member 1742146985Sthompsa * interface is detaching. 1743146985Sthompsa */ 1744151313Sthompsastatic void 1745153494Sthompsabridge_ifdetach(void *arg __unused, struct ifnet *ifp) 1746146985Sthompsa{ 1747146985Sthompsa struct bridge_softc *sc = ifp->if_bridge; 1748151594Sthompsa struct bridge_iflist *bif; 1749146985Sthompsa 1750250480Smarkj if (ifp->if_flags & IFF_RENAMING) 1751250480Smarkj return; 1752250480Smarkj 1753153494Sthompsa /* Check if the interface is a bridge member */ 1754153494Sthompsa if (sc != NULL) { 1755153494Sthompsa BRIDGE_LOCK(sc); 1756146985Sthompsa 1757153494Sthompsa bif = bridge_lookup_member_if(sc, ifp); 1758153494Sthompsa if (bif != NULL) 1759153494Sthompsa bridge_delete_member(sc, bif, 1); 1760153494Sthompsa 1761153494Sthompsa BRIDGE_UNLOCK(sc); 1762151594Sthompsa return; 1763153494Sthompsa } 1764146985Sthompsa 1765153494Sthompsa /* Check if the interface is a span port */ 1766153494Sthompsa mtx_lock(&bridge_list_mtx); 1767153494Sthompsa LIST_FOREACH(sc, &bridge_list, sc_list) { 1768153494Sthompsa BRIDGE_LOCK(sc); 1769153494Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) 1770153494Sthompsa if (ifp == bif->bif_ifp) { 1771153494Sthompsa bridge_delete_span(sc, bif); 1772153494Sthompsa break; 1773153494Sthompsa } 1774151594Sthompsa 1775153494Sthompsa BRIDGE_UNLOCK(sc); 1776153494Sthompsa } 1777153494Sthompsa mtx_unlock(&bridge_list_mtx); 1778146985Sthompsa} 1779146985Sthompsa 1780146985Sthompsa/* 1781146985Sthompsa * bridge_init: 1782146985Sthompsa * 1783146985Sthompsa * Initialize a bridge interface. 1784146985Sthompsa */ 1785146985Sthompsastatic void 1786146985Sthompsabridge_init(void *xsc) 1787146985Sthompsa{ 1788146985Sthompsa struct bridge_softc *sc = (struct bridge_softc *)xsc; 1789147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 1790146985Sthompsa 1791148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1792146985Sthompsa return; 1793146985Sthompsa 1794149253Sthompsa BRIDGE_LOCK(sc); 1795146985Sthompsa callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz, 1796146985Sthompsa bridge_timer, sc); 1797146985Sthompsa 1798148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1799160703Sthompsa bstp_init(&sc->sc_stp); /* Initialize Spanning Tree */ 1800160703Sthompsa 1801149064Sthompsa BRIDGE_UNLOCK(sc); 1802146985Sthompsa} 1803146985Sthompsa 1804146985Sthompsa/* 1805146985Sthompsa * bridge_stop: 1806146985Sthompsa * 1807146985Sthompsa * Stop the bridge interface. 1808146985Sthompsa */ 1809151313Sthompsastatic void 1810146985Sthompsabridge_stop(struct ifnet *ifp, int disable) 1811146985Sthompsa{ 1812146985Sthompsa struct bridge_softc *sc = ifp->if_softc; 1813146985Sthompsa 1814149064Sthompsa BRIDGE_LOCK_ASSERT(sc); 1815149064Sthompsa 1816148887Srwatson if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1817146985Sthompsa return; 1818146985Sthompsa 1819146985Sthompsa callout_stop(&sc->sc_brcallout); 1820160703Sthompsa bstp_stop(&sc->sc_stp); 1821146985Sthompsa 1822146985Sthompsa bridge_rtflush(sc, IFBF_FLUSHDYN); 1823146985Sthompsa 1824148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1825146985Sthompsa} 1826146985Sthompsa 1827146985Sthompsa/* 1828146985Sthompsa * bridge_enqueue: 1829146985Sthompsa * 1830146985Sthompsa * Enqueue a packet on a bridge member interface. 1831146985Sthompsa * 1832146985Sthompsa */ 1833160769Sthompsastatic void 1834147786Sthompsabridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m) 1835146985Sthompsa{ 1836158140Sthompsa int len, err = 0; 1837146985Sthompsa short mflags; 1838158140Sthompsa struct mbuf *m0; 1839146985Sthompsa 1840146985Sthompsa len = m->m_pkthdr.len; 1841146985Sthompsa mflags = m->m_flags; 1842148372Sthompsa 1843159759Sthompsa /* We may be sending a fragment so traverse the mbuf */ 1844158140Sthompsa for (; m; m = m0) { 1845158140Sthompsa m0 = m->m_nextpkt; 1846158140Sthompsa m->m_nextpkt = NULL; 1847172770Sthompsa 1848172770Sthompsa /* 1849172770Sthompsa * If underlying interface can not do VLAN tag insertion itself 1850172770Sthompsa * then attach a packet tag that holds it. 1851172770Sthompsa */ 1852172770Sthompsa if ((m->m_flags & M_VLANTAG) && 1853172770Sthompsa (dst_ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) { 1854172770Sthompsa m = ether_vlanencap(m, m->m_pkthdr.ether_vtag); 1855172770Sthompsa if (m == NULL) { 1856172770Sthompsa if_printf(dst_ifp, 1857172770Sthompsa "unable to prepend VLAN header\n"); 1858172770Sthompsa dst_ifp->if_oerrors++; 1859172770Sthompsa continue; 1860172770Sthompsa } 1861172770Sthompsa m->m_flags &= ~M_VLANTAG; 1862172770Sthompsa } 1863172770Sthompsa 1864243289Semaste if ((err = dst_ifp->if_transmit(dst_ifp, m))) { 1865243289Semaste m_freem(m0); 1866243289Semaste break; 1867243289Semaste } 1868158140Sthompsa } 1869158140Sthompsa 1870146985Sthompsa if (err == 0) { 1871147256Sbrooks sc->sc_ifp->if_opackets++; 1872147256Sbrooks sc->sc_ifp->if_obytes += len; 1873191603Ssam if (mflags & M_MCAST) 1874147256Sbrooks sc->sc_ifp->if_omcasts++; 1875146985Sthompsa } 1876146985Sthompsa} 1877146985Sthompsa 1878146985Sthompsa/* 1879147205Sthompsa * bridge_dummynet: 1880147205Sthompsa * 1881147205Sthompsa * Receive a queued packet from dummynet and pass it on to the output 1882147205Sthompsa * interface. 1883147205Sthompsa * 1884147205Sthompsa * The mbuf has the Ethernet header already attached. 1885147205Sthompsa */ 1886151313Sthompsastatic void 1887147205Sthompsabridge_dummynet(struct mbuf *m, struct ifnet *ifp) 1888147205Sthompsa{ 1889147205Sthompsa struct bridge_softc *sc; 1890147205Sthompsa 1891147205Sthompsa sc = ifp->if_bridge; 1892147205Sthompsa 1893147205Sthompsa /* 1894147205Sthompsa * The packet didnt originate from a member interface. This should only 1895147205Sthompsa * ever happen if a member interface is removed while packets are 1896147205Sthompsa * queued for it. 1897147205Sthompsa */ 1898147251Smlaier if (sc == NULL) { 1899147205Sthompsa m_freem(m); 1900147205Sthompsa return; 1901147251Smlaier } 1902147205Sthompsa 1903197952Sjulian if (PFIL_HOOKED(&V_inet_pfil_hook) 1904147786Sthompsa#ifdef INET6 1905197952Sjulian || PFIL_HOOKED(&V_inet6_pfil_hook) 1906147786Sthompsa#endif 1907147786Sthompsa ) { 1908147786Sthompsa if (bridge_pfil(&m, sc->sc_ifp, ifp, PFIL_OUT) != 0) 1909147786Sthompsa return; 1910147786Sthompsa if (m == NULL) 1911147786Sthompsa return; 1912147786Sthompsa } 1913147786Sthompsa 1914147786Sthompsa bridge_enqueue(sc, ifp, m); 1915147205Sthompsa} 1916147205Sthompsa 1917147205Sthompsa/* 1918146985Sthompsa * bridge_output: 1919146985Sthompsa * 1920146985Sthompsa * Send output from a bridge member interface. This 1921146985Sthompsa * performs the bridging function for locally originated 1922146985Sthompsa * packets. 1923146985Sthompsa * 1924146985Sthompsa * The mbuf has the Ethernet header already attached. We must 1925146985Sthompsa * enqueue or free the mbuf before returning. 1926146985Sthompsa */ 1927151313Sthompsastatic int 1928146985Sthompsabridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, 1929146985Sthompsa struct rtentry *rt) 1930146985Sthompsa{ 1931146985Sthompsa struct ether_header *eh; 1932146985Sthompsa struct ifnet *dst_if; 1933146985Sthompsa struct bridge_softc *sc; 1934170681Sthompsa uint16_t vlan; 1935146985Sthompsa 1936146985Sthompsa if (m->m_len < ETHER_HDR_LEN) { 1937146985Sthompsa m = m_pullup(m, ETHER_HDR_LEN); 1938146985Sthompsa if (m == NULL) 1939146985Sthompsa return (0); 1940146985Sthompsa } 1941146985Sthompsa 1942146985Sthompsa eh = mtod(m, struct ether_header *); 1943146985Sthompsa sc = ifp->if_bridge; 1944170681Sthompsa vlan = VLANTAGOF(m); 1945146985Sthompsa 1946146985Sthompsa BRIDGE_LOCK(sc); 1947146985Sthompsa 1948146985Sthompsa /* 1949146985Sthompsa * If bridge is down, but the original output interface is up, 1950146985Sthompsa * go ahead and send out that interface. Otherwise, the packet 1951146985Sthompsa * is dropped below. 1952146985Sthompsa */ 1953148887Srwatson if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1954146985Sthompsa dst_if = ifp; 1955146985Sthompsa goto sendunicast; 1956146985Sthompsa } 1957146985Sthompsa 1958146985Sthompsa /* 1959146985Sthompsa * If the packet is a multicast, or we don't know a better way to 1960146985Sthompsa * get there, send to all interfaces. 1961146985Sthompsa */ 1962146985Sthompsa if (ETHER_IS_MULTICAST(eh->ether_dhost)) 1963146985Sthompsa dst_if = NULL; 1964146985Sthompsa else 1965170681Sthompsa dst_if = bridge_rtlookup(sc, eh->ether_dhost, vlan); 1966146985Sthompsa if (dst_if == NULL) { 1967146985Sthompsa struct bridge_iflist *bif; 1968146985Sthompsa struct mbuf *mc; 1969146985Sthompsa int error = 0, used = 0; 1970146985Sthompsa 1971161401Sthompsa bridge_span(sc, m); 1972161401Sthompsa 1973146985Sthompsa BRIDGE_LOCK2REF(sc, error); 1974146985Sthompsa if (error) { 1975146985Sthompsa m_freem(m); 1976146985Sthompsa return (0); 1977146985Sthompsa } 1978153408Sthompsa 1979146985Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 1980146985Sthompsa dst_if = bif->bif_ifp; 1981153621Sthompsa 1982153621Sthompsa if (dst_if->if_type == IFT_GIF) 1983153621Sthompsa continue; 1984148887Srwatson if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) 1985146985Sthompsa continue; 1986146985Sthompsa 1987146985Sthompsa /* 1988146985Sthompsa * If this is not the original output interface, 1989146985Sthompsa * and the interface is participating in spanning 1990146985Sthompsa * tree, make sure the port is in a state that 1991146985Sthompsa * allows forwarding. 1992146985Sthompsa */ 1993163863Sthompsa if (dst_if != ifp && (bif->bif_flags & IFBIF_STP) && 1994163863Sthompsa bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) 1995163863Sthompsa continue; 1996146985Sthompsa 1997146985Sthompsa if (LIST_NEXT(bif, bif_next) == NULL) { 1998146985Sthompsa used = 1; 1999146985Sthompsa mc = m; 2000146985Sthompsa } else { 2001148874Sthompsa mc = m_copypacket(m, M_DONTWAIT); 2002146985Sthompsa if (mc == NULL) { 2003147256Sbrooks sc->sc_ifp->if_oerrors++; 2004146985Sthompsa continue; 2005146985Sthompsa } 2006146985Sthompsa } 2007146985Sthompsa 2008147786Sthompsa bridge_enqueue(sc, dst_if, mc); 2009146985Sthompsa } 2010146985Sthompsa if (used == 0) 2011146985Sthompsa m_freem(m); 2012146985Sthompsa BRIDGE_UNREF(sc); 2013146985Sthompsa return (0); 2014146985Sthompsa } 2015146985Sthompsa 2016153497Sthompsasendunicast: 2017146985Sthompsa /* 2018146985Sthompsa * XXX Spanning tree consideration here? 2019146985Sthompsa */ 2020146985Sthompsa 2021153408Sthompsa bridge_span(sc, m); 2022148887Srwatson if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) { 2023146985Sthompsa m_freem(m); 2024146985Sthompsa BRIDGE_UNLOCK(sc); 2025146985Sthompsa return (0); 2026146985Sthompsa } 2027146985Sthompsa 2028146985Sthompsa BRIDGE_UNLOCK(sc); 2029147786Sthompsa bridge_enqueue(sc, dst_if, m); 2030146985Sthompsa return (0); 2031146985Sthompsa} 2032146985Sthompsa 2033146985Sthompsa/* 2034146985Sthompsa * bridge_start: 2035146985Sthompsa * 2036146985Sthompsa * Start output on a bridge. 2037146985Sthompsa * 2038146985Sthompsa */ 2039151313Sthompsastatic void 2040146985Sthompsabridge_start(struct ifnet *ifp) 2041146985Sthompsa{ 2042146985Sthompsa struct bridge_softc *sc; 2043146985Sthompsa struct mbuf *m; 2044146985Sthompsa struct ether_header *eh; 2045146985Sthompsa struct ifnet *dst_if; 2046146985Sthompsa 2047146985Sthompsa sc = ifp->if_softc; 2048146985Sthompsa 2049148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2050146985Sthompsa for (;;) { 2051146985Sthompsa IFQ_DEQUEUE(&ifp->if_snd, m); 2052146985Sthompsa if (m == 0) 2053146985Sthompsa break; 2054172824Sthompsa ETHER_BPF_MTAP(ifp, m); 2055146985Sthompsa 2056146985Sthompsa eh = mtod(m, struct ether_header *); 2057146985Sthompsa dst_if = NULL; 2058146985Sthompsa 2059146985Sthompsa BRIDGE_LOCK(sc); 2060146985Sthompsa if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) { 2061170681Sthompsa dst_if = bridge_rtlookup(sc, eh->ether_dhost, 1); 2062146985Sthompsa } 2063146985Sthompsa 2064146985Sthompsa if (dst_if == NULL) 2065150837Sthompsa bridge_broadcast(sc, ifp, m, 0); 2066146985Sthompsa else { 2067146985Sthompsa BRIDGE_UNLOCK(sc); 2068147786Sthompsa bridge_enqueue(sc, dst_if, m); 2069146985Sthompsa } 2070146985Sthompsa } 2071148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2072146985Sthompsa} 2073146985Sthompsa 2074146985Sthompsa/* 2075146985Sthompsa * bridge_forward: 2076146985Sthompsa * 2077146985Sthompsa * The forwarding function of the bridge. 2078146985Sthompsa * 2079146985Sthompsa * NOTE: Releases the lock on return. 2080146985Sthompsa */ 2081151313Sthompsastatic void 2082171678Sthompsabridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif, 2083171678Sthompsa struct mbuf *m) 2084146985Sthompsa{ 2085171678Sthompsa struct bridge_iflist *dbif; 2086146985Sthompsa struct ifnet *src_if, *dst_if, *ifp; 2087146985Sthompsa struct ether_header *eh; 2088170681Sthompsa uint16_t vlan; 2089175419Sthompsa uint8_t *dst; 2090173320Sthompsa int error; 2091146985Sthompsa 2092146985Sthompsa src_if = m->m_pkthdr.rcvif; 2093147256Sbrooks ifp = sc->sc_ifp; 2094146985Sthompsa 2095174749Sthompsa ifp->if_ipackets++; 2096174749Sthompsa ifp->if_ibytes += m->m_pkthdr.len; 2097170681Sthompsa vlan = VLANTAGOF(m); 2098146985Sthompsa 2099171678Sthompsa if ((sbif->bif_flags & IFBIF_STP) && 2100174749Sthompsa sbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) 2101174749Sthompsa goto drop; 2102146985Sthompsa 2103146985Sthompsa eh = mtod(m, struct ether_header *); 2104175419Sthompsa dst = eh->ether_dhost; 2105146985Sthompsa 2106173320Sthompsa /* If the interface is learning, record the address. */ 2107173320Sthompsa if (sbif->bif_flags & IFBIF_LEARNING) { 2108173320Sthompsa error = bridge_rtupdate(sc, eh->ether_shost, vlan, 2109171678Sthompsa sbif, 0, IFBAF_DYNAMIC); 2110173320Sthompsa /* 2111173320Sthompsa * If the interface has addresses limits then deny any source 2112173320Sthompsa * that is not in the cache. 2113173320Sthompsa */ 2114174749Sthompsa if (error && sbif->bif_addrmax) 2115174749Sthompsa goto drop; 2116146985Sthompsa } 2117146985Sthompsa 2118171678Sthompsa if ((sbif->bif_flags & IFBIF_STP) != 0 && 2119174749Sthompsa sbif->bif_stp.bp_state == BSTP_IFSTATE_LEARNING) 2120174749Sthompsa goto drop; 2121146985Sthompsa 2122146985Sthompsa /* 2123146985Sthompsa * At this point, the port either doesn't participate 2124146985Sthompsa * in spanning tree or it is in the forwarding state. 2125146985Sthompsa */ 2126146985Sthompsa 2127146985Sthompsa /* 2128146985Sthompsa * If the packet is unicast, destined for someone on 2129146985Sthompsa * "this" side of the bridge, drop it. 2130146985Sthompsa */ 2131146985Sthompsa if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) { 2132175419Sthompsa dst_if = bridge_rtlookup(sc, dst, vlan); 2133174749Sthompsa if (src_if == dst_if) 2134174749Sthompsa goto drop; 2135146985Sthompsa } else { 2136175419Sthompsa /* 2137175419Sthompsa * Check if its a reserved multicast address, any address 2138175419Sthompsa * listed in 802.1D section 7.12.6 may not be forwarded by the 2139175419Sthompsa * bridge. 2140175419Sthompsa * This is currently 01-80-C2-00-00-00 to 01-80-C2-00-00-0F 2141175419Sthompsa */ 2142175419Sthompsa if (dst[0] == 0x01 && dst[1] == 0x80 && 2143175419Sthompsa dst[2] == 0xc2 && dst[3] == 0x00 && 2144175419Sthompsa dst[4] == 0x00 && dst[5] <= 0x0f) 2145175419Sthompsa goto drop; 2146175419Sthompsa 2147146985Sthompsa /* ...forward it to all interfaces. */ 2148174749Sthompsa ifp->if_imcasts++; 2149146985Sthompsa dst_if = NULL; 2150146985Sthompsa } 2151146985Sthompsa 2152156235Scsjp /* 2153156235Scsjp * If we have a destination interface which is a member of our bridge, 2154156235Scsjp * OR this is a unicast packet, push it through the bpf(4) machinery. 2155156235Scsjp * For broadcast or multicast packets, don't bother because it will 2156156235Scsjp * be reinjected into ether_input. We do this before we pass the packets 2157156235Scsjp * through the pfil(9) framework, as it is possible that pfil(9) will 2158156235Scsjp * drop the packet, or possibly modify it, making it difficult to debug 2159156235Scsjp * firewall issues on the bridge. 2160156235Scsjp */ 2161156235Scsjp if (dst_if != NULL || (m->m_flags & (M_BCAST | M_MCAST)) == 0) 2162172824Sthompsa ETHER_BPF_MTAP(ifp, m); 2163156235Scsjp 2164146985Sthompsa /* run the packet filter */ 2165197952Sjulian if (PFIL_HOOKED(&V_inet_pfil_hook) 2166147786Sthompsa#ifdef INET6 2167197952Sjulian || PFIL_HOOKED(&V_inet6_pfil_hook) 2168147786Sthompsa#endif 2169147786Sthompsa ) { 2170146985Sthompsa BRIDGE_UNLOCK(sc); 2171146985Sthompsa if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0) 2172146985Sthompsa return; 2173147786Sthompsa if (m == NULL) 2174147786Sthompsa return; 2175146985Sthompsa BRIDGE_LOCK(sc); 2176146985Sthompsa } 2177146985Sthompsa 2178146985Sthompsa if (dst_if == NULL) { 2179150837Sthompsa bridge_broadcast(sc, src_if, m, 1); 2180146985Sthompsa return; 2181146985Sthompsa } 2182146985Sthompsa 2183146985Sthompsa /* 2184146985Sthompsa * At this point, we're dealing with a unicast frame 2185146985Sthompsa * going to a different interface. 2186146985Sthompsa */ 2187174749Sthompsa if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) 2188174749Sthompsa goto drop; 2189174749Sthompsa 2190171678Sthompsa dbif = bridge_lookup_member_if(sc, dst_if); 2191174749Sthompsa if (dbif == NULL) 2192146985Sthompsa /* Not a member of the bridge (anymore?) */ 2193174749Sthompsa goto drop; 2194146985Sthompsa 2195171678Sthompsa /* Private segments can not talk to each other */ 2196174749Sthompsa if (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE) 2197174749Sthompsa goto drop; 2198146985Sthompsa 2199171678Sthompsa if ((dbif->bif_flags & IFBIF_STP) && 2200174749Sthompsa dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) 2201174749Sthompsa goto drop; 2202171678Sthompsa 2203146985Sthompsa BRIDGE_UNLOCK(sc); 2204147786Sthompsa 2205197952Sjulian if (PFIL_HOOKED(&V_inet_pfil_hook) 2206147786Sthompsa#ifdef INET6 2207197952Sjulian || PFIL_HOOKED(&V_inet6_pfil_hook) 2208147786Sthompsa#endif 2209147786Sthompsa ) { 2210174749Sthompsa if (bridge_pfil(&m, ifp, dst_if, PFIL_OUT) != 0) 2211147786Sthompsa return; 2212147786Sthompsa if (m == NULL) 2213147786Sthompsa return; 2214147786Sthompsa } 2215147786Sthompsa 2216147786Sthompsa bridge_enqueue(sc, dst_if, m); 2217174749Sthompsa return; 2218174749Sthompsa 2219174749Sthompsadrop: 2220174749Sthompsa BRIDGE_UNLOCK(sc); 2221174749Sthompsa m_freem(m); 2222146985Sthompsa} 2223146985Sthompsa 2224146985Sthompsa/* 2225146985Sthompsa * bridge_input: 2226146985Sthompsa * 2227146985Sthompsa * Receive input from a member interface. Queue the packet for 2228146985Sthompsa * bridging if it is not for us. 2229146985Sthompsa */ 2230151345Sthompsastatic struct mbuf * 2231146985Sthompsabridge_input(struct ifnet *ifp, struct mbuf *m) 2232146985Sthompsa{ 2233146985Sthompsa struct bridge_softc *sc = ifp->if_bridge; 2234164112Sthompsa struct bridge_iflist *bif, *bif2; 2235149829Sthompsa struct ifnet *bifp; 2236146985Sthompsa struct ether_header *eh; 2237149829Sthompsa struct mbuf *mc, *mc2; 2238170681Sthompsa uint16_t vlan; 2239173320Sthompsa int error; 2240146985Sthompsa 2241148887Srwatson if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 2242146985Sthompsa return (m); 2243146985Sthompsa 2244149829Sthompsa bifp = sc->sc_ifp; 2245170681Sthompsa vlan = VLANTAGOF(m); 2246149829Sthompsa 2247156235Scsjp /* 2248156235Scsjp * Implement support for bridge monitoring. If this flag has been 2249156235Scsjp * set on this interface, discard the packet once we push it through 2250156235Scsjp * the bpf(4) machinery, but before we do, increment the byte and 2251156235Scsjp * packet counters associated with this interface. 2252156235Scsjp */ 2253156235Scsjp if ((bifp->if_flags & IFF_MONITOR) != 0) { 2254156235Scsjp m->m_pkthdr.rcvif = bifp; 2255172824Sthompsa ETHER_BPF_MTAP(bifp, m); 2256156235Scsjp bifp->if_ipackets++; 2257156235Scsjp bifp->if_ibytes += m->m_pkthdr.len; 2258164002Scsjp m_freem(m); 2259156235Scsjp return (NULL); 2260156235Scsjp } 2261146985Sthompsa BRIDGE_LOCK(sc); 2262146985Sthompsa bif = bridge_lookup_member_if(sc, ifp); 2263146985Sthompsa if (bif == NULL) { 2264146985Sthompsa BRIDGE_UNLOCK(sc); 2265146985Sthompsa return (m); 2266146985Sthompsa } 2267146985Sthompsa 2268146985Sthompsa eh = mtod(m, struct ether_header *); 2269146985Sthompsa 2270153408Sthompsa bridge_span(sc, m); 2271153408Sthompsa 2272167722Sthompsa if (m->m_flags & (M_BCAST|M_MCAST)) { 2273146985Sthompsa /* Tap off 802.1D packets; they do not get forwarded. */ 2274146985Sthompsa if (memcmp(eh->ether_dhost, bstp_etheraddr, 2275146985Sthompsa ETHER_ADDR_LEN) == 0) { 2276236047Sthompsa bstp_input(&bif->bif_stp, ifp, m); /* consumes mbuf */ 2277236047Sthompsa BRIDGE_UNLOCK(sc); 2278236047Sthompsa return (NULL); 2279146985Sthompsa } 2280146985Sthompsa 2281163863Sthompsa if ((bif->bif_flags & IFBIF_STP) && 2282163863Sthompsa bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { 2283163863Sthompsa BRIDGE_UNLOCK(sc); 2284163863Sthompsa return (m); 2285146985Sthompsa } 2286146985Sthompsa 2287146985Sthompsa /* 2288146985Sthompsa * Make a deep copy of the packet and enqueue the copy 2289146985Sthompsa * for bridge processing; return the original packet for 2290146985Sthompsa * local processing. 2291146985Sthompsa */ 2292146985Sthompsa mc = m_dup(m, M_DONTWAIT); 2293146985Sthompsa if (mc == NULL) { 2294146985Sthompsa BRIDGE_UNLOCK(sc); 2295146985Sthompsa return (m); 2296146985Sthompsa } 2297146985Sthompsa 2298146985Sthompsa /* Perform the bridge forwarding function with the copy. */ 2299171678Sthompsa bridge_forward(sc, bif, mc); 2300146985Sthompsa 2301149829Sthompsa /* 2302149829Sthompsa * Reinject the mbuf as arriving on the bridge so we have a 2303149829Sthompsa * chance at claiming multicast packets. We can not loop back 2304149829Sthompsa * here from ether_input as a bridge is never a member of a 2305149829Sthompsa * bridge. 2306149829Sthompsa */ 2307149829Sthompsa KASSERT(bifp->if_bridge == NULL, 2308149829Sthompsa ("loop created in bridge_input")); 2309153458Sthompsa mc2 = m_dup(m, M_DONTWAIT); 2310149829Sthompsa if (mc2 != NULL) { 2311153458Sthompsa /* Keep the layer3 header aligned */ 2312153458Sthompsa int i = min(mc2->m_pkthdr.len, max_protohdr); 2313153458Sthompsa mc2 = m_copyup(mc2, i, ETHER_ALIGN); 2314153458Sthompsa } 2315153458Sthompsa if (mc2 != NULL) { 2316149829Sthompsa mc2->m_pkthdr.rcvif = bifp; 2317149829Sthompsa (*bifp->if_input)(bifp, mc2); 2318149829Sthompsa } 2319149829Sthompsa 2320146985Sthompsa /* Return the original packet for local processing. */ 2321146985Sthompsa return (m); 2322146985Sthompsa } 2323146985Sthompsa 2324163863Sthompsa if ((bif->bif_flags & IFBIF_STP) && 2325163863Sthompsa bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { 2326163863Sthompsa BRIDGE_UNLOCK(sc); 2327163863Sthompsa return (m); 2328146985Sthompsa } 2329146985Sthompsa 2330211157Swill#if (defined(INET) || defined(INET6)) 2331167683Srik# define OR_CARP_CHECK_WE_ARE_DST(iface) \ 2332167683Srik || ((iface)->if_carp \ 2333211193Swill && (*carp_forus_p)((iface), eh->ether_dhost)) 2334167683Srik# define OR_CARP_CHECK_WE_ARE_SRC(iface) \ 2335167683Srik || ((iface)->if_carp \ 2336211193Swill && (*carp_forus_p)((iface), eh->ether_shost)) 2337167683Srik#else 2338167683Srik# define OR_CARP_CHECK_WE_ARE_DST(iface) 2339167683Srik# define OR_CARP_CHECK_WE_ARE_SRC(iface) 2340167683Srik#endif 2341167683Srik 2342175432Sthompsa#ifdef INET6 2343175432Sthompsa# define OR_PFIL_HOOKED_INET6 \ 2344197952Sjulian || PFIL_HOOKED(&V_inet6_pfil_hook) 2345175432Sthompsa#else 2346175432Sthompsa# define OR_PFIL_HOOKED_INET6 2347175432Sthompsa#endif 2348175432Sthompsa 2349167683Srik#define GRAB_OUR_PACKETS(iface) \ 2350167683Srik if ((iface)->if_type == IFT_GIF) \ 2351167683Srik continue; \ 2352167683Srik /* It is destined for us. */ \ 2353167683Srik if (memcmp(IF_LLADDR((iface)), eh->ether_dhost, ETHER_ADDR_LEN) == 0 \ 2354167683Srik OR_CARP_CHECK_WE_ARE_DST((iface)) \ 2355167683Srik ) { \ 2356175432Sthompsa if ((iface)->if_type == IFT_BRIDGE) { \ 2357175432Sthompsa ETHER_BPF_MTAP(iface, m); \ 2358175432Sthompsa iface->if_ipackets++; \ 2359175432Sthompsa /* Filter on the physical interface. */ \ 2360175432Sthompsa if (pfil_local_phys && \ 2361197952Sjulian (PFIL_HOOKED(&V_inet_pfil_hook) \ 2362175432Sthompsa OR_PFIL_HOOKED_INET6)) { \ 2363175432Sthompsa if (bridge_pfil(&m, NULL, ifp, \ 2364175432Sthompsa PFIL_IN) != 0 || m == NULL) { \ 2365175432Sthompsa BRIDGE_UNLOCK(sc); \ 2366175432Sthompsa return (NULL); \ 2367175432Sthompsa } \ 2368252149Sglebius eh = mtod(m, struct ether_header *); \ 2369175432Sthompsa } \ 2370175432Sthompsa } \ 2371173320Sthompsa if (bif->bif_flags & IFBIF_LEARNING) { \ 2372173320Sthompsa error = bridge_rtupdate(sc, eh->ether_shost, \ 2373170681Sthompsa vlan, bif, 0, IFBAF_DYNAMIC); \ 2374173320Sthompsa if (error && bif->bif_addrmax) { \ 2375173320Sthompsa BRIDGE_UNLOCK(sc); \ 2376173320Sthompsa m_freem(m); \ 2377173320Sthompsa return (NULL); \ 2378173320Sthompsa } \ 2379173320Sthompsa } \ 2380167683Srik m->m_pkthdr.rcvif = iface; \ 2381167683Srik BRIDGE_UNLOCK(sc); \ 2382167683Srik return (m); \ 2383167683Srik } \ 2384167683Srik \ 2385167683Srik /* We just received a packet that we sent out. */ \ 2386167683Srik if (memcmp(IF_LLADDR((iface)), eh->ether_shost, ETHER_ADDR_LEN) == 0 \ 2387167683Srik OR_CARP_CHECK_WE_ARE_SRC((iface)) \ 2388167683Srik ) { \ 2389167683Srik BRIDGE_UNLOCK(sc); \ 2390167683Srik m_freem(m); \ 2391167683Srik return (NULL); \ 2392167683Srik } 2393167683Srik 2394146985Sthompsa /* 2395175432Sthompsa * Unicast. Make sure it's not for the bridge. 2396175432Sthompsa */ 2397175432Sthompsa do { GRAB_OUR_PACKETS(bifp) } while (0); 2398175432Sthompsa 2399175432Sthompsa /* 2400167683Srik * Give a chance for ifp at first priority. This will help when the 2401167683Srik * packet comes through the interface like VLAN's with the same MACs 2402167683Srik * on several interfaces from the same bridge. This also will save 2403167683Srik * some CPU cycles in case the destination interface and the input 2404167683Srik * interface (eq ifp) are the same. 2405146985Sthompsa */ 2406167683Srik do { GRAB_OUR_PACKETS(ifp) } while (0); 2407167683Srik 2408167683Srik /* Now check the all bridge members. */ 2409164112Sthompsa LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) { 2410167683Srik GRAB_OUR_PACKETS(bif2->bif_ifp) 2411146985Sthompsa } 2412146985Sthompsa 2413167683Srik#undef OR_CARP_CHECK_WE_ARE_DST 2414167683Srik#undef OR_CARP_CHECK_WE_ARE_SRC 2415175432Sthompsa#undef OR_PFIL_HOOKED_INET6 2416167683Srik#undef GRAB_OUR_PACKETS 2417167683Srik 2418146985Sthompsa /* Perform the bridge forwarding function. */ 2419171678Sthompsa bridge_forward(sc, bif, m); 2420146985Sthompsa 2421146985Sthompsa return (NULL); 2422146985Sthompsa} 2423146985Sthompsa 2424146985Sthompsa/* 2425146985Sthompsa * bridge_broadcast: 2426146985Sthompsa * 2427146985Sthompsa * Send a frame to all interfaces that are members of 2428146985Sthompsa * the bridge, except for the one on which the packet 2429146985Sthompsa * arrived. 2430146985Sthompsa * 2431146985Sthompsa * NOTE: Releases the lock on return. 2432146985Sthompsa */ 2433151313Sthompsastatic void 2434146985Sthompsabridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, 2435150837Sthompsa struct mbuf *m, int runfilt) 2436146985Sthompsa{ 2437171678Sthompsa struct bridge_iflist *dbif, *sbif; 2438146985Sthompsa struct mbuf *mc; 2439146985Sthompsa struct ifnet *dst_if; 2440157057Srik int error = 0, used = 0, i; 2441146985Sthompsa 2442171678Sthompsa sbif = bridge_lookup_member_if(sc, src_if); 2443171678Sthompsa 2444146985Sthompsa BRIDGE_LOCK2REF(sc, error); 2445146985Sthompsa if (error) { 2446146985Sthompsa m_freem(m); 2447146985Sthompsa return; 2448146985Sthompsa } 2449146985Sthompsa 2450147786Sthompsa /* Filter on the bridge interface before broadcasting */ 2451197952Sjulian if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook) 2452147786Sthompsa#ifdef INET6 2453197952Sjulian || PFIL_HOOKED(&V_inet6_pfil_hook) 2454147786Sthompsa#endif 2455150837Sthompsa )) { 2456147786Sthompsa if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0) 2457152393Sthompsa goto out; 2458147786Sthompsa if (m == NULL) 2459152393Sthompsa goto out; 2460147786Sthompsa } 2461147786Sthompsa 2462171678Sthompsa LIST_FOREACH(dbif, &sc->sc_iflist, bif_next) { 2463171678Sthompsa dst_if = dbif->bif_ifp; 2464146985Sthompsa if (dst_if == src_if) 2465146985Sthompsa continue; 2466146985Sthompsa 2467171678Sthompsa /* Private segments can not talk to each other */ 2468171678Sthompsa if (sbif && (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE)) 2469163863Sthompsa continue; 2470146985Sthompsa 2471171678Sthompsa if ((dbif->bif_flags & IFBIF_STP) && 2472171678Sthompsa dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) 2473171678Sthompsa continue; 2474171678Sthompsa 2475171678Sthompsa if ((dbif->bif_flags & IFBIF_DISCOVER) == 0 && 2476146985Sthompsa (m->m_flags & (M_BCAST|M_MCAST)) == 0) 2477146985Sthompsa continue; 2478146985Sthompsa 2479148887Srwatson if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) 2480146985Sthompsa continue; 2481146985Sthompsa 2482171678Sthompsa if (LIST_NEXT(dbif, bif_next) == NULL) { 2483146985Sthompsa mc = m; 2484146985Sthompsa used = 1; 2485146985Sthompsa } else { 2486157057Srik mc = m_dup(m, M_DONTWAIT); 2487146985Sthompsa if (mc == NULL) { 2488147256Sbrooks sc->sc_ifp->if_oerrors++; 2489146985Sthompsa continue; 2490146985Sthompsa } 2491146985Sthompsa } 2492146985Sthompsa 2493147786Sthompsa /* 2494147786Sthompsa * Filter on the output interface. Pass a NULL bridge interface 2495153497Sthompsa * pointer so we do not redundantly filter on the bridge for 2496147786Sthompsa * each interface we broadcast on. 2497147786Sthompsa */ 2498197952Sjulian if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook) 2499147786Sthompsa#ifdef INET6 2500197952Sjulian || PFIL_HOOKED(&V_inet6_pfil_hook) 2501147786Sthompsa#endif 2502150837Sthompsa )) { 2503157057Srik if (used == 0) { 2504157057Srik /* Keep the layer3 header aligned */ 2505157057Srik i = min(mc->m_pkthdr.len, max_protohdr); 2506157057Srik mc = m_copyup(mc, i, ETHER_ALIGN); 2507157057Srik if (mc == NULL) { 2508157057Srik sc->sc_ifp->if_oerrors++; 2509157057Srik continue; 2510157057Srik } 2511157057Srik } 2512152392Sthompsa if (bridge_pfil(&mc, NULL, dst_if, PFIL_OUT) != 0) 2513152392Sthompsa continue; 2514152392Sthompsa if (mc == NULL) 2515152392Sthompsa continue; 2516147786Sthompsa } 2517151305Sthompsa 2518147786Sthompsa bridge_enqueue(sc, dst_if, mc); 2519146985Sthompsa } 2520146985Sthompsa if (used == 0) 2521146985Sthompsa m_freem(m); 2522146985Sthompsa 2523152393Sthompsaout: 2524146985Sthompsa BRIDGE_UNREF(sc); 2525146985Sthompsa} 2526146985Sthompsa 2527146985Sthompsa/* 2528153408Sthompsa * bridge_span: 2529153408Sthompsa * 2530153408Sthompsa * Duplicate a packet out one or more interfaces that are in span mode, 2531153408Sthompsa * the original mbuf is unmodified. 2532153408Sthompsa */ 2533153408Sthompsastatic void 2534153408Sthompsabridge_span(struct bridge_softc *sc, struct mbuf *m) 2535153408Sthompsa{ 2536153408Sthompsa struct bridge_iflist *bif; 2537153408Sthompsa struct ifnet *dst_if; 2538153408Sthompsa struct mbuf *mc; 2539153408Sthompsa 2540153408Sthompsa if (LIST_EMPTY(&sc->sc_spanlist)) 2541153408Sthompsa return; 2542153408Sthompsa 2543153408Sthompsa LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) { 2544153408Sthompsa dst_if = bif->bif_ifp; 2545158667Sthompsa 2546153408Sthompsa if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) 2547153408Sthompsa continue; 2548153408Sthompsa 2549153408Sthompsa mc = m_copypacket(m, M_DONTWAIT); 2550153408Sthompsa if (mc == NULL) { 2551153408Sthompsa sc->sc_ifp->if_oerrors++; 2552153408Sthompsa continue; 2553153408Sthompsa } 2554153408Sthompsa 2555153408Sthompsa bridge_enqueue(sc, dst_if, mc); 2556153408Sthompsa } 2557153408Sthompsa} 2558153408Sthompsa 2559153408Sthompsa/* 2560146985Sthompsa * bridge_rtupdate: 2561146985Sthompsa * 2562146985Sthompsa * Add a bridge routing entry. 2563146985Sthompsa */ 2564151313Sthompsastatic int 2565170681Sthompsabridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan, 2566164112Sthompsa struct bridge_iflist *bif, int setflags, uint8_t flags) 2567146985Sthompsa{ 2568146985Sthompsa struct bridge_rtnode *brt; 2569146985Sthompsa int error; 2570146985Sthompsa 2571146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2572146985Sthompsa 2573173320Sthompsa /* Check the source address is valid and not multicast. */ 2574173320Sthompsa if (ETHER_IS_MULTICAST(dst) || 2575173320Sthompsa (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 && 2576173320Sthompsa dst[3] == 0 && dst[4] == 0 && dst[5] == 0) != 0) 2577173320Sthompsa return (EINVAL); 2578173320Sthompsa 2579170681Sthompsa /* 802.1p frames map to vlan 1 */ 2580170681Sthompsa if (vlan == 0) 2581170681Sthompsa vlan = 1; 2582170681Sthompsa 2583146985Sthompsa /* 2584146985Sthompsa * A route for this destination might already exist. If so, 2585146985Sthompsa * update it, otherwise create a new one. 2586146985Sthompsa */ 2587170681Sthompsa if ((brt = bridge_rtnode_lookup(sc, dst, vlan)) == NULL) { 2588160867Sthompsa if (sc->sc_brtcnt >= sc->sc_brtmax) { 2589160867Sthompsa sc->sc_brtexceeded++; 2590146985Sthompsa return (ENOSPC); 2591160867Sthompsa } 2592173320Sthompsa /* Check per interface address limits (if enabled) */ 2593173320Sthompsa if (bif->bif_addrmax && bif->bif_addrcnt >= bif->bif_addrmax) { 2594173320Sthompsa bif->bif_addrexceeded++; 2595173320Sthompsa return (ENOSPC); 2596173320Sthompsa } 2597146985Sthompsa 2598146985Sthompsa /* 2599146985Sthompsa * Allocate a new bridge forwarding node, and 2600146985Sthompsa * initialize the expiration time and Ethernet 2601146985Sthompsa * address. 2602146985Sthompsa */ 2603146985Sthompsa brt = uma_zalloc(bridge_rtnode_zone, M_NOWAIT | M_ZERO); 2604146985Sthompsa if (brt == NULL) 2605146985Sthompsa return (ENOMEM); 2606146985Sthompsa 2607164112Sthompsa if (bif->bif_flags & IFBIF_STICKY) 2608164112Sthompsa brt->brt_flags = IFBAF_STICKY; 2609164112Sthompsa else 2610164112Sthompsa brt->brt_flags = IFBAF_DYNAMIC; 2611164112Sthompsa 2612146985Sthompsa memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN); 2613170681Sthompsa brt->brt_vlan = vlan; 2614146985Sthompsa 2615146985Sthompsa if ((error = bridge_rtnode_insert(sc, brt)) != 0) { 2616146985Sthompsa uma_zfree(bridge_rtnode_zone, brt); 2617146985Sthompsa return (error); 2618146985Sthompsa } 2619173320Sthompsa brt->brt_dst = bif; 2620173320Sthompsa bif->bif_addrcnt++; 2621146985Sthompsa } 2622146985Sthompsa 2623173320Sthompsa if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && 2624173320Sthompsa brt->brt_dst != bif) { 2625173320Sthompsa brt->brt_dst->bif_addrcnt--; 2626173320Sthompsa brt->brt_dst = bif; 2627173320Sthompsa brt->brt_dst->bif_addrcnt++; 2628173320Sthompsa } 2629173320Sthompsa 2630153979Sthompsa if ((flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) 2631153978Sthompsa brt->brt_expire = time_uptime + sc->sc_brttimeout; 2632153977Sthompsa if (setflags) 2633146985Sthompsa brt->brt_flags = flags; 2634146985Sthompsa 2635146985Sthompsa return (0); 2636146985Sthompsa} 2637146985Sthompsa 2638146985Sthompsa/* 2639146985Sthompsa * bridge_rtlookup: 2640146985Sthompsa * 2641146985Sthompsa * Lookup the destination interface for an address. 2642146985Sthompsa */ 2643151345Sthompsastatic struct ifnet * 2644170681Sthompsabridge_rtlookup(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan) 2645146985Sthompsa{ 2646146985Sthompsa struct bridge_rtnode *brt; 2647146985Sthompsa 2648146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2649146985Sthompsa 2650170681Sthompsa if ((brt = bridge_rtnode_lookup(sc, addr, vlan)) == NULL) 2651146985Sthompsa return (NULL); 2652146985Sthompsa 2653146985Sthompsa return (brt->brt_ifp); 2654146985Sthompsa} 2655146985Sthompsa 2656146985Sthompsa/* 2657146985Sthompsa * bridge_rttrim: 2658146985Sthompsa * 2659146985Sthompsa * Trim the routine table so that we have a number 2660146985Sthompsa * of routing entries less than or equal to the 2661146985Sthompsa * maximum number. 2662146985Sthompsa */ 2663151313Sthompsastatic void 2664146985Sthompsabridge_rttrim(struct bridge_softc *sc) 2665146985Sthompsa{ 2666146985Sthompsa struct bridge_rtnode *brt, *nbrt; 2667146985Sthompsa 2668146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2669146985Sthompsa 2670146985Sthompsa /* Make sure we actually need to do this. */ 2671146985Sthompsa if (sc->sc_brtcnt <= sc->sc_brtmax) 2672146985Sthompsa return; 2673146985Sthompsa 2674146985Sthompsa /* Force an aging cycle; this might trim enough addresses. */ 2675146985Sthompsa bridge_rtage(sc); 2676146985Sthompsa if (sc->sc_brtcnt <= sc->sc_brtmax) 2677146985Sthompsa return; 2678146985Sthompsa 2679163142Sthompsa LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { 2680146985Sthompsa if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { 2681146985Sthompsa bridge_rtnode_destroy(sc, brt); 2682146985Sthompsa if (sc->sc_brtcnt <= sc->sc_brtmax) 2683146985Sthompsa return; 2684146985Sthompsa } 2685146985Sthompsa } 2686146985Sthompsa} 2687146985Sthompsa 2688146985Sthompsa/* 2689146985Sthompsa * bridge_timer: 2690146985Sthompsa * 2691146985Sthompsa * Aging timer for the bridge. 2692146985Sthompsa */ 2693151313Sthompsastatic void 2694146985Sthompsabridge_timer(void *arg) 2695146985Sthompsa{ 2696146985Sthompsa struct bridge_softc *sc = arg; 2697146985Sthompsa 2698149253Sthompsa BRIDGE_LOCK_ASSERT(sc); 2699149253Sthompsa 2700146985Sthompsa bridge_rtage(sc); 2701146985Sthompsa 2702148887Srwatson if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) 2703146985Sthompsa callout_reset(&sc->sc_brcallout, 2704146985Sthompsa bridge_rtable_prune_period * hz, bridge_timer, sc); 2705146985Sthompsa} 2706146985Sthompsa 2707146985Sthompsa/* 2708146985Sthompsa * bridge_rtage: 2709146985Sthompsa * 2710146985Sthompsa * Perform an aging cycle. 2711146985Sthompsa */ 2712151313Sthompsastatic void 2713146985Sthompsabridge_rtage(struct bridge_softc *sc) 2714146985Sthompsa{ 2715146985Sthompsa struct bridge_rtnode *brt, *nbrt; 2716146985Sthompsa 2717146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2718146985Sthompsa 2719163142Sthompsa LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { 2720146985Sthompsa if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { 2721153976Sthompsa if (time_uptime >= brt->brt_expire) 2722146985Sthompsa bridge_rtnode_destroy(sc, brt); 2723146985Sthompsa } 2724146985Sthompsa } 2725146985Sthompsa} 2726146985Sthompsa 2727146985Sthompsa/* 2728146985Sthompsa * bridge_rtflush: 2729146985Sthompsa * 2730146985Sthompsa * Remove all dynamic addresses from the bridge. 2731146985Sthompsa */ 2732151313Sthompsastatic void 2733146985Sthompsabridge_rtflush(struct bridge_softc *sc, int full) 2734146985Sthompsa{ 2735146985Sthompsa struct bridge_rtnode *brt, *nbrt; 2736146985Sthompsa 2737146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2738146985Sthompsa 2739163142Sthompsa LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { 2740146985Sthompsa if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) 2741146985Sthompsa bridge_rtnode_destroy(sc, brt); 2742146985Sthompsa } 2743146985Sthompsa} 2744146985Sthompsa 2745146985Sthompsa/* 2746146985Sthompsa * bridge_rtdaddr: 2747146985Sthompsa * 2748146985Sthompsa * Remove an address from the table. 2749146985Sthompsa */ 2750151313Sthompsastatic int 2751170681Sthompsabridge_rtdaddr(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan) 2752146985Sthompsa{ 2753146985Sthompsa struct bridge_rtnode *brt; 2754170681Sthompsa int found = 0; 2755146985Sthompsa 2756146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2757146985Sthompsa 2758170681Sthompsa /* 2759170681Sthompsa * If vlan is zero then we want to delete for all vlans so the lookup 2760170681Sthompsa * may return more than one. 2761170681Sthompsa */ 2762170681Sthompsa while ((brt = bridge_rtnode_lookup(sc, addr, vlan)) != NULL) { 2763170681Sthompsa bridge_rtnode_destroy(sc, brt); 2764170681Sthompsa found = 1; 2765170681Sthompsa } 2766146985Sthompsa 2767170681Sthompsa return (found ? 0 : ENOENT); 2768146985Sthompsa} 2769146985Sthompsa 2770146985Sthompsa/* 2771146985Sthompsa * bridge_rtdelete: 2772146985Sthompsa * 2773146985Sthompsa * Delete routes to a speicifc member interface. 2774146985Sthompsa */ 2775160769Sthompsastatic void 2776146985Sthompsabridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int full) 2777146985Sthompsa{ 2778146985Sthompsa struct bridge_rtnode *brt, *nbrt; 2779146985Sthompsa 2780146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2781146985Sthompsa 2782163142Sthompsa LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { 2783153497Sthompsa if (brt->brt_ifp == ifp && (full || 2784146985Sthompsa (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)) 2785146985Sthompsa bridge_rtnode_destroy(sc, brt); 2786146985Sthompsa } 2787146985Sthompsa} 2788146985Sthompsa 2789146985Sthompsa/* 2790146985Sthompsa * bridge_rtable_init: 2791146985Sthompsa * 2792146985Sthompsa * Initialize the route table for this bridge. 2793146985Sthompsa */ 2794151313Sthompsastatic int 2795146985Sthompsabridge_rtable_init(struct bridge_softc *sc) 2796146985Sthompsa{ 2797146985Sthompsa int i; 2798146985Sthompsa 2799146985Sthompsa sc->sc_rthash = malloc(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE, 2800146985Sthompsa M_DEVBUF, M_NOWAIT); 2801146985Sthompsa if (sc->sc_rthash == NULL) 2802146985Sthompsa return (ENOMEM); 2803146985Sthompsa 2804146985Sthompsa for (i = 0; i < BRIDGE_RTHASH_SIZE; i++) 2805146985Sthompsa LIST_INIT(&sc->sc_rthash[i]); 2806146985Sthompsa 2807146985Sthompsa sc->sc_rthash_key = arc4random(); 2808146985Sthompsa 2809146985Sthompsa LIST_INIT(&sc->sc_rtlist); 2810146985Sthompsa 2811146985Sthompsa return (0); 2812146985Sthompsa} 2813146985Sthompsa 2814146985Sthompsa/* 2815146985Sthompsa * bridge_rtable_fini: 2816146985Sthompsa * 2817146985Sthompsa * Deconstruct the route table for this bridge. 2818146985Sthompsa */ 2819151313Sthompsastatic void 2820146985Sthompsabridge_rtable_fini(struct bridge_softc *sc) 2821146985Sthompsa{ 2822146985Sthompsa 2823173320Sthompsa KASSERT(sc->sc_brtcnt == 0, 2824173320Sthompsa ("%s: %d bridge routes referenced", __func__, sc->sc_brtcnt)); 2825146985Sthompsa free(sc->sc_rthash, M_DEVBUF); 2826146985Sthompsa} 2827146985Sthompsa 2828146985Sthompsa/* 2829146985Sthompsa * The following hash function is adapted from "Hash Functions" by Bob Jenkins 2830146985Sthompsa * ("Algorithm Alley", Dr. Dobbs Journal, September 1997). 2831146985Sthompsa */ 2832146985Sthompsa#define mix(a, b, c) \ 2833146985Sthompsado { \ 2834146985Sthompsa a -= b; a -= c; a ^= (c >> 13); \ 2835146985Sthompsa b -= c; b -= a; b ^= (a << 8); \ 2836146985Sthompsa c -= a; c -= b; c ^= (b >> 13); \ 2837146985Sthompsa a -= b; a -= c; a ^= (c >> 12); \ 2838146985Sthompsa b -= c; b -= a; b ^= (a << 16); \ 2839146985Sthompsa c -= a; c -= b; c ^= (b >> 5); \ 2840146985Sthompsa a -= b; a -= c; a ^= (c >> 3); \ 2841146985Sthompsa b -= c; b -= a; b ^= (a << 10); \ 2842146985Sthompsa c -= a; c -= b; c ^= (b >> 15); \ 2843146985Sthompsa} while (/*CONSTCOND*/0) 2844146985Sthompsa 2845146985Sthompsastatic __inline uint32_t 2846146985Sthompsabridge_rthash(struct bridge_softc *sc, const uint8_t *addr) 2847146985Sthompsa{ 2848146985Sthompsa uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_rthash_key; 2849146985Sthompsa 2850146985Sthompsa b += addr[5] << 8; 2851146985Sthompsa b += addr[4]; 2852146985Sthompsa a += addr[3] << 24; 2853146985Sthompsa a += addr[2] << 16; 2854146985Sthompsa a += addr[1] << 8; 2855146985Sthompsa a += addr[0]; 2856146985Sthompsa 2857146985Sthompsa mix(a, b, c); 2858146985Sthompsa 2859146985Sthompsa return (c & BRIDGE_RTHASH_MASK); 2860146985Sthompsa} 2861146985Sthompsa 2862146985Sthompsa#undef mix 2863146985Sthompsa 2864155143Sthompsastatic int 2865155143Sthompsabridge_rtnode_addr_cmp(const uint8_t *a, const uint8_t *b) 2866155143Sthompsa{ 2867155143Sthompsa int i, d; 2868155143Sthompsa 2869155143Sthompsa for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) { 2870155143Sthompsa d = ((int)a[i]) - ((int)b[i]); 2871155143Sthompsa } 2872155143Sthompsa 2873155143Sthompsa return (d); 2874155143Sthompsa} 2875155143Sthompsa 2876146985Sthompsa/* 2877146985Sthompsa * bridge_rtnode_lookup: 2878146985Sthompsa * 2879170681Sthompsa * Look up a bridge route node for the specified destination. Compare the 2880170681Sthompsa * vlan id or if zero then just return the first match. 2881146985Sthompsa */ 2882151345Sthompsastatic struct bridge_rtnode * 2883170681Sthompsabridge_rtnode_lookup(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan) 2884146985Sthompsa{ 2885146985Sthompsa struct bridge_rtnode *brt; 2886146985Sthompsa uint32_t hash; 2887146985Sthompsa int dir; 2888146985Sthompsa 2889146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2890146985Sthompsa 2891146985Sthompsa hash = bridge_rthash(sc, addr); 2892146985Sthompsa LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) { 2893155143Sthompsa dir = bridge_rtnode_addr_cmp(addr, brt->brt_addr); 2894170681Sthompsa if (dir == 0 && (brt->brt_vlan == vlan || vlan == 0)) 2895146985Sthompsa return (brt); 2896146985Sthompsa if (dir > 0) 2897146985Sthompsa return (NULL); 2898146985Sthompsa } 2899146985Sthompsa 2900146985Sthompsa return (NULL); 2901146985Sthompsa} 2902146985Sthompsa 2903146985Sthompsa/* 2904146985Sthompsa * bridge_rtnode_insert: 2905146985Sthompsa * 2906146985Sthompsa * Insert the specified bridge node into the route table. We 2907146985Sthompsa * assume the entry is not already in the table. 2908146985Sthompsa */ 2909151313Sthompsastatic int 2910146985Sthompsabridge_rtnode_insert(struct bridge_softc *sc, struct bridge_rtnode *brt) 2911146985Sthompsa{ 2912146985Sthompsa struct bridge_rtnode *lbrt; 2913146985Sthompsa uint32_t hash; 2914146985Sthompsa int dir; 2915146985Sthompsa 2916146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2917146985Sthompsa 2918146985Sthompsa hash = bridge_rthash(sc, brt->brt_addr); 2919146985Sthompsa 2920146985Sthompsa lbrt = LIST_FIRST(&sc->sc_rthash[hash]); 2921146985Sthompsa if (lbrt == NULL) { 2922146985Sthompsa LIST_INSERT_HEAD(&sc->sc_rthash[hash], brt, brt_hash); 2923146985Sthompsa goto out; 2924146985Sthompsa } 2925146985Sthompsa 2926146985Sthompsa do { 2927155143Sthompsa dir = bridge_rtnode_addr_cmp(brt->brt_addr, lbrt->brt_addr); 2928170681Sthompsa if (dir == 0 && brt->brt_vlan == lbrt->brt_vlan) 2929146985Sthompsa return (EEXIST); 2930146985Sthompsa if (dir > 0) { 2931146985Sthompsa LIST_INSERT_BEFORE(lbrt, brt, brt_hash); 2932146985Sthompsa goto out; 2933146985Sthompsa } 2934146985Sthompsa if (LIST_NEXT(lbrt, brt_hash) == NULL) { 2935146985Sthompsa LIST_INSERT_AFTER(lbrt, brt, brt_hash); 2936146985Sthompsa goto out; 2937146985Sthompsa } 2938146985Sthompsa lbrt = LIST_NEXT(lbrt, brt_hash); 2939146985Sthompsa } while (lbrt != NULL); 2940146985Sthompsa 2941146985Sthompsa#ifdef DIAGNOSTIC 2942146985Sthompsa panic("bridge_rtnode_insert: impossible"); 2943146985Sthompsa#endif 2944146985Sthompsa 2945153497Sthompsaout: 2946146985Sthompsa LIST_INSERT_HEAD(&sc->sc_rtlist, brt, brt_list); 2947146985Sthompsa sc->sc_brtcnt++; 2948146985Sthompsa 2949146985Sthompsa return (0); 2950146985Sthompsa} 2951146985Sthompsa 2952146985Sthompsa/* 2953146985Sthompsa * bridge_rtnode_destroy: 2954146985Sthompsa * 2955146985Sthompsa * Destroy a bridge rtnode. 2956146985Sthompsa */ 2957151313Sthompsastatic void 2958146985Sthompsabridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt) 2959146985Sthompsa{ 2960146985Sthompsa BRIDGE_LOCK_ASSERT(sc); 2961146985Sthompsa 2962146985Sthompsa LIST_REMOVE(brt, brt_hash); 2963146985Sthompsa 2964146985Sthompsa LIST_REMOVE(brt, brt_list); 2965146985Sthompsa sc->sc_brtcnt--; 2966173320Sthompsa brt->brt_dst->bif_addrcnt--; 2967146985Sthompsa uma_zfree(bridge_rtnode_zone, brt); 2968146985Sthompsa} 2969146985Sthompsa 2970146985Sthompsa/* 2971163863Sthompsa * bridge_rtable_expire: 2972163863Sthompsa * 2973163863Sthompsa * Set the expiry time for all routes on an interface. 2974163863Sthompsa */ 2975163863Sthompsastatic void 2976163863Sthompsabridge_rtable_expire(struct ifnet *ifp, int age) 2977163863Sthompsa{ 2978163863Sthompsa struct bridge_softc *sc = ifp->if_bridge; 2979163863Sthompsa struct bridge_rtnode *brt; 2980163863Sthompsa 2981163863Sthompsa BRIDGE_LOCK(sc); 2982163863Sthompsa 2983163863Sthompsa /* 2984163863Sthompsa * If the age is zero then flush, otherwise set all the expiry times to 2985163863Sthompsa * age for the interface 2986163863Sthompsa */ 2987163863Sthompsa if (age == 0) 2988163863Sthompsa bridge_rtdelete(sc, ifp, IFBF_FLUSHDYN); 2989163863Sthompsa else { 2990163863Sthompsa LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { 2991163863Sthompsa /* Cap the expiry time to 'age' */ 2992163863Sthompsa if (brt->brt_ifp == ifp && 2993163863Sthompsa brt->brt_expire > time_uptime + age && 2994163863Sthompsa (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) 2995163863Sthompsa brt->brt_expire = time_uptime + age; 2996163863Sthompsa } 2997163863Sthompsa } 2998163863Sthompsa BRIDGE_UNLOCK(sc); 2999163863Sthompsa} 3000163863Sthompsa 3001163863Sthompsa/* 3002160902Sthompsa * bridge_state_change: 3003160902Sthompsa * 3004160902Sthompsa * Callback from the bridgestp code when a port changes states. 3005160902Sthompsa */ 3006160902Sthompsastatic void 3007160902Sthompsabridge_state_change(struct ifnet *ifp, int state) 3008160902Sthompsa{ 3009160902Sthompsa struct bridge_softc *sc = ifp->if_bridge; 3010160902Sthompsa static const char *stpstates[] = { 3011160902Sthompsa "disabled", 3012160902Sthompsa "listening", 3013160902Sthompsa "learning", 3014160902Sthompsa "forwarding", 3015160902Sthompsa "blocking", 3016163863Sthompsa "discarding" 3017160902Sthompsa }; 3018160902Sthompsa 3019160902Sthompsa if (log_stp) 3020160902Sthompsa log(LOG_NOTICE, "%s: state changed to %s on %s\n", 3021160902Sthompsa sc->sc_ifp->if_xname, stpstates[state], ifp->if_xname); 3022160902Sthompsa} 3023160902Sthompsa 3024160902Sthompsa/* 3025146985Sthompsa * Send bridge packets through pfil if they are one of the types pfil can deal 3026146985Sthompsa * with, or if they are ARP or REVARP. (pfil will pass ARP and REVARP without 3027147786Sthompsa * question.) If *bifp or *ifp are NULL then packet filtering is skipped for 3028147786Sthompsa * that interface. 3029146985Sthompsa */ 3030153497Sthompsastatic int 3031153497Sthompsabridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) 3032146985Sthompsa{ 3033158592Sdhartmei int snap, error, i, hlen; 3034146985Sthompsa struct ether_header *eh1, eh2; 3035147111Sthompsa struct ip_fw_args args; 3036146985Sthompsa struct ip *ip; 3037147665Sthompsa struct llc llc1; 3038146985Sthompsa u_int16_t ether_type; 3039146985Sthompsa 3040146985Sthompsa snap = 0; 3041146985Sthompsa error = -1; /* Default error if not error == 0 */ 3042147111Sthompsa 3043170139Sthompsa#if 0 3044157155Sthompsa /* we may return with the IP fields swapped, ensure its not shared */ 3045157155Sthompsa KASSERT(M_WRITABLE(*mp), ("%s: modifying a shared mbuf", __func__)); 3046170139Sthompsa#endif 3047157155Sthompsa 3048153831Sthompsa if (pfil_bridge == 0 && pfil_member == 0 && pfil_ipfw == 0) 3049158667Sthompsa return (0); /* filtering is disabled */ 3050153831Sthompsa 3051147111Sthompsa i = min((*mp)->m_pkthdr.len, max_protohdr); 3052147111Sthompsa if ((*mp)->m_len < i) { 3053147111Sthompsa *mp = m_pullup(*mp, i); 3054147111Sthompsa if (*mp == NULL) { 3055147111Sthompsa printf("%s: m_pullup failed\n", __func__); 3056158667Sthompsa return (-1); 3057147111Sthompsa } 3058147111Sthompsa } 3059147111Sthompsa 3060146985Sthompsa eh1 = mtod(*mp, struct ether_header *); 3061146985Sthompsa ether_type = ntohs(eh1->ether_type); 3062146985Sthompsa 3063146985Sthompsa /* 3064146985Sthompsa * Check for SNAP/LLC. 3065146985Sthompsa */ 3066146985Sthompsa if (ether_type < ETHERMTU) { 3067147665Sthompsa struct llc *llc2 = (struct llc *)(eh1 + 1); 3068146985Sthompsa 3069146985Sthompsa if ((*mp)->m_len >= ETHER_HDR_LEN + 8 && 3070147665Sthompsa llc2->llc_dsap == LLC_SNAP_LSAP && 3071147665Sthompsa llc2->llc_ssap == LLC_SNAP_LSAP && 3072147665Sthompsa llc2->llc_control == LLC_UI) { 3073147665Sthompsa ether_type = htons(llc2->llc_un.type_snap.ether_type); 3074146985Sthompsa snap = 1; 3075146985Sthompsa } 3076146985Sthompsa } 3077146985Sthompsa 3078162561Sthompsa /* 3079162561Sthompsa * If we're trying to filter bridge traffic, don't look at anything 3080162561Sthompsa * other than IP and ARP traffic. If the filter doesn't understand 3081162561Sthompsa * IPv6, don't allow IPv6 through the bridge either. This is lame 3082162561Sthompsa * since if we really wanted, say, an AppleTalk filter, we are hosed, 3083162561Sthompsa * but of course we don't have an AppleTalk filter to begin with. 3084162561Sthompsa * (Note that since pfil doesn't understand ARP it will pass *ALL* 3085162561Sthompsa * ARP traffic.) 3086162561Sthompsa */ 3087162561Sthompsa switch (ether_type) { 3088162561Sthompsa case ETHERTYPE_ARP: 3089162561Sthompsa case ETHERTYPE_REVARP: 3090162561Sthompsa if (pfil_ipfw_arp == 0) 3091162561Sthompsa return (0); /* Automatically pass */ 3092162561Sthompsa break; 3093162561Sthompsa 3094162561Sthompsa case ETHERTYPE_IP: 3095162561Sthompsa#ifdef INET6 3096162561Sthompsa case ETHERTYPE_IPV6: 3097162561Sthompsa#endif /* INET6 */ 3098162561Sthompsa break; 3099162561Sthompsa default: 3100162561Sthompsa /* 3101162561Sthompsa * Check to see if the user wants to pass non-ip 3102162561Sthompsa * packets, these will not be checked by pfil(9) and 3103162561Sthompsa * passed unconditionally so the default is to drop. 3104162561Sthompsa */ 3105162561Sthompsa if (pfil_onlyip) 3106162561Sthompsa goto bad; 3107162561Sthompsa } 3108162561Sthompsa 3109146985Sthompsa /* Strip off the Ethernet header and keep a copy. */ 3110146985Sthompsa m_copydata(*mp, 0, ETHER_HDR_LEN, (caddr_t) &eh2); 3111146985Sthompsa m_adj(*mp, ETHER_HDR_LEN); 3112146985Sthompsa 3113146985Sthompsa /* Strip off snap header, if present */ 3114146985Sthompsa if (snap) { 3115147665Sthompsa m_copydata(*mp, 0, sizeof(struct llc), (caddr_t) &llc1); 3116146985Sthompsa m_adj(*mp, sizeof(struct llc)); 3117146985Sthompsa } 3118146985Sthompsa 3119147744Sthompsa /* 3120147744Sthompsa * Check the IP header for alignment and errors 3121147744Sthompsa */ 3122147744Sthompsa if (dir == PFIL_IN) { 3123147744Sthompsa switch (ether_type) { 3124147744Sthompsa case ETHERTYPE_IP: 3125147744Sthompsa error = bridge_ip_checkbasic(mp); 3126147744Sthompsa break; 3127158667Sthompsa#ifdef INET6 3128147744Sthompsa case ETHERTYPE_IPV6: 3129147744Sthompsa error = bridge_ip6_checkbasic(mp); 3130147744Sthompsa break; 3131158667Sthompsa#endif /* INET6 */ 3132147744Sthompsa default: 3133147744Sthompsa error = 0; 3134147744Sthompsa } 3135147744Sthompsa if (error) 3136147744Sthompsa goto bad; 3137147744Sthompsa } 3138147744Sthompsa 3139200855Sluigi /* XXX this section is also in if_ethersubr.c */ 3140201527Sluigi // XXX PFIL_OUT or DIR_OUT ? 3141201527Sluigi if (V_ip_fw_chk_ptr && pfil_ipfw != 0 && 3142201527Sluigi dir == PFIL_OUT && ifp != NULL) { 3143201122Sluigi struct m_tag *mtag; 3144183550Szec 3145147744Sthompsa error = -1; 3146201527Sluigi /* fetch the start point from existing tags, if any */ 3147201527Sluigi mtag = m_tag_locate(*mp, MTAG_IPFW_RULE, 0, NULL); 3148201122Sluigi if (mtag == NULL) { 3149201527Sluigi args.rule.slot = 0; 3150200855Sluigi } else { 3151204591Sluigi struct ipfw_rule_ref *r; 3152201122Sluigi 3153201527Sluigi /* XXX can we free the tag after use ? */ 3154201122Sluigi mtag->m_tag_id = PACKET_TAG_NONE; 3155204591Sluigi r = (struct ipfw_rule_ref *)(mtag + 1); 3156201527Sluigi /* packet already partially processed ? */ 3157204591Sluigi if (r->info & IPFW_ONEPASS) 3158193859Soleg goto ipfwpass; 3159204591Sluigi args.rule = *r; 3160200855Sluigi } 3161147205Sthompsa 3162147205Sthompsa args.m = *mp; 3163147205Sthompsa args.oif = ifp; 3164147205Sthompsa args.next_hop = NULL; 3165225209Sbz args.next_hop6 = NULL; 3166147205Sthompsa args.eh = &eh2; 3167155268Soleg args.inp = NULL; /* used by ipfw uid/gid/jail rules */ 3168197952Sjulian i = V_ip_fw_chk_ptr(&args); 3169147205Sthompsa *mp = args.m; 3170147205Sthompsa 3171147205Sthompsa if (*mp == NULL) 3172158667Sthompsa return (error); 3173147205Sthompsa 3174193502Sluigi if (ip_dn_io_ptr && (i == IP_FW_DUMMYNET)) { 3175147205Sthompsa 3176147205Sthompsa /* put the Ethernet header back on */ 3177147205Sthompsa M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT); 3178147205Sthompsa if (*mp == NULL) 3179158667Sthompsa return (error); 3180147205Sthompsa bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN); 3181147205Sthompsa 3182147205Sthompsa /* 3183147205Sthompsa * Pass the pkt to dummynet, which consumes it. The 3184147205Sthompsa * packet will return to us via bridge_dummynet(). 3185147205Sthompsa */ 3186147205Sthompsa args.oif = ifp; 3187201122Sluigi ip_dn_io_ptr(mp, DIR_FWD | PROTO_IFB, &args); 3188158667Sthompsa return (error); 3189147205Sthompsa } 3190147205Sthompsa 3191147205Sthompsa if (i != IP_FW_PASS) /* drop */ 3192147205Sthompsa goto bad; 3193147205Sthompsa } 3194147205Sthompsa 3195147205Sthompsaipfwpass: 3196147744Sthompsa error = 0; 3197147744Sthompsa 3198146985Sthompsa /* 3199162561Sthompsa * Run the packet through pfil 3200146985Sthompsa */ 3201158667Sthompsa switch (ether_type) { 3202158667Sthompsa case ETHERTYPE_IP: 3203146985Sthompsa /* 3204146985Sthompsa * before calling the firewall, swap fields the same as 3205146985Sthompsa * IP does. here we assume the header is contiguous 3206146985Sthompsa */ 3207147744Sthompsa ip = mtod(*mp, struct ip *); 3208146985Sthompsa 3209147744Sthompsa ip->ip_len = ntohs(ip->ip_len); 3210147744Sthompsa ip->ip_off = ntohs(ip->ip_off); 3211146985Sthompsa 3212146985Sthompsa /* 3213146985Sthompsa * Run pfil on the member interface and the bridge, both can 3214146985Sthompsa * be skipped by clearing pfil_member or pfil_bridge. 3215146985Sthompsa * 3216146985Sthompsa * Keep the order: 3217146985Sthompsa * in_if -> bridge_if -> out_if 3218146985Sthompsa */ 3219147786Sthompsa if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) 3220197952Sjulian error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp, 3221146985Sthompsa dir, NULL); 3222146985Sthompsa 3223147744Sthompsa if (*mp == NULL || error != 0) /* filter may consume */ 3224147205Sthompsa break; 3225147205Sthompsa 3226147786Sthompsa if (pfil_member && ifp != NULL) 3227197952Sjulian error = pfil_run_hooks(&V_inet_pfil_hook, mp, ifp, 3228146985Sthompsa dir, NULL); 3229146985Sthompsa 3230147744Sthompsa if (*mp == NULL || error != 0) /* filter may consume */ 3231147205Sthompsa break; 3232147205Sthompsa 3233147786Sthompsa if (pfil_bridge && dir == PFIL_IN && bifp != NULL) 3234197952Sjulian error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp, 3235146985Sthompsa dir, NULL); 3236146985Sthompsa 3237158140Sthompsa if (*mp == NULL || error != 0) /* filter may consume */ 3238158140Sthompsa break; 3239158140Sthompsa 3240158140Sthompsa /* check if we need to fragment the packet */ 3241158140Sthompsa if (pfil_member && ifp != NULL && dir == PFIL_OUT) { 3242158140Sthompsa i = (*mp)->m_pkthdr.len; 3243158140Sthompsa if (i > ifp->if_mtu) { 3244158140Sthompsa error = bridge_fragment(ifp, *mp, &eh2, snap, 3245158140Sthompsa &llc1); 3246158140Sthompsa return (error); 3247158140Sthompsa } 3248146985Sthompsa } 3249146985Sthompsa 3250158592Sdhartmei /* Recalculate the ip checksum and restore byte ordering */ 3251158140Sthompsa ip = mtod(*mp, struct ip *); 3252158592Sdhartmei hlen = ip->ip_hl << 2; 3253158667Sthompsa if (hlen < sizeof(struct ip)) 3254158667Sthompsa goto bad; 3255158667Sthompsa if (hlen > (*mp)->m_len) { 3256158667Sthompsa if ((*mp = m_pullup(*mp, hlen)) == 0) 3257158667Sthompsa goto bad; 3258158667Sthompsa ip = mtod(*mp, struct ip *); 3259158667Sthompsa if (ip == NULL) 3260158667Sthompsa goto bad; 3261158667Sthompsa } 3262158140Sthompsa ip->ip_len = htons(ip->ip_len); 3263158140Sthompsa ip->ip_off = htons(ip->ip_off); 3264158667Sthompsa ip->ip_sum = 0; 3265158667Sthompsa if (hlen == sizeof(struct ip)) 3266158667Sthompsa ip->ip_sum = in_cksum_hdr(ip); 3267158667Sthompsa else 3268158667Sthompsa ip->ip_sum = in_cksum(*mp, hlen); 3269158140Sthompsa 3270146985Sthompsa break; 3271158667Sthompsa#ifdef INET6 3272158667Sthompsa case ETHERTYPE_IPV6: 3273147786Sthompsa if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) 3274197952Sjulian error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp, 3275147040Sthompsa dir, NULL); 3276147040Sthompsa 3277147744Sthompsa if (*mp == NULL || error != 0) /* filter may consume */ 3278147205Sthompsa break; 3279147205Sthompsa 3280147786Sthompsa if (pfil_member && ifp != NULL) 3281197952Sjulian error = pfil_run_hooks(&V_inet6_pfil_hook, mp, ifp, 3282146985Sthompsa dir, NULL); 3283147040Sthompsa 3284147744Sthompsa if (*mp == NULL || error != 0) /* filter may consume */ 3285147205Sthompsa break; 3286147205Sthompsa 3287147786Sthompsa if (pfil_bridge && dir == PFIL_IN && bifp != NULL) 3288197952Sjulian error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp, 3289147040Sthompsa dir, NULL); 3290146985Sthompsa break; 3291158667Sthompsa#endif 3292158667Sthompsa default: 3293162561Sthompsa error = 0; 3294146985Sthompsa break; 3295146985Sthompsa } 3296146985Sthompsa 3297146985Sthompsa if (*mp == NULL) 3298158667Sthompsa return (error); 3299146985Sthompsa if (error != 0) 3300146985Sthompsa goto bad; 3301146985Sthompsa 3302146985Sthompsa error = -1; 3303146985Sthompsa 3304146985Sthompsa /* 3305146985Sthompsa * Finally, put everything back the way it was and return 3306146985Sthompsa */ 3307146985Sthompsa if (snap) { 3308146985Sthompsa M_PREPEND(*mp, sizeof(struct llc), M_DONTWAIT); 3309146985Sthompsa if (*mp == NULL) 3310158667Sthompsa return (error); 3311147665Sthompsa bcopy(&llc1, mtod(*mp, caddr_t), sizeof(struct llc)); 3312146985Sthompsa } 3313146985Sthompsa 3314146985Sthompsa M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT); 3315146985Sthompsa if (*mp == NULL) 3316158667Sthompsa return (error); 3317146985Sthompsa bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN); 3318146985Sthompsa 3319158667Sthompsa return (0); 3320146985Sthompsa 3321153497Sthompsabad: 3322146985Sthompsa m_freem(*mp); 3323146985Sthompsa *mp = NULL; 3324158667Sthompsa return (error); 3325146985Sthompsa} 3326146985Sthompsa 3327146985Sthompsa/* 3328146985Sthompsa * Perform basic checks on header size since 3329146985Sthompsa * pfil assumes ip_input has already processed 3330146985Sthompsa * it for it. Cut-and-pasted from ip_input.c. 3331146985Sthompsa * Given how simple the IPv6 version is, 3332146985Sthompsa * does the IPv4 version really need to be 3333146985Sthompsa * this complicated? 3334146985Sthompsa * 3335146985Sthompsa * XXX Should we update ipstat here, or not? 3336146985Sthompsa * XXX Right now we update ipstat but not 3337146985Sthompsa * XXX csum_counter. 3338146985Sthompsa */ 3339146985Sthompsastatic int 3340146985Sthompsabridge_ip_checkbasic(struct mbuf **mp) 3341146985Sthompsa{ 3342146985Sthompsa struct mbuf *m = *mp; 3343146985Sthompsa struct ip *ip; 3344146985Sthompsa int len, hlen; 3345146985Sthompsa u_short sum; 3346146985Sthompsa 3347146985Sthompsa if (*mp == NULL) 3348158667Sthompsa return (-1); 3349146985Sthompsa 3350147744Sthompsa if (IP_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) { 3351147744Sthompsa if ((m = m_copyup(m, sizeof(struct ip), 3352147744Sthompsa (max_linkhdr + 3) & ~3)) == NULL) { 3353147744Sthompsa /* XXXJRT new stat, please */ 3354196039Srwatson KMOD_IPSTAT_INC(ips_toosmall); 3355147744Sthompsa goto bad; 3356147744Sthompsa } 3357147744Sthompsa } else if (__predict_false(m->m_len < sizeof (struct ip))) { 3358146985Sthompsa if ((m = m_pullup(m, sizeof (struct ip))) == NULL) { 3359196039Srwatson KMOD_IPSTAT_INC(ips_toosmall); 3360146985Sthompsa goto bad; 3361146985Sthompsa } 3362146985Sthompsa } 3363146985Sthompsa ip = mtod(m, struct ip *); 3364146985Sthompsa if (ip == NULL) goto bad; 3365146985Sthompsa 3366146985Sthompsa if (ip->ip_v != IPVERSION) { 3367196039Srwatson KMOD_IPSTAT_INC(ips_badvers); 3368146985Sthompsa goto bad; 3369146985Sthompsa } 3370146985Sthompsa hlen = ip->ip_hl << 2; 3371146985Sthompsa if (hlen < sizeof(struct ip)) { /* minimum header length */ 3372196039Srwatson KMOD_IPSTAT_INC(ips_badhlen); 3373146985Sthompsa goto bad; 3374146985Sthompsa } 3375146985Sthompsa if (hlen > m->m_len) { 3376146985Sthompsa if ((m = m_pullup(m, hlen)) == 0) { 3377196039Srwatson KMOD_IPSTAT_INC(ips_badhlen); 3378146985Sthompsa goto bad; 3379146985Sthompsa } 3380146985Sthompsa ip = mtod(m, struct ip *); 3381146985Sthompsa if (ip == NULL) goto bad; 3382146985Sthompsa } 3383146985Sthompsa 3384146985Sthompsa if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { 3385146985Sthompsa sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); 3386146985Sthompsa } else { 3387146985Sthompsa if (hlen == sizeof(struct ip)) { 3388146985Sthompsa sum = in_cksum_hdr(ip); 3389146985Sthompsa } else { 3390146985Sthompsa sum = in_cksum(m, hlen); 3391146985Sthompsa } 3392146985Sthompsa } 3393146985Sthompsa if (sum) { 3394196039Srwatson KMOD_IPSTAT_INC(ips_badsum); 3395146985Sthompsa goto bad; 3396146985Sthompsa } 3397146985Sthompsa 3398146985Sthompsa /* Retrieve the packet length. */ 3399146985Sthompsa len = ntohs(ip->ip_len); 3400146985Sthompsa 3401146985Sthompsa /* 3402146985Sthompsa * Check for additional length bogosity 3403146985Sthompsa */ 3404146985Sthompsa if (len < hlen) { 3405196039Srwatson KMOD_IPSTAT_INC(ips_badlen); 3406146985Sthompsa goto bad; 3407146985Sthompsa } 3408146985Sthompsa 3409146985Sthompsa /* 3410146985Sthompsa * Check that the amount of data in the buffers 3411146985Sthompsa * is as at least much as the IP header would have us expect. 3412146985Sthompsa * Drop packet if shorter than we expect. 3413146985Sthompsa */ 3414146985Sthompsa if (m->m_pkthdr.len < len) { 3415196039Srwatson KMOD_IPSTAT_INC(ips_tooshort); 3416146985Sthompsa goto bad; 3417146985Sthompsa } 3418146985Sthompsa 3419146985Sthompsa /* Checks out, proceed */ 3420146985Sthompsa *mp = m; 3421158667Sthompsa return (0); 3422146985Sthompsa 3423153497Sthompsabad: 3424146985Sthompsa *mp = m; 3425158667Sthompsa return (-1); 3426146985Sthompsa} 3427146985Sthompsa 3428158667Sthompsa#ifdef INET6 3429146985Sthompsa/* 3430146985Sthompsa * Same as above, but for IPv6. 3431146985Sthompsa * Cut-and-pasted from ip6_input.c. 3432146985Sthompsa * XXX Should we update ip6stat, or not? 3433146985Sthompsa */ 3434146985Sthompsastatic int 3435146985Sthompsabridge_ip6_checkbasic(struct mbuf **mp) 3436146985Sthompsa{ 3437146985Sthompsa struct mbuf *m = *mp; 3438146985Sthompsa struct ip6_hdr *ip6; 3439146985Sthompsa 3440146985Sthompsa /* 3441146985Sthompsa * If the IPv6 header is not aligned, slurp it up into a new 3442146985Sthompsa * mbuf with space for link headers, in the event we forward 3443146985Sthompsa * it. Otherwise, if it is aligned, make sure the entire base 3444146985Sthompsa * IPv6 header is in the first mbuf of the chain. 3445147744Sthompsa */ 3446146985Sthompsa if (IP6_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) { 3447146985Sthompsa struct ifnet *inifp = m->m_pkthdr.rcvif; 3448146985Sthompsa if ((m = m_copyup(m, sizeof(struct ip6_hdr), 3449146985Sthompsa (max_linkhdr + 3) & ~3)) == NULL) { 3450147744Sthompsa /* XXXJRT new stat, please */ 3451250044Sae IP6STAT_INC(ip6s_toosmall); 3452146985Sthompsa in6_ifstat_inc(inifp, ifs6_in_hdrerr); 3453146985Sthompsa goto bad; 3454146985Sthompsa } 3455147744Sthompsa } else if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) { 3456146985Sthompsa struct ifnet *inifp = m->m_pkthdr.rcvif; 3457146985Sthompsa if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { 3458250044Sae IP6STAT_INC(ip6s_toosmall); 3459146985Sthompsa in6_ifstat_inc(inifp, ifs6_in_hdrerr); 3460146985Sthompsa goto bad; 3461146985Sthompsa } 3462146985Sthompsa } 3463146985Sthompsa 3464146985Sthompsa ip6 = mtod(m, struct ip6_hdr *); 3465146985Sthompsa 3466146985Sthompsa if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { 3467250044Sae IP6STAT_INC(ip6s_badvers); 3468146985Sthompsa in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); 3469146985Sthompsa goto bad; 3470146985Sthompsa } 3471146985Sthompsa 3472146985Sthompsa /* Checks out, proceed */ 3473146985Sthompsa *mp = m; 3474158667Sthompsa return (0); 3475146985Sthompsa 3476153497Sthompsabad: 3477146985Sthompsa *mp = m; 3478158667Sthompsa return (-1); 3479146985Sthompsa} 3480158667Sthompsa#endif /* INET6 */ 3481158140Sthompsa 3482158140Sthompsa/* 3483158140Sthompsa * bridge_fragment: 3484158140Sthompsa * 3485158140Sthompsa * Return a fragmented mbuf chain. 3486158140Sthompsa */ 3487158140Sthompsastatic int 3488158140Sthompsabridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh, 3489158140Sthompsa int snap, struct llc *llc) 3490158140Sthompsa{ 3491158140Sthompsa struct mbuf *m0; 3492158140Sthompsa struct ip *ip; 3493158140Sthompsa int error = -1; 3494158140Sthompsa 3495158140Sthompsa if (m->m_len < sizeof(struct ip) && 3496158140Sthompsa (m = m_pullup(m, sizeof(struct ip))) == NULL) 3497158140Sthompsa goto out; 3498158140Sthompsa ip = mtod(m, struct ip *); 3499158140Sthompsa 3500158140Sthompsa error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist, 3501158140Sthompsa CSUM_DELAY_IP); 3502158140Sthompsa if (error) 3503158140Sthompsa goto out; 3504158140Sthompsa 3505158140Sthompsa /* walk the chain and re-add the Ethernet header */ 3506158140Sthompsa for (m0 = m; m0; m0 = m0->m_nextpkt) { 3507158140Sthompsa if (error == 0) { 3508158140Sthompsa if (snap) { 3509158140Sthompsa M_PREPEND(m0, sizeof(struct llc), M_DONTWAIT); 3510158140Sthompsa if (m0 == NULL) { 3511158140Sthompsa error = ENOBUFS; 3512158140Sthompsa continue; 3513158140Sthompsa } 3514158140Sthompsa bcopy(llc, mtod(m0, caddr_t), 3515158140Sthompsa sizeof(struct llc)); 3516158140Sthompsa } 3517158140Sthompsa M_PREPEND(m0, ETHER_HDR_LEN, M_DONTWAIT); 3518158140Sthompsa if (m0 == NULL) { 3519158140Sthompsa error = ENOBUFS; 3520158140Sthompsa continue; 3521158140Sthompsa } 3522158140Sthompsa bcopy(eh, mtod(m0, caddr_t), ETHER_HDR_LEN); 3523253239Shrs } else 3524158140Sthompsa m_freem(m); 3525158140Sthompsa } 3526158140Sthompsa 3527158140Sthompsa if (error == 0) 3528196039Srwatson KMOD_IPSTAT_INC(ips_fragmented); 3529158140Sthompsa 3530158140Sthompsa return (error); 3531158140Sthompsa 3532158140Sthompsaout: 3533158140Sthompsa if (m != NULL) 3534158140Sthompsa m_freem(m); 3535158140Sthompsa return (error); 3536158140Sthompsa} 3537236051Sthompsa 3538236051Sthompsastatic void 3539236051Sthompsabridge_linkstate(struct ifnet *ifp) 3540236051Sthompsa{ 3541236051Sthompsa struct bridge_softc *sc = ifp->if_bridge; 3542237103Sthompsa struct bridge_iflist *bif; 3543236051Sthompsa 3544236051Sthompsa BRIDGE_LOCK(sc); 3545236051Sthompsa bif = bridge_lookup_member_if(sc, ifp); 3546236051Sthompsa if (bif == NULL) { 3547236051Sthompsa BRIDGE_UNLOCK(sc); 3548236051Sthompsa return; 3549236051Sthompsa } 3550237103Sthompsa bridge_linkcheck(sc); 3551237103Sthompsa BRIDGE_UNLOCK(sc); 3552237103Sthompsa 3553237103Sthompsa bstp_linkstate(&bif->bif_stp); 3554237103Sthompsa} 3555237103Sthompsa 3556237103Sthompsastatic void 3557237103Sthompsabridge_linkcheck(struct bridge_softc *sc) 3558237103Sthompsa{ 3559237103Sthompsa struct bridge_iflist *bif; 3560237103Sthompsa int new_link, hasls; 3561237103Sthompsa 3562237103Sthompsa BRIDGE_LOCK_ASSERT(sc); 3563236051Sthompsa new_link = LINK_STATE_DOWN; 3564236051Sthompsa hasls = 0; 3565236051Sthompsa /* Our link is considered up if at least one of our ports is active */ 3566237103Sthompsa LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { 3567237103Sthompsa if (bif->bif_ifp->if_capabilities & IFCAP_LINKSTATE) 3568236051Sthompsa hasls++; 3569237103Sthompsa if (bif->bif_ifp->if_link_state == LINK_STATE_UP) { 3570236051Sthompsa new_link = LINK_STATE_UP; 3571236051Sthompsa break; 3572236051Sthompsa } 3573236051Sthompsa } 3574236051Sthompsa if (!LIST_EMPTY(&sc->sc_iflist) && !hasls) { 3575236051Sthompsa /* If no interfaces support link-state then we default to up */ 3576236051Sthompsa new_link = LINK_STATE_UP; 3577236051Sthompsa } 3578236051Sthompsa if_link_state_change(sc->sc_ifp, new_link); 3579236051Sthompsa} 3580