DPP: Retry PKEX Exchange Request frame up to five times
Retransmit the PKEX Exchange Request frame if no response from a peer is received. This makes the exchange more robust since this frame is sent to a broadcast address and has no link layer retries. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
cb6b22325f
commit
00d2d13db2
2 changed files with 73 additions and 12 deletions
|
@ -131,6 +131,9 @@ struct dpp_pkex {
|
||||||
struct wpabuf *exchange_req;
|
struct wpabuf *exchange_req;
|
||||||
struct wpabuf *exchange_resp;
|
struct wpabuf *exchange_resp;
|
||||||
unsigned int t; /* number of failures on code use */
|
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 {
|
struct dpp_configuration {
|
||||||
|
|
|
@ -37,6 +37,12 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
|
||||||
enum offchannel_send_action_result result);
|
enum offchannel_send_action_result result);
|
||||||
static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
|
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 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 };
|
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
|
static void
|
||||||
wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
|
wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
|
||||||
unsigned int freq, const u8 *dst,
|
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)
|
enum offchannel_send_action_result result)
|
||||||
{
|
{
|
||||||
const char *res_txt;
|
const char *res_txt;
|
||||||
|
struct dpp_pkex *pkex = wpa_s->dpp_pkex;
|
||||||
|
|
||||||
res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
|
res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
|
||||||
(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
|
(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);
|
freq, MAC2STR(dst), res_txt);
|
||||||
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
|
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
|
||||||
" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
|
" 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,
|
wpa_printf(MSG_DEBUG,
|
||||||
"DPP: Ignore TX status since there is no ongoing PKEX exchange");
|
"DPP: Ignore TX status since there is no ongoing PKEX exchange");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wpa_s->dpp_pkex->failed) {
|
if (pkex->failed) {
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"DPP: Terminate PKEX exchange due to an earlier error");
|
"DPP: Terminate PKEX exchange due to an earlier error");
|
||||||
if (wpa_s->dpp_pkex->t > wpa_s->dpp_pkex->own_bi->pkex_t)
|
if (pkex->t > pkex->own_bi->pkex_t)
|
||||||
wpa_s->dpp_pkex->own_bi->pkex_t = wpa_s->dpp_pkex->t;
|
pkex->own_bi->pkex_t = pkex->t;
|
||||||
dpp_pkex_free(wpa_s->dpp_pkex);
|
dpp_pkex_free(pkex);
|
||||||
wpa_s->dpp_pkex = NULL;
|
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;
|
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);
|
os_memcpy(wpa_s->dpp_pkex->peer_mac, src, ETH_ALEN);
|
||||||
msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, buf, len);
|
msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, buf, len);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
|
@ -2226,6 +2275,7 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (os_strstr(cmd, " init=1")) {
|
if (os_strstr(cmd, " init=1")) {
|
||||||
|
struct dpp_pkex *pkex;
|
||||||
struct wpabuf *msg;
|
struct wpabuf *msg;
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
|
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 = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr,
|
||||||
wpa_s->dpp_pkex_identifier,
|
wpa_s->dpp_pkex_identifier,
|
||||||
wpa_s->dpp_pkex_code);
|
wpa_s->dpp_pkex_code);
|
||||||
if (!wpa_s->dpp_pkex)
|
pkex = wpa_s->dpp_pkex;
|
||||||
|
if (!pkex)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
msg = wpa_s->dpp_pkex->exchange_req;
|
msg = pkex->exchange_req;
|
||||||
wait_time = wpa_s->max_remain_on_chan;
|
wait_time = wpa_s->max_remain_on_chan;
|
||||||
if (wait_time > 2000)
|
if (wait_time > 2000)
|
||||||
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
|
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
|
||||||
" freq=%u type=%d",
|
" freq=%u type=%d",
|
||||||
MAC2STR(broadcast), 2437, DPP_PA_PKEX_EXCHANGE_REQ);
|
MAC2STR(broadcast), pkex->freq,
|
||||||
offchannel_send_action(wpa_s, 2437, broadcast, wpa_s->own_addr,
|
DPP_PA_PKEX_EXCHANGE_REQ);
|
||||||
broadcast,
|
offchannel_send_action(wpa_s, pkex->freq, broadcast,
|
||||||
|
wpa_s->own_addr, broadcast,
|
||||||
wpabuf_head(msg), wpabuf_len(msg),
|
wpabuf_head(msg), wpabuf_len(msg),
|
||||||
wait_time, wpas_dpp_tx_pkex_status, 0);
|
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 */
|
/* TODO: Support multiple PKEX info entries */
|
||||||
|
@ -2330,6 +2387,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
|
||||||
#endif /* CONFIG_TESTING_OPTIONS */
|
#endif /* CONFIG_TESTING_OPTIONS */
|
||||||
if (!wpa_s->dpp_init_done)
|
if (!wpa_s->dpp_init_done)
|
||||||
return;
|
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_reply_wait_timeout, wpa_s, NULL);
|
||||||
eloop_cancel_timeout(wpas_dpp_init_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);
|
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
|
||||||
|
|
Loading…
Reference in a new issue