Merge branch 'feature/bss_max_idle' into 'master'

feat(wifi): Improve and enable bss max idle support on all chips

See merge request espressif/esp-idf!34656
This commit is contained in:
Jiang Jiang Jian
2025-04-08 22:44:33 +08:00
11 changed files with 288 additions and 25 deletions

View File

@ -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;

View File

@ -209,7 +209,7 @@ ppDisableQueue = 0x40000ed4;
ppCalVHTDeliNum = 0x40000ed8;
ppCalTxVHTSMPDULength = 0x40000edc;
ppCheckTxRTS = 0x40000ee0;
ppProcessLifeTime = 0x40000ee4;
/*ppProcessLifeTime = 0x40000ee4;*/
ppProcTxCallback = 0x40000ee8;
ppCalPreFecPaddingFactor = 0x40000eec;
ppCalDeliNum = 0x40000ef0;

View File

@ -214,7 +214,7 @@ ppMapWaitTxq = 0x40000e44;
ppProcessWaitingQueue = 0x40000e48;
ppDisableQueue = 0x40000e4c;
ppCheckTxRTS = 0x40000e50;
ppProcessLifeTime = 0x40000e54;
/*ppProcessLifeTime = 0x40000e54;*/
ppProcTxCallback = 0x40000e58;
ppCalPreFecPaddingFactor = 0x40000e5c;
ppCalDeliNum = 0x40000e60;

View File

@ -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"

View File

@ -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
*

View File

@ -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, \

View File

@ -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 */

View File

@ -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 <string.h>
#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 <endian.h>
#include <byteswap.h>
#else
#include <machine/endian.h>
#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 */

View File

@ -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

View File

@ -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) {