<
1/*
2 * Copyright (c) 2004-2024 Apple Inc. All rights reserved.
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
29/* $NetBSD: if_bridge.c,v 1.31 2005/06/01 19:45:34 jdc Exp $ */
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).
102 *
103 * - GIF isn't handled due to the lack of IPPROTO_ETHERIP support.
104 */
105
106#include <sys/cdefs.h>
107
108#include <sys/param.h>
109#include <sys/mbuf.h>
110#include <sys/malloc.h>
111#include <sys/protosw.h>
112#include <sys/systm.h>
113#include <sys/time.h>
114#include <sys/socket.h> /* for net/if.h */
115#include <sys/sockio.h>
116#include <sys/kernel.h>
117#include <sys/random.h>
118#include <sys/syslog.h>
119#include <sys/sysctl.h>
120#include <sys/proc.h>
121#include <sys/lock.h>
122#include <sys/mcache.h>
123
124#include <sys/kauth.h>
125
126#include <kern/thread_call.h>
127
128#include <libkern/libkern.h>
129
130#include <kern/zalloc.h>
131
132#if NBPFILTER > 0
133#include <net/bpf.h>
134#endif
135#include <net/if.h>
136#include <net/if_dl.h>
137#include <net/if_types.h>
138#include <net/if_var.h>
139#include <net/if_media.h>
140#include <net/net_api_stats.h>
141#include <net/pfvar.h>
142
143#include <netinet/in.h> /* for struct arpcom */
144#include <netinet/tcp.h> /* for struct tcphdr */
145#include <netinet/in_systm.h>
146#include <netinet/in_var.h>
147#define _IP_VHL
148#include <netinet/ip.h>
149#include <netinet/ip_var.h>
150#include <netinet/ip6.h>
151#include <netinet6/ip6_var.h>
152#ifdef DEV_CARP
153#include <netinet/ip_carp.h>
154#endif
155#include <netinet/if_ether.h> /* for struct arpcom */
156#include <net/bridgestp.h>
157#include <net/if_bridgevar.h>
158#include <net/if_llc.h>
159#if NVLAN > 0
160#include <net/if_vlan_var.h>
161#endif /* NVLAN > 0 */
162
163#include <net/if_ether.h>
164#include <net/dlil.h>
165#include <net/kpi_interfacefilter.h>
166
167#include <net/route.h>
168#include <dev/random/randomdev.h>
169
170#include <netinet/bootp.h>
171#include <netinet/dhcp.h>
172
173#if SKYWALK
174#include <skywalk/nexus/netif/nx_netif.h>
175#endif /* SKYWALK */
176
177#include <net/sockaddr_utils.h>
178
179#include <os/log.h>
180
181/*
182 * if_bridge_debug, BR_DBGF_*
183 * - 'if_bridge_debug' is a bitmask of BR_DBGF_* flags that can be set
184 * to enable additional logs for the corresponding bridge function
185 * - "sysctl net.link.bridge.debug" controls the value of
186 * 'if_bridge_debug'
187 */
188static uint32_t if_bridge_debug = 0;
189#define BR_DBGF_LIFECYCLE 0x0001
190#define BR_DBGF_INPUT 0x0002
191#define BR_DBGF_OUTPUT 0x0004
192#define BR_DBGF_RT_TABLE 0x0008
193#define BR_DBGF_DELAYED_CALL 0x0010
194#define BR_DBGF_IOCTL 0x0020
195#define BR_DBGF_MBUF 0x0040
196#define BR_DBGF_MCAST 0x0080
197#define BR_DBGF_HOSTFILTER 0x0100
198#define BR_DBGF_CHECKSUM 0x0200
199#define BR_DBGF_MAC_NAT 0x0400
200
201/*
202 * if_bridge_log_level
203 * - 'if_bridge_log_level' ensures that by default important logs are
204 * logged regardless of if_bridge_debug by comparing the log level
205 * in BRIDGE_LOG to if_bridge_log_level
206 * - use "sysctl net.link.bridge.log_level" controls the value of
207 * 'if_bridge_log_level'
208 * - the default value of 'if_bridge_log_level' is LOG_NOTICE; important
209 * logs must use LOG_NOTICE to ensure they appear by default
210 */
211static int if_bridge_log_level = LOG_NOTICE;
212
213#define BRIDGE_DBGF_ENABLED(__flag) ((if_bridge_debug & __flag) != 0)
214
215/*
216 * BRIDGE_LOG, BRIDGE_LOG_SIMPLE
217 * - macros to generate the specified log conditionally based on
218 * the specified log level and debug flags
219 * - BRIDGE_LOG_SIMPLE does not include the function name in the log
220 */
221#define BRIDGE_LOG(__level, __dbgf, __string, ...) \
222 do { \
223 if (__level <= if_bridge_log_level || \
224 BRIDGE_DBGF_ENABLED(__dbgf)) { \
225 os_log(OS_LOG_DEFAULT, "%s: " __string, \
226 __func__, ## __VA_ARGS__); \
227 } \
228 } while (0)
229#define BRIDGE_LOG_SIMPLE(__level, __dbgf, __string, ...) \
230 do { \
231 if (__level <= if_bridge_log_level || \
232 BRIDGE_DBGF_ENABLED(__dbgf)) { \
233 os_log(OS_LOG_DEFAULT, __string, ## __VA_ARGS__); \
234 } \
235 } while (0)
236
237#define _BRIDGE_LOCK(_sc) lck_mtx_lock(&(_sc)->sc_mtx)
238#define _BRIDGE_UNLOCK(_sc) lck_mtx_unlock(&(_sc)->sc_mtx)
239#define BRIDGE_LOCK_ASSERT_HELD(_sc) \
240 LCK_MTX_ASSERT(&(_sc)->sc_mtx, LCK_MTX_ASSERT_OWNED)
241#define BRIDGE_LOCK_ASSERT_NOTHELD(_sc) \
242 LCK_MTX_ASSERT(&(_sc)->sc_mtx, LCK_MTX_ASSERT_NOTOWNED)
243
244#define BRIDGE_LOCK_DEBUG 1
245#if BRIDGE_LOCK_DEBUG
246
247#define BR_LCKDBG_MAX 4
248
249#define BRIDGE_LOCK(_sc) bridge_lock(_sc)
250#define BRIDGE_UNLOCK(_sc) bridge_unlock(_sc)
251#define BRIDGE_LOCK2REF(_sc, _err) _err = bridge_lock2ref(_sc)
252#define BRIDGE_UNREF(_sc) bridge_unref(_sc)
253#define BRIDGE_XLOCK(_sc) bridge_xlock(_sc)
254#define BRIDGE_XDROP(_sc) bridge_xdrop(_sc)
255
256#else /* !BRIDGE_LOCK_DEBUG */
257
258#define BRIDGE_LOCK(_sc) _BRIDGE_LOCK(_sc)
259#define BRIDGE_UNLOCK(_sc) _BRIDGE_UNLOCK(_sc)
260#define BRIDGE_LOCK2REF(_sc, _err) do { \
261 BRIDGE_LOCK_ASSERT_HELD(_sc); \
262 if ((_sc)->sc_iflist_xcnt > 0) \
263 (_err) = EBUSY; \
264 else { \
265 (_sc)->sc_iflist_ref++; \
266 (_err) = 0; \
267 } \
268 _BRIDGE_UNLOCK(_sc); \
269} while (0)
270#define BRIDGE_UNREF(_sc) do { \
271 _BRIDGE_LOCK(_sc); \
272 (_sc)->sc_iflist_ref--; \
273 if (((_sc)->sc_iflist_xcnt > 0) && ((_sc)->sc_iflist_ref == 0)) { \
274 _BRIDGE_UNLOCK(_sc); \
275 wakeup(&(_sc)->sc_cv); \
276 } else \
277 _BRIDGE_UNLOCK(_sc); \
278} while (0)
279#define BRIDGE_XLOCK(_sc) do { \
280 BRIDGE_LOCK_ASSERT_HELD(_sc); \
281 (_sc)->sc_iflist_xcnt++; \
282 while ((_sc)->sc_iflist_ref > 0) \
283 msleep(&(_sc)->sc_cv, &(_sc)->sc_mtx, PZERO, \
284 "BRIDGE_XLOCK", NULL); \
285} while (0)
286#define BRIDGE_XDROP(_sc) do { \
287 BRIDGE_LOCK_ASSERT_HELD(_sc); \
288 (_sc)->sc_iflist_xcnt--; \
289} while (0)
290
291#endif /* BRIDGE_LOCK_DEBUG */
292
293#if NBPFILTER > 0
294#define BRIDGE_BPF_MTAP_INPUT(sc, m) \
295 if (sc->sc_bpf_input != NULL) \
296 bridge_bpf_input(sc->sc_ifp, m, __func__, __LINE__)
297#else /* NBPFILTER */
298#define BRIDGE_BPF_MTAP_INPUT(ifp, m)
299#endif /* NBPFILTER */
300
301/*
302 * Initial size of the route hash table. Must be a power of two.
303 */
304#ifndef BRIDGE_RTHASH_SIZE
305#define BRIDGE_RTHASH_SIZE 16
306#endif
307
308/*
309 * Maximum size of the routing hash table
310 */
311#define BRIDGE_RTHASH_SIZE_MAX 2048
312
313#define BRIDGE_RTHASH_MASK(sc) ((sc)->sc_rthash_size - 1)
314
315/*
316 * Maximum number of addresses to cache.
317 */
318#ifndef BRIDGE_RTABLE_MAX
319#define BRIDGE_RTABLE_MAX 100
320#endif
321
322
323/*
324 * Timeout (in seconds) for entries learned dynamically.
325 */
326#ifndef BRIDGE_RTABLE_TIMEOUT
327#define BRIDGE_RTABLE_TIMEOUT (20 * 60) /* same as ARP */
328#endif
329
330/*
331 * Number of seconds between walks of the route list.
332 */
333#ifndef BRIDGE_RTABLE_PRUNE_PERIOD
334#define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60)
335#endif
336
337/*
338 * Number of MAC NAT entries
339 * - sized based on 16 clients (including MAC NAT interface)
340 * each with 4 addresses
341 */
342#ifndef BRIDGE_MAC_NAT_ENTRY_MAX
343#define BRIDGE_MAC_NAT_ENTRY_MAX 64
344#endif /* BRIDGE_MAC_NAT_ENTRY_MAX */
345
346/*
347 * List of capabilities to possibly mask on the member interface.
348 */
349#define BRIDGE_IFCAPS_MASK (IFCAP_TSO | IFCAP_TXCSUM)
350/*
351 * List of capabilities to disable on the member interface.
352 */
353#define BRIDGE_IFCAPS_STRIP IFCAP_LRO
354
355/*
356 * Bridge interface list entry.
357 */
358struct bridge_iflist {
359 TAILQ_ENTRY(bridge_iflist) bif_next;
360 struct ifnet *bif_ifp; /* member if */
361 struct bstp_port bif_stp; /* STP state */
362 uint32_t bif_ifflags; /* member if flags */
363 int bif_savedcaps; /* saved capabilities */
364 uint32_t bif_addrmax; /* max # of addresses */
365 uint32_t bif_addrcnt; /* cur. # of addresses */
366 uint32_t bif_addrexceeded; /* # of address violations */
367
368 interface_filter_t bif_iff_ref;
369 struct bridge_softc *bif_sc;
370 uint32_t bif_flags;
371
372 /* host filter */
373 struct in_addr bif_hf_ipsrc;
374 uint8_t bif_hf_hwsrc[ETHER_ADDR_LEN];
375
376 struct ifbrmstats bif_stats;
377};
378
379static inline bool
380bif_ifflags_are_set(struct bridge_iflist * bif, uint32_t flags)
381{
382 return (bif->bif_ifflags & flags) == flags;
383}
384
385static inline bool
386bif_has_checksum_offload(struct bridge_iflist * bif)
387{
388 return bif_ifflags_are_set(bif, IFBIF_CHECKSUM_OFFLOAD);
389}
390
391/* fake errors to make the code clearer */
392#define _EBADIP EJUSTRETURN
393#define _EBADIPCHECKSUM EJUSTRETURN
394#define _EBADIPV6 EJUSTRETURN
395#define _EBADUDP EJUSTRETURN
396#define _EBADTCP EJUSTRETURN
397#define _EBADUDPCHECKSUM EJUSTRETURN
398#define _EBADTCPCHECKSUM EJUSTRETURN
399
400#define BIFF_PROMISC 0x01 /* promiscuous mode set */
401#define BIFF_PROTO_ATTACHED 0x02 /* protocol attached */
402#define BIFF_FILTER_ATTACHED 0x04 /* interface filter attached */
403#define BIFF_MEDIA_ACTIVE 0x08 /* interface media active */
404#define BIFF_HOST_FILTER 0x10 /* host filter enabled */
405#define BIFF_HF_HWSRC 0x20 /* host filter source MAC is set */
406#define BIFF_HF_IPSRC 0x40 /* host filter source IP is set */
407#define BIFF_INPUT_BROADCAST 0x80 /* send broadcast packets in */
408#define BIFF_IN_MEMBER_LIST 0x100 /* added to the member list */
409#define BIFF_WIFI_INFRA 0x200 /* interface is Wi-Fi infra */
410#define BIFF_ALL_MULTI 0x400 /* allmulti set */
411#define BIFF_LRO_DISABLED 0x800 /* LRO was disabled */
412#if SKYWALK
413#define BIFF_FLOWSWITCH_ATTACHED 0x1000 /* we attached the flowswitch */
414#define BIFF_NETAGENT_REMOVED 0x2000 /* we removed the netagent */
415#endif /* SKYWALK */
416
417/*
418 * mac_nat_entry
419 * - translates between an IP address and MAC address on a specific
420 * bridge interface member
421 */
422struct mac_nat_entry {
423 LIST_ENTRY(mac_nat_entry) mne_list; /* list linkage */
424 struct bridge_iflist *mne_bif; /* originating interface */
425 unsigned long mne_expire; /* expiration time */
426 union {
427 struct in_addr mneu_ip; /* originating IPv4 address */
428 struct in6_addr mneu_ip6; /* originating IPv6 address */
429 } mne_u;
430 uint8_t mne_mac[ETHER_ADDR_LEN];
431 uint8_t mne_flags;
432 uint8_t mne_reserved;
433};
434#define mne_ip mne_u.mneu_ip
435#define mne_ip6 mne_u.mneu_ip6
436
437#define MNE_FLAGS_IPV6 0x01 /* IPv6 address */
438
439LIST_HEAD(mac_nat_entry_list, mac_nat_entry);
440
441/*
442 * mac_nat_record
443 * - used by bridge_mac_nat_output() to convey the translation that needs
444 * to take place in bridge_mac_nat_translate
445 * - holds enough information so that the translation can be done later without
446 * holding the bridge lock
447 */
448struct mac_nat_record {
449 uint16_t mnr_ether_type;
450 union {
451 uint16_t mnru_arp_offset;
452 struct {
453 uint16_t mnruip_dhcp_flags;
454 uint16_t mnruip_udp_csum;
455 uint8_t mnruip_header_len;
456 } mnru_ip;
457 struct {
458 uint16_t mnruip6_icmp6_len;
459 uint16_t mnruip6_lladdr_offset;
460 uint8_t mnruip6_icmp6_type;
461 uint8_t mnruip6_header_len;
462 } mnru_ip6;
463 } mnr_u;
464};
465
466#define mnr_arp_offset mnr_u.mnru_arp_offset
467
468#define mnr_ip_header_len mnr_u.mnru_ip.mnruip_header_len
469#define mnr_ip_dhcp_flags mnr_u.mnru_ip.mnruip_dhcp_flags
470#define mnr_ip_udp_csum mnr_u.mnru_ip.mnruip_udp_csum
471
472#define mnr_ip6_icmp6_len mnr_u.mnru_ip6.mnruip6_icmp6_len
473#define mnr_ip6_icmp6_type mnr_u.mnru_ip6.mnruip6_icmp6_type
474#define mnr_ip6_header_len mnr_u.mnru_ip6.mnruip6_header_len
475#define mnr_ip6_lladdr_offset mnr_u.mnru_ip6.mnruip6_lladdr_offset
476
477/*
478 * Bridge route node.
479 */
480struct bridge_rtnode {
481 LIST_ENTRY(bridge_rtnode) brt_hash; /* hash table linkage */
482 LIST_ENTRY(bridge_rtnode) brt_list; /* list linkage */
483 struct bridge_iflist *brt_dst; /* destination if */
484 unsigned long brt_expire; /* expiration time */
485 uint8_t brt_flags; /* address flags */
486 uint8_t brt_addr[ETHER_ADDR_LEN];
487 uint16_t brt_vlan; /* vlan id */
488
489};
490#define brt_ifp brt_dst->bif_ifp
491
492/*
493 * Bridge delayed function call context
494 */
495typedef void (*bridge_delayed_func_t)(struct bridge_softc *);
496
497struct bridge_delayed_call {
498 struct bridge_softc *bdc_sc;
499 bridge_delayed_func_t bdc_func; /* Function to call */
500 struct timespec bdc_ts; /* Time to call */
501 u_int32_t bdc_flags;
502 thread_call_t bdc_thread_call;
503};
504
505#define BDCF_OUTSTANDING 0x01 /* Delayed call has been scheduled */
506#define BDCF_CANCELLING 0x02 /* May be waiting for call completion */
507
508/*
509 * Software state for each bridge.
510 */
511LIST_HEAD(_bridge_rtnode_list, bridge_rtnode);
512
513struct bridge_softc {
514 struct ifnet *sc_ifp; /* make this an interface */
515 u_int32_t sc_flags;
516 LIST_ENTRY(bridge_softc) sc_list;
517 decl_lck_mtx_data(, sc_mtx);
518 struct _bridge_rtnode_list *sc_rthash; /* our forwarding table */
519 struct _bridge_rtnode_list sc_rtlist; /* list version of above */
520 uint32_t sc_rthash_key; /* key for hash */
521 uint32_t sc_rthash_size; /* size of the hash table */
522 struct bridge_delayed_call sc_aging_timer;
523 struct bridge_delayed_call sc_resize_call;
524 TAILQ_HEAD(, bridge_iflist) sc_spanlist; /* span ports list */
525 struct bstp_state sc_stp; /* STP state */
526 bpf_packet_func sc_bpf_input;
527 bpf_packet_func sc_bpf_output;
528 void *sc_cv;
529 uint32_t sc_brtmax; /* max # of addresses */
530 uint32_t sc_brtcnt; /* cur. # of addresses */
531 uint32_t sc_brttimeout; /* rt timeout in seconds */
532 uint32_t sc_iflist_ref; /* refcount for sc_iflist */
533 uint32_t sc_iflist_xcnt; /* refcount for sc_iflist */
534 TAILQ_HEAD(, bridge_iflist) sc_iflist; /* member interface list */
535 uint32_t sc_brtexceeded; /* # of cache drops */
536 uint32_t sc_filter_flags; /* ipf and flags */
537 struct ifnet *sc_ifaddr; /* member mac copied from */
538 u_char sc_defaddr[6]; /* Default MAC address */
539 char sc_if_xname[IFNAMSIZ];
540
541 struct bridge_iflist *sc_mac_nat_bif; /* single MAC NAT interface */
542 struct mac_nat_entry_list sc_mne_list; /* MAC NAT IPv4 */
543 struct mac_nat_entry_list sc_mne_list_v6;/* MAC NAT IPv6 */
544 uint32_t sc_mne_max; /* max # of entries */
545 uint32_t sc_mne_count; /* cur. # of entries */
546 uint32_t sc_mne_allocation_failures;
547#if BRIDGE_LOCK_DEBUG
548 /*
549 * Locking and unlocking calling history
550 */
551 void *lock_lr[BR_LCKDBG_MAX];
552 int next_lock_lr;
553 void *unlock_lr[BR_LCKDBG_MAX];
554 int next_unlock_lr;
555#endif /* BRIDGE_LOCK_DEBUG */
556};
557
558#define SCF_DETACHING 0x01
559#define SCF_RESIZING 0x02
560#define SCF_MEDIA_ACTIVE 0x04
561
562typedef enum {
563 CHECKSUM_OPERATION_NONE = 0,
564 CHECKSUM_OPERATION_CLEAR_OFFLOAD = 1,
565 CHECKSUM_OPERATION_FINALIZE = 2,
566 CHECKSUM_OPERATION_COMPUTE = 3,
567} ChecksumOperation;
568
569union iphdr {
570 struct ip *ip;
571 struct ip6_hdr *ip6;
572 void * ptr;
573};
574
575typedef struct {
576 u_int ip_hlen; /* IP header length */
577 u_int ip_pay_len; /* length of payload (exclusive of ip_hlen) */
578 u_int ip_opt_len; /* IPv6 options headers length */
579 uint8_t ip_proto; /* IPPROTO_TCP, IPPROTO_UDP, etc. */
580 bool ip_is_ipv4;
581 bool ip_is_fragmented;
582 union iphdr ip_hdr; /* pointer to IP header */
583 void * ip_proto_hdr; /* ptr to protocol header (TCP) */
584} ip_packet_info, *ip_packet_info_t;
585
586struct bridge_hostfilter_stats bridge_hostfilter_stats;
587
588static LCK_GRP_DECLARE(bridge_lock_grp, "if_bridge");
589#if BRIDGE_LOCK_DEBUG
590static LCK_ATTR_DECLARE(bridge_lock_attr, 0, 0);
591#else
592static LCK_ATTR_DECLARE(bridge_lock_attr, LCK_ATTR_DEBUG, 0);
593#endif
594static LCK_MTX_DECLARE_ATTR(bridge_list_mtx, &bridge_lock_grp, &bridge_lock_attr);
595
596static int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD;
597
598static KALLOC_TYPE_DEFINE(bridge_rtnode_pool, struct bridge_rtnode, NET_KT_DEFAULT);
599static KALLOC_TYPE_DEFINE(bridge_mne_pool, struct mac_nat_entry, NET_KT_DEFAULT);
600
601static int bridge_clone_create(struct if_clone *, uint32_t, void *);
602static int bridge_clone_destroy(struct ifnet *);
603
604static errno_t bridge_ioctl(struct ifnet *, u_long, void *);
605#if HAS_IF_CAP
606static void bridge_mutecaps(struct bridge_softc *);
607static void bridge_set_ifcap(struct bridge_softc *, struct bridge_iflist *,
608 int);
609#endif
610static errno_t bridge_set_tso(struct bridge_softc *);
611static void bridge_proto_attach_changed(struct ifnet *);
612static int bridge_init(struct ifnet *);
613#if HAS_BRIDGE_DUMMYNET
614static void bridge_dummynet(struct mbuf *, struct ifnet *);
615#endif
616static void bridge_ifstop(struct ifnet *, int);
617static int bridge_output(struct ifnet *, struct mbuf *);
618static void bridge_finalize_cksum(struct ifnet *, struct mbuf *);
619static void bridge_start(struct ifnet *);
620static errno_t bridge_input(struct ifnet *, mbuf_t *);
621static errno_t bridge_iff_input(void *, ifnet_t, protocol_family_t,
622 mbuf_t *, char **);
623static errno_t bridge_iff_output(void *, ifnet_t, protocol_family_t,
624 mbuf_t *);
625static errno_t bridge_member_output(struct bridge_softc *sc, ifnet_t ifp,
626 mbuf_t *m);
627
628static int bridge_enqueue(ifnet_t, struct ifnet *,
629 struct ifnet *, struct mbuf *, ChecksumOperation);
630static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int);
631
632static void bridge_forward(struct bridge_softc *, struct bridge_iflist *,
633 struct mbuf *);
634
635static void bridge_aging_timer(struct bridge_softc *sc);
636
637static void bridge_broadcast(struct bridge_softc *, struct bridge_iflist *,
638 struct mbuf *, int);
639static void bridge_span(struct bridge_softc *, struct mbuf *);
640
641static int bridge_rtupdate(struct bridge_softc *, const uint8_t *,
642 uint16_t, struct bridge_iflist *, int, uint8_t);
643static struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *,
644 uint16_t);
645static void bridge_rttrim(struct bridge_softc *);
646static void bridge_rtage(struct bridge_softc *);
647static void bridge_rtflush(struct bridge_softc *, int);
648static int bridge_rtdaddr(struct bridge_softc *, const uint8_t *,
649 uint16_t);
650
651static int bridge_rtable_init(struct bridge_softc *);
652static void bridge_rtable_fini(struct bridge_softc *);
653
654static void bridge_rthash_resize(struct bridge_softc *);
655
656static int bridge_rtnode_addr_cmp(const uint8_t *, const uint8_t *);
657static struct bridge_rtnode *bridge_rtnode_lookup(struct bridge_softc *,
658 const uint8_t *, uint16_t);
659static int bridge_rtnode_hash(struct bridge_softc *,
660 struct bridge_rtnode *);
661static int bridge_rtnode_insert(struct bridge_softc *,
662 struct bridge_rtnode *);
663static void bridge_rtnode_destroy(struct bridge_softc *,
664 struct bridge_rtnode *);
665#if BRIDGESTP
666static void bridge_rtable_expire(struct ifnet *, int);
667static void bridge_state_change(struct ifnet *, int);
668#endif /* BRIDGESTP */
669
670static struct bridge_iflist *bridge_lookup_member(struct bridge_softc *,
671 const char *name);
672static struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *,
673 struct ifnet *ifp);
674static void bridge_delete_member(struct bridge_softc *,
675 struct bridge_iflist *);
676static void bridge_delete_span(struct bridge_softc *,
677 struct bridge_iflist *);
678
679static int bridge_ioctl_add(struct bridge_softc *, void *);
680static int bridge_ioctl_del(struct bridge_softc *, void *);
681static int bridge_ioctl_gifflags(struct bridge_softc *, void *);
682static int bridge_ioctl_sifflags(struct bridge_softc *, void *);
683static int bridge_ioctl_scache(struct bridge_softc *, void *);
684static int bridge_ioctl_gcache(struct bridge_softc *, void *);
685static int bridge_ioctl_gifs32(struct bridge_softc *, void *);
686static int bridge_ioctl_gifs64(struct bridge_softc *, void *);
687static int bridge_ioctl_rts32(struct bridge_softc *, void *);
688static int bridge_ioctl_rts64(struct bridge_softc *, void *);
689static int bridge_ioctl_saddr32(struct bridge_softc *, void *);
690static int bridge_ioctl_saddr64(struct bridge_softc *, void *);
691static int bridge_ioctl_sto(struct bridge_softc *, void *);
692static int bridge_ioctl_gto(struct bridge_softc *, void *);
693static int bridge_ioctl_daddr32(struct bridge_softc *, void *);
694static int bridge_ioctl_daddr64(struct bridge_softc *, void *);
695static int bridge_ioctl_flush(struct bridge_softc *, void *);
696static int bridge_ioctl_gpri(struct bridge_softc *, void *);
697static int bridge_ioctl_spri(struct bridge_softc *, void *);
698static int bridge_ioctl_ght(struct bridge_softc *, void *);
699static int bridge_ioctl_sht(struct bridge_softc *, void *);
700static int bridge_ioctl_gfd(struct bridge_softc *, void *);
701static int bridge_ioctl_sfd(struct bridge_softc *, void *);
702static int bridge_ioctl_gma(struct bridge_softc *, void *);
703static int bridge_ioctl_sma(struct bridge_softc *, void *);
704static int bridge_ioctl_sifprio(struct bridge_softc *, void *);
705static int bridge_ioctl_sifcost(struct bridge_softc *, void *);
706static int bridge_ioctl_sifmaxaddr(struct bridge_softc *, void *);
707static int bridge_ioctl_addspan(struct bridge_softc *, void *);
708static int bridge_ioctl_delspan(struct bridge_softc *, void *);
709static int bridge_ioctl_gbparam32(struct bridge_softc *, void *);
710static int bridge_ioctl_gbparam64(struct bridge_softc *, void *);
711static int bridge_ioctl_grte(struct bridge_softc *, void *);
712static int bridge_ioctl_gifsstp32(struct bridge_softc *, void *);
713static int bridge_ioctl_gifsstp64(struct bridge_softc *, void *);
714static int bridge_ioctl_sproto(struct bridge_softc *, void *);
715static int bridge_ioctl_stxhc(struct bridge_softc *, void *);
716static int bridge_ioctl_purge(struct bridge_softc *sc, void *);
717static int bridge_ioctl_gfilt(struct bridge_softc *, void *);
718static int bridge_ioctl_sfilt(struct bridge_softc *, void *);
719static int bridge_ioctl_ghostfilter(struct bridge_softc *, void *);
720static int bridge_ioctl_shostfilter(struct bridge_softc *, void *);
721static int bridge_ioctl_gmnelist32(struct bridge_softc *, void *);
722static int bridge_ioctl_gmnelist64(struct bridge_softc *, void *);
723static int bridge_ioctl_gifstats32(struct bridge_softc *, void *);
724static int bridge_ioctl_gifstats64(struct bridge_softc *, void *);
725
726static int bridge_pf(struct mbuf **, struct ifnet *, uint32_t sc_filter_flags, int input);
727static int bridge_ip_checkbasic(struct mbuf **);
728static int bridge_ip6_checkbasic(struct mbuf **);
729
730static errno_t bridge_set_bpf_tap(ifnet_t, bpf_tap_mode, bpf_packet_func);
731static errno_t bridge_bpf_input(ifnet_t, struct mbuf *, const char *, int);
732static errno_t bridge_bpf_output(ifnet_t, struct mbuf *);
733
734static void bridge_detach(ifnet_t);
735static void bridge_link_event(struct ifnet *, u_int32_t);
736static void bridge_iflinkevent(struct ifnet *);
737static u_int32_t bridge_updatelinkstatus(struct bridge_softc *);
738static int interface_media_active(struct ifnet *);
739static void bridge_schedule_delayed_call(struct bridge_delayed_call *);
740static void bridge_cancel_delayed_call(struct bridge_delayed_call *);
741static void bridge_cleanup_delayed_call(struct bridge_delayed_call *);
742static int bridge_host_filter(struct bridge_iflist *, mbuf_t *);
743
744static errno_t bridge_mac_nat_enable(struct bridge_softc *,
745 struct bridge_iflist *);
746static void bridge_mac_nat_disable(struct bridge_softc *sc);
747static void bridge_mac_nat_age_entries(struct bridge_softc *sc, unsigned long);
748static void bridge_mac_nat_populate_entries(struct bridge_softc *sc);
749static void bridge_mac_nat_flush_entries(struct bridge_softc *sc,
750 struct bridge_iflist *);
751static ifnet_t bridge_mac_nat_input(struct bridge_softc *, mbuf_t *,
752 boolean_t *);
753static boolean_t bridge_mac_nat_output(struct bridge_softc *,
754 struct bridge_iflist *, mbuf_t *, struct mac_nat_record *);
755static void bridge_mac_nat_translate(mbuf_t *, struct mac_nat_record *,
756 const caddr_t);
757static bool is_broadcast_ip_packet(mbuf_t *);
758static bool in_addr_is_ours(const struct in_addr);
759static bool in6_addr_is_ours(const struct in6_addr *, uint32_t);
760
761#define m_copypacket(m, how) m_copym(m, 0, M_COPYALL, how)
762
763static int
764gso_tcp(struct ifnet *ifp, struct mbuf **mp, u_int mac_hlen, bool is_ipv4,
765 boolean_t is_tx);
766
767/* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */
768#define VLANTAGOF(_m) 0
769
770u_int8_t bstp_etheraddr[ETHER_ADDR_LEN] =
771{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
772
773static u_int8_t ethernulladdr[ETHER_ADDR_LEN] =
774{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
775
776#if BRIDGESTP
777static struct bstp_cb_ops bridge_ops = {
778 .bcb_state = bridge_state_change,
779 .bcb_rtage = bridge_rtable_expire
780};
781#endif /* BRIDGESTP */
782
783SYSCTL_DECL(_net_link);
784SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
785 "Bridge");
786
787static int bridge_inherit_mac = 0; /* share MAC with first bridge member */
788SYSCTL_INT(_net_link_bridge, OID_AUTO, inherit_mac,
789 CTLFLAG_RW | CTLFLAG_LOCKED,
790 &bridge_inherit_mac, 0,
791 "Inherit MAC address from the first bridge member");
792
793SYSCTL_INT(_net_link_bridge, OID_AUTO, rtable_prune_period,
794 CTLFLAG_RW | CTLFLAG_LOCKED,
795 &bridge_rtable_prune_period, 0,
796 "Interval between pruning of routing table");
797
798static unsigned int bridge_rtable_hash_size_max = BRIDGE_RTHASH_SIZE_MAX;
799SYSCTL_UINT(_net_link_bridge, OID_AUTO, rtable_hash_size_max,
800 CTLFLAG_RW | CTLFLAG_LOCKED,
801 &bridge_rtable_hash_size_max, 0,
802 "Maximum size of the routing hash table");
803
804#if BRIDGE_DELAYED_CALLBACK_DEBUG
805static int bridge_delayed_callback_delay = 0;
806SYSCTL_INT(_net_link_bridge, OID_AUTO, delayed_callback_delay,
807 CTLFLAG_RW | CTLFLAG_LOCKED,
808 &bridge_delayed_callback_delay, 0,
809 "Delay before calling delayed function");
810#endif
811
812SYSCTL_STRUCT(_net_link_bridge, OID_AUTO,
813 hostfilterstats, CTLFLAG_RD | CTLFLAG_LOCKED,
814 &bridge_hostfilter_stats, bridge_hostfilter_stats, "");
815
816#if BRIDGESTP
817static int log_stp = 0; /* log STP state changes */
818SYSCTL_INT(_net_link_bridge, OID_AUTO, log_stp, CTLFLAG_RW,
819 &log_stp, 0, "Log STP state changes");
820#endif /* BRIDGESTP */
821
822struct bridge_control {
823 int (*bc_func)(struct bridge_softc *, void *);
824 unsigned int bc_argsize;
825 unsigned int bc_flags;
826};
827
828#define VMNET_TAG "com.apple.vmnet"
829#define VMNET_LOCAL_TAG VMNET_TAG ".local"
830#define VMNET_BROADCAST_TAG VMNET_TAG ".broadcast"
831#define VMNET_MULTICAST_TAG VMNET_TAG ".multicast"
832
833static u_int16_t vmnet_tag;
834static u_int16_t vmnet_local_tag;
835static u_int16_t vmnet_broadcast_tag;
836static u_int16_t vmnet_multicast_tag;
837
838static u_int16_t
839allocate_pf_tag(char * name)
840{
841 u_int16_t tag;
842
843 tag = pf_tagname2tag_ext(name);
844 BRIDGE_LOG(LOG_NOTICE, 0, "%s %d", name, tag);
845 return tag;
846}
847
848static void
849allocate_vmnet_pf_tags(void)
850{
851 /* allocate tags to use with PF */
852 if (vmnet_tag == 0) {
853 vmnet_tag = allocate_pf_tag(VMNET_TAG);
854 }
855 if (vmnet_local_tag == 0) {
856 vmnet_local_tag = allocate_pf_tag(VMNET_LOCAL_TAG);
857 }
858 if (vmnet_broadcast_tag == 0) {
859 vmnet_broadcast_tag = allocate_pf_tag(VMNET_BROADCAST_TAG);
860 }
861 if (vmnet_multicast_tag == 0) {
862 vmnet_multicast_tag = allocate_pf_tag(VMNET_MULTICAST_TAG);
863 }
864}
865
866#define BC_F_COPYIN 0x01 /* copy arguments in */
867#define BC_F_COPYOUT 0x02 /* copy arguments out */
868#define BC_F_SUSER 0x04 /* do super-user check */
869
870static const struct bridge_control bridge_control_table32[] = {
871 { .bc_func = bridge_ioctl_add, .bc_argsize = sizeof(struct ifbreq), /* 0 */
872 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
873 { .bc_func = bridge_ioctl_del, .bc_argsize = sizeof(struct ifbreq),
874 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
875
876 { .bc_func = bridge_ioctl_gifflags, .bc_argsize = sizeof(struct ifbreq),
877 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
878 { .bc_func = bridge_ioctl_sifflags, .bc_argsize = sizeof(struct ifbreq),
879 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
880
881 { .bc_func = bridge_ioctl_scache, .bc_argsize = sizeof(struct ifbrparam),
882 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
883 { .bc_func = bridge_ioctl_gcache, .bc_argsize = sizeof(struct ifbrparam),
884 .bc_flags = BC_F_COPYOUT },
885
886 { .bc_func = bridge_ioctl_gifs32, .bc_argsize = sizeof(struct ifbifconf32),
887 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
888 { .bc_func = bridge_ioctl_rts32, .bc_argsize = sizeof(struct ifbaconf32),
889 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
890
891 { .bc_func = bridge_ioctl_saddr32, .bc_argsize = sizeof(struct ifbareq32),
892 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
893
894 { .bc_func = bridge_ioctl_sto, .bc_argsize = sizeof(struct ifbrparam),
895 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
896 { .bc_func = bridge_ioctl_gto, .bc_argsize = sizeof(struct ifbrparam), /* 10 */
897 .bc_flags = BC_F_COPYOUT },
898
899 { .bc_func = bridge_ioctl_daddr32, .bc_argsize = sizeof(struct ifbareq32),
900 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
901
902 { .bc_func = bridge_ioctl_flush, .bc_argsize = sizeof(struct ifbreq),
903 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
904
905 { .bc_func = bridge_ioctl_gpri, .bc_argsize = sizeof(struct ifbrparam),
906 .bc_flags = BC_F_COPYOUT },
907 { .bc_func = bridge_ioctl_spri, .bc_argsize = sizeof(struct ifbrparam),
908 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
909
910 { .bc_func = bridge_ioctl_ght, .bc_argsize = sizeof(struct ifbrparam),
911 .bc_flags = BC_F_COPYOUT },
912 { .bc_func = bridge_ioctl_sht, .bc_argsize = sizeof(struct ifbrparam),
913 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
914
915 { .bc_func = bridge_ioctl_gfd, .bc_argsize = sizeof(struct ifbrparam),
916 .bc_flags = BC_F_COPYOUT },
917 { .bc_func = bridge_ioctl_sfd, .bc_argsize = sizeof(struct ifbrparam),
918 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
919
920 { .bc_func = bridge_ioctl_gma, .bc_argsize = sizeof(struct ifbrparam),
921 .bc_flags = BC_F_COPYOUT },
922 { .bc_func = bridge_ioctl_sma, .bc_argsize = sizeof(struct ifbrparam), /* 20 */
923 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
924
925 { .bc_func = bridge_ioctl_sifprio, .bc_argsize = sizeof(struct ifbreq),
926 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
927
928 { .bc_func = bridge_ioctl_sifcost, .bc_argsize = sizeof(struct ifbreq),
929 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
930
931 { .bc_func = bridge_ioctl_gfilt, .bc_argsize = sizeof(struct ifbrparam),
932 .bc_flags = BC_F_COPYOUT },
933 { .bc_func = bridge_ioctl_sfilt, .bc_argsize = sizeof(struct ifbrparam),
934 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
935
936 { .bc_func = bridge_ioctl_purge, .bc_argsize = sizeof(struct ifbreq),
937 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
938
939 { .bc_func = bridge_ioctl_addspan, .bc_argsize = sizeof(struct ifbreq),
940 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
941 { .bc_func = bridge_ioctl_delspan, .bc_argsize = sizeof(struct ifbreq),
942 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
943
944 { .bc_func = bridge_ioctl_gbparam32, .bc_argsize = sizeof(struct ifbropreq32),
945 .bc_flags = BC_F_COPYOUT },
946
947 { .bc_func = bridge_ioctl_grte, .bc_argsize = sizeof(struct ifbrparam),
948 .bc_flags = BC_F_COPYOUT },
949
950 { .bc_func = bridge_ioctl_gifsstp32, .bc_argsize = sizeof(struct ifbpstpconf32), /* 30 */
951 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
952
953 { .bc_func = bridge_ioctl_sproto, .bc_argsize = sizeof(struct ifbrparam),
954 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
955
956 { .bc_func = bridge_ioctl_stxhc, .bc_argsize = sizeof(struct ifbrparam),
957 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
958
959 { .bc_func = bridge_ioctl_sifmaxaddr, .bc_argsize = sizeof(struct ifbreq),
960 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
961
962 { .bc_func = bridge_ioctl_ghostfilter, .bc_argsize = sizeof(struct ifbrhostfilter),
963 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
964 { .bc_func = bridge_ioctl_shostfilter, .bc_argsize = sizeof(struct ifbrhostfilter),
965 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
966
967 { .bc_func = bridge_ioctl_gmnelist32,
968 .bc_argsize = sizeof(struct ifbrmnelist32),
969 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
970 { .bc_func = bridge_ioctl_gifstats32,
971 .bc_argsize = sizeof(struct ifbrmreq32),
972 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
973};
974
975static const struct bridge_control bridge_control_table64[] = {
976 { .bc_func = bridge_ioctl_add, .bc_argsize = sizeof(struct ifbreq), /* 0 */
977 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
978 { .bc_func = bridge_ioctl_del, .bc_argsize = sizeof(struct ifbreq),
979 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
980
981 { .bc_func = bridge_ioctl_gifflags, .bc_argsize = sizeof(struct ifbreq),
982 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
983 { .bc_func = bridge_ioctl_sifflags, .bc_argsize = sizeof(struct ifbreq),
984 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
985
986 { .bc_func = bridge_ioctl_scache, .bc_argsize = sizeof(struct ifbrparam),
987 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
988 { .bc_func = bridge_ioctl_gcache, .bc_argsize = sizeof(struct ifbrparam),
989 .bc_flags = BC_F_COPYOUT },
990
991 { .bc_func = bridge_ioctl_gifs64, .bc_argsize = sizeof(struct ifbifconf64),
992 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
993 { .bc_func = bridge_ioctl_rts64, .bc_argsize = sizeof(struct ifbaconf64),
994 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
995
996 { .bc_func = bridge_ioctl_saddr64, .bc_argsize = sizeof(struct ifbareq64),
997 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
998
999 { .bc_func = bridge_ioctl_sto, .bc_argsize = sizeof(struct ifbrparam),
1000 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1001 { .bc_func = bridge_ioctl_gto, .bc_argsize = sizeof(struct ifbrparam), /* 10 */
1002 .bc_flags = BC_F_COPYOUT },
1003
1004 { .bc_func = bridge_ioctl_daddr64, .bc_argsize = sizeof(struct ifbareq64),
1005 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1006
1007 { .bc_func = bridge_ioctl_flush, .bc_argsize = sizeof(struct ifbreq),
1008 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1009
1010 { .bc_func = bridge_ioctl_gpri, .bc_argsize = sizeof(struct ifbrparam),
1011 .bc_flags = BC_F_COPYOUT },
1012 { .bc_func = bridge_ioctl_spri, .bc_argsize = sizeof(struct ifbrparam),
1013 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1014
1015 { .bc_func = bridge_ioctl_ght, .bc_argsize = sizeof(struct ifbrparam),
1016 .bc_flags = BC_F_COPYOUT },
1017 { .bc_func = bridge_ioctl_sht, .bc_argsize = sizeof(struct ifbrparam),
1018 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1019
1020 { .bc_func = bridge_ioctl_gfd, .bc_argsize = sizeof(struct ifbrparam),
1021 .bc_flags = BC_F_COPYOUT },
1022 { .bc_func = bridge_ioctl_sfd, .bc_argsize = sizeof(struct ifbrparam),
1023 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1024
1025 { .bc_func = bridge_ioctl_gma, .bc_argsize = sizeof(struct ifbrparam),
1026 .bc_flags = BC_F_COPYOUT },
1027 { .bc_func = bridge_ioctl_sma, .bc_argsize = sizeof(struct ifbrparam), /* 20 */
1028 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1029
1030 { .bc_func = bridge_ioctl_sifprio, .bc_argsize = sizeof(struct ifbreq),
1031 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1032
1033 { .bc_func = bridge_ioctl_sifcost, .bc_argsize = sizeof(struct ifbreq),
1034 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1035
1036 { .bc_func = bridge_ioctl_gfilt, .bc_argsize = sizeof(struct ifbrparam),
1037 .bc_flags = BC_F_COPYOUT },
1038 { .bc_func = bridge_ioctl_sfilt, .bc_argsize = sizeof(struct ifbrparam),
1039 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1040
1041 { .bc_func = bridge_ioctl_purge, .bc_argsize = sizeof(struct ifbreq),
1042 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1043
1044 { .bc_func = bridge_ioctl_addspan, .bc_argsize = sizeof(struct ifbreq),
1045 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1046 { .bc_func = bridge_ioctl_delspan, .bc_argsize = sizeof(struct ifbreq),
1047 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1048
1049 { .bc_func = bridge_ioctl_gbparam64, .bc_argsize = sizeof(struct ifbropreq64),
1050 .bc_flags = BC_F_COPYOUT },
1051
1052 { .bc_func = bridge_ioctl_grte, .bc_argsize = sizeof(struct ifbrparam),
1053 .bc_flags = BC_F_COPYOUT },
1054
1055 { .bc_func = bridge_ioctl_gifsstp64, .bc_argsize = sizeof(struct ifbpstpconf64), /* 30 */
1056 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
1057
1058 { .bc_func = bridge_ioctl_sproto, .bc_argsize = sizeof(struct ifbrparam),
1059 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1060
1061 { .bc_func = bridge_ioctl_stxhc, .bc_argsize = sizeof(struct ifbrparam),
1062 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1063
1064 { .bc_func = bridge_ioctl_sifmaxaddr, .bc_argsize = sizeof(struct ifbreq),
1065 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1066
1067 { .bc_func = bridge_ioctl_ghostfilter, .bc_argsize = sizeof(struct ifbrhostfilter),
1068 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
1069 { .bc_func = bridge_ioctl_shostfilter, .bc_argsize = sizeof(struct ifbrhostfilter),
1070 .bc_flags = BC_F_COPYIN | BC_F_SUSER },
1071
1072 { .bc_func = bridge_ioctl_gmnelist64,
1073 .bc_argsize = sizeof(struct ifbrmnelist64),
1074 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
1075 { .bc_func = bridge_ioctl_gifstats64,
1076 .bc_argsize = sizeof(struct ifbrmreq64),
1077 .bc_flags = BC_F_COPYIN | BC_F_COPYOUT },
1078};
1079
1080static const unsigned int bridge_control_table_size =
1081 sizeof(bridge_control_table32) / sizeof(bridge_control_table32[0]);
1082
1083static LIST_HEAD(, bridge_softc) bridge_list =
1084 LIST_HEAD_INITIALIZER(bridge_list);
1085
1086#define BRIDGENAME "bridge"
1087#define BRIDGES_MAX IF_MAXUNIT
1088#define BRIDGE_ZONE_MAX_ELEM MIN(IFNETS_MAX, BRIDGES_MAX)
1089
1090static struct if_clone bridge_cloner =
1091 IF_CLONE_INITIALIZER(BRIDGENAME, bridge_clone_create, bridge_clone_destroy,
1092 0, BRIDGES_MAX);
1093
1094static int if_bridge_txstart = 0;
1095SYSCTL_INT(_net_link_bridge, OID_AUTO, txstart, CTLFLAG_RW | CTLFLAG_LOCKED,
1096 &if_bridge_txstart, 0, "Bridge interface uses TXSTART model");
1097
1098SYSCTL_INT(_net_link_bridge, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_LOCKED,
1099 &if_bridge_debug, 0, "Bridge debug flags");
1100
1101SYSCTL_INT(_net_link_bridge, OID_AUTO, log_level,
1102 CTLFLAG_RW | CTLFLAG_LOCKED,
1103 &if_bridge_log_level, 0, "Bridge log level");
1104
1105static int if_bridge_segmentation = 1;
1106SYSCTL_INT(_net_link_bridge, OID_AUTO, segmentation,
1107 CTLFLAG_RW | CTLFLAG_LOCKED,
1108 &if_bridge_segmentation, 0, "Bridge interface enable segmentation");
1109
1110static int if_bridge_vmnet_pf_tagging = 1;
1111SYSCTL_INT(_net_link_bridge, OID_AUTO, vmnet_pf_tagging,
1112 CTLFLAG_RW | CTLFLAG_LOCKED,
1113 &if_bridge_segmentation, 0, "Bridge interface enable vmnet PF tagging");
1114
1115#define BRIDGE_TSO_REDUCE_MSS_FORWARDING_MAX 256
1116#define BRIDGE_TSO_REDUCE_MSS_FORWARDING_DEFAULT 110
1117#define BRIDGE_TSO_REDUCE_MSS_TX_MAX 256
1118#define BRIDGE_TSO_REDUCE_MSS_TX_DEFAULT 0
1119
1120static u_int if_bridge_tso_reduce_mss_forwarding
1121 = BRIDGE_TSO_REDUCE_MSS_FORWARDING_DEFAULT;
1122static u_int if_bridge_tso_reduce_mss_tx
1123 = BRIDGE_TSO_REDUCE_MSS_TX_DEFAULT;
1124
1125static int
1126bridge_tso_reduce_mss(struct sysctl_req *req, u_int * val, u_int val_max)
1127{
1128 int changed;
1129 int error;
1130 u_int new_value;
1131
1132 error = sysctl_io_number(req, bigValue: *val, valueSize: sizeof(*val), pValue: &new_value,
1133 changed: &changed);
1134 if (error == 0 && changed != 0) {
1135 if (new_value > val_max) {
1136 return EINVAL;
1137 }
1138 *val = new_value;
1139 }
1140 return error;
1141}
1142
1143static int
1144bridge_tso_reduce_mss_forwarding_sysctl SYSCTL_HANDLER_ARGS
1145{
1146 return bridge_tso_reduce_mss(req, val: &if_bridge_tso_reduce_mss_forwarding,
1147 BRIDGE_TSO_REDUCE_MSS_FORWARDING_MAX);
1148}
1149
1150SYSCTL_PROC(_net_link_bridge, OID_AUTO, tso_reduce_mss_forwarding,
1151 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
1152 0, 0, bridge_tso_reduce_mss_forwarding_sysctl, "IU",
1153 "Bridge tso reduce mss when forwarding");
1154
1155static int
1156bridge_tso_reduce_mss_tx_sysctl SYSCTL_HANDLER_ARGS
1157{
1158 return bridge_tso_reduce_mss(req, val: &if_bridge_tso_reduce_mss_tx,
1159 BRIDGE_TSO_REDUCE_MSS_TX_MAX);
1160}
1161
1162SYSCTL_PROC(_net_link_bridge, OID_AUTO, tso_reduce_mss_tx,
1163 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
1164 0, 0, bridge_tso_reduce_mss_tx_sysctl, "IU",
1165 "Bridge tso reduce mss on transmit");
1166
1167#if DEBUG || DEVELOPMENT
1168#define BRIDGE_FORCE_ONE 0x00000001
1169#define BRIDGE_FORCE_TWO 0x00000002
1170static u_int32_t if_bridge_force_errors = 0;
1171SYSCTL_INT(_net_link_bridge, OID_AUTO, force_errors,
1172 CTLFLAG_RW | CTLFLAG_LOCKED,
1173 &if_bridge_force_errors, 0, "Bridge interface force errors");
1174static inline bool
1175bridge_error_is_forced(u_int32_t flags)
1176{
1177 return (if_bridge_force_errors & flags) != 0;
1178}
1179
1180#define BRIDGE_ERROR_GET_FORCED(__is_forced, __flags) \
1181 do { \
1182 __is_forced = bridge_error_is_forced(__flags); \
1183 if (__is_forced) { \
1184 BRIDGE_LOG(LOG_NOTICE, 0, "0x%x forced", __flags); \
1185 } \
1186 } while (0)
1187
1188/*
1189 * net.link.bridge.reduce_tso_mtu
1190 * - when non-zero, the bridge overrides the interface TSO MTU to a lower
1191 * value (i.e. 16K) to enable testing the "use GSO instead" path
1192 */
1193static int if_bridge_reduce_tso_mtu = 0;
1194SYSCTL_INT(_net_link_bridge, OID_AUTO, reduce_tso_mtu,
1195 CTLFLAG_RW | CTLFLAG_LOCKED,
1196 &if_bridge_reduce_tso_mtu, 0, "Bridge interface reduce TSO MTU");
1197
1198#endif /* DEBUG || DEVELOPMENT */
1199
1200static void brlog_ether_header(struct ether_header *);
1201static void brlog_mbuf_data(mbuf_t, size_t, size_t);
1202static void brlog_mbuf_pkthdr(mbuf_t, const char *, const char *);
1203static void brlog_mbuf(mbuf_t, const char *, const char *);
1204static void brlog_link(struct bridge_softc * sc);
1205
1206#if BRIDGE_LOCK_DEBUG
1207static void bridge_lock(struct bridge_softc *);
1208static void bridge_unlock(struct bridge_softc *);
1209static int bridge_lock2ref(struct bridge_softc *);
1210static void bridge_unref(struct bridge_softc *);
1211static void bridge_xlock(struct bridge_softc *);
1212static void bridge_xdrop(struct bridge_softc *);
1213
1214static void
1215bridge_lock(struct bridge_softc *sc)
1216{
1217 void *lr_saved = __builtin_return_address(0);
1218
1219 BRIDGE_LOCK_ASSERT_NOTHELD(sc);
1220
1221 _BRIDGE_LOCK(sc);
1222
1223 sc->lock_lr[sc->next_lock_lr] = lr_saved;
1224 sc->next_lock_lr = (sc->next_lock_lr + 1) % SO_LCKDBG_MAX;
1225}
1226
1227static void
1228bridge_unlock(struct bridge_softc *sc)
1229{
1230 void *lr_saved = __builtin_return_address(0);
1231
1232 BRIDGE_LOCK_ASSERT_HELD(sc);
1233
1234 sc->unlock_lr[sc->next_unlock_lr] = lr_saved;
1235 sc->next_unlock_lr = (sc->next_unlock_lr + 1) % SO_LCKDBG_MAX;
1236
1237 _BRIDGE_UNLOCK(sc);
1238}
1239
1240static int
1241bridge_lock2ref(struct bridge_softc *sc)
1242{
1243 int error = 0;
1244 void *lr_saved = __builtin_return_address(0);
1245
1246 BRIDGE_LOCK_ASSERT_HELD(sc);
1247
1248 if (sc->sc_iflist_xcnt > 0) {
1249 error = EBUSY;
1250 } else {
1251 sc->sc_iflist_ref++;
1252 }
1253
1254 sc->unlock_lr[sc->next_unlock_lr] = lr_saved;
1255 sc->next_unlock_lr = (sc->next_unlock_lr + 1) % SO_LCKDBG_MAX;
1256
1257 _BRIDGE_UNLOCK(sc);
1258
1259 return error;
1260}
1261
1262static void
1263bridge_unref(struct bridge_softc *sc)
1264{
1265 void *lr_saved = __builtin_return_address(0);
1266
1267 BRIDGE_LOCK_ASSERT_NOTHELD(sc);
1268
1269 _BRIDGE_LOCK(sc);
1270 sc->lock_lr[sc->next_lock_lr] = lr_saved;
1271 sc->next_lock_lr = (sc->next_lock_lr + 1) % SO_LCKDBG_MAX;
1272
1273 sc->sc_iflist_ref--;
1274
1275 sc->unlock_lr[sc->next_unlock_lr] = lr_saved;
1276 sc->next_unlock_lr = (sc->next_unlock_lr + 1) % SO_LCKDBG_MAX;
1277 if ((sc->sc_iflist_xcnt > 0) && (sc->sc_iflist_ref == 0)) {
1278 _BRIDGE_UNLOCK(sc);
1279 wakeup(chan: &sc->sc_cv);
1280 } else {
1281 _BRIDGE_UNLOCK(sc);
1282 }
1283}
1284
1285static void
1286bridge_xlock(struct bridge_softc *sc)
1287{
1288 void *lr_saved = __builtin_return_address(0);
1289
1290 BRIDGE_LOCK_ASSERT_HELD(sc);
1291
1292 sc->sc_iflist_xcnt++;
1293 while (sc->sc_iflist_ref > 0) {
1294 sc->unlock_lr[sc->next_unlock_lr] = lr_saved;
1295 sc->next_unlock_lr = (sc->next_unlock_lr + 1) % SO_LCKDBG_MAX;
1296
1297 msleep(chan: &sc->sc_cv, mtx: &sc->sc_mtx, PZERO, wmesg: "BRIDGE_XLOCK", NULL);
1298
1299 sc->lock_lr[sc->next_lock_lr] = lr_saved;
1300 sc->next_lock_lr = (sc->next_lock_lr + 1) % SO_LCKDBG_MAX;
1301 }
1302}
1303
1304static void
1305bridge_xdrop(struct bridge_softc *sc)
1306{
1307 BRIDGE_LOCK_ASSERT_HELD(sc);
1308
1309 sc->sc_iflist_xcnt--;
1310}
1311
1312#endif /* BRIDGE_LOCK_DEBUG */
1313
1314static void
1315brlog_mbuf_pkthdr(mbuf_t m, const char *prefix, const char *suffix)
1316{
1317 if (m) {
1318 BRIDGE_LOG_SIMPLE(LOG_NOTICE, 0,
1319 "%spktlen: %u rcvif: 0x%llx header: 0x%llx nextpkt: 0x%llx%s",
1320 prefix ? prefix : "", (unsigned int)mbuf_pkthdr_len(m),
1321 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_pkthdr_rcvif(m)),
1322 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_pkthdr_header(m)),
1323 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_nextpkt(m)),
1324 suffix ? suffix : "");
1325 } else {
1326 BRIDGE_LOG_SIMPLE(LOG_NOTICE, 0, "%s<NULL>%s", prefix, suffix);
1327 }
1328}
1329
1330static void
1331brlog_mbuf(mbuf_t m, const char *prefix, const char *suffix)
1332{
1333 if (m) {
1334 BRIDGE_LOG_SIMPLE(LOG_NOTICE, 0,
1335 "%s0x%llx type: %u flags: 0x%x len: %u data: 0x%llx "
1336 "maxlen: %u datastart: 0x%llx next: 0x%llx%s",
1337 prefix ? prefix : "", (uint64_t)VM_KERNEL_ADDRPERM(m),
1338 mbuf_type(m), mbuf_flags(m), (unsigned int)mbuf_len(m),
1339 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_data(m)),
1340 (unsigned int)mbuf_maxlen(m),
1341 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_datastart(m)),
1342 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_next(m)),
1343 !suffix || (mbuf_flags(m) & MBUF_PKTHDR) ? "" : suffix);
1344 if ((mbuf_flags(mbuf: m) & MBUF_PKTHDR)) {
1345 brlog_mbuf_pkthdr(m, prefix: "", suffix);
1346 }
1347 } else {
1348 BRIDGE_LOG_SIMPLE(LOG_NOTICE, 0, "%s<NULL>%s", prefix, suffix);
1349 }
1350}
1351
1352static void
1353brlog_mbuf_data(mbuf_t m, size_t offset, size_t len)
1354{
1355 mbuf_t n;
1356 size_t i, j;
1357 size_t pktlen, mlen, maxlen;
1358 unsigned char *ptr;
1359
1360 pktlen = mbuf_pkthdr_len(mbuf: m);
1361
1362 if (offset > pktlen) {
1363 return;
1364 }
1365
1366 maxlen = (pktlen - offset > len) ? len : pktlen - offset;
1367 n = m;
1368 mlen = mbuf_len(mbuf: n);
1369 ptr = mbuf_data(mbuf: n);
1370 for (i = 0, j = 0; i < maxlen; i++, j++) {
1371 if (j >= mlen) {
1372 n = mbuf_next(mbuf: n);
1373 if (n == 0) {
1374 break;
1375 }
1376 ptr = mbuf_data(mbuf: n);
1377 mlen = mbuf_len(mbuf: n);
1378 j = 0;
1379 }
1380 if (i >= offset) {
1381 BRIDGE_LOG_SIMPLE(LOG_NOTICE, 0,
1382 "%02x%s", ptr[j], i % 2 ? " " : "");
1383 }
1384 }
1385}
1386
1387static void
1388brlog_ether_header(struct ether_header *eh)
1389{
1390 BRIDGE_LOG_SIMPLE(LOG_NOTICE, 0,
1391 "%02x:%02x:%02x:%02x:%02x:%02x > "
1392 "%02x:%02x:%02x:%02x:%02x:%02x 0x%04x ",
1393 eh->ether_shost[0], eh->ether_shost[1], eh->ether_shost[2],
1394 eh->ether_shost[3], eh->ether_shost[4], eh->ether_shost[5],
1395 eh->ether_dhost[0], eh->ether_dhost[1], eh->ether_dhost[2],
1396 eh->ether_dhost[3], eh->ether_dhost[4], eh->ether_dhost[5],
1397 ntohs(eh->ether_type));
1398}
1399
1400static char *
1401ether_ntop(char *buf, size_t len, const u_char *ap)
1402{
1403 snprintf(buf, count: len, "%02x:%02x:%02x:%02x:%02x:%02x",
1404 ap[0], ap[1], ap[2], ap[3], ap[4], ap[5]);
1405
1406 return buf;
1407}
1408
1409static void
1410brlog_link(struct bridge_softc * sc)
1411{
1412 int i;
1413 uint32_t sdl_buffer[(offsetof(struct sockaddr_dl, sdl_data) +
1414 IFNAMSIZ + ETHER_ADDR_LEN)];
1415 struct sockaddr_dl *sdl = SDL((uint8_t*)&sdl_buffer); /* SDL requires byte pointer */
1416 const u_char * lladdr;
1417 char lladdr_str[48];
1418
1419 memset(s: sdl, c: 0, n: sizeof(sdl_buffer));
1420 sdl->sdl_family = AF_LINK;
1421 sdl->sdl_nlen = strlen(s: sc->sc_if_xname);
1422 sdl->sdl_alen = ETHER_ADDR_LEN;
1423 sdl->sdl_len = offsetof(struct sockaddr_dl, sdl_data);
1424 memcpy(dst: sdl->sdl_data, src: sc->sc_if_xname, n: sdl->sdl_nlen);
1425 memcpy(LLADDR(sdl), src: sc->sc_defaddr, ETHER_ADDR_LEN);
1426 lladdr_str[0] = '\0';
1427 for (i = 0, lladdr = CONST_LLADDR(sdl);
1428 i < sdl->sdl_alen;
1429 i++, lladdr++) {
1430 char byte_str[4];
1431
1432 snprintf(byte_str, count: sizeof(byte_str), "%s%x", i ? ":" : "",
1433 *lladdr);
1434 strlcat(dst: lladdr_str, src: byte_str, n: sizeof(lladdr_str));
1435 }
1436 BRIDGE_LOG_SIMPLE(LOG_NOTICE, 0,
1437 "%s sdl len %d index %d family %d type 0x%x nlen %d alen %d"
1438 " slen %d addr %s", sc->sc_if_xname,
1439 sdl->sdl_len, sdl->sdl_index,
1440 sdl->sdl_family, sdl->sdl_type, sdl->sdl_nlen,
1441 sdl->sdl_alen, sdl->sdl_slen, lladdr_str);
1442}
1443
1444
1445/*
1446 * bridgeattach:
1447 *
1448 * Pseudo-device attach routine.
1449 */
1450__private_extern__ int
1451bridgeattach(int n)
1452{
1453#pragma unused(n)
1454 int error;
1455
1456 LIST_INIT(&bridge_list);
1457
1458#if BRIDGESTP
1459 bstp_sys_init();
1460#endif /* BRIDGESTP */
1461
1462 error = if_clone_attach(&bridge_cloner);
1463 if (error != 0) {
1464 BRIDGE_LOG(LOG_NOTICE, 0, "ifnet_clone_attach failed %d", error);
1465 }
1466 return error;
1467}
1468
1469
1470static errno_t
1471bridge_ifnet_set_attrs(struct ifnet * ifp)
1472{
1473 errno_t error;
1474
1475 error = ifnet_set_mtu(interface: ifp, ETHERMTU);
1476 if (error != 0) {
1477 BRIDGE_LOG(LOG_NOTICE, 0, "ifnet_set_mtu failed %d", error);
1478 goto done;
1479 }
1480 error = ifnet_set_addrlen(interface: ifp, ETHER_ADDR_LEN);
1481 if (error != 0) {
1482 BRIDGE_LOG(LOG_NOTICE, 0, "ifnet_set_addrlen failed %d", error);
1483 goto done;
1484 }
1485 error = ifnet_set_hdrlen(interface: ifp, ETHER_HDR_LEN);
1486 if (error != 0) {
1487 BRIDGE_LOG(LOG_NOTICE, 0, "ifnet_set_hdrlen failed %d", error);
1488 goto done;
1489 }
1490 error = ifnet_set_flags(interface: ifp,
1491 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST,
1492 mask: 0xffff);
1493
1494 if (error != 0) {
1495 BRIDGE_LOG(LOG_NOTICE, 0, "ifnet_set_flags failed %d", error);
1496 goto done;
1497 }
1498done:
1499 return error;
1500}
1501
1502/*
1503 * bridge_clone_create:
1504 *
1505 * Create a new bridge instance.
1506 */
1507static int
1508bridge_clone_create(struct if_clone *ifc, uint32_t unit, void *params)
1509{
1510#pragma unused(params)
1511 struct ifnet *ifp = NULL;
1512 struct bridge_softc *sc = NULL;
1513 struct bridge_softc *sc2 = NULL;
1514 struct ifnet_init_eparams init_params;
1515 errno_t error = 0;
1516 uint8_t eth_hostid[ETHER_ADDR_LEN];
1517 int fb, retry, has_hostid;
1518
1519 sc = kalloc_type(struct bridge_softc, Z_WAITOK_ZERO_NOFAIL);
1520 lck_mtx_init(lck: &sc->sc_mtx, grp: &bridge_lock_grp, attr: &bridge_lock_attr);
1521 sc->sc_brtmax = BRIDGE_RTABLE_MAX;
1522 sc->sc_mne_max = BRIDGE_MAC_NAT_ENTRY_MAX;
1523 sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT;
1524 sc->sc_filter_flags = 0;
1525
1526 TAILQ_INIT(&sc->sc_iflist);
1527
1528 /* use the interface name as the unique id for ifp recycle */
1529 snprintf(sc->sc_if_xname, count: sizeof(sc->sc_if_xname), "%s%d",
1530 ifc->ifc_name, unit);
1531 bzero(s: &init_params, n: sizeof(init_params));
1532 init_params.ver = IFNET_INIT_CURRENT_VERSION;
1533 init_params.len = sizeof(init_params);
1534 /* Initialize our routing table. */
1535 error = bridge_rtable_init(sc);
1536 if (error != 0) {
1537 BRIDGE_LOG(LOG_NOTICE, 0, "bridge_rtable_init failed %d", error);
1538 goto done;
1539 }
1540 TAILQ_INIT(&sc->sc_spanlist);
1541 if (if_bridge_txstart) {
1542 init_params.start = bridge_start;
1543 } else {
1544 init_params.flags = IFNET_INIT_LEGACY;
1545 init_params.output = bridge_output;
1546 }
1547 init_params.set_bpf_tap = bridge_set_bpf_tap;
1548 init_params.uniqueid = sc->sc_if_xname;
1549 init_params.uniqueid_len = strlen(s: sc->sc_if_xname);
1550 init_params.sndq_maxlen = IFQ_MAXLEN;
1551 init_params.name = ifc->ifc_name;
1552 init_params.unit = unit;
1553 init_params.family = IFNET_FAMILY_ETHERNET;
1554 init_params.type = IFT_BRIDGE;
1555 init_params.demux = ether_demux;
1556 init_params.add_proto = ether_add_proto;
1557 init_params.del_proto = ether_del_proto;
1558 init_params.check_multi = ether_check_multi;
1559 init_params.framer_extended = ether_frameout_extended;
1560 init_params.softc = sc;
1561 init_params.ioctl = bridge_ioctl;
1562 init_params.detach = bridge_detach;
1563 init_params.broadcast_addr = etherbroadcastaddr;
1564 init_params.broadcast_len = ETHER_ADDR_LEN;
1565
1566 error = ifnet_allocate_extended(init: &init_params, interface: &ifp);
1567 if (error != 0) {
1568 BRIDGE_LOG(LOG_NOTICE, 0, "ifnet_allocate failed %d", error);
1569 goto done;
1570 }
1571 LIST_INIT(&sc->sc_mne_list);
1572 LIST_INIT(&sc->sc_mne_list_v6);
1573 sc->sc_ifp = ifp;
1574 error = bridge_ifnet_set_attrs(ifp);
1575 if (error != 0) {
1576 BRIDGE_LOG(LOG_NOTICE, 0, "bridge_ifnet_set_attrs failed %d",
1577 error);
1578 goto done;
1579 }
1580 /*
1581 * Generate an ethernet address with a locally administered address.
1582 *
1583 * Since we are using random ethernet addresses for the bridge, it is
1584 * possible that we might have address collisions, so make sure that
1585 * this hardware address isn't already in use on another bridge.
1586 * The first try uses the "hostid" and falls back to read_frandom();
1587 * for "hostid", we use the MAC address of the first-encountered
1588 * Ethernet-type interface that is currently configured.
1589 */
1590 fb = 0;
1591 has_hostid = (uuid_get_ethernet(&eth_hostid[0]) == 0);
1592 for (retry = 1; retry != 0;) {
1593 if (fb || has_hostid == 0) {
1594 read_frandom(buffer: &sc->sc_defaddr, ETHER_ADDR_LEN);
1595 sc->sc_defaddr[0] &= ~1; /* clear multicast bit */
1596 sc->sc_defaddr[0] |= 2; /* set the LAA bit */
1597 } else {
1598 bcopy(src: &eth_hostid[0], dst: &sc->sc_defaddr,
1599 ETHER_ADDR_LEN);
1600 sc->sc_defaddr[0] &= ~1; /* clear multicast bit */
1601 sc->sc_defaddr[0] |= 2; /* set the LAA bit */
1602 sc->sc_defaddr[3] = /* stir it up a bit */
1603 ((sc->sc_defaddr[3] & 0x0f) << 4) |
1604 ((sc->sc_defaddr[3] & 0xf0) >> 4);
1605 /*
1606 * Mix in the LSB as it's actually pretty significant,
1607 * see rdar://14076061
1608 */
1609 sc->sc_defaddr[4] =
1610 (((sc->sc_defaddr[4] & 0x0f) << 4) |
1611 ((sc->sc_defaddr[4] & 0xf0) >> 4)) ^
1612 sc->sc_defaddr[5];
1613 sc->sc_defaddr[5] = ifp->if_unit & 0xff;
1614 }
1615
1616 fb = 1;
1617 retry = 0;
1618 lck_mtx_lock(lck: &bridge_list_mtx);
1619 LIST_FOREACH(sc2, &bridge_list, sc_list) {
1620 if (_ether_cmp(a: sc->sc_defaddr,
1621 IF_LLADDR(sc2->sc_ifp)) == 0) {
1622 retry = 1;
1623 }
1624 }
1625 lck_mtx_unlock(lck: &bridge_list_mtx);
1626 }
1627
1628 sc->sc_flags &= ~SCF_MEDIA_ACTIVE;
1629
1630 if (BRIDGE_DBGF_ENABLED(BR_DBGF_LIFECYCLE)) {
1631 brlog_link(sc);
1632 }
1633 error = ifnet_attach(interface: ifp, NULL);
1634 if (error != 0) {
1635 BRIDGE_LOG(LOG_NOTICE, 0, "ifnet_attach failed %d", error);
1636 goto done;
1637 }
1638
1639 error = ifnet_set_lladdr_and_type(interface: ifp, lladdr: sc->sc_defaddr, ETHER_ADDR_LEN,
1640 IFT_ETHER);
1641 if (error != 0) {
1642 BRIDGE_LOG(LOG_NOTICE, 0, "ifnet_set_lladdr_and_type failed %d",
1643 error);
1644 goto done;
1645 }
1646
1647 ifnet_set_offload(interface: ifp,
1648 offload: IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP |
1649 IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | IFNET_MULTIPAGES);
1650 error = bridge_set_tso(sc);
1651 if (error != 0) {
1652 BRIDGE_LOG(LOG_NOTICE, 0, "bridge_set_tso failed %d", error);
1653 goto done;
1654 }
1655#if BRIDGESTP
1656 bstp_attach(&sc->sc_stp, &bridge_ops);
1657#endif /* BRIDGESTP */
1658
1659 lck_mtx_lock(lck: &bridge_list_mtx);
1660 LIST_INSERT_HEAD(&bridge_list, sc, sc_list);
1661 lck_mtx_unlock(lck: &bridge_list_mtx);
1662
1663 /* attach as ethernet */
1664 error = bpf_attach(interface: ifp, DLT_EN10MB, header_length: sizeof(struct ether_header),
1665 NULL, NULL);
1666
1667done:
1668 if (error != 0) {
1669 BRIDGE_LOG(LOG_NOTICE, 0, "failed error %d", error);
1670 /* TBD: Clean up: sc, sc_rthash etc */
1671 }
1672
1673 return error;
1674}
1675
1676/*
1677 * bridge_clone_destroy:
1678 *
1679 * Destroy a bridge instance.
1680 */
1681static int
1682bridge_clone_destroy(struct ifnet *ifp)
1683{
1684 struct bridge_softc *sc = ifp->if_softc;
1685 struct bridge_iflist *bif;
1686 errno_t error;
1687
1688 BRIDGE_LOCK(sc);
1689 if ((sc->sc_flags & SCF_DETACHING)) {
1690 BRIDGE_UNLOCK(sc);
1691 return 0;
1692 }
1693 sc->sc_flags |= SCF_DETACHING;
1694
1695 bridge_ifstop(ifp, 1);
1696
1697 bridge_cancel_delayed_call(&sc->sc_resize_call);
1698
1699 bridge_cleanup_delayed_call(&sc->sc_resize_call);
1700 bridge_cleanup_delayed_call(&sc->sc_aging_timer);
1701
1702 error = ifnet_set_flags(interface: ifp, new_flags: 0, IFF_UP);
1703 if (error != 0) {
1704 BRIDGE_LOG(LOG_NOTICE, 0, "ifnet_set_flags failed %d", error);
1705 }
1706
1707 while ((bif = TAILQ_FIRST(&sc->sc_iflist)) != NULL) {
1708 bridge_delete_member(sc, bif);
1709 }
1710
1711 while ((bif = TAILQ_FIRST(&sc->sc_spanlist)) != NULL) {
1712 bridge_delete_span(sc, bif);
1713 }
1714 BRIDGE_UNLOCK(sc);
1715
1716 error = ifnet_detach(interface: ifp);
1717 if (error != 0) {
1718 panic("%s (%d): ifnet_detach(%p) failed %d",
1719 __func__, __LINE__, ifp, error);
1720 }
1721 return 0;
1722}
1723
1724#define DRVSPEC do { \
1725 if (ifd->ifd_cmd >= bridge_control_table_size) { \
1726 error = EINVAL; \
1727 break; \
1728 } \
1729 bc = &bridge_control_table[ifd->ifd_cmd]; \
1730 \
1731 if (cmd == SIOCGDRVSPEC && \
1732 (bc->bc_flags & BC_F_COPYOUT) == 0) { \
1733 error = EINVAL; \
1734 break; \
1735 } else if (cmd == SIOCSDRVSPEC && \
1736 (bc->bc_flags & BC_F_COPYOUT) != 0) { \
1737 error = EINVAL; \
1738 break; \
1739 } \
1740 \
1741 if (bc->bc_flags & BC_F_SUSER) { \
1742 error = kauth_authorize_generic(kauth_cred_get(), \
1743 KAUTH_GENERIC_ISSUSER); \
1744 if (error) \
1745 break; \
1746 } \
1747 \
1748 if (ifd->ifd_len != bc->bc_argsize || \
1749 ifd->ifd_len > sizeof (args)) { \
1750 error = EINVAL; \
1751 break; \
1752 } \
1753 \
1754 bzero(&args, sizeof (args)); \
1755 if (bc->bc_flags & BC_F_COPYIN) { \
1756 error = copyin(ifd->ifd_data, &args, ifd->ifd_len); \
1757 if (error) \
1758 break; \
1759 } \
1760 \
1761 BRIDGE_LOCK(sc); \
1762 error = (*bc->bc_func)(sc, &args); \
1763 BRIDGE_UNLOCK(sc); \
1764 if (error) \
1765 break; \
1766 \
1767 if (bc->bc_flags & BC_F_COPYOUT) \
1768 error = copyout(&args, ifd->ifd_data, ifd->ifd_len); \
1769} while (0)
1770
1771static boolean_t
1772interface_needs_input_broadcast(struct ifnet * ifp)
1773{
1774 /*
1775 * Selectively enable input broadcast only when necessary.
1776 * The bridge interface itself attaches a fake protocol
1777 * so checking for at least two protocols means that the
1778 * interface is being used for something besides bridging
1779 * and needs to see broadcast packets from other members.
1780 */
1781 return if_get_protolist(ifp, NULL, count: 0) >= 2;
1782}
1783
1784static boolean_t
1785bif_set_input_broadcast(struct bridge_iflist * bif, boolean_t input_broadcast)
1786{
1787 boolean_t old_input_broadcast;
1788
1789 old_input_broadcast = (bif->bif_flags & BIFF_INPUT_BROADCAST) != 0;
1790 if (input_broadcast) {
1791 bif->bif_flags |= BIFF_INPUT_BROADCAST;
1792 } else {
1793 bif->bif_flags &= ~BIFF_INPUT_BROADCAST;
1794 }
1795 return old_input_broadcast != input_broadcast;
1796}
1797
1798/*
1799 * bridge_ioctl:
1800 *
1801 * Handle a control request from the operator.
1802 */
1803static errno_t
1804bridge_ioctl(struct ifnet *ifp, u_long cmd, void *data)
1805{
1806 struct bridge_softc *sc = ifp->if_softc;
1807 struct ifreq *ifr = (struct ifreq *)data;
1808 struct bridge_iflist *bif;
1809 int error = 0;
1810
1811 BRIDGE_LOCK_ASSERT_NOTHELD(sc);
1812
1813 BRIDGE_LOG(LOG_DEBUG, BR_DBGF_IOCTL,
1814 "ifp %s cmd 0x%08lx (%c%c [%lu] %c %lu)",
1815 ifp->if_xname, cmd, (cmd & IOC_IN) ? 'I' : ' ',
1816 (cmd & IOC_OUT) ? 'O' : ' ', IOCPARM_LEN(cmd),
1817 (char)IOCGROUP(cmd), cmd & 0xff);
1818
1819 switch (cmd) {
1820 case SIOCSIFADDR:
1821 case SIOCAIFADDR:
1822 ifnet_set_flags(interface: ifp, IFF_UP, IFF_UP);
1823 break;
1824
1825 case SIOCGIFMEDIA32:
1826 case SIOCGIFMEDIA64: {
1827 struct ifmediareq *ifmr = (struct ifmediareq *)data;
1828 user_addr_t user_addr;
1829
1830 user_addr = (cmd == SIOCGIFMEDIA64) ?
1831 ((struct ifmediareq64 *)ifmr)->ifmu_ulist :
1832 CAST_USER_ADDR_T(((struct ifmediareq32 *)ifmr)->ifmu_ulist);
1833
1834 ifmr->ifm_status = IFM_AVALID;
1835 ifmr->ifm_mask = 0;
1836 ifmr->ifm_count = 1;
1837
1838 BRIDGE_LOCK(sc);
1839 if (!(sc->sc_flags & SCF_DETACHING) &&
1840 (sc->sc_flags & SCF_MEDIA_ACTIVE)) {
1841 ifmr->ifm_status |= IFM_ACTIVE;
1842 ifmr->ifm_active = ifmr->ifm_current =
1843 IFM_ETHER | IFM_AUTO;
1844 } else {
1845 ifmr->ifm_active = ifmr->ifm_current = IFM_NONE;
1846 }
1847 BRIDGE_UNLOCK(sc);
1848
1849 if (user_addr != USER_ADDR_NULL) {
1850 error = copyout(&ifmr->ifm_current, user_addr,
1851 sizeof(int));
1852 }
1853 break;
1854 }
1855
1856 case SIOCADDMULTI:
1857 case SIOCDELMULTI:
1858 break;
1859
1860 case SIOCSDRVSPEC32:
1861 case SIOCGDRVSPEC32: {
1862 union {
1863 struct ifbreq ifbreq;
1864 struct ifbifconf32 ifbifconf;
1865 struct ifbareq32 ifbareq;
1866 struct ifbaconf32 ifbaconf;
1867 struct ifbrparam ifbrparam;
1868 struct ifbropreq32 ifbropreq;
1869 } args;
1870 struct ifdrv32 *ifd = (struct ifdrv32 *)data;
1871 const struct bridge_control *bridge_control_table =
1872 bridge_control_table32, *bc;
1873
1874 DRVSPEC;
1875
1876 break;
1877 }
1878 case SIOCSDRVSPEC64:
1879 case SIOCGDRVSPEC64: {
1880 union {
1881 struct ifbreq ifbreq;
1882 struct ifbifconf64 ifbifconf;
1883 struct ifbareq64 ifbareq;
1884 struct ifbaconf64 ifbaconf;
1885 struct ifbrparam ifbrparam;
1886 struct ifbropreq64 ifbropreq;
1887 } args;
1888 struct ifdrv64 *ifd = (struct ifdrv64 *)data;
1889 const struct bridge_control *bridge_control_table =
1890 bridge_control_table64, *bc;
1891
1892 DRVSPEC;
1893
1894 break;
1895 }
1896
1897 case SIOCSIFFLAGS:
1898 if (!(ifp->if_flags & IFF_UP) &&
1899 (ifp->if_flags & IFF_RUNNING)) {
1900 /*
1901 * If interface is marked down and it is running,
1902 * then stop and disable it.
1903 */
1904 BRIDGE_LOCK(sc);
1905 bridge_ifstop(ifp, 1);
1906 BRIDGE_UNLOCK(sc);
1907 } else if ((ifp->if_flags & IFF_UP) &&
1908 !(ifp->if_flags & IFF_RUNNING)) {
1909 /*
1910 * If interface is marked up and it is stopped, then
1911 * start it.
1912 */
1913 BRIDGE_LOCK(sc);
1914 error = bridge_init(ifp);
1915 BRIDGE_UNLOCK(sc);
1916 }
1917 break;
1918
1919 case SIOCSIFLLADDR:
1920 error = ifnet_set_lladdr(interface: ifp, lladdr: ifr->ifr_addr.sa_data,
1921 lladdr_len: ifr->ifr_addr.sa_len);
1922 if (error != 0) {
1923 BRIDGE_LOG(LOG_NOTICE, BR_DBGF_IOCTL,
1924 "%s SIOCSIFLLADDR error %d", ifp->if_xname,
1925 error);
1926 }
1927 break;
1928
1929 case SIOCSIFMTU:
1930 if (ifr->ifr_mtu < 576) {
1931 error = EINVAL;
1932 break;
1933 }
1934 BRIDGE_LOCK(sc);
1935 if (TAILQ_EMPTY(&sc->sc_iflist)) {
1936 sc->sc_ifp->if_mtu = ifr->ifr_mtu;
1937 BRIDGE_UNLOCK(sc);
1938 break;
1939 }
1940 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
1941 if (bif->bif_ifp->if_mtu != (unsigned)ifr->ifr_mtu) {
1942 BRIDGE_LOG(LOG_NOTICE, 0,
1943 "%s invalid MTU: %u(%s) != %d",
1944 sc->sc_ifp->if_xname,
1945 bif->bif_ifp->if_mtu,
1946 bif->bif_ifp->if_xname, ifr->ifr_mtu);
1947 error = EINVAL;
1948 break;
1949 }
1950 }
1951 if (!error) {
1952 sc->sc_ifp->if_mtu = ifr->ifr_mtu;
1953 }
1954 BRIDGE_UNLOCK(sc);
1955 break;
1956
1957 default:
1958 error = ether_ioctl(interface: ifp, command: cmd, data);
1959 if (error != 0 && error != EOPNOTSUPP) {
1960 BRIDGE_LOG(LOG_NOTICE, BR_DBGF_IOCTL,
1961 "ifp %s cmd 0x%08lx "
1962 "(%c%c [%lu] %c %lu) failed error: %d",
1963 ifp->if_xname, cmd,
1964 (cmd & IOC_IN) ? 'I' : ' ',
1965 (cmd & IOC_OUT) ? 'O' : ' ',
1966 IOCPARM_LEN(cmd), (char)IOCGROUP(cmd),
1967 cmd & 0xff, error);
1968 }
1969 break;
1970 }
1971 BRIDGE_LOCK_ASSERT_NOTHELD(sc);
1972
1973 return error;
1974}
1975
1976#if HAS_IF_CAP
1977/*
1978 * bridge_mutecaps:
1979 *
1980 * Clear or restore unwanted capabilities on the member interface
1981 */
1982static void
1983bridge_mutecaps(struct bridge_softc *sc)
1984{
1985 struct bridge_iflist *bif;
1986 int enabled, mask;
1987
1988 /* Initial bitmask of capabilities to test */
1989 mask = BRIDGE_IFCAPS_MASK;
1990
1991 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
1992 /* Every member must support it or its disabled */
1993 mask &= bif->bif_savedcaps;
1994 }
1995
1996 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
1997 enabled = bif->bif_ifp->if_capenable;
1998 enabled &= ~BRIDGE_IFCAPS_STRIP;
1999 /* strip off mask bits and enable them again if allowed */
2000 enabled &= ~BRIDGE_IFCAPS_MASK;
2001 enabled |= mask;
2002
2003 bridge_set_ifcap(sc, bif, enabled);
2004 }
2005}
2006
2007static void
2008bridge_set_ifcap(struct bridge_softc *sc, struct bridge_iflist *bif, int set)
2009{
2010 struct ifnet *ifp = bif->bif_ifp;
2011 struct ifreq ifr;
2012 int error;
2013
2014 bzero(&ifr, sizeof(ifr));
2015 ifr.ifr_reqcap = set;
2016
2017 if (ifp->if_capenable != set) {
2018 IFF_LOCKGIANT(ifp);
2019 error = (*ifp->if_ioctl)(ifp, SIOCSIFCAP, (caddr_t)&ifr);
2020 IFF_UNLOCKGIANT(ifp);
2021 if (error) {
2022 BRIDGE_LOG(LOG_NOTICE, 0,
2023 "%s error setting interface capabilities on %s",
2024 sc->sc_ifp->if_xname, ifp->if_xname);
2025 }
2026 }
2027}
2028#endif /* HAS_IF_CAP */
2029
2030static errno_t
2031siocsifcap(struct ifnet * ifp, uint32_t cap_enable)
2032{
2033 struct ifreq ifr;
2034
2035 bzero(s: &ifr, n: sizeof(ifr));
2036 ifr.ifr_reqcap = cap_enable;
2037 return ifnet_ioctl(interface: ifp, protocol: 0, SIOCSIFCAP, ioctl_arg: &ifr);
2038}
2039
2040static const char *
2041enable_disable_str(boolean_t enable)
2042{
2043 return enable ? "enable" : "disable";
2044}
2045
2046static boolean_t
2047bridge_set_lro(struct ifnet * ifp, boolean_t enable)
2048{
2049 uint32_t cap_enable;
2050 uint32_t cap_supported;
2051 boolean_t changed = FALSE;
2052 boolean_t lro_enabled;
2053
2054 cap_supported = ifnet_capabilities_supported(interface: ifp);
2055 if ((cap_supported & IFCAP_LRO) == 0) {
2056 BRIDGE_LOG(LOG_NOTICE, BR_DBGF_LIFECYCLE,
2057 "%s doesn't support LRO",
2058 ifp->if_xname);
2059 goto done;
2060 }
2061 cap_enable = ifnet_capabilities_enabled(interface: ifp);
2062 lro_enabled = (cap_enable & IFCAP_LRO) != 0;
2063 if (lro_enabled != enable) {
2064 errno_t error;
2065
2066 if (enable) {
2067 cap_enable |= IFCAP_LRO;
2068 } else {
2069 cap_enable &= ~IFCAP_LRO;
2070 }
2071 error = siocsifcap(ifp, cap_enable);
2072 if (error != 0) {
2073 BRIDGE_LOG(LOG_NOTICE, 0,
2074 "%s %s failed (cap 0x%x) %d",
2075 ifp->if_xname,
2076 enable_disable_str(enable),
2077 cap_enable,
2078 error);
2079 } else {
2080 changed = TRUE;
2081 BRIDGE_LOG(LOG_NOTICE, BR_DBGF_LIFECYCLE,
2082 "%s %s success (cap 0x%x)",
2083 ifp->if_xname,
2084 enable_disable_str(enable),
2085 cap_enable);
2086 }
2087 }
2088done:
2089 return changed;
2090}
2091
2092static errno_t
2093bridge_set_tso(struct bridge_softc *sc)
2094{
2095 struct bridge_iflist *bif;
2096 u_int32_t tso_v4_mtu;
2097 u_int32_t tso_v6_mtu;
2098 ifnet_offload_t offload;
2099 errno_t error = 0;
2100
2101 /* By default, support TSO */
2102 offload = sc->sc_ifp->if_hwassist | IFNET_TSO_IPV4 | IFNET_TSO_IPV6;
2103 tso_v4_mtu = IP_MAXPACKET;
2104 tso_v6_mtu = IP_MAXPACKET;
2105
2106 /* Use the lowest common denominator of the members */
2107 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
2108 ifnet_t ifp = bif->bif_ifp;
2109
2110 if (ifp == NULL) {
2111 continue;
2112 }
2113
2114 if (offload & IFNET_TSO_IPV4) {
2115 if (ifp->if_hwassist & IFNET_TSO_IPV4) {
2116 if (tso_v4_mtu > ifp->if_tso_v4_mtu) {
2117 tso_v4_mtu = ifp->if_tso_v4_mtu;
2118 }
2119 } else {
2120 offload &= ~IFNET_TSO_IPV4;
2121 tso_v4_mtu = 0;
2122 }
2123 }
2124 if (offload & IFNET_TSO_IPV6) {
2125 if (ifp->if_hwassist & IFNET_TSO_IPV6) {
2126 if (tso_v6_mtu > ifp->if_tso_v6_mtu) {
2127 tso_v6_mtu = ifp->if_tso_v6_mtu;
2128 }
2129 } else {
2130 offload &= ~IFNET_TSO_IPV6;
2131 tso_v6_mtu = 0;
2132 }
2133 }
2134 }
2135
2136 if (offload != sc->sc_ifp->if_hwassist) {
2137 error = ifnet_set_offload(interface: sc->sc_ifp, offload);
2138 if (error != 0) {
2139 BRIDGE_LOG(LOG_NOTICE, BR_DBGF_LIFECYCLE,
2140 "ifnet_set_offload(%s, 0x%x) failed %d",
2141 sc->sc_ifp->if_xname, offload, error);
2142 goto done;
2143 }
2144 /*
2145 * For ifnet_set_tso_mtu() sake, the TSO MTU must be at least
2146 * as large as the interface MTU
2147 */
2148 if (sc->sc_ifp->if_hwassist & IFNET_TSO_IPV4) {
2149 if (tso_v4_mtu < sc->sc_ifp->if_mtu) {
2150 tso_v4_mtu = sc->sc_ifp->if_mtu;
2151 }
2152 error = ifnet_set_tso_mtu(interface: sc->sc_ifp, AF_INET,
2153 mtuLen: tso_v4_mtu);
2154 if (error != 0) {
2155 BRIDGE_LOG(LOG_NOTICE, BR_DBGF_LIFECYCLE,
2156 "ifnet_set_tso_mtu(%s, "
2157 "AF_INET, %u) failed %d",
2158 sc->sc_ifp->if_xname,
2159 tso_v4_mtu, error);
2160 goto done;
2161 }
2162 }
2163 if (sc->sc_ifp->if_hwassist & IFNET_TSO_IPV6) {
2164 if (tso_v6_mtu < sc->sc_ifp->if_mtu) {
2165 tso_v6_mtu = sc->sc_ifp->if_mtu;
2166 }
2167 error = ifnet_set_tso_mtu(interface: sc->sc_ifp, AF_INET6,
2168 mtuLen: tso_v6_mtu);
2169 if (error != 0) {
2170 BRIDGE_LOG(LOG_NOTICE, BR_DBGF_LIFECYCLE,
2171 "ifnet_set_tso_mtu(%s, "
2172 "AF_INET6, %u) failed %d",
2173 sc->sc_ifp->if_xname,
2174 tso_v6_mtu, error);
2175 goto done;
2176 }
2177 }
2178 }
2179done:
2180 return error;
2181}
2182
2183/*
2184 * bridge_lookup_member:
2185 *
2186 * Lookup a bridge member interface.
2187 */
2188static struct bridge_iflist *
2189bridge_lookup_member(struct bridge_softc *sc, const char *name)
2190{
2191 struct bridge_iflist *bif;
2192 struct ifnet *ifp;
2193
2194 BRIDGE_LOCK_ASSERT_HELD(sc);
2195
2196 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
2197 ifp = bif->bif_ifp;
2198 if (strcmp(s1: ifp->if_xname, s2: name) == 0) {
2199 return bif;
2200 }
2201 }
2202
2203 return NULL;
2204}
2205
2206/*
2207 * bridge_lookup_member_if:
2208 *
2209 * Lookup a bridge member interface by ifnet*.
2210 */
2211static struct bridge_iflist *
2212bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp)
2213{
2214 struct bridge_iflist *bif;
2215
2216 BRIDGE_LOCK_ASSERT_HELD(sc);
2217
2218 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) {
2219 if (bif->bif_ifp == member_ifp) {
2220 return bif;
2221 }
2222 }
2223
2224 return NULL;
2225}
2226
2227static errno_t
2228bridge_iff_input(void *cookie, ifnet_t ifp, protocol_family_t protocol,
2229 mbuf_t *data, char **frame_ptr)
2230{
2231#pragma unused(protocol)
2232 errno_t error = 0;
2233 struct bridge_iflist *bif = (struct bridge_iflist *)cookie;
2234 struct bridge_softc *sc = bif->bif_sc;
2235 int included = 0;
2236 size_t frmlen = 0;
2237 mbuf_t m = *data;
2238
2239 if ((m->m_flags & M_PROTO1)) {
2240 goto out;
2241 }
2242
2243 if (*frame_ptr >= (char *)mbuf_datastart(mbuf: m) &&
2244 *frame_ptr <= (char *)mbuf_data(mbuf: m)) {
2245 included = 1;
2246 frmlen = (char *)mbuf_data(mbuf: m) - *frame_ptr;
2247 }
2248 BRIDGE_LOG(LOG_DEBUG, BR_DBGF_INPUT,
2249 "%s from %s m 0x%llx data 0x%llx frame 0x%llx %s "
2250 "frmlen %lu", sc->sc_ifp->if_xname,
2251 ifp->if_xname, (uint64_t)VM_KERNEL_ADDRPERM(m),
2252 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_data(m)),
2253 (uint64_t)VM_KERNEL_ADDRPERM(*frame_ptr),
2254 included ? "inside" : "outside", frmlen);
2255 if (BRIDGE_DBGF_ENABLED(BR_DBGF_MBUF)) {
2256 brlog_mbuf(m, prefix: "bridge_iff_input[", suffix: "");
2257 brlog_ether_header(eh: (struct ether_header *)
2258 (void *)*frame_ptr);
2259 brlog_mbuf_data(m, offset: 0, len: 20);
2260 }
2261 if (included == 0) {
2262 BRIDGE_LOG(LOG_DEBUG, BR_DBGF_INPUT, "frame_ptr outside mbuf");
2263 goto out;
2264 }
2265
2266 /* Move data pointer to start of frame to the link layer header */
2267 (void) mbuf_setdata(mbuf: m, data: (char *)mbuf_data(mbuf: m) - frmlen,
2268 len: mbuf_len(mbuf: m) + frmlen);
2269 (void) mbuf_pkthdr_adjustlen(mbuf: m, amount: frmlen);
2270
2271 /* make sure we can access the ethernet header */
2272 if (mbuf_pkthdr_len(mbuf: m) < sizeof(struct ether_header)) {
2273 BRIDGE_LOG(LOG_DEBUG, BR_DBGF_INPUT,
2274 "short frame %lu < %lu",
2275 mbuf_pkthdr_len(m), sizeof(struct ether_header));
2276 goto out;
2277 }
2278 if (mbuf_len(mbuf: m) < sizeof(struct ether_header)) {
2279 error = mbuf_pullup(mbuf: data, len: sizeof(struct ether_header));
2280 if (error != 0) {
2281 BRIDGE_LOG(LOG_DEBUG, BR_DBGF_INPUT,
2282 "mbuf_pullup(%lu) failed %d",
2283 sizeof(struct ether_header),
2284 error);
2285 error = EJUSTRETURN;
2286 goto out;
2287 }
2288 if (m != *data) {
2289 m = *data;
2290 *frame_ptr = mbuf_data(mbuf: m);
2291 }
2292 }
2293
2294 error = bridge_input(ifp, data);
2295
2296 /* Adjust packet back to original */
2297 if (error == 0) {
2298 /* bridge_input might have modified *data */
2299 if (*data != m) {
2300 m = *data;
2301 *frame_ptr = mbuf_data(mbuf: m);
2302 }
2303 (void) mbuf_setdata(mbuf: m, data: (char *)mbuf_data(mbuf: m) + frmlen,
2304 len: mbuf_len(mbuf: m) - frmlen);
2305 (void) mbuf_pkthdr_adjustlen(mbuf: m, amount: -frmlen);
2306 }
2307
2308 if (BRIDGE_DBGF_ENABLED(BR_DBGF_MBUF) &&
2309 BRIDGE_DBGF_ENABLED(BR_DBGF_INPUT)) {
2310 brlog_mbuf(m, prefix: "bridge_iff_input]", suffix: "");
2311 }
2312
2313out:
2314 BRIDGE_LOCK_ASSERT_NOTHELD(sc);
2315
2316 return error;
2317}
2318
2319static errno_t
2320bridge_iff_output(void *cookie, ifnet_t ifp, protocol_family_t protocol,
2321 mbuf_t *data)
2322{
2323#pragma unused(protocol)
2324 errno_t error = 0;
2325 struct bridge_iflist *bif = (struct bridge_iflist *)cookie;
2326 struct bridge_softc *sc = bif->bif_sc;
2327 mbuf_t m = *data;
2328
2329 if ((m->m_flags & M_PROTO1)) {
2330 goto out;
2331 }
2332 BRIDGE_LOG(LOG_DEBUG, BR_DBGF_OUTPUT,
2333 "%s from %s m 0x%llx data 0x%llx",
2334 sc->sc_ifp->if_xname, ifp->if_xname,
2335 (uint64_t)VM_KERNEL_ADDRPERM(m),
2336 (uint64_t)VM_KERNEL_ADDRPERM(mbuf_data(m)));
2337
2338 error = bridge_member_output(sc, ifp, m: data);
2339 if (error != 0 && error != EJUSTRETURN) {
2340 BRIDGE_LOG(LOG_NOTICE, BR_DBGF_OUTPUT,
2341 "bridge_member_output failed error %d",
2342 error);
2343 }
2344out:
2345 BRIDGE_LOCK_ASSERT_NOTHELD(sc);
2346
2347 return error;
2348}
2349
2350static void
2351bridge_iff_event(void *cookie, ifnet_t ifp, protocol_family_t protocol,
2352 const struct kev_msg *event_msg)
2353{
2354#pragma unused(protocol)
2355 struct bridge_iflist *bif = (struct bridge_iflist *)cookie;
2356 struct bridge_softc *sc = bif->bif_sc;
2357
2358 if (event_msg->vendor_code == KEV_VENDOR_APPLE &&
2359 event_msg->kev_class == KEV_NETWORK_CLASS &&
2360 event_msg->kev_subclass == KEV_DL_SUBCLASS) {
2361 BRIDGE_LOG(LOG_DEBUG, BR_DBGF_LIFECYCLE,
2362 "%s event_code %u - %s",
2363 ifp->if_xname, event_msg->event_code,
2364 dlil_kev_dl_code_str(event_msg->event_code));
2365
2366 switch (event_msg->event_code) {
2367 case KEV_DL_LINK_OFF:
2368 case KEV_DL_LINK_ON: {
2369 bridge_iflinkevent(ifp);
2370#if BRIDGESTP
2371 bstp_linkstate(ifp, event_msg->event_code);
2372#endif /* BRIDGESTP */
2373 break;
2374 }
2375 case KEV_DL_SIFFLAGS: {
2376 if ((ifp->if_flags & IFF_UP) == 0) {
2377 break;
2378 }
2379 if ((bif->bif_flags & BIFF_PROMISC) == 0) {
2380 errno_t error;
2381
2382 error = ifnet_set_promiscuous(interface: ifp, on: 1);
2383 if (error != 0) {
2384 BRIDGE_LOG(LOG_NOTICE, 0,
2385 "ifnet_set_promiscuous (%s)"
2386 " failed %d", ifp->if_xname,
2387 error);
2388 } else {
2389 bif->bif_flags |= BIFF_PROMISC;
2390 }
2391 }
2392 if ((bif->bif_flags & BIFF_WIFI_INFRA) != 0 &&
2393 (bif->bif_flags & BIFF_ALL_MULTI) == 0) {
2394 errno_t error;
2395
2396 error = if_allmulti(ifp, 1);
2397 if (error != 0) {
2398 BRIDGE_LOG(LOG_NOTICE, 0,
2399 "if_allmulti (%s)"
2400 " failed %d", ifp->if_xname,
2401 error);
2402 } else {
2403 bif->bif_flags |= BIFF_ALL_MULTI;
2404#ifdef XNU_PLATFORM_AppleTVOS
2405 ip6_forwarding = 1;
2406#endif /* XNU_PLATFORM_AppleTVOS */
2407 }
2408 }
2409 break;
2410 }
2411 case KEV_DL_IFCAP_CHANGED: {
2412 BRIDGE_LOCK(sc);
2413 bridge_set_tso(sc);
2414 BRIDGE_UNLOCK(sc);
2415 break;
2416 }
2417 case KEV_DL_PROTO_DETACHED:
2418 case KEV_DL_PROTO_ATTACHED: {
2419 bridge_proto_attach_changed(ifp);
2420 break;
2421 }
2422 default:
2423 break;
2424 }
2425 }
2426}
2427
2428/*
2429 * bridge_iff_detached:
2430 *
2431 * Called when our interface filter has been detached from a
2432 * member interface.
2433 */
2434static void
2435bridge_iff_detached(void *cookie, ifnet_t ifp)
2436{
2437#pragma unused(cookie)
2438 struct bridge_iflist *bif;
2439 struct bridge_softc *sc = ifp->if_bridge;
2440
2441 BRIDGE_LOG(LOG_DEBUG, BR_DBGF_LIFECYCLE, "%s", ifp->if_xname);
2442
2443 /* Check if the interface is a bridge member */
2444 if (sc != NULL) {
2445 BRIDGE_LOCK(sc);
2446 bif = bridge_lookup_member_if(sc, member_ifp: ifp);
2447 if (bif != NULL) {
2448 bridge_delete_member(sc, bif);
2449 }
2450 BRIDGE_UNLOCK(sc);
2451 return;
2452 }
2453 /* Check if the interface is a span port */
2454 lck_mtx_lock(lck: &bridge_list_mtx);
2455 LIST_FOREACH(sc, &bridge_list, sc_list) {
2456 BRIDGE_LOCK(sc);
2457 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
2458 if (ifp == bif->bif_ifp) {
2459 bridge_delete_span(sc, bif);
2460 break;
2461 }
2462 BRIDGE_UNLOCK(sc);
2463 }
2464 lck_mtx_unlock(lck: &bridge_list_mtx);
2465}
2466
2467static errno_t
2468bridge_proto_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t packet,
2469 char *header)
2470{
2471#pragma unused(protocol, packet, header)
2472 BRIDGE_LOG(LOG_NOTICE, 0, "%s unexpected packet",
2473 ifp->if_xname);
2474 return 0;
2475}
2476
2477static int
2478bridge_attach_protocol(struct ifnet *ifp)
2479{
2480 int error;
2481 struct ifnet_attach_proto_param reg;
2482
2483 BRIDGE_LOG(LOG_DEBUG, BR_DBGF_LIFECYCLE, "%s", ifp->if_xname);
2484 bzero(s: &reg, n: sizeof(reg));
2485 reg.input = bridge_proto_input;
2486
2487 error = ifnet_attach_protocol(interface: ifp, PF_BRIDGE, proto_details: &reg);
2488 if (error) {
2489 BRIDGE_LOG(LOG_NOTICE, 0,
2490 "ifnet_attach_protocol(%s) failed, %d",
2491 ifp->if_xname, error);
2492 }
2493
2494 return error;
2495}
2496
2497static int
2498bridge_detach_protocol(struct ifnet *ifp)
2499{
2500 int error;
2501
2502 BRIDGE_LOG(LOG_DEBUG, BR_DBGF_LIFECYCLE, "%s", ifp->if_xname);
2503 error = ifnet_detach_protocol(interface: ifp, PF_BRIDGE);
2504 if (error) {
2505 BRIDGE_LOG(LOG_NOTICE, 0,
2506 "ifnet_detach_protocol(%s) failed, %d",
2507 ifp->if_xname, error);
2508 }
2509
2510 return error;
2511}
2512
2513/*
2514 * bridge_delete_member:
2515 *
2516 * Delete the specified member interface.
2517 */
2518static void
2519bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif)
2520{
2521#if SKYWALK
2522 boolean_t add_netagent = FALSE;
2523#endif /* SKYWALK */
2524 uint32_t bif_flags;
2525 struct ifnet *ifs = bif->bif_ifp, *bifp = sc->sc_ifp;
2526 int lladdr_changed = 0, error;
2527 uint8_t eaddr[ETHER_ADDR_LEN];
2528 u_int32_t event_code = 0;
2529
2530 BRIDGE_LOCK_ASSERT_HELD(sc);
2531 VERIFY(ifs != NULL);
2532
2533 /*
2534 * Remove the member from the list first so it cannot be found anymore
2535 * when we release the bridge lock below
2536 */
2537 if ((bif->bif_flags & BIFF_IN_MEMBER_LIST) != 0) {
2538 BRIDGE_XLOCK(sc);
2539 TAILQ_REMOVE(&sc->sc_iflist, bif, bif_next);
2540 BRIDGE_XDROP(sc);
2541 }
2542 if (sc->sc_mac_nat_bif != NULL) {
2543 if (bif == sc->sc_mac_nat_bif) {
2544 bridge_mac_nat_disable(sc);
2545 } else {
2546 bridge_mac_nat_flush_entries(sc, bif);
2547 }
2548 }
2549#if BRIDGESTP
2550 if ((bif->bif_ifflags & IFBIF_STP) != 0) {
2551 bstp_disable(&bif->bif_stp);
2552 }
2553#endif /* BRIDGESTP */
2554
2555 /*
2556 * If removing the interface that gave the bridge its mac address, set
2557 * the mac address of the bridge to the address of the next member, or
2558 * to its default address if no members are left.
2559 */
2560 if (bridge_inherit_mac && sc->sc_ifaddr == ifs) {
2561 ifnet_release(interface: sc->sc_ifaddr);
2562 if (TAILQ_EMPTY(&sc->sc_iflist)) {
2563 bcopy(src: sc->sc_defaddr, dst: eaddr, ETHER_ADDR_LEN);
2564 sc->sc_ifaddr = NULL;
2565 } else {
2566 struct ifnet *fif =
2567 TAILQ_FIRST(&sc->sc_iflist)->bif_ifp;
2568 bcopy(IF_LLADDR(fif), dst: eaddr, ETHER_ADDR_LEN);
2569 sc->sc_ifaddr = fif;
2570 ifnet_reference(interface: fif); /* for sc_ifaddr */
2571 }
2572 lladdr_changed = 1;
2573 }
2574
2575#if HAS_IF_CAP
2576 bridge_mutecaps(sc); /* recalculate now this interface is removed */
2577#endif /* HAS_IF_CAP */
2578
2579 error = bridge_set_tso(sc);
2580 if (error != 0) {
2581 BRIDGE_LOG(LOG_NOTICE, 0, "bridge_set_tso failed %d", error);
2582 }
2583
2584 bridge_rtdelete(sc, ifp: ifs, IFBF_FLUSHALL);
2585
2586 KASSERT(bif->bif_addrcnt == 0,
2587 ("%s: %d bridge routes referenced", __func__, bif->bif_addrcnt));
2588
2589 /*
2590 * Update link status of the bridge based on its remaining members
2591 */
2592 event_code = bridge_updatelinkstatus(sc);
2593 bif_flags = bif->bif_flags;
2594 BRIDGE_UNLOCK(sc);
2595
2596 /* only perform these steps if the interface is still attached */
2597 if (ifnet_is_attached(ifs, refio: 1)) {
2598#if SKYWALK
2599 add_netagent = (bif_flags & BIFF_NETAGENT_REMOVED) != 0;
2600
2601 if ((bif_flags & BIFF_FLOWSWITCH_ATTACHED) != 0) {
2602 ifnet_detach_flowswitch_nexus(ifp: ifs);
2603 }
2604#endif /* SKYWALK */
2605 /* disable promiscuous mode */
2606 if ((bif_flags & BIFF_PROMISC) != 0) {
2607 (void) ifnet_set_promiscuous(interface: ifs, on: 0);
2608 }
2609 /* disable all multi */
2610 if ((bif_flags & BIFF_ALL_MULTI) != 0) {
2611 (void)if_allmulti(ifs, 0);
2612 }
2613#if HAS_IF_CAP
2614 /* re-enable any interface capabilities */
2615 bridge_set_ifcap(sc, bif, bif->bif_savedcaps);
2616#endif
2617 /* detach bridge "protocol" */
2618 if ((bif_flags & BIFF_PROTO_ATTACHED) != 0) {
2619 (void)bridge_detach_protocol(ifp: ifs);
2620 }
2621 /* detach interface filter */
2622 if ((bif_flags & BIFF_FILTER_ATTACHED) != 0) {
2623 iflt_detach(filter_ref: bif->bif_iff_ref);
2624 }
2625 /* re-enable LRO */
2626 if ((bif_flags & BIFF_LRO_DISABLED) != 0) {
2627 (void)bridge_set_lro(ifp: ifs, TRUE);
2628 }
2629 ifnet_decr_iorefcnt(ifs);
2630 }
2631
2632 if (lladdr_changed &&
2633 (error = ifnet_set_lladdr(interface: bifp, lladdr: eaddr, ETHER_ADDR_LEN)) != 0) {
2634 BRIDGE_LOG(LOG_NOTICE, 0, "ifnet_set_lladdr failed %d", error);
2635 }
2636
2637 if (event_code != 0) {
2638 bridge_link_event(bifp, event_code);
2639 }
2640
2641#if BRIDGESTP
2642 bstp_destroy(&bif->bif_stp); /* prepare to free */
2643#endif /* BRIDGESTP */
2644
2645 kfree_type(struct bridge_iflist, bif);
2646 ifs->if_bridge = NULL;
2647#if SKYWALK
2648 if (add_netagent && ifnet_is_attached(ifs, refio: 1)) {
2649 (void)ifnet_add_netagent(ifp: ifs);
2650 ifnet_decr_iorefcnt(ifs);
2651 }
2652#endif /* SKYWALK */
2653
2654 ifnet_release(interface: ifs);
2655
2656 BRIDGE_LOCK(sc);
2657}
2658
2659/*
2660 * bridge_delete_span:
2661 *
2662 * Delete the specified span interface.
2663 */
2664static void
2665bridge_delete_span(struct bridge_softc *sc, struct bridge_iflist *bif)
2666{
2667 BRIDGE_LOCK_ASSERT_HELD(sc);
2668
2669 KASSERT(bif->bif_ifp->if_bridge == NULL,
2670 ("%s: not a span interface", __func__));
2671
2672 ifnet_release(interface: bif->bif_ifp);
2673
2674 TAILQ_REMOVE(&sc->sc_spanlist, bif, bif_next);
2675 kfree_type(struct bridge_iflist, bif);
2676}
2677
2678static int
2679bridge_ioctl_add(struct bridge_softc *sc, void *arg)
2680{
2681 struct ifbreq *req = arg;
2682 struct bridge_iflist *bif = NULL;
2683 struct ifnet *ifs, *bifp = sc->sc_ifp;
2684 int error = 0, lladdr_changed = 0;
2685 uint8_t eaddr[ETHER_ADDR_LEN];
2686 struct iff_filter iff;
2687 u_int32_t event_code = 0;
2688 boolean_t input_broadcast;
2689 int media_active;
2690 boolean_t wifi_infra = FALSE;
2691
2692 ifs = ifunit(req->ifbr_ifsname);
2693 if (ifs == NULL) {
2694 return ENOENT;
2695 }
2696 if (ifs->if_ioctl == NULL) { /* must be supported */
2697 return EINVAL;
2698 }
2699
2700 if (IFNET_IS_INTCOPROC(ifs) || IFNET_IS_MANAGEMENT(ifs)) {
2701 return EINVAL;
2702 }
2703
2704 /* If it's in the span list, it can't be a member. */
2705 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) {
2706 if (ifs == bif->bif_ifp) {
2707 return EBUSY;
2708 }
2709 }
2710
2711 if (ifs->if_bridge == sc) {
2712 return EEXIST;
2713 }
2714
2715 if (ifs->if_bridge != NULL) {
2716 return EBUSY;
2717 }
2718
2719 switch (ifs->if_type) {
2720 case IFT_ETHER:
2721 if (strcmp(s1: ifs->if_name, s2: "en") == 0 &&
2722 ifs->if_subfamily == IFNET_SUBFAMILY_WIFI &&
2723 (ifs->if_eflags & IFEF_IPV4_ROUTER) == 0) {
2724 /* XXX is there a better way to identify Wi-Fi STA? */
2725 wifi_infra = TRUE;
2726 }
2727 break;
2728 case IFT_L2VLAN:
2729 case IFT_IEEE8023ADLAG:
2730 break;
2731 case IFT_GIF:
2732 /* currently not supported */
2733 /* FALLTHRU */
2734 default:
2735 return EINVAL;
2736 }
2737
2738 /* fail to add the interface if the MTU doesn't match */
2739 if (!TAILQ_EMPTY(&sc->sc_iflist) && sc->sc_ifp->if_mtu != ifs->if_mtu) {
2740 BRIDGE_LOG(LOG_NOTICE, 0, "%s invalid MTU for %s",
2741 sc->sc_ifp->if_xname,
2742 ifs->if_xname);
2743 return EINVAL;
2744 }
2745
2746 /* there's already an interface that's doing MAC NAT */
2747 if (wifi_infra && sc->sc_mac_nat_bif != NULL) {
2748 return EBUSY;
2749 }
2750
2751 /* prevent the interface from detaching while we add the member */
2752 if (!ifnet_is_attached(ifs, refio: 1)) {
2753 return ENXIO;
2754 }
2755
2756 /* allocate a new member */
2757 bif = kalloc_type(struct bridge_iflist, Z_WAITOK | Z_ZERO | Z_NOFAIL);
2758 bif->bif_ifp = ifs;
2759 ifnet_reference(interface: ifs);
2760 bif->bif_ifflags |= IFBIF_LEARNING | IFBIF_DISCOVER;
2761#if HAS_IF_CAP
2762 bif->bif_savedcaps = ifs->if_capenable;
2763#endif /* HAS_IF_CAP */
2764 bif->bif_sc = sc;
2765 if (wifi_infra) {
2766 (void)bridge_mac_nat_enable(sc, bif);
2767 }
2768
2769 if (IFNET_IS_VMNET(ifs)) {
2770 allocate_vmnet_pf_tags();
2771 }
2772 /* Allow the first Ethernet member to define the MTU */
2773 if (TAILQ_EMPTY(&sc->sc_iflist)) {
2774 sc->sc_ifp->if_mtu = ifs->if_mtu;
2775 }
2776
2777 /*
2778 * Assign the interface's MAC address to the bridge if it's the first
2779 * member and the MAC address of the bridge has not been changed from
2780 * the default (randomly) generated one.
2781 */
2782 if (bridge_inherit_mac && TAILQ_EMPTY(&sc->sc_iflist) &&
2783 _ether_cmp(IF_LLADDR(sc->sc_ifp), b: sc->sc_defaddr) == 0) {
2784 bcopy(IF_LLADDR(ifs), dst: eaddr, ETHER_ADDR_LEN);
2785 sc->sc_ifaddr = ifs;
2786 ifnet_reference(interface: ifs); /* for sc_ifaddr */
2787 lladdr_changed = 1;
2788 }
2789
2790 ifs->if_bridge = sc;
2791#if BRIDGESTP
2792 bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp);
2793#endif /* BRIDGESTP */
2794
2795#if HAS_IF_CAP
2796 /* Set interface capabilities to the intersection set of all members */
2797 bridge_mutecaps(sc);
2798#endif /* HAS_IF_CAP */
2799
2800
2801 /*
2802 * Respect lock ordering with DLIL lock for the following operations
2803 */
2804 BRIDGE_UNLOCK(sc);
2805
2806 /* enable promiscuous mode */
2807 error = ifnet_set_promiscuous(interface: ifs, on: 1);
2808 switch (error) {
2809 case 0:
2810 bif->bif_flags |= BIFF_PROMISC;
2811 break;
2812 case ENETDOWN:
2813 case EPWROFF:
2814 BRIDGE_LOG(LOG_NOTICE, 0,
2815 "ifnet_set_promiscuous(%s) failed %d, ignoring",
2816 ifs->if_xname, error);
2817 /* Ignore error when device is not up */
2818 error = 0;
2819 break;
2820 default:
2821 BRIDGE_LOG(LOG_NOTICE, 0,
2822 "ifnet_set_promiscuous(%s) failed %d",
2823 ifs->if_xname, error);
2824 BRIDGE_LOCK(sc);
2825 goto out;
2826 }
2827 if (wifi_infra) {
2828 int this_error;
2829
2830 /* Wi-Fi doesn't really support promiscuous, set allmulti */
2831 bif->bif_flags |= BIFF_WIFI_INFRA;
2832 this_error = if_allmulti(ifs, 1);
2833 if (this_error == 0) {
2834 bif->bif_flags |= BIFF_ALL_MULTI;
2835#ifdef XNU_PLATFORM_AppleTVOS
2836 ip6_forwarding = 1;
2837#endif /* XNU_PLATFORM_AppleTVOS */
2838 } else {
2839 BRIDGE_LOG(LOG_NOTICE, 0,
2840 "if_allmulti(%s) failed %d, ignoring",
2841 ifs->if_xname, this_error);
2842 }
2843 }
2844#if SKYWALK
2845 /* ensure that the flowswitch is present for native interface */
2846 if (SKYWALK_NATIVE(ifs)) {
2847 if (ifnet_attach_flowswitch_nexus(ifp: ifs)) {
2848 bif->bif_flags |= BIFF_FLOWSWITCH_ATTACHED;
2849 }
2850 }
2851 /* remove the netagent on the flowswitch (rdar://75050182) */
2852 if (if_is_fsw_netagent_enabled()) {
2853 (void)ifnet_remove_netagent(ifp: ifs);
2854 bif->bif_flags |= BIFF_NETAGENT_REMOVED;
2855 }
2856#endif /* SKYWALK */
2857
2858 /*
2859 * install an interface filter
2860 */
2861 memset(s: &iff, c: 0, n: sizeof(struct iff_filter));
2862 iff.iff_cookie = bif;
2863 iff.iff_name = "com.apple.kernel.bsd.net.if_bridge";
2864 iff.iff_input = bridge_iff_input;
2865 iff.iff_output = bridge_iff_output;
2866 iff.iff_event = bridge_iff_event;
2867 iff.iff_detached = bridge_iff_detached;
2868 error = dlil_attach_filter(ifs, &iff, &bif->bif_iff_ref,
2869 DLIL_IFF_TSO | DLIL_IFF_INTERNAL);
2870 if (error != 0) {
2871 BRIDGE_LOG(LOG_NOTICE, 0, "iflt_attach failed %d", error);
2872 BRIDGE_LOCK(sc);
2873 goto out;
2874 }
2875 bif->bif_flags |= BIFF_FILTER_ATTACHED;
2876
2877 /*
2878 * install a dummy "bridge" protocol
2879 */
2880 if ((error = bridge_attach_protocol(ifp: ifs)) != 0) {
2881 if (error != 0) {
2882 BRIDGE_LOG(LOG_NOTICE, 0,
2883 "bridge_attach_protocol failed %d", error);
2884 BRIDGE_LOCK(sc);
2885 goto out;
2886 }
2887 }
2888 bif->bif_flags |= BIFF_PROTO_ATTACHED;
2889
2890 if (lladdr_changed &&
2891 (error = ifnet_set_lladdr(interface: bifp, lladdr: eaddr, ETHER_ADDR_LEN)) != 0) {
2892 BRIDGE_LOG(LOG_NOTICE, 0, "ifnet_set_lladdr failed %d", error);
2893 }
2894
2895 media_active = interface_media_active(ifs);
2896
2897 /* disable LRO */
2898 if (bridge_set_lro(ifp: ifs, FALSE)) {
2899 bif->bif_flags |= BIFF_LRO_DISABLED;
2900 }
2901
2902 /*
2903 * No failures past this point. Add the member to the list.
2904 */
2905 BRIDGE_LOCK(sc);
2906 bif->bif_flags |= BIFF_IN_MEMBER_LIST;
2907 BRIDGE_XLOCK(sc);
2908 TAILQ_INSERT_TAIL(&sc->sc_iflist, bif, bif_next);
2909 BRIDGE_XDROP(sc);
2910
2911 /* cache the member link status */
2912 if (media_active != 0) {
2913 bif->bif_flags |= BIFF_MEDIA_ACTIVE;
2914 } else {
2915 bif->bif_flags &= ~BIFF_MEDIA_ACTIVE;
2916 }
2917
2918 /* the new member may change the link status of the bridge interface */
2919 event_code = bridge_updatelinkstatus(sc);
2920
2921 /* check whether we need input broadcast or not */
2922 input_broadcast = interface_needs_input_broadcast(ifp: ifs);
2923 bif_set_input_broadcast(bif, input_broadcast);
2924 BRIDGE_UNLOCK(sc);
2925
2926 if (event_code != 0) {
2927 bridge_link_event(bifp, event_code);
2928 }
2929 BRIDGE_LOG(LOG_DEBUG, BR_DBGF_LIFECYCLE,
2930 "%s input broadcast %s", ifs->if_xname,
2931 input_broadcast ? "ENABLED" : "DISABLED");
2932
2933 BRIDGE_LOCK(sc);
2934 bridge_set_tso(sc);
2935
2936out:
2937 /* allow the interface to detach */
2938 ifnet_decr_iorefcnt(ifs);
2939
2940 if (error != 0) {
2941 if (bif != NULL) {
2942 bridge_delete_member(sc, bif);
2943 }
2944 } else if (IFNET_IS_VMNET(ifs)) {
2945 INC_ATOMIC_INT64_LIM(net_api_stats.nas_vmnet_total);
2946 }
2947
2948 return error;
2949}
2950
2951static int
2952bridge_ioctl_del(struct bridge_softc *sc, void *arg)
2953{
2954 struct ifbreq *req = arg;
2955 struct bridge_iflist *bif;
2956
2957 bif = bridge_lookup_member(sc, name: req->ifbr_ifsname);
2958 if (bif == NULL) {
2959 return ENOENT;
2960 }
2961
2962 bridge_delete_member(sc, bif);
2963
2964 return 0;
2965}
2966
2967static int
2968bridge_ioctl_purge(struct bridge_softc *sc, void *arg)
2969{
2970#pragma unused(sc, arg)
2971 return 0;
2972}
2973
2974static int
2975bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg)
2976{
2977 struct ifbreq *req = arg;
2978 struct bridge_iflist *bif;
2979
2980 bif = bridge_lookup_member(sc, name: req->ifbr_ifsname);
2981 if (bif == NULL) {
2982 return ENOENT;
2983 }
2984
2985 struct bstp_port *bp;
2986
2987 bp = &bif->bif_stp;
2988 req->ifbr_state = bp->bp_state;
2989 req->ifbr_priority = bp->bp_priority;
2990 req->ifbr_path_cost = bp->bp_path_cost;
2991 req->ifbr_proto = bp->bp_protover;
2992 req->ifbr_role = bp->bp_role;
2993 req->ifbr_stpflags = bp->bp_flags;
2994 req->ifbr_ifsflags = bif->bif_ifflags;
2995
2996 /* Copy STP state options as flags */
2997 if (bp->bp_operedge) {
2998 req->ifbr_ifsflags |= IFBIF_BSTP_EDGE;
2999 }
3000 if (bp->bp_flags & BSTP_PORT_AUTOEDGE) {
3001 req->ifbr_ifsflags |= IFBIF_BSTP_AUTOEDGE;
3002 }
3003 if (bp->bp_ptp_link) {
3004 req->ifbr_ifsflags |= IFBIF_BSTP_PTP;
3005 }
3006 if (bp->bp_flags & BSTP_PORT_AUTOPTP) {
3007 req->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
3008 }
3009 if (bp->bp_flags & BSTP_PORT_ADMEDGE) {
3010 req->ifbr_ifsflags |= IFBIF_BSTP_ADMEDGE;
3011 }
3012 if (bp->bp_flags & BSTP_PORT_ADMCOST) {
3013 req->ifbr_ifsflags |= IFBIF_BSTP_ADMCOST;
3014 }
3015
3016 req->ifbr_portno = bif->bif_ifp->if_index & 0xfff;
3017 req->ifbr_addrcnt = bif->bif_addrcnt;
3018 req->ifbr_addrmax = bif->bif_addrmax;
3019 req->ifbr_addrexceeded = bif->bif_addrexceeded;
3020
3021 return 0;
3022}
3023
3024static int
3025bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg)
3026{
3027 struct ifbreq *req = arg;
3028 struct bridge_iflist *bif;
3029#if BRIDGESTP
3030 struct bstp_port *bp;
3031 int error;
3032#endif /* BRIDGESTP */
3033
3034 bif = bridge_lookup_member(sc, name: req->ifbr_ifsname);
3035 if (bif == NULL) {
3036 return ENOENT;
3037 }
3038
3039 if (req->ifbr_ifsflags & IFBIF_SPAN) {
3040 /* SPAN is readonly */
3041 return EINVAL;
3042 }
3043#define _EXCLUSIVE_FLAGS (IFBIF_CHECKSUM_OFFLOAD | IFBIF_MAC_NAT)
3044 if ((req->ifbr_ifsflags & _EXCLUSIVE_FLAGS) == _EXCLUSIVE_FLAGS) {
3045 /* can't specify both MAC-NAT and checksum offload */
3046 return EINVAL;
3047 }
3048 if ((req->ifbr_ifsflags & IFBIF_MAC_NAT) != 0) {
3049 errno_t error;
3050
3051 error = bridge_mac_nat_enable(sc, bif);
3052 if (error != 0) {
3053 return error;
3054 }
3055 } else if (sc->sc_mac_nat_bif == bif) {
3056 bridge_mac_nat_disable(sc);
3057 }
3058
3059
3060#if BRIDGESTP
3061 if (req->ifbr_ifsflags & IFBIF_STP) {
3062 if ((bif->bif_ifflags & IFBIF_STP) == 0) {
3063 error = bstp_enable(&bif->bif_stp);
3064 if (error) {
3065 return error;
3066 }
3067 }
3068 } else {
3069 if ((bif->bif_ifflags & IFBIF_STP) != 0) {
3070 bstp_disable(&bif->bif_stp);
3071 }
3072 }
3073
3074 /* Pass on STP flags */
3075 bp = &bif->bif_stp;
3076 bstp_set_edge(bp, req->ifbr_ifsflags & IFBIF_BSTP_EDGE ? 1 : 0);
3077 bstp_set_autoedge(bp, req->ifbr_ifsflags & IFBIF_BSTP_AUTOEDGE ? 1 : 0);
3078 bstp_set_ptp(bp, req->ifbr_ifsflags & IFBIF_BSTP_PTP ? 1 : 0);
3079 bstp_set_autoptp(bp, req->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP ? 1 : 0);
3080#else /* !BRIDGESTP */
3081 if (req->ifbr_ifsflags & IFBIF_STP) {
3082 return EOPNOTSUPP;
3083 }
3084#endif /* !BRIDGESTP */
3085
3086 /* Save the bits relating to the bridge */
3087 bif->bif_ifflags = req->ifbr_ifsflags & IFBIFMASK;
3088
3089
3090 return 0;
3091}
3092
3093static int
3094bridge_ioctl_scache(struct bridge_softc *sc, void *arg)
3095{
3096 struct ifbrparam *param = arg;
3097
3098 sc->sc_brtmax = param->ifbrp_csize;
3099 bridge_rttrim(sc);
3100 return 0;
3101}
3102
3103static int
3104bridge_ioctl_gcache(struct bridge_softc *sc, void *arg)
3105{
3106 struct ifbrparam *param = arg;
3107
3108 param->ifbrp_csize = sc->sc_brtmax;
3109
3110 return 0;
3111}
3112
3113#define BRIDGE_IOCTL_GIFS do { \
3114 struct bridge_iflist *bif; \
3115 struct ifbreq breq; \
3116 char *buf, *outbuf; \
3117 unsigned int count, buflen, len; \
3118 \
3119 count = 0; \
3120 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) \
3121 count++; \
3122 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) \
3123 count++; \
3124 \
3125 buflen = sizeof (breq) * count; \
3126 if (bifc->ifbic_len == 0) { \
3127 bifc->ifbic_len = buflen; \
3128 return (0); \
3129 } \
3130 BRIDGE_UNLOCK(sc); \
3131 outbuf = (char *)kalloc_data(buflen, Z_WAITOK | Z_ZERO); \
3132 BRIDGE_LOCK(sc); \
3133 \
3134 count = 0; \
3135 buf = outbuf; \
3136 len = min(bifc->ifbic_len, buflen); \
3137 bzero(&breq, sizeof (breq)); \
3138 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) { \
3139 if (len < sizeof (breq)) \
3140 break; \
3141 \
3142 snprintf(breq.ifbr_ifsname, sizeof (breq.ifbr_ifsname), \
3143 "%s", bif->bif_ifp->if_xname); \
3144 /* Fill in the ifbreq structure */ \
3145 error = bridge_ioctl_gifflags(sc, &breq); \
3146 if (error) \
3147 break; \
3148 memcpy(buf, &breq, sizeof (breq)); \
3149 count++; \
3150 buf += sizeof (breq); \
3151 len -= sizeof (breq); \
3152 } \
3153 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) { \
3154 if (len < sizeof (breq)) \
3155 break; \
3156 \
3157 snprintf(breq.ifbr_ifsname, \
3158 sizeof (breq.ifbr_ifsname), \
3159 "%s", bif->bif_ifp->if_xname); \
3160 breq.ifbr_ifsflags = bif->bif_ifflags; \
3161 breq.ifbr_portno \
3162 = bif->bif_ifp->if_index & 0xfff; \
3163 memcpy(buf, &breq, sizeof (breq)); \
3164 count++; \
3165 buf += sizeof (breq); \
3166 len -= sizeof (breq); \
3167 } \
3168 \
3169 BRIDGE_UNLOCK(sc); \
3170 bifc->ifbic_len = sizeof (breq) * count; \
3171 error = copyout(outbuf, bifc->ifbic_req, bifc->ifbic_len); \
3172 BRIDGE_LOCK(sc); \
3173 kfree_data(outbuf, buflen); \
3174} while (0)
3175
3176static int
3177bridge_ioctl_gifs64(struct bridge_softc *sc, void *arg)
3178{
3179 struct ifbifconf64 *bifc = arg;
3180 int error = 0;
3181
3182 BRIDGE_IOCTL_GIFS;
3183
3184 return error;
3185}
3186
3187static int
3188bridge_ioctl_gifs32(struct bridge_softc *sc, void *arg)
3189{
3190 struct ifbifconf32 *bifc = arg;
3191 int error = 0;
3192
3193 BRIDGE_IOCTL_GIFS;
3194
3195 return error;
3196}
3197
3198#define BRIDGE_IOCTL_RTS do { \
3199 struct bridge_rtnode *brt; \
3200 char *buf; \
3201 char *outbuf = NULL; \
3202 unsigned int count, buflen, len; \
3203 unsigned long now; \
3204 \
3205 if (bac->ifbac_len == 0) \
3206 return (0); \
3207 \
3208 bzero(&bareq, sizeof (bareq)); \
3209 count = 0; \
3210 LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) \
3211 count++; \
3212 buflen = sizeof (bareq) * count; \
3213 \
3214 BRIDGE_UNLOCK(sc); \
3215 outbuf = (char *)kalloc_data(buflen, Z_WAITOK | Z_ZERO); \
3216 BRIDGE_LOCK(sc); \
3217 \
3218 count = 0; \
3219 buf = outbuf; \
3220 len = min(bac->ifbac_len, buflen); \
3221 LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { \
3222 if (len < sizeof (bareq)) \
3223 goto out; \
3224 snprintf(bareq.ifba_ifsname, sizeof (bareq.ifba_ifsname), \
3225 "%s", brt->brt_ifp->if_xname); \
3226 memcpy(bareq.ifba_dst, brt->brt_addr, sizeof (brt->brt_addr)); \
3227 bareq.ifba_vlan = brt->brt_vlan; \
3228 if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { \
3229 now = (unsigned long) net_uptime(); \
3230 if (now < brt->brt_expire) \
3231 bareq.ifba_expire = \
3232 brt->brt_expire - now; \
3233 } else \
3234 bareq.ifba_expire = 0; \
3235 bareq.ifba_flags = brt->brt_flags; \
3236 \
3237 memcpy(buf, &bareq, sizeof (bareq)); \
3238 count++; \
3239 buf += sizeof (bareq); \
3240 len -= sizeof (bareq); \
3241 } \
3242out: \
3243 bac->ifbac_len = sizeof (bareq) * count; \
3244 if (outbuf != NULL) { \
3245 BRIDGE_UNLOCK(sc); \
3246 error = copyout(outbuf, bac->ifbac_req, bac->ifbac_len); \
3247 kfree_data(outbuf, buflen); \
3248 BRIDGE_LOCK(sc); \
3249 } \
3250 return (error); \
3251} while (0)
3252
3253static int
3254bridge_ioctl_rts64(struct bridge_softc *sc, void *arg)
3255{
3256 struct ifbaconf64 *bac = arg;
3257 struct ifbareq64 bareq;
3258 int error = 0;
3259
3260 BRIDGE_IOCTL_RTS;
3261 return error;
3262}
3263
3264static int
3265bridge_ioctl_rts32(struct bridge_softc *sc, void *arg)
3266{
3267 struct ifbaconf32 *bac = arg;
3268 struct ifbareq32 bareq;
3269 int error = 0;
3270
3271 BRIDGE_IOCTL_RTS;
3272 return error;
3273}
3274
3275static int
3276bridge_ioctl_saddr32(struct bridge_softc *sc, void *arg)
3277{
3278 struct ifbareq32 *req = arg;
3279 struct bridge_iflist *bif;
3280 int error;
3281
3282 bif = bridge_lookup_member(sc, name: req->ifba_ifsname);
3283 if (bif == NULL) {
3284 return ENOENT;
3285 }
3286
3287 error = bridge_rtupdate(sc, req->ifba_dst, req->ifba_vlan, bif, 1,
3288 req->ifba_flags);
3289
3290 return error;
3291}
3292
3293static int
3294bridge_ioctl_saddr64(struct bridge_softc *sc, void *arg)
3295{
3296 struct ifbareq64 *req = arg;
3297 struct bridge_iflist *bif;
3298 int error;
3299
3300 bif = bridge_lookup_member(sc, name: req->ifba_ifsname);
3301 if (bif == NULL) {
3302 return ENOENT;
3303 }
3304
3305 error = bridge_rtupdate(sc, req->ifba_dst, req->ifba_vlan, bif, 1,
3306 req->ifba_flags);
3307
3308 return error;
3309}
3310
3311static int
3312bridge_ioctl_sto(struct bridge_softc *sc, void *arg)
3313{
3314 struct ifbrparam *param = arg;
3315
3316 sc->sc_brttimeout = param->ifbrp_ctime;
3317 return 0;
3318}
3319
3320static int
3321bridge_ioctl_gto(struct bridge_softc *sc, void *arg)
3322{
3323 struct ifbrparam *param = arg;
3324
3325 param->ifbrp_ctime = sc->sc_brttimeout;
3326 return 0;
3327}
3328
3329static int
3330bridge_ioctl_daddr32(struct bridge_softc *sc, void *arg)
3331{
3332 struct ifbareq32 *req = arg;
3333
3334 return bridge_rtdaddr(sc, req->ifba_dst, req->ifba_vlan);
3335}
3336
3337static int
3338bridge_ioctl_daddr64(struct bridge_softc *sc, void *arg)
3339{
3340 struct ifbareq64 *req = arg;
3341
3342 return bridge_rtdaddr(sc, req->ifba_dst, req->ifba_vlan);
3343}
3344
3345static int
3346bridge_ioctl_flush(struct bridge_softc *sc, void *arg)
3347{
3348 struct ifbreq *req = arg;
3349
3350 bridge_rtflush(sc, req->ifbr_ifsflags);
3351 return 0;
3352}
3353
3354static int
3355bridge_ioctl_gpri(struct bridge_softc *sc, void *arg)
3356{
3357 struct ifbrparam *param = arg;
3358 struct bstp_state *bs = &sc->sc_stp;
3359
3360 param->ifbrp_prio = bs->bs_bridge_priority;
3361 return 0;
3362}
3363
3364static int
3365bridge_ioctl_spri(struct bridge_softc *sc, void *arg)
3366{
3367#if BRIDGESTP
3368 struct ifbrparam *param = arg;
3369
3370 return bstp_set_priority(&sc->sc_stp, param->ifbrp_prio);
3371#else /* !BRIDGESTP */
3372#pragma unused(sc, arg)
3373 return EOPNOTSUPP;
3374#endif /* !BRIDGESTP */
3375}
3376
3377static int
3378bridge_ioctl_ght(struct bridge_softc *sc, void *arg)
3379{
3380 struct ifbrparam *param = arg;
3381 struct bstp_state *bs = &sc->sc_stp;
3382
3383 param->ifbrp_hellotime = bs->bs_bridge_htime >> 8;
3384 return 0;
3385}
3386
3387static int
3388bridge_ioctl_sht(struct bridge_softc *sc, void *arg)
3389{
3390#if BRIDGESTP
3391 struct ifbrparam *param = arg;
3392
3393 return bstp_set_htime(&sc->sc_stp, param->ifbrp_hellotime);
3394#else /* !BRIDGESTP */
3395#pragma unused(sc, arg)
3396 return EOPNOTSUPP;
3397#endif /* !BRIDGESTP */
3398}
3399
3400static int
3401bridge_ioctl_gfd(struct bridge_softc *sc, void *arg)
3402{
3403 struct ifbrparam *param;
3404 struct bstp_state *bs;
3405
3406 param = arg;
3407 bs = &sc->sc_stp;
3408 param->ifbrp_fwddelay = bs->bs_bridge_fdelay >> 8;
3409 return 0;
3410}
3411
3412static int
3413bridge_ioctl_sfd(struct bridge_softc *sc, void *arg)
3414{
3415#if BRIDGESTP
3416 struct ifbrparam *param = arg;
3417
3418 return bstp_set_fdelay(&sc->sc_stp, param->ifbrp_fwddelay);
3419#else /* !BRIDGESTP */
3420#pragma unused(sc, arg)
3421 return EOPNOTSUPP;
3422#endif /* !BRIDGESTP */
3423}
3424
3425static int
3426bridge_ioctl_gma(struct bridge_softc *sc, void *arg)
3427{
3428 struct ifbrparam *param;
3429 struct bstp_state *bs;
3430
3431 param = arg;
3432 bs = &sc->sc_stp;
3433 param->ifbrp_maxage = bs->bs_bridge_max_age >> 8;
3434 return 0;
3435}
3436
3437static int
3438bridge_ioctl_sma(struct bridge_softc *sc, void *arg)
3439{
3440#if BRIDGESTP
3441 struct ifbrparam *param = arg;
3442
3443 return bstp_set_maxage(&sc->sc_stp, param->ifbrp_maxage);
3444#else /* !BRIDGESTP */
3445#pragma unused(sc, arg)
3446 return EOPNOTSUPP;
3447#endif /* !BRIDGESTP */
3448}
3449
3450static int
3451bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg)
3452{
3453#if BRIDGESTP
3454 struct ifbreq *req = arg;
3455 struct bridge_iflist *bif;
3456
3457 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
3458 if (bif == NULL) {
3459 return ENOENT;
3460 }
3461
3462 return bstp_set_port_priority(&bif->bif_stp, req->ifbr_priority);
3463#else /* !BRIDGESTP */
3464#pragma unused(sc, arg)
3465 return EOPNOTSUPP;
3466#endif /* !BRIDGESTP */
3467}
3468
3469static int
3470bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg)
3471{
3472#if BRIDGESTP
3473 struct ifbreq *req = arg;
3474 struct bridge_iflist *bif;
3475
3476 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
3477 if (bif == NULL) {
3478 return ENOENT;
3479 }
3480
3481 return bstp_set_path_cost(&bif->bif_stp, req->ifbr_path_cost);
3482#else /* !BRIDGESTP */
3483#pragma unused(sc, arg)
3484 return EOPNOTSUPP;
3485#endif /* !BRIDGESTP */
3486}
3487
3488static int
3489bridge_ioctl_gfilt(struct bridge_softc *sc, void *arg)
3490{
3491 struct ifbrparam *param = arg;
3492
3493 param->ifbrp_filter = sc->sc_filter_flags;
3494
3495 return 0;
3496}
3497
3498static int
3499bridge_ioctl_sfilt(struct bridge_softc *sc, void *arg)
3500{
3501 struct ifbrparam *param = arg;
3502
3503 if (param->ifbrp_filter & ~IFBF_FILT_MASK) {
3504 return EINVAL;
3505 }
3506
3507 if (param->ifbrp_filter & IFBF_FILT_USEIPF) {
3508 return EINVAL;
3509 }
3510
3511 sc->sc_filter_flags = param->ifbrp_filter;
3512
3513 return 0;
3514}
3515
3516static int
3517bridge_ioctl_sifmaxaddr(struct bridge_softc *sc, void *arg)
3518{
3519 struct ifbreq *req = arg;
3520 struct bridge_iflist *bif;
3521
3522 bif = bridge_lookup_member(sc, name: req->ifbr_ifsname);
3523 if (bif == NULL) {
3524 return ENOENT;
3525 }
3526
3527 bif->bif_addrmax = req->ifbr_addrmax;
3528 return 0;
3529}
3530
3531static int
3532bridge_ioctl_addspan(struct bridge_softc *sc, void *arg)
3533{
3534 struct ifbreq *req = arg;
3535 struct bridge_iflist *bif = NULL;
3536 struct ifnet *ifs;
3537
3538 ifs = ifunit(req->ifbr_ifsname);
3539 if (ifs == NULL) {
3540 return ENOENT;
3541 }
3542
3543 if (IFNET_IS_INTCOPROC(ifs) || IFNET_IS_MANAGEMENT(ifs)) {
3544 return EINVAL;
3545 }
3546
3547 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
3548 if (ifs == bif->bif_ifp) {
3549 return EBUSY;
3550 }
3551
3552 if (ifs->if_bridge != NULL) {
3553 return EBUSY;
3554 }
3555
3556 switch (ifs->if_type) {
3557 case IFT_ETHER:
3558 case IFT_L2VLAN:
3559 case IFT_IEEE8023ADLAG:
3560 break;
3561 case IFT_GIF:
3562 /* currently not supported */
3563 /* FALLTHRU */
3564 default:
3565 return EINVAL;
3566 }
3567
3568 bif = kalloc_type(struct bridge_iflist, Z_WAITOK | Z_ZERO | Z_NOFAIL);
3569
3570 bif->bif_ifp = ifs;
3571 bif->bif_ifflags = IFBIF_SPAN;
3572
3573 ifnet_reference(interface: bif->bif_ifp);
3574
3575 TAILQ_INSERT_HEAD(&sc->sc_spanlist, bif, bif_next);
3576
3577 return 0;
3578}
3579
3580static int
3581bridge_ioctl_delspan(struct bridge_softc *sc, void *arg)
3582{
3583 struct ifbreq *req = arg;
3584 struct bridge_iflist *bif;
3585 struct ifnet *ifs;
3586
3587 ifs = ifunit(req->ifbr_ifsname);
3588 if (ifs == NULL) {
3589 return ENOENT;
3590 }
3591
3592 TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
3593 if (ifs == bif->bif_ifp) {
3594 break;
3595 }
3596
3597 if (bif == NULL) {
3598 return ENOENT;
3599 }
3600
3601 bridge_delete_span(sc, bif);
3602
3603 return 0;
3604}
3605
3606#define BRIDGE_IOCTL_GBPARAM do { \
3607 struct bstp_state *bs = &sc->sc_stp; \
3608 struct bstp_port *root_port; \
3609 \
3610 req->ifbop_maxage = bs->bs_bridge_max_age >> 8; \
3611 req->ifbop_hellotime = bs->bs_bridge_htime >> 8; \
3612 req->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8; \
3613 \
3614 root_port = bs->bs_root_port; \
3615 if (root_port == NULL) \
3616 req->ifbop_root_port = 0; \
3617 else \
3618 req->ifbop_root_port = root_port->bp_ifp->if_index; \
3619 \
3620 req->ifbop_holdcount = bs->bs_txholdcount; \
3621 req->ifbop_priority = bs->bs_bridge_priority; \
3622 req->ifbop_protocol = bs->bs_protover; \
3623 req->ifbop_root_path_cost = bs->bs_root_pv.pv_cost; \
3624 req->ifbop_bridgeid = bs->bs_bridge_pv.pv_dbridge_id; \
3625 req->ifbop_designated_root = bs->bs_root_pv.pv_root_id; \
3626 req->ifbop_designated_bridge = bs->bs_root_pv.pv_dbridge_id; \
3627 req->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec; \
3628 req->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec; \
3629} while (0)
3630
3631static int
3632bridge_ioctl_gbparam32(struct bridge_softc *sc, void *arg)
3633{
3634 struct ifbropreq32 *req = arg;
3635
3636 BRIDGE_IOCTL_GBPARAM;
3637 return 0;
3638}
3639
3640static int
3641bridge_ioctl_gbparam64(struct bridge_softc *sc, void *arg)
3642{
3643 struct ifbropreq64 *req = arg;
3644
3645 BRIDGE_IOCTL_GBPARAM;
3646 return 0;
3647}
3648
3649static int
3650bridge_ioctl_grte(struct bridge_softc *sc, void *arg)
3651{
3652 struct ifbrparam *param = arg;
3653
3654 param->ifbrp_cexceeded = sc->sc_brtexceeded;
3655 return 0;
3656}
3657
3658#define BRIDGE_IOCTL_GIFSSTP do { \
3659 struct bridge_iflist *bif; \
3660 struct bstp_port *bp; \
3661 struct ifbpstpreq bpreq; \
3662 char *buf, *outbuf; \
3663 unsigned int count, buflen, len; \
3664 \
3665 count = 0; \
3666 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) { \
3667 if ((bif->bif_ifflags & IFBIF_STP) != 0) \
3668 count++; \
3669 } \
3670 \
3671 buflen = sizeof (bpreq) * count; \
3672 if (bifstp->ifbpstp_len == 0) { \
3673 bifstp->ifbpstp_len = buflen; \
3674 return (0); \
3675 } \
3676 \
3677 BRIDGE_UNLOCK(sc); \
3678 outbuf = (char *)kalloc_data(buflen, Z_WAITOK | Z_ZERO); \
3679 BRIDGE_LOCK(sc); \
3680 \
3681 count = 0; \
3682 buf = outbuf; \
3683 len = min(bifstp->ifbpstp_len, buflen); \
3684 bzero(&bpreq, sizeof (bpreq)); \
3685 TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next) { \
3686 if (len < sizeof (bpreq)) \
3687 break; \
3688 \
3689 if ((bif->bif_ifflags & IFBIF_STP) == 0) \
3690 continue; \
3691 \
3692 bp = &bif->bif_stp; \
3693 bpreq.ifbp_portno = bif->bif_ifp->if_index & 0xfff; \
3694 bpreq.ifbp_fwd_trans = bp->bp_forward_transitions; \
3695 bpreq.ifbp_design_cost = bp->bp_desg_pv.pv_cost; \
3696 bpreq.ifbp_design_port = bp->bp_desg_pv.pv_port_id; \
3697 bpreq.ifbp_design_bridge = bp->bp_desg_pv.pv_dbridge_id; \
3698 bpreq.ifbp_design_root = bp->bp_desg_pv.pv_root_id; \
3699 \
3700 memcpy(buf, &bpreq, sizeof (bpreq)); \
3701 count++; \
3702 buf += sizeof (bpreq); \
3703 len -= sizeof (bpreq); \
3704 } \
3705 \
3706 BRIDGE_UNLOCK(sc); \
3707 bifstp->ifbpstp_len = sizeof (bpreq) * count; \
3708 error = copyout(outbuf, bifstp->ifbpstp_req, bifstp->ifbpstp_len); \
3709 BRIDGE_LOCK(sc); \
3710 kfree_data(outbuf, buflen); \
3711 return (error); \
3712} while (0)
3713
3714static int
3715bridge_ioctl_gifsstp32(struct bridge_softc *sc, void *arg)
3716{
3717 struct ifbpstpconf32 *bifstp = arg;
3718 int error = 0;
3719
3720 BRIDGE_IOCTL_GIFSSTP;
3721 return error;
3722}
3723
3724static int
3725bridge_ioctl_gifsstp64(struct bridge_softc *sc, void *arg)
3726{
3727 struct ifbpstpconf64 *bifstp = arg;
3728 int error = 0;
3729
3730 BRIDGE_IOCTL_GIFSSTP;
3731 return error;
3732}
3733
3734static int
3735bridge_ioctl_sproto(struct bridge_softc *sc, void *arg)
3736{
3737#if BRIDGESTP
3738 struct ifbrparam *param = arg;
3739
3740 return bstp_set_protocol(&sc->sc_stp, param->ifbrp_proto);
3741#else /* !BRIDGESTP */
3742#pragma unused(sc, arg)
3743 return EOPNOTSUPP;
3744#endif /* !BRIDGESTP */
3745}
3746
3747static int
3748bridge_ioctl_stxhc(struct bridge_softc *sc, void *arg)
3749{
3750#if BRIDGESTP
3751 struct ifbrparam *param = arg;
3752
3753 return bstp_set_holdcount(&sc->sc_stp, param->ifbrp_txhc);
3754#else /* !BRIDGESTP */
3755#pragma unused(sc, arg)
3756 return EOPNOTSUPP;
3757#endif /* !BRIDGESTP */
3758}
3759
3760
3761static int
3762bridge_ioctl_ghostfilter(struct bridge_softc *sc, void *arg)
3763{
3764 struct ifbrhostfilter *req = arg;
3765 struct bridge_iflist *bif;
3766
3767 bif = bridge_lookup_member(sc, name: req->ifbrhf_ifsname);
3768 if (bif == NULL) {
3769 return ENOENT;
3770 }
3771
3772 bzero(s: req, n: sizeof(struct ifbrhostfilter));
3773 if (bif->bif_flags & BIFF_HOST_FILTER) {
3774 req->ifbrhf_flags |= IFBRHF_ENABLED;
3775 bcopy(src: bif->bif_hf_hwsrc, dst: req->ifbrhf_hwsrca,
3776 ETHER_ADDR_LEN);
3777 req->ifbrhf_ipsrc = bif->bif_hf_ipsrc.s_addr;
3778 }
3779 return 0;
3780}
3781
3782static int
3783bridge_ioctl_shostfilter(struct bridge_softc *sc, void *arg)
3784{
3785 struct ifbrhostfilter *req = arg;
3786 struct bridge_iflist *bif;
3787
3788 bif = bridge_lookup_member(sc, name: req->ifbrhf_ifsname);
3789 if (bif == NULL) {
3790 return ENOENT;
3791 }
3792
3793 if (req->ifbrhf_flags & IFBRHF_ENABLED) {
3794 bif->bif_flags |= BIFF_HOST_FILTER;
3795
3796 if (req->ifbrhf_flags & IFBRHF_HWSRC) {
3797 bcopy(src: req->ifbrhf_hwsrca, dst: bif->bif_hf_hwsrc,
3798 ETHER_ADDR_LEN);
3799 if (bcmp(s1: req->ifbrhf_hwsrca, s2: ethernulladdr,
3800 ETHER_ADDR_LEN) != 0) {
3801 bif->bif_flags |= BIFF_HF_HWSRC;
3802 } else {
3803 bif->bif_flags &= ~BIFF_HF_HWSRC;
3804 }
3805 }
3806 if (req->ifbrhf_flags & IFBRHF_IPSRC) {
3807 bif->bif_hf_ipsrc.s_addr = req->ifbrhf_ipsrc;
3808 if (bif->bif_hf_ipsrc.s_addr != INADDR_ANY) {
3809 bif->bif_flags |= BIFF_HF_IPSRC;
3810 } else {
3811 bif->bif_flags &= ~BIFF_HF_IPSRC;
3812 }
3813 }
3814 } else {
3815 bif->bif_flags &= ~(BIFF_HOST_FILTER | BIFF_HF_HWSRC |
3816 BIFF_HF_IPSRC);
3817 bzero(s: bif->bif_hf_hwsrc, ETHER_ADDR_LEN);
3818 bif->bif_hf_ipsrc.s_addr = INADDR_ANY;
3819 }
3820
3821 return 0;
3822}
3823
3824static char *
3825bridge_mac_nat_entry_out(struct mac_nat_entry_list * list,
3826 unsigned int * count_p, char *buf, unsigned int *len_p)
3827{
3828 unsigned int count = *count_p;
3829 struct ifbrmne ifbmne;
3830 unsigned int len = *len_p;
3831 struct mac_nat_entry *mne;
3832 unsigned long now;
3833
3834 bzero(s: &ifbmne, n: sizeof(ifbmne));
3835 LIST_FOREACH(mne, list, mne_list) {
3836 if (len < sizeof(ifbmne)) {
3837 break;
3838 }
3839 snprintf(ifbmne.ifbmne_ifname, count: sizeof(ifbmne.ifbmne_ifname),
3840 "%s", mne->mne_bif->bif_ifp->if_xname);
3841 memcpy(dst: ifbmne.ifbmne_mac, src: mne->mne_mac,
3842 n: sizeof(ifbmne.ifbmne_mac));
3843 now = (unsigned long) net_uptime();
3844 if (now < mne->mne_expire) {
3845 ifbmne.ifbmne_expire = mne->mne_expire - now;
3846 } else {
3847 ifbmne.ifbmne_expire = 0;
3848 }
3849 if ((mne->mne_flags & MNE_FLAGS_IPV6) != 0) {
3850 ifbmne.ifbmne_af = AF_INET6;
3851 ifbmne.ifbmne_ip6_addr = mne->mne_ip6;
3852 } else {
3853 ifbmne.ifbmne_af = AF_INET;
3854 ifbmne.ifbmne_ip_addr = mne->mne_ip;
3855 }
3856 memcpy(dst: buf, src: &ifbmne, n: sizeof(ifbmne));
3857 count++;
3858 buf += sizeof(ifbmne);
3859 len -= sizeof(ifbmne);
3860 }
3861 *count_p = count;
3862 *len_p = len;
3863 return buf;
3864}
3865
3866/*
3867 * bridge_ioctl_gmnelist()
3868 * Perform the get mac_nat_entry list ioctl.
3869 *
3870 * Note:
3871 * The struct ifbrmnelist32 and struct ifbrmnelist64 have the same
3872 * field size/layout except for the last field ifbml_buf, the user-supplied
3873 * buffer pointer. That is passed in separately via the 'user_addr'
3874 * parameter from the respective 32-bit or 64-bit ioctl routine.
3875 */
3876static int
3877bridge_ioctl_gmnelist(struct bridge_softc *sc, struct ifbrmnelist32 *mnl,
3878 user_addr_t user_addr)
3879{
3880 unsigned int count;
3881 char *buf;
3882 int error = 0;
3883 char *outbuf = NULL;
3884 struct mac_nat_entry *mne;
3885 unsigned int buflen;
3886 unsigned int len;
3887
3888 mnl->ifbml_elsize = sizeof(struct ifbrmne);
3889 count = 0;
3890 LIST_FOREACH(mne, &sc->sc_mne_list, mne_list) {
3891 count++;
3892 }
3893 LIST_FOREACH(mne, &sc->sc_mne_list_v6, mne_list) {
3894 count++;
3895 }
3896 buflen = sizeof(struct ifbrmne) * count;
3897 if (buflen == 0 || mnl->ifbml_len == 0) {
3898 mnl->ifbml_len = buflen;
3899 return error;
3900 }
3901 BRIDGE_UNLOCK(sc);
3902 outbuf = (char *)kalloc_data(buflen, Z_WAITOK | Z_ZERO);
3903 BRIDGE_LOCK(sc);
3904 count = 0;
3905 buf = outbuf;
3906 len = min(a: mnl->ifbml_len, b: buflen);
3907 buf = bridge_mac_nat_entry_out(list: &sc->sc_mne_list, count_p: &count, buf, len_p: &len);
3908 buf = bridge_mac_nat_entry_out(list: &sc->sc_mne_list_v6, count_p: &count, buf, len_p: &len);
3909 mnl->ifbml_len = count * sizeof(struct ifbrmne);
3910 BRIDGE_UNLOCK(sc);
3911 error = copyout(outbuf, user_addr, mnl->ifbml_len);
3912 kfree_data(outbuf, buflen);
3913 BRIDGE_LOCK(sc);
3914 return error;
3915}
3916
3917static int
3918bridge_ioctl_gmnelist64(struct bridge_softc *sc, void *arg)
3919{
3920 struct ifbrmnelist64 *mnl = arg;
3921
3922 return bridge_ioctl_gmnelist(sc, mnl: arg, user_addr: mnl->ifbml_buf);
3923}
3924
3925static int
3926bridge_ioctl_gmnelist32(struct bridge_softc *sc, void *arg)
3927{
3928 struct ifbrmnelist32 *mnl = arg;
3929
3930 return bridge_ioctl_gmnelist(sc, mnl: arg,
3931 CAST_USER_ADDR_T(mnl->ifbml_buf));
3932}
3933
3934/*
3935 * bridge_ioctl_gifstats()
3936 * Return per-member stats.
3937 *
3938 * Note:
3939 * The ifbrmreq32 and ifbrmreq64 structures have the same
3940 * field size/layout except for the last field brmr_buf, the user-supplied
3941 * buffer pointer. That is passed in separately via the 'user_addr'
3942 * parameter from the respective 32-bit or 64-bit ioctl routine.
3943 */
3944static int
3945bridge_ioctl_gifstats(struct bridge_softc *sc, struct ifbrmreq32 *mreq,
3946 user_addr_t user_addr)
3947{
3948 struct bridge_iflist *bif;
3949 int error = 0;
3950 unsigned int buflen;
3951
3952 bif = bridge_lookup_member(sc, name: mreq->brmr_ifname);
3953 if (bif == NULL) {
3954 error = ENOENT;
3955 goto done;
3956 }
3957
3958 buflen = mreq->brmr_elsize = sizeof(struct ifbrmstats);
3959 if (buflen == 0 || mreq->brmr_len == 0) {
3960