]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
SCS: Add support for QoS Characteristics in SCS request
authorPurushottam Kushwaha <quic_pkushwah@quicinc.com>
Tue, 18 Apr 2023 13:45:06 +0000 (19:15 +0530)
committerJouni Malinen <j@w1.fi>
Mon, 28 Aug 2023 13:06:50 +0000 (16:06 +0300)
Add support to configure the mandatory QoS Characteristics parameters
per IEEE P802.11be/D4.0, 9.4.2.316 (QoS Characteristics element), in SCS
request:
 - Minimum Service Interval
 - Maximum Service Interval
 - Minimum Data Rate
 - Delay Bound

Enable STA SCS traffic descriptor support for EHT connection when the
connected EHT AP advertises SCS traffic descriptor capability in the EHT
Capabilities element.

Signed-off-by: Purushottam Kushwaha <quic_pkushwah@quicinc.com>
src/common/ieee802_11_defs.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/robust_av.c
wpa_supplicant/wpa_supplicant_i.h

index fbf9afa7783b62981d46320a41e02491c00dafd5..a5ec42c74d41c520d3d088d84a3998177c3e6570 100644 (file)
 #define WLAN_EID_EXT_EHT_CAPABILITIES 108
 #define WLAN_EID_EXT_TID_TO_LINK_MAPPING 109
 #define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
+#define WLAN_EID_EXT_QOS_CHARACTERISTICS 113
 #define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114
 
 /* Extended Capabilities field */
@@ -2768,6 +2769,26 @@ enum scs_request_type {
        SCS_REQ_CHANGE = 2,
 };
 
+/*
+ * IEEE P802.11be/D4.0, 9.4.2.316 QoS Characteristics element,
+ * Table 9-404s (Direction subfield encoding)
+ */
+enum scs_direction {
+       SCS_DIRECTION_UP = 0,
+       SCS_DIRECTION_DOWN = 1,
+       SCS_DIRECTION_DIRECT = 2,
+};
+
+/*
+ * IEEE P802.11be/D4.0, 9.4.2.316 QoS Characteristics element,
+ * Figure 9-1001av (Control Info field format)
+ */
+#define EHT_QOS_CONTROL_INFO_DIRECTION_OFFSET          0
+#define EHT_QOS_CONTROL_INFO_TID_OFFSET                        2
+#define EHT_QOS_CONTROL_INFO_USER_PRIORITY_OFFSET      6
+#define EHT_QOS_CONTROL_INFO_PRESENCE_MASK_OFFSET      9
+#define EHT_QOS_CONTROL_INFO_LINK_ID_OFFSET            25
+
 /* Optional subelement IDs for MSCS Descriptor element */
 enum mscs_description_subelem {
        MCSC_SUBELEM_STATUS = 1,
index 9abfeb2168e6aee3ef78ed267b2acdaac99b9d60..4f81175ff522f0ce0b3e82c566ec635734bc9308 100644 (file)
@@ -11528,7 +11528,11 @@ static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s,
         * [scs_id=<decimal number>] <add|remove|change> [scs_up=<0-7>]
         * [classifier_type=<4|10>]
         * [classifier params based on classifier type]
-        * [tclas_processing=<0|1>] [scs_id=<decimal number>] ...
+        * [tclas_processing=<0|1>]
+        * [qos_characteristics] <up/down/direct> [min_si=<decimal number>]
+        * [max_si=<decimal number>] [min_data_rate=<decimal number>]
+        * [delay_bound=<decimal number>]
+        * [scs_id=<decimal number>] ...
         */
        pos1 = os_strstr(cmd, "scs_id=");
        if (!pos1) {
@@ -11543,7 +11547,8 @@ static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s,
                struct active_scs_elem *active_scs_desc;
                char *next_scs_desc;
                unsigned int num_tclas_elem = 0;
-               bool scsid_active = false;
+               bool scsid_active = false, tclas_present = false;
+               struct qos_characteristics *qos_elem = &desc_elem.qos_char_elem;
 
                desc_elem.scs_id = atoi(pos1 + 7);
                pos1 += 7;
@@ -11619,8 +11624,9 @@ static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s,
                pos = os_strstr(pos1, "classifier_type=");
                if (!pos) {
                        wpa_printf(MSG_ERROR, "classifier type empty");
-                       goto free_scs_desc;
+                       goto qos_characteristics;
                }
+               tclas_present = true;
 
                while (pos) {
                        struct tclas_element elem = { 0 }, *n;
@@ -11684,6 +11690,68 @@ static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s,
                        desc_elem.tclas_processing = val;
                }
 
+       qos_characteristics:
+               pos1 = os_strstr(pos1, "qos_characteristics");
+               if (!pos1 && !tclas_present)
+                       goto free_scs_desc;
+               if (!pos1)
+                       goto scs_desc_end;
+
+               qos_elem->available = true;
+               if (os_strstr(pos1, "up ")) {
+                       qos_elem->direction = SCS_DIRECTION_UP;
+                       if (tclas_present) {
+                               wpa_printf(MSG_ERROR,
+                                          "TCLAS with direction:UP not allowed");
+                               goto free_scs_desc;
+                       }
+               } else if (os_strstr(pos1, "down ")) {
+                       qos_elem->direction = SCS_DIRECTION_DOWN;
+               } else if (os_strstr(pos1, "direct ")) {
+                       qos_elem->direction = SCS_DIRECTION_DIRECT;
+               }
+
+               pos1 = os_strstr(pos1, "min_si=");
+               if (!pos1) {
+                       wpa_printf(MSG_ERROR, "Min SI is required");
+                       goto free_scs_desc;
+               }
+               qos_elem->min_si = atoi(pos1 + 7);
+
+               pos1 = os_strstr(pos1, "max_si=");
+               if (!pos1) {
+                       wpa_printf(MSG_ERROR, "Max SI is required");
+                       goto free_scs_desc;
+               }
+               qos_elem->max_si = atoi(pos1 + 7);
+
+               if (qos_elem->min_si && qos_elem->max_si &&
+                   qos_elem->max_si < qos_elem->min_si) {
+                       wpa_printf(MSG_ERROR, "Invalid Max SI");
+                       goto free_scs_desc;
+               }
+
+               pos1 = os_strstr(pos1, "min_data_rate=");
+               if (!pos1) {
+                       wpa_printf(MSG_ERROR, "Min data rate is required");
+                       goto free_scs_desc;
+               }
+               qos_elem->min_data_rate = atoi(pos1 + 14);
+
+               pos1 = os_strstr(pos1, "delay_bound=");
+               if (!pos1) {
+                       wpa_printf(MSG_ERROR, "Delay Bound is required");
+                       goto free_scs_desc;
+               }
+               qos_elem->delay_bound = atoi(pos1 + 12);
+
+               if (qos_elem->min_data_rate >= BIT(24) ||
+                   qos_elem->delay_bound >= BIT(24)) {
+                       wpa_printf(MSG_ERROR,
+                                  "Invalid min_data_rate or delay_bound");
+                       goto free_scs_desc;
+               }
+
 scs_desc_end:
                n1 = os_realloc(scs_data->scs_desc_elems, (num_scs_desc + 1) *
                                sizeof(struct scs_desc_elem));
index 4b4fe64948e0d9b7759a78ee8bf5e50b63ea255c..6794e99ff85c89de877c94d7e30c3f1533f983c7 100644 (file)
@@ -97,12 +97,27 @@ static int wpas_populate_type10_classifier(struct type10_params *type10_param,
 }
 
 
+static bool tclas_elem_required(const struct qos_characteristics *qos_elem)
+{
+       if (!qos_elem || !qos_elem->available)
+               return true;
+
+       if (qos_elem->direction == SCS_DIRECTION_DOWN)
+               return true;
+
+       return false;
+}
+
+
 static int wpas_populate_scs_descriptor_ie(struct scs_desc_elem *desc_elem,
-                                          struct wpabuf *buf)
+                                          struct wpabuf *buf,
+                                          bool allow_scs_traffic_desc)
 {
        u8 *len, *len1;
        struct tclas_element *tclas_elem;
        unsigned int i;
+       struct qos_characteristics *qos_elem;
+       u32 control_info = 0;
 
        /* SCS Descriptor element */
        wpabuf_put_u8(buf, WLAN_EID_SCS_DESCRIPTOR);
@@ -112,6 +127,9 @@ static int wpas_populate_scs_descriptor_ie(struct scs_desc_elem *desc_elem,
        if (desc_elem->request_type == SCS_REQ_REMOVE)
                goto end;
 
+       if (!tclas_elem_required(&desc_elem->qos_char_elem))
+               goto skip_tclas_elem;
+
        if (desc_elem->intra_access_priority || desc_elem->scs_up_avail) {
                wpabuf_put_u8(buf, WLAN_EID_INTRA_ACCESS_CATEGORY_PRIORITY);
                wpabuf_put_u8(buf, 1);
@@ -164,6 +182,40 @@ static int wpas_populate_scs_descriptor_ie(struct scs_desc_elem *desc_elem,
                wpabuf_put_u8(buf, desc_elem->tclas_processing);
        }
 
+skip_tclas_elem:
+       if (allow_scs_traffic_desc && desc_elem->qos_char_elem.available) {
+               qos_elem = &desc_elem->qos_char_elem;
+               /* Element ID, Length, and Element ID Extension */
+               wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+               len1 = wpabuf_put(buf, 1);
+               wpabuf_put_u8(buf, WLAN_EID_EXT_QOS_CHARACTERISTICS);
+
+               /* IEEE P802.11be/D4.0, 9.4.2.316 QoS Characteristics element,
+                * Figure 9-1001av (Control Info field format)
+                */
+               control_info = ((u32) qos_elem->direction <<
+                               EHT_QOS_CONTROL_INFO_DIRECTION_OFFSET);
+               control_info |= ((u32) desc_elem->intra_access_priority <<
+                                EHT_QOS_CONTROL_INFO_TID_OFFSET);
+               control_info |= ((u32) desc_elem->intra_access_priority <<
+                                EHT_QOS_CONTROL_INFO_USER_PRIORITY_OFFSET);
+               control_info |= ((u32) qos_elem->mask <<
+                                EHT_QOS_CONTROL_INFO_PRESENCE_MASK_OFFSET);
+
+               /* Control Info */
+               wpabuf_put_le32(buf, control_info);
+               /* Minimum Service Interval */
+               wpabuf_put_le32(buf, qos_elem->min_si);
+               /* Maximum Service Interval */
+               wpabuf_put_le32(buf, qos_elem->max_si);
+               /* Minimum Data Rate */
+               wpabuf_put_le24(buf, qos_elem->min_data_rate);
+               /* Delay Bound */
+               wpabuf_put_le24(buf, qos_elem->delay_bound);
+
+               *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1;
+       }
+
 end:
        *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
        return 0;
@@ -273,8 +325,26 @@ static size_t tclas_elem_len(const struct tclas_element *elem)
 }
 
 
+static size_t qos_char_len(const struct qos_characteristics *qos_elem)
+{
+       size_t buf_len = 0;
+
+       buf_len += 1 +  /* Element ID */
+               1 +     /* Length */
+               1 +     /* Element ID Extension */
+               4 +     /* Control Info */
+               4 +     /* Minimum Service Interval */
+               4 +     /* Maximum Service Interval */
+               3 +     /* Minimum Data Rate */
+               3;      /* Delay Bound */
+
+       return buf_len;
+}
+
+
 static struct wpabuf * allocate_scs_buf(struct scs_desc_elem *desc_elem,
-                                       unsigned int num_scs_desc)
+                                       unsigned int num_scs_desc,
+                                       bool allow_scs_traffic_desc)
 {
        struct wpabuf *buf;
        size_t buf_len = 0;
@@ -292,6 +362,13 @@ static struct wpabuf * allocate_scs_buf(struct scs_desc_elem *desc_elem,
                if (desc_elem->request_type == SCS_REQ_REMOVE)
                        continue;
 
+               if (allow_scs_traffic_desc &&
+                   desc_elem->qos_char_elem.available)
+                       buf_len += qos_char_len(&desc_elem->qos_char_elem);
+
+               if (!tclas_elem_required(&desc_elem->qos_char_elem))
+                       continue;
+
                if (desc_elem->intra_access_priority || desc_elem->scs_up_avail)
                        buf_len += 3;
 
@@ -369,8 +446,11 @@ int wpas_send_scs_req(struct wpa_supplicant *wpa_s)
 {
        struct wpabuf *buf = NULL;
        struct scs_desc_elem *desc_elem = NULL;
+       const struct ieee80211_eht_capabilities *eht;
+       const u8 *eht_ie;
        int ret = -1;
        unsigned int i;
+       bool allow_scs_traffic_desc = false;
 
        if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
                return -1;
@@ -385,8 +465,28 @@ int wpas_send_scs_req(struct wpa_supplicant *wpa_s)
        if (!desc_elem)
                return -1;
 
+       if (wpa_is_non_eht_scs_traffic_desc_supported(wpa_s->current_bss))
+               allow_scs_traffic_desc = true;
+
+       /* Allow SCS Traffic descriptor support for EHT connection */
+       eht_ie = wpa_bss_get_ie_ext(wpa_s->current_bss,
+                                   WLAN_EID_EXT_EHT_CAPABILITIES);
+       if (wpa_s->connection_eht && eht_ie &&
+           eht_ie[1] >= 1 + IEEE80211_EHT_CAPAB_MIN_LEN) {
+               eht = (const struct ieee80211_eht_capabilities *) &eht_ie[3];
+               if (eht->mac_cap & EHT_MACCAP_SCS_TRAFFIC_DESC)
+                       allow_scs_traffic_desc = true;
+       }
+
+       if (!allow_scs_traffic_desc && desc_elem->qos_char_elem.available) {
+               wpa_dbg(wpa_s, MSG_INFO,
+                       "Connection does not support EHT/non-EHT SCS Traffic Description - could not send SCS Request with QoS Characteristics");
+               return -1;
+       }
+
        buf = allocate_scs_buf(desc_elem,
-                              wpa_s->scs_robust_av_req.num_scs_desc);
+                              wpa_s->scs_robust_av_req.num_scs_desc,
+                              allow_scs_traffic_desc);
        if (!buf)
                return -1;
 
@@ -400,7 +500,8 @@ int wpas_send_scs_req(struct wpa_supplicant *wpa_s)
        for (i = 0; i < wpa_s->scs_robust_av_req.num_scs_desc;
             i++, desc_elem++) {
                /* SCS Descriptor element */
-               if (wpas_populate_scs_descriptor_ie(desc_elem, buf) < 0)
+               if (wpas_populate_scs_descriptor_ie(desc_elem, buf,
+                                                   allow_scs_traffic_desc) < 0)
                        goto end;
        }
 
index 478b36d867ba21eaa4a37b00eb8da6ea82cb4963..d655595cff29be224627a2526e673207fab7aff9 100644 (file)
@@ -596,6 +596,24 @@ struct tclas_element {
 };
 
 
+struct qos_characteristics {
+       bool available;
+
+       /* Control Info Direction */
+       u8 direction;
+       /* Presence Bitmap Of Additional Parameters */
+       u16 mask;
+       /* Minimum Service Interval */
+       u32 min_si;
+       /* Maximum Service Interval */
+       u32 max_si;
+       /* Minimum Data Rate */
+       u32 min_data_rate;
+       /* Delay Bound */
+       u32 delay_bound;
+};
+
+
 struct scs_desc_elem {
        u8 scs_id;
        enum scs_request_type request_type;
@@ -604,6 +622,7 @@ struct scs_desc_elem {
        struct tclas_element *tclas_elems;
        unsigned int num_tclas_elem;
        u8 tclas_processing;
+       struct qos_characteristics qos_char_elem;
 };