DPP: Wait for ROC cancelled event on Auth Resp TX on another channel

Avoid potential race conditions with the driver operations between
cancelling an ongoing ROC that was used to receive Authentication
Request that requested a different channel to be used for the
negotiation by waiting for the ROC cancelled event before issuing the
offchannel TX command for the Authentication Response.

In addition, speed up the retry on Authentication Response in this type
of a case if the first attempt on the other channel is not AKC'ed since
it might take the peer device a bit more time to be ready to listen
there.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2024-03-02 19:06:15 +02:00
parent 45fffac0fe
commit 451d299528
2 changed files with 66 additions and 8 deletions

View file

@ -237,6 +237,12 @@ static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s)
wait_time = wpa_s->dpp_resp_retry_time;
else
wait_time = 1000;
if (wpa_s->dpp_tx_chan_change) {
wpa_s->dpp_tx_chan_change = false;
if (wait_time > 100)
wait_time = 100;
}
wpa_printf(MSG_DEBUG,
"DPP: Schedule retransmission of Authentication Response frame in %u ms",
wait_time);
@ -1020,6 +1026,8 @@ static void dpp_start_listen_cb(struct wpa_radio_work *work, int deinit)
wpa_s->off_channel_freq = 0;
wpa_s->roc_waiting_drv_freq = lwork->freq;
wpa_drv_dpp_listen(wpa_s, true);
wpa_s->dpp_tx_auth_resp_on_roc_stop = false;
wpa_s->dpp_tx_chan_change = false;
}
@ -1119,11 +1127,58 @@ void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
}
static void wpas_dpp_tx_auth_resp(struct wpa_supplicant *wpa_s)
{
struct dpp_authentication *auth = wpa_s->dpp_auth;
if (!auth)
return;
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
MAC2STR(auth->peer_mac_addr), auth->curr_freq,
DPP_PA_AUTHENTICATION_RESP);
offchannel_send_action(wpa_s, auth->curr_freq,
auth->peer_mac_addr, wpa_s->own_addr, broadcast,
wpabuf_head(auth->resp_msg),
wpabuf_len(auth->resp_msg),
500, wpas_dpp_tx_status, 0);
}
static void wpas_dpp_tx_auth_resp_roc_timeout(void *eloop_ctx,
void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct dpp_authentication *auth = wpa_s->dpp_auth;
if (!auth || !wpa_s->dpp_tx_auth_resp_on_roc_stop)
return;
wpa_s->dpp_tx_auth_resp_on_roc_stop = false;
wpa_s->dpp_tx_chan_change = true;
wpa_printf(MSG_DEBUG,
"DPP: Send postponed Authentication Response on remain-on-channel termination timeout");
wpas_dpp_tx_auth_resp(wpa_s);
}
void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq)
{
wpa_printf(MSG_DEBUG, "DPP: Remain on channel cancel for %u MHz", freq);
wpas_dpp_listen_work_done(wpa_s);
if (wpa_s->dpp_auth && wpa_s->dpp_tx_auth_resp_on_roc_stop) {
eloop_cancel_timeout(wpas_dpp_tx_auth_resp_roc_timeout,
wpa_s, NULL);
wpa_s->dpp_tx_auth_resp_on_roc_stop = false;
wpa_s->dpp_tx_chan_change = true;
wpa_printf(MSG_DEBUG,
"DPP: Send postponed Authentication Response on remain-on-channel termination");
wpas_dpp_tx_auth_resp(wpa_s);
return;
}
if (wpa_s->dpp_auth && wpa_s->dpp_in_response_listen) {
unsigned int new_freq;
@ -1241,17 +1296,17 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
wpa_printf(MSG_DEBUG,
"DPP: Stop listen on %u MHz to allow response on the request %u MHz",
wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq);
wpa_s->dpp_tx_auth_resp_on_roc_stop = true;
eloop_register_timeout(0, 100000,
wpas_dpp_tx_auth_resp_roc_timeout,
wpa_s, NULL);
wpas_dpp_listen_stop(wpa_s);
return;
}
wpa_s->dpp_tx_auth_resp_on_roc_stop = false;
wpa_s->dpp_tx_chan_change = false;
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
MAC2STR(src), wpa_s->dpp_auth->curr_freq,
DPP_PA_AUTHENTICATION_RESP);
offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq,
src, wpa_s->own_addr, broadcast,
wpabuf_head(wpa_s->dpp_auth->resp_msg),
wpabuf_len(wpa_s->dpp_auth->resp_msg),
500, wpas_dpp_tx_status, 0);
wpas_dpp_tx_auth_resp(wpa_s);
}
@ -4778,6 +4833,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
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);
eloop_cancel_timeout(wpas_dpp_tx_auth_resp_roc_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,

View file

@ -1474,6 +1474,8 @@ struct wpa_supplicant {
int dpp_netrole;
int dpp_auth_ok_on_ack;
int dpp_in_response_listen;
bool dpp_tx_auth_resp_on_roc_stop;
bool dpp_tx_chan_change;
int dpp_gas_client;
int dpp_gas_server;
int dpp_gas_dialog_token;