xref: /freebsd/contrib/wpa/src/common/dpp_tcp.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
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 
dpp_connection_free(struct dpp_connection * conn)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 
dpp_connection_remove(struct dpp_connection * conn)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 
dpp_relay_add_controller(struct dpp_global * dpp,struct dpp_relay_config * config)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 *
dpp_relay_controller_get(struct dpp_global * dpp,const u8 * pkhash)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 *
dpp_relay_controller_get_ctx(struct dpp_global * dpp,void * cb_ctx)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 *
dpp_relay_controller_get_addr(struct dpp_global * dpp,const struct sockaddr_in * addr)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 
dpp_controller_gas_done(struct dpp_connection * conn)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 
dpp_tcp_send(struct dpp_connection * conn)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 
dpp_tcp_send_msg(struct dpp_connection * conn,const struct wpabuf * msg)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 
dpp_controller_start_gas_client(struct dpp_connection * conn)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 
dpp_controller_auth_success(struct dpp_connection * conn,int initiator)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 
dpp_conn_tx_ready(int sock,void * eloop_ctx,void * sock_ctx)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 
dpp_ipaddr_to_sockaddr(struct sockaddr * addr,socklen_t * addrlen,const struct hostapd_ip_addr * ipaddr,int port)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 
dpp_relay_conn_timeout(void * eloop_ctx,void * timeout_ctx)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 *
dpp_relay_new_conn(struct dpp_relay_controller * ctrl,const u8 * src,unsigned int freq)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 
dpp_tcp_encaps(const u8 * hdr,const u8 * buf,size_t len)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 
dpp_relay_tx(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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 *
dpp_relay_match_ctrl(struct dpp_relay_controller * ctrl,const u8 * src,unsigned int freq,u8 type)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 
dpp_relay_rx_action(struct dpp_global * dpp,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq,const u8 * i_bootstrap,const u8 * r_bootstrap,void * cb_ctx)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 *
dpp_relay_find_conn(struct dpp_relay_controller * ctrl,const u8 * src)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 
dpp_relay_rx_gas_req(struct dpp_global * dpp,const u8 * src,const u8 * data,size_t data_len)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 
dpp_relay_controller_available(struct dpp_global * dpp)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 
dpp_controller_free(struct dpp_controller * ctrl)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 
dpp_controller_rx_auth_req(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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 
dpp_controller_rx_auth_resp(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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 
dpp_controller_rx_auth_conf(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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 
dpp_controller_conn_status_result_wait_timeout(void * eloop_ctx,void * timeout_ctx)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 
dpp_controller_rx_conf_result(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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 
dpp_controller_rx_conn_status_result(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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 
dpp_controller_rx_presence_announcement(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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 
dpp_controller_rx_reconfig_announcement(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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 
dpp_controller_rx_reconfig_auth_resp(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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 
dpp_controller_rx_pkex_exchange_req(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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 
dpp_controller_rx_pkex_exchange_resp(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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 
dpp_controller_rx_pkex_commit_reveal_req(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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
dpp_controller_rx_pkex_commit_reveal_resp(struct dpp_connection * conn,const u8 * hdr,const u8 * buf,size_t len)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 
dpp_controller_rx_action(struct dpp_connection * conn,const u8 * msg,size_t len)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 
dpp_tcp_send_comeback_delay(struct dpp_connection * conn,u8 action)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 
dpp_tcp_send_gas_resp(struct dpp_connection * conn,u8 action,struct wpabuf * resp)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 
dpp_controller_rx_gas_req(struct dpp_connection * conn,const u8 * msg,size_t len)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 
dpp_controller_rx_gas_comeback_req(struct dpp_connection * conn,const u8 * msg,size_t len)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 
dpp_tcp_build_csr(void * eloop_ctx,void * timeout_ctx)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
dpp_tcp_build_new_key(void * eloop_ctx,void * timeout_ctx)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 
dpp_tcp_rx_gas_resp(struct dpp_connection * conn,struct wpabuf * resp)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 
dpp_tcp_gas_query_comeback(void * eloop_ctx,void * timeout_ctx)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 
dpp_rx_gas_resp(struct dpp_connection * conn,const u8 * msg,size_t len,bool comeback)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 
dpp_controller_rx(int sd,void * eloop_ctx,void * sock_ctx)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 
dpp_controller_tcp_cb(int sd,void * eloop_ctx,void * sock_ctx)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 
dpp_tcp_pkex_init(struct dpp_global * dpp,struct dpp_pkex * pkex,const struct hostapd_ip_addr * addr,int port,void * msg_ctx,void * cb_ctx,int (* pkex_done)(void * ctx,void * conn,struct dpp_bootstrap_info * bi))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 
dpp_tcp_auth_start(struct dpp_connection * conn,struct dpp_authentication * auth)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 
dpp_tcp_init(struct dpp_global * dpp,struct dpp_authentication * auth,const struct hostapd_ip_addr * addr,int port,const char * name,enum dpp_netrole netrole,const char * mud_url,const char * extra_conf_req_name,const char * extra_conf_req_value,void * msg_ctx,void * cb_ctx,int (* process_conf_obj)(void * ctx,struct dpp_authentication * auth),bool (* tcp_msg_sent)(void * ctx,struct dpp_authentication * auth))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 
dpp_tcp_auth(struct dpp_global * dpp,void * _conn,struct dpp_authentication * auth,const char * name,enum dpp_netrole netrole,const char * mud_url,const char * extra_conf_req_name,const char * extra_conf_req_value,int (* process_conf_obj)(void * ctx,struct dpp_authentication * auth),bool (* tcp_msg_sent)(void * ctx,struct dpp_authentication * auth))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 
dpp_controller_start(struct dpp_global * dpp,struct dpp_controller_config * config)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 
dpp_controller_set_params(struct dpp_global * dpp,const char * configurator_params)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 
dpp_controller_stop(struct dpp_global * dpp)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 
dpp_controller_stop_for_ctx(struct dpp_global * dpp,void * cb_ctx)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 
dpp_tcp_peer_id_match(struct dpp_authentication * auth,unsigned int id)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 
dpp_tcp_get_auth(struct dpp_global * dpp,unsigned int id)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 
dpp_controller_get_auth(struct dpp_global * dpp,unsigned int id)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 
dpp_controller_new_qr_code(struct dpp_global * dpp,struct dpp_bootstrap_info * bi)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 
dpp_controller_pkex_add(struct dpp_global * dpp,struct dpp_bootstrap_info * bi,const char * code,const char * identifier)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 
dpp_controller_is_own_pkex_req(struct dpp_global * dpp,const u8 * buf,size_t len)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 
dpp_tcp_init_flush(struct dpp_global * dpp)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 
dpp_relay_controller_free(struct dpp_relay_controller * ctrl)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 
dpp_relay_flush_controllers(struct dpp_global * dpp)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 
dpp_relay_remove_controller(struct dpp_global * dpp,const struct hostapd_ip_addr * addr)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 
dpp_relay_tcp_cb(int sd,void * eloop_ctx,void * sock_ctx)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 
dpp_relay_listen(struct dpp_global * dpp,int port,struct dpp_relay_config * config)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 
dpp_relay_stop_listen(struct dpp_global * dpp)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 
dpp_tcp_conn_status_requested(struct dpp_global * dpp)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 
dpp_tcp_send_conn_status_msg(struct dpp_global * dpp,struct dpp_connection * conn,enum dpp_status_error result,const u8 * ssid,size_t ssid_len,const char * channel_list)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 
dpp_tcp_send_conn_status(struct dpp_global * dpp,enum dpp_status_error result,const u8 * ssid,size_t ssid_len,const char * channel_list)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