]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/kpi_interface.c
xnu-3789.41.3.tar.gz
[apple/xnu.git] / bsd / net / kpi_interface.c
index 22b18df0563b311dbbd4fe2d7bd1ac1da4245785..d28af82ac02887c0823f8f529beabcc2d708bdaa 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2004-2014 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -69,6 +69,7 @@
 #ifdef INET6
 #include <netinet6/mld6_var.h>
 #endif
 #ifdef INET6
 #include <netinet6/mld6_var.h>
 #endif
+#include <netkey/key.h>
 
 #include "net/net_str_id.h"
 
 
 #include "net/net_str_id.h"
 
@@ -154,6 +155,7 @@ ifnet_allocate_extended(const struct ifnet_init_eparams *einit0,
 {
        struct ifnet_init_eparams einit;
        struct ifnet *ifp = NULL;
 {
        struct ifnet_init_eparams einit;
        struct ifnet *ifp = NULL;
+       char if_xname[IFXNAMSIZ] = {0};
        int error;
 
        einit = *einit0;
        int error;
 
        einit = *einit0;
@@ -194,6 +196,14 @@ ifnet_allocate_extended(const struct ifnet_init_eparams *einit0,
                }
        }
 
                }
        }
 
+       if (einit.uniqueid == NULL) {
+               /* Initialize external name (name + unit) */
+               snprintf(if_xname, IFXNAMSIZ,
+                               "%s%d", einit.name, einit.unit);
+               einit.uniqueid = if_xname;
+               einit.uniqueid_len = strlen(if_xname);
+       }
+
        error = dlil_if_acquire(einit.family, einit.uniqueid,
            einit.uniqueid_len, &ifp);
 
        error = dlil_if_acquire(einit.family, einit.uniqueid,
            einit.uniqueid_len, &ifp);
 
@@ -317,6 +327,9 @@ ifnet_allocate_extended(const struct ifnet_init_eparams *einit0,
                else
                        ifp->if_eflags &= ~IFEF_RXPOLL;
 
                else
                        ifp->if_eflags &= ~IFEF_RXPOLL;
 
+               ifp->if_output_handler = dlil_output_handler;
+               ifp->if_input_handler = dlil_input_handler;
+
                VERIFY(!(einit.flags & IFNET_INIT_LEGACY) ||
                    (ifp->if_pre_enqueue == NULL && ifp->if_start == NULL &&
                    ifp->if_output_ctl == NULL && ifp->if_input_poll == NULL &&
                VERIFY(!(einit.flags & IFNET_INIT_LEGACY) ||
                    (ifp->if_pre_enqueue == NULL && ifp->if_start == NULL &&
                    ifp->if_output_ctl == NULL && ifp->if_input_poll == NULL &&
@@ -346,10 +359,25 @@ ifnet_allocate_extended(const struct ifnet_init_eparams *einit0,
                        bzero(&ifp->if_broadcast, sizeof (ifp->if_broadcast));
                }
 
                        bzero(&ifp->if_broadcast, sizeof (ifp->if_broadcast));
                }
 
+               /*
+                * output target queue delay is specified in millisecond
+                * convert it to nanoseconds
+                */
                IFCQ_TARGET_QDELAY(&ifp->if_snd) =
                IFCQ_TARGET_QDELAY(&ifp->if_snd) =
-                   einit.output_target_qdelay;
+                   einit.output_target_qdelay * 1000 * 1000;
                IFCQ_MAXLEN(&ifp->if_snd) = einit.sndq_maxlen;
 
                IFCQ_MAXLEN(&ifp->if_snd) = einit.sndq_maxlen;
 
+               if (einit.start_delay_qlen > 0 &&
+                   einit.start_delay_timeout > 0) {
+                       ifp->if_eflags |= IFEF_ENQUEUE_MULTI;
+                       ifp->if_start_delay_qlen =
+                           min(100, einit.start_delay_qlen);
+                       ifp->if_start_delay_timeout =
+                           min(20000, einit.start_delay_timeout);
+                       /* convert timeout to nanoseconds */
+                       ifp->if_start_delay_timeout *= 1000;
+               }
+
                if (error == 0) {
                        *interface = ifp;
                        // temporary - this should be done in dlil_if_acquire
                if (error == 0) {
                        *interface = ifp;
                        // temporary - this should be done in dlil_if_acquire
@@ -484,7 +512,7 @@ ifnet_flags(ifnet_t interface)
  * If IFEF_AWDL has been set on the interface and the caller attempts
  * to clear one or more of the associated flags in IFEF_AWDL_MASK,
  * return failure.
  * If IFEF_AWDL has been set on the interface and the caller attempts
  * to clear one or more of the associated flags in IFEF_AWDL_MASK,
  * return failure.
- * 
+ *
  * If IFEF_AWDL_RESTRICTED is set by the caller, make sure IFEF_AWDL is set
  * on the interface.
  *
  * If IFEF_AWDL_RESTRICTED is set by the caller, make sure IFEF_AWDL is set
  * on the interface.
  *
@@ -568,8 +596,8 @@ ifnet_set_eflags(ifnet_t interface, u_int32_t new_flags, u_int32_t mask)
                ev_data.if_unit = interface->if_unit;
                ev_msg.dv[0].data_length = sizeof(struct net_event_data);
                ev_msg.dv[0].data_ptr = &ev_data;
                ev_data.if_unit = interface->if_unit;
                ev_msg.dv[0].data_length = sizeof(struct net_event_data);
                ev_msg.dv[0].data_ptr = &ev_data;
-               ev_msg.dv[1].data_length = 0; 
-               kev_post_msg(&ev_msg);
+               ev_msg.dv[1].data_length = 0;
+               dlil_post_complete_msg(interface, &ev_msg);
        }
 
        return (0);
        }
 
        return (0);
@@ -612,12 +640,8 @@ ifnet_set_idle_flags_locked(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask)
        if ((after - before) < 0 && ifp->if_idle_flags == 0 &&
            ifp->if_want_aggressive_drain != 0) {
                ifp->if_want_aggressive_drain = 0;
        if ((after - before) < 0 && ifp->if_idle_flags == 0 &&
            ifp->if_want_aggressive_drain != 0) {
                ifp->if_want_aggressive_drain = 0;
-               if (ifnet_aggressive_drainers == 0)
-                       panic("%s: ifp=%p negative aggdrain!", __func__, ifp);
        } else if ((after - before) > 0 && ifp->if_want_aggressive_drain == 0) {
                ifp->if_want_aggressive_drain++;
        } else if ((after - before) > 0 && ifp->if_want_aggressive_drain == 0) {
                ifp->if_want_aggressive_drain++;
-               if (++ifnet_aggressive_drainers == 0)
-                       panic("%s: ifp=%p wraparound aggdrain!", __func__, ifp);
        }
 
        return (0);
        }
 
        return (0);
@@ -658,7 +682,7 @@ ifnet_set_link_quality(ifnet_t ifp, int quality)
                goto done;
        }
 
                goto done;
        }
 
-       if_lqm_update(ifp, quality);
+       if_lqm_update(ifp, quality, 0);
 
 done:
        return (err);
 
 done:
        return (err);
@@ -673,12 +697,57 @@ ifnet_link_quality(ifnet_t ifp)
                return (IFNET_LQM_THRESH_OFF);
 
        ifnet_lock_shared(ifp);
                return (IFNET_LQM_THRESH_OFF);
 
        ifnet_lock_shared(ifp);
-       lqm = ifp->if_lqm;
+       lqm = ifp->if_interface_state.lqm_state;
        ifnet_lock_done(ifp);
 
        return (lqm);
 }
 
        ifnet_lock_done(ifp);
 
        return (lqm);
 }
 
+errno_t
+ifnet_set_interface_state(ifnet_t ifp,
+    struct if_interface_state *if_interface_state)
+{
+       errno_t err = 0;
+
+       if (ifp == NULL || if_interface_state == NULL) {
+               err = EINVAL;
+               goto done;
+       }
+
+       if (!ifnet_is_attached(ifp, 0)) {
+               err = ENXIO;
+               goto done;
+       }
+
+       if_state_update(ifp, if_interface_state);
+
+done:
+       return (err);
+}
+
+errno_t
+ifnet_get_interface_state(ifnet_t ifp,
+    struct if_interface_state *if_interface_state)
+{
+       errno_t err = 0;
+
+       if (ifp == NULL || if_interface_state == NULL) {
+               err = EINVAL;
+               goto done;
+       }
+
+       if (!ifnet_is_attached(ifp, 0)) {
+               err = ENXIO;
+               goto done;
+       }
+
+       if_get_state(ifp, if_interface_state);
+
+done:
+       return (err);
+}
+
+
 static errno_t
 ifnet_defrouter_llreachinfo(ifnet_t ifp, int af,
     struct ifnet_llreach_info *iflri)
 static errno_t
 ifnet_defrouter_llreachinfo(ifnet_t ifp, int af,
     struct ifnet_llreach_info *iflri)
@@ -765,7 +834,7 @@ ifnet_set_capabilities_enabled(ifnet_t ifp, u_int32_t new_caps,
        ev_msg.dv[0].data_length = sizeof (struct net_event_data);
        ev_msg.dv[0].data_ptr = &ev_data;
        ev_msg.dv[1].data_length = 0;
        ev_msg.dv[0].data_length = sizeof (struct net_event_data);
        ev_msg.dv[0].data_ptr = &ev_data;
        ev_msg.dv[1].data_length = 0;
-       kev_post_msg(&ev_msg);
+       dlil_post_complete_msg(ifp, &ev_msg);
 
        return (error);
 }
 
        return (error);
 }
@@ -781,11 +850,9 @@ static const ifnet_offload_t offload_mask =
        IFNET_IP_FRAGMENT | IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 |
        IFNET_IPV6_FRAGMENT | IFNET_CSUM_PARTIAL | IFNET_VLAN_TAGGING |
        IFNET_VLAN_MTU | IFNET_MULTIPAGES | IFNET_TSO_IPV4 | IFNET_TSO_IPV6 |
        IFNET_IP_FRAGMENT | IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 |
        IFNET_IPV6_FRAGMENT | IFNET_CSUM_PARTIAL | IFNET_VLAN_TAGGING |
        IFNET_VLAN_MTU | IFNET_MULTIPAGES | IFNET_TSO_IPV4 | IFNET_TSO_IPV6 |
-       IFNET_TX_STATUS);
+       IFNET_TX_STATUS | IFNET_HW_TIMESTAMP | IFNET_SW_TIMESTAMP);
 
 
-static const ifnet_offload_t any_offload_csum =
-       (IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT |
-       IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | IFNET_CSUM_PARTIAL);
+static const ifnet_offload_t any_offload_csum = IFNET_CHECKSUMF;
 
 errno_t
 ifnet_set_offload(ifnet_t interface, ifnet_offload_t offload)
 
 errno_t
 ifnet_set_offload(ifnet_t interface, ifnet_offload_t offload)
@@ -824,8 +891,12 @@ ifnet_set_offload(ifnet_t interface, ifnet_offload_t offload)
                ifcaps |= IFCAP_VLAN_MTU;
        if ((offload & IFNET_VLAN_TAGGING))
                ifcaps |= IFCAP_VLAN_HWTAGGING;
                ifcaps |= IFCAP_VLAN_MTU;
        if ((offload & IFNET_VLAN_TAGGING))
                ifcaps |= IFCAP_VLAN_HWTAGGING;
-       if ((offload & IFNET_TX_STATUS)) 
-               ifcaps |= IFNET_TX_STATUS;
+       if ((offload & IFNET_TX_STATUS))
+               ifcaps |= IFCAP_TXSTATUS;
+       if ((offload & IFNET_HW_TIMESTAMP))
+               ifcaps |= IFCAP_HW_TIMESTAMP;
+       if ((offload & IFNET_SW_TIMESTAMP))
+               ifcaps |= IFCAP_SW_TIMESTAMP;
        if (ifcaps != 0) {
                (void) ifnet_set_capabilities_supported(interface, ifcaps,
                    IFCAP_VALID);
        if (ifcaps != 0) {
                (void) ifnet_set_capabilities_supported(interface, ifcaps,
                    IFCAP_VALID);
@@ -923,8 +994,12 @@ ifnet_set_wake_flags(ifnet_t interface, u_int32_t properties, u_int32_t mask)
 
        ifnet_lock_exclusive(interface);
 
 
        ifnet_lock_exclusive(interface);
 
-       interface->if_wake_properties =
-           (properties & mask) | (interface->if_wake_properties & ~mask);
+       if (mask & IF_WAKE_ON_MAGIC_PACKET) {
+               if (properties & IF_WAKE_ON_MAGIC_PACKET)
+                       interface->if_xflags |= IFXF_WAKE_ON_MAGIC_PACKET;
+               else
+                       interface->if_xflags &= ~IFXF_WAKE_ON_MAGIC_PACKET;
+       }
 
        ifnet_lock_done(interface);
 
 
        ifnet_lock_done(interface);
 
@@ -942,7 +1017,7 @@ ifnet_set_wake_flags(ifnet_t interface, u_int32_t properties, u_int32_t mask)
        ev_msg.dv[0].data_length = sizeof (struct net_event_data);
        ev_msg.dv[0].data_ptr   = &ev_data;
        ev_msg.dv[1].data_length = 0;
        ev_msg.dv[0].data_length = sizeof (struct net_event_data);
        ev_msg.dv[0].data_ptr   = &ev_data;
        ev_msg.dv[1].data_length = 0;
-       kev_post_msg(&ev_msg);
+       dlil_post_complete_msg(interface, &ev_msg);
 
        return (0);
 }
 
        return (0);
 }
@@ -950,7 +1025,15 @@ ifnet_set_wake_flags(ifnet_t interface, u_int32_t properties, u_int32_t mask)
 u_int32_t
 ifnet_get_wake_flags(ifnet_t interface)
 {
 u_int32_t
 ifnet_get_wake_flags(ifnet_t interface)
 {
-       return ((interface == NULL) ? 0 : interface->if_wake_properties);
+       u_int32_t flags = 0;
+
+       if (interface == NULL)
+               return (0);
+
+       if (interface->if_xflags & IFXF_WAKE_ON_MAGIC_PACKET)
+               flags |= IF_WAKE_ON_MAGIC_PACKET;
+
+       return (flags);
 }
 
 /*
 }
 
 /*
@@ -1129,6 +1212,25 @@ ifnet_set_bandwidths(struct ifnet *ifp, struct if_bandwidths *output_bw,
        return (0);
 }
 
        return (0);
 }
 
+static void
+ifnet_set_link_status_outbw(struct ifnet *ifp)
+{
+       struct if_wifi_status_v1 *sr;
+       sr = &ifp->if_link_status->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
+       if (ifp->if_output_bw.eff_bw != 0) {
+               sr->valid_bitmask |=
+                   IF_WIFI_UL_EFFECTIVE_BANDWIDTH_VALID;
+               sr->ul_effective_bandwidth =
+                   ifp->if_output_bw.eff_bw;
+       }
+       if (ifp->if_output_bw.max_bw != 0) {
+               sr->valid_bitmask |=
+                   IF_WIFI_UL_MAX_BANDWIDTH_VALID;
+               sr->ul_max_bandwidth =
+                   ifp->if_output_bw.max_bw;
+       }
+}
+
 errno_t
 ifnet_set_output_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw,
     boolean_t locked)
 errno_t
 ifnet_set_output_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw,
     boolean_t locked)
@@ -1167,9 +1269,38 @@ ifnet_set_output_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw,
        if (!locked)
                IFCQ_UNLOCK(ifq);
 
        if (!locked)
                IFCQ_UNLOCK(ifq);
 
+       /*
+        * If this is a Wifi interface, update the values in
+        * if_link_status structure also.
+        */
+       if (IFNET_IS_WIFI(ifp) && ifp->if_link_status != NULL) {
+               lck_rw_lock_exclusive(&ifp->if_link_status_lock);
+               ifnet_set_link_status_outbw(ifp);
+               lck_rw_done(&ifp->if_link_status_lock);
+       }
+
        return (0);
 }
 
        return (0);
 }
 
+static void
+ifnet_set_link_status_inbw(struct ifnet *ifp)
+{
+       struct if_wifi_status_v1 *sr;
+
+       sr = &ifp->if_link_status->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
+       if (ifp->if_input_bw.eff_bw != 0) {
+               sr->valid_bitmask |=
+                   IF_WIFI_DL_EFFECTIVE_BANDWIDTH_VALID;
+               sr->dl_effective_bandwidth =
+                   ifp->if_input_bw.eff_bw;
+       }
+       if (ifp->if_input_bw.max_bw != 0) {
+               sr->valid_bitmask |=
+                   IF_WIFI_DL_MAX_BANDWIDTH_VALID;
+               sr->dl_max_bandwidth = ifp->if_input_bw.max_bw;
+       }
+}
+
 errno_t
 ifnet_set_input_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw)
 {
 errno_t
 ifnet_set_input_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw)
 {
@@ -1187,6 +1318,12 @@ ifnet_set_input_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw)
        else if (ifp->if_input_bw.eff_bw == 0)
                ifp->if_input_bw.eff_bw = ifp->if_input_bw.max_bw;
 
        else if (ifp->if_input_bw.eff_bw == 0)
                ifp->if_input_bw.eff_bw = ifp->if_input_bw.max_bw;
 
+       if (IFNET_IS_WIFI(ifp) && ifp->if_link_status != NULL) {
+               lck_rw_lock_exclusive(&ifp->if_link_status_lock);
+               ifnet_set_link_status_inbw(ifp);
+               lck_rw_done(&ifp->if_link_status_lock);
+       }
+
        if (old_bw.eff_bw != ifp->if_input_bw.eff_bw ||
            old_bw.max_bw != ifp->if_input_bw.max_bw)
                ifnet_update_rcv(ifp, CLASSQ_EV_LINK_BANDWIDTH);
        if (old_bw.eff_bw != ifp->if_input_bw.eff_bw ||
            old_bw.max_bw != ifp->if_input_bw.max_bw)
                ifnet_update_rcv(ifp, CLASSQ_EV_LINK_BANDWIDTH);
@@ -1526,7 +1663,7 @@ errno_t
 ifnet_get_inuse_address_list(ifnet_t interface, ifaddr_t **addresses)
 {
        return (addresses == NULL ? EINVAL :
 ifnet_get_inuse_address_list(ifnet_t interface, ifaddr_t **addresses)
 {
        return (addresses == NULL ? EINVAL :
-               ifnet_get_address_list_family_internal(interface, addresses, 
+               ifnet_get_address_list_family_internal(interface, addresses,
                0, 0, M_NOWAIT, 1));
 }
 
                0, 0, M_NOWAIT, 1));
 }
 
@@ -1625,17 +1762,16 @@ done:
                        if (return_inuse_addrs) {
                                usecount = tcp_find_anypcb_byaddr(ifal->ifal_ifa);
                                usecount += udp_find_anypcb_byaddr(ifal->ifal_ifa);
                        if (return_inuse_addrs) {
                                usecount = tcp_find_anypcb_byaddr(ifal->ifal_ifa);
                                usecount += udp_find_anypcb_byaddr(ifal->ifal_ifa);
-                               if (usecount) { 
+                               if (usecount) {
                                        (*addresses)[index] = ifal->ifal_ifa;
                                        index++;
                                        (*addresses)[index] = ifal->ifal_ifa;
                                        index++;
-                               }       
-                               else
+                               } else {
                                        IFA_REMREF(ifal->ifal_ifa);
                                        IFA_REMREF(ifal->ifal_ifa);
+                               }
                        } else {
                                (*addresses)[--count] = ifal->ifal_ifa;
                        }
                        } else {
                                (*addresses)[--count] = ifal->ifal_ifa;
                        }
-               }       
-               else {
+               } else {
                        IFA_REMREF(ifal->ifal_ifa);
                }
                FREE(ifal, M_TEMP);
                        IFA_REMREF(ifal->ifal_ifa);
                }
                FREE(ifal, M_TEMP);
@@ -2081,7 +2217,7 @@ ifnet_transmit_burst_start(ifnet_t ifp, mbuf_t pkt)
 
        ifp->if_bw.start_seq = pkt->m_pkthdr.pkt_bwseq;
        ifp->if_bw.start_ts = mach_absolute_time();
 
        ifp->if_bw.start_seq = pkt->m_pkthdr.pkt_bwseq;
        ifp->if_bw.start_ts = mach_absolute_time();
-#else /*!MEASURE_BW */
+#else /* !MEASURE_BW */
 #pragma unused(ifp, pkt)
 #endif /* !MEASURE_BW */
 }
 #pragma unused(ifp, pkt)
 #endif /* !MEASURE_BW */
 }
@@ -2093,7 +2229,7 @@ ifnet_transmit_burst_end(ifnet_t ifp, mbuf_t pkt)
        uint64_t oseq, ots, bytes, ts, t;
        uint32_t flags;
 
        uint64_t oseq, ots, bytes, ts, t;
        uint32_t flags;
 
-       if ( ifp == NULL || !(pkt->m_flags & M_PKTHDR))
+       if (ifp == NULL || !(pkt->m_flags & M_PKTHDR))
                return;
 
        flags = OSBitOrAtomic(IF_MEASURED_BW_CALCULATION, &ifp->if_bw.flags);
                return;
 
        flags = OSBitOrAtomic(IF_MEASURED_BW_CALCULATION, &ifp->if_bw.flags);
@@ -2116,7 +2252,7 @@ ifnet_transmit_burst_end(ifnet_t ifp, mbuf_t pkt)
 
        if (ifp->if_bw.start_seq > 0 && oseq > ifp->if_bw.start_seq) {
                ts = ots - ifp->if_bw.start_ts;
 
        if (ifp->if_bw.start_seq > 0 && oseq > ifp->if_bw.start_seq) {
                ts = ots - ifp->if_bw.start_ts;
-               if (ts > 0 ) {
+               if (ts > 0) {
                        absolutetime_to_nanoseconds(ts, &t);
                        bytes = oseq - ifp->if_bw.start_seq;
                        ifp->if_bw.bytes = bytes;
                        absolutetime_to_nanoseconds(ts, &t);
                        bytes = oseq - ifp->if_bw.start_seq;
                        ifp->if_bw.bytes = bytes;
@@ -2154,9 +2290,9 @@ done:
 #endif /* !MEASURE_BW */
 }
 
 #endif /* !MEASURE_BW */
 }
 
-/****************************************************************************/
-/* ifaddr_t accessors                                                      */
-/****************************************************************************/
+/*************************************************************************/
+/* ifaddr_t accessors                                          */
+/*************************************************************************/
 
 errno_t
 ifaddr_reference(ifaddr_t ifa)
 
 errno_t
 ifaddr_reference(ifaddr_t ifa)
@@ -2400,9 +2536,9 @@ ifmaddr_ifnet(ifmultiaddr_t ifma)
        return ((ifma == NULL) ? NULL : ifma->ifma_ifp);
 }
 
        return ((ifma == NULL) ? NULL : ifma->ifma_ifp);
 }
 
-/******************************************************************************/
-/* interface cloner                                                           */
-/******************************************************************************/
+/**************************************************************************/
+/* interface cloner                                            */
+/**************************************************************************/
 
 errno_t
 ifnet_clone_attach(struct ifnet_clone_params *cloner_params,
 
 errno_t
 ifnet_clone_attach(struct ifnet_clone_params *cloner_params,
@@ -2480,9 +2616,9 @@ fail:
        return (error);
 }
 
        return (error);
 }
 
-/******************************************************************************/
-/* misc                                                                       */
-/******************************************************************************/
+/**************************************************************************/
+/* misc                                                        */
+/**************************************************************************/
 
 errno_t
 ifnet_get_local_ports_extended(ifnet_t ifp, protocol_family_t protocol,
 
 errno_t
 ifnet_get_local_ports_extended(ifnet_t ifp, protocol_family_t protocol,
@@ -2495,6 +2631,12 @@ ifnet_get_local_ports_extended(ifnet_t ifp, protocol_family_t protocol,
                INPCB_GET_PORTS_USED_WILDCARDOK : 0);
        inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_NOWAKEUPOK) ?
                INPCB_GET_PORTS_USED_NOWAKEUPOK : 0);
                INPCB_GET_PORTS_USED_WILDCARDOK : 0);
        inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_NOWAKEUPOK) ?
                INPCB_GET_PORTS_USED_NOWAKEUPOK : 0);
+       inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_RECVANYIFONLY) ?
+               INPCB_GET_PORTS_USED_RECVANYIFONLY : 0);
+       inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_EXTBGIDLEONLY) ?
+               INPCB_GET_PORTS_USED_EXTBGIDLEONLY : 0);
+       inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_ACTIVEONLY) ?
+               INPCB_GET_PORTS_USED_ACTIVEONLY : 0);
 
        if (bitfield == NULL)
                return (EINVAL);
 
        if (bitfield == NULL)
                return (EINVAL);
@@ -2526,34 +2668,34 @@ errno_t
 ifnet_get_local_ports(ifnet_t ifp, u_int8_t *bitfield)
 {
        u_int32_t flags = IFNET_GET_LOCAL_PORTS_WILDCARDOK;
 ifnet_get_local_ports(ifnet_t ifp, u_int8_t *bitfield)
 {
        u_int32_t flags = IFNET_GET_LOCAL_PORTS_WILDCARDOK;
-       return (ifnet_get_local_ports_extended(ifp, PF_UNSPEC, flags, 
+       return (ifnet_get_local_ports_extended(ifp, PF_UNSPEC, flags,
                bitfield));
 }
 
 errno_t
                bitfield));
 }
 
 errno_t
-ifnet_notice_node_presence(ifnet_t ifp, struct sockaddrsa, int32_t rssi,
+ifnet_notice_node_presence(ifnet_t ifp, struct sockaddr *sa, int32_t rssi,
     int lqm, int npm, u_int8_t srvinfo[48])
 {
        if (ifp == NULL || sa == NULL || srvinfo == NULL)
     int lqm, int npm, u_int8_t srvinfo[48])
 {
        if (ifp == NULL || sa == NULL || srvinfo == NULL)
-               return(EINVAL);
+               return (EINVAL);
        if (sa->sa_len > sizeof(struct sockaddr_storage))
        if (sa->sa_len > sizeof(struct sockaddr_storage))
-               return(EINVAL);
+               return (EINVAL);
        if (sa->sa_family != AF_LINK && sa->sa_family != AF_INET6)
        if (sa->sa_family != AF_LINK && sa->sa_family != AF_INET6)
-               return(EINVAL);
+               return (EINVAL);
 
        dlil_node_present(ifp, sa, rssi, lqm, npm, srvinfo);
        return (0);
 }
 
 errno_t
 
        dlil_node_present(ifp, sa, rssi, lqm, npm, srvinfo);
        return (0);
 }
 
 errno_t
-ifnet_notice_node_absence(ifnet_t ifp, struct sockaddrsa)
+ifnet_notice_node_absence(ifnet_t ifp, struct sockaddr *sa)
 {
        if (ifp == NULL || sa == NULL)
 {
        if (ifp == NULL || sa == NULL)
-               return(EINVAL);
+               return (EINVAL);
        if (sa->sa_len > sizeof(struct sockaddr_storage))
        if (sa->sa_len > sizeof(struct sockaddr_storage))
-               return(EINVAL);
+               return (EINVAL);
        if (sa->sa_family != AF_LINK && sa->sa_family != AF_INET6)
        if (sa->sa_family != AF_LINK && sa->sa_family != AF_INET6)
-               return(EINVAL);
+               return (EINVAL);
 
        dlil_node_absent(ifp, sa);
        return (0);
 
        dlil_node_absent(ifp, sa);
        return (0);
@@ -2563,7 +2705,7 @@ errno_t
 ifnet_notice_master_elected(ifnet_t ifp)
 {
        if (ifp == NULL)
 ifnet_notice_master_elected(ifnet_t ifp)
 {
        if (ifp == NULL)
-               return(EINVAL);
+               return (EINVAL);
 
        dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_MASTER_ELECTED, NULL, 0);
        return (0);
 
        dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_MASTER_ELECTED, NULL, 0);
        return (0);
@@ -2572,8 +2714,18 @@ ifnet_notice_master_elected(ifnet_t ifp)
 errno_t
 ifnet_tx_compl_status(ifnet_t ifp, mbuf_t m, tx_compl_val_t val)
 {
 errno_t
 ifnet_tx_compl_status(ifnet_t ifp, mbuf_t m, tx_compl_val_t val)
 {
-#pragma unused(ifp, m, val)
-       /* Dummy function to be implemented XXX */
+#pragma unused(val)
+
+       m_do_tx_compl_callback(m, ifp);
+
+       return (0);
+}
+
+errno_t
+ifnet_tx_compl(ifnet_t ifp, mbuf_t m)
+{
+       m_do_tx_compl_callback(m, ifp);
+
        return (0);
 }
 
        return (0);
 }
 
@@ -2588,7 +2740,7 @@ ifnet_report_issues(ifnet_t ifp, u_int8_t modid[IFNET_MODIDLEN],
        return (0);
 }
 
        return (0);
 }
 
-extern errno_t
+errno_t
 ifnet_set_delegate(ifnet_t ifp, ifnet_t delegated_ifp)
 {
        ifnet_t odifp = NULL;
 ifnet_set_delegate(ifnet_t ifp, ifnet_t delegated_ifp)
 {
        ifnet_t odifp = NULL;
@@ -2605,6 +2757,17 @@ ifnet_set_delegate(ifnet_t ifp, ifnet_t delegated_ifp)
                ifnet_lock_done(ifp);
                goto done;
        }
                ifnet_lock_done(ifp);
                goto done;
        }
+       // Test if this delegate interface would cause a loop
+       ifnet_t delegate_check_ifp = delegated_ifp;
+       while (delegate_check_ifp != NULL) {
+               if (delegate_check_ifp == ifp) {
+                       printf("%s: delegating to %s would cause a loop\n",
+                           ifp->if_xname, delegated_ifp->if_xname);
+                       ifnet_lock_done(ifp);
+                       goto done;
+               }
+               delegate_check_ifp = delegate_check_ifp->if_delegated.ifp;
+       }
        bzero(&ifp->if_delegated, sizeof (ifp->if_delegated));
        if (delegated_ifp != NULL && ifp != delegated_ifp) {
                ifp->if_delegated.ifp = delegated_ifp;
        bzero(&ifp->if_delegated, sizeof (ifp->if_delegated));
        if (delegated_ifp != NULL && ifp != delegated_ifp) {
                ifp->if_delegated.ifp = delegated_ifp;
@@ -2612,13 +2775,22 @@ ifnet_set_delegate(ifnet_t ifp, ifnet_t delegated_ifp)
                ifp->if_delegated.type = delegated_ifp->if_type;
                ifp->if_delegated.family = delegated_ifp->if_family;
                ifp->if_delegated.subfamily = delegated_ifp->if_subfamily;
                ifp->if_delegated.type = delegated_ifp->if_type;
                ifp->if_delegated.family = delegated_ifp->if_family;
                ifp->if_delegated.subfamily = delegated_ifp->if_subfamily;
-               ifp->if_delegated.expensive = 
+               ifp->if_delegated.expensive =
                    delegated_ifp->if_eflags & IFEF_EXPENSIVE ? 1 : 0;
                    delegated_ifp->if_eflags & IFEF_EXPENSIVE ? 1 : 0;
+
+               /*
+                * Propogate flags related to ECN from delegated interface
+                */
+               ifp->if_eflags &= ~(IFEF_ECN_ENABLE|IFEF_ECN_DISABLE);
+               ifp->if_eflags |= (delegated_ifp->if_eflags &
+                   (IFEF_ECN_ENABLE|IFEF_ECN_DISABLE));
+
                printf("%s: is now delegating %s (type 0x%x, family %u, "
                    "sub-family %u)\n", ifp->if_xname, delegated_ifp->if_xname,
                    delegated_ifp->if_type, delegated_ifp->if_family,
                    delegated_ifp->if_subfamily);
        }
                printf("%s: is now delegating %s (type 0x%x, family %u, "
                    "sub-family %u)\n", ifp->if_xname, delegated_ifp->if_xname,
                    delegated_ifp->if_type, delegated_ifp->if_family,
                    delegated_ifp->if_subfamily);
        }
+
        ifnet_lock_done(ifp);
 
        if (odifp != NULL) {
        ifnet_lock_done(ifp);
 
        if (odifp != NULL) {
@@ -2639,7 +2811,7 @@ done:
        return (0);
 }
 
        return (0);
 }
 
-extern errno_t
+errno_t
 ifnet_get_delegate(ifnet_t ifp, ifnet_t *pdelegated_ifp)
 {
        if (ifp == NULL || pdelegated_ifp == NULL)
 ifnet_get_delegate(ifnet_t ifp, ifnet_t *pdelegated_ifp)
 {
        if (ifp == NULL || pdelegated_ifp == NULL)
@@ -2659,28 +2831,323 @@ ifnet_get_delegate(ifnet_t ifp, ifnet_t *pdelegated_ifp)
        return (0);
 }
 
        return (0);
 }
 
-extern u_int32_t key_fill_offload_frames_for_savs (ifnet_t ifp,
-       struct ipsec_offload_frame *frames_array, u_int32_t frames_array_count,
-       size_t frame_data_offset);
-
-extern errno_t
-ifnet_get_ipsec_offload_frames(ifnet_t ifp,
-                                                          struct ipsec_offload_frame *frames_array,
-                                                          u_int32_t frames_array_count,
-                                                          size_t frame_data_offset,
-                                                          u_int32_t *used_frames_count)
+errno_t
+ifnet_get_keepalive_offload_frames(ifnet_t ifp,
+    struct ifnet_keepalive_offload_frame *frames_array,
+    u_int32_t frames_array_count, size_t frame_data_offset,
+    u_int32_t *used_frames_count)
 {
 {
-       if (frames_array == NULL || used_frames_count == NULL) {
+       u_int32_t i;
+
+       if (frames_array == NULL || used_frames_count == NULL ||
+           frame_data_offset >= IFNET_KEEPALIVE_OFFLOAD_FRAME_DATA_SIZE)
                return (EINVAL);
                return (EINVAL);
-       }
 
 
-       *used_frames_count = 0;
+       /* frame_data_offset should be 32-bit aligned */
+       if (P2ROUNDUP(frame_data_offset, sizeof(u_int32_t)) !=
+           frame_data_offset)
+               return (EINVAL);
 
 
-       if (frames_array_count == 0) {
+       *used_frames_count = 0;
+       if (frames_array_count == 0)
                return (0);
                return (0);
+
+       for (i = 0; i < frames_array_count; i++) {
+               struct ifnet_keepalive_offload_frame *frame = frames_array + i;
+
+               bzero(frame, sizeof(struct ifnet_keepalive_offload_frame));
        }
 
        }
 
+       /* First collect IPSec related keep-alive frames */
        *used_frames_count = key_fill_offload_frames_for_savs(ifp,
        *used_frames_count = key_fill_offload_frames_for_savs(ifp,
-               frames_array, frames_array_count, frame_data_offset);
+           frames_array, frames_array_count, frame_data_offset);
+
+       /* If there is more room, collect other UDP keep-alive frames */
+       if (*used_frames_count < frames_array_count)
+               udp_fill_keepalive_offload_frames(ifp, frames_array,
+                   frames_array_count, frame_data_offset,
+                   used_frames_count);
+
+       /* If there is more room, collect other TCP keep-alive frames */
+       if (*used_frames_count < frames_array_count)
+               tcp_fill_keepalive_offload_frames(ifp, frames_array,
+                   frames_array_count, frame_data_offset,
+                   used_frames_count);
+
+       VERIFY(*used_frames_count <= frames_array_count);
+
+       return (0);
+}
+
+errno_t
+ifnet_link_status_report(ifnet_t ifp, const void *buffer,
+    size_t buffer_len)
+{
+       struct if_link_status *ifsr;
+       errno_t err = 0;
+
+       if (ifp == NULL || buffer == NULL || buffer_len == 0)
+               return (EINVAL);
+
+       ifnet_lock_shared(ifp);
+
+       /*
+        * Make sure that the interface is attached but there is no need
+        * to take a reference because this call is coming from the driver.
+        */
+       if (!ifnet_is_attached(ifp, 0)) {
+               ifnet_lock_done(ifp);
+               return (ENXIO);
+       }
+
+       lck_rw_lock_exclusive(&ifp->if_link_status_lock);
+
+       /*
+        * If this is the first status report then allocate memory
+        * to store it.
+        */
+       if (ifp->if_link_status == NULL) {
+               MALLOC(ifp->if_link_status, struct if_link_status *,
+                   sizeof(struct if_link_status), M_TEMP, M_ZERO);
+               if (ifp->if_link_status == NULL) {
+                       err = ENOMEM;
+                       goto done;
+               }
+       }
+
+       ifsr = __DECONST(struct if_link_status *, buffer);
+
+       if (ifp->if_type == IFT_CELLULAR) {
+               struct if_cellular_status_v1 *if_cell_sr, *new_cell_sr;
+               /*
+                * Currently we have a single version -- if it does
+                * not match, just return.
+                */
+               if (ifsr->ifsr_version !=
+                   IF_CELLULAR_STATUS_REPORT_CURRENT_VERSION) {
+                       err = ENOTSUP;
+                       goto done;
+               }
+
+               if (ifsr->ifsr_len != sizeof(*if_cell_sr)) {
+                       err = EINVAL;
+                       goto done;
+               }
+
+               if_cell_sr =
+                   &ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
+               new_cell_sr = &ifsr->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
+               /* Check if we need to act on any new notifications */
+               if ((new_cell_sr->valid_bitmask &
+                   IF_CELL_UL_MSS_RECOMMENDED_VALID) &&
+                   new_cell_sr->mss_recommended !=
+                   if_cell_sr->mss_recommended) {
+                       atomic_bitset_32(&tcbinfo.ipi_flags,
+                           INPCBINFO_UPDATE_MSS);
+                       inpcb_timer_sched(&tcbinfo, INPCB_TIMER_FAST);
+               }
+
+               /* Finally copy the new information */
+               ifp->if_link_status->ifsr_version = ifsr->ifsr_version;
+               ifp->if_link_status->ifsr_len = ifsr->ifsr_len;
+               if_cell_sr->valid_bitmask = 0;
+               bcopy(new_cell_sr, if_cell_sr, sizeof(*if_cell_sr));
+
+       } else if (ifp->if_subfamily == IFNET_SUBFAMILY_WIFI) {
+               struct if_wifi_status_v1 *if_wifi_sr, *new_wifi_sr;
+
+               /* Check version */
+               if (ifsr->ifsr_version !=
+                   IF_WIFI_STATUS_REPORT_CURRENT_VERSION) {
+                       err = ENOTSUP;
+                       goto done;
+               }
+
+               if (ifsr->ifsr_len != sizeof(*if_wifi_sr)) {
+                       err = EINVAL;
+                       goto done;
+               }
+
+               if_wifi_sr =
+                   &ifp->if_link_status->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
+               new_wifi_sr =
+                   &ifsr->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
+               ifp->if_link_status->ifsr_version = ifsr->ifsr_version;
+               ifp->if_link_status->ifsr_len = ifsr->ifsr_len;
+               if_wifi_sr->valid_bitmask = 0;
+               bcopy(new_wifi_sr, if_wifi_sr, sizeof(*if_wifi_sr));
+
+               /*
+                * Update the bandwidth values if we got recent values
+                * reported through the other KPI.
+                */
+               if (!(new_wifi_sr->valid_bitmask &
+                   IF_WIFI_UL_MAX_BANDWIDTH_VALID) &&
+                   ifp->if_output_bw.max_bw > 0) {
+                       if_wifi_sr->valid_bitmask |=
+                           IF_WIFI_UL_MAX_BANDWIDTH_VALID;
+                       if_wifi_sr->ul_max_bandwidth =
+                           ifp->if_output_bw.max_bw;
+               }
+               if (!(new_wifi_sr->valid_bitmask &
+                   IF_WIFI_UL_EFFECTIVE_BANDWIDTH_VALID) &&
+                   ifp->if_output_bw.eff_bw > 0) {
+                       if_wifi_sr->valid_bitmask |=
+                           IF_WIFI_UL_EFFECTIVE_BANDWIDTH_VALID;
+                       if_wifi_sr->ul_effective_bandwidth =
+                           ifp->if_output_bw.eff_bw;
+               }
+               if (!(new_wifi_sr->valid_bitmask &
+                   IF_WIFI_DL_MAX_BANDWIDTH_VALID) &&
+                   ifp->if_input_bw.max_bw > 0) {
+                       if_wifi_sr->valid_bitmask |=
+                           IF_WIFI_DL_MAX_BANDWIDTH_VALID;
+                       if_wifi_sr->dl_max_bandwidth =
+                           ifp->if_input_bw.max_bw;
+               }
+               if (!(new_wifi_sr->valid_bitmask &
+                   IF_WIFI_DL_EFFECTIVE_BANDWIDTH_VALID) &&
+                   ifp->if_input_bw.eff_bw > 0) {
+                       if_wifi_sr->valid_bitmask |=
+                           IF_WIFI_DL_EFFECTIVE_BANDWIDTH_VALID;
+                       if_wifi_sr->dl_effective_bandwidth =
+                           ifp->if_input_bw.eff_bw;
+               }
+       }
+
+done:
+       lck_rw_done(&ifp->if_link_status_lock);
+       ifnet_lock_done(ifp);
+       return (err);
+}
+
+/*************************************************************************/
+/* Packet preamble                                             */
+/*************************************************************************/
+
+#define        MAX_IF_PACKET_PREAMBLE_LEN 32
+
+errno_t
+ifnet_set_packetpreamblelen(ifnet_t interface, u_int32_t len)
+{
+       errno_t err = 0;
+
+       if (interface == NULL || len > MAX_IF_PACKET_PREAMBLE_LEN) {
+               err = EINVAL;
+               goto done;
+       }
+       interface->if_data.ifi_preamblelen = len;
+done:
+       return (err);
+}
+
+u_int32_t
+ifnet_packetpreamblelen(ifnet_t interface)
+{
+       return ((interface == NULL) ? 0 : interface->if_data.ifi_preamblelen);
+}
+
+u_int32_t
+ifnet_maxpacketpreamblelen(void)
+{
+       return (MAX_IF_PACKET_PREAMBLE_LEN);
+}
+
+
+/*************************************************************************/
+/* Fastlane QoS Ca                                             */
+/*************************************************************************/
+
+errno_t
+ifnet_set_fastlane_capable(ifnet_t interface, boolean_t capable)
+{
+       if (interface == NULL)
+               return (EINVAL);
+
+       if_set_qosmarking_mode(interface,
+           capable ? IFRTYPE_QOSMARKING_FASTLANE : IFRTYPE_QOSMARKING_MODE_NONE);
+
+       return (0);
+}
+
+errno_t
+ifnet_get_fastlane_capable(ifnet_t interface, boolean_t *capable)
+{
+       if (interface == NULL || capable == NULL)
+               return (EINVAL);
+       if (interface->if_eflags & IFEF_QOSMARKING_CAPABLE)
+               *capable = true;
+       else
+               *capable = false;
        return (0);
 }
        return (0);
 }
+
+errno_t
+ifnet_get_unsent_bytes(ifnet_t interface, int64_t *unsent_bytes)
+{
+       int64_t bytes;
+
+       if (interface == NULL || unsent_bytes == NULL)
+               return (EINVAL);
+
+       bytes = *unsent_bytes = 0;
+
+       if ((interface->if_refflags & (IFRF_ATTACHED | IFRF_DETACHING)) !=
+           IFRF_ATTACHED)
+               return (ENXIO);
+
+       bytes = interface->if_sndbyte_unsent;
+
+       if (interface->if_eflags & IFEF_TXSTART)
+               bytes += IFCQ_BYTES(&interface->if_snd);
+       *unsent_bytes = bytes;
+
+       return (0);
+}
+
+errno_t
+ifnet_get_buffer_status(const ifnet_t ifp, ifnet_buffer_status_t *buf_status)
+{
+       if (ifp == NULL || buf_status == NULL)
+               return (EINVAL);
+
+       bzero(buf_status, sizeof (*buf_status));
+
+       if ((ifp->if_refflags & (IFRF_ATTACHED | IFRF_DETACHING)) !=
+               IFRF_ATTACHED)
+               return (ENXIO);
+
+       buf_status->buf_sndbuf = ifp->if_sndbyte_unsent;
+
+       if (ifp->if_eflags & IFEF_TXSTART)
+               buf_status->buf_interface = IFCQ_BYTES(&ifp->if_snd);
+
+       return (0);
+}
+
+void
+ifnet_normalise_unsent_data(void)
+{
+       struct ifnet *ifp;
+
+       ifnet_head_lock_shared();
+       TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
+               ifnet_lock_exclusive(ifp);
+               if ((ifp->if_refflags & (IFRF_ATTACHED|IFRF_DETACHING)) !=
+                   IFRF_ATTACHED) {
+                       ifnet_lock_done(ifp);
+                       continue;
+               }
+               if (!(ifp->if_eflags & IFEF_TXSTART)) {
+                       ifnet_lock_done(ifp);
+                       continue;
+               }
+
+               if (ifp->if_sndbyte_total > 0 ||
+                   IFCQ_BYTES(&ifp->if_snd) > 0)
+                       ifp->if_unsent_data_cnt++;
+
+               ifnet_lock_done(ifp);
+       }
+       ifnet_head_done();
+}