diff --git a/src/common/dpp.h b/src/common/dpp.h index 0b6caf446..ee78f7906 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -131,6 +131,9 @@ struct dpp_pkex { struct wpabuf *exchange_req; struct wpabuf *exchange_resp; unsigned int t; /* number of failures on code use */ + unsigned int exch_req_wait_time; + unsigned int exch_req_tries; + unsigned int freq; }; struct dpp_configuration { diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 41fbab82d..7a7a8214f 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -37,6 +37,12 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s, enum offchannel_send_action_result result); static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx); static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s); +static void +wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, + unsigned int freq, const u8 *dst, + const u8 *src, const u8 *bssid, + const u8 *data, size_t data_len, + enum offchannel_send_action_result result); static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -1554,6 +1560,35 @@ fail: } +static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct dpp_pkex *pkex = wpa_s->dpp_pkex; + + if (!pkex || !pkex->exchange_req) + return; + if (pkex->exch_req_tries >= 5) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL + "No response from PKEX peer"); + dpp_pkex_free(pkex); + wpa_s->dpp_pkex = NULL; + return; + } + + pkex->exch_req_tries++; + wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)", + pkex->exch_req_tries); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(broadcast), pkex->freq, DPP_PA_PKEX_EXCHANGE_REQ); + offchannel_send_action(wpa_s, pkex->freq, broadcast, + wpa_s->own_addr, broadcast, + wpabuf_head(pkex->exchange_req), + wpabuf_len(pkex->exchange_req), + pkex->exch_req_wait_time, + wpas_dpp_tx_pkex_status, 0); +} + + static void wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, @@ -1562,6 +1597,7 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, enum offchannel_send_action_result result) { const char *res_txt; + struct dpp_pkex *pkex = wpa_s->dpp_pkex; res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" : @@ -1571,21 +1607,31 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, freq, MAC2STR(dst), res_txt); wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR " freq=%u result=%s", MAC2STR(dst), freq, res_txt); - /* TODO: Time out wait for response more quickly in error cases? */ - if (!wpa_s->dpp_pkex) { + if (!pkex) { wpa_printf(MSG_DEBUG, "DPP: Ignore TX status since there is no ongoing PKEX exchange"); return; } - if (wpa_s->dpp_pkex->failed) { + if (pkex->failed) { wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange due to an earlier error"); - if (wpa_s->dpp_pkex->t > wpa_s->dpp_pkex->own_bi->pkex_t) - wpa_s->dpp_pkex->own_bi->pkex_t = wpa_s->dpp_pkex->t; - dpp_pkex_free(wpa_s->dpp_pkex); + if (pkex->t > pkex->own_bi->pkex_t) + pkex->own_bi->pkex_t = pkex->t; + dpp_pkex_free(pkex); wpa_s->dpp_pkex = NULL; + return; + } + + if (pkex->exch_req_wait_time && pkex->exchange_req) { + /* Wait for PKEX Exchange Response frame and retry request if + * no response is seen. */ + eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL); + eloop_register_timeout(pkex->exch_req_wait_time / 1000, + (pkex->exch_req_wait_time % 1000) * 1000, + wpas_dpp_pkex_retry_timeout, wpa_s, + NULL); } } @@ -1659,6 +1705,9 @@ wpas_dpp_rx_pkex_exchange_resp(struct wpa_supplicant *wpa_s, const u8 *src, return; } + eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL); + wpa_s->dpp_pkex->exch_req_wait_time = 0; + os_memcpy(wpa_s->dpp_pkex->peer_mac, src, ETH_ALEN); msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, buf, len); if (!msg) { @@ -2226,6 +2275,7 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd) return -1; if (os_strstr(cmd, " init=1")) { + struct dpp_pkex *pkex; struct wpabuf *msg; wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX"); @@ -2233,21 +2283,28 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd) wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr, wpa_s->dpp_pkex_identifier, wpa_s->dpp_pkex_code); - if (!wpa_s->dpp_pkex) + pkex = wpa_s->dpp_pkex; + if (!pkex) return -1; - msg = wpa_s->dpp_pkex->exchange_req; + msg = pkex->exchange_req; wait_time = wpa_s->max_remain_on_chan; if (wait_time > 2000) wait_time = 2000; - /* TODO: Which channel to use? */ + /* TODO: Support for 5 GHz channels */ + pkex->freq = 2437; wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", - MAC2STR(broadcast), 2437, DPP_PA_PKEX_EXCHANGE_REQ); - offchannel_send_action(wpa_s, 2437, broadcast, wpa_s->own_addr, - broadcast, + MAC2STR(broadcast), pkex->freq, + DPP_PA_PKEX_EXCHANGE_REQ); + offchannel_send_action(wpa_s, pkex->freq, broadcast, + wpa_s->own_addr, broadcast, wpabuf_head(msg), wpabuf_len(msg), wait_time, wpas_dpp_tx_pkex_status, 0); + if (wait_time == 0) + wait_time = 2000; + pkex->exch_req_wait_time = wait_time; + pkex->exch_req_tries = 1; } /* TODO: Support multiple PKEX info entries */ @@ -2330,6 +2387,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) #endif /* CONFIG_TESTING_OPTIONS */ if (!wpa_s->dpp_init_done) return; + eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);