]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP: Allow AP/Relay to be configured to listed for new TCP connections
authorJouni Malinen <quic_jouni@quicinc.com>
Sat, 9 Jul 2022 09:36:34 +0000 (12:36 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 9 Jul 2022 10:09:04 +0000 (13:09 +0300)
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 <quic_jouni@quicinc.com>
hostapd/config_file.c
hostapd/hostapd.conf
src/ap/ap_config.h
src/ap/dpp_hostapd.c
src/common/dpp.c
src/common/dpp.h
src/common/dpp_i.h
src/common/dpp_tcp.c

index 8a86ce08bae4914616b0d6e277656d72300adf88..5d915a090fe82d297ef42b9664717b64b99a22b7 100644 (file)
@@ -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) {
index 6b4223fff8573e4b75eab23b1cbc6023e805c1f5..1c4ca71a9352992b77a2d416aa309428700f1de1 100644 (file)
@@ -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
index 9b9212feb7a48a5fa53abd2758044813bfff32af..9fb38571737aa2855000ff29e446896b31337108 100644 (file)
@@ -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 */
index 5a6fab628a91f648223e0cdc85abd119462f37ab..e99e658cad50e2275c973a5e7a41d1a914a8406c 100644 (file)
@@ -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);
index 489e061e3c11f5dc9fad644bd460b3ff31e0575a..6c1b5be0e649edce3ef37a5f39bbc4360236b7c7 100644 (file)
@@ -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;
index edeb34c47a900c3b9aa8babe1aa86417ba5cfba9..8202ef818da6036c4827d685b4c6dc1f970623c5 100644 (file)
@@ -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,
index f7184121c965c1187d743eda3221b7789afcd9c5..051d3fd8edec65da8d7002b8e88fc32892c9821b 100644 (file)
@@ -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);
index 5b1eeb449f1cc2367e504e71339285c7d23e1244..d7c23284105e781c30e1aebc1d5d04180b4f576a 100644 (file)
@@ -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;