]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP: Retransmit DPP Authentication Response frame if it is not ACKed
authorJouni Malinen <jouni@qca.qualcomm.com>
Mon, 13 Nov 2017 10:34:17 +0000 (12:34 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 13 Nov 2017 10:35:26 +0000 (12:35 +0200)
This extends wpa_supplicant DPP implementation to retransmit DPP
Authentication Response frame every 10 seconds up to 5 times if the peer
does not reply with DPP Authentication Confirm frame.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/common/dpp.c
src/common/dpp.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/dpp_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 99f6da3b28dedcd09ff433e2e2d2a8c604ebe210..5a9021922d12c1b79dd41f640ee8389814e96d49 100644 (file)
@@ -1541,6 +1541,9 @@ static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
        size_t len[2], siv_len, attr_len;
        u8 *attr_start, *attr_end, *pos;
 
+       auth->waiting_auth_conf = 1;
+       auth->auth_resp_tries = 0;
+
        /* Build DPP Authentication Response frame attributes */
        attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
                4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
@@ -1551,7 +1554,6 @@ static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
        msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
        if (!msg)
                return NULL;
-       wpabuf_free(auth->resp_msg);
 
        attr_start = wpabuf_put(msg, 0);
 
@@ -2497,6 +2499,7 @@ static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
                                  auth->k2);
        if (!msg)
                goto fail;
+       wpabuf_free(auth->resp_msg);
        auth->resp_msg = msg;
        ret = 0;
 fail:
@@ -2542,6 +2545,7 @@ static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
                                  NULL, i_nonce, NULL, 0, auth->k1);
        if (!msg)
                return -1;
+       wpabuf_free(auth->resp_msg);
        auth->resp_msg = msg;
        return 0;
 }
@@ -3454,6 +3458,8 @@ int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
        size_t unwrapped_len = 0;
        u8 i_auth2[DPP_MAX_HASH_LEN];
 
+       auth->waiting_auth_conf = 0;
+
        wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
                                    &wrapped_data_len);
        if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
index 161ffb94253ba1f0a84b4bb489024b201314a7cf..6c2805838b73c89d82eb26a70f464029e0589ffd 100644 (file)
@@ -183,6 +183,8 @@ struct dpp_authentication {
        u8 ke[DPP_MAX_HASH_LEN];
        int initiator;
        int waiting_auth_resp;
+       int waiting_auth_conf;
+       unsigned int auth_resp_tries;
        u8 allowed_roles;
        int configurator;
        int remove_on_tx_status;
index c2c423587e9f2609c815fd25abfbd2237edc976d..f756bcae6293cfaa33334e32ff6f6d6c2f53fa03 100644 (file)
@@ -611,6 +611,10 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                wpa_s->dpp_init_retry_time = atoi(value);
        } else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) {
                wpa_s->dpp_resp_wait_time = atoi(value);
+       } else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) {
+               wpa_s->dpp_resp_max_tries = atoi(value);
+       } else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) {
+               wpa_s->dpp_resp_retry_time = atoi(value);
 #endif /* CONFIG_DPP */
 #ifdef CONFIG_TESTING_OPTIONS
        } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
@@ -7755,6 +7759,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        wpa_s->dpp_init_max_tries = 0;
        wpa_s->dpp_init_retry_time = 0;
        wpa_s->dpp_resp_wait_time = 0;
+       wpa_s->dpp_resp_max_tries = 0;
+       wpa_s->dpp_resp_retry_time = 0;
 #endif /* CONFIG_DPP */
 
 #ifdef CONFIG_TDLS
index 2f7a9940ab01cd00ee20b70f58fe581b1f3b8198..e34f68dbd0aee3d091b656f9635458fd96589861 100644 (file)
@@ -300,6 +300,63 @@ int wpas_dpp_bootstrap_info(struct wpa_supplicant *wpa_s, int id,
 }
 
 
+static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+       if (!auth || !auth->resp_msg)
+               return;
+
+       wpa_printf(MSG_DEBUG,
+                  "DPP: Retry Authentication Response after timeout");
+       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_auth_resp_retry(struct wpa_supplicant *wpa_s)
+{
+       struct dpp_authentication *auth = wpa_s->dpp_auth;
+       unsigned int wait_time, max_tries;
+
+       if (!auth || !auth->resp_msg)
+               return;
+
+       if (wpa_s->dpp_resp_max_tries)
+               max_tries = wpa_s->dpp_resp_max_tries;
+       else
+               max_tries = 5;
+       auth->auth_resp_tries++;
+       if (auth->auth_resp_tries >= max_tries) {
+               wpa_printf(MSG_INFO, "DPP: No confirm received from initiator - stopping exchange");
+               offchannel_send_action_done(wpa_s);
+               dpp_auth_deinit(wpa_s->dpp_auth);
+               wpa_s->dpp_auth = NULL;
+               return;
+       }
+
+       if (wpa_s->dpp_resp_retry_time)
+               wait_time = wpa_s->dpp_resp_retry_time;
+       else
+               wait_time = 10000;
+       wpa_printf(MSG_DEBUG,
+                  "DPP: Schedule retransmission of Authentication Response frame in %u ms",
+               wait_time);
+       eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+       eloop_register_timeout(wait_time / 1000,
+                              (wait_time % 1000) * 1000,
+                              wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+}
+
+
 static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
                               unsigned int freq, const u8 *dst,
                               const u8 *src, const u8 *bssid,
@@ -328,6 +385,8 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
                           "DPP: Terminate authentication exchange due to an earlier error");
                eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
                eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+               eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
+                                    NULL);
                offchannel_send_action_done(wpa_s);
                dpp_auth_deinit(wpa_s->dpp_auth);
                wpa_s->dpp_auth = NULL;
@@ -348,6 +407,10 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
                        wpas_dpp_auth_init_next(wpa_s);
                        return;
                }
+               if (auth->waiting_auth_conf) {
+                       wpas_dpp_auth_resp_retry(wpa_s);
+                       return;
+               }
        }
 
        if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 &&
@@ -685,6 +748,8 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
        if (wpa_s->dpp_auth) {
                eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
                eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+               eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
+                                    NULL);
                offchannel_send_action_done(wpa_s);
                dpp_auth_deinit(wpa_s->dpp_auth);
        }
@@ -1856,6 +1921,7 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
        wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
                   ok);
        eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+       eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
        offchannel_send_action_done(wpa_s);
        wpas_dpp_listen_stop(wpa_s);
        if (ok)
@@ -2244,6 +2310,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
                return;
        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);
        offchannel_send_action_done(wpa_s);
        wpas_dpp_listen_stop(wpa_s);
        dpp_bootstrap_del(wpa_s, 0);
index 65454edf72209e5c7aec0884c92f18c49b21ac13..099c8d0853e7df3aa3731faae015e32643b3736a 100644 (file)
@@ -1203,6 +1203,8 @@ struct wpa_supplicant {
        unsigned int dpp_init_max_tries;
        unsigned int dpp_init_retry_time;
        unsigned int dpp_resp_wait_time;
+       unsigned int dpp_resp_max_tries;
+       unsigned int dpp_resp_retry_time;
 #ifdef CONFIG_TESTING_OPTIONS
        char *dpp_config_obj_override;
        char *dpp_discovery_override;