]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/if_bridge.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / bsd / net / if_bridge.c
index 37bea9581365c1a874d034993df8b6cca58459f0..33ae35c66f23266b1e6abe01a47427c3de3ffc10 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2014 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2018 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 #include <net/if_types.h>
 #include <net/if_var.h>
 #include <net/if_media.h>
+#include <net/net_api_stats.h>
 
 #include <netinet/in.h> /* for struct arpcom */
 #include <netinet/in_systm.h>
 #include <netinet/bootp.h>
 #include <netinet/dhcp.h>
 
+
 #if BRIDGE_DEBUG
 #define        BR_DBGF_LIFECYCLE       0x0001
 #define        BR_DBGF_INPUT           0x0002
-#define        BR_DBGF_OUTPPUT         0x0004
+#define        BR_DBGF_OUTPUT          0x0004
 #define        BR_DBGF_RT_TABLE        0x0008
 #define        BR_DBGF_DELAYED_CALL    0x0010
 #define        BR_DBGF_IOCTL           0x0020
 #define        _BRIDGE_LOCK(_sc)               lck_mtx_lock(&(_sc)->sc_mtx)
 #define        _BRIDGE_UNLOCK(_sc)             lck_mtx_unlock(&(_sc)->sc_mtx)
 #define        BRIDGE_LOCK_ASSERT_HELD(_sc)            \
-       lck_mtx_assert(&(_sc)->sc_mtx, LCK_MTX_ASSERT_OWNED)
+       LCK_MTX_ASSERT(&(_sc)->sc_mtx, LCK_MTX_ASSERT_OWNED)
 #define        BRIDGE_LOCK_ASSERT_NOTHELD(_sc)         \
-       lck_mtx_assert(&(_sc)->sc_mtx, LCK_MTX_ASSERT_NOTOWNED)
+       LCK_MTX_ASSERT(&(_sc)->sc_mtx, LCK_MTX_ASSERT_NOTOWNED)
 
 #if BRIDGE_DEBUG
 
@@ -353,14 +355,42 @@ struct bridge_delayed_call {
 #define        BDCF_OUTSTANDING        0x01    /* Delayed call has been scheduled */
 #define        BDCF_CANCELLING         0x02    /* May be waiting for call completion */
 
+
 /*
  * Software state for each bridge.
  */
-
 LIST_HEAD(_bridge_rtnode_list, bridge_rtnode);
 
+typedef struct {
+       struct _bridge_rtnode_list *bb_rthash;  /* our forwarding table */
+       struct _bridge_rtnode_list bb_rtlist;   /* list version of above */
+       uint32_t                bb_rthash_key;  /* key for hash */
+       uint32_t                bb_rthash_size; /* size of the hash table */
+       struct bridge_delayed_call bb_aging_timer;
+       struct bridge_delayed_call bb_resize_call;
+       TAILQ_HEAD(, bridge_iflist) bb_spanlist;        /* span ports list */
+       struct bstp_state       bb_stp;         /* STP state */
+       bpf_packet_func         bb_bpf_input;
+       bpf_packet_func         bb_bpf_output;
+} bridge_bsd, *bridge_bsd_t;
+
+#define sc_rthash      sc_u.scu_bsd.bb_rthash
+#define sc_rtlist      sc_u.scu_bsd.bb_rtlist
+#define sc_rthash_key  sc_u.scu_bsd.bb_rthash_key
+#define sc_rthash_size sc_u.scu_bsd.bb_rthash_size
+#define sc_aging_timer sc_u.scu_bsd.bb_aging_timer
+#define sc_resize_call sc_u.scu_bsd.bb_resize_call
+#define sc_spanlist    sc_u.scu_bsd.bb_spanlist
+#define sc_stp         sc_u.scu_bsd.bb_stp
+#define sc_bpf_input   sc_u.scu_bsd.bb_bpf_input
+#define sc_bpf_output  sc_u.scu_bsd.bb_bpf_output
+
 struct bridge_softc {
        struct ifnet            *sc_ifp;        /* make this an interface */
+       u_int32_t               sc_flags;
+       union {
+               bridge_bsd      scu_bsd;
+       } sc_u;
        LIST_ENTRY(bridge_softc) sc_list;
        decl_lck_mtx_data(,     sc_mtx);
        void                    *sc_cv;
@@ -370,23 +400,11 @@ struct bridge_softc {
        uint32_t                sc_iflist_ref;  /* refcount for sc_iflist */
        uint32_t                sc_iflist_xcnt; /* refcount for sc_iflist */
        TAILQ_HEAD(, bridge_iflist) sc_iflist;  /* member interface list */
-       struct _bridge_rtnode_list *sc_rthash;  /* our forwarding table */
-       struct _bridge_rtnode_list sc_rtlist;   /* list version of above */
-       uint32_t                sc_rthash_key;  /* key for hash */
-       uint32_t                sc_rthash_size; /* size of the hash table */
-       TAILQ_HEAD(, bridge_iflist) sc_spanlist;        /* span ports list */
-       struct bstp_state       sc_stp;         /* STP state */
        uint32_t                sc_brtexceeded; /* # of cache drops */
        uint32_t                sc_filter_flags; /* ipf and flags */
        struct ifnet            *sc_ifaddr;     /* member mac copied from */
        u_char                  sc_defaddr[6];  /* Default MAC address */
-
        char                    sc_if_xname[IFNAMSIZ];
-       bpf_packet_func         sc_bpf_input;
-       bpf_packet_func         sc_bpf_output;
-       u_int32_t               sc_flags;
-       struct bridge_delayed_call sc_aging_timer;
-       struct bridge_delayed_call sc_resize_call;
 
 #if BRIDGE_DEBUG
        /*
@@ -402,6 +420,19 @@ struct bridge_softc {
 #define        SCF_DETACHING 0x01
 #define        SCF_RESIZING 0x02
 #define        SCF_MEDIA_ACTIVE 0x04
+#define SCF_BSD_MODE   0x08
+
+static inline void
+bridge_set_bsd_mode(struct bridge_softc * sc)
+{
+       sc->sc_flags |= SCF_BSD_MODE;
+}
+
+static inline boolean_t
+bridge_in_bsd_mode(const struct bridge_softc * sc)
+{
+       return ((sc->sc_flags & SCF_BSD_MODE) != 0);
+}
 
 struct bridge_hostfilter_stats bridge_hostfilter_stats;
 
@@ -555,6 +586,7 @@ static void bridge_cancel_delayed_call(struct bridge_delayed_call *);
 static void bridge_cleanup_delayed_call(struct bridge_delayed_call *);
 static int bridge_host_filter(struct bridge_iflist *, struct mbuf *);
 
+
 #define        m_copypacket(m, how) m_copym(m, 0, M_COPYALL, how)
 
 /* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */
@@ -602,6 +634,14 @@ SYSCTL_INT(_net_link_bridge, OID_AUTO, delayed_callback_delay,
        "Delay before calling delayed function");
 #endif
 
+static int bridge_bsd_mode = 1;
+#if (DEVELOPMENT || DEBUG)
+SYSCTL_INT(_net_link_bridge, OID_AUTO, bsd_mode,
+       CTLFLAG_RW|CTLFLAG_LOCKED,
+       &bridge_bsd_mode, 0,
+       "Bridge using bsd mode");
+#endif /* (DEVELOPMENT || DEBUG) */
+
 SYSCTL_STRUCT(_net_link_bridge, OID_AUTO,
        hostfilterstats, CTLFLAG_RD | CTLFLAG_LOCKED,
        &bridge_hostfilter_stats, bridge_hostfilter_stats, "");
@@ -848,7 +888,13 @@ static LIST_HEAD(, bridge_softc) bridge_list =
 static lck_grp_t *bridge_lock_grp = NULL;
 static lck_attr_t *bridge_lock_attr = NULL;
 
-static if_clone_t bridge_cloner = NULL;
+#define        BRIDGENAME      "bridge"
+#define        BRIDGES_MAX     IF_MAXUNIT
+#define        BRIDGE_ZONE_MAX_ELEM    MIN(IFNETS_MAX, BRIDGES_MAX)
+
+static struct if_clone bridge_cloner =
+    IF_CLONE_INITIALIZER(BRIDGENAME, bridge_clone_create, bridge_clone_destroy,
+        0, BRIDGES_MAX, BRIDGE_ZONE_MAX_ELEM, sizeof(struct bridge_softc));
 
 static int if_bridge_txstart = 0;
 SYSCTL_INT(_net_link_bridge, OID_AUTO, txstart, CTLFLAG_RW | CTLFLAG_LOCKED,
@@ -863,7 +909,7 @@ static void printf_ether_header(struct ether_header *);
 static void printf_mbuf_data(mbuf_t, size_t, size_t);
 static void printf_mbuf_pkthdr(mbuf_t, const char *, const char *);
 static void printf_mbuf(mbuf_t, const char *, const char *);
-static void link_print(struct sockaddr_dl *);
+static void link_print(struct bridge_softc * sc);
 
 static void bridge_lock(struct bridge_softc *);
 static void bridge_unlock(struct bridge_softc *);
@@ -1047,18 +1093,29 @@ printf_ether_header(struct ether_header *eh)
 }
 
 static void
-link_print(struct sockaddr_dl *dl_p)
+link_print(struct bridge_softc * sc)
 {
        int i;
+       uint32_t sdl_buffer[offsetof(struct sockaddr_dl, sdl_data) +
+           IFNAMSIZ + ETHER_ADDR_LEN];
+       struct sockaddr_dl *sdl = (struct sockaddr_dl *)sdl_buffer;
+
+       memset(sdl, 0, sizeof (sdl_buffer));
+       sdl->sdl_family = AF_LINK;
+       sdl->sdl_nlen = strlen(sc->sc_if_xname);
+       sdl->sdl_alen = ETHER_ADDR_LEN;
+       sdl->sdl_len = offsetof(struct sockaddr_dl, sdl_data);
+       memcpy(sdl->sdl_data, sc->sc_if_xname, sdl->sdl_nlen);
+       memcpy(LLADDR(sdl), sc->sc_defaddr, ETHER_ADDR_LEN);
 
 #if 1
        printf("sdl len %d index %d family %d type 0x%x nlen %d alen %d"
-           " slen %d addr ", dl_p->sdl_len, dl_p->sdl_index,
-           dl_p->sdl_family, dl_p->sdl_type, dl_p->sdl_nlen,
-           dl_p->sdl_alen, dl_p->sdl_slen);
+           " slen %d addr ", sdl->sdl_len, sdl->sdl_index,
+           sdl->sdl_family, sdl->sdl_type, sdl->sdl_nlen,
+           sdl->sdl_alen, sdl->sdl_slen);
 #endif
-       for (i = 0; i < dl_p->sdl_alen; i++)
-               printf("%s%x", i ? ":" : "", (CONST_LLADDR(dl_p))[i]);
+       for (i = 0; i < sdl->sdl_alen; i++)
+               printf("%s%x", i ? ":" : "", (CONST_LLADDR(sdl))[i]);
        printf("\n");
 }
 
@@ -1075,7 +1132,6 @@ bridgeattach(int n)
 #pragma unused(n)
        int error;
        lck_grp_attr_t *lck_grp_attr = NULL;
-       struct ifnet_clone_params ifnet_clone_params;
 
        bridge_rtnode_pool = zinit(sizeof (struct bridge_rtnode),
            1024 * sizeof (struct bridge_rtnode), 0, "bridge_rtnode");
@@ -1102,11 +1158,7 @@ bridgeattach(int n)
        bstp_sys_init();
 #endif /* BRIDGESTP */
 
-       ifnet_clone_params.ifc_name = "bridge";
-       ifnet_clone_params.ifc_create = bridge_clone_create;
-       ifnet_clone_params.ifc_destroy = bridge_clone_destroy;
-
-       error = ifnet_clone_attach(&ifnet_clone_params, &bridge_cloner);
+       error = if_clone_attach(&bridge_cloner);
        if (error != 0)
                printf("%s: ifnet_clone_attach failed %d\n", __func__, error);
 
@@ -1150,6 +1202,38 @@ SYSCTL_PROC(_net_link_bridge, OID_AUTO, ipfw, CTLTYPE_INT|CTLFLAG_RW,
            &pfil_ipfw, 0, &sysctl_pfil_ipfw, "I", "Layer2 filter with IPFW");
 #endif /* PFIL_HOOKS */
 
+static errno_t
+bridge_ifnet_set_attrs(struct ifnet * ifp)
+{
+       errno_t         error;
+
+       error = ifnet_set_mtu(ifp, ETHERMTU);
+       if (error != 0) {
+               printf("%s: ifnet_set_mtu failed %d\n", __func__, error);
+               goto done;
+       }
+       error = ifnet_set_addrlen(ifp, ETHER_ADDR_LEN);
+       if (error != 0) {
+               printf("%s: ifnet_set_addrlen failed %d\n", __func__, error);
+               goto done;
+       }
+       error = ifnet_set_hdrlen(ifp, ETHER_HDR_LEN);
+       if (error != 0) {
+               printf("%s: ifnet_set_hdrlen failed %d\n", __func__, error);
+               goto done;
+       }
+       error = ifnet_set_flags(ifp,
+           IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST,
+           0xffff);
+
+       if (error != 0) {
+               printf("%s: ifnet_set_flags failed %d\n", __func__, error);
+               goto done;
+       }
+ done:
+       return (error);
+}
+
 /*
  * bridge_clone_create:
  *
@@ -1160,16 +1244,18 @@ bridge_clone_create(struct if_clone *ifc, uint32_t unit, void *params)
 {
 #pragma unused(params)
        struct ifnet *ifp = NULL;
-       struct bridge_softc *sc, *sc2;
+       struct bridge_softc *sc = NULL;
+       struct bridge_softc *sc2 = NULL;
        struct ifnet_init_eparams init_params;
        errno_t error = 0;
-       uint32_t sdl_buffer[offsetof(struct sockaddr_dl, sdl_data) +
-           IFNAMSIZ + ETHER_ADDR_LEN];
-       struct sockaddr_dl *sdl = (struct sockaddr_dl *)sdl_buffer;
        uint8_t eth_hostid[ETHER_ADDR_LEN];
        int fb, retry, has_hostid;
 
-       sc = _MALLOC(sizeof (*sc), M_DEVBUF, M_WAITOK | M_ZERO);
+       sc =  if_clone_softc_allocate(&bridge_cloner);
+       if (sc == NULL) {
+               error = ENOMEM;
+               goto done;
+       }
 
        lck_mtx_init(&sc->sc_mtx, bridge_lock_grp, bridge_lock_attr);
        sc->sc_brtmax = BRIDGE_RTABLE_MAX;
@@ -1184,15 +1270,11 @@ bridge_clone_create(struct if_clone *ifc, uint32_t unit, void *params)
        sc->sc_filter_flags &= ~IFBF_FILT_USEIPF;
 #endif
 
-       /* Initialize our routing table. */
-       error = bridge_rtable_init(sc);
-       if (error != 0) {
-               printf("%s: bridge_rtable_init failed %d\n", __func__, error);
-               goto done;
+       if (bridge_bsd_mode != 0) {
+               bridge_set_bsd_mode(sc);
        }
 
        TAILQ_INIT(&sc->sc_iflist);
-       TAILQ_INIT(&sc->sc_spanlist);
 
        /* use the interface name as the unique id for ifp recycle */
        snprintf(sc->sc_if_xname, sizeof (sc->sc_if_xname), "%s%d",
@@ -1200,11 +1282,22 @@ bridge_clone_create(struct if_clone *ifc, uint32_t unit, void *params)
        bzero(&init_params, sizeof (init_params));
        init_params.ver                 = IFNET_INIT_CURRENT_VERSION;
        init_params.len                 = sizeof (init_params);
-       if (if_bridge_txstart) {
-               init_params.start       = bridge_start;
-       } else {
-               init_params.flags       = IFNET_INIT_LEGACY;
-               init_params.output      = bridge_output;
+       if (bridge_in_bsd_mode(sc)) {
+               /* Initialize our routing table. */
+               error = bridge_rtable_init(sc);
+               if (error != 0) {
+                       printf("%s: bridge_rtable_init failed %d\n",
+                              __func__, error);
+                       goto done;
+               }
+               TAILQ_INIT(&sc->sc_spanlist);
+               if (if_bridge_txstart) {
+                       init_params.start = bridge_start;
+               } else {
+                       init_params.flags = IFNET_INIT_LEGACY;
+                       init_params.output = bridge_output;
+               }
+               init_params.set_bpf_tap = bridge_set_bpf_tap;
        }
        init_params.uniqueid            = sc->sc_if_xname;
        init_params.uniqueid_len        = strlen(sc->sc_if_xname);
@@ -1220,38 +1313,24 @@ bridge_clone_create(struct if_clone *ifc, uint32_t unit, void *params)
        init_params.framer_extended     = ether_frameout_extended;
        init_params.softc               = sc;
        init_params.ioctl               = bridge_ioctl;
-       init_params.set_bpf_tap         = bridge_set_bpf_tap;
        init_params.detach              = bridge_detach;
        init_params.broadcast_addr      = etherbroadcastaddr;
        init_params.broadcast_len       = ETHER_ADDR_LEN;
-       error = ifnet_allocate_extended(&init_params, &ifp);
-       if (error != 0) {
-               printf("%s: ifnet_allocate failed %d\n", __func__, error);
-               goto done;
-       }
-       sc->sc_ifp = ifp;
 
-       error = ifnet_set_mtu(ifp, ETHERMTU);
-       if (error != 0) {
-               printf("%s: ifnet_set_mtu failed %d\n", __func__, error);
-               goto done;
-       }
-       error = ifnet_set_addrlen(ifp, ETHER_ADDR_LEN);
-       if (error != 0) {
-               printf("%s: ifnet_set_addrlen failed %d\n", __func__, error);
-               goto done;
-       }
-       error = ifnet_set_hdrlen(ifp, ETHER_HDR_LEN);
-       if (error != 0) {
-               printf("%s: ifnet_set_hdrlen failed %d\n", __func__, error);
-               goto done;
-       }
-       error = ifnet_set_flags(ifp,
-           IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST,
-           0xffff);
-       if (error != 0) {
-               printf("%s: ifnet_set_flags failed %d\n", __func__, error);
-               goto done;
+       if (bridge_in_bsd_mode(sc)) {
+               error = ifnet_allocate_extended(&init_params, &ifp);
+               if (error != 0) {
+                       printf("%s: ifnet_allocate failed %d\n",
+                              __func__, error);
+                       goto done;
+               }
+               sc->sc_ifp = ifp;
+               error = bridge_ifnet_set_attrs(ifp);
+               if (error != 0) {
+                       printf("%s: bridge_ifnet_set_attrs failed %d\n",
+                              __func__, error);
+                       goto done;
+               }
        }
 
        /*
@@ -1260,7 +1339,7 @@ bridge_clone_create(struct if_clone *ifc, uint32_t unit, void *params)
         * Since we are using random ethernet addresses for the bridge, it is
         * possible that we might have address collisions, so make sure that
         * this hardware address isn't already in use on another bridge.
-        * The first try uses the "hostid" and falls back to read_random();
+        * The first try uses the "hostid" and falls back to read_frandom();
         * for "hostid", we use the MAC address of the first-encountered
         * Ethernet-type interface that is currently configured.
         */
@@ -1268,7 +1347,7 @@ bridge_clone_create(struct if_clone *ifc, uint32_t unit, void *params)
        has_hostid = (uuid_get_ethernet(&eth_hostid[0]) == 0);
        for (retry = 1; retry != 0; ) {
                if (fb || has_hostid == 0) {
-                       read_random(&sc->sc_defaddr, ETHER_ADDR_LEN);
+                       read_frandom(&sc->sc_defaddr, ETHER_ADDR_LEN);
                        sc->sc_defaddr[0] &= ~1; /* clear multicast bit */
                        sc->sc_defaddr[0] |= 2;  /* set the LAA bit */
                } else {
@@ -1301,25 +1380,18 @@ bridge_clone_create(struct if_clone *ifc, uint32_t unit, void *params)
                lck_mtx_unlock(&bridge_list_mtx);
        }
 
-       memset(sdl, 0, sizeof (sdl_buffer));
-       sdl->sdl_family = AF_LINK;
-       sdl->sdl_nlen = strlen(sc->sc_if_xname);
-       sdl->sdl_alen = ETHER_ADDR_LEN;
-       sdl->sdl_len = offsetof(struct sockaddr_dl, sdl_data);
-       memcpy(sdl->sdl_data, sc->sc_if_xname, sdl->sdl_nlen);
-       memcpy(LLADDR(sdl), sc->sc_defaddr, ETHER_ADDR_LEN);
-
        sc->sc_flags &= ~SCF_MEDIA_ACTIVE;
 
 #if BRIDGE_DEBUG
        if (if_bridge_debug & BR_DBGF_LIFECYCLE)
-               link_print(sdl);
+               link_print(sc);
 #endif
-
-       error = ifnet_attach(ifp, NULL);
-       if (error != 0) {
-               printf("%s: ifnet_attach failed %d\n", __func__, error);
-               goto done;
+       if (bridge_in_bsd_mode(sc)) {
+               error = ifnet_attach(ifp, NULL);
+               if (error != 0) {
+                       printf("%s: ifnet_attach failed %d\n", __func__, error);
+                       goto done;
+               }
        }
 
        error = ifnet_set_lladdr_and_type(ifp, sc->sc_defaddr, ETHER_ADDR_LEN,
@@ -1330,19 +1402,20 @@ bridge_clone_create(struct if_clone *ifc, uint32_t unit, void *params)
                goto done;
        }
 
-       ifnet_set_offload(ifp,
-           IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP |
-           IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | IFNET_MULTIPAGES);
-
-       error = bridge_set_tso(sc);
-       if (error != 0) {
-               printf("%s: bridge_set_tso failed %d\n", __func__, error);
-               goto done;
-       }
-
+       if (bridge_in_bsd_mode(sc)) {
+               ifnet_set_offload(ifp,
+                 IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP |
+                 IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | IFNET_MULTIPAGES);
+               error = bridge_set_tso(sc);
+               if (error != 0) {
+                       printf("%s: bridge_set_tso failed %d\n",
+                              __func__, error);
+                       goto done;
+               }
 #if BRIDGESTP
-       bstp_attach(&sc->sc_stp, &bridge_ops);
+               bstp_attach(&sc->sc_stp, &bridge_ops);
 #endif /* BRIDGESTP */
+       }
 
        lck_mtx_lock(&bridge_list_mtx);
        LIST_INSERT_HEAD(&bridge_list, sc, sc_list);
@@ -1355,7 +1428,7 @@ bridge_clone_create(struct if_clone *ifc, uint32_t unit, void *params)
 done:
        if (error != 0) {
                printf("%s failed error %d\n", __func__, error);
-               /* Cleanup TBD */
+               /* TBD: Clean up: sc, sc_rthash etc */
        }
 
        return (error);
@@ -1382,10 +1455,12 @@ bridge_clone_destroy(struct ifnet *ifp)
 
        bridge_ifstop(ifp, 1);
 
-       bridge_cancel_delayed_call(&sc->sc_resize_call);
+       if (bridge_in_bsd_mode(sc)) {
+               bridge_cancel_delayed_call(&sc->sc_resize_call);
 
-       bridge_cleanup_delayed_call(&sc->sc_resize_call);
-       bridge_cleanup_delayed_call(&sc->sc_aging_timer);
+               bridge_cleanup_delayed_call(&sc->sc_resize_call);
+               bridge_cleanup_delayed_call(&sc->sc_aging_timer);
+       }
 
        error = ifnet_set_flags(ifp, 0, IFF_UP);
        if (error != 0) {
@@ -1395,24 +1470,18 @@ bridge_clone_destroy(struct ifnet *ifp)
        while ((bif = TAILQ_FIRST(&sc->sc_iflist)) != NULL)
                bridge_delete_member(sc, bif, 0);
 
-       while ((bif = TAILQ_FIRST(&sc->sc_spanlist)) != NULL) {
-               bridge_delete_span(sc, bif);
+       if (bridge_in_bsd_mode(sc)) {
+               while ((bif = TAILQ_FIRST(&sc->sc_spanlist)) != NULL) {
+                       bridge_delete_span(sc, bif);
+               }
+               BRIDGE_UNLOCK(sc);
        }
 
-       BRIDGE_UNLOCK(sc);
-
        error = ifnet_detach(ifp);
        if (error != 0) {
-               panic("bridge_clone_destroy: ifnet_detach(%p) failed %d\n",
-                   ifp, error);
-               if ((sc = (struct bridge_softc *)ifnet_softc(ifp)) != NULL) {
-                       BRIDGE_LOCK(sc);
-                       sc->sc_flags &= ~SCF_DETACHING;
-                       BRIDGE_UNLOCK(sc);
-               }
-               return (0);
+               panic("%s: ifnet_detach(%p) failed %d\n",
+                     __func__, ifp, error);
        }
-
        return (0);
 }
 
@@ -1915,7 +1984,7 @@ bridge_iff_output(void *cookie, ifnet_t ifp, protocol_family_t protocol,
                goto out;
 
 #if BRIDGE_DEBUG
-       if (if_bridge_debug & BR_DBGF_OUTPPUT) {
+       if (if_bridge_debug & BR_DBGF_OUTPUT) {
                printf("%s: %s from %s m 0x%llx data 0x%llx\n", __func__,
                    sc->sc_ifp->if_xname, ifp->if_xname,
                    (uint64_t)VM_KERNEL_ADDRPERM(m),
@@ -2083,10 +2152,21 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
        int lladdr_changed = 0, error, filt_attached;
        uint8_t eaddr[ETHER_ADDR_LEN];
        u_int32_t event_code = 0;
+       boolean_t bsd_mode;
 
        BRIDGE_LOCK_ASSERT_HELD(sc);
        VERIFY(ifs != NULL);
 
+       bsd_mode = bridge_in_bsd_mode(sc);
+
+       /*
+        * First, remove the member from the list first so it cannot be found anymore
+        * when we release the bridge lock below
+        */
+       BRIDGE_XLOCK(sc);
+       TAILQ_REMOVE(&sc->sc_iflist, bif, bif_next);
+       BRIDGE_XDROP(sc);
+
        if (!gone) {
                switch (ifs->if_type) {
                case IFT_ETHER:
@@ -2094,8 +2174,15 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
                        /*
                         * Take the interface out of promiscuous mode.
                         */
-                       if (bif->bif_flags & BIFF_PROMISC)
+                       if (bif->bif_flags & BIFF_PROMISC) {
+                               /*
+                                * Unlock to prevent deadlock with bridge_iff_event() in
+                                * case the driver generates an interface event
+                                */
+                               BRIDGE_UNLOCK(sc);
                                (void) ifnet_set_promiscuous(ifs, 0);
+                               BRIDGE_LOCK(sc);
+                       }
                        break;
 
                case IFT_GIF:
@@ -2119,14 +2206,11 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
                BRIDGE_LOCK(sc);
        }
 #if BRIDGESTP
-       if (bif->bif_ifflags & IFBIF_STP)
+       if (bsd_mode && (bif->bif_ifflags & IFBIF_STP) != 0) {
                bstp_disable(&bif->bif_stp);
+       }
 #endif /* BRIDGESTP */
 
-       BRIDGE_XLOCK(sc);
-       TAILQ_REMOVE(&sc->sc_iflist, bif, bif_next);
-       BRIDGE_XDROP(sc);
-
        /*
         * If removing the interface that gave the bridge its mac address, set
         * the mac address of the bridge to the address of the next member, or
@@ -2156,7 +2240,10 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
                printf("%s: bridge_set_tso failed %d\n", __func__, error);
        }
 
-       bridge_rtdelete(sc, ifs, IFBF_FLUSHALL);
+       if (bsd_mode) {
+               bridge_rtdelete(sc, ifs, IFBF_FLUSHALL);
+       }
+
        KASSERT(bif->bif_addrcnt == 0,
            ("%s: %d bridge routes referenced", __func__, bif->bif_addrcnt));
 
@@ -2167,7 +2254,9 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
         */
        event_code = bridge_updatelinkstatus(sc);
 
-       BRIDGE_UNLOCK(sc);
+       if (bsd_mode) {
+               BRIDGE_UNLOCK(sc);
+       }
 
        if (lladdr_changed &&
            (error = ifnet_set_lladdr(bifp, eaddr, ETHER_ADDR_LEN)) != 0)
@@ -2177,7 +2266,9 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
                bridge_link_event(bifp, event_code);
 
 #if BRIDGESTP
-       bstp_destroy(&bif->bif_stp);    /* prepare to free */
+       if (bsd_mode) {
+               bstp_destroy(&bif->bif_stp);    /* prepare to free */
+       }
 #endif /* BRIDGESTP */
 
        if (filt_attached)
@@ -2220,6 +2311,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
        uint8_t eaddr[ETHER_ADDR_LEN];
        struct iff_filter iff;
        u_int32_t event_code = 0;
+       boolean_t bsd_mode = bridge_in_bsd_mode(sc);
 
        ifs = ifunit(req->ifbr_ifsname);
        if (ifs == NULL)
@@ -2227,10 +2319,16 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
        if (ifs->if_ioctl == NULL)      /* must be supported */
                return (EINVAL);
 
-       /* If it's in the span list, it can't be a member. */
-       TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
-               if (ifs == bif->bif_ifp)
-                       return (EBUSY);
+       if (IFNET_IS_INTCOPROC(ifs)) {
+               return (EINVAL);
+       }
+
+       if (bsd_mode) {
+               /* If it's in the span list, it can't be a member. */
+               TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
+                       if (ifs == bif->bif_ifp)
+                               return (EBUSY);
+       }
 
        if (ifs->if_bridge == sc)
                return (EEXIST);
@@ -2250,7 +2348,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
                return (EINVAL);
        }
 
-       bif = _MALLOC(sizeof (*bif), M_DEVBUF, M_NOWAIT | M_ZERO);
+       bif = _MALLOC(sizeof (*bif), M_DEVBUF, M_WAITOK | M_ZERO);
        if (bif == NULL)
                return (ENOMEM);
 
@@ -2287,7 +2385,9 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
 
        ifs->if_bridge = sc;
 #if BRIDGESTP
-       bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp);
+       if (bsd_mode) {
+               bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp);
+       }
 #endif /* BRIDGESTP */
 
        /*
@@ -2337,7 +2437,9 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
        /*
         * Respect lock ordering with DLIL lock for the following operations
         */
-       BRIDGE_UNLOCK(sc);
+       if (bsd_mode) {
+               BRIDGE_UNLOCK(sc);
+       }
 
        /*
         * install an interface filter
@@ -2345,13 +2447,16 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
        memset(&iff, 0, sizeof (struct iff_filter));
        iff.iff_cookie = bif;
        iff.iff_name = "com.apple.kernel.bsd.net.if_bridge";
-       iff.iff_input = bridge_iff_input;
+       if (bsd_mode) {
+               iff.iff_input = bridge_iff_input;
 #if BRIDGE_MEMBER_OUT_FILTER
-       iff.iff_output = bridge_iff_output;
+               iff.iff_output = bridge_iff_output;
 #endif /* BRIDGE_MEMBER_OUT_FILTER */
+       }
        iff.iff_event = bridge_iff_event;
        iff.iff_detached = bridge_iff_detached;
-       error = dlil_attach_filter(ifs, &iff, &bif->bif_iff_ref, DLIL_IFF_TSO);
+       error = dlil_attach_filter(ifs, &iff, &bif->bif_iff_ref,
+           DLIL_IFF_TSO | DLIL_IFF_INTERNAL);
        if (error != 0) {
                printf("%s: iflt_attach failed %d\n", __func__, error);
                BRIDGE_LOCK(sc);
@@ -2415,38 +2520,41 @@ bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg)
 {
        struct ifbreq *req = arg;
        struct bridge_iflist *bif;
-       struct bstp_port *bp;
 
        bif = bridge_lookup_member(sc, req->ifbr_ifsname);
        if (bif == NULL)
                return (ENOENT);
 
-       bp = &bif->bif_stp;
+       if (bridge_in_bsd_mode(sc)) {
+               struct bstp_port *bp;
+
+               bp = &bif->bif_stp;
+               req->ifbr_state = bp->bp_state;
+               req->ifbr_priority = bp->bp_priority;
+               req->ifbr_path_cost = bp->bp_path_cost;
+               req->ifbr_proto = bp->bp_protover;
+               req->ifbr_role = bp->bp_role;
+               req->ifbr_stpflags = bp->bp_flags;
+               /* Copy STP state options as flags */
+               if (bp->bp_operedge)
+                       req->ifbr_ifsflags |= IFBIF_BSTP_EDGE;
+               if (bp->bp_flags & BSTP_PORT_AUTOEDGE)
+                       req->ifbr_ifsflags |= IFBIF_BSTP_AUTOEDGE;
+               if (bp->bp_ptp_link)
+                       req->ifbr_ifsflags |= IFBIF_BSTP_PTP;
+               if (bp->bp_flags & BSTP_PORT_AUTOPTP)
+                       req->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
+               if (bp->bp_flags & BSTP_PORT_ADMEDGE)
+                       req->ifbr_ifsflags |= IFBIF_BSTP_ADMEDGE;
+               if (bp->bp_flags & BSTP_PORT_ADMCOST)
+                       req->ifbr_ifsflags |= IFBIF_BSTP_ADMCOST;
+       }
        req->ifbr_ifsflags = bif->bif_ifflags;
-       req->ifbr_state = bp->bp_state;
-       req->ifbr_priority = bp->bp_priority;
-       req->ifbr_path_cost = bp->bp_path_cost;
        req->ifbr_portno = bif->bif_ifp->if_index & 0xfff;
-       req->ifbr_proto = bp->bp_protover;
-       req->ifbr_role = bp->bp_role;
-       req->ifbr_stpflags = bp->bp_flags;
        req->ifbr_addrcnt = bif->bif_addrcnt;
        req->ifbr_addrmax = bif->bif_addrmax;
        req->ifbr_addrexceeded = bif->bif_addrexceeded;
 
-       /* Copy STP state options as flags */
-       if (bp->bp_operedge)
-               req->ifbr_ifsflags |= IFBIF_BSTP_EDGE;
-       if (bp->bp_flags & BSTP_PORT_AUTOEDGE)
-               req->ifbr_ifsflags |= IFBIF_BSTP_AUTOEDGE;
-       if (bp->bp_ptp_link)
-               req->ifbr_ifsflags |= IFBIF_BSTP_PTP;
-       if (bp->bp_flags & BSTP_PORT_AUTOPTP)
-               req->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
-       if (bp->bp_flags & BSTP_PORT_ADMEDGE)
-               req->ifbr_ifsflags |= IFBIF_BSTP_ADMEDGE;
-       if (bp->bp_flags & BSTP_PORT_ADMCOST)
-               req->ifbr_ifsflags |= IFBIF_BSTP_ADMCOST;
        return (0);
 }
 
@@ -2460,6 +2568,10 @@ bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg)
        int error;
 #endif /* BRIDGESTP */
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (EINVAL);
+       }
+
        bif = bridge_lookup_member(sc, req->ifbr_ifsname);
        if (bif == NULL)
                return (ENOENT);
@@ -2505,8 +2617,9 @@ bridge_ioctl_scache(struct bridge_softc *sc, void *arg)
        struct ifbrparam *param = arg;
 
        sc->sc_brtmax = param->ifbrp_csize;
-       bridge_rttrim(sc);
-
+       if (bridge_in_bsd_mode(sc)) {
+               bridge_rttrim(sc);
+       }
        return (0);
 }
 
@@ -2529,8 +2642,10 @@ bridge_ioctl_gcache(struct bridge_softc *sc, void *arg)
        count = 0;                                                      \
        TAILQ_FOREACH(bif, &sc->sc_iflist, bif_next)                    \
                count++;                                                \
-       TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)                  \
-               count++;                                                \
+       if (bridge_in_bsd_mode(sc)) {                                   \
+               TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)          \
+                       count++;                                        \
+       }                                                               \
                                                                        \
        buflen = sizeof (breq) * count;                                 \
        if (bifc->ifbic_len == 0) {                                     \
@@ -2560,18 +2675,22 @@ bridge_ioctl_gcache(struct bridge_softc *sc, void *arg)
                buf += sizeof (breq);                                   \
                len -= sizeof (breq);                                   \
        }                                                               \
-       TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) {                \
-               if (len < sizeof (breq))                                \
-                       break;                                          \
+       if (bridge_in_bsd_mode(sc)) {                                   \
+               TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next) {        \
+                       if (len < sizeof (breq))                        \
+                               break;                                  \
                                                                        \
-               snprintf(breq.ifbr_ifsname, sizeof (breq.ifbr_ifsname), \
-                   "%s", bif->bif_ifp->if_xname);                      \
-               breq.ifbr_ifsflags = bif->bif_ifflags;                  \
-               breq.ifbr_portno = bif->bif_ifp->if_index & 0xfff;      \
-               memcpy(buf, &breq, sizeof (breq));                      \
-               count++;                                                \
-               buf += sizeof (breq);                                   \
-               len -= sizeof (breq);                                   \
+                       snprintf(breq.ifbr_ifsname,                     \
+                                sizeof (breq.ifbr_ifsname),            \
+                                "%s", bif->bif_ifp->if_xname);         \
+                       breq.ifbr_ifsflags = bif->bif_ifflags;          \
+                       breq.ifbr_portno                                \
+                               = bif->bif_ifp->if_index & 0xfff;       \
+                       memcpy(buf, &breq, sizeof (breq));              \
+                       count++;                                        \
+                       buf += sizeof (breq);                           \
+                       len -= sizeof (breq);                           \
+               }                                                       \
        }                                                               \
                                                                        \
        BRIDGE_UNLOCK(sc);                                              \
@@ -2605,14 +2724,19 @@ bridge_ioctl_gifs32(struct bridge_softc *sc, void *arg)
 
 #define        BRIDGE_IOCTL_RTS do {                                               \
        struct bridge_rtnode *brt;                                          \
-       char *buf, *outbuf;                                                 \
+       char *buf;                                                          \
+       char *outbuf = NULL;                                                \
        unsigned int count, buflen, len;                                    \
        unsigned long now;                                                  \
                                                                            \
        if (bac->ifbac_len == 0)                                            \
                return (0);                                                 \
                                                                            \
+       bzero(&bareq, sizeof (bareq));                                      \
        count = 0;                                                          \
+       if (!bridge_in_bsd_mode(sc)) {                                      \
+               goto out;                                                   \
+       }                                                                   \
        LIST_FOREACH(brt, &sc->sc_rtlist, brt_list)                         \
                count++;                                                    \
        buflen = sizeof (bareq) * count;                                    \
@@ -2624,12 +2748,11 @@ bridge_ioctl_gifs32(struct bridge_softc *sc, void *arg)
        count = 0;                                                          \
        buf = outbuf;                                                       \
        len = min(bac->ifbac_len, buflen);                                  \
-       bzero(&bareq, sizeof (bareq));                                      \
        LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) {                       \
                if (len < sizeof (bareq))                                   \
                        goto out;                                           \
                snprintf(bareq.ifba_ifsname, sizeof (bareq.ifba_ifsname),   \
-                   "%s", brt->brt_ifp->if_xname);                          \
+                        "%s", brt->brt_ifp->if_xname);                     \
                memcpy(bareq.ifba_dst, brt->brt_addr, sizeof (brt->brt_addr)); \
                bareq.ifba_vlan = brt->brt_vlan;                            \
                if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {   \
@@ -2647,11 +2770,13 @@ bridge_ioctl_gifs32(struct bridge_softc *sc, void *arg)
                len -= sizeof (bareq);                                      \
        }                                                                   \
 out:                                                                       \
-       BRIDGE_UNLOCK(sc);                                                  \
        bac->ifbac_len = sizeof (bareq) * count;                            \
-       error = copyout(outbuf, bac->ifbac_req, bac->ifbac_len);            \
-       BRIDGE_LOCK(sc);                                                    \
-       _FREE(outbuf, M_TEMP);                                              \
+       if (outbuf != NULL) {                                               \
+               BRIDGE_UNLOCK(sc);                                          \
+               error = copyout(outbuf, bac->ifbac_req, bac->ifbac_len);    \
+               _FREE(outbuf, M_TEMP);                                      \
+               BRIDGE_LOCK(sc);                                            \
+       }                                                                   \
        return (error);                                                     \
 } while (0)
 
@@ -2663,7 +2788,6 @@ bridge_ioctl_rts64(struct bridge_softc *sc, void *arg)
        int error = 0;
 
        BRIDGE_IOCTL_RTS;
-
        return (error);
 }
 
@@ -2675,7 +2799,6 @@ bridge_ioctl_rts32(struct bridge_softc *sc, void *arg)
        int error = 0;
 
        BRIDGE_IOCTL_RTS;
-
        return (error);
 }
 
@@ -2686,6 +2809,10 @@ bridge_ioctl_saddr32(struct bridge_softc *sc, void *arg)
        struct bridge_iflist *bif;
        int error;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (0);
+       }
+
        bif = bridge_lookup_member(sc, req->ifba_ifsname);
        if (bif == NULL)
                return (ENOENT);
@@ -2703,6 +2830,10 @@ bridge_ioctl_saddr64(struct bridge_softc *sc, void *arg)
        struct bridge_iflist *bif;
        int error;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (0);
+       }
+
        bif = bridge_lookup_member(sc, req->ifba_ifsname);
        if (bif == NULL)
                return (ENOENT);
@@ -2736,6 +2867,9 @@ bridge_ioctl_daddr32(struct bridge_softc *sc, void *arg)
 {
        struct ifbareq32 *req = arg;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (0);
+       }
        return (bridge_rtdaddr(sc, req->ifba_dst, req->ifba_vlan));
 }
 
@@ -2744,6 +2878,9 @@ bridge_ioctl_daddr64(struct bridge_softc *sc, void *arg)
 {
        struct ifbareq64 *req = arg;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (0);
+       }
        return (bridge_rtdaddr(sc, req->ifba_dst, req->ifba_vlan));
 }
 
@@ -2752,6 +2889,9 @@ bridge_ioctl_flush(struct bridge_softc *sc, void *arg)
 {
        struct ifbreq *req = arg;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (0);
+       }
        bridge_rtflush(sc, req->ifbr_ifsflags);
        return (0);
 }
@@ -2762,6 +2902,9 @@ bridge_ioctl_gpri(struct bridge_softc *sc, void *arg)
        struct ifbrparam *param = arg;
        struct bstp_state *bs = &sc->sc_stp;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (0);
+       }
        param->ifbrp_prio = bs->bs_bridge_priority;
        return (0);
 }
@@ -2772,6 +2915,9 @@ bridge_ioctl_spri(struct bridge_softc *sc, void *arg)
 #if BRIDGESTP
        struct ifbrparam *param = arg;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (EOPNOTSUPP);
+       }
        return (bstp_set_priority(&sc->sc_stp, param->ifbrp_prio));
 #else /* !BRIDGESTP */
 #pragma unused(sc, arg)
@@ -2785,6 +2931,9 @@ bridge_ioctl_ght(struct bridge_softc *sc, void *arg)
        struct ifbrparam *param = arg;
        struct bstp_state *bs = &sc->sc_stp;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (0);
+       }
        param->ifbrp_hellotime = bs->bs_bridge_htime >> 8;
        return (0);
 }
@@ -2795,6 +2944,9 @@ bridge_ioctl_sht(struct bridge_softc *sc, void *arg)
 #if BRIDGESTP
        struct ifbrparam *param = arg;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (EOPNOTSUPP);
+       }
        return (bstp_set_htime(&sc->sc_stp, param->ifbrp_hellotime));
 #else /* !BRIDGESTP */
 #pragma unused(sc, arg)
@@ -2805,9 +2957,14 @@ bridge_ioctl_sht(struct bridge_softc *sc, void *arg)
 static int
 bridge_ioctl_gfd(struct bridge_softc *sc, void *arg)
 {
-       struct ifbrparam *param = arg;
-       struct bstp_state *bs = &sc->sc_stp;
+       struct ifbrparam *param;
+       struct bstp_state *bs;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (0);
+       }
+       param = arg;
+       bs = &sc->sc_stp;
        param->ifbrp_fwddelay = bs->bs_bridge_fdelay >> 8;
        return (0);
 }
@@ -2818,6 +2975,9 @@ bridge_ioctl_sfd(struct bridge_softc *sc, void *arg)
 #if BRIDGESTP
        struct ifbrparam *param = arg;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (EOPNOTSUPP);
+       }
        return (bstp_set_fdelay(&sc->sc_stp, param->ifbrp_fwddelay));
 #else /* !BRIDGESTP */
 #pragma unused(sc, arg)
@@ -2828,9 +2988,14 @@ bridge_ioctl_sfd(struct bridge_softc *sc, void *arg)
 static int
 bridge_ioctl_gma(struct bridge_softc *sc, void *arg)
 {
-       struct ifbrparam *param = arg;
-       struct bstp_state *bs = &sc->sc_stp;
+       struct ifbrparam *param;
+       struct bstp_state *bs;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (EOPNOTSUPP);
+       }
+       param = arg;
+       bs = &sc->sc_stp;
        param->ifbrp_maxage = bs->bs_bridge_max_age >> 8;
        return (0);
 }
@@ -2841,6 +3006,9 @@ bridge_ioctl_sma(struct bridge_softc *sc, void *arg)
 #if BRIDGESTP
        struct ifbrparam *param = arg;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (EOPNOTSUPP);
+       }
        return (bstp_set_maxage(&sc->sc_stp, param->ifbrp_maxage));
 #else /* !BRIDGESTP */
 #pragma unused(sc, arg)
@@ -2855,6 +3023,9 @@ bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg)
        struct ifbreq *req = arg;
        struct bridge_iflist *bif;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (EOPNOTSUPP);
+       }
        bif = bridge_lookup_member(sc, req->ifbr_ifsname);
        if (bif == NULL)
                return (ENOENT);
@@ -2873,6 +3044,9 @@ bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg)
        struct ifbreq *req = arg;
        struct bridge_iflist *bif;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (EOPNOTSUPP);
+       }
        bif = bridge_lookup_member(sc, req->ifbr_ifsname);
        if (bif == NULL)
                return (ENOENT);
@@ -2933,10 +3107,17 @@ bridge_ioctl_addspan(struct bridge_softc *sc, void *arg)
        struct bridge_iflist *bif = NULL;
        struct ifnet *ifs;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (EOPNOTSUPP);
+       }
        ifs = ifunit(req->ifbr_ifsname);
        if (ifs == NULL)
                return (ENOENT);
 
+       if (IFNET_IS_INTCOPROC(ifs)) {
+               return (EINVAL);
+       }
+
        TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
                if (ifs == bif->bif_ifp)
                        return (EBUSY);
@@ -2955,7 +3136,7 @@ bridge_ioctl_addspan(struct bridge_softc *sc, void *arg)
                        return (EINVAL);
        }
 
-       bif = _MALLOC(sizeof (*bif), M_DEVBUF, M_NOWAIT | M_ZERO);
+       bif = _MALLOC(sizeof (*bif), M_DEVBUF, M_WAITOK | M_ZERO);
        if (bif == NULL)
                return (ENOMEM);
 
@@ -2976,6 +3157,9 @@ bridge_ioctl_delspan(struct bridge_softc *sc, void *arg)
        struct bridge_iflist *bif;
        struct ifnet *ifs;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (EOPNOTSUPP);
+       }
        ifs = ifunit(req->ifbr_ifsname);
        if (ifs == NULL)
                return (ENOENT);
@@ -3022,8 +3206,9 @@ bridge_ioctl_gbparam32(struct bridge_softc *sc, void *arg)
 {
        struct ifbropreq32 *req = arg;
 
-       BRIDGE_IOCTL_GBPARAM;
-
+       if (bridge_in_bsd_mode(sc)) {
+               BRIDGE_IOCTL_GBPARAM;
+       }
        return (0);
 }
 
@@ -3032,8 +3217,9 @@ bridge_ioctl_gbparam64(struct bridge_softc *sc, void *arg)
 {
        struct ifbropreq64 *req = arg;
 
-       BRIDGE_IOCTL_GBPARAM;
-
+       if (bridge_in_bsd_mode(sc)) {
+               BRIDGE_IOCTL_GBPARAM;
+       }
        return (0);
 }
 
@@ -3108,8 +3294,9 @@ bridge_ioctl_gifsstp32(struct bridge_softc *sc, void *arg)
        struct ifbpstpconf32 *bifstp = arg;
        int error = 0;
 
-       BRIDGE_IOCTL_GIFSSTP;
-
+       if (bridge_in_bsd_mode(sc)) {
+               BRIDGE_IOCTL_GIFSSTP;
+       }
        return (error);
 }
 
@@ -3119,8 +3306,9 @@ bridge_ioctl_gifsstp64(struct bridge_softc *sc, void *arg)
        struct ifbpstpconf64 *bifstp = arg;
        int error = 0;
 
-       BRIDGE_IOCTL_GIFSSTP;
-
+       if (bridge_in_bsd_mode(sc)) {
+               BRIDGE_IOCTL_GIFSSTP;
+       }
        return (error);
 }
 
@@ -3130,6 +3318,9 @@ bridge_ioctl_sproto(struct bridge_softc *sc, void *arg)
 #if BRIDGESTP
        struct ifbrparam *param = arg;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (EOPNOTSUPP);
+       }
        return (bstp_set_protocol(&sc->sc_stp, param->ifbrp_proto));
 #else /* !BRIDGESTP */
 #pragma unused(sc, arg)
@@ -3143,6 +3334,9 @@ bridge_ioctl_stxhc(struct bridge_softc *sc, void *arg)
 #if BRIDGESTP
        struct ifbrparam *param = arg;
 
+       if (!bridge_in_bsd_mode(sc)) {
+               return (EOPNOTSUPP);
+       }
        return (bstp_set_holdcount(&sc->sc_stp, param->ifbrp_txhc));
 #else /* !BRIDGESTP */
 #pragma unused(sc, arg)
@@ -3181,6 +3375,8 @@ bridge_ioctl_shostfilter(struct bridge_softc *sc, void *arg)
        if (bif == NULL)
                return (ENOENT);
 
+       INC_ATOMIC_INT64_LIM(net_api_stats.nas_vmnet_total);
+
        if (req->ifbrhf_flags & IFBRHF_ENABLED) {
                bif->bif_flags |= BIFF_HOST_FILTER;
 
@@ -3236,17 +3432,18 @@ bridge_ifdetach(struct bridge_iflist *bif, struct ifnet *ifp)
                BRIDGE_UNLOCK(sc);
                return;
        }
-
        /* Check if the interface is a span port */
        lck_mtx_lock(&bridge_list_mtx);
        LIST_FOREACH(sc, &bridge_list, sc_list) {
-               BRIDGE_LOCK(sc);
-               TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
-                       if (ifp == bif->bif_ifp) {
-                               bridge_delete_span(sc, bif);
-                               break;
-                       }
-               BRIDGE_UNLOCK(sc);
+               if (bridge_in_bsd_mode(sc)) {
+                       BRIDGE_LOCK(sc);
+                       TAILQ_FOREACH(bif, &sc->sc_spanlist, bif_next)
+                               if (ifp == bif->bif_ifp) {
+                                       bridge_delete_span(sc, bif);
+                                       break;
+                               }
+                       BRIDGE_UNLOCK(sc);
+               }
        }
        lck_mtx_unlock(&bridge_list_mtx);
 }
@@ -3535,17 +3732,17 @@ bridge_init(struct ifnet *ifp)
 
        error = ifnet_set_flags(ifp, IFF_RUNNING, IFF_RUNNING);
 
-       /*
-        * Calling bridge_aging_timer() is OK as there are no entries to
-        * age so we're just going to arm the timer
-        */
-       bridge_aging_timer(sc);
-
+       if (bridge_in_bsd_mode(sc)) {
+               /*
+                * Calling bridge_aging_timer() is OK as there are no entries to
+                * age so we're just going to arm the timer
+                */
+               bridge_aging_timer(sc);
 #if BRIDGESTP
-       if (error == 0)
-               bstp_init(&sc->sc_stp);         /* Initialize Spanning Tree */
+               if (error == 0)
+                       bstp_init(&sc->sc_stp); /* Initialize Spanning Tree */
 #endif /* BRIDGESTP */
-
+       }
        return (error);
 }
 
@@ -3565,14 +3762,15 @@ bridge_ifstop(struct ifnet *ifp, int disable)
        if ((ifnet_flags(ifp) & IFF_RUNNING) == 0)
                return;
 
-       bridge_cancel_delayed_call(&sc->sc_aging_timer);
+       if (bridge_in_bsd_mode(sc)) {
+               bridge_cancel_delayed_call(&sc->sc_aging_timer);
 
 #if BRIDGESTP
-       bstp_stop(&sc->sc_stp);
+               bstp_stop(&sc->sc_stp);
 #endif /* BRIDGESTP */
 
-       bridge_rtflush(sc, IFBF_FLUSHDYN);
-
+               bridge_rtflush(sc, IFBF_FLUSHDYN);
+       }
        (void) ifnet_set_flags(ifp, 0, IFF_RUNNING);
 }
 
@@ -3709,7 +3907,7 @@ bridge_member_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
        uint16_t vlan;
 
 #if BRIDGE_DEBUG
-       if (if_bridge_debug & BR_DBGF_OUTPPUT)
+       if (if_bridge_debug & BR_DBGF_OUTPUT)
                printf("%s: ifp %s\n", __func__, ifp->if_xname);
 #endif /* BRIDGE_DEBUG */
 
@@ -3840,6 +4038,8 @@ bridge_output(struct ifnet *ifp, struct mbuf *m)
        dst_if = NULL;
 
        BRIDGE_LOCK(sc);
+       ASSERT(bridge_in_bsd_mode(sc));
+
        if (!(m->m_flags & (M_BCAST|M_MCAST)))
                dst_if = bridge_rtlookup(sc, eh->ether_dhost, 0);
 
@@ -3966,9 +4166,10 @@ bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif,
        int error;
 
        BRIDGE_LOCK_ASSERT_HELD(sc);
+       ASSERT(bridge_in_bsd_mode(sc));
 
 #if BRIDGE_DEBUG
-       if (if_bridge_debug & BR_DBGF_OUTPPUT)
+       if (if_bridge_debug & BR_DBGF_OUTPUT)
                printf("%s: %s m 0x%llx\n", __func__, sc->sc_ifp->if_xname,
                    (uint64_t)VM_KERNEL_ADDRPERM(m));
 #endif /* BRIDGE_DEBUG */
@@ -4151,6 +4352,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m, void *frame_header)
        uint16_t vlan;
        int error;
 
+       ASSERT(bridge_in_bsd_mode(sc));
 #if BRIDGE_DEBUG
        if (if_bridge_debug & BR_DBGF_INPUT)
                printf("%s: %s from %s m 0x%llx data 0x%llx\n", __func__,
@@ -4632,6 +4834,7 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan,
        int error;
 
        BRIDGE_LOCK_ASSERT_HELD(sc);
+       ASSERT(bridge_in_bsd_mode(sc));
 
        /* Check the source address is valid and not multicast. */
        if (ETHER_IS_MULTICAST(dst) ||
@@ -4880,6 +5083,8 @@ bridge_rtable_init(struct bridge_softc *sc)
 {
        u_int32_t i;
 
+       ASSERT(bridge_in_bsd_mode(sc));
+
        sc->sc_rthash = _MALLOC(sizeof (*sc->sc_rthash) * BRIDGE_RTHASH_SIZE,
            M_DEVBUF, M_WAITOK | M_ZERO);
        if (sc->sc_rthash == NULL) {
@@ -5091,6 +5296,7 @@ bridge_rtnode_lookup(struct bridge_softc *sc, const uint8_t *addr,
        int dir;
 
        BRIDGE_LOCK_ASSERT_HELD(sc);
+       ASSERT(bridge_in_bsd_mode(sc));
 
        hash = bridge_rthash(sc, addr);
        LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) {
@@ -5403,7 +5609,7 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
                if (DUMMYNET_LOADED && (i == IP_FW_DUMMYNET)) {
 
                        /* put the Ethernet header back on */
-                       M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT);
+                       M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT, 0);
                        if (*mp == NULL)
                                return (error);
                        bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN);
@@ -5534,13 +5740,13 @@ ipfwpass:
         * Finally, put everything back the way it was and return
         */
        if (snap) {
-               M_PREPEND(*mp, sizeof (struct llc), M_DONTWAIT);
+               M_PREPEND(*mp, sizeof (struct llc), M_DONTWAIT, 0);
                if (*mp == NULL)
                        return (error);
                bcopy(&llc1, mtod(*mp, caddr_t), sizeof (struct llc));
        }
 
-       M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT);
+       M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT, 0);
        if (*mp == NULL)
                return (error);
        bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN);
@@ -5737,7 +5943,7 @@ bridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh,
        for (m0 = m; m0; m0 = m0->m_nextpkt) {
                if (error == 0) {
                        if (snap) {
-                               M_PREPEND(m0, sizeof (struct llc), M_DONTWAIT);
+                               M_PREPEND(m0, sizeof (struct llc), M_DONTWAIT, 0);
                                if (m0 == NULL) {
                                        error = ENOBUFS;
                                        continue;
@@ -5745,7 +5951,7 @@ bridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh,
                                bcopy(llc, mtod(m0, caddr_t),
                                    sizeof (struct llc));
                        }
-                       M_PREPEND(m0, ETHER_HDR_LEN, M_DONTWAIT);
+                       M_PREPEND(m0, ETHER_HDR_LEN, M_DONTWAIT, 0);
                        if (m0 == NULL) {
                                error = ENOBUFS;
                                continue;
@@ -5782,7 +5988,7 @@ bridge_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode, bpf_packet_func bpf_callback)
        if (sc == NULL || (sc->sc_flags & SCF_DETACHING)) {
                return (ENODEV);
        }
-
+       ASSERT(bridge_in_bsd_mode(sc));
        switch (mode) {
                case BPF_TAP_DISABLE:
                        sc->sc_bpf_input = sc->sc_bpf_output = NULL;
@@ -5821,8 +6027,10 @@ bridge_detach(ifnet_t ifp)
        bstp_detach(&sc->sc_stp);
 #endif /* BRIDGESTP */
 
-       /* Tear down the routing table. */
-       bridge_rtable_fini(sc);
+       if (bridge_in_bsd_mode(sc)) {
+               /* Tear down the routing table. */
+               bridge_rtable_fini(sc);
+       }
 
        lck_mtx_lock(&bridge_list_mtx);
        LIST_REMOVE(sc, sc_list);
@@ -5831,8 +6039,7 @@ bridge_detach(ifnet_t ifp)
        ifnet_release(ifp);
 
        lck_mtx_destroy(&sc->sc_mtx, bridge_lock_grp);
-
-       _FREE(sc, M_DEVBUF);
+       if_clone_softc_deallocate(&bridge_cloner, sc);
 }
 
 /*
@@ -5845,6 +6052,7 @@ bridge_bpf_input(ifnet_t ifp, struct mbuf *m)
 {
        struct bridge_softc *sc = (struct bridge_softc *)ifnet_softc(ifp);
 
+       ASSERT(bridge_in_bsd_mode(sc));
        if (sc->sc_bpf_input) {
                if (mbuf_pkthdr_rcvif(m) != ifp) {
                        printf("%s: rcvif: 0x%llx != ifp 0x%llx\n", __func__,
@@ -5866,6 +6074,7 @@ bridge_bpf_output(ifnet_t ifp, struct mbuf *m)
 {
        struct bridge_softc *sc = (struct bridge_softc *)ifnet_softc(ifp);
 
+       ASSERT(bridge_in_bsd_mode(sc));
        if (sc->sc_bpf_output) {
                (*sc->sc_bpf_output)(ifp, m);
        }
@@ -6183,3 +6392,5 @@ done:
        }
        return (error);
 }
+
+