1c1d255d3SCy Schubert /* 2c1d255d3SCy Schubert * DPP over TCP 3c1d255d3SCy Schubert * Copyright (c) 2019-2020, The Linux Foundation 4*a90b9d01SCy Schubert * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. 5c1d255d3SCy Schubert * 6c1d255d3SCy Schubert * This software may be distributed under the terms of the BSD license. 7c1d255d3SCy Schubert * See README for more details. 8c1d255d3SCy Schubert */ 9c1d255d3SCy Schubert 10c1d255d3SCy Schubert #include "utils/includes.h" 11c1d255d3SCy Schubert #include <fcntl.h> 12c1d255d3SCy Schubert 13c1d255d3SCy Schubert #include "utils/common.h" 14c1d255d3SCy Schubert #include "utils/ip_addr.h" 15c1d255d3SCy Schubert #include "utils/eloop.h" 16c1d255d3SCy Schubert #include "common/ieee802_11_common.h" 17c1d255d3SCy Schubert #include "common/wpa_ctrl.h" 18c1d255d3SCy Schubert #include "dpp.h" 19c1d255d3SCy Schubert #include "dpp_i.h" 20c1d255d3SCy Schubert 21c1d255d3SCy Schubert #ifdef CONFIG_DPP2 22c1d255d3SCy Schubert 23c1d255d3SCy Schubert struct dpp_connection { 24c1d255d3SCy Schubert struct dl_list list; 25c1d255d3SCy Schubert struct dpp_controller *ctrl; 26c1d255d3SCy Schubert struct dpp_relay_controller *relay; 27c1d255d3SCy Schubert struct dpp_global *global; 28*a90b9d01SCy Schubert struct dpp_pkex *pkex; 29c1d255d3SCy Schubert struct dpp_authentication *auth; 30c1d255d3SCy Schubert void *msg_ctx; 31c1d255d3SCy Schubert void *cb_ctx; 32c1d255d3SCy Schubert int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); 33*a90b9d01SCy Schubert int (*pkex_done)(void *ctx, void *conn, struct dpp_bootstrap_info *bi); 34*a90b9d01SCy Schubert bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth); 35c1d255d3SCy Schubert int sock; 36c1d255d3SCy Schubert u8 mac_addr[ETH_ALEN]; 37c1d255d3SCy Schubert unsigned int freq; 38c1d255d3SCy Schubert u8 msg_len[4]; 39c1d255d3SCy Schubert size_t msg_len_octets; 40c1d255d3SCy Schubert struct wpabuf *msg; 41c1d255d3SCy Schubert struct wpabuf *msg_out; 42c1d255d3SCy Schubert size_t msg_out_pos; 43c1d255d3SCy Schubert unsigned int read_eloop:1; 44c1d255d3SCy Schubert unsigned int write_eloop:1; 45c1d255d3SCy Schubert unsigned int on_tcp_tx_complete_gas_done:1; 46c1d255d3SCy Schubert unsigned int on_tcp_tx_complete_remove:1; 47c1d255d3SCy Schubert unsigned int on_tcp_tx_complete_auth_ok:1; 48c1d255d3SCy Schubert unsigned int gas_comeback_in_progress:1; 49c1d255d3SCy Schubert u8 gas_dialog_token; 50c1d255d3SCy Schubert char *name; 51*a90b9d01SCy Schubert char *mud_url; 52*a90b9d01SCy Schubert char *extra_conf_req_name; 53*a90b9d01SCy Schubert char *extra_conf_req_value; 54c1d255d3SCy Schubert enum dpp_netrole netrole; 55c1d255d3SCy Schubert }; 56c1d255d3SCy Schubert 57c1d255d3SCy Schubert /* Remote Controller */ 58c1d255d3SCy Schubert struct dpp_relay_controller { 59c1d255d3SCy Schubert struct dl_list list; 60c1d255d3SCy Schubert struct dpp_global *global; 61c1d255d3SCy Schubert u8 pkhash[SHA256_MAC_LEN]; 62c1d255d3SCy Schubert struct hostapd_ip_addr ipaddr; 63c1d255d3SCy Schubert void *msg_ctx; 64c1d255d3SCy Schubert void *cb_ctx; 65c1d255d3SCy Schubert void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg, 66c1d255d3SCy Schubert size_t len); 67c1d255d3SCy Schubert void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token, 68c1d255d3SCy Schubert int prot, struct wpabuf *buf); 69c1d255d3SCy Schubert struct dl_list conn; /* struct dpp_connection */ 70c1d255d3SCy Schubert }; 71c1d255d3SCy Schubert 72c1d255d3SCy Schubert /* Local Controller */ 73c1d255d3SCy Schubert struct dpp_controller { 74c1d255d3SCy Schubert struct dpp_global *global; 75c1d255d3SCy Schubert u8 allowed_roles; 76c1d255d3SCy Schubert int qr_mutual; 77c1d255d3SCy Schubert int sock; 78c1d255d3SCy Schubert struct dl_list conn; /* struct dpp_connection */ 79c1d255d3SCy Schubert char *configurator_params; 80c1d255d3SCy Schubert enum dpp_netrole netrole; 81*a90b9d01SCy Schubert struct dpp_bootstrap_info *pkex_bi; 82*a90b9d01SCy Schubert char *pkex_code; 83*a90b9d01SCy Schubert char *pkex_identifier; 84c1d255d3SCy Schubert void *msg_ctx; 85c1d255d3SCy Schubert void *cb_ctx; 86c1d255d3SCy Schubert int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); 87*a90b9d01SCy Schubert bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth); 88c1d255d3SCy Schubert }; 89c1d255d3SCy Schubert 90c1d255d3SCy Schubert static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx); 91c1d255d3SCy Schubert static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx); 92c1d255d3SCy Schubert static void dpp_controller_auth_success(struct dpp_connection *conn, 93c1d255d3SCy Schubert int initiator); 94c1d255d3SCy Schubert static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx); 95*a90b9d01SCy Schubert #ifdef CONFIG_DPP3 96*a90b9d01SCy Schubert static void dpp_tcp_build_new_key(void *eloop_ctx, void *timeout_ctx); 97*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */ 98c1d255d3SCy Schubert static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx); 99c1d255d3SCy Schubert static void dpp_relay_conn_timeout(void *eloop_ctx, void *timeout_ctx); 100c1d255d3SCy Schubert 101c1d255d3SCy Schubert 102c1d255d3SCy Schubert static void dpp_connection_free(struct dpp_connection *conn) 103c1d255d3SCy Schubert { 104c1d255d3SCy Schubert if (conn->sock >= 0) { 105c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Close Controller socket %d", 106c1d255d3SCy Schubert conn->sock); 107c1d255d3SCy Schubert eloop_unregister_sock(conn->sock, EVENT_TYPE_READ); 108c1d255d3SCy Schubert eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE); 109c1d255d3SCy Schubert close(conn->sock); 110c1d255d3SCy Schubert } 111c1d255d3SCy Schubert eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout, 112c1d255d3SCy Schubert conn, NULL); 113c1d255d3SCy Schubert eloop_cancel_timeout(dpp_tcp_build_csr, conn, NULL); 114c1d255d3SCy Schubert eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL); 115c1d255d3SCy Schubert eloop_cancel_timeout(dpp_relay_conn_timeout, conn, NULL); 116*a90b9d01SCy Schubert #ifdef CONFIG_DPP3 117*a90b9d01SCy Schubert eloop_cancel_timeout(dpp_tcp_build_new_key, conn, NULL); 118*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */ 119c1d255d3SCy Schubert wpabuf_free(conn->msg); 120c1d255d3SCy Schubert wpabuf_free(conn->msg_out); 121c1d255d3SCy Schubert dpp_auth_deinit(conn->auth); 122*a90b9d01SCy Schubert dpp_pkex_free(conn->pkex); 123c1d255d3SCy Schubert os_free(conn->name); 124*a90b9d01SCy Schubert os_free(conn->mud_url); 125*a90b9d01SCy Schubert os_free(conn->extra_conf_req_name); 126*a90b9d01SCy Schubert os_free(conn->extra_conf_req_value); 127c1d255d3SCy Schubert os_free(conn); 128c1d255d3SCy Schubert } 129c1d255d3SCy Schubert 130c1d255d3SCy Schubert 131c1d255d3SCy Schubert static void dpp_connection_remove(struct dpp_connection *conn) 132c1d255d3SCy Schubert { 133c1d255d3SCy Schubert dl_list_del(&conn->list); 134c1d255d3SCy Schubert dpp_connection_free(conn); 135c1d255d3SCy Schubert } 136c1d255d3SCy Schubert 137c1d255d3SCy Schubert 138c1d255d3SCy Schubert int dpp_relay_add_controller(struct dpp_global *dpp, 139c1d255d3SCy Schubert struct dpp_relay_config *config) 140c1d255d3SCy Schubert { 141c1d255d3SCy Schubert struct dpp_relay_controller *ctrl; 142*a90b9d01SCy Schubert char txt[100]; 143c1d255d3SCy Schubert 144c1d255d3SCy Schubert if (!dpp) 145c1d255d3SCy Schubert return -1; 146c1d255d3SCy Schubert 147c1d255d3SCy Schubert ctrl = os_zalloc(sizeof(*ctrl)); 148c1d255d3SCy Schubert if (!ctrl) 149c1d255d3SCy Schubert return -1; 150c1d255d3SCy Schubert dl_list_init(&ctrl->conn); 151c1d255d3SCy Schubert ctrl->global = dpp; 152c1d255d3SCy Schubert os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr)); 153c1d255d3SCy Schubert os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN); 154c1d255d3SCy Schubert ctrl->msg_ctx = config->msg_ctx; 155c1d255d3SCy Schubert ctrl->cb_ctx = config->cb_ctx; 156c1d255d3SCy Schubert ctrl->tx = config->tx; 157c1d255d3SCy Schubert ctrl->gas_resp_tx = config->gas_resp_tx; 158*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Add Relay connection to Controller %s", 159*a90b9d01SCy Schubert hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt))); 160c1d255d3SCy Schubert dl_list_add(&dpp->controllers, &ctrl->list); 161c1d255d3SCy Schubert return 0; 162c1d255d3SCy Schubert } 163c1d255d3SCy Schubert 164c1d255d3SCy Schubert 165c1d255d3SCy Schubert static struct dpp_relay_controller * 166c1d255d3SCy Schubert dpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash) 167c1d255d3SCy Schubert { 168c1d255d3SCy Schubert struct dpp_relay_controller *ctrl; 169c1d255d3SCy Schubert 170c1d255d3SCy Schubert if (!dpp) 171c1d255d3SCy Schubert return NULL; 172c1d255d3SCy Schubert 173c1d255d3SCy Schubert dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller, 174c1d255d3SCy Schubert list) { 175c1d255d3SCy Schubert if (os_memcmp(pkhash, ctrl->pkhash, SHA256_MAC_LEN) == 0) 176c1d255d3SCy Schubert return ctrl; 177c1d255d3SCy Schubert } 178c1d255d3SCy Schubert 179c1d255d3SCy Schubert return NULL; 180c1d255d3SCy Schubert } 181c1d255d3SCy Schubert 182c1d255d3SCy Schubert 183c1d255d3SCy Schubert static struct dpp_relay_controller * 184c1d255d3SCy Schubert dpp_relay_controller_get_ctx(struct dpp_global *dpp, void *cb_ctx) 185c1d255d3SCy Schubert { 186c1d255d3SCy Schubert struct dpp_relay_controller *ctrl; 187c1d255d3SCy Schubert 188c1d255d3SCy Schubert if (!dpp) 189c1d255d3SCy Schubert return NULL; 190c1d255d3SCy Schubert 191c1d255d3SCy Schubert dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller, 192c1d255d3SCy Schubert list) { 193c1d255d3SCy Schubert if (cb_ctx == ctrl->cb_ctx) 194c1d255d3SCy Schubert return ctrl; 195c1d255d3SCy Schubert } 196c1d255d3SCy Schubert 197c1d255d3SCy Schubert return NULL; 198c1d255d3SCy Schubert } 199c1d255d3SCy Schubert 200c1d255d3SCy Schubert 201*a90b9d01SCy Schubert static struct dpp_relay_controller * 202*a90b9d01SCy Schubert dpp_relay_controller_get_addr(struct dpp_global *dpp, 203*a90b9d01SCy Schubert const struct sockaddr_in *addr) 204*a90b9d01SCy Schubert { 205*a90b9d01SCy Schubert struct dpp_relay_controller *ctrl; 206*a90b9d01SCy Schubert 207*a90b9d01SCy Schubert if (!dpp) 208*a90b9d01SCy Schubert return NULL; 209*a90b9d01SCy Schubert 210*a90b9d01SCy Schubert dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller, 211*a90b9d01SCy Schubert list) { 212*a90b9d01SCy Schubert if (ctrl->ipaddr.af == AF_INET && 213*a90b9d01SCy Schubert addr->sin_addr.s_addr == ctrl->ipaddr.u.v4.s_addr) 214*a90b9d01SCy Schubert return ctrl; 215*a90b9d01SCy Schubert } 216*a90b9d01SCy Schubert 217*a90b9d01SCy Schubert if (dpp->tmp_controller && 218*a90b9d01SCy Schubert dpp->tmp_controller->ipaddr.af == AF_INET && 219*a90b9d01SCy Schubert addr->sin_addr.s_addr == dpp->tmp_controller->ipaddr.u.v4.s_addr) 220*a90b9d01SCy Schubert return dpp->tmp_controller; 221*a90b9d01SCy Schubert 222*a90b9d01SCy Schubert return NULL; 223*a90b9d01SCy Schubert } 224*a90b9d01SCy Schubert 225*a90b9d01SCy Schubert 226c1d255d3SCy Schubert static void dpp_controller_gas_done(struct dpp_connection *conn) 227c1d255d3SCy Schubert { 228c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 229c1d255d3SCy Schubert 230c1d255d3SCy Schubert if (auth->waiting_csr) { 231c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Waiting for CSR"); 232c1d255d3SCy Schubert conn->on_tcp_tx_complete_gas_done = 0; 233c1d255d3SCy Schubert return; 234c1d255d3SCy Schubert } 235c1d255d3SCy Schubert 236*a90b9d01SCy Schubert #ifdef CONFIG_DPP3 237*a90b9d01SCy Schubert if (auth->waiting_new_key) { 238*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key"); 239*a90b9d01SCy Schubert conn->on_tcp_tx_complete_gas_done = 0; 240*a90b9d01SCy Schubert return; 241*a90b9d01SCy Schubert } 242*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */ 243*a90b9d01SCy Schubert 244c1d255d3SCy Schubert if (auth->peer_version >= 2 && 245c1d255d3SCy Schubert auth->conf_resp_status == DPP_STATUS_OK) { 246c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); 247c1d255d3SCy Schubert auth->waiting_conf_result = 1; 248c1d255d3SCy Schubert return; 249c1d255d3SCy Schubert } 250c1d255d3SCy Schubert 251*a90b9d01SCy Schubert wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT "conf_status=%d", 252*a90b9d01SCy Schubert auth->conf_resp_status); 253c1d255d3SCy Schubert dpp_connection_remove(conn); 254c1d255d3SCy Schubert } 255c1d255d3SCy Schubert 256c1d255d3SCy Schubert 257c1d255d3SCy Schubert static int dpp_tcp_send(struct dpp_connection *conn) 258c1d255d3SCy Schubert { 259c1d255d3SCy Schubert int res; 260c1d255d3SCy Schubert 261c1d255d3SCy Schubert if (!conn->msg_out) { 262c1d255d3SCy Schubert eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE); 263c1d255d3SCy Schubert conn->write_eloop = 0; 264c1d255d3SCy Schubert return -1; 265c1d255d3SCy Schubert } 266c1d255d3SCy Schubert res = send(conn->sock, 267c1d255d3SCy Schubert wpabuf_head_u8(conn->msg_out) + conn->msg_out_pos, 268c1d255d3SCy Schubert wpabuf_len(conn->msg_out) - conn->msg_out_pos, 0); 269c1d255d3SCy Schubert if (res < 0) { 270c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to send buffer: %s", 271c1d255d3SCy Schubert strerror(errno)); 272c1d255d3SCy Schubert dpp_connection_remove(conn); 273c1d255d3SCy Schubert return -1; 274c1d255d3SCy Schubert } 275c1d255d3SCy Schubert 276c1d255d3SCy Schubert conn->msg_out_pos += res; 277c1d255d3SCy Schubert if (wpabuf_len(conn->msg_out) > conn->msg_out_pos) { 278c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 279c1d255d3SCy Schubert "DPP: %u/%u bytes of message sent to Controller", 280c1d255d3SCy Schubert (unsigned int) conn->msg_out_pos, 281c1d255d3SCy Schubert (unsigned int) wpabuf_len(conn->msg_out)); 282c1d255d3SCy Schubert if (!conn->write_eloop && 283c1d255d3SCy Schubert eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, 284c1d255d3SCy Schubert dpp_conn_tx_ready, conn, NULL) == 0) 285c1d255d3SCy Schubert conn->write_eloop = 1; 286c1d255d3SCy Schubert return 1; 287c1d255d3SCy Schubert } 288c1d255d3SCy Schubert 289c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Full message sent over TCP"); 290c1d255d3SCy Schubert wpabuf_free(conn->msg_out); 291c1d255d3SCy Schubert conn->msg_out = NULL; 292c1d255d3SCy Schubert conn->msg_out_pos = 0; 293c1d255d3SCy Schubert eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE); 294c1d255d3SCy Schubert conn->write_eloop = 0; 295c1d255d3SCy Schubert if (!conn->read_eloop && 296c1d255d3SCy Schubert eloop_register_sock(conn->sock, EVENT_TYPE_READ, 297c1d255d3SCy Schubert dpp_controller_rx, conn, NULL) == 0) 298c1d255d3SCy Schubert conn->read_eloop = 1; 299c1d255d3SCy Schubert if (conn->on_tcp_tx_complete_remove) { 300*a90b9d01SCy Schubert if (conn->auth && conn->auth->connect_on_tx_status && 301*a90b9d01SCy Schubert conn->tcp_msg_sent && 302*a90b9d01SCy Schubert conn->tcp_msg_sent(conn->cb_ctx, conn->auth)) 303*a90b9d01SCy Schubert return 0; 304c1d255d3SCy Schubert dpp_connection_remove(conn); 305c1d255d3SCy Schubert } else if (conn->auth && (conn->ctrl || conn->auth->configurator) && 306c1d255d3SCy Schubert conn->on_tcp_tx_complete_gas_done) { 307c1d255d3SCy Schubert dpp_controller_gas_done(conn); 308c1d255d3SCy Schubert } else if (conn->on_tcp_tx_complete_auth_ok) { 309c1d255d3SCy Schubert conn->on_tcp_tx_complete_auth_ok = 0; 310c1d255d3SCy Schubert dpp_controller_auth_success(conn, 1); 311c1d255d3SCy Schubert } 312c1d255d3SCy Schubert 313c1d255d3SCy Schubert return 0; 314c1d255d3SCy Schubert } 315c1d255d3SCy Schubert 316c1d255d3SCy Schubert 317c1d255d3SCy Schubert static int dpp_tcp_send_msg(struct dpp_connection *conn, 318c1d255d3SCy Schubert const struct wpabuf *msg) 319c1d255d3SCy Schubert { 320c1d255d3SCy Schubert wpabuf_free(conn->msg_out); 321c1d255d3SCy Schubert conn->msg_out_pos = 0; 322c1d255d3SCy Schubert conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1); 323c1d255d3SCy Schubert if (!conn->msg_out) 324c1d255d3SCy Schubert return -1; 325c1d255d3SCy Schubert wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1); 326c1d255d3SCy Schubert wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1, 327c1d255d3SCy Schubert wpabuf_len(msg) - 1); 328c1d255d3SCy Schubert 329c1d255d3SCy Schubert if (dpp_tcp_send(conn) == 1) { 330c1d255d3SCy Schubert if (!conn->write_eloop) { 331c1d255d3SCy Schubert if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, 332c1d255d3SCy Schubert dpp_conn_tx_ready, 333c1d255d3SCy Schubert conn, NULL) < 0) 334c1d255d3SCy Schubert return -1; 335c1d255d3SCy Schubert conn->write_eloop = 1; 336c1d255d3SCy Schubert } 337c1d255d3SCy Schubert } 338c1d255d3SCy Schubert 339c1d255d3SCy Schubert return 0; 340c1d255d3SCy Schubert } 341c1d255d3SCy Schubert 342c1d255d3SCy Schubert 343c1d255d3SCy Schubert static void dpp_controller_start_gas_client(struct dpp_connection *conn) 344c1d255d3SCy Schubert { 345c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 346c1d255d3SCy Schubert struct wpabuf *buf; 347c1d255d3SCy Schubert const char *dpp_name; 348c1d255d3SCy Schubert 349c1d255d3SCy Schubert dpp_name = conn->name ? conn->name : "Test"; 350*a90b9d01SCy Schubert buf = dpp_build_conf_req_helper(auth, dpp_name, conn->netrole, 351*a90b9d01SCy Schubert conn->mud_url, NULL, 352*a90b9d01SCy Schubert conn->extra_conf_req_name, 353*a90b9d01SCy Schubert conn->extra_conf_req_value); 354c1d255d3SCy Schubert if (!buf) { 355c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 356c1d255d3SCy Schubert "DPP: No configuration request data available"); 357c1d255d3SCy Schubert return; 358c1d255d3SCy Schubert } 359c1d255d3SCy Schubert 360c1d255d3SCy Schubert dpp_tcp_send_msg(conn, buf); 361c1d255d3SCy Schubert wpabuf_free(buf); 362c1d255d3SCy Schubert } 363c1d255d3SCy Schubert 364c1d255d3SCy Schubert 365c1d255d3SCy Schubert static void dpp_controller_auth_success(struct dpp_connection *conn, 366c1d255d3SCy Schubert int initiator) 367c1d255d3SCy Schubert { 368c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 369c1d255d3SCy Schubert 370c1d255d3SCy Schubert if (!auth) 371c1d255d3SCy Schubert return; 372c1d255d3SCy Schubert 373c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded"); 374*a90b9d01SCy Schubert dpp_notify_auth_success(auth, initiator); 375c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 376c1d255d3SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) { 377c1d255d3SCy Schubert wpa_printf(MSG_INFO, 378c1d255d3SCy Schubert "DPP: TESTING - stop at Authentication Confirm"); 379c1d255d3SCy Schubert if (auth->configurator) { 380c1d255d3SCy Schubert /* Prevent GAS response */ 381c1d255d3SCy Schubert auth->auth_success = 0; 382c1d255d3SCy Schubert } 383c1d255d3SCy Schubert return; 384c1d255d3SCy Schubert } 385c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 386c1d255d3SCy Schubert 387c1d255d3SCy Schubert if (!auth->configurator) 388c1d255d3SCy Schubert dpp_controller_start_gas_client(conn); 389c1d255d3SCy Schubert } 390c1d255d3SCy Schubert 391c1d255d3SCy Schubert 392c1d255d3SCy Schubert static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx) 393c1d255d3SCy Schubert { 394c1d255d3SCy Schubert struct dpp_connection *conn = eloop_ctx; 395c1d255d3SCy Schubert 396c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: TCP socket %d ready for TX", sock); 397c1d255d3SCy Schubert dpp_tcp_send(conn); 398c1d255d3SCy Schubert } 399c1d255d3SCy Schubert 400c1d255d3SCy Schubert 401c1d255d3SCy Schubert static int dpp_ipaddr_to_sockaddr(struct sockaddr *addr, socklen_t *addrlen, 402c1d255d3SCy Schubert const struct hostapd_ip_addr *ipaddr, 403c1d255d3SCy Schubert int port) 404c1d255d3SCy Schubert { 405c1d255d3SCy Schubert struct sockaddr_in *dst; 406c1d255d3SCy Schubert #ifdef CONFIG_IPV6 407c1d255d3SCy Schubert struct sockaddr_in6 *dst6; 408c1d255d3SCy Schubert #endif /* CONFIG_IPV6 */ 409c1d255d3SCy Schubert 410c1d255d3SCy Schubert switch (ipaddr->af) { 411c1d255d3SCy Schubert case AF_INET: 412c1d255d3SCy Schubert dst = (struct sockaddr_in *) addr; 413c1d255d3SCy Schubert os_memset(dst, 0, sizeof(*dst)); 414c1d255d3SCy Schubert dst->sin_family = AF_INET; 415c1d255d3SCy Schubert dst->sin_addr.s_addr = ipaddr->u.v4.s_addr; 416c1d255d3SCy Schubert dst->sin_port = htons(port); 417c1d255d3SCy Schubert *addrlen = sizeof(*dst); 418c1d255d3SCy Schubert break; 419c1d255d3SCy Schubert #ifdef CONFIG_IPV6 420c1d255d3SCy Schubert case AF_INET6: 421c1d255d3SCy Schubert dst6 = (struct sockaddr_in6 *) addr; 422c1d255d3SCy Schubert os_memset(dst6, 0, sizeof(*dst6)); 423c1d255d3SCy Schubert dst6->sin6_family = AF_INET6; 424c1d255d3SCy Schubert os_memcpy(&dst6->sin6_addr, &ipaddr->u.v6, 425c1d255d3SCy Schubert sizeof(struct in6_addr)); 426c1d255d3SCy Schubert dst6->sin6_port = htons(port); 427c1d255d3SCy Schubert *addrlen = sizeof(*dst6); 428c1d255d3SCy Schubert break; 429c1d255d3SCy Schubert #endif /* CONFIG_IPV6 */ 430c1d255d3SCy Schubert default: 431c1d255d3SCy Schubert return -1; 432c1d255d3SCy Schubert } 433c1d255d3SCy Schubert 434c1d255d3SCy Schubert return 0; 435c1d255d3SCy Schubert } 436c1d255d3SCy Schubert 437c1d255d3SCy Schubert 438c1d255d3SCy Schubert static void dpp_relay_conn_timeout(void *eloop_ctx, void *timeout_ctx) 439c1d255d3SCy Schubert { 440c1d255d3SCy Schubert struct dpp_connection *conn = eloop_ctx; 441c1d255d3SCy Schubert 442c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 443c1d255d3SCy Schubert "DPP: Timeout while waiting for relayed connection to complete"); 444c1d255d3SCy Schubert dpp_connection_remove(conn); 445c1d255d3SCy Schubert } 446c1d255d3SCy Schubert 447c1d255d3SCy Schubert 448c1d255d3SCy Schubert static struct dpp_connection * 449c1d255d3SCy Schubert dpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src, 450c1d255d3SCy Schubert unsigned int freq) 451c1d255d3SCy Schubert { 452c1d255d3SCy Schubert struct dpp_connection *conn; 453c1d255d3SCy Schubert struct sockaddr_storage addr; 454c1d255d3SCy Schubert socklen_t addrlen; 455c1d255d3SCy Schubert char txt[100]; 456c1d255d3SCy Schubert 457c1d255d3SCy Schubert if (dl_list_len(&ctrl->conn) >= 15) { 458c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 459c1d255d3SCy Schubert "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one"); 460c1d255d3SCy Schubert return NULL; 461c1d255d3SCy Schubert } 462c1d255d3SCy Schubert 463c1d255d3SCy Schubert if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &addr, &addrlen, 464c1d255d3SCy Schubert &ctrl->ipaddr, DPP_TCP_PORT) < 0) 465c1d255d3SCy Schubert return NULL; 466c1d255d3SCy Schubert 467c1d255d3SCy Schubert conn = os_zalloc(sizeof(*conn)); 468c1d255d3SCy Schubert if (!conn) 469c1d255d3SCy Schubert return NULL; 470c1d255d3SCy Schubert 471c1d255d3SCy Schubert conn->global = ctrl->global; 472c1d255d3SCy Schubert conn->relay = ctrl; 473c1d255d3SCy Schubert conn->msg_ctx = ctrl->msg_ctx; 474c1d255d3SCy Schubert conn->cb_ctx = ctrl->global->cb_ctx; 475c1d255d3SCy Schubert os_memcpy(conn->mac_addr, src, ETH_ALEN); 476c1d255d3SCy Schubert conn->freq = freq; 477c1d255d3SCy Schubert 478c1d255d3SCy Schubert conn->sock = socket(AF_INET, SOCK_STREAM, 0); 479c1d255d3SCy Schubert if (conn->sock < 0) 480c1d255d3SCy Schubert goto fail; 481c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: TCP relay socket %d connection to %s", 482c1d255d3SCy Schubert conn->sock, hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt))); 483c1d255d3SCy Schubert 484c1d255d3SCy Schubert if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) { 485c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s", 486c1d255d3SCy Schubert strerror(errno)); 487c1d255d3SCy Schubert goto fail; 488c1d255d3SCy Schubert } 489c1d255d3SCy Schubert 490c1d255d3SCy Schubert if (connect(conn->sock, (struct sockaddr *) &addr, addrlen) < 0) { 491c1d255d3SCy Schubert if (errno != EINPROGRESS) { 492c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s", 493c1d255d3SCy Schubert strerror(errno)); 494c1d255d3SCy Schubert goto fail; 495c1d255d3SCy Schubert } 496c1d255d3SCy Schubert 497c1d255d3SCy Schubert /* 498c1d255d3SCy Schubert * Continue connecting in the background; eloop will call us 499c1d255d3SCy Schubert * once the connection is ready (or failed). 500c1d255d3SCy Schubert */ 501c1d255d3SCy Schubert } 502c1d255d3SCy Schubert 503c1d255d3SCy Schubert if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, 504c1d255d3SCy Schubert dpp_conn_tx_ready, conn, NULL) < 0) 505c1d255d3SCy Schubert goto fail; 506c1d255d3SCy Schubert conn->write_eloop = 1; 507c1d255d3SCy Schubert 508c1d255d3SCy Schubert eloop_cancel_timeout(dpp_relay_conn_timeout, conn, NULL); 509c1d255d3SCy Schubert eloop_register_timeout(20, 0, dpp_relay_conn_timeout, conn, NULL); 510c1d255d3SCy Schubert 511c1d255d3SCy Schubert dl_list_add(&ctrl->conn, &conn->list); 512c1d255d3SCy Schubert return conn; 513c1d255d3SCy Schubert fail: 514c1d255d3SCy Schubert dpp_connection_free(conn); 515c1d255d3SCy Schubert return NULL; 516c1d255d3SCy Schubert } 517c1d255d3SCy Schubert 518c1d255d3SCy Schubert 519c1d255d3SCy Schubert static struct wpabuf * dpp_tcp_encaps(const u8 *hdr, const u8 *buf, size_t len) 520c1d255d3SCy Schubert { 521c1d255d3SCy Schubert struct wpabuf *msg; 522c1d255d3SCy Schubert 523c1d255d3SCy Schubert msg = wpabuf_alloc(4 + 1 + DPP_HDR_LEN + len); 524c1d255d3SCy Schubert if (!msg) 525c1d255d3SCy Schubert return NULL; 526c1d255d3SCy Schubert wpabuf_put_be32(msg, 1 + DPP_HDR_LEN + len); 527c1d255d3SCy Schubert wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC); 528c1d255d3SCy Schubert wpabuf_put_data(msg, hdr, DPP_HDR_LEN); 529c1d255d3SCy Schubert wpabuf_put_data(msg, buf, len); 530c1d255d3SCy Schubert wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg); 531c1d255d3SCy Schubert return msg; 532c1d255d3SCy Schubert } 533c1d255d3SCy Schubert 534c1d255d3SCy Schubert 535c1d255d3SCy Schubert static int dpp_relay_tx(struct dpp_connection *conn, const u8 *hdr, 536c1d255d3SCy Schubert const u8 *buf, size_t len) 537c1d255d3SCy Schubert { 538c1d255d3SCy Schubert u8 type = hdr[DPP_HDR_LEN - 1]; 539c1d255d3SCy Schubert 540c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 541c1d255d3SCy Schubert "DPP: Continue already established Relay/Controller connection for this session"); 542c1d255d3SCy Schubert wpabuf_free(conn->msg_out); 543c1d255d3SCy Schubert conn->msg_out_pos = 0; 544c1d255d3SCy Schubert conn->msg_out = dpp_tcp_encaps(hdr, buf, len); 545c1d255d3SCy Schubert if (!conn->msg_out) { 546c1d255d3SCy Schubert dpp_connection_remove(conn); 547c1d255d3SCy Schubert return -1; 548c1d255d3SCy Schubert } 549c1d255d3SCy Schubert 550c1d255d3SCy Schubert /* TODO: for proto ver 1, need to do remove connection based on GAS Resp 551c1d255d3SCy Schubert * TX status */ 552c1d255d3SCy Schubert if (type == DPP_PA_CONFIGURATION_RESULT) 553c1d255d3SCy Schubert conn->on_tcp_tx_complete_remove = 1; 554c1d255d3SCy Schubert dpp_tcp_send(conn); 555c1d255d3SCy Schubert return 0; 556c1d255d3SCy Schubert } 557c1d255d3SCy Schubert 558c1d255d3SCy Schubert 559*a90b9d01SCy Schubert static struct dpp_connection * 560*a90b9d01SCy Schubert dpp_relay_match_ctrl(struct dpp_relay_controller *ctrl, const u8 *src, 561*a90b9d01SCy Schubert unsigned int freq, u8 type) 562*a90b9d01SCy Schubert { 563*a90b9d01SCy Schubert struct dpp_connection *conn; 564*a90b9d01SCy Schubert 565*a90b9d01SCy Schubert dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) { 566*a90b9d01SCy Schubert if (ether_addr_equal(src, conn->mac_addr)) 567*a90b9d01SCy Schubert return conn; 568*a90b9d01SCy Schubert if ((type == DPP_PA_PKEX_EXCHANGE_RESP || 569*a90b9d01SCy Schubert type == DPP_PA_AUTHENTICATION_RESP) && 570*a90b9d01SCy Schubert conn->freq == 0 && 571*a90b9d01SCy Schubert is_broadcast_ether_addr(conn->mac_addr)) { 572*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 573*a90b9d01SCy Schubert "DPP: Associate this peer to the new Controller initiated connection"); 574*a90b9d01SCy Schubert os_memcpy(conn->mac_addr, src, ETH_ALEN); 575*a90b9d01SCy Schubert conn->freq = freq; 576*a90b9d01SCy Schubert return conn; 577*a90b9d01SCy Schubert } 578*a90b9d01SCy Schubert } 579*a90b9d01SCy Schubert 580*a90b9d01SCy Schubert return NULL; 581*a90b9d01SCy Schubert } 582*a90b9d01SCy Schubert 583*a90b9d01SCy Schubert 584c1d255d3SCy Schubert int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, 585c1d255d3SCy Schubert const u8 *buf, size_t len, unsigned int freq, 586c1d255d3SCy Schubert const u8 *i_bootstrap, const u8 *r_bootstrap, 587c1d255d3SCy Schubert void *cb_ctx) 588c1d255d3SCy Schubert { 589c1d255d3SCy Schubert struct dpp_relay_controller *ctrl; 590c1d255d3SCy Schubert struct dpp_connection *conn; 591c1d255d3SCy Schubert u8 type = hdr[DPP_HDR_LEN - 1]; 592c1d255d3SCy Schubert 593c1d255d3SCy Schubert /* Check if there is an already started session for this peer and if so, 594c1d255d3SCy Schubert * continue that session (send this over TCP) and return 0. 595c1d255d3SCy Schubert */ 596c1d255d3SCy Schubert if (type != DPP_PA_PEER_DISCOVERY_REQ && 597c1d255d3SCy Schubert type != DPP_PA_PEER_DISCOVERY_RESP && 598c1d255d3SCy Schubert type != DPP_PA_PRESENCE_ANNOUNCEMENT && 599c1d255d3SCy Schubert type != DPP_PA_RECONFIG_ANNOUNCEMENT) { 600c1d255d3SCy Schubert dl_list_for_each(ctrl, &dpp->controllers, 601c1d255d3SCy Schubert struct dpp_relay_controller, list) { 602*a90b9d01SCy Schubert conn = dpp_relay_match_ctrl(ctrl, src, freq, type); 603*a90b9d01SCy Schubert if (conn) 604c1d255d3SCy Schubert return dpp_relay_tx(conn, hdr, buf, len); 605c1d255d3SCy Schubert } 606*a90b9d01SCy Schubert 607*a90b9d01SCy Schubert if (dpp->tmp_controller) { 608*a90b9d01SCy Schubert conn = dpp_relay_match_ctrl(dpp->tmp_controller, src, 609*a90b9d01SCy Schubert freq, type); 610*a90b9d01SCy Schubert if (conn) 611*a90b9d01SCy Schubert return dpp_relay_tx(conn, hdr, buf, len); 612c1d255d3SCy Schubert } 613c1d255d3SCy Schubert } 614c1d255d3SCy Schubert 615c1d255d3SCy Schubert if (type == DPP_PA_PRESENCE_ANNOUNCEMENT || 616c1d255d3SCy Schubert type == DPP_PA_RECONFIG_ANNOUNCEMENT) { 617c1d255d3SCy Schubert /* TODO: Could send this to all configured Controllers. For now, 618c1d255d3SCy Schubert * only the first Controller is supported. */ 619c1d255d3SCy Schubert ctrl = dpp_relay_controller_get_ctx(dpp, cb_ctx); 620*a90b9d01SCy Schubert } else if (type == DPP_PA_PKEX_EXCHANGE_REQ) { 621*a90b9d01SCy Schubert ctrl = dpp_relay_controller_get_ctx(dpp, cb_ctx); 622c1d255d3SCy Schubert } else { 623c1d255d3SCy Schubert if (!r_bootstrap) 624c1d255d3SCy Schubert return -1; 625c1d255d3SCy Schubert ctrl = dpp_relay_controller_get(dpp, r_bootstrap); 626c1d255d3SCy Schubert } 627c1d255d3SCy Schubert if (!ctrl) 628c1d255d3SCy Schubert return -1; 629c1d255d3SCy Schubert 630*a90b9d01SCy Schubert if (type == DPP_PA_PRESENCE_ANNOUNCEMENT || 631*a90b9d01SCy Schubert type == DPP_PA_RECONFIG_ANNOUNCEMENT) { 632*a90b9d01SCy Schubert conn = dpp_relay_match_ctrl(ctrl, src, freq, type); 633*a90b9d01SCy Schubert if (conn && 634*a90b9d01SCy Schubert (!conn->auth || conn->auth->waiting_auth_resp)) { 635*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 636*a90b9d01SCy Schubert "DPP: Use existing TCP connection to Controller since no Auth Resp seen on it yet"); 637*a90b9d01SCy Schubert return dpp_relay_tx(conn, hdr, buf, len); 638*a90b9d01SCy Schubert } 639*a90b9d01SCy Schubert } 640*a90b9d01SCy Schubert 641c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 642c1d255d3SCy Schubert "DPP: Authentication Request for a configured Controller"); 643c1d255d3SCy Schubert conn = dpp_relay_new_conn(ctrl, src, freq); 644c1d255d3SCy Schubert if (!conn) 645c1d255d3SCy Schubert return -1; 646c1d255d3SCy Schubert 647c1d255d3SCy Schubert conn->msg_out = dpp_tcp_encaps(hdr, buf, len); 648c1d255d3SCy Schubert if (!conn->msg_out) { 649c1d255d3SCy Schubert dpp_connection_remove(conn); 650c1d255d3SCy Schubert return -1; 651c1d255d3SCy Schubert } 652c1d255d3SCy Schubert /* Message will be sent in dpp_conn_tx_ready() */ 653c1d255d3SCy Schubert 654c1d255d3SCy Schubert return 0; 655c1d255d3SCy Schubert } 656c1d255d3SCy Schubert 657c1d255d3SCy Schubert 658*a90b9d01SCy Schubert static struct dpp_connection * 659*a90b9d01SCy Schubert dpp_relay_find_conn(struct dpp_relay_controller *ctrl, const u8 *src) 660*a90b9d01SCy Schubert { 661*a90b9d01SCy Schubert struct dpp_connection *conn; 662*a90b9d01SCy Schubert 663*a90b9d01SCy Schubert dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) { 664*a90b9d01SCy Schubert if (ether_addr_equal(src, conn->mac_addr)) 665*a90b9d01SCy Schubert return conn; 666*a90b9d01SCy Schubert } 667*a90b9d01SCy Schubert 668*a90b9d01SCy Schubert return NULL; 669*a90b9d01SCy Schubert } 670*a90b9d01SCy Schubert 671*a90b9d01SCy Schubert 672c1d255d3SCy Schubert int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data, 673c1d255d3SCy Schubert size_t data_len) 674c1d255d3SCy Schubert { 675c1d255d3SCy Schubert struct dpp_relay_controller *ctrl; 676*a90b9d01SCy Schubert struct dpp_connection *conn = NULL; 677c1d255d3SCy Schubert struct wpabuf *msg; 678c1d255d3SCy Schubert 679c1d255d3SCy Schubert /* Check if there is a successfully completed authentication for this 680c1d255d3SCy Schubert * and if so, continue that session (send this over TCP) and return 0. 681c1d255d3SCy Schubert */ 682c1d255d3SCy Schubert dl_list_for_each(ctrl, &dpp->controllers, 683c1d255d3SCy Schubert struct dpp_relay_controller, list) { 684*a90b9d01SCy Schubert conn = dpp_relay_find_conn(ctrl, src); 685*a90b9d01SCy Schubert if (conn) 686c1d255d3SCy Schubert break; 687c1d255d3SCy Schubert } 688c1d255d3SCy Schubert 689*a90b9d01SCy Schubert if (!conn && dpp->tmp_controller) 690*a90b9d01SCy Schubert conn = dpp_relay_find_conn(dpp->tmp_controller, src); 691*a90b9d01SCy Schubert 692*a90b9d01SCy Schubert if (!conn) 693c1d255d3SCy Schubert return -1; 694c1d255d3SCy Schubert 695c1d255d3SCy Schubert msg = wpabuf_alloc(4 + 1 + data_len); 696c1d255d3SCy Schubert if (!msg) 697c1d255d3SCy Schubert return -1; 698c1d255d3SCy Schubert wpabuf_put_be32(msg, 1 + data_len); 699c1d255d3SCy Schubert wpabuf_put_u8(msg, WLAN_PA_GAS_INITIAL_REQ); 700c1d255d3SCy Schubert wpabuf_put_data(msg, data, data_len); 701c1d255d3SCy Schubert wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg); 702c1d255d3SCy Schubert 703c1d255d3SCy Schubert wpabuf_free(conn->msg_out); 704c1d255d3SCy Schubert conn->msg_out_pos = 0; 705c1d255d3SCy Schubert conn->msg_out = msg; 706c1d255d3SCy Schubert dpp_tcp_send(conn); 707c1d255d3SCy Schubert return 0; 708c1d255d3SCy Schubert } 709c1d255d3SCy Schubert 710c1d255d3SCy Schubert 711*a90b9d01SCy Schubert bool dpp_relay_controller_available(struct dpp_global *dpp) 712*a90b9d01SCy Schubert { 713*a90b9d01SCy Schubert return dpp && dl_list_len(&dpp->controllers) > 0; 714*a90b9d01SCy Schubert } 715*a90b9d01SCy Schubert 716*a90b9d01SCy Schubert 717c1d255d3SCy Schubert static void dpp_controller_free(struct dpp_controller *ctrl) 718c1d255d3SCy Schubert { 719c1d255d3SCy Schubert struct dpp_connection *conn, *tmp; 720c1d255d3SCy Schubert 721c1d255d3SCy Schubert if (!ctrl) 722c1d255d3SCy Schubert return; 723c1d255d3SCy Schubert 724c1d255d3SCy Schubert dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection, 725c1d255d3SCy Schubert list) 726c1d255d3SCy Schubert dpp_connection_remove(conn); 727c1d255d3SCy Schubert 728c1d255d3SCy Schubert if (ctrl->sock >= 0) { 729c1d255d3SCy Schubert close(ctrl->sock); 730c1d255d3SCy Schubert eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ); 731c1d255d3SCy Schubert } 732c1d255d3SCy Schubert os_free(ctrl->configurator_params); 733*a90b9d01SCy Schubert os_free(ctrl->pkex_code); 734*a90b9d01SCy Schubert os_free(ctrl->pkex_identifier); 735c1d255d3SCy Schubert os_free(ctrl); 736c1d255d3SCy Schubert } 737c1d255d3SCy Schubert 738c1d255d3SCy Schubert 739c1d255d3SCy Schubert static int dpp_controller_rx_auth_req(struct dpp_connection *conn, 740c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, size_t len) 741c1d255d3SCy Schubert { 742c1d255d3SCy Schubert const u8 *r_bootstrap, *i_bootstrap; 743c1d255d3SCy Schubert u16 r_bootstrap_len, i_bootstrap_len; 744c1d255d3SCy Schubert struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL; 745c1d255d3SCy Schubert 746c1d255d3SCy Schubert if (!conn->ctrl) 747c1d255d3SCy Schubert return 0; 748c1d255d3SCy Schubert 749c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication Request"); 750c1d255d3SCy Schubert 751c1d255d3SCy Schubert r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, 752c1d255d3SCy Schubert &r_bootstrap_len); 753c1d255d3SCy Schubert if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { 754c1d255d3SCy Schubert wpa_printf(MSG_INFO, 755c1d255d3SCy Schubert "Missing or invalid required Responder Bootstrapping Key Hash attribute"); 756c1d255d3SCy Schubert return -1; 757c1d255d3SCy Schubert } 758c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", 759c1d255d3SCy Schubert r_bootstrap, r_bootstrap_len); 760c1d255d3SCy Schubert 761c1d255d3SCy Schubert i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH, 762c1d255d3SCy Schubert &i_bootstrap_len); 763c1d255d3SCy Schubert if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) { 764c1d255d3SCy Schubert wpa_printf(MSG_INFO, 765c1d255d3SCy Schubert "Missing or invalid required Initiator Bootstrapping Key Hash attribute"); 766c1d255d3SCy Schubert return -1; 767c1d255d3SCy Schubert } 768c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash", 769c1d255d3SCy Schubert i_bootstrap, i_bootstrap_len); 770c1d255d3SCy Schubert 771c1d255d3SCy Schubert /* Try to find own and peer bootstrapping key matches based on the 772c1d255d3SCy Schubert * received hash values */ 773c1d255d3SCy Schubert dpp_bootstrap_find_pair(conn->ctrl->global, i_bootstrap, r_bootstrap, 774c1d255d3SCy Schubert &own_bi, &peer_bi); 775c1d255d3SCy Schubert if (!own_bi) { 776c1d255d3SCy Schubert wpa_printf(MSG_INFO, 777c1d255d3SCy Schubert "No matching own bootstrapping key found - ignore message"); 778c1d255d3SCy Schubert return -1; 779c1d255d3SCy Schubert } 780c1d255d3SCy Schubert 781c1d255d3SCy Schubert if (conn->auth) { 782c1d255d3SCy Schubert wpa_printf(MSG_INFO, 783c1d255d3SCy Schubert "Already in DPP authentication exchange - ignore new one"); 784c1d255d3SCy Schubert return 0; 785c1d255d3SCy Schubert } 786c1d255d3SCy Schubert 787c1d255d3SCy Schubert conn->auth = dpp_auth_req_rx(conn->ctrl->global, conn->msg_ctx, 788c1d255d3SCy Schubert conn->ctrl->allowed_roles, 789c1d255d3SCy Schubert conn->ctrl->qr_mutual, 790c1d255d3SCy Schubert peer_bi, own_bi, -1, hdr, buf, len); 791c1d255d3SCy Schubert if (!conn->auth) { 792c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No response generated"); 793c1d255d3SCy Schubert return -1; 794c1d255d3SCy Schubert } 795c1d255d3SCy Schubert 796c1d255d3SCy Schubert if (dpp_set_configurator(conn->auth, 7974b72b91aSCy Schubert conn->ctrl->configurator_params) < 0) 798c1d255d3SCy Schubert return -1; 799c1d255d3SCy Schubert 800c1d255d3SCy Schubert return dpp_tcp_send_msg(conn, conn->auth->resp_msg); 801c1d255d3SCy Schubert } 802c1d255d3SCy Schubert 803c1d255d3SCy Schubert 804c1d255d3SCy Schubert static int dpp_controller_rx_auth_resp(struct dpp_connection *conn, 805c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, size_t len) 806c1d255d3SCy Schubert { 807c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 808c1d255d3SCy Schubert struct wpabuf *msg; 809c1d255d3SCy Schubert int res; 810c1d255d3SCy Schubert 811c1d255d3SCy Schubert if (!auth) 812c1d255d3SCy Schubert return -1; 813c1d255d3SCy Schubert 814c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication Response"); 815c1d255d3SCy Schubert 816c1d255d3SCy Schubert msg = dpp_auth_resp_rx(auth, hdr, buf, len); 817c1d255d3SCy Schubert if (!msg) { 818c1d255d3SCy Schubert if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) { 819c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 820c1d255d3SCy Schubert "DPP: Start wait for full response"); 821c1d255d3SCy Schubert return 0; 822c1d255d3SCy Schubert } 823c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No confirm generated"); 824c1d255d3SCy Schubert return -1; 825c1d255d3SCy Schubert } 826c1d255d3SCy Schubert 827c1d255d3SCy Schubert conn->on_tcp_tx_complete_auth_ok = 1; 828c1d255d3SCy Schubert res = dpp_tcp_send_msg(conn, msg); 829c1d255d3SCy Schubert wpabuf_free(msg); 830c1d255d3SCy Schubert return res; 831c1d255d3SCy Schubert } 832c1d255d3SCy Schubert 833c1d255d3SCy Schubert 834c1d255d3SCy Schubert static int dpp_controller_rx_auth_conf(struct dpp_connection *conn, 835c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, size_t len) 836c1d255d3SCy Schubert { 837c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 838c1d255d3SCy Schubert 839c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation"); 840c1d255d3SCy Schubert 841c1d255d3SCy Schubert if (!auth) { 842c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 843c1d255d3SCy Schubert "DPP: No DPP Authentication in progress - drop"); 844c1d255d3SCy Schubert return -1; 845c1d255d3SCy Schubert } 846c1d255d3SCy Schubert 847c1d255d3SCy Schubert if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) { 848c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication failed"); 849c1d255d3SCy Schubert return -1; 850c1d255d3SCy Schubert } 851c1d255d3SCy Schubert 852c1d255d3SCy Schubert dpp_controller_auth_success(conn, 0); 853c1d255d3SCy Schubert return 0; 854c1d255d3SCy Schubert } 855c1d255d3SCy Schubert 856c1d255d3SCy Schubert 857c1d255d3SCy Schubert void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx, 858c1d255d3SCy Schubert void *timeout_ctx) 859c1d255d3SCy Schubert { 860c1d255d3SCy Schubert struct dpp_connection *conn = eloop_ctx; 861c1d255d3SCy Schubert 862c1d255d3SCy Schubert if (!conn->auth->waiting_conf_result) 863c1d255d3SCy Schubert return; 864c1d255d3SCy Schubert 865c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 866c1d255d3SCy Schubert "DPP: Timeout while waiting for Connection Status Result"); 867c1d255d3SCy Schubert wpa_msg(conn->msg_ctx, MSG_INFO, 868c1d255d3SCy Schubert DPP_EVENT_CONN_STATUS_RESULT "timeout"); 869c1d255d3SCy Schubert dpp_connection_remove(conn); 870c1d255d3SCy Schubert } 871c1d255d3SCy Schubert 872c1d255d3SCy Schubert 873c1d255d3SCy Schubert static int dpp_controller_rx_conf_result(struct dpp_connection *conn, 874c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, 875c1d255d3SCy Schubert size_t len) 876c1d255d3SCy Schubert { 877c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 878c1d255d3SCy Schubert enum dpp_status_error status; 879c1d255d3SCy Schubert void *msg_ctx = conn->msg_ctx; 880c1d255d3SCy Schubert 881c1d255d3SCy Schubert if (!conn->ctrl && (!auth || !auth->configurator)) 882c1d255d3SCy Schubert return 0; 883c1d255d3SCy Schubert 884c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Configuration Result"); 885c1d255d3SCy Schubert 886c1d255d3SCy Schubert if (!auth || !auth->waiting_conf_result) { 887c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 888c1d255d3SCy Schubert "DPP: No DPP Configuration waiting for result - drop"); 889c1d255d3SCy Schubert return -1; 890c1d255d3SCy Schubert } 891c1d255d3SCy Schubert 892c1d255d3SCy Schubert status = dpp_conf_result_rx(auth, hdr, buf, len); 893c1d255d3SCy Schubert if (status == DPP_STATUS_OK && auth->send_conn_status) { 894*a90b9d01SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT 895*a90b9d01SCy Schubert "wait_conn_status=1 conf_resp_status=%d", 896*a90b9d01SCy Schubert auth->conf_resp_status); 897c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result"); 898*a90b9d01SCy Schubert auth->waiting_conn_status_result = 1; 899c1d255d3SCy Schubert eloop_cancel_timeout( 900c1d255d3SCy Schubert dpp_controller_conn_status_result_wait_timeout, 901c1d255d3SCy Schubert conn, NULL); 902c1d255d3SCy Schubert eloop_register_timeout( 903c1d255d3SCy Schubert 16, 0, dpp_controller_conn_status_result_wait_timeout, 904c1d255d3SCy Schubert conn, NULL); 905c1d255d3SCy Schubert return 0; 906c1d255d3SCy Schubert } 907c1d255d3SCy Schubert if (status == DPP_STATUS_OK) 908*a90b9d01SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT 909*a90b9d01SCy Schubert "conf_resp_status=%d", auth->conf_resp_status); 910c1d255d3SCy Schubert else 911c1d255d3SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); 912c1d255d3SCy Schubert return -1; /* to remove the completed connection */ 913c1d255d3SCy Schubert } 914c1d255d3SCy Schubert 915c1d255d3SCy Schubert 916c1d255d3SCy Schubert static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn, 917c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, 918c1d255d3SCy Schubert size_t len) 919c1d255d3SCy Schubert { 920c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 921c1d255d3SCy Schubert enum dpp_status_error status; 922c1d255d3SCy Schubert u8 ssid[SSID_MAX_LEN]; 923c1d255d3SCy Schubert size_t ssid_len = 0; 924c1d255d3SCy Schubert char *channel_list = NULL; 925c1d255d3SCy Schubert 926c1d255d3SCy Schubert if (!conn->ctrl) 927c1d255d3SCy Schubert return 0; 928c1d255d3SCy Schubert 929c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Connection Status Result"); 930c1d255d3SCy Schubert 931c1d255d3SCy Schubert if (!auth || !auth->waiting_conn_status_result) { 932c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 933c1d255d3SCy Schubert "DPP: No DPP Configuration waiting for connection status result - drop"); 934c1d255d3SCy Schubert return -1; 935c1d255d3SCy Schubert } 936c1d255d3SCy Schubert 937c1d255d3SCy Schubert status = dpp_conn_status_result_rx(auth, hdr, buf, len, 938c1d255d3SCy Schubert ssid, &ssid_len, &channel_list); 939c1d255d3SCy Schubert wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT 940c1d255d3SCy Schubert "result=%d ssid=%s channel_list=%s", 941c1d255d3SCy Schubert status, wpa_ssid_txt(ssid, ssid_len), 942c1d255d3SCy Schubert channel_list ? channel_list : "N/A"); 943c1d255d3SCy Schubert os_free(channel_list); 944c1d255d3SCy Schubert return -1; /* to remove the completed connection */ 945c1d255d3SCy Schubert } 946c1d255d3SCy Schubert 947c1d255d3SCy Schubert 948c1d255d3SCy Schubert static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn, 949c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, 950c1d255d3SCy Schubert size_t len) 951c1d255d3SCy Schubert { 952c1d255d3SCy Schubert const u8 *r_bootstrap; 953c1d255d3SCy Schubert u16 r_bootstrap_len; 954c1d255d3SCy Schubert struct dpp_bootstrap_info *peer_bi; 955c1d255d3SCy Schubert struct dpp_authentication *auth; 956c1d255d3SCy Schubert struct dpp_global *dpp = conn->ctrl->global; 957c1d255d3SCy Schubert 958c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Presence Announcement"); 959c1d255d3SCy Schubert 960c1d255d3SCy Schubert r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, 961c1d255d3SCy Schubert &r_bootstrap_len); 962c1d255d3SCy Schubert if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { 963c1d255d3SCy Schubert wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_FAIL 964c1d255d3SCy Schubert "Missing or invalid required Responder Bootstrapping Key Hash attribute"); 965c1d255d3SCy Schubert return -1; 966c1d255d3SCy Schubert } 967c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", 968c1d255d3SCy Schubert r_bootstrap, r_bootstrap_len); 969c1d255d3SCy Schubert peer_bi = dpp_bootstrap_find_chirp(dpp, r_bootstrap); 970c1d255d3SCy Schubert if (!peer_bi) { 971c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 972c1d255d3SCy Schubert "DPP: No matching bootstrapping information found"); 973c1d255d3SCy Schubert return -1; 974c1d255d3SCy Schubert } 975c1d255d3SCy Schubert 976*a90b9d01SCy Schubert if (conn->auth) { 977*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 978*a90b9d01SCy Schubert "DPP: Ignore Presence Announcement during ongoing Authentication"); 979*a90b9d01SCy Schubert return 0; 980*a90b9d01SCy Schubert } 981*a90b9d01SCy Schubert 982c1d255d3SCy Schubert auth = dpp_auth_init(dpp, conn->msg_ctx, peer_bi, NULL, 983c1d255d3SCy Schubert DPP_CAPAB_CONFIGURATOR, -1, NULL, 0); 984c1d255d3SCy Schubert if (!auth) 985c1d255d3SCy Schubert return -1; 986c1d255d3SCy Schubert if (dpp_set_configurator(auth, conn->ctrl->configurator_params) < 0) { 987c1d255d3SCy Schubert dpp_auth_deinit(auth); 988c1d255d3SCy Schubert return -1; 989c1d255d3SCy Schubert } 990c1d255d3SCy Schubert 991c1d255d3SCy Schubert conn->auth = auth; 992c1d255d3SCy Schubert return dpp_tcp_send_msg(conn, conn->auth->req_msg); 993c1d255d3SCy Schubert } 994c1d255d3SCy Schubert 995c1d255d3SCy Schubert 996c1d255d3SCy Schubert static int dpp_controller_rx_reconfig_announcement(struct dpp_connection *conn, 997c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, 998c1d255d3SCy Schubert size_t len) 999c1d255d3SCy Schubert { 1000c1d255d3SCy Schubert const u8 *csign_hash, *fcgroup, *a_nonce, *e_id; 1001c1d255d3SCy Schubert u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len; 1002c1d255d3SCy Schubert struct dpp_configurator *conf; 1003c1d255d3SCy Schubert struct dpp_global *dpp = conn->ctrl->global; 1004c1d255d3SCy Schubert struct dpp_authentication *auth; 1005c1d255d3SCy Schubert u16 group; 1006c1d255d3SCy Schubert 1007c1d255d3SCy Schubert if (conn->auth) { 1008c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1009c1d255d3SCy Schubert "DPP: Ignore Reconfig Announcement during ongoing Authentication"); 1010c1d255d3SCy Schubert return -1; 1011c1d255d3SCy Schubert } 1012c1d255d3SCy Schubert 1013c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Reconfig Announcement"); 1014c1d255d3SCy Schubert 1015c1d255d3SCy Schubert csign_hash = dpp_get_attr(buf, len, DPP_ATTR_C_SIGN_KEY_HASH, 1016c1d255d3SCy Schubert &csign_hash_len); 1017c1d255d3SCy Schubert if (!csign_hash || csign_hash_len != SHA256_MAC_LEN) { 1018c1d255d3SCy Schubert wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_FAIL 1019c1d255d3SCy Schubert "Missing or invalid required Configurator C-sign key Hash attribute"); 1020c1d255d3SCy Schubert return -1; 1021c1d255d3SCy Schubert } 1022c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator C-sign key Hash (kid)", 1023c1d255d3SCy Schubert csign_hash, csign_hash_len); 1024c1d255d3SCy Schubert conf = dpp_configurator_find_kid(dpp, csign_hash); 1025c1d255d3SCy Schubert if (!conf) { 1026c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1027c1d255d3SCy Schubert "DPP: No matching Configurator information found"); 1028c1d255d3SCy Schubert return -1; 1029c1d255d3SCy Schubert } 1030c1d255d3SCy Schubert 1031c1d255d3SCy Schubert fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP, 1032c1d255d3SCy Schubert &fcgroup_len); 1033c1d255d3SCy Schubert if (!fcgroup || fcgroup_len != 2) { 1034c1d255d3SCy Schubert wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_FAIL 1035c1d255d3SCy Schubert "Missing or invalid required Finite Cyclic Group attribute"); 1036c1d255d3SCy Schubert return -1; 1037c1d255d3SCy Schubert } 1038c1d255d3SCy Schubert group = WPA_GET_LE16(fcgroup); 1039c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group); 1040c1d255d3SCy Schubert 1041c1d255d3SCy Schubert a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len); 1042c1d255d3SCy Schubert e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len); 1043c1d255d3SCy Schubert 1044c1d255d3SCy Schubert auth = dpp_reconfig_init(dpp, conn->msg_ctx, conf, 0, group, 1045c1d255d3SCy Schubert a_nonce, a_nonce_len, e_id, e_id_len); 1046c1d255d3SCy Schubert if (!auth) 1047c1d255d3SCy Schubert return -1; 1048c1d255d3SCy Schubert if (dpp_set_configurator(auth, conn->ctrl->configurator_params) < 0) { 1049c1d255d3SCy Schubert dpp_auth_deinit(auth); 1050c1d255d3SCy Schubert return -1; 1051c1d255d3SCy Schubert } 1052c1d255d3SCy Schubert 1053c1d255d3SCy Schubert conn->auth = auth; 1054c1d255d3SCy Schubert return dpp_tcp_send_msg(conn, auth->reconfig_req_msg); 1055c1d255d3SCy Schubert } 1056c1d255d3SCy Schubert 1057c1d255d3SCy Schubert 1058c1d255d3SCy Schubert static int dpp_controller_rx_reconfig_auth_resp(struct dpp_connection *conn, 1059c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, 1060c1d255d3SCy Schubert size_t len) 1061c1d255d3SCy Schubert { 1062c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 1063c1d255d3SCy Schubert struct wpabuf *conf; 1064c1d255d3SCy Schubert int res; 1065c1d255d3SCy Schubert 1066c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Response"); 1067c1d255d3SCy Schubert 1068c1d255d3SCy Schubert if (!auth || !auth->reconfig || !auth->configurator) { 1069c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1070c1d255d3SCy Schubert "DPP: No DPP Reconfig Authentication in progress - drop"); 1071c1d255d3SCy Schubert return -1; 1072c1d255d3SCy Schubert } 1073c1d255d3SCy Schubert 1074c1d255d3SCy Schubert conf = dpp_reconfig_auth_resp_rx(auth, hdr, buf, len); 1075c1d255d3SCy Schubert if (!conf) 1076c1d255d3SCy Schubert return -1; 1077c1d255d3SCy Schubert 1078c1d255d3SCy Schubert res = dpp_tcp_send_msg(conn, conf); 1079c1d255d3SCy Schubert wpabuf_free(conf); 1080c1d255d3SCy Schubert return res; 1081c1d255d3SCy Schubert } 1082c1d255d3SCy Schubert 1083c1d255d3SCy Schubert 1084*a90b9d01SCy Schubert static int dpp_controller_rx_pkex_exchange_req(struct dpp_connection *conn, 1085*a90b9d01SCy Schubert const u8 *hdr, const u8 *buf, 1086*a90b9d01SCy Schubert size_t len) 1087*a90b9d01SCy Schubert { 1088*a90b9d01SCy Schubert struct dpp_controller *ctrl = conn->ctrl; 1089*a90b9d01SCy Schubert 1090*a90b9d01SCy Schubert if (!ctrl) 1091*a90b9d01SCy Schubert return 0; 1092*a90b9d01SCy Schubert 1093*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request"); 1094*a90b9d01SCy Schubert 1095*a90b9d01SCy Schubert /* TODO: Support multiple PKEX codes by iterating over all the enabled 1096*a90b9d01SCy Schubert * values here */ 1097*a90b9d01SCy Schubert 1098*a90b9d01SCy Schubert if (!ctrl->pkex_code || !ctrl->pkex_bi) { 1099*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 1100*a90b9d01SCy Schubert "DPP: No PKEX code configured - ignore request"); 1101*a90b9d01SCy Schubert return 0; 1102*a90b9d01SCy Schubert } 1103*a90b9d01SCy Schubert 1104*a90b9d01SCy Schubert if (conn->pkex || conn->auth) { 1105*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 1106*a90b9d01SCy Schubert "DPP: Already in PKEX/Authentication session - ignore new PKEX request"); 1107*a90b9d01SCy Schubert return 0; 1108*a90b9d01SCy Schubert } 1109*a90b9d01SCy Schubert 1110*a90b9d01SCy Schubert conn->pkex = dpp_pkex_rx_exchange_req(conn->msg_ctx, ctrl->pkex_bi, 1111*a90b9d01SCy Schubert NULL, NULL, 1112*a90b9d01SCy Schubert ctrl->pkex_identifier, 1113*a90b9d01SCy Schubert ctrl->pkex_code, 1114*a90b9d01SCy Schubert os_strlen(ctrl->pkex_code), 1115*a90b9d01SCy Schubert buf, len, true); 1116*a90b9d01SCy Schubert if (!conn->pkex) { 1117*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 1118*a90b9d01SCy Schubert "DPP: Failed to process the request"); 1119*a90b9d01SCy Schubert return -1; 1120*a90b9d01SCy Schubert } 1121*a90b9d01SCy Schubert 1122*a90b9d01SCy Schubert return dpp_tcp_send_msg(conn, conn->pkex->exchange_resp); 1123*a90b9d01SCy Schubert } 1124*a90b9d01SCy Schubert 1125*a90b9d01SCy Schubert 1126*a90b9d01SCy Schubert static int dpp_controller_rx_pkex_exchange_resp(struct dpp_connection *conn, 1127*a90b9d01SCy Schubert const u8 *hdr, const u8 *buf, 1128*a90b9d01SCy Schubert size_t len) 1129*a90b9d01SCy Schubert { 1130*a90b9d01SCy Schubert struct dpp_pkex *pkex = conn->pkex; 1131*a90b9d01SCy Schubert struct wpabuf *msg; 1132*a90b9d01SCy Schubert int res; 1133*a90b9d01SCy Schubert 1134*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response"); 1135*a90b9d01SCy Schubert 1136*a90b9d01SCy Schubert if (!pkex || !pkex->initiator || pkex->exchange_done) { 1137*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); 1138*a90b9d01SCy Schubert return 0; 1139*a90b9d01SCy Schubert } 1140*a90b9d01SCy Schubert 1141*a90b9d01SCy Schubert msg = dpp_pkex_rx_exchange_resp(pkex, NULL, buf, len); 1142*a90b9d01SCy Schubert if (!msg) { 1143*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); 1144*a90b9d01SCy Schubert return -1; 1145*a90b9d01SCy Schubert } 1146*a90b9d01SCy Schubert 1147*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request"); 1148*a90b9d01SCy Schubert res = dpp_tcp_send_msg(conn, msg); 1149*a90b9d01SCy Schubert wpabuf_free(msg); 1150*a90b9d01SCy Schubert return res; 1151*a90b9d01SCy Schubert } 1152*a90b9d01SCy Schubert 1153*a90b9d01SCy Schubert 1154*a90b9d01SCy Schubert static int dpp_controller_rx_pkex_commit_reveal_req(struct dpp_connection *conn, 1155*a90b9d01SCy Schubert const u8 *hdr, 1156*a90b9d01SCy Schubert const u8 *buf, size_t len) 1157*a90b9d01SCy Schubert { 1158*a90b9d01SCy Schubert struct dpp_pkex *pkex = conn->pkex; 1159*a90b9d01SCy Schubert struct wpabuf *msg; 1160*a90b9d01SCy Schubert int res; 1161*a90b9d01SCy Schubert struct dpp_bootstrap_info *bi; 1162*a90b9d01SCy Schubert 1163*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request"); 1164*a90b9d01SCy Schubert 1165*a90b9d01SCy Schubert if (!pkex || pkex->initiator || !pkex->exchange_done) { 1166*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); 1167*a90b9d01SCy Schubert return 0; 1168*a90b9d01SCy Schubert } 1169*a90b9d01SCy Schubert 1170*a90b9d01SCy Schubert msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len); 1171*a90b9d01SCy Schubert if (!msg) { 1172*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to process the request"); 1173*a90b9d01SCy Schubert return -1; 1174*a90b9d01SCy Schubert } 1175*a90b9d01SCy Schubert 1176*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response"); 1177*a90b9d01SCy Schubert res = dpp_tcp_send_msg(conn, msg); 1178*a90b9d01SCy Schubert wpabuf_free(msg); 1179*a90b9d01SCy Schubert if (res < 0) 1180*a90b9d01SCy Schubert return res; 1181*a90b9d01SCy Schubert bi = dpp_pkex_finish(conn->global, pkex, NULL, 0); 1182*a90b9d01SCy Schubert if (!bi) 1183*a90b9d01SCy Schubert return -1; 1184*a90b9d01SCy Schubert conn->pkex = NULL; 1185*a90b9d01SCy Schubert return 0; 1186*a90b9d01SCy Schubert } 1187*a90b9d01SCy Schubert 1188*a90b9d01SCy Schubert 1189*a90b9d01SCy Schubert static int 1190*a90b9d01SCy Schubert dpp_controller_rx_pkex_commit_reveal_resp(struct dpp_connection *conn, 1191*a90b9d01SCy Schubert const u8 *hdr, 1192*a90b9d01SCy Schubert const u8 *buf, size_t len) 1193*a90b9d01SCy Schubert { 1194*a90b9d01SCy Schubert struct dpp_pkex *pkex = conn->pkex; 1195*a90b9d01SCy Schubert int res; 1196*a90b9d01SCy Schubert struct dpp_bootstrap_info *bi; 1197*a90b9d01SCy Schubert 1198*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response"); 1199*a90b9d01SCy Schubert 1200*a90b9d01SCy Schubert if (!pkex || !pkex->initiator || !pkex->exchange_done) { 1201*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); 1202*a90b9d01SCy Schubert return 0; 1203*a90b9d01SCy Schubert } 1204*a90b9d01SCy Schubert 1205*a90b9d01SCy Schubert res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len); 1206*a90b9d01SCy Schubert if (res < 0) { 1207*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); 1208*a90b9d01SCy Schubert return res; 1209*a90b9d01SCy Schubert } 1210*a90b9d01SCy Schubert 1211*a90b9d01SCy Schubert bi = dpp_pkex_finish(conn->global, pkex, NULL, 0); 1212*a90b9d01SCy Schubert if (!bi) 1213*a90b9d01SCy Schubert return -1; 1214*a90b9d01SCy Schubert conn->pkex = NULL; 1215*a90b9d01SCy Schubert 1216*a90b9d01SCy Schubert if (!conn->pkex_done) 1217*a90b9d01SCy Schubert return -1; 1218*a90b9d01SCy Schubert return conn->pkex_done(conn->cb_ctx, conn, bi); 1219*a90b9d01SCy Schubert } 1220*a90b9d01SCy Schubert 1221*a90b9d01SCy Schubert 1222c1d255d3SCy Schubert static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg, 1223c1d255d3SCy Schubert size_t len) 1224c1d255d3SCy Schubert { 1225c1d255d3SCy Schubert const u8 *pos, *end; 1226c1d255d3SCy Schubert u8 type; 1227c1d255d3SCy Schubert 1228c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Received DPP Action frame over TCP"); 1229c1d255d3SCy Schubert pos = msg; 1230c1d255d3SCy Schubert end = msg + len; 1231c1d255d3SCy Schubert 1232c1d255d3SCy Schubert if (end - pos < DPP_HDR_LEN || 1233c1d255d3SCy Schubert WPA_GET_BE24(pos) != OUI_WFA || 1234c1d255d3SCy Schubert pos[3] != DPP_OUI_TYPE) { 1235c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Unrecognized header"); 1236c1d255d3SCy Schubert return -1; 1237c1d255d3SCy Schubert } 1238c1d255d3SCy Schubert 1239c1d255d3SCy Schubert if (pos[4] != 1) { 1240c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Unsupported Crypto Suite %u", 1241c1d255d3SCy Schubert pos[4]); 1242c1d255d3SCy Schubert return -1; 1243c1d255d3SCy Schubert } 1244c1d255d3SCy Schubert type = pos[5]; 1245c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Received message type %u", type); 1246c1d255d3SCy Schubert pos += DPP_HDR_LEN; 1247c1d255d3SCy Schubert 1248c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", 1249c1d255d3SCy Schubert pos, end - pos); 1250c1d255d3SCy Schubert if (dpp_check_attrs(pos, end - pos) < 0) 1251c1d255d3SCy Schubert return -1; 1252c1d255d3SCy Schubert 1253c1d255d3SCy Schubert if (conn->relay) { 1254c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN"); 1255c1d255d3SCy Schubert conn->relay->tx(conn->relay->cb_ctx, conn->mac_addr, 1256c1d255d3SCy Schubert conn->freq, msg, len); 1257c1d255d3SCy Schubert return 0; 1258c1d255d3SCy Schubert } 1259c1d255d3SCy Schubert 1260c1d255d3SCy Schubert switch (type) { 1261c1d255d3SCy Schubert case DPP_PA_AUTHENTICATION_REQ: 1262c1d255d3SCy Schubert return dpp_controller_rx_auth_req(conn, msg, pos, end - pos); 1263c1d255d3SCy Schubert case DPP_PA_AUTHENTICATION_RESP: 1264c1d255d3SCy Schubert return dpp_controller_rx_auth_resp(conn, msg, pos, end - pos); 1265c1d255d3SCy Schubert case DPP_PA_AUTHENTICATION_CONF: 1266c1d255d3SCy Schubert return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos); 1267c1d255d3SCy Schubert case DPP_PA_CONFIGURATION_RESULT: 1268c1d255d3SCy Schubert return dpp_controller_rx_conf_result(conn, msg, pos, end - pos); 1269c1d255d3SCy Schubert case DPP_PA_CONNECTION_STATUS_RESULT: 1270c1d255d3SCy Schubert return dpp_controller_rx_conn_status_result(conn, msg, pos, 1271c1d255d3SCy Schubert end - pos); 1272c1d255d3SCy Schubert case DPP_PA_PRESENCE_ANNOUNCEMENT: 1273c1d255d3SCy Schubert return dpp_controller_rx_presence_announcement(conn, msg, pos, 1274c1d255d3SCy Schubert end - pos); 1275c1d255d3SCy Schubert case DPP_PA_RECONFIG_ANNOUNCEMENT: 1276c1d255d3SCy Schubert return dpp_controller_rx_reconfig_announcement(conn, msg, pos, 1277c1d255d3SCy Schubert end - pos); 1278c1d255d3SCy Schubert case DPP_PA_RECONFIG_AUTH_RESP: 1279c1d255d3SCy Schubert return dpp_controller_rx_reconfig_auth_resp(conn, msg, pos, 1280c1d255d3SCy Schubert end - pos); 1281*a90b9d01SCy Schubert case DPP_PA_PKEX_V1_EXCHANGE_REQ: 1282*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 1283*a90b9d01SCy Schubert "DPP: Ignore PKEXv1 Exchange Request - not supported over TCP"); 1284*a90b9d01SCy Schubert return -1; 1285*a90b9d01SCy Schubert case DPP_PA_PKEX_EXCHANGE_REQ: 1286*a90b9d01SCy Schubert return dpp_controller_rx_pkex_exchange_req(conn, msg, pos, 1287*a90b9d01SCy Schubert end - pos); 1288*a90b9d01SCy Schubert case DPP_PA_PKEX_EXCHANGE_RESP: 1289*a90b9d01SCy Schubert return dpp_controller_rx_pkex_exchange_resp(conn, msg, pos, 1290*a90b9d01SCy Schubert end - pos); 1291*a90b9d01SCy Schubert case DPP_PA_PKEX_COMMIT_REVEAL_REQ: 1292*a90b9d01SCy Schubert return dpp_controller_rx_pkex_commit_reveal_req(conn, msg, pos, 1293*a90b9d01SCy Schubert end - pos); 1294*a90b9d01SCy Schubert case DPP_PA_PKEX_COMMIT_REVEAL_RESP: 1295*a90b9d01SCy Schubert return dpp_controller_rx_pkex_commit_reveal_resp(conn, msg, pos, 1296*a90b9d01SCy Schubert end - pos); 1297c1d255d3SCy Schubert default: 1298c1d255d3SCy Schubert /* TODO: missing messages types */ 1299c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1300c1d255d3SCy Schubert "DPP: Unsupported frame subtype %d", type); 1301c1d255d3SCy Schubert return -1; 1302c1d255d3SCy Schubert } 1303c1d255d3SCy Schubert } 1304c1d255d3SCy Schubert 1305c1d255d3SCy Schubert 1306c1d255d3SCy Schubert static int dpp_tcp_send_comeback_delay(struct dpp_connection *conn, u8 action) 1307c1d255d3SCy Schubert { 1308c1d255d3SCy Schubert struct wpabuf *buf; 1309c1d255d3SCy Schubert size_t len = 18; 1310c1d255d3SCy Schubert 1311c1d255d3SCy Schubert if (action == WLAN_PA_GAS_COMEBACK_RESP) 1312c1d255d3SCy Schubert len++; 1313c1d255d3SCy Schubert 1314c1d255d3SCy Schubert buf = wpabuf_alloc(4 + len); 1315c1d255d3SCy Schubert if (!buf) 1316c1d255d3SCy Schubert return -1; 1317c1d255d3SCy Schubert 1318c1d255d3SCy Schubert wpabuf_put_be32(buf, len); 1319c1d255d3SCy Schubert 1320c1d255d3SCy Schubert wpabuf_put_u8(buf, action); 1321c1d255d3SCy Schubert wpabuf_put_u8(buf, conn->gas_dialog_token); 1322c1d255d3SCy Schubert wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); 1323c1d255d3SCy Schubert if (action == WLAN_PA_GAS_COMEBACK_RESP) 1324c1d255d3SCy Schubert wpabuf_put_u8(buf, 0); 1325c1d255d3SCy Schubert wpabuf_put_le16(buf, 500); /* GAS Comeback Delay */ 1326c1d255d3SCy Schubert 1327c1d255d3SCy Schubert dpp_write_adv_proto(buf); 1328c1d255d3SCy Schubert wpabuf_put_le16(buf, 0); /* Query Response Length */ 1329c1d255d3SCy Schubert 1330c1d255d3SCy Schubert /* Send Config Response over TCP */ 1331c1d255d3SCy Schubert wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf); 1332c1d255d3SCy Schubert wpabuf_free(conn->msg_out); 1333c1d255d3SCy Schubert conn->msg_out_pos = 0; 1334c1d255d3SCy Schubert conn->msg_out = buf; 1335c1d255d3SCy Schubert dpp_tcp_send(conn); 1336c1d255d3SCy Schubert return 0; 1337c1d255d3SCy Schubert } 1338c1d255d3SCy Schubert 1339c1d255d3SCy Schubert 1340c1d255d3SCy Schubert static int dpp_tcp_send_gas_resp(struct dpp_connection *conn, u8 action, 1341c1d255d3SCy Schubert struct wpabuf *resp) 1342c1d255d3SCy Schubert { 1343c1d255d3SCy Schubert struct wpabuf *buf; 1344c1d255d3SCy Schubert size_t len; 1345c1d255d3SCy Schubert 1346c1d255d3SCy Schubert if (!resp) 1347c1d255d3SCy Schubert return -1; 1348c1d255d3SCy Schubert 1349c1d255d3SCy Schubert len = 18 + wpabuf_len(resp); 1350c1d255d3SCy Schubert if (action == WLAN_PA_GAS_COMEBACK_RESP) 1351c1d255d3SCy Schubert len++; 1352c1d255d3SCy Schubert 1353c1d255d3SCy Schubert buf = wpabuf_alloc(4 + len); 1354c1d255d3SCy Schubert if (!buf) { 1355c1d255d3SCy Schubert wpabuf_free(resp); 1356c1d255d3SCy Schubert return -1; 1357c1d255d3SCy Schubert } 1358c1d255d3SCy Schubert 1359c1d255d3SCy Schubert wpabuf_put_be32(buf, len); 1360c1d255d3SCy Schubert 1361c1d255d3SCy Schubert wpabuf_put_u8(buf, action); 1362c1d255d3SCy Schubert wpabuf_put_u8(buf, conn->gas_dialog_token); 1363c1d255d3SCy Schubert wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); 1364c1d255d3SCy Schubert if (action == WLAN_PA_GAS_COMEBACK_RESP) 1365c1d255d3SCy Schubert wpabuf_put_u8(buf, 0); 1366c1d255d3SCy Schubert wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */ 1367c1d255d3SCy Schubert 1368c1d255d3SCy Schubert dpp_write_adv_proto(buf); 1369c1d255d3SCy Schubert dpp_write_gas_query(buf, resp); 1370c1d255d3SCy Schubert wpabuf_free(resp); 1371c1d255d3SCy Schubert 1372c1d255d3SCy Schubert /* Send Config Response over TCP; GAS fragmentation is taken care of by 1373c1d255d3SCy Schubert * the Relay */ 1374c1d255d3SCy Schubert wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf); 1375c1d255d3SCy Schubert wpabuf_free(conn->msg_out); 1376c1d255d3SCy Schubert conn->msg_out_pos = 0; 1377c1d255d3SCy Schubert conn->msg_out = buf; 1378c1d255d3SCy Schubert conn->on_tcp_tx_complete_gas_done = 1; 1379c1d255d3SCy Schubert dpp_tcp_send(conn); 1380c1d255d3SCy Schubert return 0; 1381c1d255d3SCy Schubert } 1382c1d255d3SCy Schubert 1383c1d255d3SCy Schubert 1384c1d255d3SCy Schubert static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg, 1385c1d255d3SCy Schubert size_t len) 1386c1d255d3SCy Schubert { 1387c1d255d3SCy Schubert const u8 *pos, *end, *next; 1388c1d255d3SCy Schubert const u8 *adv_proto; 1389c1d255d3SCy Schubert u16 slen; 1390c1d255d3SCy Schubert struct wpabuf *resp; 1391c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 1392c1d255d3SCy Schubert 1393c1d255d3SCy Schubert if (len < 1 + 2) 1394c1d255d3SCy Schubert return -1; 1395c1d255d3SCy Schubert 1396c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1397c1d255d3SCy Schubert "DPP: Received DPP Configuration Request over TCP"); 1398c1d255d3SCy Schubert 1399c1d255d3SCy Schubert if (!auth || (!conn->ctrl && !auth->configurator) || 1400c1d255d3SCy Schubert (!auth->auth_success && !auth->reconfig_success)) { 1401c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); 1402c1d255d3SCy Schubert return -1; 1403c1d255d3SCy Schubert } 1404c1d255d3SCy Schubert 1405*a90b9d01SCy Schubert wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_REQ_RX); 1406*a90b9d01SCy Schubert 1407c1d255d3SCy Schubert pos = msg; 1408c1d255d3SCy Schubert end = msg + len; 1409c1d255d3SCy Schubert 1410c1d255d3SCy Schubert conn->gas_dialog_token = *pos++; 1411c1d255d3SCy Schubert adv_proto = pos++; 1412c1d255d3SCy Schubert slen = *pos++; 1413c1d255d3SCy Schubert if (*adv_proto != WLAN_EID_ADV_PROTO || 1414c1d255d3SCy Schubert slen > end - pos || slen < 2) 1415c1d255d3SCy Schubert return -1; 1416c1d255d3SCy Schubert 1417c1d255d3SCy Schubert next = pos + slen; 1418c1d255d3SCy Schubert pos++; /* skip QueryRespLenLimit and PAME-BI */ 1419c1d255d3SCy Schubert 1420c1d255d3SCy Schubert if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC || 1421c1d255d3SCy Schubert pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA || 1422c1d255d3SCy Schubert pos[5] != DPP_OUI_TYPE || pos[6] != 0x01) 1423c1d255d3SCy Schubert return -1; 1424c1d255d3SCy Schubert 1425c1d255d3SCy Schubert pos = next; 1426c1d255d3SCy Schubert /* Query Request */ 1427c1d255d3SCy Schubert if (end - pos < 2) 1428c1d255d3SCy Schubert return -1; 1429c1d255d3SCy Schubert slen = WPA_GET_LE16(pos); 1430c1d255d3SCy Schubert pos += 2; 1431c1d255d3SCy Schubert if (slen > end - pos) 1432c1d255d3SCy Schubert return -1; 1433c1d255d3SCy Schubert 1434c1d255d3SCy Schubert resp = dpp_conf_req_rx(auth, pos, slen); 1435c1d255d3SCy Schubert if (!resp && auth->waiting_cert) { 1436c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready"); 1437c1d255d3SCy Schubert conn->gas_comeback_in_progress = 1; 1438c1d255d3SCy Schubert return dpp_tcp_send_comeback_delay(conn, 1439c1d255d3SCy Schubert WLAN_PA_GAS_INITIAL_RESP); 1440c1d255d3SCy Schubert } 1441c1d255d3SCy Schubert 1442*a90b9d01SCy Schubert if (!resp && auth->waiting_config && auth->peer_bi) { 1443*a90b9d01SCy Schubert char *buf = NULL, *name = ""; 1444*a90b9d01SCy Schubert char band[200], *b_pos, *b_end; 1445*a90b9d01SCy Schubert int i, res, *opclass = auth->e_band_support; 1446*a90b9d01SCy Schubert char *mud_url = "N/A"; 1447*a90b9d01SCy Schubert 1448*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Configuration not yet ready"); 1449*a90b9d01SCy Schubert if (auth->e_name) { 1450*a90b9d01SCy Schubert size_t e_len = os_strlen(auth->e_name); 1451*a90b9d01SCy Schubert 1452*a90b9d01SCy Schubert buf = os_malloc(e_len * 4 + 1); 1453*a90b9d01SCy Schubert if (buf) { 1454*a90b9d01SCy Schubert printf_encode(buf, len * 4 + 1, 1455*a90b9d01SCy Schubert (const u8 *) auth->e_name, e_len); 1456*a90b9d01SCy Schubert name = buf; 1457*a90b9d01SCy Schubert } 1458*a90b9d01SCy Schubert } 1459*a90b9d01SCy Schubert band[0] = '\0'; 1460*a90b9d01SCy Schubert b_pos = band; 1461*a90b9d01SCy Schubert b_end = band + sizeof(band); 1462*a90b9d01SCy Schubert for (i = 0; opclass && opclass[i]; i++) { 1463*a90b9d01SCy Schubert res = os_snprintf(b_pos, b_end - b_pos, "%s%d", 1464*a90b9d01SCy Schubert b_pos == band ? "" : ",", opclass[i]); 1465*a90b9d01SCy Schubert if (os_snprintf_error(b_end - b_pos, res)) { 1466*a90b9d01SCy Schubert *b_pos = '\0'; 1467*a90b9d01SCy Schubert break; 1468*a90b9d01SCy Schubert } 1469*a90b9d01SCy Schubert b_pos += res; 1470*a90b9d01SCy Schubert } 1471*a90b9d01SCy Schubert if (auth->e_mud_url) { 1472*a90b9d01SCy Schubert size_t e_len = os_strlen(auth->e_mud_url); 1473*a90b9d01SCy Schubert 1474*a90b9d01SCy Schubert if (!has_ctrl_char((const u8 *) auth->e_mud_url, e_len)) 1475*a90b9d01SCy Schubert mud_url = auth->e_mud_url; 1476*a90b9d01SCy Schubert } 1477*a90b9d01SCy Schubert wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_NEEDED 1478*a90b9d01SCy Schubert "peer=%d net_role=%s name=\"%s\" opclass=%s mud_url=%s", 1479*a90b9d01SCy Schubert auth->peer_bi->id, dpp_netrole_str(auth->e_netrole), 1480*a90b9d01SCy Schubert name, band, mud_url); 1481*a90b9d01SCy Schubert os_free(buf); 1482*a90b9d01SCy Schubert 1483*a90b9d01SCy Schubert conn->gas_comeback_in_progress = 1; 1484*a90b9d01SCy Schubert return dpp_tcp_send_comeback_delay(conn, 1485*a90b9d01SCy Schubert WLAN_PA_GAS_INITIAL_RESP); 1486*a90b9d01SCy Schubert } 1487*a90b9d01SCy Schubert 1488c1d255d3SCy Schubert return dpp_tcp_send_gas_resp(conn, WLAN_PA_GAS_INITIAL_RESP, resp); 1489c1d255d3SCy Schubert } 1490c1d255d3SCy Schubert 1491c1d255d3SCy Schubert 1492c1d255d3SCy Schubert static int dpp_controller_rx_gas_comeback_req(struct dpp_connection *conn, 1493c1d255d3SCy Schubert const u8 *msg, size_t len) 1494c1d255d3SCy Schubert { 1495c1d255d3SCy Schubert u8 dialog_token; 1496c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 1497c1d255d3SCy Schubert struct wpabuf *resp; 1498c1d255d3SCy Schubert 1499c1d255d3SCy Schubert if (len < 1) 1500c1d255d3SCy Schubert return -1; 1501c1d255d3SCy Schubert 1502c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1503c1d255d3SCy Schubert "DPP: Received DPP Configuration Request over TCP (comeback)"); 1504c1d255d3SCy Schubert 1505c1d255d3SCy Schubert if (!auth || (!conn->ctrl && !auth->configurator) || 1506c1d255d3SCy Schubert (!auth->auth_success && !auth->reconfig_success) || 1507c1d255d3SCy Schubert !conn->gas_comeback_in_progress) { 1508c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); 1509c1d255d3SCy Schubert return -1; 1510c1d255d3SCy Schubert } 1511c1d255d3SCy Schubert 1512c1d255d3SCy Schubert dialog_token = msg[0]; 1513c1d255d3SCy Schubert if (dialog_token != conn->gas_dialog_token) { 1514c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Dialog token mismatch (%u != %u)", 1515c1d255d3SCy Schubert dialog_token, conn->gas_dialog_token); 1516c1d255d3SCy Schubert return -1; 1517c1d255d3SCy Schubert } 1518c1d255d3SCy Schubert 1519c1d255d3SCy Schubert if (!auth->conf_resp_tcp) { 1520c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready"); 1521c1d255d3SCy Schubert return dpp_tcp_send_comeback_delay(conn, 1522c1d255d3SCy Schubert WLAN_PA_GAS_COMEBACK_RESP); 1523c1d255d3SCy Schubert } 1524c1d255d3SCy Schubert 1525c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1526c1d255d3SCy Schubert "DPP: Configuration response is ready to be sent out"); 1527c1d255d3SCy Schubert resp = auth->conf_resp_tcp; 1528c1d255d3SCy Schubert auth->conf_resp_tcp = NULL; 1529c1d255d3SCy Schubert return dpp_tcp_send_gas_resp(conn, WLAN_PA_GAS_COMEBACK_RESP, resp); 1530c1d255d3SCy Schubert } 1531c1d255d3SCy Schubert 1532c1d255d3SCy Schubert 1533c1d255d3SCy Schubert static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx) 1534c1d255d3SCy Schubert { 1535c1d255d3SCy Schubert struct dpp_connection *conn = eloop_ctx; 1536c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 1537c1d255d3SCy Schubert 1538c1d255d3SCy Schubert if (!auth || !auth->csrattrs) 1539c1d255d3SCy Schubert return; 1540c1d255d3SCy Schubert 1541c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Build CSR"); 1542c1d255d3SCy Schubert wpabuf_free(auth->csr); 1543c1d255d3SCy Schubert /* TODO: Additional information needed for CSR based on csrAttrs */ 1544c1d255d3SCy Schubert auth->csr = dpp_build_csr(auth, conn->name ? conn->name : "Test"); 1545c1d255d3SCy Schubert if (!auth->csr) { 1546c1d255d3SCy Schubert dpp_connection_remove(conn); 1547c1d255d3SCy Schubert return; 1548c1d255d3SCy Schubert } 1549c1d255d3SCy Schubert 1550c1d255d3SCy Schubert dpp_controller_start_gas_client(conn); 1551c1d255d3SCy Schubert } 1552c1d255d3SCy Schubert 1553c1d255d3SCy Schubert 1554*a90b9d01SCy Schubert #ifdef CONFIG_DPP3 1555*a90b9d01SCy Schubert static void dpp_tcp_build_new_key(void *eloop_ctx, void *timeout_ctx) 1556*a90b9d01SCy Schubert { 1557*a90b9d01SCy Schubert struct dpp_connection *conn = eloop_ctx; 1558*a90b9d01SCy Schubert struct dpp_authentication *auth = conn->auth; 1559*a90b9d01SCy Schubert 1560*a90b9d01SCy Schubert if (!auth || !auth->waiting_new_key) 1561*a90b9d01SCy Schubert return; 1562*a90b9d01SCy Schubert 1563*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key"); 1564*a90b9d01SCy Schubert dpp_controller_start_gas_client(conn); 1565*a90b9d01SCy Schubert } 1566*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */ 1567*a90b9d01SCy Schubert 1568*a90b9d01SCy Schubert 1569c1d255d3SCy Schubert static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp) 1570c1d255d3SCy Schubert { 1571c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 1572c1d255d3SCy Schubert int res; 1573c1d255d3SCy Schubert struct wpabuf *msg; 1574c1d255d3SCy Schubert enum dpp_status_error status; 1575c1d255d3SCy Schubert 1576c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1577c1d255d3SCy Schubert "DPP: Configuration Response for local stack from TCP"); 1578c1d255d3SCy Schubert 1579c1d255d3SCy Schubert if (auth) 1580c1d255d3SCy Schubert res = dpp_conf_resp_rx(auth, resp); 1581c1d255d3SCy Schubert else 1582c1d255d3SCy Schubert res = -1; 1583c1d255d3SCy Schubert wpabuf_free(resp); 1584c1d255d3SCy Schubert if (res == -2) { 1585c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: CSR needed"); 1586c1d255d3SCy Schubert eloop_register_timeout(0, 0, dpp_tcp_build_csr, conn, NULL); 1587c1d255d3SCy Schubert return 0; 1588c1d255d3SCy Schubert } 1589*a90b9d01SCy Schubert #ifdef CONFIG_DPP3 1590*a90b9d01SCy Schubert if (res == -3) { 1591*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: New protocol key needed"); 1592*a90b9d01SCy Schubert eloop_register_timeout(0, 0, dpp_tcp_build_new_key, conn, 1593*a90b9d01SCy Schubert NULL); 1594*a90b9d01SCy Schubert return 0; 1595*a90b9d01SCy Schubert } 1596*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */ 1597c1d255d3SCy Schubert if (res < 0) { 1598c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); 1599c1d255d3SCy Schubert return -1; 1600c1d255d3SCy Schubert } 1601c1d255d3SCy Schubert 1602c1d255d3SCy Schubert if (conn->process_conf_obj) 1603c1d255d3SCy Schubert res = conn->process_conf_obj(conn->cb_ctx, auth); 1604c1d255d3SCy Schubert else 1605c1d255d3SCy Schubert res = 0; 1606c1d255d3SCy Schubert 1607c1d255d3SCy Schubert if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK) 1608c1d255d3SCy Schubert return -1; 1609c1d255d3SCy Schubert 1610c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result"); 1611c1d255d3SCy Schubert status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK; 1612c1d255d3SCy Schubert msg = dpp_build_conf_result(auth, status); 1613c1d255d3SCy Schubert if (!msg) 1614c1d255d3SCy Schubert return -1; 1615c1d255d3SCy Schubert 1616c1d255d3SCy Schubert conn->on_tcp_tx_complete_remove = 1; 1617c1d255d3SCy Schubert res = dpp_tcp_send_msg(conn, msg); 1618c1d255d3SCy Schubert wpabuf_free(msg); 1619c1d255d3SCy Schubert 1620c1d255d3SCy Schubert /* This exchange will be terminated in the TX status handler */ 1621c1d255d3SCy Schubert 1622c1d255d3SCy Schubert return res; 1623c1d255d3SCy Schubert } 1624c1d255d3SCy Schubert 1625c1d255d3SCy Schubert 1626c1d255d3SCy Schubert static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx) 1627c1d255d3SCy Schubert { 1628c1d255d3SCy Schubert struct dpp_connection *conn = eloop_ctx; 1629c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 1630c1d255d3SCy Schubert struct wpabuf *msg; 1631c1d255d3SCy Schubert 1632c1d255d3SCy Schubert if (!auth) 1633c1d255d3SCy Schubert return; 1634c1d255d3SCy Schubert 1635c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Send GAS Comeback Request"); 1636c1d255d3SCy Schubert msg = wpabuf_alloc(4 + 2); 1637c1d255d3SCy Schubert if (!msg) 1638c1d255d3SCy Schubert return; 1639c1d255d3SCy Schubert wpabuf_put_be32(msg, 2); 1640c1d255d3SCy Schubert wpabuf_put_u8(msg, WLAN_PA_GAS_COMEBACK_REQ); 1641c1d255d3SCy Schubert wpabuf_put_u8(msg, conn->gas_dialog_token); 1642c1d255d3SCy Schubert wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg); 1643c1d255d3SCy Schubert 1644c1d255d3SCy Schubert wpabuf_free(conn->msg_out); 1645c1d255d3SCy Schubert conn->msg_out_pos = 0; 1646c1d255d3SCy Schubert conn->msg_out = msg; 1647c1d255d3SCy Schubert dpp_tcp_send(conn); 1648c1d255d3SCy Schubert } 1649c1d255d3SCy Schubert 1650c1d255d3SCy Schubert 1651c1d255d3SCy Schubert static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg, 1652c1d255d3SCy Schubert size_t len, bool comeback) 1653c1d255d3SCy Schubert { 1654c1d255d3SCy Schubert struct wpabuf *buf; 1655c1d255d3SCy Schubert u8 dialog_token; 1656c1d255d3SCy Schubert const u8 *pos, *end, *next, *adv_proto; 1657c1d255d3SCy Schubert u16 status, slen, comeback_delay; 1658c1d255d3SCy Schubert 1659c1d255d3SCy Schubert if (len < (size_t) (5 + 2 + (comeback ? 1 : 0))) 1660c1d255d3SCy Schubert return -1; 1661c1d255d3SCy Schubert 1662c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1663c1d255d3SCy Schubert "DPP: Received DPP Configuration Response over TCP"); 1664c1d255d3SCy Schubert 1665c1d255d3SCy Schubert pos = msg; 1666c1d255d3SCy Schubert end = msg + len; 1667c1d255d3SCy Schubert 1668c1d255d3SCy Schubert dialog_token = *pos++; 1669c1d255d3SCy Schubert status = WPA_GET_LE16(pos); 1670c1d255d3SCy Schubert if (status != WLAN_STATUS_SUCCESS) { 1671c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Unexpected Status Code %u", status); 1672c1d255d3SCy Schubert return -1; 1673c1d255d3SCy Schubert } 1674c1d255d3SCy Schubert pos += 2; 1675c1d255d3SCy Schubert if (comeback) 1676c1d255d3SCy Schubert pos++; /* ignore Fragment ID */ 1677c1d255d3SCy Schubert comeback_delay = WPA_GET_LE16(pos); 1678c1d255d3SCy Schubert pos += 2; 1679c1d255d3SCy Schubert 1680c1d255d3SCy Schubert adv_proto = pos++; 1681c1d255d3SCy Schubert slen = *pos++; 1682c1d255d3SCy Schubert if (*adv_proto != WLAN_EID_ADV_PROTO || 1683c1d255d3SCy Schubert slen > end - pos || slen < 2) 1684c1d255d3SCy Schubert return -1; 1685c1d255d3SCy Schubert 1686c1d255d3SCy Schubert next = pos + slen; 1687c1d255d3SCy Schubert pos++; /* skip QueryRespLenLimit and PAME-BI */ 1688c1d255d3SCy Schubert 1689c1d255d3SCy Schubert if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC || 1690c1d255d3SCy Schubert pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA || 1691c1d255d3SCy Schubert pos[5] != DPP_OUI_TYPE || pos[6] != 0x01) 1692c1d255d3SCy Schubert return -1; 1693c1d255d3SCy Schubert 1694c1d255d3SCy Schubert pos = next; 1695c1d255d3SCy Schubert /* Query Response */ 1696c1d255d3SCy Schubert if (end - pos < 2) 1697c1d255d3SCy Schubert return -1; 1698c1d255d3SCy Schubert slen = WPA_GET_LE16(pos); 1699c1d255d3SCy Schubert pos += 2; 1700c1d255d3SCy Schubert if (slen > end - pos) 1701c1d255d3SCy Schubert return -1; 1702c1d255d3SCy Schubert 1703c1d255d3SCy Schubert if (comeback_delay) { 1704c1d255d3SCy Schubert unsigned int secs, usecs; 1705c1d255d3SCy Schubert 1706c1d255d3SCy Schubert conn->gas_dialog_token = dialog_token; 1707c1d255d3SCy Schubert secs = (comeback_delay * 1024) / 1000000; 1708c1d255d3SCy Schubert usecs = comeback_delay * 1024 - secs * 1000000; 1709c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Comeback delay: %u", 1710c1d255d3SCy Schubert comeback_delay); 1711c1d255d3SCy Schubert eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL); 1712c1d255d3SCy Schubert eloop_register_timeout(secs, usecs, dpp_tcp_gas_query_comeback, 1713c1d255d3SCy Schubert conn, NULL); 1714c1d255d3SCy Schubert return 0; 1715c1d255d3SCy Schubert } 1716c1d255d3SCy Schubert 1717c1d255d3SCy Schubert buf = wpabuf_alloc(slen); 1718c1d255d3SCy Schubert if (!buf) 1719c1d255d3SCy Schubert return -1; 1720c1d255d3SCy Schubert wpabuf_put_data(buf, pos, slen); 1721c1d255d3SCy Schubert 1722c1d255d3SCy Schubert if (!conn->relay && 1723c1d255d3SCy Schubert (!conn->ctrl || (conn->ctrl->allowed_roles & DPP_CAPAB_ENROLLEE))) 1724c1d255d3SCy Schubert return dpp_tcp_rx_gas_resp(conn, buf); 1725c1d255d3SCy Schubert 1726c1d255d3SCy Schubert if (!conn->relay) { 1727c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); 1728c1d255d3SCy Schubert wpabuf_free(buf); 1729c1d255d3SCy Schubert return -1; 1730c1d255d3SCy Schubert } 1731c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN"); 1732c1d255d3SCy Schubert conn->relay->gas_resp_tx(conn->relay->cb_ctx, conn->mac_addr, 1733c1d255d3SCy Schubert dialog_token, 0, buf); 1734c1d255d3SCy Schubert 1735c1d255d3SCy Schubert return 0; 1736c1d255d3SCy Schubert } 1737c1d255d3SCy Schubert 1738c1d255d3SCy Schubert 1739c1d255d3SCy Schubert static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx) 1740c1d255d3SCy Schubert { 1741c1d255d3SCy Schubert struct dpp_connection *conn = eloop_ctx; 1742c1d255d3SCy Schubert int res; 1743c1d255d3SCy Schubert const u8 *pos; 1744c1d255d3SCy Schubert 1745c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: TCP data available for reading (sock %d)", 1746c1d255d3SCy Schubert sd); 1747c1d255d3SCy Schubert 1748c1d255d3SCy Schubert if (conn->msg_len_octets < 4) { 1749c1d255d3SCy Schubert u32 msglen; 1750c1d255d3SCy Schubert 1751c1d255d3SCy Schubert res = recv(sd, &conn->msg_len[conn->msg_len_octets], 1752c1d255d3SCy Schubert 4 - conn->msg_len_octets, 0); 1753c1d255d3SCy Schubert if (res < 0) { 1754c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", 1755c1d255d3SCy Schubert strerror(errno)); 1756c1d255d3SCy Schubert dpp_connection_remove(conn); 1757c1d255d3SCy Schubert return; 1758c1d255d3SCy Schubert } 1759c1d255d3SCy Schubert if (res == 0) { 1760c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1761c1d255d3SCy Schubert "DPP: No more data available over TCP"); 1762c1d255d3SCy Schubert dpp_connection_remove(conn); 1763c1d255d3SCy Schubert return; 1764c1d255d3SCy Schubert } 1765c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1766c1d255d3SCy Schubert "DPP: Received %d/%d octet(s) of message length field", 1767c1d255d3SCy Schubert res, (int) (4 - conn->msg_len_octets)); 1768c1d255d3SCy Schubert conn->msg_len_octets += res; 1769c1d255d3SCy Schubert 1770c1d255d3SCy Schubert if (conn->msg_len_octets < 4) { 1771c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1772c1d255d3SCy Schubert "DPP: Need %d more octets of message length field", 1773c1d255d3SCy Schubert (int) (4 - conn->msg_len_octets)); 1774c1d255d3SCy Schubert return; 1775c1d255d3SCy Schubert } 1776c1d255d3SCy Schubert 1777c1d255d3SCy Schubert msglen = WPA_GET_BE32(conn->msg_len); 1778c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Message length: %u", msglen); 1779c1d255d3SCy Schubert if (msglen > 65535) { 1780c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: Unexpectedly long message"); 1781c1d255d3SCy Schubert dpp_connection_remove(conn); 1782c1d255d3SCy Schubert return; 1783c1d255d3SCy Schubert } 1784c1d255d3SCy Schubert 1785c1d255d3SCy Schubert wpabuf_free(conn->msg); 1786c1d255d3SCy Schubert conn->msg = wpabuf_alloc(msglen); 1787c1d255d3SCy Schubert } 1788c1d255d3SCy Schubert 1789c1d255d3SCy Schubert if (!conn->msg) { 1790c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1791c1d255d3SCy Schubert "DPP: No buffer available for receiving the message"); 1792c1d255d3SCy Schubert dpp_connection_remove(conn); 1793c1d255d3SCy Schubert return; 1794c1d255d3SCy Schubert } 1795c1d255d3SCy Schubert 1796c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Need %u more octets of message payload", 1797c1d255d3SCy Schubert (unsigned int) wpabuf_tailroom(conn->msg)); 1798c1d255d3SCy Schubert 1799c1d255d3SCy Schubert res = recv(sd, wpabuf_put(conn->msg, 0), wpabuf_tailroom(conn->msg), 0); 1800c1d255d3SCy Schubert if (res < 0) { 1801c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", strerror(errno)); 1802c1d255d3SCy Schubert dpp_connection_remove(conn); 1803c1d255d3SCy Schubert return; 1804c1d255d3SCy Schubert } 1805c1d255d3SCy Schubert if (res == 0) { 1806c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No more data available over TCP"); 1807c1d255d3SCy Schubert dpp_connection_remove(conn); 1808c1d255d3SCy Schubert return; 1809c1d255d3SCy Schubert } 1810c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Received %d octets", res); 1811c1d255d3SCy Schubert wpabuf_put(conn->msg, res); 1812c1d255d3SCy Schubert 1813c1d255d3SCy Schubert if (wpabuf_tailroom(conn->msg) > 0) { 1814c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1815c1d255d3SCy Schubert "DPP: Need %u more octets of message payload", 1816c1d255d3SCy Schubert (unsigned int) wpabuf_tailroom(conn->msg)); 1817c1d255d3SCy Schubert return; 1818c1d255d3SCy Schubert } 1819c1d255d3SCy Schubert 1820c1d255d3SCy Schubert conn->msg_len_octets = 0; 1821c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "DPP: Received TCP message", conn->msg); 1822c1d255d3SCy Schubert if (wpabuf_len(conn->msg) < 1) { 1823c1d255d3SCy Schubert dpp_connection_remove(conn); 1824c1d255d3SCy Schubert return; 1825c1d255d3SCy Schubert } 1826c1d255d3SCy Schubert 1827c1d255d3SCy Schubert pos = wpabuf_head(conn->msg); 1828c1d255d3SCy Schubert switch (*pos) { 1829c1d255d3SCy Schubert case WLAN_PA_VENDOR_SPECIFIC: 1830c1d255d3SCy Schubert if (dpp_controller_rx_action(conn, pos + 1, 1831c1d255d3SCy Schubert wpabuf_len(conn->msg) - 1) < 0) 1832c1d255d3SCy Schubert dpp_connection_remove(conn); 1833c1d255d3SCy Schubert break; 1834c1d255d3SCy Schubert case WLAN_PA_GAS_INITIAL_REQ: 1835c1d255d3SCy Schubert if (dpp_controller_rx_gas_req(conn, pos + 1, 1836c1d255d3SCy Schubert wpabuf_len(conn->msg) - 1) < 0) 1837c1d255d3SCy Schubert dpp_connection_remove(conn); 1838c1d255d3SCy Schubert break; 1839c1d255d3SCy Schubert case WLAN_PA_GAS_INITIAL_RESP: 1840c1d255d3SCy Schubert case WLAN_PA_GAS_COMEBACK_RESP: 1841c1d255d3SCy Schubert if (dpp_rx_gas_resp(conn, pos + 1, 1842c1d255d3SCy Schubert wpabuf_len(conn->msg) - 1, 1843c1d255d3SCy Schubert *pos == WLAN_PA_GAS_COMEBACK_RESP) < 0) 1844c1d255d3SCy Schubert dpp_connection_remove(conn); 1845c1d255d3SCy Schubert break; 1846c1d255d3SCy Schubert case WLAN_PA_GAS_COMEBACK_REQ: 1847c1d255d3SCy Schubert if (dpp_controller_rx_gas_comeback_req( 1848c1d255d3SCy Schubert conn, pos + 1, wpabuf_len(conn->msg) - 1) < 0) 1849c1d255d3SCy Schubert dpp_connection_remove(conn); 1850c1d255d3SCy Schubert break; 1851c1d255d3SCy Schubert default: 1852c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Ignore unsupported message type %u", 1853c1d255d3SCy Schubert *pos); 1854c1d255d3SCy Schubert break; 1855c1d255d3SCy Schubert } 1856c1d255d3SCy Schubert } 1857c1d255d3SCy Schubert 1858c1d255d3SCy Schubert 1859c1d255d3SCy Schubert static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx) 1860c1d255d3SCy Schubert { 1861c1d255d3SCy Schubert struct dpp_controller *ctrl = eloop_ctx; 1862c1d255d3SCy Schubert struct sockaddr_in addr; 1863c1d255d3SCy Schubert socklen_t addr_len = sizeof(addr); 1864c1d255d3SCy Schubert int fd; 1865c1d255d3SCy Schubert struct dpp_connection *conn; 1866c1d255d3SCy Schubert 1867c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: New TCP connection"); 1868c1d255d3SCy Schubert 1869c1d255d3SCy Schubert fd = accept(ctrl->sock, (struct sockaddr *) &addr, &addr_len); 1870c1d255d3SCy Schubert if (fd < 0) { 1871c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1872c1d255d3SCy Schubert "DPP: Failed to accept new connection: %s", 1873c1d255d3SCy Schubert strerror(errno)); 1874c1d255d3SCy Schubert return; 1875c1d255d3SCy Schubert } 1876c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d", 1877c1d255d3SCy Schubert inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 1878c1d255d3SCy Schubert 1879c1d255d3SCy Schubert conn = os_zalloc(sizeof(*conn)); 1880c1d255d3SCy Schubert if (!conn) 1881c1d255d3SCy Schubert goto fail; 1882c1d255d3SCy Schubert 1883c1d255d3SCy Schubert conn->global = ctrl->global; 1884c1d255d3SCy Schubert conn->ctrl = ctrl; 1885c1d255d3SCy Schubert conn->msg_ctx = ctrl->msg_ctx; 1886c1d255d3SCy Schubert conn->cb_ctx = ctrl->cb_ctx; 1887c1d255d3SCy Schubert conn->process_conf_obj = ctrl->process_conf_obj; 1888*a90b9d01SCy Schubert conn->tcp_msg_sent = ctrl->tcp_msg_sent; 1889c1d255d3SCy Schubert conn->sock = fd; 1890c1d255d3SCy Schubert conn->netrole = ctrl->netrole; 1891c1d255d3SCy Schubert 1892c1d255d3SCy Schubert if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) { 1893c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s", 1894c1d255d3SCy Schubert strerror(errno)); 1895c1d255d3SCy Schubert goto fail; 1896c1d255d3SCy Schubert } 1897c1d255d3SCy Schubert 1898c1d255d3SCy Schubert if (eloop_register_sock(conn->sock, EVENT_TYPE_READ, 1899c1d255d3SCy Schubert dpp_controller_rx, conn, NULL) < 0) 1900c1d255d3SCy Schubert goto fail; 1901c1d255d3SCy Schubert conn->read_eloop = 1; 1902c1d255d3SCy Schubert 1903c1d255d3SCy Schubert /* TODO: eloop timeout to expire connections that do not complete in 1904c1d255d3SCy Schubert * reasonable time */ 1905c1d255d3SCy Schubert dl_list_add(&ctrl->conn, &conn->list); 1906c1d255d3SCy Schubert return; 1907c1d255d3SCy Schubert 1908c1d255d3SCy Schubert fail: 1909c1d255d3SCy Schubert close(fd); 1910c1d255d3SCy Schubert os_free(conn); 1911c1d255d3SCy Schubert } 1912c1d255d3SCy Schubert 1913c1d255d3SCy Schubert 1914*a90b9d01SCy Schubert int dpp_tcp_pkex_init(struct dpp_global *dpp, struct dpp_pkex *pkex, 1915*a90b9d01SCy Schubert const struct hostapd_ip_addr *addr, int port, 1916*a90b9d01SCy Schubert void *msg_ctx, void *cb_ctx, 1917*a90b9d01SCy Schubert int (*pkex_done)(void *ctx, void *conn, 1918*a90b9d01SCy Schubert struct dpp_bootstrap_info *bi)) 1919c1d255d3SCy Schubert { 1920c1d255d3SCy Schubert struct dpp_connection *conn; 1921c1d255d3SCy Schubert struct sockaddr_storage saddr; 1922c1d255d3SCy Schubert socklen_t addrlen; 1923c1d255d3SCy Schubert const u8 *hdr, *pos, *end; 1924c1d255d3SCy Schubert char txt[100]; 1925c1d255d3SCy Schubert 1926c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d", 1927c1d255d3SCy Schubert hostapd_ip_txt(addr, txt, sizeof(txt)), port); 1928c1d255d3SCy Schubert if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen, 1929c1d255d3SCy Schubert addr, port) < 0) { 1930*a90b9d01SCy Schubert dpp_pkex_free(pkex); 1931*a90b9d01SCy Schubert return -1; 1932*a90b9d01SCy Schubert } 1933*a90b9d01SCy Schubert 1934*a90b9d01SCy Schubert conn = os_zalloc(sizeof(*conn)); 1935*a90b9d01SCy Schubert if (!conn) { 1936*a90b9d01SCy Schubert dpp_pkex_free(pkex); 1937*a90b9d01SCy Schubert return -1; 1938*a90b9d01SCy Schubert } 1939*a90b9d01SCy Schubert 1940*a90b9d01SCy Schubert conn->msg_ctx = msg_ctx; 1941*a90b9d01SCy Schubert conn->cb_ctx = cb_ctx; 1942*a90b9d01SCy Schubert conn->pkex_done = pkex_done; 1943*a90b9d01SCy Schubert conn->global = dpp; 1944*a90b9d01SCy Schubert conn->pkex = pkex; 1945*a90b9d01SCy Schubert conn->sock = socket(AF_INET, SOCK_STREAM, 0); 1946*a90b9d01SCy Schubert if (conn->sock < 0) 1947*a90b9d01SCy Schubert goto fail; 1948*a90b9d01SCy Schubert 1949*a90b9d01SCy Schubert if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) { 1950*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s", 1951*a90b9d01SCy Schubert strerror(errno)); 1952*a90b9d01SCy Schubert goto fail; 1953*a90b9d01SCy Schubert } 1954*a90b9d01SCy Schubert 1955*a90b9d01SCy Schubert if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) { 1956*a90b9d01SCy Schubert if (errno != EINPROGRESS) { 1957*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s", 1958*a90b9d01SCy Schubert strerror(errno)); 1959*a90b9d01SCy Schubert goto fail; 1960*a90b9d01SCy Schubert } 1961*a90b9d01SCy Schubert 1962*a90b9d01SCy Schubert /* 1963*a90b9d01SCy Schubert * Continue connecting in the background; eloop will call us 1964*a90b9d01SCy Schubert * once the connection is ready (or failed). 1965*a90b9d01SCy Schubert */ 1966*a90b9d01SCy Schubert } 1967*a90b9d01SCy Schubert 1968*a90b9d01SCy Schubert if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, 1969*a90b9d01SCy Schubert dpp_conn_tx_ready, conn, NULL) < 0) 1970*a90b9d01SCy Schubert goto fail; 1971*a90b9d01SCy Schubert conn->write_eloop = 1; 1972*a90b9d01SCy Schubert 1973*a90b9d01SCy Schubert hdr = wpabuf_head(pkex->exchange_req); 1974*a90b9d01SCy Schubert end = hdr + wpabuf_len(pkex->exchange_req); 1975*a90b9d01SCy Schubert hdr += 2; /* skip Category and Actiom */ 1976*a90b9d01SCy Schubert pos = hdr + DPP_HDR_LEN; 1977*a90b9d01SCy Schubert conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos); 1978*a90b9d01SCy Schubert if (!conn->msg_out) 1979*a90b9d01SCy Schubert goto fail; 1980*a90b9d01SCy Schubert /* Message will be sent in dpp_conn_tx_ready() */ 1981*a90b9d01SCy Schubert 1982*a90b9d01SCy Schubert /* TODO: eloop timeout to clear a connection if it does not complete 1983*a90b9d01SCy Schubert * properly */ 1984*a90b9d01SCy Schubert dl_list_add(&dpp->tcp_init, &conn->list); 1985*a90b9d01SCy Schubert return 0; 1986*a90b9d01SCy Schubert fail: 1987*a90b9d01SCy Schubert dpp_connection_free(conn); 1988*a90b9d01SCy Schubert return -1; 1989*a90b9d01SCy Schubert } 1990*a90b9d01SCy Schubert 1991*a90b9d01SCy Schubert 1992*a90b9d01SCy Schubert static int dpp_tcp_auth_start(struct dpp_connection *conn, 1993*a90b9d01SCy Schubert struct dpp_authentication *auth) 1994*a90b9d01SCy Schubert { 1995*a90b9d01SCy Schubert const u8 *hdr, *pos, *end; 1996*a90b9d01SCy Schubert 1997*a90b9d01SCy Schubert hdr = wpabuf_head(auth->req_msg); 1998*a90b9d01SCy Schubert end = hdr + wpabuf_len(auth->req_msg); 1999*a90b9d01SCy Schubert hdr += 2; /* skip Category and Actiom */ 2000*a90b9d01SCy Schubert pos = hdr + DPP_HDR_LEN; 2001*a90b9d01SCy Schubert conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos); 2002*a90b9d01SCy Schubert if (!conn->msg_out) 2003*a90b9d01SCy Schubert return -1; 2004*a90b9d01SCy Schubert /* Message will be sent in dpp_conn_tx_ready() */ 2005*a90b9d01SCy Schubert return 0; 2006*a90b9d01SCy Schubert } 2007*a90b9d01SCy Schubert 2008*a90b9d01SCy Schubert 2009*a90b9d01SCy Schubert int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth, 2010*a90b9d01SCy Schubert const struct hostapd_ip_addr *addr, int port, const char *name, 2011*a90b9d01SCy Schubert enum dpp_netrole netrole, const char *mud_url, 2012*a90b9d01SCy Schubert const char *extra_conf_req_name, 2013*a90b9d01SCy Schubert const char *extra_conf_req_value, 2014*a90b9d01SCy Schubert void *msg_ctx, void *cb_ctx, 2015*a90b9d01SCy Schubert int (*process_conf_obj)(void *ctx, 2016*a90b9d01SCy Schubert struct dpp_authentication *auth), 2017*a90b9d01SCy Schubert bool (*tcp_msg_sent)(void *ctx, 2018*a90b9d01SCy Schubert struct dpp_authentication *auth)) 2019*a90b9d01SCy Schubert { 2020*a90b9d01SCy Schubert struct dpp_connection *conn; 2021*a90b9d01SCy Schubert struct sockaddr_storage saddr; 2022*a90b9d01SCy Schubert socklen_t addrlen; 2023*a90b9d01SCy Schubert char txt[100]; 2024*a90b9d01SCy Schubert 2025*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d", 2026*a90b9d01SCy Schubert hostapd_ip_txt(addr, txt, sizeof(txt)), port); 2027*a90b9d01SCy Schubert if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen, 2028*a90b9d01SCy Schubert addr, port) < 0) { 2029c1d255d3SCy Schubert dpp_auth_deinit(auth); 2030c1d255d3SCy Schubert return -1; 2031c1d255d3SCy Schubert } 2032c1d255d3SCy Schubert 2033c1d255d3SCy Schubert conn = os_zalloc(sizeof(*conn)); 2034c1d255d3SCy Schubert if (!conn) { 2035c1d255d3SCy Schubert dpp_auth_deinit(auth); 2036c1d255d3SCy Schubert return -1; 2037c1d255d3SCy Schubert } 2038c1d255d3SCy Schubert 2039c1d255d3SCy Schubert conn->msg_ctx = msg_ctx; 2040c1d255d3SCy Schubert conn->cb_ctx = cb_ctx; 2041c1d255d3SCy Schubert conn->process_conf_obj = process_conf_obj; 2042*a90b9d01SCy Schubert conn->tcp_msg_sent = tcp_msg_sent; 2043c1d255d3SCy Schubert conn->name = os_strdup(name ? name : "Test"); 2044*a90b9d01SCy Schubert if (mud_url) 2045*a90b9d01SCy Schubert conn->mud_url = os_strdup(mud_url); 2046*a90b9d01SCy Schubert if (extra_conf_req_name) 2047*a90b9d01SCy Schubert conn->extra_conf_req_name = os_strdup(extra_conf_req_name); 2048*a90b9d01SCy Schubert if (extra_conf_req_value) 2049*a90b9d01SCy Schubert conn->extra_conf_req_value = os_strdup(extra_conf_req_value); 2050c1d255d3SCy Schubert conn->netrole = netrole; 2051c1d255d3SCy Schubert conn->global = dpp; 2052c1d255d3SCy Schubert conn->auth = auth; 2053c1d255d3SCy Schubert conn->sock = socket(AF_INET, SOCK_STREAM, 0); 2054c1d255d3SCy Schubert if (conn->sock < 0) 2055c1d255d3SCy Schubert goto fail; 2056c1d255d3SCy Schubert 2057c1d255d3SCy Schubert if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) { 2058c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s", 2059c1d255d3SCy Schubert strerror(errno)); 2060c1d255d3SCy Schubert goto fail; 2061c1d255d3SCy Schubert } 2062c1d255d3SCy Schubert 2063c1d255d3SCy Schubert if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) { 2064c1d255d3SCy Schubert if (errno != EINPROGRESS) { 2065c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s", 2066c1d255d3SCy Schubert strerror(errno)); 2067c1d255d3SCy Schubert goto fail; 2068c1d255d3SCy Schubert } 2069c1d255d3SCy Schubert 2070c1d255d3SCy Schubert /* 2071c1d255d3SCy Schubert * Continue connecting in the background; eloop will call us 2072c1d255d3SCy Schubert * once the connection is ready (or failed). 2073c1d255d3SCy Schubert */ 2074c1d255d3SCy Schubert } 2075c1d255d3SCy Schubert 2076c1d255d3SCy Schubert if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, 2077c1d255d3SCy Schubert dpp_conn_tx_ready, conn, NULL) < 0) 2078c1d255d3SCy Schubert goto fail; 2079c1d255d3SCy Schubert conn->write_eloop = 1; 2080c1d255d3SCy Schubert 2081*a90b9d01SCy Schubert if (dpp_tcp_auth_start(conn, auth) < 0) 2082c1d255d3SCy Schubert goto fail; 2083c1d255d3SCy Schubert 2084c1d255d3SCy Schubert /* TODO: eloop timeout to clear a connection if it does not complete 2085c1d255d3SCy Schubert * properly */ 2086c1d255d3SCy Schubert dl_list_add(&dpp->tcp_init, &conn->list); 2087c1d255d3SCy Schubert return 0; 2088c1d255d3SCy Schubert fail: 2089c1d255d3SCy Schubert dpp_connection_free(conn); 2090c1d255d3SCy Schubert return -1; 2091c1d255d3SCy Schubert } 2092c1d255d3SCy Schubert 2093c1d255d3SCy Schubert 2094*a90b9d01SCy Schubert int dpp_tcp_auth(struct dpp_global *dpp, void *_conn, 2095*a90b9d01SCy Schubert struct dpp_authentication *auth, const char *name, 2096*a90b9d01SCy Schubert enum dpp_netrole netrole, const char *mud_url, 2097*a90b9d01SCy Schubert const char *extra_conf_req_name, 2098*a90b9d01SCy Schubert const char *extra_conf_req_value, 2099*a90b9d01SCy Schubert int (*process_conf_obj)(void *ctx, 2100*a90b9d01SCy Schubert struct dpp_authentication *auth), 2101*a90b9d01SCy Schubert bool (*tcp_msg_sent)(void *ctx, 2102*a90b9d01SCy Schubert struct dpp_authentication *auth)) 2103*a90b9d01SCy Schubert { 2104*a90b9d01SCy Schubert struct dpp_connection *conn = _conn; 2105*a90b9d01SCy Schubert 2106*a90b9d01SCy Schubert /* Continue with Authentication exchange on an existing TCP connection. 2107*a90b9d01SCy Schubert */ 2108*a90b9d01SCy Schubert conn->process_conf_obj = process_conf_obj; 2109*a90b9d01SCy Schubert conn->tcp_msg_sent = tcp_msg_sent; 2110*a90b9d01SCy Schubert os_free(conn->name); 2111*a90b9d01SCy Schubert conn->name = os_strdup(name ? name : "Test"); 2112*a90b9d01SCy Schubert os_free(conn->mud_url); 2113*a90b9d01SCy Schubert conn->mud_url = mud_url ? os_strdup(mud_url) : NULL; 2114*a90b9d01SCy Schubert os_free(conn->extra_conf_req_name); 2115*a90b9d01SCy Schubert conn->extra_conf_req_name = extra_conf_req_name ? 2116*a90b9d01SCy Schubert os_strdup(extra_conf_req_name) : NULL; 2117*a90b9d01SCy Schubert conn->extra_conf_req_value = extra_conf_req_value ? 2118*a90b9d01SCy Schubert os_strdup(extra_conf_req_value) : NULL; 2119*a90b9d01SCy Schubert conn->netrole = netrole; 2120*a90b9d01SCy Schubert conn->auth = auth; 2121*a90b9d01SCy Schubert 2122*a90b9d01SCy Schubert if (dpp_tcp_auth_start(conn, auth) < 0) 2123*a90b9d01SCy Schubert return -1; 2124*a90b9d01SCy Schubert 2125*a90b9d01SCy Schubert dpp_conn_tx_ready(conn->sock, conn, NULL); 2126*a90b9d01SCy Schubert return 0; 2127*a90b9d01SCy Schubert } 2128*a90b9d01SCy Schubert 2129*a90b9d01SCy Schubert 2130c1d255d3SCy Schubert int dpp_controller_start(struct dpp_global *dpp, 2131c1d255d3SCy Schubert struct dpp_controller_config *config) 2132c1d255d3SCy Schubert { 2133c1d255d3SCy Schubert struct dpp_controller *ctrl; 2134c1d255d3SCy Schubert int on = 1; 2135c1d255d3SCy Schubert struct sockaddr_in sin; 2136c1d255d3SCy Schubert int port; 2137c1d255d3SCy Schubert 2138c1d255d3SCy Schubert if (!dpp || dpp->controller) 2139c1d255d3SCy Schubert return -1; 2140c1d255d3SCy Schubert 2141c1d255d3SCy Schubert ctrl = os_zalloc(sizeof(*ctrl)); 2142c1d255d3SCy Schubert if (!ctrl) 2143c1d255d3SCy Schubert return -1; 2144c1d255d3SCy Schubert ctrl->global = dpp; 2145c1d255d3SCy Schubert if (config->configurator_params) 2146c1d255d3SCy Schubert ctrl->configurator_params = 2147c1d255d3SCy Schubert os_strdup(config->configurator_params); 2148c1d255d3SCy Schubert dl_list_init(&ctrl->conn); 2149c1d255d3SCy Schubert ctrl->allowed_roles = config->allowed_roles; 2150c1d255d3SCy Schubert ctrl->qr_mutual = config->qr_mutual; 2151c1d255d3SCy Schubert ctrl->netrole = config->netrole; 2152c1d255d3SCy Schubert ctrl->msg_ctx = config->msg_ctx; 2153c1d255d3SCy Schubert ctrl->cb_ctx = config->cb_ctx; 2154c1d255d3SCy Schubert ctrl->process_conf_obj = config->process_conf_obj; 2155*a90b9d01SCy Schubert ctrl->tcp_msg_sent = config->tcp_msg_sent; 2156c1d255d3SCy Schubert 2157c1d255d3SCy Schubert ctrl->sock = socket(AF_INET, SOCK_STREAM, 0); 2158c1d255d3SCy Schubert if (ctrl->sock < 0) 2159c1d255d3SCy Schubert goto fail; 2160c1d255d3SCy Schubert 2161c1d255d3SCy Schubert if (setsockopt(ctrl->sock, SOL_SOCKET, SO_REUSEADDR, 2162c1d255d3SCy Schubert &on, sizeof(on)) < 0) { 2163c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 2164c1d255d3SCy Schubert "DPP: setsockopt(SO_REUSEADDR) failed: %s", 2165c1d255d3SCy Schubert strerror(errno)); 2166c1d255d3SCy Schubert /* try to continue anyway */ 2167c1d255d3SCy Schubert } 2168c1d255d3SCy Schubert 2169c1d255d3SCy Schubert if (fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0) { 2170c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s", 2171c1d255d3SCy Schubert strerror(errno)); 2172c1d255d3SCy Schubert goto fail; 2173c1d255d3SCy Schubert } 2174c1d255d3SCy Schubert 2175c1d255d3SCy Schubert /* TODO: IPv6 */ 2176c1d255d3SCy Schubert os_memset(&sin, 0, sizeof(sin)); 2177c1d255d3SCy Schubert sin.sin_family = AF_INET; 2178c1d255d3SCy Schubert sin.sin_addr.s_addr = INADDR_ANY; 2179c1d255d3SCy Schubert port = config->tcp_port ? config->tcp_port : DPP_TCP_PORT; 2180c1d255d3SCy Schubert sin.sin_port = htons(port); 2181c1d255d3SCy Schubert if (bind(ctrl->sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { 2182c1d255d3SCy Schubert wpa_printf(MSG_INFO, 2183c1d255d3SCy Schubert "DPP: Failed to bind Controller TCP port: %s", 2184c1d255d3SCy Schubert strerror(errno)); 2185c1d255d3SCy Schubert goto fail; 2186c1d255d3SCy Schubert } 2187c1d255d3SCy Schubert if (listen(ctrl->sock, 10 /* max backlog */) < 0 || 2188c1d255d3SCy Schubert fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0 || 2189c1d255d3SCy Schubert eloop_register_sock(ctrl->sock, EVENT_TYPE_READ, 2190c1d255d3SCy Schubert dpp_controller_tcp_cb, ctrl, NULL)) 2191c1d255d3SCy Schubert goto fail; 2192c1d255d3SCy Schubert 2193c1d255d3SCy Schubert dpp->controller = ctrl; 2194c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Controller started on TCP port %d", port); 2195c1d255d3SCy Schubert return 0; 2196c1d255d3SCy Schubert fail: 2197c1d255d3SCy Schubert dpp_controller_free(ctrl); 2198c1d255d3SCy Schubert return -1; 2199c1d255d3SCy Schubert } 2200c1d255d3SCy Schubert 2201c1d255d3SCy Schubert 2202*a90b9d01SCy Schubert int dpp_controller_set_params(struct dpp_global *dpp, 2203*a90b9d01SCy Schubert const char *configurator_params) 2204*a90b9d01SCy Schubert { 2205*a90b9d01SCy Schubert 2206*a90b9d01SCy Schubert if (!dpp || !dpp->controller) 2207*a90b9d01SCy Schubert return -1; 2208*a90b9d01SCy Schubert 2209*a90b9d01SCy Schubert if (configurator_params) { 2210*a90b9d01SCy Schubert char *val = os_strdup(configurator_params); 2211*a90b9d01SCy Schubert 2212*a90b9d01SCy Schubert if (!val) 2213*a90b9d01SCy Schubert return -1; 2214*a90b9d01SCy Schubert os_free(dpp->controller->configurator_params); 2215*a90b9d01SCy Schubert dpp->controller->configurator_params = val; 2216*a90b9d01SCy Schubert } else { 2217*a90b9d01SCy Schubert os_free(dpp->controller->configurator_params); 2218*a90b9d01SCy Schubert dpp->controller->configurator_params = NULL; 2219*a90b9d01SCy Schubert } 2220*a90b9d01SCy Schubert 2221*a90b9d01SCy Schubert return 0; 2222*a90b9d01SCy Schubert } 2223*a90b9d01SCy Schubert 2224*a90b9d01SCy Schubert 2225c1d255d3SCy Schubert void dpp_controller_stop(struct dpp_global *dpp) 2226c1d255d3SCy Schubert { 2227c1d255d3SCy Schubert if (dpp) { 2228c1d255d3SCy Schubert dpp_controller_free(dpp->controller); 2229c1d255d3SCy Schubert dpp->controller = NULL; 2230c1d255d3SCy Schubert } 2231c1d255d3SCy Schubert } 2232c1d255d3SCy Schubert 2233c1d255d3SCy Schubert 22344b72b91aSCy Schubert void dpp_controller_stop_for_ctx(struct dpp_global *dpp, void *cb_ctx) 22354b72b91aSCy Schubert { 22364b72b91aSCy Schubert if (dpp && dpp->controller && dpp->controller->cb_ctx == cb_ctx) 22374b72b91aSCy Schubert dpp_controller_stop(dpp); 22384b72b91aSCy Schubert } 22394b72b91aSCy Schubert 22404b72b91aSCy Schubert 2241c1d255d3SCy Schubert static bool dpp_tcp_peer_id_match(struct dpp_authentication *auth, 2242c1d255d3SCy Schubert unsigned int id) 2243c1d255d3SCy Schubert { 2244c1d255d3SCy Schubert return auth && 2245c1d255d3SCy Schubert ((auth->peer_bi && auth->peer_bi->id == id) || 2246c1d255d3SCy Schubert (auth->tmp_peer_bi && auth->tmp_peer_bi->id == id)); 2247c1d255d3SCy Schubert } 2248c1d255d3SCy Schubert 2249c1d255d3SCy Schubert 2250c1d255d3SCy Schubert static struct dpp_authentication * dpp_tcp_get_auth(struct dpp_global *dpp, 2251c1d255d3SCy Schubert unsigned int id) 2252c1d255d3SCy Schubert { 2253c1d255d3SCy Schubert struct dpp_connection *conn; 2254c1d255d3SCy Schubert 2255c1d255d3SCy Schubert dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) { 2256c1d255d3SCy Schubert if (dpp_tcp_peer_id_match(conn->auth, id)) 2257c1d255d3SCy Schubert return conn->auth; 2258c1d255d3SCy Schubert } 2259c1d255d3SCy Schubert 2260c1d255d3SCy Schubert return NULL; 2261c1d255d3SCy Schubert } 2262c1d255d3SCy Schubert 2263c1d255d3SCy Schubert 2264c1d255d3SCy Schubert struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp, 2265c1d255d3SCy Schubert unsigned int id) 2266c1d255d3SCy Schubert { 2267c1d255d3SCy Schubert struct dpp_controller *ctrl = dpp->controller; 2268c1d255d3SCy Schubert struct dpp_connection *conn; 2269c1d255d3SCy Schubert 2270c1d255d3SCy Schubert if (!ctrl) 2271c1d255d3SCy Schubert return dpp_tcp_get_auth(dpp, id); 2272c1d255d3SCy Schubert 2273c1d255d3SCy Schubert dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) { 2274c1d255d3SCy Schubert if (dpp_tcp_peer_id_match(conn->auth, id)) 2275c1d255d3SCy Schubert return conn->auth; 2276c1d255d3SCy Schubert } 2277c1d255d3SCy Schubert 2278c1d255d3SCy Schubert return dpp_tcp_get_auth(dpp, id); 2279c1d255d3SCy Schubert } 2280c1d255d3SCy Schubert 2281c1d255d3SCy Schubert 2282c1d255d3SCy Schubert void dpp_controller_new_qr_code(struct dpp_global *dpp, 2283c1d255d3SCy Schubert struct dpp_bootstrap_info *bi) 2284c1d255d3SCy Schubert { 2285c1d255d3SCy Schubert struct dpp_controller *ctrl = dpp->controller; 2286c1d255d3SCy Schubert struct dpp_connection *conn; 2287c1d255d3SCy Schubert 2288c1d255d3SCy Schubert if (!ctrl) 2289c1d255d3SCy Schubert return; 2290c1d255d3SCy Schubert 2291c1d255d3SCy Schubert dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) { 2292c1d255d3SCy Schubert struct dpp_authentication *auth = conn->auth; 2293c1d255d3SCy Schubert 2294c1d255d3SCy Schubert if (!auth->response_pending || 2295c1d255d3SCy Schubert dpp_notify_new_qr_code(auth, bi) != 1) 2296c1d255d3SCy Schubert continue; 2297c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 2298c1d255d3SCy Schubert "DPP: Sending out pending authentication response"); 2299c1d255d3SCy Schubert dpp_tcp_send_msg(conn, conn->auth->resp_msg); 2300c1d255d3SCy Schubert } 2301c1d255d3SCy Schubert } 2302c1d255d3SCy Schubert 2303c1d255d3SCy Schubert 2304*a90b9d01SCy Schubert void dpp_controller_pkex_add(struct dpp_global *dpp, 2305*a90b9d01SCy Schubert struct dpp_bootstrap_info *bi, 2306*a90b9d01SCy Schubert const char *code, const char *identifier) 2307*a90b9d01SCy Schubert { 2308*a90b9d01SCy Schubert struct dpp_controller *ctrl = dpp->controller; 2309*a90b9d01SCy Schubert 2310*a90b9d01SCy Schubert if (!ctrl) 2311*a90b9d01SCy Schubert return; 2312*a90b9d01SCy Schubert 2313*a90b9d01SCy Schubert ctrl->pkex_bi = bi; 2314*a90b9d01SCy Schubert os_free(ctrl->pkex_code); 2315*a90b9d01SCy Schubert ctrl->pkex_code = code ? os_strdup(code) : NULL; 2316*a90b9d01SCy Schubert os_free(ctrl->pkex_identifier); 2317*a90b9d01SCy Schubert ctrl->pkex_identifier = identifier ? os_strdup(identifier) : NULL; 2318*a90b9d01SCy Schubert } 2319*a90b9d01SCy Schubert 2320*a90b9d01SCy Schubert 2321*a90b9d01SCy Schubert bool dpp_controller_is_own_pkex_req(struct dpp_global *dpp, 2322*a90b9d01SCy Schubert const u8 *buf, size_t len) 2323*a90b9d01SCy Schubert { 2324*a90b9d01SCy Schubert struct dpp_connection *conn; 2325*a90b9d01SCy Schubert const u8 *attr_key = NULL; 2326*a90b9d01SCy Schubert u16 attr_key_len = 0; 2327*a90b9d01SCy Schubert 2328*a90b9d01SCy Schubert dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) { 2329*a90b9d01SCy Schubert if (!conn->pkex || !conn->pkex->enc_key) 2330*a90b9d01SCy Schubert continue; 2331*a90b9d01SCy Schubert 2332*a90b9d01SCy Schubert if (!attr_key) { 2333*a90b9d01SCy Schubert attr_key = dpp_get_attr(buf, len, 2334*a90b9d01SCy Schubert DPP_ATTR_ENCRYPTED_KEY, 2335*a90b9d01SCy Schubert &attr_key_len); 2336*a90b9d01SCy Schubert if (!attr_key) 2337*a90b9d01SCy Schubert return false; 2338*a90b9d01SCy Schubert } 2339*a90b9d01SCy Schubert 2340*a90b9d01SCy Schubert if (attr_key_len == wpabuf_len(conn->pkex->enc_key) && 2341*a90b9d01SCy Schubert os_memcmp(attr_key, wpabuf_head(conn->pkex->enc_key), 2342*a90b9d01SCy Schubert attr_key_len) == 0) 2343*a90b9d01SCy Schubert return true; 2344*a90b9d01SCy Schubert } 2345*a90b9d01SCy Schubert 2346*a90b9d01SCy Schubert return false; 2347*a90b9d01SCy Schubert } 2348*a90b9d01SCy Schubert 2349*a90b9d01SCy Schubert 2350c1d255d3SCy Schubert void dpp_tcp_init_flush(struct dpp_global *dpp) 2351c1d255d3SCy Schubert { 2352c1d255d3SCy Schubert struct dpp_connection *conn, *tmp; 2353c1d255d3SCy Schubert 2354c1d255d3SCy Schubert dl_list_for_each_safe(conn, tmp, &dpp->tcp_init, struct dpp_connection, 2355c1d255d3SCy Schubert list) 2356c1d255d3SCy Schubert dpp_connection_remove(conn); 2357c1d255d3SCy Schubert } 2358c1d255d3SCy Schubert 2359c1d255d3SCy Schubert 2360c1d255d3SCy Schubert static void dpp_relay_controller_free(struct dpp_relay_controller *ctrl) 2361c1d255d3SCy Schubert { 2362c1d255d3SCy Schubert struct dpp_connection *conn, *tmp; 2363*a90b9d01SCy Schubert char txt[100]; 2364*a90b9d01SCy Schubert 2365*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Remove Relay connection to Controller %s", 2366*a90b9d01SCy Schubert hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt))); 2367c1d255d3SCy Schubert 2368c1d255d3SCy Schubert dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection, 2369c1d255d3SCy Schubert list) 2370c1d255d3SCy Schubert dpp_connection_remove(conn); 2371c1d255d3SCy Schubert os_free(ctrl); 2372c1d255d3SCy Schubert } 2373c1d255d3SCy Schubert 2374c1d255d3SCy Schubert 2375c1d255d3SCy Schubert void dpp_relay_flush_controllers(struct dpp_global *dpp) 2376c1d255d3SCy Schubert { 2377c1d255d3SCy Schubert struct dpp_relay_controller *ctrl, *tmp; 2378c1d255d3SCy Schubert 2379c1d255d3SCy Schubert if (!dpp) 2380c1d255d3SCy Schubert return; 2381c1d255d3SCy Schubert 2382c1d255d3SCy Schubert dl_list_for_each_safe(ctrl, tmp, &dpp->controllers, 2383c1d255d3SCy Schubert struct dpp_relay_controller, list) { 2384c1d255d3SCy Schubert dl_list_del(&ctrl->list); 2385c1d255d3SCy Schubert dpp_relay_controller_free(ctrl); 2386c1d255d3SCy Schubert } 2387*a90b9d01SCy Schubert 2388*a90b9d01SCy Schubert if (dpp->tmp_controller) { 2389*a90b9d01SCy Schubert dpp_relay_controller_free(dpp->tmp_controller); 2390*a90b9d01SCy Schubert dpp->tmp_controller = NULL; 2391*a90b9d01SCy Schubert } 2392*a90b9d01SCy Schubert } 2393*a90b9d01SCy Schubert 2394*a90b9d01SCy Schubert 2395*a90b9d01SCy Schubert void dpp_relay_remove_controller(struct dpp_global *dpp, 2396*a90b9d01SCy Schubert const struct hostapd_ip_addr *addr) 2397*a90b9d01SCy Schubert { 2398*a90b9d01SCy Schubert struct dpp_relay_controller *ctrl; 2399*a90b9d01SCy Schubert 2400*a90b9d01SCy Schubert if (!dpp) 2401*a90b9d01SCy Schubert return; 2402*a90b9d01SCy Schubert 2403*a90b9d01SCy Schubert dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller, 2404*a90b9d01SCy Schubert list) { 2405*a90b9d01SCy Schubert if (hostapd_ip_equal(&ctrl->ipaddr, addr)) { 2406*a90b9d01SCy Schubert dl_list_del(&ctrl->list); 2407*a90b9d01SCy Schubert dpp_relay_controller_free(ctrl); 2408*a90b9d01SCy Schubert return; 2409*a90b9d01SCy Schubert } 2410*a90b9d01SCy Schubert } 2411*a90b9d01SCy Schubert 2412*a90b9d01SCy Schubert if (dpp->tmp_controller && 2413*a90b9d01SCy Schubert hostapd_ip_equal(&dpp->tmp_controller->ipaddr, addr)) { 2414*a90b9d01SCy Schubert dpp_relay_controller_free(dpp->tmp_controller); 2415*a90b9d01SCy Schubert dpp->tmp_controller = NULL; 2416*a90b9d01SCy Schubert } 2417*a90b9d01SCy Schubert } 2418*a90b9d01SCy Schubert 2419*a90b9d01SCy Schubert 2420*a90b9d01SCy Schubert static void dpp_relay_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx) 2421*a90b9d01SCy Schubert { 2422*a90b9d01SCy Schubert struct dpp_global *dpp = eloop_ctx; 2423*a90b9d01SCy Schubert struct sockaddr_in addr; 2424*a90b9d01SCy Schubert socklen_t addr_len = sizeof(addr); 2425*a90b9d01SCy Schubert int fd; 2426*a90b9d01SCy Schubert struct dpp_relay_controller *ctrl; 2427*a90b9d01SCy Schubert struct dpp_connection *conn = NULL; 2428*a90b9d01SCy Schubert 2429*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: New TCP connection (Relay)"); 2430*a90b9d01SCy Schubert 2431*a90b9d01SCy Schubert fd = accept(dpp->relay_sock, (struct sockaddr *) &addr, &addr_len); 2432*a90b9d01SCy Schubert if (fd < 0) { 2433*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 2434*a90b9d01SCy Schubert "DPP: Failed to accept new connection: %s", 2435*a90b9d01SCy Schubert strerror(errno)); 2436*a90b9d01SCy Schubert return; 2437*a90b9d01SCy Schubert } 2438*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d", 2439*a90b9d01SCy Schubert inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 2440*a90b9d01SCy Schubert 2441*a90b9d01SCy Schubert ctrl = dpp_relay_controller_get_addr(dpp, &addr); 2442*a90b9d01SCy Schubert if (!ctrl && dpp->tmp_controller && 2443*a90b9d01SCy Schubert dl_list_len(&dpp->tmp_controller->conn)) { 2444*a90b9d01SCy Schubert char txt[100]; 2445*a90b9d01SCy Schubert 2446*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 2447*a90b9d01SCy Schubert "DPP: Remove a temporaty Controller entry for %s", 2448*a90b9d01SCy Schubert hostapd_ip_txt(&dpp->tmp_controller->ipaddr, 2449*a90b9d01SCy Schubert txt, sizeof(txt))); 2450*a90b9d01SCy Schubert dpp_relay_controller_free(dpp->tmp_controller); 2451*a90b9d01SCy Schubert dpp->tmp_controller = NULL; 2452*a90b9d01SCy Schubert } 2453*a90b9d01SCy Schubert if (!ctrl && !dpp->tmp_controller) { 2454*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Add a temporary Controller entry"); 2455*a90b9d01SCy Schubert ctrl = os_zalloc(sizeof(*ctrl)); 2456*a90b9d01SCy Schubert if (!ctrl) 2457*a90b9d01SCy Schubert goto fail; 2458*a90b9d01SCy Schubert dl_list_init(&ctrl->conn); 2459*a90b9d01SCy Schubert ctrl->global = dpp; 2460*a90b9d01SCy Schubert ctrl->ipaddr.af = AF_INET; 2461*a90b9d01SCy Schubert ctrl->ipaddr.u.v4.s_addr = addr.sin_addr.s_addr; 2462*a90b9d01SCy Schubert ctrl->msg_ctx = dpp->relay_msg_ctx; 2463*a90b9d01SCy Schubert ctrl->cb_ctx = dpp->relay_cb_ctx; 2464*a90b9d01SCy Schubert ctrl->tx = dpp->relay_tx; 2465*a90b9d01SCy Schubert ctrl->gas_resp_tx = dpp->relay_gas_resp_tx; 2466*a90b9d01SCy Schubert dpp->tmp_controller = ctrl; 2467*a90b9d01SCy Schubert } 2468*a90b9d01SCy Schubert if (!ctrl) { 2469*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 2470*a90b9d01SCy Schubert "DPP: No Controller found for that address"); 2471*a90b9d01SCy Schubert goto fail; 2472*a90b9d01SCy Schubert } 2473*a90b9d01SCy Schubert 2474*a90b9d01SCy Schubert if (dl_list_len(&ctrl->conn) >= 15) { 2475*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 2476*a90b9d01SCy Schubert "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one"); 2477*a90b9d01SCy Schubert goto fail; 2478*a90b9d01SCy Schubert } 2479*a90b9d01SCy Schubert 2480*a90b9d01SCy Schubert conn = os_zalloc(sizeof(*conn)); 2481*a90b9d01SCy Schubert if (!conn) 2482*a90b9d01SCy Schubert goto fail; 2483*a90b9d01SCy Schubert 2484*a90b9d01SCy Schubert conn->global = ctrl->global; 2485*a90b9d01SCy Schubert conn->relay = ctrl; 2486*a90b9d01SCy Schubert conn->msg_ctx = ctrl->msg_ctx; 2487*a90b9d01SCy Schubert conn->cb_ctx = ctrl->global->cb_ctx; 2488*a90b9d01SCy Schubert os_memset(conn->mac_addr, 0xff, ETH_ALEN); 2489*a90b9d01SCy Schubert conn->sock = fd; 2490*a90b9d01SCy Schubert 2491*a90b9d01SCy Schubert if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) { 2492*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s", 2493*a90b9d01SCy Schubert strerror(errno)); 2494*a90b9d01SCy Schubert goto fail; 2495*a90b9d01SCy Schubert } 2496*a90b9d01SCy Schubert 2497*a90b9d01SCy Schubert if (eloop_register_sock(conn->sock, EVENT_TYPE_READ, 2498*a90b9d01SCy Schubert dpp_controller_rx, conn, NULL) < 0) 2499*a90b9d01SCy Schubert goto fail; 2500*a90b9d01SCy Schubert conn->read_eloop = 1; 2501*a90b9d01SCy Schubert 2502*a90b9d01SCy Schubert /* TODO: eloop timeout to expire connections that do not complete in 2503*a90b9d01SCy Schubert * reasonable time */ 2504*a90b9d01SCy Schubert dl_list_add(&ctrl->conn, &conn->list); 2505*a90b9d01SCy Schubert return; 2506*a90b9d01SCy Schubert 2507*a90b9d01SCy Schubert fail: 2508*a90b9d01SCy Schubert close(fd); 2509*a90b9d01SCy Schubert os_free(conn); 2510*a90b9d01SCy Schubert } 2511*a90b9d01SCy Schubert 2512*a90b9d01SCy Schubert 2513*a90b9d01SCy Schubert int dpp_relay_listen(struct dpp_global *dpp, int port, 2514*a90b9d01SCy Schubert struct dpp_relay_config *config) 2515*a90b9d01SCy Schubert { 2516*a90b9d01SCy Schubert int s; 2517*a90b9d01SCy Schubert int on = 1; 2518*a90b9d01SCy Schubert struct sockaddr_in sin; 2519*a90b9d01SCy Schubert 2520*a90b9d01SCy Schubert if (dpp->relay_sock >= 0) { 2521*a90b9d01SCy Schubert wpa_printf(MSG_INFO, "DPP: %s(%d) - relay port already opened", 2522*a90b9d01SCy Schubert __func__, port); 2523*a90b9d01SCy Schubert return -1; 2524*a90b9d01SCy Schubert } 2525*a90b9d01SCy Schubert 2526*a90b9d01SCy Schubert s = socket(AF_INET, SOCK_STREAM, 0); 2527*a90b9d01SCy Schubert if (s < 0) { 2528*a90b9d01SCy Schubert wpa_printf(MSG_INFO, 2529*a90b9d01SCy Schubert "DPP: socket(SOCK_STREAM) failed: %s", 2530*a90b9d01SCy Schubert strerror(errno)); 2531*a90b9d01SCy Schubert return -1; 2532*a90b9d01SCy Schubert } 2533*a90b9d01SCy Schubert 2534*a90b9d01SCy Schubert if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { 2535*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 2536*a90b9d01SCy Schubert "DPP: setsockopt(SO_REUSEADDR) failed: %s", 2537*a90b9d01SCy Schubert strerror(errno)); 2538*a90b9d01SCy Schubert /* try to continue anyway */ 2539*a90b9d01SCy Schubert } 2540*a90b9d01SCy Schubert 2541*a90b9d01SCy Schubert if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) { 2542*a90b9d01SCy Schubert wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s", 2543*a90b9d01SCy Schubert strerror(errno)); 2544*a90b9d01SCy Schubert close(s); 2545*a90b9d01SCy Schubert return -1; 2546*a90b9d01SCy Schubert } 2547*a90b9d01SCy Schubert 2548*a90b9d01SCy Schubert /* TODO: IPv6 */ 2549*a90b9d01SCy Schubert os_memset(&sin, 0, sizeof(sin)); 2550*a90b9d01SCy Schubert sin.sin_family = AF_INET; 2551*a90b9d01SCy Schubert sin.sin_addr.s_addr = INADDR_ANY; 2552*a90b9d01SCy Schubert sin.sin_port = htons(port); 2553*a90b9d01SCy Schubert if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { 2554*a90b9d01SCy Schubert wpa_printf(MSG_INFO, 2555*a90b9d01SCy Schubert "DPP: Failed to bind Relay TCP port: %s", 2556*a90b9d01SCy Schubert strerror(errno)); 2557*a90b9d01SCy Schubert close(s); 2558*a90b9d01SCy Schubert return -1; 2559*a90b9d01SCy Schubert } 2560*a90b9d01SCy Schubert if (listen(s, 10 /* max backlog */) < 0 || 2561*a90b9d01SCy Schubert fcntl(s, F_SETFL, O_NONBLOCK) < 0 || 2562*a90b9d01SCy Schubert eloop_register_sock(s, EVENT_TYPE_READ, dpp_relay_tcp_cb, dpp, 2563*a90b9d01SCy Schubert NULL)) { 2564*a90b9d01SCy Schubert close(s); 2565*a90b9d01SCy Schubert return -1; 2566*a90b9d01SCy Schubert } 2567*a90b9d01SCy Schubert 2568*a90b9d01SCy Schubert dpp->relay_sock = s; 2569*a90b9d01SCy Schubert dpp->relay_msg_ctx = config->msg_ctx; 2570*a90b9d01SCy Schubert dpp->relay_cb_ctx = config->cb_ctx; 2571*a90b9d01SCy Schubert dpp->relay_tx = config->tx; 2572*a90b9d01SCy Schubert dpp->relay_gas_resp_tx = config->gas_resp_tx; 2573*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Relay started on TCP port %d", port); 2574*a90b9d01SCy Schubert return 0; 2575*a90b9d01SCy Schubert } 2576*a90b9d01SCy Schubert 2577*a90b9d01SCy Schubert 2578*a90b9d01SCy Schubert void dpp_relay_stop_listen(struct dpp_global *dpp) 2579*a90b9d01SCy Schubert { 2580*a90b9d01SCy Schubert if (!dpp || dpp->relay_sock < 0) 2581*a90b9d01SCy Schubert return; 2582*a90b9d01SCy Schubert eloop_unregister_sock(dpp->relay_sock, EVENT_TYPE_READ); 2583*a90b9d01SCy Schubert close(dpp->relay_sock); 2584*a90b9d01SCy Schubert dpp->relay_sock = -1; 2585*a90b9d01SCy Schubert } 2586*a90b9d01SCy Schubert 2587*a90b9d01SCy Schubert 2588*a90b9d01SCy Schubert bool dpp_tcp_conn_status_requested(struct dpp_global *dpp) 2589*a90b9d01SCy Schubert { 2590*a90b9d01SCy Schubert struct dpp_connection *conn; 2591*a90b9d01SCy Schubert 2592*a90b9d01SCy Schubert if (!dpp) 2593*a90b9d01SCy Schubert return false; 2594*a90b9d01SCy Schubert 2595*a90b9d01SCy Schubert dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) { 2596*a90b9d01SCy Schubert if (conn->auth && conn->auth->conn_status_requested) 2597*a90b9d01SCy Schubert return true; 2598*a90b9d01SCy Schubert } 2599*a90b9d01SCy Schubert 2600*a90b9d01SCy Schubert return false; 2601*a90b9d01SCy Schubert } 2602*a90b9d01SCy Schubert 2603*a90b9d01SCy Schubert 2604*a90b9d01SCy Schubert static void dpp_tcp_send_conn_status_msg(struct dpp_global *dpp, 2605*a90b9d01SCy Schubert struct dpp_connection *conn, 2606*a90b9d01SCy Schubert enum dpp_status_error result, 2607*a90b9d01SCy Schubert const u8 *ssid, size_t ssid_len, 2608*a90b9d01SCy Schubert const char *channel_list) 2609*a90b9d01SCy Schubert { 2610*a90b9d01SCy Schubert struct dpp_authentication *auth = conn->auth; 2611*a90b9d01SCy Schubert int res; 2612*a90b9d01SCy Schubert struct wpabuf *msg; 2613*a90b9d01SCy Schubert struct dpp_connection *c; 2614*a90b9d01SCy Schubert 2615*a90b9d01SCy Schubert auth->conn_status_requested = 0; 2616*a90b9d01SCy Schubert 2617*a90b9d01SCy Schubert msg = dpp_build_conn_status_result(auth, result, ssid, ssid_len, 2618*a90b9d01SCy Schubert channel_list); 2619*a90b9d01SCy Schubert if (!msg) { 2620*a90b9d01SCy Schubert dpp_connection_remove(conn); 2621*a90b9d01SCy Schubert return; 2622*a90b9d01SCy Schubert } 2623*a90b9d01SCy Schubert 2624*a90b9d01SCy Schubert res = dpp_tcp_send_msg(conn, msg); 2625*a90b9d01SCy Schubert wpabuf_free(msg); 2626*a90b9d01SCy Schubert 2627*a90b9d01SCy Schubert if (res < 0) { 2628*a90b9d01SCy Schubert dpp_connection_remove(conn); 2629*a90b9d01SCy Schubert return; 2630*a90b9d01SCy Schubert } 2631*a90b9d01SCy Schubert 2632*a90b9d01SCy Schubert /* conn might have been removed during the dpp_tcp_send_msg() call, so 2633*a90b9d01SCy Schubert * need to check that it is still present before modifying it. */ 2634*a90b9d01SCy Schubert dl_list_for_each(c, &dpp->tcp_init, struct dpp_connection, list) { 2635*a90b9d01SCy Schubert if (conn == c) { 2636*a90b9d01SCy Schubert /* This exchange will be terminated in the TX status 2637*a90b9d01SCy Schubert * handler */ 2638*a90b9d01SCy Schubert conn->on_tcp_tx_complete_remove = 1; 2639*a90b9d01SCy Schubert break; 2640*a90b9d01SCy Schubert } 2641*a90b9d01SCy Schubert } 2642*a90b9d01SCy Schubert } 2643*a90b9d01SCy Schubert 2644*a90b9d01SCy Schubert 2645*a90b9d01SCy Schubert void dpp_tcp_send_conn_status(struct dpp_global *dpp, 2646*a90b9d01SCy Schubert enum dpp_status_error result, 2647*a90b9d01SCy Schubert const u8 *ssid, size_t ssid_len, 2648*a90b9d01SCy Schubert const char *channel_list) 2649*a90b9d01SCy Schubert { 2650*a90b9d01SCy Schubert struct dpp_connection *conn; 2651*a90b9d01SCy Schubert 2652*a90b9d01SCy Schubert dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) { 2653*a90b9d01SCy Schubert if (conn->auth && conn->auth->conn_status_requested) { 2654*a90b9d01SCy Schubert dpp_tcp_send_conn_status_msg(dpp, conn, result, ssid, 2655*a90b9d01SCy Schubert ssid_len, channel_list); 2656*a90b9d01SCy Schubert break; 2657*a90b9d01SCy Schubert } 2658*a90b9d01SCy Schubert } 2659c1d255d3SCy Schubert } 2660c1d255d3SCy Schubert 2661c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */ 2662