+struct dcsp_msc_map {
+ u_int8_t dscp;
+ mbuf_svc_class_t msc;
+};
+static inline int so_throttle_best_effort(struct socket *, struct ifnet *);
+static void set_dscp_to_wifi_ac_map(const struct dcsp_msc_map *, int);
+static errno_t dscp_msc_map_from_netsvctype_dscp_map(struct netsvctype_dscp_map *, size_t,
+ struct dcsp_msc_map *);
+
+static lck_grp_attr_t *tclass_lck_grp_attr = NULL; /* mutex group attributes */
+static lck_grp_t *tclass_lck_grp = NULL; /* mutex group definition */
+static lck_attr_t *tclass_lck_attr = NULL; /* mutex attributes */
+decl_lck_mtx_data(static, tclass_lock_data);
+static lck_mtx_t *tclass_lock = &tclass_lock_data;
+
+SYSCTL_NODE(_net, OID_AUTO, qos,
+ CTLFLAG_RW|CTLFLAG_LOCKED, 0, "QoS");
+
+static int sysctl_default_netsvctype_to_dscp_map SYSCTL_HANDLER_ARGS;
+SYSCTL_PROC(_net_qos, OID_AUTO, default_netsvctype_to_dscp_map,
+ CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED,
+ 0, 0, sysctl_default_netsvctype_to_dscp_map, "S", "");
+
+static int sysctl_dscp_to_wifi_ac_map SYSCTL_HANDLER_ARGS;
+SYSCTL_PROC(_net_qos, OID_AUTO, dscp_to_wifi_ac_map,
+ CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED,
+ 0, 0, sysctl_dscp_to_wifi_ac_map, "S", "");
+
+static int sysctl_reset_dscp_to_wifi_ac_map SYSCTL_HANDLER_ARGS;
+SYSCTL_PROC(_net_qos, OID_AUTO, reset_dscp_to_wifi_ac_map,
+ CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_LOCKED,
+ 0, 0, sysctl_reset_dscp_to_wifi_ac_map, "I", "");
+
+int net_qos_verbose = 0;
+SYSCTL_INT(_net_qos, OID_AUTO, verbose,
+ CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_verbose, 0, "");
+
+/*
+ * Fastlane QoS policy:
+ * By Default allow all apps to get traffic class to DSCP mapping
+ */
+SYSCTL_NODE(_net_qos, OID_AUTO, policy,
+ CTLFLAG_RW|CTLFLAG_LOCKED, 0, "");
+
+int net_qos_policy_restricted = 0;
+SYSCTL_INT(_net_qos_policy, OID_AUTO, restricted,
+ CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_policy_restricted, 0, "");
+
+int net_qos_policy_restrict_avapps = 0;
+SYSCTL_INT(_net_qos_policy, OID_AUTO, restrict_avapps,
+ CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_policy_restrict_avapps, 0, "");
+
+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_capable_enabled = 0;
+SYSCTL_INT(_net_qos_policy, OID_AUTO, capable_enabled,
+ CTLFLAG_RW | CTLFLAG_LOCKED, &net_qos_policy_capable_enabled, 0, "");
+
+/*
+ * Socket traffic class from network service type
+ */
+const int sotc_by_netservicetype[_NET_SERVICE_TYPE_COUNT] = {
+ SO_TC_BE, /* NET_SERVICE_TYPE_BE */
+ SO_TC_BK_SYS, /* NET_SERVICE_TYPE_BK */
+ SO_TC_VI, /* NET_SERVICE_TYPE_SIG */
+ SO_TC_VI, /* NET_SERVICE_TYPE_VI */
+ SO_TC_VO, /* NET_SERVICE_TYPE_VO */
+ SO_TC_RV, /* NET_SERVICE_TYPE_RV */
+ SO_TC_AV, /* NET_SERVICE_TYPE_AV */
+ SO_TC_OAM, /* NET_SERVICE_TYPE_OAM */
+ SO_TC_RD /* NET_SERVICE_TYPE_RD */
+};
+
+/*
+ * DSCP mappings for QoS Fastlane as based on network service types
+ */
+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 },
+};
+
+static struct net_qos_dscp_map default_net_qos_dscp_map;
+
+/*
+ * The size is one more than the max because DSCP start at zero
+ */
+#define DSCP_ARRAY_SIZE (_MAX_DSCP + 1)
+
+/*
+ * The DSCP to UP mapping (via mbuf service class) for WiFi follows is the mapping
+ * that implemented at the 802.11 driver level when the mbuf service class is
+ * MBUF_SC_BE.
+ *
+ * This clashes with the recommended mapping documented by the IETF document
+ * draft-szigeti-tsvwg-ieee-802-11e-01.txt but we keep the mapping to maintain
+ * binary compatibility. Applications should use the network service type socket
+ * 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 */
+};
+
+mbuf_svc_class_t wifi_dscp_to_msc_array[DSCP_ARRAY_SIZE];
+
+/*
+ * If there is no foreground activity on the interface for bg_switch_time
+ * seconds, the background connections can switch to foreground TCP
+ * congestion control.
+ */
+#define TCP_BG_SWITCH_TIME 2 /* seconds */
+
+#if (DEVELOPMENT || DEBUG)
+
+extern char *proc_best_name(proc_t p);