diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 4d3037eee..1e09e1610 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -478,6 +478,8 @@ #define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59 #define WLAN_EID_EXT_EDMG_CAPABILITIES 61 #define WLAN_EID_EXT_EDMG_OPERATION 62 +#define WLAN_EID_EXT_MSCS_DESCRIPTOR 88 +#define WLAN_EID_EXT_TCLAS_MASK 89 #define WLAN_EID_EXT_REJECTED_GROUPS 92 #define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93 @@ -562,6 +564,7 @@ #define WLAN_EXT_CAPAB_SAE_PW_ID 81 #define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82 #define WLAN_EXT_CAPAB_BEACON_PROTECTION 84 +#define WLAN_EXT_CAPAB_MSCS 85 #define WLAN_EXT_CAPAB_SAE_PK_EXCLUSIVELY 88 /* Extended RSN Capabilities */ @@ -2340,4 +2343,20 @@ enum edmg_bw_config { /* DPP Public Action frame identifiers - OUI_WFA */ #define DPP_OUI_TYPE 0x1A +/* Robust AV streaming Action field values */ +enum robust_av_streaming_action { + ROBUST_AV_SCS_REQ = 0, + ROBUST_AV_SCS_RESP = 1, + ROBUST_AV_GROUP_MEMBERSHIP_REQ = 2, + ROBUST_AV_GROUP_MEMBERSHIP_RESP = 3, + ROBUST_AV_MSCS_REQ = 4, + ROBUST_AV_MSCS_RESP = 5, +}; + +enum scs_request_type { + SCS_REQ_ADD = 0, + SCS_REQ_REMOVE = 1, + SCS_REQ_CHANGE = 2, +}; + #endif /* IEEE802_11_DEFS_H */ diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index 0f24d7b71..ed7e358ac 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -98,6 +98,7 @@ OBJS += src/utils/crc32.c OBJS += wmm_ac.c OBJS += op_classes.c OBJS += rrm.c +OBJS += robust_av.c OBJS_p = wpa_passphrase.c OBJS_p += src/utils/common.c OBJS_p += src/utils/wpa_debug.c diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 09ac7a493..a01a32982 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -107,6 +107,7 @@ OBJS += ../src/utils/ip_addr.o OBJS += ../src/utils/crc32.o OBJS += op_classes.o OBJS += rrm.o +OBJS += robust_av.o OBJS_p = wpa_passphrase.o OBJS_p += ../src/utils/common.o OBJS_p += ../src/utils/wpa_debug.o diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 0dcb0398c..5048ee83e 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -8483,6 +8483,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->next_scan_bssid_wildcard_ssid = 0; os_free(wpa_s->select_network_scan_freqs); wpa_s->select_network_scan_freqs = NULL; + os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data)); wpa_bss_flush(wpa_s); if (!dl_list_empty(&wpa_s->bss)) { @@ -8508,6 +8509,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_supplicant_update_channel_list(wpa_s, NULL); free_bss_tmp_disallowed(wpa_s); + + os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data)); } @@ -10342,6 +10345,76 @@ static int wpas_ctrl_cmd_debug_level(const char *cmd) } +static int wpas_ctrl_iface_configure_mscs(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + size_t frame_classifier_len; + const char *pos, *end; + struct robust_av_data *robust_av = &wpa_s->robust_av; + int val; + + /* + * format: + * [up_bitmap=] [up_limit=] + * [stream_timeout=] [frame_classifier=] + */ + os_memset(robust_av, 0, sizeof(struct robust_av_data)); + if (os_strncmp(cmd, "add ", 4) == 0) { + robust_av->request_type = SCS_REQ_ADD; + } else if (os_strcmp(cmd, "remove") == 0) { + robust_av->request_type = SCS_REQ_REMOVE; + robust_av->valid_config = false; + return wpas_send_mscs_req(wpa_s); + } else if (os_strncmp(cmd, "change ", 7) == 0) { + robust_av->request_type = SCS_REQ_CHANGE; + } else { + return -1; + } + + pos = os_strstr(cmd, "up_bitmap="); + if (!pos) + return -1; + + val = hex2byte(pos + 10); + if (val < 0) + return -1; + robust_av->up_bitmap = val; + + pos = os_strstr(cmd, "up_limit="); + if (!pos) + return -1; + + robust_av->up_limit = atoi(pos + 9); + + pos = os_strstr(cmd, "stream_timeout="); + if (!pos) + return -1; + + robust_av->stream_timeout = atoi(pos + 15); + if (robust_av->stream_timeout == 0) + return -1; + + pos = os_strstr(cmd, "frame_classifier="); + if (!pos) + return -1; + + pos += 17; + end = os_strchr(pos, ' '); + if (!end) + end = pos + os_strlen(pos); + + frame_classifier_len = (end - pos) / 2; + if (frame_classifier_len > sizeof(robust_av->frame_classifier) || + hexstr2bin(pos, robust_av->frame_classifier, frame_classifier_len)) + return -1; + + robust_av->frame_classifier_len = frame_classifier_len; + robust_av->valid_config = true; + + return wpas_send_mscs_req(wpa_s); +} + + char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { @@ -11233,6 +11306,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = -1; #endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ + } else if (os_strncmp(buf, "MSCS ", 5) == 0) { + if (wpas_ctrl_iface_configure_mscs(wpa_s, buf + 5)) + reply_len = -1; } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c new file mode 100644 index 000000000..6bb4e3e95 --- /dev/null +++ b/wpa_supplicant/robust_av.c @@ -0,0 +1,98 @@ +/* + * wpa_supplicant - Robust AV procedures + * Copyright (c) 2020, The Linux Foundation + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" +#include "utils/common.h" +#include "common/wpa_ctrl.h" +#include "wpa_supplicant_i.h" +#include "driver_i.h" +#include "bss.h" + + +void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av, + struct wpabuf *buf) +{ + u8 *len, *len1; + + /* MSCS descriptor element */ + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + len = wpabuf_put(buf, 1); + wpabuf_put_u8(buf, WLAN_EID_EXT_MSCS_DESCRIPTOR); + wpabuf_put_u8(buf, robust_av->request_type); + wpabuf_put_u8(buf, robust_av->up_bitmap); + wpabuf_put_u8(buf, robust_av->up_limit); + wpabuf_put_le32(buf, robust_av->stream_timeout); + + if (robust_av->request_type != SCS_REQ_REMOVE) { + /* TCLAS mask element */ + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + len1 = wpabuf_put(buf, 1); + wpabuf_put_u8(buf, WLAN_EID_EXT_TCLAS_MASK); + + /* Frame classifier */ + wpabuf_put_data(buf, robust_av->frame_classifier, + robust_av->frame_classifier_len); + *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1; + } + + *len = (u8 *) wpabuf_put(buf, 0) - len - 1; +} + + +int wpas_send_mscs_req(struct wpa_supplicant *wpa_s) +{ + struct wpabuf *buf; + const u8 *ext_capab = NULL; + size_t buf_len; + int ret; + + if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) + return 0; + + if (wpa_s->current_bss) + ext_capab = wpa_bss_get_ie(wpa_s->current_bss, + WLAN_EID_EXT_CAPAB); + + if (!ext_capab || ext_capab[1] < 11 || !(ext_capab[12] & 0x20)) { + wpa_dbg(wpa_s, MSG_INFO, + "AP does not support MSCS - could not send MSCS Req"); + return -1; + } + + buf_len = 3 + /* Action frame header */ + 3 + /* MSCS descriptor IE header */ + 1 + /* Request type */ + 2 + /* User priority control */ + 4 + /* Stream timeout */ + 3 + /* TCLAS Mask IE header */ + wpa_s->robust_av.frame_classifier_len; + + buf = wpabuf_alloc(buf_len); + if (!buf) { + wpa_printf(MSG_ERROR, "Failed to allocate MSCS req"); + return -1; + } + + wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING); + wpabuf_put_u8(buf, ROBUST_AV_MSCS_REQ); + wpa_s->robust_av.dialog_token++; + wpabuf_put_u8(buf, wpa_s->robust_av.dialog_token); + + /* MSCS descriptor element */ + wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, buf); + + wpa_hexdump_buf(MSG_MSGDUMP, "MSCS Request", wpabuf_head(buf)); + ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, + wpa_s->own_addr, wpa_s->bssid, + wpabuf_head(buf), wpabuf_len(buf), 0); + if (ret < 0) + wpa_dbg(wpa_s, MSG_INFO, "MSCS: Failed to send MSCS Request"); + + wpabuf_free(buf); + return ret; +} diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 6eb09f496..4134d089b 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1899,6 +1899,9 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) *pos |= 0x01; #endif /* CONFIG_FILS */ break; + case 10: /* Bits 80-87 */ + *pos |= 0x20; /* Bit 85 - Mirrored SCS */ + break; } } @@ -1906,7 +1909,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen) { u8 *pos = buf; - u8 len = 10, i; + u8 len = 11, i; if (len < wpa_s->extended_capa_len) len = wpa_s->extended_capa_len; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 9f513c6fe..44f5f375a 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -491,6 +491,17 @@ struct driver_signal_override { int scan_level; }; +struct robust_av_data { + u8 dialog_token; + enum scs_request_type request_type; + u8 up_bitmap; + u8 up_limit; + u32 stream_timeout; + u8 frame_classifier[48]; + size_t frame_classifier_len; + bool valid_config; +}; + /** * struct wpa_supplicant - Internal data for wpa_supplicant interface * @@ -1315,6 +1326,7 @@ struct wpa_supplicant { unsigned int multi_ap_ie:1; unsigned int multi_ap_backhaul:1; unsigned int multi_ap_fronthaul:1; + struct robust_av_data robust_av; }; @@ -1623,4 +1635,8 @@ int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s); void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s); +int wpas_send_mscs_req(struct wpa_supplicant *wpa_s); +void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av, + struct wpabuf *buf); + #endif /* WPA_SUPPLICANT_I_H */