]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP2: Accept Config Result before GAS response TX status
authorJouni Malinen <j@w1.fi>
Sun, 21 Feb 2021 14:44:33 +0000 (16:44 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 21 Feb 2021 14:44:33 +0000 (16:44 +0200)
The TX event for the next frame in the sequence might be received before
the TX status for the final GAS response frame is processed. This used
to result in the Config Result getting discarded and the negotiation not
completing successfully on the Configurator side.

Accept the Config Result message as an indication of the final GAS
response frame having went through fine even if the TX status has not
yet been processed to avoid this issue from a potential race condition
on kernel events.

Signed-off-by: Jouni Malinen <j@w1.fi>
src/common/dpp.h
src/common/gas_server.c
src/common/gas_server.h
wpa_supplicant/dpp_supplicant.c

index 2fd331b1a55d7d772d76a8691415290531a4ef2a..65ee905a78f9411040f739bd8e855e84931c0085 100644 (file)
@@ -348,6 +348,7 @@ struct dpp_authentication {
        struct wpabuf *cacert;
        struct wpabuf *certbag;
        void *cert_resp_ctx;
+       void *gas_server_ctx;
 #ifdef CONFIG_TESTING_OPTIONS
        char *config_obj_override;
        char *discovery_override;
index c000aeb6060f0f3d4144eda25a0aab8257a6f229..5f44ffebdea09d10fbb64f87b67a28ad9ac8b12c 100644 (file)
@@ -489,6 +489,21 @@ int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
 }
 
 
+bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx)
+{
+       struct gas_server_response *tmp;
+
+       dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
+                        list) {
+               if (tmp == resp_ctx)
+                       return tmp->resp &&
+                               tmp->offset == wpabuf_len(tmp->resp);
+       }
+
+       return false;
+}
+
+
 struct gas_server * gas_server_init(void *ctx,
                                    void (*tx)(void *ctx, int freq,
                                               const u8 *da,
index 2611ddedc1721f0471f1a39775d0bec81e8bf43b..db00f87e8de1097fe0a31925a381afd9b586b723 100644 (file)
@@ -36,6 +36,7 @@ void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
                          size_t data_len, int ack);
 int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
                        struct wpabuf *resp);
+bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx);
 
 #else /* CONFIG_GAS_SERVER */
 
index b2443ae37de19869d0a359c28d9c6320fa74e45d..2bcf10b4e2591f68f1d55fe3bec02d04c8daf6a9 100644 (file)
@@ -1918,9 +1918,22 @@ static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
                   MAC2STR(src));
 
        if (!auth || !auth->waiting_conf_result) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: No DPP Configuration waiting for result - drop");
-               return;
+               if (auth &&
+                   os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) == 0 &&
+                   gas_server_response_sent(wpa_s->gas_server,
+                                            auth->gas_server_ctx)) {
+                       /* This could happen if the TX status event gets delayed
+                        * long enough for the Enrollee to have time to send
+                        * the next frame before the TX status gets processed
+                        * locally. */
+                       wpa_printf(MSG_DEBUG,
+                                  "DPP: GAS response was sent but TX status not yet received - assume it was ACKed since the Enrollee sent the next frame in the sequence");
+                       auth->waiting_conf_result = 1;
+               } else {
+                       wpa_printf(MSG_DEBUG,
+                                  "DPP: No DPP Configuration waiting for result - drop");
+                       return;
+               }
        }
 
        if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
@@ -2969,6 +2982,7 @@ wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa,
        if (!resp)
                wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
        auth->conf_resp = resp;
+       auth->gas_server_ctx = resp_ctx;
        return resp;
 }
 
@@ -3006,7 +3020,8 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
        eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
 #ifdef CONFIG_DPP2
        if (ok && auth->peer_version >= 2 &&
-           auth->conf_resp_status == DPP_STATUS_OK) {
+           auth->conf_resp_status == DPP_STATUS_OK &&
+           !auth->waiting_conf_result) {
                wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
                auth->waiting_conf_result = 1;
                auth->conf_resp = NULL;