mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 02:30:52 +03:00
fix(wpa_supplicant): Fix concurrency issues between wpa3 and wifi task
This commit is contained in:
@@ -205,7 +205,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 +224,17 @@ void *hostap_init(void)
|
||||
|
||||
return (void *)hapd;
|
||||
fail:
|
||||
#ifdef CONFIG_SAE
|
||||
if (hapd->sta_list_lock) {
|
||||
wpa3_hostap_auth_deinit();
|
||||
if (g_wpa3_hostap_auth_api_lock &&
|
||||
WPA3_HOSTAP_AUTH_API_LOCK() == pdTRUE) {
|
||||
WPA3_HOSTAP_AUTH_API_UNLOCK();
|
||||
}
|
||||
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 +264,21 @@ void hostapd_cleanup(struct hostapd_data *hapd)
|
||||
hapd->conf = NULL;
|
||||
}
|
||||
|
||||
if (hapd->sta_list_lock) {
|
||||
#ifdef CONFIG_SAE
|
||||
|
||||
struct hostapd_sae_commit_queue *q, *tmp;
|
||||
|
||||
if (!dl_list_empty(&hapd->sae_commit_queue)) {
|
||||
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);
|
||||
#endif /* CONFIG_SAE */
|
||||
os_mutex_delete(hapd->sta_list_lock);
|
||||
hapd->sta_list_lock = NULL;
|
||||
}
|
||||
#ifdef CONFIG_WPS_REGISTRAR
|
||||
if (esp_wifi_get_wps_type_internal() != WPS_TYPE_DISABLE ||
|
||||
esp_wifi_get_wps_status_internal() != WPS_STATUS_DISABLE) {
|
||||
@@ -457,14 +469,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 {
|
||||
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 +501,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 {
|
||||
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;
|
||||
@@ -436,13 +441,20 @@ 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) {
|
||||
/* wait for portMAX_DELAY as sometimes queue might be full */
|
||||
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 +475,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,17 +504,28 @@ 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)) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
|
||||
sta->sae_commit_processing = true;
|
||||
ret = handle_auth_sae(hapd, sta, frm->msg, frm->len, frm->bssid, frm->auth_transaction, frm->status);
|
||||
|
||||
if (sta->remove_pending) {
|
||||
ap_free_sta(hapd, sta);
|
||||
goto free;
|
||||
os_free(frm);
|
||||
return;
|
||||
}
|
||||
sta->sae_commit_processing = false;
|
||||
os_semphr_give(sta->lock);
|
||||
@@ -505,9 +537,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 +551,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 (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:
|
||||
@@ -610,22 +669,33 @@ static void esp_wpa3_hostap_task(void *pvParameters)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -636,9 +706,13 @@ 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;
|
||||
}
|
||||
|
||||
dl_list_init(&hapd->sae_commit_queue);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -658,16 +732,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) {
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
struct sta_info *sta = ap_get_sta_internal(hapd, bssid);
|
||||
if (sta && sta->sae_commit_processing) {
|
||||
/* Ignore commit msg as we are already processing commit msg for this station */
|
||||
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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,17 +23,30 @@
|
||||
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;
|
||||
}
|
||||
@@ -43,9 +56,11 @@ 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 +84,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 +126,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 +141,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 +162,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 +192,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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,9 +62,9 @@ struct sta_info {
|
||||
#ifdef CONFIG_SAE
|
||||
void *lock;
|
||||
struct sae_data *sae;
|
||||
bool sae_commit_processing; /* halt queuing commit while we are
|
||||
volatile 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
|
||||
volatile 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 +96,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);
|
||||
|
||||
@@ -210,10 +210,30 @@ wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
return hostapd_send_eapol(wpa_auth->addr, addr, data, data_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* CAUTION: cb is invoked while HOSTAPD_STA_LIST_LOCK is held.
|
||||
* The mutex is non-recursive, so cb must NEVER call any function
|
||||
* that acquires HOSTAPD_STA_LIST_LOCK (e.g. ap_get_sta, ap_free_sta)
|
||||
* — doing so will deadlock.
|
||||
*/
|
||||
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;
|
||||
|
||||
if (hapd == NULL)
|
||||
return 1;
|
||||
|
||||
HOSTAPD_STA_LIST_LOCK(hapd);
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx)) {
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
HOSTAPD_STA_LIST_UNLOCK(hapd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user