]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP: Retry PKEX Exchange Request frame up to five times
authorJouni Malinen <jouni@qca.qualcomm.com>
Wed, 22 Nov 2017 13:54:35 +0000 (15:54 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 22 Nov 2017 13:54:35 +0000 (15:54 +0200)
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>
src/common/dpp.h
wpa_supplicant/dpp_supplicant.c

index 0b6caf446ec96eff88879aa61d1be70f21758be2..ee78f790674e60a54ae5728ff48f634899deef83 100644 (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 {
index 41fbab82d78d988f81b5f8ca7bd30c94a525837c..7a7a8214fc0f2c4dfd2907c2a420591c28ea2d62 100644 (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);