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:
Jouni Malinen 2017-11-22 15:54:35 +02:00 committed by Jouni Malinen
parent cb6b22325f
commit 00d2d13db2
2 changed files with 73 additions and 12 deletions

View file

@ -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 {

View file

@ -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);