From 834afad47e866071ae9e60552f64f25ab9068b48 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Wed, 29 Sep 2021 10:37:59 +0530 Subject: [PATCH] esp_wifi: Add support for MBO certification --- components/esp_wifi/include/esp_wifi_types.h | 22 +- components/esp_wifi/lib | 2 +- components/wpa_supplicant/CMakeLists.txt | 10 +- components/wpa_supplicant/Kconfig | 22 +- components/wpa_supplicant/component.mk | 6 + .../esp_supplicant/include/esp_mbo.h | 64 ++ .../esp_supplicant/include/esp_wnm.h | 28 +- .../esp_supplicant/src/esp_common.c | 292 +++++-- .../esp_supplicant/src/esp_common_i.h | 35 +- .../esp_supplicant/src/esp_scan.c | 49 +- .../esp_supplicant/src/esp_wifi_driver.h | 23 +- .../esp_supplicant/src/esp_wpa_main.c | 23 +- components/wpa_supplicant/src/common/bss.c | 34 +- components/wpa_supplicant/src/common/bss.h | 7 + .../src/common/ieee802_11_common.c | 36 + .../src/common/ieee802_11_common.h | 2 + .../src/common/ieee802_11_defs.h | 53 ++ components/wpa_supplicant/src/common/mbo.c | 799 ++++++++++++++++++ components/wpa_supplicant/src/common/rrm.c | 7 + .../wpa_supplicant/src/common/wnm_sta.c | 149 +++- .../wpa_supplicant/src/common/wnm_sta.h | 12 + .../wpa_supplicant/src/common/wpa_common.c | 1 - .../wpa_supplicant/src/common/wpa_common.h | 2 + .../src/common/wpa_supplicant_i.h | 61 +- .../wpa_supplicant/src/drivers/driver.h | 15 + examples/wifi/roaming/main/roaming_example.c | 35 + examples/wifi/roaming/sdkconfig.defaults | 1 + tools/ci/check_copyright_ignore.txt | 8 +- 28 files changed, 1605 insertions(+), 193 deletions(-) create mode 100644 components/wpa_supplicant/esp_supplicant/include/esp_mbo.h create mode 100644 components/wpa_supplicant/src/common/mbo.c diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index 503e8d7bb0..cee23f3faf 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -1,16 +1,8 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #ifndef __ESP_WIFI_TYPES_H__ @@ -80,6 +72,7 @@ typedef enum { WIFI_REASON_ASSOC_NOT_AUTHED = 9, WIFI_REASON_DISASSOC_PWRCAP_BAD = 10, WIFI_REASON_DISASSOC_SUPCHAN_BAD = 11, + WIFI_REASON_BSS_TRANSITION_DISASSOC = 12, WIFI_REASON_IE_INVALID = 13, WIFI_REASON_MIC_FAILURE = 14, WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, @@ -250,7 +243,8 @@ typedef struct { wifi_pmf_config_t pmf_cfg; /**< Configuration for Protected Management Frame. Will be advertized in RSN Capabilities in RSN IE. */ uint32_t rm_enabled:1; /**< Whether Radio Measurements are enabled for the connection */ uint32_t btm_enabled:1; /**< Whether BSS Transition Management is enabled for the connection */ - uint32_t reserved:30; /**< Reserved for future feature set */ + uint32_t mbo_enabled:1; /**< Whether MBO is enabled for the connection */ + uint32_t reserved:29; /**< Reserved for future feature set */ } wifi_sta_config_t; /** @brief Configuration data for ESP32 AP or STA. diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 4e1c7a8114..6f9d2a1185 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 4e1c7a8114fd03b9841f78a218f579799cb61a0a +Subproject commit 6f9d2a11850b9fc0d4fd4ce89c492129e06fd77c diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 282cd04169..3abc2bcab0 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -154,8 +154,13 @@ if(CONFIG_WPA_11KV_SUPPORT) else() set(roaming_src "") endif() +if(CONFIG_WPA_MBO_SUPPORT) + set(mbo_src "src/common/mbo.c") +else() + set(mbo_src "") +endif() -idf_component_register(SRCS "${srcs}" ${esp_srcs} "${tls_src}" "${roaming_src}" "${crypto_src}" +idf_component_register(SRCS "${srcs}" ${esp_srcs} "${tls_src}" "${roaming_src}" "${crypto_src}" "${mbo_src}" INCLUDE_DIRS include port/include esp_supplicant/include PRIV_INCLUDE_DIRS src src/utils esp_supplicant/src PRIV_REQUIRES mbedtls esp_timer) @@ -190,4 +195,7 @@ if(CONFIG_WPA_WPS_STRICT) target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_WPS_STRICT) endif() +if(CONFIG_WPA_MBO_SUPPORT) + target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_MBO) +endif() set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3) diff --git a/components/wpa_supplicant/Kconfig b/components/wpa_supplicant/Kconfig index 354ce26c2e..31c6931e45 100644 --- a/components/wpa_supplicant/Kconfig +++ b/components/wpa_supplicant/Kconfig @@ -59,12 +59,18 @@ menu "Supplicant" and on the radio environment. Current implementation adds beacon report, link measurement, neighbor report. - if WPA_11KV_SUPPORT - config WPA_SCAN_CACHE - bool "Keep scan results in cache" - default n - help - Keep scan results in cache, if not enabled, those - will be flushed immediately. - endif + menuconfig WPA_SCAN_CACHE + bool "Keep scan results in cache" + depends on WPA_11KV_SUPPORT + default n + help + Keep scan results in cache, if not enabled, those + will be flushed immediately. + + menuconfig WPA_MBO_SUPPORT + bool "Enable MBO support in supplicant" + depends on WPA_11KV_SUPPORT + default n + help + Select this option to enable WiFi Multiband operation certification support. endmenu diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk index 1d99db8da0..4f4609b7cc 100644 --- a/components/wpa_supplicant/component.mk +++ b/components/wpa_supplicant/component.mk @@ -70,6 +70,9 @@ ifneq ($(CONFIG_WPA_11KV_SUPPORT), y) esp_supplicant/src/esp_common.o \ esp_supplicant/src/esp_scan.o endif +ifneq ($(CONFIG_WPA_MBO_SUPPORT), y) + COMPONENT_OBJEXCLUDE += src/common/mbo.o +endif CFLAGS += -DCONFIG_SHA256 -DCONFIG_DPP -DCONFIG_IEEE80211W -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -DCONFIG_WNM -D__ets__ -Wno-strict-aliasing @@ -79,3 +82,6 @@ endif ifdef CONFIG_WPA_WPS_STRICT CFLAGS += -DCONFIG_WPS_STRICT endif +ifdef CONFIG_WPA_MBO_SUPPORT + CFLAGS += -DCONFIG_MBO +endif diff --git a/components/wpa_supplicant/esp_supplicant/include/esp_mbo.h b/components/wpa_supplicant/esp_supplicant/include/esp_mbo.h new file mode 100644 index 0000000000..4292213943 --- /dev/null +++ b/components/wpa_supplicant/esp_supplicant/include/esp_mbo.h @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_MBO_H +#define _ESP_MBO_H + +#include +#ifdef __cplusplus +extern "C" { +#endif + +/** + * enum non_pref_chan_reason: Reason for non preference of channel + */ +enum non_pref_chan_reason { + NON_PREF_CHAN_REASON_UNSPECIFIED = 0, + NON_PREF_CHAN_REASON_RSSI = 1, + NON_PREF_CHAN_REASON_EXT_INTERFERENCE = 2, + NON_PREF_CHAN_REASON_INT_INTERFERENCE = 3, +}; + +/** + * @brief Channel structure for non preferred channel + * + * @param reason: enum non_pref_chan_reason + * @param oper_class: operating class for the channel + * @param chan: channel number + * @param preference: channel preference + */ +struct non_pref_chan { + enum non_pref_chan_reason reason; + uint8_t oper_class; + uint8_t chan; + uint8_t preference; +}; + +/** + * @brief Array structure for non preferred channel struct + * + * @param non_pref_chan_num: channel count + * @param chan: array of non_pref_chan type + */ +struct non_pref_chan_s { + size_t non_pref_chan_num; + struct non_pref_chan chan[]; +}; + +/** + * @brief Update channel preference for MBO IE + * + * @param non_pref_chan: Non preference channel list + * + * @return + * - 0: success else failure + */ +int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/components/wpa_supplicant/esp_supplicant/include/esp_wnm.h b/components/wpa_supplicant/esp_supplicant/include/esp_wnm.h index a1dcfb655c..4301385d2c 100644 --- a/components/wpa_supplicant/esp_supplicant/include/esp_wnm.h +++ b/components/wpa_supplicant/esp_supplicant/include/esp_wnm.h @@ -1,17 +1,7 @@ -/** - * Copyright 2020 Espressif Systems (Shanghai) PTE LTD +/* + * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 */ #ifndef _ESP_WNM_H @@ -29,11 +19,13 @@ enum btm_query_reason { REASON_UNSPECIFIED = 0, REASON_FRAME_LOSS = 1, REASON_DELAY = 2, - REASON_QOS_CAPACITY = 3, - REASON_FIRST_ASSOC = 4, - REASON_LOAD_BALALNCE = 5, - REASON_BETTER_AP = 6, - REASON_CURRENT_DEAUTH = 7, + REASON_BANDWIDTH = 3, + REASON_LOAD_BALANCE = 4, + REASON_RSSI = 5, + REASON_RETRANSMISSIONS = 6, + REASON_INTERFERENCE = 7, + REASON_GRAY_ZONE = 8, + REASON_PREMIUM_AP = 9, }; /** diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_common.c b/components/wpa_supplicant/esp_supplicant/src/esp_common.c index a3ff7d73bc..22c60fcbaa 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_common.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_common.c @@ -1,17 +1,7 @@ -/** - * Copyright 2020 Espressif Systems (Shanghai) PTE LTD +/* + * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 */ #include "utils/includes.h" @@ -37,8 +27,8 @@ static void *s_supplicant_task_hdl = NULL; static void *s_supplicant_evt_queue = NULL; static void *s_supplicant_api_lock = NULL; -static int esp_handle_action_frm(u8 *frame, size_t len, - u8 *sender, u32 rssi, u8 channel) +static int handle_action_frm(u8 *frame, size_t len, + u8 *sender, u32 rssi, u8 channel) { struct ieee_mgmt_frame *frm = os_malloc(sizeof(struct ieee_mgmt_frame) + len); @@ -61,7 +51,7 @@ static int esp_handle_action_frm(u8 *frame, size_t len, return 0; } -static void esp_rx_rrm_frame(struct wpa_supplicant *wpa_s, u8 *sender, +static void handle_rrm_frame(struct wpa_supplicant *wpa_s, u8 *sender, u8 *payload, size_t len, u32 rssi) { if (payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) { @@ -78,7 +68,7 @@ static void esp_rx_rrm_frame(struct wpa_supplicant *wpa_s, u8 *sender, } } -static int esp_mgmt_rx_action(u8 *sender, u8 *payload, size_t len, u8 channel, u32 rssi) +static int mgmt_rx_action(u8 *sender, u8 *payload, size_t len, u8 channel, u32 rssi) { u8 category; u8 bssid[ETH_ALEN]; @@ -95,13 +85,13 @@ static int esp_mgmt_rx_action(u8 *sender, u8 *payload, size_t len, u8 channel, u if (category == WLAN_ACTION_WNM) { ieee802_11_rx_wnm_action(wpa_s, sender, payload, len); } else if (category == WLAN_ACTION_RADIO_MEASUREMENT) { - esp_rx_rrm_frame(wpa_s, sender, payload, len, rssi); + handle_rrm_frame(wpa_s, sender, payload, len, rssi); } return 0; } -static void esp_btm_rrm_task(void *pvParameters) +static void btm_rrm_task(void *pvParameters) { supplicant_event_t *evt; bool task_del = false; @@ -120,7 +110,7 @@ static void esp_btm_rrm_task(void *pvParameters) case SIG_SUPPLICANT_RX_ACTION: { struct ieee_mgmt_frame *frm = (struct ieee_mgmt_frame *)evt->data; - esp_mgmt_rx_action(frm->sender, frm->payload, frm->len, frm->channel, frm->rssi); + mgmt_rx_action(frm->sender, frm->payload, frm->len, frm->channel, frm->rssi); os_free(frm); break; } @@ -153,7 +143,7 @@ static void esp_btm_rrm_task(void *pvParameters) vTaskDelete(NULL); } -static void esp_clear_bssid_flag(struct wpa_supplicant *wpa_s) +static void clear_bssid_flag(struct wpa_supplicant *wpa_s) { wifi_config_t *config; @@ -175,7 +165,7 @@ static void esp_clear_bssid_flag(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "cleared bssid flag"); } -static void esp_register_action_frame(struct wpa_supplicant *wpa_s) +static void register_action_frame(struct wpa_supplicant *wpa_s) { wpa_s->type &= ~(1 << WLAN_FC_STYPE_ACTION); /* subtype is defined only for action frame */ @@ -193,8 +183,8 @@ static void esp_register_action_frame(struct wpa_supplicant *wpa_s) esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype); } -static void esp_supplicant_sta_conn_handler(void* arg, esp_event_base_t event_base, - int32_t event_id, void* event_data) +static void supplicant_sta_conn_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) { u8 bssid[ETH_ALEN]; u8 *ie; @@ -215,13 +205,13 @@ static void esp_supplicant_sta_conn_handler(void* arg, esp_event_base_t event_ba ieee802_11_parse_elems(wpa_s, ie, bss->ie_len); wpa_bss_flush(wpa_s); /* Register for action frames */ - esp_register_action_frame(wpa_s); + register_action_frame(wpa_s); /* clear set bssid flag */ - esp_clear_bssid_flag(wpa_s); + clear_bssid_flag(wpa_s); } -static void esp_supplicant_sta_disconn_handler(void* arg, esp_event_base_t event_base, - int32_t event_id, void* event_data) +static void supplicant_sta_disconn_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) { struct wpa_supplicant *wpa_s = &g_wpa_supp; wpas_rrm_reset(wpa_s); @@ -230,12 +220,49 @@ static void esp_supplicant_sta_disconn_handler(void* arg, esp_event_base_t event } } +static int ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender, + u32 rssi, u8 channel, u64 current_tsf) +{ + if (type == WLAN_FC_STYPE_BEACON || type == WLAN_FC_STYPE_PROBE_RESP) { + return esp_handle_beacon_probe(type, frame, len, sender, rssi, channel, current_tsf); + } else if (type == WLAN_FC_STYPE_ACTION) { + return handle_action_frm(frame, len, sender, rssi, channel); + } + + return -1; +} + +#ifdef CONFIG_MBO +static bool bss_profile_match(u8 *sender) +{ + /* Incase supplicant wants drivers to skip this BSS, return false */ + struct wpa_bss *bss = wpa_bss_get_bssid(&g_wpa_supp, sender); + if (!bss) { + return true; + } + const u8 *assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW); + if (assoc_disallow && assoc_disallow[1] >= 1) { + wpa_printf(MSG_DEBUG, + "skip - MBO association disallowed (reason %u)", assoc_disallow[2]); + return false; + } + + if (wpa_is_bss_tmp_disallowed(&g_wpa_supp, bss)) { + wpa_printf(MSG_DEBUG, + "skip - BSS is temporary disallowed"); + return false; + } + + return true; +} +#endif + void esp_supplicant_common_init(struct wpa_funcs *wpa_cb) { struct wpa_supplicant *wpa_s = &g_wpa_supp; s_supplicant_evt_queue = xQueueCreate(3, sizeof(supplicant_event_t)); - xTaskCreate(esp_btm_rrm_task, "btm_rrm_t", SUPPLICANT_TASK_STACK_SIZE, NULL, 2, s_supplicant_task_hdl); + xTaskCreate(btm_rrm_task, "btm_rrm_t", SUPPLICANT_TASK_STACK_SIZE, NULL, 2, s_supplicant_task_hdl); s_supplicant_api_lock = xSemaphoreCreateRecursiveMutex(); if (!s_supplicant_api_lock) { @@ -248,13 +275,22 @@ void esp_supplicant_common_init(struct wpa_funcs *wpa_cb) wpas_clear_beacon_rep_data(wpa_s); esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, - &esp_supplicant_sta_conn_handler, NULL); + &supplicant_sta_conn_handler, NULL); esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, - &esp_supplicant_sta_disconn_handler, NULL); + &supplicant_sta_disconn_handler, NULL); wpa_s->type = 0; wpa_s->subtype = 0; - wpa_cb->wpa_sta_rx_mgmt = esp_ieee80211_handle_rx_frm; + wpa_s->type |= (1 << WLAN_FC_STYPE_BEACON) | (1 << WLAN_FC_STYPE_PROBE_RESP); + esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype); + wpa_cb->wpa_sta_rx_mgmt = ieee80211_handle_rx_frm; + /* Matching is done only for MBO at the moment, this can be extended for other features*/ +#ifdef CONFIG_MBO + wpa_cb->wpa_sta_profile_match = bss_profile_match; + dl_list_init(&wpa_s->bss_tmp_disallowed); +#else + wpa_cb->wpa_sta_profile_match = NULL; +#endif } void esp_supplicant_common_deinit(void) @@ -268,28 +304,38 @@ void esp_supplicant_common_deinit(void) wpas_rrm_reset(wpa_s); wpas_clear_beacon_rep_data(wpa_s); esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, - &esp_supplicant_sta_conn_handler); + &supplicant_sta_conn_handler); esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, - &esp_supplicant_sta_disconn_handler); + &supplicant_sta_disconn_handler); } int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb, void *cb_ctx) { - struct wpa_supplicant *wpa_s = &g_wpa_supp; struct wpa_ssid_value wpa_ssid = {0}; struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal(); + os_memcpy(wpa_ssid.ssid, ssid->ssid, ssid->len); wpa_ssid.ssid_len = ssid->len; - return wpas_rrm_send_neighbor_rep_request(wpa_s, &wpa_ssid, 0, 0, cb, cb_ctx); + + return wpas_rrm_send_neighbor_rep_request(&g_wpa_supp, &wpa_ssid, 0, 0, cb, cb_ctx); } int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason, const char *btm_candidates, int cand_list) { - struct wpa_supplicant *wpa_s = &g_wpa_supp; - return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, btm_candidates, cand_list); + return wnm_send_bss_transition_mgmt_query(&g_wpa_supp, query_reason, btm_candidates, cand_list); +} + +int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan) +{ + int ret = wpas_mbo_update_non_pref_chan(&g_wpa_supp, non_pref_chan); + if (ret == 0) { + esp_set_assoc_ie(); + } + + return ret; } void wpa_supplicant_connect(struct wpa_supplicant *wpa_s, @@ -306,18 +352,25 @@ void wpa_supplicant_connect(struct wpa_supplicant *wpa_s, /* We only support roaming in same ESS, therefore only bssid setting is needed */ os_memcpy(config->sta.bssid, bss->bssid, ETH_ALEN); config->sta.bssid_set = 1; - esp_wifi_internal_issue_disconnect(WIFI_REASON_ROAMING); + /* supplicant connect will only be called in case of bss transition(roaming) */ + esp_wifi_internal_issue_disconnect(WIFI_REASON_BSS_TRANSITION_DISASSOC); esp_wifi_set_config(WIFI_IF_STA, config); os_free(config); esp_wifi_connect(); } -void esp_set_rm_enabled_ie(void) +static size_t get_rm_enabled_ie(uint8_t *ie, size_t len) { - uint8_t rmm_ie[5] = {0}; + uint8_t rrm_ie[7] = {0}; uint8_t rrm_ie_len = 5; - uint8_t *pos = rmm_ie; + uint8_t *pos = rrm_ie; + if (!esp_wifi_is_rm_enabled_internal(WIFI_IF_STA)) { + return 0; + } + + *pos++ = WLAN_EID_RRM_ENABLED_CAPABILITIES; + *pos++ = rrm_ie_len; *pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT; *pos |= WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE | @@ -326,10 +379,147 @@ void esp_set_rm_enabled_ie(void) #endif WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE; - /* set rm enabled IE if enabled in driver */ - if (esp_wifi_is_rm_enabled_internal(WIFI_IF_STA)) { - esp_wifi_set_appie_internal(WIFI_APPIE_RM_ENABLED_CAPS, rmm_ie, rrm_ie_len, 0); + os_memcpy(ie, rrm_ie, sizeof(rrm_ie)); + + return rrm_ie_len + 2; +} + +#ifdef CONFIG_MBO +static size_t get_mbo_oce_scan_ie(uint8_t *ie, size_t len) +{ + uint8_t mbo_ie[32] = {0}; + uint8_t mbo_ie_len = 32; + + /* Return if MBO IE is not enabled in driver */ + if (!esp_wifi_is_mbo_enabled_internal(WIFI_IF_STA)) { + return 0; } + + struct wpabuf *default_ies = NULL; + if (wpabuf_resize(&default_ies, 18) == 0) { + wpas_mbo_scan_ie(&g_wpa_supp, default_ies); + os_memcpy(mbo_ie, wpabuf_head_u8(default_ies), wpabuf_len(default_ies)); + mbo_ie_len = wpabuf_len(default_ies); + wpabuf_free(default_ies); + } + os_memcpy(ie, mbo_ie, mbo_ie_len); + return mbo_ie_len; +} + +static size_t get_mbo_oce_assoc_ie(uint8_t *ie, size_t len) +{ + uint8_t mbo_ie[32] = {0}; + uint8_t mbo_ie_len = 32; + + /* Return if MBO IE is not enabled in driver */ + if (!esp_wifi_is_mbo_enabled_internal(WIFI_IF_STA)) { + return 0; + } + + mbo_ie_len = wpas_mbo_ie(&g_wpa_supp, mbo_ie, mbo_ie_len, 0); + os_memcpy(ie, mbo_ie, mbo_ie_len); + + return mbo_ie_len; +} +#endif + +static uint8_t get_extended_caps_ie(uint8_t *ie, size_t len) +{ + uint8_t ext_caps_ie[5] = {0}; + uint8_t ext_caps_ie_len = 3; + uint8_t *pos = ext_caps_ie; + + if (!esp_wifi_is_btm_enabled_internal(WIFI_IF_STA)) { + return 0; + } + + *pos++ = WLAN_EID_EXT_CAPAB; + *pos++ = ext_caps_ie_len; + *pos++ = 0; + *pos++ = 0; +#define WLAN_EXT_CAPAB_BSS_TRANSITION BIT(3) + *pos |= WLAN_EXT_CAPAB_BSS_TRANSITION; +#undef WLAN_EXT_CAPAB_BSS_TRANSITION + os_memcpy(ie, ext_caps_ie, sizeof(ext_caps_ie)); + + return ext_caps_ie_len + 2; +} + + +static uint8_t get_operating_class_ie(uint8_t *ie, size_t len) +{ + uint8_t op_class_ie[4] = {0}; + uint8_t op_class_ie_len = 2; + uint8_t *pos = op_class_ie; + + *pos++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES; + *pos++ = op_class_ie_len; +#define OPER_CLASS 0x51 + /* Current Operating Class */ + *pos++ = OPER_CLASS; +#undef OPER_CLASS + *pos = 0; + os_memcpy(ie, op_class_ie, sizeof(op_class_ie)); + + return op_class_ie_len + 2; +} + +void esp_set_scan_ie(void) +{ +#define SCAN_IE_LEN 64 + uint8_t *ie, *pos; + size_t len = SCAN_IE_LEN, ie_len; + + ie = os_malloc(SCAN_IE_LEN); + if (!ie) { + wpa_printf(MSG_ERROR, "failed to allocate ie"); + return; + } + pos = ie; + ie_len = get_extended_caps_ie(pos, len); + pos += ie_len; + len -= ie_len; +#ifdef CONFIG_MBO + ie_len = get_mbo_oce_scan_ie(pos, len); + pos += ie_len; + len -= ie_len; +#endif + esp_wifi_unset_appie_internal(WIFI_APPIE_PROBEREQ); + esp_wifi_set_appie_internal(WIFI_APPIE_PROBEREQ, ie, SCAN_IE_LEN - len, 0); + os_free(ie); +#undef SCAN_IE_LEN +} + +void esp_set_assoc_ie(void) +{ +#define ASSOC_IE_LEN 128 + uint8_t *ie, *pos; + size_t len = ASSOC_IE_LEN, ie_len; + + ie = os_malloc(ASSOC_IE_LEN); + if (!ie) { + wpa_printf(MSG_ERROR, "failed to allocate ie"); + return; + } + pos = ie; + ie_len = get_extended_caps_ie(pos, len); + pos += ie_len; + len -= ie_len; + ie_len = get_operating_class_ie(pos, len); + pos += ie_len; + len -= ie_len; + ie_len = get_rm_enabled_ie(pos, len); + pos += ie_len; + len -= ie_len; +#ifdef CONFIG_MBO + ie_len = get_mbo_oce_assoc_ie(pos, len); + pos += ie_len; + len -= ie_len; +#endif + esp_wifi_unset_appie_internal(WIFI_APPIE_ASSOC_REQ); + esp_wifi_set_appie_internal(WIFI_APPIE_ASSOC_REQ, ie, ASSOC_IE_LEN - len, 0); + os_free(ie); +#undef ASSOC_IE_LEN } void esp_get_tx_power(uint8_t *tx_power) @@ -399,15 +589,3 @@ int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data) SUPPLICANT_API_UNLOCK(); return 0; } - -int esp_ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender, - u32 rssi, u8 channel, u64 current_tsf) -{ - if (type == WLAN_FC_STYPE_BEACON || type == WLAN_FC_STYPE_PROBE_RESP) { - return esp_handle_beacon_probe(type, frame, len, sender, rssi, channel, current_tsf); - } else if (type == WLAN_FC_STYPE_ACTION) { - return esp_handle_action_frm(frame, len, sender, rssi, channel); - } - - return -1; -} diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_common_i.h b/components/wpa_supplicant/esp_supplicant/src/esp_common_i.h index 4dfe7e3d06..12f61fbb03 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_common_i.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_common_i.h @@ -1,17 +1,7 @@ -/** - * Copyright 2020 Espressif Systems (Shanghai) PTE LTD +/* + * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 */ #ifndef ESP_COMMON_I_H @@ -47,23 +37,20 @@ enum SIG_SUPPLICANT { }; int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data); -int esp_ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender, - u32 rssi, u8 channel, u64 current_tsf); -void esp_set_rm_enabled_ie(void); void esp_get_tx_power(uint8_t *tx_power); void esp_supplicant_common_init(struct wpa_funcs *wpa_cb); void esp_supplicant_common_deinit(void); +void esp_set_scan_ie(void); +void esp_set_assoc_ie(void); #else #include "esp_rrm.h" #include "esp_wnm.h" +#include "esp_mbo.h" + +static inline void esp_set_scan_ie(void) { } +static inline void esp_set_assoc_ie(void) { } -static inline void esp_set_rm_enabled_ie(void) {} -static inline int esp_ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender, - u32 rssi, u8 channel, u64 current_tsf) -{ - return -1; -} int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb, void *cb_ctx) { @@ -77,5 +64,9 @@ int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason, return -1; } +int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan) +{ + return -1; +} #endif #endif diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_scan.c b/components/wpa_supplicant/esp_supplicant/src/esp_scan.c index 5c9fc41af2..bb632f3e58 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_scan.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_scan.c @@ -1,17 +1,7 @@ -/** - * Copyright 2020 Espressif Systems (Shanghai) PTE LTD +/* + * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 */ #include "utils/includes.h" @@ -32,8 +22,8 @@ extern struct wpa_supplicant g_wpa_supp; -static void esp_scan_done_event_handler(void* arg, esp_event_base_t event_base, - int32_t event_id, void* event_data) +static void scan_done_event_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) { struct wpa_supplicant *wpa_s = &g_wpa_supp; @@ -46,7 +36,7 @@ static void esp_scan_done_event_handler(void* arg, esp_event_base_t event_base, esp_supplicant_post_evt(SIG_SUPPLICANT_SCAN_DONE, 0); } -static void esp_supp_handle_wnm_scan_done(struct wpa_supplicant *wpa_s) +static void handle_wnm_scan_done(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss = wpa_bss_get_next_bss(wpa_s, wpa_s->current_bss); @@ -64,7 +54,7 @@ static void esp_supp_handle_wnm_scan_done(struct wpa_supplicant *wpa_s) } } -static void esp_supp_scan_done_cleanup(struct wpa_supplicant *wpa_s) +static void scan_done_cleanup(struct wpa_supplicant *wpa_s) { uint16_t number = 1; wifi_ap_record_t ap_records; @@ -84,10 +74,10 @@ void esp_supplicant_handle_scan_done_evt(void) if (wpa_s->scan_reason == REASON_RRM_BEACON_REPORT) { wpas_beacon_rep_scan_process(wpa_s, wpa_s->scan_start_tsf); } else if (wpa_s->scan_reason == REASON_WNM_BSS_TRANS_REQ) { - esp_supp_handle_wnm_scan_done(wpa_s); + handle_wnm_scan_done(wpa_s); } if (wpa_s->scanning) { - esp_supp_scan_done_cleanup(wpa_s); + scan_done_cleanup(wpa_s); } wpa_bss_update_end(wpa_s); #ifndef SCAN_CACHE_SUPPORTED @@ -101,7 +91,7 @@ void esp_scan_init(struct wpa_supplicant *wpa_s) wpa_bss_init(wpa_s); wpa_s->last_scan_res = NULL; esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_SCAN_DONE, - &esp_scan_done_event_handler, NULL); + &scan_done_event_handler, NULL); } void esp_scan_deinit(struct wpa_supplicant *wpa_s) @@ -110,7 +100,7 @@ void esp_scan_deinit(struct wpa_supplicant *wpa_s) os_free(wpa_s->last_scan_res); wpa_s->last_scan_res = NULL; esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_SCAN_DONE, - &esp_scan_done_event_handler); + &scan_done_event_handler); } int esp_handle_beacon_probe(u8 type, u8 *frame, size_t len, u8 *sender, @@ -158,10 +148,7 @@ int esp_handle_beacon_probe(u8 type, u8 *frame, size_t len, u8 *sender, res->level = rssi; os_memcpy(res->tsf_bssid, wpa_s->tsf_bssid, ETH_ALEN); res->parent_tsf = current_tsf - wpa_s->scan_start_tsf; - if (type == WLAN_FC_STYPE_PROBE_RESP) - res->ie_len = len; - else if (type == WLAN_FC_STYPE_BEACON) - res->beacon_ie_len = len; + res->ie_len = len; ptr += sizeof(struct wpa_scan_res); @@ -173,8 +160,8 @@ int esp_handle_beacon_probe(u8 type, u8 *frame, size_t len, u8 *sender, return 0; } -static int esp_issue_scan(struct wpa_supplicant *wpa_s, - struct wpa_driver_scan_params *scan_params) +static int issue_scan(struct wpa_supplicant *wpa_s, + struct wpa_driver_scan_params *scan_params) { wifi_scan_config_t *params = NULL; int ret = 0; @@ -203,9 +190,13 @@ static int esp_issue_scan(struct wpa_supplicant *wpa_s, goto cleanup; } os_memcpy(params->ssid, scan_params->ssids[0].ssid, scan_params->ssids[0].ssid_len); - params->scan_type = WIFI_SCAN_TYPE_ACTIVE; } else + + if (scan_params->mode == BEACON_REPORT_MODE_PASSIVE) { params->scan_type = WIFI_SCAN_TYPE_PASSIVE; + } else { + params->scan_type = WIFI_SCAN_TYPE_ACTIVE; + } if (scan_params->bssid) { params->bssid = os_zalloc(ETH_ALEN); @@ -260,7 +251,7 @@ cleanup: int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) { - return esp_issue_scan(wpa_s, params); + return issue_scan(wpa_s, params); } void wpa_scan_results_free(struct wpa_scan_results *res) diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h index 1c134c2371..f4950dfb49 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -1,16 +1,8 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #ifndef _ESP_WIFI_DRIVER_H_ #define _ESP_WIFI_DRIVER_H_ @@ -57,8 +49,7 @@ typedef enum { /* wifi_appie_t is in rom code and can't be changed anymore, use wifi_appie_ram_t for new app IEs */ typedef enum { - WIFI_APPIE_RM_ENABLED_CAPS = WIFI_APPIE_MAX, - WIFI_APPIE_RAM_MAX, + WIFI_APPIE_RAM_MAX = WIFI_APPIE_MAX, } wifi_appie_ram_t; enum { @@ -137,6 +128,7 @@ struct wpa_funcs { int (*wpa3_parse_sae_msg)(uint8_t *buf, size_t len, uint32_t type, uint16_t status); int (*wpa_sta_rx_mgmt)(u8 type, u8 *frame, size_t len, u8 *sender, u32 rssi, u8 channel, u64 current_tsf); void (*wpa_config_done)(void); + bool (*wpa_sta_profile_match)(u8 *bssid); }; struct wpa2_funcs { @@ -266,5 +258,6 @@ esp_err_t esp_wifi_action_tx_req(uint8_t type, uint8_t channel, uint32_t wait_time_ms, const wifi_action_tx_req_t *req); esp_err_t esp_wifi_remain_on_channel(uint8_t ifx, uint8_t type, uint8_t channel, uint32_t wait_time_ms, wifi_action_rx_cb_t rx_cb); +bool esp_wifi_is_mbo_enabled_internal(uint8_t if_index); #endif /* _ESP_WIFI_DRIVER_H_ */ diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c index 480ba919ff..aedac29583 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c @@ -1,16 +1,8 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "utils/includes.h" #include "utils/common.h" @@ -123,6 +115,8 @@ bool wpa_attach(void) if(ret) { ret = (esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID) == ESP_OK); } + esp_set_scan_ie(); + esp_set_assoc_ie(); return ret; } @@ -185,7 +179,7 @@ void wpa_sta_connect(uint8_t *bssid) void wpa_config_done(void) { /* used in future for setting scan and assoc IEs */ - esp_set_rm_enabled_ie(); + esp_set_assoc_ie(); } int wpa_parse_wpa_ie_wrapper(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t *data) @@ -230,6 +224,7 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code) static inline void esp_supplicant_common_init(struct wpa_funcs *wpa_cb) { wpa_cb->wpa_sta_rx_mgmt = NULL; + wpa_cb->wpa_sta_profile_match = NULL; } static inline void esp_supplicant_common_deinit(void) { diff --git a/components/wpa_supplicant/src/common/bss.c b/components/wpa_supplicant/src/common/bss.c index 559119916e..3e200d5b26 100644 --- a/components/wpa_supplicant/src/common/bss.c +++ b/components/wpa_supplicant/src/common/bss.c @@ -132,8 +132,9 @@ static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) return !is_zero_ether_addr(bss->bssid) && wpa_s->current_bss->bssid && (os_memcmp(bss->bssid, wpa_s->current_bss->bssid, ETH_ALEN) == 0); -#endif +#else return 0; +#endif } static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s) @@ -198,7 +199,7 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s, bss->ssid_len = ssid_len; bss->ie_len = res->ie_len; bss->beacon_ie_len = res->beacon_ie_len; - os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len); + os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len); dl_list_add_tail(&wpa_s->bss, &bss->list); dl_list_add_tail(&wpa_s->bss_id, &bss->list_id); @@ -238,7 +239,7 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, dl_list_del(&bss->list); if (bss->ie_len + bss->beacon_ie_len >= res->ie_len + res->beacon_ie_len) { - os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len); + os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len); bss->ie_len = res->ie_len; bss->beacon_ie_len = res->beacon_ie_len; } else { @@ -258,7 +259,7 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, if (wpa_s->current_bss == bss) wpa_s->current_bss = nbss; bss = nbss; - os_memcpy(bss + 1, res + 1, + os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len); bss->ie_len = res->ie_len; bss->beacon_ie_len = res->beacon_ie_len; @@ -471,6 +472,31 @@ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie) return get_ie((const u8 *) (bss + 1), bss->ie_len, ie); } +/** + * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry + * @bss: BSS table entry + * @vendor_type: Vendor type (four octets starting the IE payload) + * Returns: Pointer to the information element (id field) or %NULL if not found + * + * This function returns the first matching information element in the BSS + * entry. + */ +const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type) +{ + const u8 *ies; + const struct element *elem; + + ies = wpa_bss_ie_ptr(bss); + + for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, bss->ie_len) { + if (elem->datalen >= 4 && + vendor_type == WPA_GET_BE32(elem->data)) + return &elem->id; + } + + return NULL; +} + int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab) { return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB), diff --git a/components/wpa_supplicant/src/common/bss.h b/components/wpa_supplicant/src/common/bss.h index c34941a7b0..9e6f47e205 100644 --- a/components/wpa_supplicant/src/common/bss.h +++ b/components/wpa_supplicant/src/common/bss.h @@ -58,8 +58,14 @@ struct wpa_bss { size_t beacon_ie_len; /* followed by ie_len octets of IEs */ /* followed by beacon_ie_len octets of IEs */ + u8 ies[]; }; +static inline const u8 * wpa_bss_ie_ptr(const struct wpa_bss *bss) +{ + return bss->ies; +} + void wpa_bss_update_start(struct wpa_supplicant *wpa_s); void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res, @@ -75,6 +81,7 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid); const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie); +const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type); int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab); struct wpa_bss * wpa_bss_get_next_bss(struct wpa_supplicant *wpa_s, struct wpa_bss *prev_bss); diff --git a/components/wpa_supplicant/src/common/ieee802_11_common.c b/components/wpa_supplicant/src/common/ieee802_11_common.c index ca159c1bed..14f426aafa 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_common.c +++ b/components/wpa_supplicant/src/common/ieee802_11_common.c @@ -37,6 +37,42 @@ const u8 * get_ie(const u8 *ies, size_t len, u8 eid) return NULL; } +const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type) +{ + const struct element *elem; + + for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) { + if (elem->datalen >= 4 && + vendor_type == WPA_GET_BE32(elem->data)) + return &elem->id; + } + + return NULL; +} + +size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len) +{ + /* + * MBO IE requires 6 bytes without the attributes: EID (1), length (1), + * OUI (3), OUI type (1). + */ + if (len < 6 + attr_len) { + wpa_printf(MSG_DEBUG, + "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu", + len, attr_len); + return 0; + } + + *buf++ = WLAN_EID_VENDOR_SPECIFIC; + *buf++ = attr_len + 4; + WPA_PUT_BE24(buf, OUI_WFA); + buf += 3; + *buf++ = MBO_OUI_TYPE; + os_memcpy(buf, attr, attr_len); + + return 6 + attr_len; +} + int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, size_t nei_rep_len) { diff --git a/components/wpa_supplicant/src/common/ieee802_11_common.h b/components/wpa_supplicant/src/common/ieee802_11_common.h index fa23faeca5..0786d3e68c 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_common.h +++ b/components/wpa_supplicant/src/common/ieee802_11_common.h @@ -39,5 +39,7 @@ int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, const u8 * get_ie(const u8 *ies, size_t len, u8 eid); int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t len); int ieee802_11_ext_capab(const u8 *ie, unsigned int capab); +const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type); +size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len); u8 get_operating_class(u8 chan, int sec_channel); #endif /* IEEE802_11_COMMON_H */ diff --git a/components/wpa_supplicant/src/common/ieee802_11_defs.h b/components/wpa_supplicant/src/common/ieee802_11_defs.h index e0fef0b684..d4cab57655 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_defs.h +++ b/components/wpa_supplicant/src/common/ieee802_11_defs.h @@ -212,6 +212,7 @@ #define WLAN_EID_FAST_BSS_TRANSITION 55 #define WLAN_EID_TIMEOUT_INTERVAL 56 #define WLAN_EID_RIC_DATA 57 +#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59 #define WLAN_EID_HT_OPERATION 61 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 #define WLAN_EID_WAPI 68 @@ -536,6 +537,13 @@ struct ieee80211_ht_operation { /* 2 - Reserved */ #define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3 +#define MBO_IE_VENDOR_TYPE 0x506f9a16 +#define OSEN_IE_VENDOR_TYPE 0x506f9a12 +#define MBO_OUI_TYPE 22 +#define OCE_STA BIT(0) +#define OCE_STA_CFON BIT(1) +#define OCE_AP BIT(2) + /* * WMM Information Element (used in (Re)Association Request frames; may also be * used in Beacon frames) @@ -622,6 +630,45 @@ enum wmm_ac { WMM_AC_NUM = 4 }; +/* MBO v0.0_r19, 4.2: MBO Attributes */ +/* Table 4-5: MBO Attributes */ +/* OCE v0.0.10, Table 4-3: OCE Attributes */ +enum mbo_attr_id { + MBO_ATTR_ID_AP_CAPA_IND = 1, + MBO_ATTR_ID_NON_PREF_CHAN_REPORT = 2, + MBO_ATTR_ID_CELL_DATA_CAPA = 3, + MBO_ATTR_ID_ASSOC_DISALLOW = 4, + MBO_ATTR_ID_CELL_DATA_PREF = 5, + MBO_ATTR_ID_TRANSITION_REASON = 6, + MBO_ATTR_ID_TRANSITION_REJECT_REASON = 7, + MBO_ATTR_ID_ASSOC_RETRY_DELAY = 8, + OCE_ATTR_ID_CAPA_IND = 101, + OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT = 102, + OCE_ATTR_ID_REDUCED_WAN_METRICS = 103, + OCE_ATTR_ID_RNR_COMPLETENESS = 104, +}; + +/* MBO v0.0_r19, 4.2.1: MBO AP Capability Indication Attribute */ +/* Table 4-7: MBO AP Capability Indication Field Values */ +#define MBO_AP_CAPA_CELL_AWARE BIT(6) + +/* MBO v0.0_r19, 4.2.2: Non-preferred Channel Report Attribute */ +/* Table 4-10: Reason Code Field Values */ +enum mbo_non_pref_chan_reason { + MBO_NON_PREF_CHAN_REASON_UNSPECIFIED = 0, + MBO_NON_PREF_CHAN_REASON_RSSI = 1, + MBO_NON_PREF_CHAN_REASON_EXT_INTERFERENCE = 2, + MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE = 3, +}; + +/* MBO v0.0_r19, 4.2.3: Cellular Data Capabilities Attribute */ +/* Table 4-13: Cellular Data Connectivity Field */ +enum mbo_cellular_capa { + MBO_CELL_CAPA_AVAILABLE = 1, + MBO_CELL_CAPA_NOT_AVAILABLE = 2, + MBO_CELL_CAPA_NOT_SUPPORTED = 3, +}; + /* MBO v0.0_r19, 4.2.7: Transition Rejection Reason Code Attribute */ /* Table 4-21: Transition Rejection Reason Code Field Values */ enum mbo_transition_reject_reason { @@ -634,6 +681,12 @@ enum mbo_transition_reject_reason { MBO_TRANSITION_REJECT_REASON_SERVICES = 6, }; +/* OCE v0.0.10, 4.2.1: OCE Capability Indication Attribute */ +#define OCE_RELEASE 1 +#define OCE_RELEASE_MASK (BIT(0) | BIT(1) | BIT(2)) +#define OCE_IS_STA_CFON BIT(3) +#define OCE_IS_NON_OCE_AP_PRESENT BIT(4) + /* IEEE 802.11v - WNM Action field values */ enum wnm_action { WNM_EVENT_REQ = 0, diff --git a/components/wpa_supplicant/src/common/mbo.c b/components/wpa_supplicant/src/common/mbo.c new file mode 100644 index 0000000000..0441d8017e --- /dev/null +++ b/components/wpa_supplicant/src/common/mbo.c @@ -0,0 +1,799 @@ +/* + * wpa_supplicant - MBO + * + * Copyright(c) 2015 Intel Deutschland GmbH + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * 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/ieee802_11_defs.h" +#include "rsn_supp/wpa.h" +#include "wpa_supplicant_i.h" +#include "bss.h" +#include "scan.h" +#include "ieee802_11_common.h" + +#ifdef ESP_SUPPLICANT +#include "esp_timer.h" +#include "esp_mbo.h" + +extern struct wpa_supplicant g_wpa_supp; + +#endif + +/* type + length + oui + oui type */ +#define MBO_IE_HEADER 6 + +#ifndef ESP_SUPPLICANT +static int wpas_mbo_validate_non_pref_chan(u8 oper_class, u8 chan, u8 reason) +{ + if (reason > MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE) + return -1; + + /* Only checking the validity of the channel and oper_class */ + if (ieee80211_chan_to_freq(NULL, oper_class, chan) == -1) + return -1; + + return 0; +} +#endif + +const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr) +{ + const u8 *mbo; + u8 ie_len = mbo_ie[1]; + + if (ie_len < MBO_IE_HEADER - 2) + return NULL; + mbo = mbo_ie + MBO_IE_HEADER; + + return get_ie(mbo, 2 + ie_len - MBO_IE_HEADER, attr); +} + + +const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len, + enum mbo_attr_id attr) +{ + const u8 *mbo_ie; + + mbo_ie = get_vendor_ie(ies, ies_len, MBO_IE_VENDOR_TYPE); + if (!mbo_ie) + return NULL; + + return mbo_attr_from_mbo_ie(mbo_ie, attr); +} + + +const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr) +{ + const u8 *mbo, *end; + + if (!bss) + return NULL; + + mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE); + if (!mbo) + return NULL; + + end = mbo + 2 + mbo[1]; + mbo += MBO_IE_HEADER; + + return get_ie(mbo, end - mbo, attr); +} + + +void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss +#ifndef ESP_SUPPLICANT + , struct wpa_ssid *ssid +#endif + ) +{ + const u8 *rsne, *mbo, *oce; + struct wpa_ie_data ie; + + wpa_s->disable_mbo_oce = 0; + if (!bss) + return; + mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND); + oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND); + if (!mbo && !oce) + return; + if (oce && oce[1] >= 1 && (oce[2] & OCE_IS_STA_CFON)) + return; /* STA-CFON is not required to enable PMF */ + rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN); + if (!rsne || wpa_parse_wpa_ie(rsne, 2 + rsne[1], &ie) < 0) + return; /* AP is not using RSN */ + + if (!(ie.capabilities & WPA_CAPABILITY_MFPC)) + wpa_s->disable_mbo_oce = 1; /* AP uses RSN without PMF */ +#ifdef ESP_SUPPLICANT + if (!esp_wifi_sta_pmf_enabled()) +#else + if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) +#endif + wpa_s->disable_mbo_oce = 1; /* STA uses RSN without PMF */ + if (wpa_s->disable_mbo_oce) + wpa_printf(MSG_INFO, + "MBO: Disable MBO/OCE due to misbehaving AP not having enabled PMF"); +} + +static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s, + struct wpabuf *mbo, + u8 start, u8 end) +{ + u8 i; + + wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].oper_class); + + for (i = start; i < end; i++) + wpabuf_put_u8(mbo, wpa_s->non_pref_chan[i].chan); + + wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].preference); + wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].reason); +} + + +static void wpas_mbo_non_pref_chan_attr_hdr(struct wpabuf *mbo, size_t size) +{ + wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT); + wpabuf_put_u8(mbo, size); /* Length */ +} + + +static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s, + struct wpabuf *mbo, u8 start, u8 end) +{ + size_t size = end - start + 3; + + if (size + 2 > wpabuf_tailroom(mbo)) + return; + + wpas_mbo_non_pref_chan_attr_hdr(mbo, size); + wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end); +} + + +static void wpas_mbo_non_pref_chan_subelem_hdr(struct wpabuf *mbo, u8 len) +{ + wpabuf_put_u8(mbo, WLAN_EID_VENDOR_SPECIFIC); + wpabuf_put_u8(mbo, len); /* Length */ + wpabuf_put_be24(mbo, OUI_WFA); + wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT); +} + + +static void wpas_mbo_non_pref_chan_subelement(struct wpa_supplicant *wpa_s, + struct wpabuf *mbo, u8 start, + u8 end) +{ + size_t size = end - start + 7; + + if (size + 2 > wpabuf_tailroom(mbo)) + return; + + wpas_mbo_non_pref_chan_subelem_hdr(mbo, size); + wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end); +} + + +static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s, + struct wpabuf *mbo, int subelement) +{ + u8 i, start = 0; + struct wpa_mbo_non_pref_channel *start_pref; + + if (!wpa_s->non_pref_chan || !wpa_s->non_pref_chan_num) { + if (subelement) + wpas_mbo_non_pref_chan_subelem_hdr(mbo, 4); + else + wpas_mbo_non_pref_chan_attr_hdr(mbo, 0); + return; + } + start_pref = &wpa_s->non_pref_chan[0]; + + for (i = 1; i <= wpa_s->non_pref_chan_num; i++) { + struct wpa_mbo_non_pref_channel *non_pref = NULL; + + if (i < wpa_s->non_pref_chan_num) + non_pref = &wpa_s->non_pref_chan[i]; + if (!non_pref || + non_pref->oper_class != start_pref->oper_class || + non_pref->reason != start_pref->reason || + non_pref->preference != start_pref->preference) { + if (subelement) + wpas_mbo_non_pref_chan_subelement(wpa_s, mbo, + start, i); + else + wpas_mbo_non_pref_chan_attr(wpa_s, mbo, start, + i); + + if (!non_pref) + return; + + start = i; + start_pref = non_pref; + } + } +} + +int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len, + int add_oce_capa) +{ + struct wpabuf *mbo; + int res; + + if (len < MBO_IE_HEADER + 3 + 7 + + ((wpa_s->enable_oce & OCE_STA) ? 3 : 0)) + return 0; + + /* Leave room for the MBO IE header */ + mbo = wpabuf_alloc(len - MBO_IE_HEADER); + if (!mbo) + return 0; + + /* Add non-preferred channels attribute */ + wpas_mbo_non_pref_chan_attrs(wpa_s, mbo, 0); + + /* + * Send cellular capabilities attribute even if AP does not advertise + * cellular capabilities. + */ + wpabuf_put_u8(mbo, MBO_ATTR_ID_CELL_DATA_CAPA); + wpabuf_put_u8(mbo, 1); +#ifdef ESP_SUPPLICANT + wpabuf_put_u8(mbo, MBO_CELL_CAPA_NOT_SUPPORTED); +#else + wpabuf_put_u8(mbo, wpa_s->mbo_cell_capa); +#endif + + /* Add OCE capability indication attribute if OCE is enabled */ + if ((wpa_s->enable_oce & OCE_STA) && add_oce_capa) { + wpabuf_put_u8(mbo, OCE_ATTR_ID_CAPA_IND); + wpabuf_put_u8(mbo, 1); + wpabuf_put_u8(mbo, OCE_RELEASE); + } + + res = mbo_add_ie(buf, len, wpabuf_head_u8(mbo), wpabuf_len(mbo)); + if (!res) + wpa_printf(MSG_ERROR, "Failed to add MBO/OCE IE"); + + wpabuf_free(mbo); + return res; +} + + +static void wpas_mbo_send_wnm_notification(struct wpa_supplicant *wpa_s, + const u8 *data, size_t len) +{ + struct wpabuf *buf; + int res; + + /* + * Send WNM-Notification Request frame only in case of a change in + * non-preferred channels list during association, if the AP supports + * MBO. + */ + if (!wpa_s->current_bss || + !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE)) + return; + + buf = wpabuf_alloc(4 + len); + if (!buf) + return; + + wpabuf_put_u8(buf, WLAN_ACTION_WNM); + wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ); + wpa_s->mbo_wnm_token++; + if (wpa_s->mbo_wnm_token == 0) + wpa_s->mbo_wnm_token++; + wpabuf_put_u8(buf, wpa_s->mbo_wnm_token); + wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); /* Type */ + + wpabuf_put_data(buf, data, len); + + res = wpa_drv_send_action(wpa_s, 0, 0, + wpabuf_head(buf), wpabuf_len(buf), 0); + if (res < 0) + wpa_printf(MSG_DEBUG, + "Failed to send WNM-Notification Request frame with non-preferred channel list"); + + wpabuf_free(buf); +} + + +static void wpas_mbo_non_pref_chan_changed(struct wpa_supplicant *wpa_s) +{ + struct wpabuf *buf; + + buf = wpabuf_alloc(512); + if (!buf) + return; + + wpas_mbo_non_pref_chan_attrs(wpa_s, buf, 1); + wpas_mbo_send_wnm_notification(wpa_s, wpabuf_head_u8(buf), + wpabuf_len(buf)); + wpabuf_free(buf); +} + + +#ifndef ESP_SUPPLICANT +static int wpa_non_pref_chan_is_eq(struct wpa_mbo_non_pref_channel *a, + struct wpa_mbo_non_pref_channel *b) +{ + return a->oper_class == b->oper_class && a->chan == b->chan; +} + +/* + * wpa_non_pref_chan_cmp - Compare two channels for sorting + * + * In MBO IE non-preferred channel subelement we can put many channels in an + * attribute if they are in the same operating class and have the same + * preference and reason. To make it easy for the functions that build + * the IE attributes and WNM Request subelements, save the channels sorted + * by their oper_class and reason. + */ +static int wpa_non_pref_chan_cmp(const void *_a, const void *_b) +{ + const struct wpa_mbo_non_pref_channel *a = _a, *b = _b; + + if (a->oper_class != b->oper_class) + return (int) a->oper_class - (int) b->oper_class; + if (a->reason != b->reason) + return (int) a->reason - (int) b->reason; + return (int) a->preference - (int) b->preference; +} + + +int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s, + const char *non_pref_chan) +{ + char *cmd, *token, *context = NULL; + struct wpa_mbo_non_pref_channel *chans = NULL, *tmp_chans; + size_t num = 0, size = 0; + unsigned i; + + wpa_printf(MSG_DEBUG, "MBO: Update non-preferred channels, non_pref_chan=%s", + non_pref_chan ? non_pref_chan : "N/A"); + + /* + * The shortest channel configuration is 7 characters - 3 colons and + * 4 values. + */ + if (!non_pref_chan || os_strlen(non_pref_chan) < 7) + goto update; + + cmd = os_strdup(non_pref_chan); + if (!cmd) + return -1; + + while ((token = str_token(cmd, " ", &context))) { + struct wpa_mbo_non_pref_channel *chan; + int ret; + unsigned int _oper_class; + unsigned int _chan; + unsigned int _preference; + unsigned int _reason; + + if (num == size) { + size = size ? size * 2 : 1; + tmp_chans = os_realloc_array(chans, size, + sizeof(*chans)); + if (!tmp_chans) { + wpa_printf(MSG_ERROR, + "Couldn't reallocate non_pref_chan"); + goto fail; + } + chans = tmp_chans; + } + + chan = &chans[num]; + + ret = sscanf(token, "%u:%u:%u:%u", &_oper_class, + &_chan, &_preference, &_reason); + if (ret != 4 || + _oper_class > 255 || _chan > 255 || + _preference > 255 || _reason > 65535 ) { + wpa_printf(MSG_ERROR, "Invalid non-pref chan input %s", + token); + goto fail; + } + chan->oper_class = _oper_class; + chan->chan = _chan; + chan->preference = _preference; + chan->reason = _reason; + + if (wpas_mbo_validate_non_pref_chan(chan->oper_class, + chan->chan, chan->reason)) { + wpa_printf(MSG_ERROR, + "Invalid non_pref_chan: oper class %d chan %d reason %d", + chan->oper_class, chan->chan, chan->reason); + goto fail; + } + + for (i = 0; i < num; i++) + if (wpa_non_pref_chan_is_eq(chan, &chans[i])) + break; + if (i != num) { + wpa_printf(MSG_ERROR, + "oper class %d chan %d is duplicated", + chan->oper_class, chan->chan); + goto fail; + } + + num++; + } + + os_free(cmd); + + if (chans) { + qsort(chans, num, sizeof(struct wpa_mbo_non_pref_channel), + wpa_non_pref_chan_cmp); + } + +update: + os_free(wpa_s->non_pref_chan); + wpa_s->non_pref_chan = chans; + wpa_s->non_pref_chan_num = num; + wpas_mbo_non_pref_chan_changed(wpa_s); + + return 0; + +fail: + os_free(chans); + os_free(cmd); + return -1; +} +#else +int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s, + struct non_pref_chan_s *non_pref_chan) +{ + struct wpa_mbo_non_pref_channel *chans = NULL; + /* + * The shortest channel configuration is 7 characters - 3 colons and + * 4 values. + */ + if (!non_pref_chan) + goto update; + + + chans = os_malloc(sizeof(struct wpa_mbo_non_pref_channel) * non_pref_chan->non_pref_chan_num); + os_memcpy(chans, non_pref_chan->chan, sizeof(struct wpa_mbo_non_pref_channel) * non_pref_chan->non_pref_chan_num); + +update: + os_free(wpa_s->non_pref_chan); + wpa_s->non_pref_chan = chans; + if (non_pref_chan) + wpa_s->non_pref_chan_num = non_pref_chan->non_pref_chan_num; + else + wpa_s->non_pref_chan_num = 0; + wpas_mbo_non_pref_chan_changed(wpa_s); + + return 0; +} + +#endif + +void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie) +{ + u8 *len; + + wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); + len = wpabuf_put(ie, 1); + + wpabuf_put_be24(ie, OUI_WFA); + wpabuf_put_u8(ie, MBO_OUI_TYPE); + + wpabuf_put_u8(ie, MBO_ATTR_ID_CELL_DATA_CAPA); + wpabuf_put_u8(ie, 1); +#ifdef ESP_SUPPLICANT + wpabuf_put_u8(ie, MBO_CELL_CAPA_NOT_SUPPORTED); +#else + wpabuf_put_u8(ie, wpa_s->mbo_cell_capa); +#endif + if (wpa_s->enable_oce & OCE_STA) { + wpabuf_put_u8(ie, OCE_ATTR_ID_CAPA_IND); + wpabuf_put_u8(ie, 1); + wpabuf_put_u8(ie, OCE_RELEASE); + } + *len = (u8 *) wpabuf_put(ie, 0) - len - 1; +} + +#ifdef ESP_SUPPLICANT + +static struct +wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s, + const u8 *bssid) +{ + struct wpa_bss_tmp_disallowed *bss; + + dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed, + struct wpa_bss_tmp_disallowed, list) { + if (os_memcmp(bssid, bss->bssid, ETH_ALEN) == 0) + return bss; + } + + return NULL; +} + +static void wpa_bss_tmp_disallow_timeout(void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = &g_wpa_supp; + struct wpa_bss_tmp_disallowed *tmp, *bss = timeout_ctx; + + /* Make sure the bss is not already freed */ + dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed, + struct wpa_bss_tmp_disallowed, list) { + if (bss == tmp) { + dl_list_del(&tmp->list); + esp_timer_stop(bss->blacklist_timer); + esp_timer_delete(bss->blacklist_timer); + os_free(tmp); + break; + } + } +} + +void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid, + unsigned int sec, int rssi_threshold) +{ + struct wpa_bss_tmp_disallowed *bss; + + bss = wpas_get_disallowed_bss(wpa_s, bssid); + if (bss) { + esp_timer_stop(bss->blacklist_timer); + goto finish; + } + + bss = os_malloc(sizeof(*bss)); + esp_timer_create_args_t blacklist_timer_create = { + .callback = &wpa_bss_tmp_disallow_timeout, + .arg = bss, + .dispatch_method = ESP_TIMER_TASK, + .name = "blacklist_timeout_timer" + }; + esp_timer_create(&blacklist_timer_create, &(bss->blacklist_timer)); + + if (!bss) { + wpa_printf(MSG_DEBUG, + "Failed to allocate memory for temp disallow BSS"); + return; + } + + os_memcpy(bss->bssid, bssid, ETH_ALEN); + dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list); + +finish: + esp_timer_start_once(bss->blacklist_timer, (sec + 1) * 1e6); +} + +int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) +{ + struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev; + + dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed, + struct wpa_bss_tmp_disallowed, list) { + if (os_memcmp(bss->bssid, tmp->bssid, ETH_ALEN) == 0) { + disallowed = tmp; + break; + } + } + if (!disallowed) + return 0; + + return 1; +} +#endif + +void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie, + size_t len) +{ + const u8 *pos, *cell_pref = NULL; + u8 id, elen; + u16 disallowed_sec = 0; + + if (len <= 4 || WPA_GET_BE24(mbo_ie) != OUI_WFA || + mbo_ie[3] != MBO_OUI_TYPE) + return; + + pos = mbo_ie + 4; + len -= 4; + + while (len >= 2) { + id = *pos++; + elen = *pos++; + len -= 2; + + if (elen > len) + goto fail; + + switch (id) { + case MBO_ATTR_ID_CELL_DATA_PREF: + if (elen != 1) + goto fail; + +#ifndef ESP_SUPPLICANT + if (wpa_s->mbo_cell_capa == + MBO_CELL_CAPA_AVAILABLE) + cell_pref = pos; + else +#endif + wpa_printf(MSG_DEBUG, + "MBO: Station does not support Cellular data connection"); + break; + case MBO_ATTR_ID_TRANSITION_REASON: + if (elen != 1) + goto fail; + + wpa_s->wnm_mbo_trans_reason_present = 1; + wpa_s->wnm_mbo_transition_reason = *pos; + break; + case MBO_ATTR_ID_ASSOC_RETRY_DELAY: + if (elen != 2) + goto fail; + + if (wpa_s->wnm_mode & + WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { + wpa_printf(MSG_DEBUG, + "MBO: Unexpected association retry delay, BSS is terminating"); + goto fail; + } else if (wpa_s->wnm_mode & + WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { + disallowed_sec = WPA_GET_LE16(pos); + wpa_printf(MSG_DEBUG, + "MBO: Association retry delay: %u", + disallowed_sec); + } else { + wpa_printf(MSG_DEBUG, + "MBO: Association retry delay attribute not in disassoc imminent mode"); + } + + break; + case MBO_ATTR_ID_AP_CAPA_IND: + case MBO_ATTR_ID_NON_PREF_CHAN_REPORT: + case MBO_ATTR_ID_CELL_DATA_CAPA: + case MBO_ATTR_ID_ASSOC_DISALLOW: + case MBO_ATTR_ID_TRANSITION_REJECT_REASON: + wpa_printf(MSG_DEBUG, + "MBO: Attribute %d should not be included in BTM Request frame", + id); + break; + default: + wpa_printf(MSG_DEBUG, "MBO: Unknown attribute id %u", + id); + return; + } + + pos += elen; + len -= elen; + } + + if (cell_pref) + wpa_printf(MSG_INFO, "preference=%u", + *cell_pref); + + if (wpa_s->wnm_mbo_trans_reason_present) + wpa_printf(MSG_INFO, "reason=%u", + wpa_s->wnm_mbo_transition_reason); + + if (disallowed_sec && wpa_s->current_bss) + wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid, + disallowed_sec, 0); + + return; +fail: + wpa_printf(MSG_DEBUG, "MBO IE parsing failed (id=%u len=%u left=%zu)", + id, elen, len); +} + + +size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos, + size_t len, + enum mbo_transition_reject_reason reason) +{ + u8 reject_attr[3]; + + reject_attr[0] = MBO_ATTR_ID_TRANSITION_REJECT_REASON; + reject_attr[1] = 1; + reject_attr[2] = reason; + + return mbo_add_ie(pos, len, reject_attr, sizeof(reject_attr)); +} + + +#ifndef ESP_SUPPLICANT +void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa) +{ + u8 cell_capa[7]; + + if (wpa_s->mbo_cell_capa == mbo_cell_capa) { + wpa_printf(MSG_DEBUG, + "MBO: Cellular capability already set to %u", + mbo_cell_capa); + return; + } + + wpa_s->mbo_cell_capa = mbo_cell_capa; + + cell_capa[0] = WLAN_EID_VENDOR_SPECIFIC; + cell_capa[1] = 5; /* Length */ + WPA_PUT_BE24(cell_capa + 2, OUI_WFA); + cell_capa[5] = MBO_ATTR_ID_CELL_DATA_CAPA; + cell_capa[6] = mbo_cell_capa; + + wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7); + wpa_supplicant_set_default_scan_ies(wpa_s); +} + + +struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, u32 mbo_subtypes) +{ + struct wpabuf *anqp_buf; + u8 *len_pos; + u8 i; + + if (!wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) { + wpa_printf(MSG_INFO, "MBO: " MACSTR + " does not support MBO - cannot request MBO ANQP elements from it", + MAC2STR(bss->bssid)); + return NULL; + } + + /* Allocate size for the maximum case - all MBO subtypes are set */ + anqp_buf = wpabuf_alloc(9 + MAX_MBO_ANQP_SUBTYPE); + if (!anqp_buf) + return NULL; + + len_pos = gas_anqp_add_element(anqp_buf, ANQP_VENDOR_SPECIFIC); + wpabuf_put_be24(anqp_buf, OUI_WFA); + wpabuf_put_u8(anqp_buf, MBO_ANQP_OUI_TYPE); + + wpabuf_put_u8(anqp_buf, MBO_ANQP_SUBTYPE_QUERY_LIST); + + /* The first valid MBO subtype is 1 */ + for (i = 1; i <= MAX_MBO_ANQP_SUBTYPE; i++) { + if (mbo_subtypes & BIT(i)) + wpabuf_put_u8(anqp_buf, i); + } + + gas_anqp_set_element_len(anqp_buf, len_pos); + + return anqp_buf; +} + + +void mbo_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, const u8 *sa, + const u8 *data, size_t slen) +{ + const u8 *pos = data; + u8 subtype; + + if (slen < 1) + return; + + subtype = *pos++; + slen--; + + switch (subtype) { + case MBO_ANQP_SUBTYPE_CELL_CONN_PREF: + if (slen < 1) + break; + wpa_msg(wpa_s, MSG_INFO, RX_MBO_ANQP MACSTR + " cell_conn_pref=%u", MAC2STR(sa), *pos); + break; + default: + wpa_printf(MSG_DEBUG, "MBO: Unsupported ANQP subtype %u", + subtype); + break; + } +} +#endif diff --git a/components/wpa_supplicant/src/common/rrm.c b/components/wpa_supplicant/src/common/rrm.c index e3fcc3cb10..8fae4c3eb4 100644 --- a/components/wpa_supplicant/src/common/rrm.c +++ b/components/wpa_supplicant/src/common/rrm.c @@ -851,8 +851,15 @@ wpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s, goto out; } params->channel = req->channel; +#ifdef ESP_SUPPLICANT + if (params->channel == 0xff) { + /* set it to zero */ + params->channel = 0; + } +#endif params->duration = le_to_host16(req->duration); params->duration_mandatory = duration_mandatory; + params->mode = req->mode; if (!params->duration) { wpa_printf(MSG_DEBUG, "Beacon request: Duration is 0"); ret = -1; diff --git a/components/wpa_supplicant/src/common/wnm_sta.c b/components/wpa_supplicant/src/common/wnm_sta.c index 84c25c8fe3..33a58b7351 100644 --- a/components/wpa_supplicant/src/common/wnm_sta.c +++ b/components/wpa_supplicant/src/common/wnm_sta.c @@ -191,6 +191,109 @@ static struct wpa_bss * get_first_acceptable(struct wpa_supplicant *wpa_s) return NULL; } + +#ifdef CONFIG_MBO +static struct wpa_bss * +get_mbo_transition_candidate(struct wpa_supplicant *wpa_s, + enum mbo_transition_reject_reason *reason) +{ + struct wpa_bss *target = NULL; + struct wpa_bss_trans_info params; + struct wpa_bss_candidate_info *info = NULL; + struct neighbor_report *nei = wpa_s->wnm_neighbor_report_elements; + u8 *first_candidate_bssid = NULL, *pos; + unsigned int i; + + params.mbo_transition_reason = wpa_s->wnm_mbo_transition_reason; + params.n_candidates = 0; + params.bssid = os_calloc(wpa_s->wnm_num_neighbor_report, ETH_ALEN); + if (!params.bssid) + return NULL; + + pos = params.bssid; + for (i = 0; i < wpa_s->wnm_num_neighbor_report; nei++, i++) { + if (nei->is_first) + first_candidate_bssid = nei->bssid; + if (!nei->acceptable) + continue; + os_memcpy(pos, nei->bssid, ETH_ALEN); + pos += ETH_ALEN; + params.n_candidates++; + } + + if (!params.n_candidates) + goto end; + +#ifndef ESP_SUPPLICANT + info = wpa_drv_get_bss_trans_status(wpa_s, ¶ms); +#endif + if (!info) { + /* If failed to get candidate BSS transition status from driver, + * get the first acceptable candidate from wpa_supplicant. + */ + target = wpa_bss_get_bssid(wpa_s, params.bssid); + goto end; + } + + /* Get the first acceptable candidate from driver */ + for (i = 0; i < info->num; i++) { + if (info->candidates[i].is_accept) { + target = wpa_bss_get_bssid(wpa_s, + info->candidates[i].bssid); + goto end; + } + } + + /* If Disassociation Imminent is set and driver rejects all the + * candidate select first acceptable candidate which has + * rssi > disassoc_imminent_rssi_threshold + */ + if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { + for (i = 0; i < info->num; i++) { + target = wpa_bss_get_bssid(wpa_s, + info->candidates[i].bssid); +#ifndef ESP_SUPPLICANT + if (target && + (target->level < + wpa_s->conf->disassoc_imminent_rssi_threshold)) + continue; +#else + if (target) + continue; +#endif + goto end; + } + } + + /* While sending BTM reject use reason code of the first candidate + * received in BTM request frame + */ + if (reason) { + for (i = 0; i < info->num; i++) { + if (first_candidate_bssid && + os_memcmp(first_candidate_bssid, + info->candidates[i].bssid, ETH_ALEN) == 0) + { + *reason = info->candidates[i].reject_reason; + break; + } + } + } + + target = NULL; + +end: + os_free(params.bssid); + if (info) { + os_free(info->candidates); + os_free(info); + } + return target; +} +#endif /* CONFIG_MBO */ + + + /* basic function to match candidate profile with current bss */ bool wpa_scan_res_match(struct wpa_supplicant *wpa_s, struct wpa_bss *current_bss, @@ -294,7 +397,14 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, nei->acceptable = 1; } +#ifdef CONFIG_MBO + if (wpa_s->wnm_mbo_trans_reason_present) + target = get_mbo_transition_candidate(wpa_s, reason); + else + target = get_first_acceptable(wpa_s); +#else /* CONFIG_MBO */ target = get_first_acceptable(wpa_s); +#endif /* CONFIG_MBO */ if (target) { wpa_printf(MSG_DEBUG, @@ -506,6 +616,27 @@ static void wnm_send_bss_transition_mgmt_resp( if (status == WNM_BSS_TM_ACCEPT) wnm_add_cand_list(wpa_s, &buf); +#ifdef CONFIG_MBO + if (status != WNM_BSS_TM_ACCEPT && + wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE)) { + u8 mbo[10]; + size_t ret; + + ret = wpas_mbo_ie_bss_trans_reject(wpa_s, mbo, sizeof(mbo), + reason); + if (ret) { + if (wpabuf_resize(&buf, ret) < 0) { + wpabuf_free(buf); + wpa_printf(MSG_DEBUG, + "WNM: Failed to allocate memory for MBO IE"); + return; + } + + wpabuf_put_data(buf, mbo, ret); + } + } +#endif /* CONFIG_MBO */ + res = wpa_drv_send_action(wpa_s, 0, 0, wpabuf_head_u8(buf), wpabuf_len(buf), 0); if (res < 0) { @@ -692,8 +823,11 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, { unsigned int beacon_int; u8 valid_int; +#ifdef CONFIG_MBO + const u8 *vendor; +#endif /* CONFIG_MBO */ - if (wpa_s->disable_btm) + if (wpa_s->disable_mbo_oce || wpa_s->disable_btm) return; if (end - pos < 5) @@ -721,6 +855,19 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_s->wnm_dialog_token, wpa_s->wnm_mode, wpa_s->wnm_dissoc_timer, valid_int); +#if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS) + if (wpa_s->reject_btm_req_reason) { + wpa_printf(MSG_INFO, + "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d", + wpa_s->reject_btm_req_reason); + wnm_send_bss_transition_mgmt_resp( + wpa_s, wpa_s->wnm_dialog_token, + wpa_s->reject_btm_req_reason, + MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL); + return; + } +#endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */ + pos += 5; if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { diff --git a/components/wpa_supplicant/src/common/wnm_sta.h b/components/wpa_supplicant/src/common/wnm_sta.h index e513e1a586..c0c1535dba 100644 --- a/components/wpa_supplicant/src/common/wnm_sta.h +++ b/components/wpa_supplicant/src/common/wnm_sta.h @@ -44,6 +44,9 @@ struct neighbor_report { unsigned int bearing_present:1; unsigned int bss_term_present:1; unsigned int acceptable:1; +#ifdef CONFIG_MBO + unsigned int is_first:1; +#endif /* CONFIG_MBO */ struct measurement_pilot *meas_pilot; struct multiple_bssid *mul_bssid; int freq; @@ -56,6 +59,13 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, u8 *sender, u8 *payload, size_t len); +void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie, + size_t len); + +size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos, + size_t len, + enum mbo_transition_reject_reason reason); + int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, u8 query_reason, const char *btm_candidates, @@ -66,5 +76,7 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail); void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, char *ssid, int after_new_scan); +int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss); #endif /* WNM_STA_H */ diff --git a/components/wpa_supplicant/src/common/wpa_common.c b/components/wpa_supplicant/src/common/wpa_common.c index 6dd71891a3..9100517576 100644 --- a/components/wpa_supplicant/src/common/wpa_common.c +++ b/components/wpa_supplicant/src/common/wpa_common.c @@ -362,7 +362,6 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, return 0; } - /** * wpa_eapol_key_mic - Calculate EAPOL-Key MIC * @key: EAPOL-Key Key Confirmation Key (KCK) diff --git a/components/wpa_supplicant/src/common/wpa_common.h b/components/wpa_supplicant/src/common/wpa_common.h index 90ca0616e6..bb277e9779 100644 --- a/components/wpa_supplicant/src/common/wpa_common.h +++ b/components/wpa_supplicant/src/common/wpa_common.h @@ -324,6 +324,8 @@ const char * wpa_cipher_txt(int cipher); int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, struct wpa_ie_data *data); +int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, + struct wpa_ie_data *data); int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, u8 *mic); diff --git a/components/wpa_supplicant/src/common/wpa_supplicant_i.h b/components/wpa_supplicant/src/common/wpa_supplicant_i.h index f3c07a9a41..acf5e8aae4 100644 --- a/components/wpa_supplicant/src/common/wpa_supplicant_i.h +++ b/components/wpa_supplicant/src/common/wpa_supplicant_i.h @@ -41,6 +41,16 @@ struct rrm_data { u8 dst_addr[ETH_ALEN]; }; +struct wpa_bss_tmp_disallowed { + struct dl_list list; + u8 bssid[ETH_ALEN]; +#ifndef ESP_SUPPLICANT + int rssi_threshold; +#else + esp_timer_handle_t blacklist_timer; +#endif +}; + #define SSID_MAX_LEN 32 struct beacon_rep_data { u8 token; @@ -61,6 +71,7 @@ enum scan_trigger_reason { struct wpa_supplicant { int disable_btm; + unsigned int disable_mbo_oce; /* rrm ie */ uint8_t rrm_ie[5]; u8 extend_caps[8]; @@ -101,10 +112,58 @@ struct wpa_supplicant { u8 wnm_bss_termination_duration[12]; struct neighbor_report *wnm_neighbor_report_elements; struct os_reltime wnm_cand_valid_until; +#ifdef CONFIG_MBO + unsigned int wnm_mbo_trans_reason_present:1; + u8 wnm_mbo_transition_reason; + /* Multiband operation non-preferred channel */ + struct wpa_mbo_non_pref_channel { + enum mbo_non_pref_chan_reason reason; + u8 oper_class; + u8 chan; + u8 preference; + } *non_pref_chan; + size_t non_pref_chan_num; + u8 mbo_wnm_token; + /** + * enable_oce - Enable OCE if it is enabled by user and device also + * supports OCE. + * User can enable OCE with wpa_config's 'oce' parameter as follows - + * - Set BIT(0) to enable OCE in non-AP STA mode. + * - Set BIT(1) to enable OCE in STA-CFON mode. + */ + u8 enable_oce; + struct dl_list bss_tmp_disallowed; +#endif /* CONFIG_MBO */ #endif /* CONFIG_WNM */ struct rrm_data rrm; struct beacon_rep_data beacon_rep_data; struct os_reltime beacon_rep_scan; }; -#endif +struct non_pref_chan_s; + +/* MBO functions */ +int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len, + int add_oce_capa); +const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr); +const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr); +const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len, + enum mbo_attr_id attr); +void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie); +void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie, + size_t len); +size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos, + size_t len, + enum mbo_transition_reject_reason reason); +void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa); +struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, u32 mbo_subtypes); +void mbo_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, const u8 *sa, + const u8 *data, size_t slen); +void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s); + +int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s, + struct non_pref_chan_s *non_pref_chan); + +#endif /* WPA_SUPPLICANT_I_H */ diff --git a/components/wpa_supplicant/src/drivers/driver.h b/components/wpa_supplicant/src/drivers/driver.h index 759e5b629d..22bf5978b9 100644 --- a/components/wpa_supplicant/src/drivers/driver.h +++ b/components/wpa_supplicant/src/drivers/driver.h @@ -143,6 +143,7 @@ struct wpa_driver_scan_params { u16 duration; unsigned int duration_mandatory; + u8 mode; }; /** @@ -174,6 +175,20 @@ struct scan_info { u8 scan_start_tsf_bssid[ETH_ALEN]; } scan_info; +struct wpa_bss_trans_info { + u8 mbo_transition_reason; + u8 n_candidates; + u8 *bssid; +}; + +struct wpa_bss_candidate_info { + u8 num; + struct candidate_list { + u8 bssid[ETH_ALEN]; + u8 is_accept; + u32 reject_reason; + } *candidates; +}; /* driver_common.c */ void wpa_scan_results_free(struct wpa_scan_results *res); diff --git a/examples/wifi/roaming/main/roaming_example.c b/examples/wifi/roaming/main/roaming_example.c index f136c2b49c..7532d8d4da 100644 --- a/examples/wifi/roaming/main/roaming_example.c +++ b/examples/wifi/roaming/main/roaming_example.c @@ -6,6 +6,7 @@ #include "esp_wifi.h" #include "esp_wnm.h" #include "esp_rrm.h" +#include "esp_mbo.h" #include "esp_event.h" #include "esp_log.h" #include "esp_system.h" @@ -40,6 +41,7 @@ static void event_handler(void* arg, esp_event_base_t event_base, esp_wifi_connect(); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { wifi_event_sta_disconnected_t *disconn = event_data; + ESP_LOGI(TAG, "station got disconnected reason=%d", disconn->reason); if (disconn->reason == WIFI_REASON_ROAMING) { ESP_LOGI(TAG, "station roaming, do nothing"); } else { @@ -323,6 +325,37 @@ static void esp_bss_rssi_low_handler(void* arg, esp_event_base_t event_base, } #endif +#if 0 +/* Example code to update channel preference in MBO */ +static void clear_chan_preference() +{ + esp_mbo_update_non_pref_chan(NULL); +} + +static void update_chan_preference(void) +{ + struct non_pref_chan_s *chans = malloc(sizeof(struct non_pref_chan_s) + 2 * sizeof(struct non_pref_chan)); + chans->non_pref_chan_num = 2; + + /* first */ + struct non_pref_chan *chan = &chans->chan[0]; + chan->reason = NON_PREF_CHAN_REASON_UNSPECIFIED; + chan->oper_class = 0x51; + chan->chan = 1; + chan->preference = 0; + + /* second */ + chan = &chans->chan[1]; + chan->reason = NON_PREF_CHAN_REASON_UNSPECIFIED; + chan->oper_class = 0x51; + chan->chan = 11; + chan->preference = 1; + + esp_mbo_update_non_pref_chan(chans); + free(chans); +} +#endif + static void initialise_wifi(void) { ESP_ERROR_CHECK(esp_netif_init()); @@ -348,6 +381,8 @@ static void initialise_wifi(void) .password = EXAMPLE_WIFI_PASSWORD, .rm_enabled =1, .btm_enabled =1, + .mbo_enabled =1, + .pmf_cfg.capable = 1, }, }; diff --git a/examples/wifi/roaming/sdkconfig.defaults b/examples/wifi/roaming/sdkconfig.defaults index 8e1ae374a1..9154040732 100644 --- a/examples/wifi/roaming/sdkconfig.defaults +++ b/examples/wifi/roaming/sdkconfig.defaults @@ -1,2 +1,3 @@ CONFIG_WPA_11KV_SUPPORT=y CONFIG_WPA_SCAN_CACHE=y +CONFIG_WPA_MBO_SUPPORT=y diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index 167af07dca..dc79ad963e 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -1229,7 +1229,6 @@ components/esp_wifi/include/esp_wifi.h components/esp_wifi/include/esp_wifi_crypto_types.h components/esp_wifi/include/esp_wifi_default.h components/esp_wifi/include/esp_wifi_netif.h -components/esp_wifi/include/esp_wifi_types.h components/esp_wifi/include/smartconfig_ack.h components/esp_wifi/src/coexist.c components/esp_wifi/src/lib_printf.c @@ -2997,24 +2996,18 @@ components/wifi_provisioning/src/wifi_provisioning_priv.h components/wifi_provisioning/src/wifi_scan.c components/wpa_supplicant/esp_supplicant/include/esp_dpp.h components/wpa_supplicant/esp_supplicant/include/esp_rrm.h -components/wpa_supplicant/esp_supplicant/include/esp_wnm.h components/wpa_supplicant/esp_supplicant/include/esp_wpa.h components/wpa_supplicant/esp_supplicant/include/esp_wpa2.h components/wpa_supplicant/esp_supplicant/include/esp_wps.h -components/wpa_supplicant/esp_supplicant/src/esp_common.c -components/wpa_supplicant/esp_supplicant/src/esp_common_i.h components/wpa_supplicant/esp_supplicant/src/esp_dpp.c components/wpa_supplicant/esp_supplicant/src/esp_dpp_i.h components/wpa_supplicant/esp_supplicant/src/esp_hostap.c components/wpa_supplicant/esp_supplicant/src/esp_hostap.h -components/wpa_supplicant/esp_supplicant/src/esp_scan.c components/wpa_supplicant/esp_supplicant/src/esp_scan_i.h -components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h components/wpa_supplicant/esp_supplicant/src/esp_wpa2.c components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c components/wpa_supplicant/esp_supplicant/src/esp_wpa3_i.h components/wpa_supplicant/esp_supplicant/src/esp_wpa_err.h -components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.c components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.h components/wpa_supplicant/esp_supplicant/src/esp_wps.c @@ -3045,6 +3038,7 @@ components/wpa_supplicant/src/common/eapol_common.h components/wpa_supplicant/src/common/ieee802_11_common.c components/wpa_supplicant/src/common/ieee802_11_common.h components/wpa_supplicant/src/common/ieee802_11_defs.h +components/wpa_supplicant/src/common/mbo.c components/wpa_supplicant/src/common/rrm.c components/wpa_supplicant/src/common/rrm.h components/wpa_supplicant/src/common/sae.c