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>]
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;
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;
#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"
#include "bss.h"
+#define SCS_RESP_TIMEOUT 1
+
+
void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
struct wpabuf *buf)
{
}
+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;
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);
" 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;
+}