SCS: Processing of SCS Response frames

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>
This commit is contained in:
Vinita S. Maloo 2021-01-19 19:42:38 +05:30 committed by Jouni Malinen
parent b4e01ae929
commit 025f8ab52e
7 changed files with 244 additions and 4 deletions

View file

@ -157,6 +157,8 @@ extern "C" {
#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN " #define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK " #define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK "
/** Result of SCS setup */
#define WPA_EVENT_SCS_RESULT "CTRL-EVENT-SCS-RESULT "
/* WPS ER events */ /* WPS ER events */
#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD " #define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "

View 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)) (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
ret = -1; ret = -1;
/* Robust AV SCS Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x13\x01", 2) < 0)
ret = -1;
/* Robust AV MSCS Response */ /* Robust AV MSCS Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x13\x05", 2) < 0) if (nl80211_register_action_frame(bss, (u8 *) "\x13\x05", 2) < 0)
ret = -1; ret = -1;

View file

@ -11180,6 +11180,12 @@ static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s,
int val; int val;
unsigned int num_scs_desc = 0; 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: * format:
* [scs_id=<decimal number>] <add|remove|change> [scs_up=<0-7>] * [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) { while (pos1) {
struct scs_desc_elem *n1; struct scs_desc_elem *n1;
struct active_scs_elem *active_scs_desc;
char *next_scs_desc; char *next_scs_desc;
unsigned int num_tclas_elem = 0; unsigned int num_tclas_elem = 0;
bool scsid_active = false;
desc_elem.scs_id = atoi(pos1 + 7); desc_elem.scs_id = atoi(pos1 + 7);
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'; 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 ")) { if (os_strstr(pos1, "add ")) {
desc_elem.request_type = SCS_REQ_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")) { } else if (os_strstr(pos1, "remove")) {
desc_elem.request_type = SCS_REQ_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; goto scs_desc_end;
} else if (os_strstr(pos1, "change ")) { } else if (os_strstr(pos1, "change ")) {
desc_elem.request_type = SCS_REQ_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 { } else {
wpa_printf(MSG_ERROR, "SCS Request type invalid"); wpa_printf(MSG_ERROR, "SCS Request type invalid");
goto free_scs_desc; goto free_scs_desc;

View file

@ -4259,6 +4259,13 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
} }
#endif /* CONFIG_DPP */ #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 && if (category == WLAN_ACTION_ROBUST_AV_STREAMING &&
payload[0] == ROBUST_AV_MSCS_RESP) { payload[0] == ROBUST_AV_MSCS_RESP) {
wpas_handle_robust_av_recv_action(wpa_s, mgmt->sa, wpas_handle_robust_av_recv_action(wpa_s, mgmt->sa,

View file

@ -8,6 +8,7 @@
#include "utils/includes.h" #include "utils/includes.h"
#include "utils/common.h" #include "utils/common.h"
#include "utils/eloop.h"
#include "common/wpa_ctrl.h" #include "common/wpa_ctrl.h"
#include "common/ieee802_11_common.h" #include "common/ieee802_11_common.h"
#include "wpa_supplicant_i.h" #include "wpa_supplicant_i.h"
@ -15,6 +16,9 @@
#include "bss.h" #include "bss.h"
#define SCS_RESP_TIMEOUT 1
void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av, void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
struct wpabuf *buf) 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) int wpas_send_scs_req(struct wpa_supplicant *wpa_s)
{ {
struct wpabuf *buf = NULL; struct wpabuf *buf = NULL;
@ -369,7 +410,33 @@ int wpas_send_scs_req(struct wpa_supplicant *wpa_s)
if (ret < 0) { if (ret < 0) {
wpa_dbg(wpa_s, MSG_ERROR, "SCS: Failed to send SCS Request"); wpa_dbg(wpa_s, MSG_ERROR, "SCS: Failed to send SCS Request");
wpa_s->scs_dialog_token--; 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: end:
wpabuf_free(buf); wpabuf_free(buf);
free_up_scs_desc(&wpa_s->scs_robust_av_req); 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); " status_code=%u", MAC2STR(bssid), status);
wpa_s->mscs_setup_done = status == WLAN_STATUS_SUCCESS; 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;
}

View file

@ -743,8 +743,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_PASN #ifdef CONFIG_PASN
wpas_pasn_auth_stop(wpa_s); wpas_pasn_auth_stop(wpa_s);
#endif /* CONFIG_PASN */ #endif /* CONFIG_PASN */
free_up_scs_desc(&wpa_s->scs_robust_av_req); wpas_scs_deinit(wpa_s);
wpa_s->scs_dialog_token = 0;
} }
@ -3974,8 +3973,7 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
if (old_ssid != wpa_s->current_ssid) if (old_ssid != wpa_s->current_ssid)
wpas_notify_network_changed(wpa_s); wpas_notify_network_changed(wpa_s);
free_up_scs_desc(&wpa_s->scs_robust_av_req); wpas_scs_deinit(wpa_s);
wpa_s->scs_dialog_token = 0;
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
} }
@ -5174,6 +5172,7 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
dl_list_init(&wpa_s->drv_signal_override); dl_list_init(&wpa_s->drv_signal_override);
#endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_TESTING_OPTIONS */
dl_list_init(&wpa_s->active_scs_ids);
return wpa_s; return wpa_s;
} }

View 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 * struct wpa_supplicant - Internal data for wpa_supplicant interface
* *
@ -1481,6 +1494,8 @@ struct wpa_supplicant {
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
unsigned int disable_scs_support:1; unsigned int disable_scs_support:1;
#endif /* CONFIG_TESTING_OPTIONS */ #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); int wpas_send_scs_req(struct wpa_supplicant *wpa_s);
void free_up_tclas_elem(struct scs_desc_elem *elem); void free_up_tclas_elem(struct scs_desc_elem *elem);
void free_up_scs_desc(struct scs_robust_av_data *data); 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, int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
const u8 *bssid, int akmp, int cipher, const u8 *bssid, int akmp, int cipher,