]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/if.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / bsd / net / if.c
index 79921cbdba6301ca2663557d02a3f03e7b888f0a..6cc232bc665efb53f75bb90edef38978ab3a14af 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 #include <net/if_ppp.h>
 #include <net/ethernet.h>
 #include <net/network_agent.h>
+#include <net/pktsched/pktsched_netem.h>
 #include <net/radix.h>
 #include <net/route.h>
 #include <net/dlil.h>
 #include <sys/domain.h>
 #include <libkern/OSAtomic.h>
 
-#if INET || INET6
+#if INET
 #include <netinet/in.h>
 #include <netinet/in_var.h>
 #include <netinet/in_tclass.h>
 #include <netinet/tcp_var.h>
 #include <netinet/udp.h>
 #include <netinet/udp_var.h>
-#if INET6
 #include <netinet6/in6_var.h>
 #include <netinet6/in6_ifattach.h>
 #include <netinet6/ip6_var.h>
 #include <netinet6/nd6.h>
-#endif /* INET6 */
-#endif /* INET || INET6 */
+#endif /* INET */
 
-#if CONFIG_MACF_NET
-#include <security/mac_framework.h>
-#endif
 
 #include <os/log.h>
 
@@ -228,14 +224,12 @@ static decl_lck_mtx_data(, ifma_trash_lock);
 #define IFMA_ZONE_MAX           64              /* maximum elements in zone */
 #define IFMA_ZONE_NAME          "ifmultiaddr"   /* zone name */
 
-#if INET6
 /*
  * XXX: declare here to avoid to include many inet6 related files..
  * should be more generalized?
  */
 extern void     nd6_setmtu(struct ifnet *);
 extern lck_mtx_t *nd6_mutex;
-#endif
 
 SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "Link layers");
 SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
@@ -247,6 +241,52 @@ static uint32_t if_verbose = 0;
 SYSCTL_INT(_net_link_generic_system, OID_AUTO, if_verbose,
     CTLFLAG_RW | CTLFLAG_LOCKED, &if_verbose, 0, "");
 
+#if (DEBUG || DEVELOPMENT)
+static uint32_t default_tcp_kao_max = 0;
+SYSCTL_INT(_net_link_generic_system, OID_AUTO, default_tcp_kao_max,
+    CTLFLAG_RW | CTLFLAG_LOCKED, &default_tcp_kao_max, 0, "");
+#else
+static const uint32_t default_tcp_kao_max = 0;
+#endif /* (DEBUG || DEVELOPMENT) */
+
+u_int32_t companion_link_sock_buffer_limit = 0;
+
+static int
+sysctl_set_companion_link_sock_buf_limit SYSCTL_HANDLER_ARGS
+{
+#pragma unused(arg1, arg2)
+       int error, tmp = companion_link_sock_buffer_limit;
+       error = sysctl_handle_int(oidp, &tmp, 0, req);
+       if (tmp < 0) {
+               return EINVAL;
+       }
+       if ((error = priv_check_cred(kauth_cred_get(),
+           PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
+               return error;
+       }
+
+       u_int32_t new_limit = tmp;
+       if (new_limit == companion_link_sock_buffer_limit) {
+               return 0;
+       }
+
+       bool recover = new_limit == 0 ? true : false;
+       if (recover) {
+               error = inp_recover_companion_link(&tcbinfo);
+       } else {
+               error = inp_limit_companion_link(&tcbinfo, new_limit);
+       }
+       if (!error) {
+               companion_link_sock_buffer_limit = new_limit;
+       }
+       return error;
+}
+
+SYSCTL_PROC(_net_link_generic_system, OID_AUTO, companion_sndbuf_limit,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
+    &companion_link_sock_buffer_limit, 0, sysctl_set_companion_link_sock_buf_limit,
+    "I", "set sock send buffer limit of connections using companion links");
+
 boolean_t intcoproc_unrestricted;
 
 /* Eventhandler context for interface events */
@@ -265,15 +305,7 @@ ifa_init(void)
        ifma_size = (ifma_debug == 0) ? sizeof(struct ifmultiaddr) :
            sizeof(struct ifmultiaddr_dbg);
 
-       ifma_zone = zinit(ifma_size, IFMA_ZONE_MAX * ifma_size, 0,
-           IFMA_ZONE_NAME);
-       if (ifma_zone == NULL) {
-               panic("%s: failed allocating %s", __func__, IFMA_ZONE_NAME);
-               /* NOTREACHED */
-       }
-       zone_change(ifma_zone, Z_EXPAND, TRUE);
-       zone_change(ifma_zone, Z_CALLERACCT, FALSE);
-
+       ifma_zone = zone_create(IFMA_ZONE_NAME, ifma_size, ZC_NONE);
        lck_mtx_init(&ifma_trash_lock, ifa_mtx_grp, ifa_mtx_attr);
        TAILQ_INIT(&ifma_trash_head);
 
@@ -393,7 +425,7 @@ if_detach_ifa_common(struct ifnet *ifp, struct ifaddr *ifa, int link)
                panic("%s: unexpected (missing) refcnt ifa=%p", __func__, ifa);
                /* NOTREACHED */
        }
-       ifa->ifa_debug &= ~(IFD_ATTACHED | IFD_DETACHING);
+       ifa->ifa_debug &= ~IFD_ATTACHED;
 
        if (ifa->ifa_detached != NULL) {
                (*ifa->ifa_detached)(ifa);
@@ -712,14 +744,8 @@ if_clone_attach(struct if_clone *ifc)
        lck_mtx_init(&ifc->ifc_mutex, ifnet_lock_group, ifnet_lock_attr);
 
        if (ifc->ifc_softc_size != 0) {
-               ifc->ifc_zone = zinit(ifc->ifc_softc_size,
-                   ifc->ifc_zone_max_elem * ifc->ifc_softc_size, 0, ifc->ifc_name);
-               if (ifc->ifc_zone == NULL) {
-                       FREE(ifc->ifc_units, M_CLONE);
-                       return ENOBUFS;
-               }
-               zone_change(ifc->ifc_zone, Z_EXPAND, TRUE);
-               zone_change(ifc->ifc_zone, Z_CALLERACCT, FALSE);
+               ifc->ifc_zone = zone_create(ifc->ifc_name, ifc->ifc_softc_size,
+                   ZC_DESTRUCTIBLE);
        }
 
        LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
@@ -795,11 +821,15 @@ u_int32_t
 if_functional_type(struct ifnet *ifp, bool exclude_delegate)
 {
        u_int32_t ret = IFRTYPE_FUNCTIONAL_UNKNOWN;
+
        if (ifp != NULL) {
                if (ifp->if_flags & IFF_LOOPBACK) {
                        ret = IFRTYPE_FUNCTIONAL_LOOPBACK;
+               } else if (IFNET_IS_COMPANION_LINK(ifp)) {
+                       ret = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
                } else if ((exclude_delegate &&
-                   (ifp->if_subfamily == IFNET_SUBFAMILY_WIFI)) ||
+                   (ifp->if_family == IFNET_FAMILY_ETHERNET &&
+                   ifp->if_subfamily == IFNET_SUBFAMILY_WIFI)) ||
                    (!exclude_delegate && IFNET_IS_WIFI(ifp))) {
                        if (ifp->if_eflags & IFEF_AWDL) {
                                ret = IFRTYPE_FUNCTIONAL_WIFI_AWDL;
@@ -860,7 +890,6 @@ ifa_foraddr_scoped(unsigned int addr, unsigned int scope)
        return ia;
 }
 
-#if INET6
 /*
  * Similar to ifa_foraddr, except that this for IPv6.
  */
@@ -876,7 +905,7 @@ ifa_foraddr6_scoped(struct in6_addr *addr6, unsigned int scope)
        struct in6_ifaddr *ia = NULL;
 
        lck_rw_lock_shared(&in6_ifaddr_rwlock);
-       for (ia = in6_ifaddrs; ia; ia = ia->ia_next) {
+       TAILQ_FOREACH(ia, IN6ADDR_HASH(addr6), ia6_hash) {
                IFA_LOCK(&ia->ia_ifa);
                if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, addr6) &&
                    (scope == IFSCOPE_NONE || ia->ia_ifp->if_index == scope)) {
@@ -890,7 +919,6 @@ ifa_foraddr6_scoped(struct in6_addr *addr6, unsigned int scope)
 
        return ia;
 }
-#endif /* INET6 */
 
 /*
  * Return the first (primary) address of a given family on an interface.
@@ -1121,11 +1149,7 @@ ifa_ifwithnet_common(const struct sockaddr *addr, unsigned int ifscope)
        u_int af = addr->sa_family;
        const char *addr_data = addr->sa_data, *cplim;
 
-#if INET6
        if (af != AF_INET && af != AF_INET6) {
-#else
-       if (af != AF_INET) {
-#endif /* !INET6 */
                ifscope = IFSCOPE_NONE;
        }
 
@@ -1404,6 +1428,7 @@ link_rtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa)
 __private_extern__ void
 if_updown( struct ifnet *ifp, int up)
 {
+       u_int32_t eflags;
        int i;
        struct ifaddr **ifa;
        struct timespec tv;
@@ -1425,7 +1450,8 @@ if_updown( struct ifnet *ifp, int up)
        }
 
        /* Indicate that the up/down state is changing */
-       ifp->if_eflags |= IFEF_UPDOWNCHANGE;
+       eflags = if_set_eflags(ifp, IFEF_UPDOWNCHANGE);
+       ASSERT((eflags & IFEF_UPDOWNCHANGE) == 0);
 
        /* Mark interface up or down */
        if (up) {
@@ -1457,7 +1483,7 @@ if_updown( struct ifnet *ifp, int up)
 
        /* Aquire the lock to clear the changing flag */
        ifnet_lock_exclusive(ifp);
-       ifp->if_eflags &= ~IFEF_UPDOWNCHANGE;
+       if_clear_eflags(ifp, IFEF_UPDOWNCHANGE);
        wakeup(&ifp->if_eflags);
 }
 
@@ -1500,7 +1526,7 @@ if_qflush(struct ifnet *ifp, int ifq_locked)
        }
 
        if (IFCQ_IS_ENABLED(ifq)) {
-               IFCQ_PURGE(ifq);
+               fq_if_request_classq(ifq, CLASSQRQ_PURGE, NULL);
        }
 
        VERIFY(IFCQ_IS_EMPTY(ifq));
@@ -1516,7 +1542,6 @@ if_qflush_sc(struct ifnet *ifp, mbuf_svc_class_t sc, u_int32_t flow,
 {
        struct ifclassq *ifq = &ifp->if_snd;
        u_int32_t cnt = 0, len = 0;
-       u_int32_t a_cnt = 0, a_len = 0;
 
        VERIFY(sc == MBUF_SC_UNSPEC || MBUF_VALID_SC(sc));
        VERIFY(flow != 0);
@@ -1526,7 +1551,11 @@ if_qflush_sc(struct ifnet *ifp, mbuf_svc_class_t sc, u_int32_t flow,
        }
 
        if (IFCQ_IS_ENABLED(ifq)) {
-               IFCQ_PURGE_SC(ifq, sc, flow, cnt, len);
+               cqrq_purge_sc_t req = { sc, flow, 0, 0 };
+
+               fq_if_request_classq(ifq, CLASSQRQ_PURGE_SC, &req);
+               cnt = req.packets;
+               len = req.bytes;
        }
 
        if (!ifq_locked) {
@@ -1534,10 +1563,10 @@ if_qflush_sc(struct ifnet *ifp, mbuf_svc_class_t sc, u_int32_t flow,
        }
 
        if (packets != NULL) {
-               *packets = cnt + a_cnt;
+               *packets = cnt;
        }
        if (bytes != NULL) {
-               *bytes = len + a_len;
+               *bytes = len;
        }
 }
 
@@ -1806,13 +1835,23 @@ ifioctl_linkparams(struct ifnet *ifp, u_long cmd, caddr_t data, struct proc *p)
 
        switch (cmd) {
        case SIOCSIFLINKPARAMS: {               /* struct if_linkparamsreq */
-               struct tb_profile tb = { 0, 0, 0 };
+               struct tb_profile tb = { .rate = 0, .percent = 0, .depth = 0 };
 
                if ((error = proc_suser(p)) != 0) {
                        break;
                }
 
 
+               char netem_name[32];
+               (void) snprintf(netem_name, sizeof(netem_name),
+                   "if_output_netem_%s", if_name(ifp));
+               error = netem_config(&ifp->if_output_netem, netem_name,
+                   &iflpr->iflpr_output_netem, (void *)ifp,
+                   ifnet_enqueue_netem, NETEM_MAX_BATCH_SIZE);
+               if (error != 0) {
+                       break;
+               }
+
                IFCQ_LOCK(ifq);
                if (!IFCQ_IS_READY(ifq)) {
                        error = ENXIO;
@@ -1864,6 +1903,12 @@ ifioctl_linkparams(struct ifnet *ifp, u_long cmd, caddr_t data, struct proc *p)
                    sizeof(iflpr->iflpr_output_lt));
                bcopy(&ifp->if_input_lt, &iflpr->iflpr_input_lt,
                    sizeof(iflpr->iflpr_input_lt));
+
+               if (ifp->if_output_netem != NULL) {
+                       netem_get_params(ifp->if_output_netem,
+                           &iflpr->iflpr_output_netem);
+               }
+
                break;
        }
 
@@ -1980,9 +2025,11 @@ ifioctl_getnetagents(struct ifnet *ifp, u_int32_t *count, user_addr_t uuid_p)
 
 #define IF_MAXAGENTS            64
 #define IF_AGENT_INCREMENT      8
-static int
+int
 if_add_netagent_locked(struct ifnet *ifp, uuid_t new_agent_uuid)
 {
+       VERIFY(ifp != NULL);
+
        uuid_t *first_empty_slot = NULL;
        u_int32_t index = 0;
        bool already_added = FALSE;
@@ -2290,14 +2337,10 @@ if_set_qosmarking_mode(struct ifnet *ifp, u_int32_t mode)
        switch (mode) {
        case IFRTYPE_QOSMARKING_MODE_NONE:
                ifp->if_qosmarking_mode = IFRTYPE_QOSMARKING_MODE_NONE;
-               ifp->if_eflags &= ~IFEF_QOSMARKING_CAPABLE;
                break;
        case IFRTYPE_QOSMARKING_FASTLANE:
-               ifp->if_qosmarking_mode = IFRTYPE_QOSMARKING_FASTLANE;
-               ifp->if_eflags |= IFEF_QOSMARKING_CAPABLE;
-               if (net_qos_policy_capable_enabled != 0) {
-                       ifp->if_eflags |= IFEF_QOSMARKING_ENABLED;
-               }
+       case IFRTYPE_QOSMARKING_RFC4594:
+               ifp->if_qosmarking_mode = mode;
                break;
        default:
                error = EINVAL;
@@ -2305,7 +2348,7 @@ if_set_qosmarking_mode(struct ifnet *ifp, u_int32_t mode)
        }
        if (error == 0 && old_mode != ifp->if_qosmarking_mode) {
                dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_QOS_MODE_CHANGED,
-                   NULL, sizeof(struct kev_dl_rrc_state));
+                   NULL, 0);
        }
        return error;
 }
@@ -2360,10 +2403,12 @@ ifioctl_iforder(u_long cmd, caddr_t data)
                        if (found_duplicate) {
                                break;
                        }
-               }
-
-               error = ifnet_reset_order(ordered_indices, ifo->ifo_count);
 
+                       error = ifnet_reset_order(ordered_indices, ifo->ifo_count);
+               } else {
+                       // Clear the list
+                       error = ifnet_reset_order(NULL, 0);
+               }
                break;
        }
 
@@ -2380,6 +2425,33 @@ ifioctl_iforder(u_long cmd, caddr_t data)
        return error;
 }
 
+static __attribute__((noinline)) int
+ifioctl_networkid(struct ifnet *ifp, caddr_t data)
+{
+       struct if_netidreq *ifnetidr = (struct if_netidreq *)(void *)data;
+       int error = 0;
+       int len = ifnetidr->ifnetid_len;
+
+       VERIFY(ifp != NULL);
+
+       if (len > sizeof(ifnetidr->ifnetid)) {
+               error = EINVAL;
+               goto end;
+       }
+
+       if (len == 0) {
+               bzero(&ifp->network_id, sizeof(ifp->network_id));
+       } else if (len > sizeof(ifp->network_id)) {
+               error = EINVAL;
+               goto end;
+       }
+
+       ifp->network_id_len = len;
+       bcopy(data, ifp->network_id, len);
+end:
+       return error;
+}
+
 static __attribute__((noinline)) int
 ifioctl_netsignature(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
@@ -2419,7 +2491,6 @@ ifioctl_netsignature(struct ifnet *ifp, u_long cmd, caddr_t data)
        return error;
 }
 
-#if INET6
 static __attribute__((noinline)) int
 ifioctl_nat64prefix(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
@@ -2480,7 +2551,6 @@ ifioctl_clat46addr(struct ifnet *ifp, u_long cmd, caddr_t data)
 
        return error;
 }
-#endif
 
 
 static int
@@ -2595,7 +2665,6 @@ ifioctl_restrict_intcoproc(unsigned long cmd, const char *ifname,
        case SIOCGIFFLAGS:
        case SIOCGIFEFLAGS:
        case SIOCGIFCAP:
-       case SIOCGIFMAC:
        case SIOCGIFMETRIC:
        case SIOCGIFMTU:
        case SIOCGIFPHYS:
@@ -2640,6 +2709,7 @@ ifioctl_restrict_intcoproc(unsigned long cmd, const char *ifname,
        case SIOCGIFNETMASK_IN6:
        case SIOCGIFPROTOLIST32:
        case SIOCGIFPROTOLIST64:
+       case SIOCGIFXFLAGS:
                return false;
        default:
 #if (DEBUG || DEVELOPMENT)
@@ -2830,17 +2900,13 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
                        error = EOPNOTSUPP;
                        goto done;
                }
-       /* FALLTHRU */
+               OS_FALLTHROUGH;
        case SIOCIFCREATE:                      /* struct ifreq */
        case SIOCIFCREATE2:                     /* struct ifreq */
        case SIOCIFDESTROY:                     /* struct ifreq */
        case SIOCGIFFLAGS:                      /* struct ifreq */
        case SIOCGIFEFLAGS:                     /* struct ifreq */
        case SIOCGIFCAP:                        /* struct ifreq */
-#if CONFIG_MACF_NET
-       case SIOCGIFMAC:                        /* struct ifreq */
-       case SIOCSIFMAC:                        /* struct ifreq */
-#endif /* CONFIG_MACF_NET */
        case SIOCGIFMETRIC:                     /* struct ifreq */
        case SIOCGIFMTU:                        /* struct ifreq */
        case SIOCGIFPHYS:                       /* struct ifreq */
@@ -2900,6 +2966,15 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
        case SIOCGIFLOWINTERNET:                /* struct ifreq */
        case SIOCGIFLOWPOWER:                   /* struct ifreq */
        case SIOCSIFLOWPOWER:                   /* struct ifreq */
+       case SIOCSIF6LOWPAN:                    /* struct ifreq */
+       case SIOCGIF6LOWPAN:                    /* struct ifreq */
+       case SIOCGIFMPKLOG:                     /* struct ifreq */
+       case SIOCSIFMPKLOG:                     /* struct ifreq */
+       case SIOCGIFCONSTRAINED:                /* struct ifreq */
+       case SIOCSIFCONSTRAINED:                /* struct ifreq */
+       case SIOCGIFXFLAGS:                     /* struct ifreq */
+       case SIOCGIFNOACKPRIO:                  /* struct ifreq */
+       case SIOCSIFNOACKPRIO:                  /* struct ifreq */
        {                       /* struct ifreq */
                struct ifreq ifr;
                bcopy(data, &ifr, sizeof(ifr));
@@ -2924,22 +2999,20 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
        case SIOCSIFPHYADDR:                    /* struct {if,in_}aliasreq */
                bcopy(((struct in_aliasreq *)(void *)data)->ifra_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
 
-#if INET6
        case SIOCSIFPHYADDR_IN6_32:             /* struct in6_aliasreq_32 */
                bcopy(((struct in6_aliasreq_32 *)(void *)data)->ifra_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
 
        case SIOCSIFPHYADDR_IN6_64:             /* struct in6_aliasreq_64 */
                bcopy(((struct in6_aliasreq_64 *)(void *)data)->ifra_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
-#endif /* INET6 */
 
        case SIOCGIFSTATUS:                     /* struct ifstat */
                ifs = _MALLOC(sizeof(*ifs), M_DEVBUF, M_WAITOK);
@@ -2951,48 +3024,48 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
                bcopy(data, ifs, sizeof(*ifs));
                ifs->ifs_name[IFNAMSIZ - 1] = '\0';
                bcopy(ifs->ifs_name, ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
 
        case SIOCGIFMEDIA32:                    /* struct ifmediareq32 */
        case SIOCGIFXMEDIA32:                    /* struct ifmediareq32 */
                bcopy(((struct ifmediareq32 *)(void *)data)->ifm_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
 
        case SIOCGIFMEDIA64:                    /* struct ifmediareq64 */
        case SIOCGIFXMEDIA64:                    /* struct ifmediareq64 */
                bcopy(((struct ifmediareq64 *)(void *)data)->ifm_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
 
        case SIOCSIFDESC:                       /* struct if_descreq */
        case SIOCGIFDESC:                       /* struct if_descreq */
                bcopy(((struct if_descreq *)(void *)data)->ifdr_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
 
        case SIOCSIFLINKPARAMS:                 /* struct if_linkparamsreq */
        case SIOCGIFLINKPARAMS:                 /* struct if_linkparamsreq */
                bcopy(((struct if_linkparamsreq *)(void *)data)->iflpr_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
 
        case SIOCGIFQUEUESTATS:                 /* struct if_qstatsreq */
                bcopy(((struct if_qstatsreq *)(void *)data)->ifqr_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
 
        case SIOCSIFTHROTTLE:                   /* struct if_throttlereq */
        case SIOCGIFTHROTTLE:                   /* struct if_throttlereq */
                bcopy(((struct if_throttlereq *)(void *)data)->ifthr_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
 
        case SIOCAIFAGENTID:                    /* struct if_agentidreq */
@@ -3001,21 +3074,26 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
        case SIOCGIFAGENTIDS64:         /* struct if_agentidsreq64 */
                bcopy(((struct if_agentidreq *)(void *)data)->ifar_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
 
        case SIOCSIFNETSIGNATURE:               /* struct if_nsreq */
        case SIOCGIFNETSIGNATURE:               /* struct if_nsreq */
                bcopy(((struct if_nsreq *)(void *)data)->ifnsr_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
 
+       case SIOCSIFNETWORKID:                  /* struct if_netidreq */
+               bcopy(((struct if_netidreq *)(void *)data)->ifnetid_name,
+                   ifname, IFNAMSIZ);
+               ifp = ifunit_ref(ifname);
+               break;
        case SIOCGIFPROTOLIST32:                /* struct if_protolistreq32 */
        case SIOCGIFPROTOLIST64:                /* struct if_protolistreq64 */
                bcopy(((struct if_protolistreq *)(void *)data)->ifpl_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
        default:
                /*
@@ -3024,7 +3102,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
                 */
                bcopy(((struct ifreq *)(void *)data)->ifr_name,
                    ifname, IFNAMSIZ);
-               ifp = ifunit(ifname);
+               ifp = ifunit_ref(ifname);
                break;
        }
        dlil_if_unlock();
@@ -3040,10 +3118,8 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
        }
        switch (cmd) {
        case SIOCSIFPHYADDR:                    /* struct {if,in_}aliasreq */
-#if INET6
        case SIOCSIFPHYADDR_IN6_32:             /* struct in6_aliasreq_32 */
        case SIOCSIFPHYADDR_IN6_64:             /* struct in6_aliasreq_64 */
-#endif /* INET6 */
                error = proc_suser(p);
                if (error != 0) {
                        break;
@@ -3066,8 +3142,8 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
                bcopy(ifs, data, sizeof(*ifs));
                break;
 
-       case SIOCGIFMEDIA32:                   /* struct ifmediareq32 */
-       case SIOCGIFMEDIA64:                   /* struct ifmediareq64 */
+       case SIOCGIFMEDIA32:                    /* struct ifmediareq32 */
+       case SIOCGIFMEDIA64:                    /* struct ifmediareq64 */
        case SIOCGIFXMEDIA32:                    /* struct ifmediareq32 */
        case SIOCGIFXMEDIA64:                    /* struct ifmediareq64 */
                error = ifioctl_get_media(ifp, so, cmd, data);
@@ -3104,7 +3180,9 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
                error = ifioctl_netsignature(ifp, cmd, data);
                break;
 
-#if INET6
+       case SIOCSIFNETWORKID:                  /* struct if_netidreq */
+               error = ifioctl_networkid(ifp, data);
+               break;
        case SIOCSIFNAT64PREFIX:                /* struct if_nat64req */
        case SIOCGIFNAT64PREFIX:                /* struct if_nat64req */
                error = ifioctl_nat64prefix(ifp, cmd, data);
@@ -3113,7 +3191,6 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
        case SIOCGIFCLAT46ADDR:                 /* struct if_clat46req */
                error = ifioctl_clat46addr(ifp, cmd, data);
                break;
-#endif
 
        case SIOCGIFPROTOLIST32:                /* struct if_protolistreq32 */
        case SIOCGIFPROTOLIST64:                /* struct if_protolistreq64 */
@@ -3171,6 +3248,9 @@ done:
                }
        }
 
+       if (ifp != NULL) {
+               ifnet_decr_iorefcnt(ifp);
+       }
        return error;
 }
 
@@ -3228,6 +3308,12 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
                ifnet_lock_done(ifp);
                break;
 
+       case SIOCGIFXFLAGS:
+               ifnet_lock_shared(ifp);
+               ifr->ifr_xflags = ifp->if_xflags;
+               ifnet_lock_done(ifp);
+               break;
+
        case SIOCGIFCAP:
                ifnet_lock_shared(ifp);
                ifr->ifr_reqcap = ifp->if_capabilities;
@@ -3235,16 +3321,6 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
                ifnet_lock_done(ifp);
                break;
 
-#if CONFIG_MACF_NET
-       case SIOCGIFMAC:
-               error = mac_ifnet_label_get(kauth_cred_get(), ifr, ifp);
-               break;
-
-       case SIOCSIFMAC:
-               error = mac_ifnet_label_set(kauth_cred_get(), ifr, ifp);
-               break;
-#endif /* CONFIG_MACF_NET */
-
        case SIOCGIFMETRIC:
                ifnet_lock_shared(ifp);
                ifr->ifr_metric = ifp->if_metric;
@@ -3399,9 +3475,7 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
                 */
                if (ifp->if_mtu != oldmtu) {
                        if_rtmtu_update(ifp);
-#if INET6
                        nd6_setmtu(ifp);
-#endif /* INET6 */
                        /* Inform all transmit queues about the new MTU */
                        IFCQ_LOCK(ifq);
                        ifnet_update_sndq(ifq, CLASSQ_EV_LINK_MTU);
@@ -3429,6 +3503,9 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
                        error = EINVAL;
                        break;
                }
+               if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)) {
+                       ifr->ifr_addr.sa_len = sizeof(struct sockaddr);
+               }
 
                /*
                 * User is permitted to anonymously join a particular link
@@ -3495,6 +3572,7 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
        case SIOCSIFALTMTU:
        case SIOCSIFVLAN:
        case SIOCSIFBOND:
+       case SIOCSIF6LOWPAN:
                error = proc_suser(p);
                if (error != 0) {
                        break;
@@ -3545,6 +3623,7 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
        case SIOCGIFDEVMTU:
        case SIOCGIFVLAN:
        case SIOCGIFBOND:
+       case SIOCGIF6LOWPAN:
                error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
                break;
 
@@ -3611,13 +3690,13 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
                    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
                        return error;
                }
-               ifnet_lock_exclusive(ifp);
                if (ifr->ifr_expensive) {
-                       ifp->if_eflags |= IFEF_EXPENSIVE;
+                       if_set_eflags(ifp, IFEF_EXPENSIVE);
                } else {
-                       ifp->if_eflags &= ~IFEF_EXPENSIVE;
+                       if_clear_eflags(ifp, IFEF_EXPENSIVE);
                }
-               ifnet_lock_done(ifp);
+               ifnet_increment_generation(ifp);
+
                /*
                 * Update the expensive bit in the delegated interface
                 * structure.
@@ -3628,10 +3707,53 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
                        if (difp->if_delegated.ifp == ifp) {
                                difp->if_delegated.expensive =
                                    ifp->if_eflags & IFEF_EXPENSIVE ? 1 : 0;
+                               ifnet_increment_generation(difp);
                        }
                        ifnet_lock_done(difp);
                }
                ifnet_head_done();
+               necp_update_all_clients();
+               break;
+       }
+
+       case SIOCGIFCONSTRAINED:
+               if ((ifp->if_xflags & IFXF_CONSTRAINED) != 0) {
+                       ifr->ifr_constrained = 1;
+               } else {
+                       ifr->ifr_constrained = 0;
+               }
+               break;
+
+       case SIOCSIFCONSTRAINED:
+       {
+               struct ifnet *difp;
+
+               if ((error = priv_check_cred(kauth_cred_get(),
+                   PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
+                       return error;
+               }
+               if (ifr->ifr_constrained) {
+                       if_set_xflags(ifp, IFXF_CONSTRAINED);
+               } else {
+                       if_clear_xflags(ifp, IFXF_CONSTRAINED);
+               }
+               ifnet_increment_generation(ifp);
+               /*
+                * Update the constrained bit in the delegated interface
+                * structure.
+                */
+               ifnet_head_lock_shared();
+               TAILQ_FOREACH(difp, &ifnet_head, if_link) {
+                       ifnet_lock_exclusive(difp);
+                       if (difp->if_delegated.ifp == ifp) {
+                               difp->if_delegated.constrained =
+                                   ((ifp->if_xflags & IFXF_CONSTRAINED) != 0) ? 1 : 0;
+                               ifnet_increment_generation(difp);
+                       }
+                       ifnet_lock_done(difp);
+               }
+               ifnet_head_done();
+               necp_update_all_clients();
                break;
        }
 
@@ -3650,13 +3772,11 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
                    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
                        return error;
                }
-               ifnet_lock_exclusive(ifp);
                if (ifr->ifr_2kcl) {
-                       ifp->if_eflags |= IFEF_2KCL;
+                       if_set_eflags(ifp, IFEF_2KCL);
                } else {
-                       ifp->if_eflags &= ~IFEF_2KCL;
+                       if_clear_eflags(ifp, IFEF_2KCL);
                }
-               ifnet_lock_done(ifp);
                break;
        case SIOCGSTARTDELAY:
                ifnet_lock_shared(ifp);
@@ -3736,8 +3856,8 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
 
        case SIOCGIFINTERFACESTATE:
                if_get_state(ifp, &ifr->ifr_interface_state);
-
                break;
+
        case SIOCSIFINTERFACESTATE:
                if ((error = priv_check_cred(kauth_cred_get(),
                    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
@@ -3783,17 +3903,18 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
                        return error;
                }
                if (ifr->ifr_ecn_mode == IFRTYPE_ECN_DEFAULT) {
-                       ifp->if_eflags &= ~(IFEF_ECN_ENABLE | IFEF_ECN_DISABLE);
+                       if_clear_eflags(ifp, IFEF_ECN_ENABLE | IFEF_ECN_DISABLE);
                } else if (ifr->ifr_ecn_mode == IFRTYPE_ECN_ENABLE) {
-                       ifp->if_eflags |= IFEF_ECN_ENABLE;
-                       ifp->if_eflags &= ~IFEF_ECN_DISABLE;
+                       if_set_eflags(ifp, IFEF_ECN_ENABLE);
+                       if_clear_eflags(ifp, IFEF_ECN_DISABLE);
                } else if (ifr->ifr_ecn_mode == IFRTYPE_ECN_DISABLE) {
-                       ifp->if_eflags |= IFEF_ECN_DISABLE;
-                       ifp->if_eflags &= ~IFEF_ECN_ENABLE;
+                       if_set_eflags(ifp, IFEF_ECN_DISABLE);
+                       if_clear_eflags(ifp, IFEF_ECN_ENABLE);
                } else {
                        error = EINVAL;
                }
                break;
+
        case SIOCSIFTIMESTAMPENABLE:
        case SIOCSIFTIMESTAMPDISABLE:
                error = proc_suser(p);
@@ -3801,20 +3922,17 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
                        break;
                }
 
-               ifnet_lock_exclusive(ifp);
                if ((cmd == SIOCSIFTIMESTAMPENABLE &&
                    (ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) != 0) ||
                    (cmd == SIOCSIFTIMESTAMPDISABLE &&
                    (ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) == 0)) {
-                       ifnet_lock_done(ifp);
                        break;
                }
                if (cmd == SIOCSIFTIMESTAMPENABLE) {
-                       ifp->if_xflags |= IFXF_TIMESTAMP_ENABLED;
+                       if_set_xflags(ifp, IFXF_TIMESTAMP_ENABLED);
                } else {
-                       ifp->if_xflags &= ~IFXF_TIMESTAMP_ENABLED;
+                       if_clear_xflags(ifp, IFXF_TIMESTAMP_ENABLED);
                }
-               ifnet_lock_done(ifp);
                /*
                 * Pass the setting to the interface if it supports either
                 * software or hardware time stamping
@@ -3851,15 +3969,15 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
                        return error;
                }
                if (ifr->ifr_qosmarking_enabled != 0) {
-                       ifp->if_eflags |= IFEF_QOSMARKING_ENABLED;
+                       if_set_eflags(ifp, IFEF_QOSMARKING_ENABLED);
                } else {
-                       ifp->if_eflags &= ~IFEF_QOSMARKING_ENABLED;
+                       if_clear_eflags(ifp, IFEF_QOSMARKING_ENABLED);
                }
                break;
 
        case SIOCGQOSMARKINGENABLED:
                ifr->ifr_qosmarking_enabled =
-                   (ifp->if_eflags & IFEF_QOSMARKING_ENABLED) ? 1 : 0;
+                   ((ifp->if_eflags & IFEF_QOSMARKING_ENABLED) != 0) ? 1 : 0;
                break;
 
        case SIOCSIFDISABLEOUTPUT:
@@ -3875,33 +3993,40 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
                error = EINVAL;
 #endif /* (DEBUG || DEVELOPMENT) */
                break;
+
+       case SIOCSIFSUBFAMILY:
+               if ((error = priv_check_cred(kauth_cred_get(),
+                   PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
+                       return error;
+               }
+               error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
+               break;
+
        case SIOCSIFLOWINTERNET:
                if ((error = priv_check_cred(kauth_cred_get(),
                    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
                        return error;
                }
 
-               ifnet_lock_exclusive(ifp);
                if (ifr->ifr_low_internet & IFRTYPE_LOW_INTERNET_ENABLE_UL) {
-                       ifp->if_xflags |= IFXF_LOW_INTERNET_UL;
+                       if_set_xflags(ifp, IFXF_LOW_INTERNET_UL);
                } else {
-                       ifp->if_xflags &= ~(IFXF_LOW_INTERNET_UL);
+                       if_clear_xflags(ifp, IFXF_LOW_INTERNET_UL);
                }
                if (ifr->ifr_low_internet & IFRTYPE_LOW_INTERNET_ENABLE_DL) {
-                       ifp->if_xflags |= IFXF_LOW_INTERNET_DL;
+                       if_set_xflags(ifp, IFXF_LOW_INTERNET_DL);
                } else {
-                       ifp->if_xflags &= ~(IFXF_LOW_INTERNET_DL);
+                       if_clear_xflags(ifp, IFXF_LOW_INTERNET_DL);
                }
-               ifnet_lock_done(ifp);
                break;
        case SIOCGIFLOWINTERNET:
                ifnet_lock_shared(ifp);
                ifr->ifr_low_internet = 0;
-               if (ifp->if_xflags & IFXF_LOW_INTERNET_UL) {
+               if ((ifp->if_xflags & IFXF_LOW_INTERNET_UL) != 0) {
                        ifr->ifr_low_internet |=
                            IFRTYPE_LOW_INTERNET_ENABLE_UL;
                }
-               if (ifp->if_xflags & IFXF_LOW_INTERNET_DL) {
+               if ((ifp->if_xflags & IFXF_LOW_INTERNET_DL) != 0) {
                        ifr->ifr_low_internet |=
                            IFRTYPE_LOW_INTERNET_ENABLE_DL;
                }
@@ -3909,15 +4034,46 @@ ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
                break;
        case SIOCGIFLOWPOWER:
                ifr->ifr_low_power_mode =
-                   !!(ifp->if_xflags & IFXF_LOW_POWER);
+                   ((ifp->if_xflags & IFXF_LOW_POWER) != 0);
                break;
        case SIOCSIFLOWPOWER:
 #if (DEVELOPMENT || DEBUG)
-               error = if_set_low_power(ifp, !!(ifr->ifr_low_power_mode));
+               error = if_set_low_power(ifp, (ifr->ifr_low_power_mode != 0));
 #else /* DEVELOPMENT || DEBUG */
                error = EOPNOTSUPP;
 #endif /* DEVELOPMENT || DEBUG */
                break;
+
+       case SIOCGIFMPKLOG:
+               ifr->ifr_mpk_log = ((ifp->if_xflags & IFXF_MPK_LOG) != 0);
+               break;
+       case SIOCSIFMPKLOG:
+               if (ifr->ifr_mpk_log) {
+                       if_set_xflags(ifp, IFXF_MPK_LOG);
+               } else {
+                       if_clear_xflags(ifp, IFXF_MPK_LOG);
+               }
+               break;
+       case SIOCGIFNOACKPRIO:
+               if ((ifp->if_eflags & IFEF_NOACKPRI) != 0) {
+                       ifr->ifr_noack_prio = 1;
+               } else {
+                       ifr->ifr_noack_prio = 0;
+               }
+               break;
+
+       case SIOCSIFNOACKPRIO:
+               if ((error = priv_check_cred(kauth_cred_get(),
+                   PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
+                       return error;
+               }
+               if (ifr->ifr_noack_prio) {
+                       if_set_eflags(ifp, IFEF_NOACKPRI);
+               } else {
+                       if_clear_eflags(ifp, IFEF_NOACKPRI);
+               }
+               break;
+
        default:
                VERIFY(0);
                /* NOTREACHED */
@@ -5216,15 +5372,18 @@ if_copy_rxpoll_stats(struct ifnet *ifp, struct if_rxpoll_stats *if_rs)
        if (!(ifp->if_eflags & IFEF_RXPOLL) || !ifnet_is_attached(ifp, 1)) {
                return;
        }
-
-       /* by now, ifnet will stay attached so if_inp must be valid */
-       VERIFY(ifp->if_inp != NULL);
-       bcopy(&ifp->if_inp->pstats, if_rs, sizeof(*if_rs));
-
+       bcopy(&ifp->if_poll_pstats, if_rs, sizeof(*if_rs));
        /* Release the IO refcnt */
        ifnet_decr_iorefcnt(ifp);
 }
 
+void
+if_copy_netif_stats(struct ifnet *ifp, struct if_netif_stats *if_ns)
+{
+       bzero(if_ns, sizeof(*if_ns));
+#pragma unused(ifp)
+}
+
 struct ifaddr *
 ifa_remref(struct ifaddr *ifa, int locked)
 {
@@ -5330,7 +5489,6 @@ ifioctl_cassert(void)
        case SIOCGPPPSTATS:
        case SIOCGPPPCSTATS:
 
-#if INET6
        /* bsd/netinet6/in6_var.h */
        case SIOCSIFADDR_IN6:
        case SIOCGIFADDR_IN6:
@@ -5384,11 +5542,11 @@ ifioctl_cassert(void)
        case SIOCAUTOCONF_START:
        case SIOCAUTOCONF_STOP:
        case SIOCSETROUTERMODE_IN6:
+       case SIOCGETROUTERMODE_IN6:
        case SIOCLL_CGASTART_32:
        case SIOCLL_CGASTART_64:
        case SIOCGIFCGAPREP_IN6:
        case SIOCSIFCGAPREP_IN6:
-#endif /* INET6 */
 
        /* bsd/sys/sockio.h */
        case SIOCSIFADDR:
@@ -5469,10 +5627,6 @@ ifioctl_cassert(void)
 
        case SIOCGIFASYNCMAP:
        case SIOCSIFASYNCMAP:
-#if CONFIG_MACF_NET
-       case SIOCGIFMAC:
-       case SIOCSIFMAC:
-#endif /* CONFIG_MACF_NET */
        case SIOCSIFKPI:
        case SIOCGIFKPI:
 
@@ -5482,6 +5636,7 @@ ifioctl_cassert(void)
        case SIOCGIFLINKQUALITYMETRIC:
        case SIOCSIFOPPORTUNISTIC:
        case SIOCGIFOPPORTUNISTIC:
+       case SIOCGETROUTERMODE:
        case SIOCSETROUTERMODE:
        case SIOCGIFEFLAGS:
        case SIOCSIFDESC:
@@ -5528,6 +5683,7 @@ ifioctl_cassert(void)
        case SIOCSIFNETSIGNATURE:
        case SIOCGIFNETSIGNATURE:
 
+       case SIOCSIFNETWORKID:
        case SIOCGECNMODE:
        case SIOCSECNMODE:
 
@@ -5544,24 +5700,38 @@ ifioctl_cassert(void)
 
        case SIOCSIFDISABLEOUTPUT:
 
+       case SIOCSIFSUBFAMILY:
+
        case SIOCGIFAGENTLIST32:
        case SIOCGIFAGENTLIST64:
 
        case SIOCSIFLOWINTERNET:
        case SIOCGIFLOWINTERNET:
 
-#if INET6
        case SIOCGIFNAT64PREFIX:
        case SIOCSIFNAT64PREFIX:
 
        case SIOCGIFCLAT46ADDR:
-#endif /* INET6 */
 
        case SIOCGIFPROTOLIST32:
        case SIOCGIFPROTOLIST64:
 
+       case SIOCSIF6LOWPAN:
+       case SIOCGIF6LOWPAN:
+
        case SIOCGIFLOWPOWER:
        case SIOCSIFLOWPOWER:
+
+       case SIOCGIFMPKLOG:
+       case SIOCSIFMPKLOG:
+
+       case SIOCGIFCONSTRAINED:
+       case SIOCSIFCONSTRAINED:
+
+       case SIOCGIFXFLAGS:
+
+       case SIOCGIFNOACKPRIO:
+       case SIOCSIFNOACKPRIO:
                ;
        }
 }
@@ -5617,3 +5787,25 @@ intf_event_enqueue_nwk_wq_entry(struct ifnet *ifp, struct sockaddr *addrp,
        p_intf_ev->nwk_wqe.arg = &p_intf_ev->intf_ev_arg;
        nwk_wq_enqueue((struct nwk_wq_entry*)p_intf_ev);
 }
+
+int
+if_get_tcp_kao_max(struct ifnet *ifp)
+{
+       int error = 0;
+
+       if (ifp->if_tcp_kao_max == 0) {
+               struct ifreq ifr;
+
+               memset(&ifr, 0, sizeof(struct ifreq));
+               error = ifnet_ioctl(ifp, 0, SIOCGIFTCPKAOMAX, &ifr);
+
+               ifnet_lock_exclusive(ifp);
+               if (error == 0) {
+                       ifp->if_tcp_kao_max = ifr.ifr_tcp_kao_max;
+               } else if (error == EOPNOTSUPP) {
+                       ifp->if_tcp_kao_max = default_tcp_kao_max;
+               }
+               ifnet_lock_done(ifp);
+       }
+       return error;
+}