]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/if_loop.c
xnu-6153.41.3.tar.gz
[apple/xnu.git] / bsd / net / if_loop.c
index d051c7611b5f42afc611c79f93b24b12a641c9b3..b767144406c0734046e6d76faa07d5b82c09b102 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 
 #include <pexpert/pexpert.h>
 
-#define        LOMTU           16384
-#define        LOSNDQ_MAXLEN   256
+#define LOMTU           16384
+#define LOSNDQ_MAXLEN   256
 
-#define        LO_BPF_TAP_OUT(_m) {                                            \
-       if (lo_statics[0].bpf_callback != NULL) {                       \
-               bpf_tap_out(lo_ifp, DLT_NULL, _m,                       \
-                   &((struct loopback_header *)_m->m_pkthdr.header)->protocol,\
-                   sizeof (u_int32_t));                                \
-       }                                                               \
+#define LO_BPF_TAP_OUT(_m) {                                            \
+       if (lo_statics[0].bpf_callback != NULL) {                       \
+               bpf_tap_out(lo_ifp, DLT_NULL, _m,                       \
+                   &((struct loopback_header *)_m->m_pkthdr.pkt_hdr)-> \
+                   protocol, sizeof (u_int32_t));                      \
+       }                                                               \
 }
 
-#define        LO_BPF_TAP_OUT_MULTI(_m) {                                      \
-       if (lo_statics[0].bpf_callback != NULL) {                       \
-               struct mbuf *_n;                                        \
-               for (_n = _m; _n != NULL; _n = _n->m_nextpkt)           \
-                       LO_BPF_TAP_OUT(_n);                             \
-       }                                                               \
+#define LO_BPF_TAP_OUT_MULTI(_m) {                                      \
+       if (lo_statics[0].bpf_callback != NULL) {                       \
+               struct mbuf *_n;                                        \
+               for (_n = _m; _n != NULL; _n = _n->m_nextpkt)           \
+                       LO_BPF_TAP_OUT(_n);                             \
+       }                                                               \
 }
 
 struct lo_statics_str {
-       int             bpf_mode;
-       bpf_packet_func bpf_callback;
+       int             bpf_mode;
+       bpf_packet_func bpf_callback;
 };
 
 static struct lo_statics_str lo_statics[NLOOP];
@@ -143,23 +143,17 @@ static int lo_txstart = 0;
 
 struct ifnet *lo_ifp = NULL;
 
-struct loopback_header {
-       protocol_family_t       protocol;
+struct  loopback_header {
+       protocol_family_t       protocol;
 };
 
 /* Local forward declerations */
 void loopattach(void);
 static errno_t lo_demux(struct ifnet *, struct mbuf *, char *,
     protocol_family_t *);
-#if !KPI_INTERFACE_EMBEDDED
-static errno_t lo_framer(struct ifnet *, struct mbuf **,
-    const struct sockaddr *,
-    const char *, const char *);
-#else
 static errno_t
 lo_framer(struct ifnet *, struct mbuf **, const struct sockaddr *,
     const char *, const char *, u_int32_t *, u_int32_t *);
-#endif
 static errno_t lo_add_proto(struct ifnet *, protocol_family_t,
     const struct ifnet_demux_desc *, u_int32_t);
 static errno_t lo_del_proto(struct ifnet *, protocol_family_t);
@@ -183,15 +177,6 @@ SYSCTL_DECL(_net_link);
 SYSCTL_NODE(_net_link, OID_AUTO, loopback, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
     "loopback interface");
 
-#define        LO_BW_SLEEP     10
-static u_int32_t lo_bw_sleep_usec = LO_BW_SLEEP;
-SYSCTL_UINT(_net_link_loopback, OID_AUTO, bw_sleep_usec,
-    CTLFLAG_RW | CTLFLAG_LOCKED, &lo_bw_sleep_usec, LO_BW_SLEEP, "");
-
-static u_int32_t lo_bw_measure = 0;
-SYSCTL_UINT(_net_link_loopback, OID_AUTO, bw_measure,
-    CTLFLAG_RW | CTLFLAG_LOCKED, &lo_bw_measure, 0, "");
-
 static u_int32_t lo_dequeue_max = LOSNDQ_MAXLEN;
 SYSCTL_PROC(_net_link_loopback, OID_AUTO, max_dequeue,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &lo_dequeue_max, LOSNDQ_MAXLEN,
@@ -218,37 +203,33 @@ lo_demux(struct ifnet *ifp, struct mbuf *m, char *frame_header,
 
        *protocol_family = header->protocol;
 
-       return (0);
+       return 0;
 }
 
-#if !KPI_INTERFACE_EMBEDDED
-static errno_t
-lo_framer(struct ifnet *ifp, struct mbuf **m, const struct sockaddr *dest,
-    const char *dest_linkaddr, const char *frame_type)
-#else
 static errno_t
 lo_framer(struct ifnet *ifp, struct mbuf **m, const struct sockaddr *dest,
     const char *dest_linkaddr, const char *frame_type,
     u_int32_t *prepend_len, u_int32_t *postpend_len)
-#endif
 {
 #pragma unused(ifp, dest, dest_linkaddr)
        struct loopback_header  *header;
 
-       M_PREPEND(*m, sizeof (struct loopback_header), M_WAITOK);
+       M_PREPEND(*m, sizeof(struct loopback_header), M_WAITOK, 1);
        if (*m == NULL) {
                /* Tell caller not to try to free passed-in mbuf */
-               return (EJUSTRETURN);
+               return EJUSTRETURN;
        }
 
-#if KPI_INTERFACE_EMBEDDED
-       *prepend_len = sizeof (struct loopback_header);
-       *postpend_len = 0;
-#endif /* KPI_INTERFACE_EMBEDDED */
+       if (prepend_len != NULL) {
+               *prepend_len = sizeof(struct loopback_header);
+       }
+       if (postpend_len != NULL) {
+               *postpend_len = 0;
+       }
 
        header = mtod(*m, struct loopback_header *);
-       bcopy(frame_type, &header->protocol, sizeof (u_int32_t));
-       return (0);
+       bcopy(frame_type, &header->protocol, sizeof(u_int32_t));
+       return 0;
 }
 
 static errno_t
@@ -256,14 +237,46 @@ lo_add_proto(struct ifnet *interface, protocol_family_t protocol_family,
     const struct ifnet_demux_desc *demux_array, u_int32_t demux_count)
 {
 #pragma unused(interface, protocol_family, demux_array, demux_count)
-       return (0);
+       return 0;
 }
 
 static errno_t
 lo_del_proto(struct ifnet *ifp, protocol_family_t protocol)
 {
 #pragma unused(ifp, protocol)
-       return (0);
+       return 0;
+}
+
+static void
+lo_tx_compl(struct ifnet *ifp, struct mbuf *m)
+{
+       errno_t error;
+
+       if ((ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) != 0) {
+               boolean_t requested;
+
+               error = mbuf_get_timestamp_requested(m, &requested);
+               if (requested) {
+                       struct timespec now;
+                       u_int64_t ts;
+
+                       nanouptime(&now);
+                       net_timernsec(&now, &ts);
+
+                       error = mbuf_set_timestamp(m, ts, TRUE);
+                       if (error != 0) {
+                               printf("%s: mbuf_set_timestamp() failed %d\n",
+                                   __func__, error);
+                       }
+               }
+       }
+       error = mbuf_set_status(m, KERN_SUCCESS);
+       if (error != 0) {
+               printf("%s: mbuf_set_status() failed %d\n",
+                   __func__, error);
+       }
+
+       ifnet_tx_compl(ifp, m);
 }
 
 /*
@@ -281,8 +294,7 @@ lo_output(struct ifnet *ifp, struct mbuf *m_list)
        bzero(&s, sizeof(s));
 
        for (m = m_list; m; m = m->m_nextpkt) {
-               if ((m->m_flags & M_PKTHDR) == 0)
-                       panic("lo_output: no HDR");
+               VERIFY(m->m_flags & M_PKTHDR);
                cnt++;
                len += m->m_pkthdr.len;
 
@@ -291,31 +303,34 @@ lo_output(struct ifnet *ifp, struct mbuf *m_list)
                 *  This is used to match multicast packets, sent looping
                 *  back, with the appropriate group record on input.
                 */
-               if (m->m_pkthdr.rcvif == NULL)
+               if (m->m_pkthdr.rcvif == NULL) {
                        m->m_pkthdr.rcvif = ifp;
-
-               m->m_pkthdr.header = mtod(m, char *);
-               if (apple_hwcksum_tx != 0) {
-                       /* loopback checksums are always OK */
-                       m->m_pkthdr.csum_data = 0xffff;
-                       m->m_pkthdr.csum_flags =
-                           CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
-                           CSUM_IP_CHECKED | CSUM_IP_VALID;
                }
-               m_adj(m, sizeof (struct loopback_header));
+
+               m->m_pkthdr.pkt_flags |= PKTF_LOOP;
+               m->m_pkthdr.pkt_hdr = mtod(m, char *);
+
+               /* loopback checksums are always OK */
+               m->m_pkthdr.csum_data = 0xffff;
+               m->m_pkthdr.csum_flags =
+                   CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
+                   CSUM_IP_CHECKED | CSUM_IP_VALID;
+
+               m_adj(m, sizeof(struct loopback_header));
 
                LO_BPF_TAP_OUT(m);
                if (m->m_nextpkt == NULL) {
                        m_tail = m;
                }
+               lo_tx_compl(ifp, m);
        }
 
        s.packets_in = cnt;
        s.packets_out = cnt;
        s.bytes_in = len;
-       s.bytes_out = len;      
+       s.bytes_out = len;
 
-       return (ifnet_input_extended(ifp, m_list, m_tail, &s));
+       return ifnet_input_extended(ifp, m_list, m_tail, &s);
 }
 
 /*
@@ -330,7 +345,7 @@ lo_pre_enqueue(struct ifnet *ifp, struct mbuf *m0)
        int error = 0;
 
        while (m != NULL) {
-               VERIFY((m->m_flags & M_PKTHDR));
+               VERIFY(m->m_flags & M_PKTHDR);
 
                n = m->m_nextpkt;
                m->m_nextpkt = NULL;
@@ -340,18 +355,20 @@ lo_pre_enqueue(struct ifnet *ifp, struct mbuf *m0)
                 *  This is used to match multicast packets, sent looping
                 *  back, with the appropriate group record on input.
                 */
-               if (m->m_pkthdr.rcvif == NULL)
+               if (m->m_pkthdr.rcvif == NULL) {
                        m->m_pkthdr.rcvif = ifp;
-
-               m->m_pkthdr.header = mtod(m, char *);
-               if (apple_hwcksum_tx != 0) {
-                       /* loopback checksums are always OK */
-                       m->m_pkthdr.csum_data = 0xffff;
-                       m->m_pkthdr.csum_flags =
-                           CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
-                           CSUM_IP_CHECKED | CSUM_IP_VALID;
                }
-               m_adj(m, sizeof (struct loopback_header));
+
+               m->m_pkthdr.pkt_flags |= PKTF_LOOP;
+               m->m_pkthdr.pkt_hdr = mtod(m, char *);
+
+               /* loopback checksums are always OK */
+               m->m_pkthdr.csum_data = 0xffff;
+               m->m_pkthdr.csum_flags =
+                   CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
+                   CSUM_IP_CHECKED | CSUM_IP_VALID;
+
+               m_adj(m, sizeof(struct loopback_header));
 
                /*
                 * Let the callee free it in case of error,
@@ -362,7 +379,7 @@ lo_pre_enqueue(struct ifnet *ifp, struct mbuf *m0)
                m = n;
        }
 
-       return (error);
+       return error;
 }
 
 /*
@@ -380,41 +397,27 @@ lo_start(struct ifnet *ifp)
 {
        struct ifnet_stat_increment_param s;
 
-       bzero(&s, sizeof (s));
+       bzero(&s, sizeof(s));
 
        for (;;) {
                struct mbuf *m = NULL, *m_tail = NULL;
                u_int32_t cnt, len = 0;
-               int sleep_chan = 0;
-               struct timespec ts;
 
                if (lo_sched_model == IFNET_SCHED_MODEL_NORMAL) {
                        if (ifnet_dequeue_multi(ifp, lo_dequeue_max, &m,
-                           &m_tail, &cnt, &len) != 0)
+                           &m_tail, &cnt, &len) != 0) {
                                break;
+                       }
                } else {
                        if (ifnet_dequeue_service_class_multi(ifp,
                            lo_dequeue_sc, lo_dequeue_max, &m,
-                           &m_tail, &cnt, &len) != 0)
+                           &m_tail, &cnt, &len) != 0) {
                                break;
+                       }
                }
 
                LO_BPF_TAP_OUT_MULTI(m);
-
-               if (lo_bw_measure) {
-                       if (cnt >= if_bw_measure_size)
-                               ifnet_transmit_burst_start(ifp, m);
-                       if (lo_bw_sleep_usec > 0) {
-                               bzero(&ts, sizeof(ts));
-                               ts.tv_nsec = (lo_bw_sleep_usec << 10) * cnt;
-
-                               /* Add msleep with timeout */
-                               (void) msleep(&sleep_chan, NULL,
-                                   PSOCK, "lo_start", &ts);
-                       }
-                       if (cnt >= if_bw_measure_size)
-                               ifnet_transmit_burst_end(ifp, m_tail);
-               }
+               lo_tx_compl(ifp, m);
 
                /* stats are required for extended variant */
                s.packets_in = cnt;
@@ -438,27 +441,26 @@ lo_pre_output(struct ifnet *ifp, protocol_family_t protocol_family,
 #pragma unused(ifp, dst, dst_addr)
        struct rtentry *rt = route;
 
-       (*m)->m_flags |= M_LOOP;
+       VERIFY((*m)->m_flags & M_PKTHDR);
 
-       if (((*m)->m_flags & M_PKTHDR) == 0)
-               panic("looutput no HDR");
+       (*m)->m_flags |= M_LOOP;
 
        if (rt != NULL) {
                u_int32_t rt_flags = rt->rt_flags;
                if (rt_flags & (RTF_REJECT | RTF_BLACKHOLE)) {
                        if (rt_flags & RTF_BLACKHOLE) {
                                m_freem(*m);
-                               return (EJUSTRETURN);
+                               return EJUSTRETURN;
                        } else {
-                               return ((rt_flags & RTF_HOST) ?
-                                   EHOSTUNREACH : ENETUNREACH);
+                               return (rt_flags & RTF_HOST) ?
+                                      EHOSTUNREACH : ENETUNREACH;
                        }
                }
        }
 
-       bcopy(&protocol_family, frame_type, sizeof (protocol_family));
+       bcopy(&protocol_family, frame_type, sizeof(protocol_family));
 
-       return (0);
+       return 0;
 }
 
 /*
@@ -469,9 +471,26 @@ static errno_t
 lo_input(struct ifnet *ifp, protocol_family_t protocol_family, struct mbuf *m)
 {
 #pragma unused(ifp, protocol_family)
-       if (proto_input(protocol_family, m) != 0)
+
+       if ((ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) != 0) {
+               errno_t error;
+               struct timespec now;
+               u_int64_t ts;
+
+               nanouptime(&now);
+               net_timernsec(&now, &ts);
+
+               error = mbuf_set_timestamp(m, ts, TRUE);
+               if (error != 0) {
+                       printf("%s: mbuf_set_timestamp() failed %d\n",
+                           __func__, error);
+               }
+       }
+
+       if (proto_input(protocol_family, m) != 0) {
                m_freem(m);
-       return (0);
+       }
+       return 0;
 }
 
 /* ARGSUSED */
@@ -500,11 +519,10 @@ lo_ioctl(struct ifnet *ifp, u_long cmd, void *data)
        int error = 0;
 
        switch (cmd) {
-
-       case SIOCSIFADDR: {             /* struct ifaddr pointer */
+       case SIOCSIFADDR: {             /* struct ifaddr pointer */
                struct ifaddr *ifa = data;
 
-               ifnet_set_flags(ifp, IFF_UP|IFF_RUNNING, IFF_UP|IFF_RUNNING);
+               ifnet_set_flags(ifp, IFF_UP | IFF_RUNNING, IFF_UP | IFF_RUNNING);
                IFA_LOCK_SPIN(ifa);
                ifa->ifa_rtrequest = lo_rtrequest;
                IFA_UNLOCK(ifa);
@@ -514,16 +532,15 @@ lo_ioctl(struct ifnet *ifp, u_long cmd, void *data)
                break;
        }
 
-       case SIOCADDMULTI:              /* struct ifreq */
-       case SIOCDELMULTI: {            /* struct ifreq */
+       case SIOCADDMULTI:              /* struct ifreq */
+       case SIOCDELMULTI: {            /* struct ifreq */
                struct ifreq *ifr = data;
 
                if (ifr == NULL) {
-                       error = EAFNOSUPPORT;           /* XXX */
+                       error = EAFNOSUPPORT;           /* XXX */
                        break;
                }
                switch (ifr->ifr_addr.sa_family) {
-
 #if INET
                case AF_INET:
                        break;
@@ -540,21 +557,23 @@ lo_ioctl(struct ifnet *ifp, u_long cmd, void *data)
                break;
        }
 
-       case SIOCSIFMTU: {              /* struct ifreq */
+       case SIOCSIFMTU: {              /* struct ifreq */
                struct ifreq *ifr = data;
 
-               bcopy(&ifr->ifr_mtu, &ifp->if_mtu, sizeof (int));
+               bcopy(&ifr->ifr_mtu, &ifp->if_mtu, sizeof(int));
                break;
        }
 
-       case SIOCSIFFLAGS:              /* struct ifreq */
+       case SIOCSIFFLAGS:              /* struct ifreq */
+       case SIOCSIFTIMESTAMPENABLE:
+       case SIOCSIFTIMESTAMPDISABLE:
                break;
 
        default:
                error = EOPNOTSUPP;
                break;
        }
-       return (error);
+       return error;
 }
 #endif /* NLOOP > 0 */
 
@@ -562,10 +581,10 @@ lo_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 static errno_t
 lo_attach_proto(struct ifnet *ifp, protocol_family_t protocol_family)
 {
-       struct ifnet_attach_proto_param_v2      proto;
-       errno_t                                                 result = 0;
+       struct ifnet_attach_proto_param_v2      proto;
+       errno_t                                                 result = 0;
 
-       bzero(&proto, sizeof (proto));
+       bzero(&proto, sizeof(proto));
        proto.input = lo_input;
        proto.pre_output = lo_pre_output;
 
@@ -576,7 +595,7 @@ lo_attach_proto(struct ifnet *ifp, protocol_family_t protocol_family)
                    "returned=%d\n", protocol_family, result);
        }
 
-       return (result);
+       return result;
 }
 
 static void
@@ -586,14 +605,16 @@ lo_reg_if_mods(void)
 
        /* Register protocol registration functions */
        if ((error = proto_register_plumber(PF_INET,
-           APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
+           APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0) {
                printf("proto_register_plumber failed for AF_INET "
                    "error=%d\n", error);
+       }
 
        if ((error = proto_register_plumber(PF_INET6,
-           APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
+           APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0) {
                printf("proto_register_plumber failed for AF_INET6 "
                    "error=%d\n", error);
+       }
 }
 
 static errno_t
@@ -605,18 +626,18 @@ lo_set_bpf_tap(struct ifnet *ifp, bpf_tap_mode mode,
        lo_statics[0].bpf_mode = mode;
 
        switch (mode) {
-               case BPF_TAP_DISABLE:
-               case BPF_TAP_INPUT:
-                       lo_statics[0].bpf_callback = NULL;
-                       break;
+       case BPF_TAP_DISABLE:
+       case BPF_TAP_INPUT:
+               lo_statics[0].bpf_callback = NULL;
+               break;
 
-               case BPF_TAP_OUTPUT:
-               case BPF_TAP_INPUT_OUTPUT:
-                       lo_statics[0].bpf_callback = bpf_callback;
-                       break;
+       case BPF_TAP_OUTPUT:
+       case BPF_TAP_INPUT_OUTPUT:
+               lo_statics[0].bpf_callback = bpf_callback;
+               break;
        }
 
-       return (0);
+       return 0;
 }
 
 /* ARGSUSED */
@@ -624,39 +645,40 @@ void
 loopattach(void)
 {
        struct ifnet_init_eparams lo_init;
-       errno_t result = 0;
+       errno_t result = 0;
 
-       PE_parse_boot_argn("lo_txstart", &lo_txstart, sizeof (lo_txstart));
+       PE_parse_boot_argn("lo_txstart", &lo_txstart, sizeof(lo_txstart));
 
        lo_reg_if_mods();
 
        lo_statics[0].bpf_callback = NULL;
        lo_statics[0].bpf_mode = BPF_TAP_DISABLE;
 
-       bzero(&lo_init, sizeof (lo_init));
-       lo_init.ver                     = IFNET_INIT_CURRENT_VERSION;
-       lo_init.len                     = sizeof (lo_init);
-       lo_init.sndq_maxlen             = LOSNDQ_MAXLEN;
+       bzero(&lo_init, sizeof(lo_init));
+       lo_init.ver                     = IFNET_INIT_CURRENT_VERSION;
+       lo_init.len                     = sizeof(lo_init);
+       lo_init.sndq_maxlen             = LOSNDQ_MAXLEN;
        if (lo_txstart) {
-               lo_init.flags           = 0;
-               lo_init.pre_enqueue     = lo_pre_enqueue;
-               lo_init.start           = lo_start;
+               lo_init.flags           = 0;
+               lo_init.pre_enqueue     = lo_pre_enqueue;
+               lo_init.start           = lo_start;
                lo_init.output_sched_model = lo_sched_model;
        } else {
-               lo_init.flags           = IFNET_INIT_LEGACY;
-               lo_init.output          = lo_output;
+               lo_init.flags           = IFNET_INIT_LEGACY;
+               lo_init.output          = lo_output;
        }
-       lo_init.name                    = "lo";
-       lo_init.unit                    = 0;
-       lo_init.family                  = IFNET_FAMILY_LOOPBACK;
-       lo_init.type                    = IFT_LOOP;
-       lo_init.demux                   = lo_demux;
-       lo_init.add_proto               = lo_add_proto;
-       lo_init.del_proto               = lo_del_proto;
-       lo_init.framer                  = lo_framer;
-       lo_init.softc                   = &lo_statics[0];
-       lo_init.ioctl                   = lo_ioctl;
-       lo_init.set_bpf_tap             = lo_set_bpf_tap;
+       lo_init.flags                   |= IFNET_INIT_NX_NOAUTO;
+       lo_init.name                    = "lo";
+       lo_init.unit                    = 0;
+       lo_init.family                  = IFNET_FAMILY_LOOPBACK;
+       lo_init.type                    = IFT_LOOP;
+       lo_init.demux                   = lo_demux;
+       lo_init.add_proto               = lo_add_proto;
+       lo_init.del_proto               = lo_del_proto;
+       lo_init.framer_extended         = lo_framer;
+       lo_init.softc                   = &lo_statics[0];
+       lo_init.ioctl                   = lo_ioctl;
+       lo_init.set_bpf_tap             = lo_set_bpf_tap;
 
        result = ifnet_allocate_extended(&lo_init, &lo_ifp);
        if (result != 0) {
@@ -671,8 +693,9 @@ loopattach(void)
        ifnet_set_offload(lo_ifp,
            IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP |
            IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | IFNET_IPV6_FRAGMENT |
-           IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT | IFNET_MULTIPAGES);
-       ifnet_set_hdrlen(lo_ifp, sizeof (struct loopback_header));
+           IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT | IFNET_MULTIPAGES |
+           IFNET_TX_STATUS | IFNET_SW_TIMESTAMP);
+       ifnet_set_hdrlen(lo_ifp, sizeof(struct loopback_header));
        ifnet_set_eflags(lo_ifp, IFEF_SENDLIST, IFEF_SENDLIST);
 
 #if CONFIG_MACF_NET
@@ -685,7 +708,14 @@ loopattach(void)
                    __func__, result);
                /* NOTREACHED */
        }
-       bpfattach(lo_ifp, DLT_NULL, sizeof (u_int32_t));
+       /*
+        * Disable ECN on loopback as ECN serves no purpose and otherwise
+        * TCP connections are subject to heuristics like SYN retransmits on RST
+        */
+       lo_ifp->if_eflags &= ~IFEF_ECN_ENABLE;
+       lo_ifp->if_eflags |= IFEF_ECN_DISABLE;
+
+       bpfattach(lo_ifp, DLT_NULL, sizeof(u_int32_t));
 }
 
 static int
@@ -698,17 +728,19 @@ sysctl_dequeue_max SYSCTL_HANDLER_ARGS
        i = lo_dequeue_max;
 
        err = sysctl_handle_int(oidp, &i, 0, req);
-       if (err != 0 || req->newptr == USER_ADDR_NULL)
-               return (err);
+       if (err != 0 || req->newptr == USER_ADDR_NULL) {
+               return err;
+       }
 
-       if (i < 1)
+       if (i < 1) {
                i = 1;
-       else if (i > LOSNDQ_MAXLEN)
+       } else if (i > LOSNDQ_MAXLEN) {
                i = LOSNDQ_MAXLEN;
+       }
 
        lo_dequeue_max = i;
 
-       return (err);
+       return err;
 }
 
 static int
@@ -721,12 +753,14 @@ sysctl_sched_model SYSCTL_HANDLER_ARGS
        i = lo_sched_model;
 
        err = sysctl_handle_int(oidp, &i, 0, req);
-       if (err != 0 || req->newptr == USER_ADDR_NULL)
-               return (err);
+       if (err != 0 || req->newptr == USER_ADDR_NULL) {
+               return err;
+       }
 
        switch (i) {
        case IFNET_SCHED_MODEL_NORMAL:
        case IFNET_SCHED_MODEL_DRIVER_MANAGED:
+       case IFNET_SCHED_MODEL_FQ_CODEL:
                break;
 
        default:
@@ -734,10 +768,11 @@ sysctl_sched_model SYSCTL_HANDLER_ARGS
                break;
        }
 
-       if (err == 0 && (err = ifnet_set_output_sched_model(lo_ifp, i)) == 0)
+       if (err == 0 && (err = ifnet_set_output_sched_model(lo_ifp, i)) == 0) {
                lo_sched_model = i;
+       }
 
-       return (err);
+       return err;
 }
 
 static int
@@ -750,17 +785,20 @@ sysctl_dequeue_scidx SYSCTL_HANDLER_ARGS
        i = lo_dequeue_scidx;
 
        err = sysctl_handle_int(oidp, &i, 0, req);
-       if (err != 0 || req->newptr == USER_ADDR_NULL)
-               return (err);
+       if (err != 0 || req->newptr == USER_ADDR_NULL) {
+               return err;
+       }
 
-       if (!MBUF_VALID_SCIDX(i))
-               return (EINVAL);
+       if (!MBUF_VALID_SCIDX(i)) {
+               return EINVAL;
+       }
 
-       if (lo_sched_model != IFNET_SCHED_MODEL_DRIVER_MANAGED)
-               return (ENODEV);
+       if (lo_sched_model != IFNET_SCHED_MODEL_DRIVER_MANAGED) {
+               return ENODEV;
+       }
 
        lo_dequeue_sc = m_service_class_from_idx(i);
        lo_dequeue_scidx = MBUF_SCIDX(lo_dequeue_sc);
 
-       return (err);
+       return err;
 }