2 * Copyright (c) 2004-2020 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).
103 * - GIF isn't handled due to the lack of IPPROTO_ETHERIP support.
106 #include <sys/cdefs.h>
108 #define BRIDGE_DEBUG 1
110 #include <sys/param.h>
111 #include <sys/mbuf.h>
112 #include <sys/malloc.h>
113 #include <sys/protosw.h>
114 #include <sys/systm.h>
115 #include <sys/time.h>
116 #include <sys/socket.h> /* for net/if.h */
117 #include <sys/sockio.h>
118 #include <sys/kernel.h>
119 #include <sys/random.h>
120 #include <sys/syslog.h>
121 #include <sys/sysctl.h>
122 #include <sys/proc.h>
123 #include <sys/lock.h>
124 #include <sys/mcache.h>
126 #include <sys/kauth.h>
128 #include <kern/thread_call.h>
130 #include <libkern/libkern.h>
132 #include <kern/zalloc.h>
138 #include <net/if_dl.h>
139 #include <net/if_types.h>
140 #include <net/if_var.h>
141 #include <net/if_media.h>
142 #include <net/net_api_stats.h>
143 #include <net/pfvar.h>
145 #include <netinet/in.h> /* for struct arpcom */
146 #include <netinet/tcp.h> /* for struct tcphdr */
147 #include <netinet/in_systm.h>
148 #include <netinet/in_var.h>
150 #include <netinet/ip.h>
151 #include <netinet/ip_var.h>
152 #include <netinet/ip6.h>
153 #include <netinet6/ip6_var.h>
155 #include <netinet/ip_carp.h>
157 #include <netinet/if_ether.h> /* for struct arpcom */
158 #include <net/bridgestp.h>
159 #include <net/if_bridgevar.h>
160 #include <net/if_llc.h>
162 #include <net/if_vlan_var.h>
163 #endif /* NVLAN > 0 */
165 #include <net/if_ether.h>
166 #include <net/dlil.h>
167 #include <net/kpi_interfacefilter.h>
169 #include <net/route.h>
170 #include <dev/random/randomdev.h>
172 #include <netinet/bootp.h>
173 #include <netinet/dhcp.h>
177 #define BR_DBGF_LIFECYCLE 0x0001
178 #define BR_DBGF_INPUT 0x0002
179 #define BR_DBGF_OUTPUT 0x0004
180 #define BR_DBGF_RT_TABLE 0x0008
181 #define BR_DBGF_DELAYED_CALL 0x0010
182 #define BR_DBGF_IOCTL 0x0020
183 #define BR_DBGF_MBUF 0x0040
184 #define BR_DBGF_MCAST 0x0080
185 #define BR_DBGF_HOSTFILTER 0x0100
186 #define BR_DBGF_CHECKSUM 0x0200
187 #define BR_DBGF_MAC_NAT 0x0400
188 #define BR_DBGF_SEGMENTATION 0x0800
189 #endif /* BRIDGE_DEBUG */
191 #define _BRIDGE_LOCK(_sc) lck_mtx_lock(&(_sc)->sc_mtx)
192 #define _BRIDGE_UNLOCK(_sc) lck_mtx_unlock(&(_sc)->sc_mtx)
193 #define BRIDGE_LOCK_ASSERT_HELD(_sc) \
194 LCK_MTX_ASSERT(&(_sc)->sc_mtx, LCK_MTX_ASSERT_OWNED)
195 #define BRIDGE_LOCK_ASSERT_NOTHELD(_sc) \
196 LCK_MTX_ASSERT(&(_sc)->sc_mtx, LCK_MTX_ASSERT_NOTOWNED)
200 #define BR_LCKDBG_MAX 4
202 #define BRIDGE_LOCK(_sc) bridge_lock(_sc)
203 #define BRIDGE_UNLOCK(_sc) bridge_unlock(_sc)
204 #define BRIDGE_LOCK2REF(_sc, _err) _err = bridge_lock2ref(_sc)
205 #define BRIDGE_UNREF(_sc) bridge_unref(_sc)
206 #define BRIDGE_XLOCK(_sc) bridge_xlock(_sc)
207 #define BRIDGE_XDROP(_sc) bridge_xdrop(_sc)
208 #define IF_BRIDGE_DEBUG(f) bridge_debug_flag_is_set(f)
210 #else /* !BRIDGE_DEBUG */
212 #define BRIDGE_LOCK(_sc) _BRIDGE_LOCK(_sc)
213 #define BRIDGE_UNLOCK(_sc) _BRIDGE_UNLOCK(_sc)
214 #define BRIDGE_LOCK2REF(_sc, _err) do { \
215 BRIDGE_LOCK_ASSERT_HELD(_sc); \
216 if ((_sc)->sc_iflist_xcnt > 0) \
219 (_sc)->sc_iflist_ref++; \
220 _BRIDGE_UNLOCK(_sc); \
222 #define BRIDGE_UNREF(_sc) do { \
224 (_sc)->sc_iflist_ref--; \
225 if (((_sc)->sc_iflist_xcnt > 0) && ((_sc)->sc_iflist_ref == 0)) { \
226 _BRIDGE_UNLOCK(_sc); \
227 wakeup(&(_sc)->sc_cv); \
229 _BRIDGE_UNLOCK(_sc); \
231 #define BRIDGE_XLOCK(_sc) do { \
232 BRIDGE_LOCK_ASSERT_HELD(_sc); \
233 (_sc)->sc_iflist_xcnt++; \
234 while ((_sc)->sc_iflist_ref > 0) \
235 msleep(&(_sc)->sc_cv, &(_sc)->sc_mtx, PZERO, \
236 "BRIDGE_XLOCK", NULL); \
238 #define BRIDGE_XDROP(_sc) do { \
239 BRIDGE_LOCK_ASSERT_HELD(_sc); \
240 (_sc)->sc_iflist_xcnt--; \
243 #define IF_BRIDGE_DEBUG(f) FALSE
245 #endif /* BRIDGE_DEBUG */
248 #define BRIDGE_BPF_MTAP_INPUT(sc, m) \
249 if (sc->sc_bpf_input != NULL) \
250 bridge_bpf_input(sc->sc_ifp, m, __func__, __LINE__)
251 #else /* NBPFILTER */
252 #define BRIDGE_BPF_MTAP_INPUT(ifp, m)
253 #endif /* NBPFILTER */
256 * Initial size of the route hash table. Must be a power of two.
258 #ifndef BRIDGE_RTHASH_SIZE
259 #define BRIDGE_RTHASH_SIZE 16
263 * Maximum size of the routing hash table
265 #define BRIDGE_RTHASH_SIZE_MAX 2048
267 #define BRIDGE_RTHASH_MASK(sc) ((sc)->sc_rthash_size - 1)
270 * Maximum number of addresses to cache.
272 #ifndef BRIDGE_RTABLE_MAX
273 #define BRIDGE_RTABLE_MAX 100
278 * Timeout (in seconds) for entries learned dynamically.
280 #ifndef BRIDGE_RTABLE_TIMEOUT
281 #define BRIDGE_RTABLE_TIMEOUT (20 * 60) /* same as ARP */
285 * Number of seconds between walks of the route list.
287 #ifndef BRIDGE_RTABLE_PRUNE_PERIOD
288 #define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60)
292 * Number of MAC NAT entries
293 * - sized based on 16 clients (including MAC NAT interface)
294 * each with 4 addresses
296 #ifndef BRIDGE_MAC_NAT_ENTRY_MAX
297 #define BRIDGE_MAC_NAT_ENTRY_MAX 64
298 #endif /* BRIDGE_MAC_NAT_ENTRY_MAX */
301 * List of capabilities to possibly mask on the member interface.
303 #define BRIDGE_IFCAPS_MASK (IFCAP_TSO | IFCAP_TXCSUM)
305 * List of capabilities to disable on the member interface.
307 #define BRIDGE_IFCAPS_STRIP IFCAP_LRO
310 * Bridge interface list entry.
312 struct bridge_iflist
{
313 TAILQ_ENTRY(bridge_iflist
) bif_next
;
314 struct ifnet
*bif_ifp
; /* member if */
315 struct bstp_port bif_stp
; /* STP state */
316 uint32_t bif_ifflags
; /* member if flags */
317 int bif_savedcaps
; /* saved capabilities */
318 uint32_t bif_addrmax
; /* max # of addresses */
319 uint32_t bif_addrcnt
; /* cur. # of addresses */
320 uint32_t bif_addrexceeded
; /* # of address violations */
322 interface_filter_t bif_iff_ref
;
323 struct bridge_softc
*bif_sc
;
327 struct in_addr bif_hf_ipsrc
;
328 uint8_t bif_hf_hwsrc
[ETHER_ADDR_LEN
];
331 #define BIFF_PROMISC 0x01 /* promiscuous mode set */
332 #define BIFF_PROTO_ATTACHED 0x02 /* protocol attached */
333 #define BIFF_FILTER_ATTACHED 0x04 /* interface filter attached */
334 #define BIFF_MEDIA_ACTIVE 0x08 /* interface media active */
335 #define BIFF_HOST_FILTER 0x10 /* host filter enabled */
336 #define BIFF_HF_HWSRC 0x20 /* host filter source MAC is set */
337 #define BIFF_HF_IPSRC 0x40 /* host filter source IP is set */
338 #define BIFF_INPUT_BROADCAST 0x80 /* send broadcast packets in */
342 * - translates between an IP address and MAC address on a specific
343 * bridge interface member
345 struct mac_nat_entry
{
346 LIST_ENTRY(mac_nat_entry
) mne_list
; /* list linkage */
347 struct bridge_iflist
*mne_bif
; /* originating interface */
348 unsigned long mne_expire
; /* expiration time */
350 struct in_addr mneu_ip
; /* originating IPv4 address */
351 struct in6_addr mneu_ip6
; /* originating IPv6 address */
353 uint8_t mne_mac
[ETHER_ADDR_LEN
];
355 uint8_t mne_reserved
;
357 #define mne_ip mne_u.mneu_ip
358 #define mne_ip6 mne_u.mneu_ip6
360 #define MNE_FLAGS_IPV6 0x01 /* IPv6 address */
362 LIST_HEAD(mac_nat_entry_list
, mac_nat_entry
);
366 * - used by bridge_mac_nat_output() to convey the translation that needs
367 * to take place in bridge_mac_nat_translate
368 * - holds enough information so that the translation can be done later without
369 * holding the bridge lock
371 struct mac_nat_record
{
372 uint16_t mnr_ether_type
;
374 uint16_t mnru_arp_offset
;
376 uint16_t mnruip_dhcp_flags
;
377 uint16_t mnruip_udp_csum
;
378 uint8_t mnruip_header_len
;
381 uint16_t mnruip6_icmp6_len
;
382 uint16_t mnruip6_lladdr_offset
;
383 uint8_t mnruip6_icmp6_type
;
384 uint8_t mnruip6_header_len
;
389 #define mnr_arp_offset mnr_u.mnru_arp_offset
391 #define mnr_ip_header_len mnr_u.mnru_ip.mnruip_header_len
392 #define mnr_ip_dhcp_flags mnr_u.mnru_ip.mnruip_dhcp_flags
393 #define mnr_ip_udp_csum mnr_u.mnru_ip.mnruip_udp_csum
395 #define mnr_ip6_icmp6_len mnr_u.mnru_ip6.mnruip6_icmp6_len
396 #define mnr_ip6_icmp6_type mnr_u.mnru_ip6.mnruip6_icmp6_type
397 #define mnr_ip6_header_len mnr_u.mnru_ip6.mnruip6_header_len
398 #define mnr_ip6_lladdr_offset mnr_u.mnru_ip6.mnruip6_lladdr_offset
403 struct bridge_rtnode
{
404 LIST_ENTRY(bridge_rtnode
) brt_hash
; /* hash table linkage */
405 LIST_ENTRY(bridge_rtnode
) brt_list
; /* list linkage */
406 struct bridge_iflist
*brt_dst
; /* destination if */
407 unsigned long brt_expire
; /* expiration time */
408 uint8_t brt_flags
; /* address flags */
409 uint8_t brt_addr
[ETHER_ADDR_LEN
];
410 uint16_t brt_vlan
; /* vlan id */
413 #define brt_ifp brt_dst->bif_ifp
416 * Bridge delayed function call context
418 typedef void (*bridge_delayed_func_t
)(struct bridge_softc
*);
420 struct bridge_delayed_call
{
421 struct bridge_softc
*bdc_sc
;
422 bridge_delayed_func_t bdc_func
; /* Function to call */
423 struct timespec bdc_ts
; /* Time to call */
425 thread_call_t bdc_thread_call
;
428 #define BDCF_OUTSTANDING 0x01 /* Delayed call has been scheduled */
429 #define BDCF_CANCELLING 0x02 /* May be waiting for call completion */
432 * Software state for each bridge.
434 LIST_HEAD(_bridge_rtnode_list
, bridge_rtnode
);
436 struct bridge_softc
{
437 struct ifnet
*sc_ifp
; /* make this an interface */
439 LIST_ENTRY(bridge_softc
) sc_list
;
440 decl_lck_mtx_data(, sc_mtx
);
441 struct _bridge_rtnode_list
*sc_rthash
; /* our forwarding table */
442 struct _bridge_rtnode_list sc_rtlist
; /* list version of above */
443 uint32_t sc_rthash_key
; /* key for hash */
444 uint32_t sc_rthash_size
; /* size of the hash table */
445 struct bridge_delayed_call sc_aging_timer
;
446 struct bridge_delayed_call sc_resize_call
;
447 TAILQ_HEAD(, bridge_iflist
) sc_spanlist
; /* span ports list */
448 struct bstp_state sc_stp
; /* STP state */
449 bpf_packet_func sc_bpf_input
;
450 bpf_packet_func sc_bpf_output
;
452 uint32_t sc_brtmax
; /* max # of addresses */
453 uint32_t sc_brtcnt
; /* cur. # of addresses */
454 uint32_t sc_brttimeout
; /* rt timeout in seconds */
455 uint32_t sc_iflist_ref
; /* refcount for sc_iflist */
456 uint32_t sc_iflist_xcnt
; /* refcount for sc_iflist */
457 TAILQ_HEAD(, bridge_iflist
) sc_iflist
; /* member interface list */
458 uint32_t sc_brtexceeded
; /* # of cache drops */
459 uint32_t sc_filter_flags
; /* ipf and flags */
460 struct ifnet
*sc_ifaddr
; /* member mac copied from */
461 u_char sc_defaddr
[6]; /* Default MAC address */
462 char sc_if_xname
[IFNAMSIZ
];
464 struct bridge_iflist
*sc_mac_nat_bif
; /* single MAC NAT interface */
465 struct mac_nat_entry_list sc_mne_list
; /* MAC NAT IPv4 */
466 struct mac_nat_entry_list sc_mne_list_v6
;/* MAC NAT IPv6 */
467 uint32_t sc_mne_max
; /* max # of entries */
468 uint32_t sc_mne_count
; /* cur. # of entries */
469 uint32_t sc_mne_allocation_failures
;
472 * Locking and unlocking calling history
474 void *lock_lr
[BR_LCKDBG_MAX
];
476 void *unlock_lr
[BR_LCKDBG_MAX
];
478 #endif /* BRIDGE_DEBUG */
481 #define SCF_DETACHING 0x01
482 #define SCF_RESIZING 0x02
483 #define SCF_MEDIA_ACTIVE 0x04
486 kChecksumOperationNone
= 0,
487 kChecksumOperationClear
= 1,
488 kChecksumOperationFinalize
= 2,
489 kChecksumOperationCompute
= 3,
492 struct bridge_hostfilter_stats bridge_hostfilter_stats
;
494 decl_lck_mtx_data(static, bridge_list_mtx
);
496 static int bridge_rtable_prune_period
= BRIDGE_RTABLE_PRUNE_PERIOD
;
498 static ZONE_DECLARE(bridge_rtnode_pool
, "bridge_rtnode",
499 sizeof(struct bridge_rtnode
), ZC_NONE
);
500 static ZONE_DECLARE(bridge_mne_pool
, "bridge_mac_nat_entry",
501 sizeof(struct mac_nat_entry
), ZC_NONE
);
503 static int bridge_clone_create(struct if_clone
*, uint32_t, void *);
504 static int bridge_clone_destroy(struct ifnet
*);
506 static errno_t
bridge_ioctl(struct ifnet
*, u_long
, void *);
508 static void bridge_mutecaps(struct bridge_softc
*);
509 static void bridge_set_ifcap(struct bridge_softc
*, struct bridge_iflist
*,
512 static errno_t
bridge_set_tso(struct bridge_softc
*);
513 static void bridge_ifdetach(struct ifnet
*);
514 static void bridge_proto_attach_changed(struct ifnet
*);
515 static int bridge_init(struct ifnet
*);
516 #if HAS_BRIDGE_DUMMYNET
517 static void bridge_dummynet(struct mbuf
*, struct ifnet
*);
519 static void bridge_ifstop(struct ifnet
*, int);
520 static int bridge_output(struct ifnet
*, struct mbuf
*);
521 static void bridge_finalize_cksum(struct ifnet
*, struct mbuf
*);
522 static void bridge_start(struct ifnet
*);
523 static errno_t
bridge_input(struct ifnet
*, mbuf_t
*);
524 static errno_t
bridge_iff_input(void *, ifnet_t
, protocol_family_t
,
526 static errno_t
bridge_iff_output(void *, ifnet_t
, protocol_family_t
,
528 static errno_t
bridge_member_output(struct bridge_softc
*sc
, ifnet_t ifp
,
531 static int bridge_enqueue(ifnet_t
, struct ifnet
*,
532 struct ifnet
*, struct mbuf
*, ChecksumOperation
);
533 static void bridge_rtdelete(struct bridge_softc
*, struct ifnet
*ifp
, int);
535 static void bridge_forward(struct bridge_softc
*, struct bridge_iflist
*,
538 static void bridge_aging_timer(struct bridge_softc
*sc
);
540 static void bridge_broadcast(struct bridge_softc
*, struct ifnet
*,
542 static void bridge_span(struct bridge_softc
*, struct mbuf
*);
544 static int bridge_rtupdate(struct bridge_softc
*, const uint8_t *,
545 uint16_t, struct bridge_iflist
*, int, uint8_t);
546 static struct ifnet
*bridge_rtlookup(struct bridge_softc
*, const uint8_t *,
548 static void bridge_rttrim(struct bridge_softc
*);
549 static void bridge_rtage(struct bridge_softc
*);
550 static void bridge_rtflush(struct bridge_softc
*, int);
551 static int bridge_rtdaddr(struct bridge_softc
*, const uint8_t *,
554 static int bridge_rtable_init(struct bridge_softc
*);
555 static void bridge_rtable_fini(struct bridge_softc
*);
557 static void bridge_rthash_resize(struct bridge_softc
*);
559 static int bridge_rtnode_addr_cmp(const uint8_t *, const uint8_t *);
560 static struct bridge_rtnode
*bridge_rtnode_lookup(struct bridge_softc
*,
561 const uint8_t *, uint16_t);
562 static int bridge_rtnode_hash(struct bridge_softc
*,
563 struct bridge_rtnode
*);
564 static int bridge_rtnode_insert(struct bridge_softc
*,
565 struct bridge_rtnode
*);
566 static void bridge_rtnode_destroy(struct bridge_softc
*,
567 struct bridge_rtnode
*);
569 static void bridge_rtable_expire(struct ifnet
*, int);
570 static void bridge_state_change(struct ifnet
*, int);
571 #endif /* BRIDGESTP */
573 static struct bridge_iflist
*bridge_lookup_member(struct bridge_softc
*,
575 static struct bridge_iflist
*bridge_lookup_member_if(struct bridge_softc
*,
577 static void bridge_delete_member(struct bridge_softc
*,
578 struct bridge_iflist
*, int);
579 static void bridge_delete_span(struct bridge_softc
*,
580 struct bridge_iflist
*);
582 static int bridge_ioctl_add(struct bridge_softc
*, void *);
583 static int bridge_ioctl_del(struct bridge_softc
*, void *);
584 static int bridge_ioctl_gifflags(struct bridge_softc
*, void *);
585 static int bridge_ioctl_sifflags(struct bridge_softc
*, void *);
586 static int bridge_ioctl_scache(struct bridge_softc
*, void *);
587 static int bridge_ioctl_gcache(struct bridge_softc
*, void *);
588 static int bridge_ioctl_gifs32(struct bridge_softc
*, void *);
589 static int bridge_ioctl_gifs64(struct bridge_softc
*, void *);
590 static int bridge_ioctl_rts32(struct bridge_softc
*, void *);
591 static int bridge_ioctl_rts64(struct bridge_softc
*, void *);
592 static int bridge_ioctl_saddr32(struct bridge_softc
*, void *);
593 static int bridge_ioctl_saddr64(struct bridge_softc
*, void *);
594 static int bridge_ioctl_sto(struct bridge_softc
*, void *);
595 static int bridge_ioctl_gto(struct bridge_softc
*, void *);
596 static int bridge_ioctl_daddr32(struct bridge_softc
*, void *);
597 static int bridge_ioctl_daddr64(struct bridge_softc
*, void *);
598 static int bridge_ioctl_flush(struct bridge_softc
*, void *);
599 static int bridge_ioctl_gpri(struct bridge_softc
*, void *);
600 static int bridge_ioctl_spri(struct bridge_softc
*, void *);
601 static int bridge_ioctl_ght(struct bridge_softc
*, void *);
602 static int bridge_ioctl_sht(struct bridge_softc
*, void *);
603 static int bridge_ioctl_gfd(struct bridge_softc
*, void *);
604 static int bridge_ioctl_sfd(struct bridge_softc
*, void *);
605 static int bridge_ioctl_gma(struct bridge_softc
*, void *);
606 static int bridge_ioctl_sma(struct bridge_softc
*, void *);
607 static int bridge_ioctl_sifprio(struct bridge_softc
*, void *);
608 static int bridge_ioctl_sifcost(struct bridge_softc
*, void *);
609 static int bridge_ioctl_sifmaxaddr(struct bridge_softc
*, void *);
610 static int bridge_ioctl_addspan(struct bridge_softc
*, void *);
611 static int bridge_ioctl_delspan(struct bridge_softc
*, void *);
612 static int bridge_ioctl_gbparam32(struct bridge_softc
*, void *);
613 static int bridge_ioctl_gbparam64(struct bridge_softc
*, void *);
614 static int bridge_ioctl_grte(struct bridge_softc
*, void *);
615 static int bridge_ioctl_gifsstp32(struct bridge_softc
*, void *);
616 static int bridge_ioctl_gifsstp64(struct bridge_softc
*, void *);
617 static int bridge_ioctl_sproto(struct bridge_softc
*, void *);
618 static int bridge_ioctl_stxhc(struct bridge_softc
*, void *);
619 static int bridge_ioctl_purge(struct bridge_softc
*sc
, void *);
620 static int bridge_ioctl_gfilt(struct bridge_softc
*, void *);
621 static int bridge_ioctl_sfilt(struct bridge_softc
*, void *);
622 static int bridge_ioctl_ghostfilter(struct bridge_softc
*, void *);
623 static int bridge_ioctl_shostfilter(struct bridge_softc
*, void *);
624 static int bridge_ioctl_gmnelist32(struct bridge_softc
*, void *);
625 static int bridge_ioctl_gmnelist64(struct bridge_softc
*, void *);
627 static int bridge_pf(struct mbuf
**, struct ifnet
*, uint32_t sc_filter_flags
, int input
);
628 static int bridge_ip_checkbasic(struct mbuf
**);
629 static int bridge_ip6_checkbasic(struct mbuf
**);
631 static errno_t
bridge_set_bpf_tap(ifnet_t
, bpf_tap_mode
, bpf_packet_func
);
632 static errno_t
bridge_bpf_input(ifnet_t
, struct mbuf
*, const char *, int);
633 static errno_t
bridge_bpf_output(ifnet_t
, struct mbuf
*);
635 static void bridge_detach(ifnet_t
);
636 static void bridge_link_event(struct ifnet
*, u_int32_t
);
637 static void bridge_iflinkevent(struct ifnet
*);
638 static u_int32_t
bridge_updatelinkstatus(struct bridge_softc
*);
639 static int interface_media_active(struct ifnet
*);
640 static void bridge_schedule_delayed_call(struct bridge_delayed_call
*);
641 static void bridge_cancel_delayed_call(struct bridge_delayed_call
*);
642 static void bridge_cleanup_delayed_call(struct bridge_delayed_call
*);
643 static int bridge_host_filter(struct bridge_iflist
*, mbuf_t
*);
645 static errno_t
bridge_mac_nat_enable(struct bridge_softc
*,
646 struct bridge_iflist
*);
647 static void bridge_mac_nat_disable(struct bridge_softc
*sc
);
648 static void bridge_mac_nat_age_entries(struct bridge_softc
*sc
, unsigned long);
649 static void bridge_mac_nat_populate_entries(struct bridge_softc
*sc
);
650 static void bridge_mac_nat_flush_entries(struct bridge_softc
*sc
,
651 struct bridge_iflist
*);
652 static ifnet_t
bridge_mac_nat_input(struct bridge_softc
*, mbuf_t
*,
654 static boolean_t
bridge_mac_nat_output(struct bridge_softc
*,
655 struct bridge_iflist
*, mbuf_t
*, struct mac_nat_record
*);
656 static void bridge_mac_nat_translate(mbuf_t
*, struct mac_nat_record
*,
658 static boolean_t
is_broadcast_ip_packet(mbuf_t
*);
660 #define m_copypacket(m, how) m_copym(m, 0, M_COPYALL, how)
663 gso_ipv4_tcp(struct ifnet
*ifp
, struct mbuf
**mp
, u_int mac_hlen
,
667 gso_ipv6_tcp(struct ifnet
*ifp
, struct mbuf
**mp
, u_int mac_hlen
,
670 /* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */
671 #define VLANTAGOF(_m) 0
673 u_int8_t bstp_etheraddr
[ETHER_ADDR_LEN
] =
674 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
676 static u_int8_t ethernulladdr
[ETHER_ADDR_LEN
] =
677 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
680 static struct bstp_cb_ops bridge_ops
= {
681 .bcb_state
= bridge_state_change
,
682 .bcb_rtage
= bridge_rtable_expire
684 #endif /* BRIDGESTP */
686 SYSCTL_DECL(_net_link
);
687 SYSCTL_NODE(_net_link
, IFT_BRIDGE
, bridge
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0,
690 static int bridge_inherit_mac
= 0; /* share MAC with first bridge member */
691 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, inherit_mac
,
692 CTLFLAG_RW
| CTLFLAG_LOCKED
,
693 &bridge_inherit_mac
, 0,
694 "Inherit MAC address from the first bridge member");
696 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, rtable_prune_period
,
697 CTLFLAG_RW
| CTLFLAG_LOCKED
,
698 &bridge_rtable_prune_period
, 0,
699 "Interval between pruning of routing table");
701 static unsigned int bridge_rtable_hash_size_max
= BRIDGE_RTHASH_SIZE_MAX
;
702 SYSCTL_UINT(_net_link_bridge
, OID_AUTO
, rtable_hash_size_max
,
703 CTLFLAG_RW
| CTLFLAG_LOCKED
,
704 &bridge_rtable_hash_size_max
, 0,
705 "Maximum size of the routing hash table");
707 #if BRIDGE_DEBUG_DELAYED_CALLBACK
708 static int bridge_delayed_callback_delay
= 0;
709 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, delayed_callback_delay
,
710 CTLFLAG_RW
| CTLFLAG_LOCKED
,
711 &bridge_delayed_callback_delay
, 0,
712 "Delay before calling delayed function");
715 SYSCTL_STRUCT(_net_link_bridge
, OID_AUTO
,
716 hostfilterstats
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
717 &bridge_hostfilter_stats
, bridge_hostfilter_stats
, "");
721 static int log_stp
= 0; /* log STP state changes */
722 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, log_stp
, CTLFLAG_RW
,
723 &log_stp
, 0, "Log STP state changes");
724 #endif /* BRIDGESTP */
726 struct bridge_control
{
727 int (*bc_func
)(struct bridge_softc
*, void *);
728 unsigned int bc_argsize
;
729 unsigned int bc_flags
;
732 #define BC_F_COPYIN 0x01 /* copy arguments in */
733 #define BC_F_COPYOUT 0x02 /* copy arguments out */
734 #define BC_F_SUSER 0x04 /* do super-user check */
736 static const struct bridge_control bridge_control_table32
[] = {
737 { .bc_func
= bridge_ioctl_add
, .bc_argsize
= sizeof(struct ifbreq
), /* 0 */
738 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
739 { .bc_func
= bridge_ioctl_del
, .bc_argsize
= sizeof(struct ifbreq
),
740 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
742 { .bc_func
= bridge_ioctl_gifflags
, .bc_argsize
= sizeof(struct ifbreq
),
743 .bc_flags
= BC_F_COPYIN
| BC_F_COPYOUT
},
744 { .bc_func
= bridge_ioctl_sifflags
, .bc_argsize
= sizeof(struct ifbreq
),
745 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
747 { .bc_func
= bridge_ioctl_scache
, .bc_argsize
= sizeof(struct ifbrparam
),
748 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
749 { .bc_func
= bridge_ioctl_gcache
, .bc_argsize
= sizeof(struct ifbrparam
),
750 .bc_flags
= BC_F_COPYOUT
},
752 { .bc_func
= bridge_ioctl_gifs32
, .bc_argsize
= sizeof(struct ifbifconf32
),
753 .bc_flags
= BC_F_COPYIN
| BC_F_COPYOUT
},
754 { .bc_func
= bridge_ioctl_rts32
, .bc_argsize
= sizeof(struct ifbaconf32
),
755 .bc_flags
= BC_F_COPYIN
| BC_F_COPYOUT
},
757 { .bc_func
= bridge_ioctl_saddr32
, .bc_argsize
= sizeof(struct ifbareq32
),
758 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
760 { .bc_func
= bridge_ioctl_sto
, .bc_argsize
= sizeof(struct ifbrparam
),
761 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
762 { .bc_func
= bridge_ioctl_gto
, .bc_argsize
= sizeof(struct ifbrparam
), /* 10 */
763 .bc_flags
= BC_F_COPYOUT
},
765 { .bc_func
= bridge_ioctl_daddr32
, .bc_argsize
= sizeof(struct ifbareq32
),
766 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
768 { .bc_func
= bridge_ioctl_flush
, .bc_argsize
= sizeof(struct ifbreq
),
769 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
771 { .bc_func
= bridge_ioctl_gpri
, .bc_argsize
= sizeof(struct ifbrparam
),
772 .bc_flags
= BC_F_COPYOUT
},
773 { .bc_func
= bridge_ioctl_spri
, .bc_argsize
= sizeof(struct ifbrparam
),
774 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
776 { .bc_func
= bridge_ioctl_ght
, .bc_argsize
= sizeof(struct ifbrparam
),
777 .bc_flags
= BC_F_COPYOUT
},
778 { .bc_func
= bridge_ioctl_sht
, .bc_argsize
= sizeof(struct ifbrparam
),
779 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
781 { .bc_func
= bridge_ioctl_gfd
, .bc_argsize
= sizeof(struct ifbrparam
),
782 .bc_flags
= BC_F_COPYOUT
},
783 { .bc_func
= bridge_ioctl_sfd
, .bc_argsize
= sizeof(struct ifbrparam
),
784 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
786 { .bc_func
= bridge_ioctl_gma
, .bc_argsize
= sizeof(struct ifbrparam
),
787 .bc_flags
= BC_F_COPYOUT
},
788 { .bc_func
= bridge_ioctl_sma
, .bc_argsize
= sizeof(struct ifbrparam
), /* 20 */
789 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
791 { .bc_func
= bridge_ioctl_sifprio
, .bc_argsize
= sizeof(struct ifbreq
),
792 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
794 { .bc_func
= bridge_ioctl_sifcost
, .bc_argsize
= sizeof(struct ifbreq
),
795 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
797 { .bc_func
= bridge_ioctl_gfilt
, .bc_argsize
= sizeof(struct ifbrparam
),
798 .bc_flags
= BC_F_COPYOUT
},
799 { .bc_func
= bridge_ioctl_sfilt
, .bc_argsize
= sizeof(struct ifbrparam
),
800 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
802 { .bc_func
= bridge_ioctl_purge
, .bc_argsize
= sizeof(struct ifbreq
),
803 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
805 { .bc_func
= bridge_ioctl_addspan
, .bc_argsize
= sizeof(struct ifbreq
),
806 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
807 { .bc_func
= bridge_ioctl_delspan
, .bc_argsize
= sizeof(struct ifbreq
),
808 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
810 { .bc_func
= bridge_ioctl_gbparam32
, .bc_argsize
= sizeof(struct ifbropreq32
),
811 .bc_flags
= BC_F_COPYOUT
},
813 { .bc_func
= bridge_ioctl_grte
, .bc_argsize
= sizeof(struct ifbrparam
),
814 .bc_flags
= BC_F_COPYOUT
},
816 { .bc_func
= bridge_ioctl_gifsstp32
, .bc_argsize
= sizeof(struct ifbpstpconf32
), /* 30 */
817 .bc_flags
= BC_F_COPYIN
| BC_F_COPYOUT
},
819 { .bc_func
= bridge_ioctl_sproto
, .bc_argsize
= sizeof(struct ifbrparam
),
820 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
822 { .bc_func
= bridge_ioctl_stxhc
, .bc_argsize
= sizeof(struct ifbrparam
),
823 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
825 { .bc_func
= bridge_ioctl_sifmaxaddr
, .bc_argsize
= sizeof(struct ifbreq
),
826 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
828 { .bc_func
= bridge_ioctl_ghostfilter
, .bc_argsize
= sizeof(struct ifbrhostfilter
),
829 .bc_flags
= BC_F_COPYIN
| BC_F_COPYOUT
},
830 { .bc_func
= bridge_ioctl_shostfilter
, .bc_argsize
= sizeof(struct ifbrhostfilter
),
831 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
833 { .bc_func
= bridge_ioctl_gmnelist32
, .bc_argsize
= sizeof(struct ifbrmnelist32
),
834 .bc_flags
= BC_F_COPYIN
| BC_F_COPYOUT
},
837 static const struct bridge_control bridge_control_table64
[] = {
838 { .bc_func
= bridge_ioctl_add
, .bc_argsize
= sizeof(struct ifbreq
), /* 0 */
839 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
840 { .bc_func
= bridge_ioctl_del
, .bc_argsize
= sizeof(struct ifbreq
),
841 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
843 { .bc_func
= bridge_ioctl_gifflags
, .bc_argsize
= sizeof(struct ifbreq
),
844 .bc_flags
= BC_F_COPYIN
| BC_F_COPYOUT
},
845 { .bc_func
= bridge_ioctl_sifflags
, .bc_argsize
= sizeof(struct ifbreq
),
846 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
848 { .bc_func
= bridge_ioctl_scache
, .bc_argsize
= sizeof(struct ifbrparam
),
849 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
850 { .bc_func
= bridge_ioctl_gcache
, .bc_argsize
= sizeof(struct ifbrparam
),
851 .bc_flags
= BC_F_COPYOUT
},
853 { .bc_func
= bridge_ioctl_gifs64
, .bc_argsize
= sizeof(struct ifbifconf64
),
854 .bc_flags
= BC_F_COPYIN
| BC_F_COPYOUT
},
855 { .bc_func
= bridge_ioctl_rts64
, .bc_argsize
= sizeof(struct ifbaconf64
),
856 .bc_flags
= BC_F_COPYIN
| BC_F_COPYOUT
},
858 { .bc_func
= bridge_ioctl_saddr64
, .bc_argsize
= sizeof(struct ifbareq64
),
859 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
861 { .bc_func
= bridge_ioctl_sto
, .bc_argsize
= sizeof(struct ifbrparam
),
862 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
863 { .bc_func
= bridge_ioctl_gto
, .bc_argsize
= sizeof(struct ifbrparam
), /* 10 */
864 .bc_flags
= BC_F_COPYOUT
},
866 { .bc_func
= bridge_ioctl_daddr64
, .bc_argsize
= sizeof(struct ifbareq64
),
867 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
869 { .bc_func
= bridge_ioctl_flush
, .bc_argsize
= sizeof(struct ifbreq
),
870 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
872 { .bc_func
= bridge_ioctl_gpri
, .bc_argsize
= sizeof(struct ifbrparam
),
873 .bc_flags
= BC_F_COPYOUT
},
874 { .bc_func
= bridge_ioctl_spri
, .bc_argsize
= sizeof(struct ifbrparam
),
875 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
877 { .bc_func
= bridge_ioctl_ght
, .bc_argsize
= sizeof(struct ifbrparam
),
878 .bc_flags
= BC_F_COPYOUT
},
879 { .bc_func
= bridge_ioctl_sht
, .bc_argsize
= sizeof(struct ifbrparam
),
880 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
882 { .bc_func
= bridge_ioctl_gfd
, .bc_argsize
= sizeof(struct ifbrparam
),
883 .bc_flags
= BC_F_COPYOUT
},
884 { .bc_func
= bridge_ioctl_sfd
, .bc_argsize
= sizeof(struct ifbrparam
),
885 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
887 { .bc_func
= bridge_ioctl_gma
, .bc_argsize
= sizeof(struct ifbrparam
),
888 .bc_flags
= BC_F_COPYOUT
},
889 { .bc_func
= bridge_ioctl_sma
, .bc_argsize
= sizeof(struct ifbrparam
), /* 20 */
890 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
892 { .bc_func
= bridge_ioctl_sifprio
, .bc_argsize
= sizeof(struct ifbreq
),
893 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
895 { .bc_func
= bridge_ioctl_sifcost
, .bc_argsize
= sizeof(struct ifbreq
),
896 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
898 { .bc_func
= bridge_ioctl_gfilt
, .bc_argsize
= sizeof(struct ifbrparam
),
899 .bc_flags
= BC_F_COPYOUT
},
900 { .bc_func
= bridge_ioctl_sfilt
, .bc_argsize
= sizeof(struct ifbrparam
),
901 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
903 { .bc_func
= bridge_ioctl_purge
, .bc_argsize
= sizeof(struct ifbreq
),
904 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
906 { .bc_func
= bridge_ioctl_addspan
, .bc_argsize
= sizeof(struct ifbreq
),
907 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
908 { .bc_func
= bridge_ioctl_delspan
, .bc_argsize
= sizeof(struct ifbreq
),
909 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
911 { .bc_func
= bridge_ioctl_gbparam64
, .bc_argsize
= sizeof(struct ifbropreq64
),
912 .bc_flags
= BC_F_COPYOUT
},
914 { .bc_func
= bridge_ioctl_grte
, .bc_argsize
= sizeof(struct ifbrparam
),
915 .bc_flags
= BC_F_COPYOUT
},
917 { .bc_func
= bridge_ioctl_gifsstp64
, .bc_argsize
= sizeof(struct ifbpstpconf64
), /* 30 */
918 .bc_flags
= BC_F_COPYIN
| BC_F_COPYOUT
},
920 { .bc_func
= bridge_ioctl_sproto
, .bc_argsize
= sizeof(struct ifbrparam
),
921 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
923 { .bc_func
= bridge_ioctl_stxhc
, .bc_argsize
= sizeof(struct ifbrparam
),
924 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
926 { .bc_func
= bridge_ioctl_sifmaxaddr
, .bc_argsize
= sizeof(struct ifbreq
),
927 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
929 { .bc_func
= bridge_ioctl_ghostfilter
, .bc_argsize
= sizeof(struct ifbrhostfilter
),
930 .bc_flags
= BC_F_COPYIN
| BC_F_COPYOUT
},
931 { .bc_func
= bridge_ioctl_shostfilter
, .bc_argsize
= sizeof(struct ifbrhostfilter
),
932 .bc_flags
= BC_F_COPYIN
| BC_F_SUSER
},
934 { .bc_func
= bridge_ioctl_gmnelist64
, .bc_argsize
= sizeof(struct ifbrmnelist64
),
935 .bc_flags
= BC_F_COPYIN
| BC_F_COPYOUT
},
938 static const unsigned int bridge_control_table_size
=
939 sizeof(bridge_control_table32
) / sizeof(bridge_control_table32
[0]);
941 static LIST_HEAD(, bridge_softc
) bridge_list
=
942 LIST_HEAD_INITIALIZER(bridge_list
);
944 static lck_grp_t
*bridge_lock_grp
= NULL
;
945 static lck_attr_t
*bridge_lock_attr
= NULL
;
947 #define BRIDGENAME "bridge"
948 #define BRIDGES_MAX IF_MAXUNIT
949 #define BRIDGE_ZONE_MAX_ELEM MIN(IFNETS_MAX, BRIDGES_MAX)
951 static struct if_clone bridge_cloner
=
952 IF_CLONE_INITIALIZER(BRIDGENAME
, bridge_clone_create
, bridge_clone_destroy
,
953 0, BRIDGES_MAX
, BRIDGE_ZONE_MAX_ELEM
, sizeof(struct bridge_softc
));
955 static int if_bridge_txstart
= 0;
956 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, txstart
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
957 &if_bridge_txstart
, 0, "Bridge interface uses TXSTART model");
960 static int if_bridge_debug
= 0;
961 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, debug
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
962 &if_bridge_debug
, 0, "Bridge debug");
964 static int if_bridge_segmentation
= 1;
965 SYSCTL_INT(_net_link_bridge
, OID_AUTO
, segmentation
,
966 CTLFLAG_RW
| CTLFLAG_LOCKED
,
967 &if_bridge_segmentation
, 0, "Bridge interface enable segmentation");
969 static void printf_ether_header(struct ether_header
*);
970 static void printf_mbuf_data(mbuf_t
, size_t, size_t);
971 static void printf_mbuf_pkthdr(mbuf_t
, const char *, const char *);
972 static void printf_mbuf(mbuf_t
, const char *, const char *);
973 static void link_print(struct bridge_softc
* sc
);
975 static void bridge_lock(struct bridge_softc
*);
976 static void bridge_unlock(struct bridge_softc
*);
977 static int bridge_lock2ref(struct bridge_softc
*);
978 static void bridge_unref(struct bridge_softc
*);
979 static void bridge_xlock(struct bridge_softc
*);
980 static void bridge_xdrop(struct bridge_softc
*);
983 bridge_lock(struct bridge_softc
*sc
)
985 void *lr_saved
= __builtin_return_address(0);
987 BRIDGE_LOCK_ASSERT_NOTHELD(sc
);
991 sc
->lock_lr
[sc
->next_lock_lr
] = lr_saved
;
992 sc
->next_lock_lr
= (sc
->next_lock_lr
+ 1) % SO_LCKDBG_MAX
;
996 bridge_unlock(struct bridge_softc
*sc
)
998 void *lr_saved
= __builtin_return_address(0);
1000 BRIDGE_LOCK_ASSERT_HELD(sc
);
1002 sc
->unlock_lr
[sc
->next_unlock_lr
] = lr_saved
;
1003 sc
->next_unlock_lr
= (sc
->next_unlock_lr
+ 1) % SO_LCKDBG_MAX
;
1009 bridge_lock2ref(struct bridge_softc
*sc
)
1012 void *lr_saved
= __builtin_return_address(0);
1014 BRIDGE_LOCK_ASSERT_HELD(sc
);
1016 if (sc
->sc_iflist_xcnt
> 0) {
1019 sc
->sc_iflist_ref
++;
1022 sc
->unlock_lr
[sc
->next_unlock_lr
] = lr_saved
;
1023 sc
->next_unlock_lr
= (sc
->next_unlock_lr
+ 1) % SO_LCKDBG_MAX
;
1031 bridge_unref(struct bridge_softc
*sc
)
1033 void *lr_saved
= __builtin_return_address(0);
1035 BRIDGE_LOCK_ASSERT_NOTHELD(sc
);
1038 sc
->lock_lr
[sc
->next_lock_lr
] = lr_saved
;
1039 sc
->next_lock_lr
= (sc
->next_lock_lr
+ 1) % SO_LCKDBG_MAX
;
1041 sc
->sc_iflist_ref
--;
1043 sc
->unlock_lr
[sc
->next_unlock_lr
] = lr_saved
;
1044 sc
->next_unlock_lr
= (sc
->next_unlock_lr
+ 1) % SO_LCKDBG_MAX
;
1045 if ((sc
->sc_iflist_xcnt
> 0) && (sc
->sc_iflist_ref
== 0)) {
1054 bridge_xlock(struct bridge_softc
*sc
)
1056 void *lr_saved
= __builtin_return_address(0);
1058 BRIDGE_LOCK_ASSERT_HELD(sc
);
1060 sc
->sc_iflist_xcnt
++;
1061 while (sc
->sc_iflist_ref
> 0) {
1062 sc
->unlock_lr
[sc
->next_unlock_lr
] = lr_saved
;
1063 sc
->next_unlock_lr
= (sc
->next_unlock_lr
+ 1) % SO_LCKDBG_MAX
;
1065 msleep(&sc
->sc_cv
, &sc
->sc_mtx
, PZERO
, "BRIDGE_XLOCK", NULL
);
1067 sc
->lock_lr
[sc
->next_lock_lr
] = lr_saved
;
1068 sc
->next_lock_lr
= (sc
->next_lock_lr
+ 1) % SO_LCKDBG_MAX
;
1073 bridge_xdrop(struct bridge_softc
*sc
)
1075 BRIDGE_LOCK_ASSERT_HELD(sc
);
1077 sc
->sc_iflist_xcnt
--;
1081 printf_mbuf_pkthdr(mbuf_t m
, const char *prefix
, const char *suffix
)
1084 printf("%spktlen: %u rcvif: 0x%llx header: 0x%llx "
1085 "nextpkt: 0x%llx%s",
1086 prefix
? prefix
: "", (unsigned int)mbuf_pkthdr_len(m
),
1087 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_pkthdr_rcvif(m
)),
1088 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_pkthdr_header(m
)),
1089 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_nextpkt(m
)),
1090 suffix
? suffix
: "");
1092 printf("%s<NULL>%s\n", prefix
, suffix
);
1097 printf_mbuf(mbuf_t m
, const char *prefix
, const char *suffix
)
1100 printf("%s0x%llx type: %u flags: 0x%x len: %u data: 0x%llx "
1101 "maxlen: %u datastart: 0x%llx next: 0x%llx%s",
1102 prefix
? prefix
: "", (uint64_t)VM_KERNEL_ADDRPERM(m
),
1103 mbuf_type(m
), mbuf_flags(m
), (unsigned int)mbuf_len(m
),
1104 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_data(m
)),
1105 (unsigned int)mbuf_maxlen(m
),
1106 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_datastart(m
)),
1107 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_next(m
)),
1108 !suffix
|| (mbuf_flags(m
) & MBUF_PKTHDR
) ? "" : suffix
);
1109 if ((mbuf_flags(m
) & MBUF_PKTHDR
)) {
1110 printf_mbuf_pkthdr(m
, " ", suffix
);
1113 printf("%s<NULL>%s\n", prefix
, suffix
);
1118 printf_mbuf_data(mbuf_t m
, size_t offset
, size_t len
)
1122 size_t pktlen
, mlen
, maxlen
;
1125 pktlen
= mbuf_pkthdr_len(m
);
1127 if (offset
> pktlen
) {
1131 maxlen
= (pktlen
- offset
> len
) ? len
: pktlen
- offset
;
1135 for (i
= 0, j
= 0; i
< maxlen
; i
++, j
++) {
1146 printf("%02x%s", ptr
[j
], i
% 2 ? " " : "");
1152 printf_ether_header(struct ether_header
*eh
)
1154 printf("%02x:%02x:%02x:%02x:%02x:%02x > "
1155 "%02x:%02x:%02x:%02x:%02x:%02x 0x%04x ",
1156 eh
->ether_shost
[0], eh
->ether_shost
[1], eh
->ether_shost
[2],
1157 eh
->ether_shost
[3], eh
->ether_shost
[4], eh
->ether_shost
[5],
1158 eh
->ether_dhost
[0], eh
->ether_dhost
[1], eh
->ether_dhost
[2],
1159 eh
->ether_dhost
[3], eh
->ether_dhost
[4], eh
->ether_dhost
[5],
1160 ntohs(eh
->ether_type
));
1164 link_print(struct bridge_softc
* sc
)
1167 uint32_t sdl_buffer
[offsetof(struct sockaddr_dl
, sdl_data
) +
1168 IFNAMSIZ
+ ETHER_ADDR_LEN
];
1169 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)sdl_buffer
;
1171 memset(sdl
, 0, sizeof(sdl_buffer
));
1172 sdl
->sdl_family
= AF_LINK
;
1173 sdl
->sdl_nlen
= strlen(sc
->sc_if_xname
);
1174 sdl
->sdl_alen
= ETHER_ADDR_LEN
;
1175 sdl
->sdl_len
= offsetof(struct sockaddr_dl
, sdl_data
);
1176 memcpy(sdl
->sdl_data
, sc
->sc_if_xname
, sdl
->sdl_nlen
);
1177 memcpy(LLADDR(sdl
), sc
->sc_defaddr
, ETHER_ADDR_LEN
);
1180 printf("sdl len %d index %d family %d type 0x%x nlen %d alen %d"
1181 " slen %d addr ", sdl
->sdl_len
, sdl
->sdl_index
,
1182 sdl
->sdl_family
, sdl
->sdl_type
, sdl
->sdl_nlen
,
1183 sdl
->sdl_alen
, sdl
->sdl_slen
);
1185 for (i
= 0; i
< sdl
->sdl_alen
; i
++) {
1186 printf("%s%x", i
? ":" : "", (CONST_LLADDR(sdl
))[i
]);
1192 bridge_debug_flag_is_set(uint32_t flag
)
1194 return (if_bridge_debug
& flag
) != 0;
1197 #endif /* BRIDGE_DEBUG */
1202 * Pseudo-device attach routine.
1204 __private_extern__
int
1209 lck_grp_attr_t
*lck_grp_attr
= NULL
;
1211 lck_grp_attr
= lck_grp_attr_alloc_init();
1213 bridge_lock_grp
= lck_grp_alloc_init("if_bridge", lck_grp_attr
);
1215 bridge_lock_attr
= lck_attr_alloc_init();
1218 lck_attr_setdebug(bridge_lock_attr
);
1221 lck_mtx_init(&bridge_list_mtx
, bridge_lock_grp
, bridge_lock_attr
);
1223 /* can free the attributes once we've allocated the group lock */
1224 lck_grp_attr_free(lck_grp_attr
);
1226 LIST_INIT(&bridge_list
);
1230 #endif /* BRIDGESTP */
1232 error
= if_clone_attach(&bridge_cloner
);
1234 printf("%s: ifnet_clone_attach failed %d\n", __func__
, error
);
1242 bridge_ifnet_set_attrs(struct ifnet
* ifp
)
1246 error
= ifnet_set_mtu(ifp
, ETHERMTU
);
1248 printf("%s: ifnet_set_mtu failed %d\n", __func__
, error
);
1251 error
= ifnet_set_addrlen(ifp
, ETHER_ADDR_LEN
);
1253 printf("%s: ifnet_set_addrlen failed %d\n", __func__
, error
);
1256 error
= ifnet_set_hdrlen(ifp
, ETHER_HDR_LEN
);
1258 printf("%s: ifnet_set_hdrlen failed %d\n", __func__
, error
);
1261 error
= ifnet_set_flags(ifp
,
1262 IFF_BROADCAST
| IFF_SIMPLEX
| IFF_NOTRAILERS
| IFF_MULTICAST
,
1266 printf("%s: ifnet_set_flags failed %d\n", __func__
, error
);
1274 * bridge_clone_create:
1276 * Create a new bridge instance.
1279 bridge_clone_create(struct if_clone
*ifc
, uint32_t unit
, void *params
)
1281 #pragma unused(params)
1282 struct ifnet
*ifp
= NULL
;
1283 struct bridge_softc
*sc
= NULL
;
1284 struct bridge_softc
*sc2
= NULL
;
1285 struct ifnet_init_eparams init_params
;
1287 uint8_t eth_hostid
[ETHER_ADDR_LEN
];
1288 int fb
, retry
, has_hostid
;
1290 sc
= if_clone_softc_allocate(&bridge_cloner
);
1296 lck_mtx_init(&sc
->sc_mtx
, bridge_lock_grp
, bridge_lock_attr
);
1297 sc
->sc_brtmax
= BRIDGE_RTABLE_MAX
;
1298 sc
->sc_mne_max
= BRIDGE_MAC_NAT_ENTRY_MAX
;
1299 sc
->sc_brttimeout
= BRIDGE_RTABLE_TIMEOUT
;
1300 sc
->sc_filter_flags
= 0;
1302 TAILQ_INIT(&sc
->sc_iflist
);
1304 /* use the interface name as the unique id for ifp recycle */
1305 snprintf(sc
->sc_if_xname
, sizeof(sc
->sc_if_xname
), "%s%d",
1306 ifc
->ifc_name
, unit
);
1307 bzero(&init_params
, sizeof(init_params
));
1308 init_params
.ver
= IFNET_INIT_CURRENT_VERSION
;
1309 init_params
.len
= sizeof(init_params
);
1310 /* Initialize our routing table. */
1311 error
= bridge_rtable_init(sc
);
1313 printf("%s: bridge_rtable_init failed %d\n",
1317 TAILQ_INIT(&sc
->sc_spanlist
);
1318 if (if_bridge_txstart
) {
1319 init_params
.start
= bridge_start
;
1321 init_params
.flags
= IFNET_INIT_LEGACY
;
1322 init_params
.output
= bridge_output
;
1324 init_params
.set_bpf_tap
= bridge_set_bpf_tap
;
1325 init_params
.uniqueid
= sc
->sc_if_xname
;
1326 init_params
.uniqueid_len
= strlen(sc
->sc_if_xname
);
1327 init_params
.sndq_maxlen
= IFQ_MAXLEN
;
1328 init_params
.name
= ifc
->ifc_name
;
1329 init_params
.unit
= unit
;
1330 init_params
.family
= IFNET_FAMILY_ETHERNET
;
1331 init_params
.type
= IFT_BRIDGE
;
1332 init_params
.demux
= ether_demux
;
1333 init_params
.add_proto
= ether_add_proto
;
1334 init_params
.del_proto
= ether_del_proto
;
1335 init_params
.check_multi
= ether_check_multi
;
1336 init_params
.framer_extended
= ether_frameout_extended
;
1337 init_params
.softc
= sc
;
1338 init_params
.ioctl
= bridge_ioctl
;
1339 init_params
.detach
= bridge_detach
;
1340 init_params
.broadcast_addr
= etherbroadcastaddr
;
1341 init_params
.broadcast_len
= ETHER_ADDR_LEN
;
1343 error
= ifnet_allocate_extended(&init_params
, &ifp
);
1345 printf("%s: ifnet_allocate failed %d\n",
1349 LIST_INIT(&sc
->sc_mne_list
);
1350 LIST_INIT(&sc
->sc_mne_list_v6
);
1352 error
= bridge_ifnet_set_attrs(ifp
);
1354 printf("%s: bridge_ifnet_set_attrs failed %d\n",
1359 * Generate an ethernet address with a locally administered address.
1361 * Since we are using random ethernet addresses for the bridge, it is
1362 * possible that we might have address collisions, so make sure that
1363 * this hardware address isn't already in use on another bridge.
1364 * The first try uses the "hostid" and falls back to read_frandom();
1365 * for "hostid", we use the MAC address of the first-encountered
1366 * Ethernet-type interface that is currently configured.
1369 has_hostid
= (uuid_get_ethernet(ð_hostid
[0]) == 0);
1370 for (retry
= 1; retry
!= 0;) {
1371 if (fb
|| has_hostid
== 0) {
1372 read_frandom(&sc
->sc_defaddr
, ETHER_ADDR_LEN
);
1373 sc
->sc_defaddr
[0] &= ~1; /* clear multicast bit */
1374 sc
->sc_defaddr
[0] |= 2; /* set the LAA bit */
1376 bcopy(ð_hostid
[0], &sc
->sc_defaddr
,
1378 sc
->sc_defaddr
[0] &= ~1; /* clear multicast bit */
1379 sc
->sc_defaddr
[0] |= 2; /* set the LAA bit */
1380 sc
->sc_defaddr
[3] = /* stir it up a bit */
1381 ((sc
->sc_defaddr
[3] & 0x0f) << 4) |
1382 ((sc
->sc_defaddr
[3] & 0xf0) >> 4);
1384 * Mix in the LSB as it's actually pretty significant,
1385 * see rdar://14076061
1388 (((sc
->sc_defaddr
[4] & 0x0f) << 4) |
1389 ((sc
->sc_defaddr
[4] & 0xf0) >> 4)) ^
1391 sc
->sc_defaddr
[5] = ifp
->if_unit
& 0xff;
1396 lck_mtx_lock(&bridge_list_mtx
);
1397 LIST_FOREACH(sc2
, &bridge_list
, sc_list
) {
1398 if (memcmp(sc
->sc_defaddr
,
1399 IF_LLADDR(sc2
->sc_ifp
), ETHER_ADDR_LEN
) == 0) {
1403 lck_mtx_unlock(&bridge_list_mtx
);
1406 sc
->sc_flags
&= ~SCF_MEDIA_ACTIVE
;
1409 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
1413 error
= ifnet_attach(ifp
, NULL
);
1415 printf("%s: ifnet_attach failed %d\n", __func__
, error
);
1419 error
= ifnet_set_lladdr_and_type(ifp
, sc
->sc_defaddr
, ETHER_ADDR_LEN
,
1422 printf("%s: ifnet_set_lladdr_and_type failed %d\n", __func__
,
1427 ifnet_set_offload(ifp
,
1428 IFNET_CSUM_IP
| IFNET_CSUM_TCP
| IFNET_CSUM_UDP
|
1429 IFNET_CSUM_TCPIPV6
| IFNET_CSUM_UDPIPV6
| IFNET_MULTIPAGES
);
1430 error
= bridge_set_tso(sc
);
1432 printf("%s: bridge_set_tso failed %d\n",
1437 bstp_attach(&sc
->sc_stp
, &bridge_ops
);
1438 #endif /* BRIDGESTP */
1440 lck_mtx_lock(&bridge_list_mtx
);
1441 LIST_INSERT_HEAD(&bridge_list
, sc
, sc_list
);
1442 lck_mtx_unlock(&bridge_list_mtx
);
1444 /* attach as ethernet */
1445 error
= bpf_attach(ifp
, DLT_EN10MB
, sizeof(struct ether_header
),
1450 printf("%s failed error %d\n", __func__
, error
);
1451 /* TBD: Clean up: sc, sc_rthash etc */
1458 * bridge_clone_destroy:
1460 * Destroy a bridge instance.
1463 bridge_clone_destroy(struct ifnet
*ifp
)
1465 struct bridge_softc
*sc
= ifp
->if_softc
;
1466 struct bridge_iflist
*bif
;
1470 if ((sc
->sc_flags
& SCF_DETACHING
)) {
1474 sc
->sc_flags
|= SCF_DETACHING
;
1476 bridge_ifstop(ifp
, 1);
1478 bridge_cancel_delayed_call(&sc
->sc_resize_call
);
1480 bridge_cleanup_delayed_call(&sc
->sc_resize_call
);
1481 bridge_cleanup_delayed_call(&sc
->sc_aging_timer
);
1483 error
= ifnet_set_flags(ifp
, 0, IFF_UP
);
1485 printf("%s: ifnet_set_flags failed %d\n", __func__
, error
);
1488 while ((bif
= TAILQ_FIRST(&sc
->sc_iflist
)) != NULL
) {
1489 bridge_delete_member(sc
, bif
, 0);
1492 while ((bif
= TAILQ_FIRST(&sc
->sc_spanlist
)) != NULL
) {
1493 bridge_delete_span(sc
, bif
);
1497 error
= ifnet_detach(ifp
);
1499 panic("%s: ifnet_detach(%p) failed %d\n",
1500 __func__
, ifp
, error
);
1505 #define DRVSPEC do { \
1506 if (ifd->ifd_cmd >= bridge_control_table_size) { \
1510 bc = &bridge_control_table[ifd->ifd_cmd]; \
1512 if (cmd == SIOCGDRVSPEC && \
1513 (bc->bc_flags & BC_F_COPYOUT) == 0) { \
1516 } else if (cmd == SIOCSDRVSPEC && \
1517 (bc->bc_flags & BC_F_COPYOUT) != 0) { \
1522 if (bc->bc_flags & BC_F_SUSER) { \
1523 error = kauth_authorize_generic(kauth_cred_get(), \
1524 KAUTH_GENERIC_ISSUSER); \
1529 if (ifd->ifd_len != bc->bc_argsize || \
1530 ifd->ifd_len > sizeof (args)) { \
1535 bzero(&args, sizeof (args)); \
1536 if (bc->bc_flags & BC_F_COPYIN) { \
1537 error = copyin(ifd->ifd_data, &args, ifd->ifd_len); \
1543 error = (*bc->bc_func)(sc, &args); \
1544 BRIDGE_UNLOCK(sc); \
1548 if (bc->bc_flags & BC_F_COPYOUT) \
1549 error = copyout(&args, ifd->ifd_data, ifd->ifd_len); \
1555 * Handle a control request from the operator.
1558 bridge_ioctl(struct ifnet
*ifp
, u_long cmd
, void *data
)
1560 struct bridge_softc
*sc
= ifp
->if_softc
;
1561 struct ifreq
*ifr
= (struct ifreq
*)data
;
1562 struct bridge_iflist
*bif
;
1565 BRIDGE_LOCK_ASSERT_NOTHELD(sc
);
1568 if (IF_BRIDGE_DEBUG(BR_DBGF_IOCTL
)) {
1569 printf("%s: ifp %s cmd 0x%08lx (%c%c [%lu] %c %lu)\n",
1570 __func__
, ifp
->if_xname
, cmd
, (cmd
& IOC_IN
) ? 'I' : ' ',
1571 (cmd
& IOC_OUT
) ? 'O' : ' ', IOCPARM_LEN(cmd
),
1572 (char)IOCGROUP(cmd
), cmd
& 0xff);
1574 #endif /* BRIDGE_DEBUG */
1579 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
1582 case SIOCGIFMEDIA32
:
1583 case SIOCGIFMEDIA64
: {
1584 struct ifmediareq
*ifmr
= (struct ifmediareq
*)data
;
1585 user_addr_t user_addr
;
1587 user_addr
= (cmd
== SIOCGIFMEDIA64
) ?
1588 ((struct ifmediareq64
*)ifmr
)->ifmu_ulist
:
1589 CAST_USER_ADDR_T(((struct ifmediareq32
*)ifmr
)->ifmu_ulist
);
1591 ifmr
->ifm_status
= IFM_AVALID
;
1593 ifmr
->ifm_count
= 1;
1596 if (!(sc
->sc_flags
& SCF_DETACHING
) &&
1597 (sc
->sc_flags
& SCF_MEDIA_ACTIVE
)) {
1598 ifmr
->ifm_status
|= IFM_ACTIVE
;
1599 ifmr
->ifm_active
= ifmr
->ifm_current
=
1600 IFM_ETHER
| IFM_AUTO
;
1602 ifmr
->ifm_active
= ifmr
->ifm_current
= IFM_NONE
;
1606 if (user_addr
!= USER_ADDR_NULL
) {
1607 error
= copyout(&ifmr
->ifm_current
, user_addr
,
1617 case SIOCSDRVSPEC32
:
1618 case SIOCGDRVSPEC32
: {
1620 struct ifbreq ifbreq
;
1621 struct ifbifconf32 ifbifconf
;
1622 struct ifbareq32 ifbareq
;
1623 struct ifbaconf32 ifbaconf
;
1624 struct ifbrparam ifbrparam
;
1625 struct ifbropreq32 ifbropreq
;
1627 struct ifdrv32
*ifd
= (struct ifdrv32
*)data
;
1628 const struct bridge_control
*bridge_control_table
=
1629 bridge_control_table32
, *bc
;
1635 case SIOCSDRVSPEC64
:
1636 case SIOCGDRVSPEC64
: {
1638 struct ifbreq ifbreq
;
1639 struct ifbifconf64 ifbifconf
;
1640 struct ifbareq64 ifbareq
;
1641 struct ifbaconf64 ifbaconf
;
1642 struct ifbrparam ifbrparam
;
1643 struct ifbropreq64 ifbropreq
;
1645 struct ifdrv64
*ifd
= (struct ifdrv64
*)data
;
1646 const struct bridge_control
*bridge_control_table
=
1647 bridge_control_table64
, *bc
;
1655 if (!(ifp
->if_flags
& IFF_UP
) &&
1656 (ifp
->if_flags
& IFF_RUNNING
)) {
1658 * If interface is marked down and it is running,
1659 * then stop and disable it.
1662 bridge_ifstop(ifp
, 1);
1664 } else if ((ifp
->if_flags
& IFF_UP
) &&
1665 !(ifp
->if_flags
& IFF_RUNNING
)) {
1667 * If interface is marked up and it is stopped, then
1671 error
= bridge_init(ifp
);
1677 error
= ifnet_set_lladdr(ifp
, ifr
->ifr_addr
.sa_data
,
1678 ifr
->ifr_addr
.sa_len
);
1680 printf("%s: SIOCSIFLLADDR error %d\n", ifp
->if_xname
,
1686 if (ifr
->ifr_mtu
< 576) {
1691 if (TAILQ_EMPTY(&sc
->sc_iflist
)) {
1692 sc
->sc_ifp
->if_mtu
= ifr
->ifr_mtu
;
1696 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
1697 if (bif
->bif_ifp
->if_mtu
!= (unsigned)ifr
->ifr_mtu
) {
1698 printf("%s: invalid MTU: %u(%s) != %d\n",
1699 sc
->sc_ifp
->if_xname
,
1700 bif
->bif_ifp
->if_mtu
,
1701 bif
->bif_ifp
->if_xname
, ifr
->ifr_mtu
);
1707 sc
->sc_ifp
->if_mtu
= ifr
->ifr_mtu
;
1713 error
= ether_ioctl(ifp
, cmd
, data
);
1715 if (error
!= 0 && error
!= EOPNOTSUPP
) {
1716 printf("%s: ifp %s cmd 0x%08lx "
1717 "(%c%c [%lu] %c %lu) failed error: %d\n",
1718 __func__
, ifp
->if_xname
, cmd
,
1719 (cmd
& IOC_IN
) ? 'I' : ' ',
1720 (cmd
& IOC_OUT
) ? 'O' : ' ',
1721 IOCPARM_LEN(cmd
), (char)IOCGROUP(cmd
),
1724 #endif /* BRIDGE_DEBUG */
1727 BRIDGE_LOCK_ASSERT_NOTHELD(sc
);
1736 * Clear or restore unwanted capabilities on the member interface
1739 bridge_mutecaps(struct bridge_softc
*sc
)
1741 struct bridge_iflist
*bif
;
1744 /* Initial bitmask of capabilities to test */
1745 mask
= BRIDGE_IFCAPS_MASK
;
1747 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
1748 /* Every member must support it or its disabled */
1749 mask
&= bif
->bif_savedcaps
;
1752 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
1753 enabled
= bif
->bif_ifp
->if_capenable
;
1754 enabled
&= ~BRIDGE_IFCAPS_STRIP
;
1755 /* strip off mask bits and enable them again if allowed */
1756 enabled
&= ~BRIDGE_IFCAPS_MASK
;
1759 bridge_set_ifcap(sc
, bif
, enabled
);
1764 bridge_set_ifcap(struct bridge_softc
*sc
, struct bridge_iflist
*bif
, int set
)
1766 struct ifnet
*ifp
= bif
->bif_ifp
;
1770 bzero(&ifr
, sizeof(ifr
));
1771 ifr
.ifr_reqcap
= set
;
1773 if (ifp
->if_capenable
!= set
) {
1775 error
= (*ifp
->if_ioctl
)(ifp
, SIOCSIFCAP
, (caddr_t
)&ifr
);
1776 IFF_UNLOCKGIANT(ifp
);
1778 printf("%s: %s error setting interface capabilities "
1779 "on %s\n", __func__
, sc
->sc_ifp
->if_xname
,
1784 #endif /* HAS_IF_CAP */
1787 bridge_set_tso(struct bridge_softc
*sc
)
1789 struct bridge_iflist
*bif
;
1790 u_int32_t tso_v4_mtu
;
1791 u_int32_t tso_v6_mtu
;
1792 ifnet_offload_t offload
;
1795 /* By default, support TSO */
1796 offload
= sc
->sc_ifp
->if_hwassist
| IFNET_TSO_IPV4
| IFNET_TSO_IPV6
;
1797 tso_v4_mtu
= IP_MAXPACKET
;
1798 tso_v6_mtu
= IP_MAXPACKET
;
1800 /* Use the lowest common denominator of the members */
1801 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
1802 ifnet_t ifp
= bif
->bif_ifp
;
1808 if (offload
& IFNET_TSO_IPV4
) {
1809 if (ifp
->if_hwassist
& IFNET_TSO_IPV4
) {
1810 if (tso_v4_mtu
> ifp
->if_tso_v4_mtu
) {
1811 tso_v4_mtu
= ifp
->if_tso_v4_mtu
;
1814 offload
&= ~IFNET_TSO_IPV4
;
1818 if (offload
& IFNET_TSO_IPV6
) {
1819 if (ifp
->if_hwassist
& IFNET_TSO_IPV6
) {
1820 if (tso_v6_mtu
> ifp
->if_tso_v6_mtu
) {
1821 tso_v6_mtu
= ifp
->if_tso_v6_mtu
;
1824 offload
&= ~IFNET_TSO_IPV6
;
1830 if (offload
!= sc
->sc_ifp
->if_hwassist
) {
1831 error
= ifnet_set_offload(sc
->sc_ifp
, offload
);
1834 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
1835 printf("%s: ifnet_set_offload(%s, 0x%x) "
1836 "failed %d\n", __func__
,
1837 sc
->sc_ifp
->if_xname
, offload
, error
);
1839 #endif /* BRIDGE_DEBUG */
1843 * For ifnet_set_tso_mtu() sake, the TSO MTU must be at least
1844 * as large as the interface MTU
1846 if (sc
->sc_ifp
->if_hwassist
& IFNET_TSO_IPV4
) {
1847 if (tso_v4_mtu
< sc
->sc_ifp
->if_mtu
) {
1848 tso_v4_mtu
= sc
->sc_ifp
->if_mtu
;
1850 error
= ifnet_set_tso_mtu(sc
->sc_ifp
, AF_INET
,
1854 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
1855 printf("%s: ifnet_set_tso_mtu(%s, "
1856 "AF_INET, %u) failed %d\n",
1857 __func__
, sc
->sc_ifp
->if_xname
,
1860 #endif /* BRIDGE_DEBUG */
1864 if (sc
->sc_ifp
->if_hwassist
& IFNET_TSO_IPV6
) {
1865 if (tso_v6_mtu
< sc
->sc_ifp
->if_mtu
) {
1866 tso_v6_mtu
= sc
->sc_ifp
->if_mtu
;
1868 error
= ifnet_set_tso_mtu(sc
->sc_ifp
, AF_INET6
,
1872 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
1873 printf("%s: ifnet_set_tso_mtu(%s, "
1874 "AF_INET6, %u) failed %d\n",
1875 __func__
, sc
->sc_ifp
->if_xname
,
1878 #endif /* BRIDGE_DEBUG */
1888 * bridge_lookup_member:
1890 * Lookup a bridge member interface.
1892 static struct bridge_iflist
*
1893 bridge_lookup_member(struct bridge_softc
*sc
, const char *name
)
1895 struct bridge_iflist
*bif
;
1898 BRIDGE_LOCK_ASSERT_HELD(sc
);
1900 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
1902 if (strcmp(ifp
->if_xname
, name
) == 0) {
1911 * bridge_lookup_member_if:
1913 * Lookup a bridge member interface by ifnet*.
1915 static struct bridge_iflist
*
1916 bridge_lookup_member_if(struct bridge_softc
*sc
, struct ifnet
*member_ifp
)
1918 struct bridge_iflist
*bif
;
1920 BRIDGE_LOCK_ASSERT_HELD(sc
);
1922 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
1923 if (bif
->bif_ifp
== member_ifp
) {
1932 bridge_iff_input(void *cookie
, ifnet_t ifp
, protocol_family_t protocol
,
1933 mbuf_t
*data
, char **frame_ptr
)
1935 #pragma unused(protocol)
1937 struct bridge_iflist
*bif
= (struct bridge_iflist
*)cookie
;
1938 struct bridge_softc
*sc
= bif
->bif_sc
;
1943 if ((m
->m_flags
& M_PROTO1
)) {
1947 if (*frame_ptr
>= (char *)mbuf_datastart(m
) &&
1948 *frame_ptr
<= (char *)mbuf_data(m
)) {
1950 frmlen
= (char *)mbuf_data(m
) - *frame_ptr
;
1953 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT
)) {
1954 printf("%s: %s from %s m 0x%llx data 0x%llx frame 0x%llx %s "
1955 "frmlen %lu\n", __func__
, sc
->sc_ifp
->if_xname
,
1956 ifp
->if_xname
, (uint64_t)VM_KERNEL_ADDRPERM(m
),
1957 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_data(m
)),
1958 (uint64_t)VM_KERNEL_ADDRPERM(*frame_ptr
),
1959 included
? "inside" : "outside", frmlen
);
1961 if (IF_BRIDGE_DEBUG(BR_DBGF_MBUF
)) {
1962 printf_mbuf(m
, "bridge_iff_input[", "\n");
1963 printf_ether_header((struct ether_header
*)
1964 (void *)*frame_ptr
);
1965 printf_mbuf_data(m
, 0, 20);
1969 #endif /* BRIDGE_DEBUG */
1970 if (included
== 0) {
1971 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT
)) {
1972 printf("%s: frame_ptr outside mbuf\n", __func__
);
1977 /* Move data pointer to start of frame to the link layer header */
1978 (void) mbuf_setdata(m
, (char *)mbuf_data(m
) - frmlen
,
1979 mbuf_len(m
) + frmlen
);
1980 (void) mbuf_pkthdr_adjustlen(m
, frmlen
);
1982 /* make sure we can access the ethernet header */
1983 if (mbuf_pkthdr_len(m
) < sizeof(struct ether_header
)) {
1984 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT
)) {
1985 printf("%s: short frame %lu < %lu\n", __func__
,
1986 mbuf_pkthdr_len(m
), sizeof(struct ether_header
));
1990 if (mbuf_len(m
) < sizeof(struct ether_header
)) {
1991 error
= mbuf_pullup(data
, sizeof(struct ether_header
));
1993 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT
)) {
1994 printf("%s: mbuf_pullup(%lu) failed %d\n",
1995 __func__
, sizeof(struct ether_header
),
1998 error
= EJUSTRETURN
;
2003 *frame_ptr
= mbuf_data(m
);
2007 error
= bridge_input(ifp
, data
);
2009 /* Adjust packet back to original */
2011 /* bridge_input might have modified *data */
2014 *frame_ptr
= mbuf_data(m
);
2016 (void) mbuf_setdata(m
, (char *)mbuf_data(m
) + frmlen
,
2017 mbuf_len(m
) - frmlen
);
2018 (void) mbuf_pkthdr_adjustlen(m
, -frmlen
);
2021 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT
) &&
2022 IF_BRIDGE_DEBUG(BR_DBGF_MBUF
)) {
2024 printf_mbuf(m
, "bridge_iff_input]", "\n");
2026 #endif /* BRIDGE_DEBUG */
2029 BRIDGE_LOCK_ASSERT_NOTHELD(sc
);
2035 bridge_iff_output(void *cookie
, ifnet_t ifp
, protocol_family_t protocol
,
2038 #pragma unused(protocol)
2040 struct bridge_iflist
*bif
= (struct bridge_iflist
*)cookie
;
2041 struct bridge_softc
*sc
= bif
->bif_sc
;
2044 if ((m
->m_flags
& M_PROTO1
)) {
2049 if (IF_BRIDGE_DEBUG(BR_DBGF_OUTPUT
)) {
2050 printf("%s: %s from %s m 0x%llx data 0x%llx\n", __func__
,
2051 sc
->sc_ifp
->if_xname
, ifp
->if_xname
,
2052 (uint64_t)VM_KERNEL_ADDRPERM(m
),
2053 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_data(m
)));
2055 #endif /* BRIDGE_DEBUG */
2057 error
= bridge_member_output(sc
, ifp
, data
);
2058 if (error
!= 0 && error
!= EJUSTRETURN
) {
2059 printf("%s: bridge_member_output failed error %d\n", __func__
,
2063 BRIDGE_LOCK_ASSERT_NOTHELD(sc
);
2069 bridge_iff_event(void *cookie
, ifnet_t ifp
, protocol_family_t protocol
,
2070 const struct kev_msg
*event_msg
)
2072 #pragma unused(protocol)
2073 struct bridge_iflist
*bif
= (struct bridge_iflist
*)cookie
;
2074 struct bridge_softc
*sc
= bif
->bif_sc
;
2076 if (event_msg
->vendor_code
== KEV_VENDOR_APPLE
&&
2077 event_msg
->kev_class
== KEV_NETWORK_CLASS
&&
2078 event_msg
->kev_subclass
== KEV_DL_SUBCLASS
) {
2080 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
2081 printf("%s: %s event_code %u - %s\n", __func__
,
2082 ifp
->if_xname
, event_msg
->event_code
,
2083 dlil_kev_dl_code_str(event_msg
->event_code
));
2085 #endif /* BRIDGE_DEBUG */
2087 switch (event_msg
->event_code
) {
2088 case KEV_DL_IF_DETACHING
:
2089 case KEV_DL_IF_DETACHED
: {
2090 bridge_ifdetach(ifp
);
2093 case KEV_DL_LINK_OFF
:
2094 case KEV_DL_LINK_ON
: {
2095 bridge_iflinkevent(ifp
);
2097 bstp_linkstate(ifp
, event_msg
->event_code
);
2098 #endif /* BRIDGESTP */
2101 case KEV_DL_SIFFLAGS
: {
2102 if ((bif
->bif_flags
& BIFF_PROMISC
) == 0 &&
2103 (ifp
->if_flags
& IFF_UP
)) {
2106 error
= ifnet_set_promiscuous(ifp
, 1);
2109 "ifnet_set_promiscuous (%s)"
2111 __func__
, ifp
->if_xname
,
2114 bif
->bif_flags
|= BIFF_PROMISC
;
2119 case KEV_DL_IFCAP_CHANGED
: {
2125 case KEV_DL_PROTO_DETACHED
:
2126 case KEV_DL_PROTO_ATTACHED
: {
2127 bridge_proto_attach_changed(ifp
);
2137 * bridge_iff_detached:
2139 * Detach an interface from a bridge. Called when a member
2140 * interface is detaching.
2143 bridge_iff_detached(void *cookie
, ifnet_t ifp
)
2145 struct bridge_iflist
*bif
= (struct bridge_iflist
*)cookie
;
2148 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
2149 printf("%s: %s\n", __func__
, ifp
->if_xname
);
2151 #endif /* BRIDGE_DEBUG */
2153 bridge_ifdetach(ifp
);
2155 _FREE(bif
, M_DEVBUF
);
2159 bridge_proto_input(ifnet_t ifp
, protocol_family_t protocol
, mbuf_t packet
,
2162 #pragma unused(protocol, packet, header)
2164 printf("%s: unexpected packet from %s\n", __func__
,
2166 #endif /* BRIDGE_DEBUG */
2171 bridge_attach_protocol(struct ifnet
*ifp
)
2174 struct ifnet_attach_proto_param reg
;
2177 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
2178 printf("%s: %s\n", __func__
, ifp
->if_xname
);
2180 #endif /* BRIDGE_DEBUG */
2182 bzero(®
, sizeof(reg
));
2183 reg
.input
= bridge_proto_input
;
2185 error
= ifnet_attach_protocol(ifp
, PF_BRIDGE
, ®
);
2187 printf("%s: ifnet_attach_protocol(%s) failed, %d\n",
2188 __func__
, ifp
->if_xname
, error
);
2195 bridge_detach_protocol(struct ifnet
*ifp
)
2200 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
2201 printf("%s: %s\n", __func__
, ifp
->if_xname
);
2203 #endif /* BRIDGE_DEBUG */
2204 error
= ifnet_detach_protocol(ifp
, PF_BRIDGE
);
2206 printf("%s: ifnet_detach_protocol(%s) failed, %d\n",
2207 __func__
, ifp
->if_xname
, error
);
2214 * bridge_delete_member:
2216 * Delete the specified member interface.
2219 bridge_delete_member(struct bridge_softc
*sc
, struct bridge_iflist
*bif
,
2222 struct ifnet
*ifs
= bif
->bif_ifp
, *bifp
= sc
->sc_ifp
;
2223 int lladdr_changed
= 0, error
, filt_attached
;
2224 uint8_t eaddr
[ETHER_ADDR_LEN
];
2225 u_int32_t event_code
= 0;
2227 BRIDGE_LOCK_ASSERT_HELD(sc
);
2228 VERIFY(ifs
!= NULL
);
2231 * Remove the member from the list first so it cannot be found anymore
2232 * when we release the bridge lock below
2235 TAILQ_REMOVE(&sc
->sc_iflist
, bif
, bif_next
);
2238 if (sc
->sc_mac_nat_bif
!= NULL
) {
2239 if (bif
== sc
->sc_mac_nat_bif
) {
2240 bridge_mac_nat_disable(sc
);
2242 bridge_mac_nat_flush_entries(sc
, bif
);
2247 switch (ifs
->if_type
) {
2251 * Take the interface out of promiscuous mode.
2253 if (bif
->bif_flags
& BIFF_PROMISC
) {
2255 * Unlock to prevent deadlock with bridge_iff_event() in
2256 * case the driver generates an interface event
2259 (void) ifnet_set_promiscuous(ifs
, 0);
2265 /* currently not supported */
2273 /* reneable any interface capabilities */
2274 bridge_set_ifcap(sc
, bif
, bif
->bif_savedcaps
);
2278 if (bif
->bif_flags
& BIFF_PROTO_ATTACHED
) {
2279 /* Respect lock ordering with DLIL lock */
2281 (void) bridge_detach_protocol(ifs
);
2285 if ((bif
->bif_ifflags
& IFBIF_STP
) != 0) {
2286 bstp_disable(&bif
->bif_stp
);
2288 #endif /* BRIDGESTP */
2291 * If removing the interface that gave the bridge its mac address, set
2292 * the mac address of the bridge to the address of the next member, or
2293 * to its default address if no members are left.
2295 if (bridge_inherit_mac
&& sc
->sc_ifaddr
== ifs
) {
2296 ifnet_release(sc
->sc_ifaddr
);
2297 if (TAILQ_EMPTY(&sc
->sc_iflist
)) {
2298 bcopy(sc
->sc_defaddr
, eaddr
, ETHER_ADDR_LEN
);
2299 sc
->sc_ifaddr
= NULL
;
2302 TAILQ_FIRST(&sc
->sc_iflist
)->bif_ifp
;
2303 bcopy(IF_LLADDR(fif
), eaddr
, ETHER_ADDR_LEN
);
2304 sc
->sc_ifaddr
= fif
;
2305 ifnet_reference(fif
); /* for sc_ifaddr */
2311 bridge_mutecaps(sc
); /* recalculate now this interface is removed */
2312 #endif /* HAS_IF_CAP */
2314 error
= bridge_set_tso(sc
);
2316 printf("%s: bridge_set_tso failed %d\n", __func__
, error
);
2319 bridge_rtdelete(sc
, ifs
, IFBF_FLUSHALL
);
2321 KASSERT(bif
->bif_addrcnt
== 0,
2322 ("%s: %d bridge routes referenced", __func__
, bif
->bif_addrcnt
));
2324 filt_attached
= bif
->bif_flags
& BIFF_FILTER_ATTACHED
;
2327 * Update link status of the bridge based on its remaining members
2329 event_code
= bridge_updatelinkstatus(sc
);
2334 if (lladdr_changed
&&
2335 (error
= ifnet_set_lladdr(bifp
, eaddr
, ETHER_ADDR_LEN
)) != 0) {
2336 printf("%s: ifnet_set_lladdr failed %d\n", __func__
, error
);
2339 if (event_code
!= 0) {
2340 bridge_link_event(bifp
, event_code
);
2344 bstp_destroy(&bif
->bif_stp
); /* prepare to free */
2345 #endif /* BRIDGESTP */
2347 if (filt_attached
) {
2348 iflt_detach(bif
->bif_iff_ref
);
2350 _FREE(bif
, M_DEVBUF
);
2353 ifs
->if_bridge
= NULL
;
2360 * bridge_delete_span:
2362 * Delete the specified span interface.
2365 bridge_delete_span(struct bridge_softc
*sc
, struct bridge_iflist
*bif
)
2367 BRIDGE_LOCK_ASSERT_HELD(sc
);
2369 KASSERT(bif
->bif_ifp
->if_bridge
== NULL
,
2370 ("%s: not a span interface", __func__
));
2372 ifnet_release(bif
->bif_ifp
);
2374 TAILQ_REMOVE(&sc
->sc_spanlist
, bif
, bif_next
);
2375 _FREE(bif
, M_DEVBUF
);
2379 bridge_ioctl_add(struct bridge_softc
*sc
, void *arg
)
2381 struct ifbreq
*req
= arg
;
2382 struct bridge_iflist
*bif
= NULL
;
2383 struct ifnet
*ifs
, *bifp
= sc
->sc_ifp
;
2384 int error
= 0, lladdr_changed
= 0;
2385 uint8_t eaddr
[ETHER_ADDR_LEN
];
2386 struct iff_filter iff
;
2387 u_int32_t event_code
= 0;
2388 boolean_t mac_nat
= FALSE
;
2390 ifs
= ifunit(req
->ifbr_ifsname
);
2394 if (ifs
->if_ioctl
== NULL
) { /* must be supported */
2398 if (IFNET_IS_INTCOPROC(ifs
)) {
2402 /* If it's in the span list, it can't be a member. */
2403 TAILQ_FOREACH(bif
, &sc
->sc_spanlist
, bif_next
) {
2404 if (ifs
== bif
->bif_ifp
) {
2409 if (ifs
->if_bridge
== sc
) {
2413 if (ifs
->if_bridge
!= NULL
) {
2417 switch (ifs
->if_type
) {
2419 if (strcmp(ifs
->if_name
, "en") == 0 &&
2420 ifs
->if_subfamily
== IFNET_SUBFAMILY_WIFI
&&
2421 (ifs
->if_eflags
& IFEF_IPV4_ROUTER
) == 0) {
2422 /* XXX is there a better way to identify Wi-Fi STA? */
2429 /* currently not supported */
2435 /* fail to add the interface if the MTU doesn't match */
2436 if (!TAILQ_EMPTY(&sc
->sc_iflist
) && sc
->sc_ifp
->if_mtu
!= ifs
->if_mtu
) {
2437 printf("%s: %s: invalid MTU for %s", __func__
,
2438 sc
->sc_ifp
->if_xname
,
2443 /* there's already an interface that's doing MAC NAT */
2444 if (mac_nat
&& sc
->sc_mac_nat_bif
!= NULL
) {
2447 bif
= _MALLOC(sizeof(*bif
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
2452 ifnet_reference(ifs
);
2453 bif
->bif_ifflags
|= IFBIF_LEARNING
| IFBIF_DISCOVER
;
2455 bif
->bif_savedcaps
= ifs
->if_capenable
;
2456 #endif /* HAS_IF_CAP */
2459 (void)bridge_mac_nat_enable(sc
, bif
);
2462 /* Allow the first Ethernet member to define the MTU */
2463 if (TAILQ_EMPTY(&sc
->sc_iflist
)) {
2464 sc
->sc_ifp
->if_mtu
= ifs
->if_mtu
;
2468 * Assign the interface's MAC address to the bridge if it's the first
2469 * member and the MAC address of the bridge has not been changed from
2470 * the default (randomly) generated one.
2472 if (bridge_inherit_mac
&& TAILQ_EMPTY(&sc
->sc_iflist
) &&
2473 !memcmp(IF_LLADDR(sc
->sc_ifp
), sc
->sc_defaddr
, ETHER_ADDR_LEN
)) {
2474 bcopy(IF_LLADDR(ifs
), eaddr
, ETHER_ADDR_LEN
);
2475 sc
->sc_ifaddr
= ifs
;
2476 ifnet_reference(ifs
); /* for sc_ifaddr */
2480 ifs
->if_bridge
= sc
;
2482 bstp_create(&sc
->sc_stp
, &bif
->bif_stp
, bif
->bif_ifp
);
2483 #endif /* BRIDGESTP */
2486 * XXX: XLOCK HERE!?!
2488 TAILQ_INSERT_TAIL(&sc
->sc_iflist
, bif
, bif_next
);
2491 /* Set interface capabilities to the intersection set of all members */
2492 bridge_mutecaps(sc
);
2493 #endif /* HAS_IF_CAP */
2499 * Place the interface into promiscuous mode.
2501 switch (ifs
->if_type
) {
2504 error
= ifnet_set_promiscuous(ifs
, 1);
2506 /* Ignore error when device is not up */
2507 if (error
!= ENETDOWN
) {
2512 bif
->bif_flags
|= BIFF_PROMISC
;
2521 * The new member may change the link status of the bridge interface
2523 if (interface_media_active(ifs
)) {
2524 bif
->bif_flags
|= BIFF_MEDIA_ACTIVE
;
2526 bif
->bif_flags
&= ~BIFF_MEDIA_ACTIVE
;
2529 event_code
= bridge_updatelinkstatus(sc
);
2532 * Respect lock ordering with DLIL lock for the following operations
2538 * install an interface filter
2540 memset(&iff
, 0, sizeof(struct iff_filter
));
2541 iff
.iff_cookie
= bif
;
2542 iff
.iff_name
= "com.apple.kernel.bsd.net.if_bridge";
2543 iff
.iff_input
= bridge_iff_input
;
2544 iff
.iff_output
= bridge_iff_output
;
2545 iff
.iff_event
= bridge_iff_event
;
2546 iff
.iff_detached
= bridge_iff_detached
;
2547 error
= dlil_attach_filter(ifs
, &iff
, &bif
->bif_iff_ref
,
2548 DLIL_IFF_TSO
| DLIL_IFF_INTERNAL
);
2550 printf("%s: iflt_attach failed %d\n", __func__
, error
);
2555 bif
->bif_flags
|= BIFF_FILTER_ATTACHED
;
2559 * install a dummy "bridge" protocol
2561 if ((error
= bridge_attach_protocol(ifs
)) != 0) {
2563 printf("%s: bridge_attach_protocol failed %d\n",
2570 bif
->bif_flags
|= BIFF_PROTO_ATTACHED
;
2573 if (lladdr_changed
&&
2574 (error
= ifnet_set_lladdr(bifp
, eaddr
, ETHER_ADDR_LEN
)) != 0) {
2575 printf("%s: ifnet_set_lladdr failed %d\n", __func__
, error
);
2578 if (event_code
!= 0) {
2579 bridge_link_event(bifp
, event_code
);
2585 if (error
&& bif
!= NULL
) {
2586 bridge_delete_member(sc
, bif
, 1);
2593 bridge_ioctl_del(struct bridge_softc
*sc
, void *arg
)
2595 struct ifbreq
*req
= arg
;
2596 struct bridge_iflist
*bif
;
2598 bif
= bridge_lookup_member(sc
, req
->ifbr_ifsname
);
2603 bridge_delete_member(sc
, bif
, 0);
2609 bridge_ioctl_purge(struct bridge_softc
*sc
, void *arg
)
2611 #pragma unused(sc, arg)
2616 bridge_ioctl_gifflags(struct bridge_softc
*sc
, void *arg
)
2618 struct ifbreq
*req
= arg
;
2619 struct bridge_iflist
*bif
;
2621 bif
= bridge_lookup_member(sc
, req
->ifbr_ifsname
);
2626 struct bstp_port
*bp
;
2629 req
->ifbr_state
= bp
->bp_state
;
2630 req
->ifbr_priority
= bp
->bp_priority
;
2631 req
->ifbr_path_cost
= bp
->bp_path_cost
;
2632 req
->ifbr_proto
= bp
->bp_protover
;
2633 req
->ifbr_role
= bp
->bp_role
;
2634 req
->ifbr_stpflags
= bp
->bp_flags
;
2635 req
->ifbr_ifsflags
= bif
->bif_ifflags
;
2637 /* Copy STP state options as flags */
2638 if (bp
->bp_operedge
) {
2639 req
->ifbr_ifsflags
|= IFBIF_BSTP_EDGE
;
2641 if (bp
->bp_flags
& BSTP_PORT_AUTOEDGE
) {
2642 req
->ifbr_ifsflags
|= IFBIF_BSTP_AUTOEDGE
;
2644 if (bp
->bp_ptp_link
) {
2645 req
->ifbr_ifsflags
|= IFBIF_BSTP_PTP
;
2647 if (bp
->bp_flags
& BSTP_PORT_AUTOPTP
) {
2648 req
->ifbr_ifsflags
|= IFBIF_BSTP_AUTOPTP
;
2650 if (bp
->bp_flags
& BSTP_PORT_ADMEDGE
) {
2651 req
->ifbr_ifsflags
|= IFBIF_BSTP_ADMEDGE
;
2653 if (bp
->bp_flags
& BSTP_PORT_ADMCOST
) {
2654 req
->ifbr_ifsflags
|= IFBIF_BSTP_ADMCOST
;
2657 req
->ifbr_portno
= bif
->bif_ifp
->if_index
& 0xfff;
2658 req
->ifbr_addrcnt
= bif
->bif_addrcnt
;
2659 req
->ifbr_addrmax
= bif
->bif_addrmax
;
2660 req
->ifbr_addrexceeded
= bif
->bif_addrexceeded
;
2666 bridge_ioctl_sifflags(struct bridge_softc
*sc
, void *arg
)
2668 struct ifbreq
*req
= arg
;
2669 struct bridge_iflist
*bif
;
2671 struct bstp_port
*bp
;
2673 #endif /* BRIDGESTP */
2675 bif
= bridge_lookup_member(sc
, req
->ifbr_ifsname
);
2680 if (req
->ifbr_ifsflags
& IFBIF_SPAN
) {
2681 /* SPAN is readonly */
2684 if ((req
->ifbr_ifsflags
& IFBIF_MAC_NAT
) != 0) {
2686 error
= bridge_mac_nat_enable(sc
, bif
);
2690 } else if (sc
->sc_mac_nat_bif
!= NULL
) {
2691 bridge_mac_nat_disable(sc
);
2696 if (req
->ifbr_ifsflags
& IFBIF_STP
) {
2697 if ((bif
->bif_ifflags
& IFBIF_STP
) == 0) {
2698 error
= bstp_enable(&bif
->bif_stp
);
2704 if ((bif
->bif_ifflags
& IFBIF_STP
) != 0) {
2705 bstp_disable(&bif
->bif_stp
);
2709 /* Pass on STP flags */
2711 bstp_set_edge(bp
, req
->ifbr_ifsflags
& IFBIF_BSTP_EDGE
? 1 : 0);
2712 bstp_set_autoedge(bp
, req
->ifbr_ifsflags
& IFBIF_BSTP_AUTOEDGE
? 1 : 0);
2713 bstp_set_ptp(bp
, req
->ifbr_ifsflags
& IFBIF_BSTP_PTP
? 1 : 0);
2714 bstp_set_autoptp(bp
, req
->ifbr_ifsflags
& IFBIF_BSTP_AUTOPTP
? 1 : 0);
2715 #else /* !BRIDGESTP */
2716 if (req
->ifbr_ifsflags
& IFBIF_STP
) {
2719 #endif /* !BRIDGESTP */
2721 /* Save the bits relating to the bridge */
2722 bif
->bif_ifflags
= req
->ifbr_ifsflags
& IFBIFMASK
;
2729 bridge_ioctl_scache(struct bridge_softc
*sc
, void *arg
)
2731 struct ifbrparam
*param
= arg
;
2733 sc
->sc_brtmax
= param
->ifbrp_csize
;
2739 bridge_ioctl_gcache(struct bridge_softc
*sc
, void *arg
)
2741 struct ifbrparam
*param
= arg
;
2743 param
->ifbrp_csize
= sc
->sc_brtmax
;
2748 #define BRIDGE_IOCTL_GIFS do { \
2749 struct bridge_iflist *bif; \
2750 struct ifbreq breq; \
2751 char *buf, *outbuf; \
2752 unsigned int count, buflen, len; \
2755 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) \
2757 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) \
2760 buflen = sizeof (breq) * count; \
2761 if (bifc->ifbic_len == 0) { \
2762 bifc->ifbic_len = buflen; \
2765 BRIDGE_UNLOCK(sc); \
2766 outbuf = _MALLOC(buflen, M_TEMP, M_WAITOK | M_ZERO); \
2771 len = min(bifc->ifbic_len, buflen); \
2772 bzero(&breq, sizeof (breq)); \
2773 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) { \
2774 if (len < sizeof (breq)) \
2777 snprintf(breq.ifbr_ifsname, sizeof (breq.ifbr_ifsname), \
2778 "%s", bif->bif_ifp->if_xname); \
2779 /* Fill in the ifbreq structure */ \
2780 error = bridge_ioctl_gifflags(sc, &breq); \
2783 memcpy(buf, &breq, sizeof (breq)); \
2785 buf += sizeof (breq); \
2786 len -= sizeof (breq); \
2788 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) { \
2789 if (len < sizeof (breq)) \
2792 snprintf(breq.ifbr_ifsname, \
2793 sizeof (breq.ifbr_ifsname), \
2794 "%s", bif->bif_ifp->if_xname); \
2795 breq.ifbr_ifsflags = bif->bif_ifflags; \
2797 = bif->bif_ifp->if_index & 0xfff; \
2798 memcpy(buf, &breq, sizeof (breq)); \
2800 buf += sizeof (breq); \
2801 len -= sizeof (breq); \
2804 BRIDGE_UNLOCK(sc); \
2805 bifc->ifbic_len = sizeof (breq) * count; \
2806 error = copyout(outbuf, bifc->ifbic_req, bifc->ifbic_len); \
2808 _FREE(outbuf, M_TEMP); \
2812 bridge_ioctl_gifs64(struct bridge_softc
*sc
, void *arg
)
2814 struct ifbifconf64
*bifc
= arg
;
2823 bridge_ioctl_gifs32(struct bridge_softc
*sc
, void *arg
)
2825 struct ifbifconf32
*bifc
= arg
;
2833 #define BRIDGE_IOCTL_RTS do { \
2834 struct bridge_rtnode *brt; \
2836 char *outbuf = NULL; \
2837 unsigned int count, buflen, len; \
2838 unsigned long now; \
2840 if (bac->ifbac_len == 0) \
2843 bzero(&bareq, sizeof (bareq)); \
2845 LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) \
2847 buflen = sizeof (bareq) * count; \
2849 BRIDGE_UNLOCK(sc); \
2850 outbuf = _MALLOC(buflen, M_TEMP, M_WAITOK | M_ZERO); \
2855 len = min(bac->ifbac_len, buflen); \
2856 LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { \
2857 if (len < sizeof (bareq)) \
2859 snprintf(bareq.ifba_ifsname, sizeof (bareq.ifba_ifsname), \
2860 "%s", brt->brt_ifp->if_xname); \
2861 memcpy(bareq.ifba_dst, brt->brt_addr, sizeof (brt->brt_addr)); \
2862 bareq.ifba_vlan = brt->brt_vlan; \
2863 if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { \
2864 now = (unsigned long) net_uptime(); \
2865 if (now < brt->brt_expire) \
2866 bareq.ifba_expire = \
2867 brt->brt_expire - now; \
2869 bareq.ifba_expire = 0; \
2870 bareq.ifba_flags = brt->brt_flags; \
2872 memcpy(buf, &bareq, sizeof (bareq)); \
2874 buf += sizeof (bareq); \
2875 len -= sizeof (bareq); \
2878 bac->ifbac_len = sizeof (bareq) * count; \
2879 if (outbuf != NULL) { \
2880 BRIDGE_UNLOCK(sc); \
2881 error = copyout(outbuf, bac->ifbac_req, bac->ifbac_len); \
2882 _FREE(outbuf, M_TEMP); \
2889 bridge_ioctl_rts64(struct bridge_softc
*sc
, void *arg
)
2891 struct ifbaconf64
*bac
= arg
;
2892 struct ifbareq64 bareq
;
2900 bridge_ioctl_rts32(struct bridge_softc
*sc
, void *arg
)
2902 struct ifbaconf32
*bac
= arg
;
2903 struct ifbareq32 bareq
;
2911 bridge_ioctl_saddr32(struct bridge_softc
*sc
, void *arg
)
2913 struct ifbareq32
*req
= arg
;
2914 struct bridge_iflist
*bif
;
2917 bif
= bridge_lookup_member(sc
, req
->ifba_ifsname
);
2922 error
= bridge_rtupdate(sc
, req
->ifba_dst
, req
->ifba_vlan
, bif
, 1,
2929 bridge_ioctl_saddr64(struct bridge_softc
*sc
, void *arg
)
2931 struct ifbareq64
*req
= arg
;
2932 struct bridge_iflist
*bif
;
2935 bif
= bridge_lookup_member(sc
, req
->ifba_ifsname
);
2940 error
= bridge_rtupdate(sc
, req
->ifba_dst
, req
->ifba_vlan
, bif
, 1,
2947 bridge_ioctl_sto(struct bridge_softc
*sc
, void *arg
)
2949 struct ifbrparam
*param
= arg
;
2951 sc
->sc_brttimeout
= param
->ifbrp_ctime
;
2956 bridge_ioctl_gto(struct bridge_softc
*sc
, void *arg
)
2958 struct ifbrparam
*param
= arg
;
2960 param
->ifbrp_ctime
= sc
->sc_brttimeout
;
2965 bridge_ioctl_daddr32(struct bridge_softc
*sc
, void *arg
)
2967 struct ifbareq32
*req
= arg
;
2969 return bridge_rtdaddr(sc
, req
->ifba_dst
, req
->ifba_vlan
);
2973 bridge_ioctl_daddr64(struct bridge_softc
*sc
, void *arg
)
2975 struct ifbareq64
*req
= arg
;
2977 return bridge_rtdaddr(sc
, req
->ifba_dst
, req
->ifba_vlan
);
2981 bridge_ioctl_flush(struct bridge_softc
*sc
, void *arg
)
2983 struct ifbreq
*req
= arg
;
2985 bridge_rtflush(sc
, req
->ifbr_ifsflags
);
2990 bridge_ioctl_gpri(struct bridge_softc
*sc
, void *arg
)
2992 struct ifbrparam
*param
= arg
;
2993 struct bstp_state
*bs
= &sc
->sc_stp
;
2995 param
->ifbrp_prio
= bs
->bs_bridge_priority
;
3000 bridge_ioctl_spri(struct bridge_softc
*sc
, void *arg
)
3003 struct ifbrparam
*param
= arg
;
3005 return bstp_set_priority(&sc
->sc_stp
, param
->ifbrp_prio
);
3006 #else /* !BRIDGESTP */
3007 #pragma unused(sc, arg)
3009 #endif /* !BRIDGESTP */
3013 bridge_ioctl_ght(struct bridge_softc
*sc
, void *arg
)
3015 struct ifbrparam
*param
= arg
;
3016 struct bstp_state
*bs
= &sc
->sc_stp
;
3018 param
->ifbrp_hellotime
= bs
->bs_bridge_htime
>> 8;
3023 bridge_ioctl_sht(struct bridge_softc
*sc
, void *arg
)
3026 struct ifbrparam
*param
= arg
;
3028 return bstp_set_htime(&sc
->sc_stp
, param
->ifbrp_hellotime
);
3029 #else /* !BRIDGESTP */
3030 #pragma unused(sc, arg)
3032 #endif /* !BRIDGESTP */
3036 bridge_ioctl_gfd(struct bridge_softc
*sc
, void *arg
)
3038 struct ifbrparam
*param
;
3039 struct bstp_state
*bs
;
3043 param
->ifbrp_fwddelay
= bs
->bs_bridge_fdelay
>> 8;
3048 bridge_ioctl_sfd(struct bridge_softc
*sc
, void *arg
)
3051 struct ifbrparam
*param
= arg
;
3053 return bstp_set_fdelay(&sc
->sc_stp
, param
->ifbrp_fwddelay
);
3054 #else /* !BRIDGESTP */
3055 #pragma unused(sc, arg)
3057 #endif /* !BRIDGESTP */
3061 bridge_ioctl_gma(struct bridge_softc
*sc
, void *arg
)
3063 struct ifbrparam
*param
;
3064 struct bstp_state
*bs
;
3068 param
->ifbrp_maxage
= bs
->bs_bridge_max_age
>> 8;
3073 bridge_ioctl_sma(struct bridge_softc
*sc
, void *arg
)
3076 struct ifbrparam
*param
= arg
;
3078 return bstp_set_maxage(&sc
->sc_stp
, param
->ifbrp_maxage
);
3079 #else /* !BRIDGESTP */
3080 #pragma unused(sc, arg)
3082 #endif /* !BRIDGESTP */
3086 bridge_ioctl_sifprio(struct bridge_softc
*sc
, void *arg
)
3089 struct ifbreq
*req
= arg
;
3090 struct bridge_iflist
*bif
;
3092 bif
= bridge_lookup_member(sc
, req
->ifbr_ifsname
);
3097 return bstp_set_port_priority(&bif
->bif_stp
, req
->ifbr_priority
);
3098 #else /* !BRIDGESTP */
3099 #pragma unused(sc, arg)
3101 #endif /* !BRIDGESTP */
3105 bridge_ioctl_sifcost(struct bridge_softc
*sc
, void *arg
)
3108 struct ifbreq
*req
= arg
;
3109 struct bridge_iflist
*bif
;
3111 bif
= bridge_lookup_member(sc
, req
->ifbr_ifsname
);
3116 return bstp_set_path_cost(&bif
->bif_stp
, req
->ifbr_path_cost
);
3117 #else /* !BRIDGESTP */
3118 #pragma unused(sc, arg)
3120 #endif /* !BRIDGESTP */
3124 bridge_ioctl_gfilt(struct bridge_softc
*sc
, void *arg
)
3126 struct ifbrparam
*param
= arg
;
3128 param
->ifbrp_filter
= sc
->sc_filter_flags
;
3134 bridge_ioctl_sfilt(struct bridge_softc
*sc
, void *arg
)
3136 struct ifbrparam
*param
= arg
;
3138 if (param
->ifbrp_filter
& ~IFBF_FILT_MASK
) {
3142 if (param
->ifbrp_filter
& IFBF_FILT_USEIPF
) {
3146 sc
->sc_filter_flags
= param
->ifbrp_filter
;
3152 bridge_ioctl_sifmaxaddr(struct bridge_softc
*sc
, void *arg
)
3154 struct ifbreq
*req
= arg
;
3155 struct bridge_iflist
*bif
;
3157 bif
= bridge_lookup_member(sc
, req
->ifbr_ifsname
);
3162 bif
->bif_addrmax
= req
->ifbr_addrmax
;
3167 bridge_ioctl_addspan(struct bridge_softc
*sc
, void *arg
)
3169 struct ifbreq
*req
= arg
;
3170 struct bridge_iflist
*bif
= NULL
;
3173 ifs
= ifunit(req
->ifbr_ifsname
);
3178 if (IFNET_IS_INTCOPROC(ifs
)) {
3182 TAILQ_FOREACH(bif
, &sc
->sc_spanlist
, bif_next
)
3183 if (ifs
== bif
->bif_ifp
) {
3187 if (ifs
->if_bridge
!= NULL
) {
3191 switch (ifs
->if_type
) {
3196 /* currently not supported */
3202 bif
= _MALLOC(sizeof(*bif
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
3208 bif
->bif_ifflags
= IFBIF_SPAN
;
3210 ifnet_reference(bif
->bif_ifp
);
3212 TAILQ_INSERT_HEAD(&sc
->sc_spanlist
, bif
, bif_next
);
3218 bridge_ioctl_delspan(struct bridge_softc
*sc
, void *arg
)
3220 struct ifbreq
*req
= arg
;
3221 struct bridge_iflist
*bif
;
3224 ifs
= ifunit(req
->ifbr_ifsname
);
3229 TAILQ_FOREACH(bif
, &sc
->sc_spanlist
, bif_next
)
3230 if (ifs
== bif
->bif_ifp
) {
3238 bridge_delete_span(sc
, bif
);
3243 #define BRIDGE_IOCTL_GBPARAM do { \
3244 struct bstp_state *bs = &sc->sc_stp; \
3245 struct bstp_port *root_port; \
3247 req->ifbop_maxage = bs->bs_bridge_max_age >> 8; \
3248 req->ifbop_hellotime = bs->bs_bridge_htime >> 8; \
3249 req->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8; \
3251 root_port = bs->bs_root_port; \
3252 if (root_port == NULL) \
3253 req->ifbop_root_port = 0; \
3255 req->ifbop_root_port = root_port->bp_ifp->if_index; \
3257 req->ifbop_holdcount = bs->bs_txholdcount; \
3258 req->ifbop_priority = bs->bs_bridge_priority; \
3259 req->ifbop_protocol = bs->bs_protover; \
3260 req->ifbop_root_path_cost = bs->bs_root_pv.pv_cost; \
3261 req->ifbop_bridgeid = bs->bs_bridge_pv.pv_dbridge_id; \
3262 req->ifbop_designated_root = bs->bs_root_pv.pv_root_id; \
3263 req->ifbop_designated_bridge = bs->bs_root_pv.pv_dbridge_id; \
3264 req->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec; \
3265 req->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec; \
3269 bridge_ioctl_gbparam32(struct bridge_softc
*sc
, void *arg
)
3271 struct ifbropreq32
*req
= arg
;
3273 BRIDGE_IOCTL_GBPARAM
;
3278 bridge_ioctl_gbparam64(struct bridge_softc
*sc
, void *arg
)
3280 struct ifbropreq64
*req
= arg
;
3282 BRIDGE_IOCTL_GBPARAM
;
3287 bridge_ioctl_grte(struct bridge_softc
*sc
, void *arg
)
3289 struct ifbrparam
*param
= arg
;
3291 param
->ifbrp_cexceeded
= sc
->sc_brtexceeded
;
3295 #define BRIDGE_IOCTL_GIFSSTP do { \
3296 struct bridge_iflist *bif; \
3297 struct bstp_port *bp; \
3298 struct ifbpstpreq bpreq; \
3299 char *buf, *outbuf; \
3300 unsigned int count, buflen, len; \
3303 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) { \
3304 if ((bif->bif_ifflags & IFBIF_STP) != 0) \
3308 buflen = sizeof (bpreq) * count; \
3309 if (bifstp->ifbpstp_len == 0) { \
3310 bifstp->ifbpstp_len = buflen; \
3314 BRIDGE_UNLOCK(sc); \
3315 outbuf = _MALLOC(buflen, M_TEMP, M_WAITOK | M_ZERO); \
3320 len = min(bifstp->ifbpstp_len, buflen); \
3321 bzero(&bpreq, sizeof (bpreq)); \
3322 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) { \
3323 if (len < sizeof (bpreq)) \
3326 if ((bif->bif_ifflags & IFBIF_STP) == 0) \
3329 bp = &bif->bif_stp; \
3330 bpreq.ifbp_portno = bif->bif_ifp->if_index & 0xfff; \
3331 bpreq.ifbp_fwd_trans = bp->bp_forward_transitions; \
3332 bpreq.ifbp_design_cost = bp->bp_desg_pv.pv_cost; \
3333 bpreq.ifbp_design_port = bp->bp_desg_pv.pv_port_id; \
3334 bpreq.ifbp_design_bridge = bp->bp_desg_pv.pv_dbridge_id; \
3335 bpreq.ifbp_design_root = bp->bp_desg_pv.pv_root_id; \
3337 memcpy(buf, &bpreq, sizeof (bpreq)); \
3339 buf += sizeof (bpreq); \
3340 len -= sizeof (bpreq); \
3343 BRIDGE_UNLOCK(sc); \
3344 bifstp->ifbpstp_len = sizeof (bpreq) * count; \
3345 error = copyout(outbuf, bifstp->ifbpstp_req, bifstp->ifbpstp_len); \
3347 _FREE(outbuf, M_TEMP); \
3352 bridge_ioctl_gifsstp32(struct bridge_softc
*sc
, void *arg
)
3354 struct ifbpstpconf32
*bifstp
= arg
;
3357 BRIDGE_IOCTL_GIFSSTP
;
3362 bridge_ioctl_gifsstp64(struct bridge_softc
*sc
, void *arg
)
3364 struct ifbpstpconf64
*bifstp
= arg
;
3367 BRIDGE_IOCTL_GIFSSTP
;
3372 bridge_ioctl_sproto(struct bridge_softc
*sc
, void *arg
)
3375 struct ifbrparam
*param
= arg
;
3377 return bstp_set_protocol(&sc
->sc_stp
, param
->ifbrp_proto
);
3378 #else /* !BRIDGESTP */
3379 #pragma unused(sc, arg)
3381 #endif /* !BRIDGESTP */
3385 bridge_ioctl_stxhc(struct bridge_softc
*sc
, void *arg
)
3388 struct ifbrparam
*param
= arg
;
3390 return bstp_set_holdcount(&sc
->sc_stp
, param
->ifbrp_txhc
);
3391 #else /* !BRIDGESTP */
3392 #pragma unused(sc, arg)
3394 #endif /* !BRIDGESTP */
3399 bridge_ioctl_ghostfilter(struct bridge_softc
*sc
, void *arg
)
3401 struct ifbrhostfilter
*req
= arg
;
3402 struct bridge_iflist
*bif
;
3404 bif
= bridge_lookup_member(sc
, req
->ifbrhf_ifsname
);
3409 bzero(req
, sizeof(struct ifbrhostfilter
));
3410 if (bif
->bif_flags
& BIFF_HOST_FILTER
) {
3411 req
->ifbrhf_flags
|= IFBRHF_ENABLED
;
3412 bcopy(bif
->bif_hf_hwsrc
, req
->ifbrhf_hwsrca
,
3414 req
->ifbrhf_ipsrc
= bif
->bif_hf_ipsrc
.s_addr
;
3420 bridge_ioctl_shostfilter(struct bridge_softc
*sc
, void *arg
)
3422 struct ifbrhostfilter
*req
= arg
;
3423 struct bridge_iflist
*bif
;
3425 bif
= bridge_lookup_member(sc
, req
->ifbrhf_ifsname
);
3430 INC_ATOMIC_INT64_LIM(net_api_stats
.nas_vmnet_total
);
3432 if (req
->ifbrhf_flags
& IFBRHF_ENABLED
) {
3433 bif
->bif_flags
|= BIFF_HOST_FILTER
;
3435 if (req
->ifbrhf_flags
& IFBRHF_HWSRC
) {
3436 bcopy(req
->ifbrhf_hwsrca
, bif
->bif_hf_hwsrc
,
3438 if (bcmp(req
->ifbrhf_hwsrca
, ethernulladdr
,
3439 ETHER_ADDR_LEN
) != 0) {
3440 bif
->bif_flags
|= BIFF_HF_HWSRC
;
3442 bif
->bif_flags
&= ~BIFF_HF_HWSRC
;
3445 if (req
->ifbrhf_flags
& IFBRHF_IPSRC
) {
3446 bif
->bif_hf_ipsrc
.s_addr
= req
->ifbrhf_ipsrc
;
3447 if (bif
->bif_hf_ipsrc
.s_addr
!= INADDR_ANY
) {
3448 bif
->bif_flags
|= BIFF_HF_IPSRC
;
3450 bif
->bif_flags
&= ~BIFF_HF_IPSRC
;
3454 bif
->bif_flags
&= ~(BIFF_HOST_FILTER
| BIFF_HF_HWSRC
|
3456 bzero(bif
->bif_hf_hwsrc
, ETHER_ADDR_LEN
);
3457 bif
->bif_hf_ipsrc
.s_addr
= INADDR_ANY
;
3464 bridge_mac_nat_entry_out(struct mac_nat_entry_list
* list
,
3465 unsigned int * count_p
, char *buf
, unsigned int *len_p
)
3467 unsigned int count
= *count_p
;
3468 struct ifbrmne ifbmne
;
3469 unsigned int len
= *len_p
;
3470 struct mac_nat_entry
*mne
;
3473 bzero(&ifbmne
, sizeof(ifbmne
));
3474 LIST_FOREACH(mne
, list
, mne_list
) {
3475 if (len
< sizeof(ifbmne
)) {
3478 snprintf(ifbmne
.ifbmne_ifname
, sizeof(ifbmne
.ifbmne_ifname
),
3479 "%s", mne
->mne_bif
->bif_ifp
->if_xname
);
3480 memcpy(ifbmne
.ifbmne_mac
, mne
->mne_mac
,
3481 sizeof(ifbmne
.ifbmne_mac
));
3482 now
= (unsigned long) net_uptime();
3483 if (now
< mne
->mne_expire
) {
3484 ifbmne
.ifbmne_expire
= mne
->mne_expire
- now
;
3486 ifbmne
.ifbmne_expire
= 0;
3488 if ((mne
->mne_flags
& MNE_FLAGS_IPV6
) != 0) {
3489 ifbmne
.ifbmne_af
= AF_INET6
;
3490 ifbmne
.ifbmne_ip6_addr
= mne
->mne_ip6
;
3492 ifbmne
.ifbmne_af
= AF_INET
;
3493 ifbmne
.ifbmne_ip_addr
= mne
->mne_ip
;
3495 memcpy(buf
, &ifbmne
, sizeof(ifbmne
));
3497 buf
+= sizeof(ifbmne
);
3498 len
-= sizeof(ifbmne
);
3506 * bridge_ioctl_gmnelist()
3507 * Perform the get mac_nat_entry list ioctl.
3510 * The struct ifbrmnelist32 and struct ifbrmnelist64 have the same
3511 * field size/layout except for the last field ifbml_buf, the user-supplied
3512 * buffer pointer. That is passed in separately via the 'user_addr'
3513 * parameter from the respective 32-bit or 64-bit ioctl routine.
3516 bridge_ioctl_gmnelist(struct bridge_softc
*sc
, struct ifbrmnelist32
*mnl
,
3517 user_addr_t user_addr
)
3522 char *outbuf
= NULL
;
3523 struct mac_nat_entry
*mne
;
3524 unsigned int buflen
;
3527 mnl
->ifbml_elsize
= sizeof(struct ifbrmne
);
3529 LIST_FOREACH(mne
, &sc
->sc_mne_list
, mne_list
)
3531 LIST_FOREACH(mne
, &sc
->sc_mne_list_v6
, mne_list
)
3533 buflen
= sizeof(struct ifbrmne
) * count
;
3534 if (buflen
== 0 || mnl
->ifbml_len
== 0) {
3535 mnl
->ifbml_len
= buflen
;
3539 outbuf
= _MALLOC(buflen
, M_TEMP
, M_WAITOK
| M_ZERO
);
3543 len
= min(mnl
->ifbml_len
, buflen
);
3544 buf
= bridge_mac_nat_entry_out(&sc
->sc_mne_list
, &count
, buf
, &len
);
3545 buf
= bridge_mac_nat_entry_out(&sc
->sc_mne_list_v6
, &count
, buf
, &len
);
3546 mnl
->ifbml_len
= count
* sizeof(struct ifbrmne
);
3548 error
= copyout(outbuf
, user_addr
, mnl
->ifbml_len
);
3549 _FREE(outbuf
, M_TEMP
);
3555 bridge_ioctl_gmnelist64(struct bridge_softc
*sc
, void *arg
)
3557 struct ifbrmnelist64
*mnl
= arg
;
3559 return bridge_ioctl_gmnelist(sc
, arg
, mnl
->ifbml_buf
);
3563 bridge_ioctl_gmnelist32(struct bridge_softc
*sc
, void *arg
)
3565 struct ifbrmnelist32
*mnl
= arg
;
3567 return bridge_ioctl_gmnelist(sc
, arg
,
3568 CAST_USER_ADDR_T(mnl
->ifbml_buf
));
3574 * Detach an interface from a bridge. Called when a member
3575 * interface is detaching.
3578 bridge_ifdetach(struct ifnet
*ifp
)
3580 struct bridge_iflist
*bif
;
3581 struct bridge_softc
*sc
= ifp
->if_bridge
;
3584 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
3585 printf("%s: %s\n", __func__
, ifp
->if_xname
);
3587 #endif /* BRIDGE_DEBUG */
3589 /* Check if the interface is a bridge member */
3592 bif
= bridge_lookup_member_if(sc
, ifp
);
3594 bridge_delete_member(sc
, bif
, 1);
3599 /* Check if the interface is a span port */
3600 lck_mtx_lock(&bridge_list_mtx
);
3601 LIST_FOREACH(sc
, &bridge_list
, sc_list
) {
3603 TAILQ_FOREACH(bif
, &sc
->sc_spanlist
, bif_next
)
3604 if (ifp
== bif
->bif_ifp
) {
3605 bridge_delete_span(sc
, bif
);
3610 lck_mtx_unlock(&bridge_list_mtx
);
3614 * bridge_proto_attach_changed
3616 * Called when protocol attachment on the interface changes.
3619 bridge_proto_attach_changed(struct ifnet
*ifp
)
3621 boolean_t changed
= FALSE
;
3622 struct bridge_iflist
*bif
;
3623 boolean_t input_broadcast
;
3624 struct bridge_softc
*sc
= ifp
->if_bridge
;
3627 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
3628 printf("%s: %s\n", __func__
, ifp
->if_xname
);
3630 #endif /* BRIDGE_DEBUG */
3635 * Selectively enable input broadcast only when necessary.
3636 * The bridge interface itself attaches a fake protocol
3637 * so checking for at least two protocols means that the
3638 * interface is being used for something besides bridging.
3640 input_broadcast
= if_get_protolist(ifp
, NULL
, 0) >= 2;
3642 bif
= bridge_lookup_member_if(sc
, ifp
);
3644 if (input_broadcast
) {
3645 if ((bif
->bif_flags
& BIFF_INPUT_BROADCAST
) == 0) {
3646 bif
->bif_flags
|= BIFF_INPUT_BROADCAST
;
3649 } else if ((bif
->bif_flags
& BIFF_INPUT_BROADCAST
) != 0) {
3651 bif
->bif_flags
&= ~BIFF_INPUT_BROADCAST
;
3656 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
3657 printf("%s: input broadcast %s", ifp
->if_xname
,
3658 input_broadcast
? "ENABLED" : "DISABLED");
3660 #endif /* BRIDGE_DEBUG */
3665 * interface_media_active:
3667 * Tells if an interface media is active.
3670 interface_media_active(struct ifnet
*ifp
)
3672 struct ifmediareq ifmr
;
3675 bzero(&ifmr
, sizeof(ifmr
));
3676 if (ifnet_ioctl(ifp
, 0, SIOCGIFMEDIA
, &ifmr
) == 0) {
3677 if ((ifmr
.ifm_status
& IFM_AVALID
) && ifmr
.ifm_count
> 0) {
3678 status
= ifmr
.ifm_status
& IFM_ACTIVE
? 1 : 0;
3686 * bridge_updatelinkstatus:
3688 * Update the media active status of the bridge based on the
3689 * media active status of its member.
3690 * If changed, return the corresponding onf/off link event.
3693 bridge_updatelinkstatus(struct bridge_softc
*sc
)
3695 struct bridge_iflist
*bif
;
3696 int active_member
= 0;
3697 u_int32_t event_code
= 0;
3699 BRIDGE_LOCK_ASSERT_HELD(sc
);
3702 * Find out if we have an active interface
3704 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
3705 if (bif
->bif_flags
& BIFF_MEDIA_ACTIVE
) {
3711 if (active_member
&& !(sc
->sc_flags
& SCF_MEDIA_ACTIVE
)) {
3712 sc
->sc_flags
|= SCF_MEDIA_ACTIVE
;
3713 event_code
= KEV_DL_LINK_ON
;
3714 } else if (!active_member
&& (sc
->sc_flags
& SCF_MEDIA_ACTIVE
)) {
3715 sc
->sc_flags
&= ~SCF_MEDIA_ACTIVE
;
3716 event_code
= KEV_DL_LINK_OFF
;
3723 * bridge_iflinkevent:
3726 bridge_iflinkevent(struct ifnet
*ifp
)
3728 struct bridge_softc
*sc
= ifp
->if_bridge
;
3729 struct bridge_iflist
*bif
;
3730 u_int32_t event_code
= 0;
3734 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
3735 printf("%s: %s\n", __func__
, ifp
->if_xname
);
3737 #endif /* BRIDGE_DEBUG */
3739 /* Check if the interface is a bridge member */
3744 media_active
= interface_media_active(ifp
);
3746 bif
= bridge_lookup_member_if(sc
, ifp
);
3749 bif
->bif_flags
|= BIFF_MEDIA_ACTIVE
;
3751 bif
->bif_flags
&= ~BIFF_MEDIA_ACTIVE
;
3753 if (sc
->sc_mac_nat_bif
!= NULL
) {
3754 bridge_mac_nat_flush_entries(sc
, bif
);
3757 event_code
= bridge_updatelinkstatus(sc
);
3761 if (event_code
!= 0) {
3762 bridge_link_event(sc
->sc_ifp
, event_code
);
3767 * bridge_delayed_callback:
3769 * Makes a delayed call
3772 bridge_delayed_callback(void *param
)
3774 struct bridge_delayed_call
*call
= (struct bridge_delayed_call
*)param
;
3775 struct bridge_softc
*sc
= call
->bdc_sc
;
3777 #if BRIDGE_DEBUG_DELAYED_CALLBACK
3778 if (bridge_delayed_callback_delay
> 0) {
3781 ts
.tv_sec
= bridge_delayed_callback_delay
;
3784 printf("%s: sleeping for %d seconds\n",
3785 __func__
, bridge_delayed_callback_delay
);
3787 msleep(&bridge_delayed_callback_delay
, NULL
, PZERO
,
3790 printf("%s: awoken\n", __func__
);
3792 #endif /* BRIDGE_DEBUG_DELAYED_CALLBACK */
3796 #if BRIDGE_DEBUG_DELAYED_CALLBACK
3797 if (IF_BRIDGE_DEBUG(BR_DBGF_DELAYED_CALL
)) {
3798 printf("%s: %s call 0x%llx flags 0x%x\n", __func__
,
3799 sc
->sc_if_xname
, (uint64_t)VM_KERNEL_ADDRPERM(call
),
3802 #endif /* BRIDGE_DEBUG_DELAYED_CALLBACK */
3804 if (call
->bdc_flags
& BDCF_CANCELLING
) {
3807 if ((sc
->sc_flags
& SCF_DETACHING
) == 0) {
3808 (*call
->bdc_func
)(sc
);
3811 call
->bdc_flags
&= ~BDCF_OUTSTANDING
;
3816 * bridge_schedule_delayed_call:
3818 * Schedule a function to be called on a separate thread
3819 * The actual call may be scheduled to run at a given time or ASAP.
3822 bridge_schedule_delayed_call(struct bridge_delayed_call
*call
)
3824 uint64_t deadline
= 0;
3825 struct bridge_softc
*sc
= call
->bdc_sc
;
3827 BRIDGE_LOCK_ASSERT_HELD(sc
);
3829 if ((sc
->sc_flags
& SCF_DETACHING
) ||
3830 (call
->bdc_flags
& (BDCF_OUTSTANDING
| BDCF_CANCELLING
))) {
3834 if (call
->bdc_ts
.tv_sec
|| call
->bdc_ts
.tv_nsec
) {
3835 nanoseconds_to_absolutetime(
3836 (uint64_t)call
->bdc_ts
.tv_sec
* NSEC_PER_SEC
+
3837 call
->bdc_ts
.tv_nsec
, &deadline
);
3838 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
3841 call
->bdc_flags
= BDCF_OUTSTANDING
;
3843 #if BRIDGE_DEBUG_DELAYED_CALLBACK
3844 if (IF_BRIDGE_DEBUG(BR_DBGF_DELAYED_CALL
)) {
3845 printf("%s: %s call 0x%llx flags 0x%x\n", __func__
,
3846 sc
->sc_if_xname
, (uint64_t)VM_KERNEL_ADDRPERM(call
),
3849 #endif /* BRIDGE_DEBUG_DELAYED_CALLBACK */
3851 if (call
->bdc_ts
.tv_sec
|| call
->bdc_ts
.tv_nsec
) {
3852 thread_call_func_delayed(
3853 (thread_call_func_t
)bridge_delayed_callback
,
3856 if (call
->bdc_thread_call
== NULL
) {
3857 call
->bdc_thread_call
= thread_call_allocate(
3858 (thread_call_func_t
)bridge_delayed_callback
,
3861 thread_call_enter(call
->bdc_thread_call
);
3866 * bridge_cancel_delayed_call:
3868 * Cancel a queued or running delayed call.
3869 * If call is running, does not return until the call is done to
3870 * prevent race condition with the brigde interface getting destroyed
3873 bridge_cancel_delayed_call(struct bridge_delayed_call
*call
)
3876 struct bridge_softc
*sc
= call
->bdc_sc
;
3879 * The call was never scheduled
3885 BRIDGE_LOCK_ASSERT_HELD(sc
);
3887 call
->bdc_flags
|= BDCF_CANCELLING
;
3889 while (call
->bdc_flags
& BDCF_OUTSTANDING
) {
3891 if (IF_BRIDGE_DEBUG(BR_DBGF_DELAYED_CALL
)) {
3892 printf("%s: %s call 0x%llx flags 0x%x\n", __func__
,
3893 sc
->sc_if_xname
, (uint64_t)VM_KERNEL_ADDRPERM(call
),
3896 #endif /* BRIDGE_DEBUG */
3897 result
= thread_call_func_cancel(
3898 (thread_call_func_t
)bridge_delayed_callback
, call
, FALSE
);
3902 * We managed to dequeue the delayed call
3904 call
->bdc_flags
&= ~BDCF_OUTSTANDING
;
3907 * Wait for delayed call do be done running
3909 msleep(call
, &sc
->sc_mtx
, PZERO
, __func__
, NULL
);
3912 call
->bdc_flags
&= ~BDCF_CANCELLING
;
3916 * bridge_cleanup_delayed_call:
3918 * Dispose resource allocated for a delayed call
3919 * Assume the delayed call is not queued or running .
3922 bridge_cleanup_delayed_call(struct bridge_delayed_call
*call
)
3925 struct bridge_softc
*sc
= call
->bdc_sc
;
3928 * The call was never scheduled
3934 BRIDGE_LOCK_ASSERT_HELD(sc
);
3936 VERIFY((call
->bdc_flags
& BDCF_OUTSTANDING
) == 0);
3937 VERIFY((call
->bdc_flags
& BDCF_CANCELLING
) == 0);
3939 if (call
->bdc_thread_call
!= NULL
) {
3940 result
= thread_call_free(call
->bdc_thread_call
);
3941 if (result
== FALSE
) {
3942 panic("%s thread_call_free() failed for call %p",
3945 call
->bdc_thread_call
= NULL
;
3952 * Initialize a bridge interface.
3955 bridge_init(struct ifnet
*ifp
)
3957 struct bridge_softc
*sc
= (struct bridge_softc
*)ifp
->if_softc
;
3960 BRIDGE_LOCK_ASSERT_HELD(sc
);
3962 if ((ifnet_flags(ifp
) & IFF_RUNNING
)) {
3966 error
= ifnet_set_flags(ifp
, IFF_RUNNING
, IFF_RUNNING
);
3969 * Calling bridge_aging_timer() is OK as there are no entries to
3970 * age so we're just going to arm the timer
3972 bridge_aging_timer(sc
);
3975 bstp_init(&sc
->sc_stp
); /* Initialize Spanning Tree */
3977 #endif /* BRIDGESTP */
3984 * Stop the bridge interface.
3987 bridge_ifstop(struct ifnet
*ifp
, int disable
)
3989 #pragma unused(disable)
3990 struct bridge_softc
*sc
= ifp
->if_softc
;
3992 BRIDGE_LOCK_ASSERT_HELD(sc
);
3994 if ((ifnet_flags(ifp
) & IFF_RUNNING
) == 0) {
3998 bridge_cancel_delayed_call(&sc
->sc_aging_timer
);
4001 bstp_stop(&sc
->sc_stp
);
4002 #endif /* BRIDGESTP */
4004 bridge_rtflush(sc
, IFBF_FLUSHDYN
);
4005 (void) ifnet_set_flags(ifp
, 0, IFF_RUNNING
);
4009 * bridge_compute_cksum:
4011 * If the packet has checksum flags, compare the hardware checksum
4012 * capabilities of the source and destination interfaces. If they
4013 * are the same, there's nothing to do. If they are different,
4014 * finalize the checksum so that it can be sent on the destination
4018 bridge_compute_cksum(struct ifnet
*src_if
, struct ifnet
*dst_if
, struct mbuf
*m
)
4020 uint32_t csum_flags
;
4021 uint16_t dst_hw_csum
;
4023 struct ether_header
*eh
;
4024 uint16_t src_hw_csum
;
4026 csum_flags
= m
->m_pkthdr
.csum_flags
& IF_HWASSIST_CSUM_MASK
;
4027 if (csum_flags
== 0) {
4028 /* no checksum offload */
4033 * if destination/source differ in checksum offload
4034 * capabilities, finalize/compute the checksum
4036 dst_hw_csum
= IF_HWASSIST_CSUM_FLAGS(dst_if
->if_hwassist
);
4037 src_hw_csum
= IF_HWASSIST_CSUM_FLAGS(src_if
->if_hwassist
);
4038 if (dst_hw_csum
== src_hw_csum
) {
4041 eh
= mtod(m
, struct ether_header
*);
4042 switch (ntohs(eh
->ether_type
)) {
4044 did_sw
= in_finalize_cksum(m
, sizeof(*eh
), csum_flags
);
4046 case ETHERTYPE_IPV6
:
4047 did_sw
= in6_finalize_cksum(m
, sizeof(*eh
), -1, -1, csum_flags
);
4051 if (IF_BRIDGE_DEBUG(BR_DBGF_CHECKSUM
)) {
4052 printf("%s: [%s -> %s] before 0x%x did 0x%x after 0x%x\n",
4054 src_if
->if_xname
, dst_if
->if_xname
, csum_flags
, did_sw
,
4055 m
->m_pkthdr
.csum_flags
);
4057 #endif /* BRIDGE_DEBUG */
4061 bridge_transmit(struct ifnet
* ifp
, struct mbuf
*m
)
4063 struct flowadv adv
= { .code
= FADV_SUCCESS
};
4066 error
= dlil_output(ifp
, 0, m
, NULL
, NULL
, 1, &adv
);
4068 if (adv
.code
== FADV_FLOW_CONTROLLED
) {
4070 } else if (adv
.code
== FADV_SUSPENDED
) {
4071 error
= EQSUSPENDED
;
4078 bridge_send(struct ifnet
*src_ifp
,
4079 struct ifnet
*dst_ifp
, struct mbuf
*m
, ChecksumOperation cksum_op
)
4082 case kChecksumOperationClear
:
4083 m
->m_pkthdr
.csum_flags
= 0;
4085 case kChecksumOperationFinalize
:
4086 /* the checksum might not be correct, finalize now */
4087 bridge_finalize_cksum(dst_ifp
, m
);
4089 case kChecksumOperationCompute
:
4090 bridge_compute_cksum(src_ifp
, dst_ifp
, m
);
4097 * If underlying interface can not do VLAN tag insertion itself
4098 * then attach a packet tag that holds it.
4100 if ((m
->m_flags
& M_VLANTAG
) &&
4101 (dst_ifp
->if_capenable
& IFCAP_VLAN_HWTAGGING
) == 0) {
4102 m
= ether_vlanencap(m
, m
->m_pkthdr
.ether_vtag
);
4104 printf("%s: %s: unable to prepend VLAN "
4105 "header\n", __func__
, dst_ifp
->if_xname
);
4106 (void) ifnet_stat_increment_out(dst_ifp
,
4110 m
->m_flags
&= ~M_VLANTAG
;
4112 #endif /* HAS_IF_CAP */
4113 return bridge_transmit(dst_ifp
, m
);
4117 bridge_send_tso(struct ifnet
*dst_ifp
, struct mbuf
*m
)
4119 struct ether_header
*eh
;
4120 uint16_t ether_type
;
4125 eh
= mtod(m
, struct ether_header
*);
4126 ether_type
= ntohs(eh
->ether_type
);
4127 switch (ether_type
) {
4131 case ETHERTYPE_IPV6
:
4135 printf("%s: large non IPv4/IPv6 packet\n", __func__
);
4140 mac_hlen
= sizeof(*eh
);
4144 * If underlying interface can not do VLAN tag insertion itself
4145 * then attach a packet tag that holds it.
4147 if ((m
->m_flags
& M_VLANTAG
) &&
4148 (dst_ifp
->if_capenable
& IFCAP_VLAN_HWTAGGING
) == 0) {
4149 m
= ether_vlanencap(m
, m
->m_pkthdr
.ether_vtag
);
4151 printf("%s: %s: unable to prepend VLAN "
4152 "header\n", __func__
, dst_ifp
->if_xname
);
4153 (void) ifnet_stat_increment_out(dst_ifp
,
4158 m
->m_flags
&= ~M_VLANTAG
;
4159 mac_hlen
+= ETHER_VLAN_ENCAP_LEN
;
4161 #endif /* HAS_IF_CAP */
4163 error
= gso_ipv4_tcp(dst_ifp
, &m
, mac_hlen
, TRUE
);
4165 error
= gso_ipv6_tcp(dst_ifp
, &m
, mac_hlen
, TRUE
);
4175 * Enqueue a packet on a bridge member interface.
4179 bridge_enqueue(ifnet_t bridge_ifp
, struct ifnet
*src_ifp
,
4180 struct ifnet
*dst_ifp
, struct mbuf
*m
, ChecksumOperation cksum_op
)
4185 VERIFY(dst_ifp
!= NULL
);
4188 * We may be sending a fragment so traverse the mbuf
4190 * NOTE: bridge_fragment() is called only when PFIL_HOOKS is enabled.
4192 for (struct mbuf
*next_m
= NULL
; m
!= NULL
; m
= next_m
) {
4195 len
= m
->m_pkthdr
.len
;
4196 m
->m_flags
|= M_PROTO1
; /* set to avoid loops */
4197 next_m
= m
->m_nextpkt
;
4198 m
->m_nextpkt
= NULL
;
4200 * need to segment the packet if it is a large frame
4201 * and the destination interface does not support TSO
4203 if (if_bridge_segmentation
!= 0 &&
4204 len
> (bridge_ifp
->if_mtu
+ ETHER_HDR_LEN
) &&
4205 (dst_ifp
->if_capabilities
& IFCAP_TSO
) != IFCAP_TSO
) {
4206 _error
= bridge_send_tso(dst_ifp
, m
);
4208 _error
= bridge_send(src_ifp
, dst_ifp
, m
, cksum_op
);
4210 /* Preserve first error value */
4211 if (error
== 0 && _error
!= 0) {
4215 (void) ifnet_stat_increment_out(bridge_ifp
, 1, len
, 0);
4217 (void) ifnet_stat_increment_out(bridge_ifp
, 0, 0, 1);
4224 #if HAS_BRIDGE_DUMMYNET
4228 * Receive a queued packet from dummynet and pass it on to the output
4231 * The mbuf has the Ethernet header already attached.
4234 bridge_dummynet(struct mbuf
*m
, struct ifnet
*ifp
)
4236 struct bridge_softc
*sc
;
4238 sc
= ifp
->if_bridge
;
4241 * The packet didn't originate from a member interface. This should only
4242 * ever happen if a member interface is removed while packets are
4250 if (PFIL_HOOKED(&inet_pfil_hook
) || PFIL_HOOKED_INET6
) {
4251 if (bridge_pfil(&m
, sc
->sc_ifp
, ifp
, PFIL_OUT
) != 0) {
4258 (void) bridge_enqueue(sc
->sc_ifp
, NULL
, ifp
, m
, kChecksumOperationNone
);
4261 #endif /* HAS_BRIDGE_DUMMYNET */
4264 * bridge_member_output:
4266 * Send output from a bridge member interface. This
4267 * performs the bridging function for locally originated
4270 * The mbuf has the Ethernet header already attached.
4273 bridge_member_output(struct bridge_softc
*sc
, ifnet_t ifp
, mbuf_t
*data
)
4276 struct ether_header
*eh
;
4277 struct ifnet
*dst_if
;
4279 struct bridge_iflist
*mac_nat_bif
;
4280 ifnet_t mac_nat_ifp
;
4284 if (IF_BRIDGE_DEBUG(BR_DBGF_OUTPUT
)) {
4285 printf("%s: ifp %s\n", __func__
, ifp
->if_xname
);
4287 #endif /* BRIDGE_DEBUG */
4289 if (m
->m_len
< ETHER_HDR_LEN
) {
4290 m
= m_pullup(m
, ETHER_HDR_LEN
);
4297 eh
= mtod(m
, struct ether_header
*);
4298 vlan
= VLANTAGOF(m
);
4301 mac_nat_bif
= sc
->sc_mac_nat_bif
;
4302 mac_nat_ifp
= (mac_nat_bif
!= NULL
) ? mac_nat_bif
->bif_ifp
: NULL
;
4303 if (mac_nat_ifp
== ifp
) {
4304 /* record the IP address used by the MAC NAT interface */
4305 (void)bridge_mac_nat_output(sc
, mac_nat_bif
, data
, NULL
);
4308 /* packet was deallocated */
4313 bridge_ifp
= sc
->sc_ifp
;
4316 * APPLE MODIFICATION
4317 * If the packet is an 802.1X ethertype, then only send on the
4318 * original output interface.
4320 if (eh
->ether_type
== htons(ETHERTYPE_PAE
)) {
4326 * If bridge is down, but the original output interface is up,
4327 * go ahead and send out that interface. Otherwise, the packet
4330 if ((bridge_ifp
->if_flags
& IFF_RUNNING
) == 0) {
4336 * If the packet is a multicast, or we don't know a better way to
4337 * get there, send to all interfaces.
4339 if (ETHER_IS_MULTICAST(eh
->ether_dhost
)) {
4342 dst_if
= bridge_rtlookup(sc
, eh
->ether_dhost
, vlan
);
4344 if (dst_if
== NULL
) {
4345 struct bridge_iflist
*bif
;
4353 BRIDGE_LOCK2REF(sc
, error
);
4359 TAILQ_FOREACH(bif
, &sc
->sc_iflist
, bif_next
) {
4360 /* skip interface with inactive link status */
4361 if ((bif
->bif_flags
& BIFF_MEDIA_ACTIVE
) == 0) {
4364 dst_if
= bif
->bif_ifp
;
4367 if (dst_if
->if_type
== IFT_GIF
) {
4371 if ((dst_if
->if_flags
& IFF_RUNNING
) == 0) {
4374 if (dst_if
!= ifp
) {
4376 * If this is not the original output interface,
4377 * and the interface is participating in spanning
4378 * tree, make sure the port is in a state that
4379 * allows forwarding.
4381 if ((bif
->bif_ifflags
& IFBIF_STP
) &&
4382 bif
->bif_stp
.bp_state
== BSTP_IFSTATE_DISCARDING
) {
4386 * If this is not the original output interface,
4387 * and the destination is the MAC NAT interface,
4388 * drop the packet. The packet can't be sent
4389 * if the source MAC is incorrect.
4391 if (dst_if
== mac_nat_ifp
) {
4395 if (TAILQ_NEXT(bif
, bif_next
) == NULL
) {
4399 mc
= m_dup(m
, M_DONTWAIT
);
4401 (void) ifnet_stat_increment_out(
4402 bridge_ifp
, 0, 0, 1);
4406 (void) bridge_enqueue(bridge_ifp
, ifp
, dst_if
,
4407 mc
, kChecksumOperationCompute
);
4418 * XXX Spanning tree consideration here?
4422 if ((dst_if
->if_flags
& IFF_RUNNING
) == 0) {
4429 if (dst_if
== ifp
) {
4430 /* just let the packet continue on its way */
4433 if (dst_if
!= mac_nat_ifp
) {
4434 (void) bridge_enqueue(bridge_ifp
, ifp
, dst_if
, m
,
4435 kChecksumOperationCompute
);
4438 * This is not the original output interface
4439 * and the destination is the MAC NAT interface.
4440 * Drop the packet because the packet can't be sent
4441 * if the source MAC is incorrect.
4451 * This routine is called externally from above only when if_bridge_txstart
4452 * is disabled; otherwise it is called internally by bridge_start().
4455 bridge_output(struct ifnet
*ifp
, struct mbuf
*m
)
4457 struct bridge_softc
*sc
= ifnet_softc(ifp
);
4458 struct ether_header
*eh
;
4459 struct ifnet
*dst_if
= NULL
;
4462 eh
= mtod(m
, struct ether_header
*);
4466 if (!(m
->m_flags
& (M_BCAST
| M_MCAST
))) {
4467 dst_if
= bridge_rtlookup(sc
, eh
->ether_dhost
, 0);
4470 (void) ifnet_stat_increment_out(ifp
, 1, m
->m_pkthdr
.len
, 0);
4473 if (sc
->sc_bpf_output
) {
4474 bridge_bpf_output(ifp
, m
);
4478 if (dst_if
== NULL
) {
4479 /* callee will unlock */
4480 bridge_broadcast(sc
, NULL
, m
, 0);
4484 bridge_ifp
= sc
->sc_ifp
;
4486 error
= bridge_enqueue(bridge_ifp
, NULL
, dst_if
, m
,
4487 kChecksumOperationFinalize
);
4494 bridge_finalize_cksum(struct ifnet
*ifp
, struct mbuf
*m
)
4496 struct ether_header
*eh
= mtod(m
, struct ether_header
*);
4497 uint32_t sw_csum
, hwcap
;
4501 hwcap
= (ifp
->if_hwassist
| CSUM_DATA_VALID
);
4506 /* do in software what the hardware cannot */
4507 sw_csum
= m
->m_pkthdr
.csum_flags
& ~IF_HWASSIST_CSUM_FLAGS(hwcap
);
4508 sw_csum
&= IF_HWASSIST_CSUM_MASK
;
4510 switch (ntohs(eh
->ether_type
)) {
4512 if ((hwcap
& CSUM_PARTIAL
) && !(sw_csum
& CSUM_DELAY_DATA
) &&
4513 (m
->m_pkthdr
.csum_flags
& CSUM_DELAY_DATA
)) {
4514 if (m
->m_pkthdr
.csum_flags
& CSUM_TCP
) {
4516 sizeof(*eh
) + sizeof(struct ip
);
4518 m
->m_pkthdr
.csum_data
& 0xffff;
4519 m
->m_pkthdr
.csum_flags
|=
4520 (CSUM_DATA_VALID
| CSUM_PARTIAL
);
4521 m
->m_pkthdr
.csum_tx_stuff
= (ulpoff
+ start
);
4522 m
->m_pkthdr
.csum_tx_start
= start
;
4524 sw_csum
|= (CSUM_DELAY_DATA
&
4525 m
->m_pkthdr
.csum_flags
);
4528 (void) in_finalize_cksum(m
, sizeof(*eh
), sw_csum
);
4531 case ETHERTYPE_IPV6
:
4532 if ((hwcap
& CSUM_PARTIAL
) &&
4533 !(sw_csum
& CSUM_DELAY_IPV6_DATA
) &&
4534 (m
->m_pkthdr
.csum_flags
& CSUM_DELAY_IPV6_DATA
)) {
4535 if (m
->m_pkthdr
.csum_flags
& CSUM_TCPIPV6
) {
4537 sizeof(*eh
) + sizeof(struct ip6_hdr
);
4539 m
->m_pkthdr
.csum_data
& 0xffff;
4540 m
->m_pkthdr
.csum_flags
|=
4541 (CSUM_DATA_VALID
| CSUM_PARTIAL
);
4542 m
->m_pkthdr
.csum_tx_stuff
= (ulpoff
+ start
);
4543 m
->m_pkthdr
.csum_tx_start
= start
;
4545 sw_csum
|= (CSUM_DELAY_IPV6_DATA
&
4546 m
->m_pkthdr
.csum_flags
);
4549 (void) in6_finalize_cksum(m
, sizeof(*eh
), -1, -1, sw_csum
);
4557 * Start output on a bridge.
4559 * This routine is invoked by the start worker thread; because we never call
4560 * it directly, there is no need do deploy any serialization mechanism other
4561 * than what's already used by the worker thread, i.e. this is already single
4564 * This routine is called only when if_bridge_txstart is enabled.
4567 bridge_start(struct ifnet
*ifp
)
4572 if (ifnet_dequeue(ifp
, &m
) != 0) {
4576 (void) bridge_output(ifp
, m
);
4583 * The forwarding function of the bridge.
4585 * NOTE: Releases the lock on return.
4588 bridge_forward(struct bridge_softc
*sc
, struct bridge_iflist
*sbif
,
4591 struct bridge_iflist
*dbif
;
4593 struct ifnet
*src_if
, *dst_if
;
4594 struct ether_header
*eh
;
4598 struct mac_nat_record mnr
;
4599 boolean_t translate_mac
= FALSE
;
4600 uint32_t sc_filter_flags
= 0;
4602 BRIDGE_LOCK_ASSERT_HELD(sc
);
4604 bridge_ifp
= sc
->sc_ifp
;
4606 if (IF_BRIDGE_DEBUG(BR_DBGF_OUTPUT
)) {
4607 printf("%s: %s m 0x%llx\n", __func__
, bridge_ifp
->if_xname
,
4608 (uint64_t)VM_KERNEL_ADDRPERM(m
));
4610 #endif /* BRIDGE_DEBUG */
4612 src_if
= m
->m_pkthdr
.rcvif
;
4614 (void) ifnet_stat_increment_in(bridge_ifp
, 1, m
->m_pkthdr
.len
, 0);
4615 vlan
= VLANTAGOF(m
);
4618 if ((sbif
->bif_ifflags
& IFBIF_STP
) &&
4619 sbif
->bif_stp
.bp_state
== BSTP_IFSTATE_DISCARDING
) {
4623 eh
= mtod(m
, struct ether_header
*);
4624 dst
= eh
->ether_dhost
;
4626 /* If the interface is learning, record the address. */
4627 if (sbif
->bif_ifflags
& IFBIF_LEARNING
) {
4628 error
= bridge_rtupdate(sc
, eh
->ether_shost
, vlan
,
4629 sbif
, 0, IFBAF_DYNAMIC
);
4631 * If the interface has addresses limits then deny any source
4632 * that is not in the cache.
4634 if (error
&& sbif
->bif_addrmax
) {
4639 if ((sbif
->bif_ifflags
& IFBIF_STP
) != 0 &&
4640 sbif
->bif_stp
.bp_state
== BSTP_IFSTATE_LEARNING
) {
4645 * At this point, the port either doesn't participate
4646 * in spanning tree or it is in the forwarding state.
4650 * If the packet is unicast, destined for someone on
4651 * "this" side of the bridge, drop it.
4653 if ((m
->m_flags
& (M_BCAST
| M_MCAST
)) == 0) {
4655 dst_if
= bridge_rtlookup(sc
, dst
, vlan
);
4656 if (src_if
== dst_if
) {
4660 /* broadcast/multicast */
4663 * Check if its a reserved multicast address, any address
4664 * listed in 802.1D section 7.12.6 may not be forwarded by the
4666 * This is currently 01-80-C2-00-00-00 to 01-80-C2-00-00-0F
4668 if (dst
[0] == 0x01 && dst
[1] == 0x80 &&
4669 dst
[2] == 0xc2 && dst
[3] == 0x00 &&
4670 dst
[4] == 0x00 && dst
[5] <= 0x0f) {
4675 /* ...forward it to all interfaces. */
4676 atomic_add_64(&bridge_ifp
->if_imcasts
, 1);
4681 * If we have a destination interface which is a member of our bridge,
4682 * OR this is a unicast packet, push it through the bpf(4) machinery.
4683 * For broadcast or multicast packets, don't bother because it will
4684 * be reinjected into ether_input. We do this before we pass the packets
4685 * through the pfil(9) framework, as it is possible that pfil(9) will
4686 * drop the packet, or possibly modify it, making it difficult to debug
4687 * firewall issues on the bridge.
4690 if (eh
->ether_type
== htons(ETHERTYPE_RSN_PREAUTH
) ||
4691 dst_if
!= NULL
|| (m
->m_flags
& (M_BCAST
| M_MCAST
)) == 0) {
4692 m
->m_pkthdr
.rcvif
= bridge_ifp
;
4693 BRIDGE_BPF_MTAP_INPUT(sc
, m
);
4695 #endif /* NBPFILTER */
4697 if (dst_if
== NULL
) {
4698 /* bridge_broadcast will unlock */
4699 bridge_broadcast(sc
, src_if
, m
, 1);
4707 * At this point, we're dealing with a unicast frame
4708 * going to a different interface.
4710 if ((dst_if
->if_flags
& IFF_RUNNING
) == 0) {
4714 dbif
= bridge_lookup_member_if(sc
, dst_if
);
4716 /* Not a member of the bridge (anymore?) */
4720 /* Private segments can not talk to each other */
4721 if (sbif
->bif_ifflags
& dbif
->bif_ifflags
& IFBIF_PRIVATE
) {
4725 if ((dbif
->bif_ifflags
& IFBIF_STP
) &&
4726 dbif
->bif_stp
.bp_state
== BSTP_IFSTATE_DISCARDING
) {
4731 /* APPLE MODIFICATION <rdar:6985737> */
4732 if ((dst_if
->if_extflags
& IFEXTF_DHCPRA_MASK
) != 0) {
4733 m
= ip_xdhcpra_output(dst_if
, m
);
4735 ++bridge_ifp
.if_xdhcpra
;
4740 #endif /* HAS_DHCPRA_MASK */
4742 if (dbif
== sc
->sc_mac_nat_bif
) {
4743 /* determine how to translate the packet */
4745 = bridge_mac_nat_output(sc
, sbif
, &m
, &mnr
);
4747 /* packet was deallocated */
4753 sc_filter_flags
= sc
->sc_filter_flags
;
4755 if (PF_IS_ENABLED
&& (sc_filter_flags
& IFBF_FILT_MEMBER
)) {
4756 if (bridge_pf(&m
, dst_if
, sc_filter_flags
, FALSE
) != 0) {
4764 /* if we need to, translate the MAC address */
4765 if (translate_mac
) {
4766 bridge_mac_nat_translate(&m
, &mnr
, IF_LLADDR(dst_if
));
4769 * This is an inbound packet where the checksum
4770 * (if applicable) is already present/valid. Since
4771 * we are just doing layer 2 forwarding (not IP
4772 * forwarding), there's no need to validate the checksum.
4773 * Clear the checksum offload flags and send it along.
4776 (void) bridge_enqueue(bridge_ifp
, NULL
, dst_if
, m
,
4777 kChecksumOperationClear
);
4789 ether_ntop(char *buf
, size_t len
, const u_char
*ap
)
4791 snprintf(buf
, len
, "%02x:%02x:%02x:%02x:%02x:%02x",
4792 ap
[0], ap
[1], ap
[2], ap
[3], ap
[4], ap
[5]);
4797 #endif /* BRIDGE_DEBUG */
4800 inject_input_packet(ifnet_t ifp
, mbuf_t m
)
4802 mbuf_pkthdr_setrcvif(m
, ifp
);
4803 mbuf_pkthdr_setheader(m
, mbuf_data(m
));
4804 mbuf_setdata(m
, (char *)mbuf_data(m
) + ETHER_HDR_LEN
,
4805 mbuf_len(m
) - ETHER_HDR_LEN
);
4806 mbuf_pkthdr_adjustlen(m
, -ETHER_HDR_LEN
);
4807 m
->m_flags
|= M_PROTO1
; /* set to avoid loops */
4808 dlil_input_packet_list(ifp
, m
);
4813 in_addr_is_ours(struct in_addr ip
)
4815 struct in_ifaddr
*ia
;
4816 boolean_t ours
= FALSE
;
4818 lck_rw_lock_shared(in_ifaddr_rwlock
);
4819 TAILQ_FOREACH(ia
, INADDR_HASH(ip
.s_addr
), ia_hash
) {
4820 if (IA_SIN(ia
)->sin_addr
.s_addr
== ip
.s_addr
) {
4825 lck_rw_done(in_ifaddr_rwlock
);
4830 in6_addr_is_ours(const struct in6_addr
* ip6_p
)
4832 struct in6_ifaddr
*ia6
;
4833 boolean_t ours
= FALSE
;
4835 lck_rw_lock_shared(&in6_ifaddr_rwlock
);
4836 TAILQ_FOREACH(ia6
, IN6ADDR_HASH(ip6_p
), ia6_hash
) {
4837 if (IN6_ARE_ADDR_EQUAL(&ia6
->ia_addr
.sin6_addr
, ip6_p
)) {
4842 lck_rw_done(&in6_ifaddr_rwlock
);
4847 bridge_interface_input(ifnet_t bridge_ifp
, mbuf_t m
,
4848 bpf_packet_func bpf_input_func
)
4851 struct ether_header
*eh
;
4852 uint16_t ether_type
;
4859 /* segment large packets before sending them up */
4860 if (if_bridge_segmentation
== 0) {
4863 len
= m
->m_pkthdr
.len
;
4864 if (len
<= (bridge_ifp
->if_mtu
+ ETHER_HDR_LEN
)) {
4867 eh
= mtod(m
, struct ether_header
*);
4868 ether_type
= ntohs(eh
->ether_type
);
4869 switch (ether_type
) {
4873 case ETHERTYPE_IPV6
:
4877 printf("%s: large non IPv4/IPv6 packet\n", __func__
);
4883 * We have a large IPv4/IPv6 TCP packet. Segment it if required.
4885 * If gso_ipv[46]_tcp() returns success (0), the packet(s) are
4886 * ready to be passed up. If the destination is a local IP address,
4887 * the packet will be passed up as a large, single packet.
4889 * If gso_ipv[46]_tcp() returns an error, the packet has already
4892 mac_hlen
= sizeof(*eh
);
4894 error
= gso_ipv4_tcp(bridge_ifp
, &m
, mac_hlen
, FALSE
);
4896 error
= gso_ipv6_tcp(bridge_ifp
, &m
, mac_hlen
, FALSE
);
4905 for (mbuf_t scan
= m
; scan
!= NULL
; scan
= scan
->m_nextpkt
) {
4906 /* Mark the packet as arriving on the bridge interface */
4907 mbuf_pkthdr_setrcvif(scan
, bridge_ifp
);
4908 mbuf_pkthdr_setheader(scan
, mbuf_data(scan
));
4909 if (bpf_input_func
!= NULL
) {
4910 (*bpf_input_func
)(bridge_ifp
, scan
);
4912 mbuf_setdata(scan
, (char *)mbuf_data(scan
) + ETHER_HDR_LEN
,
4913 mbuf_len(scan
) - ETHER_HDR_LEN
);
4914 mbuf_pkthdr_adjustlen(scan
, -ETHER_HDR_LEN
);
4915 byte_count
+= mbuf_pkthdr_len(scan
);
4918 (void)ifnet_stat_increment_in(bridge_ifp
, pkt_count
, byte_count
, 0);
4920 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT
)) {
4921 printf("%s: %s %d packet(s) %ld bytes\n", __func__
,
4922 bridge_ifp
->if_xname
, pkt_count
, byte_count
);
4924 #endif /* BRIDGE_DEBUG */
4926 dlil_input_packet_list(bridge_ifp
, m
);
4933 * Filter input from a member interface. Queue the packet for
4934 * bridging if it is not for us.
4937 bridge_input(struct ifnet
*ifp
, mbuf_t
*data
)
4939 struct bridge_softc
*sc
= ifp
->if_bridge
;
4940 struct bridge_iflist
*bif
, *bif2
;
4942 struct ether_header
*eh
;
4943 struct mbuf
*mc
, *mc2
;
4946 boolean_t is_broadcast
;
4947 boolean_t is_ip_broadcast
= FALSE
;
4948 boolean_t is_ifp_mac
= FALSE
;
4950 uint32_t sc_filter_flags
= 0;
4952 bridge_ifp
= sc
->sc_ifp
;
4954 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT
)) {
4955 printf("%s: %s from %s m 0x%llx data 0x%llx\n", __func__
,
4956 bridge_ifp
->if_xname
, ifp
->if_xname
,
4957 (uint64_t)VM_KERNEL_ADDRPERM(m
),
4958 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_data(m
)));
4960 #endif /* BRIDGE_DEBUG */
4962 if ((sc
->sc_ifp
->if_flags
& IFF_RUNNING
) == 0) {
4964 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT
)) {
4965 printf("%s: %s not running passing along\n",
4966 __func__
, bridge_ifp
->if_xname
);
4968 #endif /* BRIDGE_DEBUG */
4972 vlan
= VLANTAGOF(m
);
4976 * Implement support for bridge monitoring. If this flag has been
4977 * set on this interface, discard the packet once we push it through
4978 * the bpf(4) machinery, but before we do, increment the byte and
4979 * packet counters associated with this interface.
4981 if ((bridge_ifp
->if_flags
& IFF_MONITOR
) != 0) {
4982 m
->m_pkthdr
.rcvif
= bridge_ifp
;
4983 BRIDGE_BPF_MTAP_INPUT(sc
, m
);
4984 (void) ifnet_stat_increment_in(bridge_ifp
, 1, m
->m_pkthdr
.len
, 0);
4988 #endif /* IFF_MONITOR */
4991 * Need to clear the promiscous flags otherwise it will be
4992 * dropped by DLIL after processing filters
4994 if ((mbuf_flags(m
) & MBUF_PROMISC
)) {
4995 mbuf_setflags_mask(m
, 0, MBUF_PROMISC
);
4998 sc_filter_flags
= sc
->sc_filter_flags
;
4999 if (PF_IS_ENABLED
&& (sc_filter_flags
& IFBF_FILT_MEMBER
)) {
5000 error
= bridge_pf(&m
, ifp
, sc_filter_flags
, TRUE
);
5008 * bridge_pf could have modified the pointer on success in order
5009 * to do its processing. Updated data such that we don't use a
5016 bif
= bridge_lookup_member_if(sc
, ifp
);
5020 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT
)) {
5021 printf("%s: %s bridge_lookup_member_if failed\n",
5022 __func__
, bridge_ifp
->if_xname
);
5024 #endif /* BRIDGE_DEBUG */
5028 if (bif
->bif_flags
& BIFF_HOST_FILTER
) {
5029 error
= bridge_host_filter(bif
, data
);
5031 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT
)) {
5032 printf("%s: %s bridge_host_filter failed\n",
5033 __func__
, bif
->bif_ifp
->if_xname
);
5041 is_broadcast
= (m
->m_flags
& (M_BCAST
| M_MCAST
)) != 0;
5042 eh
= mtod(m
, struct ether_header
*);
5043 if (!is_broadcast
&&
5044 memcmp(eh
->ether_dhost
, IF_LLADDR(ifp
), ETHER_ADDR_LEN
) == 0) {
5045 if (sc
->sc_mac_nat_bif
== bif
) {
5046 /* doing MAC-NAT, check if destination is broadcast */
5047 is_ip_broadcast
= is_broadcast_ip_packet(data
);
5048 if (*data
== NULL
) {
5054 if (!is_ip_broadcast
) {
5061 if (is_broadcast
|| is_ip_broadcast
) {
5063 if (is_broadcast
&& IF_BRIDGE_DEBUG(BR_DBGF_MCAST
)) {
5064 if ((m
->m_flags
& M_MCAST
)) {
5065 printf("%s: multicast: "
5066 "%02x:%02x:%02x:%02x:%02x:%02x\n",
5068 eh
->ether_dhost
[0], eh
->ether_dhost
[1],
5069 eh
->ether_dhost
[2], eh
->ether_dhost
[3],
5070 eh
->ether_dhost
[4], eh
->ether_dhost
[5]);
5073 #endif /* BRIDGE_DEBUG */
5075 /* Tap off 802.1D packets; they do not get forwarded. */
5076 if (is_broadcast
&& memcmp(eh
->ether_dhost
, bstp_etheraddr
,
5077 ETHER_ADDR_LEN
) == 0) {
5079 m
= bstp_input(&bif
->bif_stp
, ifp
, m
);
5080 #else /* !BRIDGESTP */
5083 #endif /* !BRIDGESTP */
5090 if ((bif
->bif_ifflags
& IFBIF_STP
) &&
5091 bif
->bif_stp
.bp_state
== BSTP_IFSTATE_DISCARDING
) {
5097 * Make a deep copy of the packet and enqueue the copy
5098 * for bridge processing; return the original packet for
5101 mc
= m_dup(m
, M_DONTWAIT
);
5108 * Perform the bridge forwarding function with the copy.
5110 * Note that bridge_forward calls BRIDGE_UNLOCK
5112 if (is_ip_broadcast
) {
5113 /* make the copy look like it is actually broadcast */
5114 mc
->m_flags
|= M_BCAST
;
5115 eh
= mtod(mc
, struct ether_header
*);
5116 bcopy(etherbroadcastaddr
, eh
->ether_dhost
,
5119 bridge_forward(sc
, bif
, mc
);
5122 * Reinject the mbuf as arriving on the bridge so we have a
5123 * chance at claiming multicast packets. We can not loop back
5124 * here from ether_input as a bridge is never a member of a
5127 VERIFY(bridge_ifp
->if_bridge
== NULL
);
5128 mc2
= m_dup(m
, M_DONTWAIT
);
5130 /* Keep the layer3 header aligned */
5131 int i
= min(mc2
->m_pkthdr
.len
, max_protohdr
);
5132 mc2
= m_copyup(mc2
, i
, ETHER_ALIGN
);
5135 /* mark packet as arriving on the bridge */
5136 mc2
->m_pkthdr
.rcvif
= bridge_ifp
;
5137 mc2
->m_pkthdr
.pkt_hdr
= mbuf_data(mc2
);
5139 BRIDGE_BPF_MTAP_INPUT(sc
, m
);
5141 (void) mbuf_setdata(mc2
,
5142 (char *)mbuf_data(mc2
) + ETHER_HDR_LEN
,
5143 mbuf_len(mc2
) - ETHER_HDR_LEN
);
5144 (void) mbuf_pkthdr_adjustlen(mc2
, -ETHER_HDR_LEN
);
5146 (void) ifnet_stat_increment_in(bridge_ifp
, 1,
5147 mbuf_pkthdr_len(mc2
), 0);
5150 if (IF_BRIDGE_DEBUG(BR_DBGF_MCAST
)) {
5151 printf("%s: %s mcast for us\n", __func__
,
5152 bridge_ifp
->if_xname
);
5154 #endif /* BRIDGE_DEBUG */
5156 dlil_input_packet_list(bridge_ifp
, mc2
);
5159 /* Return the original packet for local processing. */
5163 if ((bif
->bif_ifflags
& IFBIF_STP
) &&
5164 bif
->bif_stp
.bp_state
== BSTP_IFSTATE_DISCARDING
) {
5170 #define CARP_CHECK_WE_ARE_DST(iface) \
5171 ((iface)->if_carp &&\
5172 carp_forus((iface)->if_carp, eh->ether_dhost))
5173 #define CARP_CHECK_WE_ARE_SRC(iface) \
5174 ((iface)->if_carp &&\
5175 carp_forus((iface)->if_carp, eh->ether_shost))
5177 #define CARP_CHECK_WE_ARE_DST(iface) 0
5178 #define CARP_CHECK_WE_ARE_SRC(iface) 0
5181 #define PFIL_HOOKED_INET6 PFIL_HOOKED(&inet6_pfil_hook)
5183 #define PFIL_PHYS(sc, ifp, m)
5185 #define GRAB_OUR_PACKETS(iface) \
5186 if ((iface)->if_type == IFT_GIF) \
5188 /* It is destined for us. */ \
5189 if (memcmp(IF_LLADDR((iface)), eh->ether_dhost, \
5190 ETHER_ADDR_LEN) == 0 || CARP_CHECK_WE_ARE_DST((iface))) { \
5191 if ((iface)->if_type == IFT_BRIDGE) { \
5192 BRIDGE_BPF_MTAP_INPUT(sc, m); \
5193 /* Filter on the physical interface. */ \
5194 PFIL_PHYS(sc, iface, m); \
5196 bpf_tap_in(iface, DLT_EN10MB, m, NULL, 0); \
5198 if (bif->bif_ifflags & IFBIF_LEARNING) { \
5199 error = bridge_rtupdate(sc, eh->ether_shost, \
5200 vlan, bif, 0, IFBAF_DYNAMIC); \
5201 if (error && bif->bif_addrmax) { \
5202 BRIDGE_UNLOCK(sc); \
5204 return (EJUSTRETURN); \
5207 BRIDGE_UNLOCK(sc); \
5208 inject_input_packet(iface, m); \
5209 return (EJUSTRETURN); \
5212 /* We just received a packet that we sent out. */ \
5213 if (memcmp(IF_LLADDR((iface)), eh->ether_shost, \
5214 ETHER_ADDR_LEN) == 0 || CARP_CHECK_WE_ARE_SRC((iface))) { \
5215 BRIDGE_UNLOCK(sc); \
5217 return (EJUSTRETURN); \
5224 /* handle MAC-NAT if enabled */
5225 if (is_ifp_mac
&& sc
->sc_mac_nat_bif
== bif
) {
5227 boolean_t is_input
= FALSE
;
5229 dst_if
= bridge_mac_nat_input(sc
, data
, &is_input
);
5231 if (dst_if
== ifp
) {
5232 /* our input packet */
5233 } else if (dst_if
!= NULL
|| m
== NULL
) {
5235 if (dst_if
!= NULL
) {
5238 inject_input_packet(dst_if
, m
);
5240 (void)bridge_enqueue(bridge_ifp
, NULL
,
5242 kChecksumOperationClear
);
5250 * If the packet is for the bridge, pass it up for local processing.
5252 if (memcmp(eh
->ether_dhost
, IF_LLADDR(bridge_ifp
),
5253 ETHER_ADDR_LEN
) == 0 || CARP_CHECK_WE_ARE_DST(bridge_ifp
)) {
5254 bpf_packet_func bpf_input_func
= sc
->sc_bpf_input
;
5257 * If the interface is learning, and the source
5258 * address is valid and not multicast, record
5261 if (bif
->bif_ifflags
& IFBIF_LEARNING
) {
5262 (void) bridge_rtupdate(sc
, eh
->ether_shost
,
5263 vlan
, bif
, 0, IFBAF_DYNAMIC
);
5267 bridge_interface_input(bridge_ifp
, m
, bpf_input_func
);
5272 * if the destination of the packet is for the MAC address of
5273 * the member interface itself, then we don't need to forward
5274 * it -- just pass it back. Note that it'll likely just be
5275 * dropped by the stack, but if something else is bound to
5276 * the interface directly (for example, the wireless stats
5277 * protocol -- although that actually uses BPF right now),
5278 * then it will consume the packet
5280 * ALSO, note that we do this check AFTER checking for the
5281 * bridge's own MAC address, because the bridge may be
5282 * using the SAME MAC address as one of its interfaces
5286 #ifdef VERY_VERY_VERY_DIAGNOSTIC
5287 printf("%s: not forwarding packet bound for member "
5288 "interface\n", __func__
);
5295 /* Now check the remaining bridge members. */
5296 TAILQ_FOREACH(bif2
, &sc
->sc_iflist
, bif_next
) {
5297 if (bif2
->bif_ifp
!= ifp
) {
5298 GRAB_OUR_PACKETS(bif2
->bif_ifp
);
5302 #undef CARP_CHECK_WE_ARE_DST
5303 #undef CARP_CHECK_WE_ARE_SRC
5304 #undef GRAB_OUR_PACKETS
5307 * Perform the bridge forwarding function.
5309 * Note that bridge_forward calls BRIDGE_UNLOCK
5311 bridge_forward(sc
, bif
, m
);
5319 * Send a frame to all interfaces that are members of
5320 * the bridge, except for the one on which the packet
5323 * NOTE: Releases the lock on return.
5326 bridge_broadcast(struct bridge_softc
*sc
, struct ifnet
*src_if
,
5327 struct mbuf
*m
, int runfilt
)
5330 struct bridge_iflist
*dbif
, *sbif
;
5333 struct ifnet
*dst_if
;
5334 int error
= 0, used
= 0;
5335 boolean_t bridge_if_out
;
5336 ChecksumOperation cksum_op
;
5337 struct mac_nat_record mnr
;
5338 struct bridge_iflist
*mac_nat_bif
= sc
->sc_mac_nat_bif
;
5339 boolean_t translate_mac
= FALSE
;
5340 uint32_t sc_filter_flags
= 0;
5342 bridge_ifp
= sc
->sc_ifp
;
5343 if (src_if
!= NULL
) {
5344 bridge_if_out
= FALSE
;
5345 cksum_op
= kChecksumOperationClear
;
5346 sbif
= bridge_lookup_member_if(sc
, src_if
);
5347 if (sbif
!= NULL
&& mac_nat_bif
!= NULL
&& sbif
!= mac_nat_bif
) {
5348 /* get the translation record while holding the lock */
5350 = bridge_mac_nat_output(sc
, sbif
, &m
, &mnr
);
5352 /* packet was deallocated */
5359 * src_if is NULL when the bridge interface calls
5360 * bridge_broadcast().
5362 bridge_if_out
= TRUE
;
5363 cksum_op
= kChecksumOperationFinalize
;
5367 BRIDGE_LOCK2REF(sc
, error
);
5373 TAILQ_FOREACH(dbif
, &sc
->sc_iflist
, bif_next
) {
5374 dst_if
= dbif
->bif_ifp
;
5375 if (dst_if
== src_if
) {
5376 /* skip the interface that the packet came in on */
5380 /* Private segments can not talk to each other */
5382 (sbif
->bif_ifflags
& dbif
->bif_ifflags
& IFBIF_PRIVATE
)) {
5386 if ((dbif
->bif_ifflags
& IFBIF_STP
) &&
5387 dbif
->bif_stp
.bp_state
== BSTP_IFSTATE_DISCARDING
) {
5391 if ((dbif
->bif_ifflags
& IFBIF_DISCOVER
) == 0 &&
5392 (m
->m_flags
& (M_BCAST
| M_MCAST
)) == 0) {
5396 if ((dst_if
->if_flags
& IFF_RUNNING
) == 0) {
5400 if (!(dbif
->bif_flags
& BIFF_MEDIA_ACTIVE
)) {
5404 if (TAILQ_NEXT(dbif
, bif_next
) == NULL
) {
5408 mc
= m_dup(m
, M_DONTWAIT
);
5410 (void) ifnet_stat_increment_out(bridge_ifp
,
5417 * If broadcast input is enabled, do so only if this
5418 * is an input packet.
5420 if (!bridge_if_out
&&
5421 (dbif
->bif_flags
& BIFF_INPUT_BROADCAST
) != 0) {
5422 mc_in
= m_dup(mc
, M_DONTWAIT
);
5423 /* this could fail, but we continue anyways */
5429 if (translate_mac
&& mac_nat_bif
== dbif
) {
5430 /* translate the packet without holding the lock */
5431 bridge_mac_nat_translate(&mc
, &mnr
, IF_LLADDR(dst_if
));
5434 sc_filter_flags
= sc
->sc_filter_flags
;
5436 PF_IS_ENABLED
&& (sc_filter_flags
& IFBF_FILT_MEMBER
)) {
5438 /* Keep the layer3 header aligned */
5439 int i
= min(mc
->m_pkthdr
.len
, max_protohdr
);
5440 mc
= m_copyup(mc
, i
, ETHER_ALIGN
);
5442 (void) ifnet_stat_increment_out(
5443 sc
->sc_ifp
, 0, 0, 1);
5444 if (mc_in
!= NULL
) {
5451 if (bridge_pf(&mc
, dst_if
, sc_filter_flags
, FALSE
) != 0) {
5452 if (mc_in
!= NULL
) {
5459 if (mc_in
!= NULL
) {
5468 (void) bridge_enqueue(bridge_ifp
,
5469 NULL
, dst_if
, mc
, cksum_op
);
5473 if (mc_in
== NULL
) {
5476 bpf_tap_in(dst_if
, DLT_EN10MB
, mc_in
, NULL
, 0);
5477 mbuf_pkthdr_setrcvif(mc_in
, dst_if
);
5478 mbuf_pkthdr_setheader(mc_in
, mbuf_data(mc_in
));
5479 mbuf_setdata(mc_in
, (char *)mbuf_data(mc_in
) + ETHER_HDR_LEN
,
5480 mbuf_len(mc_in
) - ETHER_HDR_LEN
);
5481 mbuf_pkthdr_adjustlen(mc_in
, -ETHER_HDR_LEN
);
5482 mc_in
->m_flags
|= M_PROTO1
; /* set to avoid loops */
5483 dlil_input_packet_list(dst_if
, mc_in
);
5496 * Duplicate a packet out one or more interfaces that are in span mode,
5497 * the original mbuf is unmodified.
5500 bridge_span(struct bridge_softc
*sc
, struct mbuf
*m
)
5502 struct bridge_iflist
*bif
;
5503 struct ifnet
*dst_if
;
5506 if (TAILQ_EMPTY(&sc
->sc_spanlist
)) {
5510 TAILQ_FOREACH(bif
, &sc
->sc_spanlist
, bif_next
) {
5511 dst_if
= bif
->bif_ifp
;
5513 if ((dst_if
->if_flags
& IFF_RUNNING
) == 0) {
5517 mc
= m_copypacket(m
, M_DONTWAIT
);
5519 (void) ifnet_stat_increment_out(sc
->sc_ifp
, 0, 0, 1);
5523 (void) bridge_enqueue(sc
->sc_ifp
, NULL
, dst_if
, mc
,
5524 kChecksumOperationNone
);
5532 * Add a bridge routing entry.
5535 bridge_rtupdate(struct bridge_softc
*sc
, const uint8_t *dst
, uint16_t vlan
,
5536 struct bridge_iflist
*bif
, int setflags
, uint8_t flags
)
5538 struct bridge_rtnode
*brt
;
5541 BRIDGE_LOCK_ASSERT_HELD(sc
);
5543 /* Check the source address is valid and not multicast. */
5544 if (ETHER_IS_MULTICAST(dst
) ||
5545 (dst
[0] == 0 && dst
[1] == 0 && dst
[2] == 0 &&
5546 dst
[3] == 0 && dst
[4] == 0 && dst
[5] == 0) != 0) {
5551 /* 802.1p frames map to vlan 1 */
5557 * A route for this destination might already exist. If so,
5558 * update it, otherwise create a new one.
5560 if ((brt
= bridge_rtnode_lookup(sc
, dst
, vlan
)) == NULL
) {
5561 if (sc
->sc_brtcnt
>= sc
->sc_brtmax
) {
5562 sc
->sc_brtexceeded
++;
5565 /* Check per interface address limits (if enabled) */
5566 if (bif
->bif_addrmax
&& bif
->bif_addrcnt
>= bif
->bif_addrmax
) {
5567 bif
->bif_addrexceeded
++;
5572 * Allocate a new bridge forwarding node, and
5573 * initialize the expiration time and Ethernet
5576 brt
= zalloc_noblock(bridge_rtnode_pool
);
5578 if (IF_BRIDGE_DEBUG(BR_DBGF_RT_TABLE
)) {
5579 printf("%s: zalloc_nolock failed", __func__
);
5583 bzero(brt
, sizeof(struct bridge_rtnode
));
5585 if (bif
->bif_ifflags
& IFBIF_STICKY
) {
5586 brt
->brt_flags
= IFBAF_STICKY
;
5588 brt
->brt_flags
= IFBAF_DYNAMIC
;
5591 memcpy(brt
->brt_addr
, dst
, ETHER_ADDR_LEN
);
5592 brt
->brt_vlan
= vlan
;
5595 if ((error
= bridge_rtnode_insert(sc
, brt
)) != 0) {
5596 zfree(bridge_rtnode_pool
, brt
);
5602 if (IF_BRIDGE_DEBUG(BR_DBGF_RT_TABLE
)) {
5603 printf("%s: added %02x:%02x:%02x:%02x:%02x:%02x "
5604 "on %s count %u hashsize %u\n", __func__
,
5605 dst
[0], dst
[1], dst
[2], dst
[3], dst
[4], dst
[5],
5606 sc
->sc_ifp
->if_xname
, sc
->sc_brtcnt
,
5607 sc
->sc_rthash_size
);
5612 if ((brt
->brt_flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
&&
5613 brt
->brt_dst
!= bif
) {
5614 brt
->brt_dst
->bif_addrcnt
--;
5616 brt
->brt_dst
->bif_addrcnt
++;
5619 if ((flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
) {
5622 now
= (unsigned long) net_uptime();
5623 brt
->brt_expire
= now
+ sc
->sc_brttimeout
;
5626 brt
->brt_flags
= flags
;
5636 * Lookup the destination interface for an address.
5638 static struct ifnet
*
5639 bridge_rtlookup(struct bridge_softc
*sc
, const uint8_t *addr
, uint16_t vlan
)
5641 struct bridge_rtnode
*brt
;
5643 BRIDGE_LOCK_ASSERT_HELD(sc
);
5645 if ((brt
= bridge_rtnode_lookup(sc
, addr
, vlan
)) == NULL
) {
5649 return brt
->brt_ifp
;
5655 * Trim the routine table so that we have a number
5656 * of routing entries less than or equal to the
5660 bridge_rttrim(struct bridge_softc
*sc
)
5662 struct bridge_rtnode
*brt
, *nbrt
;
5664 BRIDGE_LOCK_ASSERT_HELD(sc
);
5666 /* Make sure we actually need to do this. */
5667 if (sc
->sc_brtcnt
<= sc
->sc_brtmax
) {
5671 /* Force an aging cycle; this might trim enough addresses. */
5673 if (sc
->sc_brtcnt
<= sc
->sc_brtmax
) {
5677 LIST_FOREACH_SAFE(brt
, &sc
->sc_rtlist
, brt_list
, nbrt
) {
5678 if ((brt
->brt_flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
) {
5679 bridge_rtnode_destroy(sc
, brt
);
5680 if (sc
->sc_brtcnt
<= sc
->sc_brtmax
) {
5688 * bridge_aging_timer:
5690 * Aging periodic timer for the bridge routing table.
5693 bridge_aging_timer(struct bridge_softc
*sc
)
5695 BRIDGE_LOCK_ASSERT_HELD(sc
);
5698 if ((sc
->sc_ifp
->if_flags
& IFF_RUNNING
) &&
5699 (sc
->sc_flags
& SCF_DETACHING
) == 0) {
5700 sc
->sc_aging_timer
.bdc_sc
= sc
;
5701 sc
->sc_aging_timer
.bdc_func
= bridge_aging_timer
;
5702 sc
->sc_aging_timer
.bdc_ts
.tv_sec
= bridge_rtable_prune_period
;
5703 bridge_schedule_delayed_call(&sc
->sc_aging_timer
);
5710 * Perform an aging cycle.
5713 bridge_rtage(struct bridge_softc
*sc
)
5715 struct bridge_rtnode
*brt
, *nbrt
;
5718 BRIDGE_LOCK_ASSERT_HELD(sc
);
5720 now
= (unsigned long) net_uptime();
5722 LIST_FOREACH_SAFE(brt
, &sc
->sc_rtlist
, brt_list
, nbrt
) {
5723 if ((brt
->brt_flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
) {
5724 if (now
>= brt
->brt_expire
) {
5725 bridge_rtnode_destroy(sc
, brt
);
5729 if (sc
->sc_mac_nat_bif
!= NULL
) {
5730 bridge_mac_nat_age_entries(sc
, now
);
5737 * Remove all dynamic addresses from the bridge.
5740 bridge_rtflush(struct bridge_softc
*sc
, int full
)
5742 struct bridge_rtnode
*brt
, *nbrt
;
5744 BRIDGE_LOCK_ASSERT_HELD(sc
);
5746 LIST_FOREACH_SAFE(brt
, &sc
->sc_rtlist
, brt_list
, nbrt
) {
5747 if (full
|| (brt
->brt_flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
) {
5748 bridge_rtnode_destroy(sc
, brt
);
5756 * Remove an address from the table.
5759 bridge_rtdaddr(struct bridge_softc
*sc
, const uint8_t *addr
, uint16_t vlan
)
5761 struct bridge_rtnode
*brt
;
5764 BRIDGE_LOCK_ASSERT_HELD(sc
);
5767 * If vlan is zero then we want to delete for all vlans so the lookup
5768 * may return more than one.
5770 while ((brt
= bridge_rtnode_lookup(sc
, addr
, vlan
)) != NULL
) {
5771 bridge_rtnode_destroy(sc
, brt
);
5775 return found
? 0 : ENOENT
;
5781 * Delete routes to a specific member interface.
5784 bridge_rtdelete(struct bridge_softc
*sc
, struct ifnet
*ifp
, int full
)
5786 struct bridge_rtnode
*brt
, *nbrt
;
5788 BRIDGE_LOCK_ASSERT_HELD(sc
);
5790 LIST_FOREACH_SAFE(brt
, &sc
->sc_rtlist
, brt_list
, nbrt
) {
5791 if (brt
->brt_ifp
== ifp
&& (full
||
5792 (brt
->brt_flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
)) {
5793 bridge_rtnode_destroy(sc
, brt
);
5799 * bridge_rtable_init:
5801 * Initialize the route table for this bridge.
5804 bridge_rtable_init(struct bridge_softc
*sc
)
5808 sc
->sc_rthash
= _MALLOC(sizeof(*sc
->sc_rthash
) * BRIDGE_RTHASH_SIZE
,
5809 M_DEVBUF
, M_WAITOK
| M_ZERO
);
5810 if (sc
->sc_rthash
== NULL
) {
5811 printf("%s: no memory\n", __func__
);
5814 sc
->sc_rthash_size
= BRIDGE_RTHASH_SIZE
;
5816 for (i
= 0; i
< sc
->sc_rthash_size
; i
++) {
5817 LIST_INIT(&sc
->sc_rthash
[i
]);
5820 sc
->sc_rthash_key
= RandomULong();
5822 LIST_INIT(&sc
->sc_rtlist
);
5828 * bridge_rthash_delayed_resize:
5830 * Resize the routing table hash on a delayed thread call.
5833 bridge_rthash_delayed_resize(struct bridge_softc
*sc
)
5835 u_int32_t new_rthash_size
;
5836 struct _bridge_rtnode_list
*new_rthash
= NULL
;
5837 struct _bridge_rtnode_list
*old_rthash
= NULL
;
5839 struct bridge_rtnode
*brt
;
5842 BRIDGE_LOCK_ASSERT_HELD(sc
);
5845 * Four entries per hash bucket is our ideal load factor
5847 if (sc
->sc_brtcnt
< sc
->sc_rthash_size
* 4) {
5852 * Doubling the number of hash buckets may be too simplistic
5853 * especially when facing a spike of new entries
5855 new_rthash_size
= sc
->sc_rthash_size
* 2;
5857 sc
->sc_flags
|= SCF_RESIZING
;
5860 new_rthash
= _MALLOC(sizeof(*sc
->sc_rthash
) * new_rthash_size
,
5861 M_DEVBUF
, M_WAITOK
| M_ZERO
);
5864 sc
->sc_flags
&= ~SCF_RESIZING
;
5866 if (new_rthash
== NULL
) {
5870 if ((sc
->sc_flags
& SCF_DETACHING
)) {
5875 * Fail safe from here on
5877 old_rthash
= sc
->sc_rthash
;
5878 sc
->sc_rthash
= new_rthash
;
5879 sc
->sc_rthash_size
= new_rthash_size
;
5882 * Get a new key to force entries to be shuffled around to reduce
5883 * the likelihood they will land in the same buckets
5885 sc
->sc_rthash_key
= RandomULong();
5887 for (i
= 0; i
< sc
->sc_rthash_size
; i
++) {
5888 LIST_INIT(&sc
->sc_rthash
[i
]);
5891 LIST_FOREACH(brt
, &sc
->sc_rtlist
, brt_list
) {
5892 LIST_REMOVE(brt
, brt_hash
);
5893 (void) bridge_rtnode_hash(sc
, brt
);
5898 if (IF_BRIDGE_DEBUG(BR_DBGF_RT_TABLE
)) {
5899 printf("%s: %s new size %u\n", __func__
,
5900 sc
->sc_ifp
->if_xname
, sc
->sc_rthash_size
);
5902 #endif /* BRIDGE_DEBUG */
5904 _FREE(old_rthash
, M_DEVBUF
);
5908 printf("%s: %s failed %d\n", __func__
,
5909 sc
->sc_ifp
->if_xname
, error
);
5910 #endif /* BRIDGE_DEBUG */
5911 if (new_rthash
!= NULL
) {
5912 _FREE(new_rthash
, M_DEVBUF
);
5918 * Resize the number of hash buckets based on the load factor
5919 * Currently only grow
5920 * Failing to resize the hash table is not fatal
5923 bridge_rthash_resize(struct bridge_softc
*sc
)
5925 BRIDGE_LOCK_ASSERT_HELD(sc
);
5927 if ((sc
->sc_flags
& SCF_DETACHING
) || (sc
->sc_flags
& SCF_RESIZING
)) {
5932 * Four entries per hash bucket is our ideal load factor
5934 if (sc
->sc_brtcnt
< sc
->sc_rthash_size
* 4) {
5938 * Hard limit on the size of the routing hash table
5940 if (sc
->sc_rthash_size
>= bridge_rtable_hash_size_max
) {
5944 sc
->sc_resize_call
.bdc_sc
= sc
;
5945 sc
->sc_resize_call
.bdc_func
= bridge_rthash_delayed_resize
;
5946 bridge_schedule_delayed_call(&sc
->sc_resize_call
);
5950 * bridge_rtable_fini:
5952 * Deconstruct the route table for this bridge.
5955 bridge_rtable_fini(struct bridge_softc
*sc
)
5957 KASSERT(sc
->sc_brtcnt
== 0,
5958 ("%s: %d bridge routes referenced", __func__
, sc
->sc_brtcnt
));
5959 if (sc
->sc_rthash
) {
5960 _FREE(sc
->sc_rthash
, M_DEVBUF
);
5961 sc
->sc_rthash
= NULL
;
5966 * The following hash function is adapted from "Hash Functions" by Bob Jenkins
5967 * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
5969 #define mix(a, b, c) \
5971 a -= b; a -= c; a ^= (c >> 13); \
5972 b -= c; b -= a; b ^= (a << 8); \
5973 c -= a; c -= b; c ^= (b >> 13); \
5974 a -= b; a -= c; a ^= (c >> 12); \
5975 b -= c; b -= a; b ^= (a << 16); \
5976 c -= a; c -= b; c ^= (b >> 5); \
5977 a -= b; a -= c; a ^= (c >> 3); \
5978 b -= c; b -= a; b ^= (a << 10); \
5979 c -= a; c -= b; c ^= (b >> 15); \
5980 } while ( /*CONSTCOND*/ 0)
5982 static __inline
uint32_t
5983 bridge_rthash(struct bridge_softc
*sc
, const uint8_t *addr
)
5985 uint32_t a
= 0x9e3779b9, b
= 0x9e3779b9, c
= sc
->sc_rthash_key
;
5996 return c
& BRIDGE_RTHASH_MASK(sc
);
6002 bridge_rtnode_addr_cmp(const uint8_t *a
, const uint8_t *b
)
6006 for (i
= 0, d
= 0; i
< ETHER_ADDR_LEN
&& d
== 0; i
++) {
6007 d
= ((int)a
[i
]) - ((int)b
[i
]);
6014 * bridge_rtnode_lookup:
6016 * Look up a bridge route node for the specified destination. Compare the
6017 * vlan id or if zero then just return the first match.
6019 static struct bridge_rtnode
*
6020 bridge_rtnode_lookup(struct bridge_softc
*sc
, const uint8_t *addr
,
6023 struct bridge_rtnode
*brt
;
6027 BRIDGE_LOCK_ASSERT_HELD(sc
);
6029 hash
= bridge_rthash(sc
, addr
);
6030 LIST_FOREACH(brt
, &sc
->sc_rthash
[hash
], brt_hash
) {
6031 dir
= bridge_rtnode_addr_cmp(addr
, brt
->brt_addr
);
6032 if (dir
== 0 && (brt
->brt_vlan
== vlan
|| vlan
== 0)) {
6044 * bridge_rtnode_hash:
6046 * Insert the specified bridge node into the route hash table.
6047 * This is used when adding a new node or to rehash when resizing
6051 bridge_rtnode_hash(struct bridge_softc
*sc
, struct bridge_rtnode
*brt
)
6053 struct bridge_rtnode
*lbrt
;
6057 BRIDGE_LOCK_ASSERT_HELD(sc
);
6059 hash
= bridge_rthash(sc
, brt
->brt_addr
);
6061 lbrt
= LIST_FIRST(&sc
->sc_rthash
[hash
]);
6063 LIST_INSERT_HEAD(&sc
->sc_rthash
[hash
], brt
, brt_hash
);
6068 dir
= bridge_rtnode_addr_cmp(brt
->brt_addr
, lbrt
->brt_addr
);
6069 if (dir
== 0 && brt
->brt_vlan
== lbrt
->brt_vlan
) {
6071 if (IF_BRIDGE_DEBUG(BR_DBGF_RT_TABLE
)) {
6072 printf("%s: %s EEXIST "
6073 "%02x:%02x:%02x:%02x:%02x:%02x\n",
6074 __func__
, sc
->sc_ifp
->if_xname
,
6075 brt
->brt_addr
[0], brt
->brt_addr
[1],
6076 brt
->brt_addr
[2], brt
->brt_addr
[3],
6077 brt
->brt_addr
[4], brt
->brt_addr
[5]);
6083 LIST_INSERT_BEFORE(lbrt
, brt
, brt_hash
);
6086 if (LIST_NEXT(lbrt
, brt_hash
) == NULL
) {
6087 LIST_INSERT_AFTER(lbrt
, brt
, brt_hash
);
6090 lbrt
= LIST_NEXT(lbrt
, brt_hash
);
6091 } while (lbrt
!= NULL
);
6094 if (IF_BRIDGE_DEBUG(BR_DBGF_RT_TABLE
)) {
6095 printf("%s: %s impossible %02x:%02x:%02x:%02x:%02x:%02x\n",
6096 __func__
, sc
->sc_ifp
->if_xname
,
6097 brt
->brt_addr
[0], brt
->brt_addr
[1], brt
->brt_addr
[2],
6098 brt
->brt_addr
[3], brt
->brt_addr
[4], brt
->brt_addr
[5]);
6107 * bridge_rtnode_insert:
6109 * Insert the specified bridge node into the route table. We
6110 * assume the entry is not already in the table.
6113 bridge_rtnode_insert(struct bridge_softc
*sc
, struct bridge_rtnode
*brt
)
6117 error
= bridge_rtnode_hash(sc
, brt
);
6122 LIST_INSERT_HEAD(&sc
->sc_rtlist
, brt
, brt_list
);
6125 bridge_rthash_resize(sc
);
6131 * bridge_rtnode_destroy:
6133 * Destroy a bridge rtnode.
6136 bridge_rtnode_destroy(struct bridge_softc
*sc
, struct bridge_rtnode
*brt
)
6138 BRIDGE_LOCK_ASSERT_HELD(sc
);
6140 LIST_REMOVE(brt
, brt_hash
);
6142 LIST_REMOVE(brt
, brt_list
);
6144 brt
->brt_dst
->bif_addrcnt
--;
6145 zfree(bridge_rtnode_pool
, brt
);
6150 * bridge_rtable_expire:
6152 * Set the expiry time for all routes on an interface.
6155 bridge_rtable_expire(struct ifnet
*ifp
, int age
)
6157 struct bridge_softc
*sc
= ifp
->if_bridge
;
6158 struct bridge_rtnode
*brt
;
6163 * If the age is zero then flush, otherwise set all the expiry times to
6164 * age for the interface
6167 bridge_rtdelete(sc
, ifp
, IFBF_FLUSHDYN
);
6171 now
= (unsigned long) net_uptime();
6173 LIST_FOREACH(brt
, &sc
->sc_rtlist
, brt_list
) {
6174 /* Cap the expiry time to 'age' */
6175 if (brt
->brt_ifp
== ifp
&&
6176 brt
->brt_expire
> now
+ age
&&
6177 (brt
->brt_flags
& IFBAF_TYPEMASK
) == IFBAF_DYNAMIC
) {
6178 brt
->brt_expire
= now
+ age
;
6186 * bridge_state_change:
6188 * Callback from the bridgestp code when a port changes states.
6191 bridge_state_change(struct ifnet
*ifp
, int state
)
6193 struct bridge_softc
*sc
= ifp
->if_bridge
;
6194 static const char *stpstates
[] = {
6204 log(LOG_NOTICE
, "%s: state changed to %s on %s\n",
6205 sc
->sc_ifp
->if_xname
,
6206 stpstates
[state
], ifp
->if_xname
);
6209 #endif /* BRIDGESTP */
6212 * bridge_set_bpf_tap:
6214 * Sets ups the BPF callbacks.
6217 bridge_set_bpf_tap(ifnet_t ifp
, bpf_tap_mode mode
, bpf_packet_func bpf_callback
)
6219 struct bridge_softc
*sc
= (struct bridge_softc
*)ifnet_softc(ifp
);
6222 if (sc
== NULL
|| (sc
->sc_flags
& SCF_DETACHING
)) {
6226 case BPF_TAP_DISABLE
:
6227 sc
->sc_bpf_input
= sc
->sc_bpf_output
= NULL
;
6231 sc
->sc_bpf_input
= bpf_callback
;
6234 case BPF_TAP_OUTPUT
:
6235 sc
->sc_bpf_output
= bpf_callback
;
6238 case BPF_TAP_INPUT_OUTPUT
:
6239 sc
->sc_bpf_input
= sc
->sc_bpf_output
= bpf_callback
;
6252 * Callback when interface has been detached.
6255 bridge_detach(ifnet_t ifp
)
6257 struct bridge_softc
*sc
= (struct bridge_softc
*)ifnet_softc(ifp
);
6260 bstp_detach(&sc
->sc_stp
);
6261 #endif /* BRIDGESTP */
6263 /* Tear down the routing table. */
6264 bridge_rtable_fini(sc
);
6266 lck_mtx_lock(&bridge_list_mtx
);
6267 LIST_REMOVE(sc
, sc_list
);
6268 lck_mtx_unlock(&bridge_list_mtx
);
6272 lck_mtx_destroy(&sc
->sc_mtx
, bridge_lock_grp
);
6273 if_clone_softc_deallocate(&bridge_cloner
, sc
);
6279 * Invoke the input BPF callback if enabled
6282 bridge_bpf_input(ifnet_t ifp
, struct mbuf
*m
, const char * func
, int line
)
6284 struct bridge_softc
*sc
= (struct bridge_softc
*)ifnet_softc(ifp
);
6285 bpf_packet_func input_func
= sc
->sc_bpf_input
;
6287 if (input_func
!= NULL
) {
6288 if (mbuf_pkthdr_rcvif(m
) != ifp
) {
6289 printf("%s.%d: rcvif: 0x%llx != ifp 0x%llx\n", func
, line
,
6290 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_pkthdr_rcvif(m
)),
6291 (uint64_t)VM_KERNEL_ADDRPERM(ifp
));
6293 (*input_func
)(ifp
, m
);
6299 * bridge_bpf_output:
6301 * Invoke the output BPF callback if enabled
6304 bridge_bpf_output(ifnet_t ifp
, struct mbuf
*m
)
6306 struct bridge_softc
*sc
= (struct bridge_softc
*)ifnet_softc(ifp
);
6307 bpf_packet_func output_func
= sc
->sc_bpf_output
;
6309 if (output_func
!= NULL
) {
6310 (*output_func
)(ifp
, m
);
6316 * bridge_link_event:
6318 * Report a data link event on an interface
6321 bridge_link_event(struct ifnet
*ifp
, u_int32_t event_code
)
6324 u_int32_t ifnet_family
;
6326 char if_name
[IFNAMSIZ
];
6328 _Alignas(struct kern_event_msg
) char message
[sizeof(struct kern_event_msg
) + sizeof(struct event
)] = { 0 };
6329 struct kern_event_msg
*header
= (struct kern_event_msg
*)message
;
6330 struct event
*data
= (struct event
*)(header
+ 1);
6333 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE
)) {
6334 printf("%s: %s event_code %u - %s\n", __func__
, ifp
->if_xname
,
6335 event_code
, dlil_kev_dl_code_str(event_code
));
6337 #endif /* BRIDGE_DEBUG */
6339 header
->total_size
= sizeof(message
);
6340 header
->vendor_code
= KEV_VENDOR_APPLE
;
6341 header
->kev_class
= KEV_NETWORK_CLASS
;
6342 header
->kev_subclass
= KEV_DL_SUBCLASS
;
6343 header
->event_code
= event_code
;
6344 data
->ifnet_family
= ifnet_family(ifp
);
6345 data
->unit
= (u_int32_t
)ifnet_unit(ifp
);
6346 strlcpy(data
->if_name
, ifnet_name(ifp
), IFNAMSIZ
);
6347 ifnet_event(ifp
, header
);
6350 #define BRIDGE_HF_DROP(reason, func, line) { \
6351 bridge_hostfilter_stats.reason++; \
6352 if (IF_BRIDGE_DEBUG(BR_DBGF_HOSTFILTER)) { \
6353 printf("%s.%d" #reason, func, line); \
6359 * Make sure this is a DHCP or Bootp request that match the host filter
6362 bridge_dhcp_filter(struct bridge_iflist
*bif
, struct mbuf
*m
, size_t offset
)
6368 * Note: We use the dhcp structure because bootp structure definition
6369 * is larger and some vendors do not pad the request
6371 error
= mbuf_copydata(m
, offset
, sizeof(struct dhcp
), &dhcp
);
6373 BRIDGE_HF_DROP(brhf_dhcp_too_small
, __func__
, __LINE__
);
6376 if (dhcp
.dp_op
!= BOOTREQUEST
) {
6377 BRIDGE_HF_DROP(brhf_dhcp_bad_op
, __func__
, __LINE__
);
6381 * The hardware address must be an exact match
6383 if (dhcp
.dp_htype
!= ARPHRD_ETHER
) {
6384 BRIDGE_HF_DROP(brhf_dhcp_bad_htype
, __func__
, __LINE__
);
6387 if (dhcp
.dp_hlen
!= ETHER_ADDR_LEN
) {
6388 BRIDGE_HF_DROP(brhf_dhcp_bad_hlen
, __func__
, __LINE__
);
6391 if (bcmp(dhcp
.dp_chaddr
, bif
->bif_hf_hwsrc
,
6392 ETHER_ADDR_LEN
) != 0) {
6393 BRIDGE_HF_DROP(brhf_dhcp_bad_chaddr
, __func__
, __LINE__
);
6397 * Client address must match the host address or be not specified
6399 if (dhcp
.dp_ciaddr
.s_addr
!= bif
->bif_hf_ipsrc
.s_addr
&&
6400 dhcp
.dp_ciaddr
.s_addr
!= INADDR_ANY
) {
6401 BRIDGE_HF_DROP(brhf_dhcp_bad_ciaddr
, __func__
, __LINE__
);
6410 bridge_host_filter(struct bridge_iflist
*bif
, mbuf_t
*data
)
6413 struct ether_header
*eh
;
6414 static struct in_addr inaddr_any
= { .s_addr
= INADDR_ANY
};
6417 eh
= mtod(m
, struct ether_header
*);
6420 * Restrict the source hardware address
6422 if ((bif
->bif_flags
& BIFF_HF_HWSRC
) == 0 ||
6423 bcmp(eh
->ether_shost
, bif
->bif_hf_hwsrc
,
6424 ETHER_ADDR_LEN
) != 0) {
6425 BRIDGE_HF_DROP(brhf_bad_ether_srchw_addr
, __func__
, __LINE__
);
6430 * Restrict Ethernet protocols to ARP and IP
6432 if (eh
->ether_type
== htons(ETHERTYPE_ARP
)) {
6433 struct ether_arp
*ea
;
6434 size_t minlen
= sizeof(struct ether_header
) +
6435 sizeof(struct ether_arp
);
6438 * Make the Ethernet and ARP headers contiguous
6440 if (mbuf_pkthdr_len(m
) < minlen
) {
6441 BRIDGE_HF_DROP(brhf_arp_too_small
, __func__
, __LINE__
);
6444 if (mbuf_len(m
) < minlen
&& mbuf_pullup(data
, minlen
) != 0) {
6445 BRIDGE_HF_DROP(brhf_arp_pullup_failed
,
6446 __func__
, __LINE__
);
6452 * Verify this is an ethernet/ip arp
6454 eh
= mtod(m
, struct ether_header
*);
6455 ea
= (struct ether_arp
*)(eh
+ 1);
6456 if (ea
->arp_hrd
!= htons(ARPHRD_ETHER
)) {
6457 BRIDGE_HF_DROP(brhf_arp_bad_hw_type
,
6458 __func__
, __LINE__
);
6461 if (ea
->arp_pro
!= htons(ETHERTYPE_IP
)) {
6462 BRIDGE_HF_DROP(brhf_arp_bad_pro_type
,
6463 __func__
, __LINE__
);
6467 * Verify the address lengths are correct
6469 if (ea
->arp_hln
!= ETHER_ADDR_LEN
) {
6470 BRIDGE_HF_DROP(brhf_arp_bad_hw_len
, __func__
, __LINE__
);
6473 if (ea
->arp_pln
!= sizeof(struct in_addr
)) {
6474 BRIDGE_HF_DROP(brhf_arp_bad_pro_len
,
6475 __func__
, __LINE__
);
6480 * Allow only ARP request or ARP reply
6482 if (ea
->arp_op
!= htons(ARPOP_REQUEST
) &&
6483 ea
->arp_op
!= htons(ARPOP_REPLY
)) {
6484 BRIDGE_HF_DROP(brhf_arp_bad_op
, __func__
, __LINE__
);
6488 * Verify source hardware address matches
6490 if (bcmp(ea
->arp_sha
, bif
->bif_hf_hwsrc
,
6491 ETHER_ADDR_LEN
) != 0) {
6492 BRIDGE_HF_DROP(brhf_arp_bad_sha
, __func__
, __LINE__
);
6496 * Verify source protocol address:
6497 * May be null for an ARP probe
6499 if (bcmp(ea
->arp_spa
, &bif
->bif_hf_ipsrc
.s_addr
,
6500 sizeof(struct in_addr
)) != 0 &&
6501 bcmp(ea
->arp_spa
, &inaddr_any
,
6502 sizeof(struct in_addr
)) != 0) {
6503 BRIDGE_HF_DROP(brhf_arp_bad_spa
, __func__
, __LINE__
);
6506 bridge_hostfilter_stats
.brhf_arp_ok
+= 1;
6508 } else if (eh
->ether_type
== htons(ETHERTYPE_IP
)) {
6509 size_t minlen
= sizeof(struct ether_header
) + sizeof(struct ip
);
6514 * Make the Ethernet and IP headers contiguous
6516 if (mbuf_pkthdr_len(m
) < minlen
) {
6517 BRIDGE_HF_DROP(brhf_ip_too_small
, __func__
, __LINE__
);
6520 offset
= sizeof(struct ether_header
);
6521 error
= mbuf_copydata(m
, offset
, sizeof(struct ip
), &iphdr
);
6523 BRIDGE_HF_DROP(brhf_ip_too_small
, __func__
, __LINE__
);
6527 * Verify the source IP address
6529 if (iphdr
.ip_p
== IPPROTO_UDP
) {
6532 minlen
+= sizeof(struct udphdr
);
6533 if (mbuf_pkthdr_len(m
) < minlen
) {
6534 BRIDGE_HF_DROP(brhf_ip_too_small
,
6535 __func__
, __LINE__
);
6540 * Allow all zero addresses for DHCP requests
6542 if (iphdr
.ip_src
.s_addr
!= bif
->bif_hf_ipsrc
.s_addr
&&
6543 iphdr
.ip_src
.s_addr
!= INADDR_ANY
) {
6544 BRIDGE_HF_DROP(brhf_ip_bad_srcaddr
,
6545 __func__
, __LINE__
);
6548 offset
= sizeof(struct ether_header
) +
6549 (IP_VHL_HL(iphdr
.ip_vhl
) << 2);
6550 error
= mbuf_copydata(m
, offset
,
6551 sizeof(struct udphdr
), &udp
);
6553 BRIDGE_HF_DROP(brhf_ip_too_small
,
6554 __func__
, __LINE__
);
6558 * Either it's a Bootp/DHCP packet that we like or
6559 * it's a UDP packet from the host IP as source address
6561 if (udp
.uh_sport
== htons(IPPORT_BOOTPC
) &&
6562 udp
.uh_dport
== htons(IPPORT_BOOTPS
)) {
6563 minlen
+= sizeof(struct dhcp
);
6564 if (mbuf_pkthdr_len(m
) < minlen
) {
6565 BRIDGE_HF_DROP(brhf_ip_too_small
,
6566 __func__
, __LINE__
);
6569 offset
+= sizeof(struct udphdr
);
6570 error
= bridge_dhcp_filter(bif
, m
, offset
);
6574 } else if (iphdr
.ip_src
.s_addr
== INADDR_ANY
) {
6575 BRIDGE_HF_DROP(brhf_ip_bad_srcaddr
,
6576 __func__
, __LINE__
);
6579 } else if (iphdr
.ip_src
.s_addr
!= bif
->bif_hf_ipsrc
.s_addr
||
6580 bif
->bif_hf_ipsrc
.s_addr
== INADDR_ANY
) {
6581 BRIDGE_HF_DROP(brhf_ip_bad_srcaddr
, __func__
, __LINE__
);
6585 * Allow only boring IP protocols
6587 if (iphdr
.ip_p
!= IPPROTO_TCP
&&
6588 iphdr
.ip_p
!= IPPROTO_UDP
&&
6589 iphdr
.ip_p
!= IPPROTO_ICMP
&&
6590 iphdr
.ip_p
!= IPPROTO_ESP
&&
6591 iphdr
.ip_p
!= IPPROTO_AH
&&
6592 iphdr
.ip_p
!= IPPROTO_GRE
) {
6593 BRIDGE_HF_DROP(brhf_ip_bad_proto
, __func__
, __LINE__
);
6596 bridge_hostfilter_stats
.brhf_ip_ok
+= 1;
6599 BRIDGE_HF_DROP(brhf_bad_ether_type
, __func__
, __LINE__
);
6604 if (IF_BRIDGE_DEBUG(BR_DBGF_HOSTFILTER
)) {
6606 printf_mbuf_data(m
, 0,
6607 sizeof(struct ether_header
) +
6625 bridge_mac_nat_enable(struct bridge_softc
*sc
, struct bridge_iflist
*bif
)
6629 BRIDGE_LOCK_ASSERT_HELD(sc
);
6631 if (sc
->sc_mac_nat_bif
!= NULL
) {
6632 if (sc
->sc_mac_nat_bif
!= bif
) {
6637 sc
->sc_mac_nat_bif
= bif
;
6638 bif
->bif_ifflags
|= IFBIF_MAC_NAT
;
6639 bridge_mac_nat_populate_entries(sc
);
6646 bridge_mac_nat_disable(struct bridge_softc
*sc
)
6648 struct bridge_iflist
*mac_nat_bif
= sc
->sc_mac_nat_bif
;
6650 assert(mac_nat_bif
!= NULL
);
6651 bridge_mac_nat_flush_entries(sc
, mac_nat_bif
);
6652 mac_nat_bif
->bif_ifflags
&= ~IFBIF_MAC_NAT
;
6653 sc
->sc_mac_nat_bif
= NULL
;
6658 mac_nat_entry_print2(struct mac_nat_entry
*mne
,
6659 char *ifname
, const char *msg1
, const char *msg2
)
6663 char ntopbuf
[MAX_IPv6_STR_LEN
];
6666 af
= ((mne
->mne_flags
& MNE_FLAGS_IPV6
) != 0) ? AF_INET6
: AF_INET
;
6667 ether_ntop(etopbuf
, sizeof(etopbuf
), mne
->mne_mac
);
6668 (void)inet_ntop(af
, &mne
->mne_u
, ntopbuf
, sizeof(ntopbuf
));
6675 printf("%s %s%s%s %p (%s, %s, %s)\n",
6676 ifname
, msg1
, space
, msg2
, mne
, mne
->mne_bif
->bif_ifp
->if_xname
,
6681 mac_nat_entry_print(struct mac_nat_entry
*mne
,
6682 char *ifname
, const char *msg
)
6684 mac_nat_entry_print2(mne
, ifname
, msg
, NULL
);
6687 static struct mac_nat_entry
*
6688 bridge_lookup_mac_nat_entry(struct bridge_softc
*sc
, int af
, void * ip
)
6690 struct mac_nat_entry
*mne
;
6691 struct mac_nat_entry
*ret_mne
= NULL
;
6693 if (af
== AF_INET
) {
6694 in_addr_t s_addr
= ((struct in_addr
*)ip
)->s_addr
;
6696 LIST_FOREACH(mne
, &sc
->sc_mne_list
, mne_list
) {
6697 if (mne
->mne_ip
.s_addr
== s_addr
) {
6698 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
6699 mac_nat_entry_print(mne
, sc
->sc_if_xname
,
6707 const struct in6_addr
*ip6
= (const struct in6_addr
*)ip
;
6709 LIST_FOREACH(mne
, &sc
->sc_mne_list_v6
, mne_list
) {
6710 if (IN6_ARE_ADDR_EQUAL(&mne
->mne_ip6
, ip6
)) {
6711 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
6712 mac_nat_entry_print(mne
, sc
->sc_if_xname
,
6724 bridge_destroy_mac_nat_entry(struct bridge_softc
*sc
,
6725 struct mac_nat_entry
*mne
, const char *reason
)
6727 LIST_REMOVE(mne
, mne_list
);
6728 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
6729 mac_nat_entry_print(mne
, sc
->sc_if_xname
, reason
);
6731 zfree(bridge_mne_pool
, mne
);
6735 static struct mac_nat_entry
*
6736 bridge_create_mac_nat_entry(struct bridge_softc
*sc
,
6737 struct bridge_iflist
*bif
, int af
, const void *ip
, uint8_t *eaddr
)
6739 struct mac_nat_entry_list
*list
;
6740 struct mac_nat_entry
*mne
;
6742 if (sc
->sc_mne_count
>= sc
->sc_mne_max
) {
6743 sc
->sc_mne_allocation_failures
++;
6746 mne
= zalloc_noblock(bridge_mne_pool
);
6748 sc
->sc_mne_allocation_failures
++;
6752 bzero(mne
, sizeof(*mne
));
6753 bcopy(eaddr
, mne
->mne_mac
, sizeof(mne
->mne_mac
));
6755 if (af
== AF_INET
) {
6756 bcopy(ip
, &mne
->mne_ip
, sizeof(mne
->mne_ip
));
6757 list
= &sc
->sc_mne_list
;
6759 bcopy(ip
, &mne
->mne_ip6
, sizeof(mne
->mne_ip6
));
6760 mne
->mne_flags
|= MNE_FLAGS_IPV6
;
6761 list
= &sc
->sc_mne_list_v6
;
6763 LIST_INSERT_HEAD(list
, mne
, mne_list
);
6764 mne
->mne_expire
= (unsigned long)net_uptime() + sc
->sc_brttimeout
;
6765 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
6766 mac_nat_entry_print(mne
, sc
->sc_if_xname
, "created");
6771 static struct mac_nat_entry
*
6772 bridge_update_mac_nat_entry(struct bridge_softc
*sc
,
6773 struct bridge_iflist
*bif
, int af
, void *ip
, uint8_t *eaddr
)
6775 struct mac_nat_entry
*mne
;
6777 mne
= bridge_lookup_mac_nat_entry(sc
, af
, ip
);
6779 struct bridge_iflist
*mac_nat_bif
= sc
->sc_mac_nat_bif
;
6781 if (mne
->mne_bif
== mac_nat_bif
) {
6782 /* the MAC NAT interface takes precedence */
6783 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
6784 if (mne
->mne_bif
!= bif
) {
6785 mac_nat_entry_print2(mne
,
6786 sc
->sc_if_xname
, "reject",
6787 bif
->bif_ifp
->if_xname
);
6790 } else if (mne
->mne_bif
!= bif
) {
6791 const char *old_if
= mne
->mne_bif
->bif_ifp
->if_xname
;
6794 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
6795 mac_nat_entry_print2(mne
,
6796 sc
->sc_if_xname
, "replaced",
6799 bcopy(eaddr
, mne
->mne_mac
, sizeof(mne
->mne_mac
));
6801 mne
->mne_expire
= (unsigned long)net_uptime() +
6804 mne
= bridge_create_mac_nat_entry(sc
, bif
, af
, ip
, eaddr
);
6810 bridge_mac_nat_flush_entries_common(struct bridge_softc
*sc
,
6811 struct mac_nat_entry_list
*list
, struct bridge_iflist
*bif
)
6813 struct mac_nat_entry
*mne
;
6814 struct mac_nat_entry
*tmne
;
6816 LIST_FOREACH_SAFE(mne
, list
, mne_list
, tmne
) {
6817 if (bif
!= NULL
&& mne
->mne_bif
!= bif
) {
6820 bridge_destroy_mac_nat_entry(sc
, mne
, "flushed");
6825 * bridge_mac_nat_flush_entries:
6827 * Flush MAC NAT entries for the specified member. Flush all entries if
6828 * the member is the one that requires MAC NAT, otherwise just flush the
6829 * ones for the specified member.
6832 bridge_mac_nat_flush_entries(struct bridge_softc
*sc
, struct bridge_iflist
* bif
)
6834 struct bridge_iflist
*flush_bif
;
6836 flush_bif
= (bif
== sc
->sc_mac_nat_bif
) ? NULL
: bif
;
6837 bridge_mac_nat_flush_entries_common(sc
, &sc
->sc_mne_list
, flush_bif
);
6838 bridge_mac_nat_flush_entries_common(sc
, &sc
->sc_mne_list_v6
, flush_bif
);
6842 bridge_mac_nat_populate_entries(struct bridge_softc
*sc
)
6847 struct bridge_iflist
*mac_nat_bif
= sc
->sc_mac_nat_bif
;
6849 assert(mac_nat_bif
!= NULL
);
6850 ifp
= mac_nat_bif
->bif_ifp
;
6851 error
= ifnet_get_address_list(ifp
, &list
);
6853 printf("%s: ifnet_get_address_list(%s) failed %d\n",
6854 __func__
, ifp
->if_xname
, error
);
6857 for (ifaddr_t
*scan
= list
; *scan
!= NULL
; scan
++) {
6863 struct sockaddr_in sin
;
6864 struct sockaddr_in6 sin6
;
6866 af
= ifaddr_address_family(*scan
);
6870 error
= ifaddr_address(*scan
, &u
.sa
, sizeof(u
));
6872 printf("%s: ifaddr_address failed %d\n",
6876 if (af
== AF_INET
) {
6877 ip
= (void *)&u
.sin
.sin_addr
;
6879 if (IN6_IS_ADDR_LINKLOCAL(&u
.sin6
.sin6_addr
)) {
6880 /* remove scope ID */
6881 u
.sin6
.sin6_addr
.s6_addr16
[1] = 0;
6883 ip
= (void *)&u
.sin6
.sin6_addr
;
6885 bridge_create_mac_nat_entry(sc
, mac_nat_bif
, af
, ip
,
6886 (uint8_t *)IF_LLADDR(ifp
));
6892 ifnet_free_address_list(list
);
6897 bridge_mac_nat_age_entries_common(struct bridge_softc
*sc
,
6898 struct mac_nat_entry_list
*list
, unsigned long now
)
6900 struct mac_nat_entry
*mne
;
6901 struct mac_nat_entry
*tmne
;
6903 LIST_FOREACH_SAFE(mne
, list
, mne_list
, tmne
) {
6904 if (now
>= mne
->mne_expire
) {
6905 bridge_destroy_mac_nat_entry(sc
, mne
, "aged out");
6911 bridge_mac_nat_age_entries(struct bridge_softc
*sc
, unsigned long now
)
6913 if (sc
->sc_mac_nat_bif
== NULL
) {
6916 bridge_mac_nat_age_entries_common(sc
, &sc
->sc_mne_list
, now
);
6917 bridge_mac_nat_age_entries_common(sc
, &sc
->sc_mne_list_v6
, now
);
6921 get_in_out_string(boolean_t is_output
)
6923 return is_output
? "OUT" : "IN";
6927 * is_valid_arp_packet:
6928 * Verify that this is a valid ARP packet.
6930 * Returns TRUE if the packet is valid, FALSE otherwise.
6933 is_valid_arp_packet(mbuf_t
*data
, boolean_t is_output
,
6934 struct ether_header
**eh_p
, struct ether_arp
**ea_p
)
6936 struct ether_arp
*ea
;
6937 struct ether_header
*eh
;
6938 size_t minlen
= sizeof(struct ether_header
) + sizeof(struct ether_arp
);
6939 boolean_t is_valid
= FALSE
;
6940 int flags
= is_output
? BR_DBGF_OUTPUT
: BR_DBGF_INPUT
;
6942 if (mbuf_pkthdr_len(*data
) < minlen
) {
6943 if (IF_BRIDGE_DEBUG(flags
)) {
6944 printf("%s: ARP %s short frame %lu < %lu\n",
6946 get_in_out_string(is_output
),
6947 mbuf_pkthdr_len(*data
), minlen
);
6951 if (mbuf_len(*data
) < minlen
&& mbuf_pullup(data
, minlen
) != 0) {
6952 if (IF_BRIDGE_DEBUG(flags
)) {
6953 printf("%s: ARP %s size %lu mbuf_pullup fail\n",
6955 get_in_out_string(is_output
),
6962 /* validate ARP packet */
6963 eh
= mtod(*data
, struct ether_header
*);
6964 ea
= (struct ether_arp
*)(eh
+ 1);
6965 if (ntohs(ea
->arp_hrd
) != ARPHRD_ETHER
) {
6966 if (IF_BRIDGE_DEBUG(flags
)) {
6967 printf("%s: ARP %s htype not ethernet\n",
6969 get_in_out_string(is_output
));
6973 if (ea
->arp_hln
!= ETHER_ADDR_LEN
) {
6974 if (IF_BRIDGE_DEBUG(flags
)) {
6975 printf("%s: ARP %s hlen not ethernet\n",
6977 get_in_out_string(is_output
));
6981 if (ntohs(ea
->arp_pro
) != ETHERTYPE_IP
) {
6982 if (IF_BRIDGE_DEBUG(flags
)) {
6983 printf("%s: ARP %s ptype not IP\n",
6985 get_in_out_string(is_output
));
6989 if (ea
->arp_pln
!= sizeof(struct in_addr
)) {
6990 if (IF_BRIDGE_DEBUG(flags
)) {
6991 printf("%s: ARP %s plen not IP\n",
6993 get_in_out_string(is_output
));
7004 static struct mac_nat_entry
*
7005 bridge_mac_nat_arp_input(struct bridge_softc
*sc
, mbuf_t
*data
)
7007 struct ether_arp
*ea
;
7008 struct ether_header
*eh
;
7009 struct mac_nat_entry
*mne
= NULL
;
7013 if (!is_valid_arp_packet(data
, FALSE
, &eh
, &ea
)) {
7016 op
= ntohs(ea
->arp_op
);
7020 /* only care about REQUEST and REPLY */
7026 /* check the target IP address for a NAT entry */
7027 bcopy(ea
->arp_tpa
, &tpa
, sizeof(tpa
));
7028 if (tpa
.s_addr
!= 0) {
7029 mne
= bridge_lookup_mac_nat_entry(sc
, AF_INET
, &tpa
);
7032 if (op
== ARPOP_REPLY
) {
7033 /* translate the MAC address */
7034 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7038 ether_ntop(mac_src
, sizeof(mac_src
),
7040 ether_ntop(mac_dst
, sizeof(mac_dst
),
7042 printf("%s %s ARP %s -> %s\n",
7044 mne
->mne_bif
->bif_ifp
->if_xname
,
7047 bcopy(mne
->mne_mac
, ea
->arp_tha
, sizeof(ea
->arp_tha
));
7050 /* handle conflicting ARP (sender matches mne) */
7053 bcopy(ea
->arp_spa
, &spa
, sizeof(spa
));
7054 if (spa
.s_addr
!= 0 && spa
.s_addr
!= tpa
.s_addr
) {
7055 /* check the source IP for a NAT entry */
7056 mne
= bridge_lookup_mac_nat_entry(sc
, AF_INET
, &spa
);
7065 bridge_mac_nat_arp_output(struct bridge_softc
*sc
,
7066 struct bridge_iflist
*bif
, mbuf_t
*data
, struct mac_nat_record
*mnr
)
7068 struct ether_arp
*ea
;
7069 struct ether_header
*eh
;
7071 struct mac_nat_entry
*mne
= NULL
;
7073 boolean_t translate
= FALSE
;
7075 if (!is_valid_arp_packet(data
, TRUE
, &eh
, &ea
)) {
7078 op
= ntohs(ea
->arp_op
);
7082 /* only care about REQUEST and REPLY */
7088 bcopy(ea
->arp_spa
, &ip
, sizeof(ip
));
7089 if (ip
.s_addr
== 0) {
7092 /* XXX validate IP address: no multicast/broadcast */
7093 mne
= bridge_update_mac_nat_entry(sc
, bif
, AF_INET
, &ip
, ea
->arp_sha
);
7094 if (mnr
!= NULL
&& mne
!= NULL
) {
7095 /* record the offset to do the replacement */
7097 mnr
->mnr_arp_offset
= (char *)ea
->arp_sha
- (char *)eh
;
7104 #define ETHER_IPV4_HEADER_LEN (sizeof(struct ether_header) + \
7105 + sizeof(struct ip))
7106 static struct ether_header
*
7107 get_ether_ip_header(mbuf_t
*data
, boolean_t is_output
)
7109 struct ether_header
*eh
= NULL
;
7110 int flags
= is_output
? BR_DBGF_OUTPUT
: BR_DBGF_INPUT
;
7111 size_t minlen
= ETHER_IPV4_HEADER_LEN
;
7113 if (mbuf_pkthdr_len(*data
) < minlen
) {
7114 if (IF_BRIDGE_DEBUG(flags
)) {
7115 printf("%s: IP %s short frame %lu < %lu\n",
7117 get_in_out_string(is_output
),
7118 mbuf_pkthdr_len(*data
), minlen
);
7122 if (mbuf_len(*data
) < minlen
&& mbuf_pullup(data
, minlen
) != 0) {
7123 if (IF_BRIDGE_DEBUG(flags
)) {
7124 printf("%s: IP %s size %lu mbuf_pullup fail\n",
7126 get_in_out_string(is_output
),
7132 eh
= mtod(*data
, struct ether_header
*);
7138 is_broadcast_ip_packet(mbuf_t
*data
)
7140 struct ether_header
*eh
;
7141 uint16_t ether_type
;
7142 boolean_t is_broadcast
= FALSE
;
7144 eh
= mtod(*data
, struct ether_header
*);
7145 ether_type
= ntohs(eh
->ether_type
);
7146 switch (ether_type
) {
7148 eh
= get_ether_ip_header(data
, FALSE
);
7153 iphdr
= (struct ip
*)(void *)(eh
+ 1);
7154 bcopy(&iphdr
->ip_dst
, &dst
, sizeof(dst
));
7155 is_broadcast
= (dst
.s_addr
== INADDR_BROADCAST
);
7161 return is_broadcast
;
7164 static struct mac_nat_entry
*
7165 bridge_mac_nat_ip_input(struct bridge_softc
*sc
, mbuf_t
*data
)
7168 struct ether_header
*eh
;
7170 struct mac_nat_entry
*mne
= NULL
;
7172 eh
= get_ether_ip_header(data
, FALSE
);
7176 iphdr
= (struct ip
*)(void *)(eh
+ 1);
7177 bcopy(&iphdr
->ip_dst
, &dst
, sizeof(dst
));
7178 /* XXX validate IP address */
7179 if (dst
.s_addr
== 0) {
7182 mne
= bridge_lookup_mac_nat_entry(sc
, AF_INET
, &dst
);
7188 bridge_mac_nat_udp_output(struct bridge_softc
*sc
,
7189 struct bridge_iflist
*bif
, mbuf_t m
,
7190 uint8_t ip_header_len
, struct mac_nat_record
*mnr
)
7195 struct udphdr udphdr
;
7197 /* copy the UDP header */
7198 offset
= sizeof(struct ether_header
) + ip_header_len
;
7199 error
= mbuf_copydata(m
, offset
, sizeof(struct udphdr
), &udphdr
);
7201 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7202 printf("%s: mbuf_copydata udphdr failed %d",
7207 if (ntohs(udphdr
.uh_sport
) != IPPORT_BOOTPC
||
7208 ntohs(udphdr
.uh_dport
) != IPPORT_BOOTPS
) {
7209 /* not a BOOTP/DHCP packet */
7212 /* check whether the broadcast bit is already set */
7213 offset
+= sizeof(struct udphdr
) + offsetof(struct dhcp
, dp_flags
);
7214 error
= mbuf_copydata(m
, offset
, sizeof(dp_flags
), &dp_flags
);
7216 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7217 printf("%s: mbuf_copydata dp_flags failed %d",
7222 if ((ntohs(dp_flags
) & DHCP_FLAGS_BROADCAST
) != 0) {
7223 /* it's already set, nothing to do */
7226 /* broadcast bit needs to be set */
7227 mnr
->mnr_ip_dhcp_flags
= dp_flags
| htons(DHCP_FLAGS_BROADCAST
);
7228 mnr
->mnr_ip_header_len
= ip_header_len
;
7229 if (udphdr
.uh_sum
!= 0) {
7232 /* adjust checksum to take modified dp_flags into account */
7233 delta
= dp_flags
- mnr
->mnr_ip_dhcp_flags
;
7234 mnr
->mnr_ip_udp_csum
= udphdr
.uh_sum
+ delta
;
7236 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7237 printf("%s %s DHCP dp_flags 0x%x UDP cksum 0x%x\n",
7239 bif
->bif_ifp
->if_xname
,
7240 ntohs(mnr
->mnr_ip_dhcp_flags
),
7241 ntohs(mnr
->mnr_ip_udp_csum
));
7247 bridge_mac_nat_ip_output(struct bridge_softc
*sc
,
7248 struct bridge_iflist
*bif
, mbuf_t
*data
, struct mac_nat_record
*mnr
)
7251 struct ether_header
*eh
;
7254 uint8_t ip_header_len
;
7255 struct mac_nat_entry
*mne
= NULL
;
7256 boolean_t translate
= FALSE
;
7258 eh
= get_ether_ip_header(data
, TRUE
);
7262 iphdr
= (struct ip
*)(void *)(eh
+ 1);
7263 ip_header_len
= IP_VHL_HL(iphdr
->ip_vhl
) << 2;
7264 if (ip_header_len
< sizeof(ip
)) {
7265 /* bogus IP header */
7268 bcopy(&iphdr
->ip_src
, &ip
, sizeof(ip
));
7269 /* XXX validate the source address */
7270 if (ip
.s_addr
!= 0) {
7271 mne
= bridge_update_mac_nat_entry(sc
, bif
, AF_INET
, &ip
,
7275 if (iphdr
->ip_p
== IPPROTO_UDP
) {
7276 /* handle DHCP must broadcast */
7277 bridge_mac_nat_udp_output(sc
, bif
, *data
,
7278 ip_header_len
, mnr
);
7286 #define ETHER_IPV6_HEADER_LEN (sizeof(struct ether_header) + \
7287 + sizeof(struct ip6_hdr))
7288 static struct ether_header
*
7289 get_ether_ipv6_header(mbuf_t
*data
, boolean_t is_output
)
7291 struct ether_header
*eh
= NULL
;
7292 int flags
= is_output
? BR_DBGF_OUTPUT
: BR_DBGF_INPUT
;
7293 size_t minlen
= ETHER_IPV6_HEADER_LEN
;
7295 if (mbuf_pkthdr_len(*data
) < minlen
) {
7296 if (IF_BRIDGE_DEBUG(flags
)) {
7297 printf("%s: IP %s short frame %lu < %lu\n",
7299 get_in_out_string(is_output
),
7300 mbuf_pkthdr_len(*data
), minlen
);
7304 if (mbuf_len(*data
) < minlen
&& mbuf_pullup(data
, minlen
) != 0) {
7305 if (IF_BRIDGE_DEBUG(flags
)) {
7306 printf("%s: IP %s size %lu mbuf_pullup fail\n",
7308 get_in_out_string(is_output
),
7314 eh
= mtod(*data
, struct ether_header
*);
7319 #include <netinet/icmp6.h>
7320 #include <netinet6/nd6.h>
7322 #define ETHER_ND_LLADDR_LEN (ETHER_ADDR_LEN + sizeof(struct nd_opt_hdr))
7325 bridge_mac_nat_icmpv6_output(struct bridge_softc
*sc
, struct bridge_iflist
*bif
,
7326 mbuf_t
*data
, struct ether_header
*eh
,
7327 struct ip6_hdr
*ip6h
, struct in6_addr
*saddrp
, struct mac_nat_record
*mnr
)
7329 struct icmp6_hdr
*icmp6
;
7330 unsigned int icmp6len
;
7332 char *lladdr
= NULL
;
7334 unsigned int off
= sizeof(*ip6h
);
7336 icmp6len
= m
->m_pkthdr
.len
- sizeof(*eh
) - off
;
7337 if (icmp6len
< sizeof(*icmp6
)) {
7338 printf("%s: short packet %d < %lu\n", __func__
,
7339 icmp6len
, sizeof(*icmp6
));
7342 icmp6
= (struct icmp6_hdr
*)((caddr_t
)ip6h
+ off
);
7343 switch (icmp6
->icmp6_type
) {
7344 case ND_NEIGHBOR_SOLICIT
: {
7345 struct nd_neighbor_solicit
*nd_ns
;
7346 union nd_opts ndopts
;
7347 boolean_t is_dad_probe
;
7348 struct in6_addr taddr
;
7350 if (icmp6len
< sizeof(*nd_ns
)) {
7351 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7352 printf("%s: short nd_ns %d < %lu\n", __func__
,
7353 icmp6len
, sizeof(*nd_ns
));
7358 nd_ns
= (struct nd_neighbor_solicit
*)(void *)icmp6
;
7359 bcopy(&nd_ns
->nd_ns_target
, &taddr
, sizeof(taddr
));
7360 if (IN6_IS_ADDR_MULTICAST(&taddr
) ||
7361 IN6_IS_ADDR_UNSPECIFIED(&taddr
)) {
7362 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7363 printf("%s: invalid target ignored\n", __func__
);
7368 nd6_option_init(nd_ns
+ 1, icmp6len
- sizeof(*nd_ns
), &ndopts
);
7369 if (nd6_options(&ndopts
) < 0) {
7370 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7371 printf("%s: invalid ND6 NS option\n", __func__
);
7375 if (ndopts
.nd_opts_src_lladdr
!= NULL
) {
7376 lladdr
= (char *)(ndopts
.nd_opts_src_lladdr
+ 1);
7377 lladdrlen
= ndopts
.nd_opts_src_lladdr
->nd_opt_len
<< 3;
7379 is_dad_probe
= IN6_IS_ADDR_UNSPECIFIED(saddrp
);
7380 if (lladdr
!= NULL
) {
7382 printf("%s: bad ND6 DAD packet\n", __func__
);
7385 if (lladdrlen
!= ETHER_ND_LLADDR_LEN
) {
7386 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7387 printf("%s: source lladdrlen %d != %lu\n",
7389 lladdrlen
, ETHER_ND_LLADDR_LEN
);
7393 mnr
->mnr_ip6_lladdr_offset
= (void *)lladdr
-
7395 mnr
->mnr_ip6_icmp6_len
= icmp6len
;
7396 mnr
->mnr_ip6_icmp6_type
= icmp6
->icmp6_type
;
7397 mnr
->mnr_ip6_header_len
= off
;
7400 /* node is trying use taddr, create an mne using taddr */
7405 case ND_NEIGHBOR_ADVERT
: {
7406 struct nd_neighbor_advert
*nd_na
;
7407 union nd_opts ndopts
;
7408 struct in6_addr taddr
;
7411 nd_na
= (struct nd_neighbor_advert
*)(void *)icmp6
;
7413 if (icmp6len
< sizeof(*nd_na
)) {
7414 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7415 printf("%s: short nd_na %d < %lu\n", __func__
,
7416 icmp6len
, sizeof(*nd_na
));
7421 bcopy(&nd_na
->nd_na_target
, &taddr
, sizeof(taddr
));
7422 if (IN6_IS_ADDR_MULTICAST(&taddr
) ||
7423 IN6_IS_ADDR_UNSPECIFIED(&taddr
)) {
7424 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7425 printf("%s: invalid target ignored\n", __func__
);
7430 nd6_option_init(nd_na
+ 1, icmp6len
- sizeof(*nd_na
), &ndopts
);
7431 if (nd6_options(&ndopts
) < 0) {
7432 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7433 printf("%s: invalid ND6 NA option\n", __func__
);
7437 if (ndopts
.nd_opts_tgt_lladdr
== NULL
) {
7438 /* target linklayer, nothing to do */
7441 lladdr
= (char *)(ndopts
.nd_opts_tgt_lladdr
+ 1);
7442 lladdrlen
= ndopts
.nd_opts_tgt_lladdr
->nd_opt_len
<< 3;
7443 if (lladdrlen
!= ETHER_ND_LLADDR_LEN
) {
7444 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7445 printf("%s: target lladdrlen %d != %lu\n",
7446 __func__
, lladdrlen
, ETHER_ND_LLADDR_LEN
);
7450 mnr
->mnr_ip6_lladdr_offset
= (void *)lladdr
- (void *)eh
;
7451 mnr
->mnr_ip6_icmp6_len
= icmp6len
;
7452 mnr
->mnr_ip6_header_len
= off
;
7453 mnr
->mnr_ip6_icmp6_type
= icmp6
->icmp6_type
;
7456 case ND_ROUTER_SOLICIT
: {
7457 struct nd_router_solicit
*nd_rs
;
7458 union nd_opts ndopts
;
7460 if (icmp6len
< sizeof(*nd_rs
)) {
7461 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7462 printf("%s: short nd_rs %d < %lu\n", __func__
,
7463 icmp6len
, sizeof(*nd_rs
));
7467 nd_rs
= (struct nd_router_solicit
*)(void *)icmp6
;
7470 nd6_option_init(nd_rs
+ 1, icmp6len
- sizeof(*nd_rs
), &ndopts
);
7471 if (nd6_options(&ndopts
) < 0) {
7472 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7473 printf("%s: invalid ND6 RS option\n", __func__
);
7477 if (ndopts
.nd_opts_src_lladdr
!= NULL
) {
7478 lladdr
= (char *)(ndopts
.nd_opts_src_lladdr
+ 1);
7479 lladdrlen
= ndopts
.nd_opts_src_lladdr
->nd_opt_len
<< 3;
7481 if (lladdr
!= NULL
) {
7482 if (lladdrlen
!= ETHER_ND_LLADDR_LEN
) {
7483 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7484 printf("%s: source lladdrlen %d != %lu\n",
7486 lladdrlen
, ETHER_ND_LLADDR_LEN
);
7490 mnr
->mnr_ip6_lladdr_offset
= (void *)lladdr
-
7492 mnr
->mnr_ip6_icmp6_len
= icmp6len
;
7493 mnr
->mnr_ip6_icmp6_type
= icmp6
->icmp6_type
;
7494 mnr
->mnr_ip6_header_len
= off
;
7501 if (mnr
->mnr_ip6_lladdr_offset
!= 0 &&
7502 IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT
)) {
7505 switch (mnr
->mnr_ip6_icmp6_type
) {
7506 case ND_ROUTER_SOLICIT
:
7507 str
= "ROUTER SOLICIT";
7509 case ND_NEIGHBOR_ADVERT
:
7510 str
= "NEIGHBOR ADVERT";
7512 case ND_NEIGHBOR_SOLICIT
:
7513 str
= "NEIGHBOR SOLICIT";
7519 printf("%s %s %s ip6len %d icmp6len %d lladdr offset %d\n",
7520 sc
->sc_if_xname
, bif
->bif_ifp
->if_xname
, str
,
7521 mnr
->mnr_ip6_header_len
,
7522 mnr
->mnr_ip6_icmp6_len
, mnr
->mnr_ip6_lladdr_offset
);
7526 static struct mac_nat_entry
*
7527 bridge_mac_nat_ipv6_input(struct bridge_softc
*sc
, mbuf_t
*data
)
7529 struct in6_addr dst
;
7530 struct ether_header
*eh
;
7531 struct ip6_hdr
*ip6h
;
7532 struct mac_nat_entry
*mne
= NULL
;
7534 eh
= get_ether_ipv6_header(data
, FALSE
);
7538 ip6h
= (struct ip6_hdr
*)(void *)(eh
+ 1);
7539 bcopy(&ip6h
->ip6_dst
, &dst
, sizeof(dst
));
7540 /* XXX validate IPv6 address */
7541 if (IN6_IS_ADDR_UNSPECIFIED(&dst
)) {
7544 mne
= bridge_lookup_mac_nat_entry(sc
, AF_INET6
, &dst
);
7551 bridge_mac_nat_ipv6_output(struct bridge_softc
*sc
,
7552 struct bridge_iflist
*bif
, mbuf_t
*data
, struct mac_nat_record
*mnr
)
7554 struct ether_header
*eh
;
7555 struct ip6_hdr
*ip6h
;
7556 struct in6_addr saddr
;
7557 boolean_t translate
;
7559 translate
= (bif
== sc
->sc_mac_nat_bif
) ? FALSE
: TRUE
;
7560 eh
= get_ether_ipv6_header(data
, TRUE
);
7565 ip6h
= (struct ip6_hdr
*)(void *)(eh
+ 1);
7566 bcopy(&ip6h
->ip6_src
, &saddr
, sizeof(saddr
));
7567 if (mnr
!= NULL
&& ip6h
->ip6_nxt
== IPPROTO_ICMPV6
) {
7568 bridge_mac_nat_icmpv6_output(sc
, bif
, data
,
7569 eh
, ip6h
, &saddr
, mnr
);
7571 if (IN6_IS_ADDR_UNSPECIFIED(&saddr
)) {
7574 (void)bridge_update_mac_nat_entry(sc
, bif
, AF_INET6
, &saddr
,
7582 * bridge_mac_nat_input:
7583 * Process a packet arriving on the MAC NAT interface (sc_mac_nat_bif).
7584 * This interface is the "external" interface with respect to NAT.
7585 * The interface is only capable of receiving a single MAC address
7586 * (e.g. a Wi-Fi STA interface).
7588 * When a packet arrives on the external interface, look up the destination
7589 * IP address in the mac_nat_entry table. If there is a match, *is_input
7590 * is set to TRUE if it's for the MAC NAT interface, otherwise *is_input
7591 * is set to FALSE and translate the MAC address if necessary.
7594 * The internal interface to direct the packet to, or NULL if the packet
7595 * should not be redirected.
7597 * *data may be updated to point at a different mbuf chain, or set to NULL
7598 * if the chain was deallocated during processing.
7601 bridge_mac_nat_input(struct bridge_softc
*sc
, mbuf_t
*data
,
7602 boolean_t
*is_input
)
7604 ifnet_t dst_if
= NULL
;
7605 struct ether_header
*eh
;
7606 uint16_t ether_type
;
7607 boolean_t is_unicast
;
7609 struct mac_nat_entry
*mne
= NULL
;
7611 BRIDGE_LOCK_ASSERT_HELD(sc
);
7613 assert(sc
->sc_mac_nat_bif
!= NULL
);
7614 is_unicast
= ((m
->m_flags
& (M_BCAST
| M_MCAST
)) == 0);
7615 eh
= mtod(m
, struct ether_header
*);
7616 ether_type
= ntohs(eh
->ether_type
);
7617 switch (ether_type
) {
7619 mne
= bridge_mac_nat_arp_input(sc
, data
);
7623 mne
= bridge_mac_nat_ip_input(sc
, data
);
7626 case ETHERTYPE_IPV6
:
7628 mne
= bridge_mac_nat_ipv6_input(sc
, data
);
7637 /* it may have changed */
7638 eh
= mtod(*data
, struct ether_header
*);
7640 bcopy(mne
->mne_mac
, eh
->ether_dhost
,
7641 sizeof(eh
->ether_dhost
));
7643 dst_if
= mne
->mne_bif
->bif_ifp
;
7644 *is_input
= (mne
->mne_bif
== sc
->sc_mac_nat_bif
);
7650 * bridge_mac_nat_output:
7651 * Process a packet destined to the MAC NAT interface (sc_mac_nat_bif)
7652 * from the interface 'bif'.
7654 * Create a mac_nat_entry containing the source IP address and MAC address
7655 * from the packet. Populate a mac_nat_record with information detailing
7656 * how to translate the packet. Translation takes place later when
7657 * the bridge lock is no longer held.
7659 * If 'bif' == sc_mac_nat_bif, the stack over the MAC NAT
7660 * interface is generating an output packet. No translation is required in this
7661 * case, we just record the IP address used to prevent another bif from
7662 * claiming our IP address.
7665 * TRUE if the packet should be translated (*mnr updated as well),
7668 * *data may be updated to point at a different mbuf chain or NULL if
7669 * the chain was deallocated during processing.
7673 bridge_mac_nat_output(struct bridge_softc
*sc
,
7674 struct bridge_iflist
*bif
, mbuf_t
*data
, struct mac_nat_record
*mnr
)
7676 struct ether_header
*eh
;
7677 uint16_t ether_type
;
7678 boolean_t translate
= FALSE
;
7680 BRIDGE_LOCK_ASSERT_HELD(sc
);
7681 assert(sc
->sc_mac_nat_bif
!= NULL
);
7683 eh
= mtod(*data
, struct ether_header
*);
7684 ether_type
= ntohs(eh
->ether_type
);
7686 bzero(mnr
, sizeof(*mnr
));
7687 mnr
->mnr_ether_type
= ether_type
;
7689 switch (ether_type
) {
7691 translate
= bridge_mac_nat_arp_output(sc
, bif
, data
, mnr
);
7694 translate
= bridge_mac_nat_ip_output(sc
, bif
, data
, mnr
);
7696 case ETHERTYPE_IPV6
:
7697 translate
= bridge_mac_nat_ipv6_output(sc
, bif
, data
, mnr
);
7706 bridge_mac_nat_arp_translate(mbuf_t
*data
, struct mac_nat_record
*mnr
,
7707 const caddr_t eaddr
)
7711 if (mnr
->mnr_arp_offset
== 0) {
7714 /* replace the source hardware address */
7715 error
= mbuf_copyback(*data
, mnr
->mnr_arp_offset
,
7716 ETHER_ADDR_LEN
, eaddr
,
7719 printf("%s: mbuf_copyback failed\n",
7728 bridge_mac_nat_ip_translate(mbuf_t
*data
, struct mac_nat_record
*mnr
)
7733 if (mnr
->mnr_ip_header_len
== 0) {
7736 /* update the UDP checksum */
7737 offset
= sizeof(struct ether_header
) + mnr
->mnr_ip_header_len
;
7738 error
= mbuf_copyback(*data
, offset
+ offsetof(struct udphdr
, uh_sum
),
7739 sizeof(mnr
->mnr_ip_udp_csum
),
7740 &mnr
->mnr_ip_udp_csum
,
7743 printf("%s: mbuf_copyback uh_sum failed\n",
7748 /* update the DHCP must broadcast flag */
7749 offset
+= sizeof(struct udphdr
);
7750 error
= mbuf_copyback(*data
, offset
+ offsetof(struct dhcp
, dp_flags
),
7751 sizeof(mnr
->mnr_ip_dhcp_flags
),
7752 &mnr
->mnr_ip_dhcp_flags
,
7755 printf("%s: mbuf_copyback dp_flags failed\n",
7763 bridge_mac_nat_ipv6_translate(mbuf_t
*data
, struct mac_nat_record
*mnr
,
7764 const caddr_t eaddr
)
7770 if (mnr
->mnr_ip6_header_len
== 0) {
7773 switch (mnr
->mnr_ip6_icmp6_type
) {
7774 case ND_ROUTER_SOLICIT
:
7775 case ND_NEIGHBOR_SOLICIT
:
7776 case ND_NEIGHBOR_ADVERT
:
7777 if (mnr
->mnr_ip6_lladdr_offset
== 0) {
7787 * replace the lladdr
7789 error
= mbuf_copyback(m
, mnr
->mnr_ip6_lladdr_offset
,
7790 ETHER_ADDR_LEN
, eaddr
,
7793 printf("%s: mbuf_copyback lladdr failed\n",
7801 * recompute the icmp6 checksum
7804 /* skip past the ethernet header */
7805 mbuf_setdata(m
, (char *)mbuf_data(m
) + ETHER_HDR_LEN
,
7806 mbuf_len(m
) - ETHER_HDR_LEN
);
7807 mbuf_pkthdr_adjustlen(m
, -ETHER_HDR_LEN
);
7809 #define CKSUM_OFFSET_ICMP6 offsetof(struct icmp6_hdr, icmp6_cksum)
7810 /* set the checksum to zero */
7812 error
= mbuf_copyback(m
, mnr
->mnr_ip6_header_len
+ CKSUM_OFFSET_ICMP6
,
7813 sizeof(cksum
), &cksum
, MBUF_DONTWAIT
);
7815 printf("%s: mbuf_copyback cksum=0 failed\n",
7821 /* compute and set the new checksum */
7822 cksum
= in6_cksum(m
, IPPROTO_ICMPV6
, mnr
->mnr_ip6_header_len
,
7823 mnr
->mnr_ip6_icmp6_len
);
7824 error
= mbuf_copyback(m
, mnr
->mnr_ip6_header_len
+ CKSUM_OFFSET_ICMP6
,
7825 sizeof(cksum
), &cksum
, MBUF_DONTWAIT
);
7827 printf("%s: mbuf_copyback cksum failed\n",
7833 /* restore the ethernet header */
7834 mbuf_setdata(m
, (char *)mbuf_data(m
) - ETHER_HDR_LEN
,
7835 mbuf_len(m
) + ETHER_HDR_LEN
);
7836 mbuf_pkthdr_adjustlen(m
, ETHER_HDR_LEN
);
7841 bridge_mac_nat_translate(mbuf_t
*data
, struct mac_nat_record
*mnr
,
7842 const caddr_t eaddr
)
7844 struct ether_header
*eh
;
7846 /* replace the source ethernet address with the single MAC */
7847 eh
= mtod(*data
, struct ether_header
*);
7848 bcopy(eaddr
, eh
->ether_shost
, sizeof(eh
->ether_shost
));
7849 switch (mnr
->mnr_ether_type
) {
7851 bridge_mac_nat_arp_translate(data
, mnr
, eaddr
);
7855 bridge_mac_nat_ip_translate(data
, mnr
);
7858 case ETHERTYPE_IPV6
:
7859 bridge_mac_nat_ipv6_translate(data
, mnr
, eaddr
);
7869 * bridge packet filtering
7873 * Perform basic checks on header size since
7874 * pfil assumes ip_input has already processed
7875 * it for it. Cut-and-pasted from ip_input.c.
7876 * Given how simple the IPv6 version is,
7877 * does the IPv4 version really need to be
7880 * XXX Should we update ipstat here, or not?
7881 * XXX Right now we update ipstat but not
7885 bridge_ip_checkbasic(struct mbuf
**mp
)
7887 struct mbuf
*m
= *mp
;
7896 if (IP_HDR_ALIGNED_P(mtod(m
, caddr_t
)) == 0) {
7897 /* max_linkhdr is already rounded up to nearest 4-byte */
7898 if ((m
= m_copyup(m
, sizeof(struct ip
),
7899 max_linkhdr
)) == NULL
) {
7900 /* XXXJRT new stat, please */
7901 ipstat
.ips_toosmall
++;
7904 } else if (OS_EXPECT((size_t)m
->m_len
< sizeof(struct ip
), 0)) {
7905 if ((m
= m_pullup(m
, sizeof(struct ip
))) == NULL
) {
7906 ipstat
.ips_toosmall
++;
7910 ip
= mtod(m
, struct ip
*);
7915 if (IP_VHL_V(ip
->ip_vhl
) != IPVERSION
) {
7916 ipstat
.ips_badvers
++;
7919 hlen
= IP_VHL_HL(ip
->ip_vhl
) << 2;
7920 if (hlen
< (int)sizeof(struct ip
)) { /* minimum header length */
7921 ipstat
.ips_badhlen
++;
7924 if (hlen
> m
->m_len
) {
7925 if ((m
= m_pullup(m
, hlen
)) == 0) {
7926 ipstat
.ips_badhlen
++;
7929 ip
= mtod(m
, struct ip
*);
7935 if (m
->m_pkthdr
.csum_flags
& CSUM_IP_CHECKED
) {
7936 sum
= !(m
->m_pkthdr
.csum_flags
& CSUM_IP_VALID
);
7938 if (hlen
== sizeof(struct ip
)) {
7939 sum
= in_cksum_hdr(ip
);
7941 sum
= in_cksum(m
, hlen
);
7945 ipstat
.ips_badsum
++;
7949 /* Retrieve the packet length. */
7950 len
= ntohs(ip
->ip_len
);
7953 * Check for additional length bogosity
7956 ipstat
.ips_badlen
++;
7961 * Check that the amount of data in the buffers
7962 * is as at least much as the IP header would have us expect.
7963 * Drop packet if shorter than we expect.
7965 if (m
->m_pkthdr
.len
< len
) {
7966 ipstat
.ips_tooshort
++;
7970 /* Checks out, proceed */
7980 * Same as above, but for IPv6.
7981 * Cut-and-pasted from ip6_input.c.
7982 * XXX Should we update ip6stat, or not?
7985 bridge_ip6_checkbasic(struct mbuf
**mp
)
7987 struct mbuf
*m
= *mp
;
7988 struct ip6_hdr
*ip6
;
7991 * If the IPv6 header is not aligned, slurp it up into a new
7992 * mbuf with space for link headers, in the event we forward
7993 * it. Otherwise, if it is aligned, make sure the entire base
7994 * IPv6 header is in the first mbuf of the chain.
7996 if (IP6_HDR_ALIGNED_P(mtod(m
, caddr_t
)) == 0) {
7997 struct ifnet
*inifp
= m
->m_pkthdr
.rcvif
;
7998 /* max_linkhdr is already rounded up to nearest 4-byte */
7999 if ((m
= m_copyup(m
, sizeof(struct ip6_hdr
),
8000 max_linkhdr
)) == NULL
) {
8001 /* XXXJRT new stat, please */
8002 ip6stat
.ip6s_toosmall
++;
8003 in6_ifstat_inc(inifp
, ifs6_in_hdrerr
);
8006 } else if (OS_EXPECT((size_t)m
->m_len
< sizeof(struct ip6_hdr
), 0)) {
8007 struct ifnet
*inifp
= m
->m_pkthdr
.rcvif
;
8008 if ((m
= m_pullup(m
, sizeof(struct ip6_hdr
))) == NULL
) {
8009 ip6stat
.ip6s_toosmall
++;
8010 in6_ifstat_inc(inifp
, ifs6_in_hdrerr
);
8015 ip6
= mtod(m
, struct ip6_hdr
*);
8017 if ((ip6
->ip6_vfc
& IPV6_VERSION_MASK
) != IPV6_VERSION
) {
8018 ip6stat
.ip6s_badvers
++;
8019 in6_ifstat_inc(m
->m_pkthdr
.rcvif
, ifs6_in_hdrerr
);
8023 /* Checks out, proceed */
8033 * the PF routines expect to be called from ip_input, so we
8034 * need to do and undo here some of the same processing.
8036 * XXX : this is heavily inspired on bridge_pfil()
8039 bridge_pf(struct mbuf
**mp
, struct ifnet
*ifp
, uint32_t sc_filter_flags
,
8043 * XXX : mpetit : heavily inspired by bridge_pfil()
8046 int snap
, error
, i
, hlen
;
8047 struct ether_header
*eh1
, eh2
;
8050 u_int16_t ether_type
;
8053 error
= -1; /* Default error if not error == 0 */
8055 if ((sc_filter_flags
& IFBF_FILT_MEMBER
) == 0) {
8056 return 0; /* filtering is disabled */
8058 i
= min((*mp
)->m_pkthdr
.len
, max_protohdr
);
8059 if ((*mp
)->m_len
< i
) {
8060 *mp
= m_pullup(*mp
, i
);
8062 printf("%s: m_pullup failed\n", __func__
);
8067 eh1
= mtod(*mp
, struct ether_header
*);
8068 ether_type
= ntohs(eh1
->ether_type
);
8071 * Check for SNAP/LLC.
8073 if (ether_type
< ETHERMTU
) {
8074 struct llc
*llc2
= (struct llc
*)(eh1
+ 1);
8076 if ((*mp
)->m_len
>= ETHER_HDR_LEN
+ 8 &&
8077 llc2
->llc_dsap
== LLC_SNAP_LSAP
&&
8078 llc2
->llc_ssap
== LLC_SNAP_LSAP
&&
8079 llc2
->llc_control
== LLC_UI
) {
8080 ether_type
= htons(llc2
->llc_un
.type_snap
.ether_type
);
8086 * If we're trying to filter bridge traffic, don't look at anything
8087 * other than IP and ARP traffic. If the filter doesn't understand
8088 * IPv6, don't allow IPv6 through the bridge either. This is lame
8089 * since if we really wanted, say, an AppleTalk filter, we are hosed,
8090 * but of course we don't have an AppleTalk filter to begin with.
8091 * (Note that since pfil doesn't understand ARP it will pass *ALL*
8094 switch (ether_type
) {
8096 case ETHERTYPE_REVARP
:
8097 return 0; /* Automatically pass */
8100 case ETHERTYPE_IPV6
:
8104 * Check to see if the user wants to pass non-ip
8105 * packets, these will not be checked by pf and
8106 * passed unconditionally so the default is to drop.
8108 if ((sc_filter_flags
& IFBF_FILT_ONLYIP
)) {
8114 /* Strip off the Ethernet header and keep a copy. */
8115 m_copydata(*mp
, 0, ETHER_HDR_LEN
, (caddr_t
)&eh2
);
8116 m_adj(*mp
, ETHER_HDR_LEN
);
8118 /* Strip off snap header, if present */
8120 m_copydata(*mp
, 0, sizeof(struct llc
), (caddr_t
)&llc1
);
8121 m_adj(*mp
, sizeof(struct llc
));
8125 * Check the IP header for alignment and errors
8127 switch (ether_type
) {
8129 error
= bridge_ip_checkbasic(mp
);
8131 case ETHERTYPE_IPV6
:
8132 error
= bridge_ip6_checkbasic(mp
);
8145 * Run the packet through pf rules
8147 switch (ether_type
) {
8150 * before calling the firewall, swap fields the same as
8151 * IP does. here we assume the header is contiguous
8153 ip
= mtod(*mp
, struct ip
*);
8155 ip
->ip_len
= ntohs(ip
->ip_len
);
8156 ip
->ip_off
= ntohs(ip
->ip_off
);
8159 error
= pf_af_hook(ifp
, 0, mp
, AF_INET
, input
, NULL
);
8162 if (*mp
== NULL
|| error
!= 0) { /* filter may consume */
8166 /* Recalculate the ip checksum and restore byte ordering */
8167 ip
= mtod(*mp
, struct ip
*);
8168 hlen
= IP_VHL_HL(ip
->ip_vhl
) << 2;
8169 if (hlen
< (int)sizeof(struct ip
)) {
8172 if (hlen
> (*mp
)->m_len
) {
8173 if ((*mp
= m_pullup(*mp
, hlen
)) == 0) {
8176 ip
= mtod(*mp
, struct ip
*);
8181 ip
->ip_len
= htons(ip
->ip_len
);
8182 ip
->ip_off
= htons(ip
->ip_off
);
8184 if (hlen
== sizeof(struct ip
)) {
8185 ip
->ip_sum
= in_cksum_hdr(ip
);
8187 ip
->ip_sum
= in_cksum(*mp
, hlen
);
8191 case ETHERTYPE_IPV6
:
8193 error
= pf_af_hook(ifp
, 0, mp
, AF_INET6
, input
, NULL
);
8196 if (*mp
== NULL
|| error
!= 0) { /* filter may consume */
8215 * Finally, put everything back the way it was and return
8218 M_PREPEND(*mp
, sizeof(struct llc
), M_DONTWAIT
, 0);
8222 bcopy(&llc1
, mtod(*mp
, caddr_t
), sizeof(struct llc
));
8225 M_PREPEND(*mp
, ETHER_HDR_LEN
, M_DONTWAIT
, 0);
8229 bcopy(&eh2
, mtod(*mp
, caddr_t
), ETHER_HDR_LEN
);
8240 * Copyright (C) 2014, Stefano Garzarella - Universita` di Pisa.
8241 * All rights reserved.
8243 * Redistribution and use in source and binary forms, with or without
8244 * modification, are permitted provided that the following conditions
8246 * 1. Redistributions of source code must retain the above copyright
8247 * notice, this list of conditions and the following disclaimer.
8248 * 2. Redistributions in binary form must reproduce the above copyright
8249 * notice, this list of conditions and the following disclaimer in the
8250 * documentation and/or other materials provided with the distribution.
8252 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
8253 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8254 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8255 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
8256 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8257 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8258 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8259 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8260 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8261 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8266 * XXX-ste: Maybe this function must be moved into kern/uipc_mbuf.c
8268 * Create a queue of packets/segments which fit the given mss + hdr_len.
8269 * m0 points to mbuf chain to be segmented.
8270 * This function splits the payload (m0-> m_pkthdr.len - hdr_len)
8271 * into segments of length MSS bytes and then copy the first hdr_len bytes
8272 * from m0 at the top of each segment.
8273 * If hdr2_buf is not NULL (hdr2_len is the buf length), it is copied
8274 * in each segment after the first hdr_len bytes
8276 * Return the new queue with the segments on success, NULL on failure.
8277 * (the mbuf queue is freed in this case).
8278 * nsegs contains the number of segments generated.
8281 static struct mbuf
*
8282 m_seg(struct mbuf
*m0
, int hdr_len
, int mss
, int *nsegs
,
8283 char * hdr2_buf
, int hdr2_len
)
8285 int off
= 0, n
, firstlen
;
8286 struct mbuf
**mnext
, *mseg
;
8287 int total_len
= m0
->m_pkthdr
.len
;
8290 * Segmentation useless
8292 if (total_len
<= hdr_len
+ mss
) {
8296 if (hdr2_buf
== NULL
|| hdr2_len
<= 0) {
8301 off
= hdr_len
+ mss
;
8302 firstlen
= mss
; /* first segment stored in the original mbuf */
8304 mnext
= &(m0
->m_nextpkt
); /* pointer to next packet */
8306 for (n
= 1; off
< total_len
; off
+= mss
, n
++) {
8309 * Copy the header from the original packet
8310 * and create a new mbuf chain
8312 if (MHLEN
< hdr_len
) {
8313 m
= m_getcl(M_NOWAIT
, MT_DATA
, M_PKTHDR
);
8315 m
= m_gethdr(M_NOWAIT
, MT_DATA
);
8320 D("MGETHDR error\n");
8325 m_copydata(m0
, 0, hdr_len
, mtod(m
, caddr_t
));
8329 * if the optional header is present, copy it
8331 if (hdr2_buf
!= NULL
) {
8332 m_copyback(m
, hdr_len
, hdr2_len
, hdr2_buf
);
8335 m
->m_flags
|= (m0
->m_flags
& M_COPYFLAGS
);
8336 if (off
+ mss
>= total_len
) { /* last segment */
8337 mss
= total_len
- off
;
8340 * Copy the payload from original packet
8342 mseg
= m_copym(m0
, off
, mss
, M_NOWAIT
);
8346 D("m_copym error\n");
8352 m
->m_pkthdr
.len
= hdr_len
+ hdr2_len
+ mss
;
8353 m
->m_pkthdr
.rcvif
= m0
->m_pkthdr
.rcvif
;
8355 * Copy the checksum flags and data (in_cksum() need this)
8357 m
->m_pkthdr
.csum_flags
= m0
->m_pkthdr
.csum_flags
;
8358 m
->m_pkthdr
.csum_data
= m0
->m_pkthdr
.csum_data
;
8359 m
->m_pkthdr
.tso_segsz
= m0
->m_pkthdr
.tso_segsz
;
8362 mnext
= &(m
->m_nextpkt
);
8366 * Update first segment.
8367 * If the optional header is present, is necessary
8368 * to insert it into the first segment.
8370 if (hdr2_buf
== NULL
) {
8371 m_adj(m0
, hdr_len
+ firstlen
- total_len
);
8372 m0
->m_pkthdr
.len
= hdr_len
+ firstlen
;
8374 mseg
= m_copym(m0
, hdr_len
, firstlen
, M_NOWAIT
);
8377 D("m_copym error\n");
8381 m_adj(m0
, hdr_len
- total_len
);
8382 m_copyback(m0
, hdr_len
, hdr2_len
, hdr2_buf
);
8384 m0
->m_pkthdr
.len
= hdr_len
+ hdr2_len
+ firstlen
;
8387 if (nsegs
!= NULL
) {
8392 while (m0
!= NULL
) {
8393 mseg
= m0
->m_nextpkt
;
8394 m0
->m_nextpkt
= NULL
;
8402 * Wrappers of IPv4 checksum functions
8405 gso_ipv4_data_cksum(struct mbuf
*m
, struct ip
*ip
, int mac_hlen
)
8407 m
->m_data
+= mac_hlen
;
8408 m
->m_len
-= mac_hlen
;
8409 m
->m_pkthdr
.len
-= mac_hlen
;
8410 #if __FreeBSD_version < 1000000
8411 ip
->ip_len
= ntohs(ip
->ip_len
); /* needed for in_delayed_cksum() */
8414 in_delayed_cksum(m
);
8416 #if __FreeBSD_version < 1000000
8417 ip
->ip_len
= htons(ip
->ip_len
);
8419 m
->m_pkthdr
.csum_flags
&= ~CSUM_DELAY_DATA
;
8420 m
->m_len
+= mac_hlen
;
8421 m
->m_pkthdr
.len
+= mac_hlen
;
8422 m
->m_data
-= mac_hlen
;
8426 gso_ipv4_hdr_cksum(struct mbuf
*m
, struct ip
*ip
, int mac_hlen
, int ip_hlen
)
8428 m
->m_data
+= mac_hlen
;
8430 ip
->ip_sum
= in_cksum(m
, ip_hlen
);
8432 m
->m_pkthdr
.csum_flags
&= ~CSUM_IP
;
8433 m
->m_data
-= mac_hlen
;
8437 * Structure that contains the state during the TCP segmentation
8439 struct gso_ip_tcp_state
{
8441 (struct gso_ip_tcp_state
*, struct mbuf
*);
8443 (struct gso_ip_tcp_state
*, struct mbuf
*);
8446 struct ip6_hdr
*ip6
;
8461 * Update the pointers to TCP and IPv4 headers
8464 gso_ipv4_tcp_update(struct gso_ip_tcp_state
*state
, struct mbuf
*m
)
8466 state
->hdr
.ip
= (struct ip
*)(void *)(mtod(m
, uint8_t *) + state
->mac_hlen
);
8467 state
->tcp
= (struct tcphdr
*)(void *)((caddr_t
)(state
->hdr
.ip
) + state
->ip_hlen
);
8468 state
->pay_len
= m
->m_pkthdr
.len
- state
->hlen
;
8472 * Set properly the TCP and IPv4 headers
8475 gso_ipv4_tcp_internal(struct gso_ip_tcp_state
*state
, struct mbuf
*m
)
8480 state
->hdr
.ip
->ip_id
= htons((state
->ip_id
)++);
8481 state
->hdr
.ip
->ip_len
= htons(m
->m_pkthdr
.len
- state
->mac_hlen
);
8485 state
->tcp
->th_sum
= 0;
8486 state
->tcp
->th_sum
= in_pseudo(state
->hdr
.ip
->ip_src
.s_addr
,
8487 state
->hdr
.ip
->ip_dst
.s_addr
,
8488 htons(state
->tcp_hlen
+ IPPROTO_TCP
+ state
->pay_len
));
8490 * Checksum HW not supported (TCP)
8492 if (state
->sw_csum
& CSUM_DELAY_DATA
) {
8493 gso_ipv4_data_cksum(m
, state
->hdr
.ip
, state
->mac_hlen
);
8496 state
->tcp_seq
+= state
->pay_len
;
8500 state
->hdr
.ip
->ip_sum
= 0;
8502 * Checksum HW not supported (IP)
8504 if (state
->sw_csum
& CSUM_IP
) {
8505 gso_ipv4_hdr_cksum(m
, state
->hdr
.ip
, state
->mac_hlen
, state
->ip_hlen
);
8511 * Updates the pointers to TCP and IPv6 headers
8514 gso_ipv6_tcp_update(struct gso_ip_tcp_state
*state
, struct mbuf
*m
)
8516 state
->hdr
.ip6
= (struct ip6_hdr
*)(mtod(m
, uint8_t *) + state
->mac_hlen
);
8517 state
->tcp
= (struct tcphdr
*)(void *)((caddr_t
)(state
->hdr
.ip6
) + state
->ip_hlen
);
8518 state
->pay_len
= m
->m_pkthdr
.len
- state
->hlen
;
8522 * Sets properly the TCP and IPv6 headers
8525 gso_ipv6_tcp_internal(struct gso_ip_tcp_state
*state
, struct mbuf
*m
)
8527 state
->hdr
.ip6
->ip6_plen
= htons(m
->m_pkthdr
.len
-
8528 state
->mac_hlen
- state
->ip_hlen
);
8532 state
->tcp
->th_sum
= 0;
8533 state
->tcp
->th_sum
= in6_pseudo(&state
->hdr
.ip6
->ip6_src
,
8534 &state
->hdr
.ip6
->ip6_dst
,
8535 htonl(state
->tcp_hlen
+ state
->pay_len
+ IPPROTO_TCP
));
8537 * Checksum HW not supported (TCP)
8539 if (state
->sw_csum
& CSUM_DELAY_IPV6_DATA
) {
8540 (void)in6_finalize_cksum(m
, state
->mac_hlen
, -1, -1, state
->sw_csum
);
8541 m
->m_pkthdr
.csum_flags
&= ~CSUM_DELAY_IPV6_DATA
;
8543 state
->tcp_seq
+= state
->pay_len
;
8547 * Init the state during the TCP segmentation
8549 static inline boolean_t
8550 gso_ip_tcp_init_state(struct gso_ip_tcp_state
*state
, struct ifnet
*ifp
, struct mbuf
*m
, int mac_hlen
, int ip_hlen
, boolean_t isipv6
)
8555 state
->hdr
.ip6
= (struct ip6_hdr
*)(mtod(m
, uint8_t *) + mac_hlen
);
8556 if (state
->hdr
.ip6
->ip6_nxt
!= IPPROTO_TCP
) {
8557 printf("%s: Non-TCP (%d) IPv6 frame", __func__
, state
->hdr
.ip6
->ip6_nxt
);
8560 state
->tcp
= (struct tcphdr
*)(void *)((caddr_t
)(state
->hdr
.ip6
) + ip_hlen
);
8561 state
->update
= gso_ipv6_tcp_update
;
8562 state
->internal
= gso_ipv6_tcp_internal
;
8563 state
->sw_csum
= CSUM_DELAY_IPV6_DATA
;
8565 state
->hdr
.ip
= (struct ip
*)(void *)(mtod(m
, uint8_t *) + mac_hlen
);
8566 if (state
->hdr
.ip
->ip_p
!= IPPROTO_TCP
) {
8567 printf("%s: Non-TCP (%d) IPv4 frame", __func__
, state
->hdr
.ip
->ip_p
);
8570 state
->ip_id
= ntohs(state
->hdr
.ip
->ip_id
);
8571 state
->tcp
= (struct tcphdr
*)(void *)((caddr_t
)(state
->hdr
.ip
) + ip_hlen
);
8572 state
->update
= gso_ipv4_tcp_update
;
8573 state
->internal
= gso_ipv4_tcp_internal
;
8574 state
->sw_csum
= CSUM_DELAY_DATA
| CSUM_IP
;
8576 state
->mac_hlen
= mac_hlen
;
8577 state
->ip_hlen
= ip_hlen
;
8578 state
->tcp_hlen
= state
->tcp
->th_off
<< 2;
8579 state
->hlen
= mac_hlen
+ ip_hlen
+ state
->tcp_hlen
;
8580 state
->tcp_seq
= ntohl(state
->tcp
->th_seq
);
8581 //state->sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_hwassist;
8586 * GSO on TCP/IP (v4 or v6)
8588 * If is_tx is TRUE, segmented packets are transmitted after they are
8591 * If is_tx is FALSE, the segmented packets are returned as a chain in *mp.
8594 gso_ip_tcp(struct ifnet
*ifp
, struct mbuf
**mp
, struct gso_ip_tcp_state
*state
,
8597 struct mbuf
*m
, *m_tx
;
8601 struct mbuf
*m0
= *mp
;
8603 int total_len
= m0
->m_pkthdr
.len
;
8604 #endif /* GSO_STATS */
8607 mss
= ifp
->if_mtu
- state
->ip_hlen
- state
->tcp_hlen
;
8609 if (m0
->m_pkthdr
.csum_flags
& ifp
->if_hwassist
& CSUM_TSO
) {/* TSO with GSO */
8610 mss
= ifp
->if_hw_tsomax
- state
->ip_hlen
- state
->tcp_hlen
;
8612 mss
= m0
->m_pkthdr
.tso_segsz
;
8616 *mp
= m0
= m_seg(m0
, state
->hlen
, mss
, &nsegs
, 0, 0);
8618 return ENOBUFS
; /* XXX ok? */
8621 if (IF_BRIDGE_DEBUG(BR_DBGF_SEGMENTATION
)) {
8622 printf("%s: %s %s mss %d nsegs %d\n", __func__
,
8624 is_tx
? "TX" : "RX",
8627 #endif /* BRIDGE_DEBUG */
8631 * XXX-ste: can this happen?
8633 if (m0
->m_nextpkt
== NULL
) {
8635 D("only 1 segment");
8638 error
= bridge_transmit(ifp
, m0
);
8643 GSOSTAT_SET_MAX(tcp
.gsos_max_mss
, mss
);
8644 GSOSTAT_SET_MIN(tcp
.gsos_min_mss
, mss
);
8645 GSOSTAT_ADD(tcp
.gsos_osegments
, nsegs
);
8646 #endif /* GSO_STATS */
8651 state
->update(state
, m
);
8654 state
->tcp
->th_flags
&= ~(TH_FIN
| TH_PUSH
);
8656 state
->internal(state
, m
);
8660 m_tx
->m_nextpkt
= NULL
;
8661 if ((error
= bridge_transmit(ifp
, m_tx
)) != 0) {
8663 * XXX: If a segment can not be sent, discard the following
8664 * segments and propagate the error to the upper levels.
8665 * In this way the TCP retransmits all the initial packet.
8668 D("if_transmit error\n");
8673 state
->update(state
, m
);
8675 state
->tcp
->th_flags
&= ~TH_CWR
;
8676 state
->tcp
->th_seq
= htonl(state
->tcp_seq
);
8677 } while (m
->m_nextpkt
);
8680 state
->internal(state
, m
);
8683 error
= bridge_transmit(ifp
, m
);
8686 D("last if_transmit error\n");
8687 D("error - type = %d \n", error
);
8693 GSOSTAT_INC(tcp
.gsos_segmented
);
8694 GSOSTAT_SET_MAX(tcp
.gsos_maxsegmented
, total_len
);
8695 GSOSTAT_SET_MIN(tcp
.gsos_minsegmented
, total_len
);
8696 GSOSTAT_ADD(tcp
.gsos_totalbyteseg
, total_len
);
8698 #endif /* GSO_STATS */
8703 D("error - type = %d \n", error
);
8706 m_tx
= m
->m_nextpkt
;
8707 m
->m_nextpkt
= NULL
;
8718 gso_ipv4_tcp(struct ifnet
*ifp
, struct mbuf
**mp
, u_int mac_hlen
,
8722 struct gso_ip_tcp_state state
;
8725 struct mbuf
*m0
= *mp
;
8727 if (!is_tx
&& ipforwarding
== 0) {
8728 /* no need to segment if the packet will not be forwarded */
8731 hlen
= mac_hlen
+ sizeof(struct ip
);
8732 if (m0
->m_len
< hlen
) {
8734 D("m_len < hlen - m_len: %d hlen: %d", m0
->m_len
, hlen
);
8736 *mp
= m0
= m_pullup(m0
, hlen
);
8741 ip
= (struct ip
*)(void *)(mtod(m0
, uint8_t *) + mac_hlen
);
8742 ip_hlen
= IP_VHL_HL(ip
->ip_vhl
) << 2;
8743 hlen
= mac_hlen
+ ip_hlen
+ sizeof(struct tcphdr
);
8744 if (m0
->m_len
< hlen
) {
8746 D("m_len < hlen - m_len: %d hlen: %d", m0
->m_len
, hlen
);
8748 *mp
= m0
= m_pullup(m0
, hlen
);
8754 /* if the destination is a local IP address, don't segment */
8755 struct in_addr dst_ip
;
8757 bcopy(&ip
->ip_dst
, &dst_ip
, sizeof(dst_ip
));
8758 if (in_addr_is_ours(dst_ip
)) {
8763 m0
->m_pkthdr
.csum_data
= offsetof(struct tcphdr
, th_sum
);
8764 m0
->m_pkthdr
.csum_flags
= CSUM_DELAY_DATA
;
8766 if (!gso_ip_tcp_init_state(&state
, ifp
, m0
, mac_hlen
, ip_hlen
, FALSE
)) {
8772 return gso_ip_tcp(ifp
, mp
, &state
, is_tx
);
8779 gso_ipv6_tcp(struct ifnet
*ifp
, struct mbuf
**mp
, u_int mac_hlen
,
8782 struct ip6_hdr
*ip6
;
8783 struct gso_ip_tcp_state state
;
8786 struct mbuf
*m0
= *mp
;
8788 if (!is_tx
&& ip6_forwarding
== 0) {
8789 /* no need to segment if the packet will not be forwarded */
8793 hlen
= mac_hlen
+ sizeof(struct ip6_hdr
);
8794 if (m0
->m_len
< hlen
) {
8796 D("m_len < hlen - m_len: %d hlen: %d", m0
->m_len
, hlen
);
8798 *mp
= m0
= m_pullup(m0
, hlen
);
8803 ip6
= (struct ip6_hdr
*)(mtod(m0
, uint8_t *) + mac_hlen
);
8804 ip_hlen
= ip6_lasthdr(m0
, mac_hlen
, IPPROTO_IPV6
, NULL
) - mac_hlen
;
8805 hlen
= mac_hlen
+ ip_hlen
+ sizeof(struct tcphdr
);
8806 if (m0
->m_len
< hlen
) {
8808 D("m_len < hlen - m_len: %d hlen: %d", m0
->m_len
, hlen
);
8810 *mp
= m0
= m_pullup(m0
, hlen
);
8816 struct in6_addr dst_ip6
;
8818 bcopy(&ip6
->ip6_dst
, &dst_ip6
, sizeof(dst_ip6
));
8819 if (IN6_IS_ADDR_LINKLOCAL(&dst_ip6
)) {
8820 dst_ip6
.s6_addr16
[1] = htons(ifp
->if_index
);
8822 if (in6_addr_is_ours(&dst_ip6
)) {
8823 /* local IP address, no need to segment */
8827 m0
->m_pkthdr
.csum_data
= offsetof(struct tcphdr
, th_sum
);
8828 m0
->m_pkthdr
.csum_flags
= CSUM_DELAY_IPV6_DATA
;
8830 if (!gso_ip_tcp_init_state(&state
, ifp
, m0
, mac_hlen
, ip_hlen
, TRUE
)) {
8836 return gso_ip_tcp(ifp
, mp
, &state
, is_tx
);