Merge branch 'bugfix/concurrency_issue_roam_app' into 'master'

fix(esp_wifi): Add some fixes in roaming app

See merge request espressif/esp-idf!42262
This commit is contained in:
Kapil Gupta
2025-09-30 23:25:48 +05:30
3 changed files with 70 additions and 78 deletions

View File

@@ -198,10 +198,6 @@ static esp_err_t wifi_deinit_internal(void)
esp_supplicant_deinit(); esp_supplicant_deinit();
#if CONFIG_ESP_WIFI_ENABLE_ROAMING_APP
roam_deinit_app();
#endif
#if CONFIG_ESP_WIFI_SLP_SAMPLE_BEACON_FEATURE #if CONFIG_ESP_WIFI_SLP_SAMPLE_BEACON_FEATURE
wifi_beacon_offset_config_t offset_config = WIFI_BEACON_OFFSET_CONFIG_DEFAULT(false); wifi_beacon_offset_config_t offset_config = WIFI_BEACON_OFFSET_CONFIG_DEFAULT(false);
esp_wifi_beacon_offset_configure(&offset_config); esp_wifi_beacon_offset_configure(&offset_config);
@@ -471,10 +467,6 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config)
goto _deinit; goto _deinit;
} }
#if CONFIG_ESP_WIFI_ENABLE_ROAMING_APP
roam_init_app();
#endif
} else { } else {
goto _deinit; goto _deinit;
} }

View File

@@ -35,15 +35,6 @@ struct roaming_app g_roaming_app;
typedef void (* scan_done_cb_t)(void *arg, ETS_STATUS status); typedef void (* scan_done_cb_t)(void *arg, ETS_STATUS status);
extern int esp_wifi_promiscuous_scan_start(wifi_scan_config_t *config, scan_done_cb_t cb); extern int esp_wifi_promiscuous_scan_start(wifi_scan_config_t *config, scan_done_cb_t cb);
static void *scan_results_lock = NULL;
#define ROAM_SCAN_RESULTS_LOCK() os_mutex_lock(scan_results_lock)
#define ROAM_SCAN_RESULTS_UNLOCK() os_mutex_unlock(scan_results_lock)
#if PERIODIC_RRM_MONITORING
static void *neighbor_list_lock = NULL;
#define ROAM_NEIGHBOR_LIST_LOCK() os_mutex_lock(neighbor_list_lock)
#define ROAM_NEIGHBOR_LIST_UNLOCK() os_mutex_unlock(neighbor_list_lock)
#endif /*PERIODIC_RRM_MONITORING*/
static int wifi_post_roam_event(struct cand_bss *bss); static int wifi_post_roam_event(struct cand_bss *bss);
static void determine_best_ap(int8_t rssi_threshold); static void determine_best_ap(int8_t rssi_threshold);
@@ -150,12 +141,6 @@ static void init_periodic_rrm_event(void)
ESP_LOGI(ROAMING_TAG, "RRM monitor is disabled in config"); ESP_LOGI(ROAMING_TAG, "RRM monitor is disabled in config");
return; return;
} }
if (!neighbor_list_lock) {
neighbor_list_lock = os_recursive_mutex_create();
if (!neighbor_list_lock) {
ESP_LOGE(ROAMING_TAG, "%s: failed to create roaming neighbor list lock", __func__);
}
}
ESP_LOGV(ROAMING_TAG, "Initialised Periodic RRM Monitoring event!"); ESP_LOGV(ROAMING_TAG, "Initialised Periodic RRM Monitoring event!");
g_roaming_app.periodic_rrm_active = true; g_roaming_app.periodic_rrm_active = true;
if (eloop_register_timeout(g_roaming_app.config.rrm_monitor_time, 0, roaming_app_periodic_rrm_internal_handler, NULL, NULL)) { if (eloop_register_timeout(g_roaming_app.config.rrm_monitor_time, 0, roaming_app_periodic_rrm_internal_handler, NULL, NULL)) {
@@ -422,49 +407,70 @@ cleanup:
} }
return buf; return buf;
} }
static void roaming_app_neighbor_report_recv_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
static void roaming_app_neighbor_report_recv_internal_handler(void *ctx, void *data)
{ {
wifi_event_neighbor_report_t *neighbor_report_event = data;
if (!g_roaming_app.rrm_request_active) { if (!g_roaming_app.rrm_request_active) {
ESP_LOGV(ROAMING_TAG, "Not the response for our Neighbor Report Request"); ESP_LOGV(ROAMING_TAG, "Not the response for our Neighbor Report Request");
return; goto cleanup;
} }
g_roaming_app.rrm_request_active = false; g_roaming_app.rrm_request_active = false;
if (!event_data) { if (!neighbor_report_event) {
ESP_LOGE(ROAMING_TAG, "No data received for neighbor report"); ESP_LOGE(ROAMING_TAG, "No data received for neighbor report");
return; goto cleanup;
} }
wifi_event_neighbor_report_t *neighbor_report_event = (wifi_event_neighbor_report_t*)event_data;
ESP_LOGD(ROAMING_TAG, "Received cb for Neighbor Report Request"); ESP_LOGD(ROAMING_TAG, "Received cb for Neighbor Report Request");
uint8_t *pos = (uint8_t *)neighbor_report_event->n_report; uint8_t *pos = (uint8_t *)neighbor_report_event->n_report;
uint8_t report_len = neighbor_report_event->report_len; uint8_t report_len = neighbor_report_event->report_len;
if (!report_len) { if (!report_len) {
ESP_LOGE(ROAMING_TAG, "Neighbor report is empty"); ESP_LOGE(ROAMING_TAG, "Neighbor report is empty");
return; goto cleanup;
} }
/* dump report info */ /* dump report info */
ESP_LOGD(ROAMING_TAG, "rrm: neighbor report len=%d", report_len); ESP_LOGD(ROAMING_TAG, "rrm: neighbor report len=%d", report_len);
ESP_LOG_BUFFER_HEXDUMP(ROAMING_TAG, pos, report_len, ESP_LOG_DEBUG); ESP_LOG_BUFFER_HEXDUMP(ROAMING_TAG, pos, report_len, ESP_LOG_DEBUG);
ROAM_NEIGHBOR_LIST_LOCK();
if (g_roaming_app.btm_neighbor_list) { if (g_roaming_app.btm_neighbor_list) {
os_free(g_roaming_app.btm_neighbor_list); os_free(g_roaming_app.btm_neighbor_list);
g_roaming_app.btm_neighbor_list = NULL; g_roaming_app.btm_neighbor_list = NULL;
} }
/* create neighbor list */ /* create neighbor list */
g_roaming_app.btm_neighbor_list = get_btm_neighbor_list(pos + 1, report_len - 1); g_roaming_app.btm_neighbor_list = get_btm_neighbor_list(pos + 1, report_len - 1);
ROAM_NEIGHBOR_LIST_UNLOCK();
cleanup:
if (neighbor_report_event) {
os_free(neighbor_report_event);
}
}
static void roaming_app_neighbor_report_recv_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
wifi_event_neighbor_report_t *event = (wifi_event_neighbor_report_t*)event_data;
if (!event) {
return;
}
wifi_event_neighbor_report_t *event_copy = os_malloc(sizeof(wifi_event_neighbor_report_t) + event->report_len);
if (!event_copy) {
ESP_LOGE(ROAMING_TAG, "Failed to allocate memory for neighbor report event");
return;
}
memcpy(event_copy, event, sizeof(wifi_event_neighbor_report_t) + event->report_len);
if (eloop_register_timeout(0, 0, roaming_app_neighbor_report_recv_internal_handler, NULL, event_copy) != 0) {
os_free(event_copy);
}
} }
#endif /*PERIODIC_RRM_MONITORING*/ #endif /*PERIODIC_RRM_MONITORING*/
#if LOW_RSSI_ROAMING_ENABLED #if LOW_RSSI_ROAMING_ENABLED
static void roaming_app_rssi_low_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) static void roaming_app_rssi_low_internal_handler(void *ctx, void *data)
{ {
wifi_event_bss_rssi_low_t *event = event_data; wifi_event_bss_rssi_low_t *event = data;
ESP_LOGI(ROAMING_TAG, "%s:bss rssi is=%ld", __func__, event->rssi); ESP_LOGI(ROAMING_TAG, "%s:bss rssi is=%ld", __func__, event->rssi);
roaming_app_get_ap_info(&g_roaming_app.current_bss.ap); roaming_app_get_ap_info(&g_roaming_app.current_bss.ap);
@@ -473,25 +479,34 @@ static void roaming_app_rssi_low_handler(void* arg, esp_event_base_t event_base,
ESP_LOGD(ROAMING_TAG, "Resetting RSSI Threshold to %d", g_roaming_app.current_low_rssi_threshold); ESP_LOGD(ROAMING_TAG, "Resetting RSSI Threshold to %d", g_roaming_app.current_low_rssi_threshold);
esp_wifi_set_rssi_threshold(g_roaming_app.current_low_rssi_threshold); esp_wifi_set_rssi_threshold(g_roaming_app.current_low_rssi_threshold);
os_free(event);
}
static void roaming_app_rssi_low_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
wifi_event_bss_rssi_low_t *event = event_data;
if (!event) {
return;
}
wifi_event_bss_rssi_low_t *event_copy = os_malloc(sizeof(wifi_event_bss_rssi_low_t));
if (!event_copy) {
ESP_LOGE(ROAMING_TAG, "Failed to allocate memory for rssi low event");
return;
}
memcpy(event_copy, event, sizeof(wifi_event_bss_rssi_low_t));
if (eloop_register_timeout(0, 0, roaming_app_rssi_low_internal_handler, NULL, event_copy) != 0) {
os_free(event_copy);
}
} }
#endif #endif
#if NETWORK_ASSISTED_ROAMING_ENABLED #if NETWORK_ASSISTED_ROAMING_ENABLED
static void trigger_network_assisted_roam(void) static void trigger_network_assisted_roam(void)
{ {
#if PERIODIC_RRM_MONITORING
if (g_roaming_app.current_bss.rrm_support) {
ROAM_NEIGHBOR_LIST_LOCK();
}
#endif /*PERIODIC_RRM_MONITORING*/
if (esp_wnm_send_bss_transition_mgmt_query(REASON_RSSI, g_roaming_app.btm_neighbor_list, 1) < 0) { if (esp_wnm_send_bss_transition_mgmt_query(REASON_RSSI, g_roaming_app.btm_neighbor_list, 1) < 0) {
ESP_LOGD(ROAMING_TAG, "failed to send btm query"); ESP_LOGD(ROAMING_TAG, "failed to send btm query");
} }
#if PERIODIC_RRM_MONITORING
if (g_roaming_app.current_bss.rrm_support) {
ROAM_NEIGHBOR_LIST_UNLOCK();
}
#endif /*PERIODIC_RRM_MONITORING*/
ESP_LOGD(ROAMING_TAG, "Sent BTM Query"); ESP_LOGD(ROAMING_TAG, "Sent BTM Query");
gettimeofday(&g_roaming_app.last_roamed_time, NULL); gettimeofday(&g_roaming_app.last_roamed_time, NULL);
#if LEGACY_ROAM_ENABLED #if LEGACY_ROAM_ENABLED
@@ -630,9 +645,6 @@ static bool candidate_security_match(wifi_ap_record_t candidate)
} }
#if TODO // application doesn't have a way to know SAE-PK enabled AP atm #if TODO // application doesn't have a way to know SAE-PK enabled AP atm
if (transition_disable & TRANSITION_DISABLE_SAE_PK) { if (transition_disable & TRANSITION_DISABLE_SAE_PK) {
/* This is a simplification. A more accurate check would involve
* parsing the candidate's RSN IE to see if it supports SAE-PK.
* For now, we reject all SAE APs if SAE-PK is enforced. */
if (candidate.authmode == WIFI_AUTH_WPA3_PSK) { if (candidate.authmode == WIFI_AUTH_WPA3_PSK) {
return false; return false;
} }
@@ -649,9 +661,6 @@ static bool candidate_security_match(wifi_ap_record_t candidate)
wifi_config_t wifi_cfg = {0}; wifi_config_t wifi_cfg = {0};
esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg); esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg);
if (wifi_cfg.sta.owe_enabled && OWE_COMPATIBLE(curr_auth, cand_auth)) { if (wifi_cfg.sta.owe_enabled && OWE_COMPATIBLE(curr_auth, cand_auth)) {
/*
* OWE <--> Open allowed if threshold is Open
*/
if (wifi_cfg.sta.threshold.authmode == WIFI_AUTH_OPEN) { if (wifi_cfg.sta.threshold.authmode == WIFI_AUTH_OPEN) {
ESP_LOGV(ROAMING_TAG, "transition between OWE and open permitted"); ESP_LOGV(ROAMING_TAG, "transition between OWE and open permitted");
return true; return true;
@@ -661,7 +670,7 @@ static bool candidate_security_match(wifi_ap_record_t candidate)
} }
} else if (wifi_cfg.sta.threshold.authmode > cand_auth) { } else if (wifi_cfg.sta.threshold.authmode > cand_auth) {
/* If the authmode of the candidate AP is less than our threshold, it /* If the authmode of the candidate AP is less than our threshold, it
* will fail during connection*/ * will fail during connection */
ESP_LOGV(ROAMING_TAG, "Authmode threshold failure %d -> %d", wifi_cfg.sta.threshold.authmode, cand_auth); ESP_LOGV(ROAMING_TAG, "Authmode threshold failure %d -> %d", wifi_cfg.sta.threshold.authmode, cand_auth);
return false; return false;
} else if (PSK_COMPATIBLE(curr_auth, cand_auth)) { } else if (PSK_COMPATIBLE(curr_auth, cand_auth)) {
@@ -713,7 +722,6 @@ static bool is_bssid_blacklisted(const uint8_t *bssid)
return false; return false;
} }
/* Remember to always call this function with the ROAM_SCAN_RESULTS_LOCK */
static void parse_scan_results_and_roam(void) static void parse_scan_results_and_roam(void)
{ {
int8_t rssi_threshold = g_roaming_app.current_rssi_threshold; int8_t rssi_threshold = g_roaming_app.current_rssi_threshold;
@@ -762,26 +770,21 @@ static void parse_scan_results_and_roam(void)
static void scan_done_event_handler(void *arg, ETS_STATUS status) static void scan_done_event_handler(void *arg, ETS_STATUS status)
{ {
if (status == ETS_OK) { if (status == ETS_OK) {
ROAM_SCAN_RESULTS_LOCK();
ESP_LOGD(ROAMING_TAG, "Scan Done properly"); ESP_LOGD(ROAMING_TAG, "Scan Done properly");
g_roaming_app.scanned_aps.current_count = MAX_CANDIDATE_COUNT; g_roaming_app.scanned_aps.current_count = MAX_CANDIDATE_COUNT;
esp_wifi_scan_get_ap_records(&g_roaming_app.scanned_aps.current_count, g_roaming_app.scanned_aps.ap_records); esp_wifi_scan_get_ap_records(&g_roaming_app.scanned_aps.current_count, g_roaming_app.scanned_aps.ap_records);
print_ap_records(&g_roaming_app.scanned_aps); print_ap_records(&g_roaming_app.scanned_aps);
parse_scan_results_and_roam(); parse_scan_results_and_roam();
ROAM_SCAN_RESULTS_UNLOCK();
} else { } else {
ESP_LOGD(ROAMING_TAG, "Scan Done with error %d ", status); ESP_LOGD(ROAMING_TAG, "Scan Done with error %d ", status);
} }
ROAM_SCAN_RESULTS_LOCK();
g_roaming_app.scan_ongoing = false; g_roaming_app.scan_ongoing = false;
ROAM_SCAN_RESULTS_UNLOCK();
} }
static bool conduct_scan(void) static bool conduct_scan(void)
{ {
/* Update scan time in global structure */
gettimeofday(&g_roaming_app.scanned_aps.time, NULL); gettimeofday(&g_roaming_app.scanned_aps.time, NULL);
/* Issue scan */
os_memset(&g_roaming_app.scanned_aps, 0, sizeof(struct scanned_ap_info)); os_memset(&g_roaming_app.scanned_aps, 0, sizeof(struct scanned_ap_info));
/* Issue scan */
if (esp_wifi_promiscuous_scan_start(&g_roaming_app.config.scan_config, scan_done_event_handler) < 0) { if (esp_wifi_promiscuous_scan_start(&g_roaming_app.config.scan_config, scan_done_event_handler) < 0) {
ESP_LOGE(ROAMING_TAG, "failed to issue scan"); ESP_LOGE(ROAMING_TAG, "failed to issue scan");
return false; return false;
@@ -794,7 +797,6 @@ static void determine_best_ap(int8_t rssi_threshold)
{ {
struct timeval now; struct timeval now;
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
ROAM_SCAN_RESULTS_LOCK();
/* If the scan results are recent enough or a scan is already ongoing we should not trigger a new scan */ /* If the scan results are recent enough or a scan is already ongoing we should not trigger a new scan */
if (!g_roaming_app.scan_ongoing) { if (!g_roaming_app.scan_ongoing) {
g_roaming_app.scan_ongoing = true; g_roaming_app.scan_ongoing = true;
@@ -810,7 +812,6 @@ static void determine_best_ap(int8_t rssi_threshold)
} else if(rssi_threshold < g_roaming_app.current_rssi_threshold) { } else if(rssi_threshold < g_roaming_app.current_rssi_threshold) {
g_roaming_app.current_rssi_threshold = rssi_threshold; g_roaming_app.current_rssi_threshold = rssi_threshold;
} }
ROAM_SCAN_RESULTS_UNLOCK();
} }
#if PERIODIC_SCAN_MONITORING #if PERIODIC_SCAN_MONITORING
static void periodic_scan_roam(struct timeval *now) static void periodic_scan_roam(struct timeval *now)
@@ -913,6 +914,7 @@ static int8_t parse_scan_chan_list(void)
{ {
int8_t ret = 0; int8_t ret = 0;
char *scan_chan_string = NULL; char *scan_chan_string = NULL;
char *scan_chan_string_p = NULL;
if (validate_scan_chan_list(SCAN_PREFERRED_CHAN_LIST) == false) { if (validate_scan_chan_list(SCAN_PREFERRED_CHAN_LIST) == false) {
ESP_LOGE(ROAMING_TAG, "scan chan list validation failed."); ESP_LOGE(ROAMING_TAG, "scan chan list validation failed.");
ret = -1; ret = -1;
@@ -926,22 +928,27 @@ static int8_t parse_scan_chan_list(void)
} }
strlcpy(scan_chan_string, SCAN_PREFERRED_CHAN_LIST, strlen(SCAN_PREFERRED_CHAN_LIST) + 1); strlcpy(scan_chan_string, SCAN_PREFERRED_CHAN_LIST, strlen(SCAN_PREFERRED_CHAN_LIST) + 1);
char* token; char* token;
token = strsep(&scan_chan_string, ","); scan_chan_string_p = scan_chan_string;
token = strsep(&scan_chan_string_p, ",");
g_roaming_app.config.scan_config.channel_bitmap.ghz_2_channels = 0; g_roaming_app.config.scan_config.channel_bitmap.ghz_2_channels = 0;
g_roaming_app.config.scan_config.channel_bitmap.ghz_5_channels = 0;
while (token != NULL) { while (token != NULL) {
uint8_t channel = atoi(token); uint8_t channel = atoi(token);
/* Check if the number is within the required range */ /* Check if the number is within the required range */
if (channel >= 1 && channel <= 14) { if (channel >= 1 && channel <= 14) {
/* Check if the number is already present in the array */
g_roaming_app.config.scan_config.channel_bitmap.ghz_2_channels |= (1 << channel); g_roaming_app.config.scan_config.channel_bitmap.ghz_2_channels |= (1 << channel);
#if CONFIG_SOC_WIFI_SUPPORT_5G
} else if (channel >= 36 && channel <= 177) {
g_roaming_app.config.scan_config.channel_bitmap.ghz_5_channels |= CHANNEL_TO_BIT(channel);
#endif
} else { } else {
ESP_LOGE(ROAMING_TAG, "Channel out of range: %d", channel); ESP_LOGE(ROAMING_TAG, "Channel out of range: %d", channel);
ret = -1; ret = -1;
goto cleanup; goto cleanup;
} }
token = strsep(&scan_chan_string, ","); token = strsep(&scan_chan_string_p, ",");
} }
cleanup: cleanup:
@@ -996,14 +1003,6 @@ static esp_err_t init_config_params(void)
static esp_err_t init_scan_config(void) static esp_err_t init_scan_config(void)
{ {
if (!scan_results_lock) {
scan_results_lock = os_recursive_mutex_create();
if (!scan_results_lock) {
ESP_LOGE(ROAMING_TAG, "%s: failed to create scan results lock", __func__);
return ESP_FAIL;
}
}
if (strcmp(DEFAULT_PREFERRED_SCAN_CHAN_LIST, SCAN_PREFERRED_CHAN_LIST)) { if (strcmp(DEFAULT_PREFERRED_SCAN_CHAN_LIST, SCAN_PREFERRED_CHAN_LIST)) {
ESP_ERROR_CHECK(parse_scan_chan_list()); ESP_ERROR_CHECK(parse_scan_chan_list());
} }
@@ -1059,25 +1058,19 @@ void roam_deinit_app(void)
#if PERIODIC_SCAN_MONITORING #if PERIODIC_SCAN_MONITORING
g_roaming_app.periodic_scan_active = false; g_roaming_app.periodic_scan_active = false;
eloop_cancel_timeout(roaming_app_periodic_scan_internal_handler, NULL, NULL);
#endif /*PERIODIC_SCAN_MONITORING*/ #endif /*PERIODIC_SCAN_MONITORING*/
#if PERIODIC_RRM_MONITORING #if PERIODIC_RRM_MONITORING
ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_NEIGHBOR_REP, ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_NEIGHBOR_REP,
&roaming_app_neighbor_report_recv_handler)); &roaming_app_neighbor_report_recv_handler));
/* Disabling the periodic scan and RRM events */ /* Disabling the periodic scan and RRM events */
g_roaming_app.periodic_rrm_active = false; g_roaming_app.periodic_rrm_active = false;
eloop_cancel_timeout(roaming_app_periodic_rrm_internal_handler, NULL, NULL);
if (g_roaming_app.btm_neighbor_list) { if (g_roaming_app.btm_neighbor_list) {
os_free(g_roaming_app.btm_neighbor_list); os_free(g_roaming_app.btm_neighbor_list);
g_roaming_app.btm_neighbor_list = NULL; g_roaming_app.btm_neighbor_list = NULL;
} }
if (neighbor_list_lock) {
os_mutex_delete(neighbor_list_lock);
neighbor_list_lock = NULL;
}
#endif /*PERIODIC_RRM_MONITORING*/ #endif /*PERIODIC_RRM_MONITORING*/
if (scan_results_lock) {
os_mutex_delete(scan_results_lock);
scan_results_lock = NULL;
}
} }
#if CONFIG_ESP_WIFI_ROAMING_BSSID_BLACKLIST #if CONFIG_ESP_WIFI_ROAMING_BSSID_BLACKLIST

View File

@@ -31,6 +31,7 @@
#include "esp_eap_client.h" #include "esp_eap_client.h"
#include "esp_common_i.h" #include "esp_common_i.h"
#include "esp_owe_i.h" #include "esp_owe_i.h"
#include "esp_roaming.h"
#include "esp_wps.h" #include "esp_wps.h"
#include "esp_wps_i.h" #include "esp_wps_i.h"
@@ -140,6 +141,9 @@ bool wpa_attach(void)
ret = (esp_wifi_register_eapol_txdonecb_internal(eapol_txcb) == ESP_OK); ret = (esp_wifi_register_eapol_txdonecb_internal(eapol_txcb) == ESP_OK);
} }
esp_set_scan_ie(); esp_set_scan_ie();
#if CONFIG_ESP_WIFI_ENABLE_ROAMING_APP
roam_init_app();
#endif
return ret; return ret;
} }
@@ -192,6 +196,9 @@ void wpa_ap_get_peer_spp_msg(void *sm_data, bool *spp_cap, bool *spp_req)
bool wpa_deattach(void) bool wpa_deattach(void)
{ {
struct wpa_sm *sm = &gWpaSm; struct wpa_sm *sm = &gWpaSm;
#if CONFIG_ESP_WIFI_ENABLE_ROAMING_APP
roam_deinit_app();
#endif
esp_wpa3_free_sae_data(); esp_wpa3_free_sae_data();
#ifdef CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT #ifdef CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT
if (sm->wpa_sm_eap_disable) { if (sm->wpa_sm_eap_disable) {