Merge branch 'bugfix/offchan_action_tx_failure_v5.4' into 'release/v5.4'

Fix issues with offchannel action tx and ROC operations (Backport v5.4)

See merge request espressif/esp-idf!38497
This commit is contained in:
Jiang Jiang Jian
2025-09-20 13:30:41 +08:00
11 changed files with 173 additions and 60 deletions

View File

@@ -513,7 +513,7 @@ lmacRecycleMPDU = 0x40001b44;
lmacRxDone = 0x40001b48;
/*lmacSetTxFrame = 0x40001b4c;*/
lmacTxDone = 0x40001b50;
lmacTxFrame = 0x40001b54;
/*lmacTxFrame = 0x40001b54;*/
mac_tx_set_duration = 0x40001b58;
mac_tx_set_htsig = 0x40001b5c;
mac_tx_set_plcp0 = 0x40001b60;
@@ -555,7 +555,7 @@ ppEnqueueRxq = 0x40001bec;
ppEnqueueTxDone = 0x40001bf0;
ppGetTxQFirstAvail_Locked = 0x40001bf4;
ppGetTxframe = 0x40001bf8;
ppMapTxQueue = 0x40001bfc;
/*ppMapTxQueue = 0x40001bfc;*/
ppProcTxSecFrame = 0x40001c00;
ppProcessRxPktHdr = 0x40001c04;
/*ppProcessTxQ = 0x40001c08;*/

View File

@@ -11,7 +11,7 @@ ic_mac_deinit = 0x400015dc;
lmacDiscardMSDU = 0x400015f4;
/*lmacSetTxFrame = 0x40001628;*/
lmacTxDone = 0x4000162c;
lmacTxFrame = 0x40001630;
/*lmacTxFrame = 0x40001630;*/
mac_tx_set_htsig = 0x40001638;
mac_tx_set_plcp1 = 0x40001640;
pm_check_state = 0x40001648;
@@ -22,7 +22,7 @@ pm_rx_beacon_process = 0x40001690;
pm_rx_data_process = 0x40001694;
/* pm_sleep = 0x40001698;*/
/* pm_tbtt_process = 0x400016a0;*/
ppMapTxQueue = 0x400016d8;
/*ppMapTxQueue = 0x400016d8;*/
ppProcTxSecFrame = 0x400016dc;
/*ppRxFragmentProc = 0x40001704;*/
/* rcGetSched = 0x40001764;*/

View File

@@ -76,7 +76,7 @@ lmacRecycleMPDU = 0x40000cc0;
lmacRxDone = 0x40000cc4;
lmacSetTxFrame = 0x40000cc8;
lmacTxDone = 0x40000ccc;
lmacTxFrame = 0x40000cd0;
/*lmacTxFrame = 0x40000cd0;*/
lmacDisableTransmit = 0x40000cd4;
lmacDiscardFrameExchangeSequence = 0x40000cd8;
lmacProcessCollision = 0x40000cdc;
@@ -177,7 +177,7 @@ ppEmptyDelimiterLength = 0x40000e54;
ppEnqueueRxq = 0x40000e58;
ppEnqueueTxDone = 0x40000e5c;
ppGetTxframe = 0x40000e60;
ppMapTxQueue = 0x40000e64;
/*ppMapTxQueue = 0x40000e64;*/
ppProcTxSecFrame = 0x40000e68;
ppProcessRxPktHdr = 0x40000e6c;
/*ppProcessTxQ = 0x40000e70;*/

View File

@@ -81,7 +81,7 @@ lmacRecycleMPDU = 0x40000c30;
lmacRxDone = 0x40000c34;
lmacSetTxFrame = 0x40000c38;
lmacTxDone = 0x40000c3c;
lmacTxFrame = 0x40000c40;
/*lmacTxFrame = 0x40000c40;*/
lmacDisableTransmit = 0x40000c44;
lmacDiscardFrameExchangeSequence = 0x40000c48;
lmacProcessCollision = 0x40000c4c;
@@ -184,7 +184,7 @@ ppEmptyDelimiterLength = 0x40000dcc;
ppEnqueueRxq = 0x40000dd0;
ppEnqueueTxDone = 0x40000dd4;
ppGetTxframe = 0x40000dd8;
ppMapTxQueue = 0x40000ddc;
/*ppMapTxQueue = 0x40000ddc;*/
ppProcTxSecFrame = 0x40000de0;
ppProcessRxPktHdr = 0x40000de4;
/*ppProcessTxQ = 0x40000de8;*/

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1789,6 +1789,29 @@ esp_err_t esp_wifi_set_bandwidths(wifi_interface_t ifx, wifi_bandwidths_t* bw);
*/
esp_err_t esp_wifi_get_bandwidths(wifi_interface_t ifx, wifi_bandwidths_t *bw);
/**
* @brief Send action frame on target channel
*
* @param req action tx request structure containing relevant fields
*
* @return
* - ESP_OK: succeed
* - ESP_ERR_NO_MEM: failed to allocate memory
* - ESP_FAIL: failed to send frame
*/
esp_err_t esp_wifi_action_tx_req(wifi_action_tx_req_t *req);
/**
* @brief Remain on the target channel for required duration
*
* @param req roc request structure containing relevant fields
*
* @return
* - ESP_OK: succeed
* - ESP_ERR_NO_MEM: failed to allocate memory
* - ESP_FAIL: failed to perform roc operation
*/
esp_err_t esp_wifi_remain_on_channel(wifi_roc_req_t * req);
#ifdef __cplusplus
}
#endif

View File

@@ -41,12 +41,15 @@ typedef enum {
WIFI_IF_MAX /**< Maximum number of interfaces */
} wifi_interface_t;
#define WIFI_OFFCHAN_TX_REQ 1 /**< Request off-channel transmission */
#define WIFI_OFFCHAN_TX_CANCEL 0 /**< Cancel off-channel transmission */
#define WIFI_ROC_REQ 1 /**< Request remain on channel */
#define WIFI_ROC_CANCEL 0 /**< Cancel remain on channel */
typedef enum {
WIFI_OFFCHAN_TX_CANCEL, /**< Cancel off-channel transmission */
WIFI_OFFCHAN_TX_REQ, /**< Request off-channel transmission */
} wifi_action_tx_t;
typedef enum {
WIFI_ROC_CANCEL, /**< Cancel remain on channel */
WIFI_ROC_REQ, /**< Request remain on channel */
} wifi_roc_t;
/**
* @brief Wi-Fi country policy
*/
@@ -773,12 +776,49 @@ typedef int (* wifi_action_rx_cb_t)(uint8_t *hdr, uint8_t *payload,
typedef struct {
wifi_interface_t ifx; /**< Wi-Fi interface to send request to */
uint8_t dest_mac[6]; /**< Destination MAC address */
wifi_action_tx_t type; /**< ACTION TX operation type */
uint8_t channel; /**< Channel on which to perform ACTION TX Operation */
uint32_t wait_time_ms; /**< Duration to wait for on target channel */
bool no_ack; /**< Indicates no ack required */
wifi_action_rx_cb_t rx_cb; /**< Rx Callback to receive any response */
wifi_action_rx_cb_t rx_cb; /**< Rx Callback to receive action frames */
uint8_t op_id; /**< Unique Identifier for operation provided by wifi driver */
uint32_t data_len; /**< Length of the appended Data */
uint8_t data[0]; /**< Appended Data payload */
} wifi_action_tx_req_t;
/** Status codes for WIFI_EVENT_ROC_DONE evt */
typedef enum {
WIFI_ROC_DONE = 0, /**< ROC operation was completed successfully */
WIFI_ROC_FAIL, /**< ROC operation was cancelled */
} wifi_roc_done_status_t;
/**
* @brief The callback function executed when ROC operation has ended
*
* @param context rxcb registered for the corresponding ROC operation
* @param op_id ID of the corresponding ROC operation
* @param status status code of the ROC operation denoted
*
*/
typedef void (* wifi_action_roc_done_cb_t)(uint32_t context, uint8_t op_id,
wifi_roc_done_status_t status);
/**
* @brief Remain on Channel request
*
*
*/
typedef struct {
wifi_interface_t ifx; /**< WiFi interface to send request to */
wifi_roc_t type; /**< ROC operation type */
uint8_t channel; /**< Channel on which to perform ROC Operation */
wifi_second_chan_t sec_channel; /**< Secondary channel */
uint32_t wait_time_ms; /**< Duration to wait for on target channel */
wifi_action_rx_cb_t rx_cb; /**< Rx Callback to receive any response */
uint8_t op_id; /**< ID of this specific ROC operation provided by wifi driver */
wifi_action_roc_done_cb_t done_cb; /**< Callback to function that will be called upon ROC done. If assigned, WIFI_EVENT_ROC_DONE event will not be posted */
} wifi_roc_req_t;
/**
* @brief FTM Initiator configuration
*
@@ -1236,21 +1276,32 @@ typedef struct {
#define WIFI_STATIS_PS (1<<4) /**< Power save status */
#define WIFI_STATIS_ALL (-1) /**< All status */
/**
* @brief Argument structure for WIFI_EVENT_ACTION_TX_STATUS event
*/
/** Status codes for WIFI_EVENT_ACTION_TX_STATUS evt */
/** There will be back to back events in success case TX_DONE and TX_DURATION_COMPLETED */
typedef enum {
WIFI_ACTION_TX_DONE = 0, /**< ACTION_TX operation was completed successfully */
WIFI_ACTION_TX_FAILED, /**< ACTION_TX operation failed during tx */
WIFI_ACTION_TX_DURATION_COMPLETED, /**< ACTION_TX operation completed it's wait duration */
WIFI_ACTION_TX_OP_CANCELLED, /**< ACTION_TX operation was cancelled by application or higher priority operation */
} wifi_action_tx_status_type_t;
/** Argument structure for WIFI_EVENT_ACTION_TX_STATUS event */
typedef struct {
wifi_interface_t ifx; /**< Wi-Fi interface to send request to */
wifi_interface_t ifx; /**< WiFi interface to send request to */
uint32_t context; /**< Context to identify the request */
uint8_t da[6]; /**< Destination MAC address */
uint8_t status; /**< Status of the operation */
wifi_action_tx_status_type_t status; /**< Status of the operation */
uint8_t op_id; /**< ID of the corresponding operation that was provided during action tx request */
uint8_t channel; /**< Channel provided in tx request */
} wifi_event_action_tx_status_t;
/**
* @brief Argument structure for WIFI_EVENT_ROC_DONE event
*/
typedef struct {
uint32_t context; /**< Context to identify the request */
uint32_t context; /**< Context to identify the initiator of the request */
wifi_roc_done_status_t status; /**< ROC status */
uint8_t op_id; /**< ID of the corresponding ROC operation */
uint8_t channel; /**< Channel provided in tx request */
} wifi_event_roc_done_t;
/**

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -28,7 +28,7 @@ static void *s_dpp_api_lock = NULL;
static bool s_dpp_listen_in_progress;
static struct esp_dpp_context_t s_dpp_ctx;
static wifi_action_rx_cb_t s_action_rx_cb = esp_supp_rx_action;
static uint8_t s_current_tx_op_id;
#define DPP_API_LOCK() os_mutex_lock(s_dpp_api_lock)
#define DPP_API_UNLOCK() os_mutex_unlock(s_dpp_api_lock)
@@ -101,7 +101,7 @@ static void esp_dpp_auth_conf_wait_timeout(void *eloop_ctx, void *timeout_ctx)
esp_err_t esp_dpp_send_action_frame(uint8_t *dest_mac, const uint8_t *buf, uint32_t len,
uint8_t channel, uint32_t wait_time_ms)
{
wifi_action_tx_req_t *req = os_zalloc(sizeof(*req) + len);;
wifi_action_tx_req_t *req = os_zalloc(sizeof(*req) + len);
if (!req) {
return ESP_FAIL;
}
@@ -111,19 +111,23 @@ esp_err_t esp_dpp_send_action_frame(uint8_t *dest_mac, const uint8_t *buf, uint3
req->no_ack = false;
req->data_len = len;
req->rx_cb = s_action_rx_cb;
req->channel = channel;
req->wait_time_ms = wait_time_ms;
req->type = WIFI_OFFCHAN_TX_REQ;
memcpy(req->data, buf, req->data_len);
wpa_printf(MSG_DEBUG, "DPP: Mgmt Tx - MAC:" MACSTR ", Channel-%d, WaitT-%d",
MAC2STR(dest_mac), channel, wait_time_ms);
if (ESP_OK != esp_wifi_action_tx_req(WIFI_OFFCHAN_TX_REQ, channel,
wait_time_ms, req)) {
if (ESP_OK != esp_wifi_action_tx_req(req)) {
wpa_printf(MSG_ERROR, "DPP: Failed to perform offchannel operation");
esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_TX_FAILURE);
os_free(req);
return ESP_FAIL;
}
wpa_printf(MSG_DEBUG, "Sent DPP action frame %d", req->op_id);
s_current_tx_op_id = req->op_id;
os_free(req);
return ESP_OK;
}
@@ -560,21 +564,27 @@ static void esp_dpp_task(void *pvParameters)
case SIG_DPP_LISTEN_NEXT_CHANNEL: {
struct dpp_bootstrap_params_t *p = &s_dpp_ctx.bootstrap_params;
static int counter;
int channel;
esp_err_t ret = 0;
if (p->num_chan <= 0) {
wpa_printf(MSG_ERROR, "Listen channel not set");
break;
}
channel = p->chan_list[counter++ % p->num_chan];
wpa_printf(MSG_DEBUG, "Listening on channel=%d", channel);
ret = esp_wifi_remain_on_channel(WIFI_IF_STA, WIFI_ROC_REQ, channel,
BOOTSTRAP_ROC_WAIT_TIME, s_action_rx_cb);
wifi_roc_req_t req = {0};
req.ifx = WIFI_IF_STA;
req.type = WIFI_ROC_REQ;
req.channel = p->chan_list[counter++ % p->num_chan];
req.wait_time_ms = BOOTSTRAP_ROC_WAIT_TIME;
req.rx_cb = s_action_rx_cb;
req.done_cb = NULL;
wpa_printf(MSG_DEBUG, "Listening on channel=%d", req.channel);
ret = esp_wifi_remain_on_channel(&req);
if (ret != ESP_OK) {
wpa_printf(MSG_ERROR, "Failed ROC. error : 0x%x", ret);
break;
}
wpa_printf(MSG_DEBUG, "Started DPP listen operation %d", req.op_id);
s_dpp_listen_in_progress = true;
}
break;
@@ -656,21 +666,22 @@ static void offchan_event_handler(void *arg, esp_event_base_t event_base,
if (event_id == WIFI_EVENT_ACTION_TX_STATUS) {
wifi_event_action_tx_status_t *evt =
(wifi_event_action_tx_status_t *)event_data;
wpa_printf(MSG_DEBUG, "Mgmt Tx Status - %d, Cookie - 0x%x",
evt->status, (uint32_t)evt->context);
if (evt->op_id == s_current_tx_op_id) {
wpa_printf(MSG_DEBUG,
"Mgmt Tx Status - %d, Context - 0x%x Operation ID : %d", evt->status, (uint32_t)evt->context, evt->op_id);
if (evt->status) {
if (evt->status == WIFI_ACTION_TX_FAILED) {
eloop_cancel_timeout(esp_dpp_auth_conf_wait_timeout, NULL, NULL);
if (s_dpp_listen_in_progress) {
esp_supp_dpp_stop_listen();
}
esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_TX_FAILURE);
}
}
} else if (event_id == WIFI_EVENT_ROC_DONE) {
wifi_event_roc_done_t *evt = (wifi_event_roc_done_t *)event_data;
if (s_dpp_listen_in_progress && evt->context == (uint32_t)s_action_rx_cb) {
/*@TODO : Decide flow for when ROC fails*/
if (s_dpp_listen_in_progress && evt->context == (uint32_t)s_action_rx_cb && evt->status == WIFI_ROC_DONE) {
esp_dpp_post_evt(SIG_DPP_LISTEN_NEXT_CHANNEL, 0);
}
}
@@ -856,7 +867,14 @@ esp_err_t esp_supp_dpp_start_listen(void)
esp_err_t esp_supp_dpp_stop_listen(void)
{
s_dpp_listen_in_progress = false;
return esp_wifi_remain_on_channel(WIFI_IF_STA, WIFI_ROC_CANCEL, 0, 0, NULL);
wifi_roc_req_t req = {0};
req.ifx = WIFI_IF_STA;
req.type = WIFI_ROC_CANCEL;
esp_err_t ret = esp_wifi_remain_on_channel(&req);
if (ret != ESP_OK) {
wpa_printf(MSG_ERROR, "DPP: ROC cancel failed");
}
return ret;
}
bool is_dpp_enabled(void)

View File

@@ -284,10 +284,6 @@ bool esp_wifi_is_btm_enabled_internal(uint8_t if_index);
esp_err_t esp_wifi_register_mgmt_frame_internal(uint32_t type, uint32_t subtype);
esp_err_t esp_wifi_send_mgmt_frm_internal(const wifi_mgmt_frm_req_t *req);
uint8_t esp_wifi_ap_get_prof_pairwise_cipher_internal(void);
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);
uint8_t esp_wifi_ap_get_sae_ext_config_internal(void);
bool esp_wifi_is_mbo_enabled_internal(uint8_t if_index);
void esp_wifi_get_pmf_config_internal(wifi_pmf_config_t *pmf_cfg, uint8_t ifx);

View File

@@ -25,6 +25,7 @@
#include "esp_wifi.h"
/* Modifying datatype for platform and compiler independence */
typedef uint64_t os_time_t;
/**

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*
@@ -54,7 +54,7 @@ static void wifi_event_handler(void *arg, esp_event_base_t event_base,
wifi_event_action_tx_status_t *evt =
(wifi_event_action_tx_status_t *)event_data;
if (evt->status == 0) {
if (evt->status == WIFI_ACTION_TX_DONE) {
ESP_LOGI(TAG, "Action Tx Successful");
}
}
@@ -137,17 +137,21 @@ void esp_send_action_frame(uint8_t *dest_mac, const uint8_t *buf, uint32_t len,
req->no_ack = false;
req->data_len = len;
req->rx_cb = dummy_rx_action;
req->channel = channel;
req->wait_time_ms = wait_time_ms;
req->type = WIFI_OFFCHAN_TX_REQ;
memcpy(req->data, buf, req->data_len);
ESP_LOGI(TAG, "Action Tx - MAC:" MACSTR ", Channel-%d, WaitT-%" PRId32 "",
MAC2STR(dest_mac), channel, wait_time_ms);
TEST_ESP_OK(esp_wifi_action_tx_req(WIFI_OFFCHAN_TX_REQ, channel, wait_time_ms, req));
TEST_ESP_OK(esp_wifi_action_tx_req(req));
os_free(req);
}
/* Test that foreground Scan doesn't pre-empt ROC & vice versa */
/* Test that foreground Scan doesn't preempt ROC & vice versa */
TEST_CASE("Test scan and ROC simultaneously", "[Offchan]")
{
wifi_action_rx_cb_t rx_cb = dummy_rx_action;
@@ -158,8 +162,16 @@ TEST_CASE("Test scan and ROC simultaneously", "[Offchan]")
xEventGroupWaitBits(wifi_event, WIFI_START_EVENT, 1, 0, 5000 / portTICK_PERIOD_MS);
TEST_ESP_OK(esp_wifi_remain_on_channel(WIFI_IF_STA, WIFI_ROC_REQ, TEST_LISTEN_CHANNEL,
100, rx_cb));
wifi_roc_req_t req = {0};
req.ifx = WIFI_IF_STA;
req.type = WIFI_ROC_REQ;
req.channel = TEST_LISTEN_CHANNEL;
req.wait_time_ms = 100;
req.rx_cb = rx_cb;
req.done_cb = NULL;
TEST_ESP_OK(esp_wifi_remain_on_channel(&req));
ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, false));
bits = xEventGroupWaitBits(wifi_event, WIFI_ROC_DONE_EVENT | WIFI_SCAN_DONE_EVENT,
pdTRUE, pdFALSE, 5000 / portTICK_PERIOD_MS);
@@ -167,8 +179,9 @@ TEST_CASE("Test scan and ROC simultaneously", "[Offchan]")
vTaskDelay(1000 / portTICK_PERIOD_MS);
ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, false));
TEST_ESP_OK(esp_wifi_remain_on_channel(WIFI_IF_STA, WIFI_ROC_REQ, TEST_LISTEN_CHANNEL,
100, rx_cb));
TEST_ESP_OK(esp_wifi_remain_on_channel(&req));
bits = xEventGroupWaitBits(wifi_event, WIFI_ROC_DONE_EVENT | WIFI_SCAN_DONE_EVENT,
pdTRUE, pdFALSE, 5000 / portTICK_PERIOD_MS);
TEST_ASSERT_TRUE(bits == WIFI_SCAN_DONE_EVENT);
@@ -228,13 +241,24 @@ static void test_wifi_roc(void)
sprintf(mac_str, MACSTR, MAC2STR(mac));
unity_send_signal_param("Listener mac", mac_str);
TEST_ESP_OK(esp_wifi_remain_on_channel(WIFI_IF_STA, WIFI_ROC_REQ, TEST_LISTEN_CHANNEL,
10000, rx_cb));
wifi_roc_req_t req = {0};
req.ifx = WIFI_IF_STA;
req.type = WIFI_ROC_REQ;
req.channel = TEST_LISTEN_CHANNEL;
req.wait_time_ms = 10000;
req.rx_cb = rx_cb;
req.done_cb = NULL;
TEST_ESP_OK(esp_wifi_remain_on_channel(&req));
bits = xEventGroupWaitBits(wifi_event, WIFI_ROC_DONE_EVENT | WIFI_ACTION_RX_EVENT,
pdTRUE, pdFALSE, portMAX_DELAY);
/* Confirm that Frame has been received successfully */
if (bits == WIFI_ACTION_RX_EVENT) {
TEST_ESP_OK(esp_wifi_remain_on_channel(WIFI_IF_STA, WIFI_ROC_CANCEL, 0, 0, NULL));
wifi_roc_req_t req = {0};
req.ifx = WIFI_IF_STA;
req.type = WIFI_ROC_CANCEL;
TEST_ESP_OK(esp_wifi_remain_on_channel(&req));
vTaskDelay(1000 / portTICK_PERIOD_MS);
stop_wifi();
} else {