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 <quic_jouni@quicinc.com>
This commit is contained in:
Jouni Malinen 2022-01-28 17:28:49 +02:00 committed by Jouni Malinen
parent 75f42be0a7
commit 33cb47cf01
6 changed files with 153 additions and 12 deletions

View file

@ -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;

View file

@ -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.

View file

@ -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,

View file

@ -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 */
};

View file

@ -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 */

View file

@ -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) {