2 * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 /* $NetBSD: if_bridge.c,v 1.31 2005/06/01 19:45:34 jdc Exp $ */
31 * Copyright 2001 Wasabi Systems, Inc.
32 * All rights reserved.
34 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed for the NetBSD Project by
47 * Wasabi Systems, Inc.
48 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
49 * or promote products derived from this software without specific prior
52 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
54 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
55 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
56 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
57 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
58 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
59 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
60 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
61 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
62 * POSSIBILITY OF SUCH DAMAGE.
66 * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
67 * All rights reserved.
69 * Redistribution and use in source and binary forms, with or without
70 * modification, are permitted provided that the following conditions
72 * 1. Redistributions of source code must retain the above copyright
73 * notice, this list of conditions and the following disclaimer.
74 * 2. Redistributions in binary form must reproduce the above copyright
75 * notice, this list of conditions and the following disclaimer in the
76 * documentation and/or other materials provided with the distribution.
78 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
79 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
80 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
81 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
82 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
83 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
84 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
85 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
86 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
87 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
88 * POSSIBILITY OF SUCH DAMAGE.
90 * OpenBSD: if_bridge.c,v 1.60 2001/06/15 03:38:33 itojun Exp
94 * Network interface bridge support.
98 * - Currently only supports Ethernet-like interfaces (Ethernet,
99 * 802.11, VLANs on Ethernet, etc.) Figure out a nice way
100 * to bridge other types of interfaces (FDDI-FDDI, and maybe
101 * consider heterogenous bridges).
104 #include <sys/cdefs.h>
106 #define BRIDGE_DEBUG 1
108 #define BRIDGE_DEBUG 0
109 #endif /* BRIDGE_DEBUG */
111 #include <sys/param.h>
112 #include <sys/mbuf.h>
113 #include <sys/malloc.h>
114 #include <sys/protosw.h>
115 #include <sys/systm.h>
116 #include <sys/time.h>
117 #include <sys/socket.h> /* for net/if.h */
118 #include <sys/sockio.h>
119 #include <sys/kernel.h>
120 #include <sys/random.h>
121 #include <sys/syslog.h>
122 #include <sys/sysctl.h>
123 #include <sys/proc.h>
124 #include <sys/lock.h>
125 #include <sys/mcache.h>
127 #include <sys/kauth.h>
129 #include <libkern/libkern.h>
131 #include <kern/zalloc.h>
137 #include <net/if_dl.h>
138 #include <net/if_types.h>
139 #include <net/if_var.h>
141 #include <netinet/in.h> /* for struct arpcom */
142 #include <netinet/in_systm.h>
143 #include <netinet/in_var.h>
144 #include <netinet/ip.h>
145 #include <netinet/ip_var.h>
147 #include <netinet/ip6.h>
148 #include <netinet6/ip6_var.h>
151 #include <netinet/ip_carp.h>
153 #include <netinet/if_ether.h> /* for struct arpcom */
154 #include <net/bridgestp.h>
155 #include <net/if_bridgevar.h>
156 #include <net/if_llc.h>
158 #include <net/if_vlan_var.h>
159 #endif /* NVLAN > 0 */
161 #include <net/if_ether.h>
162 #include <net/dlil.h>
163 #include <net/kpi_interfacefilter.h>
165 #include <net/route.h>
167 #include <netinet/ip_fw2.h>
168 #include <netinet/ip_dummynet.h>
169 #endif /* PFIL_HOOKS */
173 #define BR_LCKDBG_MAX 4
175 #define BRIDGE_LOCK(_sc) bridge_lock(_sc)
176 #define BRIDGE_UNLOCK(_sc) bridge_unlock(_sc)
177 #define BRIDGE_LOCK_ASSERT(_sc) \
178 lck_mtx_assert((_sc)->sc_mtx, LCK_MTX_ASSERT_OWNED)
179 #define BRIDGE_LOCK2REF(_sc, _err) _err = bridge_lock2ref(_sc)
180 #define BRIDGE_UNREF(_sc) bridge_unref(_sc)
181 #define BRIDGE_XLOCK(_sc) bridge_xlock(_sc)
182 #define BRIDGE_XDROP(_sc) bridge_xdrop(_sc)
184 #else /* BRIDGE_DEBUG */
186 #define BRIDGE_LOCK(_sc) lck_mtx_lock((_sc)->sc_mtx)
187 #define BRIDGE_UNLOCK(_sc) lck_mtx_unlock((_sc)->sc_mtx)
188 #define BRIDGE_LOCK_ASSERT(_sc) \
189 lck_mtx_assert((_sc)->sc_mtx, LCK_MTX_ASSERT_OWNED)
190 #define BRIDGE_LOCK2REF(_sc, _err) do { \
191 lck_mtx_assert((_sc)->sc_mtx, LCK_MTX_ASSERT_OWNED); \
192 if ((_sc)->sc_iflist_xcnt > 0) \
195 (_sc)->sc_iflist_ref++; \
196 lck_mtx_unlock((_sc)->sc_mtx); \
198 #define BRIDGE_UNREF(_sc) do { \
199 lck_mtx_lock((_sc)->sc_mtx); \
200 (_sc)->sc_iflist_ref--; \
201 if (((_sc)->sc_iflist_xcnt > 0) && ((_sc)->sc_iflist_ref == 0)) { \
202 lck_mtx_unlock((_sc)->sc_mtx); \
203 wakeup(&(_sc)->sc_cv); \
205 lck_mtx_unlock((_sc)->sc_mtx); \
207 #define BRIDGE_XLOCK(_sc) do { \
208 lck_mtx_assert((_sc)->sc_mtx, LCK_MTX_ASSERT_OWNED); \
209 (_sc)->sc_iflist_xcnt++; \
210 while ((_sc)->sc_iflist_ref > 0) \
211 msleep(&(_sc)->sc_cv, (_sc)->sc_mtx, PZERO, \
212 "BRIDGE_XLOCK", NULL); \
214 #define BRIDGE_XDROP(_sc) do { \
215 lck_mtx_assert((_sc)->sc_mtx, LCK_MTX_ASSERT_OWNED); \
216 (_sc)->sc_iflist_xcnt--; \
219 #endif /* BRIDGE_DEBUG */
222 #define BRIDGE_BPF_MTAP_INPUT(sc, m) \
223 if (sc->sc_bpf_input) \
224 bridge_bpf_input(sc->sc_ifp, m)
225 #else /* NBPFILTER */
226 #define BRIDGE_BPF_MTAP_INPUT(ifp, m)
227 #endif /* NBPFILTER */
230 * Size of the route hash table. Must be a power of two.
232 /* APPLE MODIFICATION - per Wasabi performance improvement, change the hash table size */
234 #ifndef BRIDGE_RTHASH_SIZE
235 #define BRIDGE_RTHASH_SIZE 1024
238 #ifndef BRIDGE_RTHASH_SIZE
239 #define BRIDGE_RTHASH_SIZE 256
243 /* APPLE MODIFICATION - support for HW checksums */
244 #if APPLE_BRIDGE_HWCKSUM_SUPPORT
245 #include <netinet/udp.h>
246 #include <netinet/tcp.h>
249 #define BRIDGE_RTHASH_MASK (BRIDGE_RTHASH_SIZE - 1)
252 * Maximum number of addresses to cache.
254 #ifndef BRIDGE_RTABLE_MAX
255 #define BRIDGE_RTABLE_MAX 100
260 * Timeout (in seconds) for entries learned dynamically.
262 #ifndef BRIDGE_RTABLE_TIMEOUT
263 #define BRIDGE_RTABLE_TIMEOUT (20 * 60) /* same as ARP */
267 * Number of seconds between walks of the route list.
269 #ifndef BRIDGE_RTABLE_PRUNE_PERIOD
270 #define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60)
274 * List of capabilities to possibly mask on the member interface.
276 #define BRIDGE_IFCAPS_MASK (IFCAP_TOE|IFCAP_TSO|IFCAP_TXCSUM)
278 * List of capabilities to disable on the member interface.
280 #define BRIDGE_IFCAPS_STRIP IFCAP_LRO
283 * Bridge interface list entry.
285 struct bridge_iflist
{
286 TAILQ_ENTRY(bridge_iflist
) bif_next
;
287 struct ifnet
*bif_ifp
; /* member if */
288 struct bstp_port bif_stp
; /* STP state */
289 uint32_t bif_flags
; /* member if flags */
290 int bif_savedcaps
; /* saved capabilities */
291 uint32_t bif_addrmax
; /* max # of addresses */
292 uint32_t bif_addrcnt
; /* cur. # of addresses */
293 uint32_t bif_addrexceeded
;/* # of address violations */
295 interface_filter_t bif_iff_ref
;
296 struct bridge_softc
*bif_sc
;
297 char bif_promisc
; /* promiscuous mode set */
298 char bif_proto_attached
; /* protocol attached */
299 char bif_filter_attached
; /* interface filter attached */
305 struct bridge_rtnode
{
306 LIST_ENTRY(bridge_rtnode
) brt_hash
; /* hash table linkage */
307 LIST_ENTRY(bridge_rtnode
) brt_list
; /* list linkage */
308 struct bridge_iflist
*brt_dst
; /* destination if */
309 unsigned long brt_expire
; /* expiration time */
310 uint8_t brt_flags
; /* address flags */
311 uint8_t brt_addr
[ETHER_ADDR_LEN
];
312 uint16_t brt_vlan
; /* vlan id */
315 #define brt_ifp brt_dst->bif_ifp
318 * Software state for each bridge.
320 struct bridge_softc
{
321 struct ifnet
*sc_ifp
; /* make this an interface */
322 LIST_ENTRY(bridge_softc
) sc_list
;
325 uint32_t sc_brtmax
; /* max # of addresses */
326 uint32_t sc_brtcnt
; /* cur. # of addresses */
327 uint32_t sc_brttimeout
; /* rt timeout in seconds */
328 uint32_t sc_iflist_ref
; /* refcount for sc_iflist */
329 uint32_t sc_iflist_xcnt
; /* refcount for sc_iflist */
330 TAILQ_HEAD(, bridge_iflist
) sc_iflist
; /* member interface list */
331 LIST_HEAD(, bridge_rtnode
) *sc_rthash
; /* our forwarding table */
332 LIST_HEAD(, bridge_rtnode
) sc_rtlist
; /* list version of above */
333 uint32_t sc_rthash_key
; /* key for hash */
334 TAILQ_HEAD(, bridge_iflist
) sc_spanlist
; /* span ports list */
335 struct bstp_state sc_stp
; /* STP state */
336 uint32_t sc_brtexceeded
; /* # of cache drops */
337 uint32_t sc_filter_flags
; /* ipf and flags */
339 char sc_if_xname
[IFNAMSIZ
];
340 bpf_packet_func sc_bpf_input
;
341 bpf_packet_func sc_bpf_output
;
345 void *lock_lr
[BR_LCKDBG_MAX
]; /* locking calling history */
347 void *unlock_lr
[BR_LCKDBG_MAX
]; /* unlocking caller history */
349 #endif /* BRIDGE_DEBUG */
352 #define SCF_DETACHING 0x1
354 decl_lck_mtx_data(static, bridge_list_mtx_data
);
355 static lck_mtx_t
*bridge_list_mtx
= &bridge_list_mtx_data
;
357 int bridge_rtable_prune_period
= BRIDGE_RTABLE_PRUNE_PERIOD
;
359 static zone_t bridge_rtnode_pool
= NULL
;
361 static int bridge_clone_create(struct if_clone
*, uint32_t, void *);
362 static int bridge_clone_destroy(struct ifnet
*);
364 static errno_t
bridge_ioctl(struct ifnet
*, u_long
, void *);
366 static void bridge_mutecaps(struct bridge_softc
*);
367 static void bridge_set_ifcap(struct bridge_softc
*, struct bridge_iflist
*,
370 __private_extern__
void bridge_ifdetach(struct bridge_iflist
*, struct ifnet
*);
371 static int bridge_init(struct ifnet
*);
372 #if HAS_BRIDGE_DUMMYNET
373 static void bridge_dummynet(struct mbuf
*, struct ifnet
*);
375 static void bridge_ifstop(struct ifnet
*, int);
376 static int bridge_output(struct ifnet
*, struct mbuf
*);
377 static void bridge_start(struct ifnet
*);
378 __private_extern__ errno_t
bridge_input(struct ifnet
*, struct mbuf
*, void *);
379 #if BRIDGE_MEMBER_OUT_FILTER
380 static errno_t
bridge_iff_output(void *, ifnet_t
, protocol_family_t
,
382 static int bridge_member_output(struct ifnet
*, struct mbuf
*,
383 struct sockaddr
*, struct rtentry
*);
385 static int bridge_enqueue(struct bridge_softc
*, struct ifnet
*,
387 static void bridge_rtdelete(struct bridge_softc
*, struct ifnet
*ifp
, int);
389 static void bridge_forward(struct bridge_softc
*, struct bridge_iflist
*,
392 static void bridge_timer(void *);
394 static void bridge_broadcast(struct bridge_softc
*, struct ifnet
*,
396 static void bridge_span(struct bridge_softc
*, struct mbuf
*);
398 static int bridge_rtupdate(struct bridge_softc
*, const uint8_t *,
399 uint16_t, struct bridge_iflist
*, int, uint8_t);
400 static struct ifnet
*bridge_rtlookup(struct bridge_softc
*, const uint8_t *,
402 static void bridge_rttrim(struct bridge_softc
*);
403 static void bridge_rtage(struct bridge_softc
*);
404 static void bridge_rtflush(struct bridge_softc
*, int);
405 static int bridge_rtdaddr(struct bridge_softc
*, const uint8_t *,
408 static int bridge_rtable_init(struct bridge_softc
*);
409 static void bridge_rtable_fini(struct bridge_softc
*);
411 static int bridge_rtnode_addr_cmp(const uint8_t *, const uint8_t *);
412 static struct bridge_rtnode
*bridge_rtnode_lookup(struct bridge_softc
*,
413 const uint8_t *, uint16_t);
414 static int bridge_rtnode_insert(struct bridge_softc
*,
415 struct bridge_rtnode
*);
416 static void bridge_rtnode_destroy(struct bridge_softc
*,
417 struct bridge_rtnode
*);
419 static void bridge_rtable_expire(struct ifnet
*, int);
420 static void bridge_state_change(struct ifnet
*, int);
421 #endif /* BRIDGESTP */
423 static struct bridge_iflist
*bridge_lookup_member(struct bridge_softc
*,
425 static struct bridge_iflist
*bridge_lookup_member_if(struct bridge_softc
*,
427 static void bridge_delete_member(struct bridge_softc
*,
428 struct bridge_iflist
*, int);
429 static void bridge_delete_span(struct bridge_softc
*,
430 struct bridge_iflist
*);
432 static int bridge_ioctl_add(struct bridge_softc
*, void *);
433 static int bridge_ioctl_del(struct bridge_softc
*, void *);
434 static int bridge_ioctl_gifflags(struct bridge_softc
*, void *);
435 static int bridge_ioctl_sifflags(struct bridge_softc
*, void *);
436 static int bridge_ioctl_scache(struct bridge_softc
*, void *);
437 static int bridge_ioctl_gcache(struct bridge_softc
*, void *);
438 static int bridge_ioctl_gifs32(struct bridge_softc
*, void *);
439 static int bridge_ioctl_gifs64(struct bridge_softc
*, void *);
440 static int bridge_ioctl_rts32(struct bridge_softc
*, void *);
441 static int bridge_ioctl_rts64(struct bridge_softc
*, void *);
442 static int bridge_ioctl_saddr32(struct bridge_softc
*, void *);
443 static int bridge_ioctl_saddr64(struct bridge_softc
*, void *);
444 static int bridge_ioctl_sto(struct bridge_softc
*, void *);
445 static int bridge_ioctl_gto(struct bridge_softc
*, void *);
446 static int bridge_ioctl_daddr32(struct bridge_softc
*, void *);
447 static int bridge_ioctl_daddr64(struct bridge_softc
*, void *);
448 static int bridge_ioctl_flush(struct bridge_softc
*, void *);
449 static int bridge_ioctl_gpri(struct bridge_softc
*, void *);
450 static int bridge_ioctl_spri(struct bridge_softc
*, void *);
451 static int bridge_ioctl_ght(struct bridge_softc
*, void *);
452 static int bridge_ioctl_sht(struct bridge_softc
*, void *);
453 static int bridge_ioctl_gfd(struct bridge_softc
*, void *);
454 static int bridge_ioctl_sfd(struct bridge_softc
*, void *);
455 static int bridge_ioctl_gma(struct bridge_softc
*, void *);
456 static int bridge_ioctl_sma(struct bridge_softc
*, void *);
457 static int bridge_ioctl_sifprio(struct bridge_softc
*, void *);
458 static int bridge_ioctl_sifcost(struct bridge_softc
*, void *);
459 static int bridge_ioctl_sifmaxaddr(struct bridge_softc
*, void *);
460 static int bridge_ioctl_addspan(struct bridge_softc
*, void *);
461 static int bridge_ioctl_delspan(struct bridge_softc
*, void *);
462 static int bridge_ioctl_gbparam32(struct bridge_softc
*, void *);
463 static int bridge_ioctl_gbparam64(struct bridge_softc
*, void *);
464 static int bridge_ioctl_grte(struct bridge_softc
*, void *);
465 static int bridge_ioctl_gifsstp32(struct bridge_softc
*, void *);
466 static int bridge_ioctl_gifsstp64(struct bridge_softc
*, void *);
467 static int bridge_ioctl_sproto(struct bridge_softc
*, void *);
468 static int bridge_ioctl_stxhc(struct bridge_softc
*, void *);
469 static int bridge_ioctl_purge(struct bridge_softc
*sc
, void *arg
);
470 static int bridge_ioctl_gfilt(struct bridge_softc
*, void *);
471 static int bridge_ioctl_sfilt(struct bridge_softc
*, void *);
473 static int bridge_pfil(struct mbuf
**, struct ifnet
*, struct ifnet
*,
475 static int bridge_ip_checkbasic(struct mbuf
**mp
);
477 static int bridge_ip6_checkbasic(struct mbuf
**mp
);
479 static int bridge_fragment(struct ifnet
*, struct mbuf
*,
480 struct ether_header
*, int, struct llc
*);
481 #endif /* PFIL_HOOKS */
483 static errno_t
bridge_set_bpf_tap(ifnet_t ifn
, bpf_tap_mode mode
, bpf_packet_func bpf_callback
);
484 __private_extern__ errno_t
bridge_bpf_input(ifnet_t ifp
, struct mbuf
*m
);
485 __private_extern__ errno_t
bridge_bpf_output(ifnet_t ifp
, struct mbuf
*m
);
487 static void bridge_detach(ifnet_t ifp
);
489 #define m_copypacket(m, how) m_copym(m, 0, M_COPYALL, how)
491 /* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */
492 #define VLANTAGOF(_m) 0
494 u_int8_t bstp_etheraddr
[ETHER_ADDR_LEN
] =
495 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
498 static struct bstp_cb_ops bridge_ops
= {
499 .bcb_state
= bridge_state_change
,
500 .bcb_rtage
= bridge_rtable_expire
502 #endif /* BRIDGESTP */
504 SYSCTL_DECL(_net_link
);
505 SYSCTL_NODE(_net_link
, IFT_BRIDGE
, bridge
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
508 #if defined(PFIL_HOOKS)
509 static int pfil_onlyip
= 1; /* only pass IP[46] packets when pfil is enabled */
510 static int pfil_bridge
= 1; /* run pfil hooks on the bridge interface */
511 static int pfil_member
= 1; /* run pfil hooks on the member interface */
512 static int pfil_ipfw
= 0; /* layer2 filter with ipfw */
513 static int pfil_ipfw_arp
= 0; /* layer2 filter with ipfw */
514 static int pfil_local_phys
= 0; /* run pfil hooks on the physical interface for
515 locally destined packets */
516 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, pfil_onlyip
, CTLFLAG_RW
|CTLFLAG_LOCKED
,
517 &pfil_onlyip
, 0, "Only pass IP packets when pfil is enabled");
518 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, ipfw_arp
, CTLFLAG_RW
|CTLFLAG_LOCKED
,
519 &pfil_ipfw_arp
, 0, "Filter ARP packets through IPFW layer2");
520 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, pfil_bridge
, CTLFLAG_RW
|CTLFLAG_LOCKED
,
521 &pfil_bridge
, 0, "Packet filter on the bridge interface");
522 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, pfil_member
, CTLFLAG_RW
|CTLFLAG_LOCKED
,
523 &pfil_member
, 0, "Packet filter on the member interface");
524 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, pfil_local_phys
,
525 CTLFLAG_RW
|CTLFLAG_LOCKED
, &pfil_local_phys
, 0,
526 "Packet filter on the physical interface for locally destined packets");
527 #endif /* PFIL_HOOKS */
530 static int log_stp
= 0; /* log STP state changes */
531 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, log_stp
, CTLFLAG_RW
,
532 &log_stp
, 0, "Log STP state changes");
533 #endif /* BRIDGESTP */
535 struct bridge_control
{
536 int (*bc_func
)(struct bridge_softc
*, void *);
537 unsigned int bc_argsize
;
538 unsigned int bc_flags
;
541 #define BC_F_COPYIN 0x01 /* copy arguments in */
542 #define BC_F_COPYOUT 0x02 /* copy arguments out */
543 #define BC_F_SUSER 0x04 /* do super-user check */
545 static const struct bridge_control bridge_control_table32
[] = {
546 { bridge_ioctl_add
, sizeof (struct ifbreq
),
547 BC_F_COPYIN
|BC_F_SUSER
},
548 { bridge_ioctl_del
, sizeof (struct ifbreq
),
549 BC_F_COPYIN
|BC_F_SUSER
},
551 { bridge_ioctl_gifflags
, sizeof (struct ifbreq
),
552 BC_F_COPYIN
|BC_F_COPYOUT
},
553 { bridge_ioctl_sifflags
, sizeof (struct ifbreq
),
554 BC_F_COPYIN
|BC_F_SUSER
},
556 { bridge_ioctl_scache
, sizeof (struct ifbrparam
),
557 BC_F_COPYIN
|BC_F_SUSER
},
558 { bridge_ioctl_gcache
, sizeof (struct ifbrparam
),
561 { bridge_ioctl_gifs32
, sizeof (struct ifbifconf32
),
562 BC_F_COPYIN
|BC_F_COPYOUT
},
563 { bridge_ioctl_rts32
, sizeof (struct ifbaconf32
),
564 BC_F_COPYIN
|BC_F_COPYOUT
},
566 { bridge_ioctl_saddr32
, sizeof (struct ifbareq32
),
567 BC_F_COPYIN
|BC_F_SUSER
},
569 { bridge_ioctl_sto
, sizeof (struct ifbrparam
),
570 BC_F_COPYIN
|BC_F_SUSER
},
571 { bridge_ioctl_gto
, sizeof (struct ifbrparam
),
574 { bridge_ioctl_daddr32
, sizeof (struct ifbareq32
),
575 BC_F_COPYIN
|BC_F_SUSER
},
577 { bridge_ioctl_flush
, sizeof (struct ifbreq
),
578 BC_F_COPYIN
|BC_F_SUSER
},
580 { bridge_ioctl_gpri
, sizeof (struct ifbrparam
),
582 { bridge_ioctl_spri
, sizeof (struct ifbrparam
),
583 BC_F_COPYIN
|BC_F_SUSER
},
585 { bridge_ioctl_ght
, sizeof (struct ifbrparam
),
587 { bridge_ioctl_sht
, sizeof (struct ifbrparam
),
588 BC_F_COPYIN
|BC_F_SUSER
},
590 { bridge_ioctl_gfd
, sizeof (struct ifbrparam
),
592 { bridge_ioctl_sfd
, sizeof (struct ifbrparam
),
593 BC_F_COPYIN
|BC_F_SUSER
},
595 { bridge_ioctl_gma
, sizeof (struct ifbrparam
),
597 { bridge_ioctl_sma
, sizeof (struct ifbrparam
),
598 BC_F_COPYIN
|BC_F_SUSER
},
600 { bridge_ioctl_sifprio
, sizeof (struct ifbreq
),
601 BC_F_COPYIN
|BC_F_SUSER
},
603 { bridge_ioctl_sifcost
, sizeof (struct ifbreq
),
604 BC_F_COPYIN
|BC_F_SUSER
},
606 { bridge_ioctl_gfilt
, sizeof (struct ifbrparam
),
608 { bridge_ioctl_sfilt
, sizeof (struct ifbrparam
),
609 BC_F_COPYIN
|BC_F_SUSER
},
611 { bridge_ioctl_purge
, sizeof (struct ifbreq
),
612 BC_F_COPYIN
|BC_F_SUSER
},
614 { bridge_ioctl_addspan
, sizeof (struct ifbreq
),
615 BC_F_COPYIN
|BC_F_SUSER
},
616 { bridge_ioctl_delspan
, sizeof (struct ifbreq
),
617 BC_F_COPYIN
|BC_F_SUSER
},
619 { bridge_ioctl_gbparam32
, sizeof (struct ifbropreq32
),
622 { bridge_ioctl_grte
, sizeof (struct ifbrparam
),
625 { bridge_ioctl_gifsstp32
, sizeof (struct ifbpstpconf32
),
626 BC_F_COPYIN
|BC_F_COPYOUT
},
628 { bridge_ioctl_sproto
, sizeof (struct ifbrparam
),
629 BC_F_COPYIN
|BC_F_SUSER
},
631 { bridge_ioctl_stxhc
, sizeof (struct ifbrparam
),
632 BC_F_COPYIN
|BC_F_SUSER
},
634 { bridge_ioctl_sifmaxaddr
, sizeof (struct ifbreq
),
635 BC_F_COPYIN
|BC_F_SUSER
},
638 static const struct bridge_control bridge_control_table64
[] = {
639 { bridge_ioctl_add
, sizeof (struct ifbreq
),
640 BC_F_COPYIN
|BC_F_SUSER
},
641 { bridge_ioctl_del
, sizeof (struct ifbreq
),
642 BC_F_COPYIN
|BC_F_SUSER
},
644 { bridge_ioctl_gifflags
, sizeof (struct ifbreq
),
645 BC_F_COPYIN
|BC_F_COPYOUT
},
646 { bridge_ioctl_sifflags
, sizeof (struct ifbreq
),
647 BC_F_COPYIN
|BC_F_SUSER
},
649 { bridge_ioctl_scache
, sizeof (struct ifbrparam
),
650 BC_F_COPYIN
|BC_F_SUSER
},
651 { bridge_ioctl_gcache
, sizeof (struct ifbrparam
),
654 { bridge_ioctl_gifs64
, sizeof (struct ifbifconf64
),
655 BC_F_COPYIN
|BC_F_COPYOUT
},
656 { bridge_ioctl_rts64
, sizeof (struct ifbaconf64
),
657 BC_F_COPYIN
|BC_F_COPYOUT
},
659 { bridge_ioctl_saddr64
, sizeof (struct ifbareq64
),
660 BC_F_COPYIN
|BC_F_SUSER
},
662 { bridge_ioctl_sto
, sizeof (struct ifbrparam
),
663 BC_F_COPYIN
|BC_F_SUSER
},
664 { bridge_ioctl_gto
, sizeof (struct ifbrparam
),
667 { bridge_ioctl_daddr64
, sizeof (struct ifbareq64
),
668 BC_F_COPYIN
|BC_F_SUSER
},
670 { bridge_ioctl_flush
, sizeof (struct ifbreq
),
671 BC_F_COPYIN
|BC_F_SUSER
},
673 { bridge_ioctl_gpri
, sizeof (struct ifbrparam
),
675 { bridge_ioctl_spri
, sizeof (struct ifbrparam
),
676 BC_F_COPYIN
|BC_F_SUSER
},
678 { bridge_ioctl_ght
, sizeof (struct ifbrparam
),
680 { bridge_ioctl_sht
, sizeof (struct ifbrparam
),
681 BC_F_COPYIN
|BC_F_SUSER
},
683 { bridge_ioctl_gfd
, sizeof (struct ifbrparam
),
685 { bridge_ioctl_sfd
, sizeof (struct ifbrparam
),
686 BC_F_COPYIN
|BC_F_SUSER
},
688 { bridge_ioctl_gma
, sizeof (struct ifbrparam
),
690 { bridge_ioctl_sma
, sizeof (struct ifbrparam
),
691 BC_F_COPYIN
|BC_F_SUSER
},
693 { bridge_ioctl_sifprio
, sizeof (struct ifbreq
),
694 BC_F_COPYIN
|BC_F_SUSER
},
696 { bridge_ioctl_sifcost
, sizeof (struct ifbreq
),
697 BC_F_COPYIN
|BC_F_SUSER
},
699 { bridge_ioctl_gfilt
, sizeof (struct ifbrparam
),
701 { bridge_ioctl_sfilt
, sizeof (struct ifbrparam
),
702 BC_F_COPYIN
|BC_F_SUSER
},
704 { bridge_ioctl_purge
, sizeof (struct ifbreq
),
705 BC_F_COPYIN
|BC_F_SUSER
},
707 { bridge_ioctl_addspan
, sizeof (struct ifbreq
),
708 BC_F_COPYIN
|BC_F_SUSER
},
709 { bridge_ioctl_delspan
, sizeof (struct ifbreq
),
710 BC_F_COPYIN
|BC_F_SUSER
},
712 { bridge_ioctl_gbparam64
, sizeof (struct ifbropreq64
),
715 { bridge_ioctl_grte
, sizeof (struct ifbrparam
),
718 { bridge_ioctl_gifsstp64
, sizeof (struct ifbpstpconf64
),
719 BC_F_COPYIN
|BC_F_COPYOUT
},
721 { bridge_ioctl_sproto
, sizeof (struct ifbrparam
),
722 BC_F_COPYIN
|BC_F_SUSER
},
724 { bridge_ioctl_stxhc
, sizeof (struct ifbrparam
),
725 BC_F_COPYIN
|BC_F_SUSER
},
727 { bridge_ioctl_sifmaxaddr
, sizeof (struct ifbreq
),
728 BC_F_COPYIN
|BC_F_SUSER
},
731 static const unsigned int bridge_control_table_size
=
732 sizeof (bridge_control_table32
) / sizeof (bridge_control_table32
[0]);
734 static LIST_HEAD(, bridge_softc
) bridge_list
=
735 LIST_HEAD_INITIALIZER(bridge_list
);
737 static lck_grp_t
*bridge_lock_grp
= NULL
;
738 static lck_attr_t
*bridge_lock_attr
= NULL
;
740 static if_clone_t bridge_cloner
= NULL
;
742 static int if_bridge_txstart
= 0;
743 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, txstart
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
744 &if_bridge_txstart
, 0, "Bridge interface uses TXSTART model");
747 static int if_bridge_debug
= 0;
748 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, debug
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
749 &if_bridge_debug
, 0, "Bridge debug");
751 static void printf_ether_header(struct ether_header
*eh
);
752 static void printf_mbuf_data(mbuf_t m
, size_t offset
, size_t len
);
753 static void printf_mbuf_pkthdr(mbuf_t m
, const char *prefix
, const char *suffix
);
754 static void printf_mbuf(mbuf_t m
, const char *prefix
, const char *suffix
);
755 static void link_print(struct sockaddr_dl
*dl_p
);
757 static void bridge_lock(struct bridge_softc
*);
758 static void bridge_unlock(struct bridge_softc
*);
759 static int bridge_lock2ref(struct bridge_softc
*);
760 static void bridge_unref(struct bridge_softc
*);
761 static void bridge_xlock(struct bridge_softc
*);
762 static void bridge_xdrop(struct bridge_softc
*);
765 bridge_lock(struct bridge_softc
*sc
)
767 void *lr_saved
= __builtin_return_address(0);
769 lck_mtx_assert(sc
->sc_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
771 lck_mtx_lock(sc
->sc_mtx
);
773 sc
->lock_lr
[sc
->next_lock_lr
] = lr_saved
;
774 sc
->next_lock_lr
= (sc
->next_lock_lr
+1) % SO_LCKDBG_MAX
;
778 bridge_unlock(struct bridge_softc
*sc
)
780 void *lr_saved
= __builtin_return_address(0);
782 lck_mtx_assert(sc
->sc_mtx
, LCK_MTX_ASSERT_OWNED
);
784 sc
->unlock_lr
[sc
->next_unlock_lr
] = lr_saved
;
785 sc
->next_unlock_lr
= (sc
->next_unlock_lr
+1) % SO_LCKDBG_MAX
;
787 lck_mtx_unlock(sc
->sc_mtx
);
791 bridge_lock2ref(struct bridge_softc
*sc
)
794 void *lr_saved
= __builtin_return_address(0);
796 lck_mtx_assert(sc
->sc_mtx
, LCK_MTX_ASSERT_OWNED
);
798 if (sc
->sc_iflist_xcnt
> 0)
803 sc
->unlock_lr
[sc
->next_unlock_lr
] = lr_saved
;
804 sc
->next_unlock_lr
= (sc
->next_unlock_lr
+1) % SO_LCKDBG_MAX
;
805 lck_mtx_unlock(sc
->sc_mtx
);
811 bridge_unref(struct bridge_softc
*sc
)
813 void *lr_saved
= __builtin_return_address(0);
815 lck_mtx_assert(sc
->sc_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
817 lck_mtx_lock(sc
->sc_mtx
);
818 sc
->lock_lr
[sc
->next_lock_lr
] = lr_saved
;
819 sc
->next_lock_lr
= (sc
->next_lock_lr
+1) % SO_LCKDBG_MAX
;
823 sc
->unlock_lr
[sc
->next_unlock_lr
] = lr_saved
;
824 sc
->next_unlock_lr
= (sc
->next_unlock_lr
+1) % SO_LCKDBG_MAX
;
825 if ((sc
->sc_iflist_xcnt
> 0) && (sc
->sc_iflist_ref
== 0)) {
826 lck_mtx_unlock(sc
->sc_mtx
);
829 lck_mtx_unlock(sc
->sc_mtx
);
833 bridge_xlock(struct bridge_softc
*sc
)
835 void *lr_saved
= __builtin_return_address(0);
837 lck_mtx_assert(sc
->sc_mtx
, LCK_MTX_ASSERT_OWNED
);
839 sc
->sc_iflist_xcnt
++;
840 while (sc
->sc_iflist_ref
> 0) {
841 sc
->unlock_lr
[sc
->next_unlock_lr
] = lr_saved
;
842 sc
->next_unlock_lr
= (sc
->next_unlock_lr
+1) % SO_LCKDBG_MAX
;
844 msleep(&sc
->sc_cv
, sc
->sc_mtx
, PZERO
, "BRIDGE_XLOCK", NULL
);
846 sc
->lock_lr
[sc
->next_lock_lr
] = lr_saved
;
847 sc
->next_lock_lr
= (sc
->next_lock_lr
+1) % SO_LCKDBG_MAX
;
852 bridge_xdrop(struct bridge_softc
*sc
)
854 lck_mtx_assert(sc
->sc_mtx
, LCK_MTX_ASSERT_OWNED
);
856 sc
->sc_iflist_xcnt
--;
860 printf_mbuf_pkthdr(mbuf_t m
, const char *prefix
, const char *suffix
)
863 printf("%spktlen: %u rcvif: %p header: %p nextpkt: %p%s",
864 prefix
? prefix
: "", (unsigned int)mbuf_pkthdr_len(m
),
865 mbuf_pkthdr_rcvif(m
), mbuf_pkthdr_header(m
),
866 mbuf_nextpkt(m
), suffix
? suffix
: "");
868 printf("%s<NULL>%s\n", prefix
, suffix
);
872 printf_mbuf(mbuf_t m
, const char *prefix
, const char *suffix
)
875 printf("%s%p type: %u flags: 0x%x len: %u data: %p maxlen: %u "
876 "datastart: %p next: %p%s", prefix
? prefix
: "",
877 m
, mbuf_type(m
), mbuf_flags(m
), (unsigned int)mbuf_len(m
),
878 mbuf_data(m
), (unsigned int)mbuf_maxlen(m
),
879 mbuf_datastart(m
), mbuf_next(m
),
880 !suffix
|| (mbuf_flags(m
) & MBUF_PKTHDR
) ? "" : suffix
);
881 if ((mbuf_flags(m
) & MBUF_PKTHDR
))
882 printf_mbuf_pkthdr(m
, " ", suffix
);
884 printf("%s<NULL>%s\n", prefix
, suffix
);
888 printf_mbuf_data(mbuf_t m
, size_t offset
, size_t len
)
892 size_t pktlen
, mlen
, maxlen
;
895 pktlen
= mbuf_pkthdr_len(m
);
900 maxlen
= (pktlen
- offset
> len
) ? len
: pktlen
;
904 for (i
= 0, j
= 0; i
< maxlen
; i
++, j
++) {
914 printf("%02x%s", ptr
[j
], i
% 2 ? " " : "");
920 printf_ether_header(struct ether_header
*eh
)
922 printf("%02x:%02x:%02x:%02x:%02x:%02x > "
923 "%02x:%02x:%02x:%02x:%02x:%02x 0x%04x ",
924 eh
->ether_shost
[0], eh
->ether_shost
[1], eh
->ether_shost
[2],
925 eh
->ether_shost
[3], eh
->ether_shost
[4], eh
->ether_shost
[5],
926 eh
->ether_dhost
[0], eh
->ether_dhost
[1], eh
->ether_dhost
[2],
927 eh
->ether_dhost
[3], eh
->ether_dhost
[4], eh
->ether_dhost
[5],
932 link_print(struct sockaddr_dl
*dl_p
)
937 printf("sdl len %d index %d family %d type 0x%x nlen %d alen %d"
938 " slen %d addr ", dl_p
->sdl_len
,
939 dl_p
->sdl_index
, dl_p
->sdl_family
, dl_p
->sdl_type
,
940 dl_p
->sdl_nlen
, dl_p
->sdl_alen
, dl_p
->sdl_slen
);
942 for (i
= 0; i
< dl_p
->sdl_alen
; i
++)
943 printf("%s%x", i
? ":" : "", (CONST_LLADDR(dl_p
))[i
]);
947 #endif /* BRIDGE_DEBUG */
952 * Pseudo-device attach routine.
954 __private_extern__
int
955 bridgeattach(__unused
int n
)
958 lck_grp_attr_t
*lck_grp_attr
= NULL
;
959 struct ifnet_clone_params ifnet_clone_params
;
961 bridge_rtnode_pool
= zinit(sizeof (struct bridge_rtnode
),
962 1024 * sizeof (struct bridge_rtnode
), 0, "bridge_rtnode");
963 zone_change(bridge_rtnode_pool
, Z_CALLERACCT
, FALSE
);
965 lck_grp_attr
= lck_grp_attr_alloc_init();
967 bridge_lock_grp
= lck_grp_alloc_init("if_bridge", lck_grp_attr
);
969 bridge_lock_attr
= lck_attr_alloc_init();
972 lck_attr_setdebug(bridge_lock_attr
);
975 lck_mtx_init(bridge_list_mtx
, bridge_lock_grp
, bridge_lock_attr
);
977 /* can free the attributes once we've allocated the group lock */
978 lck_grp_attr_free(lck_grp_attr
);
980 LIST_INIT(&bridge_list
);
984 #endif /* BRIDGESTP */
986 ifnet_clone_params
.ifc_name
= "bridge";
987 ifnet_clone_params
.ifc_create
= bridge_clone_create
;
988 ifnet_clone_params
.ifc_destroy
= bridge_clone_destroy
;
990 error
= ifnet_clone_attach(&ifnet_clone_params
, &bridge_cloner
);
992 printf("%s: ifnet_clone_attach failed %d\n", __func__
, error
);
997 #if defined(PFIL_HOOKS)
999 * handler for net.link.bridge.pfil_ipfw
1002 sysctl_pfil_ipfw SYSCTL_HANDLER_ARGS
1004 #pragma unused(arg1, arg2)
1005 int enable
= pfil_ipfw
;
1008 error
= sysctl_handle_int(oidp
, &enable
, 0, req
);
1009 enable
= (enable
) ? 1 : 0;
1011 if (enable
!= pfil_ipfw
) {
1015 * Disable pfil so that ipfw doesnt run twice, if the user
1016 * really wants both then they can re-enable pfil_bridge and/or
1017 * pfil_member. Also allow non-ip packets as ipfw can filter by
1030 SYSCTL_PROC(_net_link_bridge
, OID_AUTO
, ipfw
, CTLTYPE_INT
|CTLFLAG_RW
,
1031 &pfil_ipfw
, 0, &sysctl_pfil_ipfw
, "I", "Layer2 filter with IPFW");
1032 #endif /* PFIL_HOOKS */
1035 * bridge_clone_create:
1037 * Create a new bridge instance.
1040 bridge_clone_create(struct if_clone
*ifc
, uint32_t unit
, __unused
void *params
)
1042 struct ifnet
*ifp
= NULL
;
1043 struct bridge_softc
*sc
;
1045 struct ifnet_init_eparams init_params
;
1047 uint32_t sdl_buffer
[offsetof(struct sockaddr_dl
, sdl_data
) +
1048 IFNAMSIZ
+ ETHER_ADDR_LEN
];
1049 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)sdl_buffer
;
1051 sc
= _MALLOC(sizeof (*sc
), M_DEVBUF
, M_WAITOK
);
1052 memset(sc
, 0, sizeof (*sc
));
1054 sc
->sc_mtx
= lck_mtx_alloc_init(bridge_lock_grp
, bridge_lock_attr
);
1055 sc
->sc_brtmax
= BRIDGE_RTABLE_MAX
;
1056 sc
->sc_brttimeout
= BRIDGE_RTABLE_TIMEOUT
;
1057 sc
->sc_filter_flags
= IFBF_FILT_DEFAULT
;
1060 * For backwards compatibility with previous behaviour...
1061 * Switch off filtering on the bridge itself if BRIDGE_IPF is
1064 sc
->sc_filter_flags
&= ~IFBF_FILT_USEIPF
;
1067 /* Initialize our routing table. */
1068 error
= bridge_rtable_init(sc
);
1070 printf("%s: bridge_rtable_init failed %d\n", __func__
, error
);
1074 TAILQ_INIT(&sc
->sc_iflist
);
1075 TAILQ_INIT(&sc
->sc_spanlist
);
1077 /* use the interface name as the unique id for ifp recycle */
1078 snprintf(sc
->sc_if_xname
, sizeof (sc
->sc_if_xname
), "%s%d",
1079 ifc
->ifc_name
, unit
);
1080 bzero(&init_params
, sizeof (init_params
));
1081 init_params
.ver
= IFNET_INIT_CURRENT_VERSION
;
1082 init_params
.len
= sizeof (init_params
);
1083 if (if_bridge_txstart
) {
1084 init_params
.start
= bridge_start
;
1086 init_params
.flags
= IFNET_INIT_LEGACY
;
1087 init_params
.output
= bridge_output
;
1089 init_params
.uniqueid
= sc
->sc_if_xname
;
1090 init_params
.uniqueid_len
= strlen(sc
->sc_if_xname
);
1091 init_params
.sndq_maxlen
= IFQ_MAXLEN
;
1092 init_params
.name
= ifc
->ifc_name
;
1093 init_params
.unit
= unit
;
1094 init_params
.family
= IFNET_FAMILY_ETHERNET
;
1095 init_params
.type
= IFT_BRIDGE
;
1096 init_params
.demux
= ether_demux
;
1097 init_params
.add_proto
= ether_add_proto
;
1098 init_params
.del_proto
= ether_del_proto
;
1099 init_params
.check_multi
= ether_check_multi
;
1100 init_params
.framer
= ether_frameout
;
1101 init_params
.softc
= sc
;
1102 init_params
.ioctl
= bridge_ioctl
;
1103 init_params
.set_bpf_tap
= bridge_set_bpf_tap
;
1104 init_params
.detach
= bridge_detach
;
1105 init_params
.broadcast_addr
= etherbroadcastaddr
;
1106 init_params
.broadcast_len
= ETHER_ADDR_LEN
;
1107 error
= ifnet_allocate_extended(&init_params
, &ifp
);
1109 printf("%s: ifnet_allocate failed %d\n", __func__
, error
);
1114 error
= ifnet_set_mtu(ifp
, ETHERMTU
);
1116 printf("%s: ifnet_set_mtu failed %d\n", __func__
, error
);
1119 error
= ifnet_set_addrlen(ifp
, ETHER_ADDR_LEN
);
1121 printf("%s: ifnet_set_addrlen failed %d\n", __func__
, error
);
1124 error
= ifnet_set_hdrlen(ifp
, ETHER_HDR_LEN
);
1126 printf("%s: ifnet_set_hdrlen failed %d\n", __func__
, error
);
1129 error
= ifnet_set_flags(ifp
,
1130 IFF_BROADCAST
| IFF_SIMPLEX
| IFF_NOTRAILERS
| IFF_MULTICAST
,
1133 printf("%s: ifnet_set_flags failed %d\n", __func__
, error
);
1139 * Generate a random ethernet address with a locally administered
1142 * Since we are using random ethernet addresses for the bridge, it is
1143 * possible that we might have address collisions, so make sure that
1144 * this hardware address isn't already in use on another bridge.
1149 for (retry
= 1; retry
!= 0;) {
1151 struct bridge_softc
*sc2
;
1153 read_random(eaddr
, ETHER_ADDR_LEN
);
1154 eaddr
[0] &= ~1; /* clear multicast bit */
1155 eaddr
[0] |= 2; /* set the LAA bit */
1157 lck_mtx_lock(bridge_list_mtx
);
1158 LIST_FOREACH(sc2
, &bridge_list
, sc_list
) {
1160 if (memcmp(eaddr
, ifnet_lladdr(bifp
),
1161 ETHER_ADDR_LEN
) == 0)
1164 lck_mtx_unlock(bridge_list_mtx
);
1169 * Generate a random ethernet address and use the private AC:DE:48
1175 read_random(&r
, sizeof (r
));
1179 eaddr
[3] = (r
>> 0) & 0xffu
;
1180 eaddr
[4] = (r
>> 8) & 0xffu
;
1181 eaddr
[5] = (r
>> 16) & 0xffu
;
1185 memset(sdl
, 0, sizeof (sdl_buffer
));
1186 sdl
->sdl_family
= AF_LINK
;
1187 sdl
->sdl_nlen
= strlen(sc
->sc_if_xname
);
1188 sdl
->sdl_alen
= ETHER_ADDR_LEN
;
1189 sdl
->sdl_len
= offsetof(struct sockaddr_dl
, sdl_data
);
1190 memcpy(sdl
->sdl_data
, sc
->sc_if_xname
, sdl
->sdl_nlen
);
1191 memcpy(LLADDR(sdl
), eaddr
, ETHER_ADDR_LEN
);
1194 if (if_bridge_debug
)
1198 error
= ifnet_attach(ifp
, NULL
);
1200 printf("%s: ifnet_attach failed %d\n", __func__
, error
);
1204 error
= ifnet_set_lladdr_and_type(ifp
, eaddr
, ETHER_ADDR_LEN
,
1207 printf("%s: ifnet_set_lladdr_and_type failed %d\n", __func__
,
1212 #if APPLE_BRIDGE_HWCKSUM_SUPPORT
1214 * APPLE MODIFICATION - our bridge can support HW checksums
1215 * (useful if underlying interfaces support them) on TX,
1216 * RX is not that interesting, since the stack just looks to
1217 * see if the packet has been checksummed already (I think)
1218 * but we might as well indicate we support it
1220 ifp
->if_capabilities
=
1221 IFCAP_CSUM_IPv4_Tx
| IFCAP_CSUM_TCPv4_Tx
| IFCAP_CSUM_UDPv4_Tx
|
1222 IFCAP_CSUM_IPv4_Rx
| IFCAP_CSUM_TCPv4_Rx
| IFCAP_CSUM_UDPv4_Rx
;
1226 bstp_attach(&sc
->sc_stp
, &bridge_ops
);
1227 #endif /* BRIDGESTP */
1229 lck_mtx_lock(bridge_list_mtx
);
1230 LIST_INSERT_HEAD(&bridge_list
, sc
, sc_list
);
1231 lck_mtx_unlock(bridge_list_mtx
);
1233 /* attach as ethernet */
1234 error
= bpf_attach(ifp
, DLT_EN10MB
, sizeof (struct ether_header
),
1239 printf("%s failed error %d\n", __func__
, error
);
1247 * bridge_clone_destroy:
1249 * Destroy a bridge instance.
1252 bridge_clone_destroy(struct ifnet
*ifp
)
1254 struct bridge_softc
*sc
= ifp
->if_softc
;
1255 struct bridge_iflist
*bif
;
1259 if ((sc
->sc_flags
& SCF_DETACHING
)) {
1263 sc
->sc_flags
|= SCF_DETACHING
;
1265 bridge_ifstop(ifp
, 1);
1267 error
= ifnet_set_flags(ifp
, 0, IFF_UP
);
1269 printf("%s: ifnet_set_flags failed %d\n", __func__
, error
);
1272 while ((bif
= TAILQ_FIRST(&sc
->sc_iflist
)) != NULL
)
1273 bridge_delete_member(sc
, bif
, 0);
1275 while ((bif
= TAILQ_FIRST(&sc
->sc_spanlist
)) != NULL
) {
1276 bridge_delete_span(sc
, bif
);
1281 error
= ifnet_detach(ifp
);
1283 panic("bridge_clone_destroy: ifnet_detach(%p) failed %d\n",
1285 if ((sc
= (struct bridge_softc
*)ifnet_softc(ifp
)) != NULL
) {
1287 sc
->sc_flags
&= ~SCF_DETACHING
;
1296 #define DRVSPEC do { \
1297 if (ifd->ifd_cmd >= bridge_control_table_size) { \
1301 bc = &bridge_control_table[ifd->ifd_cmd]; \
1303 if (cmd == SIOCGDRVSPEC && \
1304 (bc->bc_flags & BC_F_COPYOUT) == 0) { \
1307 } else if (cmd == SIOCSDRVSPEC && \
1308 (bc->bc_flags & BC_F_COPYOUT) != 0) { \
1313 if (bc->bc_flags & BC_F_SUSER) { \
1314 error = kauth_authorize_generic(kauth_cred_get(), \
1315 KAUTH_GENERIC_ISSUSER); \
1320 if (ifd->ifd_len != bc->bc_argsize || \
1321 ifd->ifd_len > sizeof (args)) { \
1326 bzero(&args, sizeof (args)); \
1327 if (bc->bc_flags & BC_F_COPYIN) { \
1328 error = copyin(ifd->ifd_data, &args, ifd->ifd_len); \
1334 error = (*bc->bc_func)(sc, &args); \
1335 BRIDGE_UNLOCK(sc); \
1339 if (bc->bc_flags & BC_F_COPYOUT) \
1340 error = copyout(&args, ifd->ifd_data, ifd->ifd_len); \
1347 * Handle a control request from the operator.
1350 bridge_ioctl(struct ifnet
*ifp
, u_long cmd
, void *data
)
1352 struct bridge_softc
*sc
= ifp
->if_softc
;
1353 struct ifreq
*ifr
= (struct ifreq
*)data
;
1356 lck_mtx_assert(sc
->sc_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
1359 if (if_bridge_debug
)
1360 printf("%s: ifp %p cmd 0x%08lx (%c%c [%lu] %c %lu)\n",
1361 __func__
, ifp
, cmd
, (cmd
& IOC_IN
) ? 'I' : ' ',
1362 (cmd
& IOC_OUT
) ? 'O' : ' ', IOCPARM_LEN(cmd
),
1363 (char)IOCGROUP(cmd
), cmd
& 0xff);
1370 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
1373 case SIOCGIFMEDIA32
:
1374 case SIOCGIFMEDIA64
:
1382 case SIOCSDRVSPEC32
:
1383 case SIOCGDRVSPEC32
: {
1385 struct ifbreq ifbreq
;
1386 struct ifbifconf32 ifbifconf
;
1387 struct ifbareq32 ifbareq
;
1388 struct ifbaconf32 ifbaconf
;
1389 struct ifbrparam ifbrparam
;
1390 struct ifbropreq32 ifbropreq
;
1392 struct ifdrv32
*ifd
= (struct ifdrv32
*)data
;
1393 const struct bridge_control
*bridge_control_table
=
1394 bridge_control_table32
, *bc
;
1400 case SIOCSDRVSPEC64
:
1401 case SIOCGDRVSPEC64
: {
1403 struct ifbreq ifbreq
;
1404 struct ifbifconf64 ifbifconf
;
1405 struct ifbareq64 ifbareq
;
1406 struct ifbaconf64 ifbaconf
;
1407 struct ifbrparam ifbrparam
;
1408 struct ifbropreq64 ifbropreq
;
1410 struct ifdrv64
*ifd
= (struct ifdrv64
*)data
;
1411 const struct bridge_control
*bridge_control_table
=
1412 bridge_control_table64
, *bc
;
1420 if (!(ifp
->if_flags
& IFF_UP
) &&
1421 (ifp
->if_flags
& IFF_RUNNING
)) {
1423 * If interface is marked down and it is running,
1424 * then stop and disable it.
1427 bridge_ifstop(ifp
, 1);
1429 } else if ((ifp
->if_flags
& IFF_UP
) &&
1430 !(ifp
->if_flags
& IFF_RUNNING
)) {
1432 * If interface is marked up and it is stopped, then
1436 error
= bridge_init(ifp
);
1442 error
= ifnet_set_lladdr(ifp
, ifr
->ifr_addr
.sa_data
,
1443 ifr
->ifr_addr
.sa_len
);
1445 printf("%s: ifnet_set_lladdr failed %d\n", __func__
,
1450 /* Do not allow the MTU to be changed on the bridge */
1455 error
= ether_ioctl(ifp
, cmd
, data
);
1457 if (error
!= 0 && error
!= EOPNOTSUPP
)
1458 printf("%s: ether_ioctl ifp %p cmd 0x%08lx "
1459 "(%c%c [%lu] %c %lu) failed error: %d\n",
1460 __func__
, ifp
, cmd
, (cmd
& IOC_IN
) ? 'I' : ' ',
1461 (cmd
& IOC_OUT
) ? 'O' : ' ',
1462 IOCPARM_LEN(cmd
), (char)IOCGROUP(cmd
),
1464 #endif /* BRIDGE_DEBUG */
1467 lck_mtx_assert(sc
->sc_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
1476 * Clear or restore unwanted capabilities on the member interface
1479 bridge_mutecaps(struct bridge_softc
*sc
)
1481 struct bridge_iflist
*bif
;
1484 /* Initial bitmask of capabilities to test */
1485 mask
= BRIDGE_IFCAPS_MASK
;
1487 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
1488 /* Every member must support it or its disabled */
1489 mask
&= bif
->bif_savedcaps
;
1492 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
1493 enabled
= bif
->bif_ifp
->if_capenable
;
1494 enabled
&= ~BRIDGE_IFCAPS_STRIP
;
1495 /* strip off mask bits and enable them again if allowed */
1496 enabled
&= ~BRIDGE_IFCAPS_MASK
;
1499 bridge_set_ifcap(sc
, bif
, enabled
);
1505 bridge_set_ifcap(struct bridge_softc
*sc
, struct bridge_iflist
*bif
, int set
)
1507 struct ifnet
*ifp
= bif
->bif_ifp
;
1511 bzero(&ifr
, sizeof (ifr
));
1512 ifr
.ifr_reqcap
= set
;
1514 if (ifp
->if_capenable
!= set
) {
1516 error
= (*ifp
->if_ioctl
)(ifp
, SIOCSIFCAP
, (caddr_t
)&ifr
);
1517 IFF_UNLOCKGIANT(ifp
);
1519 printf("%s: error setting interface capabilities "
1520 "on %s\n", __func__
, ifnet_name(sc
->sc_ifp
),
1521 ifnet_unit(sc
->sc_ifp
), ifp
->if_xname
);
1524 #endif /* HAS_IF_CAP */
1527 * bridge_lookup_member:
1529 * Lookup a bridge member interface.
1531 static struct bridge_iflist
*
1532 bridge_lookup_member(struct bridge_softc
*sc
, const char *name
)
1534 struct bridge_iflist
*bif
;
1536 char if_xname
[IFNAMSIZ
];
1538 BRIDGE_LOCK_ASSERT(sc
);
1540 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
1542 snprintf(if_xname
, sizeof (if_xname
), "%s%d",
1543 ifnet_name(ifp
), ifnet_unit(ifp
));
1544 if (strncmp(if_xname
, name
, sizeof (if_xname
)) == 0)
1552 * bridge_lookup_member_if:
1554 * Lookup a bridge member interface by ifnet*.
1556 static struct bridge_iflist
*
1557 bridge_lookup_member_if(struct bridge_softc
*sc
, struct ifnet
*member_ifp
)
1559 struct bridge_iflist
*bif
;
1561 BRIDGE_LOCK_ASSERT(sc
);
1563 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
1564 if (bif
->bif_ifp
== member_ifp
)
1572 bridge_iff_input(void *cookie
, ifnet_t ifp
, __unused protocol_family_t protocol
,
1573 mbuf_t
*data
, char **frame_ptr
)
1576 struct bridge_iflist
*bif
= (struct bridge_iflist
*)cookie
;
1577 struct bridge_softc
*sc
= bif
->bif_sc
;
1582 if ((m
->m_flags
& M_PROTO1
))
1585 if (*frame_ptr
>= (char *)mbuf_datastart(m
) &&
1586 *frame_ptr
<= (char *)mbuf_data(m
)) {
1588 frmlen
= (char *)mbuf_data(m
) - *frame_ptr
;
1591 if (if_bridge_debug
) {
1592 printf("%s: %s%d from %s%d m %p data %p frame %p %s "
1593 "frmlen %lu\n", __func__
, ifnet_name(sc
->sc_ifp
),
1594 ifnet_unit(sc
->sc_ifp
), ifnet_name(ifp
), ifnet_unit(ifp
),
1595 m
, mbuf_data(m
), *frame_ptr
,
1596 included
? "inside" : "outside", frmlen
);
1598 if (if_bridge_debug
> 1) {
1599 printf_mbuf(m
, "bridge_iff_input[", "\n");
1600 printf_ether_header((struct ether_header
*)
1601 (void *)*frame_ptr
);
1602 printf_mbuf_data(m
, 0, 20);
1606 #endif /* BRIDGE_DEBUG */
1608 /* Move data pointer to start of frame to the link layer header */
1610 (void) mbuf_setdata(m
, (char *)mbuf_data(m
) - frmlen
,
1611 mbuf_len(m
) + frmlen
);
1612 (void) mbuf_pkthdr_adjustlen(m
, frmlen
);
1614 printf("%s: frame_ptr outside mbuf\n", __func__
);
1618 error
= bridge_input(ifp
, m
, *frame_ptr
);
1620 /* Adjust packet back to original */
1622 (void) mbuf_setdata(m
, (char *)mbuf_data(m
) + frmlen
,
1623 mbuf_len(m
) - frmlen
);
1624 (void) mbuf_pkthdr_adjustlen(m
, -frmlen
);
1627 if (if_bridge_debug
> 1) {
1629 printf_mbuf(m
, "bridge_iff_input]", "\n");
1631 #endif /* BRIDGE_DEBUG */
1634 lck_mtx_assert(sc
->sc_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
1640 #if BRIDGE_MEMBER_OUT_FILTER
1642 bridge_iff_output(void *cookie
, ifnet_t ifp
, __unused protocol_family_t protocol
, mbuf_t
*data
)
1645 struct bridge_iflist
*bif
= (struct bridge_iflist
*)cookie
;
1646 struct bridge_softc
*sc
= bif
->bif_sc
;
1649 if ((m
->m_flags
& M_PROTO1
))
1653 if (if_bridge_debug
) {
1654 printf("%s: %s%d from %s%d m %p data %p\n", __func__
,
1655 ifnet_name(sc
->sc_ifp
), ifnet_unit(sc
->sc_ifp
),
1656 ifnet_name(ifp
), ifnet_unit(ifp
), m
, mbuf_data(m
));
1658 #endif /* BRIDGE_DEBUG */
1660 error
= bridge_member_output(sc
, ifp
, m
);
1662 printf("%s: bridge_member_output failed error %d\n", __func__
,
1667 lck_mtx_assert(sc
->sc_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
1671 #endif /* BRIDGE_MEMBER_OUT_FILTER */
1675 bridge_iff_event(void *cookie
, ifnet_t ifp
, __unused protocol_family_t protocol
,
1676 const struct kev_msg
*event_msg
)
1678 struct bridge_iflist
*bif
= (struct bridge_iflist
*)cookie
;
1680 if (event_msg
->vendor_code
== KEV_VENDOR_APPLE
&&
1681 event_msg
->kev_class
== KEV_NETWORK_CLASS
&&
1682 event_msg
->kev_subclass
== KEV_DL_SUBCLASS
) {
1683 switch (event_msg
->event_code
) {
1684 case KEV_DL_IF_DETACHING
:
1685 case KEV_DL_IF_DETACHED
:
1686 bridge_ifdetach(bif
, ifp
);
1689 case KEV_DL_LINK_OFF
:
1690 case KEV_DL_LINK_ON
: {
1692 bstp_linkstate(ifp
, event_msg
->event_code
);
1693 #endif /* BRIDGESTP */
1697 case KEV_DL_SIFFLAGS
: {
1698 if (bif
->bif_promisc
== 0 &&
1699 (ifp
->if_flags
& IFF_UP
)) {
1701 ifnet_set_promiscuous(ifp
, 1);
1704 "ifnet_set_promiscuous"
1705 "(%s%d) failed %d\n",
1706 __func__
, ifnet_name(ifp
),
1707 ifnet_unit(ifp
), error
);
1709 bif
->bif_promisc
= 1;
1722 * bridge_iff_detached:
1724 * Detach an interface from a bridge. Called when a member
1725 * interface is detaching.
1728 bridge_iff_detached(void *cookie
, __unused ifnet_t ifp
)
1730 struct bridge_iflist
*bif
= (struct bridge_iflist
*)cookie
;
1733 printf("%s: %s%d\n", __func__
, ifnet_name(ifp
), ifnet_unit(ifp
));
1736 bridge_ifdetach(bif
, ifp
);
1738 _FREE(bif
, M_DEVBUF
);
1742 bridge_proto_input(ifnet_t ifp
, __unused protocol_family_t protocol
,
1743 __unused mbuf_t packet
, __unused
char *header
)
1745 printf("%s: unexpected packet from %s%d\n", __func__
,
1746 ifnet_name(ifp
), ifnet_unit(ifp
));
1751 bridge_attach_protocol(struct ifnet
*ifp
)
1754 struct ifnet_attach_proto_param reg
;
1756 printf("%s: %s%d\n", __func__
, ifnet_name(ifp
), ifnet_unit(ifp
));
1758 bzero(®
, sizeof (reg
));
1759 reg
.input
= bridge_proto_input
;
1761 error
= ifnet_attach_protocol(ifp
, PF_BRIDGE
, ®
);
1763 printf("%s: ifnet_attach_protocol(%s%d) failed, %d\n",
1764 __func__
, ifnet_name(ifp
), ifnet_unit(ifp
), error
);
1770 bridge_detach_protocol(struct ifnet
*ifp
)
1774 printf("%s: %s%d\n", __func__
, ifnet_name(ifp
), ifnet_unit(ifp
));
1776 error
= ifnet_detach_protocol(ifp
, PF_BRIDGE
);
1778 printf("%s: ifnet_detach_protocol(%s%d) failed, %d\n",
1779 __func__
, ifnet_name(ifp
), ifnet_unit(ifp
), error
);
1785 * bridge_delete_member:
1787 * Delete the specified member interface.
1790 bridge_delete_member(struct bridge_softc
*sc
, struct bridge_iflist
*bif
,
1793 struct ifnet
*ifs
= bif
->bif_ifp
;
1795 BRIDGE_LOCK_ASSERT(sc
);
1798 switch (ifs
->if_type
) {
1802 * Take the interface out of promiscuous mode.
1804 if (bif
->bif_promisc
)
1805 (void) ifnet_set_promiscuous(ifs
, 0);
1813 panic("bridge_delete_member: impossible");
1819 /* reneable any interface capabilities */
1820 bridge_set_ifcap(sc
, bif
, bif
->bif_savedcaps
);
1824 if (bif
->bif_proto_attached
) {
1825 /* Respect lock ordering with DLIL lock */
1827 (void) bridge_detach_protocol(ifs
);
1831 if (bif
->bif_flags
& IFBIF_STP
)
1832 bstp_disable(&bif
->bif_stp
);
1833 #endif /* BRIDGESTP */
1835 ifs
->if_bridge
= NULL
;
1837 TAILQ_REMOVE(&sc
->sc_iflist
, bif
, bif_next
);
1843 bridge_mutecaps(sc
); /* recalcuate now this interface is removed */
1844 #endif /* HAS_IF_CAP */
1845 bridge_rtdelete(sc
, ifs
, IFBF_FLUSHALL
);
1846 KASSERT(bif
->bif_addrcnt
== 0,
1847 ("%s: %d bridge routes referenced", __func__
, bif
->bif_addrcnt
));
1851 bstp_destroy(&bif
->bif_stp
); /* prepare to free */
1853 #endif /* BRIDGESTP */
1855 if (bif
->bif_filter_attached
) {
1856 /* Respect lock ordering with DLIL lock */
1858 iflt_detach(bif
->bif_iff_ref
);
1861 _FREE(bif
, M_DEVBUF
);
1866 * bridge_delete_span:
1868 * Delete the specified span interface.
1871 bridge_delete_span(struct bridge_softc
*sc
, struct bridge_iflist
*bif
)
1873 BRIDGE_LOCK_ASSERT(sc
);
1875 KASSERT(bif
->bif_ifp
->if_bridge
== NULL
,
1876 ("%s: not a span interface", __func__
));
1878 ifnet_release(bif
->bif_ifp
);
1880 TAILQ_REMOVE(&sc
->sc_spanlist
, bif
, bif_next
);
1881 _FREE(bif
, M_DEVBUF
);
1885 bridge_ioctl_add(struct bridge_softc
*sc
, void *arg
)
1887 struct ifbreq
*req
= arg
;
1888 struct bridge_iflist
*bif
= NULL
;
1891 struct iff_filter iff
;
1893 ifs
= ifunit(req
->ifbr_ifsname
);
1896 if (ifs
->if_ioctl
== NULL
) /* must be supported */
1899 /* If it's in the span list, it can't be a member. */
1900 TAILQ_FOREACH(bif
, &sc
->sc_spanlist
, bif_next
)
1901 if (ifs
== bif
->bif_ifp
)
1904 /* Allow the first Ethernet member to define the MTU */
1905 if (ifs
->if_type
!= IFT_GIF
) {
1906 if (TAILQ_EMPTY(&sc
->sc_iflist
))
1907 sc
->sc_ifp
->if_mtu
= ifs
->if_mtu
;
1908 else if (sc
->sc_ifp
->if_mtu
!= ifs
->if_mtu
) {
1909 printf("%s: %s%d: invalid MTU for %s%d", __func__
,
1910 ifnet_name(sc
->sc_ifp
), ifnet_unit(sc
->sc_ifp
),
1911 ifnet_name(ifs
), ifnet_unit(ifs
));
1916 if (ifs
->if_bridge
== sc
)
1919 if (ifs
->if_bridge
!= NULL
)
1922 bif
= _MALLOC(sizeof (*bif
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
1927 bif
->bif_flags
= IFBIF_LEARNING
| IFBIF_DISCOVER
;
1929 bif
->bif_savedcaps
= ifs
->if_capenable
;
1930 #endif /* HAS_IF_CAP */
1933 ifnet_reference(ifs
);
1935 ifs
->if_bridge
= sc
;
1937 bstp_create(&sc
->sc_stp
, &bif
->bif_stp
, bif
->bif_ifp
);
1938 #endif /* BRIDGESTP */
1940 * XXX: XLOCK HERE!?!
1942 TAILQ_INSERT_TAIL(&sc
->sc_iflist
, bif
, bif_next
);
1945 /* Set interface capabilities to the intersection set of all members */
1946 bridge_mutecaps(sc
);
1947 #endif /* HAS_IF_CAP */
1950 switch (ifs
->if_type
) {
1954 * Place the interface into promiscuous mode.
1956 error
= ifnet_set_promiscuous(ifs
, 1);
1958 /* Ignore error when device is not up */
1959 if (error
!= ENETDOWN
)
1963 bif
->bif_promisc
= 1;
1976 * Respect lock ordering with DLIL lock for the following operations
1981 * install an interface filter
1983 memset(&iff
, 0, sizeof (struct iff_filter
));
1984 iff
.iff_cookie
= bif
;
1985 iff
.iff_name
= "com.apple.kernel.bsd.net.if_bridge";
1986 iff
.iff_input
= bridge_iff_input
;
1987 #if BRIDGE_MEMBER_OUT_FILTER
1988 iff
.iff_output
= bridge_iff_output
;
1989 #endif /* BRIDGE_MEMBER_OUT_FILTER */
1990 iff
.iff_event
= bridge_iff_event
;
1991 iff
.iff_detached
= bridge_iff_detached
;
1992 error
= iflt_attach(ifs
, &iff
, &bif
->bif_iff_ref
);
1994 printf("%s: iflt_attach failed %d\n", __func__
, error
);
1998 bif
->bif_filter_attached
= 1;
2001 * install an dummy "bridge" protocol
2003 if ((error
= bridge_attach_protocol(ifs
)) != 0) {
2005 printf("%s: bridge_attach_protocol failed %d\n",
2011 bif
->bif_proto_attached
= 1;
2016 if (error
&& bif
!= NULL
)
2017 bridge_delete_member(sc
, bif
, 1);
2023 bridge_ioctl_del(struct bridge_softc
*sc
, void *arg
)
2025 struct ifbreq
*req
= arg
;
2026 struct bridge_iflist
*bif
;
2028 bif
= bridge_lookup_member(sc
, req
->ifbr_ifsname
);
2032 bridge_delete_member(sc
, bif
, 0);
2038 bridge_ioctl_purge(__unused
struct bridge_softc
*sc
, __unused
void *arg
)
2044 bridge_ioctl_gifflags(struct bridge_softc
*sc
, void *arg
)
2046 struct ifbreq
*req
= arg
;
2047 struct bridge_iflist
*bif
;
2048 struct bstp_port
*bp
;
2050 bif
= bridge_lookup_member(sc
, req
->ifbr_ifsname
);
2055 req
->ifbr_ifsflags
= bif
->bif_flags
;
2056 req
->ifbr_state
= bp
->bp_state
;
2057 req
->ifbr_priority
= bp
->bp_priority
;
2058 req
->ifbr_path_cost
= bp
->bp_path_cost
;
2059 req
->ifbr_portno
= bif
->bif_ifp
->if_index
& 0xfff;
2060 req
->ifbr_proto
= bp
->bp_protover
;
2061 req
->ifbr_role
= bp
->bp_role
;
2062 req
->ifbr_stpflags
= bp
->bp_flags
;
2063 req
->ifbr_addrcnt
= bif
->bif_addrcnt
;
2064 req
->ifbr_addrmax
= bif
->bif_addrmax
;
2065 req
->ifbr_addrexceeded
= bif
->bif_addrexceeded
;
2067 /* Copy STP state options as flags */
2068 if (bp
->bp_operedge
)
2069 req
->ifbr_ifsflags
|= IFBIF_BSTP_EDGE
;
2070 if (bp
->bp_flags
& BSTP_PORT_AUTOEDGE
)
2071 req
->ifbr_ifsflags
|= IFBIF_BSTP_AUTOEDGE
;
2072 if (bp
->bp_ptp_link
)
2073 req
->ifbr_ifsflags
|= IFBIF_BSTP_PTP
;
2074 if (bp
->bp_flags
& BSTP_PORT_AUTOPTP
)
2075 req
->ifbr_ifsflags
|= IFBIF_BSTP_AUTOPTP
;
2076 if (bp
->bp_flags
& BSTP_PORT_ADMEDGE
)
2077 req
->ifbr_ifsflags
|= IFBIF_BSTP_ADMEDGE
;
2078 if (bp
->bp_flags
& BSTP_PORT_ADMCOST
)
2079 req
->ifbr_ifsflags
|= IFBIF_BSTP_ADMCOST
;
2084 bridge_ioctl_sifflags(struct bridge_softc
*sc
, void *arg
)
2086 struct ifbreq
*req
= arg
;
2087 struct bridge_iflist
*bif
;
2089 struct bstp_port
*bp
;
2091 #endif /* BRIDGESTP */
2093 bif
= bridge_lookup_member(sc
, req
->ifbr_ifsname
);
2097 if (req
->ifbr_ifsflags
& IFBIF_SPAN
)
2098 /* SPAN is readonly */
2103 if (req
->ifbr_ifsflags
& IFBIF_STP
) {
2104 if ((bif
->bif_flags
& IFBIF_STP
) == 0) {
2105 error
= bstp_enable(&bif
->bif_stp
);
2110 if ((bif
->bif_flags
& IFBIF_STP
) != 0)
2111 bstp_disable(&bif
->bif_stp
);
2114 /* Pass on STP flags */
2116 bstp_set_edge(bp
, req
->ifbr_ifsflags
& IFBIF_BSTP_EDGE
? 1 : 0);
2117 bstp_set_autoedge(bp
, req
->ifbr_ifsflags
& IFBIF_BSTP_AUTOEDGE
? 1 : 0);
2118 bstp_set_ptp(bp
, req
->ifbr_ifsflags
& IFBIF_BSTP_PTP
? 1 : 0);
2119 bstp_set_autoptp(bp
, req
->ifbr_ifsflags
& IFBIF_BSTP_AUTOPTP
? 1 : 0);
2120 #else /* !BRIDGESTP */
2121 if (req
->ifbr_ifsflags
& IFBIF_STP
)
2122 return (EOPNOTSUPP
);
2123 #endif /* !BRIDGESTP */
2125 /* Save the bits relating to the bridge */
2126 bif
->bif_flags
= req
->ifbr_ifsflags
& IFBIFMASK
;
2133 bridge_ioctl_scache(struct bridge_softc
*sc
, void *arg
)
2135 struct ifbrparam
*param
= arg
;
2137 sc
->sc_brtmax
= param
->ifbrp_csize
;
2144 bridge_ioctl_gcache(struct bridge_softc
*sc
, void *arg
)
2146 struct ifbrparam
*param
= arg
;
2148 param
->ifbrp_csize
= sc
->sc_brtmax
;
2154 #define BRIDGE_IOCTL_GIFS do { \
2155 struct bridge_iflist *bif; \
2156 struct ifbreq breq; \
2157 char *buf, *outbuf; \
2158 unsigned int count, buflen, len; \
2161 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) \
2163 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) \
2166 buflen = sizeof (breq) * count; \
2167 if (bifc->ifbic_len == 0) { \
2168 bifc->ifbic_len = buflen; \
2171 BRIDGE_UNLOCK(sc); \
2172 outbuf = _MALLOC(buflen, M_TEMP, M_WAITOK | M_ZERO); \
2177 len = min(bifc->ifbic_len, buflen); \
2178 bzero(&breq, sizeof (breq)); \
2179 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) { \
2180 if (len < sizeof (breq)) \
2183 snprintf(breq.ifbr_ifsname, sizeof (breq.ifbr_ifsname), \
2184 "%s%d", ifnet_name(bif->bif_ifp), \
2185 ifnet_unit(bif->bif_ifp)); \
2186 /* Fill in the ifbreq structure */ \
2187 error = bridge_ioctl_gifflags(sc, &breq); \
2190 memcpy(buf, &breq, sizeof (breq)); \
2192 buf += sizeof (breq); \
2193 len -= sizeof (breq); \
2195 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) { \
2196 if (len < sizeof (breq)) \
2199 snprintf(breq.ifbr_ifsname, sizeof (breq.ifbr_ifsname), \
2200 "%s%d", ifnet_name(bif->bif_ifp), \
2201 ifnet_unit(bif->bif_ifp)); \
2202 breq.ifbr_ifsflags = bif->bif_flags; \
2203 breq.ifbr_portno = bif->bif_ifp->if_index & 0xfff; \
2204 memcpy(buf, &breq, sizeof (breq)); \
2206 buf += sizeof (breq); \
2207 len -= sizeof (breq); \
2210 BRIDGE_UNLOCK(sc); \
2211 bifc->ifbic_len = sizeof (breq) * count; \
2212 error = copyout(outbuf, bifc->ifbic_req, bifc->ifbic_len); \
2214 _FREE(outbuf, M_TEMP); \
2218 bridge_ioctl_gifs64(struct bridge_softc
*sc
, void *arg
)
2220 struct ifbifconf64
*bifc
= arg
;
2229 bridge_ioctl_gifs32(struct bridge_softc
*sc
, void *arg
)
2231 struct ifbifconf32
*bifc
= arg
;
2240 #define BRIDGE_IOCTL_RTS do { \
2241 struct bridge_rtnode *brt; \
2242 char *buf, *outbuf; \
2243 unsigned int count, buflen, len; \
2244 struct timespec now; \
2246 if (bac->ifbac_len == 0) \
2250 LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) \
2252 buflen = sizeof (bareq) * count; \
2254 BRIDGE_UNLOCK(sc); \
2255 outbuf = _MALLOC(buflen, M_TEMP, M_WAITOK | M_ZERO); \
2260 len = min(bac->ifbac_len, buflen); \
2261 bzero(&bareq, sizeof (bareq)); \
2262 LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { \
2263 if (len < sizeof (bareq)) \
2265 snprintf(bareq.ifba_ifsname, sizeof (bareq.ifba_ifsname), \
2266 "%s%d", ifnet_name(brt->brt_ifp), \
2267 ifnet_unit(brt->brt_ifp)); \
2268 memcpy(bareq.ifba_dst, brt->brt_addr, sizeof (brt->brt_addr)); \
2269 bareq.ifba_vlan = brt->brt_vlan; \
2270 if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { \
2272 if ((unsigned long)now.tv_sec < brt->brt_expire) \
2273 bareq.ifba_expire = \
2274 brt->brt_expire - now.tv_sec; \
2276 bareq.ifba_expire = 0; \
2277 bareq.ifba_flags = brt->brt_flags; \
2279 memcpy(buf, &bareq, sizeof (bareq)); \
2281 buf += sizeof (bareq); \
2282 len -= sizeof (bareq); \
2285 BRIDGE_UNLOCK(sc); \
2286 bac->ifbac_len = sizeof (bareq) * count; \
2287 error = copyout(outbuf, bac->ifbac_req, bac->ifbac_len); \
2289 _FREE(outbuf, M_TEMP); \
2294 bridge_ioctl_rts64(struct bridge_softc
*sc
, void *arg
)
2296 struct ifbaconf64
*bac
= arg
;
2297 struct ifbareq64 bareq
;
2306 bridge_ioctl_rts32(struct bridge_softc
*sc
, void *arg
)
2308 struct ifbaconf32
*bac
= arg
;
2309 struct ifbareq32 bareq
;
2318 bridge_ioctl_saddr32(struct bridge_softc
*sc
, void *arg
)
2320 struct ifbareq32
*req
= arg
;
2321 struct bridge_iflist
*bif
;
2324 bif
= bridge_lookup_member(sc
, req
->ifba_ifsname
);
2328 error
= bridge_rtupdate(sc
, req
->ifba_dst
, req
->ifba_vlan
, bif
, 1,
2335 bridge_ioctl_saddr64(struct bridge_softc
*sc
, void *arg
)
2337 struct ifbareq64
*req
= arg
;
2338 struct bridge_iflist
*bif
;
2341 bif
= bridge_lookup_member(sc
, req
->ifba_ifsname
);
2345 error
= bridge_rtupdate(sc
, req
->ifba_dst
, req
->ifba_vlan
, bif
, 1,
2352 bridge_ioctl_sto(struct bridge_softc
*sc
, void *arg
)
2354 struct ifbrparam
*param
= arg
;
2356 sc
->sc_brttimeout
= param
->ifbrp_ctime
;
2361 bridge_ioctl_gto(struct bridge_softc
*sc
, void *arg
)
2363 struct ifbrparam
*param
= arg
;
2365 param
->ifbrp_ctime
= sc
->sc_brttimeout
;
2370 bridge_ioctl_daddr32(struct bridge_softc
*sc
, void *arg
)
2372 struct ifbareq32
*req
= arg
;
2374 return (bridge_rtdaddr(sc
, req
->ifba_dst
, req
->ifba_vlan
));
2378 bridge_ioctl_daddr64(struct bridge_softc
*sc
, void *arg
)
2380 struct ifbareq64
*req
= arg
;
2382 return (bridge_rtdaddr(sc
, req
->ifba_dst
, req
->ifba_vlan
));
2386 bridge_ioctl_flush(struct bridge_softc
*sc
, void *arg
)
2388 struct ifbreq
*req
= arg
;
2390 bridge_rtflush(sc
, req
->ifbr_ifsflags
);
2395 bridge_ioctl_gpri(struct bridge_softc
*sc
, void *arg
)
2397 struct ifbrparam
*param
= arg
;
2398 struct bstp_state
*bs
= &sc
->sc_stp
;
2400 param
->ifbrp_prio
= bs
->bs_bridge_priority
;
2405 bridge_ioctl_spri(struct bridge_softc
*sc
, void *arg
)
2408 struct ifbrparam
*param
= arg
;
2410 return (bstp_set_priority(&sc
->sc_stp
, param
->ifbrp_prio
));
2411 #else /* !BRIDGESTP */
2412 #pragma unused(sc, arg)
2413 return (EOPNOTSUPP
);
2414 #endif /* !BRIDGESTP */
2418 bridge_ioctl_ght(struct bridge_softc
*sc
, void *arg
)
2420 struct ifbrparam
*param
= arg
;
2421 struct bstp_state
*bs
= &sc
->sc_stp
;
2423 param
->ifbrp_hellotime
= bs
->bs_bridge_htime
>> 8;
2428 bridge_ioctl_sht(struct bridge_softc
*sc
, void *arg
)
2431 struct ifbrparam
*param
= arg
;
2433 return (bstp_set_htime(&sc
->sc_stp
, param
->ifbrp_hellotime
));
2434 #else /* !BRIDGESTP */
2435 #pragma unused(sc, arg)
2436 return (EOPNOTSUPP
);
2437 #endif /* !BRIDGESTP */
2441 bridge_ioctl_gfd(struct bridge_softc
*sc
, void *arg
)
2443 struct ifbrparam
*param
= arg
;
2444 struct bstp_state
*bs
= &sc
->sc_stp
;
2446 param
->ifbrp_fwddelay
= bs
->bs_bridge_fdelay
>> 8;
2451 bridge_ioctl_sfd(struct bridge_softc
*sc
, void *arg
)
2454 struct ifbrparam
*param
= arg
;
2456 return (bstp_set_fdelay(&sc
->sc_stp
, param
->ifbrp_fwddelay
));
2457 #else /* !BRIDGESTP */
2458 #pragma unused(sc, arg)
2459 return (EOPNOTSUPP
);
2460 #endif /* !BRIDGESTP */
2464 bridge_ioctl_gma(struct bridge_softc
*sc
, void *arg
)
2466 struct ifbrparam
*param
= arg
;
2467 struct bstp_state
*bs
= &sc
->sc_stp
;
2469 param
->ifbrp_maxage
= bs
->bs_bridge_max_age
>> 8;
2474 bridge_ioctl_sma(struct bridge_softc
*sc
, void *arg
)
2477 struct ifbrparam
*param
= arg
;
2479 return (bstp_set_maxage(&sc
->sc_stp
, param
->ifbrp_maxage
));
2480 #else /* !BRIDGESTP */
2481 #pragma unused(sc, arg)
2482 return (EOPNOTSUPP
);
2483 #endif /* !BRIDGESTP */
2487 bridge_ioctl_sifprio(struct bridge_softc
*sc
, void *arg
)
2490 struct ifbreq
*req
= arg
;
2491 struct bridge_iflist
*bif
;
2493 bif
= bridge_lookup_member(sc
, req
->ifbr_ifsname
);
2497 return (bstp_set_port_priority(&bif
->bif_stp
, req
->ifbr_priority
));
2498 #else /* !BRIDGESTP */
2499 #pragma unused(sc, arg)
2500 return (EOPNOTSUPP
);
2501 #endif /* !BRIDGESTP */
2505 bridge_ioctl_sifcost(struct bridge_softc
*sc
, void *arg
)
2508 struct ifbreq
*req
= arg
;
2509 struct bridge_iflist
*bif
;
2511 bif
= bridge_lookup_member(sc
, req
->ifbr_ifsname
);
2515 return (bstp_set_path_cost(&bif
->bif_stp
, req
->ifbr_path_cost
));
2516 #else /* !BRIDGESTP */
2517 #pragma unused(sc, arg)
2518 return (EOPNOTSUPP
);
2519 #endif /* !BRIDGESTP */
2523 bridge_ioctl_gfilt(struct bridge_softc
*sc
, void *arg
)
2525 struct ifbrparam
*param
= arg
;
2527 param
->ifbrp_filter
= sc
->sc_filter_flags
;
2533 bridge_ioctl_sfilt(struct bridge_softc
*sc
, void *arg
)
2535 struct ifbrparam
*param
= arg
;
2537 if (param
->ifbrp_filter
& ~IFBF_FILT_MASK
)
2541 if (param
->ifbrp_filter
& IFBF_FILT_USEIPF
)
2545 sc
->sc_filter_flags
= param
->ifbrp_filter
;
2551 bridge_ioctl_sifmaxaddr(struct bridge_softc
*sc
, void *arg
)
2553 struct ifbreq
*req
= arg
;
2554 struct bridge_iflist
*bif
;
2556 bif
= bridge_lookup_member(sc
, req
->ifbr_ifsname
);
2560 bif
->bif_addrmax
= req
->ifbr_addrmax
;
2565 bridge_ioctl_addspan(struct bridge_softc
*sc
, void *arg
)
2567 struct ifbreq
*req
= arg
;
2568 struct bridge_iflist
*bif
= NULL
;
2571 ifs
= ifunit(req
->ifbr_ifsname
);
2575 TAILQ_FOREACH(bif
, &sc
->sc_spanlist
, bif_next
)
2576 if (ifs
== bif
->bif_ifp
)
2579 if (ifs
->if_bridge
!= NULL
)
2582 switch (ifs
->if_type
) {
2591 bif
= _MALLOC(sizeof (*bif
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
2596 bif
->bif_flags
= IFBIF_SPAN
;
2598 ifnet_reference(bif
->bif_ifp
);
2600 TAILQ_INSERT_HEAD(&sc
->sc_spanlist
, bif
, bif_next
);
2606 bridge_ioctl_delspan(struct bridge_softc
*sc
, void *arg
)
2608 struct ifbreq
*req
= arg
;
2609 struct bridge_iflist
*bif
;
2612 ifs
= ifunit(req
->ifbr_ifsname
);
2616 TAILQ_FOREACH(bif
, &sc
->sc_spanlist
, bif_next
)
2617 if (ifs
== bif
->bif_ifp
)
2623 bridge_delete_span(sc
, bif
);
2628 #define BRIDGE_IOCTL_GBPARAM do { \
2629 struct bstp_state *bs = &sc->sc_stp; \
2630 struct bstp_port *root_port; \
2632 req->ifbop_maxage = bs->bs_bridge_max_age >> 8; \
2633 req->ifbop_hellotime = bs->bs_bridge_htime >> 8; \
2634 req->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8; \
2636 root_port = bs->bs_root_port; \
2637 if (root_port == NULL) \
2638 req->ifbop_root_port = 0; \
2640 req->ifbop_root_port = root_port->bp_ifp->if_index; \
2642 req->ifbop_holdcount = bs->bs_txholdcount; \
2643 req->ifbop_priority = bs->bs_bridge_priority; \
2644 req->ifbop_protocol = bs->bs_protover; \
2645 req->ifbop_root_path_cost = bs->bs_root_pv.pv_cost; \
2646 req->ifbop_bridgeid = bs->bs_bridge_pv.pv_dbridge_id; \
2647 req->ifbop_designated_root = bs->bs_root_pv.pv_root_id; \
2648 req->ifbop_designated_bridge = bs->bs_root_pv.pv_dbridge_id; \
2649 req->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec; \
2650 req->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec; \
2654 bridge_ioctl_gbparam32(struct bridge_softc
*sc
, void *arg
)
2656 struct ifbropreq32
*req
= arg
;
2658 BRIDGE_IOCTL_GBPARAM
;
2664 bridge_ioctl_gbparam64(struct bridge_softc
*sc
, void *arg
)
2666 struct ifbropreq64
*req
= arg
;
2668 BRIDGE_IOCTL_GBPARAM
;
2674 bridge_ioctl_grte(struct bridge_softc
*sc
, void *arg
)
2676 struct ifbrparam
*param
= arg
;
2678 param
->ifbrp_cexceeded
= sc
->sc_brtexceeded
;
2682 #define BRIDGE_IOCTL_GIFSSTP do { \
2683 struct bridge_iflist *bif; \
2684 struct bstp_port *bp; \
2685 struct ifbpstpreq bpreq; \
2686 char *buf, *outbuf; \
2687 unsigned int count, buflen, len; \
2690 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) { \
2691 if ((bif->bif_flags & IFBIF_STP) != 0) \
2695 buflen = sizeof (bpreq) * count; \
2696 if (bifstp->ifbpstp_len == 0) { \
2697 bifstp->ifbpstp_len = buflen; \
2701 BRIDGE_UNLOCK(sc); \
2702 outbuf = _MALLOC(buflen, M_TEMP, M_WAITOK | M_ZERO); \
2707 len = min(bifstp->ifbpstp_len, buflen); \
2708 bzero(&bpreq, sizeof (bpreq)); \
2709 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) { \
2710 if (len < sizeof (bpreq)) \
2713 if ((bif->bif_flags & IFBIF_STP) == 0) \
2716 bp = &bif->bif_stp; \
2717 bpreq.ifbp_portno = bif->bif_ifp->if_index & 0xfff; \
2718 bpreq.ifbp_fwd_trans = bp->bp_forward_transitions; \
2719 bpreq.ifbp_design_cost = bp->bp_desg_pv.pv_cost; \
2720 bpreq.ifbp_design_port = bp->bp_desg_pv.pv_port_id; \
2721 bpreq.ifbp_design_bridge = bp->bp_desg_pv.pv_dbridge_id; \
2722 bpreq.ifbp_design_root = bp->bp_desg_pv.pv_root_id; \
2724 memcpy(buf, &bpreq, sizeof (bpreq)); \
2726 buf += sizeof (bpreq); \
2727 len -= sizeof (bpreq); \
2730 BRIDGE_UNLOCK(sc); \
2731 bifstp->ifbpstp_len = sizeof (bpreq) * count; \
2732 error = copyout(outbuf, bifstp->ifbpstp_req, bifstp->ifbpstp_len); \
2734 _FREE(outbuf, M_TEMP); \
2739 bridge_ioctl_gifsstp32(struct bridge_softc
*sc
, void *arg
)
2741 struct ifbpstpconf32
*bifstp
= arg
;
2744 BRIDGE_IOCTL_GIFSSTP
;
2750 bridge_ioctl_gifsstp64(struct bridge_softc
*sc
, void *arg
)
2752 struct ifbpstpconf64
*bifstp
= arg
;
2755 BRIDGE_IOCTL_GIFSSTP
;
2761 bridge_ioctl_sproto(struct bridge_softc
*sc
, void *arg
)
2764 struct ifbrparam
*param
= arg
;
2766 return (bstp_set_protocol(&sc
->sc_stp
, param
->ifbrp_proto
));
2767 #else /* !BRIDGESTP */
2768 #pragma unused(sc, arg)
2769 return (EOPNOTSUPP
);
2770 #endif /* !BRIDGESTP */
2774 bridge_ioctl_stxhc(struct bridge_softc
*sc
, void *arg
)
2777 struct ifbrparam
*param
= arg
;
2779 return (bstp_set_holdcount(&sc
->sc_stp
, param
->ifbrp_txhc
));
2780 #else /* !BRIDGESTP */
2781 #pragma unused(sc, arg)
2782 return (EOPNOTSUPP
);
2783 #endif /* !BRIDGESTP */
2789 * Detach an interface from a bridge. Called when a member
2790 * interface is detaching.
2792 __private_extern__
void
2793 bridge_ifdetach(struct bridge_iflist
*bif
, struct ifnet
*ifp
)
2795 struct bridge_softc
*sc
= ifp
->if_bridge
;
2798 printf("%s: %s%d\n", __func__
, ifnet_name(ifp
), ifnet_unit(ifp
));
2801 /* Check if the interface is a bridge member */
2805 bif
= bridge_lookup_member_if(sc
, ifp
);
2807 bridge_delete_member(sc
, bif
, 1);
2813 /* Check if the interface is a span port */
2814 lck_mtx_lock(bridge_list_mtx
);
2815 LIST_FOREACH(sc
, &bridge_list
, sc_list
) {
2817 TAILQ_FOREACH(bif
, &sc
->sc_spanlist
, bif_next
)
2818 if (ifp
== bif
->bif_ifp
) {
2819 bridge_delete_span(sc
, bif
);
2825 lck_mtx_unlock(bridge_list_mtx
);
2831 * Initialize a bridge interface.
2834 bridge_init(struct ifnet
*ifp
)
2836 struct bridge_softc
*sc
= (struct bridge_softc
*)ifp
->if_softc
;
2840 BRIDGE_LOCK_ASSERT(sc
);
2842 if ((ifnet_flags(ifp
) & IFF_RUNNING
))
2845 ts
.tv_sec
= bridge_rtable_prune_period
;
2847 bsd_timeout(bridge_timer
, sc
, &ts
);
2849 error
= ifnet_set_flags(ifp
, IFF_RUNNING
, IFF_RUNNING
);
2852 bstp_init(&sc
->sc_stp
); /* Initialize Spanning Tree */
2853 #endif /* BRIDGESTP */
2861 * Stop the bridge interface.
2864 bridge_ifstop(struct ifnet
*ifp
, __unused
int disable
)
2866 struct bridge_softc
*sc
= ifp
->if_softc
;
2868 BRIDGE_LOCK_ASSERT(sc
);
2870 if ((ifnet_flags(ifp
) & IFF_RUNNING
) == 0)
2873 bsd_untimeout(bridge_timer
, sc
);
2875 bstp_stop(&sc
->sc_stp
);
2876 #endif /* BRIDGESTP */
2878 bridge_rtflush(sc
, IFBF_FLUSHDYN
);
2880 (void) ifnet_set_flags(ifp
, 0, IFF_RUNNING
);
2886 * Enqueue a packet on a bridge member interface.
2890 bridge_enqueue(struct bridge_softc
*sc
, struct ifnet
*dst_ifp
, struct mbuf
*m
)
2896 VERIFY(dst_ifp
!= NULL
);
2899 * We may be sending a fragment so traverse the mbuf
2901 * NOTE: bridge_fragment() is called only when PFIL_HOOKS is enabled.
2905 struct flowadv adv
= { FADV_SUCCESS
};
2908 m
->m_nextpkt
= NULL
;
2910 len
= m
->m_pkthdr
.len
;
2911 mflags
= m
->m_flags
;
2912 m
->m_flags
|= M_PROTO1
; /* set to avoid loops */
2916 * If underlying interface can not do VLAN tag insertion itself
2917 * then attach a packet tag that holds it.
2919 if ((m
->m_flags
& M_VLANTAG
) &&
2920 (dst_ifp
->if_capenable
& IFCAP_VLAN_HWTAGGING
) == 0) {
2921 m
= ether_vlanencap(m
, m
->m_pkthdr
.ether_vtag
);
2923 printf("%s: %s%d: unable to prepend VLAN "
2924 "header\n", __func__
, ifnet_name(dst_ifp
),
2925 ifnet_unit(dst_ifp
));
2926 (void) ifnet_stat_increment_out(dst_ifp
,
2930 m
->m_flags
&= ~M_VLANTAG
;
2932 #endif /* HAS_IF_CAP */
2934 _error
= dlil_output(dst_ifp
, 0, m
, NULL
, NULL
, 1, &adv
);
2936 /* Preserve existing error value */
2940 else if (adv
.code
== FADV_FLOW_CONTROLLED
)
2942 else if (adv
.code
== FADV_SUSPENDED
)
2943 error
= EQSUSPENDED
;
2947 (void) ifnet_stat_increment_out(sc
->sc_ifp
, 1, len
, 0);
2949 (void) ifnet_stat_increment_out(sc
->sc_ifp
, 0, 0, 1);
2956 #if HAS_BRIDGE_DUMMYNET
2960 * Receive a queued packet from dummynet and pass it on to the output
2963 * The mbuf has the Ethernet header already attached.
2966 bridge_dummynet(struct mbuf
*m
, struct ifnet
*ifp
)
2968 struct bridge_softc
*sc
;
2970 sc
= ifp
->if_bridge
;
2973 * The packet didnt originate from a member interface. This should only
2974 * ever happen if a member interface is removed while packets are
2982 if (PFIL_HOOKED(&inet_pfil_hook
)
2984 || PFIL_HOOKED(&inet6_pfil_hook
)
2987 if (bridge_pfil(&m
, sc
->sc_ifp
, ifp
, PFIL_OUT
) != 0)
2993 (void) bridge_enqueue(sc
, ifp
, m
);
2995 #endif /* HAS_BRIDGE_DUMMYNET */
2997 #if BRIDGE_MEMBER_OUT_FILTER
2999 * bridge_member_output:
3001 * Send output from a bridge member interface. This
3002 * performs the bridging function for locally originated
3005 * The mbuf has the Ethernet header already attached. We must
3006 * enqueue or free the mbuf before returning.
3009 bridge_member_output(struct ifnet
*ifp
, struct mbuf
*m
,
3010 __unused
struct sockaddr
*sa
, __unused
struct rtentry
*rt
)
3012 struct ether_header
*eh
;
3013 struct ifnet
*dst_if
;
3014 struct bridge_softc
*sc
;
3018 if (if_bridge_debug
)
3019 printf("%s: ifp %p %s%d\n", __func__
, ifp
, ifnet_name(ifp
),
3021 #endif /* BRIDGE_DEBUG */
3023 if (m
->m_len
< ETHER_HDR_LEN
) {
3024 m
= m_pullup(m
, ETHER_HDR_LEN
);
3029 eh
= mtod(m
, struct ether_header
*);
3030 sc
= ifp
->if_bridge
;
3031 vlan
= VLANTAGOF(m
);
3036 * APPLE MODIFICATION
3037 * If the packet is an 802.1X ethertype, then only send on the
3038 * original output interface.
3040 if (eh
->ether_type
== htons(ETHERTYPE_PAE
)) {
3046 * If bridge is down, but the original output interface is up,
3047 * go ahead and send out that interface. Otherwise, the packet
3050 if ((sc
->sc_ifp
->if_flags
& IFF_RUNNING
) == 0) {
3056 * If the packet is a multicast, or we don't know a better way to
3057 * get there, send to all interfaces.
3059 if (ETHER_IS_MULTICAST(eh
->ether_dhost
))
3062 dst_if
= bridge_rtlookup(sc
, eh
->ether_dhost
, vlan
);
3063 if (dst_if
== NULL
) {
3064 struct bridge_iflist
*bif
;
3066 int error
= 0, used
= 0;
3070 BRIDGE_LOCK2REF(sc
, error
);
3076 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
3077 dst_if
= bif
->bif_ifp
;
3079 if (dst_if
->if_type
== IFT_GIF
)
3081 if ((dst_if
->if_flags
& IFF_RUNNING
) == 0)
3085 * If this is not the original output interface,
3086 * and the interface is participating in spanning
3087 * tree, make sure the port is in a state that
3088 * allows forwarding.
3090 if (dst_if
!= ifp
&& (bif
->bif_flags
& IFBIF_STP
) &&
3091 bif
->bif_stp
.bp_state
== BSTP_IFSTATE_DISCARDING
)
3094 if (LIST_NEXT(bif
, bif_next
) == NULL
) {
3098 mc
= m_copypacket(m
, M_DONTWAIT
);
3100 (void) ifnet_stat_increment_out(
3101 sc
->sc_ifp
, 0, 0, 1);
3106 (void) bridge_enqueue(sc
, dst_if
, mc
);
3116 * XXX Spanning tree consideration here?
3120 if ((dst_if
->if_flags
& IFF_RUNNING
) == 0) {
3127 (void) bridge_enqueue(sc
, dst_if
, m
);
3130 #endif /* BRIDGE_MEMBER_OUT_FILTER */
3132 #if APPLE_BRIDGE_HWCKSUM_SUPPORT
3133 static struct mbuf
*
3134 bridge_fix_txcsum(struct mbuf
*m
)
3137 * basic tests indicate that the vast majority of packets being
3138 * processed here have an Ethernet header mbuf pre-pended to them
3139 * (the first case below)
3141 * the second highest are those where the Ethernet and IP/TCP/UDP
3142 * headers are all in one mbuf (second case below)
3144 * the third case has, in fact, never hit for me -- although if I
3145 * comment out the first two cases, that code works for them, so I
3146 * consider it a decent general solution
3148 int amt
= ETHER_HDR_LEN
;
3149 int hlen
= M_CSUM_DATA_IPv4_IPHL(m
->m_pkthdr
.csum_data
);
3150 int off
= M_CSUM_DATA_IPv4_OFFSET(m
->m_pkthdr
.csum_data
);
3153 * NOTE we should never get vlan-attached packets here;
3154 * support for those COULD be added, but we don't use them
3155 * and it really kinda slows things down to worry about them
3159 if (m_tag_find(m
, PACKET_TAG_VLAN
, NULL
) != NULL
) {
3160 printf("%s: transmitting packet tagged with VLAN?\n", __func__
);
3167 if (m
->m_pkthdr
.csum_flags
& M_CSUM_IPv4
) {
3170 if (m
->m_pkthdr
.csum_flags
& M_CSUM_TCPv4
) {
3171 amt
+= off
+ sizeof (uint16_t);
3174 if (m
->m_pkthdr
.csum_flags
& M_CSUM_UDPv4
) {
3175 amt
+= off
+ sizeof (uint16_t);
3178 if (m
->m_len
== ETHER_HDR_LEN
) {
3180 * this is the case where there's an Ethernet header in an
3181 * mbuf the first mbuf is the Ethernet header -- just strip
3182 * it off and do the checksum
3184 /* set up m_ip so the cksum operations work */
3185 struct mbuf
*m_ip
= m
->m_next
;
3187 /* APPLE MODIFICATION 22 Apr 2008 <mvega@apple.com>
3188 * <rdar://5817385> Clear the m_tag list before setting
3191 * If this m_buf chain was extended via M_PREPEND(), then
3192 * m_ip->m_pkthdr is identical to m->m_pkthdr (see
3193 * M_MOVE_PKTHDR()). The only thing preventing access to this
3194 * invalid packet header data is the fact that the M_PKTHDR
3195 * flag is clear, i.e., m_ip->m_flag & M_PKTHDR == 0, but we're
3196 * about to set the M_PKTHDR flag, so to be safe we initialize,
3197 * more accurately, we clear, m_ip->m_pkthdr.tags via
3200 * Suppose that we do not do this; if m_pullup(), below, fails,
3201 * then m_ip will be freed along with m_ip->m_pkthdr.tags, but
3202 * we will also free m soon after, via m_freem(), and
3203 * consequently attempt to free m->m_pkthdr.tags in the
3204 * process. The problem is that m->m_pkthdr.tags will have
3205 * already been freed by virtue of being equal to
3206 * m_ip->m_pkthdr.tags. Attempts to dereference
3207 * m->m_pkthdr.tags in m_tag_delete_chain() will result in a
3211 /* END MODIFICATION */
3212 m_ip
->m_flags
|= M_PKTHDR
;
3213 m_ip
->m_pkthdr
.csum_flags
= m
->m_pkthdr
.csum_flags
;
3214 m_ip
->m_pkthdr
.csum_data
= m
->m_pkthdr
.csum_data
;
3215 m_ip
->m_pkthdr
.len
= m
->m_pkthdr
.len
- ETHER_HDR_LEN
;
3218 * set up the header mbuf so we can prepend it
3219 * back on again later
3221 m
->m_pkthdr
.csum_flags
= 0;
3222 m
->m_pkthdr
.csum_data
= 0;
3223 m
->m_pkthdr
.len
= ETHER_HDR_LEN
;
3226 /* now do the checksums we need -- first IP */
3227 if (m_ip
->m_pkthdr
.csum_flags
& M_CSUM_IPv4
) {
3229 * make sure the IP header (or at least the part with
3230 * the cksum) is there
3232 m_ip
= m_pullup(m_ip
, sizeof (struct ip
));
3234 printf("%s: failed to flatten header\n",
3240 /* now do the checksum */
3242 struct ip
*ip
= mtod(m_ip
, struct ip
*);
3243 ip
->ip_sum
= in_cksum(m_ip
, hlen
);
3245 #ifdef VERY_VERY_VERY_DIAGNOSTIC
3246 printf("%s: performed IPv4 checksum\n",
3252 /* now do a TCP or UDP delayed checksum */
3253 if (m_ip
->m_pkthdr
.csum_flags
& (M_CSUM_TCPv4
|M_CSUM_UDPv4
)) {
3254 in_delayed_cksum(m_ip
);
3256 #ifdef VERY_VERY_VERY_DIAGNOSTIC
3257 printf("%s: performed TCPv4/UDPv4 checksum\n",
3262 /* now attach the ethernet header back onto the IP packet */
3264 m
->m_pkthdr
.len
+= m_length(m_ip
);
3267 * clear the M_PKTHDR flags on the ip packet (again,
3268 * we re-attach later)
3270 m_ip
->m_flags
&= ~M_PKTHDR
;
3272 /* and clear any csum flags */
3273 m
->m_pkthdr
.csum_flags
&=
3274 ~(M_CSUM_TCPv4
|M_CSUM_UDPv4
|M_CSUM_IPv4
);
3275 } else if (m
->m_len
>= amt
) {
3277 * everything fits in the first mbuf, so futz with
3278 * m->m_data, m->m_len and m->m_pkthdr.len to make it work
3280 m
->m_len
-= ETHER_HDR_LEN
;
3281 m
->m_data
+= ETHER_HDR_LEN
;
3282 m
->m_pkthdr
.len
-= ETHER_HDR_LEN
;
3284 /* now do the checksums we need -- first IP */
3285 if (m
->m_pkthdr
.csum_flags
& M_CSUM_IPv4
) {
3286 struct ip
*ip
= mtod(m
, struct ip
*);
3287 ip
->ip_sum
= in_cksum(m
, hlen
);
3289 #ifdef VERY_VERY_VERY_DIAGNOSTIC
3290 printf("%s: performed IPv4 checksum\n", __func__
);
3294 // now do a TCP or UDP delayed checksum
3295 if (m
->m_pkthdr
.csum_flags
& (M_CSUM_TCPv4
|M_CSUM_UDPv4
)) {
3296 in_delayed_cksum(m
);
3298 #ifdef VERY_VERY_VERY_DIAGNOSTIC
3299 printf("%s: performed TCPv4/UDPv4 checksum\n",
3304 /* now stick the ethernet header back on */
3305 m
->m_len
+= ETHER_HDR_LEN
;
3306 m
->m_data
-= ETHER_HDR_LEN
;
3307 m
->m_pkthdr
.len
+= ETHER_HDR_LEN
;
3309 /* and clear any csum flags */
3310 m
->m_pkthdr
.csum_flags
&=
3311 ~(M_CSUM_TCPv4
|M_CSUM_UDPv4
|M_CSUM_IPv4
);
3316 * general case -- need to simply split it off and deal
3317 * first, calculate how much needs to be made writable
3318 * (we may have a read-only mbuf here)
3320 hlen
= M_CSUM_DATA_IPv4_IPHL(m
->m_pkthdr
.csum_data
);
3322 off
= M_CSUM_DATA_IPv4_OFFSET(m
->m_pkthdr
.csum_data
);
3324 if (m
->m_pkthdr
.csum_flags
& M_CSUM_IPv4
) {
3328 if (m
->m_pkthdr
.csum_flags
& M_CSUM_TCPv4
) {
3329 amt
+= sizeof (struct tcphdr
*);
3333 if (m
->m_pkthdr
.csum_flags
& M_CSUM_UDPv4
) {
3334 amt
+= sizeof (struct udphdr
*);
3340 * now split the ethernet header off of the IP packet
3341 * (we'll re-attach later)
3343 m_ip
= m_split(m
, ETHER_HDR_LEN
, M_NOWAIT
);
3345 printf("%s: could not split ether header\n", __func__
);
3353 * make sure that the IP packet is writable
3354 * for the portion we need
3356 if (m_makewritable(&m_ip
, 0, amt
, M_DONTWAIT
) != 0) {
3357 printf("%s: could not make %d bytes writable\n",
3366 m_ip
->m_pkthdr
.csum_flags
= m
->m_pkthdr
.csum_flags
;
3367 m_ip
->m_pkthdr
.csum_data
= m
->m_pkthdr
.csum_data
;
3369 m
->m_pkthdr
.csum_flags
= 0;
3370 m
->m_pkthdr
.csum_data
= 0;
3372 /* now do the checksums we need -- first IP */
3373 if (m_ip
->m_pkthdr
.csum_flags
& M_CSUM_IPv4
) {
3375 * make sure the IP header (or at least the part
3376 * with the cksum) is there
3378 m_ip
= m_pullup(m_ip
, sizeof (struct ip
));
3380 printf("%s: failed to flatten header\n",
3386 /* now do the checksum */
3388 struct ip
*ip
= mtod(m_ip
, struct ip
*);
3389 ip
->ip_sum
= in_cksum(m_ip
, hlen
);
3391 #ifdef VERY_VERY_VERY_DIAGNOSTIC
3392 printf("%s: performed IPv4 checksum\n",
3398 /* now do a TCP or UDP delayed checksum */
3399 if (m_ip
->m_pkthdr
.csum_flags
& (M_CSUM_TCPv4
|M_CSUM_UDPv4
)) {
3400 in_delayed_cksum(m_ip
);
3402 #ifdef VERY_VERY_VERY_DIAGNOSTIC
3403 printf("%s: performed TCPv4/UDPv4 checksum\n",
3408 // now attach the ethernet header back onto the IP packet
3410 m
->m_pkthdr
.len
+= m_length(m_ip
);
3413 * clear the M_PKTHDR flags on the ip packet
3414 * (again, we re-attach later)
3416 m_ip
->m_flags
&= ~M_PKTHDR
;
3418 /* and clear any csum flags */
3419 m
->m_pkthdr
.csum_flags
&=
3420 ~(M_CSUM_TCPv4
|M_CSUM_UDPv4
|M_CSUM_IPv4
);
3430 * This routine is called externally from above only when if_bridge_txstart
3431 * is disabled; otherwise it is called internally by bridge_start().
3434 bridge_output(struct ifnet
*ifp
, struct mbuf
*m
)
3436 struct bridge_softc
*sc
= ifnet_softc(ifp
);
3437 struct ether_header
*eh
;
3438 struct ifnet
*dst_if
;
3441 eh
= mtod(m
, struct ether_header
*);
3445 if (!(m
->m_flags
& (M_BCAST
|M_MCAST
))) {
3446 dst_if
= bridge_rtlookup(sc
, eh
->ether_dhost
, 0);
3449 #if APPLE_BRIDGE_HWCKSUM_SUPPORT
3451 * APPLE MODIFICATION - if the packet needs a checksum
3452 * (i.e., checksum has been deferred for HW support)
3453 * AND the destination interface doesn't support HW
3454 * checksums, then we need to fix-up the checksum here
3456 if ((m
->m_pkthdr
.csum_flags
&
3457 (M_CSUM_TCPv4
|M_CSUM_UDPv4
|M_CSUM_IPv4
)) &&
3459 (dst_if
->if_csum_flags_tx
& m
->m_pkthdr
.csum_flags
) !=
3460 m
->m_pkthdr
.csum_flags
)) {
3461 m
= bridge_fix_txcsum(m
);
3468 if (eh
->ether_type
== htons(ETHERTYPE_IP
))
3469 mbuf_outbound_finalize(m
, PF_INET
, sizeof (*eh
));
3471 m
->m_pkthdr
.csum_flags
= 0;
3472 #endif /* APPLE_BRIDGE_HWCKSUM_SUPPORT */
3474 atomic_add_64(&ifp
->if_obytes
, m
->m_pkthdr
.len
);
3475 atomic_add_64(&ifp
->if_opackets
, 1);
3478 if (sc
->sc_bpf_output
)
3479 bridge_bpf_output(ifp
, m
);
3482 if (dst_if
== NULL
) {
3483 /* callee will unlock */
3484 bridge_broadcast(sc
, ifp
, m
, 0);
3487 error
= bridge_enqueue(sc
, dst_if
, m
);
3496 * Start output on a bridge.
3498 * This routine is invoked by the start worker thread; because we never call
3499 * it directly, there is no need do deploy any serialization mechanism other
3500 * than what's already used by the worker thread, i.e. this is already single
3503 * This routine is called only when if_bridge_txstart is enabled.
3506 bridge_start(struct ifnet
*ifp
)
3511 if (ifnet_dequeue(ifp
, &m
) != 0)
3514 (void) bridge_output(ifp
, m
);
3521 * The forwarding function of the bridge.
3523 * NOTE: Releases the lock on return.
3526 bridge_forward(struct bridge_softc
*sc
, struct bridge_iflist
*sbif
,
3529 struct bridge_iflist
*dbif
;
3530 struct ifnet
*src_if
, *dst_if
, *ifp
;
3531 struct ether_header
*eh
;
3536 lck_mtx_assert(sc
->sc_mtx
, LCK_MTX_ASSERT_OWNED
);
3539 if (if_bridge_debug
)
3540 printf("%s: %s%d m%p\n", __func__
, ifnet_name(sc
->sc_ifp
),
3541 ifnet_unit(sc
->sc_ifp
), m
);
3542 #endif /* BRIDGE_DEBUG */
3544 src_if
= m
->m_pkthdr
.rcvif
;
3547 (void) ifnet_stat_increment_in(ifp
, 1, m
->m_pkthdr
.len
, 0);
3548 vlan
= VLANTAGOF(m
);
3551 if ((sbif
->bif_flags
& IFBIF_STP
) &&
3552 sbif
->bif_stp
.bp_state
== BSTP_IFSTATE_DISCARDING
)
3555 eh
= mtod(m
, struct ether_header
*);
3556 dst
= eh
->ether_dhost
;
3558 /* If the interface is learning, record the address. */
3559 if (sbif
->bif_flags
& IFBIF_LEARNING
) {
3560 error
= bridge_rtupdate(sc
, eh
->ether_shost
, vlan
,
3561 sbif
, 0, IFBAF_DYNAMIC
);
3563 * If the interface has addresses limits then deny any source
3564 * that is not in the cache.
3566 if (error
&& sbif
->bif_addrmax
)
3570 if ((sbif
->bif_flags
& IFBIF_STP
) != 0 &&
3571 sbif
->bif_stp
.bp_state
== BSTP_IFSTATE_LEARNING
)
3575 * At this point, the port either doesn't participate
3576 * in spanning tree or it is in the forwarding state.
3580 * If the packet is unicast, destined for someone on
3581 * "this" side of the bridge, drop it.
3583 if ((m
->m_flags
& (M_BCAST
|M_MCAST
)) == 0) {
3584 dst_if
= bridge_rtlookup(sc
, dst
, vlan
);
3585 if (src_if
== dst_if
)
3589 * Check if its a reserved multicast address, any address
3590 * listed in 802.1D section 7.12.6 may not be forwarded by the
3592 * This is currently 01-80-C2-00-00-00 to 01-80-C2-00-00-0F
3594 if (dst
[0] == 0x01 && dst
[1] == 0x80 &&
3595 dst
[2] == 0xc2 && dst
[3] == 0x00 &&
3596 dst
[4] == 0x00 && dst
[5] <= 0x0f)
3600 /* ...forward it to all interfaces. */
3601 atomic_add_64(&ifp
->if_imcasts
, 1);
3606 * If we have a destination interface which is a member of our bridge,
3607 * OR this is a unicast packet, push it through the bpf(4) machinery.
3608 * For broadcast or multicast packets, don't bother because it will
3609 * be reinjected into ether_input. We do this before we pass the packets
3610 * through the pfil(9) framework, as it is possible that pfil(9) will
3611 * drop the packet, or possibly modify it, making it difficult to debug
3612 * firewall issues on the bridge.
3615 if (eh
->ether_type
== htons(ETHERTYPE_RSN_PREAUTH
) ||
3616 dst_if
!= NULL
|| (m
->m_flags
& (M_BCAST
| M_MCAST
)) == 0) {
3617 m
->m_pkthdr
.rcvif
= ifp
;
3618 if (sc
->sc_bpf_input
)
3619 bridge_bpf_input(ifp
, m
);
3621 #endif /* NBPFILTER */
3623 #if defined(PFIL_HOOKS)
3624 /* run the packet filter */
3625 if (PFIL_HOOKED(&inet_pfil_hook
)
3627 || PFIL_HOOKED(&inet6_pfil_hook
)
3631 if (bridge_pfil(&m
, ifp
, src_if
, PFIL_IN
) != 0)
3637 #endif /* PFIL_HOOKS */
3639 if (dst_if
== NULL
) {
3641 * Clear any in-bound checksum flags for this packet.
3643 mbuf_inbound_modified(m
);
3645 bridge_broadcast(sc
, src_if
, m
, 1);
3651 * At this point, we're dealing with a unicast frame
3652 * going to a different interface.
3654 if ((dst_if
->if_flags
& IFF_RUNNING
) == 0)
3657 dbif
= bridge_lookup_member_if(sc
, dst_if
);
3659 /* Not a member of the bridge (anymore?) */
3662 /* Private segments can not talk to each other */
3663 if (sbif
->bif_flags
& dbif
->bif_flags
& IFBIF_PRIVATE
)
3666 if ((dbif
->bif_flags
& IFBIF_STP
) &&
3667 dbif
->bif_stp
.bp_state
== BSTP_IFSTATE_DISCARDING
)
3671 /* APPLE MODIFICATION <rdar://6985737> */
3672 if ((dst_if
->if_extflags
& IFEXTF_DHCPRA_MASK
) != 0) {
3673 m
= ip_xdhcpra_output(dst_if
, m
);
3675 ++sc
->sc_sc
.sc_ifp
.if_xdhcpra
;
3679 #endif /* HAS_DHCPRA_MASK */
3683 #if defined(PFIL_HOOKS)
3684 if (PFIL_HOOKED(&inet_pfil_hook
)
3686 || PFIL_HOOKED(&inet6_pfil_hook
)
3689 if (bridge_pfil(&m
, ifp
, dst_if
, PFIL_OUT
) != 0)
3694 #endif /* PFIL_HOOKS */
3697 * Clear any in-bound checksum flags for this packet.
3699 mbuf_inbound_modified(m
);
3701 (void) bridge_enqueue(sc
, dst_if
, m
);
3711 char *ether_ntop(char *, size_t, const u_char
*);
3713 __private_extern__
char *
3714 ether_ntop(char *buf
, size_t len
, const u_char
*ap
)
3716 snprintf(buf
, len
, "%02x:%02x:%02x:%02x:%02x:%02x",
3717 ap
[0], ap
[1], ap
[2], ap
[3], ap
[4], ap
[5]);
3722 #endif /* BRIDGE_DEBUG */
3727 * Filter input from a member interface. Queue the packet for
3728 * bridging if it is not for us.
3730 __private_extern__ errno_t
3731 bridge_input(struct ifnet
*ifp
, struct mbuf
*m
, __unused
void *frame_header
)
3733 struct bridge_softc
*sc
= ifp
->if_bridge
;
3734 struct bridge_iflist
*bif
, *bif2
;
3736 struct ether_header
*eh
;
3737 struct mbuf
*mc
, *mc2
;
3742 if (if_bridge_debug
)
3743 printf("%s: %s%d from %s%d m %p data %p\n", __func__
,
3744 ifnet_name(sc
->sc_ifp
), ifnet_unit(sc
->sc_ifp
),
3745 ifnet_name(ifp
), ifnet_unit(ifp
), m
, mbuf_data(m
));
3746 #endif /* BRIDGE_DEBUG */
3748 if ((sc
->sc_ifp
->if_flags
& IFF_RUNNING
) == 0) {
3750 if (if_bridge_debug
)
3751 printf("%s: %s%d not running passing along\n",
3752 __func__
, ifnet_name(sc
->sc_ifp
),
3753 ifnet_unit(sc
->sc_ifp
));
3754 #endif /* BRIDGE_DEBUG */
3759 vlan
= VLANTAGOF(m
);
3763 * Implement support for bridge monitoring. If this flag has been
3764 * set on this interface, discard the packet once we push it through
3765 * the bpf(4) machinery, but before we do, increment the byte and
3766 * packet counters associated with this interface.
3768 if ((bifp
->if_flags
& IFF_MONITOR
) != 0) {
3769 m
->m_pkthdr
.rcvif
= bifp
;
3770 BRIDGE_BPF_MTAP_INPUT(sc
, m
);
3771 (void) ifnet_stat_increment_in(bifp
, 1, m
->m_pkthdr
.len
, 0);
3773 return (EJUSTRETURN
);
3775 #endif /* IFF_MONITOR */
3778 * Need to clear the promiscous flags otherwise it will be
3779 * dropped by DLIL after processing filters
3781 if ((mbuf_flags(m
) & MBUF_PROMISC
))
3782 mbuf_setflags_mask(m
, 0, MBUF_PROMISC
);
3785 bif
= bridge_lookup_member_if(sc
, ifp
);
3789 if (if_bridge_debug
)
3790 printf("%s: %s%d bridge_lookup_member_if failed\n",
3791 __func__
, ifnet_name(sc
->sc_ifp
),
3792 ifnet_unit(sc
->sc_ifp
));
3793 #endif /* BRIDGE_DEBUG */
3797 eh
= mtod(m
, struct ether_header
*);
3801 if (m
->m_flags
& (M_BCAST
|M_MCAST
)) {
3804 if (if_bridge_debug
)
3805 if ((m
->m_flags
& M_MCAST
))
3806 printf("%s: mulicast: "
3807 "%02x:%02x:%02x:%02x:%02x:%02x\n",
3809 eh
->ether_dhost
[0], eh
->ether_dhost
[1],
3810 eh
->ether_dhost
[2], eh
->ether_dhost
[3],
3811 eh
->ether_dhost
[4], eh
->ether_dhost
[5]);
3812 #endif /* BRIDGE_DEBUG */
3814 /* Tap off 802.1D packets; they do not get forwarded. */
3815 if (memcmp(eh
->ether_dhost
, bstp_etheraddr
,
3816 ETHER_ADDR_LEN
) == 0) {
3818 m
= bstp_input(&bif
->bif_stp
, ifp
, m
);
3819 #else /* !BRIDGESTP */
3822 #endif /* !BRIDGESTP */
3825 return (EJUSTRETURN
);
3829 if ((bif
->bif_flags
& IFBIF_STP
) &&
3830 bif
->bif_stp
.bp_state
== BSTP_IFSTATE_DISCARDING
) {
3836 * Make a deep copy of the packet and enqueue the copy
3837 * for bridge processing; return the original packet for
3840 mc
= m_dup(m
, M_DONTWAIT
);
3847 * Perform the bridge forwarding function with the copy.
3849 * Note that bridge_forward calls BRIDGE_UNLOCK
3851 bridge_forward(sc
, bif
, mc
);
3854 * Reinject the mbuf as arriving on the bridge so we have a
3855 * chance at claiming multicast packets. We can not loop back
3856 * here from ether_input as a bridge is never a member of a
3859 KASSERT(bifp
->if_bridge
== NULL
,
3860 ("loop created in bridge_input"));
3861 mc2
= m_dup(m
, M_DONTWAIT
);
3863 /* Keep the layer3 header aligned */
3864 int i
= min(mc2
->m_pkthdr
.len
, max_protohdr
);
3865 mc2
= m_copyup(mc2
, i
, ETHER_ALIGN
);
3868 // mark packet as arriving on the bridge
3869 mc2
->m_pkthdr
.rcvif
= bifp
;
3870 mc2
->m_pkthdr
.header
= mbuf_data(mc2
);
3873 if (sc
->sc_bpf_input
)
3874 bridge_bpf_input(bifp
, mc2
);
3875 #endif /* NBPFILTER */
3876 (void) mbuf_setdata(mc2
,
3877 (char *)mbuf_data(mc2
) + ETHER_HDR_LEN
,
3878 mbuf_len(mc2
) - ETHER_HDR_LEN
);
3879 (void) mbuf_pkthdr_adjustlen(mc2
, - ETHER_HDR_LEN
);
3881 (void) ifnet_stat_increment_in(bifp
, 1,
3882 mbuf_pkthdr_len(mc2
), 0);
3885 if (if_bridge_debug
)
3886 printf("%s: %s%d mcast for us\n", __func__
,
3887 ifnet_name(sc
->sc_ifp
),
3888 ifnet_unit(sc
->sc_ifp
));
3889 #endif /* BRIDGE_DEBUG */
3891 dlil_input_packet_list(bifp
, mc2
);
3894 /* Return the original packet for local processing. */
3898 if ((bif
->bif_flags
& IFBIF_STP
) &&
3899 bif
->bif_stp
.bp_state
== BSTP_IFSTATE_DISCARDING
) {
3905 # define OR_CARP_CHECK_WE_ARE_DST(iface) \
3906 || ((iface)->if_carp \
3907 && carp_forus((iface)->if_carp, eh->ether_dhost))
3908 # define OR_CARP_CHECK_WE_ARE_SRC(iface) \
3909 || ((iface)->if_carp \
3910 && carp_forus((iface)->if_carp, eh->ether_shost))
3912 # define OR_CARP_CHECK_WE_ARE_DST(iface)
3913 # define OR_CARP_CHECK_WE_ARE_SRC(iface)
3917 # define OR_PFIL_HOOKED_INET6 \
3918 || PFIL_HOOKED(&inet6_pfil_hook)
3920 # define OR_PFIL_HOOKED_INET6
3923 #if defined(PFIL_HOOKS)
3924 #define PFIL_PHYS(sc, ifp, m) do { \
3925 if (pfil_local_phys && \
3926 (PFIL_HOOKED(&inet_pfil_hook) OR_PFIL_HOOKED_INET6)) { \
3927 if (bridge_pfil(&m, NULL, ifp, \
3928 PFIL_IN) != 0 || m == NULL) { \
3929 BRIDGE_UNLOCK(sc); \
3934 #else /* PFIL_HOOKS */
3935 #define PFIL_PHYS(sc, ifp, m)
3936 #endif /* PFIL_HOOKS */
3938 #define GRAB_OUR_PACKETS(iface) \
3939 if ((iface)->if_type == IFT_GIF) \
3941 /* It is destined for us. */ \
3942 if (memcmp(ifnet_lladdr((iface)), eh->ether_dhost, \
3943 ETHER_ADDR_LEN) == 0 OR_CARP_CHECK_WE_ARE_DST((iface))) { \
3944 if ((iface)->if_type == IFT_BRIDGE) { \
3945 BRIDGE_BPF_MTAP_INPUT(sc, m); \
3946 /* Filter on the physical interface. */ \
3947 PFIL_PHYS(sc, iface, m); \
3949 if (bif->bif_flags & IFBIF_LEARNING) { \
3950 error = bridge_rtupdate(sc, eh->ether_shost, \
3951 vlan, bif, 0, IFBAF_DYNAMIC); \
3952 if (error && bif->bif_addrmax) { \
3953 BRIDGE_UNLOCK(sc); \
3954 return (EJUSTRETURN); \
3957 m->m_pkthdr.rcvif = iface; \
3958 BRIDGE_UNLOCK(sc); \
3962 /* We just received a packet that we sent out. */ \
3963 if (memcmp(ifnet_lladdr((iface)), eh->ether_shost, \
3964 ETHER_ADDR_LEN) == 0 OR_CARP_CHECK_WE_ARE_SRC((iface))) { \
3965 BRIDGE_UNLOCK(sc); \
3966 return (EJUSTRETURN); \
3973 * If the packet is for us, set the packets source as the
3974 * bridge, and return the packet back to ether_input for
3977 if (memcmp(eh
->ether_dhost
, ifnet_lladdr(bifp
),
3978 ETHER_ADDR_LEN
) == 0 OR_CARP_CHECK_WE_ARE_DST(bifp
)) {
3980 /* Mark the packet as arriving on the bridge interface */
3981 (void) mbuf_pkthdr_setrcvif(m
, bifp
);
3982 mbuf_pkthdr_setheader(m
, frame_header
);
3985 * If the interface is learning, and the source
3986 * address is valid and not multicast, record
3989 if ((bif
->bif_flags
& IFBIF_LEARNING
) != 0 &&
3990 ETHER_IS_MULTICAST(eh
->ether_shost
) == 0 &&
3991 (eh
->ether_shost
[0] | eh
->ether_shost
[1] |
3992 eh
->ether_shost
[2] | eh
->ether_shost
[3] |
3993 eh
->ether_shost
[4] | eh
->ether_shost
[5]) != 0) {
3994 (void) bridge_rtupdate(sc
, eh
->ether_shost
,
3995 vlan
, bif
, 0, IFBAF_DYNAMIC
);
3998 BRIDGE_BPF_MTAP_INPUT(sc
, m
);
4000 (void) mbuf_setdata(m
, (char *)mbuf_data(m
) + ETHER_HDR_LEN
,
4001 mbuf_len(m
) - ETHER_HDR_LEN
);
4002 (void) mbuf_pkthdr_adjustlen(m
, - ETHER_HDR_LEN
);
4004 (void) ifnet_stat_increment_in(bifp
, 1, mbuf_pkthdr_len(m
), 0);
4009 if (if_bridge_debug
)
4010 printf("%s: %s%d packet for bridge\n", __func__
,
4011 ifnet_name(sc
->sc_ifp
), ifnet_unit(sc
->sc_ifp
));
4012 #endif /* BRIDGE_DEBUG */
4014 dlil_input_packet_list(bifp
, m
);
4016 return (EJUSTRETURN
);
4020 * if the destination of the packet is for the MAC address of
4021 * the member interface itself, then we don't need to forward
4022 * it -- just pass it back. Note that it'll likely just be
4023 * dropped by the stack, but if something else is bound to
4024 * the interface directly (for example, the wireless stats
4025 * protocol -- although that actually uses BPF right now),
4026 * then it will consume the packet
4028 * ALSO, note that we do this check AFTER checking for the
4029 * bridge's own MAC address, because the bridge may be
4030 * using the SAME MAC address as one of its interfaces
4032 if (memcmp(eh
->ether_dhost
, ifnet_lladdr(ifp
), ETHER_ADDR_LEN
) == 0) {
4034 #ifdef VERY_VERY_VERY_DIAGNOSTIC
4035 printf("%s: not forwarding packet bound for member "
4036 "interface\n", __func__
);
4042 /* Now check the all bridge members. */
4043 TAILQ_FOREACH(bif2
, &sc
->sc_iflist
, bif_next
) {
4044 GRAB_OUR_PACKETS(bif2
->bif_ifp
)
4047 #undef OR_CARP_CHECK_WE_ARE_DST
4048 #undef OR_CARP_CHECK_WE_ARE_SRC
4049 #undef OR_PFIL_HOOKED_INET6
4050 #undef GRAB_OUR_PACKETS
4053 * Perform the bridge forwarding function.
4055 * Note that bridge_forward calls BRIDGE_UNLOCK
4057 bridge_forward(sc
, bif
, m
);
4059 return (EJUSTRETURN
);
4065 * Send a frame to all interfaces that are members of
4066 * the bridge, except for the one on which the packet
4069 * NOTE: Releases the lock on return.
4072 bridge_broadcast(struct bridge_softc
*sc
, struct ifnet
*src_if
,
4073 struct mbuf
*m
, int runfilt
)
4076 #pragma unused(runfilt)
4078 struct bridge_iflist
*dbif
, *sbif
;
4080 struct ifnet
*dst_if
;
4081 int error
= 0, used
= 0;
4083 sbif
= bridge_lookup_member_if(sc
, src_if
);
4085 BRIDGE_LOCK2REF(sc
, error
);
4092 /* Filter on the bridge interface before broadcasting */
4093 if (runfilt
&& (PFIL_HOOKED(&inet_pfil_hook
)
4095 || PFIL_HOOKED(&inet6_pfil_hook
)
4098 if (bridge_pfil(&m
, sc
->sc_ifp
, NULL
, PFIL_OUT
) != 0)
4103 #endif /* PFIL_HOOKS */
4105 TAILQ_FOREACH(dbif
, &sc
->sc_iflist
, bif_next
) {
4106 dst_if
= dbif
->bif_ifp
;
4107 if (dst_if
== src_if
)
4110 /* Private segments can not talk to each other */
4111 if (sbif
&& (sbif
->bif_flags
& dbif
->bif_flags
& IFBIF_PRIVATE
))
4114 if ((dbif
->bif_flags
& IFBIF_STP
) &&
4115 dbif
->bif_stp
.bp_state
== BSTP_IFSTATE_DISCARDING
)
4118 if ((dbif
->bif_flags
& IFBIF_DISCOVER
) == 0 &&
4119 (m
->m_flags
& (M_BCAST
|M_MCAST
)) == 0)
4122 if ((dst_if
->if_flags
& IFF_RUNNING
) == 0)
4125 if (TAILQ_NEXT(dbif
, bif_next
) == NULL
) {
4129 mc
= m_dup(m
, M_DONTWAIT
);
4131 (void) ifnet_stat_increment_out(sc
->sc_ifp
,
4139 * Filter on the output interface. Pass a NULL bridge interface
4140 * pointer so we do not redundantly filter on the bridge for
4141 * each interface we broadcast on.
4143 if (runfilt
&& (PFIL_HOOKED(&inet_pfil_hook
)
4145 || PFIL_HOOKED(&inet6_pfil_hook
)
4149 /* Keep the layer3 header aligned */
4150 int i
= min(mc
->m_pkthdr
.len
, max_protohdr
);
4151 mc
= m_copyup(mc
, i
, ETHER_ALIGN
);
4153 (void) ifnet_stat_increment_out(
4154 sc
->sc_ifp
, 0, 0, 1);
4158 if (bridge_pfil(&mc
, NULL
, dst_if
, PFIL_OUT
) != 0)
4163 #endif /* PFIL_HOOKS */
4165 (void) bridge_enqueue(sc
, dst_if
, mc
);
4172 #endif /* PFIL_HOOKS */
4180 * Duplicate a packet out one or more interfaces that are in span mode,
4181 * the original mbuf is unmodified.
4184 bridge_span(struct bridge_softc
*sc
, struct mbuf
*m
)
4186 struct bridge_iflist
*bif
;
4187 struct ifnet
*dst_if
;
4190 if (TAILQ_EMPTY(&sc
->sc_spanlist
))
4193 TAILQ_FOREACH(bif
, &sc
->sc_spanlist
, bif_next
) {
4194 dst_if
= bif
->bif_ifp
;
4196 if ((dst_if
->if_flags
& IFF_RUNNING
) == 0)
4199 mc
= m_copypacket(m
, M_DONTWAIT
);
4201 (void) ifnet_stat_increment_out(sc
->sc_ifp
, 0, 0, 1);
4205 (void) bridge_enqueue(sc
, dst_if
, mc
);
4214 * Add a bridge routing entry.
4217 bridge_rtupdate(struct bridge_softc
*sc
, const uint8_t *dst
, uint16_t vlan
,
4218 struct bridge_iflist
*bif
, int setflags
, uint8_t flags
)
4220 struct bridge_rtnode
*brt
;
4223 BRIDGE_LOCK_ASSERT(sc
);
4225 /* Check the source address is valid and not multicast. */
4226 if (ETHER_IS_MULTICAST(dst
) ||
4227 (dst
[0] == 0 && dst
[1] == 0 && dst
[2] == 0 &&
4228 dst
[3] == 0 && dst
[4] == 0 && dst
[5] == 0) != 0)
4232 /* 802.1p frames map to vlan 1 */
4237 * A route for this destination might already exist. If so,
4238 * update it, otherwise create a new one.
4240 if ((brt
= bridge_rtnode_lookup(sc
, dst
, vlan
)) == NULL
) {
4241 if (sc
->sc_brtcnt
>= sc
->sc_brtmax
) {
4242 sc
->sc_brtexceeded
++;
4245 /* Check per interface address limits (if enabled) */
4246 if (bif
->bif_addrmax
&& bif
->bif_addrcnt
>= bif
->bif_addrmax
) {
4247 bif
->bif_addrexceeded
++;
4252 * Allocate a new bridge forwarding node, and
4253 * initialize the expiration time and Ethernet
4256 brt
= zalloc_noblock(bridge_rtnode_pool
);
4260 if (bif
->bif_flags
& IFBIF_STICKY
)
4261 brt
->brt_flags
= IFBAF_STICKY
;
4263 brt
->brt_flags
= IFBAF_DYNAMIC
;
4265 memcpy(brt
->brt_addr
, dst
, ETHER_ADDR_LEN
);
4266 brt
->brt_vlan
= vlan
;
4269 if ((error
= bridge_rtnode_insert(sc
, brt
)) != 0) {
4270 zfree(bridge_rtnode_pool
, brt
);
4277 if ((brt
->brt_flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
&&
4278 brt
->brt_dst
!= bif
) {
4279 brt
->brt_dst
->bif_addrcnt
--;
4281 brt
->brt_dst
->bif_addrcnt
++;
4284 if ((flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
) {
4285 struct timespec now
;
4288 brt
->brt_expire
= now
.tv_sec
+ sc
->sc_brttimeout
;
4291 brt
->brt_flags
= flags
;
4300 * Lookup the destination interface for an address.
4302 static struct ifnet
*
4303 bridge_rtlookup(struct bridge_softc
*sc
, const uint8_t *addr
, uint16_t vlan
)
4305 struct bridge_rtnode
*brt
;
4307 BRIDGE_LOCK_ASSERT(sc
);
4309 if ((brt
= bridge_rtnode_lookup(sc
, addr
, vlan
)) == NULL
)
4312 return (brt
->brt_ifp
);
4318 * Trim the routine table so that we have a number
4319 * of routing entries less than or equal to the
4323 bridge_rttrim(struct bridge_softc
*sc
)
4325 struct bridge_rtnode
*brt
, *nbrt
;
4327 BRIDGE_LOCK_ASSERT(sc
);
4329 /* Make sure we actually need to do this. */
4330 if (sc
->sc_brtcnt
<= sc
->sc_brtmax
)
4333 /* Force an aging cycle; this might trim enough addresses. */
4335 if (sc
->sc_brtcnt
<= sc
->sc_brtmax
)
4338 LIST_FOREACH_SAFE(brt
, &sc
->sc_rtlist
, brt_list
, nbrt
) {
4339 if ((brt
->brt_flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
) {
4340 bridge_rtnode_destroy(sc
, brt
);
4341 if (sc
->sc_brtcnt
<= sc
->sc_brtmax
)
4350 * Aging timer for the bridge.
4353 bridge_timer(void *arg
)
4355 struct bridge_softc
*sc
= arg
;
4363 if (sc
->sc_ifp
->if_flags
& IFF_RUNNING
) {
4366 ts
.tv_sec
= bridge_rtable_prune_period
;
4368 bsd_timeout(bridge_timer
, sc
, &ts
);
4375 * Perform an aging cycle.
4378 bridge_rtage(struct bridge_softc
*sc
)
4380 struct bridge_rtnode
*brt
, *nbrt
;
4382 BRIDGE_LOCK_ASSERT(sc
);
4384 LIST_FOREACH_SAFE(brt
, &sc
->sc_rtlist
, brt_list
, nbrt
) {
4385 if ((brt
->brt_flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
) {
4386 struct timespec now
;
4389 if ((unsigned long)now
.tv_sec
>= brt
->brt_expire
)
4390 bridge_rtnode_destroy(sc
, brt
);
4398 * Remove all dynamic addresses from the bridge.
4401 bridge_rtflush(struct bridge_softc
*sc
, int full
)
4403 struct bridge_rtnode
*brt
, *nbrt
;
4405 BRIDGE_LOCK_ASSERT(sc
);
4407 LIST_FOREACH_SAFE(brt
, &sc
->sc_rtlist
, brt_list
, nbrt
) {
4408 if (full
|| (brt
->brt_flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
)
4409 bridge_rtnode_destroy(sc
, brt
);
4416 * Remove an address from the table.
4419 bridge_rtdaddr(struct bridge_softc
*sc
, const uint8_t *addr
, uint16_t vlan
)
4421 struct bridge_rtnode
*brt
;
4424 BRIDGE_LOCK_ASSERT(sc
);
4427 * If vlan is zero then we want to delete for all vlans so the lookup
4428 * may return more than one.
4430 while ((brt
= bridge_rtnode_lookup(sc
, addr
, vlan
)) != NULL
) {
4431 bridge_rtnode_destroy(sc
, brt
);
4435 return (found
? 0 : ENOENT
);
4441 * Delete routes to a speicifc member interface.
4444 bridge_rtdelete(struct bridge_softc
*sc
, struct ifnet
*ifp
, int full
)
4446 struct bridge_rtnode
*brt
, *nbrt
;
4448 BRIDGE_LOCK_ASSERT(sc
);
4450 LIST_FOREACH_SAFE(brt
, &sc
->sc_rtlist
, brt_list
, nbrt
) {
4451 if (brt
->brt_ifp
== ifp
&& (full
||
4452 (brt
->brt_flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
))
4453 bridge_rtnode_destroy(sc
, brt
);
4458 * bridge_rtable_init:
4460 * Initialize the route table for this bridge.
4463 bridge_rtable_init(struct bridge_softc
*sc
)
4467 sc
->sc_rthash
= _MALLOC(sizeof (*sc
->sc_rthash
) * BRIDGE_RTHASH_SIZE
,
4468 M_DEVBUF
, M_NOWAIT
);
4469 if (sc
->sc_rthash
== NULL
)
4472 for (i
= 0; i
< BRIDGE_RTHASH_SIZE
; i
++)
4473 LIST_INIT(&sc
->sc_rthash
[i
]);
4475 sc
->sc_rthash_key
= random();
4477 LIST_INIT(&sc
->sc_rtlist
);
4483 * bridge_rtable_fini:
4485 * Deconstruct the route table for this bridge.
4488 bridge_rtable_fini(struct bridge_softc
*sc
)
4491 KASSERT(sc
->sc_brtcnt
== 0,
4492 ("%s: %d bridge routes referenced", __func__
, sc
->sc_brtcnt
));
4493 _FREE(sc
->sc_rthash
, M_DEVBUF
);
4497 * The following hash function is adapted from "Hash Functions" by Bob Jenkins
4498 * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
4500 #define mix(a, b, c) \
4502 a -= b; a -= c; a ^= (c >> 13); \
4503 b -= c; b -= a; b ^= (a << 8); \
4504 c -= a; c -= b; c ^= (b >> 13); \
4505 a -= b; a -= c; a ^= (c >> 12); \
4506 b -= c; b -= a; b ^= (a << 16); \
4507 c -= a; c -= b; c ^= (b >> 5); \
4508 a -= b; a -= c; a ^= (c >> 3); \
4509 b -= c; b -= a; b ^= (a << 10); \
4510 c -= a; c -= b; c ^= (b >> 15); \
4511 } while (/*CONSTCOND*/0)
4513 static __inline
uint32_t
4514 bridge_rthash(struct bridge_softc
*sc
, const uint8_t *addr
)
4516 uint32_t a
= 0x9e3779b9, b
= 0x9e3779b9, c
= sc
->sc_rthash_key
;
4527 return (c
& BRIDGE_RTHASH_MASK
);
4533 bridge_rtnode_addr_cmp(const uint8_t *a
, const uint8_t *b
)
4537 for (i
= 0, d
= 0; i
< ETHER_ADDR_LEN
&& d
== 0; i
++) {
4538 d
= ((int)a
[i
]) - ((int)b
[i
]);
4545 * bridge_rtnode_lookup:
4547 * Look up a bridge route node for the specified destination. Compare the
4548 * vlan id or if zero then just return the first match.
4550 static struct bridge_rtnode
*
4551 bridge_rtnode_lookup(struct bridge_softc
*sc
, const uint8_t *addr
,
4554 struct bridge_rtnode
*brt
;
4558 BRIDGE_LOCK_ASSERT(sc
);
4560 hash
= bridge_rthash(sc
, addr
);
4561 LIST_FOREACH(brt
, &sc
->sc_rthash
[hash
], brt_hash
) {
4562 dir
= bridge_rtnode_addr_cmp(addr
, brt
->brt_addr
);
4563 if (dir
== 0 && (brt
->brt_vlan
== vlan
|| vlan
== 0))
4573 * bridge_rtnode_insert:
4575 * Insert the specified bridge node into the route table. We
4576 * assume the entry is not already in the table.
4579 bridge_rtnode_insert(struct bridge_softc
*sc
, struct bridge_rtnode
*brt
)
4581 struct bridge_rtnode
*lbrt
;
4585 BRIDGE_LOCK_ASSERT(sc
);
4587 hash
= bridge_rthash(sc
, brt
->brt_addr
);
4589 lbrt
= LIST_FIRST(&sc
->sc_rthash
[hash
]);
4591 LIST_INSERT_HEAD(&sc
->sc_rthash
[hash
], brt
, brt_hash
);
4596 dir
= bridge_rtnode_addr_cmp(brt
->brt_addr
, lbrt
->brt_addr
);
4597 if (dir
== 0 && brt
->brt_vlan
== lbrt
->brt_vlan
)
4600 LIST_INSERT_BEFORE(lbrt
, brt
, brt_hash
);
4603 if (LIST_NEXT(lbrt
, brt_hash
) == NULL
) {
4604 LIST_INSERT_AFTER(lbrt
, brt
, brt_hash
);
4607 lbrt
= LIST_NEXT(lbrt
, brt_hash
);
4608 } while (lbrt
!= NULL
);
4611 panic("bridge_rtnode_insert: impossible");
4615 LIST_INSERT_HEAD(&sc
->sc_rtlist
, brt
, brt_list
);
4622 * bridge_rtnode_destroy:
4624 * Destroy a bridge rtnode.
4627 bridge_rtnode_destroy(struct bridge_softc
*sc
, struct bridge_rtnode
*brt
)
4629 BRIDGE_LOCK_ASSERT(sc
);
4631 LIST_REMOVE(brt
, brt_hash
);
4633 LIST_REMOVE(brt
, brt_list
);
4635 brt
->brt_dst
->bif_addrcnt
--;
4636 zfree(bridge_rtnode_pool
, brt
);
4641 * bridge_rtable_expire:
4643 * Set the expiry time for all routes on an interface.
4646 bridge_rtable_expire(struct ifnet
*ifp
, int age
)
4648 struct bridge_softc
*sc
= ifp
->if_bridge
;
4649 struct bridge_rtnode
*brt
;
4654 * If the age is zero then flush, otherwise set all the expiry times to
4655 * age for the interface
4658 bridge_rtdelete(sc
, ifp
, IFBF_FLUSHDYN
);
4660 LIST_FOREACH(brt
, &sc
->sc_rtlist
, brt_list
) {
4661 struct timespec now
;
4664 /* Cap the expiry time to 'age' */
4665 if (brt
->brt_ifp
== ifp
&&
4666 brt
->brt_expire
> (unsigned long)now
.tv_sec
+ age
&&
4667 (brt
->brt_flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
)
4669 (unsigned long)now
.tv_sec
+ age
;
4676 * bridge_state_change:
4678 * Callback from the bridgestp code when a port changes states.
4681 bridge_state_change(struct ifnet
*ifp
, int state
)
4683 struct bridge_softc
*sc
= ifp
->if_bridge
;
4684 static const char *stpstates
[] = {
4694 log(LOG_NOTICE
, "%s%d: state changed to %s on %s%d\n",
4695 ifnet_name(sc
->sc_ifp
), ifnet_unit(sc
->sc_ifp
),
4696 stpstates
[state
], ifnet_name(ifp
), ifnet_unit(ifp
));
4698 #endif /* BRIDGESTP */
4702 * Send bridge packets through pfil if they are one of the types pfil can deal
4703 * with, or if they are ARP or REVARP. (pfil will pass ARP and REVARP without
4704 * question.) If *bifp or *ifp are NULL then packet filtering is skipped for
4708 bridge_pfil(struct mbuf
**mp
, struct ifnet
*bifp
, struct ifnet
*ifp
, int dir
)
4710 int snap
, error
, i
, hlen
;
4711 struct ether_header
*eh1
, eh2
;
4712 struct ip_fw_args args
;
4715 u_int16_t ether_type
;
4718 error
= -1; /* Default error if not error == 0 */
4721 /* we may return with the IP fields swapped, ensure its not shared */
4722 KASSERT(M_WRITABLE(*mp
), ("%s: modifying a shared mbuf", __func__
));
4725 if (pfil_bridge
== 0 && pfil_member
== 0 && pfil_ipfw
== 0)
4726 return (0); /* filtering is disabled */
4728 i
= min((*mp
)->m_pkthdr
.len
, max_protohdr
);
4729 if ((*mp
)->m_len
< i
) {
4730 *mp
= m_pullup(*mp
, i
);
4732 printf("%s: m_pullup failed\n", __func__
);
4737 eh1
= mtod(*mp
, struct ether_header
*);
4738 ether_type
= ntohs(eh1
->ether_type
);
4741 * Check for SNAP/LLC.
4743 if (ether_type
< ETHERMTU
) {
4744 struct llc
*llc2
= (struct llc
*)(eh1
+ 1);
4746 if ((*mp
)->m_len
>= ETHER_HDR_LEN
+ 8 &&
4747 llc2
->llc_dsap
== LLC_SNAP_LSAP
&&
4748 llc2
->llc_ssap
== LLC_SNAP_LSAP
&&
4749 llc2
->llc_control
== LLC_UI
) {
4750 ether_type
= htons(llc2
->llc_un
.type_snap
.ether_type
);
4756 * If we're trying to filter bridge traffic, don't look at anything
4757 * other than IP and ARP traffic. If the filter doesn't understand
4758 * IPv6, don't allow IPv6 through the bridge either. This is lame
4759 * since if we really wanted, say, an AppleTalk filter, we are hosed,
4760 * but of course we don't have an AppleTalk filter to begin with.
4761 * (Note that since pfil doesn't understand ARP it will pass *ALL*
4764 switch (ether_type
) {
4766 case ETHERTYPE_REVARP
:
4767 if (pfil_ipfw_arp
== 0)
4768 return (0); /* Automatically pass */
4773 case ETHERTYPE_IPV6
:
4778 * Check to see if the user wants to pass non-ip
4779 * packets, these will not be checked by pfil(9) and
4780 * passed unconditionally so the default is to drop.
4786 /* Strip off the Ethernet header and keep a copy. */
4787 m_copydata(*mp
, 0, ETHER_HDR_LEN
, (caddr_t
)&eh2
);
4788 m_adj(*mp
, ETHER_HDR_LEN
);
4790 /* Strip off snap header, if present */
4792 m_copydata(*mp
, 0, sizeof (struct llc
), (caddr_t
)&llc1
);
4793 m_adj(*mp
, sizeof (struct llc
));
4797 * Check the IP header for alignment and errors
4799 if (dir
== PFIL_IN
) {
4800 switch (ether_type
) {
4802 error
= bridge_ip_checkbasic(mp
);
4805 case ETHERTYPE_IPV6
:
4806 error
= bridge_ip6_checkbasic(mp
);
4816 if (IPFW_LOADED
&& pfil_ipfw
!= 0 && dir
== PFIL_OUT
&& ifp
!= NULL
) {
4818 args
.rule
= ip_dn_claim_rule(*mp
);
4819 if (args
.rule
!= NULL
&& fw_one_pass
)
4820 goto ipfwpass
; /* packet already partially processed */
4824 args
.next_hop
= NULL
;
4826 args
.inp
= NULL
; /* used by ipfw uid/gid/jail rules */
4827 i
= ip_fw_chk_ptr(&args
);
4833 if (DUMMYNET_LOADED
&& (i
== IP_FW_DUMMYNET
)) {
4835 /* put the Ethernet header back on */
4836 M_PREPEND(*mp
, ETHER_HDR_LEN
, M_DONTWAIT
);
4839 bcopy(&eh2
, mtod(*mp
, caddr_t
), ETHER_HDR_LEN
);
4842 * Pass the pkt to dummynet, which consumes it. The
4843 * packet will return to us via bridge_dummynet().
4846 ip_dn_io_ptr(mp
, DN_TO_IFB_FWD
, &args
, DN_CLIENT_IPFW
);
4850 if (i
!= IP_FW_PASS
) /* drop */
4858 * Run the packet through pfil
4860 switch (ether_type
) {
4863 * before calling the firewall, swap fields the same as
4864 * IP does. here we assume the header is contiguous
4866 ip
= mtod(*mp
, struct ip
*);
4868 ip
->ip_len
= ntohs(ip
->ip_len
);
4869 ip
->ip_off
= ntohs(ip
->ip_off
);
4872 * Run pfil on the member interface and the bridge, both can
4873 * be skipped by clearing pfil_member or pfil_bridge.
4876 * in_if -> bridge_if -> out_if
4878 if (pfil_bridge
&& dir
== PFIL_OUT
&& bifp
!= NULL
)
4879 error
= pfil_run_hooks(&inet_pfil_hook
, mp
, bifp
,
4882 if (*mp
== NULL
|| error
!= 0) /* filter may consume */
4885 if (pfil_member
&& ifp
!= NULL
)
4886 error
= pfil_run_hooks(&inet_pfil_hook
, mp
, ifp
,
4889 if (*mp
== NULL
|| error
!= 0) /* filter may consume */
4892 if (pfil_bridge
&& dir
== PFIL_IN
&& bifp
!= NULL
)
4893 error
= pfil_run_hooks(&inet_pfil_hook
, mp
, bifp
,
4896 if (*mp
== NULL
|| error
!= 0) /* filter may consume */
4899 /* check if we need to fragment the packet */
4900 if (pfil_member
&& ifp
!= NULL
&& dir
== PFIL_OUT
) {
4901 i
= (*mp
)->m_pkthdr
.len
;
4902 if (i
> ifp
->if_mtu
) {
4903 error
= bridge_fragment(ifp
, *mp
, &eh2
, snap
,
4909 /* Recalculate the ip checksum and restore byte ordering */
4910 ip
= mtod(*mp
, struct ip
*);
4911 hlen
= ip
->ip_hl
<< 2;
4912 if (hlen
< sizeof (struct ip
))
4914 if (hlen
> (*mp
)->m_len
) {
4915 if ((*mp
= m_pullup(*mp
, hlen
)) == 0)
4917 ip
= mtod(*mp
, struct ip
*);
4921 ip
->ip_len
= htons(ip
->ip_len
);
4922 ip
->ip_off
= htons(ip
->ip_off
);
4924 if (hlen
== sizeof (struct ip
))
4925 ip
->ip_sum
= in_cksum_hdr(ip
);
4927 ip
->ip_sum
= in_cksum(*mp
, hlen
);
4931 case ETHERTYPE_IPV6
:
4932 if (pfil_bridge
&& dir
== PFIL_OUT
&& bifp
!= NULL
)
4933 error
= pfil_run_hooks(&inet6_pfil_hook
, mp
, bifp
,
4936 if (*mp
== NULL
|| error
!= 0) /* filter may consume */
4939 if (pfil_member
&& ifp
!= NULL
)
4940 error
= pfil_run_hooks(&inet6_pfil_hook
, mp
, ifp
,
4943 if (*mp
== NULL
|| error
!= 0) /* filter may consume */
4946 if (pfil_bridge
&& dir
== PFIL_IN
&& bifp
!= NULL
)
4947 error
= pfil_run_hooks(&inet6_pfil_hook
, mp
, bifp
,
4964 * Finally, put everything back the way it was and return
4967 M_PREPEND(*mp
, sizeof (struct llc
), M_DONTWAIT
);
4970 bcopy(&llc1
, mtod(*mp
, caddr_t
), sizeof (struct llc
));
4973 M_PREPEND(*mp
, ETHER_HDR_LEN
, M_DONTWAIT
);
4976 bcopy(&eh2
, mtod(*mp
, caddr_t
), ETHER_HDR_LEN
);
4988 * Perform basic checks on header size since
4989 * pfil assumes ip_input has already processed
4990 * it for it. Cut-and-pasted from ip_input.c.
4991 * Given how simple the IPv6 version is,
4992 * does the IPv4 version really need to be
4995 * XXX Should we update ipstat here, or not?
4996 * XXX Right now we update ipstat but not
5000 bridge_ip_checkbasic(struct mbuf
**mp
)
5002 struct mbuf
*m
= *mp
;
5010 if (IP_HDR_ALIGNED_P(mtod(m
, caddr_t
)) == 0) {
5011 /* max_linkhdr is already rounded up to nearest 4-byte */
5012 if ((m
= m_copyup(m
, sizeof (struct ip
),
5013 max_linkhdr
)) == NULL
) {
5014 /* XXXJRT new stat, please */
5015 ipstat
.ips_toosmall
++;
5018 } else if (__predict_false(m
->m_len
< sizeof (struct ip
))) {
5019 if ((m
= m_pullup(m
, sizeof (struct ip
))) == NULL
) {
5020 ipstat
.ips_toosmall
++;
5024 ip
= mtod(m
, struct ip
*);
5025 if (ip
== NULL
) goto bad
;
5027 if (ip
->ip_v
!= IPVERSION
) {
5028 ipstat
.ips_badvers
++;
5031 hlen
= ip
->ip_hl
<< 2;
5032 if (hlen
< sizeof (struct ip
)) { /* minimum header length */
5033 ipstat
.ips_badhlen
++;
5036 if (hlen
> m
->m_len
) {
5037 if ((m
= m_pullup(m
, hlen
)) == 0) {
5038 ipstat
.ips_badhlen
++;
5041 ip
= mtod(m
, struct ip
*);
5042 if (ip
== NULL
) goto bad
;
5045 if (m
->m_pkthdr
.csum_flags
& CSUM_IP_CHECKED
) {
5046 sum
= !(m
->m_pkthdr
.csum_flags
& CSUM_IP_VALID
);
5048 if (hlen
== sizeof (struct ip
)) {
5049 sum
= in_cksum_hdr(ip
);
5051 sum
= in_cksum(m
, hlen
);
5055 ipstat
.ips_badsum
++;
5059 /* Retrieve the packet length. */
5060 len
= ntohs(ip
->ip_len
);
5063 * Check for additional length bogosity
5066 ipstat
.ips_badlen
++;
5071 * Check that the amount of data in the buffers
5072 * is as at least much as the IP header would have us expect.
5073 * Drop packet if shorter than we expect.
5075 if (m
->m_pkthdr
.len
< len
) {
5076 ipstat
.ips_tooshort
++;
5080 /* Checks out, proceed */
5091 * Same as above, but for IPv6.
5092 * Cut-and-pasted from ip6_input.c.
5093 * XXX Should we update ip6stat, or not?
5096 bridge_ip6_checkbasic(struct mbuf
**mp
)
5098 struct mbuf
*m
= *mp
;
5099 struct ip6_hdr
*ip6
;
5102 * If the IPv6 header is not aligned, slurp it up into a new
5103 * mbuf with space for link headers, in the event we forward
5104 * it. Otherwise, if it is aligned, make sure the entire base
5105 * IPv6 header is in the first mbuf of the chain.
5107 if (IP6_HDR_ALIGNED_P(mtod(m
, caddr_t
)) == 0) {
5108 struct ifnet
*inifp
= m
->m_pkthdr
.rcvif
;
5109 /* max_linkhdr is already rounded up to nearest 4-byte */
5110 if ((m
= m_copyup(m
, sizeof (struct ip6_hdr
),
5111 max_linkhdr
)) == NULL
) {
5112 /* XXXJRT new stat, please */
5113 ip6stat
.ip6s_toosmall
++;
5114 in6_ifstat_inc(inifp
, ifs6_in_hdrerr
);
5117 } else if (__predict_false(m
->m_len
< sizeof (struct ip6_hdr
))) {
5118 struct ifnet
*inifp
= m
->m_pkthdr
.rcvif
;
5119 if ((m
= m_pullup(m
, sizeof (struct ip6_hdr
))) == NULL
) {
5120 ip6stat
.ip6s_toosmall
++;
5121 in6_ifstat_inc(inifp
, ifs6_in_hdrerr
);
5126 ip6
= mtod(m
, struct ip6_hdr
*);
5128 if ((ip6
->ip6_vfc
& IPV6_VERSION_MASK
) != IPV6_VERSION
) {
5129 ip6stat
.ip6s_badvers
++;
5130 in6_ifstat_inc(m
->m_pkthdr
.rcvif
, ifs6_in_hdrerr
);
5134 /* Checks out, proceed */
5147 * Return a fragmented mbuf chain.
5150 bridge_fragment(struct ifnet
*ifp
, struct mbuf
*m
, struct ether_header
*eh
,
5151 int snap
, struct llc
*llc
)
5157 if (m
->m_len
< sizeof (struct ip
) &&
5158 (m
= m_pullup(m
, sizeof (struct ip
))) == NULL
)
5160 ip
= mtod(m
, struct ip
*);
5162 error
= ip_fragment(ip
, &m
, ifp
->if_mtu
, ifp
->if_hwassist
,
5167 /* walk the chain and re-add the Ethernet header */
5168 for (m0
= m
; m0
; m0
= m0
->m_nextpkt
) {
5171 M_PREPEND(m0
, sizeof (struct llc
), M_DONTWAIT
);
5176 bcopy(llc
, mtod(m0
, caddr_t
),
5177 sizeof (struct llc
));
5179 M_PREPEND(m0
, ETHER_HDR_LEN
, M_DONTWAIT
);
5184 bcopy(eh
, mtod(m0
, caddr_t
), ETHER_HDR_LEN
);
5191 ipstat
.ips_fragmented
++;
5200 #endif /* PFIL_HOOKS */
5203 bridge_set_bpf_tap(ifnet_t ifp
, bpf_tap_mode mode
, bpf_packet_func bpf_callback
)
5205 struct bridge_softc
*sc
= (struct bridge_softc
*)ifnet_softc(ifp
);
5208 if (sc
== NULL
|| (sc
->sc_flags
& SCF_DETACHING
)) {
5213 case BPF_TAP_DISABLE
:
5214 sc
->sc_bpf_input
= sc
->sc_bpf_output
= NULL
;
5218 sc
->sc_bpf_input
= bpf_callback
;
5221 case BPF_TAP_OUTPUT
:
5222 sc
->sc_bpf_output
= bpf_callback
;
5225 case BPF_TAP_INPUT_OUTPUT
:
5226 sc
->sc_bpf_input
= sc
->sc_bpf_output
= bpf_callback
;
5237 bridge_detach(ifnet_t ifp
)
5239 struct bridge_softc
*sc
= (struct bridge_softc
*)ifnet_softc(ifp
);
5242 bstp_detach(&sc
->sc_stp
);
5243 #endif /* BRIDGESTP */
5245 /* Tear down the routing table. */
5246 bridge_rtable_fini(sc
);
5248 lck_mtx_lock(bridge_list_mtx
);
5249 LIST_REMOVE(sc
, sc_list
);
5250 lck_mtx_unlock(bridge_list_mtx
);
5254 lck_mtx_free(sc
->sc_mtx
, bridge_lock_grp
);
5256 _FREE(sc
, M_DEVBUF
);
5259 __private_extern__ errno_t
5260 bridge_bpf_input(ifnet_t ifp
, struct mbuf
*m
)
5262 struct bridge_softc
*sc
= (struct bridge_softc
*)ifnet_softc(ifp
);
5264 if (sc
->sc_bpf_input
) {
5265 if (mbuf_pkthdr_rcvif(m
) != ifp
) {
5266 printf("%s: rcvif: %p != ifp %p\n", __func__
,
5267 mbuf_pkthdr_rcvif(m
), ifp
);
5269 (*sc
->sc_bpf_input
)(ifp
, m
);
5274 __private_extern__ errno_t
5275 bridge_bpf_output(ifnet_t ifp
, struct mbuf
*m
)
5277 struct bridge_softc
*sc
= (struct bridge_softc
*)ifnet_softc(ifp
);
5279 if (sc
->sc_bpf_output
) {
5280 (*sc
->sc_bpf_output
)(ifp
, m
);