From 976c3c161f890dd3960ca9c7e26d75bc1a9766c3 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 21 Feb 2021 16:44:33 +0200 Subject: [PATCH] DPP2: Accept Config Result before GAS response TX status 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 --- src/common/dpp.h | 1 + src/common/gas_server.c | 15 +++++++++++++++ src/common/gas_server.h | 1 + wpa_supplicant/dpp_supplicant.c | 23 +++++++++++++++++++---- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/common/dpp.h b/src/common/dpp.h index 2fd331b1a..65ee905a7 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -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; diff --git a/src/common/gas_server.c b/src/common/gas_server.c index c000aeb60..5f44ffebd 100644 --- a/src/common/gas_server.c +++ b/src/common/gas_server.c @@ -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, diff --git a/src/common/gas_server.h b/src/common/gas_server.h index 2611ddedc..db00f87e8 100644 --- a/src/common/gas_server.h +++ b/src/common/gas_server.h @@ -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 */ diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index b2443ae37..2bcf10b4e 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -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;