From c4f592679bc4a8af33b1006b587cf0be88966ce8 Mon Sep 17 00:00:00 2001 From: Sajia Date: Tue, 1 Apr 2025 12:00:03 +0530 Subject: [PATCH] feat(wifi): Enable bss max idle support on all chips - Fix issues in Max Idle period negotiation and protected keep alive - Add BSS Max Idle config in SoftAP config and create a feature flag - Add a unit test case to test both STA and SoftAP implementation --- .../esp_rom/esp32c2/ld/esp32c2.rom.eco4.ld | 2 +- .../esp_rom/esp32c5/ld/esp32c5.rom.pp.ld | 2 +- .../esp_rom/esp32c61/ld/esp32c61.rom.pp.ld | 2 +- components/esp_wifi/Kconfig | 16 +- .../include/esp_private/esp_wifi_he_private.h | 17 +- components/esp_wifi/include/esp_wifi.h | 10 +- .../esp_wifi/include/esp_wifi_types_generic.h | 11 + components/esp_wifi/lib | 2 +- .../wifi_connect/main/test_bss_max_idle.c | 242 ++++++++++++++++++ .../test_apps/wifi_connect/sdkconfig.defaults | 3 +- .../softAP/main/softap_example_main.c | 6 + 11 files changed, 288 insertions(+), 25 deletions(-) create mode 100644 components/esp_wifi/test_apps/wifi_connect/main/test_bss_max_idle.c diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.eco4.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.eco4.ld index 21ed0cb284..d35efbeca4 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.eco4.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.eco4.ld @@ -92,7 +92,7 @@ ieee80211_deauth_construct = 0x40002040; ieee80211_disassoc_construct = 0x40002044; //ieee80211_add_xrates = 0x40002058; //ieee80211_assoc_req_construct = 0x40002060; -ieee80211_assoc_resp_construct = 0x40002064; +//ieee80211_assoc_resp_construct = 0x40002064; //ieee80211_timer_process = 0x4000208c; cnx_coexist_timeout = 0x40002090; //sta_recv_mgmt = 0x40002094; diff --git a/components/esp_rom/esp32c5/ld/esp32c5.rom.pp.ld b/components/esp_rom/esp32c5/ld/esp32c5.rom.pp.ld index c162dc27f9..9030c954eb 100644 --- a/components/esp_rom/esp32c5/ld/esp32c5.rom.pp.ld +++ b/components/esp_rom/esp32c5/ld/esp32c5.rom.pp.ld @@ -209,7 +209,7 @@ ppDisableQueue = 0x40000ed4; ppCalVHTDeliNum = 0x40000ed8; ppCalTxVHTSMPDULength = 0x40000edc; ppCheckTxRTS = 0x40000ee0; -ppProcessLifeTime = 0x40000ee4; +/*ppProcessLifeTime = 0x40000ee4;*/ ppProcTxCallback = 0x40000ee8; ppCalPreFecPaddingFactor = 0x40000eec; ppCalDeliNum = 0x40000ef0; diff --git a/components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld b/components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld index 8ab490f7e9..d23d8cb19f 100644 --- a/components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld +++ b/components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld @@ -214,7 +214,7 @@ ppMapWaitTxq = 0x40000e44; ppProcessWaitingQueue = 0x40000e48; ppDisableQueue = 0x40000e4c; ppCheckTxRTS = 0x40000e50; -ppProcessLifeTime = 0x40000e54; +/*ppProcessLifeTime = 0x40000e54;*/ ppProcTxCallback = 0x40000e58; ppCalPreFecPaddingFactor = 0x40000e5c; ppCalDeliNum = 0x40000e60; diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index 836294228c..eded761a34 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -363,14 +363,24 @@ menu "Wi-Fi" during this period, the time will be refreshed. If the time is up, but the station still has packets to receive or send, the time will also be refreshed. unit: milliseconds. + config ESP_WIFI_BSS_MAX_IDLE_SUPPORT + bool "Enable bss max idle support" + default y if (SOC_WIFI_HE_SUPPORT || ESP_WIFI_WNM_SUPPORT) + help + Enables bss max idle support for Station and SoftAP. BSS max idle period enables an SoftAP to indicate + a time period during which the AP does not disassociate a STA due to nonreceipt of frames from the STA. + For station, max idle period is default 10 (1000TUs) and can be set through + ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME. For softap, bss max idle parameters will be set through + bss_max_idle_cfg in wifi_ap_config_t. + config ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME int "Maximum keep alive time" range 10 60 default 10 help - Only for station in WIFI_PS_MIN_MODEM or WIFI_PS_MAX_MODEM. If no packet has been - sent within ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME, a null data packet will be sent - to maintain the connection with the AP. unit: seconds. + Only for station. If no packet has been sent within ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME, a null data + packet will be sent to maintain the connection with the AP. If ESP_WIFI_BSS_MAX_IDLE_SUPPORT is set, + it will be sent as bss max idle period in association request. unit: seconds. config ESP_WIFI_SLP_DEFAULT_WAIT_BROADCAST_DATA_TIME int "Minimum wait broadcast data time" diff --git a/components/esp_wifi/include/esp_private/esp_wifi_he_private.h b/components/esp_wifi/include/esp_private/esp_wifi_he_private.h index 1247415e3e..9e437720af 100644 --- a/components/esp_wifi/include/esp_private/esp_wifi_he_private.h +++ b/components/esp_wifi/include/esp_private/esp_wifi_he_private.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -165,21 +165,6 @@ esp_err_t esp_wifi_get_tx_tb_statistics(esp_wifi_aci_t aci, esp_test_tx_tb_stati */ esp_err_t esp_wifi_softap_add_color_change_announcement(uint8_t color); -/** -* @brief Add bss max idle ie -* -* @attention This API should be called after esp_wifi_start(). -* -* @param[in] bss_max_idle_enable enable bss max idle -* @param[in] bss_max_idle_period_secs bss max idle period, unit seconds -* @param[in] protected_keep_alive using protected/unprotected frame to keep alive -* -* @return -* - ESP_OK: succeed -* - others: failed -*/ -esp_err_t esp_wifi_softap_set_bss_max_idle(bool bss_max_idle_enable, uint16_t bss_max_idle_period_secs, bool protected_keep_alive); - /** * @brief Reset MU EDCA Timer * diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index 7d6e80529b..6801aa9497 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -278,6 +278,12 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs; #define WIFI_TX_HETB_QUEUE_NUM 1 #endif +#if CONFIG_ESP_WIFI_BSS_MAX_IDLE_SUPPORT +#define WIFI_ENABLE_BSS_MAX_IDLE (1<<8) +#else +#define WIFI_ENABLE_BSS_MAX_IDLE 0 +#endif + #define CONFIG_FEATURE_WPA3_SAE_BIT (1<<0) #define CONFIG_FEATURE_CACHE_TX_BUF_BIT (1<<1) #define CONFIG_FEATURE_FTM_INITIATOR_BIT (1<<2) @@ -286,6 +292,7 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs; #define CONFIG_FEATURE_GMAC_BIT (1<<5) #define CONFIG_FEATURE_11R_BIT (1<<6) #define CONFIG_FEATURE_WIFI_ENT_BIT (1<<7) +#define CONFIG_FEATURE_BSS_MAX_IDLE_BIT (1<<8) /* Set additional WiFi features and capabilities */ #define WIFI_FEATURE_CAPS (WIFI_ENABLE_WPA3_SAE | \ @@ -295,7 +302,8 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs; WIFI_ENABLE_GCMP | \ WIFI_ENABLE_GMAC | \ WIFI_ENABLE_11R | \ - WIFI_ENABLE_ENTERPRISE) + WIFI_ENABLE_ENTERPRISE | \ + WIFI_ENABLE_BSS_MAX_IDLE) #define WIFI_INIT_CONFIG_DEFAULT() { \ .osi_funcs = &g_wifi_osi_funcs, \ diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index aed87cb5f2..b0c24eec6d 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -17,6 +17,8 @@ extern "C" { #endif +#define WIFI_AP_DEFAULT_MAX_IDLE_PERIOD 292 /**< Default timeout for SoftAP BSS Max Idle. Unit: 1000TUs >**/ + /** * @brief Wi-Fi mode type */ @@ -507,6 +509,14 @@ typedef enum { WPA3_SAE_PK_MODE_DISABLED = 2, } wifi_sae_pk_mode_t; +/** + * @brief Configuration structure for BSS max idle + */ +typedef struct { + uint16_t period; /**< Sets BSS Max idle period (1 Unit = 1000TUs OR 1.024 Seconds). If there are no frames for this period from a STA, SoftAP will disassociate due to inactivity. Setting it to 0 disables the feature */ + bool protected_keep_alive; /**< Requires clients to use protected keep alive frames for BSS Max Idle period */ +} wifi_bss_max_idle_config_t; + /** * @brief Soft-AP configuration settings for the device */ @@ -527,6 +537,7 @@ typedef struct { wifi_sae_pwe_method_t sae_pwe_h2e; /**< Configuration for SAE PWE derivation method */ uint8_t transition_disable; /**< Whether to enable transition disable feature */ uint8_t sae_ext; /**< Enable SAE EXT feature. SOC_GCMP_SUPPORT is required for this feature. */ + wifi_bss_max_idle_config_t bss_max_idle_cfg; /**< Configuration for bss max idle, effective if CONFIG_WIFI_BSS_MAX_IDLE_SUPPORT is enabled */ } wifi_ap_config_t; #define SAE_H2E_IDENTIFIER_LEN 32 /**< Length of the password identifier for H2E */ diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 3e289f371e..d152ee7b81 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 3e289f371e35a2c71f613a6664dfffb841b5543b +Subproject commit d152ee7b81ac7073c5dce0d2a44bfbe4aa9dd2ae diff --git a/components/esp_wifi/test_apps/wifi_connect/main/test_bss_max_idle.c b/components/esp_wifi/test_apps/wifi_connect/main/test_bss_max_idle.c new file mode 100644 index 0000000000..7cd19b5c99 --- /dev/null +++ b/components/esp_wifi/test_apps/wifi_connect/main/test_bss_max_idle.c @@ -0,0 +1,242 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#ifdef CONFIG_ESP_WIFI_BSS_MAX_IDLE_SUPPORT + +#include +#include "unity.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_log.h" +#include "test_utils.h" +#include "freertos/event_groups.h" +#include "unity_test_utils.h" +#include "esp_private/wifi.h" + +#ifdef __CHECKER__ +#define __force __attribute__((force)) +#define __bitwise __attribute__((bitwise)) +#else +#define __force +#define __bitwise +#endif + +#if defined(__linux__) || defined(__GLIBC__) +#include +#include +#else +#include +#define __BYTE_ORDER BYTE_ORDER +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#endif /* __linux__ */ +#ifndef __BYTE_ORDER +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN 1234 +#endif +#endif + +typedef uint16_t u16; +typedef uint8_t u8; +typedef u16 __bitwise be16; + +#define host_to_be16(n) ((__force be16) __builtin_bswap16((n))) + +#ifndef TEST_SUFFIX_STR +#define TEST_SUFFIX_STR "_0000" +#endif + +#define TEST_DEFAULT_SSID "SSID_" CONFIG_IDF_TARGET TEST_SUFFIX_STR +#define TEST_DEFAULT_PWD "PASS_" CONFIG_IDF_TARGET TEST_SUFFIX_STR +#define TEST_DEFAULT_CHANNEL (6) +#define CONNECT_TIMEOUT_MS (8000) +#define MAXIMUM_RETRY (5) + +#define WIFI_DISCONNECT_EVENT (1) +#define WIFI_STA_CONNECTED (1<<1) +#define WIFI_AP_STA_CONNECTED (1<<2) +#define WIFI_FAIL (1<<3) +#define EMPH_STR(s) "****** "s" ******" + +#define MAX_IDLE_PERIOD (5) +#define ETHTYPE_IP 0x0800 + +static const char* TAG = "test_bss_max_idle"; + +static bool s_sta_conn_first = false; +static bool s_keep_alive_received = false; +static int s_retry_num = 0; +static EventGroupHandle_t wifi_events; + +struct eth_header { + u8 dest_mac[6]; + u8 src_mac[6]; + be16 ethertype; +}; + +static esp_err_t wifi_ap_receive_test(void *buffer, uint16_t len, void *eb) +{ + struct eth_header *pac = (struct eth_header *)buffer; + if ((host_to_be16(pac->ethertype) == ETHTYPE_IP) && (len < 48)) { + ESP_LOGI(TAG, "KEEP ALIVE RECEIVED"); + s_keep_alive_received = true; + esp_wifi_deauth_sta(0); + } + esp_wifi_internal_free_rx_buffer(eb); + return ESP_OK; +} + +static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) +{ + ESP_LOGI(TAG, "wifi event handler: %"PRIi32, event_id); + switch (event_id) { + case WIFI_EVENT_AP_START: + ESP_LOGI(TAG, "WIFI_EVENT_AP_START"); + esp_wifi_internal_reg_rxcb(WIFI_IF_AP, wifi_ap_receive_test); + break; + case WIFI_EVENT_STA_START: + ESP_LOGI(TAG, "WIFI_EVENT_STA_START"); + break; + case WIFI_EVENT_AP_STACONNECTED: + ESP_LOGI(TAG, "Wi-Fi AP got a station connected"); + break; + case WIFI_EVENT_STA_CONNECTED: + ESP_LOGI(TAG, "WIFI_EVENT_STA_CONNECTED"); + if (wifi_events) { + xEventGroupSetBits(wifi_events, WIFI_STA_CONNECTED); + s_sta_conn_first = true; + } + break; + case WIFI_EVENT_STA_DISCONNECTED: + if ((s_retry_num < MAXIMUM_RETRY) && !s_sta_conn_first) { + esp_wifi_connect(); + s_retry_num++; + ESP_LOGI(TAG, "retry to connect to AP"); + } else { + xEventGroupSetBits(wifi_events, WIFI_DISCONNECT_EVENT); + ESP_LOGI(TAG, "WIFI_EVENT_STA_DISCONNECTED"); + wifi_event_sta_disconnected_t *event = (wifi_event_sta_disconnected_t *)event_data; + ESP_LOGI(TAG, "disconnect reason: %u", event->reason); + } + break; + default: + break; + } + return; +} + +static esp_err_t event_init(void) +{ + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL)); + return ESP_OK; +} + +static esp_err_t event_deinit(void) +{ + ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler)); + ESP_ERROR_CHECK(esp_event_loop_delete_default()); + return ESP_OK; +} + +static void start_wifi_as_softap(void) +{ + wifi_config_t w_config = { + .ap.ssid = TEST_DEFAULT_SSID, + .ap.password = TEST_DEFAULT_PWD, + .ap.ssid_len = strlen(TEST_DEFAULT_SSID), + .ap.channel = TEST_DEFAULT_CHANNEL, + .ap.authmode = WIFI_AUTH_WPA3_PSK, + .ap.ssid_hidden = false, + .ap.max_connection = 4, + .ap.beacon_interval = 100, + .ap.bss_max_idle_cfg = { + .period = MAX_IDLE_PERIOD, + .protected_keep_alive = true, + }, + }; + event_init(); + if (wifi_events == NULL) { + wifi_events = xEventGroupCreate(); + } + xEventGroupClearBits(wifi_events, 0x00ffffff); + + TEST_ESP_OK(esp_wifi_set_mode(WIFI_MODE_AP)); + TEST_ESP_OK(esp_wifi_set_config(WIFI_IF_AP, &w_config)); + TEST_ESP_OK(esp_wifi_start()); + ESP_LOGI(TAG, "start wifi softap: %s", TEST_DEFAULT_SSID); +} + +static void start_wifi_as_sta(void) +{ + event_init(); + if (wifi_events == NULL) { + wifi_events = xEventGroupCreate(); + } + xEventGroupClearBits(wifi_events, 0x00ffffff); + TEST_ESP_OK(esp_wifi_set_mode(WIFI_MODE_STA)); + TEST_ESP_OK(esp_wifi_start()); +} + +static void stop_wifi(void) +{ + TEST_ESP_OK(esp_wifi_stop()); + event_deinit(); + if (wifi_events) { + vEventGroupDelete(wifi_events); + wifi_events = NULL; + } + vTaskDelay(500 / portTICK_PERIOD_MS); +} + +static void wifi_connect(void) +{ + wifi_config_t w_config = { + .sta.ssid = TEST_DEFAULT_SSID, + .sta.password = TEST_DEFAULT_PWD, + .sta.channel = TEST_DEFAULT_CHANNEL, + }; + + TEST_ESP_OK(esp_wifi_set_config(WIFI_IF_STA, &w_config)); + TEST_ESP_OK(esp_wifi_connect()); + ESP_LOGI(TAG, "start esp_wifi_connect: %s", TEST_DEFAULT_SSID); +} + +static void test_bss_max_idle_sta(void) +{ + start_wifi_as_sta(); + wifi_connect(); + // Waiting untill connection est or failed + EventBits_t bits = xEventGroupWaitBits(wifi_events, + WIFI_STA_CONNECTED | WIFI_FAIL, + pdFALSE, + pdFALSE, + portMAX_DELAY); + TEST_ASSERT(bits & WIFI_STA_CONNECTED); + if (bits != WIFI_FAIL) { + bits = xEventGroupWaitBits(wifi_events, + WIFI_DISCONNECT_EVENT, + pdFALSE, + pdFALSE, + portMAX_DELAY); + } + stop_wifi(); +} + +static void test_bss_max_idle_softap(void) +{ + start_wifi_as_softap(); + + vTaskDelay((CONNECT_TIMEOUT_MS + MAX_IDLE_PERIOD * 1000) / portTICK_PERIOD_MS); + + TEST_ASSERT(s_keep_alive_received); + stop_wifi(); +} + +TEST_CASE_MULTIPLE_DEVICES("Connection with bss max idle enabled", "[wifi][bss max idle]", test_bss_max_idle_sta, test_bss_max_idle_softap); + +#endif /* CONFIG_ESP_WIFI_BSS_MAX_IDLE_SUPPORT */ diff --git a/components/esp_wifi/test_apps/wifi_connect/sdkconfig.defaults b/components/esp_wifi/test_apps/wifi_connect/sdkconfig.defaults index 7a161c4bbd..c46e7bbe80 100644 --- a/components/esp_wifi/test_apps/wifi_connect/sdkconfig.defaults +++ b/components/esp_wifi/test_apps/wifi_connect/sdkconfig.defaults @@ -1,3 +1,4 @@ # ignore task watchdog triggered by unity_run_menu -CONFIG_ESP_TASK_WDT=n +CONFIG_ESP_TASK_WDT_EN=n +CONFIG_ESP_WIFI_BSS_MAX_IDLE_SUPPORT=y diff --git a/examples/wifi/getting_started/softAP/main/softap_example_main.c b/examples/wifi/getting_started/softAP/main/softap_example_main.c index 485d74e90b..941b0b77c3 100644 --- a/examples/wifi/getting_started/softAP/main/softap_example_main.c +++ b/examples/wifi/getting_started/softAP/main/softap_example_main.c @@ -75,6 +75,12 @@ void wifi_init_softap(void) .pmf_cfg = { .required = true, }, +#ifdef CONFIG_ESP_WIFI_BSS_MAX_IDLE_SUPPORT + .bss_max_idle_cfg = { + .period = WIFI_AP_DEFAULT_MAX_IDLE_PERIOD, + .protected_keep_alive = 1, + }, +#endif }, }; if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {