From 33cb47cf01912dbd054300fa6c118782cba69812 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 28 Jan 2022 17:28:49 +0200 Subject: [PATCH] DPP: Fix connection result reporting when using TCP The TCP code path did not handle the postponed connection attempt on TX status and the following result message from the Enrollee to the Configurator. Fix this by adding TCP-versions of these operations to match the way wpa_supplicant implemented this for the Public Action frames. Signed-off-by: Jouni Malinen --- src/ap/dpp_hostapd.c | 5 +- src/common/dpp.c | 1 + src/common/dpp.h | 15 +++++- src/common/dpp_i.h | 2 + src/common/dpp_tcp.c | 81 ++++++++++++++++++++++++++++++++- wpa_supplicant/dpp_supplicant.c | 61 ++++++++++++++++++++++--- 6 files changed, 153 insertions(+), 12 deletions(-) diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index 6239bebe5..96a13fb6f 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -2,6 +2,7 @@ * hostapd / DPP integration * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -340,7 +341,7 @@ static int hostapd_dpp_pkex_done(void *ctx, void *conn, return dpp_tcp_auth(hapd->iface->interfaces->dpp, conn, auth, hapd->conf->dpp_name, DPP_NETROLE_AP, - hostapd_dpp_process_conf_obj); + hostapd_dpp_process_conf_obj, NULL); } #endif /* CONFIG_DPP2 */ @@ -922,7 +923,7 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd) return dpp_tcp_init(hapd->iface->interfaces->dpp, auth, &ipaddr, tcp_port, hapd->conf->dpp_name, DPP_NETROLE_AP, hapd->msg_ctx, hapd, - hostapd_dpp_process_conf_obj); + hostapd_dpp_process_conf_obj, NULL); #endif /* CONFIG_DPP2 */ hapd->dpp_auth = auth; diff --git a/src/common/dpp.c b/src/common/dpp.c index ac6eae4c8..77964f264 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -2,6 +2,7 @@ * DPP functionality shared between hostapd and wpa_supplicant * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. diff --git a/src/common/dpp.h b/src/common/dpp.h index ca488f391..83f3d94af 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -2,6 +2,7 @@ * DPP functionality shared between hostapd and wpa_supplicant * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -402,6 +403,7 @@ struct dpp_controller_config { void *msg_ctx; void *cb_ctx; int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); + bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth); }; #ifdef CONFIG_TESTING_OPTIONS @@ -703,12 +705,21 @@ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth, const char *name, enum dpp_netrole netrole, void *msg_ctx, void *cb_ctx, int (*process_conf_obj)(void *ctx, - struct dpp_authentication *auth)); + struct dpp_authentication *auth), + bool (*tcp_msg_sent)(void *ctx, + struct dpp_authentication *auth)); int dpp_tcp_auth(struct dpp_global *dpp, void *_conn, struct dpp_authentication *auth, const char *name, enum dpp_netrole netrole, int (*process_conf_obj)(void *ctx, - struct dpp_authentication *auth)); + struct dpp_authentication *auth), + bool (*tcp_msg_sent)(void *ctx, + struct dpp_authentication *auth)); +bool dpp_tcp_conn_status_requested(struct dpp_global *dpp); +void dpp_tcp_send_conn_status(struct dpp_global *dpp, + enum dpp_status_error result, + const u8 *ssid, size_t ssid_len, + const char *channel_list); struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi); void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src, diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h index c00b1ee41..0f31ae56a 100644 --- a/src/common/dpp_i.h +++ b/src/common/dpp_i.h @@ -2,6 +2,7 @@ * DPP module internal definitions * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -22,6 +23,7 @@ struct dpp_global { struct dl_list tcp_init; /* struct dpp_connection */ void *cb_ctx; int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); + bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth); void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi); #endif /* CONFIG_DPP2 */ }; diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c index 1a8a7c7d5..14ff2d903 100644 --- a/src/common/dpp_tcp.c +++ b/src/common/dpp_tcp.c @@ -1,6 +1,7 @@ /* * DPP over TCP * Copyright (c) 2019-2020, The Linux Foundation + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -30,6 +31,7 @@ struct dpp_connection { void *cb_ctx; int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); int (*pkex_done)(void *ctx, void *conn, struct dpp_bootstrap_info *bi); + bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth); int sock; u8 mac_addr[ETH_ALEN]; unsigned int freq; @@ -79,6 +81,7 @@ struct dpp_controller { void *msg_ctx; void *cb_ctx; int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); + bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth); }; static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx); @@ -245,6 +248,10 @@ static int dpp_tcp_send(struct dpp_connection *conn) dpp_controller_rx, conn, NULL) == 0) conn->read_eloop = 1; if (conn->on_tcp_tx_complete_remove) { + if (conn->auth && conn->auth->connect_on_tx_status && + conn->tcp_msg_sent && + conn->tcp_msg_sent(conn->cb_ctx, conn->auth)) + return 0; dpp_connection_remove(conn); } else if (conn->auth && (conn->ctrl || conn->auth->configurator) && conn->on_tcp_tx_complete_gas_done) { @@ -781,6 +788,7 @@ static int dpp_controller_rx_conf_result(struct dpp_connection *conn, wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT "wait_conn_status=1"); wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result"); + auth->waiting_conn_status_result = 1; eloop_cancel_timeout( dpp_controller_conn_status_result_wait_timeout, conn, NULL); @@ -1697,6 +1705,7 @@ static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx) conn->msg_ctx = ctrl->msg_ctx; conn->cb_ctx = ctrl->cb_ctx; conn->process_conf_obj = ctrl->process_conf_obj; + conn->tcp_msg_sent = ctrl->tcp_msg_sent; conn->sock = fd; conn->netrole = ctrl->netrole; @@ -1821,7 +1830,9 @@ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth, const struct hostapd_ip_addr *addr, int port, const char *name, enum dpp_netrole netrole, void *msg_ctx, void *cb_ctx, int (*process_conf_obj)(void *ctx, - struct dpp_authentication *auth)) + struct dpp_authentication *auth), + bool (*tcp_msg_sent)(void *ctx, + struct dpp_authentication *auth)) { struct dpp_connection *conn; struct sockaddr_storage saddr; @@ -1845,6 +1856,7 @@ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth, conn->msg_ctx = msg_ctx; conn->cb_ctx = cb_ctx; conn->process_conf_obj = process_conf_obj; + conn->tcp_msg_sent = tcp_msg_sent; conn->name = os_strdup(name ? name : "Test"); conn->netrole = netrole; conn->global = dpp; @@ -1894,13 +1906,16 @@ int dpp_tcp_auth(struct dpp_global *dpp, void *_conn, struct dpp_authentication *auth, const char *name, enum dpp_netrole netrole, int (*process_conf_obj)(void *ctx, - struct dpp_authentication *auth)) + struct dpp_authentication *auth), + bool (*tcp_msg_sent)(void *ctx, + struct dpp_authentication *auth)) { struct dpp_connection *conn = _conn; /* Continue with Authentication exchange on an existing TCP connection. */ conn->process_conf_obj = process_conf_obj; + conn->tcp_msg_sent = tcp_msg_sent; os_free(conn->name); conn->name = os_strdup(name ? name : "Test"); conn->netrole = netrole; @@ -1939,6 +1954,7 @@ int dpp_controller_start(struct dpp_global *dpp, ctrl->msg_ctx = config->msg_ctx; ctrl->cb_ctx = config->cb_ctx; ctrl->process_conf_obj = config->process_conf_obj; + ctrl->tcp_msg_sent = config->tcp_msg_sent; ctrl->sock = socket(AF_INET, SOCK_STREAM, 0); if (ctrl->sock < 0) @@ -2116,4 +2132,65 @@ void dpp_relay_flush_controllers(struct dpp_global *dpp) } } + +bool dpp_tcp_conn_status_requested(struct dpp_global *dpp) +{ + struct dpp_connection *conn; + + dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) { + if (conn->auth && conn->auth->conn_status_requested) + return true; + } + + return false; +} + + +static void dpp_tcp_send_conn_status_msg(struct dpp_connection *conn, + enum dpp_status_error result, + const u8 *ssid, size_t ssid_len, + const char *channel_list) +{ + struct dpp_authentication *auth = conn->auth; + int res; + struct wpabuf *msg; + + auth->conn_status_requested = 0; + + msg = dpp_build_conn_status_result(auth, result, ssid, ssid_len, + channel_list); + if (!msg) { + dpp_connection_remove(conn); + return; + } + + res = dpp_tcp_send_msg(conn, msg); + wpabuf_free(msg); + + if (res < 0) { + dpp_connection_remove(conn); + return; + } + + /* This exchange will be terminated in the TX status handler */ + conn->on_tcp_tx_complete_remove = 1; +} + + +void dpp_tcp_send_conn_status(struct dpp_global *dpp, + enum dpp_status_error result, + const u8 *ssid, size_t ssid_len, + const char *channel_list) +{ + struct dpp_connection *conn; + + dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) { + if (conn->auth && conn->auth->conn_status_requested) { + dpp_tcp_send_conn_status_msg(conn, result, ssid, + ssid_len, channel_list); + break; + } + } +} + #endif /* CONFIG_DPP2 */ diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index b8c7a6712..acd8521c3 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -2,6 +2,7 @@ * wpa_supplicant - DPP * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -53,6 +54,7 @@ static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx, static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s); static int wpas_dpp_process_conf_obj(void *ctx, struct dpp_authentication *auth); +static bool wpas_dpp_tcp_msg_sent(void *ctx, struct dpp_authentication *auth); #endif /* CONFIG_DPP2 */ static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -295,7 +297,8 @@ static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx, struct dpp_authentication *auth = wpa_s->dpp_auth; enum dpp_status_error result; - if (!auth || !auth->conn_status_requested) + if ((!auth || !auth->conn_status_requested) && + !dpp_tcp_conn_status_requested(wpa_s->dpp)) return; wpa_printf(MSG_DEBUG, @@ -371,9 +374,10 @@ void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s, eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL); - if (!auth || !auth->conn_status_requested) + if ((!auth || !auth->conn_status_requested) && + !dpp_tcp_conn_status_requested(wpa_s->dpp)) return; - auth->conn_status_requested = 0; + wpa_printf(MSG_DEBUG, "DPP: Report connection status result %d", result); @@ -382,6 +386,19 @@ void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s, channel_list = channel_list_buf; } + if (!auth || !auth->conn_status_requested) { + dpp_tcp_send_conn_status(wpa_s->dpp, result, + ssid ? ssid->ssid : + wpa_s->dpp_last_ssid, + ssid ? ssid->ssid_len : + wpa_s->dpp_last_ssid_len, + channel_list); + os_free(channel_list_buf); + return; + } + + auth->conn_status_requested = 0; + msg = dpp_build_conn_status_result(auth, result, ssid ? ssid->ssid : wpa_s->dpp_last_ssid, @@ -416,7 +433,8 @@ void wpas_dpp_connected(struct wpa_supplicant *wpa_s) { struct dpp_authentication *auth = wpa_s->dpp_auth; - if (auth && auth->conn_status_requested) + if ((auth && auth->conn_status_requested) || + dpp_tcp_conn_status_requested(wpa_s->dpp)) wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_OK); } @@ -874,7 +892,8 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) if (tcp) return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port, wpa_s->conf->dpp_name, DPP_NETROLE_STA, - wpa_s, wpa_s, wpas_dpp_process_conf_obj); + wpa_s, wpa_s, wpas_dpp_process_conf_obj, + wpas_dpp_tcp_msg_sent); #endif /* CONFIG_DPP2 */ wpa_s->dpp_auth = auth; @@ -2028,6 +2047,34 @@ static int wpas_dpp_process_conf_obj(void *ctx, } +static bool wpas_dpp_tcp_msg_sent(void *ctx, struct dpp_authentication *auth) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpa_printf(MSG_DEBUG, "DPP: TCP message sent callback"); + + if (auth->connect_on_tx_status) { + auth->connect_on_tx_status = 0; + wpa_printf(MSG_DEBUG, + "DPP: Try to connect after completed configuration result"); + wpas_dpp_try_to_connect(wpa_s); + if (auth->conn_status_requested) { + wpa_printf(MSG_DEBUG, + "DPP: Start 15 second timeout for reporting connection status result"); + eloop_cancel_timeout( + wpas_dpp_conn_status_result_timeout, + wpa_s, NULL); + eloop_register_timeout( + 15, 0, wpas_dpp_conn_status_result_timeout, + wpa_s, NULL); + return true; + } + } + + return false; +} + + static void wpas_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi) { struct wpa_supplicant *wpa_s = ctx; @@ -2617,7 +2664,8 @@ static int wpas_dpp_pkex_done(void *ctx, void *conn, } return dpp_tcp_auth(wpa_s->dpp, conn, auth, wpa_s->conf->dpp_name, - DPP_NETROLE_STA, wpas_dpp_process_conf_obj); + DPP_NETROLE_STA, wpas_dpp_process_conf_obj, + wpas_dpp_tcp_msg_sent); } #endif /* CONFIG_DPP2 */ @@ -3641,6 +3689,7 @@ int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd) config.msg_ctx = wpa_s; config.cb_ctx = wpa_s; config.process_conf_obj = wpas_dpp_process_conf_obj; + config.tcp_msg_sent = wpas_dpp_tcp_msg_sent; if (cmd) { pos = os_strstr(cmd, " tcp_port="); if (pos) {