]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
SCS: Processing of SCS Response frames
authorVinita S. Maloo <vmaloo@codeaurora.org>
Tue, 19 Jan 2021 14:12:38 +0000 (19:42 +0530)
committerJouni Malinen <j@w1.fi>
Thu, 12 Aug 2021 15:28:07 +0000 (18:28 +0300)
Add support to receive and process SCS Response frames from the AP and
indicate the status to upper layers.

Signed-off-by: Vinita S. Maloo <vmaloo@codeaurora.org>
src/common/wpa_ctrl.h
src/drivers/driver_nl80211.c
wpa_supplicant/ctrl_iface.c
wpa_supplicant/events.c
wpa_supplicant/robust_av.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 126a7892c8a88d420b7c5656248a687d003d6dda..8da5683c2bf6df7a7bd5895085dcaeb04f43c2ba 100644 (file)
@@ -157,6 +157,8 @@ extern "C" {
 #define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
 
 #define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK "
+/** Result of SCS setup */
+#define WPA_EVENT_SCS_RESULT "CTRL-EVENT-SCS-RESULT "
 
 /* WPS ER events */
 #define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "
index 8eb033c78cf9a7bd575cf7330cc79b4352328327..49b2f86649898678754779422b7c72bccd7347e4 100644 (file)
@@ -2505,6 +2505,10 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
            (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
                ret = -1;
 
+       /* Robust AV SCS Response */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x13\x01", 2) < 0)
+               ret = -1;
+
        /* Robust AV MSCS Response */
        if (nl80211_register_action_frame(bss, (u8 *) "\x13\x05", 2) < 0)
                ret = -1;
index 0773c0452368e9ff58c700ce093e8686f3883a07..170d8c19c701ec34d72f841c527393d8d83febe1 100644 (file)
@@ -11180,6 +11180,12 @@ static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s,
        int val;
        unsigned int num_scs_desc = 0;
 
+       if (wpa_s->ongoing_scs_req) {
+               wpa_printf(MSG_ERROR, "%s: SCS Request already in queue",
+                          __func__);
+               return -1;
+       }
+
        /**
         * format:
         * [scs_id=<decimal number>] <add|remove|change> [scs_up=<0-7>]
@@ -11197,8 +11203,10 @@ static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s,
 
        while (pos1) {
                struct scs_desc_elem *n1;
+               struct active_scs_elem *active_scs_desc;
                char *next_scs_desc;
                unsigned int num_tclas_elem = 0;
+               bool scsid_active = false;
 
                desc_elem.scs_id = atoi(pos1 + 7);
                pos1 += 7;
@@ -11218,13 +11226,36 @@ static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s,
                        pos1[next_scs_desc - pos1 - 1] = '\0';
                }
 
+               dl_list_for_each(active_scs_desc, &wpa_s->active_scs_ids,
+                                struct active_scs_elem, list) {
+                       if (desc_elem.scs_id == active_scs_desc->scs_id) {
+                               scsid_active = true;
+                               break;
+                       }
+               }
+
                if (os_strstr(pos1, "add ")) {
                        desc_elem.request_type = SCS_REQ_ADD;
+                       if (scsid_active) {
+                               wpa_printf(MSG_ERROR, "SCSID %d already active",
+                                          desc_elem.scs_id);
+                               return -1;
+                       }
                } else if (os_strstr(pos1, "remove")) {
                        desc_elem.request_type = SCS_REQ_REMOVE;
+                       if (!scsid_active) {
+                               wpa_printf(MSG_ERROR, "SCSID %d not active",
+                                          desc_elem.scs_id);
+                               return -1;
+                       }
                        goto scs_desc_end;
                } else if (os_strstr(pos1, "change ")) {
                        desc_elem.request_type = SCS_REQ_CHANGE;
+                       if (!scsid_active) {
+                               wpa_printf(MSG_ERROR, "SCSID %d not active",
+                                          desc_elem.scs_id);
+                               return -1;
+                       }
                } else {
                        wpa_printf(MSG_ERROR, "SCS Request type invalid");
                        goto free_scs_desc;
index a565e658f33db31f393a0ae15aa404dbb6b1ed39..44f2c41f2e1b3d072a31b88630c0f62e8b073880 100644 (file)
@@ -4259,6 +4259,13 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_DPP */
 
+       if (category == WLAN_ACTION_ROBUST_AV_STREAMING &&
+           payload[0] == ROBUST_AV_SCS_RESP) {
+               wpas_handle_robust_av_scs_recv_action(wpa_s, mgmt->sa,
+                                                     payload + 1, plen - 1);
+               return;
+       }
+
        if (category == WLAN_ACTION_ROBUST_AV_STREAMING &&
            payload[0] == ROBUST_AV_MSCS_RESP) {
                wpas_handle_robust_av_recv_action(wpa_s, mgmt->sa,
index 598bbdedf4dd3fb6b943961b29c3827236a651db..a8b77d1d4d755211d948786dc52202383003fc01 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "utils/includes.h"
 #include "utils/common.h"
+#include "utils/eloop.h"
 #include "common/wpa_ctrl.h"
 #include "common/ieee802_11_common.h"
 #include "wpa_supplicant_i.h"
@@ -15,6 +16,9 @@
 #include "bss.h"
 
 
+#define SCS_RESP_TIMEOUT 1
+
+
 void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
                                      struct wpabuf *buf)
 {
@@ -323,6 +327,43 @@ static struct wpabuf * allocate_scs_buf(struct scs_desc_elem *desc_elem,
 }
 
 
+static void scs_request_timer(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       struct active_scs_elem *scs_desc, *prev;
+
+       if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
+               return;
+
+       /* Once timeout is over, remove all SCS descriptors with no response */
+       dl_list_for_each_safe(scs_desc, prev, &wpa_s->active_scs_ids,
+                             struct active_scs_elem, list) {
+               u8 bssid[ETH_ALEN] = { 0 };
+               const u8 *src;
+
+               if (scs_desc->status == SCS_DESC_SUCCESS)
+                       continue;
+
+               if (wpa_s->current_bss)
+                       src = wpa_s->current_bss->bssid;
+               else
+                       src = bssid;
+
+               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCS_RESULT "bssid=" MACSTR
+                       " SCSID=%u status_code=timedout", MAC2STR(src),
+                       scs_desc->scs_id);
+
+               dl_list_del(&scs_desc->list);
+               wpa_printf(MSG_INFO, "%s: SCSID %d removed after timeout",
+                          __func__, scs_desc->scs_id);
+               os_free(scs_desc);
+       }
+
+       eloop_cancel_timeout(scs_request_timer, wpa_s, NULL);
+       wpa_s->ongoing_scs_req = false;
+}
+
+
 int wpas_send_scs_req(struct wpa_supplicant *wpa_s)
 {
        struct wpabuf *buf = NULL;
@@ -369,7 +410,33 @@ int wpas_send_scs_req(struct wpa_supplicant *wpa_s)
        if (ret < 0) {
                wpa_dbg(wpa_s, MSG_ERROR, "SCS: Failed to send SCS Request");
                wpa_s->scs_dialog_token--;
+               goto end;
        }
+
+       desc_elem = wpa_s->scs_robust_av_req.scs_desc_elems;
+       for (i = 0; i < wpa_s->scs_robust_av_req.num_scs_desc;
+            i++, desc_elem++) {
+               struct active_scs_elem *active_scs_elem;
+
+               if (desc_elem->request_type != SCS_REQ_ADD)
+                       continue;
+
+               active_scs_elem = os_malloc(sizeof(struct active_scs_elem));
+               if (!active_scs_elem)
+                       break;
+               active_scs_elem->scs_id = desc_elem->scs_id;
+               active_scs_elem->status = SCS_DESC_SENT;
+               dl_list_add(&wpa_s->active_scs_ids, &active_scs_elem->list);
+       }
+
+       /*
+        * Register a timeout after which this request will be removed from
+        * the cache.
+        */
+       eloop_register_timeout(SCS_RESP_TIMEOUT, 0, scs_request_timer, wpa_s,
+                              NULL);
+       wpa_s->ongoing_scs_req = true;
+
 end:
        wpabuf_free(buf);
        free_up_scs_desc(&wpa_s->scs_robust_av_req);
@@ -481,3 +548,114 @@ void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
                " status_code=%u", MAC2STR(bssid), status);
        wpa_s->mscs_setup_done = status == WLAN_STATUS_SUCCESS;
 }
+
+
+void wpas_handle_robust_av_scs_recv_action(struct wpa_supplicant *wpa_s,
+                                          const u8 *src, const u8 *buf,
+                                          size_t len)
+{
+       u8 dialog_token;
+       unsigned int i, count;
+       struct active_scs_elem *scs_desc, *prev;
+
+       if (len < 2)
+               return;
+       if (!wpa_s->ongoing_scs_req) {
+               wpa_printf(MSG_INFO,
+                          "SCS: Drop received response due to no ongoing request");
+               return;
+       }
+
+       dialog_token = *buf++;
+       len--;
+       if (dialog_token != wpa_s->scs_dialog_token) {
+               wpa_printf(MSG_INFO,
+                          "SCS: Drop received frame due to dialog token mismatch: received:%u expected:%u",
+                          dialog_token, wpa_s->scs_dialog_token);
+               return;
+       }
+
+       /* This Count field does not exist in the IEEE Std 802.11-2020
+        * definition of the SCS Response frame. However, it was accepted to
+        * be added into REVme per REVme/D0.0 CC35 CID 49 (edits in document
+        * 11-21-0688-07). */
+       count = *buf++;
+       len--;
+       if (count == 0 || count * 3 > len) {
+               wpa_printf(MSG_INFO,
+                          "SCS: Drop received frame due to invalid count: %u (remaining %zu octets)",
+                          count, len);
+               return;
+       }
+
+       for (i = 0; i < count; i++) {
+               u8 id;
+               u16 status;
+               bool scs_desc_found = false;
+
+               id = *buf++;
+               status = WPA_GET_LE16(buf);
+               buf += 2;
+               len -= 3;
+
+               dl_list_for_each(scs_desc, &wpa_s->active_scs_ids,
+                                struct active_scs_elem, list) {
+                       if (id == scs_desc->scs_id) {
+                               scs_desc_found = true;
+                               break;
+                       }
+               }
+
+               if (!scs_desc_found) {
+                       wpa_printf(MSG_INFO, "SCS: SCS ID invalid %u", id);
+                       continue;
+               }
+
+               if (status != WLAN_STATUS_SUCCESS) {
+                       dl_list_del(&scs_desc->list);
+                       os_free(scs_desc);
+               } else if (status == WLAN_STATUS_SUCCESS) {
+                       scs_desc->status = SCS_DESC_SUCCESS;
+               }
+
+               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCS_RESULT "bssid=" MACSTR
+                       " SCSID=%u status_code=%u", MAC2STR(src), id, status);
+       }
+
+       eloop_cancel_timeout(scs_request_timer, wpa_s, NULL);
+       wpa_s->ongoing_scs_req = false;
+
+       dl_list_for_each_safe(scs_desc, prev, &wpa_s->active_scs_ids,
+                             struct active_scs_elem, list) {
+               if (scs_desc->status != SCS_DESC_SUCCESS) {
+                       wpa_msg(wpa_s, MSG_INFO,
+                               WPA_EVENT_SCS_RESULT "bssid=" MACSTR
+                               " SCSID=%u status_code=response_not_received",
+                               MAC2STR(src), scs_desc->scs_id);
+                       dl_list_del(&scs_desc->list);
+                       os_free(scs_desc);
+               }
+       }
+}
+
+
+static void wpas_clear_active_scs_ids(struct wpa_supplicant *wpa_s)
+{
+       struct active_scs_elem *scs_elem;
+
+       while ((scs_elem = dl_list_first(&wpa_s->active_scs_ids,
+                                        struct active_scs_elem, list))) {
+               dl_list_del(&scs_elem->list);
+               os_free(scs_elem);
+       }
+}
+
+
+void wpas_scs_deinit(struct wpa_supplicant *wpa_s)
+{
+       free_up_scs_desc(&wpa_s->scs_robust_av_req);
+       wpa_s->scs_dialog_token = 0;
+       wpas_clear_active_scs_ids(wpa_s);
+       eloop_cancel_timeout(scs_request_timer, wpa_s, NULL);
+       wpa_s->ongoing_scs_req = false;
+}
index 4eda013fc472b3cb2d59c79b732d93cb4d1c2222..d994de4bf9ba0e0a90bef4c74871ce016cc9d539 100644 (file)
@@ -743,8 +743,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_PASN
        wpas_pasn_auth_stop(wpa_s);
 #endif /* CONFIG_PASN */
-       free_up_scs_desc(&wpa_s->scs_robust_av_req);
-       wpa_s->scs_dialog_token = 0;
+       wpas_scs_deinit(wpa_s);
 }
 
 
@@ -3974,8 +3973,7 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
        if (old_ssid != wpa_s->current_ssid)
                wpas_notify_network_changed(wpa_s);
 
-       free_up_scs_desc(&wpa_s->scs_robust_av_req);
-       wpa_s->scs_dialog_token = 0;
+       wpas_scs_deinit(wpa_s);
        eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
 }
 
@@ -5174,6 +5172,7 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
 #ifdef CONFIG_TESTING_OPTIONS
        dl_list_init(&wpa_s->drv_signal_override);
 #endif /* CONFIG_TESTING_OPTIONS */
+       dl_list_init(&wpa_s->active_scs_ids);
 
        return wpa_s;
 }
index 417a479aa56c7aaf9ce8f2efd9233cd950116b4d..6c394fe89f10e7a8066b02cee5f0868fc98e27ef 100644 (file)
@@ -650,6 +650,19 @@ struct scs_robust_av_data {
 };
 
 
+enum scs_response_status {
+       SCS_DESC_SENT = 0,
+       SCS_DESC_SUCCESS = 1,
+};
+
+
+struct active_scs_elem {
+       struct dl_list list;
+       u8 scs_id;
+       enum scs_response_status status;
+};
+
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -1481,6 +1494,8 @@ struct wpa_supplicant {
 #ifdef CONFIG_TESTING_OPTIONS
        unsigned int disable_scs_support:1;
 #endif /* CONFIG_TESTING_OPTIONS */
+       struct dl_list active_scs_ids;
+       bool ongoing_scs_req;
 };
 
 
@@ -1816,6 +1831,10 @@ void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
 int wpas_send_scs_req(struct wpa_supplicant *wpa_s);
 void free_up_tclas_elem(struct scs_desc_elem *elem);
 void free_up_scs_desc(struct scs_robust_av_data *data);
+void wpas_handle_robust_av_scs_recv_action(struct wpa_supplicant *wpa_s,
+                                          const u8 *src, const u8 *buf,
+                                          size_t len);
+void wpas_scs_deinit(struct wpa_supplicant *wpa_s);
 
 int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
                         const u8 *bssid, int akmp, int cipher,