From: Jouni Malinen Date: Sat, 9 Jul 2022 09:36:34 +0000 (+0300) Subject: DPP: Allow AP/Relay to be configured to listed for new TCP connections X-Git-Tag: hostap_2_11~1842 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=451ede2c31e167407025123422868a209f98324c;p=thirdparty%2Fhostap.git DPP: Allow AP/Relay to be configured to listed for new TCP connections This extends Relay functionality to allow a Controller to intitiate a new DPP exchange in addition to the previously supported case where the exchange was initiated through a DPP Public Action frame. Signed-off-by: Jouni Malinen --- diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 8a86ce08b..5d915a090 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -4471,6 +4471,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "dpp_controller") == 0) { if (hostapd_dpp_controller_parse(bss, pos)) return 1; + } else if (os_strcmp(buf, "dpp_relay_port") == 0) { + bss->dpp_relay_port = atoi(pos); } else if (os_strcmp(buf, "dpp_configurator_connectivity") == 0) { bss->dpp_configurator_connectivity = atoi(pos); } else if (os_strcmp(buf, "dpp_pfs") == 0) { diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 6b4223fff..1c4ca71a9 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -2520,6 +2520,12 @@ own_ip_addr=127.0.0.1 #dpp_csign #dpp_controller +# DPP Relay port number +# TCP port to listen to for incoming connections from a Controller. This can be +# used to allow Controller initiated exchanges in addition to the +# Controller-as-responder cases covered by the dpp_controller parameter. +#dpp_relay_port=12345 + # Configurator Connectivity indication # 0: no Configurator is currently connected (default) # 1: advertise that a Configurator is available diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 9b9212feb..9fb385717 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -761,6 +761,7 @@ struct hostapd_bss_config { struct wpabuf *dpp_csign; #ifdef CONFIG_DPP2 struct dpp_controller_conf *dpp_controller; + int dpp_relay_port; int dpp_configurator_connectivity; int dpp_pfs; #endif /* CONFIG_DPP2 */ diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index 5a6fab628..e99e658ca 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -3017,6 +3017,9 @@ static void hostapd_dpp_relay_tx(void *ctx, const u8 *addr, unsigned int freq, struct hostapd_data *hapd = ctx; u8 *buf; + if (freq == 0) + freq = hapd->iface->freq; + wpa_printf(MSG_DEBUG, "DPP: Send action frame dst=" MACSTR " freq=%u", MAC2STR(addr), freq); buf = os_malloc(2 + len); @@ -3059,6 +3062,10 @@ static int hostapd_dpp_add_controllers(struct hostapd_data *hapd) &config) < 0) return -1; } + + if (hapd->conf->dpp_relay_port) + dpp_relay_listen(hapd->iface->interfaces->dpp, + hapd->conf->dpp_relay_port); #endif /* CONFIG_DPP2 */ return 0; @@ -3099,8 +3106,10 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd) eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd, NULL); hostapd_dpp_chirp_stop(hapd); - if (hapd->iface->interfaces) + if (hapd->iface->interfaces) { + dpp_relay_stop_listen(hapd->iface->interfaces->dpp); dpp_controller_stop_for_ctx(hapd->iface->interfaces->dpp, hapd); + } #endif /* CONFIG_DPP2 */ #ifdef CONFIG_DPP3 eloop_cancel_timeout(hostapd_dpp_build_new_key, hapd, NULL); diff --git a/src/common/dpp.c b/src/common/dpp.c index 489e061e3..6c1b5be0e 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -4890,6 +4890,7 @@ struct dpp_global * dpp_global_init(struct dpp_global_config *config) #ifdef CONFIG_DPP2 dl_list_init(&dpp->controllers); dl_list_init(&dpp->tcp_init); + dpp->relay_sock = -1; #endif /* CONFIG_DPP2 */ return dpp; diff --git a/src/common/dpp.h b/src/common/dpp.h index edeb34c47..8202ef818 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -719,6 +719,8 @@ struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp, const u8 *kid); int dpp_relay_add_controller(struct dpp_global *dpp, struct dpp_relay_config *config); +int dpp_relay_listen(struct dpp_global *dpp, int port); +void dpp_relay_stop_listen(struct dpp_global *dpp); int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, const u8 *buf, size_t len, unsigned int freq, const u8 *i_bootstrap, const u8 *r_bootstrap, diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h index f7184121c..051d3fd8e 100644 --- a/src/common/dpp_i.h +++ b/src/common/dpp_i.h @@ -21,6 +21,7 @@ struct dpp_global { struct dl_list controllers; /* struct dpp_relay_controller */ struct dpp_controller *controller; struct dl_list tcp_init; /* struct dpp_connection */ + int relay_sock; void *cb_ctx; int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth); diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c index 5b1eeb449..d7c232841 100644 --- a/src/common/dpp_tcp.c +++ b/src/common/dpp_tcp.c @@ -189,6 +189,26 @@ dpp_relay_controller_get_ctx(struct dpp_global *dpp, void *cb_ctx) } +static struct dpp_relay_controller * +dpp_relay_controller_get_addr(struct dpp_global *dpp, + const struct sockaddr_in *addr) +{ + struct dpp_relay_controller *ctrl; + + if (!dpp) + return NULL; + + dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller, + list) { + if (ctrl->ipaddr.af == AF_INET && + addr->sin_addr.s_addr == ctrl->ipaddr.u.v4.s_addr) + return ctrl; + } + + return NULL; +} + + static void dpp_controller_gas_done(struct dpp_connection *conn) { struct dpp_authentication *auth = conn->auth; @@ -543,6 +563,17 @@ int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, if (os_memcmp(src, conn->mac_addr, ETH_ALEN) == 0) return dpp_relay_tx(conn, hdr, buf, len); + if (type == DPP_PA_AUTHENTICATION_RESP && + conn->freq == 0 && + is_broadcast_ether_addr(conn->mac_addr)) { + wpa_printf(MSG_DEBUG, + "DPP: Associate this peer to the new Controller initiated connection"); + os_memcpy(conn->mac_addr, src, + ETH_ALEN); + conn->freq = freq; + return dpp_relay_tx(conn, hdr, buf, + len); + } } } } @@ -2240,6 +2271,143 @@ void dpp_relay_flush_controllers(struct dpp_global *dpp) } +static void dpp_relay_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx) +{ + struct dpp_global *dpp = eloop_ctx; + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + int fd; + struct dpp_relay_controller *ctrl; + struct dpp_connection *conn = NULL; + + wpa_printf(MSG_DEBUG, "DPP: New TCP connection (Relay)"); + + fd = accept(dpp->relay_sock, (struct sockaddr *) &addr, &addr_len); + if (fd < 0) { + wpa_printf(MSG_DEBUG, + "DPP: Failed to accept new connection: %s", + strerror(errno)); + return; + } + wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d", + inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + ctrl = dpp_relay_controller_get_addr(dpp, &addr); + if (!ctrl) { + wpa_printf(MSG_DEBUG, + "DPP: No Controller found for that address"); + goto fail; + } + + if (dl_list_len(&ctrl->conn) >= 15) { + wpa_printf(MSG_DEBUG, + "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one"); + goto fail; + } + + conn = os_zalloc(sizeof(*conn)); + if (!conn) + goto fail; + + conn->global = ctrl->global; + conn->relay = ctrl; + conn->msg_ctx = ctrl->msg_ctx; + conn->cb_ctx = ctrl->global->cb_ctx; + os_memset(conn->mac_addr, 0xff, ETH_ALEN); + conn->sock = fd; + + if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) { + wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s", + strerror(errno)); + goto fail; + } + + if (eloop_register_sock(conn->sock, EVENT_TYPE_READ, + dpp_controller_rx, conn, NULL) < 0) + goto fail; + conn->read_eloop = 1; + + /* TODO: eloop timeout to expire connections that do not complete in + * reasonable time */ + dl_list_add(&ctrl->conn, &conn->list); + return; + +fail: + close(fd); + os_free(conn); +} + + +int dpp_relay_listen(struct dpp_global *dpp, int port) +{ + int s; + int on = 1; + struct sockaddr_in sin; + + if (dpp->relay_sock >= 0) { + wpa_printf(MSG_INFO, "DPP: %s(%d) - relay port already opened", + __func__, port); + return -1; + } + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) { + wpa_printf(MSG_INFO, + "DPP: socket(SOCK_STREAM) failed: %s", + strerror(errno)); + return -1; + } + + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { + wpa_printf(MSG_DEBUG, + "DPP: setsockopt(SO_REUSEADDR) failed: %s", + strerror(errno)); + /* try to continue anyway */ + } + + if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) { + wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s", + strerror(errno)); + close(s); + return -1; + } + + /* TODO: IPv6 */ + os_memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = htons(port); + if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { + wpa_printf(MSG_INFO, + "DPP: Failed to bind Relay TCP port: %s", + strerror(errno)); + close(s); + return -1; + } + if (listen(s, 10 /* max backlog */) < 0 || + fcntl(s, F_SETFL, O_NONBLOCK) < 0 || + eloop_register_sock(s, EVENT_TYPE_READ, dpp_relay_tcp_cb, dpp, + NULL)) { + close(s); + return -1; + } + + dpp->relay_sock = s; + wpa_printf(MSG_DEBUG, "DPP: Relay started on TCP port %d", port); + return 0; +} + + +void dpp_relay_stop_listen(struct dpp_global *dpp) +{ + if (!dpp || dpp->relay_sock < 0) + return; + eloop_unregister_sock(dpp->relay_sock, EVENT_TYPE_READ); + close(dpp->relay_sock); + dpp->relay_sock = -1; +} + + bool dpp_tcp_conn_status_requested(struct dpp_global *dpp) { struct dpp_connection *conn;