DPP: Start next auth init from driver event to avoid race condition

It looks like mac80211 ROC handling can end up postponing offchannel TX
operation by the previously started and already canceled wait time if
the new NL80211_CMD_FRAME is issued immediately after
NL80211_CMD_FRAME_WAIT_CANCEL. Make this more robust by waiting for the
driver event that indicates completion of the cancel operation (i.e.,
NL80211_CMD_FRAME_WAIT_CANCEL as an event) before issuing
NL80211_CMD_FRAME for another channel. If the driver event is not
received within 10 ms, start the operation anyway to avoid unexpected
behavior if there are drivers that do not end up notifying end of the
wait.

This fixes some issues with authentication initiation for cases where
multiple channels are iterated. This can also significantly speed up
that process.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2023-11-04 11:11:46 +02:00
parent 7e9efc3cdf
commit 5c5f86900b

View file

@ -443,6 +443,23 @@ void wpas_dpp_connected(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_DPP2 */
static void wpas_dpp_drv_wait_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct dpp_authentication *auth = wpa_s->dpp_auth;
if (auth && auth->waiting_auth_resp) {
wpa_printf(MSG_DEBUG,
"DPP: Call wpas_dpp_auth_init_next() from %s",
__func__);
wpas_dpp_auth_init_next(wpa_s);
} else {
wpa_printf(MSG_DEBUG, "DPP: %s, but no waiting_auth_resp",
__func__);
}
}
static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid,
@ -519,7 +536,12 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
/* In case of DPP Authentication Request frame, move to
* the next channel immediately. */
offchannel_send_action_done(wpa_s);
wpas_dpp_auth_init_next(wpa_s);
/* Call wpas_dpp_auth_init_next(wpa_s) from driver event
* notifying frame wait was completed or from eloop
* timeout. */
eloop_register_timeout(0, 10000,
wpas_dpp_drv_wait_timeout,
wpa_s, NULL);
return;
}
if (auth->waiting_auth_conf) {
@ -681,6 +703,8 @@ static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s)
unsigned int wait_time, max_wait_time, freq, max_tries, used;
struct os_reltime now, diff;
eloop_cancel_timeout(wpas_dpp_drv_wait_timeout, wpa_s, NULL);
wpa_s->dpp_in_response_listen = 0;
if (!auth)
return -1;
@ -1219,8 +1243,19 @@ void wpas_dpp_tx_wait_expire(struct wpa_supplicant *wpa_s)
struct dpp_authentication *auth = wpa_s->dpp_auth;
int freq;
if (!wpa_s->dpp_gas_server || !auth)
if (!wpa_s->dpp_gas_server || !auth) {
if (auth && auth->waiting_auth_resp &&
eloop_is_timeout_registered(wpas_dpp_drv_wait_timeout,
wpa_s, NULL)) {
eloop_cancel_timeout(wpas_dpp_drv_wait_timeout,
wpa_s, NULL);
wpa_printf(MSG_DEBUG,
"DPP: Call wpas_dpp_auth_init_next() from %s",
__func__);
wpas_dpp_auth_init_next(wpa_s);
}
return;
}
freq = auth->neg_freq > 0 ? auth->neg_freq : auth->curr_freq;
if (wpa_s->dpp_listen_work || (int) wpa_s->dpp_listen_freq == freq)
@ -4714,6 +4749,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_gas_client_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_drv_wait_timeout, wpa_s, NULL);
#ifdef CONFIG_DPP2
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,