]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet/in_tclass.c
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / bsd / netinet / in_tclass.c
index 7d8f336bde2ec3bc3c72a9559f9b8d289a3660cf..d14323a4cac8f3cd1817efac6af1b0a4f125ec17 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2019 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2020 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 #include <netinet/tcp.h>
 #include <netinet/tcp_var.h>
 #include <netinet/tcp_cc.h>
-#include <netinet/lro_ext.h>
 #include <netinet/in_tclass.h>
 
+struct net_qos_dscp_map {
+       uint8_t        sotc_to_dscp[SO_TC_MAX];
+       uint8_t        netsvctype_to_dscp[_NET_SERVICE_TYPE_COUNT];
+};
+
 struct dcsp_msc_map {
-       u_int8_t                dscp;
+       uint8_t                 dscp;
        mbuf_svc_class_t        msc;
 };
 static inline int so_throttle_best_effort(struct socket *, struct ifnet *);
@@ -117,10 +121,6 @@ int net_qos_policy_wifi_enabled = 0;
 SYSCTL_INT(_net_qos_policy, OID_AUTO, wifi_enabled,
     CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_policy_wifi_enabled, 0, "");
 
-int net_qos_policy_none_wifi_enabled = 0;
-SYSCTL_INT(_net_qos_policy, OID_AUTO, none_wifi_enabled,
-    CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_policy_none_wifi_enabled, 0, "");
-
 int net_qos_policy_capable_enabled = 0;
 SYSCTL_INT(_net_qos_policy, OID_AUTO, capable_enabled,
     CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_policy_capable_enabled, 0, "");
@@ -145,18 +145,36 @@ const int sotc_by_netservicetype[_NET_SERVICE_TYPE_COUNT] = {
  */
 static const
 struct netsvctype_dscp_map fastlane_netsvctype_dscp_map[_NET_SERVICE_TYPE_COUNT] = {
-       { NET_SERVICE_TYPE_BE, _DSCP_DF },
-       { NET_SERVICE_TYPE_BK, _DSCP_AF11 },
-       { NET_SERVICE_TYPE_SIG, _DSCP_CS3 },
-       { NET_SERVICE_TYPE_VI, _DSCP_AF41 },
-       { NET_SERVICE_TYPE_VO, _DSCP_EF },
-       { NET_SERVICE_TYPE_RV, _DSCP_CS4 },
-       { NET_SERVICE_TYPE_AV, _DSCP_AF31 },
-       { NET_SERVICE_TYPE_OAM, _DSCP_CS2 },
-       { NET_SERVICE_TYPE_RD, _DSCP_AF21 },
+       { .netsvctype = NET_SERVICE_TYPE_BE, .dscp = _DSCP_DF },
+       { .netsvctype = NET_SERVICE_TYPE_BK, .dscp = _DSCP_AF11 },
+       { .netsvctype = NET_SERVICE_TYPE_SIG, .dscp = _DSCP_CS3 },
+       { .netsvctype = NET_SERVICE_TYPE_VI, .dscp = _DSCP_AF41 },
+       { .netsvctype = NET_SERVICE_TYPE_VO, .dscp = _DSCP_EF },
+       { .netsvctype = NET_SERVICE_TYPE_RV, .dscp = _DSCP_CS4 },
+       { .netsvctype = NET_SERVICE_TYPE_AV, .dscp = _DSCP_AF31 },
+       { .netsvctype = NET_SERVICE_TYPE_OAM, .dscp = _DSCP_CS2 },
+       { .netsvctype = NET_SERVICE_TYPE_RD, .dscp = _DSCP_AF21 },
+};
+
+
+/*
+ * DSCP mappings for QoS RFC4594 as based on network service types
+ */
+static const
+struct netsvctype_dscp_map rfc4594_netsvctype_dscp_map[_NET_SERVICE_TYPE_COUNT] = {
+       { .netsvctype = NET_SERVICE_TYPE_BE, .dscp = _DSCP_DF },
+       { .netsvctype = NET_SERVICE_TYPE_BK, .dscp = _DSCP_CS1 },
+       { .netsvctype = NET_SERVICE_TYPE_SIG, .dscp = _DSCP_CS5 },
+       { .netsvctype = NET_SERVICE_TYPE_VI, .dscp = _DSCP_AF41 },
+       { .netsvctype = NET_SERVICE_TYPE_VO, .dscp = _DSCP_EF },
+       { .netsvctype = NET_SERVICE_TYPE_RV, .dscp = _DSCP_CS4 },
+       { .netsvctype = NET_SERVICE_TYPE_AV, .dscp = _DSCP_AF31 },
+       { .netsvctype = NET_SERVICE_TYPE_OAM, .dscp = _DSCP_CS2 },
+       { .netsvctype = NET_SERVICE_TYPE_RD, .dscp = _DSCP_AF21 },
 };
 
-static struct net_qos_dscp_map default_net_qos_dscp_map;
+static struct net_qos_dscp_map fastlane_net_qos_dscp_map;
+static struct net_qos_dscp_map rfc4594_net_qos_dscp_map;
 
 /*
  * The size is one more than the max because DSCP start at zero
@@ -174,79 +192,79 @@ static struct net_qos_dscp_map default_net_qos_dscp_map;
  * option instead to select L2 QoS marking instead of IP_TOS or IPV6_TCLASS.
  */
 static const struct dcsp_msc_map default_dscp_to_wifi_ac_map[] = {
-       { _DSCP_DF, MBUF_SC_BE },               /* RFC 2474 Standard */
-       { 1, MBUF_SC_BE },                      /*  */
-       { 2, MBUF_SC_BE },                      /*  */
-       { 3, MBUF_SC_BE },                      /*  */
-       { 4, MBUF_SC_BE },                      /*  */
-       { 5, MBUF_SC_BE },                      /*  */
-       { 6, MBUF_SC_BE },                      /*  */
-       { 7, MBUF_SC_BE },                      /*  */
-
-       { _DSCP_CS1, MBUF_SC_BK },              /* RFC 3662 Low-Priority Data */
-       { 9, MBUF_SC_BK },                      /*  */
-       { _DSCP_AF11, MBUF_SC_BK },             /* RFC 2597 High-Throughput Data */
-       { 11, MBUF_SC_BK },                     /*  */
-       { _DSCP_AF12, MBUF_SC_BK },             /* RFC 2597 High-Throughput Data */
-       { 13, MBUF_SC_BK },                     /*  */
-       { _DSCP_AF13, MBUF_SC_BK },             /* RFC 2597 High-Throughput Data */
-       { 15, MBUF_SC_BK },                     /*  */
-
-       { _DSCP_CS2, MBUF_SC_BK },              /* RFC 4594 OAM */
-       { 17, MBUF_SC_BK },                     /*  */
-       { _DSCP_AF21, MBUF_SC_BK },             /* RFC 2597 Low-Latency Data */
-       { 19, MBUF_SC_BK },                     /*  */
-       { _DSCP_AF22, MBUF_SC_BK },             /* RFC 2597 Low-Latency Data */
-       { 21, MBUF_SC_BK },                     /*  */
-       { _DSCP_AF23, MBUF_SC_BK },             /* RFC 2597 Low-Latency Data */
-       { 23, MBUF_SC_BK },                     /*  */
-
-       { _DSCP_CS3, MBUF_SC_BE },              /* RFC 2474 Broadcast Video */
-       { 25, MBUF_SC_BE },                     /*  */
-       { _DSCP_AF31, MBUF_SC_BE },             /* RFC 2597 Multimedia Streaming */
-       { 27, MBUF_SC_BE },                     /*  */
-       { _DSCP_AF32, MBUF_SC_BE },             /* RFC 2597 Multimedia Streaming */
-       { 29, MBUF_SC_BE },                     /*  */
-       { _DSCP_AF33, MBUF_SC_BE },             /* RFC 2597 Multimedia Streaming */
-       { 31, MBUF_SC_BE },                     /*  */
-
-       { _DSCP_CS4, MBUF_SC_VI },              /* RFC 2474 Real-Time Interactive */
-       { 33, MBUF_SC_VI },                     /*  */
-       { _DSCP_AF41, MBUF_SC_VI },             /* RFC 2597 Multimedia Conferencing */
-       { 35, MBUF_SC_VI },                     /*  */
-       { _DSCP_AF42, MBUF_SC_VI },             /* RFC 2597 Multimedia Conferencing */
-       { 37, MBUF_SC_VI },                     /*  */
-       { _DSCP_AF43, MBUF_SC_VI },             /* RFC 2597 Multimedia Conferencing */
-       { 39, MBUF_SC_VI },                     /*  */
-
-       { _DSCP_CS5, MBUF_SC_VI },              /* RFC 2474 Signaling */
-       { 41, MBUF_SC_VI },                     /*  */
-       { 42, MBUF_SC_VI },                     /*  */
-       { 43, MBUF_SC_VI },                     /*  */
-       { _DSCP_VA, MBUF_SC_VI },               /* RFC 5865 VOICE-ADMIT */
-       { 45, MBUF_SC_VI },                     /*  */
-       { _DSCP_EF, MBUF_SC_VI },               /* RFC 3246 Telephony */
-       { 47, MBUF_SC_VI },                     /*  */
-
-       { _DSCP_CS6, MBUF_SC_VO },              /* Wi-Fi WMM Certification: Chariot */
-       { 49, MBUF_SC_VO },                     /*  */
-       { 50, MBUF_SC_VO },                     /*  */
-       { 51, MBUF_SC_VO },                     /*  */
-       { 52, MBUF_SC_VO },                     /* Wi-Fi WMM Certification: Sigma */
-       { 53, MBUF_SC_VO },                     /*  */
-       { 54, MBUF_SC_VO },                     /*  */
-       { 55, MBUF_SC_VO },                     /*  */
-
-       { _DSCP_CS7, MBUF_SC_VO },              /* Wi-Fi WMM Certification: Chariot */
-       { 57, MBUF_SC_VO },                     /*  */
-       { 58, MBUF_SC_VO },                     /*  */
-       { 59, MBUF_SC_VO },                     /*  */
-       { 60, MBUF_SC_VO },                     /*  */
-       { 61, MBUF_SC_VO },                     /*  */
-       { 62, MBUF_SC_VO },                     /*  */
-       { 63, MBUF_SC_VO },                     /*  */
-
-       { 255, MBUF_SC_UNSPEC }                  /* invalid DSCP to mark last entry */
+       { .dscp = _DSCP_DF, .msc = MBUF_SC_BE },        /* RFC 2474 Standard */
+       { .dscp = 1, .msc = MBUF_SC_BE },               /*  */
+       { .dscp = 2, .msc = MBUF_SC_BE },               /*  */
+       { .dscp = 3, .msc = MBUF_SC_BE },               /*  */
+       { .dscp = 4, .msc = MBUF_SC_BE },               /*  */
+       { .dscp = 5, .msc = MBUF_SC_BE },               /*  */
+       { .dscp = 6, .msc = MBUF_SC_BE },               /*  */
+       { .dscp = 7, .msc = MBUF_SC_BE },               /*  */
+
+       { .dscp = _DSCP_CS1, .msc = MBUF_SC_BK },       /* RFC 3662 Low-Priority Data */
+       { .dscp = 9, .msc = MBUF_SC_BK },               /*  */
+       { .dscp = _DSCP_AF11, .msc = MBUF_SC_BK },      /* RFC 2597 High-Throughput Data */
+       { .dscp = 11, .msc = MBUF_SC_BK },              /*  */
+       { .dscp = _DSCP_AF12, .msc = MBUF_SC_BK },      /* RFC 2597 High-Throughput Data */
+       { .dscp = 13, .msc = MBUF_SC_BK },              /*  */
+       { .dscp = _DSCP_AF13, .msc = MBUF_SC_BK },      /* RFC 2597 High-Throughput Data */
+       { .dscp = 15, .msc = MBUF_SC_BK },              /*  */
+
+       { .dscp = _DSCP_CS2, .msc = MBUF_SC_BK },       /* RFC 4594 OAM */
+       { .dscp = 17, .msc = MBUF_SC_BK },              /*  */
+       { .dscp = _DSCP_AF21, .msc = MBUF_SC_BK },      /* RFC 2597 Low-Latency Data */
+       { .dscp = 19, .msc = MBUF_SC_BK },              /*  */
+       { .dscp = _DSCP_AF22, .msc = MBUF_SC_BK },      /* RFC 2597 Low-Latency Data */
+       { .dscp = 21, .msc = MBUF_SC_BK },              /*  */
+       { .dscp = _DSCP_AF23, .msc = MBUF_SC_BK },      /* RFC 2597 Low-Latency Data */
+       { .dscp = 23, .msc = MBUF_SC_BK },              /*  */
+
+       { .dscp = _DSCP_CS3, .msc = MBUF_SC_BE },       /* RFC 2474 Broadcast Video */
+       { .dscp = 25, .msc = MBUF_SC_BE },              /*  */
+       { .dscp = _DSCP_AF31, .msc = MBUF_SC_BE },      /* RFC 2597 Multimedia Streaming */
+       { .dscp = 27, .msc = MBUF_SC_BE },              /*  */
+       { .dscp = _DSCP_AF32, .msc = MBUF_SC_BE },      /* RFC 2597 Multimedia Streaming */
+       { .dscp = 29, .msc = MBUF_SC_BE },              /*  */
+       { .dscp = _DSCP_AF33, .msc = MBUF_SC_BE },      /* RFC 2597 Multimedia Streaming */
+       { .dscp = 31, .msc = MBUF_SC_BE },              /*  */
+
+       { .dscp = _DSCP_CS4, .msc = MBUF_SC_VI },       /* RFC 2474 Real-Time Interactive */
+       { .dscp = 33, .msc = MBUF_SC_VI },              /*  */
+       { .dscp = _DSCP_AF41, .msc = MBUF_SC_VI },      /* RFC 2597 Multimedia Conferencing */
+       { .dscp = 35, .msc = MBUF_SC_VI },              /*  */
+       { .dscp = _DSCP_AF42, .msc = MBUF_SC_VI },      /* RFC 2597 Multimedia Conferencing */
+       { .dscp = 37, .msc = MBUF_SC_VI },              /*  */
+       { .dscp = _DSCP_AF43, .msc = MBUF_SC_VI },      /* RFC 2597 Multimedia Conferencing */
+       { .dscp = 39, .msc = MBUF_SC_VI },              /*  */
+
+       { .dscp = _DSCP_CS5, .msc = MBUF_SC_VI },       /* RFC 2474 Signaling */
+       { .dscp = 41, .msc = MBUF_SC_VI },              /*  */
+       { .dscp = 42, .msc = MBUF_SC_VI },              /*  */
+       { .dscp = 43, .msc = MBUF_SC_VI },              /*  */
+       { .dscp = _DSCP_VA, .msc = MBUF_SC_VI },        /* RFC 5865 VOICE-ADMIT */
+       { .dscp = 45, .msc = MBUF_SC_VI },              /*  */
+       { .dscp = _DSCP_EF, .msc = MBUF_SC_VI },        /* RFC 3246 Telephony */
+       { .dscp = 47, .msc = MBUF_SC_VI },              /*  */
+
+       { .dscp = _DSCP_CS6, .msc = MBUF_SC_VO },       /* Wi-Fi WMM Certification: Chariot */
+       { .dscp = 49, .msc = MBUF_SC_VO },              /*  */
+       { .dscp = 50, .msc = MBUF_SC_VO },              /*  */
+       { .dscp = 51, .msc = MBUF_SC_VO },              /*  */
+       { .dscp = 52, .msc = MBUF_SC_VO },              /* Wi-Fi WMM Certification: Sigma */
+       { .dscp = 53, .msc = MBUF_SC_VO },              /*  */
+       { .dscp = 54, .msc = MBUF_SC_VO },              /*  */
+       { .dscp = 55, .msc = MBUF_SC_VO },              /*  */
+
+       { .dscp = _DSCP_CS7, .msc = MBUF_SC_VO },       /* Wi-Fi WMM Certification: Chariot */
+       { .dscp = 57, .msc = MBUF_SC_VO },              /*  */
+       { .dscp = 58, .msc = MBUF_SC_VO },              /*  */
+       { .dscp = 59, .msc = MBUF_SC_VO },              /*  */
+       { .dscp = 60, .msc = MBUF_SC_VO },              /*  */
+       { .dscp = 61, .msc = MBUF_SC_VO },              /*  */
+       { .dscp = 62, .msc = MBUF_SC_VO },              /*  */
+       { .dscp = 63, .msc = MBUF_SC_VO },              /*  */
+
+       { .dscp = 255, .msc = MBUF_SC_UNSPEC }          /* invalid DSCP to mark last entry */
 };
 
 mbuf_svc_class_t wifi_dscp_to_msc_array[DSCP_ARRAY_SIZE];
@@ -270,7 +288,7 @@ struct tclass_for_proc {
        int             tfp_class;
        pid_t           tfp_pid;
        char            tfp_pname[(2 * MAXCOMLEN) + 1];
-       u_int32_t       tfp_qos_mode;
+       uint32_t        tfp_qos_mode;
 };
 
 static int get_pid_tclass(struct so_tcdbg *);
@@ -330,7 +348,7 @@ set_tclass_for_curr_proc(struct socket *so)
                    strncmp(pname, tfp->tfp_pname,
                    sizeof(tfp->tfp_pname)) == 0)) {
                        if (tfp->tfp_class != SO_TC_UNSPEC) {
-                               so->so_traffic_class = tfp->tfp_class;
+                               so->so_traffic_class = (uint16_t)tfp->tfp_class;
                        }
 
                        if (tfp->tfp_qos_mode == QOS_MODE_MARKING_POLICY_ENABLE) {
@@ -454,10 +472,7 @@ set_pid_tclass(struct so_tcdbg *so_tcdbg)
 {
        int error = EINVAL;
        proc_t p = NULL;
-       struct filedesc *fdp;
-       struct fileproc *fp;
        struct tclass_for_proc *tfp;
-       int i;
        pid_t pid = so_tcdbg->so_tcdbg_pid;
        int tclass = so_tcdbg->so_tcdbg_tclass;
        int netsvctype = so_tcdbg->so_tcdbg_netsvctype;
@@ -486,20 +501,16 @@ set_pid_tclass(struct so_tcdbg *so_tcdbg)
        lck_mtx_unlock(tclass_lock);
 
        if (tfp != NULL) {
-               proc_fdlock(p);
+               struct fileproc *fp;
 
-               fdp = p->p_fd;
-               for (i = 0; i < fdp->fd_nfiles; i++) {
+               fdt_foreach(fp, p) {
                        struct socket *so;
 
-                       fp = fdp->fd_ofiles[i];
-                       if (fp == NULL ||
-                           (fdp->fd_ofileflags[i] & UF_RESERVED) != 0 ||
-                           FILEGLOB_DTYPE(fp->f_fglob) != DTYPE_SOCKET) {
+                       if (FILEGLOB_DTYPE(fp->fp_glob) != DTYPE_SOCKET) {
                                continue;
                        }
 
-                       so = (struct socket *)fp->f_fglob->fg_data;
+                       so = (struct socket *)fp->fp_glob->fg_data;
                        if (SOCK_DOM(so) != PF_INET && SOCK_DOM(so) != PF_INET6) {
                                continue;
                        }
@@ -567,50 +578,40 @@ flush_pid_tclass(struct so_tcdbg *so_tcdbg)
 {
        pid_t pid = so_tcdbg->so_tcdbg_pid;
        int tclass = so_tcdbg->so_tcdbg_tclass;
-       struct filedesc *fdp;
-       int error = EINVAL;
+       struct fileproc *fp;
        proc_t p;
-       int i;
+       int error;
 
        p = proc_find(pid);
        if (p == PROC_NULL) {
                printf("%s proc_find(%d) failed\n", __func__, pid);
-               goto done;
+               return EINVAL;
        }
 
        proc_fdlock(p);
-       fdp = p->p_fd;
-       for (i = 0; i < fdp->fd_nfiles; i++) {
+
+       fdt_foreach(fp, p) {
                struct socket *so;
-               struct fileproc *fp;
 
-               fp = fdp->fd_ofiles[i];
-               if (fp == NULL ||
-                   (fdp->fd_ofileflags[i] & UF_RESERVED) != 0 ||
-                   FILEGLOB_DTYPE(fp->f_fglob) != DTYPE_SOCKET) {
+               if (FILEGLOB_DTYPE(fp->fp_glob) != DTYPE_SOCKET) {
                        continue;
                }
 
-               so = (struct socket *)fp->f_fglob->fg_data;
+               so = (struct socket *)fp->fp_glob->fg_data;
                error = sock_setsockopt(so, SOL_SOCKET, SO_FLUSH, &tclass,
                    sizeof(tclass));
                if (error != 0) {
                        printf("%s: setsockopt(SO_FLUSH) (so=0x%llx, fd=%d, "
                            "tclass=%d) failed %d\n", __func__,
-                           (uint64_t)VM_KERNEL_ADDRPERM(so), i, tclass,
+                           (uint64_t)VM_KERNEL_ADDRPERM(so), fdt_foreach_fd(), tclass,
                            error);
-                       error = 0;
                }
        }
-       proc_fdunlock(p);
 
-       error = 0;
-done:
-       if (p != PROC_NULL) {
-               proc_rele(p);
-       }
+       proc_fdunlock(p);
 
-       return error;
+       proc_rele(p);
+       return 0;
 }
 
 int
@@ -873,9 +874,7 @@ so_get_netsvc_marking_level(struct socket *so)
                break;
        }
        if (ifp != NULL) {
-               if ((ifp->if_eflags &
-                   (IFEF_QOSMARKING_ENABLED | IFEF_QOSMARKING_CAPABLE)) ==
-                   (IFEF_QOSMARKING_ENABLED | IFEF_QOSMARKING_CAPABLE)) {
+               if ((ifp->if_eflags & IFEF_QOSMARKING_ENABLED) != 0) {
                        if ((so->so_flags1 & SOF1_QOSMARKING_ALLOWED)) {
                                marking_level = NETSVC_MRKNG_LVL_L3L2_ALL;
                        } else {
@@ -917,7 +916,7 @@ so_set_traffic_class(struct socket *so, int optval)
                        int oldval = so->so_traffic_class;
 
                        VERIFY(SO_VALID_TC(optval));
-                       so->so_traffic_class = optval;
+                       so->so_traffic_class = (uint16_t)optval;
 
                        if ((SOCK_DOM(so) == PF_INET ||
                            SOCK_DOM(so) == PF_INET6) &&
@@ -963,7 +962,7 @@ so_set_net_service_type(struct socket *so, int netsvctype)
        if (error != 0) {
                return error;
        }
-       so->so_netsvctype = netsvctype;
+       so->so_netsvctype = (int8_t)netsvctype;
        so->so_flags1 |= SOF1_TC_NET_SERV_TYPE;
 
        return 0;
@@ -1034,7 +1033,7 @@ so_tc_from_control(struct mbuf *control, int *out_netsvctype)
                         * passed using SO_TRAFFIC_CLASS
                         */
                        val = val - SO_TC_NET_SERVICE_OFFSET;
-               /* FALLTHROUGH */
+                       OS_FALLTHROUGH;
                case SO_NET_SERVICE_TYPE:
                        if (!IS_VALID_NET_SERVICE_TYPE(val)) {
                                break;
@@ -1051,6 +1050,32 @@ so_tc_from_control(struct mbuf *control, int *out_netsvctype)
        return sotc;
 }
 
+__private_extern__ int
+so_tos_from_control(struct mbuf *control)
+{
+       struct cmsghdr *cm;
+       int tos = IPTOS_UNSPEC;
+
+       for (cm = M_FIRST_CMSGHDR(control);
+           is_cmsg_valid(control, cm);
+           cm = M_NXT_CMSGHDR(control, cm)) {
+               if (cm->cmsg_len != CMSG_LEN(sizeof(int))) {
+                       continue;
+               }
+
+               if ((cm->cmsg_level == IPPROTO_IP &&
+                   cm->cmsg_type == IP_TOS) ||
+                   (cm->cmsg_level == IPPROTO_IPV6 &&
+                   cm->cmsg_type == IPV6_TCLASS)) {
+                       tos = *(int *)(void *)CMSG_DATA(cm) & IPTOS_MASK;
+                       /* The first valid option wins */
+                       break;
+               }
+       }
+
+       return tos;
+}
+
 __private_extern__ void
 so_recv_data_stat(struct socket *so, struct mbuf *m, size_t off)
 {
@@ -1080,7 +1105,7 @@ so_inc_recv_data_stat(struct socket *so, size_t pkts, size_t bytes,
 static inline int
 so_throttle_best_effort(struct socket *so, struct ifnet *ifp)
 {
-       u_int32_t uptime = net_uptime();
+       uint32_t uptime = (uint32_t)net_uptime();
        return soissrcbesteffort(so) &&
               net_io_policy_throttle_best_effort == 1 &&
               ifp->if_rt_sendts > 0 &&
@@ -1096,7 +1121,7 @@ set_tcp_stream_priority(struct socket *so)
        u_char old_cc = tp->tcp_cc_index;
        int recvbg = IS_TCP_RECV_BG(so);
        bool is_local = false, fg_active = false;
-       u_int32_t uptime;
+       uint32_t uptime;
 
        VERIFY((SOCK_CHECK_DOM(so, PF_INET) ||
            SOCK_CHECK_DOM(so, PF_INET6)) &&
@@ -1109,7 +1134,7 @@ set_tcp_stream_priority(struct socket *so)
        }
 
        outifp = inp->inp_last_outifp;
-       uptime = net_uptime();
+       uptime = (uint32_t)net_uptime();
 
        /*
         * If the socket was marked as a background socket or if the
@@ -1210,7 +1235,7 @@ set_tcp_stream_priority(struct socket *so)
  */
 __private_extern__ void
 set_packet_service_class(struct mbuf *m, struct socket *so,
-    int sotc, u_int32_t flags)
+    int sotc, uint32_t flags)
 {
        mbuf_svc_class_t msc = MBUF_SC_BE;         /* Best effort by default */
        struct inpcb *inp = sotoinpcb(so); /* in6pcb and inpcb are the same */
@@ -1405,34 +1430,6 @@ so_svc2tc(mbuf_svc_class_t svc)
        }
 }
 
-/*
- * LRO is turned on for AV streaming class.
- */
-void
-so_set_lro(struct socket *so, int optval)
-{
-       if (optval == SO_TC_AV) {
-               so->so_flags |= SOF_USELRO;
-       } else {
-               if (so->so_flags & SOF_USELRO) {
-                       /* transition to non LRO class */
-                       so->so_flags &= ~SOF_USELRO;
-                       struct inpcb *inp = sotoinpcb(so);
-                       struct tcpcb *tp = NULL;
-                       if (inp) {
-                               tp = intotcpcb(inp);
-                               if (tp && (tp->t_flagsext & TF_LRO_OFFLOADED)) {
-                                       tcp_lro_remove_state(inp->inp_laddr,
-                                           inp->inp_faddr,
-                                           inp->inp_lport,
-                                           inp->inp_fport);
-                                       tp->t_flagsext &= ~TF_LRO_OFFLOADED;
-                               }
-                       }
-               }
-       }
-}
-
 static size_t
 sotc_index(int sotc)
 {
@@ -1473,28 +1470,160 @@ sotc_index(int sotc)
        return SIZE_T_MAX;
 }
 
+uint8_t
+fastlane_sc_to_dscp(uint32_t svc_class)
+{
+       uint8_t dscp = _DSCP_DF;
+
+       switch (svc_class) {
+       case MBUF_SC_BK_SYS:
+       case MBUF_SC_BK:
+               dscp = _DSCP_AF11;
+               break;
+
+       case MBUF_SC_BE:
+               dscp = _DSCP_DF;
+               break;
+       case MBUF_SC_RD:
+               dscp = _DSCP_AF21;
+               break;
+       case MBUF_SC_OAM:
+               dscp = _DSCP_CS2;
+               break;
+
+       case MBUF_SC_AV:
+               dscp = _DSCP_AF31;
+               break;
+       case MBUF_SC_RV:
+               dscp = _DSCP_CS4;
+               break;
+       case MBUF_SC_VI:
+               dscp = _DSCP_AF41;
+               break;
+       case MBUF_SC_SIG:
+               dscp = _DSCP_CS3;
+               break;
+
+       case MBUF_SC_VO:
+               dscp = _DSCP_EF;
+               break;
+       case MBUF_SC_CTL:
+               dscp = _DSCP_DF;
+               break;
+       default:
+               dscp = _DSCP_DF;
+               break;
+       }
+
+       return dscp;
+}
+
+uint8_t
+rfc4594_sc_to_dscp(uint32_t svc_class)
+{
+       uint8_t dscp = _DSCP_DF;
+
+       switch (svc_class) {
+       case MBUF_SC_BK_SYS:            /* Low-Priority Data */
+       case MBUF_SC_BK:
+               dscp = _DSCP_CS1;
+               break;
+
+       case MBUF_SC_BE:                        /* Standard */
+               dscp = _DSCP_DF;
+               break;
+       case MBUF_SC_RD:                        /* Low-Latency Data */
+               dscp = _DSCP_AF21;
+               break;
+
+       /* SVC_CLASS Not Defined:  High-Throughput Data */
+
+       case MBUF_SC_OAM:               /* OAM */
+               dscp = _DSCP_CS2;
+               break;
+
+       /* SVC_CLASS Not Defined:  Broadcast Video */
+
+       case MBUF_SC_AV:                        /* Multimedia Streaming */
+               dscp = _DSCP_AF31;
+               break;
+       case MBUF_SC_RV:                        /* Real-Time Interactive */
+               dscp = _DSCP_CS4;
+               break;
+       case MBUF_SC_VI:                        /* Multimedia Conferencing */
+               dscp = _DSCP_AF41;
+               break;
+       case MBUF_SC_SIG:               /* Signaling */
+               dscp = _DSCP_CS5;
+               break;
+
+       case MBUF_SC_VO:                        /* Telephony */
+               dscp = _DSCP_EF;
+               break;
+       case MBUF_SC_CTL:               /* Network Control*/
+               dscp = _DSCP_CS6;
+               break;
+       default:
+               dscp = _DSCP_DF;
+               break;
+       }
+
+       return dscp;
+}
+
+mbuf_traffic_class_t
+rfc4594_dscp_to_tc(uint8_t dscp)
+{
+       mbuf_traffic_class_t tc = MBUF_TC_BE;
+
+       switch (dscp) {
+       case _DSCP_CS1:
+               tc = MBUF_TC_BK;
+               break;
+       case _DSCP_DF:
+       case _DSCP_AF21:
+       case _DSCP_CS2:
+               tc = MBUF_TC_BE;
+               break;
+       case _DSCP_AF31:
+       case _DSCP_CS4:
+       case _DSCP_AF41:
+       case _DSCP_CS5:
+               tc = MBUF_TC_VI;
+               break;
+       case _DSCP_EF:
+       case _DSCP_CS6:
+               tc = MBUF_TC_VO;
+               break;
+       default:
+               tc = MBUF_TC_BE;
+               break;
+       }
+
+       return tc;
+}
+
 /*
  * Pass NULL ifp for default map
  */
 static errno_t
-set_netsvctype_dscp_map(size_t in_count,
+set_netsvctype_dscp_map(struct net_qos_dscp_map *net_qos_dscp_map,
     const struct netsvctype_dscp_map *netsvctype_dscp_map)
 {
        size_t i;
-       struct net_qos_dscp_map *net_qos_dscp_map = NULL;
        int netsvctype;
 
        /*
         * Do not accept more that max number of distinct DSCPs
         */
-       if (in_count > _MAX_DSCP || netsvctype_dscp_map == NULL) {
+       if (net_qos_dscp_map == NULL || netsvctype_dscp_map == NULL) {
                return EINVAL;
        }
 
        /*
         * Validate input parameters
         */
-       for (i = 0; i < in_count; i++) {
+       for (i = 0; i < _NET_SERVICE_TYPE_COUNT; i++) {
                if (!IS_VALID_NET_SERVICE_TYPE(netsvctype_dscp_map[i].netsvctype)) {
                        return EINVAL;
                }
@@ -1503,9 +1632,7 @@ set_netsvctype_dscp_map(size_t in_count,
                }
        }
 
-       net_qos_dscp_map = &default_net_qos_dscp_map;
-
-       for (i = 0; i < in_count; i++) {
+       for (i = 0; i < _NET_SERVICE_TYPE_COUNT; i++) {
                netsvctype = netsvctype_dscp_map[i].netsvctype;
 
                net_qos_dscp_map->netsvctype_to_dscp[netsvctype] =
@@ -1538,8 +1665,12 @@ set_netsvctype_dscp_map(size_t in_count,
                        ASSERT(0);
                }
        }
-       /* Network control socket traffic class is always best effort */
-       net_qos_dscp_map->sotc_to_dscp[SOTCIX_CTL] = _DSCP_DF;
+       if (net_qos_dscp_map == &fastlane_net_qos_dscp_map) {
+               /* Network control socket traffic class is always best effort for fastlane*/
+               net_qos_dscp_map->sotc_to_dscp[SOTCIX_CTL] = _DSCP_DF;
+       } else {
+               net_qos_dscp_map->sotc_to_dscp[SOTCIX_CTL] = _DSCP_CS6;
+       }
 
        /* Backround socket traffic class DSCP same as backround system */
        net_qos_dscp_map->sotc_to_dscp[SOTCIX_BK] =
@@ -1548,35 +1679,20 @@ set_netsvctype_dscp_map(size_t in_count,
        return 0;
 }
 
-/*
- * out_count is an input/ouput parameter
- */
-static errno_t
-get_netsvctype_dscp_map(size_t *out_count,
-    struct netsvctype_dscp_map *netsvctype_dscp_map)
+static size_t
+get_netsvctype_dscp_map(struct netsvctype_dscp_map *netsvctype_dscp_map)
 {
-       size_t i;
-       struct net_qos_dscp_map *net_qos_dscp_map = NULL;
-
-       /*
-        * Do not accept more that max number of distinct DSCPs
-        */
-       if (out_count == NULL || netsvctype_dscp_map == NULL) {
-               return EINVAL;
-       }
-       if (*out_count > _MAX_DSCP) {
-               return EINVAL;
-       }
+       struct net_qos_dscp_map *net_qos_dscp_map;
+       int i;
 
-       net_qos_dscp_map = &default_net_qos_dscp_map;
+       net_qos_dscp_map = &fastlane_net_qos_dscp_map;
 
-       for (i = 0; i < MIN(_NET_SERVICE_TYPE_COUNT, *out_count); i++) {
+       for (i = 0; i < _NET_SERVICE_TYPE_COUNT; i++) {
                netsvctype_dscp_map[i].netsvctype = i;
                netsvctype_dscp_map[i].dscp = net_qos_dscp_map->netsvctype_to_dscp[i];
        }
-       *out_count = i;
 
-       return 0;
+       return i * sizeof(struct netsvctype_dscp_map);
 }
 
 void
@@ -1584,17 +1700,13 @@ net_qos_map_init()
 {
        errno_t error;
 
-       /*
-        * By default use the Fastlane DSCP mappngs
-        */
-       error = set_netsvctype_dscp_map(_NET_SERVICE_TYPE_COUNT,
+       error = set_netsvctype_dscp_map(&fastlane_net_qos_dscp_map,
            fastlane_netsvctype_dscp_map);
        ASSERT(error == 0);
 
-       /*
-        * No DSCP mapping for network control
-        */
-       default_net_qos_dscp_map.sotc_to_dscp[SOTCIX_CTL] = _DSCP_DF;
+       error = set_netsvctype_dscp_map(&rfc4594_net_qos_dscp_map,
+           rfc4594_netsvctype_dscp_map);
+       ASSERT(error == 0);
 
        set_dscp_to_wifi_ac_map(default_dscp_to_wifi_ac_map, 1);
 }
@@ -1604,22 +1716,16 @@ sysctl_default_netsvctype_to_dscp_map SYSCTL_HANDLER_ARGS
 {
 #pragma unused(oidp, arg1, arg2)
        int error = 0;
-       const size_t max_netsvctype_to_dscp_map_len =
-           _NET_SERVICE_TYPE_COUNT * sizeof(struct netsvctype_dscp_map);
-       size_t len;
-       struct netsvctype_dscp_map netsvctype_dscp_map[_NET_SERVICE_TYPE_COUNT] = {};
-       size_t count;
 
        if (req->oldptr == USER_ADDR_NULL) {
                req->oldidx =
                    _NET_SERVICE_TYPE_COUNT * sizeof(struct netsvctype_dscp_map);
        } else if (req->oldlen > 0) {
-               count = _NET_SERVICE_TYPE_COUNT;
-               error = get_netsvctype_dscp_map(&count, netsvctype_dscp_map);
-               if (error != 0) {
-                       goto done;
-               }
-               len = count * sizeof(struct netsvctype_dscp_map);
+               struct netsvctype_dscp_map netsvctype_dscp_map[_NET_SERVICE_TYPE_COUNT] = {};
+               size_t len;
+
+               len = get_netsvctype_dscp_map(netsvctype_dscp_map);
+
                error = SYSCTL_OUT(req, netsvctype_dscp_map,
                    MIN(len, req->oldlen));
                if (error != 0) {
@@ -1627,48 +1733,37 @@ sysctl_default_netsvctype_to_dscp_map SYSCTL_HANDLER_ARGS
                }
        }
 
-       if (req->newptr == USER_ADDR_NULL) {
-               goto done;
-       }
-
-       error = proc_suser(current_proc());
-       if (error != 0) {
-               goto done;
+       if (req->newptr != USER_ADDR_NULL) {
+               error = EPERM;
        }
-
-       /*
-        * Check input length
-        */
-       if (req->newlen > max_netsvctype_to_dscp_map_len) {
-               error = EINVAL;
-               goto done;
-       }
-       /*
-        * Cap the number of entries to copy from input buffer
-        */
-       error = SYSCTL_IN(req, netsvctype_dscp_map, req->newlen);
-       if (error != 0) {
-               goto done;
-       }
-
-       count = req->newlen / sizeof(struct netsvctype_dscp_map);
-       error = set_netsvctype_dscp_map(count, netsvctype_dscp_map);
 done:
        return error;
 }
 
 __private_extern__ errno_t
 set_packet_qos(struct mbuf *m, struct ifnet *ifp, boolean_t qos_allowed,
-    int sotc, int netsvctype, u_int8_t *dscp_inout)
+    int sotc, int netsvctype, uint8_t *dscp_inout)
 {
        if (ifp == NULL || dscp_inout == NULL) {
                return EINVAL;
        }
 
-       if ((ifp->if_eflags &
-           (IFEF_QOSMARKING_ENABLED | IFEF_QOSMARKING_CAPABLE)) ==
-           (IFEF_QOSMARKING_ENABLED | IFEF_QOSMARKING_CAPABLE)) {
-               u_int8_t dscp;
+       if ((ifp->if_eflags & IFEF_QOSMARKING_ENABLED) != 0 &&
+           ifp->if_qosmarking_mode != IFRTYPE_QOSMARKING_MODE_NONE) {
+               uint8_t dscp;
+               const struct net_qos_dscp_map *net_qos_dscp_map = NULL;
+
+               switch (ifp->if_qosmarking_mode) {
+               case IFRTYPE_QOSMARKING_FASTLANE:
+                       net_qos_dscp_map = &fastlane_net_qos_dscp_map;
+                       break;
+               case IFRTYPE_QOSMARKING_RFC4594:
+                       net_qos_dscp_map = &rfc4594_net_qos_dscp_map;
+                       break;
+               default:
+                       panic("invalid QoS marking type");
+                       /* NOTREACHED */
+               }
 
                /*
                 * When on a Fastlane network, IP_TOS/IPV6_TCLASS are no-ops
@@ -1688,7 +1783,7 @@ set_packet_qos(struct mbuf *m, struct ifnet *ifp, boolean_t qos_allowed,
                 */
                if (IS_VALID_NET_SERVICE_TYPE(netsvctype) &&
                    netsvctype != NET_SERVICE_TYPE_BE) {
-                       dscp = default_net_qos_dscp_map.netsvctype_to_dscp[netsvctype];
+                       dscp = net_qos_dscp_map->netsvctype_to_dscp[netsvctype];
 
                        if (qos_allowed == FALSE &&
                            netsvctype != NET_SERVICE_TYPE_BE &&
@@ -1701,7 +1796,7 @@ set_packet_qos(struct mbuf *m, struct ifnet *ifp, boolean_t qos_allowed,
                } else if (sotc != SO_TC_UNSPEC) {
                        size_t sotcix = sotc_index(sotc);
                        if (sotcix != SIZE_T_MAX) {
-                               dscp = default_net_qos_dscp_map.sotc_to_dscp[sotcix];
+                               dscp = net_qos_dscp_map->sotc_to_dscp[sotcix];
 
                                if (qos_allowed == FALSE && sotc != SO_TC_BE &&
                                    sotc != SO_TC_BK && sotc != SO_TC_BK_SYS &&
@@ -1790,7 +1885,7 @@ dscp_msc_map_from_netsvctype_dscp_map(struct netsvctype_dscp_map *netsvctype_dsc
     size_t count, struct dcsp_msc_map *dcsp_msc_map)
 {
        errno_t error = 0;
-       u_int32_t i;
+       uint32_t i;
 
        /*
         * Validate input parameters
@@ -1825,11 +1920,12 @@ sysctl_dscp_to_wifi_ac_map SYSCTL_HANDLER_ARGS
        struct netsvctype_dscp_map netsvctype_dscp_map[DSCP_ARRAY_SIZE] = {};
        struct dcsp_msc_map dcsp_msc_map[DSCP_ARRAY_SIZE];
        size_t count;
-       u_int32_t i;
 
        if (req->oldptr == USER_ADDR_NULL) {
                req->oldidx = len;
        } else if (req->oldlen > 0) {
+               uint8_t i;
+
                for (i = 0; i < DSCP_ARRAY_SIZE; i++) {
                        netsvctype_dscp_map[i].dscp = i;
                        netsvctype_dscp_map[i].netsvctype =
@@ -1967,6 +2063,15 @@ net_qos_guideline(struct proc *p, struct net_qos_guideline_args *arg,
                        return 0;
                }
        }
+       if (ipv4_primary != NULL && IFNET_IS_CONSTRAINED(ipv4_primary) &&
+           ipv6_primary != NULL && IFNET_IS_CONSTRAINED(ipv6_primary)) {
+               if (qos_arg.nq_use_constrained) {
+                       return 0;
+               } else {
+                       *retval = RETURN_USE_BK;
+                       return 0;
+               }
+       }
        if (qos_arg.nq_transfer_size >= 5 * 1024 * 1024) {
                *retval = RETURN_USE_BK;
                return 0;