]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_bridge.c
xnu-6153.121.1.tar.gz
[apple/xnu.git] / bsd / net / if_bridge.c
CommitLineData
6d2010ae 1/*
cb323159 2 * Copyright (c) 2004-2019 Apple Inc. All rights reserved.
6d2010ae
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
316670eb 29/* $NetBSD: if_bridge.c,v 1.31 2005/06/01 19:45:34 jdc Exp $ */
6d2010ae
A
30/*
31 * Copyright 2001 Wasabi Systems, Inc.
32 * All rights reserved.
33 *
34 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
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
50 * written permission.
51 *
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.
63 */
64
65/*
66 * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
67 * All rights reserved.
68 *
69 * Redistribution and use in source and binary forms, with or without
70 * modification, are permitted provided that the following conditions
71 * are met:
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.
77 *
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.
89 *
90 * OpenBSD: if_bridge.c,v 1.60 2001/06/15 03:38:33 itojun Exp
91 */
92
93/*
94 * Network interface bridge support.
95 *
96 * TODO:
97 *
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).
39236c6e
A
102 *
103 * - GIF isn't handled due to the lack of IPPROTO_ETHERIP support.
6d2010ae
A
104 */
105
106#include <sys/cdefs.h>
6d2010ae 107
0a7de745 108#define BRIDGE_DEBUG 1
6d2010ae
A
109
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>
6d2010ae
A
118#include <sys/kernel.h>
119#include <sys/random.h>
120#include <sys/syslog.h>
121#include <sys/sysctl.h>
6d2010ae
A
122#include <sys/proc.h>
123#include <sys/lock.h>
6d2010ae
A
124#include <sys/mcache.h>
125
126#include <sys/kauth.h>
127
39236c6e
A
128#include <kern/thread_call.h>
129
6d2010ae
A
130#include <libkern/libkern.h>
131
132#include <kern/zalloc.h>
133
134#if NBPFILTER > 0
135#include <net/bpf.h>
136#endif
137#include <net/if.h>
6d2010ae
A
138#include <net/if_dl.h>
139#include <net/if_types.h>
140#include <net/if_var.h>
39236c6e 141#include <net/if_media.h>
5ba3f43e 142#include <net/net_api_stats.h>
bca245ac 143#include <net/pfvar.h>
6d2010ae
A
144
145#include <netinet/in.h> /* for struct arpcom */
146#include <netinet/in_systm.h>
147#include <netinet/in_var.h>
0a7de745 148#define _IP_VHL
6d2010ae
A
149#include <netinet/ip.h>
150#include <netinet/ip_var.h>
39236c6e 151#if INET6
6d2010ae
A
152#include <netinet/ip6.h>
153#include <netinet6/ip6_var.h>
154#endif
155#ifdef DEV_CARP
156#include <netinet/ip_carp.h>
157#endif
6d2010ae
A
158#include <netinet/if_ether.h> /* for struct arpcom */
159#include <net/bridgestp.h>
160#include <net/if_bridgevar.h>
161#include <net/if_llc.h>
316670eb 162#if NVLAN > 0
6d2010ae 163#include <net/if_vlan_var.h>
316670eb 164#endif /* NVLAN > 0 */
6d2010ae
A
165
166#include <net/if_ether.h>
167#include <net/dlil.h>
168#include <net/kpi_interfacefilter.h>
169
170#include <net/route.h>
171#ifdef PFIL_HOOKS
172#include <netinet/ip_fw2.h>
173#include <netinet/ip_dummynet.h>
174#endif /* PFIL_HOOKS */
39236c6e
A
175#include <dev/random/randomdev.h>
176
fe8ab488
A
177#include <netinet/bootp.h>
178#include <netinet/dhcp.h>
179
5ba3f43e 180
39236c6e 181#if BRIDGE_DEBUG
0a7de745
A
182#define BR_DBGF_LIFECYCLE 0x0001
183#define BR_DBGF_INPUT 0x0002
184#define BR_DBGF_OUTPUT 0x0004
185#define BR_DBGF_RT_TABLE 0x0008
186#define BR_DBGF_DELAYED_CALL 0x0010
187#define BR_DBGF_IOCTL 0x0020
188#define BR_DBGF_MBUF 0x0040
189#define BR_DBGF_MCAST 0x0080
190#define BR_DBGF_HOSTFILTER 0x0100
cb323159 191#define BR_DBGF_CHECKSUM 0x0200
ea3f0419 192#define BR_DBGF_MAC_NAT 0x0400
39236c6e
A
193#endif /* BRIDGE_DEBUG */
194
0a7de745
A
195#define _BRIDGE_LOCK(_sc) lck_mtx_lock(&(_sc)->sc_mtx)
196#define _BRIDGE_UNLOCK(_sc) lck_mtx_unlock(&(_sc)->sc_mtx)
197#define BRIDGE_LOCK_ASSERT_HELD(_sc) \
5ba3f43e 198 LCK_MTX_ASSERT(&(_sc)->sc_mtx, LCK_MTX_ASSERT_OWNED)
0a7de745 199#define BRIDGE_LOCK_ASSERT_NOTHELD(_sc) \
5ba3f43e 200 LCK_MTX_ASSERT(&(_sc)->sc_mtx, LCK_MTX_ASSERT_NOTOWNED)
6d2010ae
A
201
202#if BRIDGE_DEBUG
203
0a7de745 204#define BR_LCKDBG_MAX 4
6d2010ae 205
0a7de745
A
206#define BRIDGE_LOCK(_sc) bridge_lock(_sc)
207#define BRIDGE_UNLOCK(_sc) bridge_unlock(_sc)
208#define BRIDGE_LOCK2REF(_sc, _err) _err = bridge_lock2ref(_sc)
209#define BRIDGE_UNREF(_sc) bridge_unref(_sc)
210#define BRIDGE_XLOCK(_sc) bridge_xlock(_sc)
211#define BRIDGE_XDROP(_sc) bridge_xdrop(_sc)
ea3f0419 212#define IF_BRIDGE_DEBUG(f) bridge_debug_flag_is_set(f)
6d2010ae 213
39236c6e 214#else /* !BRIDGE_DEBUG */
6d2010ae 215
0a7de745
A
216#define BRIDGE_LOCK(_sc) _BRIDGE_LOCK(_sc)
217#define BRIDGE_UNLOCK(_sc) _BRIDGE_UNLOCK(_sc)
218#define BRIDGE_LOCK2REF(_sc, _err) do { \
219 BRIDGE_LOCK_ASSERT_HELD(_sc); \
220 if ((_sc)->sc_iflist_xcnt > 0) \
221 (_err) = EBUSY; \
222 else \
223 (_sc)->sc_iflist_ref++; \
224 _BRIDGE_UNLOCK(_sc); \
6d2010ae 225} while (0)
0a7de745
A
226#define BRIDGE_UNREF(_sc) do { \
227 _BRIDGE_LOCK(_sc); \
228 (_sc)->sc_iflist_ref--; \
6d2010ae 229 if (((_sc)->sc_iflist_xcnt > 0) && ((_sc)->sc_iflist_ref == 0)) { \
0a7de745
A
230 _BRIDGE_UNLOCK(_sc); \
231 wakeup(&(_sc)->sc_cv); \
232 } else \
233 _BRIDGE_UNLOCK(_sc); \
6d2010ae 234} while (0)
0a7de745
A
235#define BRIDGE_XLOCK(_sc) do { \
236 BRIDGE_LOCK_ASSERT_HELD(_sc); \
237 (_sc)->sc_iflist_xcnt++; \
238 while ((_sc)->sc_iflist_ref > 0) \
239 msleep(&(_sc)->sc_cv, &(_sc)->sc_mtx, PZERO, \
240 "BRIDGE_XLOCK", NULL); \
6d2010ae 241} while (0)
0a7de745
A
242#define BRIDGE_XDROP(_sc) do { \
243 BRIDGE_LOCK_ASSERT_HELD(_sc); \
244 (_sc)->sc_iflist_xcnt--; \
6d2010ae
A
245} while (0)
246
ea3f0419
A
247#define IF_BRIDGE_DEBUG(f) FALSE
248
6d2010ae
A
249#endif /* BRIDGE_DEBUG */
250
251#if NBPFILTER > 0
0a7de745 252#define BRIDGE_BPF_MTAP_INPUT(sc, m) \
ea3f0419
A
253 if (sc->sc_bpf_input != NULL) \
254 bridge_bpf_input(sc->sc_ifp, m, __func__, __LINE__)
6d2010ae 255#else /* NBPFILTER */
0a7de745 256#define BRIDGE_BPF_MTAP_INPUT(ifp, m)
6d2010ae
A
257#endif /* NBPFILTER */
258
259/*
39236c6e 260 * Initial size of the route hash table. Must be a power of two.
6d2010ae 261 */
6d2010ae 262#ifndef BRIDGE_RTHASH_SIZE
0a7de745 263#define BRIDGE_RTHASH_SIZE 16
6d2010ae
A
264#endif
265
39236c6e
A
266/*
267 * Maximum size of the routing hash table
268 */
0a7de745 269#define BRIDGE_RTHASH_SIZE_MAX 2048
6d2010ae 270
0a7de745 271#define BRIDGE_RTHASH_MASK(sc) ((sc)->sc_rthash_size - 1)
6d2010ae
A
272
273/*
274 * Maximum number of addresses to cache.
275 */
276#ifndef BRIDGE_RTABLE_MAX
0a7de745 277#define BRIDGE_RTABLE_MAX 100
6d2010ae
A
278#endif
279
280
281/*
282 * Timeout (in seconds) for entries learned dynamically.
283 */
284#ifndef BRIDGE_RTABLE_TIMEOUT
0a7de745 285#define BRIDGE_RTABLE_TIMEOUT (20 * 60) /* same as ARP */
6d2010ae
A
286#endif
287
288/*
289 * Number of seconds between walks of the route list.
290 */
291#ifndef BRIDGE_RTABLE_PRUNE_PERIOD
0a7de745 292#define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60)
6d2010ae
A
293#endif
294
ea3f0419
A
295/*
296 * Number of MAC NAT entries
297 * - sized based on 16 clients (including MAC NAT interface)
298 * each with 4 addresses
299 */
300#ifndef BRIDGE_MAC_NAT_ENTRY_MAX
301#define BRIDGE_MAC_NAT_ENTRY_MAX 64
302#endif /* BRIDGE_MAC_NAT_ENTRY_MAX */
303
6d2010ae
A
304/*
305 * List of capabilities to possibly mask on the member interface.
306 */
0a7de745 307#define BRIDGE_IFCAPS_MASK (IFCAP_TOE|IFCAP_TSO|IFCAP_TXCSUM)
6d2010ae
A
308/*
309 * List of capabilities to disable on the member interface.
310 */
0a7de745 311#define BRIDGE_IFCAPS_STRIP IFCAP_LRO
6d2010ae
A
312
313/*
314 * Bridge interface list entry.
315 */
316struct bridge_iflist {
317 TAILQ_ENTRY(bridge_iflist) bif_next;
0a7de745
A
318 struct ifnet *bif_ifp; /* member if */
319 struct bstp_port bif_stp; /* STP state */
320 uint32_t bif_ifflags; /* member if flags */
321 int bif_savedcaps; /* saved capabilities */
322 uint32_t bif_addrmax; /* max # of addresses */
323 uint32_t bif_addrcnt; /* cur. # of addresses */
324 uint32_t bif_addrexceeded; /* # of address violations */
325
326 interface_filter_t bif_iff_ref;
327 struct bridge_softc *bif_sc;
328 uint32_t bif_flags;
329
330 struct in_addr bif_hf_ipsrc;
331 uint8_t bif_hf_hwsrc[ETHER_ADDR_LEN];
6d2010ae
A
332};
333
0a7de745
A
334#define BIFF_PROMISC 0x01 /* promiscuous mode set */
335#define BIFF_PROTO_ATTACHED 0x02 /* protocol attached */
336#define BIFF_FILTER_ATTACHED 0x04 /* interface filter attached */
337#define BIFF_MEDIA_ACTIVE 0x08 /* interface media active */
338#define BIFF_HOST_FILTER 0x10 /* host filter enabled */
339#define BIFF_HF_HWSRC 0x20 /* host filter source MAC is set */
340#define BIFF_HF_IPSRC 0x40 /* host filter source IP is set */
cb323159 341#define BIFF_INPUT_BROADCAST 0x80 /* send broadcast packets in */
39236c6e 342
ea3f0419
A
343/*
344 * mac_nat_entry
345 * - translates between an IP address and MAC address on a specific
346 * bridge interface member
347 */
348struct mac_nat_entry {
349 LIST_ENTRY(mac_nat_entry) mne_list; /* list linkage */
350 struct bridge_iflist *mne_bif; /* originating interface */
351 unsigned long mne_expire; /* expiration time */
352 union {
353 struct in_addr mneu_ip; /* originating IPv4 address */
354 struct in6_addr mneu_ip6; /* originating IPv6 address */
355 } mne_u;
356 uint8_t mne_mac[ETHER_ADDR_LEN];
357 uint8_t mne_flags;
358 uint8_t mne_reserved;
359};
360#define mne_ip mne_u.mneu_ip
361#define mne_ip6 mne_u.mneu_ip6
362
363#define MNE_FLAGS_IPV6 0x01 /* IPv6 address */
364
365LIST_HEAD(mac_nat_entry_list, mac_nat_entry);
366
367/*
368 * mac_nat_record
369 * - used by bridge_mac_nat_output() to convey the translation that needs
370 * to take place in bridge_mac_nat_translate
371 * - holds enough information so that the translation can be done later without
372 * holding the bridge lock
373 */
374struct mac_nat_record {
375 uint16_t mnr_ether_type;
376 union {
377 uint16_t mnru_arp_offset;
378 struct {
379 uint16_t mnruip_dhcp_flags;
380 uint16_t mnruip_udp_csum;
381 uint8_t mnruip_header_len;
382 } mnru_ip;
383 struct {
384 uint16_t mnruip6_icmp6_len;
385 uint16_t mnruip6_lladdr_offset;
386 uint8_t mnruip6_icmp6_type;
387 uint8_t mnruip6_header_len;
388 } mnru_ip6;
389 } mnr_u;
390};
391
392#define mnr_arp_offset mnr_u.mnru_arp_offset
393
394#define mnr_ip_header_len mnr_u.mnru_ip.mnruip_header_len
395#define mnr_ip_dhcp_flags mnr_u.mnru_ip.mnruip_dhcp_flags
396#define mnr_ip_udp_csum mnr_u.mnru_ip.mnruip_udp_csum
397
398#define mnr_ip6_icmp6_len mnr_u.mnru_ip6.mnruip6_icmp6_len
399#define mnr_ip6_icmp6_type mnr_u.mnru_ip6.mnruip6_icmp6_type
400#define mnr_ip6_header_len mnr_u.mnru_ip6.mnruip6_header_len
401#define mnr_ip6_lladdr_offset mnr_u.mnru_ip6.mnruip6_lladdr_offset
402
6d2010ae
A
403/*
404 * Bridge route node.
405 */
406struct bridge_rtnode {
0a7de745
A
407 LIST_ENTRY(bridge_rtnode) brt_hash; /* hash table linkage */
408 LIST_ENTRY(bridge_rtnode) brt_list; /* list linkage */
409 struct bridge_iflist *brt_dst; /* destination if */
410 unsigned long brt_expire; /* expiration time */
411 uint8_t brt_flags; /* address flags */
412 uint8_t brt_addr[ETHER_ADDR_LEN];
413 uint16_t brt_vlan; /* vlan id */
6d2010ae
A
414
415};
0a7de745 416#define brt_ifp brt_dst->bif_ifp
6d2010ae 417
39236c6e
A
418/*
419 * Bridge delayed function call context
420 */
421typedef void (*bridge_delayed_func_t)(struct bridge_softc *);
422
423struct bridge_delayed_call {
0a7de745
A
424 struct bridge_softc *bdc_sc;
425 bridge_delayed_func_t bdc_func; /* Function to call */
426 struct timespec bdc_ts; /* Time to call */
427 u_int32_t bdc_flags;
428 thread_call_t bdc_thread_call;
39236c6e
A
429};
430
0a7de745
A
431#define BDCF_OUTSTANDING 0x01 /* Delayed call has been scheduled */
432#define BDCF_CANCELLING 0x02 /* May be waiting for call completion */
39236c6e 433
6d2010ae
A
434/*
435 * Software state for each bridge.
436 */
39236c6e
A
437LIST_HEAD(_bridge_rtnode_list, bridge_rtnode);
438
6d2010ae 439struct bridge_softc {
0a7de745
A
440 struct ifnet *sc_ifp; /* make this an interface */
441 u_int32_t sc_flags;
316670eb 442 LIST_ENTRY(bridge_softc) sc_list;
0a7de745 443 decl_lck_mtx_data(, sc_mtx);
cb323159
A
444 struct _bridge_rtnode_list *sc_rthash; /* our forwarding table */
445 struct _bridge_rtnode_list sc_rtlist; /* list version of above */
446 uint32_t sc_rthash_key; /* key for hash */
447 uint32_t sc_rthash_size; /* size of the hash table */
448 struct bridge_delayed_call sc_aging_timer;
449 struct bridge_delayed_call sc_resize_call;
450 TAILQ_HEAD(, bridge_iflist) sc_spanlist; /* span ports list */
451 struct bstp_state sc_stp; /* STP state */
452 bpf_packet_func sc_bpf_input;
453 bpf_packet_func sc_bpf_output;
0a7de745
A
454 void *sc_cv;
455 uint32_t sc_brtmax; /* max # of addresses */
456 uint32_t sc_brtcnt; /* cur. # of addresses */
457 uint32_t sc_brttimeout; /* rt timeout in seconds */
458 uint32_t sc_iflist_ref; /* refcount for sc_iflist */
459 uint32_t sc_iflist_xcnt; /* refcount for sc_iflist */
460 TAILQ_HEAD(, bridge_iflist) sc_iflist; /* member interface list */
461 uint32_t sc_brtexceeded; /* # of cache drops */
462 uint32_t sc_filter_flags; /* ipf and flags */
463 struct ifnet *sc_ifaddr; /* member mac copied from */
464 u_char sc_defaddr[6]; /* Default MAC address */
465 char sc_if_xname[IFNAMSIZ];
6d2010ae 466
ea3f0419
A
467 struct bridge_iflist *sc_mac_nat_bif; /* single MAC NAT interface */
468 struct mac_nat_entry_list sc_mne_list; /* MAC NAT IPv4 */
469 struct mac_nat_entry_list sc_mne_list_v6;/* MAC NAT IPv6 */
470 uint32_t sc_mne_max; /* max # of entries */
471 uint32_t sc_mne_count; /* cur. # of entries */
472 uint32_t sc_mne_allocation_failures;
6d2010ae 473#if BRIDGE_DEBUG
39236c6e
A
474 /*
475 * Locking and unlocking calling history
476 */
0a7de745
A
477 void *lock_lr[BR_LCKDBG_MAX];
478 int next_lock_lr;
479 void *unlock_lr[BR_LCKDBG_MAX];
480 int next_unlock_lr;
6d2010ae
A
481#endif /* BRIDGE_DEBUG */
482};
483
ea3f0419
A
484#define SCF_DETACHING 0x01
485#define SCF_RESIZING 0x02
486#define SCF_MEDIA_ACTIVE 0x04
5ba3f43e 487
cb323159
A
488typedef enum {
489 kChecksumOperationNone = 0,
490 kChecksumOperationClear = 1,
491 kChecksumOperationFinalize = 2,
492 kChecksumOperationCompute = 3,
493} ChecksumOperation;
6d2010ae 494
fe8ab488
A
495struct bridge_hostfilter_stats bridge_hostfilter_stats;
496
39236c6e 497decl_lck_mtx_data(static, bridge_list_mtx);
6d2010ae 498
0a7de745 499static int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD;
6d2010ae 500
0a7de745 501static zone_t bridge_rtnode_pool = NULL;
ea3f0419 502static zone_t bridge_mne_pool = NULL;
6d2010ae 503
0a7de745
A
504static int bridge_clone_create(struct if_clone *, uint32_t, void *);
505static int bridge_clone_destroy(struct ifnet *);
6d2010ae 506
0a7de745 507static errno_t bridge_ioctl(struct ifnet *, u_long, void *);
6d2010ae 508#if HAS_IF_CAP
0a7de745
A
509static void bridge_mutecaps(struct bridge_softc *);
510static void bridge_set_ifcap(struct bridge_softc *, struct bridge_iflist *,
511 int);
6d2010ae 512#endif
39236c6e 513static errno_t bridge_set_tso(struct bridge_softc *);
cb323159
A
514static void bridge_ifdetach(struct ifnet *);
515static void bridge_proto_attach_changed(struct ifnet *);
0a7de745 516static int bridge_init(struct ifnet *);
6d2010ae 517#if HAS_BRIDGE_DUMMYNET
0a7de745 518static void bridge_dummynet(struct mbuf *, struct ifnet *);
6d2010ae 519#endif
0a7de745
A
520static void bridge_ifstop(struct ifnet *, int);
521static int bridge_output(struct ifnet *, struct mbuf *);
522static void bridge_finalize_cksum(struct ifnet *, struct mbuf *);
523static void bridge_start(struct ifnet *);
ea3f0419
A
524static errno_t bridge_input(struct ifnet *, mbuf_t *);
525static errno_t bridge_iff_input(void *, ifnet_t, protocol_family_t,
526 mbuf_t *, char **);
cb323159 527static errno_t bridge_iff_output(void *, ifnet_t, protocol_family_t,
0a7de745 528 mbuf_t *);
cb323159 529static errno_t bridge_member_output(struct bridge_softc *sc, ifnet_t ifp,
ea3f0419 530 mbuf_t *m);
cb323159 531
ea3f0419 532static int bridge_enqueue(ifnet_t, struct ifnet *,
cb323159 533 struct ifnet *, struct mbuf *, ChecksumOperation);
0a7de745 534static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int);
6d2010ae 535
0a7de745
A
536static void bridge_forward(struct bridge_softc *, struct bridge_iflist *,
537 struct mbuf *);
6d2010ae 538
0a7de745 539static void bridge_aging_timer(struct bridge_softc *sc);
6d2010ae 540
0a7de745
A
541static void bridge_broadcast(struct bridge_softc *, struct ifnet *,
542 struct mbuf *, int);
543static void bridge_span(struct bridge_softc *, struct mbuf *);
6d2010ae 544
0a7de745
A
545static int bridge_rtupdate(struct bridge_softc *, const uint8_t *,
546 uint16_t, struct bridge_iflist *, int, uint8_t);
6d2010ae 547static struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *,
0a7de745
A
548 uint16_t);
549static void bridge_rttrim(struct bridge_softc *);
550static void bridge_rtage(struct bridge_softc *);
551static void bridge_rtflush(struct bridge_softc *, int);
552static int bridge_rtdaddr(struct bridge_softc *, const uint8_t *,
553 uint16_t);
6d2010ae 554
0a7de745
A
555static int bridge_rtable_init(struct bridge_softc *);
556static void bridge_rtable_fini(struct bridge_softc *);
6d2010ae 557
0a7de745 558static void bridge_rthash_resize(struct bridge_softc *);
39236c6e 559
0a7de745 560static int bridge_rtnode_addr_cmp(const uint8_t *, const uint8_t *);
6d2010ae 561static struct bridge_rtnode *bridge_rtnode_lookup(struct bridge_softc *,
0a7de745
A
562 const uint8_t *, uint16_t);
563static int bridge_rtnode_hash(struct bridge_softc *,
564 struct bridge_rtnode *);
565static int bridge_rtnode_insert(struct bridge_softc *,
566 struct bridge_rtnode *);
567static void bridge_rtnode_destroy(struct bridge_softc *,
568 struct bridge_rtnode *);
316670eb 569#if BRIDGESTP
0a7de745
A
570static void bridge_rtable_expire(struct ifnet *, int);
571static void bridge_state_change(struct ifnet *, int);
316670eb 572#endif /* BRIDGESTP */
6d2010ae
A
573
574static struct bridge_iflist *bridge_lookup_member(struct bridge_softc *,
0a7de745 575 const char *name);
6d2010ae 576static struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *,
0a7de745
A
577 struct ifnet *ifp);
578static void bridge_delete_member(struct bridge_softc *,
579 struct bridge_iflist *, int);
580static void bridge_delete_span(struct bridge_softc *,
581 struct bridge_iflist *);
582
583static int bridge_ioctl_add(struct bridge_softc *, void *);
584static int bridge_ioctl_del(struct bridge_softc *, void *);
585static int bridge_ioctl_gifflags(struct bridge_softc *, void *);
586static int bridge_ioctl_sifflags(struct bridge_softc *, void *);
587static int bridge_ioctl_scache(struct bridge_softc *, void *);
588static int bridge_ioctl_gcache(struct bridge_softc *, void *);
589static int bridge_ioctl_gifs32(struct bridge_softc *, void *);
590static int bridge_ioctl_gifs64(struct bridge_softc *, void *);
591static int bridge_ioctl_rts32(struct bridge_softc *, void *);
592static int bridge_ioctl_rts64(struct bridge_softc *, void *);
593static int bridge_ioctl_saddr32(struct bridge_softc *, void *);
594static int bridge_ioctl_saddr64(struct bridge_softc *, void *);
595static int bridge_ioctl_sto(struct bridge_softc *, void *);
596static int bridge_ioctl_gto(struct bridge_softc *, void *);
597static int bridge_ioctl_daddr32(struct bridge_softc *, void *);
598static int bridge_ioctl_daddr64(struct bridge_softc *, void *);
599static int bridge_ioctl_flush(struct bridge_softc *, void *);
600static int bridge_ioctl_gpri(struct bridge_softc *, void *);
601static int bridge_ioctl_spri(struct bridge_softc *, void *);
602static int bridge_ioctl_ght(struct bridge_softc *, void *);
603static int bridge_ioctl_sht(struct bridge_softc *, void *);
604static int bridge_ioctl_gfd(struct bridge_softc *, void *);
605static int bridge_ioctl_sfd(struct bridge_softc *, void *);
606static int bridge_ioctl_gma(struct bridge_softc *, void *);
607static int bridge_ioctl_sma(struct bridge_softc *, void *);
608static int bridge_ioctl_sifprio(struct bridge_softc *, void *);
609static int bridge_ioctl_sifcost(struct bridge_softc *, void *);
610static int bridge_ioctl_sifmaxaddr(struct bridge_softc *, void *);
611static int bridge_ioctl_addspan(struct bridge_softc *, void *);
612static int bridge_ioctl_delspan(struct bridge_softc *, void *);
613static int bridge_ioctl_gbparam32(struct bridge_softc *, void *);
614static int bridge_ioctl_gbparam64(struct bridge_softc *, void *);
615static int bridge_ioctl_grte(struct bridge_softc *, void *);
616static int bridge_ioctl_gifsstp32(struct bridge_softc *, void *);
617static int bridge_ioctl_gifsstp64(struct bridge_softc *, void *);
618static int bridge_ioctl_sproto(struct bridge_softc *, void *);
619static int bridge_ioctl_stxhc(struct bridge_softc *, void *);
620static int bridge_ioctl_purge(struct bridge_softc *sc, void *);
621static int bridge_ioctl_gfilt(struct bridge_softc *, void *);
622static int bridge_ioctl_sfilt(struct bridge_softc *, void *);
623static int bridge_ioctl_ghostfilter(struct bridge_softc *, void *);
624static int bridge_ioctl_shostfilter(struct bridge_softc *, void *);
ea3f0419
A
625static int bridge_ioctl_gmnelist32(struct bridge_softc *, void *);
626static int bridge_ioctl_gmnelist64(struct bridge_softc *, void *);
6d2010ae 627#ifdef PFIL_HOOKS
0a7de745
A
628static int bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *,
629 int);
0a7de745
A
630static int bridge_fragment(struct ifnet *, struct mbuf *,
631 struct ether_header *, int, struct llc *);
6d2010ae 632#endif /* PFIL_HOOKS */
ea3f0419
A
633static int bridge_ip_checkbasic(struct mbuf **);
634#ifdef INET6
635static int bridge_ip6_checkbasic(struct mbuf **);
636#endif /* INET6 */
637
638static int bridge_pf(struct mbuf **, struct ifnet *, uint32_t sc_filter_flags, int input);
6d2010ae 639
39236c6e 640static errno_t bridge_set_bpf_tap(ifnet_t, bpf_tap_mode, bpf_packet_func);
ea3f0419
A
641static errno_t bridge_bpf_input(ifnet_t, struct mbuf *, const char *, int);
642static errno_t bridge_bpf_output(ifnet_t, struct mbuf *);
6d2010ae 643
39236c6e
A
644static void bridge_detach(ifnet_t);
645static void bridge_link_event(struct ifnet *, u_int32_t);
646static void bridge_iflinkevent(struct ifnet *);
647static u_int32_t bridge_updatelinkstatus(struct bridge_softc *);
648static int interface_media_active(struct ifnet *);
649static void bridge_schedule_delayed_call(struct bridge_delayed_call *);
650static void bridge_cancel_delayed_call(struct bridge_delayed_call *);
fe8ab488 651static void bridge_cleanup_delayed_call(struct bridge_delayed_call *);
ea3f0419
A
652static int bridge_host_filter(struct bridge_iflist *, mbuf_t *);
653
654static errno_t bridge_mac_nat_enable(struct bridge_softc *,
655 struct bridge_iflist *);
656static void bridge_mac_nat_disable(struct bridge_softc *sc);
657static void bridge_mac_nat_age_entries(struct bridge_softc *sc, unsigned long);
658static void bridge_mac_nat_populate_entries(struct bridge_softc *sc);
659static void bridge_mac_nat_flush_entries(struct bridge_softc *sc,
660 struct bridge_iflist *);
661static ifnet_t bridge_mac_nat_input(struct bridge_softc *, mbuf_t *,
662 boolean_t *);
663static boolean_t bridge_mac_nat_output(struct bridge_softc *,
664 struct bridge_iflist *, mbuf_t *, struct mac_nat_record *);
665static void bridge_mac_nat_translate(mbuf_t *, struct mac_nat_record *,
666 const caddr_t);
6d2010ae 667
0a7de745 668#define m_copypacket(m, how) m_copym(m, 0, M_COPYALL, how)
6d2010ae
A
669
670/* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */
0a7de745 671#define VLANTAGOF(_m) 0
6d2010ae 672
316670eb 673u_int8_t bstp_etheraddr[ETHER_ADDR_LEN] =
0a7de745 674{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
316670eb 675
fe8ab488 676static u_int8_t ethernulladdr[ETHER_ADDR_LEN] =
0a7de745 677{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
fe8ab488 678
316670eb 679#if BRIDGESTP
6d2010ae
A
680static struct bstp_cb_ops bridge_ops = {
681 .bcb_state = bridge_state_change,
682 .bcb_rtage = bridge_rtable_expire
683};
316670eb 684#endif /* BRIDGESTP */
6d2010ae
A
685
686SYSCTL_DECL(_net_link);
0a7de745
A
687SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
688 "Bridge");
39236c6e
A
689
690static int bridge_inherit_mac = 0; /* share MAC with first bridge member */
691SYSCTL_INT(_net_link_bridge, OID_AUTO, inherit_mac,
0a7de745
A
692 CTLFLAG_RW | CTLFLAG_LOCKED,
693 &bridge_inherit_mac, 0,
694 "Inherit MAC address from the first bridge member");
39236c6e
A
695
696SYSCTL_INT(_net_link_bridge, OID_AUTO, rtable_prune_period,
0a7de745
A
697 CTLFLAG_RW | CTLFLAG_LOCKED,
698 &bridge_rtable_prune_period, 0,
699 "Interval between pruning of routing table");
39236c6e
A
700
701static unsigned int bridge_rtable_hash_size_max = BRIDGE_RTHASH_SIZE_MAX;
702SYSCTL_UINT(_net_link_bridge, OID_AUTO, rtable_hash_size_max,
0a7de745
A
703 CTLFLAG_RW | CTLFLAG_LOCKED,
704 &bridge_rtable_hash_size_max, 0,
705 "Maximum size of the routing hash table");
39236c6e
A
706
707#if BRIDGE_DEBUG_DELAYED_CALLBACK
708static int bridge_delayed_callback_delay = 0;
709SYSCTL_INT(_net_link_bridge, OID_AUTO, delayed_callback_delay,
0a7de745
A
710 CTLFLAG_RW | CTLFLAG_LOCKED,
711 &bridge_delayed_callback_delay, 0,
712 "Delay before calling delayed function");
39236c6e 713#endif
6d2010ae 714
fe8ab488 715SYSCTL_STRUCT(_net_link_bridge, OID_AUTO,
0a7de745
A
716 hostfilterstats, CTLFLAG_RD | CTLFLAG_LOCKED,
717 &bridge_hostfilter_stats, bridge_hostfilter_stats, "");
fe8ab488 718
6d2010ae
A
719#if defined(PFIL_HOOKS)
720static int pfil_onlyip = 1; /* only pass IP[46] packets when pfil is enabled */
721static int pfil_bridge = 1; /* run pfil hooks on the bridge interface */
722static int pfil_member = 1; /* run pfil hooks on the member interface */
723static int pfil_ipfw = 0; /* layer2 filter with ipfw */
724static int pfil_ipfw_arp = 0; /* layer2 filter with ipfw */
39236c6e 725static int pfil_local_phys = 0; /* run pfil hooks on the physical interface */
0a7de745
A
726 /* for locally destined packets */
727SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_onlyip, CTLFLAG_RW | CTLFLAG_LOCKED,
728 &pfil_onlyip, 0, "Only pass IP packets when pfil is enabled");
729SYSCTL_INT(_net_link_bridge, OID_AUTO, ipfw_arp, CTLFLAG_RW | CTLFLAG_LOCKED,
730 &pfil_ipfw_arp, 0, "Filter ARP packets through IPFW layer2");
731SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_bridge, CTLFLAG_RW | CTLFLAG_LOCKED,
732 &pfil_bridge, 0, "Packet filter on the bridge interface");
733SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_member, CTLFLAG_RW | CTLFLAG_LOCKED,
734 &pfil_member, 0, "Packet filter on the member interface");
316670eb 735SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_local_phys,
0a7de745
A
736 CTLFLAG_RW | CTLFLAG_LOCKED, &pfil_local_phys, 0,
737 "Packet filter on the physical interface for locally destined packets");
6d2010ae
A
738#endif /* PFIL_HOOKS */
739
316670eb 740#if BRIDGESTP
6d2010ae
A
741static int log_stp = 0; /* log STP state changes */
742SYSCTL_INT(_net_link_bridge, OID_AUTO, log_stp, CTLFLAG_RW,
0a7de745 743 &log_stp, 0, "Log STP state changes");
316670eb 744#endif /* BRIDGESTP */
6d2010ae
A
745
746struct bridge_control {
0a7de745
A
747 int (*bc_func)(struct bridge_softc *, void *);
748 unsigned int bc_argsize;
749 unsigned int bc_flags;
6d2010ae
A
750};
751
0a7de745
A
752#define BC_F_COPYIN 0x01 /* copy arguments in */
753#define BC_F_COPYOUT 0x02 /* copy arguments out */
754#define BC_F_SUSER 0x04 /* do super-user check */
6d2010ae
A
755
756static const struct bridge_control bridge_control_table32[] = {
cb323159
A
757 { .bc_func = bridge_ioctl_add, .bc_argsize = sizeof(struct ifbreq), /* 0 */
758 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
759 { .bc_func = bridge_ioctl_del, .bc_argsize = sizeof(struct ifbreq),
760 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 761
cb323159
A
762 { .bc_func = bridge_ioctl_gifflags, .bc_argsize = sizeof(struct ifbreq),
763 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
764 { .bc_func = bridge_ioctl_sifflags, .bc_argsize = sizeof(struct ifbreq),
765 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 766
cb323159
A
767 { .bc_func = bridge_ioctl_scache, .bc_argsize = sizeof(struct ifbrparam),
768 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
769 { .bc_func = bridge_ioctl_gcache, .bc_argsize = sizeof(struct ifbrparam),
770 .bc_flags = BC_F_COPYOUT },
316670eb 771
cb323159
A
772 { .bc_func = bridge_ioctl_gifs32, .bc_argsize = sizeof(struct ifbifconf32),
773 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
774 { .bc_func = bridge_ioctl_rts32, .bc_argsize = sizeof(struct ifbaconf32),
775 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
316670eb 776
cb323159
A
777 { .bc_func = bridge_ioctl_saddr32, .bc_argsize = sizeof(struct ifbareq32),
778 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 779
cb323159
A
780 { .bc_func = bridge_ioctl_sto, .bc_argsize = sizeof(struct ifbrparam),
781 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
782 { .bc_func = bridge_ioctl_gto, .bc_argsize = sizeof(struct ifbrparam), /* 10 */
783 .bc_flags = BC_F_COPYOUT },
316670eb 784
cb323159
A
785 { .bc_func = bridge_ioctl_daddr32, .bc_argsize = sizeof(struct ifbareq32),
786 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 787
cb323159
A
788 { .bc_func = bridge_ioctl_flush, .bc_argsize = sizeof(struct ifbreq),
789 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 790
cb323159
A
791 { .bc_func = bridge_ioctl_gpri, .bc_argsize = sizeof(struct ifbrparam),
792 .bc_flags = BC_F_COPYOUT },
793 { .bc_func = bridge_ioctl_spri, .bc_argsize = sizeof(struct ifbrparam),
794 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 795
cb323159
A
796 { .bc_func = bridge_ioctl_ght, .bc_argsize = sizeof(struct ifbrparam),
797 .bc_flags = BC_F_COPYOUT },
798 { .bc_func = bridge_ioctl_sht, .bc_argsize = sizeof(struct ifbrparam),
799 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 800
cb323159
A
801 { .bc_func = bridge_ioctl_gfd, .bc_argsize = sizeof(struct ifbrparam),
802 .bc_flags = BC_F_COPYOUT },
803 { .bc_func = bridge_ioctl_sfd, .bc_argsize = sizeof(struct ifbrparam),
804 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 805
cb323159
A
806 { .bc_func = bridge_ioctl_gma, .bc_argsize = sizeof(struct ifbrparam),
807 .bc_flags = BC_F_COPYOUT },
808 { .bc_func = bridge_ioctl_sma, .bc_argsize = sizeof(struct ifbrparam), /* 20 */
809 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 810
cb323159
A
811 { .bc_func = bridge_ioctl_sifprio, .bc_argsize = sizeof(struct ifbreq),
812 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 813
cb323159
A
814 { .bc_func = bridge_ioctl_sifcost, .bc_argsize = sizeof(struct ifbreq),
815 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 816
cb323159
A
817 { .bc_func = bridge_ioctl_gfilt, .bc_argsize = sizeof(struct ifbrparam),
818 .bc_flags = BC_F_COPYOUT },
819 { .bc_func = bridge_ioctl_sfilt, .bc_argsize = sizeof(struct ifbrparam),
820 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 821
cb323159
A
822 { .bc_func = bridge_ioctl_purge, .bc_argsize = sizeof(struct ifbreq),
823 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 824
cb323159
A
825 { .bc_func = bridge_ioctl_addspan, .bc_argsize = sizeof(struct ifbreq),
826 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
827 { .bc_func = bridge_ioctl_delspan, .bc_argsize = sizeof(struct ifbreq),
828 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
6d2010ae 829
cb323159
A
830 { .bc_func = bridge_ioctl_gbparam32, .bc_argsize = sizeof(struct ifbropreq32),
831 .bc_flags = BC_F_COPYOUT },
6d2010ae 832
cb323159
A
833 { .bc_func = bridge_ioctl_grte, .bc_argsize = sizeof(struct ifbrparam),
834 .bc_flags = BC_F_COPYOUT },
316670eb 835
cb323159
A
836 { .bc_func = bridge_ioctl_gifsstp32, .bc_argsize = sizeof(struct ifbpstpconf32), /* 30 */
837 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
316670eb 838
cb323159
A
839 { .bc_func = bridge_ioctl_sproto, .bc_argsize = sizeof(struct ifbrparam),
840 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 841
cb323159
A
842 { .bc_func = bridge_ioctl_stxhc, .bc_argsize = sizeof(struct ifbrparam),
843 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 844
cb323159
A
845 { .bc_func = bridge_ioctl_sifmaxaddr, .bc_argsize = sizeof(struct ifbreq),
846 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
fe8ab488 847
cb323159
A
848 { .bc_func = bridge_ioctl_ghostfilter, .bc_argsize = sizeof(struct ifbrhostfilter),
849 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
850 { .bc_func = bridge_ioctl_shostfilter, .bc_argsize = sizeof(struct ifbrhostfilter),
851 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
ea3f0419
A
852
853 { .bc_func = bridge_ioctl_gmnelist32, .bc_argsize = sizeof(struct ifbrmnelist32),
854 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
6d2010ae
A
855};
856
857static const struct bridge_control bridge_control_table64[] = {
cb323159
A
858 { .bc_func = bridge_ioctl_add, .bc_argsize = sizeof(struct ifbreq), /* 0 */
859 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
860 { .bc_func = bridge_ioctl_del, .bc_argsize = sizeof(struct ifbreq),
861 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
6d2010ae 862
cb323159
A
863 { .bc_func = bridge_ioctl_gifflags, .bc_argsize = sizeof(struct ifbreq),
864 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
865 { .bc_func = bridge_ioctl_sifflags, .bc_argsize = sizeof(struct ifbreq),
866 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
6d2010ae 867
cb323159
A
868 { .bc_func = bridge_ioctl_scache, .bc_argsize = sizeof(struct ifbrparam),
869 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
870 { .bc_func = bridge_ioctl_gcache, .bc_argsize = sizeof(struct ifbrparam),
871 .bc_flags = BC_F_COPYOUT },
316670eb 872
cb323159
A
873 { .bc_func = bridge_ioctl_gifs64, .bc_argsize = sizeof(struct ifbifconf64),
874 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
875 { .bc_func = bridge_ioctl_rts64, .bc_argsize = sizeof(struct ifbaconf64),
876 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
316670eb 877
cb323159
A
878 { .bc_func = bridge_ioctl_saddr64, .bc_argsize = sizeof(struct ifbareq64),
879 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 880
cb323159
A
881 { .bc_func = bridge_ioctl_sto, .bc_argsize = sizeof(struct ifbrparam),
882 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
883 { .bc_func = bridge_ioctl_gto, .bc_argsize = sizeof(struct ifbrparam), /* 10 */
884 .bc_flags = BC_F_COPYOUT },
316670eb 885
cb323159
A
886 { .bc_func = bridge_ioctl_daddr64, .bc_argsize = sizeof(struct ifbareq64),
887 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 888
cb323159
A
889 { .bc_func = bridge_ioctl_flush, .bc_argsize = sizeof(struct ifbreq),
890 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 891
cb323159
A
892 { .bc_func = bridge_ioctl_gpri, .bc_argsize = sizeof(struct ifbrparam),
893 .bc_flags = BC_F_COPYOUT },
894 { .bc_func = bridge_ioctl_spri, .bc_argsize = sizeof(struct ifbrparam),
895 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 896
cb323159
A
897 { .bc_func = bridge_ioctl_ght, .bc_argsize = sizeof(struct ifbrparam),
898 .bc_flags = BC_F_COPYOUT },
899 { .bc_func = bridge_ioctl_sht, .bc_argsize = sizeof(struct ifbrparam),
900 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 901
cb323159
A
902 { .bc_func = bridge_ioctl_gfd, .bc_argsize = sizeof(struct ifbrparam),
903 .bc_flags = BC_F_COPYOUT },
904 { .bc_func = bridge_ioctl_sfd, .bc_argsize = sizeof(struct ifbrparam),
905 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 906
cb323159
A
907 { .bc_func = bridge_ioctl_gma, .bc_argsize = sizeof(struct ifbrparam),
908 .bc_flags = BC_F_COPYOUT },
909 { .bc_func = bridge_ioctl_sma, .bc_argsize = sizeof(struct ifbrparam), /* 20 */
910 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 911
cb323159
A
912 { .bc_func = bridge_ioctl_sifprio, .bc_argsize = sizeof(struct ifbreq),
913 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 914
cb323159
A
915 { .bc_func = bridge_ioctl_sifcost, .bc_argsize = sizeof(struct ifbreq),
916 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 917
cb323159
A
918 { .bc_func = bridge_ioctl_gfilt, .bc_argsize = sizeof(struct ifbrparam),
919 .bc_flags = BC_F_COPYOUT },
920 { .bc_func = bridge_ioctl_sfilt, .bc_argsize = sizeof(struct ifbrparam),
921 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 922
cb323159
A
923 { .bc_func = bridge_ioctl_purge, .bc_argsize = sizeof(struct ifbreq),
924 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 925
cb323159
A
926 { .bc_func = bridge_ioctl_addspan, .bc_argsize = sizeof(struct ifbreq),
927 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
928 { .bc_func = bridge_ioctl_delspan, .bc_argsize = sizeof(struct ifbreq),
929 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 930
cb323159
A
931 { .bc_func = bridge_ioctl_gbparam64, .bc_argsize = sizeof(struct ifbropreq64),
932 .bc_flags = BC_F_COPYOUT },
316670eb 933
cb323159
A
934 { .bc_func = bridge_ioctl_grte, .bc_argsize = sizeof(struct ifbrparam),
935 .bc_flags = BC_F_COPYOUT },
316670eb 936
cb323159
A
937 { .bc_func = bridge_ioctl_gifsstp64, .bc_argsize = sizeof(struct ifbpstpconf64), /* 30 */
938 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
316670eb 939
cb323159
A
940 { .bc_func = bridge_ioctl_sproto, .bc_argsize = sizeof(struct ifbrparam),
941 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 942
cb323159
A
943 { .bc_func = bridge_ioctl_stxhc, .bc_argsize = sizeof(struct ifbrparam),
944 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
316670eb 945
cb323159
A
946 { .bc_func = bridge_ioctl_sifmaxaddr, .bc_argsize = sizeof(struct ifbreq),
947 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
fe8ab488 948
cb323159
A
949 { .bc_func = bridge_ioctl_ghostfilter, .bc_argsize = sizeof(struct ifbrhostfilter),
950 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
951 { .bc_func = bridge_ioctl_shostfilter, .bc_argsize = sizeof(struct ifbrhostfilter),
952 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
ea3f0419
A
953
954 { .bc_func = bridge_ioctl_gmnelist64, .bc_argsize = sizeof(struct ifbrmnelist64),
955 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
6d2010ae
A
956};
957
958static const unsigned int bridge_control_table_size =
0a7de745 959 sizeof(bridge_control_table32) / sizeof(bridge_control_table32[0]);
6d2010ae 960
316670eb 961static LIST_HEAD(, bridge_softc) bridge_list =
0a7de745 962 LIST_HEAD_INITIALIZER(bridge_list);
6d2010ae
A
963
964static lck_grp_t *bridge_lock_grp = NULL;
965static lck_attr_t *bridge_lock_attr = NULL;
966
0a7de745
A
967#define BRIDGENAME "bridge"
968#define BRIDGES_MAX IF_MAXUNIT
969#define BRIDGE_ZONE_MAX_ELEM MIN(IFNETS_MAX, BRIDGES_MAX)
d9a64523
A
970
971static struct if_clone bridge_cloner =
972 IF_CLONE_INITIALIZER(BRIDGENAME, bridge_clone_create, bridge_clone_destroy,
0a7de745 973 0, BRIDGES_MAX, BRIDGE_ZONE_MAX_ELEM, sizeof(struct bridge_softc));
6d2010ae 974
316670eb
A
975static int if_bridge_txstart = 0;
976SYSCTL_INT(_net_link_bridge, OID_AUTO, txstart, CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745 977 &if_bridge_txstart, 0, "Bridge interface uses TXSTART model");
6d2010ae
A
978
979#if BRIDGE_DEBUG
316670eb
A
980static int if_bridge_debug = 0;
981SYSCTL_INT(_net_link_bridge, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745 982 &if_bridge_debug, 0, "Bridge debug");
6d2010ae 983
39236c6e
A
984static void printf_ether_header(struct ether_header *);
985static void printf_mbuf_data(mbuf_t, size_t, size_t);
986static void printf_mbuf_pkthdr(mbuf_t, const char *, const char *);
987static void printf_mbuf(mbuf_t, const char *, const char *);
5ba3f43e 988static void link_print(struct bridge_softc * sc);
6d2010ae
A
989
990static void bridge_lock(struct bridge_softc *);
991static void bridge_unlock(struct bridge_softc *);
992static int bridge_lock2ref(struct bridge_softc *);
993static void bridge_unref(struct bridge_softc *);
994static void bridge_xlock(struct bridge_softc *);
995static void bridge_xdrop(struct bridge_softc *);
996
316670eb
A
997static void
998bridge_lock(struct bridge_softc *sc)
6d2010ae
A
999{
1000 void *lr_saved = __builtin_return_address(0);
316670eb 1001
39236c6e 1002 BRIDGE_LOCK_ASSERT_NOTHELD(sc);
6d2010ae 1003
39236c6e 1004 _BRIDGE_LOCK(sc);
316670eb 1005
6d2010ae 1006 sc->lock_lr[sc->next_lock_lr] = lr_saved;
0a7de745 1007 sc->next_lock_lr = (sc->next_lock_lr + 1) % SO_LCKDBG_MAX;
6d2010ae
A
1008}
1009
316670eb
A
1010static void
1011bridge_unlock(struct bridge_softc *sc)
6d2010ae
A
1012{
1013 void *lr_saved = __builtin_return_address(0);
316670eb 1014
39236c6e 1015 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
1016
1017 sc->unlock_lr[sc->next_unlock_lr] = lr_saved;
0a7de745 1018 sc->next_unlock_lr = (sc->next_unlock_lr + 1) % SO_LCKDBG_MAX;
316670eb 1019
39236c6e 1020 _BRIDGE_UNLOCK(sc);
6d2010ae
A
1021}
1022
316670eb
A
1023static int
1024bridge_lock2ref(struct bridge_softc *sc)
6d2010ae
A
1025{
1026 int error = 0;
1027 void *lr_saved = __builtin_return_address(0);
316670eb 1028
39236c6e 1029 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae 1030
0a7de745 1031 if (sc->sc_iflist_xcnt > 0) {
6d2010ae 1032 error = EBUSY;
0a7de745 1033 } else {
6d2010ae 1034 sc->sc_iflist_ref++;
0a7de745 1035 }
6d2010ae
A
1036
1037 sc->unlock_lr[sc->next_unlock_lr] = lr_saved;
0a7de745 1038 sc->next_unlock_lr = (sc->next_unlock_lr + 1) % SO_LCKDBG_MAX;
39236c6e
A
1039
1040 _BRIDGE_UNLOCK(sc);
316670eb 1041
0a7de745 1042 return error;
6d2010ae
A
1043}
1044
316670eb
A
1045static void
1046bridge_unref(struct bridge_softc *sc)
6d2010ae
A
1047{
1048 void *lr_saved = __builtin_return_address(0);
1049
39236c6e 1050 BRIDGE_LOCK_ASSERT_NOTHELD(sc);
6d2010ae 1051
39236c6e 1052 _BRIDGE_LOCK(sc);
6d2010ae 1053 sc->lock_lr[sc->next_lock_lr] = lr_saved;
0a7de745 1054 sc->next_lock_lr = (sc->next_lock_lr + 1) % SO_LCKDBG_MAX;
6d2010ae
A
1055
1056 sc->sc_iflist_ref--;
316670eb 1057
6d2010ae 1058 sc->unlock_lr[sc->next_unlock_lr] = lr_saved;
0a7de745 1059 sc->next_unlock_lr = (sc->next_unlock_lr + 1) % SO_LCKDBG_MAX;
316670eb 1060 if ((sc->sc_iflist_xcnt > 0) && (sc->sc_iflist_ref == 0)) {
39236c6e 1061 _BRIDGE_UNLOCK(sc);
6d2010ae 1062 wakeup(&sc->sc_cv);
0a7de745 1063 } else {
39236c6e 1064 _BRIDGE_UNLOCK(sc);
0a7de745 1065 }
6d2010ae
A
1066}
1067
316670eb
A
1068static void
1069bridge_xlock(struct bridge_softc *sc)
6d2010ae
A
1070{
1071 void *lr_saved = __builtin_return_address(0);
1072
39236c6e 1073 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
1074
1075 sc->sc_iflist_xcnt++;
1076 while (sc->sc_iflist_ref > 0) {
1077 sc->unlock_lr[sc->next_unlock_lr] = lr_saved;
0a7de745 1078 sc->next_unlock_lr = (sc->next_unlock_lr + 1) % SO_LCKDBG_MAX;
316670eb 1079
39236c6e 1080 msleep(&sc->sc_cv, &sc->sc_mtx, PZERO, "BRIDGE_XLOCK", NULL);
6d2010ae
A
1081
1082 sc->lock_lr[sc->next_lock_lr] = lr_saved;
0a7de745 1083 sc->next_lock_lr = (sc->next_lock_lr + 1) % SO_LCKDBG_MAX;
6d2010ae
A
1084 }
1085}
1086
316670eb
A
1087static void
1088bridge_xdrop(struct bridge_softc *sc)
6d2010ae 1089{
39236c6e 1090 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
1091
1092 sc->sc_iflist_xcnt--;
1093}
1094
1095void
1096printf_mbuf_pkthdr(mbuf_t m, const char *prefix, const char *suffix)
1097{
0a7de745 1098 if (m) {
39236c6e
A
1099 printf("%spktlen: %u rcvif: 0x%llx header: 0x%llx "
1100 "nextpkt: 0x%llx%s",
316670eb 1101 prefix ? prefix : "", (unsigned int)mbuf_pkthdr_len(m),
39236c6e
A
1102 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_pkthdr_rcvif(m)),
1103 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_pkthdr_header(m)),
1104 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_nextpkt(m)),
1105 suffix ? suffix : "");
0a7de745 1106 } else {
6d2010ae 1107 printf("%s<NULL>%s\n", prefix, suffix);
0a7de745 1108 }
6d2010ae
A
1109}
1110
1111void
1112printf_mbuf(mbuf_t m, const char *prefix, const char *suffix)
1113{
1114 if (m) {
39236c6e
A
1115 printf("%s0x%llx type: %u flags: 0x%x len: %u data: 0x%llx "
1116 "maxlen: %u datastart: 0x%llx next: 0x%llx%s",
1117 prefix ? prefix : "", (uint64_t)VM_KERNEL_ADDRPERM(m),
1118 mbuf_type(m), mbuf_flags(m), (unsigned int)mbuf_len(m),
1119 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_data(m)),
1120 (unsigned int)mbuf_maxlen(m),
1121 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_datastart(m)),
1122 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_next(m)),
316670eb 1123 !suffix || (mbuf_flags(m) & MBUF_PKTHDR) ? "" : suffix);
0a7de745 1124 if ((mbuf_flags(m) & MBUF_PKTHDR)) {
6d2010ae 1125 printf_mbuf_pkthdr(m, " ", suffix);
0a7de745
A
1126 }
1127 } else {
6d2010ae 1128 printf("%s<NULL>%s\n", prefix, suffix);
0a7de745 1129 }
6d2010ae
A
1130}
1131
1132void
1133printf_mbuf_data(mbuf_t m, size_t offset, size_t len)
1134{
0a7de745
A
1135 mbuf_t n;
1136 size_t i, j;
1137 size_t pktlen, mlen, maxlen;
1138 unsigned char *ptr;
316670eb 1139
6d2010ae 1140 pktlen = mbuf_pkthdr_len(m);
316670eb 1141
0a7de745 1142 if (offset > pktlen) {
6d2010ae 1143 return;
0a7de745 1144 }
316670eb 1145
fe8ab488 1146 maxlen = (pktlen - offset > len) ? len : pktlen - offset;
6d2010ae
A
1147 n = m;
1148 mlen = mbuf_len(n);
1149 ptr = mbuf_data(n);
1150 for (i = 0, j = 0; i < maxlen; i++, j++) {
1151 if (j >= mlen) {
1152 n = mbuf_next(n);
0a7de745 1153 if (n == 0) {
6d2010ae 1154 break;
0a7de745 1155 }
6d2010ae
A
1156 ptr = mbuf_data(n);
1157 mlen = mbuf_len(n);
1158 j = 0;
1159 }
1160 if (i >= offset) {
1161 printf("%02x%s", ptr[j], i % 2 ? " " : "");
1162 }
1163 }
6d2010ae
A
1164}
1165
1166static void
1167printf_ether_header(struct ether_header *eh)
1168{
316670eb
A
1169 printf("%02x:%02x:%02x:%02x:%02x:%02x > "
1170 "%02x:%02x:%02x:%02x:%02x:%02x 0x%04x ",
1171 eh->ether_shost[0], eh->ether_shost[1], eh->ether_shost[2],
1172 eh->ether_shost[3], eh->ether_shost[4], eh->ether_shost[5],
1173 eh->ether_dhost[0], eh->ether_dhost[1], eh->ether_dhost[2],
1174 eh->ether_dhost[3], eh->ether_dhost[4], eh->ether_dhost[5],
39236c6e 1175 ntohs(eh->ether_type));
6d2010ae
A
1176}
1177
1178static void
5ba3f43e 1179link_print(struct bridge_softc * sc)
6d2010ae
A
1180{
1181 int i;
5ba3f43e 1182 uint32_t sdl_buffer[offsetof(struct sockaddr_dl, sdl_data) +
0a7de745 1183 IFNAMSIZ + ETHER_ADDR_LEN];
5ba3f43e
A
1184 struct sockaddr_dl *sdl = (struct sockaddr_dl *)sdl_buffer;
1185
0a7de745 1186 memset(sdl, 0, sizeof(sdl_buffer));
5ba3f43e
A
1187 sdl->sdl_family = AF_LINK;
1188 sdl->sdl_nlen = strlen(sc->sc_if_xname);
1189 sdl->sdl_alen = ETHER_ADDR_LEN;
1190 sdl->sdl_len = offsetof(struct sockaddr_dl, sdl_data);
1191 memcpy(sdl->sdl_data, sc->sc_if_xname, sdl->sdl_nlen);
1192 memcpy(LLADDR(sdl), sc->sc_defaddr, ETHER_ADDR_LEN);
316670eb 1193
6d2010ae
A
1194#if 1
1195 printf("sdl len %d index %d family %d type 0x%x nlen %d alen %d"
5ba3f43e
A
1196 " slen %d addr ", sdl->sdl_len, sdl->sdl_index,
1197 sdl->sdl_family, sdl->sdl_type, sdl->sdl_nlen,
1198 sdl->sdl_alen, sdl->sdl_slen);
6d2010ae 1199#endif
0a7de745 1200 for (i = 0; i < sdl->sdl_alen; i++) {
5ba3f43e 1201 printf("%s%x", i ? ":" : "", (CONST_LLADDR(sdl))[i]);
0a7de745 1202 }
6d2010ae 1203 printf("\n");
6d2010ae
A
1204}
1205
ea3f0419
A
1206static boolean_t
1207bridge_debug_flag_is_set(uint32_t flag)
1208{
1209 return (if_bridge_debug & flag) != 0;
1210}
1211
6d2010ae
A
1212#endif /* BRIDGE_DEBUG */
1213
1214/*
1215 * bridgeattach:
1216 *
1217 * Pseudo-device attach routine.
1218 */
1219__private_extern__ int
39236c6e 1220bridgeattach(int n)
6d2010ae 1221{
39236c6e 1222#pragma unused(n)
6d2010ae
A
1223 int error;
1224 lck_grp_attr_t *lck_grp_attr = NULL;
316670eb 1225
0a7de745
A
1226 bridge_rtnode_pool = zinit(sizeof(struct bridge_rtnode),
1227 1024 * sizeof(struct bridge_rtnode), 0, "bridge_rtnode");
6d2010ae
A
1228 zone_change(bridge_rtnode_pool, Z_CALLERACCT, FALSE);
1229
ea3f0419
A
1230 bridge_mne_pool = zinit(sizeof(struct mac_nat_entry),
1231 256 * sizeof(struct mac_nat_entry), 0, "bridge_mac_nat_entry");
1232 zone_change(bridge_mne_pool, Z_CALLERACCT, FALSE);
1233
6d2010ae 1234 lck_grp_attr = lck_grp_attr_alloc_init();
316670eb 1235
6d2010ae 1236 bridge_lock_grp = lck_grp_alloc_init("if_bridge", lck_grp_attr);
316670eb 1237
6d2010ae 1238 bridge_lock_attr = lck_attr_alloc_init();
316670eb 1239
6d2010ae
A
1240#if BRIDGE_DEBUG
1241 lck_attr_setdebug(bridge_lock_attr);
1242#endif
1243
39236c6e 1244 lck_mtx_init(&bridge_list_mtx, bridge_lock_grp, bridge_lock_attr);
316670eb
A
1245
1246 /* can free the attributes once we've allocated the group lock */
6d2010ae 1247 lck_grp_attr_free(lck_grp_attr);
316670eb 1248
6d2010ae 1249 LIST_INIT(&bridge_list);
316670eb
A
1250
1251#if BRIDGESTP
6d2010ae 1252 bstp_sys_init();
316670eb
A
1253#endif /* BRIDGESTP */
1254
d9a64523 1255 error = if_clone_attach(&bridge_cloner);
0a7de745 1256 if (error != 0) {
316670eb 1257 printf("%s: ifnet_clone_attach failed %d\n", __func__, error);
0a7de745 1258 }
6d2010ae 1259
0a7de745 1260 return error;
6d2010ae
A
1261}
1262
1263#if defined(PFIL_HOOKS)
1264/*
1265 * handler for net.link.bridge.pfil_ipfw
1266 */
1267static int
1268sysctl_pfil_ipfw SYSCTL_HANDLER_ARGS
1269{
316670eb 1270#pragma unused(arg1, arg2)
6d2010ae
A
1271 int enable = pfil_ipfw;
1272 int error;
1273
1274 error = sysctl_handle_int(oidp, &enable, 0, req);
1275 enable = (enable) ? 1 : 0;
1276
1277 if (enable != pfil_ipfw) {
1278 pfil_ipfw = enable;
1279
1280 /*
1281 * Disable pfil so that ipfw doesnt run twice, if the user
1282 * really wants both then they can re-enable pfil_bridge and/or
1283 * pfil_member. Also allow non-ip packets as ipfw can filter by
1284 * layer2 type.
1285 */
1286 if (pfil_ipfw) {
1287 pfil_onlyip = 0;
1288 pfil_bridge = 0;
1289 pfil_member = 0;
1290 }
1291 }
1292
0a7de745 1293 return error;
6d2010ae 1294}
316670eb 1295
0a7de745
A
1296SYSCTL_PROC(_net_link_bridge, OID_AUTO, ipfw, CTLTYPE_INT | CTLFLAG_RW,
1297 &pfil_ipfw, 0, &sysctl_pfil_ipfw, "I", "Layer2 filter with IPFW");
6d2010ae
A
1298#endif /* PFIL_HOOKS */
1299
5ba3f43e
A
1300static errno_t
1301bridge_ifnet_set_attrs(struct ifnet * ifp)
1302{
0a7de745 1303 errno_t error;
5ba3f43e
A
1304
1305 error = ifnet_set_mtu(ifp, ETHERMTU);
1306 if (error != 0) {
1307 printf("%s: ifnet_set_mtu failed %d\n", __func__, error);
1308 goto done;
1309 }
1310 error = ifnet_set_addrlen(ifp, ETHER_ADDR_LEN);
1311 if (error != 0) {
1312 printf("%s: ifnet_set_addrlen failed %d\n", __func__, error);
1313 goto done;
1314 }
1315 error = ifnet_set_hdrlen(ifp, ETHER_HDR_LEN);
1316 if (error != 0) {
1317 printf("%s: ifnet_set_hdrlen failed %d\n", __func__, error);
1318 goto done;
1319 }
1320 error = ifnet_set_flags(ifp,
1321 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST,
1322 0xffff);
1323
1324 if (error != 0) {
1325 printf("%s: ifnet_set_flags failed %d\n", __func__, error);
1326 goto done;
1327 }
0a7de745
A
1328done:
1329 return error;
5ba3f43e
A
1330}
1331
6d2010ae
A
1332/*
1333 * bridge_clone_create:
1334 *
1335 * Create a new bridge instance.
1336 */
1337static int
39236c6e 1338bridge_clone_create(struct if_clone *ifc, uint32_t unit, void *params)
6d2010ae 1339{
39236c6e 1340#pragma unused(params)
6d2010ae 1341 struct ifnet *ifp = NULL;
d9a64523
A
1342 struct bridge_softc *sc = NULL;
1343 struct bridge_softc *sc2 = NULL;
316670eb 1344 struct ifnet_init_eparams init_params;
6d2010ae 1345 errno_t error = 0;
39236c6e
A
1346 uint8_t eth_hostid[ETHER_ADDR_LEN];
1347 int fb, retry, has_hostid;
6d2010ae 1348
d9a64523
A
1349 sc = if_clone_softc_allocate(&bridge_cloner);
1350 if (sc == NULL) {
1351 error = ENOMEM;
1352 goto done;
1353 }
6d2010ae 1354
39236c6e 1355 lck_mtx_init(&sc->sc_mtx, bridge_lock_grp, bridge_lock_attr);
6d2010ae 1356 sc->sc_brtmax = BRIDGE_RTABLE_MAX;
ea3f0419 1357 sc->sc_mne_max = BRIDGE_MAC_NAT_ENTRY_MAX;
6d2010ae 1358 sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT;
ea3f0419 1359 sc->sc_filter_flags = 0;
6d2010ae 1360
6d2010ae 1361 TAILQ_INIT(&sc->sc_iflist);
6d2010ae
A
1362
1363 /* use the interface name as the unique id for ifp recycle */
0a7de745 1364 snprintf(sc->sc_if_xname, sizeof(sc->sc_if_xname), "%s%d",
39236c6e 1365 ifc->ifc_name, unit);
0a7de745
A
1366 bzero(&init_params, sizeof(init_params));
1367 init_params.ver = IFNET_INIT_CURRENT_VERSION;
1368 init_params.len = sizeof(init_params);
cb323159
A
1369 /* Initialize our routing table. */
1370 error = bridge_rtable_init(sc);
1371 if (error != 0) {
1372 printf("%s: bridge_rtable_init failed %d\n",
1373 __func__, error);
1374 goto done;
1375 }
1376 TAILQ_INIT(&sc->sc_spanlist);
1377 if (if_bridge_txstart) {
1378 init_params.start = bridge_start;
1379 } else {
1380 init_params.flags = IFNET_INIT_LEGACY;
1381 init_params.output = bridge_output;
0a7de745 1382 }
cb323159 1383 init_params.set_bpf_tap = bridge_set_bpf_tap;
0a7de745
A
1384 init_params.uniqueid = sc->sc_if_xname;
1385 init_params.uniqueid_len = strlen(sc->sc_if_xname);
1386 init_params.sndq_maxlen = IFQ_MAXLEN;
1387 init_params.name = ifc->ifc_name;
1388 init_params.unit = unit;
1389 init_params.family = IFNET_FAMILY_ETHERNET;
1390 init_params.type = IFT_BRIDGE;
1391 init_params.demux = ether_demux;
1392 init_params.add_proto = ether_add_proto;
1393 init_params.del_proto = ether_del_proto;
1394 init_params.check_multi = ether_check_multi;
1395 init_params.framer_extended = ether_frameout_extended;
1396 init_params.softc = sc;
1397 init_params.ioctl = bridge_ioctl;
1398 init_params.detach = bridge_detach;
1399 init_params.broadcast_addr = etherbroadcastaddr;
1400 init_params.broadcast_len = ETHER_ADDR_LEN;
316670eb 1401
cb323159
A
1402 error = ifnet_allocate_extended(&init_params, &ifp);
1403 if (error != 0) {
1404 printf("%s: ifnet_allocate failed %d\n",
1405 __func__, error);
1406 goto done;
1407 }
ea3f0419
A
1408 LIST_INIT(&sc->sc_mne_list);
1409 LIST_INIT(&sc->sc_mne_list_v6);
cb323159
A
1410 sc->sc_ifp = ifp;
1411 error = bridge_ifnet_set_attrs(ifp);
1412 if (error != 0) {
1413 printf("%s: bridge_ifnet_set_attrs failed %d\n",
1414 __func__, error);
1415 goto done;
6d2010ae 1416 }
6d2010ae 1417 /*
39236c6e 1418 * Generate an ethernet address with a locally administered address.
6d2010ae
A
1419 *
1420 * Since we are using random ethernet addresses for the bridge, it is
1421 * possible that we might have address collisions, so make sure that
1422 * this hardware address isn't already in use on another bridge.
5ba3f43e 1423 * The first try uses the "hostid" and falls back to read_frandom();
39236c6e
A
1424 * for "hostid", we use the MAC address of the first-encountered
1425 * Ethernet-type interface that is currently configured.
6d2010ae 1426 */
39236c6e
A
1427 fb = 0;
1428 has_hostid = (uuid_get_ethernet(&eth_hostid[0]) == 0);
0a7de745 1429 for (retry = 1; retry != 0;) {
39236c6e 1430 if (fb || has_hostid == 0) {
5ba3f43e 1431 read_frandom(&sc->sc_defaddr, ETHER_ADDR_LEN);
39236c6e
A
1432 sc->sc_defaddr[0] &= ~1; /* clear multicast bit */
1433 sc->sc_defaddr[0] |= 2; /* set the LAA bit */
1434 } else {
1435 bcopy(&eth_hostid[0], &sc->sc_defaddr,
1436 ETHER_ADDR_LEN);
1437 sc->sc_defaddr[0] &= ~1; /* clear multicast bit */
1438 sc->sc_defaddr[0] |= 2; /* set the LAA bit */
0a7de745 1439 sc->sc_defaddr[3] = /* stir it up a bit */
39236c6e
A
1440 ((sc->sc_defaddr[3] & 0x0f) << 4) |
1441 ((sc->sc_defaddr[3] & 0xf0) >> 4);
1442 /*
1443 * Mix in the LSB as it's actually pretty significant,
1444 * see rdar://14076061
1445 */
1446 sc->sc_defaddr[4] =
1447 (((sc->sc_defaddr[4] & 0x0f) << 4) |
fe8ab488 1448 ((sc->sc_defaddr[4] & 0xf0) >> 4)) ^
39236c6e
A
1449 sc->sc_defaddr[5];
1450 sc->sc_defaddr[5] = ifp->if_unit & 0xff;
6d2010ae 1451 }
316670eb 1452
39236c6e
A
1453 fb = 1;
1454 retry = 0;
1455 lck_mtx_lock(&bridge_list_mtx);
1456 LIST_FOREACH(sc2, &bridge_list, sc_list) {
1457 if (memcmp(sc->sc_defaddr,
0a7de745 1458 IF_LLADDR(sc2->sc_ifp), ETHER_ADDR_LEN) == 0) {
39236c6e 1459 retry = 1;
0a7de745 1460 }
39236c6e
A
1461 }
1462 lck_mtx_unlock(&bridge_list_mtx);
6d2010ae 1463 }
6d2010ae 1464
39236c6e 1465 sc->sc_flags &= ~SCF_MEDIA_ACTIVE;
316670eb 1466
6d2010ae 1467#if BRIDGE_DEBUG
ea3f0419 1468 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
5ba3f43e 1469 link_print(sc);
0a7de745 1470 }
6d2010ae 1471#endif
cb323159
A
1472 error = ifnet_attach(ifp, NULL);
1473 if (error != 0) {
1474 printf("%s: ifnet_attach failed %d\n", __func__, error);
1475 goto done;
6d2010ae 1476 }
316670eb 1477
39236c6e 1478 error = ifnet_set_lladdr_and_type(ifp, sc->sc_defaddr, ETHER_ADDR_LEN,
316670eb 1479 IFT_ETHER);
6d2010ae 1480 if (error != 0) {
316670eb
A
1481 printf("%s: ifnet_set_lladdr_and_type failed %d\n", __func__,
1482 error);
6d2010ae
A
1483 goto done;
1484 }
316670eb 1485
cb323159
A
1486 ifnet_set_offload(ifp,
1487 IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP |
1488 IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | IFNET_MULTIPAGES);
1489 error = bridge_set_tso(sc);
1490 if (error != 0) {
1491 printf("%s: bridge_set_tso failed %d\n",
1492 __func__, error);
1493 goto done;
1494 }
316670eb 1495#if BRIDGESTP
cb323159 1496 bstp_attach(&sc->sc_stp, &bridge_ops);
316670eb 1497#endif /* BRIDGESTP */
6d2010ae 1498
39236c6e 1499 lck_mtx_lock(&bridge_list_mtx);
6d2010ae 1500 LIST_INSERT_HEAD(&bridge_list, sc, sc_list);
39236c6e 1501 lck_mtx_unlock(&bridge_list_mtx);
6d2010ae
A
1502
1503 /* attach as ethernet */
0a7de745 1504 error = bpf_attach(ifp, DLT_EN10MB, sizeof(struct ether_header),
316670eb 1505 NULL, NULL);
6d2010ae
A
1506
1507done:
1508 if (error != 0) {
316670eb 1509 printf("%s failed error %d\n", __func__, error);
d9a64523 1510 /* TBD: Clean up: sc, sc_rthash etc */
6d2010ae 1511 }
316670eb 1512
0a7de745 1513 return error;
6d2010ae
A
1514}
1515
1516/*
1517 * bridge_clone_destroy:
1518 *
1519 * Destroy a bridge instance.
1520 */
1521static int
1522bridge_clone_destroy(struct ifnet *ifp)
1523{
1524 struct bridge_softc *sc = ifp->if_softc;
1525 struct bridge_iflist *bif;
1526 errno_t error;
1527
1528 BRIDGE_LOCK(sc);
1529 if ((sc->sc_flags & SCF_DETACHING)) {
1530 BRIDGE_UNLOCK(sc);
0a7de745 1531 return 0;
6d2010ae
A
1532 }
1533 sc->sc_flags |= SCF_DETACHING;
1534
316670eb 1535 bridge_ifstop(ifp, 1);
6d2010ae 1536
cb323159 1537 bridge_cancel_delayed_call(&sc->sc_resize_call);
39236c6e 1538
cb323159
A
1539 bridge_cleanup_delayed_call(&sc->sc_resize_call);
1540 bridge_cleanup_delayed_call(&sc->sc_aging_timer);
fe8ab488 1541
6d2010ae
A
1542 error = ifnet_set_flags(ifp, 0, IFF_UP);
1543 if (error != 0) {
316670eb 1544 printf("%s: ifnet_set_flags failed %d\n", __func__, error);
6d2010ae
A
1545 }
1546
0a7de745 1547 while ((bif = TAILQ_FIRST(&sc->sc_iflist)) != NULL) {
6d2010ae 1548 bridge_delete_member(sc, bif, 0);
0a7de745 1549 }
6d2010ae 1550
cb323159
A
1551 while ((bif = TAILQ_FIRST(&sc->sc_spanlist)) != NULL) {
1552 bridge_delete_span(sc, bif);
6d2010ae 1553 }
cb323159 1554 BRIDGE_UNLOCK(sc);
6d2010ae 1555
6d2010ae
A
1556 error = ifnet_detach(ifp);
1557 if (error != 0) {
5ba3f43e 1558 panic("%s: ifnet_detach(%p) failed %d\n",
0a7de745
A
1559 __func__, ifp, error);
1560 }
1561 return 0;
1562}
1563
1564#define DRVSPEC do { \
1565 if (ifd->ifd_cmd >= bridge_control_table_size) { \
1566 error = EINVAL; \
1567 break; \
1568 } \
1569 bc = &bridge_control_table[ifd->ifd_cmd]; \
1570 \
1571 if (cmd == SIOCGDRVSPEC && \
1572 (bc->bc_flags & BC_F_COPYOUT) == 0) { \
1573 error = EINVAL; \
1574 break; \
1575 } else if (cmd == SIOCSDRVSPEC && \
1576 (bc->bc_flags & BC_F_COPYOUT) != 0) { \
1577 error = EINVAL; \
1578 break; \
1579 } \
1580 \
1581 if (bc->bc_flags & BC_F_SUSER) { \
1582 error = kauth_authorize_generic(kauth_cred_get(), \
1583 KAUTH_GENERIC_ISSUSER); \
1584 if (error) \
1585 break; \
1586 } \
1587 \
1588 if (ifd->ifd_len != bc->bc_argsize || \
1589 ifd->ifd_len > sizeof (args)) { \
1590 error = EINVAL; \
1591 break; \
1592 } \
1593 \
1594 bzero(&args, sizeof (args)); \
1595 if (bc->bc_flags & BC_F_COPYIN) { \
1596 error = copyin(ifd->ifd_data, &args, ifd->ifd_len); \
1597 if (error) \
1598 break; \
1599 } \
1600 \
1601 BRIDGE_LOCK(sc); \
1602 error = (*bc->bc_func)(sc, &args); \
1603 BRIDGE_UNLOCK(sc); \
1604 if (error) \
1605 break; \
1606 \
1607 if (bc->bc_flags & BC_F_COPYOUT) \
1608 error = copyout(&args, ifd->ifd_data, ifd->ifd_len); \
6d2010ae
A
1609} while (0)
1610
6d2010ae
A
1611/*
1612 * bridge_ioctl:
1613 *
1614 * Handle a control request from the operator.
1615 */
1616static errno_t
1617bridge_ioctl(struct ifnet *ifp, u_long cmd, void *data)
1618{
1619 struct bridge_softc *sc = ifp->if_softc;
316670eb 1620 struct ifreq *ifr = (struct ifreq *)data;
39236c6e 1621 struct bridge_iflist *bif;
6d2010ae
A
1622 int error = 0;
1623
39236c6e 1624 BRIDGE_LOCK_ASSERT_NOTHELD(sc);
6d2010ae
A
1625
1626#if BRIDGE_DEBUG
ea3f0419 1627 if (IF_BRIDGE_DEBUG(BR_DBGF_IOCTL)) {
39236c6e
A
1628 printf("%s: ifp %s cmd 0x%08lx (%c%c [%lu] %c %lu)\n",
1629 __func__, ifp->if_xname, cmd, (cmd & IOC_IN) ? 'I' : ' ',
316670eb
A
1630 (cmd & IOC_OUT) ? 'O' : ' ', IOCPARM_LEN(cmd),
1631 (char)IOCGROUP(cmd), cmd & 0xff);
0a7de745 1632 }
39236c6e 1633#endif /* BRIDGE_DEBUG */
316670eb 1634
6d2010ae 1635 switch (cmd) {
6d2010ae
A
1636 case SIOCSIFADDR:
1637 case SIOCAIFADDR:
1638 ifnet_set_flags(ifp, IFF_UP, IFF_UP);
1639 break;
1640
1641 case SIOCGIFMEDIA32:
39236c6e
A
1642 case SIOCGIFMEDIA64: {
1643 struct ifmediareq *ifmr = (struct ifmediareq *)data;
1644 user_addr_t user_addr;
1645
1646 user_addr = (cmd == SIOCGIFMEDIA64) ?
1647 ((struct ifmediareq64 *)ifmr)->ifmu_ulist :
1648 CAST_USER_ADDR_T(((struct ifmediareq32 *)ifmr)->ifmu_ulist);
1649
1650 ifmr->ifm_status = IFM_AVALID;
1651 ifmr->ifm_mask = 0;
1652 ifmr->ifm_count = 1;
1653
1654 BRIDGE_LOCK(sc);
1655 if (!(sc->sc_flags & SCF_DETACHING) &&
1656 (sc->sc_flags & SCF_MEDIA_ACTIVE)) {
1657 ifmr->ifm_status |= IFM_ACTIVE;
1658 ifmr->ifm_active = ifmr->ifm_current =
1659 IFM_ETHER | IFM_AUTO;
1660 } else {
1661 ifmr->ifm_active = ifmr->ifm_current = IFM_NONE;
1662 }
1663 BRIDGE_UNLOCK(sc);
1664
1665 if (user_addr != USER_ADDR_NULL) {
1666 error = copyout(&ifmr->ifm_current, user_addr,
0a7de745 1667 sizeof(int));
39236c6e 1668 }
6d2010ae 1669 break;
39236c6e 1670 }
6d2010ae
A
1671
1672 case SIOCADDMULTI:
1673 case SIOCDELMULTI:
1674 break;
1675
1676 case SIOCSDRVSPEC32:
1677 case SIOCGDRVSPEC32: {
1678 union {
1679 struct ifbreq ifbreq;
1680 struct ifbifconf32 ifbifconf;
1681 struct ifbareq32 ifbareq;
1682 struct ifbaconf32 ifbaconf;
1683 struct ifbrparam ifbrparam;
1684 struct ifbropreq32 ifbropreq;
1685 } args;
316670eb
A
1686 struct ifdrv32 *ifd = (struct ifdrv32 *)data;
1687 const struct bridge_control *bridge_control_table =
1688 bridge_control_table32, *bc;
1689
6d2010ae
A
1690 DRVSPEC;
1691
1692 break;
1693 }
1694 case SIOCSDRVSPEC64:
1695 case SIOCGDRVSPEC64: {
1696 union {
1697 struct ifbreq ifbreq;
1698 struct ifbifconf64 ifbifconf;
1699 struct ifbareq64 ifbareq;
1700 struct ifbaconf64 ifbaconf;
1701 struct ifbrparam ifbrparam;
1702 struct ifbropreq64 ifbropreq;
1703 } args;
316670eb
A
1704 struct ifdrv64 *ifd = (struct ifdrv64 *)data;
1705 const struct bridge_control *bridge_control_table =
1706 bridge_control_table64, *bc;
1707
6d2010ae 1708 DRVSPEC;
316670eb 1709
6d2010ae
A
1710 break;
1711 }
1712
1713 case SIOCSIFFLAGS:
1714 if (!(ifp->if_flags & IFF_UP) &&
1715 (ifp->if_flags & IFF_RUNNING)) {
1716 /*
1717 * If interface is marked down and it is running,
1718 * then stop and disable it.
1719 */
1720 BRIDGE_LOCK(sc);
316670eb 1721 bridge_ifstop(ifp, 1);
6d2010ae
A
1722 BRIDGE_UNLOCK(sc);
1723 } else if ((ifp->if_flags & IFF_UP) &&
1724 !(ifp->if_flags & IFF_RUNNING)) {
1725 /*
1726 * If interface is marked up and it is stopped, then
1727 * start it.
1728 */
1729 BRIDGE_LOCK(sc);
1730 error = bridge_init(ifp);
1731 BRIDGE_UNLOCK(sc);
1732 }
1733 break;
1734
1735 case SIOCSIFLLADDR:
316670eb
A
1736 error = ifnet_set_lladdr(ifp, ifr->ifr_addr.sa_data,
1737 ifr->ifr_addr.sa_len);
0a7de745 1738 if (error != 0) {
39236c6e 1739 printf("%s: SIOCSIFLLADDR error %d\n", ifp->if_xname,
316670eb 1740 error);
0a7de745 1741 }
6d2010ae
A
1742 break;
1743
1744 case SIOCSIFMTU:
39236c6e
A
1745 if (ifr->ifr_mtu < 576) {
1746 error = EINVAL;
1747 break;
1748 }
1749 BRIDGE_LOCK(sc);
1750 if (TAILQ_EMPTY(&sc->sc_iflist)) {
1751 sc->sc_ifp->if_mtu = ifr->ifr_mtu;
1752 BRIDGE_UNLOCK(sc);
1753 break;
1754 }
1755 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
1756 if (bif->bif_ifp->if_mtu != (unsigned)ifr->ifr_mtu) {
1757 printf("%s: invalid MTU: %u(%s) != %d\n",
1758 sc->sc_ifp->if_xname,
1759 bif->bif_ifp->if_mtu,
1760 bif->bif_ifp->if_xname, ifr->ifr_mtu);
1761 error = EINVAL;
1762 break;
1763 }
1764 }
0a7de745 1765 if (!error) {
39236c6e 1766 sc->sc_ifp->if_mtu = ifr->ifr_mtu;
0a7de745 1767 }
39236c6e 1768 BRIDGE_UNLOCK(sc);
6d2010ae
A
1769 break;
1770
1771 default:
6d2010ae
A
1772 error = ether_ioctl(ifp, cmd, data);
1773#if BRIDGE_DEBUG
0a7de745 1774 if (error != 0 && error != EOPNOTSUPP) {
39236c6e 1775 printf("%s: ifp %s cmd 0x%08lx "
316670eb 1776 "(%c%c [%lu] %c %lu) failed error: %d\n",
39236c6e
A
1777 __func__, ifp->if_xname, cmd,
1778 (cmd & IOC_IN) ? 'I' : ' ',
316670eb
A
1779 (cmd & IOC_OUT) ? 'O' : ' ',
1780 IOCPARM_LEN(cmd), (char)IOCGROUP(cmd),
1781 cmd & 0xff, error);
0a7de745 1782 }
6d2010ae
A
1783#endif /* BRIDGE_DEBUG */
1784 break;
1785 }
39236c6e 1786 BRIDGE_LOCK_ASSERT_NOTHELD(sc);
6d2010ae 1787
0a7de745 1788 return error;
6d2010ae
A
1789}
1790
1791#if HAS_IF_CAP
1792/*
1793 * bridge_mutecaps:
1794 *
1795 * Clear or restore unwanted capabilities on the member interface
1796 */
1797static void
1798bridge_mutecaps(struct bridge_softc *sc)
1799{
1800 struct bridge_iflist *bif;
1801 int enabled, mask;
1802
1803 /* Initial bitmask of capabilities to test */
1804 mask = BRIDGE_IFCAPS_MASK;
1805
1806 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
1807 /* Every member must support it or its disabled */
1808 mask &= bif->bif_savedcaps;
1809 }
1810
1811 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
1812 enabled = bif->bif_ifp->if_capenable;
1813 enabled &= ~BRIDGE_IFCAPS_STRIP;
1814 /* strip off mask bits and enable them again if allowed */
1815 enabled &= ~BRIDGE_IFCAPS_MASK;
1816 enabled |= mask;
1817
1818 bridge_set_ifcap(sc, bif, enabled);
1819 }
6d2010ae
A
1820}
1821
1822static void
1823bridge_set_ifcap(struct bridge_softc *sc, struct bridge_iflist *bif, int set)
1824{
1825 struct ifnet *ifp = bif->bif_ifp;
1826 struct ifreq ifr;
1827 int error;
1828
0a7de745 1829 bzero(&ifr, sizeof(ifr));
6d2010ae
A
1830 ifr.ifr_reqcap = set;
1831
1832 if (ifp->if_capenable != set) {
1833 IFF_LOCKGIANT(ifp);
1834 error = (*ifp->if_ioctl)(ifp, SIOCSIFCAP, (caddr_t)&ifr);
1835 IFF_UNLOCKGIANT(ifp);
0a7de745 1836 if (error) {
39236c6e
A
1837 printf("%s: %s error setting interface capabilities "
1838 "on %s\n", __func__, sc->sc_ifp->if_xname,
1839 ifp->if_xname);
0a7de745 1840 }
6d2010ae
A
1841 }
1842}
1843#endif /* HAS_IF_CAP */
1844
39236c6e
A
1845static errno_t
1846bridge_set_tso(struct bridge_softc *sc)
1847{
1848 struct bridge_iflist *bif;
1849 u_int32_t tso_v4_mtu;
1850 u_int32_t tso_v6_mtu;
1851 ifnet_offload_t offload;
1852 errno_t error = 0;
1853
1854 /* By default, support TSO */
1855 offload = sc->sc_ifp->if_hwassist | IFNET_TSO_IPV4 | IFNET_TSO_IPV6;
1856 tso_v4_mtu = IP_MAXPACKET;
1857 tso_v6_mtu = IP_MAXPACKET;
1858
1859 /* Use the lowest common denominator of the members */
1860 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
1861 ifnet_t ifp = bif->bif_ifp;
1862
0a7de745 1863 if (ifp == NULL) {
39236c6e 1864 continue;
0a7de745 1865 }
39236c6e
A
1866
1867 if (offload & IFNET_TSO_IPV4) {
1868 if (ifp->if_hwassist & IFNET_TSO_IPV4) {
0a7de745 1869 if (tso_v4_mtu > ifp->if_tso_v4_mtu) {
39236c6e 1870 tso_v4_mtu = ifp->if_tso_v4_mtu;
0a7de745 1871 }
39236c6e
A
1872 } else {
1873 offload &= ~IFNET_TSO_IPV4;
1874 tso_v4_mtu = 0;
1875 }
1876 }
1877 if (offload & IFNET_TSO_IPV6) {
1878 if (ifp->if_hwassist & IFNET_TSO_IPV6) {
0a7de745 1879 if (tso_v6_mtu > ifp->if_tso_v6_mtu) {
39236c6e 1880 tso_v6_mtu = ifp->if_tso_v6_mtu;
0a7de745 1881 }
39236c6e
A
1882 } else {
1883 offload &= ~IFNET_TSO_IPV6;
1884 tso_v6_mtu = 0;
1885 }
1886 }
1887 }
1888
1889 if (offload != sc->sc_ifp->if_hwassist) {
1890 error = ifnet_set_offload(sc->sc_ifp, offload);
1891 if (error != 0) {
1892#if BRIDGE_DEBUG
ea3f0419 1893 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
39236c6e
A
1894 printf("%s: ifnet_set_offload(%s, 0x%x) "
1895 "failed %d\n", __func__,
1896 sc->sc_ifp->if_xname, offload, error);
0a7de745 1897 }
39236c6e
A
1898#endif /* BRIDGE_DEBUG */
1899 goto done;
1900 }
1901 /*
1902 * For ifnet_set_tso_mtu() sake, the TSO MTU must be at least
1903 * as large as the interface MTU
1904 */
1905 if (sc->sc_ifp->if_hwassist & IFNET_TSO_IPV4) {
0a7de745 1906 if (tso_v4_mtu < sc->sc_ifp->if_mtu) {
39236c6e 1907 tso_v4_mtu = sc->sc_ifp->if_mtu;
0a7de745 1908 }
39236c6e
A
1909 error = ifnet_set_tso_mtu(sc->sc_ifp, AF_INET,
1910 tso_v4_mtu);
1911 if (error != 0) {
1912#if BRIDGE_DEBUG
ea3f0419 1913 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
39236c6e
A
1914 printf("%s: ifnet_set_tso_mtu(%s, "
1915 "AF_INET, %u) failed %d\n",
1916 __func__, sc->sc_ifp->if_xname,
1917 tso_v4_mtu, error);
0a7de745 1918 }
39236c6e
A
1919#endif /* BRIDGE_DEBUG */
1920 goto done;
1921 }
1922 }
1923 if (sc->sc_ifp->if_hwassist & IFNET_TSO_IPV6) {
0a7de745 1924 if (tso_v6_mtu < sc->sc_ifp->if_mtu) {
39236c6e 1925 tso_v6_mtu = sc->sc_ifp->if_mtu;
0a7de745 1926 }
39236c6e
A
1927 error = ifnet_set_tso_mtu(sc->sc_ifp, AF_INET6,
1928 tso_v6_mtu);
1929 if (error != 0) {
1930#if BRIDGE_DEBUG
ea3f0419 1931 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
39236c6e
A
1932 printf("%s: ifnet_set_tso_mtu(%s, "
1933 "AF_INET6, %u) failed %d\n",
1934 __func__, sc->sc_ifp->if_xname,
1935 tso_v6_mtu, error);
0a7de745 1936 }
39236c6e
A
1937#endif /* BRIDGE_DEBUG */
1938 goto done;
1939 }
1940 }
1941 }
1942done:
0a7de745 1943 return error;
39236c6e
A
1944}
1945
6d2010ae
A
1946/*
1947 * bridge_lookup_member:
1948 *
1949 * Lookup a bridge member interface.
1950 */
1951static struct bridge_iflist *
1952bridge_lookup_member(struct bridge_softc *sc, const char *name)
1953{
1954 struct bridge_iflist *bif;
1955 struct ifnet *ifp;
6d2010ae 1956
39236c6e 1957 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
1958
1959 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
1960 ifp = bif->bif_ifp;
0a7de745
A
1961 if (strcmp(ifp->if_xname, name) == 0) {
1962 return bif;
1963 }
6d2010ae
A
1964 }
1965
0a7de745 1966 return NULL;
6d2010ae
A
1967}
1968
1969/*
1970 * bridge_lookup_member_if:
1971 *
1972 * Lookup a bridge member interface by ifnet*.
1973 */
1974static struct bridge_iflist *
1975bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp)
1976{
1977 struct bridge_iflist *bif;
1978
39236c6e 1979 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
1980
1981 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
0a7de745
A
1982 if (bif->bif_ifp == member_ifp) {
1983 return bif;
1984 }
6d2010ae
A
1985 }
1986
0a7de745 1987 return NULL;
6d2010ae
A
1988}
1989
316670eb 1990static errno_t
39236c6e 1991bridge_iff_input(void *cookie, ifnet_t ifp, protocol_family_t protocol,
0a7de745 1992 mbuf_t *data, char **frame_ptr)
6d2010ae 1993{
39236c6e 1994#pragma unused(protocol)
6d2010ae
A
1995 errno_t error = 0;
1996 struct bridge_iflist *bif = (struct bridge_iflist *)cookie;
1997 struct bridge_softc *sc = bif->bif_sc;
1998 int included = 0;
1999 size_t frmlen = 0;
2000 mbuf_t m = *data;
2001
0a7de745 2002 if ((m->m_flags & M_PROTO1)) {
6d2010ae 2003 goto out;
0a7de745 2004 }
316670eb
A
2005
2006 if (*frame_ptr >= (char *)mbuf_datastart(m) &&
2007 *frame_ptr <= (char *)mbuf_data(m)) {
6d2010ae
A
2008 included = 1;
2009 frmlen = (char *)mbuf_data(m) - *frame_ptr;
2010 }
2011#if BRIDGE_DEBUG
ea3f0419 2012 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT)) {
39236c6e
A
2013 printf("%s: %s from %s m 0x%llx data 0x%llx frame 0x%llx %s "
2014 "frmlen %lu\n", __func__, sc->sc_ifp->if_xname,
2015 ifp->if_xname, (uint64_t)VM_KERNEL_ADDRPERM(m),
2016 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_data(m)),
2017 (uint64_t)VM_KERNEL_ADDRPERM(*frame_ptr),
316670eb
A
2018 included ? "inside" : "outside", frmlen);
2019
ea3f0419 2020 if (IF_BRIDGE_DEBUG(BR_DBGF_MBUF)) {
6d2010ae 2021 printf_mbuf(m, "bridge_iff_input[", "\n");
316670eb
A
2022 printf_ether_header((struct ether_header *)
2023 (void *)*frame_ptr);
6d2010ae
A
2024 printf_mbuf_data(m, 0, 20);
2025 printf("\n");
2026 }
2027 }
2028#endif /* BRIDGE_DEBUG */
ea3f0419
A
2029 if (included == 0) {
2030 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT)) {
2031 printf("%s: frame_ptr outside mbuf\n", __func__);
2032 }
2033 goto out;
2034 }
6d2010ae
A
2035
2036 /* Move data pointer to start of frame to the link layer header */
ea3f0419
A
2037 (void) mbuf_setdata(m, (char *)mbuf_data(m) - frmlen,
2038 mbuf_len(m) + frmlen);
2039 (void) mbuf_pkthdr_adjustlen(m, frmlen);
2040
2041 /* make sure we can access the ethernet header */
2042 if (mbuf_pkthdr_len(m) < sizeof(struct ether_header)) {
2043 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT)) {
2044 printf("%s: short frame %lu < %lu\n", __func__,
2045 mbuf_pkthdr_len(m), sizeof(struct ether_header));
2046 }
6d2010ae
A
2047 goto out;
2048 }
ea3f0419
A
2049 if (mbuf_len(m) < sizeof(struct ether_header)) {
2050 error = mbuf_pullup(data, sizeof(struct ether_header));
2051 if (error != 0) {
2052 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT)) {
2053 printf("%s: mbuf_pullup(%lu) failed %d\n",
2054 __func__, sizeof(struct ether_header),
2055 error);
2056 }
2057 error = EJUSTRETURN;
2058 goto out;
2059 }
2060 if (m != *data) {
2061 m = *data;
2062 *frame_ptr = mbuf_data(m);
2063 }
2064 }
316670eb 2065
ea3f0419 2066 error = bridge_input(ifp, data);
316670eb 2067
6d2010ae
A
2068 /* Adjust packet back to original */
2069 if (error == 0) {
ea3f0419
A
2070 /* bridge_input might have modified *data */
2071 if (*data != m) {
2072 m = *data;
2073 *frame_ptr = mbuf_data(m);
2074 }
316670eb
A
2075 (void) mbuf_setdata(m, (char *)mbuf_data(m) + frmlen,
2076 mbuf_len(m) - frmlen);
6d2010ae
A
2077 (void) mbuf_pkthdr_adjustlen(m, -frmlen);
2078 }
2079#if BRIDGE_DEBUG
ea3f0419
A
2080 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT) &&
2081 IF_BRIDGE_DEBUG(BR_DBGF_MBUF)) {
6d2010ae
A
2082 printf("\n");
2083 printf_mbuf(m, "bridge_iff_input]", "\n");
2084 }
2085#endif /* BRIDGE_DEBUG */
2086
2087out:
39236c6e 2088 BRIDGE_LOCK_ASSERT_NOTHELD(sc);
316670eb 2089
0a7de745 2090 return error;
6d2010ae
A
2091}
2092
6d2010ae 2093static errno_t
39236c6e 2094bridge_iff_output(void *cookie, ifnet_t ifp, protocol_family_t protocol,
0a7de745 2095 mbuf_t *data)
6d2010ae 2096{
39236c6e 2097#pragma unused(protocol)
6d2010ae
A
2098 errno_t error = 0;
2099 struct bridge_iflist *bif = (struct bridge_iflist *)cookie;
2100 struct bridge_softc *sc = bif->bif_sc;
2101 mbuf_t m = *data;
316670eb 2102
0a7de745 2103 if ((m->m_flags & M_PROTO1)) {
6d2010ae 2104 goto out;
0a7de745 2105 }
316670eb 2106
6d2010ae 2107#if BRIDGE_DEBUG
ea3f0419 2108 if (IF_BRIDGE_DEBUG(BR_DBGF_OUTPUT)) {
39236c6e
A
2109 printf("%s: %s from %s m 0x%llx data 0x%llx\n", __func__,
2110 sc->sc_ifp->if_xname, ifp->if_xname,
2111 (uint64_t)VM_KERNEL_ADDRPERM(m),
2112 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_data(m)));
6d2010ae
A
2113 }
2114#endif /* BRIDGE_DEBUG */
2115
ea3f0419 2116 error = bridge_member_output(sc, ifp, data);
cb323159 2117 if (error != 0 && error != EJUSTRETURN) {
316670eb
A
2118 printf("%s: bridge_member_output failed error %d\n", __func__,
2119 error);
6d2010ae 2120 }
316670eb 2121out:
39236c6e 2122 BRIDGE_LOCK_ASSERT_NOTHELD(sc);
6d2010ae 2123
0a7de745 2124 return error;
6d2010ae 2125}
6d2010ae 2126
316670eb 2127static void
39236c6e 2128bridge_iff_event(void *cookie, ifnet_t ifp, protocol_family_t protocol,
0a7de745 2129 const struct kev_msg *event_msg)
6d2010ae 2130{
39236c6e 2131#pragma unused(protocol)
6d2010ae 2132 struct bridge_iflist *bif = (struct bridge_iflist *)cookie;
39236c6e 2133 struct bridge_softc *sc = bif->bif_sc;
316670eb
A
2134
2135 if (event_msg->vendor_code == KEV_VENDOR_APPLE &&
39236c6e
A
2136 event_msg->kev_class == KEV_NETWORK_CLASS &&
2137 event_msg->kev_subclass == KEV_DL_SUBCLASS) {
2138#if BRIDGE_DEBUG
ea3f0419 2139 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
39236c6e
A
2140 printf("%s: %s event_code %u - %s\n", __func__,
2141 ifp->if_xname, event_msg->event_code,
2142 dlil_kev_dl_code_str(event_msg->event_code));
0a7de745 2143 }
39236c6e
A
2144#endif /* BRIDGE_DEBUG */
2145
6d2010ae 2146 switch (event_msg->event_code) {
0a7de745
A
2147 case KEV_DL_IF_DETACHING:
2148 case KEV_DL_IF_DETACHED: {
cb323159 2149 bridge_ifdetach(ifp);
0a7de745
A
2150 break;
2151 }
2152 case KEV_DL_LINK_OFF:
2153 case KEV_DL_LINK_ON: {
2154 bridge_iflinkevent(ifp);
316670eb 2155#if BRIDGESTP
0a7de745 2156 bstp_linkstate(ifp, event_msg->event_code);
316670eb 2157#endif /* BRIDGESTP */
0a7de745
A
2158 break;
2159 }
2160 case KEV_DL_SIFFLAGS: {
2161 if ((bif->bif_flags & BIFF_PROMISC) == 0 &&
2162 (ifp->if_flags & IFF_UP)) {
2163 errno_t error;
2164
2165 error = ifnet_set_promiscuous(ifp, 1);
2166 if (error != 0) {
2167 printf("%s: "
2168 "ifnet_set_promiscuous (%s)"
2169 " failed %d\n",
2170 __func__, ifp->if_xname,
2171 error);
2172 } else {
2173 bif->bif_flags |= BIFF_PROMISC;
6d2010ae 2174 }
39236c6e 2175 }
0a7de745
A
2176 break;
2177 }
2178 case KEV_DL_IFCAP_CHANGED: {
2179 BRIDGE_LOCK(sc);
2180 bridge_set_tso(sc);
2181 BRIDGE_UNLOCK(sc);
2182 break;
2183 }
cb323159
A
2184 case KEV_DL_PROTO_DETACHED:
2185 case KEV_DL_PROTO_ATTACHED: {
2186 bridge_proto_attach_changed(ifp);
2187 break;
2188 }
0a7de745
A
2189 default:
2190 break;
6d2010ae 2191 }
316670eb 2192 }
6d2010ae
A
2193}
2194
2195/*
2196 * bridge_iff_detached:
2197 *
2198 * Detach an interface from a bridge. Called when a member
2199 * interface is detaching.
2200 */
316670eb 2201static void
39236c6e 2202bridge_iff_detached(void *cookie, ifnet_t ifp)
6d2010ae
A
2203{
2204 struct bridge_iflist *bif = (struct bridge_iflist *)cookie;
2205
316670eb 2206#if BRIDGE_DEBUG
ea3f0419 2207 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
39236c6e 2208 printf("%s: %s\n", __func__, ifp->if_xname);
0a7de745 2209 }
39236c6e 2210#endif /* BRIDGE_DEBUG */
6d2010ae 2211
cb323159 2212 bridge_ifdetach(ifp);
6d2010ae
A
2213
2214 _FREE(bif, M_DEVBUF);
6d2010ae
A
2215}
2216
2217static errno_t
39236c6e 2218bridge_proto_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t packet,
0a7de745 2219 char *header)
6d2010ae 2220{
39236c6e
A
2221#pragma unused(protocol, packet, header)
2222#if BRIDGE_DEBUG
2223 printf("%s: unexpected packet from %s\n", __func__,
2224 ifp->if_xname);
2225#endif /* BRIDGE_DEBUG */
0a7de745 2226 return 0;
6d2010ae
A
2227}
2228
2229static int
2230bridge_attach_protocol(struct ifnet *ifp)
2231{
0a7de745
A
2232 int error;
2233 struct ifnet_attach_proto_param reg;
6d2010ae 2234
39236c6e 2235#if BRIDGE_DEBUG
ea3f0419 2236 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
39236c6e 2237 printf("%s: %s\n", __func__, ifp->if_xname);
0a7de745 2238 }
39236c6e 2239#endif /* BRIDGE_DEBUG */
316670eb 2240
0a7de745 2241 bzero(&reg, sizeof(reg));
6d2010ae 2242 reg.input = bridge_proto_input;
316670eb 2243
6d2010ae 2244 error = ifnet_attach_protocol(ifp, PF_BRIDGE, &reg);
0a7de745 2245 if (error) {
39236c6e
A
2246 printf("%s: ifnet_attach_protocol(%s) failed, %d\n",
2247 __func__, ifp->if_xname, error);
0a7de745 2248 }
6d2010ae 2249
0a7de745 2250 return error;
6d2010ae
A
2251}
2252
2253static int
2254bridge_detach_protocol(struct ifnet *ifp)
2255{
0a7de745 2256 int error;
6d2010ae 2257
39236c6e 2258#if BRIDGE_DEBUG
ea3f0419 2259 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
39236c6e 2260 printf("%s: %s\n", __func__, ifp->if_xname);
0a7de745 2261 }
39236c6e 2262#endif /* BRIDGE_DEBUG */
6d2010ae 2263 error = ifnet_detach_protocol(ifp, PF_BRIDGE);
0a7de745 2264 if (error) {
39236c6e
A
2265 printf("%s: ifnet_detach_protocol(%s) failed, %d\n",
2266 __func__, ifp->if_xname, error);
0a7de745 2267 }
6d2010ae 2268
0a7de745 2269 return error;
6d2010ae
A
2270}
2271
2272/*
2273 * bridge_delete_member:
2274 *
2275 * Delete the specified member interface.
2276 */
2277static void
2278bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
0a7de745 2279 int gone)
6d2010ae 2280{
39236c6e
A
2281 struct ifnet *ifs = bif->bif_ifp, *bifp = sc->sc_ifp;
2282 int lladdr_changed = 0, error, filt_attached;
2283 uint8_t eaddr[ETHER_ADDR_LEN];
2284 u_int32_t event_code = 0;
6d2010ae 2285
39236c6e
A
2286 BRIDGE_LOCK_ASSERT_HELD(sc);
2287 VERIFY(ifs != NULL);
6d2010ae 2288
04b8595b 2289 /*
ea3f0419 2290 * Remove the member from the list first so it cannot be found anymore
04b8595b
A
2291 * when we release the bridge lock below
2292 */
2293 BRIDGE_XLOCK(sc);
2294 TAILQ_REMOVE(&sc->sc_iflist, bif, bif_next);
2295 BRIDGE_XDROP(sc);
2296
ea3f0419
A
2297 if (sc->sc_mac_nat_bif != NULL) {
2298 if (bif == sc->sc_mac_nat_bif) {
2299 bridge_mac_nat_disable(sc);
2300 } else {
2301 bridge_mac_nat_flush_entries(sc, bif);
2302 }
2303 }
2304
6d2010ae
A
2305 if (!gone) {
2306 switch (ifs->if_type) {
2307 case IFT_ETHER:
2308 case IFT_L2VLAN:
2309 /*
2310 * Take the interface out of promiscuous mode.
2311 */
04b8595b
A
2312 if (bif->bif_flags & BIFF_PROMISC) {
2313 /*
2314 * Unlock to prevent deadlock with bridge_iff_event() in
2315 * case the driver generates an interface event
2316 */
2317 BRIDGE_UNLOCK(sc);
6d2010ae 2318 (void) ifnet_set_promiscuous(ifs, 0);
04b8595b
A
2319 BRIDGE_LOCK(sc);
2320 }
6d2010ae
A
2321 break;
2322
2323 case IFT_GIF:
0a7de745
A
2324 /* currently not supported */
2325 /* FALLTHRU */
6d2010ae 2326 default:
39236c6e
A
2327 VERIFY(0);
2328 /* NOTREACHED */
6d2010ae
A
2329 }
2330
2331#if HAS_IF_CAP
2332 /* reneable any interface capabilities */
2333 bridge_set_ifcap(sc, bif, bif->bif_savedcaps);
2334#endif
2335 }
2336
39236c6e 2337 if (bif->bif_flags & BIFF_PROTO_ATTACHED) {
6d2010ae
A
2338 /* Respect lock ordering with DLIL lock */
2339 BRIDGE_UNLOCK(sc);
2340 (void) bridge_detach_protocol(ifs);
2341 BRIDGE_LOCK(sc);
2342 }
316670eb 2343#if BRIDGESTP
cb323159 2344 if ((bif->bif_ifflags & IFBIF_STP) != 0) {
6d2010ae 2345 bstp_disable(&bif->bif_stp);
5ba3f43e 2346 }
316670eb 2347#endif /* BRIDGESTP */
6d2010ae 2348
39236c6e
A
2349 /*
2350 * If removing the interface that gave the bridge its mac address, set
2351 * the mac address of the bridge to the address of the next member, or
2352 * to its default address if no members are left.
2353 */
2354 if (bridge_inherit_mac && sc->sc_ifaddr == ifs) {
2355 ifnet_release(sc->sc_ifaddr);
2356 if (TAILQ_EMPTY(&sc->sc_iflist)) {
2357 bcopy(sc->sc_defaddr, eaddr, ETHER_ADDR_LEN);
2358 sc->sc_ifaddr = NULL;
2359 } else {
2360 struct ifnet *fif =
2361 TAILQ_FIRST(&sc->sc_iflist)->bif_ifp;
2362 bcopy(IF_LLADDR(fif), eaddr, ETHER_ADDR_LEN);
2363 sc->sc_ifaddr = fif;
0a7de745 2364 ifnet_reference(fif); /* for sc_ifaddr */
39236c6e
A
2365 }
2366 lladdr_changed = 1;
2367 }
6d2010ae
A
2368
2369#if HAS_IF_CAP
0a7de745 2370 bridge_mutecaps(sc); /* recalculate now this interface is removed */
6d2010ae 2371#endif /* HAS_IF_CAP */
39236c6e
A
2372
2373 error = bridge_set_tso(sc);
2374 if (error != 0) {
2375 printf("%s: bridge_set_tso failed %d\n", __func__, error);
2376 }
2377
cb323159 2378 bridge_rtdelete(sc, ifs, IFBF_FLUSHALL);
5ba3f43e 2379
6d2010ae
A
2380 KASSERT(bif->bif_addrcnt == 0,
2381 ("%s: %d bridge routes referenced", __func__, bif->bif_addrcnt));
2382
39236c6e
A
2383 filt_attached = bif->bif_flags & BIFF_FILTER_ATTACHED;
2384
2385 /*
2386 * Update link status of the bridge based on its remaining members
2387 */
2388 event_code = bridge_updatelinkstatus(sc);
2389
cb323159
A
2390 BRIDGE_UNLOCK(sc);
2391
39236c6e
A
2392
2393 if (lladdr_changed &&
0a7de745 2394 (error = ifnet_set_lladdr(bifp, eaddr, ETHER_ADDR_LEN)) != 0) {
39236c6e 2395 printf("%s: ifnet_set_lladdr failed %d\n", __func__, error);
0a7de745 2396 }
39236c6e 2397
0a7de745 2398 if (event_code != 0) {
39236c6e 2399 bridge_link_event(bifp, event_code);
0a7de745 2400 }
39236c6e
A
2401
2402#if BRIDGESTP
cb323159 2403 bstp_destroy(&bif->bif_stp); /* prepare to free */
316670eb
A
2404#endif /* BRIDGESTP */
2405
0a7de745 2406 if (filt_attached) {
6d2010ae 2407 iflt_detach(bif->bif_iff_ref);
0a7de745 2408 } else {
6d2010ae 2409 _FREE(bif, M_DEVBUF);
0a7de745 2410 }
39236c6e
A
2411
2412 ifs->if_bridge = NULL;
2413 ifnet_release(ifs);
2414
2415 BRIDGE_LOCK(sc);
6d2010ae
A
2416}
2417
2418/*
2419 * bridge_delete_span:
2420 *
2421 * Delete the specified span interface.
2422 */
2423static void
2424bridge_delete_span(struct bridge_softc *sc, struct bridge_iflist *bif)
2425{
39236c6e 2426 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
2427
2428 KASSERT(bif->bif_ifp->if_bridge == NULL,
2429 ("%s: not a span interface", __func__));
2430
2431 ifnet_release(bif->bif_ifp);
2432
2433 TAILQ_REMOVE(&sc->sc_spanlist, bif, bif_next);
2434 _FREE(bif, M_DEVBUF);
2435}
2436
2437static int
2438bridge_ioctl_add(struct bridge_softc *sc, void *arg)
2439{
2440 struct ifbreq *req = arg;
2441 struct bridge_iflist *bif = NULL;
39236c6e
A
2442 struct ifnet *ifs, *bifp = sc->sc_ifp;
2443 int error = 0, lladdr_changed = 0;
2444 uint8_t eaddr[ETHER_ADDR_LEN];
6d2010ae 2445 struct iff_filter iff;
39236c6e 2446 u_int32_t event_code = 0;
ea3f0419 2447 boolean_t mac_nat = FALSE;
6d2010ae
A
2448
2449 ifs = ifunit(req->ifbr_ifsname);
0a7de745
A
2450 if (ifs == NULL) {
2451 return ENOENT;
2452 }
2453 if (ifs->if_ioctl == NULL) { /* must be supported */
2454 return EINVAL;
2455 }
6d2010ae 2456
5c9f4661 2457 if (IFNET_IS_INTCOPROC(ifs)) {
0a7de745 2458 return EINVAL;
5c9f4661
A
2459 }
2460
cb323159 2461 /* If it's in the span list, it can't be a member. */
ea3f0419
A
2462 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) {
2463 if (ifs == bif->bif_ifp) {
2464 return EBUSY;
2465 }
5ba3f43e 2466 }
6d2010ae 2467
0a7de745
A
2468 if (ifs->if_bridge == sc) {
2469 return EEXIST;
2470 }
6d2010ae 2471
0a7de745
A
2472 if (ifs->if_bridge != NULL) {
2473 return EBUSY;
2474 }
6d2010ae 2475
39236c6e
A
2476 switch (ifs->if_type) {
2477 case IFT_ETHER:
ea3f0419 2478 if (strcmp(ifs->if_name, "en") == 0 &&
bca245ac
A
2479 ifs->if_subfamily == IFNET_SUBFAMILY_WIFI &&
2480 (ifs->if_eflags & IFEF_IPV4_ROUTER) == 0) {
ea3f0419
A
2481 /* XXX is there a better way to identify Wi-Fi STA? */
2482 mac_nat = TRUE;
2483 }
39236c6e
A
2484 case IFT_L2VLAN:
2485 /* permitted interface types */
2486 break;
2487 case IFT_GIF:
0a7de745
A
2488 /* currently not supported */
2489 /* FALLTHRU */
39236c6e 2490 default:
0a7de745 2491 return EINVAL;
39236c6e
A
2492 }
2493
ea3f0419
A
2494 /* fail to add the interface if the MTU doesn't match */
2495 if (!TAILQ_EMPTY(&sc->sc_iflist) && sc->sc_ifp->if_mtu != ifs->if_mtu) {
2496 printf("%s: %s: invalid MTU for %s", __func__,
2497 sc->sc_ifp->if_xname,
2498 ifs->if_xname);
2499 return EINVAL;
2500 }
2501
2502 /* there's already an interface that's doing MAC NAT */
2503 if (mac_nat && sc->sc_mac_nat_bif != NULL) {
2504 return EBUSY;
2505 }
0a7de745
A
2506 bif = _MALLOC(sizeof(*bif), M_DEVBUF, M_WAITOK | M_ZERO);
2507 if (bif == NULL) {
2508 return ENOMEM;
2509 }
6d2010ae 2510 bif->bif_ifp = ifs;
39236c6e 2511 ifnet_reference(ifs);
ea3f0419 2512 bif->bif_ifflags |= IFBIF_LEARNING | IFBIF_DISCOVER;
6d2010ae
A
2513#if HAS_IF_CAP
2514 bif->bif_savedcaps = ifs->if_capenable;
2515#endif /* HAS_IF_CAP */
2516 bif->bif_sc = sc;
ea3f0419
A
2517 if (mac_nat) {
2518 (void)bridge_mac_nat_enable(sc, bif);
2519 }
6d2010ae 2520
39236c6e 2521 /* Allow the first Ethernet member to define the MTU */
0a7de745 2522 if (TAILQ_EMPTY(&sc->sc_iflist)) {
39236c6e 2523 sc->sc_ifp->if_mtu = ifs->if_mtu;
39236c6e
A
2524 }
2525
2526 /*
2527 * Assign the interface's MAC address to the bridge if it's the first
2528 * member and the MAC address of the bridge has not been changed from
2529 * the default (randomly) generated one.
2530 */
2531 if (bridge_inherit_mac && TAILQ_EMPTY(&sc->sc_iflist) &&
2532 !memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr, ETHER_ADDR_LEN)) {
2533 bcopy(IF_LLADDR(ifs), eaddr, ETHER_ADDR_LEN);
2534 sc->sc_ifaddr = ifs;
0a7de745 2535 ifnet_reference(ifs); /* for sc_ifaddr */
39236c6e
A
2536 lladdr_changed = 1;
2537 }
6d2010ae
A
2538
2539 ifs->if_bridge = sc;
316670eb 2540#if BRIDGESTP
cb323159 2541 bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp);
316670eb 2542#endif /* BRIDGESTP */
39236c6e 2543
6d2010ae
A
2544 /*
2545 * XXX: XLOCK HERE!?!
2546 */
2547 TAILQ_INSERT_TAIL(&sc->sc_iflist, bif, bif_next);
2548
2549#if HAS_IF_CAP
2550 /* Set interface capabilities to the intersection set of all members */
2551 bridge_mutecaps(sc);
2552#endif /* HAS_IF_CAP */
2553
39236c6e
A
2554 bridge_set_tso(sc);
2555
316670eb 2556
39236c6e
A
2557 /*
2558 * Place the interface into promiscuous mode.
2559 */
6d2010ae
A
2560 switch (ifs->if_type) {
2561 case IFT_ETHER:
2562 case IFT_L2VLAN:
6d2010ae
A
2563 error = ifnet_set_promiscuous(ifs, 1);
2564 if (error) {
2565 /* Ignore error when device is not up */
0a7de745 2566 if (error != ENETDOWN) {
6d2010ae 2567 goto out;
0a7de745 2568 }
6d2010ae
A
2569 error = 0;
2570 } else {
39236c6e 2571 bif->bif_flags |= BIFF_PROMISC;
6d2010ae
A
2572 }
2573 break;
2574
6d2010ae 2575 default:
39236c6e 2576 break;
6d2010ae
A
2577 }
2578
39236c6e
A
2579 /*
2580 * The new member may change the link status of the bridge interface
2581 */
0a7de745 2582 if (interface_media_active(ifs)) {
39236c6e 2583 bif->bif_flags |= BIFF_MEDIA_ACTIVE;
0a7de745 2584 } else {
39236c6e 2585 bif->bif_flags &= ~BIFF_MEDIA_ACTIVE;
0a7de745 2586 }
39236c6e
A
2587
2588 event_code = bridge_updatelinkstatus(sc);
2589
2590 /*
6d2010ae
A
2591 * Respect lock ordering with DLIL lock for the following operations
2592 */
cb323159
A
2593 BRIDGE_UNLOCK(sc);
2594
6d2010ae
A
2595
2596 /*
2597 * install an interface filter
2598 */
0a7de745 2599 memset(&iff, 0, sizeof(struct iff_filter));
6d2010ae
A
2600 iff.iff_cookie = bif;
2601 iff.iff_name = "com.apple.kernel.bsd.net.if_bridge";
cb323159
A
2602 iff.iff_input = bridge_iff_input;
2603 iff.iff_output = bridge_iff_output;
6d2010ae
A
2604 iff.iff_event = bridge_iff_event;
2605 iff.iff_detached = bridge_iff_detached;
5ba3f43e
A
2606 error = dlil_attach_filter(ifs, &iff, &bif->bif_iff_ref,
2607 DLIL_IFF_TSO | DLIL_IFF_INTERNAL);
6d2010ae 2608 if (error != 0) {
316670eb 2609 printf("%s: iflt_attach failed %d\n", __func__, error);
6d2010ae
A
2610 BRIDGE_LOCK(sc);
2611 goto out;
2612 }
cb323159 2613 BRIDGE_LOCK(sc);
39236c6e 2614 bif->bif_flags |= BIFF_FILTER_ATTACHED;
cb323159 2615 BRIDGE_UNLOCK(sc);
6d2010ae
A
2616
2617 /*
cb323159 2618 * install a dummy "bridge" protocol
6d2010ae
A
2619 */
2620 if ((error = bridge_attach_protocol(ifs)) != 0) {
2621 if (error != 0) {
316670eb
A
2622 printf("%s: bridge_attach_protocol failed %d\n",
2623 __func__, error);
6d2010ae
A
2624 BRIDGE_LOCK(sc);
2625 goto out;
2626 }
2627 }
cb323159 2628 BRIDGE_LOCK(sc);
39236c6e 2629 bif->bif_flags |= BIFF_PROTO_ATTACHED;
cb323159 2630 BRIDGE_UNLOCK(sc);
39236c6e
A
2631
2632 if (lladdr_changed &&
0a7de745 2633 (error = ifnet_set_lladdr(bifp, eaddr, ETHER_ADDR_LEN)) != 0) {
39236c6e 2634 printf("%s: ifnet_set_lladdr failed %d\n", __func__, error);
0a7de745 2635 }
39236c6e 2636
0a7de745 2637 if (event_code != 0) {
39236c6e 2638 bridge_link_event(bifp, event_code);
0a7de745 2639 }
6d2010ae
A
2640
2641 BRIDGE_LOCK(sc);
2642
2643out:
0a7de745 2644 if (error && bif != NULL) {
6d2010ae 2645 bridge_delete_member(sc, bif, 1);
0a7de745 2646 }
316670eb 2647
0a7de745 2648 return error;
6d2010ae
A
2649}
2650
2651static int
2652bridge_ioctl_del(struct bridge_softc *sc, void *arg)
2653{
2654 struct ifbreq *req = arg;
2655 struct bridge_iflist *bif;
2656
2657 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
0a7de745
A
2658 if (bif == NULL) {
2659 return ENOENT;
2660 }
6d2010ae
A
2661
2662 bridge_delete_member(sc, bif, 0);
2663
0a7de745 2664 return 0;
6d2010ae
A
2665}
2666
2667static int
39236c6e 2668bridge_ioctl_purge(struct bridge_softc *sc, void *arg)
316670eb 2669{
39236c6e 2670#pragma unused(sc, arg)
0a7de745 2671 return 0;
6d2010ae
A
2672}
2673
2674static int
2675bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg)
2676{
2677 struct ifbreq *req = arg;
2678 struct bridge_iflist *bif;
6d2010ae
A
2679
2680 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
0a7de745
A
2681 if (bif == NULL) {
2682 return ENOENT;
2683 }
6d2010ae 2684
cb323159 2685 struct bstp_port *bp;
5ba3f43e 2686
cb323159
A
2687 bp = &bif->bif_stp;
2688 req->ifbr_state = bp->bp_state;
2689 req->ifbr_priority = bp->bp_priority;
2690 req->ifbr_path_cost = bp->bp_path_cost;
2691 req->ifbr_proto = bp->bp_protover;
2692 req->ifbr_role = bp->bp_role;
2693 req->ifbr_stpflags = bp->bp_flags;
ea3f0419
A
2694 req->ifbr_ifsflags = bif->bif_ifflags;
2695
cb323159
A
2696 /* Copy STP state options as flags */
2697 if (bp->bp_operedge) {
2698 req->ifbr_ifsflags |= IFBIF_BSTP_EDGE;
2699 }
2700 if (bp->bp_flags & BSTP_PORT_AUTOEDGE) {
2701 req->ifbr_ifsflags |= IFBIF_BSTP_AUTOEDGE;
2702 }
2703 if (bp->bp_ptp_link) {
2704 req->ifbr_ifsflags |= IFBIF_BSTP_PTP;
5ba3f43e 2705 }
cb323159
A
2706 if (bp->bp_flags & BSTP_PORT_AUTOPTP) {
2707 req->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
2708 }
2709 if (bp->bp_flags & BSTP_PORT_ADMEDGE) {
2710 req->ifbr_ifsflags |= IFBIF_BSTP_ADMEDGE;
2711 }
2712 if (bp->bp_flags & BSTP_PORT_ADMCOST) {
2713 req->ifbr_ifsflags |= IFBIF_BSTP_ADMCOST;
2714 }
2715
6d2010ae 2716 req->ifbr_portno = bif->bif_ifp->if_index & 0xfff;
6d2010ae
A
2717 req->ifbr_addrcnt = bif->bif_addrcnt;
2718 req->ifbr_addrmax = bif->bif_addrmax;
2719 req->ifbr_addrexceeded = bif->bif_addrexceeded;
2720
0a7de745 2721 return 0;
6d2010ae
A
2722}
2723
2724static int
2725bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg)
2726{
2727 struct ifbreq *req = arg;
2728 struct bridge_iflist *bif;
316670eb 2729#if BRIDGESTP
6d2010ae
A
2730 struct bstp_port *bp;
2731 int error;
316670eb 2732#endif /* BRIDGESTP */
6d2010ae
A
2733
2734 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
0a7de745
A
2735 if (bif == NULL) {
2736 return ENOENT;
2737 }
6d2010ae 2738
0a7de745 2739 if (req->ifbr_ifsflags & IFBIF_SPAN) {
6d2010ae 2740 /* SPAN is readonly */
0a7de745
A
2741 return EINVAL;
2742 }
ea3f0419
A
2743 if ((req->ifbr_ifsflags & IFBIF_MAC_NAT) != 0) {
2744 errno_t error;
2745 error = bridge_mac_nat_enable(sc, bif);
2746 if (error != 0) {
2747 return error;
2748 }
2749 } else if (sc->sc_mac_nat_bif != NULL) {
2750 bridge_mac_nat_disable(sc);
2751 }
6d2010ae 2752
316670eb
A
2753
2754#if BRIDGESTP
6d2010ae 2755 if (req->ifbr_ifsflags & IFBIF_STP) {
39236c6e 2756 if ((bif->bif_ifflags & IFBIF_STP) == 0) {
6d2010ae 2757 error = bstp_enable(&bif->bif_stp);
0a7de745
A
2758 if (error) {
2759 return error;
2760 }
6d2010ae
A
2761 }
2762 } else {
0a7de745 2763 if ((bif->bif_ifflags & IFBIF_STP) != 0) {
6d2010ae 2764 bstp_disable(&bif->bif_stp);
0a7de745 2765 }
6d2010ae
A
2766 }
2767
2768 /* Pass on STP flags */
316670eb 2769 bp = &bif->bif_stp;
6d2010ae
A
2770 bstp_set_edge(bp, req->ifbr_ifsflags & IFBIF_BSTP_EDGE ? 1 : 0);
2771 bstp_set_autoedge(bp, req->ifbr_ifsflags & IFBIF_BSTP_AUTOEDGE ? 1 : 0);
2772 bstp_set_ptp(bp, req->ifbr_ifsflags & IFBIF_BSTP_PTP ? 1 : 0);
2773 bstp_set_autoptp(bp, req->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP ? 1 : 0);
316670eb 2774#else /* !BRIDGESTP */
0a7de745
A
2775 if (req->ifbr_ifsflags & IFBIF_STP) {
2776 return EOPNOTSUPP;
2777 }
316670eb 2778#endif /* !BRIDGESTP */
6d2010ae
A
2779
2780 /* Save the bits relating to the bridge */
39236c6e 2781 bif->bif_ifflags = req->ifbr_ifsflags & IFBIFMASK;
6d2010ae
A
2782
2783
0a7de745 2784 return 0;
6d2010ae
A
2785}
2786
2787static int
2788bridge_ioctl_scache(struct bridge_softc *sc, void *arg)
2789{
2790 struct ifbrparam *param = arg;
2791
2792 sc->sc_brtmax = param->ifbrp_csize;
cb323159 2793 bridge_rttrim(sc);
0a7de745 2794 return 0;
6d2010ae
A
2795}
2796
2797static int
2798bridge_ioctl_gcache(struct bridge_softc *sc, void *arg)
2799{
2800 struct ifbrparam *param = arg;
2801
2802 param->ifbrp_csize = sc->sc_brtmax;
2803
0a7de745
A
2804 return 0;
2805}
2806
2807#define BRIDGE_IOCTL_GIFS do { \
2808 struct bridge_iflist *bif; \
2809 struct ifbreq breq; \
2810 char *buf, *outbuf; \
2811 unsigned int count, buflen, len; \
2812 \
2813 count = 0; \
2814 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) \
2815 count++; \
cb323159
A
2816 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) \
2817 count++; \
0a7de745
A
2818 \
2819 buflen = sizeof (breq) * count; \
2820 if (bifc->ifbic_len == 0) { \
2821 bifc->ifbic_len = buflen; \
2822 return (0); \
2823 } \
2824 BRIDGE_UNLOCK(sc); \
2825 outbuf = _MALLOC(buflen, M_TEMP, M_WAITOK | M_ZERO); \
2826 BRIDGE_LOCK(sc); \
2827 \
2828 count = 0; \
2829 buf = outbuf; \
2830 len = min(bifc->ifbic_len, buflen); \
2831 bzero(&breq, sizeof (breq)); \
2832 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) { \
2833 if (len < sizeof (breq)) \
2834 break; \
2835 \
2836 snprintf(breq.ifbr_ifsname, sizeof (breq.ifbr_ifsname), \
2837 "%s", bif->bif_ifp->if_xname); \
2838 /* Fill in the ifbreq structure */ \
2839 error = bridge_ioctl_gifflags(sc, &breq); \
2840 if (error) \
2841 break; \
2842 memcpy(buf, &breq, sizeof (breq)); \
2843 count++; \
2844 buf += sizeof (breq); \
2845 len -= sizeof (breq); \
2846 } \
cb323159
A
2847 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) { \
2848 if (len < sizeof (breq)) \
2849 break; \
0a7de745 2850 \
cb323159
A
2851 snprintf(breq.ifbr_ifsname, \
2852 sizeof (breq.ifbr_ifsname), \
2853 "%s", bif->bif_ifp->if_xname); \
2854 breq.ifbr_ifsflags = bif->bif_ifflags; \
2855 breq.ifbr_portno \
2856 = bif->bif_ifp->if_index & 0xfff; \
2857 memcpy(buf, &breq, sizeof (breq)); \
2858 count++; \
2859 buf += sizeof (breq); \
2860 len -= sizeof (breq); \
0a7de745
A
2861 } \
2862 \
2863 BRIDGE_UNLOCK(sc); \
2864 bifc->ifbic_len = sizeof (breq) * count; \
2865 error = copyout(outbuf, bifc->ifbic_req, bifc->ifbic_len); \
2866 BRIDGE_LOCK(sc); \
2867 _FREE(outbuf, M_TEMP); \
6d2010ae
A
2868} while (0)
2869
2870static int
2871bridge_ioctl_gifs64(struct bridge_softc *sc, void *arg)
2872{
2873 struct ifbifconf64 *bifc = arg;
2874 int error = 0;
316670eb 2875
6d2010ae
A
2876 BRIDGE_IOCTL_GIFS;
2877
0a7de745 2878 return error;
6d2010ae
A
2879}
2880
2881static int
2882bridge_ioctl_gifs32(struct bridge_softc *sc, void *arg)
2883{
2884 struct ifbifconf32 *bifc = arg;
2885 int error = 0;
2886
2887 BRIDGE_IOCTL_GIFS;
2888
0a7de745
A
2889 return error;
2890}
2891
2892#define BRIDGE_IOCTL_RTS do { \
2893 struct bridge_rtnode *brt; \
2894 char *buf; \
2895 char *outbuf = NULL; \
2896 unsigned int count, buflen, len; \
2897 unsigned long now; \
2898 \
2899 if (bac->ifbac_len == 0) \
2900 return (0); \
2901 \
2902 bzero(&bareq, sizeof (bareq)); \
2903 count = 0; \
0a7de745
A
2904 LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) \
2905 count++; \
2906 buflen = sizeof (bareq) * count; \
2907 \
2908 BRIDGE_UNLOCK(sc); \
2909 outbuf = _MALLOC(buflen, M_TEMP, M_WAITOK | M_ZERO); \
2910 BRIDGE_LOCK(sc); \
2911 \
2912 count = 0; \
2913 buf = outbuf; \
2914 len = min(bac->ifbac_len, buflen); \
2915 LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { \
2916 if (len < sizeof (bareq)) \
2917 goto out; \
2918 snprintf(bareq.ifba_ifsname, sizeof (bareq.ifba_ifsname), \
2919 "%s", brt->brt_ifp->if_xname); \
2920 memcpy(bareq.ifba_dst, brt->brt_addr, sizeof (brt->brt_addr)); \
2921 bareq.ifba_vlan = brt->brt_vlan; \
2922 if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { \
2923 now = (unsigned long) net_uptime(); \
2924 if (now < brt->brt_expire) \
2925 bareq.ifba_expire = \
2926 brt->brt_expire - now; \
2927 } else \
2928 bareq.ifba_expire = 0; \
2929 bareq.ifba_flags = brt->brt_flags; \
2930 \
2931 memcpy(buf, &bareq, sizeof (bareq)); \
2932 count++; \
2933 buf += sizeof (bareq); \
2934 len -= sizeof (bareq); \
2935 } \
2936out: \
2937 bac->ifbac_len = sizeof (bareq) * count; \
2938 if (outbuf != NULL) { \
2939 BRIDGE_UNLOCK(sc); \
2940 error = copyout(outbuf, bac->ifbac_req, bac->ifbac_len); \
2941 _FREE(outbuf, M_TEMP); \
2942 BRIDGE_LOCK(sc); \
2943 } \
2944 return (error); \
6d2010ae
A
2945} while (0)
2946
2947static int
2948bridge_ioctl_rts64(struct bridge_softc *sc, void *arg)
2949{
2950 struct ifbaconf64 *bac = arg;
2951 struct ifbareq64 bareq;
2952 int error = 0;
316670eb 2953
6d2010ae 2954 BRIDGE_IOCTL_RTS;
0a7de745 2955 return error;
6d2010ae
A
2956}
2957
2958static int
2959bridge_ioctl_rts32(struct bridge_softc *sc, void *arg)
2960{
2961 struct ifbaconf32 *bac = arg;
2962 struct ifbareq32 bareq;
2963 int error = 0;
316670eb 2964
6d2010ae 2965 BRIDGE_IOCTL_RTS;
0a7de745 2966 return error;
6d2010ae
A
2967}
2968
2969static int
2970bridge_ioctl_saddr32(struct bridge_softc *sc, void *arg)
2971{
2972 struct ifbareq32 *req = arg;
2973 struct bridge_iflist *bif;
2974 int error;
2975
2976 bif = bridge_lookup_member(sc, req->ifba_ifsname);
0a7de745
A
2977 if (bif == NULL) {
2978 return ENOENT;
2979 }
6d2010ae
A
2980
2981 error = bridge_rtupdate(sc, req->ifba_dst, req->ifba_vlan, bif, 1,
2982 req->ifba_flags);
2983
0a7de745 2984 return error;
6d2010ae
A
2985}
2986
2987static int
2988bridge_ioctl_saddr64(struct bridge_softc *sc, void *arg)
2989{
2990 struct ifbareq64 *req = arg;
2991 struct bridge_iflist *bif;
2992 int error;
2993
2994 bif = bridge_lookup_member(sc, req->ifba_ifsname);
0a7de745
A
2995 if (bif == NULL) {
2996 return ENOENT;
2997 }
6d2010ae
A
2998
2999 error = bridge_rtupdate(sc, req->ifba_dst, req->ifba_vlan, bif, 1,
3000 req->ifba_flags);
3001
0a7de745 3002 return error;
6d2010ae
A
3003}
3004
3005static int
3006bridge_ioctl_sto(struct bridge_softc *sc, void *arg)
3007{
3008 struct ifbrparam *param = arg;
3009
3010 sc->sc_brttimeout = param->ifbrp_ctime;
0a7de745 3011 return 0;
6d2010ae
A
3012}
3013
3014static int
3015bridge_ioctl_gto(struct bridge_softc *sc, void *arg)
3016{
3017 struct ifbrparam *param = arg;
3018
3019 param->ifbrp_ctime = sc->sc_brttimeout;
0a7de745 3020 return 0;
6d2010ae
A
3021}
3022
3023static int
3024bridge_ioctl_daddr32(struct bridge_softc *sc, void *arg)
3025{
3026 struct ifbareq32 *req = arg;
3027
0a7de745 3028 return bridge_rtdaddr(sc, req->ifba_dst, req->ifba_vlan);
6d2010ae
A
3029}
3030
3031static int
3032bridge_ioctl_daddr64(struct bridge_softc *sc, void *arg)
3033{
3034 struct ifbareq64 *req = arg;
3035
0a7de745 3036 return bridge_rtdaddr(sc, req->ifba_dst, req->ifba_vlan);
6d2010ae
A
3037}
3038
3039static int
3040bridge_ioctl_flush(struct bridge_softc *sc, void *arg)
3041{
3042 struct ifbreq *req = arg;
3043
3044 bridge_rtflush(sc, req->ifbr_ifsflags);
0a7de745 3045 return 0;
6d2010ae
A
3046}
3047
3048static int
3049bridge_ioctl_gpri(struct bridge_softc *sc, void *arg)
3050{
3051 struct ifbrparam *param = arg;
3052 struct bstp_state *bs = &sc->sc_stp;
3053
3054 param->ifbrp_prio = bs->bs_bridge_priority;
0a7de745 3055 return 0;
6d2010ae
A
3056}
3057
3058static int
3059bridge_ioctl_spri(struct bridge_softc *sc, void *arg)
3060{
316670eb 3061#if BRIDGESTP
6d2010ae
A
3062 struct ifbrparam *param = arg;
3063
0a7de745 3064 return bstp_set_priority(&sc->sc_stp, param->ifbrp_prio);
316670eb
A
3065#else /* !BRIDGESTP */
3066#pragma unused(sc, arg)
0a7de745 3067 return EOPNOTSUPP;
316670eb 3068#endif /* !BRIDGESTP */
6d2010ae
A
3069}
3070
3071static int
3072bridge_ioctl_ght(struct bridge_softc *sc, void *arg)
3073{
3074 struct ifbrparam *param = arg;
3075 struct bstp_state *bs = &sc->sc_stp;
3076
3077 param->ifbrp_hellotime = bs->bs_bridge_htime >> 8;
0a7de745 3078 return 0;
6d2010ae
A
3079}
3080
3081static int
3082bridge_ioctl_sht(struct bridge_softc *sc, void *arg)
3083{
316670eb 3084#if BRIDGESTP
6d2010ae
A
3085 struct ifbrparam *param = arg;
3086
0a7de745 3087 return bstp_set_htime(&sc->sc_stp, param->ifbrp_hellotime);
316670eb
A
3088#else /* !BRIDGESTP */
3089#pragma unused(sc, arg)
0a7de745 3090 return EOPNOTSUPP;
316670eb 3091#endif /* !BRIDGESTP */
6d2010ae
A
3092}
3093
3094static int
3095bridge_ioctl_gfd(struct bridge_softc *sc, void *arg)
3096{
5ba3f43e
A
3097 struct ifbrparam *param;
3098 struct bstp_state *bs;
6d2010ae 3099
5ba3f43e
A
3100 param = arg;
3101 bs = &sc->sc_stp;
6d2010ae 3102 param->ifbrp_fwddelay = bs->bs_bridge_fdelay >> 8;
0a7de745 3103 return 0;
6d2010ae
A
3104}
3105
3106static int
3107bridge_ioctl_sfd(struct bridge_softc *sc, void *arg)
3108{
316670eb 3109#if BRIDGESTP
6d2010ae
A
3110 struct ifbrparam *param = arg;
3111
0a7de745 3112 return bstp_set_fdelay(&sc->sc_stp, param->ifbrp_fwddelay);
316670eb
A
3113#else /* !BRIDGESTP */
3114#pragma unused(sc, arg)
0a7de745 3115 return EOPNOTSUPP;
316670eb 3116#endif /* !BRIDGESTP */
6d2010ae
A
3117}
3118
3119static int
3120bridge_ioctl_gma(struct bridge_softc *sc, void *arg)
3121{
5ba3f43e
A
3122 struct ifbrparam *param;
3123 struct bstp_state *bs;
6d2010ae 3124
5ba3f43e
A
3125 param = arg;
3126 bs = &sc->sc_stp;
6d2010ae 3127 param->ifbrp_maxage = bs->bs_bridge_max_age >> 8;
0a7de745 3128 return 0;
6d2010ae
A
3129}
3130
3131static int
3132bridge_ioctl_sma(struct bridge_softc *sc, void *arg)
3133{
316670eb 3134#if BRIDGESTP
6d2010ae
A
3135 struct ifbrparam *param = arg;
3136
0a7de745 3137 return bstp_set_maxage(&sc->sc_stp, param->ifbrp_maxage);
316670eb
A
3138#else /* !BRIDGESTP */
3139#pragma unused(sc, arg)
0a7de745 3140 return EOPNOTSUPP;
316670eb 3141#endif /* !BRIDGESTP */
6d2010ae
A
3142}
3143
3144static int
3145bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg)
3146{
316670eb 3147#if BRIDGESTP
6d2010ae
A
3148 struct ifbreq *req = arg;
3149 struct bridge_iflist *bif;
3150
3151 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
0a7de745
A
3152 if (bif == NULL) {
3153 return ENOENT;
3154 }
6d2010ae 3155
0a7de745 3156 return bstp_set_port_priority(&bif->bif_stp, req->ifbr_priority);
316670eb
A
3157#else /* !BRIDGESTP */
3158#pragma unused(sc, arg)
0a7de745 3159 return EOPNOTSUPP;
316670eb 3160#endif /* !BRIDGESTP */
6d2010ae
A
3161}
3162
3163static int
3164bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg)
3165{
316670eb 3166#if BRIDGESTP
6d2010ae
A
3167 struct ifbreq *req = arg;
3168 struct bridge_iflist *bif;
3169
3170 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
0a7de745
A
3171 if (bif == NULL) {
3172 return ENOENT;
3173 }
6d2010ae 3174
0a7de745 3175 return bstp_set_path_cost(&bif->bif_stp, req->ifbr_path_cost);
316670eb
A
3176#else /* !BRIDGESTP */
3177#pragma unused(sc, arg)
0a7de745 3178 return EOPNOTSUPP;
316670eb 3179#endif /* !BRIDGESTP */
6d2010ae
A
3180}
3181
3182static int
3183bridge_ioctl_gfilt(struct bridge_softc *sc, void *arg)
3184{
3185 struct ifbrparam *param = arg;
3186
3187 param->ifbrp_filter = sc->sc_filter_flags;
3188
0a7de745 3189 return 0;
6d2010ae
A
3190}
3191
3192static int
3193bridge_ioctl_sfilt(struct bridge_softc *sc, void *arg)
3194{
3195 struct ifbrparam *param = arg;
3196
0a7de745
A
3197 if (param->ifbrp_filter & ~IFBF_FILT_MASK) {
3198 return EINVAL;
3199 }
6d2010ae 3200
0a7de745
A
3201 if (param->ifbrp_filter & IFBF_FILT_USEIPF) {
3202 return EINVAL;
3203 }
6d2010ae
A
3204
3205 sc->sc_filter_flags = param->ifbrp_filter;
3206
0a7de745 3207 return 0;
6d2010ae
A
3208}
3209
3210static int
3211bridge_ioctl_sifmaxaddr(struct bridge_softc *sc, void *arg)
3212{
3213 struct ifbreq *req = arg;
3214 struct bridge_iflist *bif;
3215
3216 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
0a7de745
A
3217 if (bif == NULL) {
3218 return ENOENT;
3219 }
6d2010ae
A
3220
3221 bif->bif_addrmax = req->ifbr_addrmax;
0a7de745 3222 return 0;
6d2010ae
A
3223}
3224
3225static int
3226bridge_ioctl_addspan(struct bridge_softc *sc, void *arg)
3227{
3228 struct ifbreq *req = arg;
3229 struct bridge_iflist *bif = NULL;
3230 struct ifnet *ifs;
3231
3232 ifs = ifunit(req->ifbr_ifsname);
0a7de745
A
3233 if (ifs == NULL) {
3234 return ENOENT;
3235 }
6d2010ae 3236
5c9f4661 3237 if (IFNET_IS_INTCOPROC(ifs)) {
0a7de745 3238 return EINVAL;
5c9f4661
A
3239 }
3240
6d2010ae 3241 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
0a7de745
A
3242 if (ifs == bif->bif_ifp) {
3243 return EBUSY;
3244 }
6d2010ae 3245
0a7de745
A
3246 if (ifs->if_bridge != NULL) {
3247 return EBUSY;
3248 }
6d2010ae
A
3249
3250 switch (ifs->if_type) {
0a7de745
A
3251 case IFT_ETHER:
3252 case IFT_L2VLAN:
3253 break;
3254 case IFT_GIF:
3255 /* currently not supported */
3256 /* FALLTHRU */
3257 default:
3258 return EINVAL;
6d2010ae
A
3259 }
3260
0a7de745
A
3261 bif = _MALLOC(sizeof(*bif), M_DEVBUF, M_WAITOK | M_ZERO);
3262 if (bif == NULL) {
3263 return ENOMEM;
3264 }
6d2010ae
A
3265
3266 bif->bif_ifp = ifs;
39236c6e 3267 bif->bif_ifflags = IFBIF_SPAN;
6d2010ae
A
3268
3269 ifnet_reference(bif->bif_ifp);
3270
3271 TAILQ_INSERT_HEAD(&sc->sc_spanlist, bif, bif_next);
3272
0a7de745 3273 return 0;
6d2010ae
A
3274}
3275
3276static int
3277bridge_ioctl_delspan(struct bridge_softc *sc, void *arg)
3278{
3279 struct ifbreq *req = arg;
3280 struct bridge_iflist *bif;
3281 struct ifnet *ifs;
3282
3283 ifs = ifunit(req->ifbr_ifsname);
0a7de745
A
3284 if (ifs == NULL) {
3285 return ENOENT;
3286 }
6d2010ae
A
3287
3288 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
0a7de745
A
3289 if (ifs == bif->bif_ifp) {
3290 break;
3291 }
6d2010ae 3292
0a7de745
A
3293 if (bif == NULL) {
3294 return ENOENT;
3295 }
6d2010ae
A
3296
3297 bridge_delete_span(sc, bif);
3298
0a7de745
A
3299 return 0;
3300}
3301
3302#define BRIDGE_IOCTL_GBPARAM do { \
3303 struct bstp_state *bs = &sc->sc_stp; \
3304 struct bstp_port *root_port; \
3305 \
3306 req->ifbop_maxage = bs->bs_bridge_max_age >> 8; \
3307 req->ifbop_hellotime = bs->bs_bridge_htime >> 8; \
3308 req->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8; \
3309 \
3310 root_port = bs->bs_root_port; \
3311 if (root_port == NULL) \
3312 req->ifbop_root_port = 0; \
3313 else \
3314 req->ifbop_root_port = root_port->bp_ifp->if_index; \
3315 \
3316 req->ifbop_holdcount = bs->bs_txholdcount; \
3317 req->ifbop_priority = bs->bs_bridge_priority; \
3318 req->ifbop_protocol = bs->bs_protover; \
3319 req->ifbop_root_path_cost = bs->bs_root_pv.pv_cost; \
3320 req->ifbop_bridgeid = bs->bs_bridge_pv.pv_dbridge_id; \
3321 req->ifbop_designated_root = bs->bs_root_pv.pv_root_id; \
3322 req->ifbop_designated_bridge = bs->bs_root_pv.pv_dbridge_id; \
3323 req->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec; \
3324 req->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec; \
6d2010ae
A
3325} while (0)
3326
3327static int
3328bridge_ioctl_gbparam32(struct bridge_softc *sc, void *arg)
3329{
3330 struct ifbropreq32 *req = arg;
3331
cb323159 3332 BRIDGE_IOCTL_GBPARAM;
0a7de745 3333 return 0;
6d2010ae
A
3334}
3335
3336static int
3337bridge_ioctl_gbparam64(struct bridge_softc *sc, void *arg)
3338{
3339 struct ifbropreq64 *req = arg;
3340
cb323159 3341 BRIDGE_IOCTL_GBPARAM;
0a7de745 3342 return 0;
6d2010ae
A
3343}
3344
6d2010ae
A
3345static int
3346bridge_ioctl_grte(struct bridge_softc *sc, void *arg)
3347{
3348 struct ifbrparam *param = arg;
3349
3350 param->ifbrp_cexceeded = sc->sc_brtexceeded;
0a7de745
A
3351 return 0;
3352}
3353
3354#define BRIDGE_IOCTL_GIFSSTP do { \
3355 struct bridge_iflist *bif; \
3356 struct bstp_port *bp; \
3357 struct ifbpstpreq bpreq; \
3358 char *buf, *outbuf; \
3359 unsigned int count, buflen, len; \
3360 \
3361 count = 0; \
3362 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) { \
3363 if ((bif->bif_ifflags & IFBIF_STP) != 0) \
3364 count++; \
3365 } \
3366 \
3367 buflen = sizeof (bpreq) * count; \
3368 if (bifstp->ifbpstp_len == 0) { \
3369 bifstp->ifbpstp_len = buflen; \
3370 return (0); \
3371 } \
3372 \
3373 BRIDGE_UNLOCK(sc); \
3374 outbuf = _MALLOC(buflen, M_TEMP, M_WAITOK | M_ZERO); \
3375 BRIDGE_LOCK(sc); \
3376 \
3377 count = 0; \
3378 buf = outbuf; \
3379 len = min(bifstp->ifbpstp_len, buflen); \
3380 bzero(&bpreq, sizeof (bpreq)); \
3381 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) { \
3382 if (len < sizeof (bpreq)) \
3383 break; \
3384 \
3385 if ((bif->bif_ifflags & IFBIF_STP) == 0) \
3386 continue; \
3387 \
3388 bp = &bif->bif_stp; \
3389 bpreq.ifbp_portno = bif->bif_ifp->if_index & 0xfff; \
3390 bpreq.ifbp_fwd_trans = bp->bp_forward_transitions; \
3391 bpreq.ifbp_design_cost = bp->bp_desg_pv.pv_cost; \
3392 bpreq.ifbp_design_port = bp->bp_desg_pv.pv_port_id; \
3393 bpreq.ifbp_design_bridge = bp->bp_desg_pv.pv_dbridge_id; \
3394 bpreq.ifbp_design_root = bp->bp_desg_pv.pv_root_id; \
3395 \
3396 memcpy(buf, &bpreq, sizeof (bpreq)); \
3397 count++; \
3398 buf += sizeof (bpreq); \
3399 len -= sizeof (bpreq); \
3400 } \
3401 \
3402 BRIDGE_UNLOCK(sc); \
3403 bifstp->ifbpstp_len = sizeof (bpreq) * count; \
6d2010ae 3404 error = copyout(outbuf, bifstp->ifbpstp_req, bifstp->ifbpstp_len); \
0a7de745
A
3405 BRIDGE_LOCK(sc); \
3406 _FREE(outbuf, M_TEMP); \
3407 return (error); \
6d2010ae
A
3408} while (0)
3409
3410static int
3411bridge_ioctl_gifsstp32(struct bridge_softc *sc, void *arg)
3412{
3413 struct ifbpstpconf32 *bifstp = arg;
3414 int error = 0;
3415
cb323159 3416 BRIDGE_IOCTL_GIFSSTP;
0a7de745 3417 return error;
6d2010ae
A
3418}
3419
3420static int
3421bridge_ioctl_gifsstp64(struct bridge_softc *sc, void *arg)
3422{
3423 struct ifbpstpconf64 *bifstp = arg;
3424 int error = 0;
3425
cb323159 3426 BRIDGE_IOCTL_GIFSSTP;
0a7de745 3427 return error;
6d2010ae
A
3428}
3429
3430static int
3431bridge_ioctl_sproto(struct bridge_softc *sc, void *arg)
3432{
316670eb 3433#if BRIDGESTP
6d2010ae
A
3434 struct ifbrparam *param = arg;
3435
0a7de745 3436 return bstp_set_protocol(&sc->sc_stp, param->ifbrp_proto);
316670eb
A
3437#else /* !BRIDGESTP */
3438#pragma unused(sc, arg)
0a7de745 3439 return EOPNOTSUPP;
316670eb 3440#endif /* !BRIDGESTP */
6d2010ae
A
3441}
3442
3443static int
3444bridge_ioctl_stxhc(struct bridge_softc *sc, void *arg)
3445{
316670eb 3446#if BRIDGESTP
6d2010ae
A
3447 struct ifbrparam *param = arg;
3448
0a7de745 3449 return bstp_set_holdcount(&sc->sc_stp, param->ifbrp_txhc);
316670eb
A
3450#else /* !BRIDGESTP */
3451#pragma unused(sc, arg)
0a7de745 3452 return EOPNOTSUPP;
316670eb 3453#endif /* !BRIDGESTP */
6d2010ae
A
3454}
3455
fe8ab488
A
3456
3457static int
3458bridge_ioctl_ghostfilter(struct bridge_softc *sc, void *arg)
3459{
3460 struct ifbrhostfilter *req = arg;
3461 struct bridge_iflist *bif;
3462
3463 bif = bridge_lookup_member(sc, req->ifbrhf_ifsname);
0a7de745
A
3464 if (bif == NULL) {
3465 return ENOENT;
3466 }
fe8ab488
A
3467
3468 bzero(req, sizeof(struct ifbrhostfilter));
3469 if (bif->bif_flags & BIFF_HOST_FILTER) {
3470 req->ifbrhf_flags |= IFBRHF_ENABLED;
3471 bcopy(bif->bif_hf_hwsrc, req->ifbrhf_hwsrca,
3472 ETHER_ADDR_LEN);
3473 req->ifbrhf_ipsrc = bif->bif_hf_ipsrc.s_addr;
3474 }
0a7de745 3475 return 0;
fe8ab488
A
3476}
3477
3478static int
3479bridge_ioctl_shostfilter(struct bridge_softc *sc, void *arg)
3480{
3481 struct ifbrhostfilter *req = arg;
3482 struct bridge_iflist *bif;
3483
3484 bif = bridge_lookup_member(sc, req->ifbrhf_ifsname);
0a7de745
A
3485 if (bif == NULL) {
3486 return ENOENT;
3487 }
fe8ab488 3488
5ba3f43e
A
3489 INC_ATOMIC_INT64_LIM(net_api_stats.nas_vmnet_total);
3490
fe8ab488
A
3491 if (req->ifbrhf_flags & IFBRHF_ENABLED) {
3492 bif->bif_flags |= BIFF_HOST_FILTER;
3493
3494 if (req->ifbrhf_flags & IFBRHF_HWSRC) {
3495 bcopy(req->ifbrhf_hwsrca, bif->bif_hf_hwsrc,
3496 ETHER_ADDR_LEN);
3497 if (bcmp(req->ifbrhf_hwsrca, ethernulladdr,
0a7de745 3498 ETHER_ADDR_LEN) != 0) {
fe8ab488 3499 bif->bif_flags |= BIFF_HF_HWSRC;
0a7de745 3500 } else {
fe8ab488 3501 bif->bif_flags &= ~BIFF_HF_HWSRC;
0a7de745 3502 }
fe8ab488
A
3503 }
3504 if (req->ifbrhf_flags & IFBRHF_IPSRC) {
3505 bif->bif_hf_ipsrc.s_addr = req->ifbrhf_ipsrc;
0a7de745 3506 if (bif->bif_hf_ipsrc.s_addr != INADDR_ANY) {
fe8ab488 3507 bif->bif_flags |= BIFF_HF_IPSRC;
0a7de745 3508 } else {
fe8ab488 3509 bif->bif_flags &= ~BIFF_HF_IPSRC;
0a7de745 3510 }
fe8ab488
A
3511 }
3512 } else {
3513 bif->bif_flags &= ~(BIFF_HOST_FILTER | BIFF_HF_HWSRC |
3514 BIFF_HF_IPSRC);
3515 bzero(bif->bif_hf_hwsrc, ETHER_ADDR_LEN);
3516 bif->bif_hf_ipsrc.s_addr = INADDR_ANY;
3517 }
3518
0a7de745 3519 return 0;
fe8ab488
A
3520}
3521
ea3f0419
A
3522static char *
3523bridge_mac_nat_entry_out(struct mac_nat_entry_list * list,
3524 unsigned int * count_p, char *buf, unsigned int *len_p)
3525{
3526 unsigned int count = *count_p;
3527 struct ifbrmne ifbmne;
3528 unsigned int len = *len_p;
3529 struct mac_nat_entry *mne;
3530 unsigned long now;
3531
3532 bzero(&ifbmne, sizeof(ifbmne));
3533 LIST_FOREACH(mne, list, mne_list) {
3534 if (len < sizeof(ifbmne)) {
3535 break;
3536 }
3537 snprintf(ifbmne.ifbmne_ifname, sizeof(ifbmne.ifbmne_ifname),
3538 "%s", mne->mne_bif->bif_ifp->if_xname);
3539 memcpy(ifbmne.ifbmne_mac, mne->mne_mac,
3540 sizeof(ifbmne.ifbmne_mac));
3541 now = (unsigned long) net_uptime();
3542 if (now < mne->mne_expire) {
3543 ifbmne.ifbmne_expire = mne->mne_expire - now;
3544 } else {
3545 ifbmne.ifbmne_expire = 0;
3546 }
3547 if ((mne->mne_flags & MNE_FLAGS_IPV6) != 0) {
3548 ifbmne.ifbmne_af = AF_INET6;
3549 ifbmne.ifbmne_ip6_addr = mne->mne_ip6;
3550 } else {
3551 ifbmne.ifbmne_af = AF_INET;
3552 ifbmne.ifbmne_ip_addr = mne->mne_ip;
3553 }
3554 memcpy(buf, &ifbmne, sizeof(ifbmne));
3555 count++;
3556 buf += sizeof(ifbmne);
3557 len -= sizeof(ifbmne);
3558 }
3559 *count_p = count;
3560 *len_p = len;
3561 return buf;
3562}
3563
3564/*
3565 * bridge_ioctl_gmnelist()
3566 * Perform the get mac_nat_entry list ioctl.
3567 *
3568 * Note:
3569 * The struct ifbrmnelist32 and struct ifbrmnelist64 have the same
3570 * field size/layout except for the last field ifbml_buf, the user-supplied
3571 * buffer pointer. That is passed in separately via the 'user_addr'
3572 * parameter from the respective 32-bit or 64-bit ioctl routine.
3573 */
3574static int
3575bridge_ioctl_gmnelist(struct bridge_softc *sc, struct ifbrmnelist32 *mnl,
3576 user_addr_t user_addr)
3577{
3578 unsigned int count;
3579 char *buf;
3580 int error = 0;
3581 char *outbuf = NULL;
3582 struct mac_nat_entry *mne;
3583 unsigned int buflen;
3584 unsigned int len;
3585
3586 mnl->ifbml_elsize = sizeof(struct ifbrmne);
3587 count = 0;
3588 LIST_FOREACH(mne, &sc->sc_mne_list, mne_list)
3589 count++;
3590 LIST_FOREACH(mne, &sc->sc_mne_list_v6, mne_list)
3591 count++;
3592 buflen = sizeof(struct ifbrmne) * count;
3593 if (buflen == 0 || mnl->ifbml_len == 0) {
3594 mnl->ifbml_len = buflen;
3595 return error;
3596 }
3597 BRIDGE_UNLOCK(sc);
3598 outbuf = _MALLOC(buflen, M_TEMP, M_WAITOK | M_ZERO);
3599 BRIDGE_LOCK(sc);
3600 count = 0;
3601 buf = outbuf;
3602 len = min(mnl->ifbml_len, buflen);
3603 buf = bridge_mac_nat_entry_out(&sc->sc_mne_list, &count, buf, &len);
3604 buf = bridge_mac_nat_entry_out(&sc->sc_mne_list_v6, &count, buf, &len);
3605 mnl->ifbml_len = count * sizeof(struct ifbrmne);
3606 BRIDGE_UNLOCK(sc);
3607 error = copyout(outbuf, user_addr, mnl->ifbml_len);
3608 _FREE(outbuf, M_TEMP);
3609 BRIDGE_LOCK(sc);
3610 return error;
3611}
3612
3613static int
3614bridge_ioctl_gmnelist64(struct bridge_softc *sc, void *arg)
3615{
3616 struct ifbrmnelist64 *mnl = arg;
3617
3618 return bridge_ioctl_gmnelist(sc, arg, mnl->ifbml_buf);
3619}
3620
3621static int
3622bridge_ioctl_gmnelist32(struct bridge_softc *sc, void *arg)
3623{
3624 struct ifbrmnelist32 *mnl = arg;
3625
3626 return bridge_ioctl_gmnelist(sc, arg,
3627 CAST_USER_ADDR_T(mnl->ifbml_buf));
3628}
fe8ab488 3629
6d2010ae
A
3630/*
3631 * bridge_ifdetach:
3632 *
3633 * Detach an interface from a bridge. Called when a member
3634 * interface is detaching.
3635 */
cb323159
A
3636static void
3637bridge_ifdetach(struct ifnet *ifp)
6d2010ae 3638{
cb323159 3639 struct bridge_iflist *bif;
6d2010ae
A
3640 struct bridge_softc *sc = ifp->if_bridge;
3641
3642#if BRIDGE_DEBUG
ea3f0419 3643 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
39236c6e 3644 printf("%s: %s\n", __func__, ifp->if_xname);
0a7de745 3645 }
39236c6e 3646#endif /* BRIDGE_DEBUG */
6d2010ae
A
3647
3648 /* Check if the interface is a bridge member */
3649 if (sc != NULL) {
3650 BRIDGE_LOCK(sc);
6d2010ae 3651 bif = bridge_lookup_member_if(sc, ifp);
0a7de745 3652 if (bif != NULL) {
6d2010ae 3653 bridge_delete_member(sc, bif, 1);
0a7de745 3654 }
6d2010ae
A
3655 BRIDGE_UNLOCK(sc);
3656 return;
3657 }
6d2010ae 3658 /* Check if the interface is a span port */
39236c6e 3659 lck_mtx_lock(&bridge_list_mtx);
6d2010ae 3660 LIST_FOREACH(sc, &bridge_list, sc_list) {
cb323159
A
3661 BRIDGE_LOCK(sc);
3662 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
3663 if (ifp == bif->bif_ifp) {
3664 bridge_delete_span(sc, bif);
3665 break;
5ba3f43e 3666 }
cb323159 3667 BRIDGE_UNLOCK(sc);
6d2010ae 3668 }
39236c6e 3669 lck_mtx_unlock(&bridge_list_mtx);
6d2010ae
A
3670}
3671
cb323159
A
3672/*
3673 * bridge_proto_attach_changed
3674 *
3675 * Called when protocol attachment on the interface changes.
3676 */
3677static void
3678bridge_proto_attach_changed(struct ifnet *ifp)
3679{
3680 boolean_t changed = FALSE;
3681 struct bridge_iflist *bif;
3682 boolean_t input_broadcast;
3683 struct bridge_softc *sc = ifp->if_bridge;
3684
3685#if BRIDGE_DEBUG
ea3f0419 3686 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
cb323159
A
3687 printf("%s: %s\n", __func__, ifp->if_xname);
3688 }
3689#endif /* BRIDGE_DEBUG */
3690 if (sc == NULL) {
3691 return;
3692 }
3693 /*
3694 * Selectively enable input broadcast only when necessary.
3695 * The bridge interface itself attaches a fake protocol
3696 * so checking for at least two protocols means that the
3697 * interface is being used for something besides bridging.
3698 */
3699 input_broadcast = if_get_protolist(ifp, NULL, 0) >= 2;
3700 BRIDGE_LOCK(sc);
3701 bif = bridge_lookup_member_if(sc, ifp);
3702 if (bif != NULL) {
3703 if (input_broadcast) {
3704 if ((bif->bif_flags & BIFF_INPUT_BROADCAST) == 0) {
3705 bif->bif_flags |= BIFF_INPUT_BROADCAST;
3706 changed = TRUE;
3707 }
3708 } else if ((bif->bif_flags & BIFF_INPUT_BROADCAST) != 0) {
3709 changed = TRUE;
3710 bif->bif_flags &= ~BIFF_INPUT_BROADCAST;
3711 }
3712 }
3713 BRIDGE_UNLOCK(sc);
3714#if BRIDGE_DEBUG
ea3f0419 3715 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
cb323159
A
3716 printf("%s: input broadcast %s", ifp->if_xname,
3717 input_broadcast ? "ENABLED" : "DISABLED");
3718 }
3719#endif /* BRIDGE_DEBUG */
3720 return;
3721}
3722
6d2010ae 3723/*
39236c6e 3724 * interface_media_active:
6d2010ae 3725 *
39236c6e 3726 * Tells if an interface media is active.
6d2010ae
A
3727 */
3728static int
39236c6e 3729interface_media_active(struct ifnet *ifp)
6d2010ae 3730{
39236c6e
A
3731 struct ifmediareq ifmr;
3732 int status = 0;
6d2010ae 3733
39236c6e
A
3734 bzero(&ifmr, sizeof(ifmr));
3735 if (ifnet_ioctl(ifp, 0, SIOCGIFMEDIA, &ifmr) == 0) {
0a7de745 3736 if ((ifmr.ifm_status & IFM_AVALID) && ifmr.ifm_count > 0) {
39236c6e 3737 status = ifmr.ifm_status & IFM_ACTIVE ? 1 : 0;
0a7de745 3738 }
39236c6e 3739 }
6d2010ae 3740
0a7de745 3741 return status;
6d2010ae
A
3742}
3743
3744/*
39236c6e 3745 * bridge_updatelinkstatus:
6d2010ae 3746 *
0a7de745 3747 * Update the media active status of the bridge based on the
39236c6e
A
3748 * media active status of its member.
3749 * If changed, return the corresponding onf/off link event.
6d2010ae 3750 */
39236c6e
A
3751static u_int32_t
3752bridge_updatelinkstatus(struct bridge_softc *sc)
6d2010ae 3753{
39236c6e
A
3754 struct bridge_iflist *bif;
3755 int active_member = 0;
3756 u_int32_t event_code = 0;
6d2010ae 3757
39236c6e 3758 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae 3759
39236c6e
A
3760 /*
3761 * Find out if we have an active interface
3762 */
3763 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
3764 if (bif->bif_flags & BIFF_MEDIA_ACTIVE) {
3765 active_member = 1;
3766 break;
3767 }
3768 }
3769
3770 if (active_member && !(sc->sc_flags & SCF_MEDIA_ACTIVE)) {
3771 sc->sc_flags |= SCF_MEDIA_ACTIVE;
3772 event_code = KEV_DL_LINK_ON;
3773 } else if (!active_member && (sc->sc_flags & SCF_MEDIA_ACTIVE)) {
3774 sc->sc_flags &= ~SCF_MEDIA_ACTIVE;
3775 event_code = KEV_DL_LINK_OFF;
3776 }
3777
0a7de745 3778 return event_code;
39236c6e
A
3779}
3780
3781/*
3782 * bridge_iflinkevent:
3783 */
3784static void
3785bridge_iflinkevent(struct ifnet *ifp)
3786{
3787 struct bridge_softc *sc = ifp->if_bridge;
3788 struct bridge_iflist *bif;
3789 u_int32_t event_code = 0;
3790
3791#if BRIDGE_DEBUG
ea3f0419 3792 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
39236c6e 3793 printf("%s: %s\n", __func__, ifp->if_xname);
0a7de745 3794 }
39236c6e
A
3795#endif /* BRIDGE_DEBUG */
3796
3797 /* Check if the interface is a bridge member */
0a7de745 3798 if (sc == NULL) {
39236c6e 3799 return;
0a7de745 3800 }
39236c6e
A
3801
3802 BRIDGE_LOCK(sc);
3803 bif = bridge_lookup_member_if(sc, ifp);
3804 if (bif != NULL) {
0a7de745 3805 if (interface_media_active(ifp)) {
39236c6e 3806 bif->bif_flags |= BIFF_MEDIA_ACTIVE;
0a7de745 3807 } else {
39236c6e 3808 bif->bif_flags &= ~BIFF_MEDIA_ACTIVE;
0a7de745 3809 }
ea3f0419
A
3810 if (sc->sc_mac_nat_bif != NULL) {
3811 bridge_mac_nat_flush_entries(sc, bif);
3812 }
39236c6e 3813
0a7de745 3814 event_code = bridge_updatelinkstatus(sc);
39236c6e
A
3815 }
3816 BRIDGE_UNLOCK(sc);
3817
0a7de745 3818 if (event_code != 0) {
39236c6e 3819 bridge_link_event(sc->sc_ifp, event_code);
0a7de745 3820 }
39236c6e
A
3821}
3822
3823/*
3824 * bridge_delayed_callback:
3825 *
3826 * Makes a delayed call
3827 */
3828static void
3829bridge_delayed_callback(void *param)
3830{
3831 struct bridge_delayed_call *call = (struct bridge_delayed_call *)param;
3832 struct bridge_softc *sc = call->bdc_sc;
3833
3834#if BRIDGE_DEBUG_DELAYED_CALLBACK
3835 if (bridge_delayed_callback_delay > 0) {
3836 struct timespec ts;
3837
3838 ts.tv_sec = bridge_delayed_callback_delay;
3839 ts.tv_nsec = 0;
3840
3841 printf("%s: sleeping for %d seconds\n",
3842 __func__, bridge_delayed_callback_delay);
3843
3844 msleep(&bridge_delayed_callback_delay, NULL, PZERO,
3845 __func__, &ts);
3846
3847 printf("%s: awoken\n", __func__);
3848 }
3849#endif /* BRIDGE_DEBUG_DELAYED_CALLBACK */
3850
3851 BRIDGE_LOCK(sc);
3852
fe8ab488 3853#if BRIDGE_DEBUG_DELAYED_CALLBACK
ea3f0419 3854 if (IF_BRIDGE_DEBUG(BR_DBGF_DELAYED_CALL)) {
39236c6e
A
3855 printf("%s: %s call 0x%llx flags 0x%x\n", __func__,
3856 sc->sc_if_xname, (uint64_t)VM_KERNEL_ADDRPERM(call),
3857 call->bdc_flags);
0a7de745 3858 }
fe8ab488 3859#endif /* BRIDGE_DEBUG_DELAYED_CALLBACK */
39236c6e 3860
fe8ab488 3861 if (call->bdc_flags & BDCF_CANCELLING) {
39236c6e
A
3862 wakeup(call);
3863 } else {
0a7de745 3864 if ((sc->sc_flags & SCF_DETACHING) == 0) {
39236c6e
A
3865 (*call->bdc_func)(sc);
3866 }
0a7de745 3867 }
39236c6e
A
3868 call->bdc_flags &= ~BDCF_OUTSTANDING;
3869 BRIDGE_UNLOCK(sc);
3870}
3871
3872/*
3873 * bridge_schedule_delayed_call:
3874 *
3875 * Schedule a function to be called on a separate thread
0a7de745 3876 * The actual call may be scheduled to run at a given time or ASAP.
39236c6e
A
3877 */
3878static void
3879bridge_schedule_delayed_call(struct bridge_delayed_call *call)
3880{
3881 uint64_t deadline = 0;
3882 struct bridge_softc *sc = call->bdc_sc;
3883
3884 BRIDGE_LOCK_ASSERT_HELD(sc);
3885
3886 if ((sc->sc_flags & SCF_DETACHING) ||
0a7de745 3887 (call->bdc_flags & (BDCF_OUTSTANDING | BDCF_CANCELLING))) {
39236c6e 3888 return;
0a7de745 3889 }
39236c6e
A
3890
3891 if (call->bdc_ts.tv_sec || call->bdc_ts.tv_nsec) {
3892 nanoseconds_to_absolutetime(
0a7de745
A
3893 (uint64_t)call->bdc_ts.tv_sec * NSEC_PER_SEC +
3894 call->bdc_ts.tv_nsec, &deadline);
39236c6e
A
3895 clock_absolutetime_interval_to_deadline(deadline, &deadline);
3896 }
3897
3898 call->bdc_flags = BDCF_OUTSTANDING;
3899
fe8ab488 3900#if BRIDGE_DEBUG_DELAYED_CALLBACK
ea3f0419 3901 if (IF_BRIDGE_DEBUG(BR_DBGF_DELAYED_CALL)) {
39236c6e
A
3902 printf("%s: %s call 0x%llx flags 0x%x\n", __func__,
3903 sc->sc_if_xname, (uint64_t)VM_KERNEL_ADDRPERM(call),
3904 call->bdc_flags);
0a7de745 3905 }
fe8ab488 3906#endif /* BRIDGE_DEBUG_DELAYED_CALLBACK */
39236c6e 3907
0a7de745 3908 if (call->bdc_ts.tv_sec || call->bdc_ts.tv_nsec) {
fe8ab488
A
3909 thread_call_func_delayed(
3910 (thread_call_func_t)bridge_delayed_callback,
3911 call, deadline);
0a7de745
A
3912 } else {
3913 if (call->bdc_thread_call == NULL) {
fe8ab488
A
3914 call->bdc_thread_call = thread_call_allocate(
3915 (thread_call_func_t)bridge_delayed_callback,
3916 call);
0a7de745 3917 }
fe8ab488
A
3918 thread_call_enter(call->bdc_thread_call);
3919 }
39236c6e
A
3920}
3921
3922/*
3923 * bridge_cancel_delayed_call:
3924 *
3925 * Cancel a queued or running delayed call.
3926 * If call is running, does not return until the call is done to
3927 * prevent race condition with the brigde interface getting destroyed
3928 */
3929static void
3930bridge_cancel_delayed_call(struct bridge_delayed_call *call)
3931{
3932 boolean_t result;
3933 struct bridge_softc *sc = call->bdc_sc;
3934
3935 /*
3936 * The call was never scheduled
3937 */
0a7de745 3938 if (sc == NULL) {
39236c6e 3939 return;
0a7de745 3940 }
39236c6e
A
3941
3942 BRIDGE_LOCK_ASSERT_HELD(sc);
3943
3944 call->bdc_flags |= BDCF_CANCELLING;
3945
3946 while (call->bdc_flags & BDCF_OUTSTANDING) {
3947#if BRIDGE_DEBUG
ea3f0419 3948 if (IF_BRIDGE_DEBUG(BR_DBGF_DELAYED_CALL)) {
39236c6e
A
3949 printf("%s: %s call 0x%llx flags 0x%x\n", __func__,
3950 sc->sc_if_xname, (uint64_t)VM_KERNEL_ADDRPERM(call),
3951 call->bdc_flags);
0a7de745 3952 }
39236c6e
A
3953#endif /* BRIDGE_DEBUG */
3954 result = thread_call_func_cancel(
0a7de745 3955 (thread_call_func_t)bridge_delayed_callback, call, FALSE);
39236c6e
A
3956
3957 if (result) {
3958 /*
3959 * We managed to dequeue the delayed call
3960 */
3961 call->bdc_flags &= ~BDCF_OUTSTANDING;
3962 } else {
3963 /*
3964 * Wait for delayed call do be done running
3965 */
3966 msleep(call, &sc->sc_mtx, PZERO, __func__, NULL);
3967 }
3968 }
3969 call->bdc_flags &= ~BDCF_CANCELLING;
3970}
3971
fe8ab488
A
3972/*
3973 * bridge_cleanup_delayed_call:
3974 *
3975 * Dispose resource allocated for a delayed call
3976 * Assume the delayed call is not queued or running .
3977 */
3978static void
3979bridge_cleanup_delayed_call(struct bridge_delayed_call *call)
3980{
3981 boolean_t result;
3982 struct bridge_softc *sc = call->bdc_sc;
3983
3984 /*
3985 * The call was never scheduled
3986 */
0a7de745 3987 if (sc == NULL) {
fe8ab488 3988 return;
0a7de745 3989 }
fe8ab488
A
3990
3991 BRIDGE_LOCK_ASSERT_HELD(sc);
3992
3993 VERIFY((call->bdc_flags & BDCF_OUTSTANDING) == 0);
3994 VERIFY((call->bdc_flags & BDCF_CANCELLING) == 0);
3995
3996 if (call->bdc_thread_call != NULL) {
3997 result = thread_call_free(call->bdc_thread_call);
0a7de745 3998 if (result == FALSE) {
fe8ab488 3999 panic("%s thread_call_free() failed for call %p",
0a7de745
A
4000 __func__, call);
4001 }
fe8ab488
A
4002 call->bdc_thread_call = NULL;
4003 }
4004}
4005
39236c6e
A
4006/*
4007 * bridge_init:
4008 *
4009 * Initialize a bridge interface.
4010 */
4011static int
4012bridge_init(struct ifnet *ifp)
4013{
4014 struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
4015 errno_t error;
4016
4017 BRIDGE_LOCK_ASSERT_HELD(sc);
4018
0a7de745
A
4019 if ((ifnet_flags(ifp) & IFF_RUNNING)) {
4020 return 0;
4021 }
39236c6e
A
4022
4023 error = ifnet_set_flags(ifp, IFF_RUNNING, IFF_RUNNING);
4024
cb323159
A
4025 /*
4026 * Calling bridge_aging_timer() is OK as there are no entries to
4027 * age so we're just going to arm the timer
4028 */
4029 bridge_aging_timer(sc);
39236c6e 4030#if BRIDGESTP
cb323159
A
4031 if (error == 0) {
4032 bstp_init(&sc->sc_stp); /* Initialize Spanning Tree */
5ba3f43e 4033 }
cb323159 4034#endif /* BRIDGESTP */
0a7de745 4035 return error;
39236c6e
A
4036}
4037
4038/*
4039 * bridge_ifstop:
4040 *
4041 * Stop the bridge interface.
4042 */
4043static void
4044bridge_ifstop(struct ifnet *ifp, int disable)
4045{
4046#pragma unused(disable)
4047 struct bridge_softc *sc = ifp->if_softc;
4048
4049 BRIDGE_LOCK_ASSERT_HELD(sc);
4050
0a7de745 4051 if ((ifnet_flags(ifp) & IFF_RUNNING) == 0) {
39236c6e 4052 return;
0a7de745 4053 }
39236c6e 4054
cb323159 4055 bridge_cancel_delayed_call(&sc->sc_aging_timer);
39236c6e
A
4056
4057#if BRIDGESTP
cb323159 4058 bstp_stop(&sc->sc_stp);
316670eb 4059#endif /* BRIDGESTP */
6d2010ae 4060
cb323159 4061 bridge_rtflush(sc, IFBF_FLUSHDYN);
6d2010ae
A
4062 (void) ifnet_set_flags(ifp, 0, IFF_RUNNING);
4063}
4064
cb323159
A
4065/*
4066 * bridge_compute_cksum:
4067 *
4068 * If the packet has checksum flags, compare the hardware checksum
4069 * capabilities of the source and destination interfaces. If they
4070 * are the same, there's nothing to do. If they are different,
4071 * finalize the checksum so that it can be sent on the destination
4072 * interface.
4073 */
4074static void
4075bridge_compute_cksum(struct ifnet *src_if, struct ifnet *dst_if, struct mbuf *m)
4076{
4077 uint32_t csum_flags;
4078 uint16_t dst_hw_csum;
4079 uint32_t did_sw;
4080 struct ether_header *eh;
4081 uint16_t src_hw_csum;
4082
4083 csum_flags = m->m_pkthdr.csum_flags & IF_HWASSIST_CSUM_MASK;
4084 if (csum_flags == 0) {
4085 /* no checksum offload */
4086 return;
4087 }
4088
4089 /*
4090 * if destination/source differ in checksum offload
4091 * capabilities, finalize/compute the checksum
4092 */
4093 dst_hw_csum = IF_HWASSIST_CSUM_FLAGS(dst_if->if_hwassist);
4094 src_hw_csum = IF_HWASSIST_CSUM_FLAGS(src_if->if_hwassist);
4095 if (dst_hw_csum == src_hw_csum) {
4096 return;
4097 }
4098 eh = mtod(m, struct ether_header *);
4099 switch (ntohs(eh->ether_type)) {
4100 case ETHERTYPE_IP:
4101 did_sw = in_finalize_cksum(m, sizeof(*eh), csum_flags);
4102 break;
4103#if INET6
4104 case ETHERTYPE_IPV6:
4105 did_sw = in6_finalize_cksum(m, sizeof(*eh), -1, -1, csum_flags);
4106 break;
4107#endif /* INET6 */
4108 }
4109#if BRIDGE_DEBUG
ea3f0419 4110 if (IF_BRIDGE_DEBUG(BR_DBGF_CHECKSUM)) {
cb323159
A
4111 printf("%s: [%s -> %s] before 0x%x did 0x%x after 0x%x\n",
4112 __func__,
4113 src_if->if_xname, dst_if->if_xname, csum_flags, did_sw,
4114 m->m_pkthdr.csum_flags);
4115 }
4116#endif /* BRIDGE_DEBUG */
4117}
4118
6d2010ae
A
4119/*
4120 * bridge_enqueue:
4121 *
4122 * Enqueue a packet on a bridge member interface.
4123 *
4124 */
316670eb 4125static int
ea3f0419 4126bridge_enqueue(ifnet_t bridge_ifp, struct ifnet *src_ifp,
cb323159 4127 struct ifnet *dst_ifp, struct mbuf *m, ChecksumOperation cksum_op)
6d2010ae
A
4128{
4129 int len, error = 0;
cb323159 4130 struct mbuf *next_m;
6d2010ae 4131
316670eb
A
4132 VERIFY(dst_ifp != NULL);
4133
4134 /*
4135 * We may be sending a fragment so traverse the mbuf
4136 *
4137 * NOTE: bridge_fragment() is called only when PFIL_HOOKS is enabled.
4138 */
cb323159 4139 for (; m; m = next_m) {
316670eb 4140 errno_t _error;
cb323159 4141 struct flowadv adv = { .code = FADV_SUCCESS };
316670eb 4142
cb323159 4143 next_m = m->m_nextpkt;
6d2010ae
A
4144 m->m_nextpkt = NULL;
4145
4146 len = m->m_pkthdr.len;
316670eb 4147 m->m_flags |= M_PROTO1; /* set to avoid loops */
6d2010ae 4148
cb323159
A
4149 switch (cksum_op) {
4150 case kChecksumOperationClear:
4151 m->m_pkthdr.csum_flags = 0;
4152 break;
4153 case kChecksumOperationFinalize:
4154 /* the checksum might not be correct, finalize now */
4155 bridge_finalize_cksum(dst_ifp, m);
4156 break;
4157 case kChecksumOperationCompute:
4158 bridge_compute_cksum(src_ifp, dst_ifp, m);
4159 break;
4160 default:
4161 break;
4162 }
6d2010ae
A
4163#if HAS_IF_CAP
4164 /*
4165 * If underlying interface can not do VLAN tag insertion itself
4166 * then attach a packet tag that holds it.
4167 */
4168 if ((m->m_flags & M_VLANTAG) &&
4169 (dst_ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) {
4170 m = ether_vlanencap(m, m->m_pkthdr.ether_vtag);
4171 if (m == NULL) {
39236c6e
A
4172 printf("%s: %s: unable to prepend VLAN "
4173 "header\n", __func__, dst_ifp->if_xname);
316670eb
A
4174 (void) ifnet_stat_increment_out(dst_ifp,
4175 0, 0, 1);
6d2010ae
A
4176 continue;
4177 }
4178 m->m_flags &= ~M_VLANTAG;
4179 }
4180#endif /* HAS_IF_CAP */
4181
316670eb
A
4182 _error = dlil_output(dst_ifp, 0, m, NULL, NULL, 1, &adv);
4183
4184 /* Preserve existing error value */
6d2010ae 4185 if (error == 0) {
0a7de745 4186 if (_error != 0) {
316670eb 4187 error = _error;
0a7de745 4188 } else if (adv.code == FADV_FLOW_CONTROLLED) {
316670eb 4189 error = EQFULL;
0a7de745 4190 } else if (adv.code == FADV_SUSPENDED) {
316670eb 4191 error = EQSUSPENDED;
0a7de745 4192 }
316670eb
A
4193 }
4194
4195 if (_error == 0) {
ea3f0419 4196 (void) ifnet_stat_increment_out(bridge_ifp, 1, len, 0);
6d2010ae 4197 } else {
ea3f0419 4198 (void) ifnet_stat_increment_out(bridge_ifp, 0, 0, 1);
6d2010ae
A
4199 }
4200 }
4201
0a7de745 4202 return error;
6d2010ae
A
4203}
4204
4205#if HAS_BRIDGE_DUMMYNET
4206/*
4207 * bridge_dummynet:
4208 *
316670eb
A
4209 * Receive a queued packet from dummynet and pass it on to the output
4210 * interface.
6d2010ae
A
4211 *
4212 * The mbuf has the Ethernet header already attached.
4213 */
4214static void
4215bridge_dummynet(struct mbuf *m, struct ifnet *ifp)
4216{
4217 struct bridge_softc *sc;
4218
4219 sc = ifp->if_bridge;
4220
4221 /*
cb323159 4222 * The packet didn't originate from a member interface. This should only
6d2010ae
A
4223 * ever happen if a member interface is removed while packets are
4224 * queued for it.
4225 */
4226 if (sc == NULL) {
4227 m_freem(m);
4228 return;
4229 }
4230
39236c6e 4231 if (PFIL_HOOKED(&inet_pfil_hook) || PFIL_HOOKED_INET6) {
0a7de745 4232 if (bridge_pfil(&m, sc->sc_ifp, ifp, PFIL_OUT) != 0) {
6d2010ae 4233 return;
0a7de745
A
4234 }
4235 if (m == NULL) {
6d2010ae 4236 return;
0a7de745 4237 }
6d2010ae 4238 }
ea3f0419 4239 (void) bridge_enqueue(sc->sc_ifp, NULL, ifp, m, kChecksumOperationNone);
6d2010ae
A
4240}
4241#endif /* HAS_BRIDGE_DUMMYNET */
4242
6d2010ae 4243/*
316670eb 4244 * bridge_member_output:
6d2010ae
A
4245 *
4246 * Send output from a bridge member interface. This
4247 * performs the bridging function for locally originated
4248 * packets.
4249 *
cb323159 4250 * The mbuf has the Ethernet header already attached.
6d2010ae 4251 */
cb323159 4252static errno_t
ea3f0419 4253bridge_member_output(struct bridge_softc *sc, ifnet_t ifp, mbuf_t *data)
6d2010ae 4254{
ea3f0419 4255 ifnet_t bridge_ifp;
6d2010ae
A
4256 struct ether_header *eh;
4257 struct ifnet *dst_if;
6d2010ae 4258 uint16_t vlan;
ea3f0419
A
4259 struct bridge_iflist *mac_nat_bif;
4260 ifnet_t mac_nat_ifp;
4261 mbuf_t m = *data;
6d2010ae
A
4262
4263#if BRIDGE_DEBUG
ea3f0419 4264 if (IF_BRIDGE_DEBUG(BR_DBGF_OUTPUT)) {
39236c6e 4265 printf("%s: ifp %s\n", __func__, ifp->if_xname);
0a7de745 4266 }
6d2010ae 4267#endif /* BRIDGE_DEBUG */
316670eb 4268
6d2010ae
A
4269 if (m->m_len < ETHER_HDR_LEN) {
4270 m = m_pullup(m, ETHER_HDR_LEN);
0a7de745 4271 if (m == NULL) {
ea3f0419
A
4272 *data = NULL;
4273 return EJUSTRETURN;
0a7de745 4274 }
6d2010ae
A
4275 }
4276
4277 eh = mtod(m, struct ether_header *);
6d2010ae
A
4278 vlan = VLANTAGOF(m);
4279
4280 BRIDGE_LOCK(sc);
ea3f0419
A
4281 mac_nat_bif = sc->sc_mac_nat_bif;
4282 mac_nat_ifp = (mac_nat_bif != NULL) ? mac_nat_bif->bif_ifp : NULL;
4283 if (mac_nat_ifp == ifp) {
4284 /* record the IP address used by the MAC NAT interface */
4285 (void)bridge_mac_nat_output(sc, mac_nat_bif, data, NULL);
4286 m = *data;
4287 if (m == NULL) {
4288 /* packet was deallocated */
4289 BRIDGE_UNLOCK(sc);
4290 return EJUSTRETURN;
4291 }
4292 }
4293 bridge_ifp = sc->sc_ifp;
6d2010ae 4294
316670eb
A
4295 /*
4296 * APPLE MODIFICATION
6d2010ae
A
4297 * If the packet is an 802.1X ethertype, then only send on the
4298 * original output interface.
4299 */
4300 if (eh->ether_type == htons(ETHERTYPE_PAE)) {
4301 dst_if = ifp;
4302 goto sendunicast;
4303 }
316670eb 4304
6d2010ae
A
4305 /*
4306 * If bridge is down, but the original output interface is up,
4307 * go ahead and send out that interface. Otherwise, the packet
4308 * is dropped below.
4309 */
ea3f0419 4310 if ((bridge_ifp->if_flags & IFF_RUNNING) == 0) {
6d2010ae
A
4311 dst_if = ifp;
4312 goto sendunicast;
4313 }
4314
4315 /*
4316 * If the packet is a multicast, or we don't know a better way to
4317 * get there, send to all interfaces.
4318 */
0a7de745 4319 if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
6d2010ae 4320 dst_if = NULL;
0a7de745 4321 } else {
6d2010ae 4322 dst_if = bridge_rtlookup(sc, eh->ether_dhost, vlan);
0a7de745 4323 }
6d2010ae
A
4324 if (dst_if == NULL) {
4325 struct bridge_iflist *bif;
4326 struct mbuf *mc;
cb323159
A
4327 int used = 0;
4328 errno_t error;
4329
6d2010ae
A
4330
4331 bridge_span(sc, m);
4332
4333 BRIDGE_LOCK2REF(sc, error);
cb323159 4334 if (error != 0) {
6d2010ae 4335 m_freem(m);
ea3f0419 4336 return EJUSTRETURN;
6d2010ae
A
4337 }
4338
4339 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
cb323159
A
4340 /* skip interface with inactive link status */
4341 if ((bif->bif_flags & BIFF_MEDIA_ACTIVE) == 0) {
4342 continue;
4343 }
6d2010ae
A
4344 dst_if = bif->bif_ifp;
4345
0a7de745 4346 if (dst_if->if_type == IFT_GIF) {
6d2010ae 4347 continue;
0a7de745
A
4348 }
4349 if ((dst_if->if_flags & IFF_RUNNING) == 0) {
6d2010ae 4350 continue;
0a7de745 4351 }
ea3f0419
A
4352 if (dst_if != ifp) {
4353 /*
4354 * If this is not the original output interface,
4355 * and the interface is participating in spanning
4356 * tree, make sure the port is in a state that
4357 * allows forwarding.
4358 */
4359 if ((bif->bif_ifflags & IFBIF_STP) &&
4360 bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
4361 continue;
4362 }
4363 /*
4364 * If this is not the original output interface,
4365 * and the destination is the MAC NAT interface,
4366 * drop the packet. The packet can't be sent
4367 * if the source MAC is incorrect.
4368 */
4369 if (dst_if == mac_nat_ifp) {
4370 continue;
4371 }
0a7de745 4372 }
cb323159 4373 if (TAILQ_NEXT(bif, bif_next) == NULL) {
6d2010ae
A
4374 used = 1;
4375 mc = m;
4376 } else {
cb323159 4377 mc = m_dup(m, M_DONTWAIT);
6d2010ae 4378 if (mc == NULL) {
316670eb 4379 (void) ifnet_stat_increment_out(
ea3f0419 4380 bridge_ifp, 0, 0, 1);
6d2010ae
A
4381 continue;
4382 }
4383 }
ea3f0419
A
4384 (void) bridge_enqueue(bridge_ifp, ifp, dst_if,
4385 mc, kChecksumOperationCompute);
6d2010ae 4386 }
0a7de745 4387 if (used == 0) {
6d2010ae 4388 m_freem(m);
0a7de745 4389 }
6d2010ae 4390 BRIDGE_UNREF(sc);
cb323159 4391 return EJUSTRETURN;
6d2010ae
A
4392 }
4393
4394sendunicast:
4395 /*
4396 * XXX Spanning tree consideration here?
4397 */
4398
4399 bridge_span(sc, m);
4400 if ((dst_if->if_flags & IFF_RUNNING) == 0) {
4401 m_freem(m);
4402 BRIDGE_UNLOCK(sc);
cb323159 4403 return EJUSTRETURN;
6d2010ae
A
4404 }
4405
4406 BRIDGE_UNLOCK(sc);
cb323159
A
4407 if (dst_if == ifp) {
4408 /* just let the packet continue on its way */
4409 return 0;
4410 }
ea3f0419
A
4411 if (dst_if != mac_nat_ifp) {
4412 (void) bridge_enqueue(bridge_ifp, ifp, dst_if, m,
4413 kChecksumOperationCompute);
4414 } else {
4415 /*
4416 * This is not the original output interface
4417 * and the destination is the MAC NAT interface.
4418 * Drop the packet because the packet can't be sent
4419 * if the source MAC is incorrect.
4420 */
4421 m_freem(m);
4422 }
cb323159 4423 return EJUSTRETURN;
6d2010ae 4424}
6d2010ae 4425
6d2010ae 4426/*
316670eb 4427 * Output callback.
6d2010ae 4428 *
316670eb
A
4429 * This routine is called externally from above only when if_bridge_txstart
4430 * is disabled; otherwise it is called internally by bridge_start().
6d2010ae 4431 */
316670eb
A
4432static int
4433bridge_output(struct ifnet *ifp, struct mbuf *m)
6d2010ae
A
4434{
4435 struct bridge_softc *sc = ifnet_softc(ifp);
4436 struct ether_header *eh;
ea3f0419 4437 struct ifnet *dst_if = NULL;
316670eb 4438 int error = 0;
6d2010ae
A
4439
4440 eh = mtod(m, struct ether_header *);
316670eb 4441
6d2010ae 4442 BRIDGE_LOCK(sc);
5ba3f43e 4443
0a7de745 4444 if (!(m->m_flags & (M_BCAST | M_MCAST))) {
316670eb 4445 dst_if = bridge_rtlookup(sc, eh->ether_dhost, 0);
0a7de745 4446 }
316670eb 4447
39236c6e 4448 (void) ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0);
316670eb
A
4449
4450#if NBPFILTER > 0
0a7de745 4451 if (sc->sc_bpf_output) {
316670eb 4452 bridge_bpf_output(ifp, m);
0a7de745 4453 }
6d2010ae 4454#endif
316670eb
A
4455
4456 if (dst_if == NULL) {
4457 /* callee will unlock */
cb323159 4458 bridge_broadcast(sc, NULL, m, 0);
316670eb 4459 } else {
ea3f0419
A
4460 ifnet_t bridge_ifp;
4461
4462 bridge_ifp = sc->sc_ifp;
316670eb 4463 BRIDGE_UNLOCK(sc);
ea3f0419 4464 error = bridge_enqueue(bridge_ifp, NULL, dst_if, m,
cb323159 4465 kChecksumOperationFinalize);
6d2010ae 4466 }
6d2010ae 4467
0a7de745 4468 return error;
316670eb
A
4469}
4470
39236c6e
A
4471static void
4472bridge_finalize_cksum(struct ifnet *ifp, struct mbuf *m)
4473{
4474 struct ether_header *eh = mtod(m, struct ether_header *);
4475 uint32_t sw_csum, hwcap;
4476
cb323159 4477
0a7de745 4478 if (ifp != NULL) {
39236c6e 4479 hwcap = (ifp->if_hwassist | CSUM_DATA_VALID);
0a7de745 4480 } else {
39236c6e 4481 hwcap = 0;
0a7de745 4482 }
39236c6e
A
4483
4484 /* do in software what the hardware cannot */
4485 sw_csum = m->m_pkthdr.csum_flags & ~IF_HWASSIST_CSUM_FLAGS(hwcap);
4486 sw_csum &= IF_HWASSIST_CSUM_MASK;
4487
4488 switch (ntohs(eh->ether_type)) {
4489 case ETHERTYPE_IP:
4490 if ((hwcap & CSUM_PARTIAL) && !(sw_csum & CSUM_DELAY_DATA) &&
4491 (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA)) {
4492 if (m->m_pkthdr.csum_flags & CSUM_TCP) {
4493 uint16_t start =
0a7de745 4494 sizeof(*eh) + sizeof(struct ip);
39236c6e
A
4495 uint16_t ulpoff =
4496 m->m_pkthdr.csum_data & 0xffff;
4497 m->m_pkthdr.csum_flags |=
4498 (CSUM_DATA_VALID | CSUM_PARTIAL);
4499 m->m_pkthdr.csum_tx_stuff = (ulpoff + start);
4500 m->m_pkthdr.csum_tx_start = start;
4501 } else {
4502 sw_csum |= (CSUM_DELAY_DATA &
4503 m->m_pkthdr.csum_flags);
4504 }
4505 }
0a7de745 4506 (void) in_finalize_cksum(m, sizeof(*eh), sw_csum);
39236c6e
A
4507 break;
4508
4509#if INET6
4510 case ETHERTYPE_IPV6:
4511 if ((hwcap & CSUM_PARTIAL) &&
4512 !(sw_csum & CSUM_DELAY_IPV6_DATA) &&
4513 (m->m_pkthdr.csum_flags & CSUM_DELAY_IPV6_DATA)) {
4514 if (m->m_pkthdr.csum_flags & CSUM_TCPIPV6) {
4515 uint16_t start =
0a7de745 4516 sizeof(*eh) + sizeof(struct ip6_hdr);
39236c6e
A
4517 uint16_t ulpoff =
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;
4523 } else {
4524 sw_csum |= (CSUM_DELAY_IPV6_DATA &
4525 m->m_pkthdr.csum_flags);
4526 }
4527 }
0a7de745 4528 (void) in6_finalize_cksum(m, sizeof(*eh), -1, -1, sw_csum);
39236c6e
A
4529 break;
4530#endif /* INET6 */
4531 }
4532}
4533
316670eb
A
4534/*
4535 * bridge_start:
4536 *
4537 * Start output on a bridge.
4538 *
4539 * This routine is invoked by the start worker thread; because we never call
4540 * it directly, there is no need do deploy any serialization mechanism other
4541 * than what's already used by the worker thread, i.e. this is already single
4542 * threaded.
4543 *
4544 * This routine is called only when if_bridge_txstart is enabled.
4545 */
4546static void
4547bridge_start(struct ifnet *ifp)
4548{
4549 struct mbuf *m;
4550
4551 for (;;) {
0a7de745 4552 if (ifnet_dequeue(ifp, &m) != 0) {
316670eb 4553 break;
0a7de745 4554 }
316670eb
A
4555
4556 (void) bridge_output(ifp, m);
4557 }
6d2010ae
A
4558}
4559
4560/*
4561 * bridge_forward:
4562 *
4563 * The forwarding function of the bridge.
4564 *
4565 * NOTE: Releases the lock on return.
4566 */
4567static void
4568bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif,
0a7de745 4569 struct mbuf *m)
6d2010ae
A
4570{
4571 struct bridge_iflist *dbif;
ea3f0419
A
4572 ifnet_t bridge_ifp;
4573 struct ifnet *src_if, *dst_if;
6d2010ae
A
4574 struct ether_header *eh;
4575 uint16_t vlan;
4576 uint8_t *dst;
4577 int error;
ea3f0419
A
4578 struct mac_nat_record mnr;
4579 boolean_t translate_mac = FALSE;
4580 uint32_t sc_filter_flags = 0;
6d2010ae 4581
39236c6e 4582 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae 4583
ea3f0419 4584 bridge_ifp = sc->sc_ifp;
6d2010ae 4585#if BRIDGE_DEBUG
ea3f0419
A
4586 if (IF_BRIDGE_DEBUG(BR_DBGF_OUTPUT)) {
4587 printf("%s: %s m 0x%llx\n", __func__, bridge_ifp->if_xname,
39236c6e 4588 (uint64_t)VM_KERNEL_ADDRPERM(m));
0a7de745 4589 }
6d2010ae 4590#endif /* BRIDGE_DEBUG */
316670eb 4591
6d2010ae 4592 src_if = m->m_pkthdr.rcvif;
6d2010ae 4593
ea3f0419 4594 (void) ifnet_stat_increment_in(bridge_ifp, 1, m->m_pkthdr.len, 0);
6d2010ae
A
4595 vlan = VLANTAGOF(m);
4596
4597
39236c6e 4598 if ((sbif->bif_ifflags & IFBIF_STP) &&
0a7de745 4599 sbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
6d2010ae 4600 goto drop;
0a7de745 4601 }
6d2010ae
A
4602
4603 eh = mtod(m, struct ether_header *);
4604 dst = eh->ether_dhost;
4605
4606 /* If the interface is learning, record the address. */
39236c6e 4607 if (sbif->bif_ifflags & IFBIF_LEARNING) {
6d2010ae
A
4608 error = bridge_rtupdate(sc, eh->ether_shost, vlan,
4609 sbif, 0, IFBAF_DYNAMIC);
4610 /*
4611 * If the interface has addresses limits then deny any source
4612 * that is not in the cache.
4613 */
0a7de745 4614 if (error && sbif->bif_addrmax) {
6d2010ae 4615 goto drop;
0a7de745 4616 }
6d2010ae
A
4617 }
4618
39236c6e 4619 if ((sbif->bif_ifflags & IFBIF_STP) != 0 &&
0a7de745 4620 sbif->bif_stp.bp_state == BSTP_IFSTATE_LEARNING) {
6d2010ae 4621 goto drop;
0a7de745 4622 }
6d2010ae
A
4623
4624 /*
4625 * At this point, the port either doesn't participate
4626 * in spanning tree or it is in the forwarding state.
4627 */
4628
4629 /*
4630 * If the packet is unicast, destined for someone on
4631 * "this" side of the bridge, drop it.
4632 */
0a7de745 4633 if ((m->m_flags & (M_BCAST | M_MCAST)) == 0) {
cb323159 4634 /* unicast */
6d2010ae 4635 dst_if = bridge_rtlookup(sc, dst, vlan);
0a7de745 4636 if (src_if == dst_if) {
6d2010ae 4637 goto drop;
0a7de745 4638 }
6d2010ae 4639 } else {
cb323159
A
4640 /* broadcast/multicast */
4641
6d2010ae
A
4642 /*
4643 * Check if its a reserved multicast address, any address
4644 * listed in 802.1D section 7.12.6 may not be forwarded by the
4645 * bridge.
4646 * This is currently 01-80-C2-00-00-00 to 01-80-C2-00-00-0F
4647 */
4648 if (dst[0] == 0x01 && dst[1] == 0x80 &&
4649 dst[2] == 0xc2 && dst[3] == 0x00 &&
0a7de745 4650 dst[4] == 0x00 && dst[5] <= 0x0f) {
6d2010ae 4651 goto drop;
0a7de745 4652 }
6d2010ae
A
4653
4654
4655 /* ...forward it to all interfaces. */
ea3f0419 4656 atomic_add_64(&bridge_ifp->if_imcasts, 1);
6d2010ae
A
4657 dst_if = NULL;
4658 }
4659
4660 /*
4661 * If we have a destination interface which is a member of our bridge,
4662 * OR this is a unicast packet, push it through the bpf(4) machinery.
4663 * For broadcast or multicast packets, don't bother because it will
4664 * be reinjected into ether_input. We do this before we pass the packets
4665 * through the pfil(9) framework, as it is possible that pfil(9) will
4666 * drop the packet, or possibly modify it, making it difficult to debug
4667 * firewall issues on the bridge.
4668 */
4669#if NBPFILTER > 0
4670 if (eh->ether_type == htons(ETHERTYPE_RSN_PREAUTH) ||
316670eb 4671 dst_if != NULL || (m->m_flags & (M_BCAST | M_MCAST)) == 0) {
ea3f0419
A
4672 m->m_pkthdr.rcvif = bridge_ifp;
4673 BRIDGE_BPF_MTAP_INPUT(sc, m);
6d2010ae
A
4674 }
4675#endif /* NBPFILTER */
4676
4677#if defined(PFIL_HOOKS)
4678 /* run the packet filter */
39236c6e 4679 if (PFIL_HOOKED(&inet_pfil_hook) || PFIL_HOOKED_INET6) {
6d2010ae 4680 BRIDGE_UNLOCK(sc);
ea3f0419 4681 if (bridge_pfil(&m, bridge_ifp, src_if, PFIL_IN) != 0) {
6d2010ae 4682 return;
0a7de745
A
4683 }
4684 if (m == NULL) {
6d2010ae 4685 return;
0a7de745 4686 }
6d2010ae
A
4687 BRIDGE_LOCK(sc);
4688 }
4689#endif /* PFIL_HOOKS */
4690
4691 if (dst_if == NULL) {
ea3f0419 4692 /* bridge_broadcast will unlock */
6d2010ae 4693 bridge_broadcast(sc, src_if, m, 1);
6d2010ae
A
4694 return;
4695 }
4696
cb323159
A
4697 /*
4698 * Unicast.
4699 */
6d2010ae
A
4700 /*
4701 * At this point, we're dealing with a unicast frame
4702 * going to a different interface.
4703 */
0a7de745 4704 if ((dst_if->if_flags & IFF_RUNNING) == 0) {
6d2010ae 4705 goto drop;
0a7de745 4706 }
6d2010ae
A
4707
4708 dbif = bridge_lookup_member_if(sc, dst_if);
0a7de745 4709 if (dbif == NULL) {
6d2010ae
A
4710 /* Not a member of the bridge (anymore?) */
4711 goto drop;
0a7de745 4712 }
6d2010ae
A
4713
4714 /* Private segments can not talk to each other */
0a7de745 4715 if (sbif->bif_ifflags & dbif->bif_ifflags & IFBIF_PRIVATE) {
6d2010ae 4716 goto drop;
0a7de745 4717 }
6d2010ae 4718
39236c6e 4719 if ((dbif->bif_ifflags & IFBIF_STP) &&
0a7de745 4720 dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
6d2010ae 4721 goto drop;
0a7de745 4722 }
6d2010ae
A
4723
4724#if HAS_DHCPRA_MASK
39236c6e 4725 /* APPLE MODIFICATION <rdar:6985737> */
6d2010ae
A
4726 if ((dst_if->if_extflags & IFEXTF_DHCPRA_MASK) != 0) {
4727 m = ip_xdhcpra_output(dst_if, m);
4728 if (!m) {
ea3f0419
A
4729 ++bridge_ifp.if_xdhcpra;
4730 BRIDGE_UNLOCK(sc);
6d2010ae
A
4731 return;
4732 }
4733 }
4734#endif /* HAS_DHCPRA_MASK */
4735
ea3f0419
A
4736 if (dbif == sc->sc_mac_nat_bif) {
4737 /* determine how to translate the packet */
4738 translate_mac
4739 = bridge_mac_nat_output(sc, sbif, &m, &mnr);
4740 if (m == NULL) {
4741 /* packet was deallocated */
4742 BRIDGE_UNLOCK(sc);
4743 return;
4744 }
4745 }
6d2010ae
A
4746
4747#if defined(PFIL_HOOKS)
39236c6e 4748 if (PFIL_HOOKED(&inet_pfil_hook) || PFIL_HOOKED_INET6) {
ea3f0419 4749 if (bridge_pfil(&m, bridge_ifp, dst_if, PFIL_OUT) != 0) {
6d2010ae 4750 return;
0a7de745
A
4751 }
4752 if (m == NULL) {
6d2010ae 4753 return;
0a7de745 4754 }
6d2010ae
A
4755 }
4756#endif /* PFIL_HOOKS */
4757
ea3f0419
A
4758 sc_filter_flags = sc->sc_filter_flags;
4759 BRIDGE_UNLOCK(sc);
4760 if (PF_IS_ENABLED && (sc_filter_flags & IFBF_FILT_MEMBER)) {
4761 if (bridge_pf(&m, dst_if, sc_filter_flags, FALSE) != 0) {
4762 return;
4763 }
4764 if (m == NULL) {
4765 return;
4766 }
4767 }
4768
4769 /* if we need to, translate the MAC address */
4770 if (translate_mac) {
4771 bridge_mac_nat_translate(&m, &mnr, IF_LLADDR(dst_if));
4772 }
cb323159
A
4773 /*
4774 * This is an inbound packet where the checksum
4775 * (if applicable) is already present/valid. Since
4776 * we are just doing layer 2 forwarding (not IP
4777 * forwarding), there's no need to validate the checksum.
4778 * Clear the checksum offload flags and send it along.
4779 */
ea3f0419
A
4780 if (m != NULL) {
4781 (void) bridge_enqueue(bridge_ifp, NULL, dst_if, m,
4782 kChecksumOperationClear);
4783 }
6d2010ae
A
4784 return;
4785
4786drop:
4787 BRIDGE_UNLOCK(sc);
4788 m_freem(m);
4789}
4790
4791#if BRIDGE_DEBUG
4792
ea3f0419 4793static char *
6d2010ae
A
4794ether_ntop(char *buf, size_t len, const u_char *ap)
4795{
316670eb
A
4796 snprintf(buf, len, "%02x:%02x:%02x:%02x:%02x:%02x",
4797 ap[0], ap[1], ap[2], ap[3], ap[4], ap[5]);
4798
0a7de745 4799 return buf;
6d2010ae
A
4800}
4801
4802#endif /* BRIDGE_DEBUG */
4803
ea3f0419
A
4804static void
4805inject_input_packet(ifnet_t ifp, mbuf_t m)
4806{
4807 mbuf_pkthdr_setrcvif(m, ifp);
4808 mbuf_pkthdr_setheader(m, mbuf_data(m));
4809 mbuf_setdata(m, (char *)mbuf_data(m) + ETHER_HDR_LEN,
4810 mbuf_len(m) - ETHER_HDR_LEN);
4811 mbuf_pkthdr_adjustlen(m, -ETHER_HDR_LEN);
4812 m->m_flags |= M_PROTO1; /* set to avoid loops */
4813 dlil_input_packet_list(ifp, m);
4814 return;
4815}
4816
6d2010ae
A
4817/*
4818 * bridge_input:
4819 *
4820 * Filter input from a member interface. Queue the packet for
4821 * bridging if it is not for us.
4822 */
ea3f0419
A
4823errno_t
4824bridge_input(struct ifnet *ifp, mbuf_t *data)
6d2010ae
A
4825{
4826 struct bridge_softc *sc = ifp->if_bridge;
4827 struct bridge_iflist *bif, *bif2;
ea3f0419 4828 ifnet_t bridge_ifp;
6d2010ae
A
4829 struct ether_header *eh;
4830 struct mbuf *mc, *mc2;
4831 uint16_t vlan;
ea3f0419
A
4832 errno_t error;
4833 boolean_t is_ifp_mac = FALSE;
4834 mbuf_t m = *data;
4835 uint32_t sc_filter_flags = 0;
6d2010ae 4836
ea3f0419 4837 bridge_ifp = sc->sc_ifp;
6d2010ae 4838#if BRIDGE_DEBUG
ea3f0419 4839 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT)) {
39236c6e 4840 printf("%s: %s from %s m 0x%llx data 0x%llx\n", __func__,
ea3f0419 4841 bridge_ifp->if_xname, ifp->if_xname,
39236c6e
A
4842 (uint64_t)VM_KERNEL_ADDRPERM(m),
4843 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_data(m)));
0a7de745 4844 }
6d2010ae
A
4845#endif /* BRIDGE_DEBUG */
4846
4847 if ((sc->sc_ifp->if_flags & IFF_RUNNING) == 0) {
4848#if BRIDGE_DEBUG
ea3f0419 4849 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT)) {
39236c6e 4850 printf("%s: %s not running passing along\n",
ea3f0419 4851 __func__, bridge_ifp->if_xname);
0a7de745 4852 }
6d2010ae 4853#endif /* BRIDGE_DEBUG */
0a7de745 4854 return 0;
6d2010ae 4855 }
316670eb 4856
6d2010ae
A
4857 vlan = VLANTAGOF(m);
4858
4859#ifdef IFF_MONITOR
4860 /*
4861 * Implement support for bridge monitoring. If this flag has been
4862 * set on this interface, discard the packet once we push it through
4863 * the bpf(4) machinery, but before we do, increment the byte and
4864 * packet counters associated with this interface.
4865 */
ea3f0419
A
4866 if ((bridge_ifp->if_flags & IFF_MONITOR) != 0) {
4867 m->m_pkthdr.rcvif = bridge_ifp;
6d2010ae 4868 BRIDGE_BPF_MTAP_INPUT(sc, m);
ea3f0419 4869 (void) ifnet_stat_increment_in(bridge_ifp, 1, m->m_pkthdr.len, 0);
6d2010ae 4870 m_freem(m);
0a7de745 4871 return EJUSTRETURN;
6d2010ae
A
4872 }
4873#endif /* IFF_MONITOR */
4874
316670eb
A
4875 /*
4876 * Need to clear the promiscous flags otherwise it will be
4877 * dropped by DLIL after processing filters
6d2010ae 4878 */
0a7de745 4879 if ((mbuf_flags(m) & MBUF_PROMISC)) {
6d2010ae 4880 mbuf_setflags_mask(m, 0, MBUF_PROMISC);
0a7de745 4881 }
316670eb 4882
ea3f0419
A
4883 sc_filter_flags = sc->sc_filter_flags;
4884 if (PF_IS_ENABLED && (sc_filter_flags & IFBF_FILT_MEMBER)) {
4885 error = bridge_pf(&m, ifp, sc_filter_flags, TRUE);
4886 if (error != 0) {
4887 return EJUSTRETURN;
4888 }
4889 if (m == NULL) {
4890 return EJUSTRETURN;
4891 }
4892 /*
4893 * bridge_pf could have modified the pointer on success in order
4894 * to do its processing. Updated data such that we don't use a
4895 * stale pointer.
4896 */
4897 *data = m;
4898 }
4899
6d2010ae
A
4900 BRIDGE_LOCK(sc);
4901 bif = bridge_lookup_member_if(sc, ifp);
4902 if (bif == NULL) {
4903 BRIDGE_UNLOCK(sc);
4904#if BRIDGE_DEBUG
ea3f0419 4905 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT)) {
39236c6e 4906 printf("%s: %s bridge_lookup_member_if failed\n",
ea3f0419 4907 __func__, bridge_ifp->if_xname);
0a7de745 4908 }
6d2010ae 4909#endif /* BRIDGE_DEBUG */
0a7de745 4910 return 0;
6d2010ae
A
4911 }
4912
fe8ab488 4913 if (bif->bif_flags & BIFF_HOST_FILTER) {
ea3f0419 4914 error = bridge_host_filter(bif, data);
fe8ab488 4915 if (error != 0) {
ea3f0419 4916 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT)) {
fe8ab488
A
4917 printf("%s: %s bridge_host_filter failed\n",
4918 __func__, bif->bif_ifp->if_xname);
0a7de745 4919 }
fe8ab488 4920 BRIDGE_UNLOCK(sc);
0a7de745 4921 return EJUSTRETURN;
fe8ab488 4922 }
ea3f0419 4923 m = *data;
fe8ab488
A
4924 }
4925
6d2010ae
A
4926 eh = mtod(m, struct ether_header *);
4927
4928 bridge_span(sc, m);
4929
0a7de745 4930 if (m->m_flags & (M_BCAST | M_MCAST)) {
6d2010ae 4931#if BRIDGE_DEBUG
ea3f0419 4932 if (IF_BRIDGE_DEBUG(BR_DBGF_MCAST)) {
0a7de745 4933 if ((m->m_flags & M_MCAST)) {
39236c6e 4934 printf("%s: multicast: "
316670eb
A
4935 "%02x:%02x:%02x:%02x:%02x:%02x\n",
4936 __func__,
4937 eh->ether_dhost[0], eh->ether_dhost[1],
4938 eh->ether_dhost[2], eh->ether_dhost[3],
4939 eh->ether_dhost[4], eh->ether_dhost[5]);
0a7de745
A
4940 }
4941 }
6d2010ae
A
4942#endif /* BRIDGE_DEBUG */
4943
4944 /* Tap off 802.1D packets; they do not get forwarded. */
4945 if (memcmp(eh->ether_dhost, bstp_etheraddr,
4946 ETHER_ADDR_LEN) == 0) {
316670eb 4947#if BRIDGESTP
6d2010ae 4948 m = bstp_input(&bif->bif_stp, ifp, m);
316670eb
A
4949#else /* !BRIDGESTP */
4950 m_freem(m);
4951 m = NULL;
4952#endif /* !BRIDGESTP */
6d2010ae
A
4953 if (m == NULL) {
4954 BRIDGE_UNLOCK(sc);
0a7de745 4955 return EJUSTRETURN;
6d2010ae
A
4956 }
4957 }
4958
39236c6e 4959 if ((bif->bif_ifflags & IFBIF_STP) &&
6d2010ae
A
4960 bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
4961 BRIDGE_UNLOCK(sc);
0a7de745 4962 return 0;
6d2010ae
A
4963 }
4964
4965 /*
4966 * Make a deep copy of the packet and enqueue the copy
4967 * for bridge processing; return the original packet for
4968 * local processing.
4969 */
4970 mc = m_dup(m, M_DONTWAIT);
4971 if (mc == NULL) {
4972 BRIDGE_UNLOCK(sc);
0a7de745 4973 return 0;
6d2010ae
A
4974 }
4975
316670eb
A
4976 /*
4977 * Perform the bridge forwarding function with the copy.
6d2010ae
A
4978 *
4979 * Note that bridge_forward calls BRIDGE_UNLOCK
4980 */
4981 bridge_forward(sc, bif, mc);
316670eb 4982
6d2010ae
A
4983 /*
4984 * Reinject the mbuf as arriving on the bridge so we have a
4985 * chance at claiming multicast packets. We can not loop back
4986 * here from ether_input as a bridge is never a member of a
4987 * bridge.
4988 */
ea3f0419 4989 VERIFY(bridge_ifp->if_bridge == NULL);
6d2010ae
A
4990 mc2 = m_dup(m, M_DONTWAIT);
4991 if (mc2 != NULL) {
4992 /* Keep the layer3 header aligned */
4993 int i = min(mc2->m_pkthdr.len, max_protohdr);
4994 mc2 = m_copyup(mc2, i, ETHER_ALIGN);
4995 }
4996 if (mc2 != NULL) {
39236c6e 4997 /* mark packet as arriving on the bridge */
ea3f0419 4998 mc2->m_pkthdr.rcvif = bridge_ifp;
39236c6e 4999 mc2->m_pkthdr.pkt_hdr = mbuf_data(mc2);
316670eb 5000
ea3f0419
A
5001 BRIDGE_BPF_MTAP_INPUT(sc, m);
5002
316670eb
A
5003 (void) mbuf_setdata(mc2,
5004 (char *)mbuf_data(mc2) + ETHER_HDR_LEN,
5005 mbuf_len(mc2) - ETHER_HDR_LEN);
0a7de745 5006 (void) mbuf_pkthdr_adjustlen(mc2, -ETHER_HDR_LEN);
316670eb 5007
ea3f0419 5008 (void) ifnet_stat_increment_in(bridge_ifp, 1,
316670eb
A
5009 mbuf_pkthdr_len(mc2), 0);
5010
6d2010ae 5011#if BRIDGE_DEBUG
ea3f0419 5012 if (IF_BRIDGE_DEBUG(BR_DBGF_MCAST)) {
39236c6e 5013 printf("%s: %s mcast for us\n", __func__,
ea3f0419 5014 bridge_ifp->if_xname);
0a7de745 5015 }
6d2010ae 5016#endif /* BRIDGE_DEBUG */
316670eb 5017
ea3f0419 5018 dlil_input_packet_list(bridge_ifp, mc2);
6d2010ae
A
5019 }
5020
5021 /* Return the original packet for local processing. */
0a7de745 5022 return 0;
6d2010ae
A
5023 }
5024
39236c6e 5025 if ((bif->bif_ifflags & IFBIF_STP) &&
6d2010ae
A
5026 bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
5027 BRIDGE_UNLOCK(sc);
0a7de745 5028 return 0;
6d2010ae
A
5029 }
5030
5031#ifdef DEV_CARP
0a7de745 5032#define CARP_CHECK_WE_ARE_DST(iface) \
39236c6e 5033 ((iface)->if_carp &&\
0a7de745
A
5034 carp_forus((iface)->if_carp, eh->ether_dhost))
5035#define CARP_CHECK_WE_ARE_SRC(iface) \
39236c6e 5036 ((iface)->if_carp &&\
0a7de745 5037 carp_forus((iface)->if_carp, eh->ether_shost))
6d2010ae 5038#else
0a7de745
A
5039#define CARP_CHECK_WE_ARE_DST(iface) 0
5040#define CARP_CHECK_WE_ARE_SRC(iface) 0
6d2010ae
A
5041#endif
5042
5043#ifdef INET6
0a7de745 5044#define PFIL_HOOKED_INET6 PFIL_HOOKED(&inet6_pfil_hook)
6d2010ae 5045#else
0a7de745 5046#define PFIL_HOOKED_INET6 0
6d2010ae
A
5047#endif
5048
5049#if defined(PFIL_HOOKS)
0a7de745
A
5050#define PFIL_PHYS(sc, ifp, m) do { \
5051 if (pfil_local_phys && \
5052 (PFIL_HOOKED(&inet_pfil_hook) || PFIL_HOOKED_INET6)) { \
5053 if (bridge_pfil(&m, NULL, ifp, \
5054 PFIL_IN) != 0 || m == NULL) { \
5055 BRIDGE_UNLOCK(sc); \
5056 return (NULL); \
5057 } \
5058 } \
316670eb 5059} while (0)
6d2010ae 5060#else /* PFIL_HOOKS */
0a7de745 5061#define PFIL_PHYS(sc, ifp, m)
6d2010ae
A
5062#endif /* PFIL_HOOKS */
5063
0a7de745
A
5064#define GRAB_OUR_PACKETS(iface) \
5065 if ((iface)->if_type == IFT_GIF) \
5066 continue; \
5067 /* It is destined for us. */ \
cb323159 5068 if (memcmp(IF_LLADDR((iface)), eh->ether_dhost, \
0a7de745
A
5069 ETHER_ADDR_LEN) == 0 || CARP_CHECK_WE_ARE_DST((iface))) { \
5070 if ((iface)->if_type == IFT_BRIDGE) { \
5071 BRIDGE_BPF_MTAP_INPUT(sc, m); \
5072 /* Filter on the physical interface. */ \
5073 PFIL_PHYS(sc, iface, m); \
cb323159
A
5074 } else { \
5075 bpf_tap_in(iface, DLT_EN10MB, m, NULL, 0); \
0a7de745
A
5076 } \
5077 if (bif->bif_ifflags & IFBIF_LEARNING) { \
5078 error = bridge_rtupdate(sc, eh->ether_shost, \
5079 vlan, bif, 0, IFBAF_DYNAMIC); \
5080 if (error && bif->bif_addrmax) { \
5081 BRIDGE_UNLOCK(sc); \
cb323159 5082 m_freem(m); \
0a7de745
A
5083 return (EJUSTRETURN); \
5084 } \
5085 } \
0a7de745 5086 BRIDGE_UNLOCK(sc); \
ea3f0419 5087 inject_input_packet(iface, m); \
cb323159 5088 return (EJUSTRETURN); \
0a7de745
A
5089 } \
5090 \
5091 /* We just received a packet that we sent out. */ \
cb323159 5092 if (memcmp(IF_LLADDR((iface)), eh->ether_shost, \
0a7de745
A
5093 ETHER_ADDR_LEN) == 0 || CARP_CHECK_WE_ARE_SRC((iface))) { \
5094 BRIDGE_UNLOCK(sc); \
cb323159 5095 m_freem(m); \
0a7de745 5096 return (EJUSTRETURN); \
6d2010ae
A
5097 }
5098
5099 /*
5100 * Unicast.
5101 */
ea3f0419
A
5102 if (memcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0) {
5103 is_ifp_mac = TRUE;
5104 }
5105
5106 /* handle MAC-NAT if enabled */
5107 if (is_ifp_mac && sc->sc_mac_nat_bif == bif) {
5108 ifnet_t dst_if;
5109 boolean_t is_input = FALSE;
5110
5111 dst_if = bridge_mac_nat_input(sc, data, &is_input);
5112 m = *data;
5113 if (dst_if == ifp) {
5114 /* our input packet */
5115 } else if (dst_if != NULL || m == NULL) {
5116 BRIDGE_UNLOCK(sc);
5117 if (dst_if != NULL) {
5118 ASSERT(m != NULL);
5119 if (is_input) {
5120 inject_input_packet(dst_if, m);
5121 } else {
5122 (void)bridge_enqueue(bridge_ifp, NULL,
5123 dst_if, m,
5124 kChecksumOperationClear);
5125 }
5126 }
5127 return EJUSTRETURN;
5128 }
5129 }
5130
6d2010ae 5131 /*
ea3f0419
A
5132 * If the packet is for the bridge, set the packet's source interface
5133 * and return the packet back to ether_input for local processing.
6d2010ae 5134 */
ea3f0419
A
5135 if (memcmp(eh->ether_dhost, IF_LLADDR(bridge_ifp),
5136 ETHER_ADDR_LEN) == 0 || CARP_CHECK_WE_ARE_DST(bridge_ifp)) {
6d2010ae 5137 /* Mark the packet as arriving on the bridge interface */
ea3f0419
A
5138 (void) mbuf_pkthdr_setrcvif(m, bridge_ifp);
5139 mbuf_pkthdr_setheader(m, mbuf_data(m));
316670eb 5140
6d2010ae
A
5141 /*
5142 * If the interface is learning, and the source
5143 * address is valid and not multicast, record
5144 * the address.
5145 */
0a7de745 5146 if (bif->bif_ifflags & IFBIF_LEARNING) {
316670eb
A
5147 (void) bridge_rtupdate(sc, eh->ether_shost,
5148 vlan, bif, 0, IFBAF_DYNAMIC);
0a7de745 5149 }
316670eb 5150
6d2010ae
A
5151 BRIDGE_BPF_MTAP_INPUT(sc, m);
5152
316670eb
A
5153 (void) mbuf_setdata(m, (char *)mbuf_data(m) + ETHER_HDR_LEN,
5154 mbuf_len(m) - ETHER_HDR_LEN);
0a7de745 5155 (void) mbuf_pkthdr_adjustlen(m, -ETHER_HDR_LEN);
316670eb 5156
ea3f0419 5157 (void) ifnet_stat_increment_in(bridge_ifp, 1, mbuf_pkthdr_len(m), 0);
6d2010ae
A
5158
5159 BRIDGE_UNLOCK(sc);
316670eb 5160
6d2010ae 5161#if BRIDGE_DEBUG
ea3f0419 5162 if (IF_BRIDGE_DEBUG(BR_DBGF_INPUT)) {
39236c6e 5163 printf("%s: %s packet for bridge\n", __func__,
ea3f0419 5164 bridge_ifp->if_xname);
0a7de745 5165 }
6d2010ae 5166#endif /* BRIDGE_DEBUG */
316670eb 5167
ea3f0419 5168 dlil_input_packet_list(bridge_ifp, m);
316670eb 5169
0a7de745 5170 return EJUSTRETURN;
6d2010ae
A
5171 }
5172
5173 /*
316670eb 5174 * if the destination of the packet is for the MAC address of
6d2010ae
A
5175 * the member interface itself, then we don't need to forward
5176 * it -- just pass it back. Note that it'll likely just be
316670eb 5177 * dropped by the stack, but if something else is bound to
6d2010ae 5178 * the interface directly (for example, the wireless stats
316670eb 5179 * protocol -- although that actually uses BPF right now),
6d2010ae
A
5180 * then it will consume the packet
5181 *
316670eb 5182 * ALSO, note that we do this check AFTER checking for the
6d2010ae
A
5183 * bridge's own MAC address, because the bridge may be
5184 * using the SAME MAC address as one of its interfaces
5185 */
ea3f0419 5186 if (is_ifp_mac) {
316670eb 5187
6d2010ae 5188#ifdef VERY_VERY_VERY_DIAGNOSTIC
0a7de745
A
5189 printf("%s: not forwarding packet bound for member "
5190 "interface\n", __func__);
6d2010ae 5191#endif
cb323159 5192
0a7de745
A
5193 BRIDGE_UNLOCK(sc);
5194 return 0;
6d2010ae
A
5195 }
5196
cb323159 5197 /* Now check the remaining bridge members. */
6d2010ae 5198 TAILQ_FOREACH(bif2, &sc->sc_iflist, bif_next) {
cb323159
A
5199 if (bif2->bif_ifp != ifp) {
5200 GRAB_OUR_PACKETS(bif2->bif_ifp);
5201 }
6d2010ae
A
5202 }
5203
39236c6e
A
5204#undef CARP_CHECK_WE_ARE_DST
5205#undef CARP_CHECK_WE_ARE_SRC
6d2010ae
A
5206#undef GRAB_OUR_PACKETS
5207
316670eb
A
5208 /*
5209 * Perform the bridge forwarding function.
6d2010ae
A
5210 *
5211 * Note that bridge_forward calls BRIDGE_UNLOCK
5212 */
5213 bridge_forward(sc, bif, m);
5214
0a7de745 5215 return EJUSTRETURN;
6d2010ae
A
5216}
5217
5218/*
5219 * bridge_broadcast:
5220 *
5221 * Send a frame to all interfaces that are members of
5222 * the bridge, except for the one on which the packet
5223 * arrived.
5224 *
5225 * NOTE: Releases the lock on return.
5226 */
5227static void
5228bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
0a7de745 5229 struct mbuf *m, int runfilt)
6d2010ae 5230{
ea3f0419 5231 ifnet_t bridge_ifp;
6d2010ae
A
5232 struct bridge_iflist *dbif, *sbif;
5233 struct mbuf *mc;
cb323159 5234 struct mbuf *mc_in;
6d2010ae
A
5235 struct ifnet *dst_if;
5236 int error = 0, used = 0;
ea3f0419 5237 boolean_t bridge_if_out;
cb323159 5238 ChecksumOperation cksum_op;
ea3f0419
A
5239 struct mac_nat_record mnr;
5240 struct bridge_iflist *mac_nat_bif = sc->sc_mac_nat_bif;
5241 boolean_t translate_mac = FALSE;
5242 uint32_t sc_filter_flags = 0;
6d2010ae 5243
ea3f0419 5244 bridge_ifp = sc->sc_ifp;
cb323159 5245 if (src_if != NULL) {
ea3f0419 5246 bridge_if_out = FALSE;
cb323159
A
5247 cksum_op = kChecksumOperationClear;
5248 sbif = bridge_lookup_member_if(sc, src_if);
ea3f0419
A
5249 if (sbif != NULL && mac_nat_bif != NULL && sbif != mac_nat_bif) {
5250 /* get the translation record while holding the lock */
5251 translate_mac
5252 = bridge_mac_nat_output(sc, sbif, &m, &mnr);
5253 if (m == NULL) {
5254 /* packet was deallocated */
5255 BRIDGE_UNLOCK(sc);
5256 return;
5257 }
5258 }
cb323159
A
5259 } else {
5260 /*
5261 * src_if is NULL when the bridge interface calls
5262 * bridge_broadcast().
5263 */
ea3f0419 5264 bridge_if_out = TRUE;
cb323159
A
5265 cksum_op = kChecksumOperationFinalize;
5266 sbif = NULL;
5267 }
6d2010ae
A
5268
5269 BRIDGE_LOCK2REF(sc, error);
5270 if (error) {
5271 m_freem(m);
5272 return;
5273 }
5274
5275#ifdef PFIL_HOOKS
5276 /* Filter on the bridge interface before broadcasting */
39236c6e 5277 if (runfilt && (PFIL_HOOKED(&inet_pfil_hook) || PFIL_HOOKED_INET6)) {
ea3f0419 5278 if (bridge_pfil(&m, bridge_ifp, NULL, PFIL_OUT) != 0) {
6d2010ae 5279 goto out;
0a7de745
A
5280 }
5281 if (m == NULL) {
6d2010ae 5282 goto out;
0a7de745 5283 }
6d2010ae
A
5284 }
5285#endif /* PFIL_HOOKS */
6d2010ae
A
5286 TAILQ_FOREACH(dbif, &sc->sc_iflist, bif_next) {
5287 dst_if = dbif->bif_ifp;
0a7de745 5288 if (dst_if == src_if) {
cb323159 5289 /* skip the interface that the packet came in on */
6d2010ae 5290 continue;
0a7de745 5291 }
6d2010ae
A
5292
5293 /* Private segments can not talk to each other */
cb323159 5294 if (sbif != NULL &&
0a7de745 5295 (sbif->bif_ifflags & dbif->bif_ifflags & IFBIF_PRIVATE)) {
6d2010ae 5296 continue;
0a7de745 5297 }
6d2010ae 5298
39236c6e 5299 if ((dbif->bif_ifflags & IFBIF_STP) &&
0a7de745 5300 dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
6d2010ae 5301 continue;
0a7de745 5302 }
6d2010ae 5303
39236c6e 5304 if ((dbif->bif_ifflags & IFBIF_DISCOVER) == 0 &&
0a7de745 5305 (m->m_flags & (M_BCAST | M_MCAST)) == 0) {
6d2010ae 5306 continue;
0a7de745 5307 }
6d2010ae 5308
0a7de745 5309 if ((dst_if->if_flags & IFF_RUNNING) == 0) {
6d2010ae 5310 continue;
0a7de745 5311 }
6d2010ae 5312
fe8ab488
A
5313 if (!(dbif->bif_flags & BIFF_MEDIA_ACTIVE)) {
5314 continue;
5315 }
5316
6d2010ae
A
5317 if (TAILQ_NEXT(dbif, bif_next) == NULL) {
5318 mc = m;
5319 used = 1;
5320 } else {
5321 mc = m_dup(m, M_DONTWAIT);
5322 if (mc == NULL) {
ea3f0419 5323 (void) ifnet_stat_increment_out(bridge_ifp,
316670eb 5324 0, 0, 1);
6d2010ae
A
5325 continue;
5326 }
5327 }
5328
cb323159
A
5329 /*
5330 * If broadcast input is enabled, do so only if this
5331 * is an input packet.
5332 */
ea3f0419 5333 if (!bridge_if_out &&
cb323159
A
5334 (dbif->bif_flags & BIFF_INPUT_BROADCAST) != 0) {
5335 mc_in = m_dup(mc, M_DONTWAIT);
5336 /* this could fail, but we continue anyways */
5337 } else {
5338 mc_in = NULL;
5339 }
5340
6d2010ae
A
5341#ifdef PFIL_HOOKS
5342 /*
5343 * Filter on the output interface. Pass a NULL bridge interface
5344 * pointer so we do not redundantly filter on the bridge for
5345 * each interface we broadcast on.
5346 */
39236c6e
A
5347 if (runfilt &&
5348 (PFIL_HOOKED(&inet_pfil_hook) || PFIL_HOOKED_INET6)) {
6d2010ae
A
5349 if (used == 0) {
5350 /* Keep the layer3 header aligned */
5351 int i = min(mc->m_pkthdr.len, max_protohdr);
5352 mc = m_copyup(mc, i, ETHER_ALIGN);
5353 if (mc == NULL) {
316670eb 5354 (void) ifnet_stat_increment_out(
ea3f0419 5355 bridge_ifp, 0, 0, 1);
cb323159
A
5356 if (mc_in != NULL) {
5357 m_freem(mc_in);
5358 }
6d2010ae
A
5359 continue;
5360 }
5361 }
0a7de745 5362 if (bridge_pfil(&mc, NULL, dst_if, PFIL_OUT) != 0) {
cb323159
A
5363 if (mc_in != NULL) {
5364 m_freem(mc_in);
5365 }
6d2010ae 5366 continue;
0a7de745
A
5367 }
5368 if (mc == NULL) {
cb323159
A
5369 if (mc_in != NULL) {
5370 m_freem(mc_in);
5371 }
6d2010ae 5372 continue;
0a7de745 5373 }
6d2010ae
A
5374 }
5375#endif /* PFIL_HOOKS */
5376
cb323159 5377 /* out */
ea3f0419
A
5378 if (translate_mac && mac_nat_bif == dbif) {
5379 /* translate the packet without holding the lock */
5380 bridge_mac_nat_translate(&mc, &mnr, IF_LLADDR(dst_if));
5381 }
5382
5383 sc_filter_flags = sc->sc_filter_flags;
5384 if (runfilt &&
5385 PF_IS_ENABLED && (sc_filter_flags & IFBF_FILT_MEMBER)) {
5386 if (used == 0) {
5387 /* Keep the layer3 header aligned */
5388 int i = min(mc->m_pkthdr.len, max_protohdr);
5389 mc = m_copyup(mc, i, ETHER_ALIGN);
5390 if (mc == NULL) {
5391 (void) ifnet_stat_increment_out(
5392 sc->sc_ifp, 0, 0, 1);
5393 if (mc_in != NULL) {
5394 m_freem(mc_in);
5395 mc_in = NULL;
5396 }
5397 continue;
5398 }
5399 }
5400 if (bridge_pf(&mc, dst_if, sc_filter_flags, FALSE) != 0) {
5401 if (mc_in != NULL) {
5402 m_freem(mc_in);
5403 mc_in = NULL;
5404 }
5405 continue;
5406 }
5407 if (mc == NULL) {
5408 if (mc_in != NULL) {
5409 m_freem(mc_in);
5410 mc_in = NULL;
5411 }
5412 continue;
5413 }
5414 }
5415
5416 if (mc != NULL) {
5417 (void) bridge_enqueue(bridge_ifp,
5418 NULL, dst_if, mc, cksum_op);
5419 }
cb323159
A
5420
5421 /* in */
5422 if (mc_in == NULL) {
5423 continue;
5424 }
5425 bpf_tap_in(dst_if, DLT_EN10MB, mc_in, NULL, 0);
5426 mbuf_pkthdr_setrcvif(mc_in, dst_if);
5427 mbuf_pkthdr_setheader(mc_in, mbuf_data(mc_in));
5428 mbuf_setdata(mc_in, (char *)mbuf_data(mc_in) + ETHER_HDR_LEN,
5429 mbuf_len(mc_in) - ETHER_HDR_LEN);
5430 mbuf_pkthdr_adjustlen(mc_in, -ETHER_HDR_LEN);
5431 mc_in->m_flags |= M_PROTO1; /* set to avoid loops */
5432 dlil_input_packet_list(dst_if, mc_in);
6d2010ae 5433 }
0a7de745 5434 if (used == 0) {
6d2010ae 5435 m_freem(m);
0a7de745 5436 }
6d2010ae
A
5437
5438#ifdef PFIL_HOOKS
5439out:
5440#endif /* PFIL_HOOKS */
5441
5442 BRIDGE_UNREF(sc);
5443}
5444
5445/*
5446 * bridge_span:
5447 *
5448 * Duplicate a packet out one or more interfaces that are in span mode,
5449 * the original mbuf is unmodified.
5450 */
5451static void
5452bridge_span(struct bridge_softc *sc, struct mbuf *m)
5453{
5454 struct bridge_iflist *bif;
5455 struct ifnet *dst_if;
5456 struct mbuf *mc;
5457
0a7de745 5458 if (TAILQ_EMPTY(&sc->sc_spanlist)) {
6d2010ae 5459 return;
0a7de745 5460 }
6d2010ae
A
5461
5462 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) {
5463 dst_if = bif->bif_ifp;
5464
0a7de745 5465 if ((dst_if->if_flags & IFF_RUNNING) == 0) {
6d2010ae 5466 continue;
0a7de745 5467 }
6d2010ae
A
5468
5469 mc = m_copypacket(m, M_DONTWAIT);
5470 if (mc == NULL) {
5471 (void) ifnet_stat_increment_out(sc->sc_ifp, 0, 0, 1);
5472 continue;
5473 }
5474
ea3f0419 5475 (void) bridge_enqueue(sc->sc_ifp, NULL, dst_if, mc,
cb323159 5476 kChecksumOperationNone);
6d2010ae
A
5477 }
5478}
5479
5480
6d2010ae
A
5481/*
5482 * bridge_rtupdate:
5483 *
5484 * Add a bridge routing entry.
5485 */
5486static int
5487bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan,
0a7de745 5488 struct bridge_iflist *bif, int setflags, uint8_t flags)
6d2010ae
A
5489{
5490 struct bridge_rtnode *brt;
5491 int error;
5492
39236c6e 5493 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
5494
5495 /* Check the source address is valid and not multicast. */
5496 if (ETHER_IS_MULTICAST(dst) ||
5497 (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
0a7de745
A
5498 dst[3] == 0 && dst[4] == 0 && dst[5] == 0) != 0) {
5499 return EINVAL;
5500 }
6d2010ae
A
5501
5502
5503 /* 802.1p frames map to vlan 1 */
0a7de745 5504 if (vlan == 0) {
6d2010ae 5505 vlan = 1;
0a7de745 5506 }
6d2010ae
A
5507
5508 /*
5509 * A route for this destination might already exist. If so,
5510 * update it, otherwise create a new one.
5511 */
5512 if ((brt = bridge_rtnode_lookup(sc, dst, vlan)) == NULL) {
5513 if (sc->sc_brtcnt >= sc->sc_brtmax) {
5514 sc->sc_brtexceeded++;
0a7de745 5515 return ENOSPC;
6d2010ae
A
5516 }
5517 /* Check per interface address limits (if enabled) */
5518 if (bif->bif_addrmax && bif->bif_addrcnt >= bif->bif_addrmax) {
5519 bif->bif_addrexceeded++;
0a7de745 5520 return ENOSPC;
6d2010ae
A
5521 }
5522
5523 /*
5524 * Allocate a new bridge forwarding node, and
5525 * initialize the expiration time and Ethernet
5526 * address.
5527 */
5528 brt = zalloc_noblock(bridge_rtnode_pool);
0a7de745 5529 if (brt == NULL) {
ea3f0419
A
5530 if (IF_BRIDGE_DEBUG(BR_DBGF_RT_TABLE)) {
5531 printf("%s: zalloc_nolock failed", __func__);
5532 }
0a7de745
A
5533 return ENOMEM;
5534 }
39236c6e 5535 bzero(brt, sizeof(struct bridge_rtnode));
6d2010ae 5536
0a7de745 5537 if (bif->bif_ifflags & IFBIF_STICKY) {
6d2010ae 5538 brt->brt_flags = IFBAF_STICKY;
0a7de745 5539 } else {
6d2010ae 5540 brt->brt_flags = IFBAF_DYNAMIC;
0a7de745 5541 }
6d2010ae
A
5542
5543 memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN);
5544 brt->brt_vlan = vlan;
5545
5546
5547 if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
5548 zfree(bridge_rtnode_pool, brt);
0a7de745 5549 return error;
6d2010ae
A
5550 }
5551 brt->brt_dst = bif;
5552 bif->bif_addrcnt++;
39236c6e 5553#if BRIDGE_DEBUG
ea3f0419 5554 if (IF_BRIDGE_DEBUG(BR_DBGF_RT_TABLE)) {
39236c6e
A
5555 printf("%s: added %02x:%02x:%02x:%02x:%02x:%02x "
5556 "on %s count %u hashsize %u\n", __func__,
5557 dst[0], dst[1], dst[2], dst[3], dst[4], dst[5],
5558 sc->sc_ifp->if_xname, sc->sc_brtcnt,
5559 sc->sc_rthash_size);
0a7de745 5560 }
39236c6e 5561#endif
6d2010ae
A
5562 }
5563
5564 if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC &&
5565 brt->brt_dst != bif) {
5566 brt->brt_dst->bif_addrcnt--;
5567 brt->brt_dst = bif;
5568 brt->brt_dst->bif_addrcnt++;
5569 }
5570
5571 if ((flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
39236c6e 5572 unsigned long now;
316670eb 5573
39236c6e
A
5574 now = (unsigned long) net_uptime();
5575 brt->brt_expire = now + sc->sc_brttimeout;
6d2010ae 5576 }
0a7de745 5577 if (setflags) {
6d2010ae 5578 brt->brt_flags = flags;
0a7de745 5579 }
6d2010ae 5580
316670eb 5581
0a7de745 5582 return 0;
6d2010ae
A
5583}
5584
5585/*
5586 * bridge_rtlookup:
5587 *
5588 * Lookup the destination interface for an address.
5589 */
5590static struct ifnet *
5591bridge_rtlookup(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan)
5592{
5593 struct bridge_rtnode *brt;
5594
39236c6e 5595 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae 5596
0a7de745
A
5597 if ((brt = bridge_rtnode_lookup(sc, addr, vlan)) == NULL) {
5598 return NULL;
5599 }
6d2010ae 5600
0a7de745 5601 return brt->brt_ifp;
6d2010ae
A
5602}
5603
5604/*
5605 * bridge_rttrim:
5606 *
5607 * Trim the routine table so that we have a number
5608 * of routing entries less than or equal to the
5609 * maximum number.
5610 */
5611static void
5612bridge_rttrim(struct bridge_softc *sc)
5613{
5614 struct bridge_rtnode *brt, *nbrt;
5615
39236c6e 5616 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
5617
5618 /* Make sure we actually need to do this. */
0a7de745 5619 if (sc->sc_brtcnt <= sc->sc_brtmax) {
6d2010ae 5620 return;
0a7de745 5621 }
6d2010ae
A
5622
5623 /* Force an aging cycle; this might trim enough addresses. */
5624 bridge_rtage(sc);
0a7de745 5625 if (sc->sc_brtcnt <= sc->sc_brtmax) {
6d2010ae 5626 return;
0a7de745 5627 }
6d2010ae
A
5628
5629 LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
5630 if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
5631 bridge_rtnode_destroy(sc, brt);
0a7de745 5632 if (sc->sc_brtcnt <= sc->sc_brtmax) {
6d2010ae 5633 return;
0a7de745 5634 }
6d2010ae
A
5635 }
5636 }
5637}
5638
5639/*
39236c6e 5640 * bridge_aging_timer:
6d2010ae 5641 *
39236c6e 5642 * Aging periodic timer for the bridge routing table.
6d2010ae
A
5643 */
5644static void
39236c6e 5645bridge_aging_timer(struct bridge_softc *sc)
6d2010ae 5646{
39236c6e 5647 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
5648
5649 bridge_rtage(sc);
39236c6e
A
5650 if ((sc->sc_ifp->if_flags & IFF_RUNNING) &&
5651 (sc->sc_flags & SCF_DETACHING) == 0) {
5652 sc->sc_aging_timer.bdc_sc = sc;
5653 sc->sc_aging_timer.bdc_func = bridge_aging_timer;
5654 sc->sc_aging_timer.bdc_ts.tv_sec = bridge_rtable_prune_period;
5655 bridge_schedule_delayed_call(&sc->sc_aging_timer);
6d2010ae
A
5656 }
5657}
5658
5659/*
5660 * bridge_rtage:
5661 *
5662 * Perform an aging cycle.
5663 */
5664static void
5665bridge_rtage(struct bridge_softc *sc)
5666{
5667 struct bridge_rtnode *brt, *nbrt;
39236c6e 5668 unsigned long now;
6d2010ae 5669
39236c6e
A
5670 BRIDGE_LOCK_ASSERT_HELD(sc);
5671
5672 now = (unsigned long) net_uptime();
6d2010ae
A
5673
5674 LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
5675 if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
0a7de745 5676 if (now >= brt->brt_expire) {
6d2010ae 5677 bridge_rtnode_destroy(sc, brt);
0a7de745 5678 }
6d2010ae
A
5679 }
5680 }
ea3f0419
A
5681 if (sc->sc_mac_nat_bif != NULL) {
5682 bridge_mac_nat_age_entries(sc, now);
5683 }
6d2010ae
A
5684}
5685
5686/*
5687 * bridge_rtflush:
5688 *
5689 * Remove all dynamic addresses from the bridge.
5690 */
5691static void
5692bridge_rtflush(struct bridge_softc *sc, int full)
5693{
5694 struct bridge_rtnode *brt, *nbrt;
5695
39236c6e 5696 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
5697
5698 LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
0a7de745 5699 if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
6d2010ae 5700 bridge_rtnode_destroy(sc, brt);
0a7de745 5701 }
6d2010ae
A
5702 }
5703}
5704
5705/*
5706 * bridge_rtdaddr:
5707 *
5708 * Remove an address from the table.
5709 */
5710static int
5711bridge_rtdaddr(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan)
5712{
5713 struct bridge_rtnode *brt;
5714 int found = 0;
5715
39236c6e 5716 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
5717
5718 /*
5719 * If vlan is zero then we want to delete for all vlans so the lookup
5720 * may return more than one.
5721 */
5722 while ((brt = bridge_rtnode_lookup(sc, addr, vlan)) != NULL) {
5723 bridge_rtnode_destroy(sc, brt);
5724 found = 1;
5725 }
5726
0a7de745 5727 return found ? 0 : ENOENT;
6d2010ae
A
5728}
5729
5730/*
5731 * bridge_rtdelete:
5732 *
ea3f0419 5733 * Delete routes to a specific member interface.
6d2010ae
A
5734 */
5735static void
5736bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int full)
5737{
5738 struct bridge_rtnode *brt, *nbrt;
5739
39236c6e 5740 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
5741
5742 LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
5743 if (brt->brt_ifp == ifp && (full ||
0a7de745 5744 (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)) {
6d2010ae 5745 bridge_rtnode_destroy(sc, brt);
0a7de745 5746 }
6d2010ae
A
5747 }
5748}
5749
5750/*
5751 * bridge_rtable_init:
5752 *
5753 * Initialize the route table for this bridge.
5754 */
5755static int
5756bridge_rtable_init(struct bridge_softc *sc)
5757{
39236c6e 5758 u_int32_t i;
6d2010ae 5759
0a7de745 5760 sc->sc_rthash = _MALLOC(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE,
39236c6e
A
5761 M_DEVBUF, M_WAITOK | M_ZERO);
5762 if (sc->sc_rthash == NULL) {
5763 printf("%s: no memory\n", __func__);
0a7de745 5764 return ENOMEM;
39236c6e
A
5765 }
5766 sc->sc_rthash_size = BRIDGE_RTHASH_SIZE;
6d2010ae 5767
0a7de745 5768 for (i = 0; i < sc->sc_rthash_size; i++) {
6d2010ae 5769 LIST_INIT(&sc->sc_rthash[i]);
0a7de745 5770 }
6d2010ae 5771
39236c6e 5772 sc->sc_rthash_key = RandomULong();
6d2010ae
A
5773
5774 LIST_INIT(&sc->sc_rtlist);
5775
0a7de745 5776 return 0;
6d2010ae
A
5777}
5778
39236c6e
A
5779/*
5780 * bridge_rthash_delayed_resize:
5781 *
5782 * Resize the routing table hash on a delayed thread call.
5783 */
5784static void
5785bridge_rthash_delayed_resize(struct bridge_softc *sc)
5786{
5787 u_int32_t new_rthash_size;
5788 struct _bridge_rtnode_list *new_rthash = NULL;
5789 struct _bridge_rtnode_list *old_rthash = NULL;
5790 u_int32_t i;
5791 struct bridge_rtnode *brt;
5792 int error = 0;
5793
5794 BRIDGE_LOCK_ASSERT_HELD(sc);
5795
5796 /*
5797 * Four entries per hash bucket is our ideal load factor
5798 */
0a7de745 5799 if (sc->sc_brtcnt < sc->sc_rthash_size * 4) {
39236c6e 5800 goto out;
0a7de745 5801 }
39236c6e
A
5802
5803 /*
5804 * Doubling the number of hash buckets may be too simplistic
5805 * especially when facing a spike of new entries
5806 */
5807 new_rthash_size = sc->sc_rthash_size * 2;
5808
5809 sc->sc_flags |= SCF_RESIZING;
5810 BRIDGE_UNLOCK(sc);
5811
0a7de745 5812 new_rthash = _MALLOC(sizeof(*sc->sc_rthash) * new_rthash_size,
39236c6e
A
5813 M_DEVBUF, M_WAITOK | M_ZERO);
5814
5815 BRIDGE_LOCK(sc);
5816 sc->sc_flags &= ~SCF_RESIZING;
5817
5818 if (new_rthash == NULL) {
5819 error = ENOMEM;
5820 goto out;
5821 }
5822 if ((sc->sc_flags & SCF_DETACHING)) {
5823 error = ENODEV;
5824 goto out;
5825 }
5826 /*
5827 * Fail safe from here on
5828 */
5829 old_rthash = sc->sc_rthash;
5830 sc->sc_rthash = new_rthash;
5831 sc->sc_rthash_size = new_rthash_size;
5832
5833 /*
5834 * Get a new key to force entries to be shuffled around to reduce
5835 * the likelihood they will land in the same buckets
5836 */
5837 sc->sc_rthash_key = RandomULong();
5838
0a7de745 5839 for (i = 0; i < sc->sc_rthash_size; i++) {
39236c6e 5840 LIST_INIT(&sc->sc_rthash[i]);
0a7de745 5841 }
39236c6e 5842
0a7de745 5843 LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) {
39236c6e
A
5844 LIST_REMOVE(brt, brt_hash);
5845 (void) bridge_rtnode_hash(sc, brt);
5846 }
5847out:
5848 if (error == 0) {
5849#if BRIDGE_DEBUG
ea3f0419 5850 if (IF_BRIDGE_DEBUG(BR_DBGF_RT_TABLE)) {
39236c6e
A
5851 printf("%s: %s new size %u\n", __func__,
5852 sc->sc_ifp->if_xname, sc->sc_rthash_size);
0a7de745 5853 }
39236c6e 5854#endif /* BRIDGE_DEBUG */
0a7de745 5855 if (old_rthash) {
39236c6e 5856 _FREE(old_rthash, M_DEVBUF);
0a7de745 5857 }
39236c6e
A
5858 } else {
5859#if BRIDGE_DEBUG
5860 printf("%s: %s failed %d\n", __func__,
5861 sc->sc_ifp->if_xname, error);
5862#endif /* BRIDGE_DEBUG */
0a7de745 5863 if (new_rthash != NULL) {
39236c6e 5864 _FREE(new_rthash, M_DEVBUF);
0a7de745 5865 }
39236c6e
A
5866 }
5867}
5868
5869/*
5870 * Resize the number of hash buckets based on the load factor
5871 * Currently only grow
5872 * Failing to resize the hash table is not fatal
5873 */
5874static void
5875bridge_rthash_resize(struct bridge_softc *sc)
5876{
5877 BRIDGE_LOCK_ASSERT_HELD(sc);
5878
0a7de745 5879 if ((sc->sc_flags & SCF_DETACHING) || (sc->sc_flags & SCF_RESIZING)) {
39236c6e 5880 return;
0a7de745 5881 }
39236c6e
A
5882
5883 /*
5884 * Four entries per hash bucket is our ideal load factor
5885 */
0a7de745 5886 if (sc->sc_brtcnt < sc->sc_rthash_size * 4) {
39236c6e 5887 return;
0a7de745 5888 }
39236c6e
A
5889 /*
5890 * Hard limit on the size of the routing hash table
5891 */
0a7de745 5892 if (sc->sc_rthash_size >= bridge_rtable_hash_size_max) {
39236c6e 5893 return;
0a7de745 5894 }
39236c6e
A
5895
5896 sc->sc_resize_call.bdc_sc = sc;
5897 sc->sc_resize_call.bdc_func = bridge_rthash_delayed_resize;
5898 bridge_schedule_delayed_call(&sc->sc_resize_call);
5899}
5900
6d2010ae
A
5901/*
5902 * bridge_rtable_fini:
5903 *
5904 * Deconstruct the route table for this bridge.
5905 */
5906static void
5907bridge_rtable_fini(struct bridge_softc *sc)
5908{
6d2010ae
A
5909 KASSERT(sc->sc_brtcnt == 0,
5910 ("%s: %d bridge routes referenced", __func__, sc->sc_brtcnt));
39236c6e
A
5911 if (sc->sc_rthash) {
5912 _FREE(sc->sc_rthash, M_DEVBUF);
5913 sc->sc_rthash = NULL;
5914 }
6d2010ae
A
5915}
5916
5917/*
5918 * The following hash function is adapted from "Hash Functions" by Bob Jenkins
5919 * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
5920 */
0a7de745
A
5921#define mix(a, b, c) \
5922do { \
5923 a -= b; a -= c; a ^= (c >> 13); \
5924 b -= c; b -= a; b ^= (a << 8); \
5925 c -= a; c -= b; c ^= (b >> 13); \
5926 a -= b; a -= c; a ^= (c >> 12); \
5927 b -= c; b -= a; b ^= (a << 16); \
5928 c -= a; c -= b; c ^= (b >> 5); \
5929 a -= b; a -= c; a ^= (c >> 3); \
5930 b -= c; b -= a; b ^= (a << 10); \
5931 c -= a; c -= b; c ^= (b >> 15); \
5932} while ( /*CONSTCOND*/ 0)
6d2010ae
A
5933
5934static __inline uint32_t
5935bridge_rthash(struct bridge_softc *sc, const uint8_t *addr)
5936{
5937 uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_rthash_key;
5938
5939 b += addr[5] << 8;
5940 b += addr[4];
5941 a += addr[3] << 24;
5942 a += addr[2] << 16;
5943 a += addr[1] << 8;
5944 a += addr[0];
5945
5946 mix(a, b, c);
5947
0a7de745 5948 return c & BRIDGE_RTHASH_MASK(sc);
6d2010ae
A
5949}
5950
5951#undef mix
5952
5953static int
5954bridge_rtnode_addr_cmp(const uint8_t *a, const uint8_t *b)
5955{
5956 int i, d;
5957
5958 for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) {
5959 d = ((int)a[i]) - ((int)b[i]);
5960 }
5961
0a7de745 5962 return d;
6d2010ae
A
5963}
5964
5965/*
5966 * bridge_rtnode_lookup:
5967 *
5968 * Look up a bridge route node for the specified destination. Compare the
5969 * vlan id or if zero then just return the first match.
5970 */
5971static struct bridge_rtnode *
316670eb 5972bridge_rtnode_lookup(struct bridge_softc *sc, const uint8_t *addr,
0a7de745 5973 uint16_t vlan)
6d2010ae
A
5974{
5975 struct bridge_rtnode *brt;
5976 uint32_t hash;
5977 int dir;
5978
39236c6e 5979 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
5980
5981 hash = bridge_rthash(sc, addr);
5982 LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) {
5983 dir = bridge_rtnode_addr_cmp(addr, brt->brt_addr);
0a7de745
A
5984 if (dir == 0 && (brt->brt_vlan == vlan || vlan == 0)) {
5985 return brt;
5986 }
5987 if (dir > 0) {
5988 return NULL;
5989 }
6d2010ae
A
5990 }
5991
0a7de745 5992 return NULL;
6d2010ae
A
5993}
5994
5995/*
39236c6e 5996 * bridge_rtnode_hash:
6d2010ae 5997 *
39236c6e
A
5998 * Insert the specified bridge node into the route hash table.
5999 * This is used when adding a new node or to rehash when resizing
6000 * the hash table
6d2010ae
A
6001 */
6002static int
39236c6e 6003bridge_rtnode_hash(struct bridge_softc *sc, struct bridge_rtnode *brt)
6d2010ae
A
6004{
6005 struct bridge_rtnode *lbrt;
6006 uint32_t hash;
6007 int dir;
6008
39236c6e 6009 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
6010
6011 hash = bridge_rthash(sc, brt->brt_addr);
6012
6013 lbrt = LIST_FIRST(&sc->sc_rthash[hash]);
6014 if (lbrt == NULL) {
6015 LIST_INSERT_HEAD(&sc->sc_rthash[hash], brt, brt_hash);
6016 goto out;
6017 }
6018
6019 do {
6020 dir = bridge_rtnode_addr_cmp(brt->brt_addr, lbrt->brt_addr);
39236c6e
A
6021 if (dir == 0 && brt->brt_vlan == lbrt->brt_vlan) {
6022#if BRIDGE_DEBUG
ea3f0419 6023 if (IF_BRIDGE_DEBUG(BR_DBGF_RT_TABLE)) {
39236c6e
A
6024 printf("%s: %s EEXIST "
6025 "%02x:%02x:%02x:%02x:%02x:%02x\n",
6026 __func__, sc->sc_ifp->if_xname,
6027 brt->brt_addr[0], brt->brt_addr[1],
6028 brt->brt_addr[2], brt->brt_addr[3],
6029 brt->brt_addr[4], brt->brt_addr[5]);
0a7de745 6030 }
39236c6e 6031#endif
0a7de745 6032 return EEXIST;
39236c6e 6033 }
6d2010ae
A
6034 if (dir > 0) {
6035 LIST_INSERT_BEFORE(lbrt, brt, brt_hash);
6036 goto out;
6037 }
6038 if (LIST_NEXT(lbrt, brt_hash) == NULL) {
6039 LIST_INSERT_AFTER(lbrt, brt, brt_hash);
6040 goto out;
6041 }
6042 lbrt = LIST_NEXT(lbrt, brt_hash);
6043 } while (lbrt != NULL);
6044
39236c6e 6045#if BRIDGE_DEBUG
ea3f0419 6046 if (IF_BRIDGE_DEBUG(BR_DBGF_RT_TABLE)) {
39236c6e
A
6047 printf("%s: %s impossible %02x:%02x:%02x:%02x:%02x:%02x\n",
6048 __func__, sc->sc_ifp->if_xname,
6049 brt->brt_addr[0], brt->brt_addr[1], brt->brt_addr[2],
6050 brt->brt_addr[3], brt->brt_addr[4], brt->brt_addr[5]);
0a7de745 6051 }
6d2010ae
A
6052#endif
6053
6054out:
0a7de745 6055 return 0;
39236c6e
A
6056}
6057
6058/*
6059 * bridge_rtnode_insert:
6060 *
6061 * Insert the specified bridge node into the route table. We
6062 * assume the entry is not already in the table.
6063 */
6064static int
6065bridge_rtnode_insert(struct bridge_softc *sc, struct bridge_rtnode *brt)
6066{
6067 int error;
6068
6069 error = bridge_rtnode_hash(sc, brt);
0a7de745
A
6070 if (error != 0) {
6071 return error;
6072 }
39236c6e 6073
6d2010ae
A
6074 LIST_INSERT_HEAD(&sc->sc_rtlist, brt, brt_list);
6075 sc->sc_brtcnt++;
6076
39236c6e
A
6077 bridge_rthash_resize(sc);
6078
0a7de745 6079 return 0;
6d2010ae
A
6080}
6081
6082/*
6083 * bridge_rtnode_destroy:
6084 *
6085 * Destroy a bridge rtnode.
6086 */
6087static void
6088bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt)
6089{
39236c6e 6090 BRIDGE_LOCK_ASSERT_HELD(sc);
6d2010ae
A
6091
6092 LIST_REMOVE(brt, brt_hash);
6093
6094 LIST_REMOVE(brt, brt_list);
6095 sc->sc_brtcnt--;
6096 brt->brt_dst->bif_addrcnt--;
6097 zfree(bridge_rtnode_pool, brt);
6098}
6099
316670eb 6100#if BRIDGESTP
6d2010ae
A
6101/*
6102 * bridge_rtable_expire:
6103 *
6104 * Set the expiry time for all routes on an interface.
6105 */
6106static void
6107bridge_rtable_expire(struct ifnet *ifp, int age)
6108{
6109 struct bridge_softc *sc = ifp->if_bridge;
6110 struct bridge_rtnode *brt;
6111
6112 BRIDGE_LOCK(sc);
6113
6114 /*
6115 * If the age is zero then flush, otherwise set all the expiry times to
6116 * age for the interface
6117 */
316670eb 6118 if (age == 0) {
6d2010ae 6119 bridge_rtdelete(sc, ifp, IFBF_FLUSHDYN);
316670eb 6120 } else {
39236c6e 6121 unsigned long now;
316670eb 6122
39236c6e
A
6123 now = (unsigned long) net_uptime();
6124
6125 LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) {
6d2010ae
A
6126 /* Cap the expiry time to 'age' */
6127 if (brt->brt_ifp == ifp &&
39236c6e 6128 brt->brt_expire > now + age &&
0a7de745 6129 (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
39236c6e 6130 brt->brt_expire = now + age;
0a7de745 6131 }
6d2010ae
A
6132 }
6133 }
6134 BRIDGE_UNLOCK(sc);
6135}
6136
6137/*
6138 * bridge_state_change:
6139 *
6140 * Callback from the bridgestp code when a port changes states.
6141 */
6142static void
6143bridge_state_change(struct ifnet *ifp, int state)
6144{
6145 struct bridge_softc *sc = ifp->if_bridge;
6146 static const char *stpstates[] = {
6147 "disabled",
6148 "listening",
6149 "learning",
6150 "forwarding",
6151 "blocking",
6152 "discarding"
6153 };
6154
0a7de745 6155 if (log_stp) {
39236c6e
A
6156 log(LOG_NOTICE, "%s: state changed to %s on %s\n",
6157 sc->sc_ifp->if_xname,
6158 stpstates[state], ifp->if_xname);
0a7de745 6159 }
6d2010ae 6160}
316670eb 6161#endif /* BRIDGESTP */
6d2010ae
A
6162
6163#ifdef PFIL_HOOKS
6164/*
6165 * Send bridge packets through pfil if they are one of the types pfil can deal
6166 * with, or if they are ARP or REVARP. (pfil will pass ARP and REVARP without
6167 * question.) If *bifp or *ifp are NULL then packet filtering is skipped for
6168 * that interface.
6169 */
6170static int
6171bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
6172{
6173 int snap, error, i, hlen;
6174 struct ether_header *eh1, eh2;
6175 struct ip_fw_args args;
6176 struct ip *ip;
6177 struct llc llc1;
6178 u_int16_t ether_type;
6179
6180 snap = 0;
0a7de745 6181 error = -1; /* Default error if not error == 0 */
6d2010ae
A
6182
6183#if 0
6184 /* we may return with the IP fields swapped, ensure its not shared */
6185 KASSERT(M_WRITABLE(*mp), ("%s: modifying a shared mbuf", __func__));
6186#endif
6187
0a7de745
A
6188 if (pfil_bridge == 0 && pfil_member == 0 && pfil_ipfw == 0) {
6189 return 0; /* filtering is disabled */
6190 }
6d2010ae
A
6191 i = min((*mp)->m_pkthdr.len, max_protohdr);
6192 if ((*mp)->m_len < i) {
316670eb
A
6193 *mp = m_pullup(*mp, i);
6194 if (*mp == NULL) {
6195 printf("%s: m_pullup failed\n", __func__);
0a7de745 6196 return -1;
316670eb 6197 }
6d2010ae
A
6198 }
6199
6200 eh1 = mtod(*mp, struct ether_header *);
6201 ether_type = ntohs(eh1->ether_type);
6202
6203 /*
6204 * Check for SNAP/LLC.
6205 */
6206 if (ether_type < ETHERMTU) {
6207 struct llc *llc2 = (struct llc *)(eh1 + 1);
6208
6209 if ((*mp)->m_len >= ETHER_HDR_LEN + 8 &&
6210 llc2->llc_dsap == LLC_SNAP_LSAP &&
6211 llc2->llc_ssap == LLC_SNAP_LSAP &&
6212 llc2->llc_control == LLC_UI) {
6213 ether_type = htons(llc2->llc_un.type_snap.ether_type);
6214 snap = 1;
6215 }
6216 }
6217
6218 /*
6219 * If we're trying to filter bridge traffic, don't look at anything
6220 * other than IP and ARP traffic. If the filter doesn't understand
6221 * IPv6, don't allow IPv6 through the bridge either. This is lame
6222 * since if we really wanted, say, an AppleTalk filter, we are hosed,
6223 * but of course we don't have an AppleTalk filter to begin with.
6224 * (Note that since pfil doesn't understand ARP it will pass *ALL*
6225 * ARP traffic.)
6226 */
6227 switch (ether_type) {
0a7de745
A
6228 case ETHERTYPE_ARP:
6229 case ETHERTYPE_REVARP:
6230 if (pfil_ipfw_arp == 0) {
6231 return 0; /* Automatically pass */
6232 }
6233 break;
6d2010ae 6234
0a7de745 6235 case ETHERTYPE_IP:
39236c6e 6236#if INET6
0a7de745 6237 case ETHERTYPE_IPV6:
6d2010ae 6238#endif /* INET6 */
0a7de745
A
6239 break;
6240 default:
6241 /*
6242 * Check to see if the user wants to pass non-ip
6243 * packets, these will not be checked by pfil(9) and
6244 * passed unconditionally so the default is to drop.
6245 */
6246 if (pfil_onlyip) {
6247 goto bad;
6248 }
6d2010ae
A
6249 }
6250
6251 /* Strip off the Ethernet header and keep a copy. */
316670eb 6252 m_copydata(*mp, 0, ETHER_HDR_LEN, (caddr_t)&eh2);
6d2010ae
A
6253 m_adj(*mp, ETHER_HDR_LEN);
6254
6255 /* Strip off snap header, if present */
6256 if (snap) {
0a7de745
A
6257 m_copydata(*mp, 0, sizeof(struct llc), (caddr_t)&llc1);
6258 m_adj(*mp, sizeof(struct llc));
6d2010ae
A
6259 }
6260
6261 /*
6262 * Check the IP header for alignment and errors
6263 */
6264 if (dir == PFIL_IN) {
6265 switch (ether_type) {
0a7de745
A
6266 case ETHERTYPE_IP:
6267 error = bridge_ip_checkbasic(mp);
6268 break;
39236c6e 6269#if INET6
0a7de745
A
6270 case ETHERTYPE_IPV6:
6271 error = bridge_ip6_checkbasic(mp);
6272 break;
6d2010ae 6273#endif /* INET6 */
0a7de745
A
6274 default:
6275 error = 0;
6d2010ae 6276 }
0a7de745 6277 if (error) {
6d2010ae 6278 goto bad;
0a7de745 6279 }
6d2010ae
A
6280 }
6281
6282 if (IPFW_LOADED && pfil_ipfw != 0 && dir == PFIL_OUT && ifp != NULL) {
6283 error = -1;
6284 args.rule = ip_dn_claim_rule(*mp);
0a7de745 6285 if (args.rule != NULL && fw_one_pass) {
6d2010ae 6286 goto ipfwpass; /* packet already partially processed */
0a7de745 6287 }
6d2010ae
A
6288 args.m = *mp;
6289 args.oif = ifp;
6290 args.next_hop = NULL;
6291 args.eh = &eh2;
0a7de745 6292 args.inp = NULL; /* used by ipfw uid/gid/jail rules */
6d2010ae
A
6293 i = ip_fw_chk_ptr(&args);
6294 *mp = args.m;
6295
0a7de745
A
6296 if (*mp == NULL) {
6297 return error;
6298 }
6d2010ae
A
6299
6300 if (DUMMYNET_LOADED && (i == IP_FW_DUMMYNET)) {
6d2010ae 6301 /* put the Ethernet header back on */
3e170ce0 6302 M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT, 0);
0a7de745
A
6303 if (*mp == NULL) {
6304 return error;
6305 }
6d2010ae
A
6306 bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN);
6307
6308 /*
6309 * Pass the pkt to dummynet, which consumes it. The
6310 * packet will return to us via bridge_dummynet().
6311 */
6312 args.oif = ifp;
316670eb 6313 ip_dn_io_ptr(mp, DN_TO_IFB_FWD, &args, DN_CLIENT_IPFW);
0a7de745 6314 return error;
6d2010ae
A
6315 }
6316
0a7de745 6317 if (i != IP_FW_PASS) { /* drop */
6d2010ae 6318 goto bad;
0a7de745 6319 }
6d2010ae
A
6320 }
6321
6322ipfwpass:
6323 error = 0;
6324
6325 /*
6326 * Run the packet through pfil
6327 */
6328 switch (ether_type) {
6329 case ETHERTYPE_IP:
6330 /*
6331 * before calling the firewall, swap fields the same as
6332 * IP does. here we assume the header is contiguous
6333 */
6334 ip = mtod(*mp, struct ip *);
6335
6336 ip->ip_len = ntohs(ip->ip_len);
6337 ip->ip_off = ntohs(ip->ip_off);
6338
6339 /*
6340 * Run pfil on the member interface and the bridge, both can
6341 * be skipped by clearing pfil_member or pfil_bridge.
6342 *
6343 * Keep the order:
6344 * in_if -> bridge_if -> out_if
6345 */
0a7de745 6346 if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) {
6d2010ae 6347 error = pfil_run_hooks(&inet_pfil_hook, mp, bifp,
316670eb 6348 dir, NULL);
0a7de745 6349 }
6d2010ae 6350
0a7de745 6351 if (*mp == NULL || error != 0) { /* filter may consume */
6d2010ae 6352 break;
0a7de745 6353 }
6d2010ae 6354
0a7de745 6355 if (pfil_member && ifp != NULL) {
6d2010ae 6356 error = pfil_run_hooks(&inet_pfil_hook, mp, ifp,
316670eb 6357 dir, NULL);
0a7de745 6358 }
6d2010ae 6359
0a7de745 6360 if (*mp == NULL || error != 0) { /* filter may consume */
6d2010ae 6361 break;
0a7de745 6362 }
6d2010ae 6363
0a7de745 6364 if (pfil_bridge && dir == PFIL_IN && bifp != NULL) {
6d2010ae 6365 error = pfil_run_hooks(&inet_pfil_hook, mp, bifp,
316670eb 6366 dir, NULL);
0a7de745 6367 }
6d2010ae 6368
0a7de745 6369 if (*mp == NULL || error != 0) { /* filter may consume */
6d2010ae 6370 break;
0a7de745 6371 }
6d2010ae
A
6372
6373 /* check if we need to fragment the packet */
6374 if (pfil_member && ifp != NULL && dir == PFIL_OUT) {
6375 i = (*mp)->m_pkthdr.len;
6376 if (i > ifp->if_mtu) {
6377 error = bridge_fragment(ifp, *mp, &eh2, snap,
316670eb 6378 &llc1);
0a7de745 6379 return error;
6d2010ae
A
6380 }
6381 }
6382
6383 /* Recalculate the ip checksum and restore byte ordering */
6384 ip = mtod(*mp, struct ip *);
6385 hlen = ip->ip_hl << 2;
0a7de745 6386 if (hlen < sizeof(struct ip)) {
6d2010ae 6387 goto bad;
0a7de745 6388 }
6d2010ae 6389 if (hlen > (*mp)->m_len) {
0a7de745 6390 if ((*mp = m_pullup(*mp, hlen)) == 0) {
6d2010ae 6391 goto bad;
0a7de745 6392 }
6d2010ae 6393 ip = mtod(*mp, struct ip *);
0a7de745 6394 if (ip == NULL) {
6d2010ae 6395 goto bad;
0a7de745 6396 }
6d2010ae
A
6397 }
6398 ip->ip_len = htons(ip->ip_len);
6399 ip->ip_off = htons(ip->ip_off);
6400 ip->ip_sum = 0;
0a7de745 6401 if (hlen == sizeof(struct ip)) {
6d2010ae 6402 ip->ip_sum = in_cksum_hdr(ip);
0a7de745 6403 } else {
6d2010ae 6404 ip->ip_sum = in_cksum(*mp, hlen);
0a7de745 6405 }
6d2010ae
A
6406
6407 break;
39236c6e 6408#if INET6
6d2010ae 6409 case ETHERTYPE_IPV6:
0a7de745 6410 if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) {
6d2010ae 6411 error = pfil_run_hooks(&inet6_pfil_hook, mp, bifp,
316670eb 6412 dir, NULL);
0a7de745 6413 }
6d2010ae 6414
0a7de745 6415 if (*mp == NULL || error != 0) { /* filter may consume */
6d2010ae 6416 break;
0a7de745 6417 }
6d2010ae 6418
0a7de745 6419 if (pfil_member && ifp != NULL) {
6d2010ae 6420 error = pfil_run_hooks(&inet6_pfil_hook, mp, ifp,
316670eb 6421 dir, NULL);
0a7de745 6422 }
6d2010ae 6423
0a7de745 6424 if (*mp == NULL || error != 0) { /* filter may consume */
6d2010ae 6425 break;
0a7de745 6426 }
6d2010ae 6427
0a7de745 6428 if (pfil_bridge && dir == PFIL_IN && bifp != NULL) {
6d2010ae 6429 error = pfil_run_hooks(&inet6_pfil_hook, mp, bifp,
316670eb 6430 dir, NULL);
0a7de745 6431 }
6d2010ae
A
6432 break;
6433#endif
6434 default:
6435 error = 0;
6436 break;
6437 }
6438
0a7de745
A
6439 if (*mp == NULL) {
6440 return error;
6441 }
6442 if (error != 0) {
6d2010ae 6443 goto bad;
0a7de745 6444 }
6d2010ae
A
6445
6446 error = -1;
6447
6448 /*
6449 * Finally, put everything back the way it was and return
6450 */
6451 if (snap) {
0a7de745
A
6452 M_PREPEND(*mp, sizeof(struct llc), M_DONTWAIT, 0);
6453 if (*mp == NULL) {
6454 return error;
6455 }
6456 bcopy(&llc1, mtod(*mp, caddr_t), sizeof(struct llc));
6d2010ae
A
6457 }
6458
3e170ce0 6459 M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT, 0);
0a7de745
A
6460 if (*mp == NULL) {
6461 return error;
6462 }
6d2010ae
A
6463 bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN);
6464
0a7de745 6465 return 0;
6d2010ae
A
6466
6467bad:
6468 m_freem(*mp);
6469 *mp = NULL;
0a7de745 6470 return error;
6d2010ae 6471}
ea3f0419 6472#endif /* PFIL_HOOKS */
6d2010ae 6473
6d2010ae
A
6474/*
6475 * Perform basic checks on header size since
6476 * pfil assumes ip_input has already processed
6477 * it for it. Cut-and-pasted from ip_input.c.
6478 * Given how simple the IPv6 version is,
6479 * does the IPv4 version really need to be
6480 * this complicated?
6481 *
6482 * XXX Should we update ipstat here, or not?
6483 * XXX Right now we update ipstat but not
6484 * XXX csum_counter.
6485 */
6486static int
6487bridge_ip_checkbasic(struct mbuf **mp)
6488{
6489 struct mbuf *m = *mp;
6490 struct ip *ip;
6491 int len, hlen;
6492 u_short sum;
6493
0a7de745
A
6494 if (*mp == NULL) {
6495 return -1;
6496 }
6d2010ae
A
6497
6498 if (IP_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) {
316670eb 6499 /* max_linkhdr is already rounded up to nearest 4-byte */
0a7de745 6500 if ((m = m_copyup(m, sizeof(struct ip),
316670eb 6501 max_linkhdr)) == NULL) {
6d2010ae
A
6502 /* XXXJRT new stat, please */
6503 ipstat.ips_toosmall++;
6504 goto bad;
6505 }
ea3f0419 6506 } else if (OS_EXPECT((size_t)m->m_len < sizeof(struct ip), 0)) {
0a7de745 6507 if ((m = m_pullup(m, sizeof(struct ip))) == NULL) {
6d2010ae
A
6508 ipstat.ips_toosmall++;
6509 goto bad;
6510 }
6511 }
6512 ip = mtod(m, struct ip *);
0a7de745
A
6513 if (ip == NULL) {
6514 goto bad;
6515 }
6d2010ae 6516
ea3f0419 6517 if (IP_VHL_V(ip->ip_vhl) != IPVERSION) {
6d2010ae
A
6518 ipstat.ips_badvers++;
6519 goto bad;
6520 }
ea3f0419
A
6521 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
6522 if (hlen < (int)sizeof(struct ip)) { /* minimum header length */
6d2010ae
A
6523 ipstat.ips_badhlen++;
6524 goto bad;
6525 }
6526 if (hlen > m->m_len) {
6527 if ((m = m_pullup(m, hlen)) == 0) {
6528 ipstat.ips_badhlen++;
6529 goto bad;
6530 }
6531 ip = mtod(m, struct ip *);
0a7de745
A
6532 if (ip == NULL) {
6533 goto bad;
6534 }
6d2010ae
A
6535 }
6536
6537 if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
6538 sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
6539 } else {
0a7de745 6540 if (hlen == sizeof(struct ip)) {
6d2010ae
A
6541 sum = in_cksum_hdr(ip);
6542 } else {
6543 sum = in_cksum(m, hlen);
6544 }
6545 }
6546 if (sum) {
6547 ipstat.ips_badsum++;
6548 goto bad;
6549 }
6550
6551 /* Retrieve the packet length. */
6552 len = ntohs(ip->ip_len);
6553
6554 /*
6555 * Check for additional length bogosity
6556 */
6557 if (len < hlen) {
6558 ipstat.ips_badlen++;
6559 goto bad;
6560 }
6561
6562 /*
6563 * Check that the amount of data in the buffers
6564 * is as at least much as the IP header would have us expect.
6565 * Drop packet if shorter than we expect.
6566 */
6567 if (m->m_pkthdr.len < len) {
6568 ipstat.ips_tooshort++;
6569 goto bad;
6570 }
6571
6572 /* Checks out, proceed */
6573 *mp = m;
0a7de745 6574 return 0;
6d2010ae
A
6575
6576bad:
6577 *mp = m;
0a7de745 6578 return -1;
6d2010ae
A
6579}
6580
39236c6e 6581#if INET6
6d2010ae
A
6582/*
6583 * Same as above, but for IPv6.
6584 * Cut-and-pasted from ip6_input.c.
6585 * XXX Should we update ip6stat, or not?
6586 */
6587static int
6588bridge_ip6_checkbasic(struct mbuf **mp)
6589{
6590 struct mbuf *m = *mp;
6591 struct ip6_hdr *ip6;
6592
6593 /*
6594 * If the IPv6 header is not aligned, slurp it up into a new
6595 * mbuf with space for link headers, in the event we forward
6596 * it. Otherwise, if it is aligned, make sure the entire base
6597 * IPv6 header is in the first mbuf of the chain.
6598 */
6599 if (IP6_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) {
6600 struct ifnet *inifp = m->m_pkthdr.rcvif;
316670eb 6601 /* max_linkhdr is already rounded up to nearest 4-byte */
0a7de745 6602 if ((m = m_copyup(m, sizeof(struct ip6_hdr),
316670eb 6603 max_linkhdr)) == NULL) {
6d2010ae
A
6604 /* XXXJRT new stat, please */
6605 ip6stat.ip6s_toosmall++;
6606 in6_ifstat_inc(inifp, ifs6_in_hdrerr);
6607 goto bad;
6608 }
ea3f0419 6609 } else if (OS_EXPECT((size_t)m->m_len < sizeof(struct ip6_hdr), 0)) {
6d2010ae 6610 struct ifnet *inifp = m->m_pkthdr.rcvif;
0a7de745 6611 if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
6d2010ae
A
6612 ip6stat.ip6s_toosmall++;
6613 in6_ifstat_inc(inifp, ifs6_in_hdrerr);
6614 goto bad;
6615 }
6616 }
6617
6618 ip6 = mtod(m, struct ip6_hdr *);
6619
6620 if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
6621 ip6stat.ip6s_badvers++;
6622 in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
6623 goto bad;
6624 }
6625
6626 /* Checks out, proceed */
6627 *mp = m;
0a7de745 6628 return 0;
6d2010ae
A
6629
6630bad:
6631 *mp = m;
0a7de745 6632 return -1;
6d2010ae
A
6633}
6634#endif /* INET6 */
6635
ea3f0419 6636#ifdef PFIL_HOOKS
6d2010ae
A
6637/*
6638 * bridge_fragment:
6639 *
6640 * Return a fragmented mbuf chain.
6641 */
6642static int
6643bridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh,
0a7de745 6644 int snap, struct llc *llc)
6d2010ae
A
6645{
6646 struct mbuf *m0;
6647 struct ip *ip;
6648 int error = -1;
6649
0a7de745
A
6650 if (m->m_len < sizeof(struct ip) &&
6651 (m = m_pullup(m, sizeof(struct ip))) == NULL) {
6d2010ae 6652 goto out;
0a7de745 6653 }
6d2010ae
A
6654 ip = mtod(m, struct ip *);
6655
6656 error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist,
316670eb 6657 CSUM_DELAY_IP);
0a7de745 6658 if (error) {
6d2010ae 6659 goto out;
0a7de745 6660 }
6d2010ae
A
6661
6662 /* walk the chain and re-add the Ethernet header */
6663 for (m0 = m; m0; m0 = m0->m_nextpkt) {
6664 if (error == 0) {
6665 if (snap) {
0a7de745 6666 M_PREPEND(m0, sizeof(struct llc), M_DONTWAIT, 0);
6d2010ae
A
6667 if (m0 == NULL) {
6668 error = ENOBUFS;
6669 continue;
6670 }
6671 bcopy(llc, mtod(m0, caddr_t),
0a7de745 6672 sizeof(struct llc));
6d2010ae 6673 }
3e170ce0 6674 M_PREPEND(m0, ETHER_HDR_LEN, M_DONTWAIT, 0);
6d2010ae
A
6675 if (m0 == NULL) {
6676 error = ENOBUFS;
6677 continue;
6678 }
6679 bcopy(eh, mtod(m0, caddr_t), ETHER_HDR_LEN);
316670eb 6680 } else {
6d2010ae 6681 m_freem(m);
316670eb 6682 }
6d2010ae
A
6683 }
6684
0a7de745 6685 if (error == 0) {
6d2010ae 6686 ipstat.ips_fragmented++;
0a7de745 6687 }
6d2010ae 6688
0a7de745 6689 return error;
6d2010ae
A
6690
6691out:
0a7de745 6692 if (m != NULL) {
6d2010ae 6693 m_freem(m);
0a7de745
A
6694 }
6695 return error;
6d2010ae
A
6696}
6697#endif /* PFIL_HOOKS */
6698
39236c6e
A
6699/*
6700 * bridge_set_bpf_tap:
6701 *
6702 * Sets ups the BPF callbacks.
6703 */
6d2010ae
A
6704static errno_t
6705bridge_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode, bpf_packet_func bpf_callback)
6706{
6707 struct bridge_softc *sc = (struct bridge_softc *)ifnet_softc(ifp);
316670eb 6708
6d2010ae
A
6709 /* TBD locking */
6710 if (sc == NULL || (sc->sc_flags & SCF_DETACHING)) {
0a7de745 6711 return ENODEV;
6d2010ae 6712 }
6d2010ae 6713 switch (mode) {
0a7de745
A
6714 case BPF_TAP_DISABLE:
6715 sc->sc_bpf_input = sc->sc_bpf_output = NULL;
6716 break;
316670eb 6717
0a7de745
A
6718 case BPF_TAP_INPUT:
6719 sc->sc_bpf_input = bpf_callback;
6720 break;
316670eb 6721
0a7de745
A
6722 case BPF_TAP_OUTPUT:
6723 sc->sc_bpf_output = bpf_callback;
6724 break;
316670eb 6725
0a7de745
A
6726 case BPF_TAP_INPUT_OUTPUT:
6727 sc->sc_bpf_input = sc->sc_bpf_output = bpf_callback;
6728 break;
316670eb 6729
0a7de745
A
6730 default:
6731 break;
6d2010ae 6732 }
316670eb 6733
0a7de745 6734 return 0;
6d2010ae
A
6735}
6736
39236c6e
A
6737/*
6738 * bridge_detach:
6739 *
6740 * Callback when interface has been detached.
6741 */
6d2010ae
A
6742static void
6743bridge_detach(ifnet_t ifp)
6744{
6745 struct bridge_softc *sc = (struct bridge_softc *)ifnet_softc(ifp);
316670eb
A
6746
6747#if BRIDGESTP
6d2010ae 6748 bstp_detach(&sc->sc_stp);
316670eb 6749#endif /* BRIDGESTP */
6d2010ae 6750
cb323159
A
6751 /* Tear down the routing table. */
6752 bridge_rtable_fini(sc);
316670eb 6753
39236c6e 6754 lck_mtx_lock(&bridge_list_mtx);
6d2010ae 6755 LIST_REMOVE(sc, sc_list);
39236c6e 6756 lck_mtx_unlock(&bridge_list_mtx);
316670eb 6757
6d2010ae 6758 ifnet_release(ifp);
316670eb 6759
39236c6e 6760 lck_mtx_destroy(&sc->sc_mtx, bridge_lock_grp);
d9a64523 6761 if_clone_softc_deallocate(&bridge_cloner, sc);
6d2010ae
A
6762}
6763
39236c6e
A
6764/*
6765 * bridge_bpf_input:
6766 *
6767 * Invoke the input BPF callback if enabled
6768 */
ea3f0419
A
6769static errno_t
6770bridge_bpf_input(ifnet_t ifp, struct mbuf *m, const char * func, int line)
6d2010ae
A
6771{
6772 struct bridge_softc *sc = (struct bridge_softc *)ifnet_softc(ifp);
ea3f0419 6773 bpf_packet_func input_func = sc->sc_bpf_input;
316670eb 6774
ea3f0419 6775 if (input_func != NULL) {
316670eb 6776 if (mbuf_pkthdr_rcvif(m) != ifp) {
ea3f0419 6777 printf("%s.%d: rcvif: 0x%llx != ifp 0x%llx\n", func, line,
39236c6e
A
6778 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_pkthdr_rcvif(m)),
6779 (uint64_t)VM_KERNEL_ADDRPERM(ifp));
316670eb 6780 }
ea3f0419 6781 (*input_func)(ifp, m);
6d2010ae 6782 }
0a7de745 6783 return 0;
6d2010ae
A
6784}
6785
39236c6e
A
6786/*
6787 * bridge_bpf_output:
6788 *
6789 * Invoke the output BPF callback if enabled
6790 */
ea3f0419 6791static errno_t
316670eb 6792bridge_bpf_output(ifnet_t ifp, struct mbuf *m)
6d2010ae
A
6793{
6794 struct bridge_softc *sc = (struct bridge_softc *)ifnet_softc(ifp);
ea3f0419 6795 bpf_packet_func output_func = sc->sc_bpf_output;
316670eb 6796
ea3f0419
A
6797 if (output_func != NULL) {
6798 (*output_func)(ifp, m);
6d2010ae 6799 }
0a7de745 6800 return 0;
6d2010ae 6801}
39236c6e
A
6802
6803/*
6804 * bridge_link_event:
6805 *
6806 * Report a data link event on an interface
6807 */
6808static void
6809bridge_link_event(struct ifnet *ifp, u_int32_t event_code)
6810{
6811 struct {
0a7de745
A
6812 struct kern_event_msg header;
6813 u_int32_t unit;
6814 char if_name[IFNAMSIZ];
39236c6e
A
6815 } event;
6816
6817#if BRIDGE_DEBUG
ea3f0419 6818 if (IF_BRIDGE_DEBUG(BR_DBGF_LIFECYCLE)) {
39236c6e
A
6819 printf("%s: %s event_code %u - %s\n", __func__, ifp->if_xname,
6820 event_code, dlil_kev_dl_code_str(event_code));
0a7de745 6821 }
39236c6e
A
6822#endif /* BRIDGE_DEBUG */
6823
0a7de745
A
6824 bzero(&event, sizeof(event));
6825 event.header.total_size = sizeof(event);
6826 event.header.vendor_code = KEV_VENDOR_APPLE;
6827 event.header.kev_class = KEV_NETWORK_CLASS;
6828 event.header.kev_subclass = KEV_DL_SUBCLASS;
6829 event.header.event_code = event_code;
6830 event.header.event_data[0] = ifnet_family(ifp);
6831 event.unit = (u_int32_t)ifnet_unit(ifp);
fe8ab488 6832 strlcpy(event.if_name, ifnet_name(ifp), IFNAMSIZ);
39236c6e
A
6833 ifnet_event(ifp, &event.header);
6834}
fe8ab488 6835
ea3f0419
A
6836#define BRIDGE_HF_DROP(reason, func, line) { \
6837 bridge_hostfilter_stats.reason++; \
6838 if (IF_BRIDGE_DEBUG(BR_DBGF_HOSTFILTER)) { \
6839 printf("%s.%d" #reason, func, line); \
6840 error = EINVAL; \
6841 } \
6842 }
fe8ab488
A
6843
6844/*
6845 * Make sure this is a DHCP or Bootp request that match the host filter
6846 */
6847static int
6848bridge_dhcp_filter(struct bridge_iflist *bif, struct mbuf *m, size_t offset)
6849{
6850 int error = EINVAL;
6851 struct dhcp dhcp;
6852
6853 /*
6854 * Note: We use the dhcp structure because bootp structure definition
6855 * is larger and some vendors do not pad the request
6856 */
6857 error = mbuf_copydata(m, offset, sizeof(struct dhcp), &dhcp);
6858 if (error != 0) {
6859 BRIDGE_HF_DROP(brhf_dhcp_too_small, __func__, __LINE__);
6860 goto done;
6861 }
6862 if (dhcp.dp_op != BOOTREQUEST) {
6863 BRIDGE_HF_DROP(brhf_dhcp_bad_op, __func__, __LINE__);
6864 goto done;
6865 }
6866 /*
6867 * The hardware address must be an exact match
6868 */
6869 if (dhcp.dp_htype != ARPHRD_ETHER) {
6870 BRIDGE_HF_DROP(brhf_dhcp_bad_htype, __func__, __LINE__);
6871 goto done;
6872 }
6873 if (dhcp.dp_hlen != ETHER_ADDR_LEN) {
6874 BRIDGE_HF_DROP(brhf_dhcp_bad_hlen, __func__, __LINE__);
6875 goto done;
6876 }
6877 if (bcmp(dhcp.dp_chaddr, bif->bif_hf_hwsrc,
6878 ETHER_ADDR_LEN) != 0) {
6879 BRIDGE_HF_DROP(brhf_dhcp_bad_chaddr, __func__, __LINE__);
6880 goto done;
6881 }
6882 /*
6883 * Client address must match the host address or be not specified
6884 */
6885 if (dhcp.dp_ciaddr.s_addr != bif->bif_hf_ipsrc.s_addr &&
6886 dhcp.dp_ciaddr.s_addr != INADDR_ANY) {
6887 BRIDGE_HF_DROP(brhf_dhcp_bad_ciaddr, __func__, __LINE__);
6888 goto done;
6889 }
6890 error = 0;
6891done:
0a7de745 6892 return error;
fe8ab488
A
6893}
6894
6895static int
ea3f0419 6896bridge_host_filter(struct bridge_iflist *bif, mbuf_t *data)
fe8ab488
A
6897{
6898 int error = EINVAL;
6899 struct ether_header *eh;
6900 static struct in_addr inaddr_any = { .s_addr = INADDR_ANY };
ea3f0419 6901 mbuf_t m = *data;
fe8ab488 6902
fe8ab488
A
6903 eh = mtod(m, struct ether_header *);
6904
6905 /*
6906 * Restrict the source hardware address
6907 */
6908 if ((bif->bif_flags & BIFF_HF_HWSRC) == 0 ||
6909 bcmp(eh->ether_shost, bif->bif_hf_hwsrc,
6910 ETHER_ADDR_LEN) != 0) {
6911 BRIDGE_HF_DROP(brhf_bad_ether_srchw_addr, __func__, __LINE__);
6912 goto done;
6913 }
6914
6915 /*
6916 * Restrict Ethernet protocols to ARP and IP
6917 */
6918 if (eh->ether_type == htons(ETHERTYPE_ARP)) {
6919 struct ether_arp *ea;
6920 size_t minlen = sizeof(struct ether_header) +
0a7de745 6921 sizeof(struct ether_arp);
fe8ab488
A
6922
6923 /*
6924 * Make the Ethernet and ARP headers contiguous
6925 */
6926 if (mbuf_pkthdr_len(m) < minlen) {
6927 BRIDGE_HF_DROP(brhf_arp_too_small, __func__, __LINE__);
6928 goto done;
6929 }
ea3f0419 6930 if (mbuf_len(m) < minlen && mbuf_pullup(data, minlen) != 0) {
fe8ab488 6931 BRIDGE_HF_DROP(brhf_arp_pullup_failed,
0a7de745 6932 __func__, __LINE__);
fe8ab488
A
6933 goto done;
6934 }
ea3f0419
A
6935 m = *data;
6936
fe8ab488
A
6937 /*
6938 * Verify this is an ethernet/ip arp
6939 */
6940 eh = mtod(m, struct ether_header *);
6941 ea = (struct ether_arp *)(eh + 1);
6942 if (ea->arp_hrd != htons(ARPHRD_ETHER)) {
6943 BRIDGE_HF_DROP(brhf_arp_bad_hw_type,
0a7de745 6944 __func__, __LINE__);
fe8ab488
A
6945 goto done;
6946 }
6947 if (ea->arp_pro != htons(ETHERTYPE_IP)) {
6948 BRIDGE_HF_DROP(brhf_arp_bad_pro_type,
0a7de745 6949 __func__, __LINE__);
fe8ab488
A
6950 goto done;
6951 }
6952 /*
6953 * Verify the address lengths are correct
6954 */
6955 if (ea->arp_hln != ETHER_ADDR_LEN) {
6956 BRIDGE_HF_DROP(brhf_arp_bad_hw_len, __func__, __LINE__);
6957 goto done;
6958 }
6959 if (ea->arp_pln != sizeof(struct in_addr)) {
6960 BRIDGE_HF_DROP(brhf_arp_bad_pro_len,
0a7de745 6961 __func__, __LINE__);
fe8ab488
A
6962 goto done;
6963 }
6964
6965 /*
6966 * Allow only ARP request or ARP reply
6967 */
6968 if (ea->arp_op != htons(ARPOP_REQUEST) &&
6969 ea->arp_op != htons(ARPOP_REPLY)) {
6970 BRIDGE_HF_DROP(brhf_arp_bad_op, __func__, __LINE__);
6971 goto done;
6972 }
6973 /*
6974 * Verify source hardware address matches
6975 */
6976 if (bcmp(ea->arp_sha, bif->bif_hf_hwsrc,
6977 ETHER_ADDR_LEN) != 0) {
6978 BRIDGE_HF_DROP(brhf_arp_bad_sha, __func__, __LINE__);
6979 goto done;
6980 }
6981 /*
6982 * Verify source protocol address:
6983 * May be null for an ARP probe
6984 */
6985 if (bcmp(ea->arp_spa, &bif->bif_hf_ipsrc.s_addr,
0a7de745 6986 sizeof(struct in_addr)) != 0 &&
fe8ab488 6987 bcmp(ea->arp_spa, &inaddr_any,
0a7de745 6988 sizeof(struct in_addr)) != 0) {
fe8ab488
A
6989 BRIDGE_HF_DROP(brhf_arp_bad_spa, __func__, __LINE__);
6990 goto done;
6991 }
fe8ab488
A
6992 bridge_hostfilter_stats.brhf_arp_ok += 1;
6993 error = 0;
6994 } else if (eh->ether_type == htons(ETHERTYPE_IP)) {
6995 size_t minlen = sizeof(struct ether_header) + sizeof(struct ip);
6996 struct ip iphdr;
6997 size_t offset;
6998
6999 /*
7000 * Make the Ethernet and IP headers contiguous
7001 */
7002 if (mbuf_pkthdr_len(m) < minlen) {
7003 BRIDGE_HF_DROP(brhf_ip_too_small, __func__, __LINE__);
7004 goto done;
7005 }
7006 offset = sizeof(struct ether_header);
7007 error = mbuf_copydata(m, offset, sizeof(struct ip), &iphdr);
7008 if (error != 0) {
7009 BRIDGE_HF_DROP(brhf_ip_too_small, __func__, __LINE__);
7010 goto done;
7011 }
7012 /*
7013 * Verify the source IP address
7014 */
7015 if (iphdr.ip_p == IPPROTO_UDP) {
7016 struct udphdr udp;
7017
7018 minlen += sizeof(struct udphdr);
7019 if (mbuf_pkthdr_len(m) < minlen) {
7020 BRIDGE_HF_DROP(brhf_ip_too_small,
0a7de745 7021 __func__, __LINE__);
fe8ab488
A
7022 goto done;
7023 }
7024
7025 /*
7026 * Allow all zero addresses for DHCP requests
7027 */
7028 if (iphdr.ip_src.s_addr != bif->bif_hf_ipsrc.s_addr &&
7029 iphdr.ip_src.s_addr != INADDR_ANY) {
7030 BRIDGE_HF_DROP(brhf_ip_bad_srcaddr,
0a7de745 7031 __func__, __LINE__);
fe8ab488
A
7032 goto done;
7033 }
7034 offset = sizeof(struct ether_header) +
7035 (IP_VHL_HL(iphdr.ip_vhl) << 2);
7036 error = mbuf_copydata(m, offset,
7037 sizeof(struct udphdr), &udp);
7038 if (error != 0) {
7039 BRIDGE_HF_DROP(brhf_ip_too_small,
0a7de745 7040 __func__, __LINE__);
fe8ab488
A
7041 goto done;
7042 }
7043 /*
7044 * Either it's a Bootp/DHCP packet that we like or
7045 * it's a UDP packet from the host IP as source address
7046 */
7047 if (udp.uh_sport == htons(IPPORT_BOOTPC) &&
7048 udp.uh_dport == htons(IPPORT_BOOTPS)) {
7049 minlen += sizeof(struct dhcp);
7050 if (mbuf_pkthdr_len(m) < minlen) {
7051 BRIDGE_HF_DROP(brhf_ip_too_small,
0a7de745 7052 __func__, __LINE__);
fe8ab488
A
7053 goto done;
7054 }
7055 offset += sizeof(struct udphdr);
7056 error = bridge_dhcp_filter(bif, m, offset);
0a7de745 7057 if (error != 0) {
fe8ab488 7058 goto done;
0a7de745 7059 }
fe8ab488
A
7060 } else if (iphdr.ip_src.s_addr == INADDR_ANY) {
7061 BRIDGE_HF_DROP(brhf_ip_bad_srcaddr,
0a7de745 7062 __func__, __LINE__);
fe8ab488
A
7063 goto done;
7064 }
7065 } else if (iphdr.ip_src.s_addr != bif->bif_hf_ipsrc.s_addr ||
7066 bif->bif_hf_ipsrc.s_addr == INADDR_ANY) {
fe8ab488
A
7067 BRIDGE_HF_DROP(brhf_ip_bad_srcaddr, __func__, __LINE__);
7068 goto done;
7069 }
7070 /*
7071 * Allow only boring IP protocols
7072 */
7073 if (iphdr.ip_p != IPPROTO_TCP &&
7074 iphdr.ip_p != IPPROTO_UDP &&
7075 iphdr.ip_p != IPPROTO_ICMP &&
7076 iphdr.ip_p != IPPROTO_ESP &&
7077 iphdr.ip_p != IPPROTO_AH &&
7078 iphdr.ip_p != IPPROTO_GRE) {
7079 BRIDGE_HF_DROP(brhf_ip_bad_proto, __func__, __LINE__);
7080 goto done;
7081 }
7082 bridge_hostfilter_stats.brhf_ip_ok += 1;
7083 error = 0;
7084 } else {
7085 BRIDGE_HF_DROP(brhf_bad_ether_type, __func__, __LINE__);
7086 goto done;
7087 }
7088done:
7089 if (error != 0) {
ea3f0419 7090 if (IF_BRIDGE_DEBUG(BR_DBGF_HOSTFILTER)) {
fe8ab488
A
7091 if (m) {
7092 printf_mbuf_data(m, 0,
7093 sizeof(struct ether_header) +
7094 sizeof(struct ip));
7095 }
7096 printf("\n");
7097 }
7098
0a7de745 7099 if (m != NULL) {
fe8ab488 7100 m_freem(m);
0a7de745 7101 }
fe8ab488 7102 }
0a7de745 7103 return error;
fe8ab488 7104}
ea3f0419
A
7105
7106/*
7107 * MAC NAT
7108 */
7109
7110static errno_t
7111bridge_mac_nat_enable(struct bridge_softc *sc, struct bridge_iflist *bif)
7112{
7113 errno_t error = 0;
7114
7115 BRIDGE_LOCK_ASSERT_HELD(sc);
7116
7117 if (sc->sc_mac_nat_bif != NULL) {
7118 if (sc->sc_mac_nat_bif != bif) {
7119 error = EBUSY;
7120 }
7121 goto done;
7122 }
7123 sc->sc_mac_nat_bif = bif;
7124 bif->bif_ifflags |= IFBIF_MAC_NAT;
7125 bridge_mac_nat_populate_entries(sc);
7126
7127done:
7128 return error;
7129}
7130
7131static void
7132bridge_mac_nat_disable(struct bridge_softc *sc)
7133{
7134 struct bridge_iflist *mac_nat_bif = sc->sc_mac_nat_bif;
7135
7136 assert(mac_nat_bif != NULL);
7137 bridge_mac_nat_flush_entries(sc, mac_nat_bif);
7138 mac_nat_bif->bif_ifflags &= ~IFBIF_MAC_NAT;
7139 sc->sc_mac_nat_bif = NULL;
7140 return;
7141}
7142
7143static void
7144mac_nat_entry_print2(struct mac_nat_entry *mne,
7145 char *ifname, const char *msg1, const char *msg2)
7146{
7147 int af;
7148 char etopbuf[24];
7149 char ntopbuf[MAX_IPv6_STR_LEN];
7150 const char *space;
7151
7152 af = ((mne->mne_flags & MNE_FLAGS_IPV6) != 0) ? AF_INET6 : AF_INET;
7153 ether_ntop(etopbuf, sizeof(etopbuf), mne->mne_mac);
7154 (void)inet_ntop(af, &mne->mne_u, ntopbuf, sizeof(ntopbuf));
7155 if (msg2 == NULL) {
7156 msg2 = "";
7157 space = "";
7158 } else {
7159 space = " ";
7160 }
7161 printf("%s %s%s%s %p (%s, %s, %s)\n",
7162 ifname, msg1, space, msg2, mne, mne->mne_bif->bif_ifp->if_xname,
7163 ntopbuf, etopbuf);
7164}
7165
7166static void
7167mac_nat_entry_print(struct mac_nat_entry *mne,
7168 char *ifname, const char *msg)
7169{
7170 mac_nat_entry_print2(mne, ifname, msg, NULL);
7171}
7172
7173static struct mac_nat_entry *
7174bridge_lookup_mac_nat_entry(struct bridge_softc *sc, int af, void * ip)
7175{
7176 struct mac_nat_entry *mne;
7177 struct mac_nat_entry *ret_mne = NULL;
7178
7179 if (af == AF_INET) {
7180 in_addr_t s_addr = ((struct in_addr *)ip)->s_addr;
7181
7182 LIST_FOREACH(mne, &sc->sc_mne_list, mne_list) {
7183 if (mne->mne_ip.s_addr == s_addr) {
7184 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7185 mac_nat_entry_print(mne, sc->sc_if_xname,
7186 "found");
7187 }
7188 ret_mne = mne;
7189 break;
7190 }
7191 }
7192 } else {
7193 const struct in6_addr *ip6 = (const struct in6_addr *)ip;
7194
7195 LIST_FOREACH(mne, &sc->sc_mne_list_v6, mne_list) {
7196 if (IN6_ARE_ADDR_EQUAL(&mne->mne_ip6, ip6)) {
7197 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7198 mac_nat_entry_print(mne, sc->sc_if_xname,
7199 "found");
7200 }
7201 ret_mne = mne;
7202 break;
7203 }
7204 }
7205 }
7206 return ret_mne;
7207}
7208
7209static void
7210bridge_destroy_mac_nat_entry(struct bridge_softc *sc,
7211 struct mac_nat_entry *mne, const char *reason)
7212{
7213 LIST_REMOVE(mne, mne_list);
7214 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7215 mac_nat_entry_print(mne, sc->sc_if_xname, reason);
7216 }
7217 zfree(bridge_mne_pool, mne);
7218 sc->sc_mne_count--;
7219}
7220
7221static struct mac_nat_entry *
7222bridge_create_mac_nat_entry(struct bridge_softc *sc,
7223 struct bridge_iflist *bif, int af, const void *ip, uint8_t *eaddr)
7224{
7225 struct mac_nat_entry_list *list;
7226 struct mac_nat_entry *mne;
7227
7228 if (sc->sc_mne_count >= sc->sc_mne_max) {
7229 sc->sc_mne_allocation_failures++;
7230 return NULL;
7231 }
7232 mne = zalloc_noblock(bridge_mne_pool);
7233 if (mne == NULL) {
7234 sc->sc_mne_allocation_failures++;
7235 return NULL;
7236 }
7237 sc->sc_mne_count++;
7238 bzero(mne, sizeof(*mne));
7239 bcopy(eaddr, mne->mne_mac, sizeof(mne->mne_mac));
7240 mne->mne_bif = bif;
7241 if (af == AF_INET) {
7242 bcopy(ip, &mne->mne_ip, sizeof(mne->mne_ip));
7243 list = &sc->sc_mne_list;
7244 } else {
7245 bcopy(ip, &mne->mne_ip6, sizeof(mne->mne_ip6));
7246 mne->mne_flags |= MNE_FLAGS_IPV6;
7247 list = &sc->sc_mne_list_v6;
7248 }
7249 LIST_INSERT_HEAD(list, mne, mne_list);
7250 mne->mne_expire = (unsigned long)net_uptime() + sc->sc_brttimeout;
7251 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7252 mac_nat_entry_print(mne, sc->sc_if_xname, "created");
7253 }
7254 return mne;
7255}
7256
7257static struct mac_nat_entry *
7258bridge_update_mac_nat_entry(struct bridge_softc *sc,
7259 struct bridge_iflist *bif, int af, void *ip, uint8_t *eaddr)
7260{
7261 struct mac_nat_entry *mne;
7262
7263 mne = bridge_lookup_mac_nat_entry(sc, af, ip);
7264 if (mne != NULL) {
7265 struct bridge_iflist *mac_nat_bif = sc->sc_mac_nat_bif;
7266
7267 if (mne->mne_bif == mac_nat_bif) {
7268 /* the MAC NAT interface takes precedence */
7269 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7270 if (mne->mne_bif != bif) {
7271 mac_nat_entry_print2(mne,
7272 sc->sc_if_xname, "reject",
7273 bif->bif_ifp->if_xname);
7274 }
7275 }
7276 } else if (mne->mne_bif != bif) {
7277 const char *old_if = mne->mne_bif->bif_ifp->if_xname;
7278
7279 mne->mne_bif = bif;
7280 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7281 mac_nat_entry_print2(mne,
7282 sc->sc_if_xname, "replaced",
7283 old_if);
7284 }
7285 bcopy(eaddr, mne->mne_mac, sizeof(mne->mne_mac));
7286 }
7287 mne->mne_expire = (unsigned long)net_uptime() +
7288 sc->sc_brttimeout;
7289 } else {
7290 mne = bridge_create_mac_nat_entry(sc, bif, af, ip, eaddr);
7291 }
7292 return mne;
7293}
7294
7295static void
7296bridge_mac_nat_flush_entries_common(struct bridge_softc *sc,
7297 struct mac_nat_entry_list *list, struct bridge_iflist *bif)
7298{
7299 struct mac_nat_entry *mne;
7300 struct mac_nat_entry *tmne;
7301
7302 LIST_FOREACH_SAFE(mne, list, mne_list, tmne) {
7303 if (bif != NULL && mne->mne_bif != bif) {
7304 continue;
7305 }
7306 bridge_destroy_mac_nat_entry(sc, mne, "flushed");
7307 }
7308}
7309
7310/*
7311 * bridge_mac_nat_flush_entries:
7312 *
7313 * Flush MAC NAT entries for the specified member. Flush all entries if
7314 * the member is the one that requires MAC NAT, otherwise just flush the
7315 * ones for the specified member.
7316 */
7317static void
7318bridge_mac_nat_flush_entries(struct bridge_softc *sc, struct bridge_iflist * bif)
7319{
7320 struct bridge_iflist *flush_bif;
7321
7322 flush_bif = (bif == sc->sc_mac_nat_bif) ? NULL : bif;
7323 bridge_mac_nat_flush_entries_common(sc, &sc->sc_mne_list, flush_bif);
7324 bridge_mac_nat_flush_entries_common(sc, &sc->sc_mne_list_v6, flush_bif);
7325}
7326
7327static void
7328bridge_mac_nat_populate_entries(struct bridge_softc *sc)
7329{
7330 errno_t error;
7331 ifnet_t ifp;
7332 ifaddr_t *list;
7333 struct bridge_iflist *mac_nat_bif = sc->sc_mac_nat_bif;
7334
7335 assert(mac_nat_bif != NULL);
7336 ifp = mac_nat_bif->bif_ifp;
7337 error = ifnet_get_address_list(ifp, &list);
7338 if (error != 0) {
7339 printf("%s: ifnet_get_address_list(%s) failed %d\n",
7340 __func__, ifp->if_xname, error);
7341 return;
7342 }
7343 for (ifaddr_t *scan = list; *scan != NULL; scan++) {
7344 sa_family_t af;
7345 void *ip;
7346
7347 union {
7348 struct sockaddr sa;
7349 struct sockaddr_in sin;
7350 struct sockaddr_in6 sin6;
7351 } u;
7352 af = ifaddr_address_family(*scan);
7353 switch (af) {
7354 case AF_INET:
7355 case AF_INET6:
7356 error = ifaddr_address(*scan, &u.sa, sizeof(u));
7357 if (error != 0) {
7358 printf("%s: ifaddr_address failed %d\n",
7359 __func__, error);
7360 break;
7361 }
7362 if (af == AF_INET) {
7363 ip = (void *)&u.sin.sin_addr;
7364 } else {
7365 if (IN6_IS_ADDR_LINKLOCAL(&u.sin6.sin6_addr)) {
7366 /* remove scope ID */
7367 u.sin6.sin6_addr.s6_addr16[1] = 0;
7368 }
7369 ip = (void *)&u.sin6.sin6_addr;
7370 }
7371 bridge_create_mac_nat_entry(sc, mac_nat_bif, af, ip,
7372 (uint8_t *)IF_LLADDR(ifp));
7373 break;
7374 default:
7375 break;
7376 }
7377 }
7378 ifnet_free_address_list(list);
7379 return;
7380}
7381
7382static void
7383bridge_mac_nat_age_entries_common(struct bridge_softc *sc,
7384 struct mac_nat_entry_list *list, unsigned long now)
7385{
7386 struct mac_nat_entry *mne;
7387 struct mac_nat_entry *tmne;
7388
7389 LIST_FOREACH_SAFE(mne, list, mne_list, tmne) {
7390 if (now >= mne->mne_expire) {
7391 bridge_destroy_mac_nat_entry(sc, mne, "aged out");
7392 }
7393 }
7394}
7395
7396static void
7397bridge_mac_nat_age_entries(struct bridge_softc *sc, unsigned long now)
7398{
7399 if (sc->sc_mac_nat_bif == NULL) {
7400 return;
7401 }
7402 bridge_mac_nat_age_entries_common(sc, &sc->sc_mne_list, now);
7403 bridge_mac_nat_age_entries_common(sc, &sc->sc_mne_list_v6, now);
7404}
7405
7406static const char *
7407get_in_out_string(boolean_t is_output)
7408{
7409 return is_output ? "OUT" : "IN";
7410}
7411
7412/*
7413 * is_valid_arp_packet:
7414 * Verify that this is a valid ARP packet.
7415 *
7416 * Returns TRUE if the packet is valid, FALSE otherwise.
7417 */
7418static boolean_t
7419is_valid_arp_packet(mbuf_t *data, boolean_t is_output,
7420 struct ether_header **eh_p, struct ether_arp **ea_p)
7421{
7422 struct ether_arp *ea;
7423 struct ether_header *eh;
7424 size_t minlen = sizeof(struct ether_header) + sizeof(struct ether_arp);
7425 boolean_t is_valid = FALSE;
7426 int flags = is_output ? BR_DBGF_OUTPUT : BR_DBGF_INPUT;
7427
7428 if (mbuf_pkthdr_len(*data) < minlen) {
7429 if (IF_BRIDGE_DEBUG(flags)) {
7430 printf("%s: ARP %s short frame %lu < %lu\n",
7431 __func__,
7432 get_in_out_string(is_output),
7433 mbuf_pkthdr_len(*data), minlen);
7434 }
7435 goto done;
7436 }
7437 if (mbuf_len(*data) < minlen && mbuf_pullup(data, minlen) != 0) {
7438 if (IF_BRIDGE_DEBUG(flags)) {
7439 printf("%s: ARP %s size %lu mbuf_pullup fail\n",
7440 __func__,
7441 get_in_out_string(is_output),
7442 minlen);
7443 }
7444 *data = NULL;
7445 goto done;
7446 }
7447
7448 /* validate ARP packet */
7449 eh = mtod(*data, struct ether_header *);
7450 ea = (struct ether_arp *)(eh + 1);
7451 if (ntohs(ea->arp_hrd) != ARPHRD_ETHER) {
7452 if (IF_BRIDGE_DEBUG(flags)) {
7453 printf("%s: ARP %s htype not ethernet\n",
7454 __func__,
7455 get_in_out_string(is_output));
7456 }
7457 goto done;
7458 }
7459 if (ea->arp_hln != ETHER_ADDR_LEN) {
7460 if (IF_BRIDGE_DEBUG(flags)) {
7461 printf("%s: ARP %s hlen not ethernet\n",
7462 __func__,
7463 get_in_out_string(is_output));
7464 }
7465 goto done;
7466 }
7467 if (ntohs(ea->arp_pro) != ETHERTYPE_IP) {
7468 if (IF_BRIDGE_DEBUG(flags)) {
7469 printf("%s: ARP %s ptype not IP\n",
7470 __func__,
7471 get_in_out_string(is_output));
7472 }
7473 goto done;
7474 }
7475 if (ea->arp_pln != sizeof(struct in_addr)) {
7476 if (IF_BRIDGE_DEBUG(flags)) {
7477 printf("%s: ARP %s plen not IP\n",
7478 __func__,
7479 get_in_out_string(is_output));
7480 }
7481 goto done;
7482 }
7483 is_valid = TRUE;
7484 *ea_p = ea;
7485 *eh_p = eh;
7486done:
7487 return is_valid;
7488}
7489
7490static struct mac_nat_entry *
7491bridge_mac_nat_arp_input(struct bridge_softc *sc, mbuf_t *data)
7492{
7493 struct ether_arp *ea;
7494 struct ether_header *eh;
7495 struct mac_nat_entry *mne = NULL;
7496 u_short op;
7497 struct in_addr tpa;
7498
7499 if (!is_valid_arp_packet(data, FALSE, &eh, &ea)) {
7500 goto done;
7501 }
7502 op = ntohs(ea->arp_op);
7503 switch (op) {
7504 case ARPOP_REQUEST:
7505 case ARPOP_REPLY:
7506 /* only care about REQUEST and REPLY */
7507 break;
7508 default:
7509 goto done;
7510 }
7511
7512 /* check the target IP address for a NAT entry */
7513 bcopy(ea->arp_tpa, &tpa, sizeof(tpa));
7514 if (tpa.s_addr != 0) {
7515 mne = bridge_lookup_mac_nat_entry(sc, AF_INET, &tpa);
7516 }
7517 if (mne != NULL) {
7518 if (op == ARPOP_REPLY) {
7519 /* translate the MAC address */
7520 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7521 char mac_src[24];
7522 char mac_dst[24];
7523
7524 ether_ntop(mac_src, sizeof(mac_src),
7525 ea->arp_tha);
7526 ether_ntop(mac_dst, sizeof(mac_dst),
7527 mne->mne_mac);
7528 printf("%s %s ARP %s -> %s\n",
7529 sc->sc_if_xname,
7530 mne->mne_bif->bif_ifp->if_xname,
7531 mac_src, mac_dst);
7532 }
7533 bcopy(mne->mne_mac, ea->arp_tha, sizeof(ea->arp_tha));
7534 }
7535 } else {
7536 /* handle conflicting ARP (sender matches mne) */
7537 struct in_addr spa;
7538
7539 bcopy(ea->arp_spa, &spa, sizeof(spa));
7540 if (spa.s_addr != 0 && spa.s_addr != tpa.s_addr) {
7541 /* check the source IP for a NAT entry */
7542 mne = bridge_lookup_mac_nat_entry(sc, AF_INET, &spa);
7543 }
7544 }
7545
7546done:
7547 return mne;
7548}
7549
7550static boolean_t
7551bridge_mac_nat_arp_output(struct bridge_softc *sc,
7552 struct bridge_iflist *bif, mbuf_t *data, struct mac_nat_record *mnr)
7553{
7554 struct ether_arp *ea;
7555 struct ether_header *eh;
7556 struct in_addr ip;
7557 struct mac_nat_entry *mne = NULL;
7558 u_short op;
7559 boolean_t translate = FALSE;
7560
7561 if (!is_valid_arp_packet(data, TRUE, &eh, &ea)) {
7562 goto done;
7563 }
7564 op = ntohs(ea->arp_op);
7565 switch (op) {
7566 case ARPOP_REQUEST:
7567 case ARPOP_REPLY:
7568 /* only care about REQUEST and REPLY */
7569 break;
7570 default:
7571 goto done;
7572 }
7573
7574 bcopy(ea->arp_spa, &ip, sizeof(ip));
7575 if (ip.s_addr == 0) {
7576 goto done;
7577 }
7578 /* XXX validate IP address: no multicast/broadcast */
7579 mne = bridge_update_mac_nat_entry(sc, bif, AF_INET, &ip, ea->arp_sha);
7580 if (mnr != NULL && mne != NULL) {
7581 /* record the offset to do the replacement */
7582 translate = TRUE;
7583 mnr->mnr_arp_offset = (char *)ea->arp_sha - (char *)eh;
7584 }
7585
7586done:
7587 return translate;
7588}
7589
7590#define ETHER_IPV4_HEADER_LEN (sizeof(struct ether_header) + \
7591 + sizeof(struct ip))
7592static struct ether_header *
7593get_ether_ip_header(mbuf_t *data, boolean_t is_output)
7594{
7595 struct ether_header *eh = NULL;
7596 int flags = is_output ? BR_DBGF_OUTPUT : BR_DBGF_INPUT;
7597 size_t minlen = ETHER_IPV4_HEADER_LEN;
7598
7599 if (mbuf_pkthdr_len(*data) < minlen) {
7600 if (IF_BRIDGE_DEBUG(flags)) {
7601 printf("%s: IP %s short frame %lu < %lu\n",
7602 __func__,
7603 get_in_out_string(is_output),
7604 mbuf_pkthdr_len(*data), minlen);
7605 }
7606 goto done;
7607 }
7608 if (mbuf_len(*data) < minlen && mbuf_pullup(data, minlen) != 0) {
7609 if (IF_BRIDGE_DEBUG(flags)) {
7610 printf("%s: IP %s size %lu mbuf_pullup fail\n",
7611 __func__,
7612 get_in_out_string(is_output),
7613 minlen);
7614 }
7615 *data = NULL;
7616 goto done;
7617 }
7618 eh = mtod(*data, struct ether_header *);
7619done:
7620 return eh;
7621}
7622
7623static struct mac_nat_entry *
7624bridge_mac_nat_ip_input(struct bridge_softc *sc, mbuf_t *data)
7625{
7626 struct in_addr dst;
7627 struct ether_header *eh;
7628 struct ip *iphdr;
7629 struct mac_nat_entry *mne = NULL;
7630
7631 eh = get_ether_ip_header(data, FALSE);
7632 if (eh == NULL) {
7633 goto done;
7634 }
7635 iphdr = (struct ip *)(void *)(eh + 1);
7636 bcopy(&iphdr->ip_dst, &dst, sizeof(dst));
7637 /* XXX validate IP address */
7638 if (dst.s_addr == 0) {
7639 goto done;
7640 }
7641 mne = bridge_lookup_mac_nat_entry(sc, AF_INET, &dst);
7642done:
7643 return mne;
7644}
7645
7646static void
7647bridge_mac_nat_udp_output(struct bridge_softc *sc,
7648 struct bridge_iflist *bif, mbuf_t m,
7649 uint8_t ip_header_len, struct mac_nat_record *mnr)
7650{
7651 uint16_t dp_flags;
7652 errno_t error;
7653 size_t offset;
7654 struct udphdr udphdr;
7655
7656 /* copy the UDP header */
7657 offset = sizeof(struct ether_header) + ip_header_len;
7658 error = mbuf_copydata(m, offset, sizeof(struct udphdr), &udphdr);
7659 if (error != 0) {
7660 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7661 printf("%s: mbuf_copydata udphdr failed %d",
7662 __func__, error);
7663 }
7664 return;
7665 }
7666 if (ntohs(udphdr.uh_sport) != IPPORT_BOOTPC ||
7667 ntohs(udphdr.uh_dport) != IPPORT_BOOTPS) {
7668 /* not a BOOTP/DHCP packet */
7669 return;
7670 }
7671 /* check whether the broadcast bit is already set */
7672 offset += sizeof(struct udphdr) + offsetof(struct dhcp, dp_flags);
7673 error = mbuf_copydata(m, offset, sizeof(dp_flags), &dp_flags);
7674 if (error != 0) {
7675 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7676 printf("%s: mbuf_copydata dp_flags failed %d",
7677 __func__, error);
7678 }
7679 return;
7680 }
7681 if ((ntohs(dp_flags) & DHCP_FLAGS_BROADCAST) != 0) {
7682 /* it's already set, nothing to do */
7683 return;
7684 }
7685 /* broadcast bit needs to be set */
7686 mnr->mnr_ip_dhcp_flags = dp_flags | htons(DHCP_FLAGS_BROADCAST);
7687 mnr->mnr_ip_header_len = ip_header_len;
7688 if (udphdr.uh_sum != 0) {
7689 uint16_t delta;
7690
7691 /* adjust checksum to take modified dp_flags into account */
7692 delta = dp_flags - mnr->mnr_ip_dhcp_flags;
7693 mnr->mnr_ip_udp_csum = udphdr.uh_sum + delta;
7694 }
7695 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7696 printf("%s %s DHCP dp_flags 0x%x UDP cksum 0x%x\n",
7697 sc->sc_if_xname,
7698 bif->bif_ifp->if_xname,
7699 ntohs(mnr->mnr_ip_dhcp_flags),
7700 ntohs(mnr->mnr_ip_udp_csum));
7701 }
7702 return;
7703}
7704
7705static boolean_t
7706bridge_mac_nat_ip_output(struct bridge_softc *sc,
7707 struct bridge_iflist *bif, mbuf_t *data, struct mac_nat_record *mnr)
7708{
7709#pragma unused(mnr)
7710 struct ether_header *eh;
7711 struct in_addr ip;
7712 struct ip *iphdr;
7713 uint8_t ip_header_len;
7714 struct mac_nat_entry *mne = NULL;
7715 boolean_t translate = FALSE;
7716
7717 eh = get_ether_ip_header(data, TRUE);
7718 if (eh == NULL) {
7719 goto done;
7720 }
7721 iphdr = (struct ip *)(void *)(eh + 1);
7722 ip_header_len = IP_VHL_HL(iphdr->ip_vhl) << 2;
7723 if (ip_header_len < sizeof(ip)) {
7724 /* bogus IP header */
7725 goto done;
7726 }
7727 bcopy(&iphdr->ip_src, &ip, sizeof(ip));
7728 /* XXX validate the source address */
7729 if (ip.s_addr != 0) {
7730 mne = bridge_update_mac_nat_entry(sc, bif, AF_INET, &ip,
7731 eh->ether_shost);
7732 }
7733 if (mnr != NULL) {
7734 if (iphdr->ip_p == IPPROTO_UDP) {
7735 /* handle DHCP must broadcast */
7736 bridge_mac_nat_udp_output(sc, bif, *data,
7737 ip_header_len, mnr);
7738 }
7739 translate = TRUE;
7740 }
7741done:
7742 return translate;
7743}
7744
7745#define ETHER_IPV6_HEADER_LEN (sizeof(struct ether_header) + \
7746 + sizeof(struct ip6_hdr))
7747static struct ether_header *
7748get_ether_ipv6_header(mbuf_t *data, boolean_t is_output)
7749{
7750 struct ether_header *eh = NULL;
7751 int flags = is_output ? BR_DBGF_OUTPUT : BR_DBGF_INPUT;
7752 size_t minlen = ETHER_IPV6_HEADER_LEN;
7753
7754 if (mbuf_pkthdr_len(*data) < minlen) {
7755 if (IF_BRIDGE_DEBUG(flags)) {
7756 printf("%s: IP %s short frame %lu < %lu\n",
7757 __func__,
7758 get_in_out_string(is_output),
7759 mbuf_pkthdr_len(*data), minlen);
7760 }
7761 goto done;
7762 }
7763 if (mbuf_len(*data) < minlen && mbuf_pullup(data, minlen) != 0) {
7764 if (IF_BRIDGE_DEBUG(flags)) {
7765 printf("%s: IP %s size %lu mbuf_pullup fail\n",
7766 __func__,
7767 get_in_out_string(is_output),
7768 minlen);
7769 }
7770 *data = NULL;
7771 goto done;
7772 }
7773 eh = mtod(*data, struct ether_header *);
7774done:
7775 return eh;
7776}
7777
7778#if 0
7779static void
7780bridge_mac_nat_icmpv6_input(struct bridge_softc *sc, mbuf_t *data,
7781 struct ether_header *eh, struct ip6_hdr *hdr)
7782{
7783#pragma unused(sc)
7784#pragma unused(data)
7785#pragma unused(eh)
7786#pragma unused(hdr)
7787 return;
7788}
7789#endif
7790
7791#include <netinet/icmp6.h>
7792#include <netinet6/nd6.h>
7793
7794#define ETHER_ND_LLADDR_LEN (ETHER_ADDR_LEN + sizeof(struct nd_opt_hdr))
7795
7796static void
7797bridge_mac_nat_icmpv6_output(struct bridge_softc *sc, struct bridge_iflist *bif,
7798 mbuf_t *data, struct ether_header *eh,
7799 struct ip6_hdr *ip6h, struct in6_addr *saddrp, struct mac_nat_record *mnr)
7800{
7801 struct icmp6_hdr *icmp6;
7802 unsigned int icmp6len;
7803 int lladdrlen = 0;
7804 char *lladdr = NULL;
7805 mbuf_t m = *data;
7806 unsigned int off = sizeof(*ip6h);
7807
7808 icmp6len = m->m_pkthdr.len - sizeof(*eh) - off;
7809 if (icmp6len < sizeof(*icmp6)) {
7810 printf("%s: short packet %d < %lu\n", __func__,
7811 icmp6len, sizeof(*icmp6));
7812 return;
7813 }
7814 icmp6 = (struct icmp6_hdr *)((caddr_t)ip6h + off);
7815 switch (icmp6->icmp6_type) {
7816 case ND_NEIGHBOR_SOLICIT: {
7817 struct nd_neighbor_solicit *nd_ns;
7818 union nd_opts ndopts;
7819 boolean_t is_dad_probe;
7820 struct in6_addr taddr;
7821
7822 if (icmp6len < sizeof(*nd_ns)) {
7823 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7824 printf("%s: short nd_ns %d < %lu\n", __func__,
7825 icmp6len, sizeof(*nd_ns));
7826 }
7827 return;
7828 }
7829
7830 nd_ns = (struct nd_neighbor_solicit *)(void *)icmp6;
7831 bcopy(&nd_ns->nd_ns_target, &taddr, sizeof(taddr));
7832 if (IN6_IS_ADDR_MULTICAST(&taddr) ||
7833 IN6_IS_ADDR_UNSPECIFIED(&taddr)) {
7834 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7835 printf("%s: invalid target ignored\n", __func__);
7836 }
7837 return;
7838 }
7839 /* parse options */
7840 nd6_option_init(nd_ns + 1, icmp6len - sizeof(*nd_ns), &ndopts);
7841 if (nd6_options(&ndopts) < 0) {
7842 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7843 printf("%s: invalid ND6 NS option\n", __func__);
7844 }
7845 return;
7846 }
7847 if (ndopts.nd_opts_src_lladdr != NULL) {
7848 lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
7849 lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
7850 }
7851 is_dad_probe = IN6_IS_ADDR_UNSPECIFIED(saddrp);
7852 if (lladdr != NULL) {
7853 if (is_dad_probe) {
7854 printf("%s: bad ND6 DAD packet\n", __func__);
7855 return;
7856 }
7857 if (lladdrlen != ETHER_ND_LLADDR_LEN) {
7858 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7859 printf("%s: source lladdrlen %d != %lu\n",
7860 __func__,
7861 lladdrlen, ETHER_ND_LLADDR_LEN);
7862 }
7863 return;
7864 }
7865 mnr->mnr_ip6_lladdr_offset = (void *)lladdr -
7866 (void *)eh;
7867 mnr->mnr_ip6_icmp6_len = icmp6len;
7868 mnr->mnr_ip6_icmp6_type = icmp6->icmp6_type;
7869 mnr->mnr_ip6_header_len = off;
7870 }
7871 if (is_dad_probe) {
7872 /* node is trying use taddr, create an mne using taddr */
7873 *saddrp = taddr;
7874 }
7875 break;
7876 }
7877 case ND_NEIGHBOR_ADVERT: {
7878 struct nd_neighbor_advert *nd_na;
7879 union nd_opts ndopts;
7880 struct in6_addr taddr;
7881
7882
7883 nd_na = (struct nd_neighbor_advert *)(void *)icmp6;
7884
7885 if (icmp6len < sizeof(*nd_na)) {
7886 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7887 printf("%s: short nd_na %d < %lu\n", __func__,
7888 icmp6len, sizeof(*nd_na));
7889 }
7890 return;
7891 }
7892
7893 bcopy(&nd_na->nd_na_target, &taddr, sizeof(taddr));
7894 if (IN6_IS_ADDR_MULTICAST(&taddr) ||
7895 IN6_IS_ADDR_UNSPECIFIED(&taddr)) {
7896 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7897 printf("%s: invalid target ignored\n", __func__);
7898 }
7899 return;
7900 }
7901 /* parse options */
7902 nd6_option_init(nd_na + 1, icmp6len - sizeof(*nd_na), &ndopts);
7903 if (nd6_options(&ndopts) < 0) {
7904 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7905 printf("%s: invalid ND6 NA option\n", __func__);
7906 }
7907 return;
7908 }
7909 if (ndopts.nd_opts_tgt_lladdr == NULL) {
7910 /* target linklayer, nothing to do */
7911 return;
7912 }
7913 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
7914 lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
7915 if (lladdrlen != ETHER_ND_LLADDR_LEN) {
7916 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7917 printf("%s: target lladdrlen %d != %lu\n",
7918 __func__, lladdrlen, ETHER_ND_LLADDR_LEN);
7919 }
7920 return;
7921 }
7922 mnr->mnr_ip6_lladdr_offset = (void *)lladdr - (void *)eh;
7923 mnr->mnr_ip6_icmp6_len = icmp6len;
7924 mnr->mnr_ip6_header_len = off;
7925 mnr->mnr_ip6_icmp6_type = icmp6->icmp6_type;
7926 break;
7927 }
7928 case ND_ROUTER_SOLICIT: {
7929 struct nd_router_solicit *nd_rs;
7930 union nd_opts ndopts;
7931
7932 if (icmp6len < sizeof(*nd_rs)) {
7933 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7934 printf("%s: short nd_rs %d < %lu\n", __func__,
7935 icmp6len, sizeof(*nd_rs));
7936 }
7937 return;
7938 }
7939 nd_rs = (struct nd_router_solicit *)(void *)icmp6;
7940
7941 /* parse options */
7942 nd6_option_init(nd_rs + 1, icmp6len - sizeof(*nd_rs), &ndopts);
7943 if (nd6_options(&ndopts) < 0) {
7944 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7945 printf("%s: invalid ND6 RS option\n", __func__);
7946 }
7947 return;
7948 }
7949 if (ndopts.nd_opts_src_lladdr != NULL) {
7950 lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
7951 lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
7952 }
7953 if (lladdr != NULL) {
7954 if (lladdrlen != ETHER_ND_LLADDR_LEN) {
7955 if (IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7956 printf("%s: source lladdrlen %d != %lu\n",
7957 __func__,
7958 lladdrlen, ETHER_ND_LLADDR_LEN);
7959 }
7960 return;
7961 }
7962 mnr->mnr_ip6_lladdr_offset = (void *)lladdr -
7963 (void *)eh;
7964 mnr->mnr_ip6_icmp6_len = icmp6len;
7965 mnr->mnr_ip6_icmp6_type = icmp6->icmp6_type;
7966 mnr->mnr_ip6_header_len = off;
7967 }
7968 break;
7969 }
7970 default:
7971 break;
7972 }
7973 if (mnr->mnr_ip6_lladdr_offset != 0 &&
7974 IF_BRIDGE_DEBUG(BR_DBGF_MAC_NAT)) {
7975 const char *str;
7976
7977 switch (mnr->mnr_ip6_icmp6_type) {
7978 case ND_ROUTER_SOLICIT:
7979 str = "ROUTER SOLICIT";
7980 break;
7981 case ND_NEIGHBOR_ADVERT:
7982 str = "NEIGHBOR ADVERT";
7983 break;
7984 case ND_NEIGHBOR_SOLICIT:
7985 str = "NEIGHBOR SOLICIT";
7986 break;
7987 default:
7988 str = "";
7989 break;
7990 }
7991 printf("%s %s %s ip6len %d icmp6len %d lladdr offset %d\n",
7992 sc->sc_if_xname, bif->bif_ifp->if_xname, str,
7993 mnr->mnr_ip6_header_len,
7994 mnr->mnr_ip6_icmp6_len, mnr->mnr_ip6_lladdr_offset);
7995 }
7996}
7997
7998static struct mac_nat_entry *
7999bridge_mac_nat_ipv6_input(struct bridge_softc *sc, mbuf_t *data)
8000{
8001 struct in6_addr dst;
8002 struct ether_header *eh;
8003 struct ip6_hdr *ip6h;
8004 struct mac_nat_entry *mne = NULL;
8005
8006 eh = get_ether_ipv6_header(data, FALSE);
8007 if (eh == NULL) {
8008 goto done;
8009 }
8010 ip6h = (struct ip6_hdr *)(void *)(eh + 1);
8011#if 0
8012 if (ip6h->ip6_nxt == IPPROTO_ICMPV6) {
8013 bridge_mac_nat_icmpv6_input(sc, data, eh, ip6h);
8014 }
8015#endif
8016 bcopy(&ip6h->ip6_dst, &dst, sizeof(dst));
8017 /* XXX validate IPv6 address */
8018 if (IN6_IS_ADDR_UNSPECIFIED(&dst)) {
8019 goto done;
8020 }
8021 mne = bridge_lookup_mac_nat_entry(sc, AF_INET6, &dst);
8022
8023done:
8024 return mne;
8025}
8026
8027static boolean_t
8028bridge_mac_nat_ipv6_output(struct bridge_softc *sc,
8029 struct bridge_iflist *bif, mbuf_t *data, struct mac_nat_record *mnr)
8030{
8031 struct ether_header *eh;
8032 struct ip6_hdr *ip6h;
8033 struct in6_addr saddr;
8034 boolean_t translate;
8035
8036 translate = (bif == sc->sc_mac_nat_bif) ? FALSE : TRUE;
8037 eh = get_ether_ipv6_header(data, TRUE);
8038 if (eh == NULL) {
8039 translate = FALSE;
8040 goto done;
8041 }
8042 ip6h = (struct ip6_hdr *)(void *)(eh + 1);
8043 bcopy(&ip6h->ip6_src, &saddr, sizeof(saddr));
8044 if (mnr != NULL && ip6h->ip6_nxt == IPPROTO_ICMPV6) {
8045 bridge_mac_nat_icmpv6_output(sc, bif, data,
8046 eh, ip6h, &saddr, mnr);
8047 }
8048 if (IN6_IS_ADDR_UNSPECIFIED(&saddr)) {
8049 goto done;
8050 }
8051 (void)bridge_update_mac_nat_entry(sc, bif, AF_INET6, &saddr,
8052 eh->ether_shost);
8053
8054done:
8055 return translate;
8056}
8057
8058/*
8059 * bridge_mac_nat_input:
8060 * Process a packet arriving on the MAC NAT interface (sc_mac_nat_bif).
8061 * This interface is the "external" interface with respect to NAT.
8062 * The interface is only capable of receiving a single MAC address
8063 * (e.g. a Wi-Fi STA interface).
8064 *
8065 * When a packet arrives on the external interface, look up the destination
8066 * IP address in the mac_nat_entry table. If there is a match, *is_input
8067 * is set to TRUE if it's for the MAC NAT interface, otherwise *is_input
8068 * is set to FALSE and translate the MAC address if necessary.
8069 *
8070 * Returns:
8071 * The internal interface to direct the packet to, or NULL if the packet
8072 * should not be redirected.
8073 *
8074 * *data may be updated to point at a different mbuf chain, or set to NULL
8075 * if the chain was deallocated during processing.
8076 */
8077static ifnet_t
8078bridge_mac_nat_input(struct bridge_softc *sc, mbuf_t *data,
8079 boolean_t *is_input)
8080{
8081 ifnet_t dst_if = NULL;
8082 struct ether_header *eh;
8083 uint16_t ether_type;
8084 boolean_t is_unicast;
8085 mbuf_t m = *data;
8086 struct mac_nat_entry *mne = NULL;
8087
8088 BRIDGE_LOCK_ASSERT_HELD(sc);
8089 *is_input = FALSE;
8090 assert(sc->sc_mac_nat_bif != NULL);
8091 is_unicast = ((m->m_flags & (M_BCAST | M_MCAST)) == 0);
8092 eh = mtod(m, struct ether_header *);
8093 ether_type = ntohs(eh->ether_type);
8094 switch (ether_type) {
8095 case ETHERTYPE_ARP:
8096 mne = bridge_mac_nat_arp_input(sc, data);
8097 break;
8098 case ETHERTYPE_IP:
8099 if (is_unicast) {
8100 mne = bridge_mac_nat_ip_input(sc, data);
8101 }
8102 break;
8103 case ETHERTYPE_IPV6:
8104 if (is_unicast) {
8105 mne = bridge_mac_nat_ipv6_input(sc, data);
8106 }
8107 break;
8108 default:
8109 break;
8110 }
8111 if (mne != NULL) {
8112 if (is_unicast) {
8113 if (m != *data) {
8114 /* it may have changed */
8115 eh = mtod(*data, struct ether_header *);
8116 }
8117 bcopy(mne->mne_mac, eh->ether_dhost,
8118 sizeof(eh->ether_dhost));
8119 }
8120 dst_if = mne->mne_bif->bif_ifp;
8121 *is_input = (mne->mne_bif == sc->sc_mac_nat_bif);
8122 }
8123 return dst_if;
8124}
8125
8126/*
8127 * bridge_mac_nat_output:
8128 * Process a packet destined to the MAC NAT interface (sc_mac_nat_bif)
8129 * from the interface 'bif'.
8130 *
8131 * Create a mac_nat_entry containing the source IP address and MAC address
8132 * from the packet. Populate a mac_nat_record with information detailing
8133 * how to translate the packet. Translation takes place later when
8134 * the bridge lock is no longer held.
8135 *
8136 * If 'bif' == sc_mac_nat_bif, the stack over the MAC NAT
8137 * interface is generating an output packet. No translation is required in this
8138 * case, we just record the IP address used to prevent another bif from
8139 * claiming our IP address.
8140 *
8141 * Returns:
8142 * TRUE if the packet should be translated (*mnr updated as well),
8143 * FALSE otherwise.
8144 *
8145 * *data may be updated to point at a different mbuf chain or NULL if
8146 * the chain was deallocated during processing.
8147 */
8148
8149static boolean_t
8150bridge_mac_nat_output(struct bridge_softc *sc,
8151 struct bridge_iflist *bif, mbuf_t *data, struct mac_nat_record *mnr)
8152{
8153 struct ether_header *eh;
8154 uint16_t ether_type;
8155 boolean_t translate = FALSE;
8156
8157 BRIDGE_LOCK_ASSERT_HELD(sc);
8158 assert(sc->sc_mac_nat_bif != NULL);
8159
8160 eh = mtod(*data, struct ether_header *);
8161 ether_type = ntohs(eh->ether_type);
8162 if (mnr != NULL) {
8163 bzero(mnr, sizeof(*mnr));
8164 mnr->mnr_ether_type = ether_type;
8165 }
8166 switch (ether_type) {
8167 case ETHERTYPE_ARP:
8168 translate = bridge_mac_nat_arp_output(sc, bif, data, mnr);
8169 break;
8170 case ETHERTYPE_IP:
8171 translate = bridge_mac_nat_ip_output(sc, bif, data, mnr);
8172 break;
8173 case ETHERTYPE_IPV6:
8174 translate = bridge_mac_nat_ipv6_output(sc, bif, data, mnr);
8175 break;
8176 default:
8177 break;
8178 }
8179 return translate;
8180}
8181
8182static void
8183bridge_mac_nat_arp_translate(mbuf_t *data, struct mac_nat_record *mnr,
8184 const caddr_t eaddr)
8185{
8186 errno_t error;
8187
8188 if (mnr->mnr_arp_offset == 0) {
8189 return;
8190 }
8191 /* replace the source hardware address */
8192 error = mbuf_copyback(*data, mnr->mnr_arp_offset,
8193 ETHER_ADDR_LEN, eaddr,
8194 MBUF_DONTWAIT);
8195 if (error != 0) {
8196 printf("%s: mbuf_copyback failed\n",
8197 __func__);
8198 m_freem(*data);
8199 *data = NULL;
8200 }
8201 return;
8202}
8203
8204static void
8205bridge_mac_nat_ip_translate(mbuf_t *data, struct mac_nat_record *mnr)
8206{
8207 errno_t error;
8208 size_t offset;
8209
8210 if (mnr->mnr_ip_header_len == 0) {
8211 return;
8212 }
8213 /* update the UDP checksum */
8214 offset = sizeof(struct ether_header) + mnr->mnr_ip_header_len;
8215 error = mbuf_copyback(*data, offset + offsetof(struct udphdr, uh_sum),
8216 sizeof(mnr->mnr_ip_udp_csum),
8217 &mnr->mnr_ip_udp_csum,
8218 MBUF_DONTWAIT);
8219 if (error != 0) {
8220 printf("%s: mbuf_copyback uh_sum failed\n",
8221 __func__);
8222 m_freem(*data);
8223 *data = NULL;
8224 }
8225 /* update the DHCP must broadcast flag */
8226 offset += sizeof(struct udphdr);
8227 error = mbuf_copyback(*data, offset + offsetof(struct dhcp, dp_flags),
8228 sizeof(mnr->mnr_ip_dhcp_flags),
8229 &mnr->mnr_ip_dhcp_flags,
8230 MBUF_DONTWAIT);
8231 if (error != 0) {
8232 printf("%s: mbuf_copyback dp_flags failed\n",
8233 __func__);
8234 m_freem(*data);
8235 *data = NULL;
8236 }
8237}
8238
8239static void
8240bridge_mac_nat_ipv6_translate(mbuf_t *data, struct mac_nat_record *mnr,
8241 const caddr_t eaddr)
8242{
8243 uint16_t cksum;
8244 errno_t error;
8245 mbuf_t m = *data;
8246
8247 if (mnr->mnr_ip6_header_len == 0) {
8248 return;
8249 }
8250 switch (mnr->mnr_ip6_icmp6_type) {
8251 case ND_ROUTER_SOLICIT:
8252 case ND_NEIGHBOR_SOLICIT:
8253 case ND_NEIGHBOR_ADVERT:
8254 if (mnr->mnr_ip6_lladdr_offset == 0) {
8255 /* nothing to do */
8256 return;
8257 }
8258 break;
8259 default:
8260 return;
8261 }
8262
8263 /*
8264 * replace the lladdr
8265 */
8266 error = mbuf_copyback(m, mnr->mnr_ip6_lladdr_offset,
8267 ETHER_ADDR_LEN, eaddr,
8268 MBUF_DONTWAIT);
8269 if (error != 0) {
8270 printf("%s: mbuf_copyback lladdr failed\n",
8271 __func__);
8272 m_freem(m);
8273 *data = NULL;
8274 return;
8275 }
8276
8277 /*
8278 * recompute the icmp6 checksum
8279 */
8280
8281 /* skip past the ethernet header */
8282 mbuf_setdata(m, (char *)mbuf_data(m) + ETHER_HDR_LEN,
8283 mbuf_len(m) - ETHER_HDR_LEN);
8284 mbuf_pkthdr_adjustlen(m, -ETHER_HDR_LEN);
8285
8286#define CKSUM_OFFSET_ICMP6 offsetof(struct icmp6_hdr, icmp6_cksum)
8287 /* set the checksum to zero */
8288 cksum = 0;
8289 error = mbuf_copyback(m, mnr->mnr_ip6_header_len + CKSUM_OFFSET_ICMP6,
8290 sizeof(cksum), &cksum, MBUF_DONTWAIT);
8291 if (error != 0) {
8292 printf("%s: mbuf_copyback cksum=0 failed\n",
8293 __func__);
8294 m_freem(m);
8295 *data = NULL;
8296 return;
8297 }
8298 /* compute and set the new checksum */
8299 cksum = in6_cksum(m, IPPROTO_ICMPV6, mnr->mnr_ip6_header_len,
8300 mnr->mnr_ip6_icmp6_len);
8301 error = mbuf_copyback(m, mnr->mnr_ip6_header_len + CKSUM_OFFSET_ICMP6,
8302 sizeof(cksum), &cksum, MBUF_DONTWAIT);
8303 if (error != 0) {
8304 printf("%s: mbuf_copyback cksum failed\n",
8305 __func__);
8306 m_freem(m);
8307 *data = NULL;
8308 return;
8309 }
8310 /* restore the ethernet header */
8311 mbuf_setdata(m, (char *)mbuf_data(m) - ETHER_HDR_LEN,
8312 mbuf_len(m) + ETHER_HDR_LEN);
8313 mbuf_pkthdr_adjustlen(m, ETHER_HDR_LEN);
8314 return;
8315}
8316
8317static void
8318bridge_mac_nat_translate(mbuf_t *data, struct mac_nat_record *mnr,
8319 const caddr_t eaddr)
8320{
8321 struct ether_header *eh;
8322
8323 /* replace the source ethernet address with the single MAC */
8324 eh = mtod(*data, struct ether_header *);
8325 bcopy(eaddr, eh->ether_shost, sizeof(eh->ether_shost));
8326 switch (mnr->mnr_ether_type) {
8327 case ETHERTYPE_ARP:
8328 bridge_mac_nat_arp_translate(data, mnr, eaddr);
8329 break;
8330
8331 case ETHERTYPE_IP:
8332 bridge_mac_nat_ip_translate(data, mnr);
8333 break;
8334
8335 case ETHERTYPE_IPV6:
8336 bridge_mac_nat_ipv6_translate(data, mnr, eaddr);
8337 break;
8338
8339 default:
8340 break;
8341 }
8342 return;
8343}
8344
8345/*
8346 * bridge packet filtering
8347 */
8348
8349/*
8350 * the PF routines expect to be called from ip_input, so we
8351 * need to do and undo here some of the same processing.
8352 *
8353 * XXX : this is heavily inspired on bridge_pfil()
8354 */
8355static
8356int
8357bridge_pf(struct mbuf **mp, struct ifnet *ifp, uint32_t sc_filter_flags, int input)
8358{
8359 /*
8360 * XXX : mpetit : heavily inspired by bridge_pfil()
8361 */
8362
8363 int snap, error, i, hlen;
8364 struct ether_header *eh1, eh2;
8365 struct ip *ip;
8366 struct llc llc1;
8367 u_int16_t ether_type;
8368
8369 snap = 0;
8370 error = -1; /* Default error if not error == 0 */
8371
8372 if ((sc_filter_flags & IFBF_FILT_MEMBER) == 0) {
8373 return 0; /* filtering is disabled */
8374 }
8375 i = min((*mp)->m_pkthdr.len, max_protohdr);
8376 if ((*mp)->m_len < i) {
8377 *mp = m_pullup(*mp, i);
8378 if (*mp == NULL) {
8379 printf("%s: m_pullup failed\n", __func__);
8380 return -1;
8381 }
8382 }
8383
8384 eh1 = mtod(*mp, struct ether_header *);
8385 ether_type = ntohs(eh1->ether_type);
8386
8387 /*
8388 * Check for SNAP/LLC.
8389 */
8390 if (ether_type < ETHERMTU) {
8391 struct llc *llc2 = (struct llc *)(eh1 + 1);
8392
8393 if ((*mp)->m_len >= ETHER_HDR_LEN + 8 &&
8394 llc2->llc_dsap == LLC_SNAP_LSAP &&
8395 llc2->llc_ssap == LLC_SNAP_LSAP &&
8396 llc2->llc_control == LLC_UI) {
8397 ether_type = htons(llc2->llc_un.type_snap.ether_type);
8398 snap = 1;
8399 }
8400 }
8401
8402 /*
8403 * If we're trying to filter bridge traffic, don't look at anything
8404 * other than IP and ARP traffic. If the filter doesn't understand
8405 * IPv6, don't allow IPv6 through the bridge either. This is lame
8406 * since if we really wanted, say, an AppleTalk filter, we are hosed,
8407 * but of course we don't have an AppleTalk filter to begin with.
8408 * (Note that since pfil doesn't understand ARP it will pass *ALL*
8409 * ARP traffic.)
8410 */
8411 switch (ether_type) {
8412 case ETHERTYPE_ARP:
8413 case ETHERTYPE_REVARP:
8414 return 0; /* Automatically pass */
8415
8416 case ETHERTYPE_IP:
8417 case ETHERTYPE_IPV6:
8418 break;
8419 default:
8420 /*
8421 * Check to see if the user wants to pass non-ip
8422 * packets, these will not be checked by pf and
8423 * passed unconditionally so the default is to drop.
8424 */
8425 if ((sc_filter_flags & IFBF_FILT_ONLYIP)) {
8426 goto bad;
8427 }
8428 break;
8429 }
8430
8431 /* Strip off the Ethernet header and keep a copy. */
8432 m_copydata(*mp, 0, ETHER_HDR_LEN, (caddr_t)&eh2);
8433 m_adj(*mp, ETHER_HDR_LEN);
8434
8435 /* Strip off snap header, if present */
8436 if (snap) {
8437 m_copydata(*mp, 0, sizeof(struct llc), (caddr_t)&llc1);
8438 m_adj(*mp, sizeof(struct llc));
8439 }
8440
8441 /*
8442 * Check the IP header for alignment and errors
8443 */
8444 switch (ether_type) {
8445 case ETHERTYPE_IP:
8446 error = bridge_ip_checkbasic(mp);
8447 break;
8448 case ETHERTYPE_IPV6:
8449 error = bridge_ip6_checkbasic(mp);
8450 break;
8451 default:
8452 error = 0;
8453 break;
8454 }
8455 if (error) {
8456 goto bad;
8457 }
8458
8459 error = 0;
8460
8461 /*
8462 * Run the packet through pf rules
8463 */
8464 switch (ether_type) {
8465 case ETHERTYPE_IP:
8466 /*
8467 * before calling the firewall, swap fields the same as
8468 * IP does. here we assume the header is contiguous
8469 */
8470 ip = mtod(*mp, struct ip *);
8471
8472 ip->ip_len = ntohs(ip->ip_len);
8473 ip->ip_off = ntohs(ip->ip_off);
8474
8475 if (ifp != NULL) {
8476 error = pf_af_hook(ifp, 0, mp, AF_INET, input, NULL);
8477 }
8478
8479 if (*mp == NULL || error != 0) { /* filter may consume */
8480 break;
8481 }
8482
8483 /* Recalculate the ip checksum and restore byte ordering */
8484 ip = mtod(*mp, struct ip *);
8485 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
8486 if (hlen < (int)sizeof(struct ip)) {
8487 goto bad;
8488 }
8489 if (hlen > (*mp)->m_len) {
8490 if ((*mp = m_pullup(*mp, hlen)) == 0) {
8491 goto bad;
8492 }
8493 ip = mtod(*mp, struct ip *);
8494 if (ip == NULL) {
8495 goto bad;
8496 }
8497 }
8498 ip->ip_len = htons(ip->ip_len);
8499 ip->ip_off = htons(ip->ip_off);
8500 ip->ip_sum = 0;
8501 if (hlen == sizeof(struct ip)) {
8502 ip->ip_sum = in_cksum_hdr(ip);
8503 } else {
8504 ip->ip_sum = in_cksum(*mp, hlen);
8505 }
8506 break;
8507
8508 case ETHERTYPE_IPV6:
8509 if (ifp != NULL) {
8510 error = pf_af_hook(ifp, 0, mp, AF_INET6, input, NULL);
8511 }
8512
8513 if (*mp == NULL || error != 0) { /* filter may consume */
8514 break;
8515 }
8516 break;
8517 default:
8518 error = 0;
8519 break;
8520 }
8521
8522 if (*mp == NULL) {
8523 return error;
8524 }
8525 if (error != 0) {
8526 goto bad;
8527 }
8528
8529 error = -1;
8530
8531 /*
8532 * Finally, put everything back the way it was and return
8533 */
8534 if (snap) {
8535 M_PREPEND(*mp, sizeof(struct llc), M_DONTWAIT, 0);
8536 if (*mp == NULL) {
8537 return error;
8538 }
8539 bcopy(&llc1, mtod(*mp, caddr_t), sizeof(struct llc));
8540 }
8541
8542 M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT, 0);
8543 if (*mp == NULL) {
8544 return error;
8545 }
8546 bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN);
8547
8548 return 0;
8549
8550bad:
8551 m_freem(*mp);
8552 *mp = NULL;
8553 return error;
8554}