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:
parent
b4e01ae929
commit
025f8ab52e
7 changed files with 244 additions and 4 deletions
|
@ -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 "
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue