mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
fix(roaming): prevent timeout payload double-free on deinit
Track timeout user_data before registration, untrack on register failure
This commit is contained in:
@@ -608,12 +608,17 @@ menu "Wi-Fi"
|
||||
config ESP_WIFI_ENABLE_ROAMING_APP
|
||||
bool "Advanced support for Wi-Fi Roaming (Experimental)"
|
||||
depends on IDF_EXPERIMENTAL_FEATURES
|
||||
select ESP_WIFI_11KV_SUPPORT
|
||||
default n
|
||||
help
|
||||
Enable Espressif's roaming app to allow for efficient Wi-Fi roaming.
|
||||
This includes configurable periodic environment scans, maintaining a cache of the
|
||||
best APs, handling low rssi events etc.
|
||||
|
||||
802.11k/v is selected so roaming-app scans can deliver beacon/probe frames to
|
||||
the supplicant BSS table used by candidate_security_match() for RSN IE checks.
|
||||
Without it, PMF/SAE-PK/H2E validation can fall back to coarse authmode heuristics.
|
||||
|
||||
Risk Warning
|
||||
Please note that this feature is still experimental and enabling this potentially can
|
||||
lead to unpredictable scanning, connection and roaming attempts.
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "common/wpa_common.h"
|
||||
#include "esp_wpas_glue.h"
|
||||
#include "common/bss.h"
|
||||
#include "common/wpa_supplicant_i.h"
|
||||
|
||||
extern struct wpa_supplicant g_wpa_supp;
|
||||
|
||||
@@ -42,6 +43,8 @@ extern bool current_task_is_wifi_task(void);
|
||||
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);
|
||||
|
||||
static bool s_roaming_bss_ie_scan_active;
|
||||
|
||||
static int wifi_post_roam_event(struct cand_bss *bss);
|
||||
static void determine_best_ap(int8_t rssi_threshold);
|
||||
static bool is_bssid_blacklisted(const uint8_t *bssid);
|
||||
@@ -124,6 +127,20 @@ static void roaming_app_free_tracked_timeout_user_data(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int roaming_app_register_timeout_with_user_data(unsigned int secs, unsigned int usecs,
|
||||
eloop_timeout_handler handler, void *eloop_data,
|
||||
void *user_data)
|
||||
{
|
||||
roaming_app_track_timeout_user_data(user_data);
|
||||
|
||||
if (eloop_register_timeout(secs, usecs, handler, eloop_data, user_data) != 0) {
|
||||
roaming_app_untrack_timeout_user_data(user_data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void esp_wifi_roaming_set_current_bssid(const uint8_t *bssid)
|
||||
{
|
||||
if (bssid) {
|
||||
@@ -1118,10 +1135,8 @@ void roam_sta_disconnected(void *data)
|
||||
return;
|
||||
}
|
||||
os_memcpy(disconn, data, sizeof(*disconn));
|
||||
if (eloop_register_timeout(0, 0, roaming_app_disconnected_event_handler, NULL, disconn) != 0) {
|
||||
if (roaming_app_register_timeout_with_user_data(0, 0, roaming_app_disconnected_event_handler, NULL, disconn) != 0) {
|
||||
os_free(disconn);
|
||||
} else {
|
||||
roaming_app_track_timeout_user_data(disconn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1311,10 +1326,8 @@ static void roaming_app_neighbor_report_recv_handler(void* arg, esp_event_base_t
|
||||
}
|
||||
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) {
|
||||
if (roaming_app_register_timeout_with_user_data(0, 0, roaming_app_neighbor_report_recv_internal_handler, NULL, event_copy) != 0) {
|
||||
os_free(event_copy);
|
||||
} else {
|
||||
roaming_app_track_timeout_user_data(event_copy);
|
||||
}
|
||||
}
|
||||
#endif /*PERIODIC_RRM_MONITORING*/
|
||||
@@ -1372,10 +1385,8 @@ static void roaming_app_rssi_low_handler(void* arg, esp_event_base_t event_base,
|
||||
}
|
||||
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) {
|
||||
if (roaming_app_register_timeout_with_user_data(0, 0, roaming_app_rssi_low_internal_handler, NULL, event_copy) != 0) {
|
||||
os_free(event_copy);
|
||||
} else {
|
||||
roaming_app_track_timeout_user_data(event_copy);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1493,6 +1504,7 @@ void roaming_app_trigger_roam(struct cand_bss *bss)
|
||||
ESP_LOGD(ROAMING_TAG, "Processing trigger roaming request.");
|
||||
if (g_roaming_app.pending_roam_bss) {
|
||||
eloop_cancel_timeout(roaming_app_trigger_roam_internal_handler, NULL, g_roaming_app.pending_roam_bss);
|
||||
roaming_app_untrack_timeout_user_data(g_roaming_app.pending_roam_bss);
|
||||
os_free(g_roaming_app.pending_roam_bss);
|
||||
g_roaming_app.pending_roam_bss = NULL;
|
||||
}
|
||||
@@ -1503,8 +1515,8 @@ void roaming_app_trigger_roam(struct cand_bss *bss)
|
||||
ESP_LOGD(ROAMING_TAG,
|
||||
"Deferring roam during backoff (elapsed %ld s since anchor), reschedule in %ld s",
|
||||
elapsed_sec, remaining_sec);
|
||||
if (eloop_register_timeout((unsigned int)remaining_sec, 0,
|
||||
roaming_app_trigger_roam_internal_handler, NULL, (void *)bss)) {
|
||||
if (roaming_app_register_timeout_with_user_data((unsigned int)remaining_sec, 0,
|
||||
roaming_app_trigger_roam_internal_handler, NULL, (void *)bss)) {
|
||||
ESP_LOGE(ROAMING_TAG, "Could not register roaming event.");
|
||||
goto free_bss;
|
||||
}
|
||||
@@ -1578,12 +1590,11 @@ static int wifi_post_roam_event(struct cand_bss *bss)
|
||||
}
|
||||
os_memcpy(cand_bss, bss, sizeof(struct cand_bss));
|
||||
/* trigger the roaming event */
|
||||
if (eloop_register_timeout(0, 0, roaming_app_trigger_roam_internal_handler, NULL, (void *)cand_bss)) {
|
||||
if (roaming_app_register_timeout_with_user_data(0, 0, roaming_app_trigger_roam_internal_handler, NULL, (void *)cand_bss)) {
|
||||
ESP_LOGE(ROAMING_TAG, "Could not register roaming event.");
|
||||
os_free(cand_bss);
|
||||
return -1;
|
||||
}
|
||||
roaming_app_track_timeout_user_data(cand_bss);
|
||||
} else {
|
||||
ESP_LOGE(ROAMING_TAG, "Cannot trigger roaming event without any candidate APs");
|
||||
return -1;
|
||||
@@ -1862,8 +1873,53 @@ static void parse_scan_results_and_roam(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate wpa_bss with beacon/probe IEs during roaming-app scans (same as issue_scan). */
|
||||
static int roaming_app_prepare_bss_ie_collection(void)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
u64 scan_start_tsf;
|
||||
|
||||
/* Avoid conflicting with an in-progress RRM/WNM scan. */
|
||||
if (wpa_s->scanning) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
scan_start_tsf = esp_wifi_get_tsf_time(WIFI_IF_STA);
|
||||
if ((scan_start_tsf - wpa_s->scan_start_tsf) > 100000) {
|
||||
wpa_bss_flush(wpa_s);
|
||||
}
|
||||
|
||||
esp_wifi_get_macaddr_internal(WIFI_IF_STA, wpa_s->tsf_bssid);
|
||||
wpa_s->scan_start_tsf = scan_start_tsf;
|
||||
wpa_s->type |= (1 << WLAN_FC_STYPE_BEACON) | (1 << WLAN_FC_STYPE_PROBE_RESP);
|
||||
if (esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype) != ESP_OK) {
|
||||
wpa_s->type &= ~(1 << WLAN_FC_STYPE_BEACON) & ~(1 << WLAN_FC_STYPE_PROBE_RESP);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_bss_update_start(wpa_s);
|
||||
s_roaming_bss_ie_scan_active = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void roaming_app_finish_bss_ie_collection(void)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
|
||||
if (!s_roaming_bss_ie_scan_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_s->type &= ~(1 << WLAN_FC_STYPE_BEACON) & ~(1 << WLAN_FC_STYPE_PROBE_RESP);
|
||||
esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype);
|
||||
wpa_bss_update_end(wpa_s);
|
||||
s_roaming_bss_ie_scan_active = false;
|
||||
}
|
||||
|
||||
static void scan_done_event_handler(void *arg, ETS_STATUS status)
|
||||
{
|
||||
roaming_app_finish_bss_ie_collection();
|
||||
|
||||
if (status == ETS_OK) {
|
||||
esp_err_t err;
|
||||
|
||||
@@ -1892,11 +1948,16 @@ static void scan_done_event_handler(void *arg, ETS_STATUS status)
|
||||
}
|
||||
static bool conduct_scan(void)
|
||||
{
|
||||
/* Issue scan */
|
||||
bool bss_ie_collection = (roaming_app_prepare_bss_ie_collection() == 0);
|
||||
|
||||
if (esp_wifi_promiscuous_scan_start(&g_roaming_app.config.scan_config, scan_done_event_handler) != ESP_OK) {
|
||||
ESP_LOGE(ROAMING_TAG, "failed to issue scan");
|
||||
roaming_app_finish_bss_ie_collection();
|
||||
return false;
|
||||
}
|
||||
if (!bss_ie_collection) {
|
||||
ESP_LOGD(ROAMING_TAG, "Supplicant scan active; skip BSS IE collection for this roam scan");
|
||||
}
|
||||
ESP_LOGI(ROAMING_TAG, "Issued Scan");
|
||||
return true;
|
||||
}
|
||||
@@ -2185,6 +2246,7 @@ static void roaming_app_cancel_pending_events(void)
|
||||
eloop_cancel_timeout(roaming_app_disconnected_event_handler, ELOOP_ALL_CTX, ELOOP_ALL_CTX);
|
||||
eloop_cancel_timeout(roaming_app_trigger_roam_internal_handler, ELOOP_ALL_CTX, ELOOP_ALL_CTX);
|
||||
if (g_roaming_app.pending_roam_bss) {
|
||||
roaming_app_untrack_timeout_user_data(g_roaming_app.pending_roam_bss);
|
||||
os_free(g_roaming_app.pending_roam_bss);
|
||||
g_roaming_app.pending_roam_bss = NULL;
|
||||
}
|
||||
@@ -2209,6 +2271,8 @@ static int roaming_app_deinit_internal(void *ctx, void *data)
|
||||
(void) ctx;
|
||||
(void) data;
|
||||
g_roaming_app.app_active = false;
|
||||
roaming_app_finish_bss_ie_collection();
|
||||
g_roaming_app.scan_ongoing = false;
|
||||
roaming_app_cancel_pending_events();
|
||||
roaming_app_stop_periodic_monitors();
|
||||
roaming_app_reset_connect_hint_state();
|
||||
@@ -2288,11 +2352,10 @@ esp_err_t esp_wifi_blacklist_add(const uint8_t *bssid)
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(bssid_copy, bssid, ETH_ALEN);
|
||||
if (eloop_register_timeout(0, 0, roaming_app_blacklist_add_handler, NULL, bssid_copy) != 0) {
|
||||
if (roaming_app_register_timeout_with_user_data(0, 0, roaming_app_blacklist_add_handler, NULL, bssid_copy) != 0) {
|
||||
os_free(bssid_copy);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
roaming_app_track_timeout_user_data(bssid_copy);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -2339,11 +2402,10 @@ esp_err_t esp_wifi_blacklist_remove(const uint8_t *bssid)
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(bssid_copy, bssid, ETH_ALEN);
|
||||
if (eloop_register_timeout(0, 0, roaming_app_blacklist_remove_handler, NULL, bssid_copy) != 0) {
|
||||
if (roaming_app_register_timeout_with_user_data(0, 0, roaming_app_blacklist_remove_handler, NULL, bssid_copy) != 0) {
|
||||
os_free(bssid_copy);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
roaming_app_track_timeout_user_data(bssid_copy);
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user