Skip to content

Commit c4f5926

Browse files
committed
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
1 parent 6b4f08c commit c4f5926

File tree

11 files changed

+288
-25
lines changed

11 files changed

+288
-25
lines changed

components/esp_rom/esp32c2/ld/esp32c2.rom.eco4.ld

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ ieee80211_deauth_construct = 0x40002040;
9292
ieee80211_disassoc_construct = 0x40002044;
9393
//ieee80211_add_xrates = 0x40002058;
9494
//ieee80211_assoc_req_construct = 0x40002060;
95-
ieee80211_assoc_resp_construct = 0x40002064;
95+
//ieee80211_assoc_resp_construct = 0x40002064;
9696
//ieee80211_timer_process = 0x4000208c;
9797
cnx_coexist_timeout = 0x40002090;
9898
//sta_recv_mgmt = 0x40002094;

components/esp_rom/esp32c5/ld/esp32c5.rom.pp.ld

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ ppDisableQueue = 0x40000ed4;
209209
ppCalVHTDeliNum = 0x40000ed8;
210210
ppCalTxVHTSMPDULength = 0x40000edc;
211211
ppCheckTxRTS = 0x40000ee0;
212-
ppProcessLifeTime = 0x40000ee4;
212+
/*ppProcessLifeTime = 0x40000ee4;*/
213213
ppProcTxCallback = 0x40000ee8;
214214
ppCalPreFecPaddingFactor = 0x40000eec;
215215
ppCalDeliNum = 0x40000ef0;

components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ ppMapWaitTxq = 0x40000e44;
214214
ppProcessWaitingQueue = 0x40000e48;
215215
ppDisableQueue = 0x40000e4c;
216216
ppCheckTxRTS = 0x40000e50;
217-
ppProcessLifeTime = 0x40000e54;
217+
/*ppProcessLifeTime = 0x40000e54;*/
218218
ppProcTxCallback = 0x40000e58;
219219
ppCalPreFecPaddingFactor = 0x40000e5c;
220220
ppCalDeliNum = 0x40000e60;

components/esp_wifi/Kconfig

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,14 +363,24 @@ menu "Wi-Fi"
363363
during this period, the time will be refreshed. If the time is up, but the station still has packets
364364
to receive or send, the time will also be refreshed. unit: milliseconds.
365365

366+
config ESP_WIFI_BSS_MAX_IDLE_SUPPORT
367+
bool "Enable bss max idle support"
368+
default y if (SOC_WIFI_HE_SUPPORT || ESP_WIFI_WNM_SUPPORT)
369+
help
370+
Enables bss max idle support for Station and SoftAP. BSS max idle period enables an SoftAP to indicate
371+
a time period during which the AP does not disassociate a STA due to nonreceipt of frames from the STA.
372+
For station, max idle period is default 10 (1000TUs) and can be set through
373+
ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME. For softap, bss max idle parameters will be set through
374+
bss_max_idle_cfg in wifi_ap_config_t.
375+
366376
config ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME
367377
int "Maximum keep alive time"
368378
range 10 60
369379
default 10
370380
help
371-
Only for station in WIFI_PS_MIN_MODEM or WIFI_PS_MAX_MODEM. If no packet has been
372-
sent within ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME, a null data packet will be sent
373-
to maintain the connection with the AP. unit: seconds.
381+
Only for station. If no packet has been sent within ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME, a null data
382+
packet will be sent to maintain the connection with the AP. If ESP_WIFI_BSS_MAX_IDLE_SUPPORT is set,
383+
it will be sent as bss max idle period in association request. unit: seconds.
374384

375385
config ESP_WIFI_SLP_DEFAULT_WAIT_BROADCAST_DATA_TIME
376386
int "Minimum wait broadcast data time"

components/esp_wifi/include/esp_private/esp_wifi_he_private.h

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -165,21 +165,6 @@ esp_err_t esp_wifi_get_tx_tb_statistics(esp_wifi_aci_t aci, esp_test_tx_tb_stati
165165
*/
166166
esp_err_t esp_wifi_softap_add_color_change_announcement(uint8_t color);
167167

168-
/**
169-
* @brief Add bss max idle ie
170-
*
171-
* @attention This API should be called after esp_wifi_start().
172-
*
173-
* @param[in] bss_max_idle_enable enable bss max idle
174-
* @param[in] bss_max_idle_period_secs bss max idle period, unit seconds
175-
* @param[in] protected_keep_alive using protected/unprotected frame to keep alive
176-
*
177-
* @return
178-
* - ESP_OK: succeed
179-
* - others: failed
180-
*/
181-
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);
182-
183168
/**
184169
* @brief Reset MU EDCA Timer
185170
*

components/esp_wifi/include/esp_wifi.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,12 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs;
278278
#define WIFI_TX_HETB_QUEUE_NUM 1
279279
#endif
280280

281+
#if CONFIG_ESP_WIFI_BSS_MAX_IDLE_SUPPORT
282+
#define WIFI_ENABLE_BSS_MAX_IDLE (1<<8)
283+
#else
284+
#define WIFI_ENABLE_BSS_MAX_IDLE 0
285+
#endif
286+
281287
#define CONFIG_FEATURE_WPA3_SAE_BIT (1<<0)
282288
#define CONFIG_FEATURE_CACHE_TX_BUF_BIT (1<<1)
283289
#define CONFIG_FEATURE_FTM_INITIATOR_BIT (1<<2)
@@ -286,6 +292,7 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs;
286292
#define CONFIG_FEATURE_GMAC_BIT (1<<5)
287293
#define CONFIG_FEATURE_11R_BIT (1<<6)
288294
#define CONFIG_FEATURE_WIFI_ENT_BIT (1<<7)
295+
#define CONFIG_FEATURE_BSS_MAX_IDLE_BIT (1<<8)
289296

290297
/* Set additional WiFi features and capabilities */
291298
#define WIFI_FEATURE_CAPS (WIFI_ENABLE_WPA3_SAE | \
@@ -295,7 +302,8 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs;
295302
WIFI_ENABLE_GCMP | \
296303
WIFI_ENABLE_GMAC | \
297304
WIFI_ENABLE_11R | \
298-
WIFI_ENABLE_ENTERPRISE)
305+
WIFI_ENABLE_ENTERPRISE | \
306+
WIFI_ENABLE_BSS_MAX_IDLE)
299307

300308
#define WIFI_INIT_CONFIG_DEFAULT() { \
301309
.osi_funcs = &g_wifi_osi_funcs, \

components/esp_wifi/include/esp_wifi_types_generic.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
extern "C" {
1818
#endif
1919

20+
#define WIFI_AP_DEFAULT_MAX_IDLE_PERIOD 292 /**< Default timeout for SoftAP BSS Max Idle. Unit: 1000TUs >**/
21+
2022
/**
2123
* @brief Wi-Fi mode type
2224
*/
@@ -507,6 +509,14 @@ typedef enum {
507509
WPA3_SAE_PK_MODE_DISABLED = 2,
508510
} wifi_sae_pk_mode_t;
509511

512+
/**
513+
* @brief Configuration structure for BSS max idle
514+
*/
515+
typedef struct {
516+
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 */
517+
bool protected_keep_alive; /**< Requires clients to use protected keep alive frames for BSS Max Idle period */
518+
} wifi_bss_max_idle_config_t;
519+
510520
/**
511521
* @brief Soft-AP configuration settings for the device
512522
*/
@@ -527,6 +537,7 @@ typedef struct {
527537
wifi_sae_pwe_method_t sae_pwe_h2e; /**< Configuration for SAE PWE derivation method */
528538
uint8_t transition_disable; /**< Whether to enable transition disable feature */
529539
uint8_t sae_ext; /**< Enable SAE EXT feature. SOC_GCMP_SUPPORT is required for this feature. */
540+
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 */
530541
} wifi_ap_config_t;
531542

532543
#define SAE_H2E_IDENTIFIER_LEN 32 /**< Length of the password identifier for H2E */
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Unlicense OR CC0-1.0
5+
*/
6+
7+
#ifdef CONFIG_ESP_WIFI_BSS_MAX_IDLE_SUPPORT
8+
9+
#include <string.h>
10+
#include "unity.h"
11+
#include "freertos/FreeRTOS.h"
12+
#include "freertos/task.h"
13+
#include "esp_wifi.h"
14+
#include "esp_event.h"
15+
#include "esp_log.h"
16+
#include "test_utils.h"
17+
#include "freertos/event_groups.h"
18+
#include "unity_test_utils.h"
19+
#include "esp_private/wifi.h"
20+
21+
#ifdef __CHECKER__
22+
#define __force __attribute__((force))
23+
#define __bitwise __attribute__((bitwise))
24+
#else
25+
#define __force
26+
#define __bitwise
27+
#endif
28+
29+
#if defined(__linux__) || defined(__GLIBC__)
30+
#include <endian.h>
31+
#include <byteswap.h>
32+
#else
33+
#include <machine/endian.h>
34+
#define __BYTE_ORDER BYTE_ORDER
35+
#define __LITTLE_ENDIAN LITTLE_ENDIAN
36+
#endif /* __linux__ */
37+
#ifndef __BYTE_ORDER
38+
#ifndef __LITTLE_ENDIAN
39+
#define __LITTLE_ENDIAN 1234
40+
#endif
41+
#endif
42+
43+
typedef uint16_t u16;
44+
typedef uint8_t u8;
45+
typedef u16 __bitwise be16;
46+
47+
#define host_to_be16(n) ((__force be16) __builtin_bswap16((n)))
48+
49+
#ifndef TEST_SUFFIX_STR
50+
#define TEST_SUFFIX_STR "_0000"
51+
#endif
52+
53+
#define TEST_DEFAULT_SSID "SSID_" CONFIG_IDF_TARGET TEST_SUFFIX_STR
54+
#define TEST_DEFAULT_PWD "PASS_" CONFIG_IDF_TARGET TEST_SUFFIX_STR
55+
#define TEST_DEFAULT_CHANNEL (6)
56+
#define CONNECT_TIMEOUT_MS (8000)
57+
#define MAXIMUM_RETRY (5)
58+
59+
#define WIFI_DISCONNECT_EVENT (1)
60+
#define WIFI_STA_CONNECTED (1<<1)
61+
#define WIFI_AP_STA_CONNECTED (1<<2)
62+
#define WIFI_FAIL (1<<3)
63+
#define EMPH_STR(s) "****** "s" ******"
64+
65+
#define MAX_IDLE_PERIOD (5)
66+
#define ETHTYPE_IP 0x0800
67+
68+
static const char* TAG = "test_bss_max_idle";
69+
70+
static bool s_sta_conn_first = false;
71+
static bool s_keep_alive_received = false;
72+
static int s_retry_num = 0;
73+
static EventGroupHandle_t wifi_events;
74+
75+
struct eth_header {
76+
u8 dest_mac[6];
77+
u8 src_mac[6];
78+
be16 ethertype;
79+
};
80+
81+
static esp_err_t wifi_ap_receive_test(void *buffer, uint16_t len, void *eb)
82+
{
83+
struct eth_header *pac = (struct eth_header *)buffer;
84+
if ((host_to_be16(pac->ethertype) == ETHTYPE_IP) && (len < 48)) {
85+
ESP_LOGI(TAG, "KEEP ALIVE RECEIVED");
86+
s_keep_alive_received = true;
87+
esp_wifi_deauth_sta(0);
88+
}
89+
esp_wifi_internal_free_rx_buffer(eb);
90+
return ESP_OK;
91+
}
92+
93+
static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
94+
{
95+
ESP_LOGI(TAG, "wifi event handler: %"PRIi32, event_id);
96+
switch (event_id) {
97+
case WIFI_EVENT_AP_START:
98+
ESP_LOGI(TAG, "WIFI_EVENT_AP_START");
99+
esp_wifi_internal_reg_rxcb(WIFI_IF_AP, wifi_ap_receive_test);
100+
break;
101+
case WIFI_EVENT_STA_START:
102+
ESP_LOGI(TAG, "WIFI_EVENT_STA_START");
103+
break;
104+
case WIFI_EVENT_AP_STACONNECTED:
105+
ESP_LOGI(TAG, "Wi-Fi AP got a station connected");
106+
break;
107+
case WIFI_EVENT_STA_CONNECTED:
108+
ESP_LOGI(TAG, "WIFI_EVENT_STA_CONNECTED");
109+
if (wifi_events) {
110+
xEventGroupSetBits(wifi_events, WIFI_STA_CONNECTED);
111+
s_sta_conn_first = true;
112+
}
113+
break;
114+
case WIFI_EVENT_STA_DISCONNECTED:
115+
if ((s_retry_num < MAXIMUM_RETRY) && !s_sta_conn_first) {
116+
esp_wifi_connect();
117+
s_retry_num++;
118+
ESP_LOGI(TAG, "retry to connect to AP");
119+
} else {
120+
xEventGroupSetBits(wifi_events, WIFI_DISCONNECT_EVENT);
121+
ESP_LOGI(TAG, "WIFI_EVENT_STA_DISCONNECTED");
122+
wifi_event_sta_disconnected_t *event = (wifi_event_sta_disconnected_t *)event_data;
123+
ESP_LOGI(TAG, "disconnect reason: %u", event->reason);
124+
}
125+
break;
126+
default:
127+
break;
128+
}
129+
return;
130+
}
131+
132+
static esp_err_t event_init(void)
133+
{
134+
ESP_ERROR_CHECK(esp_event_loop_create_default());
135+
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
136+
return ESP_OK;
137+
}
138+
139+
static esp_err_t event_deinit(void)
140+
{
141+
ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler));
142+
ESP_ERROR_CHECK(esp_event_loop_delete_default());
143+
return ESP_OK;
144+
}
145+
146+
static void start_wifi_as_softap(void)
147+
{
148+
wifi_config_t w_config = {
149+
.ap.ssid = TEST_DEFAULT_SSID,
150+
.ap.password = TEST_DEFAULT_PWD,
151+
.ap.ssid_len = strlen(TEST_DEFAULT_SSID),
152+
.ap.channel = TEST_DEFAULT_CHANNEL,
153+
.ap.authmode = WIFI_AUTH_WPA3_PSK,
154+
.ap.ssid_hidden = false,
155+
.ap.max_connection = 4,
156+
.ap.beacon_interval = 100,
157+
.ap.bss_max_idle_cfg = {
158+
.period = MAX_IDLE_PERIOD,
159+
.protected_keep_alive = true,
160+
},
161+
};
162+
event_init();
163+
if (wifi_events == NULL) {
164+
wifi_events = xEventGroupCreate();
165+
}
166+
xEventGroupClearBits(wifi_events, 0x00ffffff);
167+
168+
TEST_ESP_OK(esp_wifi_set_mode(WIFI_MODE_AP));
169+
TEST_ESP_OK(esp_wifi_set_config(WIFI_IF_AP, &w_config));
170+
TEST_ESP_OK(esp_wifi_start());
171+
ESP_LOGI(TAG, "start wifi softap: %s", TEST_DEFAULT_SSID);
172+
}
173+
174+
static void start_wifi_as_sta(void)
175+
{
176+
event_init();
177+
if (wifi_events == NULL) {
178+
wifi_events = xEventGroupCreate();
179+
}
180+
xEventGroupClearBits(wifi_events, 0x00ffffff);
181+
TEST_ESP_OK(esp_wifi_set_mode(WIFI_MODE_STA));
182+
TEST_ESP_OK(esp_wifi_start());
183+
}
184+
185+
static void stop_wifi(void)
186+
{
187+
TEST_ESP_OK(esp_wifi_stop());
188+
event_deinit();
189+
if (wifi_events) {
190+
vEventGroupDelete(wifi_events);
191+
wifi_events = NULL;
192+
}
193+
vTaskDelay(500 / portTICK_PERIOD_MS);
194+
}
195+
196+
static void wifi_connect(void)
197+
{
198+
wifi_config_t w_config = {
199+
.sta.ssid = TEST_DEFAULT_SSID,
200+
.sta.password = TEST_DEFAULT_PWD,
201+
.sta.channel = TEST_DEFAULT_CHANNEL,
202+
};
203+
204+
TEST_ESP_OK(esp_wifi_set_config(WIFI_IF_STA, &w_config));
205+
TEST_ESP_OK(esp_wifi_connect());
206+
ESP_LOGI(TAG, "start esp_wifi_connect: %s", TEST_DEFAULT_SSID);
207+
}
208+
209+
static void test_bss_max_idle_sta(void)
210+
{
211+
start_wifi_as_sta();
212+
wifi_connect();
213+
// Waiting untill connection est or failed
214+
EventBits_t bits = xEventGroupWaitBits(wifi_events,
215+
WIFI_STA_CONNECTED | WIFI_FAIL,
216+
pdFALSE,
217+
pdFALSE,
218+
portMAX_DELAY);
219+
TEST_ASSERT(bits & WIFI_STA_CONNECTED);
220+
if (bits != WIFI_FAIL) {
221+
bits = xEventGroupWaitBits(wifi_events,
222+
WIFI_DISCONNECT_EVENT,
223+
pdFALSE,
224+
pdFALSE,
225+
portMAX_DELAY);
226+
}
227+
stop_wifi();
228+
}
229+
230+
static void test_bss_max_idle_softap(void)
231+
{
232+
start_wifi_as_softap();
233+
234+
vTaskDelay((CONNECT_TIMEOUT_MS + MAX_IDLE_PERIOD * 1000) / portTICK_PERIOD_MS);
235+
236+
TEST_ASSERT(s_keep_alive_received);
237+
stop_wifi();
238+
}
239+
240+
TEST_CASE_MULTIPLE_DEVICES("Connection with bss max idle enabled", "[wifi][bss max idle]", test_bss_max_idle_sta, test_bss_max_idle_softap);
241+
242+
#endif /* CONFIG_ESP_WIFI_BSS_MAX_IDLE_SUPPORT */
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11

22
# ignore task watchdog triggered by unity_run_menu
3-
CONFIG_ESP_TASK_WDT=n
3+
CONFIG_ESP_TASK_WDT_EN=n
4+
CONFIG_ESP_WIFI_BSS_MAX_IDLE_SUPPORT=y

0 commit comments

Comments
 (0)