mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
Merge branch 'bugfix/concurrency_hostapd_sae_queue_v5.4' into 'release/v5.4'
fix(wifi): Fix concurrency issues for hostapd_sae_queue for softap (v5.4) See merge request espressif/esp-idf!48366
This commit is contained in:
@@ -61,6 +61,9 @@ void *hostap_init(void)
|
||||
wifi_pmf_config_t pmf_cfg = {0};
|
||||
uint8_t authmode;
|
||||
uint8_t sae_ext = 0;
|
||||
#ifdef CONFIG_SAE
|
||||
struct hostapd_sae_commit_queue *q, *tmp;
|
||||
#endif
|
||||
|
||||
sae_ext = esp_wifi_ap_get_sae_ext_config_internal();
|
||||
|
||||
@@ -205,7 +208,6 @@ void *hostap_init(void)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
dl_list_init(&hapd->sae_commit_queue);
|
||||
auth_conf->sae_require_mfp = 1;
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
@@ -225,6 +227,35 @@ void *hostap_init(void)
|
||||
|
||||
return (void *)hapd;
|
||||
fail:
|
||||
#ifdef CONFIG_SAE
|
||||
if (hapd->sta_list_lock) {
|
||||
if (wpa3_hostap_auth_deinit()) {
|
||||
if (g_wpa3_hostap_auth_api_lock) {
|
||||
/* Block until WPA3 task gives the API lock after SIG_TASK_DEL teardown */
|
||||
WPA3_HOSTAP_AUTH_API_LOCK();
|
||||
WPA3_HOSTAP_AUTH_API_UNLOCK();
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"hostap_init fail: failed to post SIG_TASK_DEL, skipping WPA3 API lock wait");
|
||||
}
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
/*
|
||||
* hostap_init() failed before global_hapd was assigned, so the WPA3
|
||||
* hostap task has no registered hapd to drain this queue on exit;
|
||||
* free queued commits here before releasing hapd.
|
||||
*/
|
||||
dl_list_for_each_safe(q, tmp, &hapd->sae_commit_queue,
|
||||
struct hostapd_sae_commit_queue, list) {
|
||||
dl_list_del(&q->list);
|
||||
os_free(q);
|
||||
}
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
|
||||
os_mutex_delete(hapd->sta_list_lock);
|
||||
hapd->sta_list_lock = NULL;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
if (hapd->conf->ssid.wpa_passphrase != NULL) {
|
||||
os_free(hapd->conf->ssid.wpa_passphrase);
|
||||
}
|
||||
@@ -254,19 +285,6 @@ void hostapd_cleanup(struct hostapd_data *hapd)
|
||||
hapd->conf = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
|
||||
struct hostapd_sae_commit_queue *q, *tmp;
|
||||
|
||||
if (!dl_list_empty(&hapd->sae_commit_queue)) {
|
||||
dl_list_for_each_safe(q, tmp, &hapd->sae_commit_queue,
|
||||
struct hostapd_sae_commit_queue, list) {
|
||||
dl_list_del(&q->list);
|
||||
os_free(q);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SAE */
|
||||
#ifdef CONFIG_WPS_REGISTRAR
|
||||
if (esp_wifi_get_wps_type_internal() != WPS_TYPE_DISABLE ||
|
||||
esp_wifi_get_wps_status_internal() != WPS_STATUS_DISABLE) {
|
||||
@@ -292,11 +310,15 @@ bool hostap_deinit(void *data)
|
||||
wifi_ap_wps_disable_internal();
|
||||
#endif
|
||||
#ifdef CONFIG_SAE
|
||||
wpa3_hostap_auth_deinit();
|
||||
/* Wait till lock is released by wpa3 task */
|
||||
if (g_wpa3_hostap_auth_api_lock &&
|
||||
WPA3_HOSTAP_AUTH_API_LOCK() == pdTRUE) {
|
||||
WPA3_HOSTAP_AUTH_API_UNLOCK();
|
||||
if (wpa3_hostap_auth_deinit()) {
|
||||
/* Block until WPA3 task gives the API lock after SIG_TASK_DEL teardown */
|
||||
if (g_wpa3_hostap_auth_api_lock) {
|
||||
WPA3_HOSTAP_AUTH_API_LOCK();
|
||||
WPA3_HOSTAP_AUTH_API_UNLOCK();
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"hostap_deinit: failed to post SIG_TASK_DEL, skipping WPA3 API lock wait");
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
@@ -457,14 +479,31 @@ send_resp:
|
||||
#ifdef CONFIG_WPS_REGISTRAR
|
||||
static void ap_free_sta_timeout(void *ctx, void *data)
|
||||
{
|
||||
struct hostapd_data *hapd = (struct hostapd_data *) ctx;
|
||||
u8 *addr = (u8 *) data;
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
struct hostapd_data *hapd = (struct hostapd_data *)ctx;
|
||||
u8 *addr = (u8 *)data;
|
||||
struct sta_info *sta;
|
||||
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
sta = ap_get_sta_internal(hapd, addr);
|
||||
if (sta) {
|
||||
#ifdef CONFIG_SAE
|
||||
if (sta->lock) {
|
||||
if (os_semphr_take(sta->lock, 0)) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
ap_free_sta(hapd, sta);
|
||||
} else {
|
||||
atomic_store(&sta->remove_pending, true);
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
ap_free_sta(hapd, sta);
|
||||
} else {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
}
|
||||
|
||||
done:
|
||||
os_free(addr);
|
||||
}
|
||||
#endif
|
||||
@@ -472,42 +511,51 @@ static void ap_free_sta_timeout(void *ctx, void *data)
|
||||
bool wpa_ap_remove(u8* bssid)
|
||||
{
|
||||
struct hostapd_data *hapd = hostapd_get_hapd_data();
|
||||
struct sta_info *sta;
|
||||
|
||||
if (!hapd) {
|
||||
return false;
|
||||
}
|
||||
struct sta_info *sta = ap_get_sta(hapd, bssid);
|
||||
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
sta = ap_get_sta_internal(hapd, bssid);
|
||||
if (!sta) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
if (sta->lock) {
|
||||
if (os_semphr_take(sta->lock, 0)) {
|
||||
ap_free_sta(hapd, sta);
|
||||
} else {
|
||||
sta->remove_pending = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
#ifdef CONFIG_WPS_REGISTRAR
|
||||
wpa_printf(MSG_DEBUG, "wps_status=%d", wps_get_status());
|
||||
if (wps_get_status() == WPS_STATUS_PENDING) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
u8 *addr = os_malloc(ETH_ALEN);
|
||||
|
||||
if (!addr) {
|
||||
return false;
|
||||
}
|
||||
os_memcpy(addr, sta->addr, ETH_ALEN);
|
||||
os_memcpy(addr, bssid, ETH_ALEN);
|
||||
if (eloop_register_timeout(0, 10000, ap_free_sta_timeout, hapd, addr) != 0) {
|
||||
os_free(addr);
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
ap_free_sta(hapd, sta);
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_WPS_REGISTRAR */
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
if (sta->lock) {
|
||||
if (os_semphr_take(sta->lock, 0)) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
ap_free_sta(hapd, sta);
|
||||
} else {
|
||||
atomic_store(&sta->remove_pending, true);
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
ap_free_sta(hapd, sta);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -197,6 +197,11 @@ static esp_err_t wpa3_build_sae_confirm(void)
|
||||
|
||||
void esp_wpa3_free_sae_data(void)
|
||||
{
|
||||
if (g_sae_token) {
|
||||
wpabuf_free(g_sae_token);
|
||||
g_sae_token = NULL;
|
||||
}
|
||||
|
||||
if (g_sae_commit) {
|
||||
wpabuf_free(g_sae_commit);
|
||||
g_sae_commit = NULL;
|
||||
@@ -416,6 +421,7 @@ void esp_wifi_unregister_wpa3_cb(void)
|
||||
|
||||
static TaskHandle_t g_wpa3_hostap_task_hdl = NULL;
|
||||
static QueueHandle_t g_wpa3_hostap_evt_queue = NULL;
|
||||
/* Global API lock - created once, never deleted */
|
||||
SemaphoreHandle_t g_wpa3_hostap_auth_api_lock = NULL;
|
||||
|
||||
int wpa3_hostap_post_evt(uint32_t evt_id, uint32_t data)
|
||||
@@ -436,13 +442,21 @@ int wpa3_hostap_post_evt(uint32_t evt_id, uint32_t data)
|
||||
wpa_printf(MSG_DEBUG, "g_wpa3_hostap_auth_api_lock not found");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (evt.id == SIG_WPA3_RX_CONFIRM || evt.id == SIG_TASK_DEL) {
|
||||
if (evt.id == SIG_WPA3_RX_CONFIRM) {
|
||||
/* prioritising confirm for completing handshake for committed sta */
|
||||
if (os_queue_send_to_front(g_wpa3_hostap_evt_queue, &evt, 0) != pdPASS) {
|
||||
WPA3_HOSTAP_AUTH_API_UNLOCK();
|
||||
wpa_printf(MSG_DEBUG, "failed to add msg to queue front");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
} else if (evt.id == SIG_TASK_DEL) {
|
||||
/* Wi-Fi blocks until SIG_TASK_DEL is queued; only Wi-Fi calls wpa3_hostap_post_evt. */
|
||||
/* Hence there will be no deadlock for g_wpa3_hostap_auth_api_lock. */
|
||||
if (os_queue_send_to_front(g_wpa3_hostap_evt_queue, &evt, portMAX_DELAY) != pdPASS) {
|
||||
WPA3_HOSTAP_AUTH_API_UNLOCK();
|
||||
wpa_printf(MSG_DEBUG, "failed to add msg to queue front");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
} else {
|
||||
if (os_queue_send(g_wpa3_hostap_evt_queue, &evt, 0) != pdPASS) {
|
||||
WPA3_HOSTAP_AUTH_API_UNLOCK();
|
||||
@@ -463,17 +477,26 @@ static void wpa3_process_rx_commit(wpa3_hostap_auth_event_t *evt)
|
||||
struct hostapd_data *hapd = (struct hostapd_data *)esp_wifi_get_hostap_private_internal();
|
||||
struct sta_info *sta = NULL;
|
||||
int ret;
|
||||
|
||||
if (!hapd || !hapd->sta_list_lock) {
|
||||
wpa_printf(MSG_ERROR, "hapd or sta_list_lock not initialized in %s", __func__);
|
||||
return;
|
||||
}
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
frm = dl_list_first(&hapd->sae_commit_queue,
|
||||
struct hostapd_sae_commit_queue, list);
|
||||
if (!frm) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return;
|
||||
}
|
||||
|
||||
dl_list_del(&frm->list);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "SAE: Process next available message from queue");
|
||||
|
||||
sta = ap_get_sta(hapd, frm->bssid);
|
||||
sta = ap_get_sta_internal(hapd, frm->bssid);
|
||||
if (!sta) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
sta = ap_sta_add(hapd, frm->bssid);
|
||||
if (!sta) {
|
||||
wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
|
||||
@@ -483,19 +506,30 @@ static void wpa3_process_rx_commit(wpa3_hostap_auth_event_t *evt)
|
||||
0) != 0) {
|
||||
wpa_printf(MSG_INFO, "esp_send_sae_auth_reply: send failed");
|
||||
}
|
||||
goto free;
|
||||
os_free(frm);
|
||||
return;
|
||||
}
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
sta = ap_get_sta_internal(hapd, frm->bssid);
|
||||
if (!sta) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
os_free(frm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (sta->lock && os_semphr_take(sta->lock, 0)) {
|
||||
sta->sae_commit_processing = true;
|
||||
atomic_store(&sta->sae_commit_processing, true);
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
|
||||
ret = handle_auth_sae(hapd, sta, frm->msg, frm->len, frm->bssid, frm->auth_transaction, frm->status);
|
||||
|
||||
if (sta->remove_pending) {
|
||||
if (atomic_load(&sta->remove_pending)) {
|
||||
ap_free_sta(hapd, sta);
|
||||
goto free;
|
||||
os_free(frm);
|
||||
return;
|
||||
}
|
||||
sta->sae_commit_processing = false;
|
||||
atomic_store(&sta->sae_commit_processing, false);
|
||||
os_semphr_give(sta->lock);
|
||||
uint16_t aid = 0;
|
||||
if (ret != WLAN_STATUS_SUCCESS &&
|
||||
@@ -505,9 +539,11 @@ static void wpa3_process_rx_commit(wpa3_hostap_auth_event_t *evt)
|
||||
esp_wifi_ap_deauth_internal(frm->bssid, ret);
|
||||
}
|
||||
}
|
||||
os_free(frm);
|
||||
return;
|
||||
}
|
||||
|
||||
free:
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
os_free(frm);
|
||||
}
|
||||
|
||||
@@ -517,45 +553,70 @@ static void wpa3_process_rx_confirm(wpa3_hostap_auth_event_t *evt)
|
||||
struct sta_info *sta = NULL;
|
||||
int ret = WLAN_STATUS_SUCCESS;
|
||||
struct sae_hostap_confirm_data *frm = (struct sae_hostap_confirm_data *)evt->data;
|
||||
|
||||
if (!frm) {
|
||||
return;
|
||||
}
|
||||
sta = ap_get_sta(hapd, frm->bssid);
|
||||
if (!sta) {
|
||||
|
||||
if (!hapd || !hapd->sta_list_lock) {
|
||||
wpa_printf(MSG_ERROR, "hapd or sta_list_lock not initialized in %s", __func__);
|
||||
os_free(frm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sta->lock && os_semphr_take(sta->lock, 0)) {
|
||||
ret = handle_auth_sae(hapd, sta, frm->msg, frm->len, frm->bssid, frm->auth_transaction, frm->status);
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
sta = ap_get_sta_internal(hapd, frm->bssid);
|
||||
if (!sta) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
os_free(frm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sta->remove_pending) {
|
||||
if (!sta->lock) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: sta->lock is NULL for " MACSTR, MAC2STR(frm->bssid));
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
os_free(frm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (os_semphr_take(sta->lock, 0) != pdTRUE) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
os_free(frm);
|
||||
return;
|
||||
}
|
||||
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
|
||||
ret = handle_auth_sae(hapd, sta, frm->msg, frm->len, frm->bssid, frm->auth_transaction, frm->status);
|
||||
|
||||
if (atomic_load(&sta->remove_pending)) {
|
||||
ap_free_sta(hapd, sta);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ret == WLAN_STATUS_SUCCESS) {
|
||||
if (sta->sae_data && esp_send_sae_auth_reply(hapd, sta->addr, frm->bssid, WLAN_AUTH_SAE, 2,
|
||||
WLAN_STATUS_SUCCESS, wpabuf_head(sta->sae_data), wpabuf_len(sta->sae_data)) != ESP_OK) {
|
||||
ap_free_sta(hapd, sta);
|
||||
goto done;
|
||||
}
|
||||
if (ret == WLAN_STATUS_SUCCESS) {
|
||||
if (sta->sae_data && esp_send_sae_auth_reply(hapd, sta->addr, frm->bssid, WLAN_AUTH_SAE, 2,
|
||||
WLAN_STATUS_SUCCESS, wpabuf_head(sta->sae_data), wpabuf_len(sta->sae_data)) != ESP_OK) {
|
||||
ap_free_sta(hapd, sta);
|
||||
goto done;
|
||||
}
|
||||
if (esp_wifi_ap_notify_node_sae_auth_done(frm->bssid) != true) {
|
||||
ap_free_sta(hapd, sta);
|
||||
goto done;
|
||||
}
|
||||
if (esp_wifi_ap_notify_node_sae_auth_done(frm->bssid) != true) {
|
||||
ap_free_sta(hapd, sta);
|
||||
goto done;
|
||||
}
|
||||
os_semphr_give(sta->lock);
|
||||
if (ret != WLAN_STATUS_SUCCESS) {
|
||||
uint16_t aid = 0;
|
||||
esp_wifi_ap_get_sta_aid(frm->bssid, &aid);
|
||||
if (aid == 0) {
|
||||
esp_wifi_ap_deauth_internal(frm->bssid, ret);
|
||||
} else {
|
||||
if (sta && sta->sae_data) {
|
||||
wpabuf_free(sta->sae_data);
|
||||
sta->sae_data = NULL;
|
||||
}
|
||||
} else {
|
||||
uint16_t aid = 0;
|
||||
esp_wifi_ap_get_sta_aid(frm->bssid, &aid);
|
||||
if (aid == 0) {
|
||||
os_semphr_give(sta->lock);
|
||||
esp_wifi_ap_deauth_internal(frm->bssid, ret);
|
||||
} else {
|
||||
if (sta->sae_data) {
|
||||
wpabuf_free(sta->sae_data);
|
||||
sta->sae_data = NULL;
|
||||
}
|
||||
os_semphr_give(sta->lock);
|
||||
}
|
||||
}
|
||||
done:
|
||||
@@ -601,34 +662,68 @@ static void esp_wpa3_hostap_task(void *pvParameters)
|
||||
os_queue_delete(g_wpa3_hostap_evt_queue);
|
||||
g_wpa3_hostap_evt_queue = NULL;
|
||||
|
||||
struct hostapd_data *hapd = hostapd_get_hapd_data();
|
||||
if (hapd && hapd->sta_list_lock) {
|
||||
struct hostapd_sae_commit_queue *q, *tmp;
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
dl_list_for_each_safe(q, tmp, &hapd->sae_commit_queue,
|
||||
struct hostapd_sae_commit_queue, list) {
|
||||
dl_list_del(&q->list);
|
||||
os_free(q);
|
||||
}
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
/*
|
||||
* Safe to delete sta_list_lock after unlock: only the WPA3 hostap task and
|
||||
* the Wi-Fi task take this lock; the Wi-Fi task is blocked while posting
|
||||
* SIG_TASK_DEL, so it cannot acquire sta_list_lock again until teardown
|
||||
* sequencing completes.
|
||||
*/
|
||||
os_mutex_delete(hapd->sta_list_lock);
|
||||
hapd->sta_list_lock = NULL;
|
||||
}
|
||||
|
||||
if (g_wpa3_hostap_auth_api_lock) {
|
||||
WPA3_HOSTAP_AUTH_API_UNLOCK();
|
||||
}
|
||||
/* At this point, task is deleted*/
|
||||
/* At this point, task is deleted */
|
||||
os_task_delete(NULL);
|
||||
}
|
||||
|
||||
int wpa3_hostap_auth_init(void *data)
|
||||
{
|
||||
struct hostapd_data *hapd = (struct hostapd_data *)data;
|
||||
if (g_wpa3_hostap_evt_queue) {
|
||||
wpa_printf(MSG_ERROR, "esp_wpa3_hostap_task has already been initialised");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
hapd->sta_list_lock = os_mutex_create();
|
||||
if (!hapd->sta_list_lock) {
|
||||
wpa_printf(MSG_ERROR, "wpa3_hostap_auth_init: failed to create sta_list_lock");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* g_wpa3_hostap_auth_api_lock is global - created once, never deleted */
|
||||
if (g_wpa3_hostap_auth_api_lock == NULL) {
|
||||
g_wpa3_hostap_auth_api_lock = os_semphr_create(1, 1);
|
||||
if (!g_wpa3_hostap_auth_api_lock) {
|
||||
wpa_printf(MSG_ERROR, "wpa3_hostap_auth_init: failed to create WPA3 hostap auth API lock");
|
||||
os_mutex_delete(hapd->sta_list_lock);
|
||||
hapd->sta_list_lock = NULL;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
g_wpa3_hostap_evt_queue = os_queue_create(10, sizeof(wpa3_hostap_auth_event_t));
|
||||
g_wpa3_hostap_evt_queue = os_queue_create(10, sizeof(wpa3_hostap_auth_event_t));
|
||||
if (!g_wpa3_hostap_evt_queue) {
|
||||
wpa_printf(MSG_ERROR, "wpa3_hostap_auth_init: failed to create queue");
|
||||
os_mutex_delete(hapd->sta_list_lock);
|
||||
hapd->sta_list_lock = NULL;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
dl_list_init(&hapd->sae_commit_queue);
|
||||
|
||||
if (os_task_create(esp_wpa3_hostap_task, "esp_wpa3_hostap_task",
|
||||
WPA3_HOSTAP_HANDLE_AUTH_TASK_STACK_SIZE, NULL,
|
||||
WPA3_HOSTAP_HANDLE_AUTH_TASK_PRIORITY,
|
||||
@@ -636,6 +731,8 @@ int wpa3_hostap_auth_init(void *data)
|
||||
wpa_printf(MSG_ERROR, "wpa3_hostap_auth_init: failed to create task");
|
||||
os_queue_delete(g_wpa3_hostap_evt_queue);
|
||||
g_wpa3_hostap_evt_queue = NULL;
|
||||
os_mutex_delete(hapd->sta_list_lock);
|
||||
hapd->sta_list_lock = NULL;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@@ -647,9 +744,8 @@ bool wpa3_hostap_auth_deinit(void)
|
||||
if (wpa3_hostap_post_evt(SIG_TASK_DEL, 0) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "failed to send task delete event");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int wpa3_hostap_handle_auth(u8 *buf, size_t len, u32 auth_transaction, u16 status, u8 *bssid)
|
||||
@@ -658,16 +754,25 @@ static int wpa3_hostap_handle_auth(u8 *buf, size_t len, u32 auth_transaction, u1
|
||||
if (!hapd) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
struct sta_info *sta = ap_get_sta(hapd, bssid);
|
||||
|
||||
if (auth_transaction == SAE_MSG_COMMIT) {
|
||||
if (sta && sta->sae_commit_processing) {
|
||||
/* Ignore commit msg as we are already processing commit msg for this station */
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
struct sta_info *sta = ap_get_sta_internal(hapd, bssid);
|
||||
if (sta && atomic_load(&sta->sae_commit_processing)) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return ESP_OK;
|
||||
}
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return auth_sae_queue(hapd, buf, len, bssid, status, auth_transaction);
|
||||
}
|
||||
|
||||
if (sta && auth_transaction == SAE_MSG_CONFIRM) {
|
||||
if (auth_transaction == SAE_MSG_CONFIRM) {
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
bool sta_exists = (ap_get_sta_internal(hapd, bssid) != NULL);
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
if (!sta_exists) {
|
||||
return ESP_OK;
|
||||
}
|
||||
struct sae_hostap_confirm_data *frm = os_malloc(sizeof(struct sae_hostap_confirm_data) + len);
|
||||
if (!frm) {
|
||||
wpa_printf(MSG_ERROR, "failed to allocate memory for confirm event");
|
||||
|
||||
@@ -107,6 +107,10 @@ struct hostapd_data {
|
||||
struct sta_info *sta_hash[STA_HASH_SIZE];
|
||||
int num_sta; /* number of entries in sta_list */
|
||||
|
||||
#ifdef ESP_SUPPLICANT
|
||||
void *sta_list_lock;
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
|
||||
struct eapol_authenticator *eapol_auth;
|
||||
struct wpa_authenticator *wpa_auth;
|
||||
|
||||
@@ -169,4 +173,21 @@ const struct hostapd_eap_user *
|
||||
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
|
||||
size_t identity_len, int phase2);
|
||||
|
||||
#ifdef ESP_SUPPLICANT
|
||||
#define HOSTAPD_STA_LIST_LOCK(hapd) \
|
||||
do { \
|
||||
if ((hapd) && (hapd)->sta_list_lock) \
|
||||
os_mutex_lock((hapd)->sta_list_lock); \
|
||||
} while (0)
|
||||
|
||||
#define HOSTAPD_STA_LIST_UNLOCK(hapd) \
|
||||
do { \
|
||||
if ((hapd) && (hapd)->sta_list_lock) \
|
||||
os_mutex_unlock((hapd)->sta_list_lock); \
|
||||
} while (0)
|
||||
#else
|
||||
#define HOSTAPD_STA_LIST_LOCK(hapd) do { } while (0)
|
||||
#define HOSTAPD_STA_LIST_UNLOCK(hapd) do { } while (0)
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
|
||||
#endif /* HOSTAPD_H */
|
||||
|
||||
@@ -151,7 +151,7 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
#ifdef ESP_SUPPLICANT
|
||||
if (sta->remove_pending) {
|
||||
if (atomic_load(&sta->remove_pending)) {
|
||||
reply_res = -1;
|
||||
} else {
|
||||
reply_res = esp_send_sae_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
|
||||
@@ -177,7 +177,7 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
#ifdef ESP_SUPPLICANT
|
||||
if (sta->remove_pending) {
|
||||
if (atomic_load(&sta->remove_pending)) {
|
||||
reply_res = -1;
|
||||
wpabuf_free(data);
|
||||
} else {
|
||||
@@ -204,6 +204,10 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef ESP_SUPPLICANT
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (sta->sae &&
|
||||
(sta->sae->state == SAE_COMMITTED ||
|
||||
@@ -211,6 +215,9 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd)
|
||||
open++;
|
||||
}
|
||||
if (open >= hapd->conf->sae_anti_clogging_threshold) {
|
||||
#ifdef ESP_SUPPLICANT
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -220,9 +227,16 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd)
|
||||
* potentially result in too many open sessions. */
|
||||
if (open + dl_list_len(&hapd->sae_commit_queue) >=
|
||||
hapd->conf->sae_anti_clogging_threshold) {
|
||||
#ifdef ESP_SUPPLICANT
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef ESP_SUPPLICANT
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -243,7 +257,7 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
sta->flags |= WLAN_STA_AUTH;
|
||||
|
||||
#ifdef ESP_SUPPLICANT
|
||||
sta->sae_commit_processing = false;
|
||||
atomic_store(&sta->sae_commit_processing, false);
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
|
||||
sta->auth_alg = WLAN_AUTH_SAE;
|
||||
@@ -591,7 +605,7 @@ int handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
|
||||
|
||||
#ifdef ESP_SUPPLICANT
|
||||
sta->sae_commit_processing = false;
|
||||
atomic_store(&sta->sae_commit_processing, false);
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
|
||||
goto reply;
|
||||
@@ -660,7 +674,7 @@ reply:
|
||||
data = wpabuf_alloc_copy(pos, 2);
|
||||
}
|
||||
#ifdef ESP_SUPPLICANT
|
||||
if (!sta->remove_pending) {
|
||||
if (!atomic_load(&sta->remove_pending)) {
|
||||
esp_send_sae_auth_reply(hapd, bssid, bssid, WLAN_AUTH_SAE,
|
||||
auth_transaction, resp,
|
||||
data ? wpabuf_head(data) : (u8 *) "",
|
||||
@@ -681,11 +695,23 @@ int auth_sae_queue(struct hostapd_data *hapd,
|
||||
struct hostapd_sae_commit_queue *q, *q2;
|
||||
unsigned int queue_len;
|
||||
|
||||
#ifdef ESP_SUPPLICANT
|
||||
if (!hapd->sta_list_lock) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SAE: sta_list_lock not set (no WPA3 hostap path), drop from " MACSTR,
|
||||
MAC2STR(bssid));
|
||||
return -1;
|
||||
}
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
queue_len = dl_list_len(&hapd->sae_commit_queue);
|
||||
if (queue_len >= hapd->conf->max_num_sta) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SAE: No more room in message queue - drop the new frame from "
|
||||
MACSTR, MAC2STR(bssid));
|
||||
#ifdef ESP_SUPPLICANT
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -694,6 +720,9 @@ int auth_sae_queue(struct hostapd_data *hapd,
|
||||
queue_len);
|
||||
q = os_zalloc(sizeof(*q) + len);
|
||||
if (!q) {
|
||||
#ifdef ESP_SUPPLICANT
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -731,11 +760,13 @@ queued:
|
||||
if (wpa3_hostap_post_evt(SIG_WPA3_RX_COMMIT, 0) != 0) {
|
||||
wpa_printf(MSG_ERROR, "failed to queue commit build event");
|
||||
dl_list_del(&q->list);
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
os_free(q);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -23,29 +23,62 @@
|
||||
static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
|
||||
void hostapd_wps_eap_completed(struct hostapd_data *hapd);
|
||||
|
||||
/*
|
||||
* CAUTION: cb is invoked while HOSTAPD_STA_LIST_LOCK is held.
|
||||
* The mutex is non-recursive (os_mutex_create), so cb must NEVER
|
||||
* call ap_get_sta, ap_free_sta, ap_sta_add, or any other function
|
||||
* that acquires HOSTAPD_STA_LIST_LOCK — doing so will deadlock.
|
||||
* Use the lock-free variants (e.g. ap_get_sta_internal) if needed.
|
||||
*/
|
||||
int ap_for_each_sta(struct hostapd_data *hapd,
|
||||
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
void *ctx),
|
||||
void *ctx)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
int ret;
|
||||
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (cb(hapd, sta, ctx))
|
||||
return 1;
|
||||
if (cb(hapd, sta, ctx)) {
|
||||
ret = 1;
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ap_get_sta - Look up a station by MAC address
|
||||
* @hapd: hostapd data structure
|
||||
* @sta: MAC address to look up
|
||||
* Returns: Pointer to sta_info structure, or NULL if not found
|
||||
*
|
||||
* This function acquires and releases HOSTAPD_STA_LIST_LOCK internally.
|
||||
* The returned pointer is NOT protected after the lock is released.
|
||||
* Use-after-free can occur if the station is freed by another task
|
||||
* (via ap_free_sta) between the unlock here and the caller's use.
|
||||
*
|
||||
* For safe access to sta fields, callers should either:
|
||||
* - Use ap_get_sta_internal() while holding HOSTAPD_STA_LIST_LOCK, OR
|
||||
* - Take sta->lock immediately after (for SAE stations), OR
|
||||
* - Copy needed data while lock is still held
|
||||
*
|
||||
* Note: This is particularly important for wpa3_task callers.
|
||||
*/
|
||||
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
|
||||
{
|
||||
struct sta_info *s;
|
||||
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
s = hapd->sta_hash[STA_HASH(sta)];
|
||||
while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
|
||||
s = s->hnext;
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -69,6 +102,17 @@ static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
tmp->next = sta->next;
|
||||
}
|
||||
|
||||
/* Caller MUST hold HOSTAPD_STA_LIST_LOCK (see sta_info.h). */
|
||||
struct sta_info * ap_get_sta_internal(struct hostapd_data *hapd, const u8 *sta)
|
||||
{
|
||||
struct sta_info *s;
|
||||
|
||||
s = hapd->sta_hash[STA_HASH(sta)];
|
||||
while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
|
||||
s = s->hnext;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
@@ -100,10 +144,12 @@ static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
|
||||
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
ap_sta_hash_del(hapd, sta);
|
||||
ap_sta_list_del(hapd, sta);
|
||||
|
||||
hapd->num_sta--;
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
sae_clear_data(sta->sae);
|
||||
@@ -113,10 +159,12 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
os_mutex_delete(sta->lock);
|
||||
sta->lock = NULL;
|
||||
}
|
||||
#ifdef ESP_SUPPLICANT
|
||||
if (sta->sae_data) {
|
||||
wpabuf_free(sta->sae_data);
|
||||
sta->sae_data = NULL;
|
||||
}
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
#endif /* CONFIG_SAE */
|
||||
wpa_auth_sta_deinit(sta->wpa_sm);
|
||||
#ifdef CONFIG_WPS_REGISTRAR
|
||||
@@ -132,18 +180,28 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
}
|
||||
|
||||
|
||||
/* Called during teardown after WPA3 task is stopped, so sta->lock is always available. */
|
||||
void hostapd_free_stas(struct hostapd_data *hapd)
|
||||
{
|
||||
struct sta_info *sta, *prev;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = hapd->sta_list;
|
||||
|
||||
while (sta) {
|
||||
prev = sta;
|
||||
sta = sta->next;
|
||||
wpa_printf(MSG_DEBUG, "Removing station " MACSTR,
|
||||
MAC2STR(prev->addr));
|
||||
ap_free_sta(hapd, prev);
|
||||
while (1) {
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
sta = hapd->sta_list;
|
||||
if (!sta) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_SAE
|
||||
if (sta->lock) {
|
||||
os_semphr_take(sta->lock, OS_BLOCK);
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
ap_free_sta(hapd, sta);
|
||||
continue;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
ap_free_sta(hapd, sta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,35 +210,48 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta)
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
sta = ap_get_sta_internal(hapd, addr);
|
||||
if (sta) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return sta;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, " New STA");
|
||||
if (hapd->num_sta >= hapd->conf->max_num_sta) {
|
||||
/* FIX: might try to remove some old STAs first? */
|
||||
wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)",
|
||||
hapd->num_sta, hapd->conf->max_num_sta);
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sta = os_zalloc(sizeof(struct sta_info));
|
||||
if (sta == NULL) {
|
||||
wpa_printf(MSG_ERROR, "malloc failed");
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* initialize STA info data */
|
||||
os_memcpy(sta->addr, addr, ETH_ALEN);
|
||||
sta->next = hapd->sta_list;
|
||||
#ifdef CONFIG_SAE
|
||||
sta->sae_commit_processing = false;
|
||||
sta->remove_pending = false;
|
||||
atomic_init(&sta->sae_commit_processing, false);
|
||||
atomic_init(&sta->remove_pending, false);
|
||||
sta->lock = os_semphr_create(1, 1);
|
||||
if (!sta->lock) {
|
||||
wpa_printf(MSG_ERROR, "Failed to create sta->lock for " MACSTR,
|
||||
MAC2STR(addr));
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
os_free(sta);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
sta->next = hapd->sta_list;
|
||||
hapd->sta_list = sta;
|
||||
hapd->num_sta++;
|
||||
ap_sta_hash_add(hapd, sta);
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
|
||||
return sta;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#ifndef STA_INFO_H
|
||||
#define STA_INFO_H
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
#include <stdatomic.h>
|
||||
#endif
|
||||
|
||||
/* STA flags */
|
||||
#define WLAN_STA_AUTH BIT(0)
|
||||
#define WLAN_STA_ASSOC BIT(1)
|
||||
@@ -62,9 +66,9 @@ struct sta_info {
|
||||
#ifdef CONFIG_SAE
|
||||
void *lock;
|
||||
struct sae_data *sae;
|
||||
bool sae_commit_processing; /* halt queuing commit while we are
|
||||
atomic_bool sae_commit_processing; /* halt queuing commit while we are
|
||||
* processing commit for that station */
|
||||
bool remove_pending; /* Flag to indicate to free station when
|
||||
atomic_bool remove_pending; /* Flag to indicate to free station when
|
||||
* whose mutex is taken by task */
|
||||
struct wpabuf *sae_data;
|
||||
#endif /* CONFIG_SAE */
|
||||
@@ -96,6 +100,8 @@ int ap_for_each_sta(struct hostapd_data *hapd,
|
||||
void *ctx),
|
||||
void *ctx);
|
||||
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
|
||||
/* Caller must hold HOSTAPD_STA_LIST_LOCK(hapd) for the duration of the lookup. */
|
||||
struct sta_info * ap_get_sta_internal(struct hostapd_data *hapd, const u8 *sta);
|
||||
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void hostapd_free_stas(struct hostapd_data *hapd);
|
||||
|
||||
@@ -136,17 +136,26 @@ static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
/* wpa_auth_get_psk runs on the Wi-Fi task only, so sae_pmk_copy is not shared with any other task. */
|
||||
static u8 sae_pmk_copy[PMK_LEN];
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
struct sta_info *sta = ap_get_sta_internal(hapd, addr);
|
||||
if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
|
||||
if (!sta->sae || prev_psk)
|
||||
if (!sta->sae || prev_psk) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return NULL;
|
||||
return sta->sae->pmk;
|
||||
}
|
||||
os_memcpy(sae_pmk_copy, sta->sae->pmk, PMK_LEN);
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return sae_pmk_copy;
|
||||
}
|
||||
if (sta && wpa_auth_uses_sae(sta->wpa_sm)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"No PSK for STA trying to use SAE with PMKSA caching");
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return NULL;
|
||||
}
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
#endif /*CONFIG_SAE*/
|
||||
|
||||
return (u8*)hostapd_get_psk(hapd->conf, addr, prev_psk);
|
||||
@@ -210,10 +219,104 @@ wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
return hostapd_send_eapol(wpa_auth->addr, addr, data, data_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Modified to handle Wi-Fi vs WPA3 task concurrency only when CONFIG_SAE is enabled.
|
||||
* Snapshot SM indices under HOSTAPD_STA_LIST_LOCK, then per entry try
|
||||
* sta->lock (timeout 0) when present; if it is not acquired, skip
|
||||
* cb for that station; otherwise run cb.
|
||||
*/
|
||||
int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
|
||||
int (*cb)(struct wpa_state_machine *sm, void *ctx),
|
||||
void *cb_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = hostapd_get_hapd_data();
|
||||
struct sta_info *sta;
|
||||
u8 idx_snap[WPA_SM_MAX_INDEX];
|
||||
unsigned int n = 0;
|
||||
unsigned int i;
|
||||
#ifdef CONFIG_SAE
|
||||
void *sta_lk = NULL;
|
||||
u8 sta_mac[ETH_ALEN];
|
||||
#endif /* CONFIG_SAE */
|
||||
int cb_ret;
|
||||
|
||||
|
||||
if (hapd == NULL)
|
||||
return 1;
|
||||
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
struct wpa_state_machine *sm = sta->wpa_sm;
|
||||
|
||||
if (!sm || n >= WPA_SM_MAX_INDEX)
|
||||
continue;
|
||||
if (sm->index >= WPA_SM_MAX_INDEX)
|
||||
continue;
|
||||
if (!(BIT(sm->index) & s_sm_valid_bitmap))
|
||||
continue;
|
||||
if (s_sm_table[sm->index] != sm)
|
||||
continue;
|
||||
idx_snap[n++] = (u8) sm->index;
|
||||
}
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
struct wpa_state_machine *sm;
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
sta_lk = NULL;
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
sm = wpa_auth_get_sm(idx_snap[i]);
|
||||
if (!sm) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
continue;
|
||||
}
|
||||
#ifdef CONFIG_SAE
|
||||
sta = ap_get_sta_internal(hapd, sm->addr);
|
||||
if (sta && sta->wpa_sm == sm && sta->lock) {
|
||||
/* Take sta->lock with timeout 0.
|
||||
* Skip cb for this STA if sta->lock is not taken (WPA3 task may be holding the lock). */
|
||||
if (!os_semphr_take(sta->lock, 0)) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
continue;
|
||||
}
|
||||
sta_lk = sta->lock;
|
||||
os_memcpy(sta_mac, sta->addr, ETH_ALEN);
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
|
||||
cb_ret = cb(sm, cb_ctx);
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
/*
|
||||
* Give only when re-lookup finds sta->lock == sta_lk; otherwise skip
|
||||
* os_semphr_give(sta_lk) (sta_lk is not dereferenced on that path).
|
||||
* ap_free_sta() give+deletes sta->lock and clears the field before freeing sta.
|
||||
* ESP softAP: wpa_ap_remove and this walk usually run on the same Wi-Fi task as
|
||||
* cb(), so STA removal does not run concurrently with cb() in the typical model.
|
||||
*/
|
||||
if (sta_lk) {
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
sta = ap_get_sta_internal(hapd, sta_mac);
|
||||
if (sta && sta->lock == sta_lk) {
|
||||
os_semphr_give(sta_lk);
|
||||
} else if (!sta) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA: sta->lock not released (STA " MACSTR
|
||||
" gone); ap_free_sta released semaphore",
|
||||
MAC2STR(sta_mac));
|
||||
}
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
sta_lk = NULL;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
if (cb_ret)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user