1 1.199 ozaki /* $NetBSD: if_bridge.c,v 1.199 2025/04/22 05:47:51 ozaki-r Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.1 thorpej * Copyright 2001 Wasabi Systems, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 1.1 thorpej * 9 1.1 thorpej * Redistribution and use in source and binary forms, with or without 10 1.1 thorpej * modification, are permitted provided that the following conditions 11 1.1 thorpej * are met: 12 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 13 1.1 thorpej * notice, this list of conditions and the following disclaimer. 14 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 16 1.1 thorpej * documentation and/or other materials provided with the distribution. 17 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 18 1.1 thorpej * must display the following acknowledgement: 19 1.1 thorpej * This product includes software developed for the NetBSD Project by 20 1.1 thorpej * Wasabi Systems, Inc. 21 1.1 thorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 thorpej * or promote products derived from this software without specific prior 23 1.1 thorpej * written permission. 24 1.1 thorpej * 25 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 36 1.1 thorpej */ 37 1.1 thorpej 38 1.29 perry /* 39 1.1 thorpej * Copyright (c) 1999, 2000 Jason L. Wright (jason (at) thought.net) 40 1.29 perry * All rights reserved. 41 1.1 thorpej * 42 1.29 perry * Redistribution and use in source and binary forms, with or without 43 1.29 perry * modification, are permitted provided that the following conditions 44 1.1 thorpej * are met: 45 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 46 1.1 thorpej * notice, this list of conditions and the following disclaimer. 47 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 48 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 49 1.1 thorpej * documentation and/or other materials provided with the distribution. 50 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 51 1.1 thorpej * must display the following acknowledgement: 52 1.1 thorpej * This product includes software developed by Jason L. Wright 53 1.1 thorpej * 4. The name of the author may not be used to endorse or promote products 54 1.1 thorpej * derived from this software without specific prior written permission. 55 1.1 thorpej * 56 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 57 1.1 thorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 58 1.1 thorpej * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 59 1.1 thorpej * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 60 1.1 thorpej * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 61 1.1 thorpej * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 62 1.1 thorpej * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 64 1.1 thorpej * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 65 1.1 thorpej * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 66 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 67 1.1 thorpej * 68 1.1 thorpej * OpenBSD: if_bridge.c,v 1.60 2001/06/15 03:38:33 itojun Exp 69 1.1 thorpej */ 70 1.1 thorpej 71 1.1 thorpej /* 72 1.1 thorpej * Network interface bridge support. 73 1.1 thorpej * 74 1.1 thorpej * TODO: 75 1.1 thorpej * 76 1.1 thorpej * - Currently only supports Ethernet-like interfaces (Ethernet, 77 1.1 thorpej * 802.11, VLANs on Ethernet, etc.) Figure out a nice way 78 1.1 thorpej * to bridge other types of interfaces (FDDI-FDDI, and maybe 79 1.1 thorpej * consider heterogenous bridges). 80 1.1 thorpej */ 81 1.3 lukem 82 1.3 lukem #include <sys/cdefs.h> 83 1.199 ozaki __KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.199 2025/04/22 05:47:51 ozaki-r Exp $"); 84 1.1 thorpej 85 1.72 pooka #ifdef _KERNEL_OPT 86 1.16 jdc #include "opt_inet.h" 87 1.114 ozaki #include "opt_net_mpsafe.h" 88 1.72 pooka #endif /* _KERNEL_OPT */ 89 1.1 thorpej 90 1.29 perry #include <sys/param.h> 91 1.1 thorpej #include <sys/kernel.h> 92 1.1 thorpej #include <sys/mbuf.h> 93 1.1 thorpej #include <sys/queue.h> 94 1.1 thorpej #include <sys/socket.h> 95 1.68 bouyer #include <sys/socketvar.h> /* for softnet_lock */ 96 1.1 thorpej #include <sys/sockio.h> 97 1.1 thorpej #include <sys/systm.h> 98 1.29 perry #include <sys/proc.h> 99 1.1 thorpej #include <sys/pool.h> 100 1.37 elad #include <sys/kauth.h> 101 1.65 bouyer #include <sys/cpu.h> 102 1.74 tls #include <sys/cprng.h> 103 1.86 ozaki #include <sys/mutex.h> 104 1.93 ozaki #include <sys/kmem.h> 105 1.194 ozaki #include <sys/syslog.h> 106 1.1 thorpej 107 1.1 thorpej #include <net/bpf.h> 108 1.1 thorpej #include <net/if.h> 109 1.1 thorpej #include <net/if_dl.h> 110 1.1 thorpej #include <net/if_types.h> 111 1.1 thorpej #include <net/if_llc.h> 112 1.1 thorpej 113 1.1 thorpej #include <net/if_ether.h> 114 1.1 thorpej #include <net/if_bridgevar.h> 115 1.161 rin #include <net/ether_sw_offload.h> 116 1.1 thorpej 117 1.25 christos /* Used for bridge_ip[6]_checkbasic */ 118 1.9 perseant #include <netinet/in.h> 119 1.9 perseant #include <netinet/in_systm.h> 120 1.9 perseant #include <netinet/ip.h> 121 1.9 perseant #include <netinet/ip_var.h> 122 1.61 thorpej #include <netinet/ip_private.h> /* XXX */ 123 1.9 perseant #include <netinet/ip6.h> 124 1.9 perseant #include <netinet6/in6_var.h> 125 1.162 martin #include <netinet6/ip6_var.h> 126 1.61 thorpej #include <netinet6/ip6_private.h> /* XXX */ 127 1.9 perseant 128 1.1 thorpej /* 129 1.1 thorpej * Size of the route hash table. Must be a power of two. 130 1.1 thorpej */ 131 1.1 thorpej #ifndef BRIDGE_RTHASH_SIZE 132 1.1 thorpej #define BRIDGE_RTHASH_SIZE 1024 133 1.1 thorpej #endif 134 1.1 thorpej 135 1.1 thorpej #define BRIDGE_RTHASH_MASK (BRIDGE_RTHASH_SIZE - 1) 136 1.1 thorpej 137 1.38 liamjfoy #include "carp.h" 138 1.38 liamjfoy #if NCARP > 0 139 1.38 liamjfoy #include <netinet/in.h> 140 1.38 liamjfoy #include <netinet/in_var.h> 141 1.38 liamjfoy #include <netinet/ip_carp.h> 142 1.38 liamjfoy #endif 143 1.38 liamjfoy 144 1.101 christos #include "ioconf.h" 145 1.101 christos 146 1.99 matt __CTASSERT(sizeof(struct ifbifconf) == sizeof(struct ifbaconf)); 147 1.99 matt __CTASSERT(offsetof(struct ifbifconf, ifbic_len) == offsetof(struct ifbaconf, ifbac_len)); 148 1.99 matt __CTASSERT(offsetof(struct ifbifconf, ifbic_buf) == offsetof(struct ifbaconf, ifbac_buf)); 149 1.99 matt 150 1.1 thorpej /* 151 1.1 thorpej * Maximum number of addresses to cache. 152 1.1 thorpej */ 153 1.1 thorpej #ifndef BRIDGE_RTABLE_MAX 154 1.1 thorpej #define BRIDGE_RTABLE_MAX 100 155 1.1 thorpej #endif 156 1.1 thorpej 157 1.1 thorpej /* 158 1.1 thorpej * Spanning tree defaults. 159 1.1 thorpej */ 160 1.1 thorpej #define BSTP_DEFAULT_MAX_AGE (20 * 256) 161 1.1 thorpej #define BSTP_DEFAULT_HELLO_TIME (2 * 256) 162 1.1 thorpej #define BSTP_DEFAULT_FORWARD_DELAY (15 * 256) 163 1.1 thorpej #define BSTP_DEFAULT_HOLD_TIME (1 * 256) 164 1.1 thorpej #define BSTP_DEFAULT_BRIDGE_PRIORITY 0x8000 165 1.1 thorpej #define BSTP_DEFAULT_PORT_PRIORITY 0x80 166 1.1 thorpej #define BSTP_DEFAULT_PATH_COST 55 167 1.1 thorpej 168 1.1 thorpej /* 169 1.1 thorpej * Timeout (in seconds) for entries learned dynamically. 170 1.1 thorpej */ 171 1.1 thorpej #ifndef BRIDGE_RTABLE_TIMEOUT 172 1.1 thorpej #define BRIDGE_RTABLE_TIMEOUT (20 * 60) /* same as ARP */ 173 1.1 thorpej #endif 174 1.1 thorpej 175 1.1 thorpej /* 176 1.1 thorpej * Number of seconds between walks of the route list. 177 1.1 thorpej */ 178 1.1 thorpej #ifndef BRIDGE_RTABLE_PRUNE_PERIOD 179 1.1 thorpej #define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60) 180 1.1 thorpej #endif 181 1.1 thorpej 182 1.150 ozaki #define BRIDGE_RT_LOCK(_sc) mutex_enter((_sc)->sc_rtlist_lock) 183 1.150 ozaki #define BRIDGE_RT_UNLOCK(_sc) mutex_exit((_sc)->sc_rtlist_lock) 184 1.150 ozaki #define BRIDGE_RT_LOCKED(_sc) mutex_owned((_sc)->sc_rtlist_lock) 185 1.97 ozaki 186 1.97 ozaki #define BRIDGE_RT_PSZ_PERFORM(_sc) \ 187 1.153 ozaki pserialize_perform((_sc)->sc_rtlist_psz) 188 1.97 ozaki 189 1.152 ozaki #define BRIDGE_RTLIST_READER_FOREACH(_brt, _sc) \ 190 1.152 ozaki PSLIST_READER_FOREACH((_brt), &((_sc)->sc_rtlist), \ 191 1.152 ozaki struct bridge_rtnode, brt_list) 192 1.152 ozaki #define BRIDGE_RTLIST_WRITER_FOREACH(_brt, _sc) \ 193 1.152 ozaki PSLIST_WRITER_FOREACH((_brt), &((_sc)->sc_rtlist), \ 194 1.152 ozaki struct bridge_rtnode, brt_list) 195 1.152 ozaki #define BRIDGE_RTLIST_WRITER_INSERT_HEAD(_sc, _brt) \ 196 1.152 ozaki PSLIST_WRITER_INSERT_HEAD(&(_sc)->sc_rtlist, brt, brt_list) 197 1.152 ozaki #define BRIDGE_RTLIST_WRITER_REMOVE(_brt) \ 198 1.152 ozaki PSLIST_WRITER_REMOVE((_brt), brt_list) 199 1.152 ozaki 200 1.152 ozaki #define BRIDGE_RTHASH_READER_FOREACH(_brt, _sc, _hash) \ 201 1.152 ozaki PSLIST_READER_FOREACH((_brt), &(_sc)->sc_rthash[(_hash)], \ 202 1.152 ozaki struct bridge_rtnode, brt_hash) 203 1.152 ozaki #define BRIDGE_RTHASH_WRITER_FOREACH(_brt, _sc, _hash) \ 204 1.152 ozaki PSLIST_WRITER_FOREACH((_brt), &(_sc)->sc_rthash[(_hash)], \ 205 1.152 ozaki struct bridge_rtnode, brt_hash) 206 1.152 ozaki #define BRIDGE_RTHASH_WRITER_INSERT_HEAD(_sc, _hash, _brt) \ 207 1.152 ozaki PSLIST_WRITER_INSERT_HEAD(&(_sc)->sc_rthash[(_hash)], brt, brt_hash) 208 1.152 ozaki #define BRIDGE_RTHASH_WRITER_INSERT_AFTER(_brt, _new) \ 209 1.152 ozaki PSLIST_WRITER_INSERT_AFTER((_brt), (_new), brt_hash) 210 1.152 ozaki #define BRIDGE_RTHASH_WRITER_REMOVE(_brt) \ 211 1.152 ozaki PSLIST_WRITER_REMOVE((_brt), brt_hash) 212 1.114 ozaki 213 1.114 ozaki #ifdef NET_MPSAFE 214 1.114 ozaki #define DECLARE_LOCK_VARIABLE 215 1.114 ozaki #define ACQUIRE_GLOBAL_LOCKS() do { } while (0) 216 1.114 ozaki #define RELEASE_GLOBAL_LOCKS() do { } while (0) 217 1.114 ozaki #else 218 1.114 ozaki #define DECLARE_LOCK_VARIABLE int __s 219 1.114 ozaki #define ACQUIRE_GLOBAL_LOCKS() do { \ 220 1.114 ozaki KERNEL_LOCK(1, NULL); \ 221 1.114 ozaki mutex_enter(softnet_lock); \ 222 1.132 ozaki __s = splsoftnet(); \ 223 1.114 ozaki } while (0) 224 1.114 ozaki #define RELEASE_GLOBAL_LOCKS() do { \ 225 1.114 ozaki splx(__s); \ 226 1.114 ozaki mutex_exit(softnet_lock); \ 227 1.114 ozaki KERNEL_UNLOCK_ONE(NULL); \ 228 1.114 ozaki } while (0) 229 1.114 ozaki #endif 230 1.97 ozaki 231 1.115 ozaki struct psref_class *bridge_psref_class __read_mostly; 232 1.115 ozaki 233 1.1 thorpej int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; 234 1.1 thorpej 235 1.33 thorpej static struct pool bridge_rtnode_pool; 236 1.1 thorpej 237 1.33 thorpej static int bridge_clone_create(struct if_clone *, int); 238 1.33 thorpej static int bridge_clone_destroy(struct ifnet *); 239 1.1 thorpej 240 1.50 christos static int bridge_ioctl(struct ifnet *, u_long, void *); 241 1.33 thorpej static int bridge_init(struct ifnet *); 242 1.33 thorpej static void bridge_stop(struct ifnet *, int); 243 1.33 thorpej static void bridge_start(struct ifnet *); 244 1.183 yamaguch static void bridge_ifdetach(void *); 245 1.33 thorpej 246 1.81 ozaki static void bridge_input(struct ifnet *, struct mbuf *); 247 1.108 ozaki static void bridge_forward(struct bridge_softc *, struct mbuf *); 248 1.33 thorpej 249 1.33 thorpej static void bridge_timer(void *); 250 1.33 thorpej 251 1.194 ozaki static void bridge_broadcast(struct bridge_softc *, struct ifnet *, bool, 252 1.33 thorpej struct mbuf *); 253 1.33 thorpej 254 1.33 thorpej static int bridge_rtupdate(struct bridge_softc *, const uint8_t *, 255 1.33 thorpej struct ifnet *, int, uint8_t); 256 1.33 thorpej static struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *); 257 1.33 thorpej static void bridge_rttrim(struct bridge_softc *); 258 1.33 thorpej static void bridge_rtage(struct bridge_softc *); 259 1.97 ozaki static void bridge_rtage_work(struct work *, void *); 260 1.33 thorpej static void bridge_rtflush(struct bridge_softc *, int); 261 1.33 thorpej static int bridge_rtdaddr(struct bridge_softc *, const uint8_t *); 262 1.33 thorpej static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp); 263 1.33 thorpej 264 1.93 ozaki static void bridge_rtable_init(struct bridge_softc *); 265 1.33 thorpej static void bridge_rtable_fini(struct bridge_softc *); 266 1.33 thorpej 267 1.33 thorpej static struct bridge_rtnode *bridge_rtnode_lookup(struct bridge_softc *, 268 1.33 thorpej const uint8_t *); 269 1.33 thorpej static int bridge_rtnode_insert(struct bridge_softc *, 270 1.33 thorpej struct bridge_rtnode *); 271 1.97 ozaki static void bridge_rtnode_remove(struct bridge_softc *, 272 1.97 ozaki struct bridge_rtnode *); 273 1.97 ozaki static void bridge_rtnode_destroy(struct bridge_rtnode *); 274 1.33 thorpej 275 1.33 thorpej static struct bridge_iflist *bridge_lookup_member(struct bridge_softc *, 276 1.115 ozaki const char *name, 277 1.115 ozaki struct psref *); 278 1.33 thorpej static struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *, 279 1.115 ozaki struct ifnet *ifp, 280 1.115 ozaki struct psref *); 281 1.115 ozaki static void bridge_release_member(struct bridge_softc *, struct bridge_iflist *, 282 1.115 ozaki struct psref *); 283 1.33 thorpej static void bridge_delete_member(struct bridge_softc *, 284 1.33 thorpej struct bridge_iflist *); 285 1.115 ozaki static void bridge_acquire_member(struct bridge_softc *sc, 286 1.115 ozaki struct bridge_iflist *, 287 1.115 ozaki struct psref *); 288 1.33 thorpej 289 1.33 thorpej static int bridge_ioctl_add(struct bridge_softc *, void *); 290 1.33 thorpej static int bridge_ioctl_del(struct bridge_softc *, void *); 291 1.33 thorpej static int bridge_ioctl_gifflags(struct bridge_softc *, void *); 292 1.33 thorpej static int bridge_ioctl_sifflags(struct bridge_softc *, void *); 293 1.33 thorpej static int bridge_ioctl_scache(struct bridge_softc *, void *); 294 1.33 thorpej static int bridge_ioctl_gcache(struct bridge_softc *, void *); 295 1.33 thorpej static int bridge_ioctl_gifs(struct bridge_softc *, void *); 296 1.33 thorpej static int bridge_ioctl_rts(struct bridge_softc *, void *); 297 1.33 thorpej static int bridge_ioctl_saddr(struct bridge_softc *, void *); 298 1.33 thorpej static int bridge_ioctl_sto(struct bridge_softc *, void *); 299 1.33 thorpej static int bridge_ioctl_gto(struct bridge_softc *, void *); 300 1.33 thorpej static int bridge_ioctl_daddr(struct bridge_softc *, void *); 301 1.33 thorpej static int bridge_ioctl_flush(struct bridge_softc *, void *); 302 1.33 thorpej static int bridge_ioctl_gpri(struct bridge_softc *, void *); 303 1.33 thorpej static int bridge_ioctl_spri(struct bridge_softc *, void *); 304 1.33 thorpej static int bridge_ioctl_ght(struct bridge_softc *, void *); 305 1.33 thorpej static int bridge_ioctl_sht(struct bridge_softc *, void *); 306 1.33 thorpej static int bridge_ioctl_gfd(struct bridge_softc *, void *); 307 1.33 thorpej static int bridge_ioctl_sfd(struct bridge_softc *, void *); 308 1.33 thorpej static int bridge_ioctl_gma(struct bridge_softc *, void *); 309 1.33 thorpej static int bridge_ioctl_sma(struct bridge_softc *, void *); 310 1.33 thorpej static int bridge_ioctl_sifprio(struct bridge_softc *, void *); 311 1.33 thorpej static int bridge_ioctl_sifcost(struct bridge_softc *, void *); 312 1.33 thorpej static int bridge_ioctl_gfilt(struct bridge_softc *, void *); 313 1.33 thorpej static int bridge_ioctl_sfilt(struct bridge_softc *, void *); 314 1.33 thorpej static int bridge_ipf(void *, struct mbuf **, struct ifnet *, int); 315 1.33 thorpej static int bridge_ip_checkbasic(struct mbuf **mp); 316 1.9 perseant # ifdef INET6 317 1.33 thorpej static int bridge_ip6_checkbasic(struct mbuf **mp); 318 1.9 perseant # endif /* INET6 */ 319 1.1 thorpej 320 1.1 thorpej struct bridge_control { 321 1.1 thorpej int (*bc_func)(struct bridge_softc *, void *); 322 1.1 thorpej int bc_argsize; 323 1.1 thorpej int bc_flags; 324 1.1 thorpej }; 325 1.1 thorpej 326 1.1 thorpej #define BC_F_COPYIN 0x01 /* copy arguments in */ 327 1.1 thorpej #define BC_F_COPYOUT 0x02 /* copy arguments out */ 328 1.1 thorpej #define BC_F_SUSER 0x04 /* do super-user check */ 329 1.99 matt #define BC_F_XLATEIN 0x08 /* xlate arguments in */ 330 1.99 matt #define BC_F_XLATEOUT 0x10 /* xlate arguments out */ 331 1.1 thorpej 332 1.33 thorpej static const struct bridge_control bridge_control_table[] = { 333 1.55 dyoung [BRDGADD] = {bridge_ioctl_add, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, 334 1.188 skrll [BRDGDEL] = {bridge_ioctl_del, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, 335 1.1 thorpej 336 1.188 skrll [BRDGGIFFLGS] = {bridge_ioctl_gifflags, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_COPYOUT}, 337 1.188 skrll [BRDGSIFFLGS] = {bridge_ioctl_sifflags, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, 338 1.11 bouyer 339 1.188 skrll [BRDGSCACHE] = {bridge_ioctl_scache, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, 340 1.188 skrll [BRDGGCACHE] = {bridge_ioctl_gcache, sizeof(struct ifbrparam), BC_F_COPYOUT}, 341 1.55 dyoung 342 1.188 skrll [OBRDGGIFS] = {bridge_ioctl_gifs, sizeof(struct ifbifconf), BC_F_COPYIN|BC_F_COPYOUT}, 343 1.188 skrll [OBRDGRTS] = {bridge_ioctl_rts, sizeof(struct ifbaconf), BC_F_COPYIN|BC_F_COPYOUT}, 344 1.55 dyoung 345 1.188 skrll [BRDGSADDR] = {bridge_ioctl_saddr, sizeof(struct ifbareq), BC_F_COPYIN|BC_F_SUSER}, 346 1.55 dyoung 347 1.188 skrll [BRDGSTO] = {bridge_ioctl_sto, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, 348 1.188 skrll [BRDGGTO] = {bridge_ioctl_gto, sizeof(struct ifbrparam), BC_F_COPYOUT}, 349 1.55 dyoung 350 1.188 skrll [BRDGDADDR] = {bridge_ioctl_daddr, sizeof(struct ifbareq), BC_F_COPYIN|BC_F_SUSER}, 351 1.55 dyoung 352 1.188 skrll [BRDGFLUSH] = {bridge_ioctl_flush, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, 353 1.55 dyoung 354 1.188 skrll [BRDGGPRI] = {bridge_ioctl_gpri, sizeof(struct ifbrparam), BC_F_COPYOUT}, 355 1.188 skrll [BRDGSPRI] = {bridge_ioctl_spri, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, 356 1.55 dyoung 357 1.188 skrll [BRDGGHT] = {bridge_ioctl_ght, sizeof(struct ifbrparam), BC_F_COPYOUT}, 358 1.188 skrll [BRDGSHT] = {bridge_ioctl_sht, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, 359 1.55 dyoung 360 1.188 skrll [BRDGGFD] = {bridge_ioctl_gfd, sizeof(struct ifbrparam), BC_F_COPYOUT}, 361 1.188 skrll [BRDGSFD] = {bridge_ioctl_sfd, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, 362 1.55 dyoung 363 1.188 skrll [BRDGGMA] = {bridge_ioctl_gma, sizeof(struct ifbrparam), BC_F_COPYOUT}, 364 1.188 skrll [BRDGSMA] = {bridge_ioctl_sma, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, 365 1.55 dyoung 366 1.188 skrll [BRDGSIFPRIO] = {bridge_ioctl_sifprio, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, 367 1.55 dyoung 368 1.188 skrll [BRDGSIFCOST] = {bridge_ioctl_sifcost, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER}, 369 1.174 maxv 370 1.55 dyoung [BRDGGFILT] = {bridge_ioctl_gfilt, sizeof(struct ifbrparam), BC_F_COPYOUT}, 371 1.55 dyoung [BRDGSFILT] = {bridge_ioctl_sfilt, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER}, 372 1.174 maxv 373 1.99 matt [BRDGGIFS] = {bridge_ioctl_gifs, sizeof(struct ifbifconf), BC_F_XLATEIN|BC_F_XLATEOUT}, 374 1.99 matt [BRDGRTS] = {bridge_ioctl_rts, sizeof(struct ifbaconf), BC_F_XLATEIN|BC_F_XLATEOUT}, 375 1.1 thorpej }; 376 1.99 matt 377 1.49 dyoung static const int bridge_control_table_size = __arraycount(bridge_control_table); 378 1.1 thorpej 379 1.33 thorpej static struct if_clone bridge_cloner = 380 1.1 thorpej IF_CLONE_INITIALIZER("bridge", bridge_clone_create, bridge_clone_destroy); 381 1.1 thorpej 382 1.1 thorpej /* 383 1.1 thorpej * bridgeattach: 384 1.1 thorpej * 385 1.1 thorpej * Pseudo-device attach routine. 386 1.1 thorpej */ 387 1.1 thorpej void 388 1.45 christos bridgeattach(int n) 389 1.1 thorpej { 390 1.1 thorpej 391 1.1 thorpej pool_init(&bridge_rtnode_pool, sizeof(struct bridge_rtnode), 392 1.51 ad 0, 0, 0, "brtpl", NULL, IPL_NET); 393 1.1 thorpej 394 1.115 ozaki bridge_psref_class = psref_class_create("bridge", IPL_SOFTNET); 395 1.115 ozaki 396 1.1 thorpej if_clone_attach(&bridge_cloner); 397 1.1 thorpej } 398 1.1 thorpej 399 1.1 thorpej /* 400 1.1 thorpej * bridge_clone_create: 401 1.1 thorpej * 402 1.1 thorpej * Create a new bridge instance. 403 1.1 thorpej */ 404 1.33 thorpej static int 405 1.1 thorpej bridge_clone_create(struct if_clone *ifc, int unit) 406 1.1 thorpej { 407 1.1 thorpej struct bridge_softc *sc; 408 1.1 thorpej struct ifnet *ifp; 409 1.114 ozaki int error; 410 1.1 thorpej 411 1.93 ozaki sc = kmem_zalloc(sizeof(*sc), KM_SLEEP); 412 1.1 thorpej ifp = &sc->sc_if; 413 1.1 thorpej 414 1.1 thorpej sc->sc_brtmax = BRIDGE_RTABLE_MAX; 415 1.1 thorpej sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT; 416 1.29 perry sc->sc_bridge_max_age = BSTP_DEFAULT_MAX_AGE; 417 1.1 thorpej sc->sc_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME; 418 1.1 thorpej sc->sc_bridge_forward_delay = BSTP_DEFAULT_FORWARD_DELAY; 419 1.1 thorpej sc->sc_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY; 420 1.1 thorpej sc->sc_hold_time = BSTP_DEFAULT_HOLD_TIME; 421 1.9 perseant sc->sc_filter_flags = 0; 422 1.1 thorpej 423 1.1 thorpej /* Initialize our routing table. */ 424 1.1 thorpej bridge_rtable_init(sc); 425 1.1 thorpej 426 1.97 ozaki error = workqueue_create(&sc->sc_rtage_wq, "bridge_rtage", 427 1.114 ozaki bridge_rtage_work, sc, PRI_SOFTNET, IPL_SOFTNET, WQ_MPSAFE); 428 1.97 ozaki if (error) 429 1.97 ozaki panic("%s: workqueue_create %d\n", __func__, error); 430 1.97 ozaki 431 1.139 ozaki callout_init(&sc->sc_brcallout, CALLOUT_MPSAFE); 432 1.139 ozaki callout_init(&sc->sc_bstpcallout, CALLOUT_MPSAFE); 433 1.1 thorpej 434 1.115 ozaki mutex_init(&sc->sc_iflist_psref.bip_lock, MUTEX_DEFAULT, IPL_NONE); 435 1.115 ozaki PSLIST_INIT(&sc->sc_iflist_psref.bip_iflist); 436 1.115 ozaki sc->sc_iflist_psref.bip_psz = pserialize_create(); 437 1.1 thorpej 438 1.62 christos if_initname(ifp, ifc->ifc_name, unit); 439 1.1 thorpej ifp->if_softc = sc; 440 1.146 ozaki #ifdef NET_MPSAFE 441 1.175 roy ifp->if_extflags = IFEF_MPSAFE; 442 1.146 ozaki #endif 443 1.1 thorpej ifp->if_mtu = ETHERMTU; 444 1.1 thorpej ifp->if_ioctl = bridge_ioctl; 445 1.1 thorpej ifp->if_output = bridge_output; 446 1.1 thorpej ifp->if_start = bridge_start; 447 1.1 thorpej ifp->if_stop = bridge_stop; 448 1.1 thorpej ifp->if_init = bridge_init; 449 1.6 itojun ifp->if_type = IFT_BRIDGE; 450 1.1 thorpej ifp->if_addrlen = 0; 451 1.1 thorpej ifp->if_dlt = DLT_EN10MB; 452 1.1 thorpej ifp->if_hdrlen = ETHER_HDR_LEN; 453 1.180 riastrad if_initialize(ifp); 454 1.175 roy 455 1.175 roy /* 456 1.175 roy * Set the link state to down. 457 1.175 roy * When interfaces are added the link state will reflect 458 1.175 roy * the best link state of the combined interfaces. 459 1.175 roy */ 460 1.175 roy ifp->if_link_state = LINK_STATE_DOWN; 461 1.175 roy 462 1.156 ozaki if_alloc_sadl(ifp); 463 1.106 ozaki if_register(ifp); 464 1.1 thorpej 465 1.136 msaitoh return 0; 466 1.1 thorpej } 467 1.1 thorpej 468 1.1 thorpej /* 469 1.1 thorpej * bridge_clone_destroy: 470 1.1 thorpej * 471 1.1 thorpej * Destroy a bridge instance. 472 1.1 thorpej */ 473 1.33 thorpej static int 474 1.1 thorpej bridge_clone_destroy(struct ifnet *ifp) 475 1.1 thorpej { 476 1.1 thorpej struct bridge_softc *sc = ifp->if_softc; 477 1.1 thorpej struct bridge_iflist *bif; 478 1.1 thorpej 479 1.148 maxv if ((ifp->if_flags & IFF_RUNNING) != 0) 480 1.148 maxv bridge_stop(ifp, 1); 481 1.1 thorpej 482 1.98 ozaki BRIDGE_LOCK(sc); 483 1.112 ozaki for (;;) { 484 1.115 ozaki bif = PSLIST_WRITER_FIRST(&sc->sc_iflist_psref.bip_iflist, struct bridge_iflist, 485 1.112 ozaki bif_next); 486 1.112 ozaki if (bif == NULL) 487 1.112 ozaki break; 488 1.1 thorpej bridge_delete_member(sc, bif); 489 1.112 ozaki } 490 1.115 ozaki PSLIST_DESTROY(&sc->sc_iflist_psref.bip_iflist); 491 1.98 ozaki BRIDGE_UNLOCK(sc); 492 1.1 thorpej 493 1.1 thorpej if_detach(ifp); 494 1.1 thorpej 495 1.1 thorpej /* Tear down the routing table. */ 496 1.1 thorpej bridge_rtable_fini(sc); 497 1.1 thorpej 498 1.115 ozaki pserialize_destroy(sc->sc_iflist_psref.bip_psz); 499 1.115 ozaki mutex_destroy(&sc->sc_iflist_psref.bip_lock); 500 1.136 msaitoh callout_destroy(&sc->sc_brcallout); 501 1.136 msaitoh callout_destroy(&sc->sc_bstpcallout); 502 1.97 ozaki workqueue_destroy(sc->sc_rtage_wq); 503 1.93 ozaki kmem_free(sc, sizeof(*sc)); 504 1.27 peter 505 1.136 msaitoh return 0; 506 1.1 thorpej } 507 1.1 thorpej 508 1.1 thorpej /* 509 1.1 thorpej * bridge_ioctl: 510 1.1 thorpej * 511 1.1 thorpej * Handle a control request from the operator. 512 1.1 thorpej */ 513 1.33 thorpej static int 514 1.50 christos bridge_ioctl(struct ifnet *ifp, u_long cmd, void *data) 515 1.1 thorpej { 516 1.1 thorpej struct bridge_softc *sc = ifp->if_softc; 517 1.40 ad struct lwp *l = curlwp; /* XXX */ 518 1.1 thorpej union { 519 1.1 thorpej struct ifbreq ifbreq; 520 1.1 thorpej struct ifbifconf ifbifconf; 521 1.1 thorpej struct ifbareq ifbareq; 522 1.1 thorpej struct ifbaconf ifbaconf; 523 1.1 thorpej struct ifbrparam ifbrparam; 524 1.1 thorpej } args; 525 1.1 thorpej struct ifdrv *ifd = (struct ifdrv *) data; 526 1.69 elad const struct bridge_control *bc = NULL; /* XXXGCC */ 527 1.189 skrll int error = 0; 528 1.1 thorpej 529 1.132 ozaki /* Authorize command before calling splsoftnet(). */ 530 1.1 thorpej switch (cmd) { 531 1.1 thorpej case SIOCGDRVSPEC: 532 1.1 thorpej case SIOCSDRVSPEC: 533 1.99 matt if (ifd->ifd_cmd >= bridge_control_table_size 534 1.99 matt || (bc = &bridge_control_table[ifd->ifd_cmd]) == NULL) { 535 1.1 thorpej error = EINVAL; 536 1.70 cegger return error; 537 1.1 thorpej } 538 1.69 elad 539 1.69 elad /* We only care about BC_F_SUSER at this point. */ 540 1.69 elad if ((bc->bc_flags & BC_F_SUSER) == 0) 541 1.69 elad break; 542 1.69 elad 543 1.75 elad error = kauth_authorize_network(l->l_cred, 544 1.75 elad KAUTH_NETWORK_INTERFACE_BRIDGE, 545 1.75 elad cmd == SIOCGDRVSPEC ? 546 1.75 elad KAUTH_REQ_NETWORK_INTERFACE_BRIDGE_GETPRIV : 547 1.76 wiz KAUTH_REQ_NETWORK_INTERFACE_BRIDGE_SETPRIV, 548 1.75 elad ifd, NULL, NULL); 549 1.69 elad if (error) 550 1.136 msaitoh return error; 551 1.69 elad 552 1.69 elad break; 553 1.69 elad } 554 1.69 elad 555 1.189 skrll const int s = splsoftnet(); 556 1.69 elad 557 1.69 elad switch (cmd) { 558 1.69 elad case SIOCGDRVSPEC: 559 1.69 elad case SIOCSDRVSPEC: 560 1.70 cegger KASSERT(bc != NULL); 561 1.1 thorpej if (cmd == SIOCGDRVSPEC && 562 1.99 matt (bc->bc_flags & (BC_F_COPYOUT|BC_F_XLATEOUT)) == 0) { 563 1.14 kristerw error = EINVAL; 564 1.14 kristerw break; 565 1.14 kristerw } 566 1.1 thorpej else if (cmd == SIOCSDRVSPEC && 567 1.99 matt (bc->bc_flags & (BC_F_COPYOUT|BC_F_XLATEOUT)) != 0) { 568 1.14 kristerw error = EINVAL; 569 1.14 kristerw break; 570 1.14 kristerw } 571 1.1 thorpej 572 1.132 ozaki /* BC_F_SUSER is checked above, before splsoftnet(). */ 573 1.1 thorpej 574 1.99 matt if ((bc->bc_flags & (BC_F_XLATEIN|BC_F_XLATEOUT)) == 0 575 1.99 matt && (ifd->ifd_len != bc->bc_argsize 576 1.99 matt || ifd->ifd_len > sizeof(args))) { 577 1.1 thorpej error = EINVAL; 578 1.1 thorpej break; 579 1.1 thorpej } 580 1.1 thorpej 581 1.35 christos memset(&args, 0, sizeof(args)); 582 1.1 thorpej if (bc->bc_flags & BC_F_COPYIN) { 583 1.1 thorpej error = copyin(ifd->ifd_data, &args, ifd->ifd_len); 584 1.1 thorpej if (error) 585 1.1 thorpej break; 586 1.99 matt } else if (bc->bc_flags & BC_F_XLATEIN) { 587 1.99 matt args.ifbifconf.ifbic_len = ifd->ifd_len; 588 1.99 matt args.ifbifconf.ifbic_buf = ifd->ifd_data; 589 1.1 thorpej } 590 1.1 thorpej 591 1.1 thorpej error = (*bc->bc_func)(sc, &args); 592 1.1 thorpej if (error) 593 1.1 thorpej break; 594 1.1 thorpej 595 1.99 matt if (bc->bc_flags & BC_F_COPYOUT) { 596 1.1 thorpej error = copyout(&args, ifd->ifd_data, ifd->ifd_len); 597 1.99 matt } else if (bc->bc_flags & BC_F_XLATEOUT) { 598 1.99 matt ifd->ifd_len = args.ifbifconf.ifbic_len; 599 1.99 matt ifd->ifd_data = args.ifbifconf.ifbic_buf; 600 1.99 matt } 601 1.1 thorpej break; 602 1.1 thorpej 603 1.1 thorpej case SIOCSIFFLAGS: 604 1.63 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0) 605 1.63 dyoung break; 606 1.63 dyoung switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) { 607 1.63 dyoung case IFF_RUNNING: 608 1.1 thorpej /* 609 1.1 thorpej * If interface is marked down and it is running, 610 1.1 thorpej * then stop and disable it. 611 1.1 thorpej */ 612 1.184 riastrad if_stop(ifp, 1); 613 1.63 dyoung break; 614 1.63 dyoung case IFF_UP: 615 1.1 thorpej /* 616 1.1 thorpej * If interface is marked up and it is stopped, then 617 1.1 thorpej * start it. 618 1.1 thorpej */ 619 1.186 riastrad error = if_init(ifp); 620 1.63 dyoung break; 621 1.63 dyoung default: 622 1.63 dyoung break; 623 1.1 thorpej } 624 1.1 thorpej break; 625 1.1 thorpej 626 1.88 ozaki case SIOCSIFMTU: 627 1.88 ozaki if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 628 1.88 ozaki error = 0; 629 1.88 ozaki break; 630 1.88 ozaki 631 1.172 jdolecek case SIOCGIFCAP: 632 1.172 jdolecek { 633 1.172 jdolecek struct ifcapreq *ifcr = (struct ifcapreq *)data; 634 1.172 jdolecek ifcr->ifcr_capabilities = sc->sc_capenable; 635 1.172 jdolecek ifcr->ifcr_capenable = sc->sc_capenable; 636 1.172 jdolecek break; 637 1.172 jdolecek } 638 1.172 jdolecek 639 1.1 thorpej default: 640 1.63 dyoung error = ifioctl_common(ifp, cmd, data); 641 1.1 thorpej break; 642 1.1 thorpej } 643 1.1 thorpej 644 1.1 thorpej splx(s); 645 1.1 thorpej 646 1.136 msaitoh return error; 647 1.1 thorpej } 648 1.1 thorpej 649 1.1 thorpej /* 650 1.1 thorpej * bridge_lookup_member: 651 1.1 thorpej * 652 1.87 ozaki * Lookup a bridge member interface. 653 1.1 thorpej */ 654 1.33 thorpej static struct bridge_iflist * 655 1.115 ozaki bridge_lookup_member(struct bridge_softc *sc, const char *name, struct psref *psref) 656 1.1 thorpej { 657 1.1 thorpej struct bridge_iflist *bif; 658 1.1 thorpej struct ifnet *ifp; 659 1.95 ozaki int s; 660 1.1 thorpej 661 1.193 ozaki s = pserialize_read_enter(); 662 1.87 ozaki 663 1.115 ozaki BRIDGE_IFLIST_READER_FOREACH(bif, sc) { 664 1.1 thorpej ifp = bif->bif_ifp; 665 1.1 thorpej if (strcmp(ifp->if_xname, name) == 0) 666 1.87 ozaki break; 667 1.1 thorpej } 668 1.115 ozaki if (bif != NULL) 669 1.115 ozaki bridge_acquire_member(sc, bif, psref); 670 1.1 thorpej 671 1.193 ozaki pserialize_read_exit(s); 672 1.87 ozaki 673 1.87 ozaki return bif; 674 1.1 thorpej } 675 1.1 thorpej 676 1.1 thorpej /* 677 1.8 martin * bridge_lookup_member_if: 678 1.8 martin * 679 1.87 ozaki * Lookup a bridge member interface by ifnet*. 680 1.8 martin */ 681 1.33 thorpej static struct bridge_iflist * 682 1.115 ozaki bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp, 683 1.115 ozaki struct psref *psref) 684 1.8 martin { 685 1.8 martin struct bridge_iflist *bif; 686 1.95 ozaki int s; 687 1.8 martin 688 1.193 ozaki s = pserialize_read_enter(); 689 1.87 ozaki 690 1.87 ozaki bif = member_ifp->if_bridgeif; 691 1.115 ozaki if (bif != NULL) { 692 1.115 ozaki psref_acquire(psref, &bif->bif_psref, 693 1.115 ozaki bridge_psref_class); 694 1.115 ozaki } 695 1.95 ozaki 696 1.193 ozaki pserialize_read_exit(s); 697 1.95 ozaki 698 1.95 ozaki return bif; 699 1.95 ozaki } 700 1.87 ozaki 701 1.115 ozaki static void 702 1.115 ozaki bridge_acquire_member(struct bridge_softc *sc, struct bridge_iflist *bif, 703 1.115 ozaki struct psref *psref) 704 1.95 ozaki { 705 1.114 ozaki 706 1.115 ozaki psref_acquire(psref, &bif->bif_psref, bridge_psref_class); 707 1.87 ozaki } 708 1.87 ozaki 709 1.87 ozaki /* 710 1.87 ozaki * bridge_release_member: 711 1.87 ozaki * 712 1.87 ozaki * Release the specified member interface. 713 1.87 ozaki */ 714 1.87 ozaki static void 715 1.115 ozaki bridge_release_member(struct bridge_softc *sc, struct bridge_iflist *bif, 716 1.115 ozaki struct psref *psref) 717 1.87 ozaki { 718 1.95 ozaki 719 1.115 ozaki psref_release(psref, &bif->bif_psref, bridge_psref_class); 720 1.8 martin } 721 1.8 martin 722 1.8 martin /* 723 1.1 thorpej * bridge_delete_member: 724 1.1 thorpej * 725 1.1 thorpej * Delete the specified member interface. 726 1.1 thorpej */ 727 1.33 thorpej static void 728 1.1 thorpej bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif) 729 1.1 thorpej { 730 1.1 thorpej struct ifnet *ifs = bif->bif_ifp; 731 1.1 thorpej 732 1.98 ozaki KASSERT(BRIDGE_LOCKED(sc)); 733 1.1 thorpej 734 1.106 ozaki ifs->_if_input = ether_input; 735 1.1 thorpej ifs->if_bridge = NULL; 736 1.87 ozaki ifs->if_bridgeif = NULL; 737 1.87 ozaki 738 1.112 ozaki PSLIST_WRITER_REMOVE(bif, bif_next); 739 1.95 ozaki BRIDGE_PSZ_PERFORM(sc); 740 1.182 yamaguch 741 1.182 yamaguch if_linkstate_change_disestablish(ifs, 742 1.182 yamaguch bif->bif_linkstate_hook, BRIDGE_LOCK_OBJ(sc)); 743 1.183 yamaguch ether_ifdetachhook_disestablish(ifs, 744 1.183 yamaguch bif->bif_ifdetach_hook, BRIDGE_LOCK_OBJ(sc)); 745 1.182 yamaguch 746 1.115 ozaki BRIDGE_UNLOCK(sc); 747 1.95 ozaki 748 1.164 rin switch (ifs->if_type) { 749 1.164 rin case IFT_ETHER: 750 1.164 rin case IFT_L2TP: 751 1.164 rin /* 752 1.164 rin * Take the interface out of promiscuous mode. 753 1.164 rin * Don't call it with holding a spin lock. 754 1.164 rin */ 755 1.164 rin (void) ifpromisc(ifs, 0); 756 1.164 rin IFNET_LOCK(ifs); 757 1.164 rin (void) ether_disable_vlan_mtu(ifs); 758 1.164 rin IFNET_UNLOCK(ifs); 759 1.164 rin break; 760 1.164 rin default: 761 1.164 rin #ifdef DIAGNOSTIC 762 1.164 rin panic("%s: impossible", __func__); 763 1.164 rin #endif 764 1.164 rin break; 765 1.164 rin } 766 1.164 rin 767 1.115 ozaki psref_target_destroy(&bif->bif_psref, bridge_psref_class); 768 1.1 thorpej 769 1.113 ozaki PSLIST_ENTRY_DESTROY(bif, bif_next); 770 1.93 ozaki kmem_free(bif, sizeof(*bif)); 771 1.98 ozaki 772 1.98 ozaki BRIDGE_LOCK(sc); 773 1.1 thorpej } 774 1.1 thorpej 775 1.161 rin /* 776 1.161 rin * bridge_calc_csum_flags: 777 1.161 rin * 778 1.161 rin * Calculate logical and b/w csum flags each member interface supports. 779 1.161 rin */ 780 1.161 rin void 781 1.161 rin bridge_calc_csum_flags(struct bridge_softc *sc) 782 1.161 rin { 783 1.161 rin struct bridge_iflist *bif; 784 1.173 jdolecek struct ifnet *ifs = NULL; 785 1.161 rin int flags = ~0; 786 1.172 jdolecek int capenable = ~0; 787 1.161 rin 788 1.161 rin BRIDGE_LOCK(sc); 789 1.161 rin BRIDGE_IFLIST_READER_FOREACH(bif, sc) { 790 1.161 rin ifs = bif->bif_ifp; 791 1.161 rin flags &= ifs->if_csum_flags_tx; 792 1.172 jdolecek capenable &= ifs->if_capenable; 793 1.161 rin } 794 1.161 rin sc->sc_csum_flags_tx = flags; 795 1.173 jdolecek sc->sc_capenable = (ifs != NULL) ? capenable : 0; 796 1.161 rin BRIDGE_UNLOCK(sc); 797 1.161 rin } 798 1.161 rin 799 1.175 roy /* 800 1.175 roy * bridge_calc_link_state: 801 1.175 roy * 802 1.175 roy * Calculate the link state based on each member interface. 803 1.175 roy */ 804 1.182 yamaguch static void 805 1.182 yamaguch bridge_calc_link_state(void *xsc) 806 1.175 roy { 807 1.182 yamaguch struct bridge_softc *sc = xsc; 808 1.175 roy struct bridge_iflist *bif; 809 1.175 roy struct ifnet *ifs; 810 1.175 roy int link_state = LINK_STATE_DOWN; 811 1.175 roy 812 1.175 roy BRIDGE_LOCK(sc); 813 1.175 roy BRIDGE_IFLIST_READER_FOREACH(bif, sc) { 814 1.175 roy ifs = bif->bif_ifp; 815 1.175 roy if (ifs->if_link_state == LINK_STATE_UP) { 816 1.175 roy link_state = LINK_STATE_UP; 817 1.175 roy break; 818 1.175 roy } 819 1.175 roy if (ifs->if_link_state == LINK_STATE_UNKNOWN) 820 1.175 roy link_state = LINK_STATE_UNKNOWN; 821 1.175 roy } 822 1.175 roy if_link_state_change(&sc->sc_if, link_state); 823 1.175 roy BRIDGE_UNLOCK(sc); 824 1.175 roy } 825 1.175 roy 826 1.33 thorpej static int 827 1.1 thorpej bridge_ioctl_add(struct bridge_softc *sc, void *arg) 828 1.1 thorpej { 829 1.1 thorpej struct ifbreq *req = arg; 830 1.1 thorpej struct bridge_iflist *bif = NULL; 831 1.1 thorpej struct ifnet *ifs; 832 1.1 thorpej int error = 0; 833 1.123 ozaki struct psref psref; 834 1.1 thorpej 835 1.123 ozaki ifs = if_get(req->ifbr_ifsname, &psref); 836 1.1 thorpej if (ifs == NULL) 837 1.136 msaitoh return ENOENT; 838 1.7 itojun 839 1.123 ozaki if (ifs->if_bridge == sc) { 840 1.123 ozaki error = EEXIST; 841 1.123 ozaki goto out; 842 1.123 ozaki } 843 1.1 thorpej 844 1.123 ozaki if (ifs->if_bridge != NULL) { 845 1.123 ozaki error = EBUSY; 846 1.123 ozaki goto out; 847 1.123 ozaki } 848 1.1 thorpej 849 1.123 ozaki if (ifs->_if_input != ether_input) { 850 1.123 ozaki error = EINVAL; 851 1.123 ozaki goto out; 852 1.123 ozaki } 853 1.81 ozaki 854 1.91 ozaki /* FIXME: doesn't work with non-IFF_SIMPLEX interfaces */ 855 1.123 ozaki if ((ifs->if_flags & IFF_SIMPLEX) == 0) { 856 1.123 ozaki error = EINVAL; 857 1.123 ozaki goto out; 858 1.123 ozaki } 859 1.91 ozaki 860 1.93 ozaki bif = kmem_alloc(sizeof(*bif), KM_SLEEP); 861 1.1 thorpej 862 1.1 thorpej switch (ifs->if_type) { 863 1.1 thorpej case IFT_ETHER: 864 1.133 knakahar if (sc->sc_if.if_mtu != ifs->if_mtu) { 865 1.171 jdolecek /* Change MTU of added interface to bridge MTU */ 866 1.171 jdolecek struct ifreq ifr; 867 1.171 jdolecek memset(&ifr, 0, sizeof(ifr)); 868 1.171 jdolecek ifr.ifr_mtu = sc->sc_if.if_mtu; 869 1.171 jdolecek IFNET_LOCK(ifs); 870 1.185 riastrad error = if_ioctl(ifs, SIOCSIFMTU, &ifr); 871 1.171 jdolecek IFNET_UNLOCK(ifs); 872 1.171 jdolecek if (error != 0) 873 1.171 jdolecek goto out; 874 1.133 knakahar } 875 1.133 knakahar /* FALLTHROUGH */ 876 1.133 knakahar case IFT_L2TP: 877 1.145 ozaki IFNET_LOCK(ifs); 878 1.144 ozaki error = ether_enable_vlan_mtu(ifs); 879 1.145 ozaki IFNET_UNLOCK(ifs); 880 1.142 ozaki if (error > 0) 881 1.105 christos goto out; 882 1.1 thorpej /* 883 1.1 thorpej * Place the interface into promiscuous mode. 884 1.1 thorpej */ 885 1.1 thorpej error = ifpromisc(ifs, 1); 886 1.1 thorpej if (error) 887 1.1 thorpej goto out; 888 1.1 thorpej break; 889 1.1 thorpej default: 890 1.5 jdolecek error = EINVAL; 891 1.5 jdolecek goto out; 892 1.1 thorpej } 893 1.1 thorpej 894 1.1 thorpej bif->bif_ifp = ifs; 895 1.1 thorpej bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; 896 1.1 thorpej bif->bif_priority = BSTP_DEFAULT_PORT_PRIORITY; 897 1.1 thorpej bif->bif_path_cost = BSTP_DEFAULT_PATH_COST; 898 1.182 yamaguch bif->bif_linkstate_hook = if_linkstate_change_establish(ifs, 899 1.182 yamaguch bridge_calc_link_state, sc); 900 1.112 ozaki PSLIST_ENTRY_INIT(bif, bif_next); 901 1.115 ozaki psref_target_init(&bif->bif_psref, bridge_psref_class); 902 1.87 ozaki 903 1.87 ozaki BRIDGE_LOCK(sc); 904 1.1 thorpej 905 1.1 thorpej ifs->if_bridge = sc; 906 1.87 ozaki ifs->if_bridgeif = bif; 907 1.115 ozaki PSLIST_WRITER_INSERT_HEAD(&sc->sc_iflist_psref.bip_iflist, bif, bif_next); 908 1.106 ozaki ifs->_if_input = bridge_input; 909 1.1 thorpej 910 1.87 ozaki BRIDGE_UNLOCK(sc); 911 1.87 ozaki 912 1.183 yamaguch bif->bif_ifdetach_hook = ether_ifdetachhook_establish(ifs, 913 1.183 yamaguch bridge_ifdetach, (void *)ifs); 914 1.183 yamaguch 915 1.161 rin bridge_calc_csum_flags(sc); 916 1.175 roy bridge_calc_link_state(sc); 917 1.161 rin 918 1.1 thorpej if (sc->sc_if.if_flags & IFF_RUNNING) 919 1.1 thorpej bstp_initialization(sc); 920 1.1 thorpej else 921 1.1 thorpej bstp_stop(sc); 922 1.1 thorpej 923 1.161 rin out: 924 1.123 ozaki if_put(ifs, &psref); 925 1.1 thorpej if (error) { 926 1.1 thorpej if (bif != NULL) 927 1.93 ozaki kmem_free(bif, sizeof(*bif)); 928 1.1 thorpej } 929 1.136 msaitoh return error; 930 1.1 thorpej } 931 1.1 thorpej 932 1.33 thorpej static int 933 1.1 thorpej bridge_ioctl_del(struct bridge_softc *sc, void *arg) 934 1.1 thorpej { 935 1.1 thorpej struct ifbreq *req = arg; 936 1.87 ozaki const char *name = req->ifbr_ifsname; 937 1.1 thorpej struct bridge_iflist *bif; 938 1.87 ozaki struct ifnet *ifs; 939 1.1 thorpej 940 1.87 ozaki BRIDGE_LOCK(sc); 941 1.87 ozaki 942 1.87 ozaki /* 943 1.87 ozaki * Don't use bridge_lookup_member. We want to get a member 944 1.87 ozaki * with bif_refs == 0. 945 1.87 ozaki */ 946 1.115 ozaki BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { 947 1.87 ozaki ifs = bif->bif_ifp; 948 1.87 ozaki if (strcmp(ifs->if_xname, name) == 0) 949 1.87 ozaki break; 950 1.87 ozaki } 951 1.87 ozaki 952 1.87 ozaki if (bif == NULL) { 953 1.87 ozaki BRIDGE_UNLOCK(sc); 954 1.87 ozaki return ENOENT; 955 1.87 ozaki } 956 1.1 thorpej 957 1.1 thorpej bridge_delete_member(sc, bif); 958 1.1 thorpej 959 1.98 ozaki BRIDGE_UNLOCK(sc); 960 1.87 ozaki 961 1.87 ozaki bridge_rtdelete(sc, ifs); 962 1.161 rin bridge_calc_csum_flags(sc); 963 1.175 roy bridge_calc_link_state(sc); 964 1.87 ozaki 965 1.87 ozaki if (sc->sc_if.if_flags & IFF_RUNNING) 966 1.87 ozaki bstp_initialization(sc); 967 1.87 ozaki 968 1.87 ozaki return 0; 969 1.1 thorpej } 970 1.1 thorpej 971 1.33 thorpej static int 972 1.1 thorpej bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg) 973 1.1 thorpej { 974 1.1 thorpej struct ifbreq *req = arg; 975 1.1 thorpej struct bridge_iflist *bif; 976 1.115 ozaki struct psref psref; 977 1.1 thorpej 978 1.115 ozaki bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); 979 1.1 thorpej if (bif == NULL) 980 1.136 msaitoh return ENOENT; 981 1.1 thorpej 982 1.1 thorpej req->ifbr_ifsflags = bif->bif_flags; 983 1.1 thorpej req->ifbr_state = bif->bif_state; 984 1.1 thorpej req->ifbr_priority = bif->bif_priority; 985 1.11 bouyer req->ifbr_path_cost = bif->bif_path_cost; 986 1.1 thorpej req->ifbr_portno = bif->bif_ifp->if_index & 0xff; 987 1.1 thorpej 988 1.115 ozaki bridge_release_member(sc, bif, &psref); 989 1.87 ozaki 990 1.136 msaitoh return 0; 991 1.1 thorpej } 992 1.1 thorpej 993 1.33 thorpej static int 994 1.1 thorpej bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg) 995 1.1 thorpej { 996 1.1 thorpej struct ifbreq *req = arg; 997 1.1 thorpej struct bridge_iflist *bif; 998 1.115 ozaki struct psref psref; 999 1.1 thorpej 1000 1.115 ozaki bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); 1001 1.1 thorpej if (bif == NULL) 1002 1.136 msaitoh return ENOENT; 1003 1.1 thorpej 1004 1.1 thorpej if (req->ifbr_ifsflags & IFBIF_STP) { 1005 1.1 thorpej switch (bif->bif_ifp->if_type) { 1006 1.1 thorpej case IFT_ETHER: 1007 1.133 knakahar case IFT_L2TP: 1008 1.1 thorpej /* These can do spanning tree. */ 1009 1.1 thorpej break; 1010 1.1 thorpej 1011 1.1 thorpej default: 1012 1.1 thorpej /* Nothing else can. */ 1013 1.115 ozaki bridge_release_member(sc, bif, &psref); 1014 1.136 msaitoh return EINVAL; 1015 1.1 thorpej } 1016 1.1 thorpej } 1017 1.1 thorpej 1018 1.194 ozaki if (bif->bif_flags & IFBIF_PROTECTED) { 1019 1.194 ozaki if ((req->ifbr_ifsflags & IFBIF_PROTECTED) == 0) { 1020 1.194 ozaki log(LOG_INFO, "%s: disabling protection on %s\n", 1021 1.194 ozaki sc->sc_if.if_xname, bif->bif_ifp->if_xname); 1022 1.194 ozaki } 1023 1.194 ozaki } else { 1024 1.194 ozaki if (req->ifbr_ifsflags & IFBIF_PROTECTED) { 1025 1.194 ozaki log(LOG_INFO, "%s: enabling protection on %s\n", 1026 1.194 ozaki sc->sc_if.if_xname, bif->bif_ifp->if_xname); 1027 1.194 ozaki } 1028 1.194 ozaki } 1029 1.194 ozaki 1030 1.1 thorpej bif->bif_flags = req->ifbr_ifsflags; 1031 1.1 thorpej 1032 1.115 ozaki bridge_release_member(sc, bif, &psref); 1033 1.87 ozaki 1034 1.1 thorpej if (sc->sc_if.if_flags & IFF_RUNNING) 1035 1.1 thorpej bstp_initialization(sc); 1036 1.1 thorpej 1037 1.136 msaitoh return 0; 1038 1.1 thorpej } 1039 1.1 thorpej 1040 1.33 thorpej static int 1041 1.1 thorpej bridge_ioctl_scache(struct bridge_softc *sc, void *arg) 1042 1.1 thorpej { 1043 1.1 thorpej struct ifbrparam *param = arg; 1044 1.1 thorpej 1045 1.1 thorpej sc->sc_brtmax = param->ifbrp_csize; 1046 1.1 thorpej bridge_rttrim(sc); 1047 1.1 thorpej 1048 1.136 msaitoh return 0; 1049 1.1 thorpej } 1050 1.1 thorpej 1051 1.33 thorpej static int 1052 1.1 thorpej bridge_ioctl_gcache(struct bridge_softc *sc, void *arg) 1053 1.1 thorpej { 1054 1.1 thorpej struct ifbrparam *param = arg; 1055 1.1 thorpej 1056 1.1 thorpej param->ifbrp_csize = sc->sc_brtmax; 1057 1.1 thorpej 1058 1.136 msaitoh return 0; 1059 1.1 thorpej } 1060 1.1 thorpej 1061 1.33 thorpej static int 1062 1.1 thorpej bridge_ioctl_gifs(struct bridge_softc *sc, void *arg) 1063 1.1 thorpej { 1064 1.1 thorpej struct ifbifconf *bifc = arg; 1065 1.1 thorpej struct bridge_iflist *bif; 1066 1.90 ozaki struct ifbreq *breqs; 1067 1.90 ozaki int i, count, error = 0; 1068 1.1 thorpej 1069 1.93 ozaki retry: 1070 1.87 ozaki BRIDGE_LOCK(sc); 1071 1.1 thorpej count = 0; 1072 1.115 ozaki BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) 1073 1.1 thorpej count++; 1074 1.93 ozaki BRIDGE_UNLOCK(sc); 1075 1.93 ozaki 1076 1.93 ozaki if (count == 0) { 1077 1.93 ozaki bifc->ifbic_len = 0; 1078 1.93 ozaki return 0; 1079 1.93 ozaki } 1080 1.1 thorpej 1081 1.90 ozaki if (bifc->ifbic_len == 0 || bifc->ifbic_len < (sizeof(*breqs) * count)) { 1082 1.90 ozaki /* Tell that a larger buffer is needed */ 1083 1.90 ozaki bifc->ifbic_len = sizeof(*breqs) * count; 1084 1.90 ozaki return 0; 1085 1.1 thorpej } 1086 1.1 thorpej 1087 1.93 ozaki breqs = kmem_alloc(sizeof(*breqs) * count, KM_SLEEP); 1088 1.93 ozaki 1089 1.93 ozaki BRIDGE_LOCK(sc); 1090 1.93 ozaki 1091 1.93 ozaki i = 0; 1092 1.115 ozaki BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) 1093 1.93 ozaki i++; 1094 1.93 ozaki if (i > count) { 1095 1.93 ozaki /* 1096 1.93 ozaki * The number of members has been increased. 1097 1.93 ozaki * We need more memory! 1098 1.93 ozaki */ 1099 1.93 ozaki BRIDGE_UNLOCK(sc); 1100 1.93 ozaki kmem_free(breqs, sizeof(*breqs) * count); 1101 1.93 ozaki goto retry; 1102 1.93 ozaki } 1103 1.90 ozaki 1104 1.90 ozaki i = 0; 1105 1.115 ozaki BRIDGE_IFLIST_WRITER_FOREACH(bif, sc) { 1106 1.90 ozaki struct ifbreq *breq = &breqs[i++]; 1107 1.90 ozaki memset(breq, 0, sizeof(*breq)); 1108 1.90 ozaki 1109 1.90 ozaki strlcpy(breq->ifbr_ifsname, bif->bif_ifp->if_xname, 1110 1.90 ozaki sizeof(breq->ifbr_ifsname)); 1111 1.90 ozaki breq->ifbr_ifsflags = bif->bif_flags; 1112 1.90 ozaki breq->ifbr_state = bif->bif_state; 1113 1.90 ozaki breq->ifbr_priority = bif->bif_priority; 1114 1.90 ozaki breq->ifbr_path_cost = bif->bif_path_cost; 1115 1.90 ozaki breq->ifbr_portno = bif->bif_ifp->if_index & 0xff; 1116 1.90 ozaki } 1117 1.90 ozaki 1118 1.90 ozaki /* Don't call copyout with holding the mutex */ 1119 1.90 ozaki BRIDGE_UNLOCK(sc); 1120 1.1 thorpej 1121 1.90 ozaki for (i = 0; i < count; i++) { 1122 1.90 ozaki error = copyout(&breqs[i], bifc->ifbic_req + i, sizeof(*breqs)); 1123 1.1 thorpej if (error) 1124 1.1 thorpej break; 1125 1.1 thorpej } 1126 1.90 ozaki bifc->ifbic_len = sizeof(*breqs) * i; 1127 1.1 thorpej 1128 1.93 ozaki kmem_free(breqs, sizeof(*breqs) * count); 1129 1.87 ozaki 1130 1.90 ozaki return error; 1131 1.1 thorpej } 1132 1.1 thorpej 1133 1.33 thorpej static int 1134 1.1 thorpej bridge_ioctl_rts(struct bridge_softc *sc, void *arg) 1135 1.1 thorpej { 1136 1.1 thorpej struct ifbaconf *bac = arg; 1137 1.1 thorpej struct bridge_rtnode *brt; 1138 1.1 thorpej struct ifbareq bareq; 1139 1.1 thorpej int count = 0, error = 0, len; 1140 1.1 thorpej 1141 1.1 thorpej if (bac->ifbac_len == 0) 1142 1.136 msaitoh return 0; 1143 1.1 thorpej 1144 1.108 ozaki BRIDGE_RT_LOCK(sc); 1145 1.87 ozaki 1146 1.160 ozaki /* The passed buffer is not enough, tell a required size. */ 1147 1.160 ozaki if (bac->ifbac_len < (sizeof(bareq) * sc->sc_brtcnt)) { 1148 1.160 ozaki count = sc->sc_brtcnt; 1149 1.160 ozaki goto out; 1150 1.160 ozaki } 1151 1.160 ozaki 1152 1.1 thorpej len = bac->ifbac_len; 1153 1.152 ozaki BRIDGE_RTLIST_WRITER_FOREACH(brt, sc) { 1154 1.1 thorpej if (len < sizeof(bareq)) 1155 1.1 thorpej goto out; 1156 1.35 christos memset(&bareq, 0, sizeof(bareq)); 1157 1.13 itojun strlcpy(bareq.ifba_ifsname, brt->brt_ifp->if_xname, 1158 1.13 itojun sizeof(bareq.ifba_ifsname)); 1159 1.1 thorpej memcpy(bareq.ifba_dst, brt->brt_addr, sizeof(brt->brt_addr)); 1160 1.39 kardel if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { 1161 1.39 kardel bareq.ifba_expire = brt->brt_expire - time_uptime; 1162 1.39 kardel } else 1163 1.2 thorpej bareq.ifba_expire = 0; 1164 1.1 thorpej bareq.ifba_flags = brt->brt_flags; 1165 1.1 thorpej 1166 1.1 thorpej error = copyout(&bareq, bac->ifbac_req + count, sizeof(bareq)); 1167 1.1 thorpej if (error) 1168 1.1 thorpej goto out; 1169 1.1 thorpej count++; 1170 1.1 thorpej len -= sizeof(bareq); 1171 1.1 thorpej } 1172 1.161 rin out: 1173 1.108 ozaki BRIDGE_RT_UNLOCK(sc); 1174 1.87 ozaki 1175 1.1 thorpej bac->ifbac_len = sizeof(bareq) * count; 1176 1.136 msaitoh return error; 1177 1.1 thorpej } 1178 1.1 thorpej 1179 1.33 thorpej static int 1180 1.1 thorpej bridge_ioctl_saddr(struct bridge_softc *sc, void *arg) 1181 1.1 thorpej { 1182 1.1 thorpej struct ifbareq *req = arg; 1183 1.1 thorpej struct bridge_iflist *bif; 1184 1.1 thorpej int error; 1185 1.115 ozaki struct psref psref; 1186 1.1 thorpej 1187 1.115 ozaki bif = bridge_lookup_member(sc, req->ifba_ifsname, &psref); 1188 1.1 thorpej if (bif == NULL) 1189 1.136 msaitoh return ENOENT; 1190 1.1 thorpej 1191 1.1 thorpej error = bridge_rtupdate(sc, req->ifba_dst, bif->bif_ifp, 1, 1192 1.1 thorpej req->ifba_flags); 1193 1.1 thorpej 1194 1.115 ozaki bridge_release_member(sc, bif, &psref); 1195 1.87 ozaki 1196 1.136 msaitoh return error; 1197 1.1 thorpej } 1198 1.1 thorpej 1199 1.33 thorpej static int 1200 1.1 thorpej bridge_ioctl_sto(struct bridge_softc *sc, void *arg) 1201 1.1 thorpej { 1202 1.1 thorpej struct ifbrparam *param = arg; 1203 1.1 thorpej 1204 1.1 thorpej sc->sc_brttimeout = param->ifbrp_ctime; 1205 1.1 thorpej 1206 1.136 msaitoh return 0; 1207 1.1 thorpej } 1208 1.1 thorpej 1209 1.33 thorpej static int 1210 1.1 thorpej bridge_ioctl_gto(struct bridge_softc *sc, void *arg) 1211 1.1 thorpej { 1212 1.1 thorpej struct ifbrparam *param = arg; 1213 1.1 thorpej 1214 1.1 thorpej param->ifbrp_ctime = sc->sc_brttimeout; 1215 1.1 thorpej 1216 1.136 msaitoh return 0; 1217 1.1 thorpej } 1218 1.1 thorpej 1219 1.33 thorpej static int 1220 1.1 thorpej bridge_ioctl_daddr(struct bridge_softc *sc, void *arg) 1221 1.1 thorpej { 1222 1.1 thorpej struct ifbareq *req = arg; 1223 1.1 thorpej 1224 1.1 thorpej return (bridge_rtdaddr(sc, req->ifba_dst)); 1225 1.1 thorpej } 1226 1.1 thorpej 1227 1.33 thorpej static int 1228 1.1 thorpej bridge_ioctl_flush(struct bridge_softc *sc, void *arg) 1229 1.1 thorpej { 1230 1.1 thorpej struct ifbreq *req = arg; 1231 1.1 thorpej 1232 1.1 thorpej bridge_rtflush(sc, req->ifbr_ifsflags); 1233 1.1 thorpej 1234 1.136 msaitoh return 0; 1235 1.1 thorpej } 1236 1.1 thorpej 1237 1.33 thorpej static int 1238 1.1 thorpej bridge_ioctl_gpri(struct bridge_softc *sc, void *arg) 1239 1.1 thorpej { 1240 1.1 thorpej struct ifbrparam *param = arg; 1241 1.1 thorpej 1242 1.1 thorpej param->ifbrp_prio = sc->sc_bridge_priority; 1243 1.1 thorpej 1244 1.136 msaitoh return 0; 1245 1.1 thorpej } 1246 1.1 thorpej 1247 1.33 thorpej static int 1248 1.1 thorpej bridge_ioctl_spri(struct bridge_softc *sc, void *arg) 1249 1.1 thorpej { 1250 1.1 thorpej struct ifbrparam *param = arg; 1251 1.1 thorpej 1252 1.1 thorpej sc->sc_bridge_priority = param->ifbrp_prio; 1253 1.1 thorpej 1254 1.1 thorpej if (sc->sc_if.if_flags & IFF_RUNNING) 1255 1.1 thorpej bstp_initialization(sc); 1256 1.1 thorpej 1257 1.136 msaitoh return 0; 1258 1.1 thorpej } 1259 1.1 thorpej 1260 1.33 thorpej static int 1261 1.1 thorpej bridge_ioctl_ght(struct bridge_softc *sc, void *arg) 1262 1.1 thorpej { 1263 1.1 thorpej struct ifbrparam *param = arg; 1264 1.1 thorpej 1265 1.1 thorpej param->ifbrp_hellotime = sc->sc_bridge_hello_time >> 8; 1266 1.1 thorpej 1267 1.136 msaitoh return 0; 1268 1.1 thorpej } 1269 1.1 thorpej 1270 1.33 thorpej static int 1271 1.1 thorpej bridge_ioctl_sht(struct bridge_softc *sc, void *arg) 1272 1.1 thorpej { 1273 1.1 thorpej struct ifbrparam *param = arg; 1274 1.1 thorpej 1275 1.1 thorpej if (param->ifbrp_hellotime == 0) 1276 1.136 msaitoh return EINVAL; 1277 1.1 thorpej sc->sc_bridge_hello_time = param->ifbrp_hellotime << 8; 1278 1.1 thorpej 1279 1.1 thorpej if (sc->sc_if.if_flags & IFF_RUNNING) 1280 1.1 thorpej bstp_initialization(sc); 1281 1.1 thorpej 1282 1.136 msaitoh return 0; 1283 1.1 thorpej } 1284 1.1 thorpej 1285 1.33 thorpej static int 1286 1.1 thorpej bridge_ioctl_gfd(struct bridge_softc *sc, void *arg) 1287 1.1 thorpej { 1288 1.1 thorpej struct ifbrparam *param = arg; 1289 1.1 thorpej 1290 1.1 thorpej param->ifbrp_fwddelay = sc->sc_bridge_forward_delay >> 8; 1291 1.1 thorpej 1292 1.136 msaitoh return 0; 1293 1.1 thorpej } 1294 1.1 thorpej 1295 1.33 thorpej static int 1296 1.1 thorpej bridge_ioctl_sfd(struct bridge_softc *sc, void *arg) 1297 1.1 thorpej { 1298 1.29 perry struct ifbrparam *param = arg; 1299 1.1 thorpej 1300 1.1 thorpej if (param->ifbrp_fwddelay == 0) 1301 1.136 msaitoh return EINVAL; 1302 1.1 thorpej sc->sc_bridge_forward_delay = param->ifbrp_fwddelay << 8; 1303 1.1 thorpej 1304 1.1 thorpej if (sc->sc_if.if_flags & IFF_RUNNING) 1305 1.1 thorpej bstp_initialization(sc); 1306 1.1 thorpej 1307 1.136 msaitoh return 0; 1308 1.1 thorpej } 1309 1.1 thorpej 1310 1.33 thorpej static int 1311 1.1 thorpej bridge_ioctl_gma(struct bridge_softc *sc, void *arg) 1312 1.1 thorpej { 1313 1.1 thorpej struct ifbrparam *param = arg; 1314 1.1 thorpej 1315 1.1 thorpej param->ifbrp_maxage = sc->sc_bridge_max_age >> 8; 1316 1.1 thorpej 1317 1.136 msaitoh return 0; 1318 1.1 thorpej } 1319 1.1 thorpej 1320 1.33 thorpej static int 1321 1.1 thorpej bridge_ioctl_sma(struct bridge_softc *sc, void *arg) 1322 1.1 thorpej { 1323 1.1 thorpej struct ifbrparam *param = arg; 1324 1.1 thorpej 1325 1.1 thorpej if (param->ifbrp_maxage == 0) 1326 1.136 msaitoh return EINVAL; 1327 1.1 thorpej sc->sc_bridge_max_age = param->ifbrp_maxage << 8; 1328 1.1 thorpej 1329 1.1 thorpej if (sc->sc_if.if_flags & IFF_RUNNING) 1330 1.1 thorpej bstp_initialization(sc); 1331 1.1 thorpej 1332 1.136 msaitoh return 0; 1333 1.1 thorpej } 1334 1.1 thorpej 1335 1.33 thorpej static int 1336 1.1 thorpej bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg) 1337 1.1 thorpej { 1338 1.1 thorpej struct ifbreq *req = arg; 1339 1.1 thorpej struct bridge_iflist *bif; 1340 1.115 ozaki struct psref psref; 1341 1.1 thorpej 1342 1.115 ozaki bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); 1343 1.1 thorpej if (bif == NULL) 1344 1.136 msaitoh return ENOENT; 1345 1.1 thorpej 1346 1.1 thorpej bif->bif_priority = req->ifbr_priority; 1347 1.1 thorpej 1348 1.1 thorpej if (sc->sc_if.if_flags & IFF_RUNNING) 1349 1.1 thorpej bstp_initialization(sc); 1350 1.1 thorpej 1351 1.115 ozaki bridge_release_member(sc, bif, &psref); 1352 1.87 ozaki 1353 1.136 msaitoh return 0; 1354 1.1 thorpej } 1355 1.1 thorpej 1356 1.33 thorpej static int 1357 1.9 perseant bridge_ioctl_gfilt(struct bridge_softc *sc, void *arg) 1358 1.9 perseant { 1359 1.9 perseant struct ifbrparam *param = arg; 1360 1.9 perseant 1361 1.9 perseant param->ifbrp_filter = sc->sc_filter_flags; 1362 1.9 perseant 1363 1.136 msaitoh return 0; 1364 1.9 perseant } 1365 1.9 perseant 1366 1.33 thorpej static int 1367 1.9 perseant bridge_ioctl_sfilt(struct bridge_softc *sc, void *arg) 1368 1.9 perseant { 1369 1.29 perry struct ifbrparam *param = arg; 1370 1.9 perseant uint32_t nflags, oflags; 1371 1.9 perseant 1372 1.9 perseant if (param->ifbrp_filter & ~IFBF_FILT_MASK) 1373 1.136 msaitoh return EINVAL; 1374 1.9 perseant 1375 1.9 perseant nflags = param->ifbrp_filter; 1376 1.9 perseant oflags = sc->sc_filter_flags; 1377 1.9 perseant 1378 1.9 perseant if ((nflags & IFBF_FILT_USEIPF) && !(oflags & IFBF_FILT_USEIPF)) { 1379 1.9 perseant pfil_add_hook((void *)bridge_ipf, NULL, PFIL_IN|PFIL_OUT, 1380 1.77 rmind sc->sc_if.if_pfil); 1381 1.9 perseant } 1382 1.9 perseant if (!(nflags & IFBF_FILT_USEIPF) && (oflags & IFBF_FILT_USEIPF)) { 1383 1.9 perseant pfil_remove_hook((void *)bridge_ipf, NULL, PFIL_IN|PFIL_OUT, 1384 1.77 rmind sc->sc_if.if_pfil); 1385 1.9 perseant } 1386 1.9 perseant 1387 1.9 perseant sc->sc_filter_flags = nflags; 1388 1.9 perseant 1389 1.136 msaitoh return 0; 1390 1.9 perseant } 1391 1.9 perseant 1392 1.33 thorpej static int 1393 1.11 bouyer bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg) 1394 1.11 bouyer { 1395 1.11 bouyer struct ifbreq *req = arg; 1396 1.11 bouyer struct bridge_iflist *bif; 1397 1.115 ozaki struct psref psref; 1398 1.11 bouyer 1399 1.115 ozaki bif = bridge_lookup_member(sc, req->ifbr_ifsname, &psref); 1400 1.11 bouyer if (bif == NULL) 1401 1.136 msaitoh return ENOENT; 1402 1.11 bouyer 1403 1.11 bouyer bif->bif_path_cost = req->ifbr_path_cost; 1404 1.11 bouyer 1405 1.11 bouyer if (sc->sc_if.if_flags & IFF_RUNNING) 1406 1.11 bouyer bstp_initialization(sc); 1407 1.11 bouyer 1408 1.115 ozaki bridge_release_member(sc, bif, &psref); 1409 1.87 ozaki 1410 1.136 msaitoh return 0; 1411 1.11 bouyer } 1412 1.11 bouyer 1413 1.1 thorpej /* 1414 1.1 thorpej * bridge_ifdetach: 1415 1.1 thorpej * 1416 1.1 thorpej * Detach an interface from a bridge. Called when a member 1417 1.1 thorpej * interface is detaching. 1418 1.1 thorpej */ 1419 1.183 yamaguch static void 1420 1.183 yamaguch bridge_ifdetach(void *xifs) 1421 1.1 thorpej { 1422 1.183 yamaguch struct ifnet *ifs; 1423 1.183 yamaguch struct bridge_softc *sc; 1424 1.1 thorpej struct ifbreq breq; 1425 1.1 thorpej 1426 1.183 yamaguch ifs = (struct ifnet *)xifs; 1427 1.183 yamaguch sc = ifs->if_bridge; 1428 1.183 yamaguch 1429 1.87 ozaki /* ioctl_lock should prevent this from happening */ 1430 1.87 ozaki KASSERT(sc != NULL); 1431 1.87 ozaki 1432 1.1 thorpej memset(&breq, 0, sizeof(breq)); 1433 1.183 yamaguch strlcpy(breq.ifbr_ifsname, ifs->if_xname, sizeof(breq.ifbr_ifsname)); 1434 1.1 thorpej 1435 1.1 thorpej (void) bridge_ioctl_del(sc, &breq); 1436 1.1 thorpej } 1437 1.1 thorpej 1438 1.1 thorpej /* 1439 1.1 thorpej * bridge_init: 1440 1.1 thorpej * 1441 1.1 thorpej * Initialize a bridge interface. 1442 1.1 thorpej */ 1443 1.33 thorpej static int 1444 1.1 thorpej bridge_init(struct ifnet *ifp) 1445 1.1 thorpej { 1446 1.1 thorpej struct bridge_softc *sc = ifp->if_softc; 1447 1.1 thorpej 1448 1.143 ozaki KASSERT((ifp->if_flags & IFF_RUNNING) == 0); 1449 1.1 thorpej 1450 1.199 ozaki BRIDGE_LOCK(sc); 1451 1.199 ozaki sc->sc_stopping = false; 1452 1.199 ozaki BRIDGE_UNLOCK(sc); 1453 1.199 ozaki 1454 1.1 thorpej callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz, 1455 1.1 thorpej bridge_timer, sc); 1456 1.143 ozaki bstp_initialization(sc); 1457 1.1 thorpej 1458 1.1 thorpej ifp->if_flags |= IFF_RUNNING; 1459 1.136 msaitoh return 0; 1460 1.1 thorpej } 1461 1.1 thorpej 1462 1.1 thorpej /* 1463 1.1 thorpej * bridge_stop: 1464 1.1 thorpej * 1465 1.1 thorpej * Stop the bridge interface. 1466 1.1 thorpej */ 1467 1.33 thorpej static void 1468 1.45 christos bridge_stop(struct ifnet *ifp, int disable) 1469 1.1 thorpej { 1470 1.1 thorpej struct bridge_softc *sc = ifp->if_softc; 1471 1.1 thorpej 1472 1.143 ozaki KASSERT((ifp->if_flags & IFF_RUNNING) != 0); 1473 1.143 ozaki ifp->if_flags &= ~IFF_RUNNING; 1474 1.1 thorpej 1475 1.199 ozaki BRIDGE_LOCK(sc); 1476 1.199 ozaki sc->sc_stopping = true; 1477 1.199 ozaki BRIDGE_UNLOCK(sc); 1478 1.199 ozaki 1479 1.147 ozaki callout_halt(&sc->sc_brcallout, NULL); 1480 1.147 ozaki workqueue_wait(sc->sc_rtage_wq, &sc->sc_rtage_wk); 1481 1.1 thorpej bstp_stop(sc); 1482 1.1 thorpej bridge_rtflush(sc, IFBF_FLUSHDYN); 1483 1.1 thorpej } 1484 1.1 thorpej 1485 1.1 thorpej /* 1486 1.1 thorpej * bridge_enqueue: 1487 1.1 thorpej * 1488 1.1 thorpej * Enqueue a packet on a bridge member interface. 1489 1.1 thorpej */ 1490 1.33 thorpej void 1491 1.18 jdc bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m, 1492 1.18 jdc int runfilt) 1493 1.1 thorpej { 1494 1.1 thorpej int len, error; 1495 1.1 thorpej short mflags; 1496 1.1 thorpej 1497 1.18 jdc if (runfilt) { 1498 1.77 rmind if (pfil_run_hooks(sc->sc_if.if_pfil, &m, 1499 1.22 jdc dst_ifp, PFIL_OUT) != 0) { 1500 1.191 rin m_freem(m); 1501 1.18 jdc return; 1502 1.18 jdc } 1503 1.22 jdc if (m == NULL) 1504 1.22 jdc return; 1505 1.9 perseant } 1506 1.9 perseant 1507 1.1 thorpej #ifdef ALTQ 1508 1.126 knakahar KERNEL_LOCK(1, NULL); 1509 1.1 thorpej /* 1510 1.1 thorpej * If ALTQ is enabled on the member interface, do 1511 1.1 thorpej * classification; the queueing discipline might 1512 1.1 thorpej * not require classification, but might require 1513 1.1 thorpej * the address family/header pointer in the pktattr. 1514 1.1 thorpej */ 1515 1.1 thorpej if (ALTQ_IS_ENABLED(&dst_ifp->if_snd)) { 1516 1.1 thorpej /* XXX IFT_ETHER */ 1517 1.116 knakahar altq_etherclassify(&dst_ifp->if_snd, m); 1518 1.1 thorpej } 1519 1.126 knakahar KERNEL_UNLOCK_ONE(NULL); 1520 1.1 thorpej #endif /* ALTQ */ 1521 1.1 thorpej 1522 1.187 yamaguch if (vlan_has_tag(m) && 1523 1.187 yamaguch !vlan_is_hwtag_enabled(dst_ifp)) { 1524 1.187 yamaguch (void)ether_inject_vlantag(&m, ETHERTYPE_VLAN, 1525 1.187 yamaguch vlan_get_tag(m)); 1526 1.187 yamaguch if (m == NULL) { 1527 1.187 yamaguch if_statinc(&sc->sc_if, if_oerrors); 1528 1.187 yamaguch return; 1529 1.187 yamaguch } 1530 1.187 yamaguch } 1531 1.187 yamaguch 1532 1.1 thorpej len = m->m_pkthdr.len; 1533 1.1 thorpej mflags = m->m_flags; 1534 1.87 ozaki 1535 1.129 knakahar error = if_transmit_lock(dst_ifp, m); 1536 1.1 thorpej if (error) { 1537 1.1 thorpej /* mbuf is already freed */ 1538 1.166 thorpej if_statinc(&sc->sc_if, if_oerrors); 1539 1.1 thorpej return; 1540 1.1 thorpej } 1541 1.1 thorpej 1542 1.166 thorpej net_stat_ref_t nsr = IF_STAT_GETREF(&sc->sc_if); 1543 1.190 riastrad if_statinc_ref(&sc->sc_if, nsr, if_opackets); 1544 1.190 riastrad if_statadd_ref(&sc->sc_if, nsr, if_obytes, len); 1545 1.121 knakahar if (mflags & M_MCAST) 1546 1.190 riastrad if_statinc_ref(&sc->sc_if, nsr, if_omcasts); 1547 1.166 thorpej IF_STAT_PUTREF(&sc->sc_if); 1548 1.1 thorpej } 1549 1.1 thorpej 1550 1.1 thorpej /* 1551 1.1 thorpej * bridge_output: 1552 1.1 thorpej * 1553 1.1 thorpej * Send output from a bridge member interface. This 1554 1.1 thorpej * performs the bridging function for locally originated 1555 1.1 thorpej * packets. 1556 1.1 thorpej * 1557 1.1 thorpej * The mbuf has the Ethernet header already attached. We must 1558 1.1 thorpej * enqueue or free the mbuf before returning. 1559 1.1 thorpej */ 1560 1.1 thorpej int 1561 1.48 dyoung bridge_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa, 1562 1.120 ozaki const struct rtentry *rt) 1563 1.1 thorpej { 1564 1.1 thorpej struct ether_header *eh; 1565 1.1 thorpej struct ifnet *dst_if; 1566 1.1 thorpej struct bridge_softc *sc; 1567 1.161 rin struct mbuf *n; 1568 1.192 ozaki int s, bound; 1569 1.1 thorpej 1570 1.128 knakahar /* 1571 1.128 knakahar * bridge_output() is called from ether_output(), furthermore 1572 1.128 knakahar * ifp argument doesn't point to bridge(4). So, don't assert 1573 1.140 ozaki * IFEF_MPSAFE here. 1574 1.128 knakahar */ 1575 1.128 knakahar 1576 1.170 jdolecek KASSERT(m->m_len >= ETHER_HDR_LEN); 1577 1.1 thorpej 1578 1.1 thorpej eh = mtod(m, struct ether_header *); 1579 1.1 thorpej sc = ifp->if_bridge; 1580 1.1 thorpej 1581 1.122 roy if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 1582 1.122 roy if (memcmp(etherbroadcastaddr, 1583 1.122 roy eh->ether_dhost, ETHER_ADDR_LEN) == 0) 1584 1.122 roy m->m_flags |= M_BCAST; 1585 1.122 roy else 1586 1.122 roy m->m_flags |= M_MCAST; 1587 1.122 roy } 1588 1.122 roy 1589 1.1 thorpej /* 1590 1.1 thorpej * If bridge is down, but the original output interface is up, 1591 1.1 thorpej * go ahead and send out that interface. Otherwise, the packet 1592 1.1 thorpej * is dropped below. 1593 1.1 thorpej */ 1594 1.87 ozaki if (__predict_false(sc == NULL) || 1595 1.87 ozaki (sc->sc_if.if_flags & IFF_RUNNING) == 0) { 1596 1.1 thorpej dst_if = ifp; 1597 1.161 rin goto unicast_asis; 1598 1.1 thorpej } 1599 1.1 thorpej 1600 1.1 thorpej /* 1601 1.1 thorpej * If the packet is a multicast, or we don't know a better way to 1602 1.1 thorpej * get there, send to all interfaces. 1603 1.1 thorpej */ 1604 1.122 roy if ((m->m_flags & (M_MCAST | M_BCAST)) != 0) 1605 1.1 thorpej dst_if = NULL; 1606 1.1 thorpej else 1607 1.1 thorpej dst_if = bridge_rtlookup(sc, eh->ether_dhost); 1608 1.161 rin 1609 1.161 rin /* 1610 1.161 rin * In general, we need to handle TX offload in software before 1611 1.161 rin * enqueueing a packet. However, we can send it as is in the 1612 1.161 rin * cases of unicast via (1) the source interface, or (2) an 1613 1.161 rin * interface which supports the specified offload options. 1614 1.161 rin * For multicast or broadcast, send it as is only if (3) all 1615 1.161 rin * the member interfaces support the specified options. 1616 1.161 rin */ 1617 1.161 rin 1618 1.161 rin /* 1619 1.161 rin * Unicast via the source interface. 1620 1.161 rin */ 1621 1.161 rin if (dst_if == ifp) 1622 1.161 rin goto unicast_asis; 1623 1.161 rin 1624 1.161 rin /* 1625 1.161 rin * Unicast via other interface. 1626 1.161 rin */ 1627 1.161 rin if (dst_if != NULL) { 1628 1.161 rin KASSERT(m->m_flags & M_PKTHDR); 1629 1.161 rin if (TX_OFFLOAD_SUPPORTED(dst_if->if_csum_flags_tx, 1630 1.161 rin m->m_pkthdr.csum_flags)) { 1631 1.161 rin /* 1632 1.161 rin * Unicast via an interface which supports the 1633 1.161 rin * specified offload options. 1634 1.161 rin */ 1635 1.161 rin goto unicast_asis; 1636 1.161 rin } 1637 1.161 rin 1638 1.161 rin /* 1639 1.161 rin * Handle TX offload in software. For TSO, a packet is 1640 1.161 rin * split into multiple chunks. Thus, the return value of 1641 1.163 rin * ether_sw_offload_tx() is mbuf queue consists of them. 1642 1.161 rin */ 1643 1.161 rin m = ether_sw_offload_tx(ifp, m); 1644 1.161 rin if (m == NULL) 1645 1.161 rin return 0; 1646 1.161 rin 1647 1.161 rin do { 1648 1.161 rin n = m->m_nextpkt; 1649 1.161 rin if ((dst_if->if_flags & IFF_RUNNING) == 0) 1650 1.161 rin m_freem(m); 1651 1.161 rin else 1652 1.161 rin bridge_enqueue(sc, dst_if, m, 0); 1653 1.161 rin m = n; 1654 1.161 rin } while (m != NULL); 1655 1.161 rin 1656 1.161 rin return 0; 1657 1.161 rin } 1658 1.161 rin 1659 1.161 rin /* 1660 1.161 rin * Multicast or broadcast. 1661 1.161 rin */ 1662 1.161 rin if (TX_OFFLOAD_SUPPORTED(sc->sc_csum_flags_tx, 1663 1.161 rin m->m_pkthdr.csum_flags)) { 1664 1.161 rin /* 1665 1.161 rin * Specified TX offload options are supported by all 1666 1.161 rin * the member interfaces of this bridge. 1667 1.161 rin */ 1668 1.161 rin m->m_nextpkt = NULL; /* XXX */ 1669 1.161 rin } else { 1670 1.161 rin /* 1671 1.161 rin * Otherwise, handle TX offload in software. 1672 1.161 rin */ 1673 1.161 rin m = ether_sw_offload_tx(ifp, m); 1674 1.161 rin if (m == NULL) 1675 1.161 rin return 0; 1676 1.161 rin } 1677 1.161 rin 1678 1.192 ozaki /* 1679 1.192 ozaki * When we use pppoe over bridge, bridge_output() can be called 1680 1.192 ozaki * in a lwp context by pppoe_timeout_wk(). 1681 1.192 ozaki */ 1682 1.192 ozaki bound = curlwp_bind(); 1683 1.161 rin do { 1684 1.122 roy /* XXX Should call bridge_broadcast, but there are locking 1685 1.122 roy * issues which need resolving first. */ 1686 1.1 thorpej struct bridge_iflist *bif; 1687 1.1 thorpej struct mbuf *mc; 1688 1.118 roy bool used = false; 1689 1.1 thorpej 1690 1.161 rin n = m->m_nextpkt; 1691 1.161 rin 1692 1.193 ozaki s = pserialize_read_enter(); 1693 1.115 ozaki BRIDGE_IFLIST_READER_FOREACH(bif, sc) { 1694 1.115 ozaki struct psref psref; 1695 1.115 ozaki 1696 1.115 ozaki bridge_acquire_member(sc, bif, &psref); 1697 1.193 ozaki pserialize_read_exit(s); 1698 1.87 ozaki 1699 1.1 thorpej dst_if = bif->bif_ifp; 1700 1.1 thorpej if ((dst_if->if_flags & IFF_RUNNING) == 0) 1701 1.95 ozaki goto next; 1702 1.1 thorpej 1703 1.1 thorpej /* 1704 1.1 thorpej * If this is not the original output interface, 1705 1.1 thorpej * and the interface is participating in spanning 1706 1.1 thorpej * tree, make sure the port is in a state that 1707 1.1 thorpej * allows forwarding. 1708 1.1 thorpej */ 1709 1.1 thorpej if (dst_if != ifp && 1710 1.1 thorpej (bif->bif_flags & IFBIF_STP) != 0) { 1711 1.1 thorpej switch (bif->bif_state) { 1712 1.1 thorpej case BSTP_IFSTATE_BLOCKING: 1713 1.1 thorpej case BSTP_IFSTATE_LISTENING: 1714 1.1 thorpej case BSTP_IFSTATE_DISABLED: 1715 1.95 ozaki goto next; 1716 1.1 thorpej } 1717 1.1 thorpej } 1718 1.1 thorpej 1719 1.112 ozaki if (PSLIST_READER_NEXT(bif, struct bridge_iflist, 1720 1.122 roy bif_next) == NULL && 1721 1.122 roy ((m->m_flags & (M_MCAST | M_BCAST)) == 0 || 1722 1.122 roy dst_if == ifp)) 1723 1.122 roy { 1724 1.118 roy used = true; 1725 1.1 thorpej mc = m; 1726 1.1 thorpej } else { 1727 1.159 msaitoh mc = m_copypacket(m, M_DONTWAIT); 1728 1.1 thorpej if (mc == NULL) { 1729 1.166 thorpej if_statinc(&sc->sc_if, if_oerrors); 1730 1.95 ozaki goto next; 1731 1.1 thorpej } 1732 1.1 thorpej } 1733 1.1 thorpej 1734 1.18 jdc bridge_enqueue(sc, dst_if, mc, 0); 1735 1.122 roy 1736 1.122 roy if ((m->m_flags & (M_MCAST | M_BCAST)) != 0 && 1737 1.122 roy dst_if != ifp) 1738 1.122 roy { 1739 1.122 roy if (PSLIST_READER_NEXT(bif, 1740 1.122 roy struct bridge_iflist, bif_next) == NULL) 1741 1.122 roy { 1742 1.122 roy used = true; 1743 1.122 roy mc = m; 1744 1.122 roy } else { 1745 1.159 msaitoh mc = m_copypacket(m, M_DONTWAIT); 1746 1.122 roy if (mc == NULL) { 1747 1.166 thorpej if_statinc(&sc->sc_if, 1748 1.166 thorpej if_oerrors); 1749 1.122 roy goto next; 1750 1.122 roy } 1751 1.122 roy } 1752 1.122 roy 1753 1.124 ozaki m_set_rcvif(mc, dst_if); 1754 1.122 roy mc->m_flags &= ~M_PROMISC; 1755 1.122 roy 1756 1.189 skrll const int _s = splsoftnet(); 1757 1.155 ozaki KERNEL_LOCK_UNLESS_IFP_MPSAFE(dst_if); 1758 1.122 roy ether_input(dst_if, mc); 1759 1.155 ozaki KERNEL_UNLOCK_UNLESS_IFP_MPSAFE(dst_if); 1760 1.189 skrll splx(_s); 1761 1.122 roy } 1762 1.122 roy 1763 1.95 ozaki next: 1764 1.193 ozaki s = pserialize_read_enter(); 1765 1.115 ozaki bridge_release_member(sc, bif, &psref); 1766 1.118 roy 1767 1.118 roy /* Guarantee we don't re-enter the loop as we already 1768 1.118 roy * decided we're at the end. */ 1769 1.118 roy if (used) 1770 1.118 roy break; 1771 1.1 thorpej } 1772 1.193 ozaki pserialize_read_exit(s); 1773 1.87 ozaki 1774 1.118 roy if (!used) 1775 1.1 thorpej m_freem(m); 1776 1.1 thorpej 1777 1.161 rin m = n; 1778 1.161 rin } while (m != NULL); 1779 1.192 ozaki curlwp_bindx(bound); 1780 1.192 ozaki 1781 1.161 rin return 0; 1782 1.161 rin 1783 1.161 rin unicast_asis: 1784 1.1 thorpej /* 1785 1.1 thorpej * XXX Spanning tree consideration here? 1786 1.1 thorpej */ 1787 1.161 rin if ((dst_if->if_flags & IFF_RUNNING) == 0) 1788 1.1 thorpej m_freem(m); 1789 1.161 rin else 1790 1.161 rin bridge_enqueue(sc, dst_if, m, 0); 1791 1.136 msaitoh return 0; 1792 1.1 thorpej } 1793 1.1 thorpej 1794 1.1 thorpej /* 1795 1.1 thorpej * bridge_start: 1796 1.1 thorpej * 1797 1.1 thorpej * Start output on a bridge. 1798 1.1 thorpej * 1799 1.1 thorpej * NOTE: This routine should never be called in this implementation. 1800 1.1 thorpej */ 1801 1.33 thorpej static void 1802 1.1 thorpej bridge_start(struct ifnet *ifp) 1803 1.1 thorpej { 1804 1.1 thorpej 1805 1.1 thorpej printf("%s: bridge_start() called\n", ifp->if_xname); 1806 1.1 thorpej } 1807 1.1 thorpej 1808 1.1 thorpej /* 1809 1.1 thorpej * bridge_forward: 1810 1.1 thorpej * 1811 1.21 augustss * The forwarding function of the bridge. 1812 1.1 thorpej */ 1813 1.33 thorpej static void 1814 1.108 ozaki bridge_forward(struct bridge_softc *sc, struct mbuf *m) 1815 1.1 thorpej { 1816 1.1 thorpej struct bridge_iflist *bif; 1817 1.1 thorpej struct ifnet *src_if, *dst_if; 1818 1.1 thorpej struct ether_header *eh; 1819 1.115 ozaki struct psref psref; 1820 1.125 ozaki struct psref psref_src; 1821 1.114 ozaki DECLARE_LOCK_VARIABLE; 1822 1.194 ozaki bool src_if_protected; 1823 1.1 thorpej 1824 1.125 ozaki src_if = m_get_rcvif_psref(m, &psref_src); 1825 1.125 ozaki if (src_if == NULL) { 1826 1.125 ozaki /* Interface is being destroyed? */ 1827 1.196 ozaki goto discard; 1828 1.125 ozaki } 1829 1.1 thorpej 1830 1.166 thorpej if_statadd2(&sc->sc_if, if_ipackets, 1, if_ibytes, m->m_pkthdr.len); 1831 1.65 bouyer 1832 1.108 ozaki /* 1833 1.108 ozaki * Look up the bridge_iflist. 1834 1.108 ozaki */ 1835 1.115 ozaki bif = bridge_lookup_member_if(sc, src_if, &psref); 1836 1.108 ozaki if (bif == NULL) { 1837 1.108 ozaki /* Interface is not a bridge member (anymore?) */ 1838 1.196 ozaki goto discard; 1839 1.108 ozaki } 1840 1.1 thorpej 1841 1.108 ozaki if (bif->bif_flags & IFBIF_STP) { 1842 1.108 ozaki switch (bif->bif_state) { 1843 1.108 ozaki case BSTP_IFSTATE_BLOCKING: 1844 1.108 ozaki case BSTP_IFSTATE_LISTENING: 1845 1.108 ozaki case BSTP_IFSTATE_DISABLED: 1846 1.115 ozaki bridge_release_member(sc, bif, &psref); 1847 1.196 ozaki goto discard; 1848 1.65 bouyer } 1849 1.108 ozaki } 1850 1.1 thorpej 1851 1.108 ozaki eh = mtod(m, struct ether_header *); 1852 1.87 ozaki 1853 1.108 ozaki /* 1854 1.108 ozaki * If the interface is learning, and the source 1855 1.108 ozaki * address is valid and not multicast, record 1856 1.108 ozaki * the address. 1857 1.108 ozaki */ 1858 1.108 ozaki if ((bif->bif_flags & IFBIF_LEARNING) != 0 && 1859 1.108 ozaki ETHER_IS_MULTICAST(eh->ether_shost) == 0 && 1860 1.108 ozaki (eh->ether_shost[0] == 0 && 1861 1.108 ozaki eh->ether_shost[1] == 0 && 1862 1.108 ozaki eh->ether_shost[2] == 0 && 1863 1.108 ozaki eh->ether_shost[3] == 0 && 1864 1.108 ozaki eh->ether_shost[4] == 0 && 1865 1.108 ozaki eh->ether_shost[5] == 0) == 0) { 1866 1.108 ozaki (void) bridge_rtupdate(sc, eh->ether_shost, 1867 1.108 ozaki src_if, 0, IFBAF_DYNAMIC); 1868 1.108 ozaki } 1869 1.1 thorpej 1870 1.108 ozaki if ((bif->bif_flags & IFBIF_STP) != 0 && 1871 1.108 ozaki bif->bif_state == BSTP_IFSTATE_LEARNING) { 1872 1.115 ozaki bridge_release_member(sc, bif, &psref); 1873 1.196 ozaki goto discard; 1874 1.108 ozaki } 1875 1.1 thorpej 1876 1.194 ozaki src_if_protected = ((bif->bif_flags & IFBIF_PROTECTED) != 0); 1877 1.194 ozaki 1878 1.115 ozaki bridge_release_member(sc, bif, &psref); 1879 1.9 perseant 1880 1.108 ozaki /* 1881 1.108 ozaki * At this point, the port either doesn't participate 1882 1.108 ozaki * in spanning tree or it is in the forwarding state. 1883 1.108 ozaki */ 1884 1.1 thorpej 1885 1.108 ozaki /* 1886 1.108 ozaki * If the packet is unicast, destined for someone on 1887 1.108 ozaki * "this" side of the bridge, drop it. 1888 1.108 ozaki */ 1889 1.108 ozaki if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) { 1890 1.108 ozaki dst_if = bridge_rtlookup(sc, eh->ether_dhost); 1891 1.196 ozaki if (src_if == dst_if) 1892 1.196 ozaki goto discard; 1893 1.108 ozaki } else { 1894 1.108 ozaki /* ...forward it to all interfaces. */ 1895 1.166 thorpej if_statinc(&sc->sc_if, if_imcasts); 1896 1.108 ozaki dst_if = NULL; 1897 1.108 ozaki } 1898 1.87 ozaki 1899 1.196 ozaki if (pfil_run_hooks(sc->sc_if.if_pfil, &m, src_if, PFIL_IN) != 0 || 1900 1.196 ozaki m == NULL) { 1901 1.196 ozaki goto discard; 1902 1.108 ozaki } 1903 1.108 ozaki 1904 1.108 ozaki if (dst_if == NULL) { 1905 1.194 ozaki bridge_broadcast(sc, src_if, src_if_protected, m); 1906 1.108 ozaki goto out; 1907 1.108 ozaki } 1908 1.108 ozaki 1909 1.125 ozaki m_put_rcvif_psref(src_if, &psref_src); 1910 1.125 ozaki src_if = NULL; 1911 1.125 ozaki 1912 1.108 ozaki /* 1913 1.108 ozaki * At this point, we're dealing with a unicast frame 1914 1.108 ozaki * going to a different interface. 1915 1.108 ozaki */ 1916 1.196 ozaki if ((dst_if->if_flags & IFF_RUNNING) == 0) 1917 1.196 ozaki goto discard; 1918 1.108 ozaki 1919 1.115 ozaki bif = bridge_lookup_member_if(sc, dst_if, &psref); 1920 1.108 ozaki if (bif == NULL) { 1921 1.108 ozaki /* Not a member of the bridge (anymore?) */ 1922 1.196 ozaki goto discard; 1923 1.108 ozaki } 1924 1.1 thorpej 1925 1.108 ozaki if (bif->bif_flags & IFBIF_STP) { 1926 1.108 ozaki switch (bif->bif_state) { 1927 1.108 ozaki case BSTP_IFSTATE_DISABLED: 1928 1.108 ozaki case BSTP_IFSTATE_BLOCKING: 1929 1.115 ozaki bridge_release_member(sc, bif, &psref); 1930 1.196 ozaki goto discard; 1931 1.1 thorpej } 1932 1.108 ozaki } 1933 1.65 bouyer 1934 1.194 ozaki if ((bif->bif_flags & IFBIF_PROTECTED) && src_if_protected) { 1935 1.194 ozaki bridge_release_member(sc, bif, &psref); 1936 1.196 ozaki goto discard; 1937 1.194 ozaki } 1938 1.194 ozaki 1939 1.115 ozaki bridge_release_member(sc, bif, &psref); 1940 1.87 ozaki 1941 1.157 msaitoh /* 1942 1.158 msaitoh * Before enqueueing this packet to the destination interface, 1943 1.158 msaitoh * clear any in-bound checksum flags to prevent them from being 1944 1.158 msaitoh * misused as out-bound flags. 1945 1.157 msaitoh */ 1946 1.157 msaitoh m->m_pkthdr.csum_flags = 0; 1947 1.157 msaitoh 1948 1.114 ozaki ACQUIRE_GLOBAL_LOCKS(); 1949 1.108 ozaki bridge_enqueue(sc, dst_if, m, 1); 1950 1.114 ozaki RELEASE_GLOBAL_LOCKS(); 1951 1.108 ozaki out: 1952 1.125 ozaki if (src_if != NULL) 1953 1.125 ozaki m_put_rcvif_psref(src_if, &psref_src); 1954 1.108 ozaki return; 1955 1.196 ozaki 1956 1.196 ozaki discard: 1957 1.196 ozaki m_freem(m); 1958 1.196 ozaki goto out; 1959 1.1 thorpej } 1960 1.1 thorpej 1961 1.82 ozaki static bool 1962 1.82 ozaki bstp_state_before_learning(struct bridge_iflist *bif) 1963 1.82 ozaki { 1964 1.82 ozaki if (bif->bif_flags & IFBIF_STP) { 1965 1.82 ozaki switch (bif->bif_state) { 1966 1.82 ozaki case BSTP_IFSTATE_BLOCKING: 1967 1.82 ozaki case BSTP_IFSTATE_LISTENING: 1968 1.82 ozaki case BSTP_IFSTATE_DISABLED: 1969 1.82 ozaki return true; 1970 1.82 ozaki } 1971 1.82 ozaki } 1972 1.82 ozaki return false; 1973 1.82 ozaki } 1974 1.82 ozaki 1975 1.82 ozaki static bool 1976 1.82 ozaki bridge_ourether(struct bridge_iflist *bif, struct ether_header *eh, int src) 1977 1.82 ozaki { 1978 1.82 ozaki uint8_t *ether = src ? eh->ether_shost : eh->ether_dhost; 1979 1.82 ozaki 1980 1.82 ozaki if (memcmp(CLLADDR(bif->bif_ifp->if_sadl), ether, ETHER_ADDR_LEN) == 0 1981 1.82 ozaki #if NCARP > 0 1982 1.82 ozaki || (bif->bif_ifp->if_carp && 1983 1.82 ozaki carp_ourether(bif->bif_ifp->if_carp, eh, IFT_ETHER, src) != NULL) 1984 1.82 ozaki #endif /* NCARP > 0 */ 1985 1.82 ozaki ) 1986 1.82 ozaki return true; 1987 1.82 ozaki 1988 1.82 ozaki return false; 1989 1.82 ozaki } 1990 1.82 ozaki 1991 1.1 thorpej /* 1992 1.1 thorpej * bridge_input: 1993 1.1 thorpej * 1994 1.1 thorpej * Receive input from a member interface. Queue the packet for 1995 1.1 thorpej * bridging if it is not for us. 1996 1.1 thorpej */ 1997 1.81 ozaki static void 1998 1.1 thorpej bridge_input(struct ifnet *ifp, struct mbuf *m) 1999 1.1 thorpej { 2000 1.1 thorpej struct bridge_softc *sc = ifp->if_bridge; 2001 1.1 thorpej struct bridge_iflist *bif; 2002 1.1 thorpej struct ether_header *eh; 2003 1.115 ozaki struct psref psref; 2004 1.135 ozaki int bound; 2005 1.114 ozaki DECLARE_LOCK_VARIABLE; 2006 1.1 thorpej 2007 1.106 ozaki KASSERT(!cpu_intr_p()); 2008 1.106 ozaki 2009 1.87 ozaki if (__predict_false(sc == NULL) || 2010 1.87 ozaki (sc->sc_if.if_flags & IFF_RUNNING) == 0) { 2011 1.114 ozaki ACQUIRE_GLOBAL_LOCKS(); 2012 1.81 ozaki ether_input(ifp, m); 2013 1.114 ozaki RELEASE_GLOBAL_LOCKS(); 2014 1.81 ozaki return; 2015 1.81 ozaki } 2016 1.1 thorpej 2017 1.135 ozaki bound = curlwp_bind(); 2018 1.115 ozaki bif = bridge_lookup_member_if(sc, ifp, &psref); 2019 1.81 ozaki if (bif == NULL) { 2020 1.135 ozaki curlwp_bindx(bound); 2021 1.114 ozaki ACQUIRE_GLOBAL_LOCKS(); 2022 1.81 ozaki ether_input(ifp, m); 2023 1.114 ozaki RELEASE_GLOBAL_LOCKS(); 2024 1.81 ozaki return; 2025 1.81 ozaki } 2026 1.1 thorpej 2027 1.1 thorpej eh = mtod(m, struct ether_header *); 2028 1.1 thorpej 2029 1.81 ozaki if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 2030 1.81 ozaki if (memcmp(etherbroadcastaddr, 2031 1.81 ozaki eh->ether_dhost, ETHER_ADDR_LEN) == 0) 2032 1.81 ozaki m->m_flags |= M_BCAST; 2033 1.81 ozaki else 2034 1.81 ozaki m->m_flags |= M_MCAST; 2035 1.81 ozaki } 2036 1.81 ozaki 2037 1.83 ozaki /* 2038 1.83 ozaki * A 'fast' path for packets addressed to interfaces that are 2039 1.83 ozaki * part of this bridge. 2040 1.83 ozaki */ 2041 1.83 ozaki if (!(m->m_flags & (M_BCAST|M_MCAST)) && 2042 1.83 ozaki !bstp_state_before_learning(bif)) { 2043 1.83 ozaki struct bridge_iflist *_bif; 2044 1.92 ozaki struct ifnet *_ifp = NULL; 2045 1.95 ozaki int s; 2046 1.115 ozaki struct psref _psref; 2047 1.83 ozaki 2048 1.193 ozaki s = pserialize_read_enter(); 2049 1.115 ozaki BRIDGE_IFLIST_READER_FOREACH(_bif, sc) { 2050 1.83 ozaki /* It is destined for us. */ 2051 1.83 ozaki if (bridge_ourether(_bif, eh, 0)) { 2052 1.115 ozaki bridge_acquire_member(sc, _bif, &_psref); 2053 1.193 ozaki pserialize_read_exit(s); 2054 1.83 ozaki if (_bif->bif_flags & IFBIF_LEARNING) 2055 1.83 ozaki (void) bridge_rtupdate(sc, 2056 1.83 ozaki eh->ether_shost, ifp, 0, IFBAF_DYNAMIC); 2057 1.124 ozaki m_set_rcvif(m, _bif->bif_ifp); 2058 1.124 ozaki _ifp = _bif->bif_ifp; 2059 1.115 ozaki bridge_release_member(sc, _bif, &_psref); 2060 1.95 ozaki goto out; 2061 1.64 mrg } 2062 1.1 thorpej 2063 1.83 ozaki /* We just received a packet that we sent out. */ 2064 1.92 ozaki if (bridge_ourether(_bif, eh, 1)) 2065 1.87 ozaki break; 2066 1.1 thorpej } 2067 1.193 ozaki pserialize_read_exit(s); 2068 1.95 ozaki out: 2069 1.87 ozaki 2070 1.87 ozaki if (_bif != NULL) { 2071 1.115 ozaki bridge_release_member(sc, bif, &psref); 2072 1.135 ozaki curlwp_bindx(bound); 2073 1.100 ozaki if (_ifp != NULL) { 2074 1.100 ozaki m->m_flags &= ~M_PROMISC; 2075 1.114 ozaki ACQUIRE_GLOBAL_LOCKS(); 2076 1.92 ozaki ether_input(_ifp, m); 2077 1.114 ozaki RELEASE_GLOBAL_LOCKS(); 2078 1.100 ozaki } else 2079 1.92 ozaki m_freem(m); 2080 1.87 ozaki return; 2081 1.87 ozaki } 2082 1.83 ozaki } 2083 1.1 thorpej 2084 1.83 ozaki /* Tap off 802.1D packets; they do not get forwarded. */ 2085 1.83 ozaki if (bif->bif_flags & IFBIF_STP && 2086 1.83 ozaki memcmp(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN) == 0) { 2087 1.83 ozaki bstp_input(sc, bif, m); 2088 1.115 ozaki bridge_release_member(sc, bif, &psref); 2089 1.135 ozaki curlwp_bindx(bound); 2090 1.81 ozaki return; 2091 1.1 thorpej } 2092 1.1 thorpej 2093 1.83 ozaki /* 2094 1.83 ozaki * A normal switch would discard the packet here, but that's not what 2095 1.83 ozaki * we've done historically. This also prevents some obnoxious behaviour. 2096 1.83 ozaki */ 2097 1.82 ozaki if (bstp_state_before_learning(bif)) { 2098 1.115 ozaki bridge_release_member(sc, bif, &psref); 2099 1.135 ozaki curlwp_bindx(bound); 2100 1.114 ozaki ACQUIRE_GLOBAL_LOCKS(); 2101 1.82 ozaki ether_input(ifp, m); 2102 1.114 ozaki RELEASE_GLOBAL_LOCKS(); 2103 1.82 ozaki return; 2104 1.1 thorpej } 2105 1.1 thorpej 2106 1.115 ozaki bridge_release_member(sc, bif, &psref); 2107 1.87 ozaki 2108 1.108 ozaki bridge_forward(sc, m); 2109 1.135 ozaki 2110 1.135 ozaki curlwp_bindx(bound); 2111 1.1 thorpej } 2112 1.1 thorpej 2113 1.1 thorpej /* 2114 1.1 thorpej * bridge_broadcast: 2115 1.1 thorpej * 2116 1.1 thorpej * Send a frame to all interfaces that are members of 2117 1.1 thorpej * the bridge, except for the one on which the packet 2118 1.1 thorpej * arrived. 2119 1.1 thorpej */ 2120 1.33 thorpej static void 2121 1.1 thorpej bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, 2122 1.194 ozaki bool src_if_protected, struct mbuf *m) 2123 1.1 thorpej { 2124 1.1 thorpej struct bridge_iflist *bif; 2125 1.1 thorpej struct mbuf *mc; 2126 1.1 thorpej struct ifnet *dst_if; 2127 1.100 ozaki bool bmcast; 2128 1.95 ozaki int s; 2129 1.114 ozaki DECLARE_LOCK_VARIABLE; 2130 1.83 ozaki 2131 1.100 ozaki bmcast = m->m_flags & (M_BCAST|M_MCAST); 2132 1.1 thorpej 2133 1.193 ozaki s = pserialize_read_enter(); 2134 1.115 ozaki BRIDGE_IFLIST_READER_FOREACH(bif, sc) { 2135 1.115 ozaki struct psref psref; 2136 1.115 ozaki 2137 1.115 ozaki bridge_acquire_member(sc, bif, &psref); 2138 1.193 ozaki pserialize_read_exit(s); 2139 1.87 ozaki 2140 1.1 thorpej dst_if = bif->bif_ifp; 2141 1.1 thorpej 2142 1.1 thorpej if (bif->bif_flags & IFBIF_STP) { 2143 1.1 thorpej switch (bif->bif_state) { 2144 1.1 thorpej case BSTP_IFSTATE_BLOCKING: 2145 1.1 thorpej case BSTP_IFSTATE_DISABLED: 2146 1.95 ozaki goto next; 2147 1.1 thorpej } 2148 1.1 thorpej } 2149 1.1 thorpej 2150 1.83 ozaki if ((bif->bif_flags & IFBIF_DISCOVER) == 0 && !bmcast) 2151 1.95 ozaki goto next; 2152 1.1 thorpej 2153 1.1 thorpej if ((dst_if->if_flags & IFF_RUNNING) == 0) 2154 1.95 ozaki goto next; 2155 1.1 thorpej 2156 1.100 ozaki if (dst_if != src_if) { 2157 1.194 ozaki if ((bif->bif_flags & IFBIF_PROTECTED) && 2158 1.194 ozaki src_if_protected) { 2159 1.194 ozaki goto next; 2160 1.194 ozaki } 2161 1.194 ozaki 2162 1.159 msaitoh mc = m_copypacket(m, M_DONTWAIT); 2163 1.1 thorpej if (mc == NULL) { 2164 1.166 thorpej if_statinc(&sc->sc_if, if_oerrors); 2165 1.95 ozaki goto next; 2166 1.1 thorpej } 2167 1.157 msaitoh /* 2168 1.158 msaitoh * Before enqueueing this packet to the destination 2169 1.158 msaitoh * interface, clear any in-bound checksum flags to 2170 1.158 msaitoh * prevent them from being misused as out-bound flags. 2171 1.157 msaitoh */ 2172 1.158 msaitoh mc->m_pkthdr.csum_flags = 0; 2173 1.157 msaitoh 2174 1.114 ozaki ACQUIRE_GLOBAL_LOCKS(); 2175 1.100 ozaki bridge_enqueue(sc, dst_if, mc, 1); 2176 1.114 ozaki RELEASE_GLOBAL_LOCKS(); 2177 1.1 thorpej } 2178 1.1 thorpej 2179 1.100 ozaki if (bmcast) { 2180 1.159 msaitoh mc = m_copypacket(m, M_DONTWAIT); 2181 1.100 ozaki if (mc == NULL) { 2182 1.166 thorpej if_statinc(&sc->sc_if, if_oerrors); 2183 1.100 ozaki goto next; 2184 1.100 ozaki } 2185 1.169 jdolecek /* 2186 1.169 jdolecek * Before enqueueing this packet to the destination 2187 1.169 jdolecek * interface, clear any in-bound checksum flags to 2188 1.169 jdolecek * prevent them from being misused as out-bound flags. 2189 1.169 jdolecek */ 2190 1.169 jdolecek mc->m_pkthdr.csum_flags = 0; 2191 1.100 ozaki 2192 1.124 ozaki m_set_rcvif(mc, dst_if); 2193 1.100 ozaki mc->m_flags &= ~M_PROMISC; 2194 1.114 ozaki 2195 1.114 ozaki ACQUIRE_GLOBAL_LOCKS(); 2196 1.100 ozaki ether_input(dst_if, mc); 2197 1.114 ozaki RELEASE_GLOBAL_LOCKS(); 2198 1.100 ozaki } 2199 1.95 ozaki next: 2200 1.193 ozaki s = pserialize_read_enter(); 2201 1.115 ozaki bridge_release_member(sc, bif, &psref); 2202 1.1 thorpej } 2203 1.193 ozaki pserialize_read_exit(s); 2204 1.83 ozaki 2205 1.100 ozaki m_freem(m); 2206 1.1 thorpej } 2207 1.1 thorpej 2208 1.97 ozaki static int 2209 1.97 ozaki bridge_rtalloc(struct bridge_softc *sc, const uint8_t *dst, 2210 1.97 ozaki struct bridge_rtnode **brtp) 2211 1.97 ozaki { 2212 1.97 ozaki struct bridge_rtnode *brt; 2213 1.97 ozaki int error; 2214 1.97 ozaki 2215 1.97 ozaki if (sc->sc_brtcnt >= sc->sc_brtmax) 2216 1.97 ozaki return ENOSPC; 2217 1.97 ozaki 2218 1.97 ozaki /* 2219 1.97 ozaki * Allocate a new bridge forwarding node, and 2220 1.97 ozaki * initialize the expiration time and Ethernet 2221 1.97 ozaki * address. 2222 1.97 ozaki */ 2223 1.97 ozaki brt = pool_get(&bridge_rtnode_pool, PR_NOWAIT); 2224 1.97 ozaki if (brt == NULL) 2225 1.97 ozaki return ENOMEM; 2226 1.97 ozaki 2227 1.97 ozaki memset(brt, 0, sizeof(*brt)); 2228 1.97 ozaki brt->brt_expire = time_uptime + sc->sc_brttimeout; 2229 1.97 ozaki brt->brt_flags = IFBAF_DYNAMIC; 2230 1.97 ozaki memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN); 2231 1.154 ozaki PSLIST_ENTRY_INIT(brt, brt_list); 2232 1.154 ozaki PSLIST_ENTRY_INIT(brt, brt_hash); 2233 1.97 ozaki 2234 1.108 ozaki BRIDGE_RT_LOCK(sc); 2235 1.97 ozaki error = bridge_rtnode_insert(sc, brt); 2236 1.108 ozaki BRIDGE_RT_UNLOCK(sc); 2237 1.97 ozaki 2238 1.97 ozaki if (error != 0) { 2239 1.97 ozaki pool_put(&bridge_rtnode_pool, brt); 2240 1.97 ozaki return error; 2241 1.97 ozaki } 2242 1.97 ozaki 2243 1.97 ozaki *brtp = brt; 2244 1.97 ozaki return 0; 2245 1.97 ozaki } 2246 1.97 ozaki 2247 1.1 thorpej /* 2248 1.1 thorpej * bridge_rtupdate: 2249 1.1 thorpej * 2250 1.1 thorpej * Add a bridge routing entry. 2251 1.1 thorpej */ 2252 1.33 thorpej static int 2253 1.1 thorpej bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, 2254 1.1 thorpej struct ifnet *dst_if, int setflags, uint8_t flags) 2255 1.1 thorpej { 2256 1.1 thorpej struct bridge_rtnode *brt; 2257 1.97 ozaki int s; 2258 1.1 thorpej 2259 1.97 ozaki again: 2260 1.1 thorpej /* 2261 1.1 thorpej * A route for this destination might already exist. If so, 2262 1.1 thorpej * update it, otherwise create a new one. 2263 1.1 thorpej */ 2264 1.193 ozaki s = pserialize_read_enter(); 2265 1.97 ozaki brt = bridge_rtnode_lookup(sc, dst); 2266 1.1 thorpej 2267 1.97 ozaki if (brt != NULL) { 2268 1.97 ozaki brt->brt_ifp = dst_if; 2269 1.97 ozaki if (setflags) { 2270 1.97 ozaki brt->brt_flags = flags; 2271 1.97 ozaki if (flags & IFBAF_STATIC) 2272 1.97 ozaki brt->brt_expire = 0; 2273 1.97 ozaki else 2274 1.97 ozaki brt->brt_expire = time_uptime + sc->sc_brttimeout; 2275 1.97 ozaki } else { 2276 1.97 ozaki if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) 2277 1.97 ozaki brt->brt_expire = time_uptime + sc->sc_brttimeout; 2278 1.87 ozaki } 2279 1.97 ozaki } 2280 1.193 ozaki pserialize_read_exit(s); 2281 1.1 thorpej 2282 1.97 ozaki if (brt == NULL) { 2283 1.97 ozaki int r; 2284 1.1 thorpej 2285 1.97 ozaki r = bridge_rtalloc(sc, dst, &brt); 2286 1.97 ozaki if (r != 0) 2287 1.97 ozaki return r; 2288 1.97 ozaki goto again; 2289 1.1 thorpej } 2290 1.1 thorpej 2291 1.97 ozaki return 0; 2292 1.1 thorpej } 2293 1.1 thorpej 2294 1.1 thorpej /* 2295 1.1 thorpej * bridge_rtlookup: 2296 1.1 thorpej * 2297 1.1 thorpej * Lookup the destination interface for an address. 2298 1.1 thorpej */ 2299 1.33 thorpej static struct ifnet * 2300 1.1 thorpej bridge_rtlookup(struct bridge_softc *sc, const uint8_t *addr) 2301 1.1 thorpej { 2302 1.1 thorpej struct bridge_rtnode *brt; 2303 1.87 ozaki struct ifnet *ifs = NULL; 2304 1.97 ozaki int s; 2305 1.87 ozaki 2306 1.193 ozaki s = pserialize_read_enter(); 2307 1.87 ozaki brt = bridge_rtnode_lookup(sc, addr); 2308 1.87 ozaki if (brt != NULL) 2309 1.87 ozaki ifs = brt->brt_ifp; 2310 1.193 ozaki pserialize_read_exit(s); 2311 1.97 ozaki 2312 1.97 ozaki return ifs; 2313 1.97 ozaki } 2314 1.97 ozaki 2315 1.97 ozaki typedef bool (*bridge_iterate_cb_t) 2316 1.97 ozaki (struct bridge_softc *, struct bridge_rtnode *, bool *, void *); 2317 1.97 ozaki 2318 1.97 ozaki /* 2319 1.97 ozaki * bridge_rtlist_iterate_remove: 2320 1.97 ozaki * 2321 1.97 ozaki * It iterates on sc->sc_rtlist and removes rtnodes of it which func 2322 1.97 ozaki * callback judges to remove. Removals of rtnodes are done in a manner 2323 1.97 ozaki * of pserialize. To this end, all kmem_* operations are placed out of 2324 1.97 ozaki * mutexes. 2325 1.97 ozaki */ 2326 1.97 ozaki static void 2327 1.97 ozaki bridge_rtlist_iterate_remove(struct bridge_softc *sc, bridge_iterate_cb_t func, void *arg) 2328 1.97 ozaki { 2329 1.152 ozaki struct bridge_rtnode *brt; 2330 1.97 ozaki struct bridge_rtnode **brt_list; 2331 1.97 ozaki int i, count; 2332 1.1 thorpej 2333 1.97 ozaki retry: 2334 1.97 ozaki count = sc->sc_brtcnt; 2335 1.97 ozaki if (count == 0) 2336 1.97 ozaki return; 2337 1.104 maxv brt_list = kmem_alloc(sizeof(*brt_list) * count, KM_SLEEP); 2338 1.97 ozaki 2339 1.97 ozaki BRIDGE_RT_LOCK(sc); 2340 1.97 ozaki if (__predict_false(sc->sc_brtcnt > count)) { 2341 1.97 ozaki /* The rtnodes increased, we need more memory */ 2342 1.97 ozaki BRIDGE_RT_UNLOCK(sc); 2343 1.97 ozaki kmem_free(brt_list, sizeof(*brt_list) * count); 2344 1.97 ozaki goto retry; 2345 1.97 ozaki } 2346 1.97 ozaki 2347 1.97 ozaki i = 0; 2348 1.152 ozaki /* 2349 1.152 ozaki * We don't need to use a _SAFE variant here because we know 2350 1.152 ozaki * that a removed item keeps its next pointer as-is thanks to 2351 1.152 ozaki * pslist(9) and isn't freed in the loop. 2352 1.152 ozaki */ 2353 1.152 ozaki BRIDGE_RTLIST_WRITER_FOREACH(brt, sc) { 2354 1.97 ozaki bool need_break = false; 2355 1.97 ozaki if (func(sc, brt, &need_break, arg)) { 2356 1.97 ozaki bridge_rtnode_remove(sc, brt); 2357 1.97 ozaki brt_list[i++] = brt; 2358 1.97 ozaki } 2359 1.97 ozaki if (need_break) 2360 1.97 ozaki break; 2361 1.97 ozaki } 2362 1.97 ozaki 2363 1.97 ozaki if (i > 0) 2364 1.97 ozaki BRIDGE_RT_PSZ_PERFORM(sc); 2365 1.97 ozaki BRIDGE_RT_UNLOCK(sc); 2366 1.97 ozaki 2367 1.97 ozaki while (--i >= 0) 2368 1.97 ozaki bridge_rtnode_destroy(brt_list[i]); 2369 1.97 ozaki 2370 1.97 ozaki kmem_free(brt_list, sizeof(*brt_list) * count); 2371 1.97 ozaki } 2372 1.97 ozaki 2373 1.97 ozaki static bool 2374 1.97 ozaki bridge_rttrim0_cb(struct bridge_softc *sc, struct bridge_rtnode *brt, 2375 1.97 ozaki bool *need_break, void *arg) 2376 1.97 ozaki { 2377 1.97 ozaki if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { 2378 1.97 ozaki /* Take into account of the subsequent removal */ 2379 1.97 ozaki if ((sc->sc_brtcnt - 1) <= sc->sc_brtmax) 2380 1.97 ozaki *need_break = true; 2381 1.97 ozaki return true; 2382 1.97 ozaki } else 2383 1.97 ozaki return false; 2384 1.97 ozaki } 2385 1.1 thorpej 2386 1.97 ozaki static void 2387 1.97 ozaki bridge_rttrim0(struct bridge_softc *sc) 2388 1.97 ozaki { 2389 1.97 ozaki bridge_rtlist_iterate_remove(sc, bridge_rttrim0_cb, NULL); 2390 1.1 thorpej } 2391 1.1 thorpej 2392 1.1 thorpej /* 2393 1.1 thorpej * bridge_rttrim: 2394 1.1 thorpej * 2395 1.1 thorpej * Trim the routine table so that we have a number 2396 1.1 thorpej * of routing entries less than or equal to the 2397 1.1 thorpej * maximum number. 2398 1.1 thorpej */ 2399 1.33 thorpej static void 2400 1.1 thorpej bridge_rttrim(struct bridge_softc *sc) 2401 1.1 thorpej { 2402 1.87 ozaki 2403 1.1 thorpej /* Make sure we actually need to do this. */ 2404 1.1 thorpej if (sc->sc_brtcnt <= sc->sc_brtmax) 2405 1.97 ozaki return; 2406 1.1 thorpej 2407 1.1 thorpej /* Force an aging cycle; this might trim enough addresses. */ 2408 1.1 thorpej bridge_rtage(sc); 2409 1.1 thorpej if (sc->sc_brtcnt <= sc->sc_brtmax) 2410 1.97 ozaki return; 2411 1.1 thorpej 2412 1.97 ozaki bridge_rttrim0(sc); 2413 1.87 ozaki 2414 1.87 ozaki return; 2415 1.1 thorpej } 2416 1.1 thorpej 2417 1.1 thorpej /* 2418 1.1 thorpej * bridge_timer: 2419 1.1 thorpej * 2420 1.1 thorpej * Aging timer for the bridge. 2421 1.1 thorpej */ 2422 1.33 thorpej static void 2423 1.1 thorpej bridge_timer(void *arg) 2424 1.1 thorpej { 2425 1.1 thorpej struct bridge_softc *sc = arg; 2426 1.1 thorpej 2427 1.107 ozaki workqueue_enqueue(sc->sc_rtage_wq, &sc->sc_rtage_wk, NULL); 2428 1.97 ozaki } 2429 1.97 ozaki 2430 1.97 ozaki static void 2431 1.97 ozaki bridge_rtage_work(struct work *wk, void *arg) 2432 1.97 ozaki { 2433 1.97 ozaki struct bridge_softc *sc = arg; 2434 1.97 ozaki 2435 1.107 ozaki KASSERT(wk == &sc->sc_rtage_wk); 2436 1.87 ozaki 2437 1.1 thorpej bridge_rtage(sc); 2438 1.1 thorpej 2439 1.199 ozaki BRIDGE_LOCK(sc); 2440 1.199 ozaki if (!sc->sc_stopping) { 2441 1.1 thorpej callout_reset(&sc->sc_brcallout, 2442 1.1 thorpej bridge_rtable_prune_period * hz, bridge_timer, sc); 2443 1.199 ozaki } 2444 1.199 ozaki BRIDGE_UNLOCK(sc); 2445 1.97 ozaki } 2446 1.87 ozaki 2447 1.97 ozaki static bool 2448 1.97 ozaki bridge_rtage_cb(struct bridge_softc *sc, struct bridge_rtnode *brt, 2449 1.97 ozaki bool *need_break, void *arg) 2450 1.97 ozaki { 2451 1.97 ozaki if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && 2452 1.97 ozaki time_uptime >= brt->brt_expire) 2453 1.97 ozaki return true; 2454 1.97 ozaki else 2455 1.97 ozaki return false; 2456 1.1 thorpej } 2457 1.1 thorpej 2458 1.1 thorpej /* 2459 1.1 thorpej * bridge_rtage: 2460 1.1 thorpej * 2461 1.1 thorpej * Perform an aging cycle. 2462 1.1 thorpej */ 2463 1.33 thorpej static void 2464 1.1 thorpej bridge_rtage(struct bridge_softc *sc) 2465 1.1 thorpej { 2466 1.97 ozaki bridge_rtlist_iterate_remove(sc, bridge_rtage_cb, NULL); 2467 1.97 ozaki } 2468 1.97 ozaki 2469 1.1 thorpej 2470 1.97 ozaki static bool 2471 1.97 ozaki bridge_rtflush_cb(struct bridge_softc *sc, struct bridge_rtnode *brt, 2472 1.97 ozaki bool *need_break, void *arg) 2473 1.97 ozaki { 2474 1.97 ozaki int full = *(int*)arg; 2475 1.87 ozaki 2476 1.97 ozaki if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) 2477 1.97 ozaki return true; 2478 1.97 ozaki else 2479 1.97 ozaki return false; 2480 1.1 thorpej } 2481 1.1 thorpej 2482 1.1 thorpej /* 2483 1.1 thorpej * bridge_rtflush: 2484 1.1 thorpej * 2485 1.1 thorpej * Remove all dynamic addresses from the bridge. 2486 1.1 thorpej */ 2487 1.33 thorpej static void 2488 1.1 thorpej bridge_rtflush(struct bridge_softc *sc, int full) 2489 1.1 thorpej { 2490 1.97 ozaki bridge_rtlist_iterate_remove(sc, bridge_rtflush_cb, &full); 2491 1.1 thorpej } 2492 1.1 thorpej 2493 1.1 thorpej /* 2494 1.1 thorpej * bridge_rtdaddr: 2495 1.1 thorpej * 2496 1.1 thorpej * Remove an address from the table. 2497 1.1 thorpej */ 2498 1.33 thorpej static int 2499 1.1 thorpej bridge_rtdaddr(struct bridge_softc *sc, const uint8_t *addr) 2500 1.1 thorpej { 2501 1.1 thorpej struct bridge_rtnode *brt; 2502 1.1 thorpej 2503 1.97 ozaki BRIDGE_RT_LOCK(sc); 2504 1.87 ozaki if ((brt = bridge_rtnode_lookup(sc, addr)) == NULL) { 2505 1.97 ozaki BRIDGE_RT_UNLOCK(sc); 2506 1.97 ozaki return ENOENT; 2507 1.87 ozaki } 2508 1.97 ozaki bridge_rtnode_remove(sc, brt); 2509 1.97 ozaki BRIDGE_RT_PSZ_PERFORM(sc); 2510 1.97 ozaki BRIDGE_RT_UNLOCK(sc); 2511 1.1 thorpej 2512 1.97 ozaki bridge_rtnode_destroy(brt); 2513 1.87 ozaki 2514 1.97 ozaki return 0; 2515 1.1 thorpej } 2516 1.1 thorpej 2517 1.1 thorpej /* 2518 1.1 thorpej * bridge_rtdelete: 2519 1.1 thorpej * 2520 1.1 thorpej * Delete routes to a speicifc member interface. 2521 1.1 thorpej */ 2522 1.33 thorpej static void 2523 1.1 thorpej bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp) 2524 1.1 thorpej { 2525 1.110 ozaki struct bridge_rtnode *brt; 2526 1.1 thorpej 2527 1.149 ozaki /* XXX pserialize_perform for each entry is slow */ 2528 1.149 ozaki again: 2529 1.97 ozaki BRIDGE_RT_LOCK(sc); 2530 1.152 ozaki BRIDGE_RTLIST_WRITER_FOREACH(brt, sc) { 2531 1.1 thorpej if (brt->brt_ifp == ifp) 2532 1.97 ozaki break; 2533 1.1 thorpej } 2534 1.97 ozaki if (brt == NULL) { 2535 1.97 ozaki BRIDGE_RT_UNLOCK(sc); 2536 1.97 ozaki return; 2537 1.97 ozaki } 2538 1.97 ozaki bridge_rtnode_remove(sc, brt); 2539 1.97 ozaki BRIDGE_RT_PSZ_PERFORM(sc); 2540 1.97 ozaki BRIDGE_RT_UNLOCK(sc); 2541 1.87 ozaki 2542 1.97 ozaki bridge_rtnode_destroy(brt); 2543 1.149 ozaki 2544 1.149 ozaki goto again; 2545 1.1 thorpej } 2546 1.1 thorpej 2547 1.1 thorpej /* 2548 1.1 thorpej * bridge_rtable_init: 2549 1.1 thorpej * 2550 1.1 thorpej * Initialize the route table for this bridge. 2551 1.1 thorpej */ 2552 1.93 ozaki static void 2553 1.1 thorpej bridge_rtable_init(struct bridge_softc *sc) 2554 1.1 thorpej { 2555 1.1 thorpej int i; 2556 1.1 thorpej 2557 1.93 ozaki sc->sc_rthash = kmem_alloc(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE, 2558 1.93 ozaki KM_SLEEP); 2559 1.1 thorpej 2560 1.1 thorpej for (i = 0; i < BRIDGE_RTHASH_SIZE; i++) 2561 1.152 ozaki PSLIST_INIT(&sc->sc_rthash[i]); 2562 1.1 thorpej 2563 1.74 tls sc->sc_rthash_key = cprng_fast32(); 2564 1.1 thorpej 2565 1.152 ozaki PSLIST_INIT(&sc->sc_rtlist); 2566 1.1 thorpej 2567 1.97 ozaki sc->sc_rtlist_psz = pserialize_create(); 2568 1.97 ozaki sc->sc_rtlist_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET); 2569 1.1 thorpej } 2570 1.1 thorpej 2571 1.1 thorpej /* 2572 1.1 thorpej * bridge_rtable_fini: 2573 1.1 thorpej * 2574 1.1 thorpej * Deconstruct the route table for this bridge. 2575 1.1 thorpej */ 2576 1.33 thorpej static void 2577 1.1 thorpej bridge_rtable_fini(struct bridge_softc *sc) 2578 1.1 thorpej { 2579 1.1 thorpej 2580 1.93 ozaki kmem_free(sc->sc_rthash, sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE); 2581 1.150 ozaki mutex_obj_free(sc->sc_rtlist_lock); 2582 1.150 ozaki pserialize_destroy(sc->sc_rtlist_psz); 2583 1.1 thorpej } 2584 1.1 thorpej 2585 1.1 thorpej /* 2586 1.1 thorpej * The following hash function is adapted from "Hash Functions" by Bob Jenkins 2587 1.1 thorpej * ("Algorithm Alley", Dr. Dobbs Journal, September 1997). 2588 1.1 thorpej */ 2589 1.1 thorpej #define mix(a, b, c) \ 2590 1.1 thorpej do { \ 2591 1.1 thorpej a -= b; a -= c; a ^= (c >> 13); \ 2592 1.1 thorpej b -= c; b -= a; b ^= (a << 8); \ 2593 1.1 thorpej c -= a; c -= b; c ^= (b >> 13); \ 2594 1.1 thorpej a -= b; a -= c; a ^= (c >> 12); \ 2595 1.1 thorpej b -= c; b -= a; b ^= (a << 16); \ 2596 1.1 thorpej c -= a; c -= b; c ^= (b >> 5); \ 2597 1.1 thorpej a -= b; a -= c; a ^= (c >> 3); \ 2598 1.1 thorpej b -= c; b -= a; b ^= (a << 10); \ 2599 1.1 thorpej c -= a; c -= b; c ^= (b >> 15); \ 2600 1.1 thorpej } while (/*CONSTCOND*/0) 2601 1.1 thorpej 2602 1.34 perry static inline uint32_t 2603 1.1 thorpej bridge_rthash(struct bridge_softc *sc, const uint8_t *addr) 2604 1.1 thorpej { 2605 1.1 thorpej uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_rthash_key; 2606 1.1 thorpej 2607 1.1 thorpej b += addr[5] << 8; 2608 1.1 thorpej b += addr[4]; 2609 1.165 msaitoh a += (uint32_t)addr[3] << 24; 2610 1.1 thorpej a += addr[2] << 16; 2611 1.1 thorpej a += addr[1] << 8; 2612 1.1 thorpej a += addr[0]; 2613 1.1 thorpej 2614 1.1 thorpej mix(a, b, c); 2615 1.1 thorpej 2616 1.1 thorpej return (c & BRIDGE_RTHASH_MASK); 2617 1.1 thorpej } 2618 1.1 thorpej 2619 1.1 thorpej #undef mix 2620 1.1 thorpej 2621 1.1 thorpej /* 2622 1.1 thorpej * bridge_rtnode_lookup: 2623 1.1 thorpej * 2624 1.1 thorpej * Look up a bridge route node for the specified destination. 2625 1.1 thorpej */ 2626 1.33 thorpej static struct bridge_rtnode * 2627 1.1 thorpej bridge_rtnode_lookup(struct bridge_softc *sc, const uint8_t *addr) 2628 1.1 thorpej { 2629 1.1 thorpej struct bridge_rtnode *brt; 2630 1.1 thorpej uint32_t hash; 2631 1.1 thorpej int dir; 2632 1.1 thorpej 2633 1.1 thorpej hash = bridge_rthash(sc, addr); 2634 1.152 ozaki BRIDGE_RTHASH_READER_FOREACH(brt, sc, hash) { 2635 1.1 thorpej dir = memcmp(addr, brt->brt_addr, ETHER_ADDR_LEN); 2636 1.1 thorpej if (dir == 0) 2637 1.136 msaitoh return brt; 2638 1.1 thorpej if (dir > 0) 2639 1.136 msaitoh return NULL; 2640 1.1 thorpej } 2641 1.1 thorpej 2642 1.136 msaitoh return NULL; 2643 1.1 thorpej } 2644 1.1 thorpej 2645 1.1 thorpej /* 2646 1.1 thorpej * bridge_rtnode_insert: 2647 1.1 thorpej * 2648 1.1 thorpej * Insert the specified bridge node into the route table. We 2649 1.1 thorpej * assume the entry is not already in the table. 2650 1.1 thorpej */ 2651 1.33 thorpej static int 2652 1.1 thorpej bridge_rtnode_insert(struct bridge_softc *sc, struct bridge_rtnode *brt) 2653 1.1 thorpej { 2654 1.151 ozaki struct bridge_rtnode *lbrt, *prev = NULL; 2655 1.1 thorpej uint32_t hash; 2656 1.1 thorpej 2657 1.108 ozaki KASSERT(BRIDGE_RT_LOCKED(sc)); 2658 1.87 ozaki 2659 1.1 thorpej hash = bridge_rthash(sc, brt->brt_addr); 2660 1.152 ozaki BRIDGE_RTHASH_WRITER_FOREACH(lbrt, sc, hash) { 2661 1.151 ozaki int dir = memcmp(brt->brt_addr, lbrt->brt_addr, ETHER_ADDR_LEN); 2662 1.1 thorpej if (dir == 0) 2663 1.136 msaitoh return EEXIST; 2664 1.151 ozaki if (dir > 0) 2665 1.151 ozaki break; 2666 1.151 ozaki prev = lbrt; 2667 1.151 ozaki } 2668 1.151 ozaki if (prev == NULL) 2669 1.152 ozaki BRIDGE_RTHASH_WRITER_INSERT_HEAD(sc, hash, brt); 2670 1.151 ozaki else 2671 1.152 ozaki BRIDGE_RTHASH_WRITER_INSERT_AFTER(prev, brt); 2672 1.1 thorpej 2673 1.152 ozaki BRIDGE_RTLIST_WRITER_INSERT_HEAD(sc, brt); 2674 1.1 thorpej sc->sc_brtcnt++; 2675 1.1 thorpej 2676 1.136 msaitoh return 0; 2677 1.1 thorpej } 2678 1.1 thorpej 2679 1.1 thorpej /* 2680 1.97 ozaki * bridge_rtnode_remove: 2681 1.1 thorpej * 2682 1.97 ozaki * Remove a bridge rtnode from the rthash and the rtlist of a bridge. 2683 1.1 thorpej */ 2684 1.33 thorpej static void 2685 1.97 ozaki bridge_rtnode_remove(struct bridge_softc *sc, struct bridge_rtnode *brt) 2686 1.1 thorpej { 2687 1.87 ozaki 2688 1.108 ozaki KASSERT(BRIDGE_RT_LOCKED(sc)); 2689 1.1 thorpej 2690 1.152 ozaki BRIDGE_RTHASH_WRITER_REMOVE(brt); 2691 1.152 ozaki BRIDGE_RTLIST_WRITER_REMOVE(brt); 2692 1.1 thorpej sc->sc_brtcnt--; 2693 1.97 ozaki } 2694 1.97 ozaki 2695 1.97 ozaki /* 2696 1.97 ozaki * bridge_rtnode_destroy: 2697 1.97 ozaki * 2698 1.97 ozaki * Destroy a bridge rtnode. 2699 1.97 ozaki */ 2700 1.97 ozaki static void 2701 1.97 ozaki bridge_rtnode_destroy(struct bridge_rtnode *brt) 2702 1.97 ozaki { 2703 1.97 ozaki 2704 1.154 ozaki PSLIST_ENTRY_DESTROY(brt, brt_list); 2705 1.154 ozaki PSLIST_ENTRY_DESTROY(brt, brt_hash); 2706 1.1 thorpej pool_put(&bridge_rtnode_pool, brt); 2707 1.1 thorpej } 2708 1.9 perseant 2709 1.77 rmind extern pfil_head_t *inet_pfil_hook; /* XXX */ 2710 1.77 rmind extern pfil_head_t *inet6_pfil_hook; /* XXX */ 2711 1.9 perseant 2712 1.9 perseant /* 2713 1.9 perseant * Send bridge packets through IPF if they are one of the types IPF can deal 2714 1.9 perseant * with, or if they are ARP or REVARP. (IPF will pass ARP and REVARP without 2715 1.9 perseant * question.) 2716 1.9 perseant */ 2717 1.33 thorpej static int 2718 1.45 christos bridge_ipf(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 2719 1.9 perseant { 2720 1.22 jdc int snap, error; 2721 1.22 jdc struct ether_header *eh1, eh2; 2722 1.31 jdc struct llc llc1; 2723 1.56 matt uint16_t ether_type; 2724 1.9 perseant 2725 1.9 perseant snap = 0; 2726 1.22 jdc error = -1; /* Default error if not error == 0 */ 2727 1.22 jdc eh1 = mtod(*mp, struct ether_header *); 2728 1.22 jdc ether_type = ntohs(eh1->ether_type); 2729 1.9 perseant 2730 1.9 perseant /* 2731 1.9 perseant * Check for SNAP/LLC. 2732 1.9 perseant */ 2733 1.130 ozaki if (ether_type < ETHERMTU) { 2734 1.130 ozaki struct llc *llc2 = (struct llc *)(eh1 + 1); 2735 1.29 perry 2736 1.130 ozaki if ((*mp)->m_len >= ETHER_HDR_LEN + 8 && 2737 1.130 ozaki llc2->llc_dsap == LLC_SNAP_LSAP && 2738 1.130 ozaki llc2->llc_ssap == LLC_SNAP_LSAP && 2739 1.130 ozaki llc2->llc_control == LLC_UI) { 2740 1.130 ozaki ether_type = htons(llc2->llc_un.type_snap.ether_type); 2741 1.9 perseant snap = 1; 2742 1.130 ozaki } 2743 1.130 ozaki } 2744 1.9 perseant 2745 1.187 yamaguch /* drop VLAN traffic untagged by hardware offloading */ 2746 1.187 yamaguch if (vlan_has_tag(*mp)) 2747 1.187 yamaguch goto bad; 2748 1.187 yamaguch 2749 1.9 perseant /* 2750 1.9 perseant * If we're trying to filter bridge traffic, don't look at anything 2751 1.9 perseant * other than IP and ARP traffic. If the filter doesn't understand 2752 1.9 perseant * IPv6, don't allow IPv6 through the bridge either. This is lame 2753 1.9 perseant * since if we really wanted, say, an AppleTalk filter, we are hosed, 2754 1.9 perseant * but of course we don't have an AppleTalk filter to begin with. 2755 1.9 perseant * (Note that since IPF doesn't understand ARP it will pass *ALL* 2756 1.9 perseant * ARP traffic.) 2757 1.9 perseant */ 2758 1.9 perseant switch (ether_type) { 2759 1.9 perseant case ETHERTYPE_ARP: 2760 1.9 perseant case ETHERTYPE_REVARP: 2761 1.9 perseant return 0; /* Automatically pass */ 2762 1.9 perseant case ETHERTYPE_IP: 2763 1.9 perseant # ifdef INET6 2764 1.9 perseant case ETHERTYPE_IPV6: 2765 1.9 perseant # endif /* INET6 */ 2766 1.9 perseant break; 2767 1.9 perseant default: 2768 1.9 perseant goto bad; 2769 1.9 perseant } 2770 1.9 perseant 2771 1.22 jdc /* Strip off the Ethernet header and keep a copy. */ 2772 1.50 christos m_copydata(*mp, 0, ETHER_HDR_LEN, (void *) &eh2); 2773 1.22 jdc m_adj(*mp, ETHER_HDR_LEN); 2774 1.22 jdc 2775 1.9 perseant /* Strip off snap header, if present */ 2776 1.9 perseant if (snap) { 2777 1.50 christos m_copydata(*mp, 0, sizeof(struct llc), (void *) &llc1); 2778 1.22 jdc m_adj(*mp, sizeof(struct llc)); 2779 1.19 christos } 2780 1.9 perseant 2781 1.9 perseant /* 2782 1.22 jdc * Check basic packet sanity and run IPF through pfil. 2783 1.9 perseant */ 2784 1.65 bouyer KASSERT(!cpu_intr_p()); 2785 1.22 jdc switch (ether_type) 2786 1.22 jdc { 2787 1.22 jdc case ETHERTYPE_IP : 2788 1.131 christos error = bridge_ip_checkbasic(mp); 2789 1.22 jdc if (error == 0) 2790 1.77 rmind error = pfil_run_hooks(inet_pfil_hook, mp, ifp, dir); 2791 1.22 jdc break; 2792 1.9 perseant # ifdef INET6 2793 1.22 jdc case ETHERTYPE_IPV6 : 2794 1.131 christos error = bridge_ip6_checkbasic(mp); 2795 1.22 jdc if (error == 0) 2796 1.77 rmind error = pfil_run_hooks(inet6_pfil_hook, mp, ifp, dir); 2797 1.22 jdc break; 2798 1.22 jdc # endif 2799 1.22 jdc default : 2800 1.22 jdc error = 0; 2801 1.22 jdc break; 2802 1.9 perseant } 2803 1.22 jdc 2804 1.22 jdc if (*mp == NULL) 2805 1.22 jdc return error; 2806 1.22 jdc if (error != 0) 2807 1.22 jdc goto bad; 2808 1.22 jdc 2809 1.22 jdc error = -1; 2810 1.9 perseant 2811 1.9 perseant /* 2812 1.9 perseant * Finally, put everything back the way it was and return 2813 1.9 perseant */ 2814 1.18 jdc if (snap) { 2815 1.22 jdc M_PREPEND(*mp, sizeof(struct llc), M_DONTWAIT); 2816 1.22 jdc if (*mp == NULL) 2817 1.22 jdc return error; 2818 1.50 christos bcopy(&llc1, mtod(*mp, void *), sizeof(struct llc)); 2819 1.18 jdc } 2820 1.18 jdc 2821 1.22 jdc M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT); 2822 1.22 jdc if (*mp == NULL) 2823 1.22 jdc return error; 2824 1.50 christos bcopy(&eh2, mtod(*mp, void *), ETHER_HDR_LEN); 2825 1.22 jdc 2826 1.9 perseant return 0; 2827 1.9 perseant 2828 1.9 perseant bad: 2829 1.9 perseant m_freem(*mp); 2830 1.9 perseant *mp = NULL; 2831 1.9 perseant return error; 2832 1.9 perseant } 2833 1.9 perseant 2834 1.9 perseant /* 2835 1.9 perseant * Perform basic checks on header size since 2836 1.9 perseant * IPF assumes ip_input has already processed 2837 1.9 perseant * it for it. Cut-and-pasted from ip_input.c. 2838 1.9 perseant * Given how simple the IPv6 version is, 2839 1.9 perseant * does the IPv4 version really need to be 2840 1.9 perseant * this complicated? 2841 1.9 perseant * 2842 1.9 perseant * XXX Should we update ipstat here, or not? 2843 1.9 perseant * XXX Right now we update ipstat but not 2844 1.9 perseant * XXX csum_counter. 2845 1.9 perseant */ 2846 1.9 perseant static int 2847 1.9 perseant bridge_ip_checkbasic(struct mbuf **mp) 2848 1.9 perseant { 2849 1.9 perseant struct mbuf *m = *mp; 2850 1.9 perseant struct ip *ip; 2851 1.9 perseant int len, hlen; 2852 1.9 perseant 2853 1.9 perseant if (*mp == NULL) 2854 1.9 perseant return -1; 2855 1.9 perseant 2856 1.179 christos if (M_GET_ALIGNED_HDR(&m, struct ip, true) != 0) { 2857 1.178 christos /* XXXJRT new stat, please */ 2858 1.178 christos ip_statinc(IP_STAT_TOOSMALL); 2859 1.178 christos goto bad; 2860 1.9 perseant } 2861 1.9 perseant ip = mtod(m, struct ip *); 2862 1.9 perseant if (ip == NULL) goto bad; 2863 1.9 perseant 2864 1.9 perseant if (ip->ip_v != IPVERSION) { 2865 1.59 thorpej ip_statinc(IP_STAT_BADVERS); 2866 1.9 perseant goto bad; 2867 1.9 perseant } 2868 1.9 perseant hlen = ip->ip_hl << 2; 2869 1.9 perseant if (hlen < sizeof(struct ip)) { /* minimum header length */ 2870 1.59 thorpej ip_statinc(IP_STAT_BADHLEN); 2871 1.9 perseant goto bad; 2872 1.9 perseant } 2873 1.9 perseant if (hlen > m->m_len) { 2874 1.9 perseant if ((m = m_pullup(m, hlen)) == 0) { 2875 1.59 thorpej ip_statinc(IP_STAT_BADHLEN); 2876 1.9 perseant goto bad; 2877 1.9 perseant } 2878 1.9 perseant ip = mtod(m, struct ip *); 2879 1.9 perseant if (ip == NULL) goto bad; 2880 1.9 perseant } 2881 1.9 perseant 2882 1.130 ozaki switch (m->m_pkthdr.csum_flags & 2883 1.130 ozaki ((m_get_rcvif_NOMPSAFE(m)->if_csum_flags_rx & M_CSUM_IPv4) | 2884 1.130 ozaki M_CSUM_IPv4_BAD)) { 2885 1.130 ozaki case M_CSUM_IPv4|M_CSUM_IPv4_BAD: 2886 1.130 ozaki /* INET_CSUM_COUNTER_INCR(&ip_hwcsum_bad); */ 2887 1.130 ozaki goto bad; 2888 1.130 ozaki 2889 1.130 ozaki case M_CSUM_IPv4: 2890 1.130 ozaki /* Checksum was okay. */ 2891 1.130 ozaki /* INET_CSUM_COUNTER_INCR(&ip_hwcsum_ok); */ 2892 1.130 ozaki break; 2893 1.130 ozaki 2894 1.130 ozaki default: 2895 1.130 ozaki /* Must compute it ourselves. */ 2896 1.130 ozaki /* INET_CSUM_COUNTER_INCR(&ip_swcsum); */ 2897 1.130 ozaki if (in_cksum(m, hlen) != 0) 2898 1.130 ozaki goto bad; 2899 1.130 ozaki break; 2900 1.130 ozaki } 2901 1.130 ozaki 2902 1.130 ozaki /* Retrieve the packet length. */ 2903 1.130 ozaki len = ntohs(ip->ip_len); 2904 1.130 ozaki 2905 1.130 ozaki /* 2906 1.130 ozaki * Check for additional length bogosity 2907 1.130 ozaki */ 2908 1.130 ozaki if (len < hlen) { 2909 1.59 thorpej ip_statinc(IP_STAT_BADLEN); 2910 1.130 ozaki goto bad; 2911 1.130 ozaki } 2912 1.9 perseant 2913 1.130 ozaki /* 2914 1.130 ozaki * Check that the amount of data in the buffers 2915 1.130 ozaki * is as at least much as the IP header would have us expect. 2916 1.130 ozaki * Drop packet if shorter than we expect. 2917 1.130 ozaki */ 2918 1.130 ozaki if (m->m_pkthdr.len < len) { 2919 1.59 thorpej ip_statinc(IP_STAT_TOOSHORT); 2920 1.130 ozaki goto bad; 2921 1.130 ozaki } 2922 1.9 perseant 2923 1.9 perseant /* Checks out, proceed */ 2924 1.9 perseant *mp = m; 2925 1.9 perseant return 0; 2926 1.9 perseant 2927 1.9 perseant bad: 2928 1.9 perseant *mp = m; 2929 1.9 perseant return -1; 2930 1.9 perseant } 2931 1.9 perseant 2932 1.9 perseant # ifdef INET6 2933 1.9 perseant /* 2934 1.9 perseant * Same as above, but for IPv6. 2935 1.9 perseant * Cut-and-pasted from ip6_input.c. 2936 1.9 perseant * XXX Should we update ip6stat, or not? 2937 1.9 perseant */ 2938 1.9 perseant static int 2939 1.9 perseant bridge_ip6_checkbasic(struct mbuf **mp) 2940 1.9 perseant { 2941 1.9 perseant struct mbuf *m = *mp; 2942 1.16 jdc struct ip6_hdr *ip6; 2943 1.9 perseant 2944 1.130 ozaki /* 2945 1.130 ozaki * If the IPv6 header is not aligned, slurp it up into a new 2946 1.130 ozaki * mbuf with space for link headers, in the event we forward 2947 1.130 ozaki * it. Otherwise, if it is aligned, make sure the entire base 2948 1.130 ozaki * IPv6 header is in the first mbuf of the chain. 2949 1.130 ozaki */ 2950 1.179 christos if (M_GET_ALIGNED_HDR(&m, struct ip6_hdr, true) != 0) { 2951 1.130 ozaki struct ifnet *inifp = m_get_rcvif_NOMPSAFE(m); 2952 1.178 christos /* XXXJRT new stat, please */ 2953 1.178 christos ip6_statinc(IP6_STAT_TOOSMALL); 2954 1.178 christos in6_ifstat_inc(inifp, ifs6_in_hdrerr); 2955 1.178 christos goto bad; 2956 1.130 ozaki } 2957 1.9 perseant 2958 1.130 ozaki ip6 = mtod(m, struct ip6_hdr *); 2959 1.9 perseant 2960 1.130 ozaki if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { 2961 1.61 thorpej ip6_statinc(IP6_STAT_BADVERS); 2962 1.130 ozaki in6_ifstat_inc(m_get_rcvif_NOMPSAFE(m), ifs6_in_hdrerr); 2963 1.130 ozaki goto bad; 2964 1.130 ozaki } 2965 1.9 perseant 2966 1.9 perseant /* Checks out, proceed */ 2967 1.9 perseant *mp = m; 2968 1.9 perseant return 0; 2969 1.9 perseant 2970 1.9 perseant bad: 2971 1.9 perseant *mp = m; 2972 1.9 perseant return -1; 2973 1.9 perseant } 2974 1.9 perseant # endif /* INET6 */ 2975