xref: /freebsd/contrib/wpa/wpa_supplicant/dpp_supplicant.c (revision 32a95656b51ebefcdf3e0b02c110825f59abd26f)
185732ac8SCy Schubert /*
285732ac8SCy Schubert  * wpa_supplicant - DPP
385732ac8SCy Schubert  * Copyright (c) 2017, Qualcomm Atheros, Inc.
4c1d255d3SCy Schubert  * Copyright (c) 2018-2020, The Linux Foundation
585732ac8SCy Schubert  *
685732ac8SCy Schubert  * This software may be distributed under the terms of the BSD license.
785732ac8SCy Schubert  * See README for more details.
885732ac8SCy Schubert  */
985732ac8SCy Schubert 
1085732ac8SCy Schubert #include "utils/includes.h"
1185732ac8SCy Schubert 
1285732ac8SCy Schubert #include "utils/common.h"
1385732ac8SCy Schubert #include "utils/eloop.h"
14206b73d0SCy Schubert #include "utils/ip_addr.h"
15c1d255d3SCy Schubert #include "utils/base64.h"
1685732ac8SCy Schubert #include "common/dpp.h"
1785732ac8SCy Schubert #include "common/gas.h"
1885732ac8SCy Schubert #include "common/gas_server.h"
1985732ac8SCy Schubert #include "rsn_supp/wpa.h"
2085732ac8SCy Schubert #include "rsn_supp/pmksa_cache.h"
2185732ac8SCy Schubert #include "wpa_supplicant_i.h"
2285732ac8SCy Schubert #include "config.h"
2385732ac8SCy Schubert #include "driver_i.h"
2485732ac8SCy Schubert #include "offchannel.h"
2585732ac8SCy Schubert #include "gas_query.h"
2685732ac8SCy Schubert #include "bss.h"
2785732ac8SCy Schubert #include "scan.h"
2885732ac8SCy Schubert #include "notify.h"
2985732ac8SCy Schubert #include "dpp_supplicant.h"
3085732ac8SCy Schubert 
3185732ac8SCy Schubert 
3285732ac8SCy Schubert static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
3385732ac8SCy Schubert 				 unsigned int freq);
3485732ac8SCy Schubert static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
35c1d255d3SCy Schubert static void wpas_dpp_auth_conf_wait_timeout(void *eloop_ctx, void *timeout_ctx);
3685732ac8SCy Schubert static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator);
3785732ac8SCy Schubert static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
3885732ac8SCy Schubert 			       unsigned int freq, const u8 *dst,
3985732ac8SCy Schubert 			       const u8 *src, const u8 *bssid,
4085732ac8SCy Schubert 			       const u8 *data, size_t data_len,
4185732ac8SCy Schubert 			       enum offchannel_send_action_result result);
4285732ac8SCy Schubert static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
4385732ac8SCy Schubert static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s);
4485732ac8SCy Schubert static void
4585732ac8SCy Schubert wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
4685732ac8SCy Schubert 			unsigned int freq, const u8 *dst,
4785732ac8SCy Schubert 			const u8 *src, const u8 *bssid,
4885732ac8SCy Schubert 			const u8 *data, size_t data_len,
4985732ac8SCy Schubert 			enum offchannel_send_action_result result);
50c1d255d3SCy Schubert #ifdef CONFIG_DPP2
51c1d255d3SCy Schubert static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
52c1d255d3SCy Schubert 						 void *timeout_ctx);
53c1d255d3SCy Schubert static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s);
54c1d255d3SCy Schubert static int wpas_dpp_process_conf_obj(void *ctx,
55c1d255d3SCy Schubert 				     struct dpp_authentication *auth);
56c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
5785732ac8SCy Schubert 
5885732ac8SCy Schubert static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
5985732ac8SCy Schubert 
6085732ac8SCy Schubert /* Use a hardcoded Transaction ID 1 in Peer Discovery frames since there is only
6185732ac8SCy Schubert  * a single transaction in progress at any point in time. */
6285732ac8SCy Schubert static const u8 TRANSACTION_ID = 1;
6385732ac8SCy Schubert 
6485732ac8SCy Schubert 
6585732ac8SCy Schubert /**
6685732ac8SCy Schubert  * wpas_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
6785732ac8SCy Schubert  * @wpa_s: Pointer to wpa_supplicant data
6885732ac8SCy Schubert  * @cmd: DPP URI read from a QR Code
6985732ac8SCy Schubert  * Returns: Identifier of the stored info or -1 on failure
7085732ac8SCy Schubert  */
7185732ac8SCy Schubert int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd)
7285732ac8SCy Schubert {
7385732ac8SCy Schubert 	struct dpp_bootstrap_info *bi;
7485732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
7585732ac8SCy Schubert 
764bc52338SCy Schubert 	bi = dpp_add_qr_code(wpa_s->dpp, cmd);
7785732ac8SCy Schubert 	if (!bi)
7885732ac8SCy Schubert 		return -1;
7985732ac8SCy Schubert 
8085732ac8SCy Schubert 	if (auth && auth->response_pending &&
8185732ac8SCy Schubert 	    dpp_notify_new_qr_code(auth, bi) == 1) {
8285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
8385732ac8SCy Schubert 			   "DPP: Sending out pending authentication response");
8485732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
8585732ac8SCy Schubert 			" freq=%u type=%d",
8685732ac8SCy Schubert 			MAC2STR(auth->peer_mac_addr), auth->curr_freq,
8785732ac8SCy Schubert 			DPP_PA_AUTHENTICATION_RESP);
8885732ac8SCy Schubert 		offchannel_send_action(wpa_s, auth->curr_freq,
8985732ac8SCy Schubert 				       auth->peer_mac_addr, wpa_s->own_addr,
9085732ac8SCy Schubert 				       broadcast,
9185732ac8SCy Schubert 				       wpabuf_head(auth->resp_msg),
9285732ac8SCy Schubert 				       wpabuf_len(auth->resp_msg),
9385732ac8SCy Schubert 				       500, wpas_dpp_tx_status, 0);
9485732ac8SCy Schubert 	}
9585732ac8SCy Schubert 
96c1d255d3SCy Schubert #ifdef CONFIG_DPP2
97c1d255d3SCy Schubert 	dpp_controller_new_qr_code(wpa_s->dpp, bi);
98c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
99c1d255d3SCy Schubert 
10085732ac8SCy Schubert 	return bi->id;
10185732ac8SCy Schubert }
10285732ac8SCy Schubert 
10385732ac8SCy Schubert 
104c1d255d3SCy Schubert /**
105c1d255d3SCy Schubert  * wpas_dpp_nfc_uri - Parse and add DPP bootstrapping info from NFC Tag (URI)
106c1d255d3SCy Schubert  * @wpa_s: Pointer to wpa_supplicant data
107c1d255d3SCy Schubert  * @cmd: DPP URI read from a NFC Tag (URI NDEF message)
108c1d255d3SCy Schubert  * Returns: Identifier of the stored info or -1 on failure
109c1d255d3SCy Schubert  */
110c1d255d3SCy Schubert int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd)
111c1d255d3SCy Schubert {
112c1d255d3SCy Schubert 	struct dpp_bootstrap_info *bi;
113c1d255d3SCy Schubert 
114c1d255d3SCy Schubert 	bi = dpp_add_nfc_uri(wpa_s->dpp, cmd);
115c1d255d3SCy Schubert 	if (!bi)
116c1d255d3SCy Schubert 		return -1;
117c1d255d3SCy Schubert 
118c1d255d3SCy Schubert 	return bi->id;
119c1d255d3SCy Schubert }
120c1d255d3SCy Schubert 
121c1d255d3SCy Schubert 
122c1d255d3SCy Schubert int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd)
123c1d255d3SCy Schubert {
124c1d255d3SCy Schubert 	const char *pos;
125c1d255d3SCy Schubert 	struct dpp_bootstrap_info *peer_bi, *own_bi;
126c1d255d3SCy Schubert 
127c1d255d3SCy Schubert 	pos = os_strstr(cmd, " own=");
128c1d255d3SCy Schubert 	if (!pos)
129c1d255d3SCy Schubert 		return -1;
130c1d255d3SCy Schubert 	pos += 5;
131c1d255d3SCy Schubert 	own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
132c1d255d3SCy Schubert 	if (!own_bi)
133c1d255d3SCy Schubert 		return -1;
134c1d255d3SCy Schubert 	own_bi->nfc_negotiated = 1;
135c1d255d3SCy Schubert 
136c1d255d3SCy Schubert 	pos = os_strstr(cmd, " uri=");
137c1d255d3SCy Schubert 	if (!pos)
138c1d255d3SCy Schubert 		return -1;
139c1d255d3SCy Schubert 	pos += 5;
140c1d255d3SCy Schubert 	peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
141c1d255d3SCy Schubert 	if (!peer_bi) {
142c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
143c1d255d3SCy Schubert 			   "DPP: Failed to parse URI from NFC Handover Request");
144c1d255d3SCy Schubert 		return -1;
145c1d255d3SCy Schubert 	}
146c1d255d3SCy Schubert 
147c1d255d3SCy Schubert 	if (dpp_nfc_update_bi(own_bi, peer_bi) < 0)
148c1d255d3SCy Schubert 		return -1;
149c1d255d3SCy Schubert 
150c1d255d3SCy Schubert 	return peer_bi->id;
151c1d255d3SCy Schubert }
152c1d255d3SCy Schubert 
153c1d255d3SCy Schubert 
154c1d255d3SCy Schubert int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd)
155c1d255d3SCy Schubert {
156c1d255d3SCy Schubert 	const char *pos;
157c1d255d3SCy Schubert 	struct dpp_bootstrap_info *peer_bi, *own_bi;
158c1d255d3SCy Schubert 
159c1d255d3SCy Schubert 	pos = os_strstr(cmd, " own=");
160c1d255d3SCy Schubert 	if (!pos)
161c1d255d3SCy Schubert 		return -1;
162c1d255d3SCy Schubert 	pos += 5;
163c1d255d3SCy Schubert 	own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
164c1d255d3SCy Schubert 	if (!own_bi)
165c1d255d3SCy Schubert 		return -1;
166c1d255d3SCy Schubert 	own_bi->nfc_negotiated = 1;
167c1d255d3SCy Schubert 
168c1d255d3SCy Schubert 	pos = os_strstr(cmd, " uri=");
169c1d255d3SCy Schubert 	if (!pos)
170c1d255d3SCy Schubert 		return -1;
171c1d255d3SCy Schubert 	pos += 5;
172c1d255d3SCy Schubert 	peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
173c1d255d3SCy Schubert 	if (!peer_bi) {
174c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
175c1d255d3SCy Schubert 			   "DPP: Failed to parse URI from NFC Handover Select");
176c1d255d3SCy Schubert 		return -1;
177c1d255d3SCy Schubert 	}
178c1d255d3SCy Schubert 
179c1d255d3SCy Schubert 	if (peer_bi->curve != own_bi->curve) {
180c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
181c1d255d3SCy Schubert 			   "DPP: Peer (NFC Handover Selector) used different curve");
182c1d255d3SCy Schubert 		return -1;
183c1d255d3SCy Schubert 	}
184c1d255d3SCy Schubert 
185c1d255d3SCy Schubert 	return peer_bi->id;
186c1d255d3SCy Schubert }
187c1d255d3SCy Schubert 
188c1d255d3SCy Schubert 
18985732ac8SCy Schubert static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
19085732ac8SCy Schubert {
19185732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
19285732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
19385732ac8SCy Schubert 
19485732ac8SCy Schubert 	if (!auth || !auth->resp_msg)
19585732ac8SCy Schubert 		return;
19685732ac8SCy Schubert 
19785732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
19885732ac8SCy Schubert 		   "DPP: Retry Authentication Response after timeout");
19985732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
20085732ac8SCy Schubert 		" freq=%u type=%d",
20185732ac8SCy Schubert 		MAC2STR(auth->peer_mac_addr), auth->curr_freq,
20285732ac8SCy Schubert 		DPP_PA_AUTHENTICATION_RESP);
20385732ac8SCy Schubert 	offchannel_send_action(wpa_s, auth->curr_freq, auth->peer_mac_addr,
20485732ac8SCy Schubert 			       wpa_s->own_addr, broadcast,
20585732ac8SCy Schubert 			       wpabuf_head(auth->resp_msg),
20685732ac8SCy Schubert 			       wpabuf_len(auth->resp_msg),
20785732ac8SCy Schubert 			       500, wpas_dpp_tx_status, 0);
20885732ac8SCy Schubert }
20985732ac8SCy Schubert 
21085732ac8SCy Schubert 
21185732ac8SCy Schubert static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s)
21285732ac8SCy Schubert {
21385732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
21485732ac8SCy Schubert 	unsigned int wait_time, max_tries;
21585732ac8SCy Schubert 
21685732ac8SCy Schubert 	if (!auth || !auth->resp_msg)
21785732ac8SCy Schubert 		return;
21885732ac8SCy Schubert 
21985732ac8SCy Schubert 	if (wpa_s->dpp_resp_max_tries)
22085732ac8SCy Schubert 		max_tries = wpa_s->dpp_resp_max_tries;
22185732ac8SCy Schubert 	else
22285732ac8SCy Schubert 		max_tries = 5;
22385732ac8SCy Schubert 	auth->auth_resp_tries++;
22485732ac8SCy Schubert 	if (auth->auth_resp_tries >= max_tries) {
22585732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: No confirm received from initiator - stopping exchange");
22685732ac8SCy Schubert 		offchannel_send_action_done(wpa_s);
22785732ac8SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
22885732ac8SCy Schubert 		wpa_s->dpp_auth = NULL;
22985732ac8SCy Schubert 		return;
23085732ac8SCy Schubert 	}
23185732ac8SCy Schubert 
23285732ac8SCy Schubert 	if (wpa_s->dpp_resp_retry_time)
23385732ac8SCy Schubert 		wait_time = wpa_s->dpp_resp_retry_time;
23485732ac8SCy Schubert 	else
23585732ac8SCy Schubert 		wait_time = 1000;
23685732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
23785732ac8SCy Schubert 		   "DPP: Schedule retransmission of Authentication Response frame in %u ms",
23885732ac8SCy Schubert 		wait_time);
23985732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
24085732ac8SCy Schubert 	eloop_register_timeout(wait_time / 1000,
24185732ac8SCy Schubert 			       (wait_time % 1000) * 1000,
24285732ac8SCy Schubert 			       wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
24385732ac8SCy Schubert }
24485732ac8SCy Schubert 
24585732ac8SCy Schubert 
2464bc52338SCy Schubert static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
2474bc52338SCy Schubert {
2484bc52338SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
249c1d255d3SCy Schubert 	wpa_s->suitable_network = 0;
250c1d255d3SCy Schubert 	wpa_s->no_suitable_network = 0;
2514bc52338SCy Schubert 	wpa_s->disconnected = 0;
2524bc52338SCy Schubert 	wpa_s->reassociate = 1;
2534bc52338SCy Schubert 	wpa_s->scan_runs = 0;
2544bc52338SCy Schubert 	wpa_s->normal_scans = 0;
2554bc52338SCy Schubert 	wpa_supplicant_cancel_sched_scan(wpa_s);
2564bc52338SCy Schubert 	wpa_supplicant_req_scan(wpa_s, 0, 0);
2574bc52338SCy Schubert }
2584bc52338SCy Schubert 
2594bc52338SCy Schubert 
260c1d255d3SCy Schubert #ifdef CONFIG_DPP2
261c1d255d3SCy Schubert 
262c1d255d3SCy Schubert static void wpas_dpp_stop_listen_for_tx(struct wpa_supplicant *wpa_s,
263c1d255d3SCy Schubert 					unsigned int freq,
264c1d255d3SCy Schubert 					unsigned int wait_time)
265c1d255d3SCy Schubert {
266c1d255d3SCy Schubert 	struct os_reltime now, res;
267c1d255d3SCy Schubert 	unsigned int remaining;
268c1d255d3SCy Schubert 
269c1d255d3SCy Schubert 	if (!wpa_s->dpp_listen_freq)
270c1d255d3SCy Schubert 		return;
271c1d255d3SCy Schubert 
272c1d255d3SCy Schubert 	os_get_reltime(&now);
273c1d255d3SCy Schubert 	if (os_reltime_before(&now, &wpa_s->dpp_listen_end)) {
274c1d255d3SCy Schubert 		os_reltime_sub(&wpa_s->dpp_listen_end, &now, &res);
275c1d255d3SCy Schubert 		remaining = res.sec * 1000 + res.usec / 1000;
276c1d255d3SCy Schubert 	} else {
277c1d255d3SCy Schubert 		remaining = 0;
278c1d255d3SCy Schubert 	}
279c1d255d3SCy Schubert 	if (wpa_s->dpp_listen_freq == freq && remaining > wait_time)
280c1d255d3SCy Schubert 		return;
281c1d255d3SCy Schubert 
282c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG,
283c1d255d3SCy Schubert 		   "DPP: Stop listen on %u MHz ending in %u ms to allow immediate TX on %u MHz for %u ms",
284c1d255d3SCy Schubert 		   wpa_s->dpp_listen_freq, remaining, freq, wait_time);
285c1d255d3SCy Schubert 	wpas_dpp_listen_stop(wpa_s);
286c1d255d3SCy Schubert 
287c1d255d3SCy Schubert 	/* TODO: Restart listen in some cases after TX? */
288c1d255d3SCy Schubert }
289c1d255d3SCy Schubert 
290c1d255d3SCy Schubert 
291c1d255d3SCy Schubert static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx,
292c1d255d3SCy Schubert 						void *timeout_ctx)
293c1d255d3SCy Schubert {
294c1d255d3SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
295c1d255d3SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
296c1d255d3SCy Schubert 	enum dpp_status_error result;
297c1d255d3SCy Schubert 
298c1d255d3SCy Schubert 	if (!auth || !auth->conn_status_requested)
299c1d255d3SCy Schubert 		return;
300c1d255d3SCy Schubert 
301c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG,
302c1d255d3SCy Schubert 		   "DPP: Connection timeout - report Connection Status Result");
303c1d255d3SCy Schubert 	if (wpa_s->suitable_network)
304c1d255d3SCy Schubert 		result = DPP_STATUS_AUTH_FAILURE;
305c1d255d3SCy Schubert 	else if (wpa_s->no_suitable_network)
306c1d255d3SCy Schubert 		result = DPP_STATUS_NO_AP;
307c1d255d3SCy Schubert 	else
308c1d255d3SCy Schubert 		result = 255; /* What to report here for unexpected state? */
309c1d255d3SCy Schubert 	if (wpa_s->wpa_state == WPA_SCANNING)
310c1d255d3SCy Schubert 		wpas_abort_ongoing_scan(wpa_s);
311c1d255d3SCy Schubert 	wpas_dpp_send_conn_status_result(wpa_s, result);
312c1d255d3SCy Schubert }
313c1d255d3SCy Schubert 
314c1d255d3SCy Schubert 
315c1d255d3SCy Schubert static char * wpas_dpp_scan_channel_list(struct wpa_supplicant *wpa_s)
316c1d255d3SCy Schubert {
317c1d255d3SCy Schubert 	char *str, *end, *pos;
318c1d255d3SCy Schubert 	size_t len;
319c1d255d3SCy Schubert 	unsigned int i;
320c1d255d3SCy Schubert 	u8 last_op_class = 0;
321c1d255d3SCy Schubert 	int res;
322c1d255d3SCy Schubert 
323c1d255d3SCy Schubert 	if (!wpa_s->last_scan_freqs || !wpa_s->num_last_scan_freqs)
324c1d255d3SCy Schubert 		return NULL;
325c1d255d3SCy Schubert 
326c1d255d3SCy Schubert 	len = wpa_s->num_last_scan_freqs * 8;
327c1d255d3SCy Schubert 	str = os_zalloc(len);
328c1d255d3SCy Schubert 	if (!str)
329c1d255d3SCy Schubert 		return NULL;
330c1d255d3SCy Schubert 	end = str + len;
331c1d255d3SCy Schubert 	pos = str;
332c1d255d3SCy Schubert 
333c1d255d3SCy Schubert 	for (i = 0; i < wpa_s->num_last_scan_freqs; i++) {
334c1d255d3SCy Schubert 		enum hostapd_hw_mode mode;
335c1d255d3SCy Schubert 		u8 op_class, channel;
336c1d255d3SCy Schubert 
337c1d255d3SCy Schubert 		mode = ieee80211_freq_to_channel_ext(wpa_s->last_scan_freqs[i],
338c1d255d3SCy Schubert 						     0, 0, &op_class, &channel);
339c1d255d3SCy Schubert 		if (mode == NUM_HOSTAPD_MODES)
340c1d255d3SCy Schubert 			continue;
341c1d255d3SCy Schubert 		if (op_class == last_op_class)
342c1d255d3SCy Schubert 			res = os_snprintf(pos, end - pos, ",%d", channel);
343c1d255d3SCy Schubert 		else
344c1d255d3SCy Schubert 			res = os_snprintf(pos, end - pos, "%s%d/%d",
345c1d255d3SCy Schubert 					  pos == str ? "" : ",",
346c1d255d3SCy Schubert 					  op_class, channel);
347c1d255d3SCy Schubert 		if (os_snprintf_error(end - pos, res)) {
348c1d255d3SCy Schubert 			*pos = '\0';
349c1d255d3SCy Schubert 			break;
350c1d255d3SCy Schubert 		}
351c1d255d3SCy Schubert 		pos += res;
352c1d255d3SCy Schubert 		last_op_class = op_class;
353c1d255d3SCy Schubert 	}
354c1d255d3SCy Schubert 
355c1d255d3SCy Schubert 	if (pos == str) {
356c1d255d3SCy Schubert 		os_free(str);
357c1d255d3SCy Schubert 		str = NULL;
358c1d255d3SCy Schubert 	}
359c1d255d3SCy Schubert 	return str;
360c1d255d3SCy Schubert }
361c1d255d3SCy Schubert 
362c1d255d3SCy Schubert 
363c1d255d3SCy Schubert void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
364c1d255d3SCy Schubert 				      enum dpp_status_error result)
365c1d255d3SCy Schubert {
366c1d255d3SCy Schubert 	struct wpabuf *msg;
367c1d255d3SCy Schubert 	const char *channel_list = NULL;
368c1d255d3SCy Schubert 	char *channel_list_buf = NULL;
369c1d255d3SCy Schubert 	struct wpa_ssid *ssid = wpa_s->current_ssid;
370c1d255d3SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
371c1d255d3SCy Schubert 
372c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
373c1d255d3SCy Schubert 
374c1d255d3SCy Schubert 	if (!auth || !auth->conn_status_requested)
375c1d255d3SCy Schubert 		return;
376c1d255d3SCy Schubert 	auth->conn_status_requested = 0;
377c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Report connection status result %d",
378c1d255d3SCy Schubert 		   result);
379c1d255d3SCy Schubert 
380c1d255d3SCy Schubert 	if (result == DPP_STATUS_NO_AP) {
381c1d255d3SCy Schubert 		channel_list_buf = wpas_dpp_scan_channel_list(wpa_s);
382c1d255d3SCy Schubert 		channel_list = channel_list_buf;
383c1d255d3SCy Schubert 	}
384c1d255d3SCy Schubert 
385c1d255d3SCy Schubert 	msg = dpp_build_conn_status_result(auth, result,
386c1d255d3SCy Schubert 					   ssid ? ssid->ssid :
387c1d255d3SCy Schubert 					   wpa_s->dpp_last_ssid,
388c1d255d3SCy Schubert 					   ssid ? ssid->ssid_len :
389c1d255d3SCy Schubert 					   wpa_s->dpp_last_ssid_len,
390c1d255d3SCy Schubert 					   channel_list);
391c1d255d3SCy Schubert 	os_free(channel_list_buf);
392c1d255d3SCy Schubert 	if (!msg) {
393c1d255d3SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
394c1d255d3SCy Schubert 		wpa_s->dpp_auth = NULL;
395c1d255d3SCy Schubert 		return;
396c1d255d3SCy Schubert 	}
397c1d255d3SCy Schubert 
398c1d255d3SCy Schubert 	wpa_msg(wpa_s, MSG_INFO,
399c1d255d3SCy Schubert 		DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
400c1d255d3SCy Schubert 		MAC2STR(auth->peer_mac_addr), auth->curr_freq,
401c1d255d3SCy Schubert 		DPP_PA_CONNECTION_STATUS_RESULT);
402c1d255d3SCy Schubert 	offchannel_send_action(wpa_s, auth->curr_freq,
403c1d255d3SCy Schubert 			       auth->peer_mac_addr, wpa_s->own_addr, broadcast,
404c1d255d3SCy Schubert 			       wpabuf_head(msg), wpabuf_len(msg),
405c1d255d3SCy Schubert 			       500, wpas_dpp_tx_status, 0);
406c1d255d3SCy Schubert 	wpabuf_free(msg);
407c1d255d3SCy Schubert 
408c1d255d3SCy Schubert 	/* This exchange will be terminated in the TX status handler */
409c1d255d3SCy Schubert 	auth->remove_on_tx_status = 1;
410c1d255d3SCy Schubert 
411c1d255d3SCy Schubert 	return;
412c1d255d3SCy Schubert }
413c1d255d3SCy Schubert 
414c1d255d3SCy Schubert 
415c1d255d3SCy Schubert void wpas_dpp_connected(struct wpa_supplicant *wpa_s)
416c1d255d3SCy Schubert {
417c1d255d3SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
418c1d255d3SCy Schubert 
419c1d255d3SCy Schubert 	if (auth && auth->conn_status_requested)
420c1d255d3SCy Schubert 		wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_OK);
421c1d255d3SCy Schubert }
422c1d255d3SCy Schubert 
423c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
424c1d255d3SCy Schubert 
425c1d255d3SCy Schubert 
42685732ac8SCy Schubert static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
42785732ac8SCy Schubert 			       unsigned int freq, const u8 *dst,
42885732ac8SCy Schubert 			       const u8 *src, const u8 *bssid,
42985732ac8SCy Schubert 			       const u8 *data, size_t data_len,
43085732ac8SCy Schubert 			       enum offchannel_send_action_result result)
43185732ac8SCy Schubert {
43285732ac8SCy Schubert 	const char *res_txt;
43385732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
43485732ac8SCy Schubert 
43585732ac8SCy Schubert 	res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
43685732ac8SCy Schubert 		(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
43785732ac8SCy Schubert 		 "FAILED");
43885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
43985732ac8SCy Schubert 		   " result=%s", freq, MAC2STR(dst), res_txt);
44085732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
44185732ac8SCy Schubert 		" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
44285732ac8SCy Schubert 
44385732ac8SCy Schubert 	if (!wpa_s->dpp_auth) {
44485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
44585732ac8SCy Schubert 			   "DPP: Ignore TX status since there is no ongoing authentication exchange");
44685732ac8SCy Schubert 		return;
44785732ac8SCy Schubert 	}
44885732ac8SCy Schubert 
4494bc52338SCy Schubert #ifdef CONFIG_DPP2
4504bc52338SCy Schubert 	if (auth->connect_on_tx_status) {
451c1d255d3SCy Schubert 		auth->connect_on_tx_status = 0;
4524bc52338SCy Schubert 		wpa_printf(MSG_DEBUG,
4534bc52338SCy Schubert 			   "DPP: Try to connect after completed configuration result");
4544bc52338SCy Schubert 		wpas_dpp_try_to_connect(wpa_s);
455c1d255d3SCy Schubert 		if (auth->conn_status_requested) {
456c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
457c1d255d3SCy Schubert 				   "DPP: Start 15 second timeout for reporting connection status result");
458c1d255d3SCy Schubert 			eloop_cancel_timeout(
459c1d255d3SCy Schubert 				wpas_dpp_conn_status_result_timeout,
460c1d255d3SCy Schubert 				wpa_s, NULL);
461c1d255d3SCy Schubert 			eloop_register_timeout(
462c1d255d3SCy Schubert 				15, 0, wpas_dpp_conn_status_result_timeout,
463c1d255d3SCy Schubert 				wpa_s, NULL);
464c1d255d3SCy Schubert 		} else {
4654bc52338SCy Schubert 			dpp_auth_deinit(wpa_s->dpp_auth);
4664bc52338SCy Schubert 			wpa_s->dpp_auth = NULL;
467c1d255d3SCy Schubert 		}
4684bc52338SCy Schubert 		return;
4694bc52338SCy Schubert 	}
4704bc52338SCy Schubert #endif /* CONFIG_DPP2 */
4714bc52338SCy Schubert 
47285732ac8SCy Schubert 	if (wpa_s->dpp_auth->remove_on_tx_status) {
47385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
474c1d255d3SCy Schubert 			   "DPP: Terminate authentication exchange due to a request to do so on TX status");
47585732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
47685732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
477c1d255d3SCy Schubert 		eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s,
478c1d255d3SCy Schubert 				     NULL);
47985732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
48085732ac8SCy Schubert 				     NULL);
481c1d255d3SCy Schubert #ifdef CONFIG_DPP2
482c1d255d3SCy Schubert 		eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
483c1d255d3SCy Schubert 				     wpa_s, NULL);
484c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
48585732ac8SCy Schubert 		offchannel_send_action_done(wpa_s);
48685732ac8SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
48785732ac8SCy Schubert 		wpa_s->dpp_auth = NULL;
48885732ac8SCy Schubert 		return;
48985732ac8SCy Schubert 	}
49085732ac8SCy Schubert 
49185732ac8SCy Schubert 	if (wpa_s->dpp_auth_ok_on_ack)
49285732ac8SCy Schubert 		wpas_dpp_auth_success(wpa_s, 1);
49385732ac8SCy Schubert 
49485732ac8SCy Schubert 	if (!is_broadcast_ether_addr(dst) &&
49585732ac8SCy Schubert 	    result != OFFCHANNEL_SEND_ACTION_SUCCESS) {
49685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
49785732ac8SCy Schubert 			   "DPP: Unicast DPP Action frame was not ACKed");
49885732ac8SCy Schubert 		if (auth->waiting_auth_resp) {
49985732ac8SCy Schubert 			/* In case of DPP Authentication Request frame, move to
50085732ac8SCy Schubert 			 * the next channel immediately. */
50185732ac8SCy Schubert 			offchannel_send_action_done(wpa_s);
50285732ac8SCy Schubert 			wpas_dpp_auth_init_next(wpa_s);
50385732ac8SCy Schubert 			return;
50485732ac8SCy Schubert 		}
50585732ac8SCy Schubert 		if (auth->waiting_auth_conf) {
50685732ac8SCy Schubert 			wpas_dpp_auth_resp_retry(wpa_s);
50785732ac8SCy Schubert 			return;
50885732ac8SCy Schubert 		}
50985732ac8SCy Schubert 	}
51085732ac8SCy Schubert 
511c1d255d3SCy Schubert 	if (auth->waiting_auth_conf &&
512c1d255d3SCy Schubert 	    auth->auth_resp_status == DPP_STATUS_OK) {
513c1d255d3SCy Schubert 		/* Make sure we do not get stuck waiting for Auth Confirm
514c1d255d3SCy Schubert 		 * indefinitely after successfully transmitted Auth Response to
515c1d255d3SCy Schubert 		 * allow new authentication exchanges to be started. */
516c1d255d3SCy Schubert 		eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s,
517c1d255d3SCy Schubert 				     NULL);
518c1d255d3SCy Schubert 		eloop_register_timeout(1, 0, wpas_dpp_auth_conf_wait_timeout,
519c1d255d3SCy Schubert 				       wpa_s, NULL);
520c1d255d3SCy Schubert 	}
521c1d255d3SCy Schubert 
52285732ac8SCy Schubert 	if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp &&
52385732ac8SCy Schubert 	    result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
52485732ac8SCy Schubert 		/* Allow timeout handling to stop iteration if no response is
52585732ac8SCy Schubert 		 * received from a peer that has ACKed a request. */
52685732ac8SCy Schubert 		auth->auth_req_ack = 1;
52785732ac8SCy Schubert 	}
52885732ac8SCy Schubert 
52985732ac8SCy Schubert 	if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 &&
53085732ac8SCy Schubert 	    wpa_s->dpp_auth->curr_freq != wpa_s->dpp_auth->neg_freq) {
53185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
53285732ac8SCy Schubert 			   "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
53385732ac8SCy Schubert 			   wpa_s->dpp_auth->curr_freq,
53485732ac8SCy Schubert 			   wpa_s->dpp_auth->neg_freq);
53585732ac8SCy Schubert 		offchannel_send_action_done(wpa_s);
53685732ac8SCy Schubert 		wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->neg_freq);
53785732ac8SCy Schubert 	}
53885732ac8SCy Schubert 
53985732ac8SCy Schubert 	if (wpa_s->dpp_auth_ok_on_ack)
54085732ac8SCy Schubert 		wpa_s->dpp_auth_ok_on_ack = 0;
54185732ac8SCy Schubert }
54285732ac8SCy Schubert 
54385732ac8SCy Schubert 
54485732ac8SCy Schubert static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
54585732ac8SCy Schubert {
54685732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
54785732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
54885732ac8SCy Schubert 	unsigned int freq;
54985732ac8SCy Schubert 	struct os_reltime now, diff;
55085732ac8SCy Schubert 	unsigned int wait_time, diff_ms;
55185732ac8SCy Schubert 
55285732ac8SCy Schubert 	if (!auth || !auth->waiting_auth_resp)
55385732ac8SCy Schubert 		return;
55485732ac8SCy Schubert 
55585732ac8SCy Schubert 	wait_time = wpa_s->dpp_resp_wait_time ?
55685732ac8SCy Schubert 		wpa_s->dpp_resp_wait_time : 2000;
55785732ac8SCy Schubert 	os_get_reltime(&now);
55885732ac8SCy Schubert 	os_reltime_sub(&now, &wpa_s->dpp_last_init, &diff);
55985732ac8SCy Schubert 	diff_ms = diff.sec * 1000 + diff.usec / 1000;
56085732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
56185732ac8SCy Schubert 		   "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
56285732ac8SCy Schubert 		   wait_time, diff_ms);
56385732ac8SCy Schubert 
56485732ac8SCy Schubert 	if (auth->auth_req_ack && diff_ms >= wait_time) {
56585732ac8SCy Schubert 		/* Peer ACK'ed Authentication Request frame, but did not reply
56685732ac8SCy Schubert 		 * with Authentication Response frame within two seconds. */
56785732ac8SCy Schubert 		wpa_printf(MSG_INFO,
56885732ac8SCy Schubert 			   "DPP: No response received from responder - stopping initiation attempt");
56985732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
57085732ac8SCy Schubert 		offchannel_send_action_done(wpa_s);
57185732ac8SCy Schubert 		wpas_dpp_listen_stop(wpa_s);
57285732ac8SCy Schubert 		dpp_auth_deinit(auth);
57385732ac8SCy Schubert 		wpa_s->dpp_auth = NULL;
57485732ac8SCy Schubert 		return;
57585732ac8SCy Schubert 	}
57685732ac8SCy Schubert 
57785732ac8SCy Schubert 	if (diff_ms >= wait_time) {
57885732ac8SCy Schubert 		/* Authentication Request frame was not ACK'ed and no reply
57985732ac8SCy Schubert 		 * was receiving within two seconds. */
58085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
58185732ac8SCy Schubert 			   "DPP: Continue Initiator channel iteration");
58285732ac8SCy Schubert 		offchannel_send_action_done(wpa_s);
58385732ac8SCy Schubert 		wpas_dpp_listen_stop(wpa_s);
58485732ac8SCy Schubert 		wpas_dpp_auth_init_next(wpa_s);
58585732ac8SCy Schubert 		return;
58685732ac8SCy Schubert 	}
58785732ac8SCy Schubert 
58885732ac8SCy Schubert 	/* Driver did not support 2000 ms long wait_time with TX command, so
58985732ac8SCy Schubert 	 * schedule listen operation to continue waiting for the response.
59085732ac8SCy Schubert 	 *
59185732ac8SCy Schubert 	 * DPP listen operations continue until stopped, so simply schedule a
59285732ac8SCy Schubert 	 * new call to this function at the point when the two second reply
59385732ac8SCy Schubert 	 * wait has expired. */
59485732ac8SCy Schubert 	wait_time -= diff_ms;
59585732ac8SCy Schubert 
59685732ac8SCy Schubert 	freq = auth->curr_freq;
59785732ac8SCy Schubert 	if (auth->neg_freq > 0)
59885732ac8SCy Schubert 		freq = auth->neg_freq;
59985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
60085732ac8SCy Schubert 		   "DPP: Continue reply wait on channel %u MHz for %u ms",
60185732ac8SCy Schubert 		   freq, wait_time);
60285732ac8SCy Schubert 	wpa_s->dpp_in_response_listen = 1;
60385732ac8SCy Schubert 	wpas_dpp_listen_start(wpa_s, freq);
60485732ac8SCy Schubert 
60585732ac8SCy Schubert 	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
60685732ac8SCy Schubert 			       wpas_dpp_reply_wait_timeout, wpa_s, NULL);
60785732ac8SCy Schubert }
60885732ac8SCy Schubert 
60985732ac8SCy Schubert 
610c1d255d3SCy Schubert static void wpas_dpp_auth_conf_wait_timeout(void *eloop_ctx, void *timeout_ctx)
611c1d255d3SCy Schubert {
612c1d255d3SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
613c1d255d3SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
614c1d255d3SCy Schubert 
615c1d255d3SCy Schubert 	if (!auth || !auth->waiting_auth_conf)
616c1d255d3SCy Schubert 		return;
617c1d255d3SCy Schubert 
618c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG,
619c1d255d3SCy Schubert 		   "DPP: Terminate authentication exchange due to Auth Confirm timeout");
620c1d255d3SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL "No Auth Confirm received");
621c1d255d3SCy Schubert 	offchannel_send_action_done(wpa_s);
622c1d255d3SCy Schubert 	dpp_auth_deinit(auth);
623c1d255d3SCy Schubert 	wpa_s->dpp_auth = NULL;
624c1d255d3SCy Schubert }
625c1d255d3SCy Schubert 
626c1d255d3SCy Schubert 
62785732ac8SCy Schubert static void wpas_dpp_set_testing_options(struct wpa_supplicant *wpa_s,
62885732ac8SCy Schubert 					 struct dpp_authentication *auth)
62985732ac8SCy Schubert {
63085732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
63185732ac8SCy Schubert 	if (wpa_s->dpp_config_obj_override)
63285732ac8SCy Schubert 		auth->config_obj_override =
63385732ac8SCy Schubert 			os_strdup(wpa_s->dpp_config_obj_override);
63485732ac8SCy Schubert 	if (wpa_s->dpp_discovery_override)
63585732ac8SCy Schubert 		auth->discovery_override =
63685732ac8SCy Schubert 			os_strdup(wpa_s->dpp_discovery_override);
63785732ac8SCy Schubert 	if (wpa_s->dpp_groups_override)
63885732ac8SCy Schubert 		auth->groups_override =
63985732ac8SCy Schubert 			os_strdup(wpa_s->dpp_groups_override);
64085732ac8SCy Schubert 	auth->ignore_netaccesskey_mismatch =
64185732ac8SCy Schubert 		wpa_s->dpp_ignore_netaccesskey_mismatch;
64285732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
64385732ac8SCy Schubert }
64485732ac8SCy Schubert 
64585732ac8SCy Schubert 
64685732ac8SCy Schubert static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
64785732ac8SCy Schubert {
64885732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
64985732ac8SCy Schubert 
65085732ac8SCy Schubert 	if (!wpa_s->dpp_auth)
65185732ac8SCy Schubert 		return;
65285732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
65385732ac8SCy Schubert 	wpas_dpp_auth_init_next(wpa_s);
65485732ac8SCy Schubert }
65585732ac8SCy Schubert 
65685732ac8SCy Schubert 
65785732ac8SCy Schubert static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s)
65885732ac8SCy Schubert {
65985732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
66085732ac8SCy Schubert 	const u8 *dst;
66185732ac8SCy Schubert 	unsigned int wait_time, max_wait_time, freq, max_tries, used;
66285732ac8SCy Schubert 	struct os_reltime now, diff;
66385732ac8SCy Schubert 
66485732ac8SCy Schubert 	wpa_s->dpp_in_response_listen = 0;
66585732ac8SCy Schubert 	if (!auth)
66685732ac8SCy Schubert 		return -1;
66785732ac8SCy Schubert 
66885732ac8SCy Schubert 	if (auth->freq_idx == 0)
66985732ac8SCy Schubert 		os_get_reltime(&wpa_s->dpp_init_iter_start);
67085732ac8SCy Schubert 
67185732ac8SCy Schubert 	if (auth->freq_idx >= auth->num_freq) {
67285732ac8SCy Schubert 		auth->num_freq_iters++;
67385732ac8SCy Schubert 		if (wpa_s->dpp_init_max_tries)
67485732ac8SCy Schubert 			max_tries = wpa_s->dpp_init_max_tries;
67585732ac8SCy Schubert 		else
67685732ac8SCy Schubert 			max_tries = 5;
67785732ac8SCy Schubert 		if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
67885732ac8SCy Schubert 			wpa_printf(MSG_INFO,
67985732ac8SCy Schubert 				   "DPP: No response received from responder - stopping initiation attempt");
68085732ac8SCy Schubert 			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
68185732ac8SCy Schubert 			eloop_cancel_timeout(wpas_dpp_reply_wait_timeout,
68285732ac8SCy Schubert 					     wpa_s, NULL);
68385732ac8SCy Schubert 			offchannel_send_action_done(wpa_s);
68485732ac8SCy Schubert 			dpp_auth_deinit(wpa_s->dpp_auth);
68585732ac8SCy Schubert 			wpa_s->dpp_auth = NULL;
68685732ac8SCy Schubert 			return -1;
68785732ac8SCy Schubert 		}
68885732ac8SCy Schubert 		auth->freq_idx = 0;
68985732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
69085732ac8SCy Schubert 		if (wpa_s->dpp_init_retry_time)
69185732ac8SCy Schubert 			wait_time = wpa_s->dpp_init_retry_time;
69285732ac8SCy Schubert 		else
69385732ac8SCy Schubert 			wait_time = 10000;
69485732ac8SCy Schubert 		os_get_reltime(&now);
69585732ac8SCy Schubert 		os_reltime_sub(&now, &wpa_s->dpp_init_iter_start, &diff);
69685732ac8SCy Schubert 		used = diff.sec * 1000 + diff.usec / 1000;
69785732ac8SCy Schubert 		if (used > wait_time)
69885732ac8SCy Schubert 			wait_time = 0;
69985732ac8SCy Schubert 		else
70085732ac8SCy Schubert 			wait_time -= used;
70185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
70285732ac8SCy Schubert 			   wait_time);
70385732ac8SCy Schubert 		eloop_register_timeout(wait_time / 1000,
70485732ac8SCy Schubert 				       (wait_time % 1000) * 1000,
70585732ac8SCy Schubert 				       wpas_dpp_init_timeout, wpa_s,
70685732ac8SCy Schubert 				       NULL);
70785732ac8SCy Schubert 		return 0;
70885732ac8SCy Schubert 	}
70985732ac8SCy Schubert 	freq = auth->freq[auth->freq_idx++];
71085732ac8SCy Schubert 	auth->curr_freq = freq;
71185732ac8SCy Schubert 
712c1d255d3SCy Schubert 	if (!is_zero_ether_addr(auth->peer_mac_addr))
713c1d255d3SCy Schubert 		dst = auth->peer_mac_addr;
714c1d255d3SCy Schubert 	else if (is_zero_ether_addr(auth->peer_bi->mac_addr))
71585732ac8SCy Schubert 		dst = broadcast;
71685732ac8SCy Schubert 	else
71785732ac8SCy Schubert 		dst = auth->peer_bi->mac_addr;
71885732ac8SCy Schubert 	wpa_s->dpp_auth_ok_on_ack = 0;
71985732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
72085732ac8SCy Schubert 	wait_time = wpa_s->max_remain_on_chan;
72185732ac8SCy Schubert 	max_wait_time = wpa_s->dpp_resp_wait_time ?
72285732ac8SCy Schubert 		wpa_s->dpp_resp_wait_time : 2000;
72385732ac8SCy Schubert 	if (wait_time > max_wait_time)
72485732ac8SCy Schubert 		wait_time = max_wait_time;
72585732ac8SCy Schubert 	wait_time += 10; /* give the driver some extra time to complete */
72685732ac8SCy Schubert 	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
72785732ac8SCy Schubert 			       wpas_dpp_reply_wait_timeout,
72885732ac8SCy Schubert 			       wpa_s, NULL);
72985732ac8SCy Schubert 	wait_time -= 10;
73085732ac8SCy Schubert 	if (auth->neg_freq > 0 && freq != auth->neg_freq) {
73185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
73285732ac8SCy Schubert 			   "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
73385732ac8SCy Schubert 			   freq, auth->neg_freq);
73485732ac8SCy Schubert 	}
73585732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
73685732ac8SCy Schubert 		MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
73785732ac8SCy Schubert 	auth->auth_req_ack = 0;
73885732ac8SCy Schubert 	os_get_reltime(&wpa_s->dpp_last_init);
73985732ac8SCy Schubert 	return offchannel_send_action(wpa_s, freq, dst,
74085732ac8SCy Schubert 				      wpa_s->own_addr, broadcast,
74185732ac8SCy Schubert 				      wpabuf_head(auth->req_msg),
74285732ac8SCy Schubert 				      wpabuf_len(auth->req_msg),
74385732ac8SCy Schubert 				      wait_time, wpas_dpp_tx_status, 0);
74485732ac8SCy Schubert }
74585732ac8SCy Schubert 
74685732ac8SCy Schubert 
74785732ac8SCy Schubert int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
74885732ac8SCy Schubert {
74985732ac8SCy Schubert 	const char *pos;
75085732ac8SCy Schubert 	struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
751206b73d0SCy Schubert 	struct dpp_authentication *auth;
75285732ac8SCy Schubert 	u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
75385732ac8SCy Schubert 	unsigned int neg_freq = 0;
754206b73d0SCy Schubert 	int tcp = 0;
755206b73d0SCy Schubert #ifdef CONFIG_DPP2
756206b73d0SCy Schubert 	int tcp_port = DPP_TCP_PORT;
757206b73d0SCy Schubert 	struct hostapd_ip_addr ipaddr;
758206b73d0SCy Schubert 	char *addr;
759206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
76085732ac8SCy Schubert 
76185732ac8SCy Schubert 	wpa_s->dpp_gas_client = 0;
76285732ac8SCy Schubert 
76385732ac8SCy Schubert 	pos = os_strstr(cmd, " peer=");
76485732ac8SCy Schubert 	if (!pos)
76585732ac8SCy Schubert 		return -1;
76685732ac8SCy Schubert 	pos += 6;
7674bc52338SCy Schubert 	peer_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
76885732ac8SCy Schubert 	if (!peer_bi) {
76985732ac8SCy Schubert 		wpa_printf(MSG_INFO,
77085732ac8SCy Schubert 			   "DPP: Could not find bootstrapping info for the identified peer");
77185732ac8SCy Schubert 		return -1;
77285732ac8SCy Schubert 	}
77385732ac8SCy Schubert 
774206b73d0SCy Schubert #ifdef CONFIG_DPP2
775206b73d0SCy Schubert 	pos = os_strstr(cmd, " tcp_port=");
776206b73d0SCy Schubert 	if (pos) {
777206b73d0SCy Schubert 		pos += 10;
778206b73d0SCy Schubert 		tcp_port = atoi(pos);
779206b73d0SCy Schubert 	}
780206b73d0SCy Schubert 
781206b73d0SCy Schubert 	addr = get_param(cmd, " tcp_addr=");
782206b73d0SCy Schubert 	if (addr) {
783206b73d0SCy Schubert 		int res;
784206b73d0SCy Schubert 
785206b73d0SCy Schubert 		res = hostapd_parse_ip_addr(addr, &ipaddr);
786206b73d0SCy Schubert 		os_free(addr);
787206b73d0SCy Schubert 		if (res)
788206b73d0SCy Schubert 			return -1;
789206b73d0SCy Schubert 		tcp = 1;
790206b73d0SCy Schubert 	}
791206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
792206b73d0SCy Schubert 
79385732ac8SCy Schubert 	pos = os_strstr(cmd, " own=");
79485732ac8SCy Schubert 	if (pos) {
79585732ac8SCy Schubert 		pos += 5;
7964bc52338SCy Schubert 		own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
79785732ac8SCy Schubert 		if (!own_bi) {
79885732ac8SCy Schubert 			wpa_printf(MSG_INFO,
79985732ac8SCy Schubert 				   "DPP: Could not find bootstrapping info for the identified local entry");
80085732ac8SCy Schubert 			return -1;
80185732ac8SCy Schubert 		}
80285732ac8SCy Schubert 
80385732ac8SCy Schubert 		if (peer_bi->curve != own_bi->curve) {
80485732ac8SCy Schubert 			wpa_printf(MSG_INFO,
80585732ac8SCy Schubert 				   "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
80685732ac8SCy Schubert 				   peer_bi->curve->name, own_bi->curve->name);
80785732ac8SCy Schubert 			return -1;
80885732ac8SCy Schubert 		}
80985732ac8SCy Schubert 	}
81085732ac8SCy Schubert 
81185732ac8SCy Schubert 	pos = os_strstr(cmd, " role=");
81285732ac8SCy Schubert 	if (pos) {
81385732ac8SCy Schubert 		pos += 6;
81485732ac8SCy Schubert 		if (os_strncmp(pos, "configurator", 12) == 0)
81585732ac8SCy Schubert 			allowed_roles = DPP_CAPAB_CONFIGURATOR;
81685732ac8SCy Schubert 		else if (os_strncmp(pos, "enrollee", 8) == 0)
81785732ac8SCy Schubert 			allowed_roles = DPP_CAPAB_ENROLLEE;
81885732ac8SCy Schubert 		else if (os_strncmp(pos, "either", 6) == 0)
81985732ac8SCy Schubert 			allowed_roles = DPP_CAPAB_CONFIGURATOR |
82085732ac8SCy Schubert 				DPP_CAPAB_ENROLLEE;
82185732ac8SCy Schubert 		else
82285732ac8SCy Schubert 			goto fail;
82385732ac8SCy Schubert 	}
82485732ac8SCy Schubert 
82585732ac8SCy Schubert 	pos = os_strstr(cmd, " netrole=");
82685732ac8SCy Schubert 	if (pos) {
82785732ac8SCy Schubert 		pos += 9;
828c1d255d3SCy Schubert 		if (os_strncmp(pos, "ap", 2) == 0)
829c1d255d3SCy Schubert 			wpa_s->dpp_netrole = DPP_NETROLE_AP;
830c1d255d3SCy Schubert 		else if (os_strncmp(pos, "configurator", 12) == 0)
831c1d255d3SCy Schubert 			wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
832c1d255d3SCy Schubert 		else
833c1d255d3SCy Schubert 			wpa_s->dpp_netrole = DPP_NETROLE_STA;
834c1d255d3SCy Schubert 	} else {
835c1d255d3SCy Schubert 		wpa_s->dpp_netrole = DPP_NETROLE_STA;
83685732ac8SCy Schubert 	}
83785732ac8SCy Schubert 
83885732ac8SCy Schubert 	pos = os_strstr(cmd, " neg_freq=");
83985732ac8SCy Schubert 	if (pos)
84085732ac8SCy Schubert 		neg_freq = atoi(pos + 10);
84185732ac8SCy Schubert 
842206b73d0SCy Schubert 	if (!tcp && wpa_s->dpp_auth) {
84385732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
84485732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
845c1d255d3SCy Schubert 		eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s,
846c1d255d3SCy Schubert 				     NULL);
84785732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
84885732ac8SCy Schubert 				     NULL);
849c1d255d3SCy Schubert #ifdef CONFIG_DPP2
850c1d255d3SCy Schubert 		eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
851c1d255d3SCy Schubert 				     wpa_s, NULL);
852c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
85385732ac8SCy Schubert 		offchannel_send_action_done(wpa_s);
85485732ac8SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
85585732ac8SCy Schubert 		wpa_s->dpp_auth = NULL;
856206b73d0SCy Schubert 	}
857206b73d0SCy Schubert 
858c1d255d3SCy Schubert 	auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, own_bi, allowed_roles,
859c1d255d3SCy Schubert 			     neg_freq, wpa_s->hw.modes, wpa_s->hw.num_modes);
860206b73d0SCy Schubert 	if (!auth)
861206b73d0SCy Schubert 		goto fail;
862206b73d0SCy Schubert 	wpas_dpp_set_testing_options(wpa_s, auth);
863c1d255d3SCy Schubert 	if (dpp_set_configurator(auth, cmd) < 0) {
864206b73d0SCy Schubert 		dpp_auth_deinit(auth);
86585732ac8SCy Schubert 		goto fail;
86685732ac8SCy Schubert 	}
86785732ac8SCy Schubert 
868206b73d0SCy Schubert 	auth->neg_freq = neg_freq;
86985732ac8SCy Schubert 
87085732ac8SCy Schubert 	if (!is_zero_ether_addr(peer_bi->mac_addr))
871206b73d0SCy Schubert 		os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
87285732ac8SCy Schubert 
873206b73d0SCy Schubert #ifdef CONFIG_DPP2
874206b73d0SCy Schubert 	if (tcp)
875c1d255d3SCy Schubert 		return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port,
876c1d255d3SCy Schubert 				    wpa_s->conf->dpp_name, DPP_NETROLE_STA,
877c1d255d3SCy Schubert 				    wpa_s, wpa_s, wpas_dpp_process_conf_obj);
878206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
879206b73d0SCy Schubert 
880206b73d0SCy Schubert 	wpa_s->dpp_auth = auth;
88185732ac8SCy Schubert 	return wpas_dpp_auth_init_next(wpa_s);
88285732ac8SCy Schubert fail:
88385732ac8SCy Schubert 	return -1;
88485732ac8SCy Schubert }
88585732ac8SCy Schubert 
88685732ac8SCy Schubert 
88785732ac8SCy Schubert struct wpas_dpp_listen_work {
88885732ac8SCy Schubert 	unsigned int freq;
88985732ac8SCy Schubert 	unsigned int duration;
89085732ac8SCy Schubert 	struct wpabuf *probe_resp_ie;
89185732ac8SCy Schubert };
89285732ac8SCy Schubert 
89385732ac8SCy Schubert 
89485732ac8SCy Schubert static void wpas_dpp_listen_work_free(struct wpas_dpp_listen_work *lwork)
89585732ac8SCy Schubert {
89685732ac8SCy Schubert 	if (!lwork)
89785732ac8SCy Schubert 		return;
89885732ac8SCy Schubert 	os_free(lwork);
89985732ac8SCy Schubert }
90085732ac8SCy Schubert 
90185732ac8SCy Schubert 
90285732ac8SCy Schubert static void wpas_dpp_listen_work_done(struct wpa_supplicant *wpa_s)
90385732ac8SCy Schubert {
90485732ac8SCy Schubert 	struct wpas_dpp_listen_work *lwork;
90585732ac8SCy Schubert 
90685732ac8SCy Schubert 	if (!wpa_s->dpp_listen_work)
90785732ac8SCy Schubert 		return;
90885732ac8SCy Schubert 
90985732ac8SCy Schubert 	lwork = wpa_s->dpp_listen_work->ctx;
91085732ac8SCy Schubert 	wpas_dpp_listen_work_free(lwork);
91185732ac8SCy Schubert 	radio_work_done(wpa_s->dpp_listen_work);
91285732ac8SCy Schubert 	wpa_s->dpp_listen_work = NULL;
91385732ac8SCy Schubert }
91485732ac8SCy Schubert 
91585732ac8SCy Schubert 
91685732ac8SCy Schubert static void dpp_start_listen_cb(struct wpa_radio_work *work, int deinit)
91785732ac8SCy Schubert {
91885732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = work->wpa_s;
91985732ac8SCy Schubert 	struct wpas_dpp_listen_work *lwork = work->ctx;
92085732ac8SCy Schubert 
92185732ac8SCy Schubert 	if (deinit) {
92285732ac8SCy Schubert 		if (work->started) {
92385732ac8SCy Schubert 			wpa_s->dpp_listen_work = NULL;
92485732ac8SCy Schubert 			wpas_dpp_listen_stop(wpa_s);
92585732ac8SCy Schubert 		}
92685732ac8SCy Schubert 		wpas_dpp_listen_work_free(lwork);
92785732ac8SCy Schubert 		return;
92885732ac8SCy Schubert 	}
92985732ac8SCy Schubert 
93085732ac8SCy Schubert 	wpa_s->dpp_listen_work = work;
93185732ac8SCy Schubert 
93285732ac8SCy Schubert 	wpa_s->dpp_pending_listen_freq = lwork->freq;
93385732ac8SCy Schubert 
93485732ac8SCy Schubert 	if (wpa_drv_remain_on_channel(wpa_s, lwork->freq,
93585732ac8SCy Schubert 				      wpa_s->max_remain_on_chan) < 0) {
93685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
93785732ac8SCy Schubert 			   "DPP: Failed to request the driver to remain on channel (%u MHz) for listen",
93885732ac8SCy Schubert 			   lwork->freq);
9394bc52338SCy Schubert 		wpa_s->dpp_listen_freq = 0;
94085732ac8SCy Schubert 		wpas_dpp_listen_work_done(wpa_s);
94185732ac8SCy Schubert 		wpa_s->dpp_pending_listen_freq = 0;
94285732ac8SCy Schubert 		return;
94385732ac8SCy Schubert 	}
94485732ac8SCy Schubert 	wpa_s->off_channel_freq = 0;
94585732ac8SCy Schubert 	wpa_s->roc_waiting_drv_freq = lwork->freq;
946c1d255d3SCy Schubert 	wpa_drv_dpp_listen(wpa_s, true);
94785732ac8SCy Schubert }
94885732ac8SCy Schubert 
94985732ac8SCy Schubert 
95085732ac8SCy Schubert static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
95185732ac8SCy Schubert 				 unsigned int freq)
95285732ac8SCy Schubert {
95385732ac8SCy Schubert 	struct wpas_dpp_listen_work *lwork;
95485732ac8SCy Schubert 
95585732ac8SCy Schubert 	if (wpa_s->dpp_listen_work) {
95685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
95785732ac8SCy Schubert 			   "DPP: Reject start_listen since dpp_listen_work already exists");
95885732ac8SCy Schubert 		return -1;
95985732ac8SCy Schubert 	}
96085732ac8SCy Schubert 
96185732ac8SCy Schubert 	if (wpa_s->dpp_listen_freq)
96285732ac8SCy Schubert 		wpas_dpp_listen_stop(wpa_s);
96385732ac8SCy Schubert 	wpa_s->dpp_listen_freq = freq;
96485732ac8SCy Schubert 
96585732ac8SCy Schubert 	lwork = os_zalloc(sizeof(*lwork));
96685732ac8SCy Schubert 	if (!lwork)
96785732ac8SCy Schubert 		return -1;
96885732ac8SCy Schubert 	lwork->freq = freq;
96985732ac8SCy Schubert 
97085732ac8SCy Schubert 	if (radio_add_work(wpa_s, freq, "dpp-listen", 0, dpp_start_listen_cb,
97185732ac8SCy Schubert 			   lwork) < 0) {
97285732ac8SCy Schubert 		wpas_dpp_listen_work_free(lwork);
97385732ac8SCy Schubert 		return -1;
97485732ac8SCy Schubert 	}
97585732ac8SCy Schubert 
97685732ac8SCy Schubert 	return 0;
97785732ac8SCy Schubert }
97885732ac8SCy Schubert 
97985732ac8SCy Schubert 
98085732ac8SCy Schubert int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd)
98185732ac8SCy Schubert {
98285732ac8SCy Schubert 	int freq;
98385732ac8SCy Schubert 
98485732ac8SCy Schubert 	freq = atoi(cmd);
98585732ac8SCy Schubert 	if (freq <= 0)
98685732ac8SCy Schubert 		return -1;
98785732ac8SCy Schubert 
98885732ac8SCy Schubert 	if (os_strstr(cmd, " role=configurator"))
98985732ac8SCy Schubert 		wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR;
99085732ac8SCy Schubert 	else if (os_strstr(cmd, " role=enrollee"))
99185732ac8SCy Schubert 		wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
99285732ac8SCy Schubert 	else
99385732ac8SCy Schubert 		wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
99485732ac8SCy Schubert 			DPP_CAPAB_ENROLLEE;
99585732ac8SCy Schubert 	wpa_s->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
996c1d255d3SCy Schubert 	if (os_strstr(cmd, " netrole=ap"))
997c1d255d3SCy Schubert 		wpa_s->dpp_netrole = DPP_NETROLE_AP;
998c1d255d3SCy Schubert 	else if (os_strstr(cmd, " netrole=configurator"))
999c1d255d3SCy Schubert 		wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
1000c1d255d3SCy Schubert 	else
1001c1d255d3SCy Schubert 		wpa_s->dpp_netrole = DPP_NETROLE_STA;
100285732ac8SCy Schubert 	if (wpa_s->dpp_listen_freq == (unsigned int) freq) {
100385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz",
100485732ac8SCy Schubert 			   freq);
100585732ac8SCy Schubert 		return 0;
100685732ac8SCy Schubert 	}
100785732ac8SCy Schubert 
100885732ac8SCy Schubert 	return wpas_dpp_listen_start(wpa_s, freq);
100985732ac8SCy Schubert }
101085732ac8SCy Schubert 
101185732ac8SCy Schubert 
101285732ac8SCy Schubert void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s)
101385732ac8SCy Schubert {
101485732ac8SCy Schubert 	wpa_s->dpp_in_response_listen = 0;
101585732ac8SCy Schubert 	if (!wpa_s->dpp_listen_freq)
101685732ac8SCy Schubert 		return;
101785732ac8SCy Schubert 
101885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Stop listen on %u MHz",
101985732ac8SCy Schubert 		   wpa_s->dpp_listen_freq);
102085732ac8SCy Schubert 	wpa_drv_cancel_remain_on_channel(wpa_s);
1021c1d255d3SCy Schubert 	wpa_drv_dpp_listen(wpa_s, false);
102285732ac8SCy Schubert 	wpa_s->dpp_listen_freq = 0;
102385732ac8SCy Schubert 	wpas_dpp_listen_work_done(wpa_s);
1024*32a95656SCy Schubert 	radio_remove_works(wpa_s, "dpp-listen", 0);
102585732ac8SCy Schubert }
102685732ac8SCy Schubert 
102785732ac8SCy Schubert 
1028c1d255d3SCy Schubert void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
1029c1d255d3SCy Schubert 				   unsigned int freq, unsigned int duration)
1030c1d255d3SCy Schubert {
1031c1d255d3SCy Schubert 	if (wpa_s->dpp_listen_freq != freq)
1032c1d255d3SCy Schubert 		return;
1033c1d255d3SCy Schubert 
1034c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG,
1035c1d255d3SCy Schubert 		   "DPP: Remain-on-channel started for listen on %u MHz for %u ms",
1036c1d255d3SCy Schubert 		   freq, duration);
1037c1d255d3SCy Schubert 	os_get_reltime(&wpa_s->dpp_listen_end);
1038c1d255d3SCy Schubert 	wpa_s->dpp_listen_end.usec += duration * 1000;
1039c1d255d3SCy Schubert 	while (wpa_s->dpp_listen_end.usec >= 1000000) {
1040c1d255d3SCy Schubert 		wpa_s->dpp_listen_end.sec++;
1041c1d255d3SCy Schubert 		wpa_s->dpp_listen_end.usec -= 1000000;
1042c1d255d3SCy Schubert 	}
1043c1d255d3SCy Schubert }
1044c1d255d3SCy Schubert 
1045c1d255d3SCy Schubert 
104685732ac8SCy Schubert void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
104785732ac8SCy Schubert 					  unsigned int freq)
104885732ac8SCy Schubert {
104985732ac8SCy Schubert 	wpas_dpp_listen_work_done(wpa_s);
105085732ac8SCy Schubert 
105185732ac8SCy Schubert 	if (wpa_s->dpp_auth && wpa_s->dpp_in_response_listen) {
105285732ac8SCy Schubert 		unsigned int new_freq;
105385732ac8SCy Schubert 
105485732ac8SCy Schubert 		/* Continue listen with a new remain-on-channel */
105585732ac8SCy Schubert 		if (wpa_s->dpp_auth->neg_freq > 0)
105685732ac8SCy Schubert 			new_freq = wpa_s->dpp_auth->neg_freq;
105785732ac8SCy Schubert 		else
105885732ac8SCy Schubert 			new_freq = wpa_s->dpp_auth->curr_freq;
105985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
106085732ac8SCy Schubert 			   "DPP: Continue wait on %u MHz for the ongoing DPP provisioning session",
106185732ac8SCy Schubert 			   new_freq);
106285732ac8SCy Schubert 		wpas_dpp_listen_start(wpa_s, new_freq);
106385732ac8SCy Schubert 		return;
106485732ac8SCy Schubert 	}
106585732ac8SCy Schubert 
106685732ac8SCy Schubert 	if (wpa_s->dpp_listen_freq) {
106785732ac8SCy Schubert 		/* Continue listen with a new remain-on-channel */
106885732ac8SCy Schubert 		wpas_dpp_listen_start(wpa_s, wpa_s->dpp_listen_freq);
106985732ac8SCy Schubert 	}
107085732ac8SCy Schubert }
107185732ac8SCy Schubert 
107285732ac8SCy Schubert 
107385732ac8SCy Schubert static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
107485732ac8SCy Schubert 				 const u8 *hdr, const u8 *buf, size_t len,
107585732ac8SCy Schubert 				 unsigned int freq)
107685732ac8SCy Schubert {
107785732ac8SCy Schubert 	const u8 *r_bootstrap, *i_bootstrap;
107885732ac8SCy Schubert 	u16 r_bootstrap_len, i_bootstrap_len;
10794bc52338SCy Schubert 	struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
10804bc52338SCy Schubert 
10814bc52338SCy Schubert 	if (!wpa_s->dpp)
10824bc52338SCy Schubert 		return;
108385732ac8SCy Schubert 
108485732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
108585732ac8SCy Schubert 		   MAC2STR(src));
108685732ac8SCy Schubert 
1087c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1088c1d255d3SCy Schubert 	wpas_dpp_chirp_stop(wpa_s);
1089c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1090c1d255d3SCy Schubert 
109185732ac8SCy Schubert 	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
109285732ac8SCy Schubert 				   &r_bootstrap_len);
109385732ac8SCy Schubert 	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
109485732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
109585732ac8SCy Schubert 			"Missing or invalid required Responder Bootstrapping Key Hash attribute");
109685732ac8SCy Schubert 		return;
109785732ac8SCy Schubert 	}
109885732ac8SCy Schubert 	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
109985732ac8SCy Schubert 		    r_bootstrap, r_bootstrap_len);
110085732ac8SCy Schubert 
110185732ac8SCy Schubert 	i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
110285732ac8SCy Schubert 				   &i_bootstrap_len);
110385732ac8SCy Schubert 	if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
110485732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
110585732ac8SCy Schubert 			"Missing or invalid required Initiator Bootstrapping Key Hash attribute");
110685732ac8SCy Schubert 		return;
110785732ac8SCy Schubert 	}
110885732ac8SCy Schubert 	wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
110985732ac8SCy Schubert 		    i_bootstrap, i_bootstrap_len);
111085732ac8SCy Schubert 
111185732ac8SCy Schubert 	/* Try to find own and peer bootstrapping key matches based on the
111285732ac8SCy Schubert 	 * received hash values */
11134bc52338SCy Schubert 	dpp_bootstrap_find_pair(wpa_s->dpp, i_bootstrap, r_bootstrap,
11144bc52338SCy Schubert 				&own_bi, &peer_bi);
111585732ac8SCy Schubert 	if (!own_bi) {
111685732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
111785732ac8SCy Schubert 			"No matching own bootstrapping key found - ignore message");
111885732ac8SCy Schubert 		return;
111985732ac8SCy Schubert 	}
112085732ac8SCy Schubert 
112185732ac8SCy Schubert 	if (wpa_s->dpp_auth) {
112285732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
112385732ac8SCy Schubert 			"Already in DPP authentication exchange - ignore new one");
112485732ac8SCy Schubert 		return;
112585732ac8SCy Schubert 	}
112685732ac8SCy Schubert 
112785732ac8SCy Schubert 	wpa_s->dpp_gas_client = 0;
112885732ac8SCy Schubert 	wpa_s->dpp_auth_ok_on_ack = 0;
1129c1d255d3SCy Schubert 	wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s->dpp, wpa_s,
1130c1d255d3SCy Schubert 					  wpa_s->dpp_allowed_roles,
113185732ac8SCy Schubert 					  wpa_s->dpp_qr_mutual,
113285732ac8SCy Schubert 					  peer_bi, own_bi, freq, hdr, buf, len);
113385732ac8SCy Schubert 	if (!wpa_s->dpp_auth) {
113485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No response generated");
113585732ac8SCy Schubert 		return;
113685732ac8SCy Schubert 	}
113785732ac8SCy Schubert 	wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
1138c1d255d3SCy Schubert 	if (dpp_set_configurator(wpa_s->dpp_auth,
113985732ac8SCy Schubert 				 wpa_s->dpp_configurator_params) < 0) {
114085732ac8SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
114185732ac8SCy Schubert 		wpa_s->dpp_auth = NULL;
114285732ac8SCy Schubert 		return;
114385732ac8SCy Schubert 	}
114485732ac8SCy Schubert 	os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN);
114585732ac8SCy Schubert 
114685732ac8SCy Schubert 	if (wpa_s->dpp_listen_freq &&
114785732ac8SCy Schubert 	    wpa_s->dpp_listen_freq != wpa_s->dpp_auth->curr_freq) {
114885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
114985732ac8SCy Schubert 			   "DPP: Stop listen on %u MHz to allow response on the request %u MHz",
115085732ac8SCy Schubert 			   wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq);
115185732ac8SCy Schubert 		wpas_dpp_listen_stop(wpa_s);
115285732ac8SCy Schubert 	}
115385732ac8SCy Schubert 
115485732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
115585732ac8SCy Schubert 		MAC2STR(src), wpa_s->dpp_auth->curr_freq,
115685732ac8SCy Schubert 		DPP_PA_AUTHENTICATION_RESP);
115785732ac8SCy Schubert 	offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq,
115885732ac8SCy Schubert 			       src, wpa_s->own_addr, broadcast,
115985732ac8SCy Schubert 			       wpabuf_head(wpa_s->dpp_auth->resp_msg),
116085732ac8SCy Schubert 			       wpabuf_len(wpa_s->dpp_auth->resp_msg),
116185732ac8SCy Schubert 			       500, wpas_dpp_tx_status, 0);
116285732ac8SCy Schubert }
116385732ac8SCy Schubert 
116485732ac8SCy Schubert 
116585732ac8SCy Schubert static void wpas_dpp_start_gas_server(struct wpa_supplicant *wpa_s)
116685732ac8SCy Schubert {
116785732ac8SCy Schubert 	/* TODO: stop wait and start ROC */
116885732ac8SCy Schubert }
116985732ac8SCy Schubert 
117085732ac8SCy Schubert 
117185732ac8SCy Schubert static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
1172c1d255d3SCy Schubert 					      struct dpp_authentication *auth,
1173c1d255d3SCy Schubert 					      struct dpp_config_obj *conf)
117485732ac8SCy Schubert {
117585732ac8SCy Schubert 	struct wpa_ssid *ssid;
117685732ac8SCy Schubert 
11774bc52338SCy Schubert #ifdef CONFIG_DPP2
1178c1d255d3SCy Schubert 	if (conf->akm == DPP_AKM_SAE) {
11794bc52338SCy Schubert #ifdef CONFIG_SAE
11804bc52338SCy Schubert 		struct wpa_driver_capa capa;
11814bc52338SCy Schubert 		int res;
11824bc52338SCy Schubert 
11834bc52338SCy Schubert 		res = wpa_drv_get_capa(wpa_s, &capa);
11844bc52338SCy Schubert 		if (res == 0 &&
1185c1d255d3SCy Schubert 		    !(capa.key_mgmt_iftype[WPA_IF_STATION] &
1186c1d255d3SCy Schubert 		      WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
11874bc52338SCy Schubert 		    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
11884bc52338SCy Schubert 			wpa_printf(MSG_DEBUG,
11894bc52338SCy Schubert 				   "DPP: SAE not supported by the driver");
11904bc52338SCy Schubert 			return NULL;
11914bc52338SCy Schubert 		}
11924bc52338SCy Schubert #else /* CONFIG_SAE */
11934bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: SAE not supported in the build");
11944bc52338SCy Schubert 		return NULL;
11954bc52338SCy Schubert #endif /* CONFIG_SAE */
11964bc52338SCy Schubert 	}
11974bc52338SCy Schubert #endif /* CONFIG_DPP2 */
11984bc52338SCy Schubert 
119985732ac8SCy Schubert 	ssid = wpa_config_add_network(wpa_s->conf);
120085732ac8SCy Schubert 	if (!ssid)
120185732ac8SCy Schubert 		return NULL;
120285732ac8SCy Schubert 	wpas_notify_network_added(wpa_s, ssid);
120385732ac8SCy Schubert 	wpa_config_set_network_defaults(ssid);
120485732ac8SCy Schubert 	ssid->disabled = 1;
120585732ac8SCy Schubert 
1206c1d255d3SCy Schubert 	ssid->ssid = os_malloc(conf->ssid_len);
120785732ac8SCy Schubert 	if (!ssid->ssid)
120885732ac8SCy Schubert 		goto fail;
1209c1d255d3SCy Schubert 	os_memcpy(ssid->ssid, conf->ssid, conf->ssid_len);
1210c1d255d3SCy Schubert 	ssid->ssid_len = conf->ssid_len;
121185732ac8SCy Schubert 
1212c1d255d3SCy Schubert 	if (conf->connector) {
1213c1d255d3SCy Schubert 		if (dpp_akm_dpp(conf->akm)) {
121485732ac8SCy Schubert 			ssid->key_mgmt = WPA_KEY_MGMT_DPP;
121585732ac8SCy Schubert 			ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
1216c1d255d3SCy Schubert 		}
1217c1d255d3SCy Schubert 		ssid->dpp_connector = os_strdup(conf->connector);
121885732ac8SCy Schubert 		if (!ssid->dpp_connector)
121985732ac8SCy Schubert 			goto fail;
122085732ac8SCy Schubert 	}
122185732ac8SCy Schubert 
1222c1d255d3SCy Schubert 	if (conf->c_sign_key) {
1223c1d255d3SCy Schubert 		ssid->dpp_csign = os_malloc(wpabuf_len(conf->c_sign_key));
122485732ac8SCy Schubert 		if (!ssid->dpp_csign)
122585732ac8SCy Schubert 			goto fail;
1226c1d255d3SCy Schubert 		os_memcpy(ssid->dpp_csign, wpabuf_head(conf->c_sign_key),
1227c1d255d3SCy Schubert 			  wpabuf_len(conf->c_sign_key));
1228c1d255d3SCy Schubert 		ssid->dpp_csign_len = wpabuf_len(conf->c_sign_key);
1229c1d255d3SCy Schubert 	}
1230c1d255d3SCy Schubert 
1231c1d255d3SCy Schubert 	if (conf->pp_key) {
1232c1d255d3SCy Schubert 		ssid->dpp_pp_key = os_malloc(wpabuf_len(conf->pp_key));
1233c1d255d3SCy Schubert 		if (!ssid->dpp_pp_key)
1234c1d255d3SCy Schubert 			goto fail;
1235c1d255d3SCy Schubert 		os_memcpy(ssid->dpp_pp_key, wpabuf_head(conf->pp_key),
1236c1d255d3SCy Schubert 			  wpabuf_len(conf->pp_key));
1237c1d255d3SCy Schubert 		ssid->dpp_pp_key_len = wpabuf_len(conf->pp_key);
123885732ac8SCy Schubert 	}
123985732ac8SCy Schubert 
124085732ac8SCy Schubert 	if (auth->net_access_key) {
124185732ac8SCy Schubert 		ssid->dpp_netaccesskey =
124285732ac8SCy Schubert 			os_malloc(wpabuf_len(auth->net_access_key));
124385732ac8SCy Schubert 		if (!ssid->dpp_netaccesskey)
124485732ac8SCy Schubert 			goto fail;
124585732ac8SCy Schubert 		os_memcpy(ssid->dpp_netaccesskey,
124685732ac8SCy Schubert 			  wpabuf_head(auth->net_access_key),
124785732ac8SCy Schubert 			  wpabuf_len(auth->net_access_key));
124885732ac8SCy Schubert 		ssid->dpp_netaccesskey_len = wpabuf_len(auth->net_access_key);
124985732ac8SCy Schubert 		ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
125085732ac8SCy Schubert 	}
125185732ac8SCy Schubert 
1252c1d255d3SCy Schubert 	if (!conf->connector || dpp_akm_psk(conf->akm) ||
1253c1d255d3SCy Schubert 	    dpp_akm_sae(conf->akm)) {
1254c1d255d3SCy Schubert 		if (!conf->connector || !dpp_akm_dpp(conf->akm))
125585732ac8SCy Schubert 			ssid->key_mgmt = 0;
1256c1d255d3SCy Schubert 		if (dpp_akm_psk(conf->akm))
125785732ac8SCy Schubert 			ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
125885732ac8SCy Schubert 				WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
1259c1d255d3SCy Schubert 		if (dpp_akm_sae(conf->akm))
126085732ac8SCy Schubert 			ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
126185732ac8SCy Schubert 				WPA_KEY_MGMT_FT_SAE;
126285732ac8SCy Schubert 		ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
1263c1d255d3SCy Schubert 		if (conf->passphrase[0]) {
126485732ac8SCy Schubert 			if (wpa_config_set_quoted(ssid, "psk",
1265c1d255d3SCy Schubert 						  conf->passphrase) < 0)
126685732ac8SCy Schubert 				goto fail;
126785732ac8SCy Schubert 			wpa_config_update_psk(ssid);
126885732ac8SCy Schubert 			ssid->export_keys = 1;
126985732ac8SCy Schubert 		} else {
1270c1d255d3SCy Schubert 			ssid->psk_set = conf->psk_set;
1271c1d255d3SCy Schubert 			os_memcpy(ssid->psk, conf->psk, PMK_LEN);
127285732ac8SCy Schubert 		}
127385732ac8SCy Schubert 	}
127485732ac8SCy Schubert 
1275c1d255d3SCy Schubert #if defined(CONFIG_DPP2) && defined(IEEE8021X_EAPOL)
1276c1d255d3SCy Schubert 	if (conf->akm == DPP_AKM_DOT1X) {
1277c1d255d3SCy Schubert 		int i;
1278c1d255d3SCy Schubert 		char name[100], blobname[128];
1279c1d255d3SCy Schubert 		struct wpa_config_blob *blob;
1280c1d255d3SCy Schubert 
1281c1d255d3SCy Schubert 		ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X |
1282c1d255d3SCy Schubert 			WPA_KEY_MGMT_IEEE8021X_SHA256 |
1283c1d255d3SCy Schubert 			WPA_KEY_MGMT_IEEE8021X_SHA256;
1284c1d255d3SCy Schubert 		ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
1285c1d255d3SCy Schubert 
1286c1d255d3SCy Schubert 		if (conf->cacert) {
1287c1d255d3SCy Schubert 			/* caCert is DER-encoded X.509v3 certificate for the
1288c1d255d3SCy Schubert 			 * server certificate if that is different from the
1289c1d255d3SCy Schubert 			 * trust root included in certBag. */
1290c1d255d3SCy Schubert 			/* TODO: ssid->eap.cert.ca_cert */
1291c1d255d3SCy Schubert 		}
1292c1d255d3SCy Schubert 
1293c1d255d3SCy Schubert 		if (conf->certs) {
1294c1d255d3SCy Schubert 			for (i = 0; ; i++) {
1295c1d255d3SCy Schubert 				os_snprintf(name, sizeof(name), "dpp-certs-%d",
1296c1d255d3SCy Schubert 					    i);
1297c1d255d3SCy Schubert 				if (!wpa_config_get_blob(wpa_s->conf, name))
1298c1d255d3SCy Schubert 					break;
1299c1d255d3SCy Schubert 			}
1300c1d255d3SCy Schubert 
1301c1d255d3SCy Schubert 			blob = os_zalloc(sizeof(*blob));
1302c1d255d3SCy Schubert 			if (!blob)
1303c1d255d3SCy Schubert 				goto fail;
1304c1d255d3SCy Schubert 			blob->len = wpabuf_len(conf->certs);
1305c1d255d3SCy Schubert 			blob->name = os_strdup(name);
1306c1d255d3SCy Schubert 			blob->data = os_malloc(blob->len);
1307c1d255d3SCy Schubert 			if (!blob->name || !blob->data) {
1308c1d255d3SCy Schubert 				wpa_config_free_blob(blob);
1309c1d255d3SCy Schubert 				goto fail;
1310c1d255d3SCy Schubert 			}
1311c1d255d3SCy Schubert 			os_memcpy(blob->data, wpabuf_head(conf->certs),
1312c1d255d3SCy Schubert 				  blob->len);
1313c1d255d3SCy Schubert 			os_snprintf(blobname, sizeof(blobname), "blob://%s",
1314c1d255d3SCy Schubert 				    name);
1315c1d255d3SCy Schubert 			wpa_config_set_blob(wpa_s->conf, blob);
1316c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: Added certificate blob %s",
1317c1d255d3SCy Schubert 				   name);
1318c1d255d3SCy Schubert 			ssid->eap.cert.client_cert = os_strdup(blobname);
1319c1d255d3SCy Schubert 			if (!ssid->eap.cert.client_cert)
1320c1d255d3SCy Schubert 				goto fail;
1321c1d255d3SCy Schubert 
1322c1d255d3SCy Schubert 			/* TODO: ssid->eap.identity from own certificate */
1323c1d255d3SCy Schubert 			if (wpa_config_set(ssid, "identity", "\"dpp-ent\"",
1324c1d255d3SCy Schubert 					   0) < 0)
1325c1d255d3SCy Schubert 				goto fail;
1326c1d255d3SCy Schubert 		}
1327c1d255d3SCy Schubert 
1328c1d255d3SCy Schubert 		if (auth->priv_key) {
1329c1d255d3SCy Schubert 			for (i = 0; ; i++) {
1330c1d255d3SCy Schubert 				os_snprintf(name, sizeof(name), "dpp-key-%d",
1331c1d255d3SCy Schubert 					    i);
1332c1d255d3SCy Schubert 				if (!wpa_config_get_blob(wpa_s->conf, name))
1333c1d255d3SCy Schubert 					break;
1334c1d255d3SCy Schubert 			}
1335c1d255d3SCy Schubert 
1336c1d255d3SCy Schubert 			blob = os_zalloc(sizeof(*blob));
1337c1d255d3SCy Schubert 			if (!blob)
1338c1d255d3SCy Schubert 				goto fail;
1339c1d255d3SCy Schubert 			blob->len = wpabuf_len(auth->priv_key);
1340c1d255d3SCy Schubert 			blob->name = os_strdup(name);
1341c1d255d3SCy Schubert 			blob->data = os_malloc(blob->len);
1342c1d255d3SCy Schubert 			if (!blob->name || !blob->data) {
1343c1d255d3SCy Schubert 				wpa_config_free_blob(blob);
1344c1d255d3SCy Schubert 				goto fail;
1345c1d255d3SCy Schubert 			}
1346c1d255d3SCy Schubert 			os_memcpy(blob->data, wpabuf_head(auth->priv_key),
1347c1d255d3SCy Schubert 				  blob->len);
1348c1d255d3SCy Schubert 			os_snprintf(blobname, sizeof(blobname), "blob://%s",
1349c1d255d3SCy Schubert 				    name);
1350c1d255d3SCy Schubert 			wpa_config_set_blob(wpa_s->conf, blob);
1351c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: Added private key blob %s",
1352c1d255d3SCy Schubert 				   name);
1353c1d255d3SCy Schubert 			ssid->eap.cert.private_key = os_strdup(blobname);
1354c1d255d3SCy Schubert 			if (!ssid->eap.cert.private_key)
1355c1d255d3SCy Schubert 				goto fail;
1356c1d255d3SCy Schubert 		}
1357c1d255d3SCy Schubert 
1358c1d255d3SCy Schubert 		if (conf->server_name) {
1359c1d255d3SCy Schubert 			ssid->eap.cert.domain_suffix_match =
1360c1d255d3SCy Schubert 				os_strdup(conf->server_name);
1361c1d255d3SCy Schubert 			if (!ssid->eap.cert.domain_suffix_match)
1362c1d255d3SCy Schubert 				goto fail;
1363c1d255d3SCy Schubert 		}
1364c1d255d3SCy Schubert 
1365c1d255d3SCy Schubert 		/* TODO: Use entCreds::eapMethods */
1366c1d255d3SCy Schubert 		if (wpa_config_set(ssid, "eap", "TLS", 0) < 0)
1367c1d255d3SCy Schubert 			goto fail;
1368c1d255d3SCy Schubert 	}
1369c1d255d3SCy Schubert #endif /* CONFIG_DPP2 && IEEE8021X_EAPOL */
1370c1d255d3SCy Schubert 
1371c1d255d3SCy Schubert 	os_memcpy(wpa_s->dpp_last_ssid, conf->ssid, conf->ssid_len);
1372c1d255d3SCy Schubert 	wpa_s->dpp_last_ssid_len = conf->ssid_len;
1373c1d255d3SCy Schubert 
137485732ac8SCy Schubert 	return ssid;
137585732ac8SCy Schubert fail:
137685732ac8SCy Schubert 	wpas_notify_network_removed(wpa_s, ssid);
137785732ac8SCy Schubert 	wpa_config_remove_network(wpa_s->conf, ssid->id);
137885732ac8SCy Schubert 	return NULL;
137985732ac8SCy Schubert }
138085732ac8SCy Schubert 
138185732ac8SCy Schubert 
13824bc52338SCy Schubert static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
1383c1d255d3SCy Schubert 				   struct dpp_authentication *auth,
1384c1d255d3SCy Schubert 				   struct dpp_config_obj *conf)
138585732ac8SCy Schubert {
138685732ac8SCy Schubert 	struct wpa_ssid *ssid;
138785732ac8SCy Schubert 
138885732ac8SCy Schubert 	if (wpa_s->conf->dpp_config_processing < 1)
13894bc52338SCy Schubert 		return 0;
139085732ac8SCy Schubert 
1391c1d255d3SCy Schubert 	ssid = wpas_dpp_add_network(wpa_s, auth, conf);
139285732ac8SCy Schubert 	if (!ssid)
13934bc52338SCy Schubert 		return -1;
139485732ac8SCy Schubert 
139585732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id);
13964bc52338SCy Schubert 	if (wpa_s->conf->dpp_config_processing == 2)
139785732ac8SCy Schubert 		ssid->disabled = 0;
13984bc52338SCy Schubert 
13994bc52338SCy Schubert #ifndef CONFIG_NO_CONFIG_WRITE
14004bc52338SCy Schubert 	if (wpa_s->conf->update_config &&
14014bc52338SCy Schubert 	    wpa_config_write(wpa_s->confname, wpa_s->conf))
14024bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration");
14034bc52338SCy Schubert #endif /* CONFIG_NO_CONFIG_WRITE */
14044bc52338SCy Schubert 
14054bc52338SCy Schubert 	return 0;
1406c1d255d3SCy Schubert }
1407c1d255d3SCy Schubert 
1408c1d255d3SCy Schubert 
1409c1d255d3SCy Schubert static void wpas_dpp_post_process_config(struct wpa_supplicant *wpa_s,
1410c1d255d3SCy Schubert 					 struct dpp_authentication *auth)
1411c1d255d3SCy Schubert {
1412c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1413c1d255d3SCy Schubert 	if (auth->reconfig && wpa_s->dpp_reconfig_ssid &&
1414c1d255d3SCy Schubert 	    wpa_config_get_network(wpa_s->conf, wpa_s->dpp_reconfig_ssid_id) ==
1415c1d255d3SCy Schubert 	    wpa_s->dpp_reconfig_ssid) {
1416c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1417c1d255d3SCy Schubert 			   "DPP: Remove reconfigured network profile");
1418c1d255d3SCy Schubert 		wpas_notify_network_removed(wpa_s, wpa_s->dpp_reconfig_ssid);
1419c1d255d3SCy Schubert 		wpa_config_remove_network(wpa_s->conf,
1420c1d255d3SCy Schubert 					  wpa_s->dpp_reconfig_ssid_id);
1421c1d255d3SCy Schubert 		wpa_s->dpp_reconfig_ssid = NULL;
1422c1d255d3SCy Schubert 		wpa_s->dpp_reconfig_ssid_id = -1;
1423c1d255d3SCy Schubert 	}
1424c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1425c1d255d3SCy Schubert 
1426c1d255d3SCy Schubert 	if (wpa_s->conf->dpp_config_processing < 2)
1427c1d255d3SCy Schubert 		return;
14284bc52338SCy Schubert 
14294bc52338SCy Schubert #ifdef CONFIG_DPP2
14304bc52338SCy Schubert 	if (auth->peer_version >= 2) {
14314bc52338SCy Schubert 		wpa_printf(MSG_DEBUG,
14324bc52338SCy Schubert 			   "DPP: Postpone connection attempt to wait for completion of DPP Configuration Result");
14334bc52338SCy Schubert 		auth->connect_on_tx_status = 1;
1434c1d255d3SCy Schubert 		return;
14354bc52338SCy Schubert 	}
14364bc52338SCy Schubert #endif /* CONFIG_DPP2 */
14374bc52338SCy Schubert 
14384bc52338SCy Schubert 	wpas_dpp_try_to_connect(wpa_s);
143985732ac8SCy Schubert }
144085732ac8SCy Schubert 
144185732ac8SCy Schubert 
14424bc52338SCy Schubert static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
1443c1d255d3SCy Schubert 				      struct dpp_authentication *auth,
1444c1d255d3SCy Schubert 				      struct dpp_config_obj *conf)
144585732ac8SCy Schubert {
144685732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
1447c1d255d3SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
1448c1d255d3SCy Schubert 		dpp_akm_str(conf->akm));
1449c1d255d3SCy Schubert 	if (conf->ssid_len)
145085732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
1451c1d255d3SCy Schubert 			wpa_ssid_txt(conf->ssid, conf->ssid_len));
1452c1d255d3SCy Schubert 	if (conf->ssid_charset)
1453c1d255d3SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID_CHARSET "%d",
1454c1d255d3SCy Schubert 			conf->ssid_charset);
1455c1d255d3SCy Schubert 	if (conf->connector) {
145685732ac8SCy Schubert 		/* TODO: Save the Connector and consider using a command
145785732ac8SCy Schubert 		 * to fetch the value instead of sending an event with
145885732ac8SCy Schubert 		 * it. The Connector could end up being larger than what
145985732ac8SCy Schubert 		 * most clients are ready to receive as an event
146085732ac8SCy Schubert 		 * message. */
146185732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
1462c1d255d3SCy Schubert 			conf->connector);
146385732ac8SCy Schubert 	}
1464c1d255d3SCy Schubert 	if (conf->passphrase[0]) {
1465c1d255d3SCy Schubert 		char hex[64 * 2 + 1];
1466c1d255d3SCy Schubert 
1467c1d255d3SCy Schubert 		wpa_snprintf_hex(hex, sizeof(hex),
1468c1d255d3SCy Schubert 				 (const u8 *) conf->passphrase,
1469c1d255d3SCy Schubert 				 os_strlen(conf->passphrase));
1470c1d255d3SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s",
1471c1d255d3SCy Schubert 			hex);
1472c1d255d3SCy Schubert 	} else if (conf->psk_set) {
1473c1d255d3SCy Schubert 		char hex[PMK_LEN * 2 + 1];
1474c1d255d3SCy Schubert 
1475c1d255d3SCy Schubert 		wpa_snprintf_hex(hex, sizeof(hex), conf->psk, PMK_LEN);
1476c1d255d3SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
1477c1d255d3SCy Schubert 			hex);
1478c1d255d3SCy Schubert 	}
1479c1d255d3SCy Schubert 	if (conf->c_sign_key) {
148085732ac8SCy Schubert 		char *hex;
148185732ac8SCy Schubert 		size_t hexlen;
148285732ac8SCy Schubert 
1483c1d255d3SCy Schubert 		hexlen = 2 * wpabuf_len(conf->c_sign_key) + 1;
148485732ac8SCy Schubert 		hex = os_malloc(hexlen);
148585732ac8SCy Schubert 		if (hex) {
148685732ac8SCy Schubert 			wpa_snprintf_hex(hex, hexlen,
1487c1d255d3SCy Schubert 					 wpabuf_head(conf->c_sign_key),
1488c1d255d3SCy Schubert 					 wpabuf_len(conf->c_sign_key));
148985732ac8SCy Schubert 			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s",
149085732ac8SCy Schubert 				hex);
149185732ac8SCy Schubert 			os_free(hex);
149285732ac8SCy Schubert 		}
149385732ac8SCy Schubert 	}
1494c1d255d3SCy Schubert 	if (conf->pp_key) {
1495c1d255d3SCy Schubert 		char *hex;
1496c1d255d3SCy Schubert 		size_t hexlen;
1497c1d255d3SCy Schubert 
1498c1d255d3SCy Schubert 		hexlen = 2 * wpabuf_len(conf->pp_key) + 1;
1499c1d255d3SCy Schubert 		hex = os_malloc(hexlen);
1500c1d255d3SCy Schubert 		if (hex) {
1501c1d255d3SCy Schubert 			wpa_snprintf_hex(hex, hexlen,
1502c1d255d3SCy Schubert 					 wpabuf_head(conf->pp_key),
1503c1d255d3SCy Schubert 					 wpabuf_len(conf->pp_key));
1504c1d255d3SCy Schubert 			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PP_KEY "%s", hex);
1505c1d255d3SCy Schubert 			os_free(hex);
1506c1d255d3SCy Schubert 		}
1507c1d255d3SCy Schubert 	}
150885732ac8SCy Schubert 	if (auth->net_access_key) {
150985732ac8SCy Schubert 		char *hex;
151085732ac8SCy Schubert 		size_t hexlen;
151185732ac8SCy Schubert 
151285732ac8SCy Schubert 		hexlen = 2 * wpabuf_len(auth->net_access_key) + 1;
151385732ac8SCy Schubert 		hex = os_malloc(hexlen);
151485732ac8SCy Schubert 		if (hex) {
151585732ac8SCy Schubert 			wpa_snprintf_hex(hex, hexlen,
151685732ac8SCy Schubert 					 wpabuf_head(auth->net_access_key),
151785732ac8SCy Schubert 					 wpabuf_len(auth->net_access_key));
151885732ac8SCy Schubert 			if (auth->net_access_key_expiry)
151985732ac8SCy Schubert 				wpa_msg(wpa_s, MSG_INFO,
152085732ac8SCy Schubert 					DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex,
152185732ac8SCy Schubert 					(long unsigned)
152285732ac8SCy Schubert 					auth->net_access_key_expiry);
152385732ac8SCy Schubert 			else
152485732ac8SCy Schubert 				wpa_msg(wpa_s, MSG_INFO,
152585732ac8SCy Schubert 					DPP_EVENT_NET_ACCESS_KEY "%s", hex);
152685732ac8SCy Schubert 			os_free(hex);
152785732ac8SCy Schubert 		}
152885732ac8SCy Schubert 	}
152985732ac8SCy Schubert 
1530c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1531c1d255d3SCy Schubert 	if (conf->certbag) {
1532c1d255d3SCy Schubert 		char *b64;
1533c1d255d3SCy Schubert 
1534c1d255d3SCy Schubert 		b64 = base64_encode_no_lf(wpabuf_head(conf->certbag),
1535c1d255d3SCy Schubert 					  wpabuf_len(conf->certbag), NULL);
1536c1d255d3SCy Schubert 		if (b64)
1537c1d255d3SCy Schubert 			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CERTBAG "%s", b64);
1538c1d255d3SCy Schubert 		os_free(b64);
153985732ac8SCy Schubert 	}
154085732ac8SCy Schubert 
1541c1d255d3SCy Schubert 	if (conf->cacert) {
1542c1d255d3SCy Schubert 		char *b64;
1543c1d255d3SCy Schubert 
1544c1d255d3SCy Schubert 		b64 = base64_encode_no_lf(wpabuf_head(conf->cacert),
1545c1d255d3SCy Schubert 					  wpabuf_len(conf->cacert), NULL);
1546c1d255d3SCy Schubert 		if (b64)
1547c1d255d3SCy Schubert 			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CACERT "%s", b64);
1548c1d255d3SCy Schubert 		os_free(b64);
1549c1d255d3SCy Schubert 	}
1550c1d255d3SCy Schubert 
1551c1d255d3SCy Schubert 	if (conf->server_name)
1552c1d255d3SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_SERVER_NAME "%s",
1553c1d255d3SCy Schubert 			conf->server_name);
1554c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1555c1d255d3SCy Schubert 
1556c1d255d3SCy Schubert 	return wpas_dpp_process_config(wpa_s, auth, conf);
1557c1d255d3SCy Schubert }
1558c1d255d3SCy Schubert 
1559c1d255d3SCy Schubert 
1560c1d255d3SCy Schubert static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
1561c1d255d3SCy Schubert 				   struct dpp_asymmetric_key *key)
1562c1d255d3SCy Schubert {
1563c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1564c1d255d3SCy Schubert 	int res;
1565c1d255d3SCy Schubert 
1566c1d255d3SCy Schubert 	if (!key)
1567c1d255d3SCy Schubert 		return 0;
1568c1d255d3SCy Schubert 
1569c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
1570c1d255d3SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
1571c1d255d3SCy Schubert 	wpa_s->dpp_conf_backup_received = true;
1572c1d255d3SCy Schubert 
1573c1d255d3SCy Schubert 	while (key) {
1574c1d255d3SCy Schubert 		res = dpp_configurator_from_backup(wpa_s->dpp, key);
1575c1d255d3SCy Schubert 		if (res < 0)
1576c1d255d3SCy Schubert 			return -1;
1577c1d255d3SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d",
1578c1d255d3SCy Schubert 			res);
1579c1d255d3SCy Schubert 		key = key->next;
1580c1d255d3SCy Schubert 	}
1581c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1582c1d255d3SCy Schubert 
1583c1d255d3SCy Schubert 	return 0;
1584c1d255d3SCy Schubert }
1585c1d255d3SCy Schubert 
1586c1d255d3SCy Schubert 
1587c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1588c1d255d3SCy Schubert static void wpas_dpp_build_csr(void *eloop_ctx, void *timeout_ctx)
1589c1d255d3SCy Schubert {
1590c1d255d3SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
1591c1d255d3SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
1592c1d255d3SCy Schubert 
1593c1d255d3SCy Schubert 	if (!auth || !auth->csrattrs)
1594c1d255d3SCy Schubert 		return;
1595c1d255d3SCy Schubert 
1596c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Build CSR");
1597c1d255d3SCy Schubert 	wpabuf_free(auth->csr);
1598c1d255d3SCy Schubert 	/* TODO: Additional information needed for CSR based on csrAttrs */
1599c1d255d3SCy Schubert 	auth->csr = dpp_build_csr(auth, wpa_s->conf->dpp_name ?
1600c1d255d3SCy Schubert 				  wpa_s->conf->dpp_name : "Test");
1601c1d255d3SCy Schubert 	if (!auth->csr) {
1602c1d255d3SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
1603c1d255d3SCy Schubert 		wpa_s->dpp_auth = NULL;
1604c1d255d3SCy Schubert 		return;
1605c1d255d3SCy Schubert 	}
1606c1d255d3SCy Schubert 
1607c1d255d3SCy Schubert 	wpas_dpp_start_gas_client(wpa_s);
1608c1d255d3SCy Schubert }
1609c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1610c1d255d3SCy Schubert 
161185732ac8SCy Schubert 
161285732ac8SCy Schubert static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
161385732ac8SCy Schubert 				 enum gas_query_result result,
161485732ac8SCy Schubert 				 const struct wpabuf *adv_proto,
161585732ac8SCy Schubert 				 const struct wpabuf *resp, u16 status_code)
161685732ac8SCy Schubert {
161785732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = ctx;
161885732ac8SCy Schubert 	const u8 *pos;
161985732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
16204bc52338SCy Schubert 	int res;
16214bc52338SCy Schubert 	enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
1622c1d255d3SCy Schubert 	unsigned int i;
162385732ac8SCy Schubert 
162485732ac8SCy Schubert 	wpa_s->dpp_gas_dialog_token = -1;
162585732ac8SCy Schubert 
1626c1d255d3SCy Schubert 	if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
1627c1d255d3SCy Schubert 	    os_memcmp(addr, auth->peer_mac_addr, ETH_ALEN) != 0) {
162885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
162985732ac8SCy Schubert 		return;
163085732ac8SCy Schubert 	}
163185732ac8SCy Schubert 	if (result != GAS_QUERY_SUCCESS ||
163285732ac8SCy Schubert 	    !resp || status_code != WLAN_STATUS_SUCCESS) {
163385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
163485732ac8SCy Schubert 		goto fail;
163585732ac8SCy Schubert 	}
163685732ac8SCy Schubert 
163785732ac8SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
163885732ac8SCy Schubert 			adv_proto);
163985732ac8SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
164085732ac8SCy Schubert 			resp);
164185732ac8SCy Schubert 
164285732ac8SCy Schubert 	if (wpabuf_len(adv_proto) != 10 ||
164385732ac8SCy Schubert 	    !(pos = wpabuf_head(adv_proto)) ||
164485732ac8SCy Schubert 	    pos[0] != WLAN_EID_ADV_PROTO ||
164585732ac8SCy Schubert 	    pos[1] != 8 ||
164685732ac8SCy Schubert 	    pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
164785732ac8SCy Schubert 	    pos[4] != 5 ||
164885732ac8SCy Schubert 	    WPA_GET_BE24(&pos[5]) != OUI_WFA ||
164985732ac8SCy Schubert 	    pos[8] != 0x1a ||
165085732ac8SCy Schubert 	    pos[9] != 1) {
165185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
165285732ac8SCy Schubert 			   "DPP: Not a DPP Advertisement Protocol ID");
165385732ac8SCy Schubert 		goto fail;
165485732ac8SCy Schubert 	}
165585732ac8SCy Schubert 
1656c1d255d3SCy Schubert 	res = dpp_conf_resp_rx(auth, resp);
1657c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1658c1d255d3SCy Schubert 	if (res == -2) {
1659c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: CSR needed");
1660c1d255d3SCy Schubert 		eloop_register_timeout(0, 0, wpas_dpp_build_csr, wpa_s, NULL);
1661c1d255d3SCy Schubert 		return;
1662c1d255d3SCy Schubert 	}
1663c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1664c1d255d3SCy Schubert 	if (res < 0) {
166585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
166685732ac8SCy Schubert 		goto fail;
166785732ac8SCy Schubert 	}
166885732ac8SCy Schubert 
1669c1d255d3SCy Schubert 	wpa_s->dpp_conf_backup_received = false;
1670c1d255d3SCy Schubert 	for (i = 0; i < auth->num_conf_obj; i++) {
1671c1d255d3SCy Schubert 		res = wpas_dpp_handle_config_obj(wpa_s, auth,
1672c1d255d3SCy Schubert 						 &auth->conf_obj[i]);
16734bc52338SCy Schubert 		if (res < 0)
16744bc52338SCy Schubert 			goto fail;
1675c1d255d3SCy Schubert 	}
1676c1d255d3SCy Schubert 	if (auth->num_conf_obj)
1677c1d255d3SCy Schubert 		wpas_dpp_post_process_config(wpa_s, auth);
1678c1d255d3SCy Schubert 	if (wpas_dpp_handle_key_pkg(wpa_s, auth->conf_key_pkg) < 0)
1679c1d255d3SCy Schubert 		goto fail;
168085732ac8SCy Schubert 
16814bc52338SCy Schubert 	status = DPP_STATUS_OK;
16824bc52338SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
16834bc52338SCy Schubert 	if (dpp_test == DPP_TEST_REJECT_CONFIG) {
16844bc52338SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
16854bc52338SCy Schubert 		status = DPP_STATUS_CONFIG_REJECTED;
16864bc52338SCy Schubert 	}
16874bc52338SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
168885732ac8SCy Schubert fail:
16894bc52338SCy Schubert 	if (status != DPP_STATUS_OK)
169085732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
16914bc52338SCy Schubert #ifdef CONFIG_DPP2
16924bc52338SCy Schubert 	if (auth->peer_version >= 2 &&
16934bc52338SCy Schubert 	    auth->conf_resp_status == DPP_STATUS_OK) {
16944bc52338SCy Schubert 		struct wpabuf *msg;
16954bc52338SCy Schubert 
16964bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
16974bc52338SCy Schubert 		msg = dpp_build_conf_result(auth, status);
16984bc52338SCy Schubert 		if (!msg)
16994bc52338SCy Schubert 			goto fail2;
17004bc52338SCy Schubert 
17014bc52338SCy Schubert 		wpa_msg(wpa_s, MSG_INFO,
17024bc52338SCy Schubert 			DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
17034bc52338SCy Schubert 			MAC2STR(addr), auth->curr_freq,
17044bc52338SCy Schubert 			DPP_PA_CONFIGURATION_RESULT);
17054bc52338SCy Schubert 		offchannel_send_action(wpa_s, auth->curr_freq,
17064bc52338SCy Schubert 				       addr, wpa_s->own_addr, broadcast,
17074bc52338SCy Schubert 				       wpabuf_head(msg),
17084bc52338SCy Schubert 				       wpabuf_len(msg),
17094bc52338SCy Schubert 				       500, wpas_dpp_tx_status, 0);
17104bc52338SCy Schubert 		wpabuf_free(msg);
17114bc52338SCy Schubert 
17124bc52338SCy Schubert 		/* This exchange will be terminated in the TX status handler */
1713c1d255d3SCy Schubert 		if (wpa_s->conf->dpp_config_processing < 2 ||
1714c1d255d3SCy Schubert 		    wpa_s->dpp_conf_backup_received)
1715c1d255d3SCy Schubert 			auth->remove_on_tx_status = 1;
17164bc52338SCy Schubert 		return;
17174bc52338SCy Schubert 	}
17184bc52338SCy Schubert fail2:
17194bc52338SCy Schubert #endif /* CONFIG_DPP2 */
172085732ac8SCy Schubert 	dpp_auth_deinit(wpa_s->dpp_auth);
172185732ac8SCy Schubert 	wpa_s->dpp_auth = NULL;
172285732ac8SCy Schubert }
172385732ac8SCy Schubert 
172485732ac8SCy Schubert 
172585732ac8SCy Schubert static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s)
172685732ac8SCy Schubert {
172785732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
17284bc52338SCy Schubert 	struct wpabuf *buf;
172985732ac8SCy Schubert 	int res;
1730c1d255d3SCy Schubert 	int *supp_op_classes;
173185732ac8SCy Schubert 
173285732ac8SCy Schubert 	wpa_s->dpp_gas_client = 1;
173385732ac8SCy Schubert 	offchannel_send_action_done(wpa_s);
173485732ac8SCy Schubert 	wpas_dpp_listen_stop(wpa_s);
173585732ac8SCy Schubert 
1736c1d255d3SCy Schubert 	supp_op_classes = wpas_supp_op_classes(wpa_s);
1737c1d255d3SCy Schubert 	buf = dpp_build_conf_req_helper(auth, wpa_s->conf->dpp_name,
1738c1d255d3SCy Schubert 					wpa_s->dpp_netrole,
1739c1d255d3SCy Schubert 					wpa_s->conf->dpp_mud_url,
1740c1d255d3SCy Schubert 					supp_op_classes);
1741c1d255d3SCy Schubert 	os_free(supp_op_classes);
17424bc52338SCy Schubert 	if (!buf) {
174385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
174485732ac8SCy Schubert 			   "DPP: No configuration request data available");
174585732ac8SCy Schubert 		return;
174685732ac8SCy Schubert 	}
174785732ac8SCy Schubert 
174885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
174985732ac8SCy Schubert 		   MAC2STR(auth->peer_mac_addr), auth->curr_freq);
175085732ac8SCy Schubert 
175185732ac8SCy Schubert 	res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq,
1752c1d255d3SCy Schubert 			    1, 1, buf, wpas_dpp_gas_resp_cb, wpa_s);
175385732ac8SCy Schubert 	if (res < 0) {
175485732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
175585732ac8SCy Schubert 		wpabuf_free(buf);
175685732ac8SCy Schubert 	} else {
175785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
175885732ac8SCy Schubert 			   "DPP: GAS query started with dialog token %u", res);
175985732ac8SCy Schubert 		wpa_s->dpp_gas_dialog_token = res;
176085732ac8SCy Schubert 	}
176185732ac8SCy Schubert }
176285732ac8SCy Schubert 
176385732ac8SCy Schubert 
176485732ac8SCy Schubert static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator)
176585732ac8SCy Schubert {
176685732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
176785732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
176885732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
176985732ac8SCy Schubert 	if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
177085732ac8SCy Schubert 		wpa_printf(MSG_INFO,
177185732ac8SCy Schubert 			   "DPP: TESTING - stop at Authentication Confirm");
177285732ac8SCy Schubert 		if (wpa_s->dpp_auth->configurator) {
177385732ac8SCy Schubert 			/* Prevent GAS response */
177485732ac8SCy Schubert 			wpa_s->dpp_auth->auth_success = 0;
177585732ac8SCy Schubert 		}
177685732ac8SCy Schubert 		return;
177785732ac8SCy Schubert 	}
177885732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
177985732ac8SCy Schubert 
178085732ac8SCy Schubert 	if (wpa_s->dpp_auth->configurator)
178185732ac8SCy Schubert 		wpas_dpp_start_gas_server(wpa_s);
178285732ac8SCy Schubert 	else
178385732ac8SCy Schubert 		wpas_dpp_start_gas_client(wpa_s);
178485732ac8SCy Schubert }
178585732ac8SCy Schubert 
178685732ac8SCy Schubert 
178785732ac8SCy Schubert static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
178885732ac8SCy Schubert 				  const u8 *hdr, const u8 *buf, size_t len,
178985732ac8SCy Schubert 				  unsigned int freq)
179085732ac8SCy Schubert {
179185732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
179285732ac8SCy Schubert 	struct wpabuf *msg;
179385732ac8SCy Schubert 
179485732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR
179585732ac8SCy Schubert 		   " (freq %u MHz)", MAC2STR(src), freq);
179685732ac8SCy Schubert 
179785732ac8SCy Schubert 	if (!auth) {
179885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
179985732ac8SCy Schubert 			   "DPP: No DPP Authentication in progress - drop");
180085732ac8SCy Schubert 		return;
180185732ac8SCy Schubert 	}
180285732ac8SCy Schubert 
180385732ac8SCy Schubert 	if (!is_zero_ether_addr(auth->peer_mac_addr) &&
180485732ac8SCy Schubert 	    os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
180585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
180685732ac8SCy Schubert 			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
180785732ac8SCy Schubert 		return;
180885732ac8SCy Schubert 	}
180985732ac8SCy Schubert 
181085732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
181185732ac8SCy Schubert 
181285732ac8SCy Schubert 	if (auth->curr_freq != freq && auth->neg_freq == freq) {
181385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
181485732ac8SCy Schubert 			   "DPP: Responder accepted request for different negotiation channel");
181585732ac8SCy Schubert 		auth->curr_freq = freq;
181685732ac8SCy Schubert 	}
181785732ac8SCy Schubert 
181885732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
181985732ac8SCy Schubert 	msg = dpp_auth_resp_rx(auth, hdr, buf, len);
182085732ac8SCy Schubert 	if (!msg) {
182185732ac8SCy Schubert 		if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
182285732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
182385732ac8SCy Schubert 				   "DPP: Start wait for full response");
182485732ac8SCy Schubert 			offchannel_send_action_done(wpa_s);
182585732ac8SCy Schubert 			wpas_dpp_listen_start(wpa_s, auth->curr_freq);
182685732ac8SCy Schubert 			return;
182785732ac8SCy Schubert 		}
182885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
182985732ac8SCy Schubert 		return;
183085732ac8SCy Schubert 	}
183185732ac8SCy Schubert 	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
183285732ac8SCy Schubert 
183385732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
183485732ac8SCy Schubert 		MAC2STR(src), auth->curr_freq, DPP_PA_AUTHENTICATION_CONF);
183585732ac8SCy Schubert 	offchannel_send_action(wpa_s, auth->curr_freq,
183685732ac8SCy Schubert 			       src, wpa_s->own_addr, broadcast,
183785732ac8SCy Schubert 			       wpabuf_head(msg), wpabuf_len(msg),
183885732ac8SCy Schubert 			       500, wpas_dpp_tx_status, 0);
183985732ac8SCy Schubert 	wpabuf_free(msg);
184085732ac8SCy Schubert 	wpa_s->dpp_auth_ok_on_ack = 1;
184185732ac8SCy Schubert }
184285732ac8SCy Schubert 
184385732ac8SCy Schubert 
184485732ac8SCy Schubert static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
184585732ac8SCy Schubert 				  const u8 *hdr, const u8 *buf, size_t len)
184685732ac8SCy Schubert {
184785732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
184885732ac8SCy Schubert 
184985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
185085732ac8SCy Schubert 		   MAC2STR(src));
185185732ac8SCy Schubert 
185285732ac8SCy Schubert 	if (!auth) {
185385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
185485732ac8SCy Schubert 			   "DPP: No DPP Authentication in progress - drop");
185585732ac8SCy Schubert 		return;
185685732ac8SCy Schubert 	}
185785732ac8SCy Schubert 
185885732ac8SCy Schubert 	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
185985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
186085732ac8SCy Schubert 			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
186185732ac8SCy Schubert 		return;
186285732ac8SCy Schubert 	}
186385732ac8SCy Schubert 
1864c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s, NULL);
1865c1d255d3SCy Schubert 
186685732ac8SCy Schubert 	if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
186785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
186885732ac8SCy Schubert 		return;
186985732ac8SCy Schubert 	}
187085732ac8SCy Schubert 
187185732ac8SCy Schubert 	wpas_dpp_auth_success(wpa_s, 0);
187285732ac8SCy Schubert }
187385732ac8SCy Schubert 
187485732ac8SCy Schubert 
18754bc52338SCy Schubert #ifdef CONFIG_DPP2
18764bc52338SCy Schubert 
18774bc52338SCy Schubert static void wpas_dpp_config_result_wait_timeout(void *eloop_ctx,
18784bc52338SCy Schubert 						void *timeout_ctx)
18794bc52338SCy Schubert {
18804bc52338SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
18814bc52338SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
18824bc52338SCy Schubert 
18834bc52338SCy Schubert 	if (!auth || !auth->waiting_conf_result)
18844bc52338SCy Schubert 		return;
18854bc52338SCy Schubert 
18864bc52338SCy Schubert 	wpa_printf(MSG_DEBUG,
18874bc52338SCy Schubert 		   "DPP: Timeout while waiting for Configuration Result");
18884bc52338SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
18894bc52338SCy Schubert 	dpp_auth_deinit(auth);
18904bc52338SCy Schubert 	wpa_s->dpp_auth = NULL;
18914bc52338SCy Schubert }
18924bc52338SCy Schubert 
18934bc52338SCy Schubert 
1894c1d255d3SCy Schubert static void wpas_dpp_conn_status_result_wait_timeout(void *eloop_ctx,
1895c1d255d3SCy Schubert 						     void *timeout_ctx)
1896c1d255d3SCy Schubert {
1897c1d255d3SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
1898c1d255d3SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
1899c1d255d3SCy Schubert 
1900c1d255d3SCy Schubert 	if (!auth || !auth->waiting_conn_status_result)
1901c1d255d3SCy Schubert 		return;
1902c1d255d3SCy Schubert 
1903c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG,
1904c1d255d3SCy Schubert 		   "DPP: Timeout while waiting for Connection Status Result");
1905c1d255d3SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT "timeout");
1906c1d255d3SCy Schubert 	wpas_dpp_listen_stop(wpa_s);
1907c1d255d3SCy Schubert 	dpp_auth_deinit(auth);
1908c1d255d3SCy Schubert 	wpa_s->dpp_auth = NULL;
1909c1d255d3SCy Schubert }
1910c1d255d3SCy Schubert 
1911c1d255d3SCy Schubert 
19124bc52338SCy Schubert static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
19134bc52338SCy Schubert 				    const u8 *hdr, const u8 *buf, size_t len)
19144bc52338SCy Schubert {
19154bc52338SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
19164bc52338SCy Schubert 	enum dpp_status_error status;
19174bc52338SCy Schubert 
19184bc52338SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
19194bc52338SCy Schubert 		   MAC2STR(src));
19204bc52338SCy Schubert 
19214bc52338SCy Schubert 	if (!auth || !auth->waiting_conf_result) {
1922c1d255d3SCy Schubert 		if (auth &&
1923c1d255d3SCy Schubert 		    os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) == 0 &&
1924c1d255d3SCy Schubert 		    gas_server_response_sent(wpa_s->gas_server,
1925c1d255d3SCy Schubert 					     auth->gas_server_ctx)) {
1926c1d255d3SCy Schubert 			/* This could happen if the TX status event gets delayed
1927c1d255d3SCy Schubert 			 * long enough for the Enrollee to have time to send
1928c1d255d3SCy Schubert 			 * the next frame before the TX status gets processed
1929c1d255d3SCy Schubert 			 * locally. */
1930c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
1931c1d255d3SCy Schubert 				   "DPP: GAS response was sent but TX status not yet received - assume it was ACKed since the Enrollee sent the next frame in the sequence");
1932c1d255d3SCy Schubert 			auth->waiting_conf_result = 1;
1933c1d255d3SCy Schubert 		} else {
19344bc52338SCy Schubert 			wpa_printf(MSG_DEBUG,
19354bc52338SCy Schubert 				   "DPP: No DPP Configuration waiting for result - drop");
19364bc52338SCy Schubert 			return;
19374bc52338SCy Schubert 		}
1938c1d255d3SCy Schubert 	}
19394bc52338SCy Schubert 
19404bc52338SCy Schubert 	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
19414bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
19424bc52338SCy Schubert 			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
19434bc52338SCy Schubert 		return;
19444bc52338SCy Schubert 	}
19454bc52338SCy Schubert 
19464bc52338SCy Schubert 	status = dpp_conf_result_rx(auth, hdr, buf, len);
19474bc52338SCy Schubert 
1948c1d255d3SCy Schubert 	if (status == DPP_STATUS_OK && auth->send_conn_status) {
1949c1d255d3SCy Schubert 		wpa_msg(wpa_s, MSG_INFO,
1950c1d255d3SCy Schubert 			DPP_EVENT_CONF_SENT "wait_conn_status=1");
1951c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
1952c1d255d3SCy Schubert 		eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
1953c1d255d3SCy Schubert 				     wpa_s, NULL);
1954c1d255d3SCy Schubert 		auth->waiting_conn_status_result = 1;
1955c1d255d3SCy Schubert 		eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
1956c1d255d3SCy Schubert 				     wpa_s, NULL);
1957c1d255d3SCy Schubert 		eloop_register_timeout(16, 0,
1958c1d255d3SCy Schubert 				       wpas_dpp_conn_status_result_wait_timeout,
1959c1d255d3SCy Schubert 				       wpa_s, NULL);
1960c1d255d3SCy Schubert 		offchannel_send_action_done(wpa_s);
1961c1d255d3SCy Schubert 		wpas_dpp_listen_start(wpa_s, auth->neg_freq ? auth->neg_freq :
1962c1d255d3SCy Schubert 				      auth->curr_freq);
1963c1d255d3SCy Schubert 		return;
1964c1d255d3SCy Schubert 	}
19654bc52338SCy Schubert 	offchannel_send_action_done(wpa_s);
19664bc52338SCy Schubert 	wpas_dpp_listen_stop(wpa_s);
19674bc52338SCy Schubert 	if (status == DPP_STATUS_OK)
19684bc52338SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
19694bc52338SCy Schubert 	else
19704bc52338SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
19714bc52338SCy Schubert 	dpp_auth_deinit(auth);
19724bc52338SCy Schubert 	wpa_s->dpp_auth = NULL;
19734bc52338SCy Schubert 	eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
19744bc52338SCy Schubert }
19754bc52338SCy Schubert 
1976206b73d0SCy Schubert 
1977c1d255d3SCy Schubert static void wpas_dpp_rx_conn_status_result(struct wpa_supplicant *wpa_s,
1978c1d255d3SCy Schubert 					   const u8 *src, const u8 *hdr,
1979c1d255d3SCy Schubert 					   const u8 *buf, size_t len)
1980c1d255d3SCy Schubert {
1981c1d255d3SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
1982c1d255d3SCy Schubert 	enum dpp_status_error status;
1983c1d255d3SCy Schubert 	u8 ssid[SSID_MAX_LEN];
1984c1d255d3SCy Schubert 	size_t ssid_len = 0;
1985c1d255d3SCy Schubert 	char *channel_list = NULL;
1986c1d255d3SCy Schubert 
1987c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
1988c1d255d3SCy Schubert 
1989c1d255d3SCy Schubert 	if (!auth || !auth->waiting_conn_status_result) {
1990c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1991c1d255d3SCy Schubert 			   "DPP: No DPP Configuration waiting for connection status result - drop");
1992c1d255d3SCy Schubert 		return;
1993c1d255d3SCy Schubert 	}
1994c1d255d3SCy Schubert 
1995c1d255d3SCy Schubert 	status = dpp_conn_status_result_rx(auth, hdr, buf, len,
1996c1d255d3SCy Schubert 					   ssid, &ssid_len, &channel_list);
1997c1d255d3SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
1998c1d255d3SCy Schubert 		"result=%d ssid=%s channel_list=%s",
1999c1d255d3SCy Schubert 		status, wpa_ssid_txt(ssid, ssid_len),
2000c1d255d3SCy Schubert 		channel_list ? channel_list : "N/A");
2001c1d255d3SCy Schubert 	os_free(channel_list);
2002c1d255d3SCy Schubert 	offchannel_send_action_done(wpa_s);
2003c1d255d3SCy Schubert 	wpas_dpp_listen_stop(wpa_s);
2004c1d255d3SCy Schubert 	dpp_auth_deinit(auth);
2005c1d255d3SCy Schubert 	wpa_s->dpp_auth = NULL;
2006c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
2007c1d255d3SCy Schubert 			     wpa_s, NULL);
2008c1d255d3SCy Schubert }
2009c1d255d3SCy Schubert 
2010c1d255d3SCy Schubert 
2011206b73d0SCy Schubert static int wpas_dpp_process_conf_obj(void *ctx,
2012206b73d0SCy Schubert 				     struct dpp_authentication *auth)
2013206b73d0SCy Schubert {
2014206b73d0SCy Schubert 	struct wpa_supplicant *wpa_s = ctx;
2015c1d255d3SCy Schubert 	unsigned int i;
2016c1d255d3SCy Schubert 	int res = -1;
2017206b73d0SCy Schubert 
2018c1d255d3SCy Schubert 	for (i = 0; i < auth->num_conf_obj; i++) {
2019c1d255d3SCy Schubert 		res = wpas_dpp_handle_config_obj(wpa_s, auth,
2020c1d255d3SCy Schubert 						 &auth->conf_obj[i]);
2021c1d255d3SCy Schubert 		if (res)
2022c1d255d3SCy Schubert 			break;
2023c1d255d3SCy Schubert 	}
2024c1d255d3SCy Schubert 	if (!res)
2025c1d255d3SCy Schubert 		wpas_dpp_post_process_config(wpa_s, auth);
2026c1d255d3SCy Schubert 
2027c1d255d3SCy Schubert 	return res;
2028c1d255d3SCy Schubert }
2029c1d255d3SCy Schubert 
2030c1d255d3SCy Schubert 
2031c1d255d3SCy Schubert static void wpas_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi)
2032c1d255d3SCy Schubert {
2033c1d255d3SCy Schubert 	struct wpa_supplicant *wpa_s = ctx;
2034c1d255d3SCy Schubert 
2035c1d255d3SCy Schubert 	if (bi == wpa_s->dpp_chirp_bi)
2036c1d255d3SCy Schubert 		wpas_dpp_chirp_stop(wpa_s);
2037c1d255d3SCy Schubert }
2038c1d255d3SCy Schubert 
2039c1d255d3SCy Schubert 
2040c1d255d3SCy Schubert static void
2041c1d255d3SCy Schubert wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
2042c1d255d3SCy Schubert 				  const u8 *hdr, const u8 *buf, size_t len,
2043c1d255d3SCy Schubert 				  unsigned int freq)
2044c1d255d3SCy Schubert {
2045c1d255d3SCy Schubert 	const u8 *r_bootstrap;
2046c1d255d3SCy Schubert 	u16 r_bootstrap_len;
2047c1d255d3SCy Schubert 	struct dpp_bootstrap_info *peer_bi;
2048c1d255d3SCy Schubert 	struct dpp_authentication *auth;
2049c1d255d3SCy Schubert 
2050c1d255d3SCy Schubert 	if (!wpa_s->dpp)
2051c1d255d3SCy Schubert 		return;
2052c1d255d3SCy Schubert 
2053c1d255d3SCy Schubert 	if (wpa_s->dpp_auth) {
2054c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2055c1d255d3SCy Schubert 			   "DPP: Ignore Presence Announcement during ongoing Authentication");
2056c1d255d3SCy Schubert 		return;
2057c1d255d3SCy Schubert 	}
2058c1d255d3SCy Schubert 
2059c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
2060c1d255d3SCy Schubert 		   MAC2STR(src));
2061c1d255d3SCy Schubert 
2062c1d255d3SCy Schubert 	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
2063c1d255d3SCy Schubert 				   &r_bootstrap_len);
2064c1d255d3SCy Schubert 	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
2065c1d255d3SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
2066c1d255d3SCy Schubert 			"Missing or invalid required Responder Bootstrapping Key Hash attribute");
2067c1d255d3SCy Schubert 		return;
2068c1d255d3SCy Schubert 	}
2069c1d255d3SCy Schubert 	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
2070c1d255d3SCy Schubert 		    r_bootstrap, r_bootstrap_len);
2071c1d255d3SCy Schubert 	peer_bi = dpp_bootstrap_find_chirp(wpa_s->dpp, r_bootstrap);
2072c1d255d3SCy Schubert 	dpp_notify_chirp_received(wpa_s, peer_bi ? (int) peer_bi->id : -1, src,
2073c1d255d3SCy Schubert 				  freq, r_bootstrap);
2074c1d255d3SCy Schubert 	if (!peer_bi) {
2075c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2076c1d255d3SCy Schubert 			   "DPP: No matching bootstrapping information found");
2077c1d255d3SCy Schubert 		return;
2078c1d255d3SCy Schubert 	}
2079c1d255d3SCy Schubert 
2080c1d255d3SCy Schubert 	auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, NULL,
2081c1d255d3SCy Schubert 			     DPP_CAPAB_CONFIGURATOR, freq, NULL, 0);
2082c1d255d3SCy Schubert 	if (!auth)
2083c1d255d3SCy Schubert 		return;
2084c1d255d3SCy Schubert 	wpas_dpp_set_testing_options(wpa_s, auth);
2085c1d255d3SCy Schubert 	if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) {
2086c1d255d3SCy Schubert 		dpp_auth_deinit(auth);
2087c1d255d3SCy Schubert 		return;
2088c1d255d3SCy Schubert 	}
2089c1d255d3SCy Schubert 
2090c1d255d3SCy Schubert 	auth->neg_freq = freq;
2091c1d255d3SCy Schubert 
2092c1d255d3SCy Schubert 	/* The source address of the Presence Announcement frame overrides any
2093c1d255d3SCy Schubert 	 * MAC address information from the bootstrapping information. */
2094c1d255d3SCy Schubert 	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
2095c1d255d3SCy Schubert 
2096c1d255d3SCy Schubert 	wpa_s->dpp_auth = auth;
2097c1d255d3SCy Schubert 	if (wpas_dpp_auth_init_next(wpa_s) < 0) {
2098c1d255d3SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
2099c1d255d3SCy Schubert 		wpa_s->dpp_auth = NULL;
2100c1d255d3SCy Schubert 	}
2101c1d255d3SCy Schubert }
2102c1d255d3SCy Schubert 
2103c1d255d3SCy Schubert 
2104c1d255d3SCy Schubert static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
2105c1d255d3SCy Schubert 						 void *timeout_ctx)
2106c1d255d3SCy Schubert {
2107c1d255d3SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
2108c1d255d3SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
2109c1d255d3SCy Schubert 
2110c1d255d3SCy Schubert 	if (!auth)
2111c1d255d3SCy Schubert 		return;
2112c1d255d3SCy Schubert 
2113c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Reconfig Reply wait timeout");
2114c1d255d3SCy Schubert 	offchannel_send_action_done(wpa_s);
2115c1d255d3SCy Schubert 	wpas_dpp_listen_stop(wpa_s);
2116c1d255d3SCy Schubert 	dpp_auth_deinit(auth);
2117c1d255d3SCy Schubert 	wpa_s->dpp_auth = NULL;
2118c1d255d3SCy Schubert }
2119c1d255d3SCy Schubert 
2120c1d255d3SCy Schubert 
2121c1d255d3SCy Schubert static void
2122c1d255d3SCy Schubert wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
2123c1d255d3SCy Schubert 				  const u8 *hdr, const u8 *buf, size_t len,
2124c1d255d3SCy Schubert 				  unsigned int freq)
2125c1d255d3SCy Schubert {
2126c1d255d3SCy Schubert 	const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
2127c1d255d3SCy Schubert 	u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
2128c1d255d3SCy Schubert 	struct dpp_configurator *conf;
2129c1d255d3SCy Schubert 	struct dpp_authentication *auth;
2130c1d255d3SCy Schubert 	unsigned int wait_time, max_wait_time;
2131c1d255d3SCy Schubert 	u16 group;
2132c1d255d3SCy Schubert 
2133c1d255d3SCy Schubert 	if (!wpa_s->dpp)
2134c1d255d3SCy Schubert 		return;
2135c1d255d3SCy Schubert 
2136c1d255d3SCy Schubert 	if (wpa_s->dpp_auth) {
2137c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2138c1d255d3SCy Schubert 			   "DPP: Ignore Reconfig Announcement during ongoing Authentication");
2139c1d255d3SCy Schubert 		return;
2140c1d255d3SCy Schubert 	}
2141c1d255d3SCy Schubert 
2142c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Reconfig Announcement from " MACSTR,
2143c1d255d3SCy Schubert 		   MAC2STR(src));
2144c1d255d3SCy Schubert 
2145c1d255d3SCy Schubert 	csign_hash = dpp_get_attr(buf, len, DPP_ATTR_C_SIGN_KEY_HASH,
2146c1d255d3SCy Schubert 				  &csign_hash_len);
2147c1d255d3SCy Schubert 	if (!csign_hash || csign_hash_len != SHA256_MAC_LEN) {
2148c1d255d3SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
2149c1d255d3SCy Schubert 			"Missing or invalid required Configurator C-sign key Hash attribute");
2150c1d255d3SCy Schubert 		return;
2151c1d255d3SCy Schubert 	}
2152c1d255d3SCy Schubert 	wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator C-sign key Hash (kid)",
2153c1d255d3SCy Schubert 		    csign_hash, csign_hash_len);
2154c1d255d3SCy Schubert 	conf = dpp_configurator_find_kid(wpa_s->dpp, csign_hash);
2155c1d255d3SCy Schubert 	if (!conf) {
2156c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2157c1d255d3SCy Schubert 			   "DPP: No matching Configurator information found");
2158c1d255d3SCy Schubert 		return;
2159c1d255d3SCy Schubert 	}
2160c1d255d3SCy Schubert 
2161c1d255d3SCy Schubert 	fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
2162c1d255d3SCy Schubert 			       &fcgroup_len);
2163c1d255d3SCy Schubert 	if (!fcgroup || fcgroup_len != 2) {
2164c1d255d3SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
2165c1d255d3SCy Schubert 			"Missing or invalid required Finite Cyclic Group attribute");
2166c1d255d3SCy Schubert 		return;
2167c1d255d3SCy Schubert 	}
2168c1d255d3SCy Schubert 	group = WPA_GET_LE16(fcgroup);
2169c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
2170c1d255d3SCy Schubert 
2171c1d255d3SCy Schubert 	a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
2172c1d255d3SCy Schubert 	e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
2173c1d255d3SCy Schubert 
2174c1d255d3SCy Schubert 	auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq, group,
2175c1d255d3SCy Schubert 				 a_nonce, a_nonce_len, e_id, e_id_len);
2176c1d255d3SCy Schubert 	if (!auth)
2177c1d255d3SCy Schubert 		return;
2178c1d255d3SCy Schubert 	wpas_dpp_set_testing_options(wpa_s, auth);
2179c1d255d3SCy Schubert 	if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) {
2180c1d255d3SCy Schubert 		dpp_auth_deinit(auth);
2181c1d255d3SCy Schubert 		return;
2182c1d255d3SCy Schubert 	}
2183c1d255d3SCy Schubert 
2184c1d255d3SCy Schubert 	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
2185c1d255d3SCy Schubert 	wpa_s->dpp_auth = auth;
2186c1d255d3SCy Schubert 
2187c1d255d3SCy Schubert 	wpa_s->dpp_in_response_listen = 0;
2188c1d255d3SCy Schubert 	wpa_s->dpp_auth_ok_on_ack = 0;
2189c1d255d3SCy Schubert 	wait_time = wpa_s->max_remain_on_chan;
2190c1d255d3SCy Schubert 	max_wait_time = wpa_s->dpp_resp_wait_time ?
2191c1d255d3SCy Schubert 		wpa_s->dpp_resp_wait_time : 2000;
2192c1d255d3SCy Schubert 	if (wait_time > max_wait_time)
2193c1d255d3SCy Schubert 		wait_time = max_wait_time;
2194c1d255d3SCy Schubert 	wait_time += 10; /* give the driver some extra time to complete */
2195c1d255d3SCy Schubert 	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
2196c1d255d3SCy Schubert 			       wpas_dpp_reconfig_reply_wait_timeout,
2197c1d255d3SCy Schubert 			       wpa_s, NULL);
2198c1d255d3SCy Schubert 	wait_time -= 10;
2199c1d255d3SCy Schubert 
2200c1d255d3SCy Schubert 	wpas_dpp_stop_listen_for_tx(wpa_s, freq, wait_time);
2201c1d255d3SCy Schubert 
2202c1d255d3SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
2203c1d255d3SCy Schubert 		MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_REQ);
2204c1d255d3SCy Schubert 	if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
2205c1d255d3SCy Schubert 				   wpabuf_head(auth->reconfig_req_msg),
2206c1d255d3SCy Schubert 				   wpabuf_len(auth->reconfig_req_msg),
2207c1d255d3SCy Schubert 				   wait_time, wpas_dpp_tx_status, 0) < 0) {
2208c1d255d3SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
2209c1d255d3SCy Schubert 		wpa_s->dpp_auth = NULL;
2210c1d255d3SCy Schubert 	}
2211c1d255d3SCy Schubert }
2212c1d255d3SCy Schubert 
2213c1d255d3SCy Schubert 
2214c1d255d3SCy Schubert static void
2215c1d255d3SCy Schubert wpas_dpp_rx_reconfig_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
2216c1d255d3SCy Schubert 			      const u8 *hdr, const u8 *buf, size_t len,
2217c1d255d3SCy Schubert 			      unsigned int freq)
2218c1d255d3SCy Schubert {
2219c1d255d3SCy Schubert 	struct wpa_ssid *ssid;
2220c1d255d3SCy Schubert 	struct dpp_authentication *auth;
2221c1d255d3SCy Schubert 
2222c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Request from "
2223c1d255d3SCy Schubert 		   MACSTR, MAC2STR(src));
2224c1d255d3SCy Schubert 
2225c1d255d3SCy Schubert 	if (!wpa_s->dpp)
2226c1d255d3SCy Schubert 		return;
2227c1d255d3SCy Schubert 	if (wpa_s->dpp_auth) {
2228c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2229c1d255d3SCy Schubert 			   "DPP: Not ready for reconfiguration - pending authentication exchange in progress");
2230c1d255d3SCy Schubert 		return;
2231c1d255d3SCy Schubert 	}
2232c1d255d3SCy Schubert 	if (!wpa_s->dpp_reconfig_ssid) {
2233c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2234c1d255d3SCy Schubert 			   "DPP: Not ready for reconfiguration - not requested");
2235c1d255d3SCy Schubert 		return;
2236c1d255d3SCy Schubert 	}
2237c1d255d3SCy Schubert 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
2238c1d255d3SCy Schubert 		if (ssid == wpa_s->dpp_reconfig_ssid &&
2239c1d255d3SCy Schubert 		    ssid->id == wpa_s->dpp_reconfig_ssid_id)
2240c1d255d3SCy Schubert 			break;
2241c1d255d3SCy Schubert 	}
2242c1d255d3SCy Schubert 	if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
2243c1d255d3SCy Schubert 	    !ssid->dpp_csign) {
2244c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2245c1d255d3SCy Schubert 			   "DPP: Not ready for reconfiguration - no matching network profile with Connector found");
2246c1d255d3SCy Schubert 		return;
2247c1d255d3SCy Schubert 	}
2248c1d255d3SCy Schubert 
2249c1d255d3SCy Schubert 	auth = dpp_reconfig_auth_req_rx(wpa_s->dpp, wpa_s, ssid->dpp_connector,
2250c1d255d3SCy Schubert 					ssid->dpp_netaccesskey,
2251c1d255d3SCy Schubert 					ssid->dpp_netaccesskey_len,
2252c1d255d3SCy Schubert 					ssid->dpp_csign, ssid->dpp_csign_len,
2253c1d255d3SCy Schubert 					freq, hdr, buf, len);
2254c1d255d3SCy Schubert 	if (!auth)
2255c1d255d3SCy Schubert 		return;
2256c1d255d3SCy Schubert 	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
2257c1d255d3SCy Schubert 	wpa_s->dpp_auth = auth;
2258c1d255d3SCy Schubert 
2259c1d255d3SCy Schubert 	wpas_dpp_chirp_stop(wpa_s);
2260c1d255d3SCy Schubert 
2261c1d255d3SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
2262c1d255d3SCy Schubert 		MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_RESP);
2263c1d255d3SCy Schubert 	if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
2264c1d255d3SCy Schubert 				   wpabuf_head(auth->reconfig_resp_msg),
2265c1d255d3SCy Schubert 				   wpabuf_len(auth->reconfig_resp_msg),
2266c1d255d3SCy Schubert 				   500, wpas_dpp_tx_status, 0) < 0) {
2267c1d255d3SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
2268c1d255d3SCy Schubert 		wpa_s->dpp_auth = NULL;
2269c1d255d3SCy Schubert 	}
2270c1d255d3SCy Schubert }
2271c1d255d3SCy Schubert 
2272c1d255d3SCy Schubert 
2273c1d255d3SCy Schubert static void
2274c1d255d3SCy Schubert wpas_dpp_rx_reconfig_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
2275c1d255d3SCy Schubert 			       const u8 *hdr, const u8 *buf, size_t len,
2276c1d255d3SCy Schubert 			       unsigned int freq)
2277c1d255d3SCy Schubert {
2278c1d255d3SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
2279c1d255d3SCy Schubert 	struct wpabuf *conf;
2280c1d255d3SCy Schubert 
2281c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Response from "
2282c1d255d3SCy Schubert 		   MACSTR, MAC2STR(src));
2283c1d255d3SCy Schubert 
2284c1d255d3SCy Schubert 	if (!auth || !auth->reconfig || !auth->configurator) {
2285c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2286c1d255d3SCy Schubert 			   "DPP: No DPP Reconfig Authentication in progress - drop");
2287c1d255d3SCy Schubert 		return;
2288c1d255d3SCy Schubert 	}
2289c1d255d3SCy Schubert 
2290c1d255d3SCy Schubert 	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
2291c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
2292c1d255d3SCy Schubert 			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
2293c1d255d3SCy Schubert 		return;
2294c1d255d3SCy Schubert 	}
2295c1d255d3SCy Schubert 
2296c1d255d3SCy Schubert 	conf = dpp_reconfig_auth_resp_rx(auth, hdr, buf, len);
2297c1d255d3SCy Schubert 	if (!conf)
2298c1d255d3SCy Schubert 		return;
2299c1d255d3SCy Schubert 
2300c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout, wpa_s, NULL);
2301c1d255d3SCy Schubert 
2302c1d255d3SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
2303c1d255d3SCy Schubert 		MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_CONF);
2304c1d255d3SCy Schubert 	if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
2305c1d255d3SCy Schubert 				   wpabuf_head(conf), wpabuf_len(conf),
2306c1d255d3SCy Schubert 				   500, wpas_dpp_tx_status, 0) < 0) {
2307c1d255d3SCy Schubert 		wpabuf_free(conf);
2308c1d255d3SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
2309c1d255d3SCy Schubert 		wpa_s->dpp_auth = NULL;
2310c1d255d3SCy Schubert 		return;
2311c1d255d3SCy Schubert 	}
2312c1d255d3SCy Schubert 	wpabuf_free(conf);
2313c1d255d3SCy Schubert 
2314c1d255d3SCy Schubert 	wpas_dpp_start_gas_server(wpa_s);
2315c1d255d3SCy Schubert }
2316c1d255d3SCy Schubert 
2317c1d255d3SCy Schubert 
2318c1d255d3SCy Schubert static void
2319c1d255d3SCy Schubert wpas_dpp_rx_reconfig_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
2320c1d255d3SCy Schubert 			       const u8 *hdr, const u8 *buf, size_t len,
2321c1d255d3SCy Schubert 			       unsigned int freq)
2322c1d255d3SCy Schubert {
2323c1d255d3SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
2324c1d255d3SCy Schubert 
2325c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Confirm from "
2326c1d255d3SCy Schubert 		   MACSTR, MAC2STR(src));
2327c1d255d3SCy Schubert 
2328c1d255d3SCy Schubert 	if (!auth || !auth->reconfig || auth->configurator) {
2329c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2330c1d255d3SCy Schubert 			   "DPP: No DPP Reconfig Authentication in progress - drop");
2331c1d255d3SCy Schubert 		return;
2332c1d255d3SCy Schubert 	}
2333c1d255d3SCy Schubert 
2334c1d255d3SCy Schubert 	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
2335c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
2336c1d255d3SCy Schubert 			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
2337c1d255d3SCy Schubert 		return;
2338c1d255d3SCy Schubert 	}
2339c1d255d3SCy Schubert 
2340c1d255d3SCy Schubert 	if (dpp_reconfig_auth_conf_rx(auth, hdr, buf, len) < 0)
2341c1d255d3SCy Schubert 		return;
2342c1d255d3SCy Schubert 
2343c1d255d3SCy Schubert 	wpas_dpp_start_gas_client(wpa_s);
2344206b73d0SCy Schubert }
2345206b73d0SCy Schubert 
23464bc52338SCy Schubert #endif /* CONFIG_DPP2 */
23474bc52338SCy Schubert 
23484bc52338SCy Schubert 
234985732ac8SCy Schubert static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
235085732ac8SCy Schubert 				       const u8 *src,
235185732ac8SCy Schubert 				       const u8 *buf, size_t len)
235285732ac8SCy Schubert {
235385732ac8SCy Schubert 	struct wpa_ssid *ssid;
235485732ac8SCy Schubert 	const u8 *connector, *trans_id, *status;
235585732ac8SCy Schubert 	u16 connector_len, trans_id_len, status_len;
2356c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2357c1d255d3SCy Schubert 	const u8 *version;
2358c1d255d3SCy Schubert 	u16 version_len;
2359c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
2360c1d255d3SCy Schubert 	u8 peer_version = 1;
236185732ac8SCy Schubert 	struct dpp_introduction intro;
236285732ac8SCy Schubert 	struct rsn_pmksa_cache_entry *entry;
236385732ac8SCy Schubert 	struct os_time now;
236485732ac8SCy Schubert 	struct os_reltime rnow;
236585732ac8SCy Schubert 	os_time_t expiry;
236685732ac8SCy Schubert 	unsigned int seconds;
236785732ac8SCy Schubert 	enum dpp_status_error res;
236885732ac8SCy Schubert 
236985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Response from " MACSTR,
237085732ac8SCy Schubert 		   MAC2STR(src));
237185732ac8SCy Schubert 	if (is_zero_ether_addr(wpa_s->dpp_intro_bssid) ||
237285732ac8SCy Schubert 	    os_memcmp(src, wpa_s->dpp_intro_bssid, ETH_ALEN) != 0) {
237385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Not waiting for response from "
237485732ac8SCy Schubert 			   MACSTR " - drop", MAC2STR(src));
237585732ac8SCy Schubert 		return;
237685732ac8SCy Schubert 	}
237785732ac8SCy Schubert 	offchannel_send_action_done(wpa_s);
237885732ac8SCy Schubert 
237985732ac8SCy Schubert 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
238085732ac8SCy Schubert 		if (ssid == wpa_s->dpp_intro_network)
238185732ac8SCy Schubert 			break;
238285732ac8SCy Schubert 	}
238385732ac8SCy Schubert 	if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
238485732ac8SCy Schubert 	    !ssid->dpp_csign) {
238585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
238685732ac8SCy Schubert 			   "DPP: Profile not found for network introduction");
238785732ac8SCy Schubert 		return;
238885732ac8SCy Schubert 	}
238985732ac8SCy Schubert 
239085732ac8SCy Schubert 	trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
239185732ac8SCy Schubert 			       &trans_id_len);
239285732ac8SCy Schubert 	if (!trans_id || trans_id_len != 1) {
239385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
239485732ac8SCy Schubert 			   "DPP: Peer did not include Transaction ID");
239585732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
239685732ac8SCy Schubert 			" fail=missing_transaction_id", MAC2STR(src));
239785732ac8SCy Schubert 		goto fail;
239885732ac8SCy Schubert 	}
239985732ac8SCy Schubert 	if (trans_id[0] != TRANSACTION_ID) {
240085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
240185732ac8SCy Schubert 			   "DPP: Ignore frame with unexpected Transaction ID %u",
240285732ac8SCy Schubert 			   trans_id[0]);
240385732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
240485732ac8SCy Schubert 			" fail=transaction_id_mismatch", MAC2STR(src));
240585732ac8SCy Schubert 		goto fail;
240685732ac8SCy Schubert 	}
240785732ac8SCy Schubert 
240885732ac8SCy Schubert 	status = dpp_get_attr(buf, len, DPP_ATTR_STATUS, &status_len);
240985732ac8SCy Schubert 	if (!status || status_len != 1) {
241085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Peer did not include Status");
241185732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
241285732ac8SCy Schubert 			" fail=missing_status", MAC2STR(src));
241385732ac8SCy Schubert 		goto fail;
241485732ac8SCy Schubert 	}
241585732ac8SCy Schubert 	if (status[0] != DPP_STATUS_OK) {
241685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
241785732ac8SCy Schubert 			   "DPP: Peer rejected network introduction: Status %u",
241885732ac8SCy Schubert 			   status[0]);
241985732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
242085732ac8SCy Schubert 			" status=%u", MAC2STR(src), status[0]);
2421c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2422c1d255d3SCy Schubert 		wpas_dpp_send_conn_status_result(wpa_s, status[0]);
2423c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
242485732ac8SCy Schubert 		goto fail;
242585732ac8SCy Schubert 	}
242685732ac8SCy Schubert 
242785732ac8SCy Schubert 	connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len);
242885732ac8SCy Schubert 	if (!connector) {
242985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
243085732ac8SCy Schubert 			   "DPP: Peer did not include its Connector");
243185732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
243285732ac8SCy Schubert 			" fail=missing_connector", MAC2STR(src));
243385732ac8SCy Schubert 		goto fail;
243485732ac8SCy Schubert 	}
243585732ac8SCy Schubert 
243685732ac8SCy Schubert 	res = dpp_peer_intro(&intro, ssid->dpp_connector,
243785732ac8SCy Schubert 			     ssid->dpp_netaccesskey,
243885732ac8SCy Schubert 			     ssid->dpp_netaccesskey_len,
243985732ac8SCy Schubert 			     ssid->dpp_csign,
244085732ac8SCy Schubert 			     ssid->dpp_csign_len,
244185732ac8SCy Schubert 			     connector, connector_len, &expiry);
244285732ac8SCy Schubert 	if (res != DPP_STATUS_OK) {
244385732ac8SCy Schubert 		wpa_printf(MSG_INFO,
244485732ac8SCy Schubert 			   "DPP: Network Introduction protocol resulted in failure");
244585732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
244685732ac8SCy Schubert 			" fail=peer_connector_validation_failed", MAC2STR(src));
2447c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2448c1d255d3SCy Schubert 		wpas_dpp_send_conn_status_result(wpa_s, res);
2449c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
245085732ac8SCy Schubert 		goto fail;
245185732ac8SCy Schubert 	}
245285732ac8SCy Schubert 
245385732ac8SCy Schubert 	entry = os_zalloc(sizeof(*entry));
245485732ac8SCy Schubert 	if (!entry)
245585732ac8SCy Schubert 		goto fail;
245685732ac8SCy Schubert 	os_memcpy(entry->aa, src, ETH_ALEN);
245785732ac8SCy Schubert 	os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN);
245885732ac8SCy Schubert 	os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
245985732ac8SCy Schubert 	entry->pmk_len = intro.pmk_len;
246085732ac8SCy Schubert 	entry->akmp = WPA_KEY_MGMT_DPP;
2461c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2462c1d255d3SCy Schubert 	version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
2463c1d255d3SCy Schubert 			       &version_len);
2464c1d255d3SCy Schubert 	if (version && version_len >= 1)
2465c1d255d3SCy Schubert 		peer_version = version[0];
2466*32a95656SCy Schubert #ifdef CONFIG_DPP3
2467*32a95656SCy Schubert 	if (intro.peer_version && intro.peer_version >= 2 &&
2468*32a95656SCy Schubert 	    peer_version != intro.peer_version) {
2469*32a95656SCy Schubert 		wpa_printf(MSG_INFO,
2470*32a95656SCy Schubert 			   "DPP: Protocol version mismatch (Connector: %d Attribute: %d",
2471*32a95656SCy Schubert 			   intro.peer_version, peer_version);
2472*32a95656SCy Schubert 		wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_NO_MATCH);
2473*32a95656SCy Schubert 		goto fail;
2474*32a95656SCy Schubert 	}
2475*32a95656SCy Schubert #endif /* CONFIG_DPP3 */
2476c1d255d3SCy Schubert 	entry->dpp_pfs = peer_version >= 2;
2477c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
247885732ac8SCy Schubert 	if (expiry) {
247985732ac8SCy Schubert 		os_get_time(&now);
248085732ac8SCy Schubert 		seconds = expiry - now.sec;
248185732ac8SCy Schubert 	} else {
248285732ac8SCy Schubert 		seconds = 86400 * 7;
248385732ac8SCy Schubert 	}
248485732ac8SCy Schubert 	os_get_reltime(&rnow);
248585732ac8SCy Schubert 	entry->expiration = rnow.sec + seconds;
248685732ac8SCy Schubert 	entry->reauth_time = rnow.sec + seconds;
248785732ac8SCy Schubert 	entry->network_ctx = ssid;
248885732ac8SCy Schubert 	wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
248985732ac8SCy Schubert 
249085732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
2491c1d255d3SCy Schubert 		" status=%u version=%u", MAC2STR(src), status[0], peer_version);
249285732ac8SCy Schubert 
249385732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
249485732ac8SCy Schubert 		   "DPP: Try connection again after successful network introduction");
249585732ac8SCy Schubert 	if (wpa_supplicant_fast_associate(wpa_s) != 1) {
249685732ac8SCy Schubert 		wpa_supplicant_cancel_sched_scan(wpa_s);
249785732ac8SCy Schubert 		wpa_supplicant_req_scan(wpa_s, 0, 0);
249885732ac8SCy Schubert 	}
249985732ac8SCy Schubert fail:
250085732ac8SCy Schubert 	os_memset(&intro, 0, sizeof(intro));
250185732ac8SCy Schubert }
250285732ac8SCy Schubert 
250385732ac8SCy Schubert 
250485732ac8SCy Schubert static int wpas_dpp_allow_ir(struct wpa_supplicant *wpa_s, unsigned int freq)
250585732ac8SCy Schubert {
250685732ac8SCy Schubert 	int i, j;
250785732ac8SCy Schubert 
250885732ac8SCy Schubert 	if (!wpa_s->hw.modes)
250985732ac8SCy Schubert 		return -1;
251085732ac8SCy Schubert 
251185732ac8SCy Schubert 	for (i = 0; i < wpa_s->hw.num_modes; i++) {
251285732ac8SCy Schubert 		struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
251385732ac8SCy Schubert 
251485732ac8SCy Schubert 		for (j = 0; j < mode->num_channels; j++) {
251585732ac8SCy Schubert 			struct hostapd_channel_data *chan = &mode->channels[j];
251685732ac8SCy Schubert 
251785732ac8SCy Schubert 			if (chan->freq != (int) freq)
251885732ac8SCy Schubert 				continue;
251985732ac8SCy Schubert 
252085732ac8SCy Schubert 			if (chan->flag & (HOSTAPD_CHAN_DISABLED |
252185732ac8SCy Schubert 					  HOSTAPD_CHAN_NO_IR |
252285732ac8SCy Schubert 					  HOSTAPD_CHAN_RADAR))
252385732ac8SCy Schubert 				continue;
252485732ac8SCy Schubert 
252585732ac8SCy Schubert 			return 1;
252685732ac8SCy Schubert 		}
252785732ac8SCy Schubert 	}
252885732ac8SCy Schubert 
252985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
253085732ac8SCy Schubert 		   "DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list",
253185732ac8SCy Schubert 		   freq);
253285732ac8SCy Schubert 
253385732ac8SCy Schubert 	return 0;
253485732ac8SCy Schubert }
253585732ac8SCy Schubert 
253685732ac8SCy Schubert 
253785732ac8SCy Schubert static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s,
253885732ac8SCy Schubert 				      struct dpp_pkex *pkex)
253985732ac8SCy Schubert {
254085732ac8SCy Schubert 	if (pkex->freq == 2437)
254185732ac8SCy Schubert 		pkex->freq = 5745;
254285732ac8SCy Schubert 	else if (pkex->freq == 5745)
254385732ac8SCy Schubert 		pkex->freq = 5220;
254485732ac8SCy Schubert 	else if (pkex->freq == 5220)
254585732ac8SCy Schubert 		pkex->freq = 60480;
254685732ac8SCy Schubert 	else
254785732ac8SCy Schubert 		return -1; /* no more channels to try */
254885732ac8SCy Schubert 
254985732ac8SCy Schubert 	if (wpas_dpp_allow_ir(wpa_s, pkex->freq) == 1) {
255085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz",
255185732ac8SCy Schubert 			   pkex->freq);
255285732ac8SCy Schubert 		return 0;
255385732ac8SCy Schubert 	}
255485732ac8SCy Schubert 
255585732ac8SCy Schubert 	/* Could not use this channel - try the next one */
255685732ac8SCy Schubert 	return wpas_dpp_pkex_next_channel(wpa_s, pkex);
255785732ac8SCy Schubert }
255885732ac8SCy Schubert 
255985732ac8SCy Schubert 
256085732ac8SCy Schubert static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
256185732ac8SCy Schubert {
256285732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
256385732ac8SCy Schubert 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
256485732ac8SCy Schubert 
256585732ac8SCy Schubert 	if (!pkex || !pkex->exchange_req)
256685732ac8SCy Schubert 		return;
256785732ac8SCy Schubert 	if (pkex->exch_req_tries >= 5) {
256885732ac8SCy Schubert 		if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) {
256985732ac8SCy Schubert 			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
257085732ac8SCy Schubert 				"No response from PKEX peer");
257185732ac8SCy Schubert 			dpp_pkex_free(pkex);
257285732ac8SCy Schubert 			wpa_s->dpp_pkex = NULL;
257385732ac8SCy Schubert 			return;
257485732ac8SCy Schubert 		}
257585732ac8SCy Schubert 		pkex->exch_req_tries = 0;
257685732ac8SCy Schubert 	}
257785732ac8SCy Schubert 
257885732ac8SCy Schubert 	pkex->exch_req_tries++;
257985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)",
258085732ac8SCy Schubert 		   pkex->exch_req_tries);
258185732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
2582*32a95656SCy Schubert 		MAC2STR(broadcast), pkex->freq,
2583*32a95656SCy Schubert 		pkex->v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
2584*32a95656SCy Schubert 		DPP_PA_PKEX_V1_EXCHANGE_REQ);
258585732ac8SCy Schubert 	offchannel_send_action(wpa_s, pkex->freq, broadcast,
258685732ac8SCy Schubert 			       wpa_s->own_addr, broadcast,
258785732ac8SCy Schubert 			       wpabuf_head(pkex->exchange_req),
258885732ac8SCy Schubert 			       wpabuf_len(pkex->exchange_req),
258985732ac8SCy Schubert 			       pkex->exch_req_wait_time,
259085732ac8SCy Schubert 			       wpas_dpp_tx_pkex_status, 0);
259185732ac8SCy Schubert }
259285732ac8SCy Schubert 
259385732ac8SCy Schubert 
259485732ac8SCy Schubert static void
259585732ac8SCy Schubert wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
259685732ac8SCy Schubert 			unsigned int freq, const u8 *dst,
259785732ac8SCy Schubert 			const u8 *src, const u8 *bssid,
259885732ac8SCy Schubert 			const u8 *data, size_t data_len,
259985732ac8SCy Schubert 			enum offchannel_send_action_result result)
260085732ac8SCy Schubert {
260185732ac8SCy Schubert 	const char *res_txt;
260285732ac8SCy Schubert 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
260385732ac8SCy Schubert 
260485732ac8SCy Schubert 	res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
260585732ac8SCy Schubert 		(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
260685732ac8SCy Schubert 		 "FAILED");
260785732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
260885732ac8SCy Schubert 		   " result=%s (PKEX)",
260985732ac8SCy Schubert 		   freq, MAC2STR(dst), res_txt);
261085732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
261185732ac8SCy Schubert 		" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
261285732ac8SCy Schubert 
261385732ac8SCy Schubert 	if (!pkex) {
261485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
261585732ac8SCy Schubert 			   "DPP: Ignore TX status since there is no ongoing PKEX exchange");
261685732ac8SCy Schubert 		return;
261785732ac8SCy Schubert 	}
261885732ac8SCy Schubert 
261985732ac8SCy Schubert 	if (pkex->failed) {
262085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
262185732ac8SCy Schubert 			   "DPP: Terminate PKEX exchange due to an earlier error");
262285732ac8SCy Schubert 		if (pkex->t > pkex->own_bi->pkex_t)
262385732ac8SCy Schubert 			pkex->own_bi->pkex_t = pkex->t;
262485732ac8SCy Schubert 		dpp_pkex_free(pkex);
262585732ac8SCy Schubert 		wpa_s->dpp_pkex = NULL;
262685732ac8SCy Schubert 		return;
262785732ac8SCy Schubert 	}
262885732ac8SCy Schubert 
262985732ac8SCy Schubert 	if (pkex->exch_req_wait_time && pkex->exchange_req) {
263085732ac8SCy Schubert 		/* Wait for PKEX Exchange Response frame and retry request if
263185732ac8SCy Schubert 		 * no response is seen. */
263285732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
263385732ac8SCy Schubert 		eloop_register_timeout(pkex->exch_req_wait_time / 1000,
263485732ac8SCy Schubert 				       (pkex->exch_req_wait_time % 1000) * 1000,
263585732ac8SCy Schubert 				       wpas_dpp_pkex_retry_timeout, wpa_s,
263685732ac8SCy Schubert 				       NULL);
263785732ac8SCy Schubert 	}
263885732ac8SCy Schubert }
263985732ac8SCy Schubert 
264085732ac8SCy Schubert 
264185732ac8SCy Schubert static void
264285732ac8SCy Schubert wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src,
2643*32a95656SCy Schubert 			      const u8 *buf, size_t len, unsigned int freq,
2644*32a95656SCy Schubert 			      bool v2)
264585732ac8SCy Schubert {
264685732ac8SCy Schubert 	struct wpabuf *msg;
264785732ac8SCy Schubert 	unsigned int wait_time;
264885732ac8SCy Schubert 
264985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR,
265085732ac8SCy Schubert 		   MAC2STR(src));
265185732ac8SCy Schubert 
265285732ac8SCy Schubert 	/* TODO: Support multiple PKEX codes by iterating over all the enabled
265385732ac8SCy Schubert 	 * values here */
265485732ac8SCy Schubert 
265585732ac8SCy Schubert 	if (!wpa_s->dpp_pkex_code || !wpa_s->dpp_pkex_bi) {
265685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
265785732ac8SCy Schubert 			   "DPP: No PKEX code configured - ignore request");
265885732ac8SCy Schubert 		return;
265985732ac8SCy Schubert 	}
266085732ac8SCy Schubert 
266185732ac8SCy Schubert 	if (wpa_s->dpp_pkex) {
266285732ac8SCy Schubert 		/* TODO: Support parallel operations */
266385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
266485732ac8SCy Schubert 			   "DPP: Already in PKEX session - ignore new request");
266585732ac8SCy Schubert 		return;
266685732ac8SCy Schubert 	}
266785732ac8SCy Schubert 
266885732ac8SCy Schubert 	wpa_s->dpp_pkex = dpp_pkex_rx_exchange_req(wpa_s, wpa_s->dpp_pkex_bi,
266985732ac8SCy Schubert 						   wpa_s->own_addr, src,
267085732ac8SCy Schubert 						   wpa_s->dpp_pkex_identifier,
267185732ac8SCy Schubert 						   wpa_s->dpp_pkex_code,
2672*32a95656SCy Schubert 						   buf, len, v2);
267385732ac8SCy Schubert 	if (!wpa_s->dpp_pkex) {
267485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
267585732ac8SCy Schubert 			   "DPP: Failed to process the request - ignore it");
267685732ac8SCy Schubert 		return;
267785732ac8SCy Schubert 	}
267885732ac8SCy Schubert 
267985732ac8SCy Schubert 	msg = wpa_s->dpp_pkex->exchange_resp;
268085732ac8SCy Schubert 	wait_time = wpa_s->max_remain_on_chan;
268185732ac8SCy Schubert 	if (wait_time > 2000)
268285732ac8SCy Schubert 		wait_time = 2000;
268385732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
268485732ac8SCy Schubert 		MAC2STR(src), freq, DPP_PA_PKEX_EXCHANGE_RESP);
268585732ac8SCy Schubert 	offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
268685732ac8SCy Schubert 			       broadcast,
268785732ac8SCy Schubert 			       wpabuf_head(msg), wpabuf_len(msg),
268885732ac8SCy Schubert 			       wait_time, wpas_dpp_tx_pkex_status, 0);
268985732ac8SCy Schubert }
269085732ac8SCy Schubert 
269185732ac8SCy Schubert 
269285732ac8SCy Schubert static void
269385732ac8SCy Schubert wpas_dpp_rx_pkex_exchange_resp(struct wpa_supplicant *wpa_s, const u8 *src,
269485732ac8SCy Schubert 			       const u8 *buf, size_t len, unsigned int freq)
269585732ac8SCy Schubert {
269685732ac8SCy Schubert 	struct wpabuf *msg;
269785732ac8SCy Schubert 	unsigned int wait_time;
269885732ac8SCy Schubert 
269985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR,
270085732ac8SCy Schubert 		   MAC2STR(src));
270185732ac8SCy Schubert 
270285732ac8SCy Schubert 	/* TODO: Support multiple PKEX codes by iterating over all the enabled
270385732ac8SCy Schubert 	 * values here */
270485732ac8SCy Schubert 
270585732ac8SCy Schubert 	if (!wpa_s->dpp_pkex || !wpa_s->dpp_pkex->initiator ||
270685732ac8SCy Schubert 	    wpa_s->dpp_pkex->exchange_done) {
270785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
270885732ac8SCy Schubert 		return;
270985732ac8SCy Schubert 	}
271085732ac8SCy Schubert 
271185732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
271285732ac8SCy Schubert 	wpa_s->dpp_pkex->exch_req_wait_time = 0;
271385732ac8SCy Schubert 
271485732ac8SCy Schubert 	msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, src, buf, len);
271585732ac8SCy Schubert 	if (!msg) {
271685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
271785732ac8SCy Schubert 		return;
271885732ac8SCy Schubert 	}
271985732ac8SCy Schubert 
272085732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR,
272185732ac8SCy Schubert 		   MAC2STR(src));
272285732ac8SCy Schubert 
272385732ac8SCy Schubert 	wait_time = wpa_s->max_remain_on_chan;
272485732ac8SCy Schubert 	if (wait_time > 2000)
272585732ac8SCy Schubert 		wait_time = 2000;
272685732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
272785732ac8SCy Schubert 		MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_REQ);
272885732ac8SCy Schubert 	offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
272985732ac8SCy Schubert 			       broadcast,
273085732ac8SCy Schubert 			       wpabuf_head(msg), wpabuf_len(msg),
273185732ac8SCy Schubert 			       wait_time, wpas_dpp_tx_pkex_status, 0);
273285732ac8SCy Schubert 	wpabuf_free(msg);
273385732ac8SCy Schubert }
273485732ac8SCy Schubert 
273585732ac8SCy Schubert 
273685732ac8SCy Schubert static struct dpp_bootstrap_info *
273785732ac8SCy Schubert wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer,
273885732ac8SCy Schubert 		     unsigned int freq)
273985732ac8SCy Schubert {
274085732ac8SCy Schubert 	struct dpp_bootstrap_info *bi;
274185732ac8SCy Schubert 
27424bc52338SCy Schubert 	bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq);
274385732ac8SCy Schubert 	if (!bi)
274485732ac8SCy Schubert 		return NULL;
274585732ac8SCy Schubert 	wpa_s->dpp_pkex = NULL;
274685732ac8SCy Schubert 	return bi;
274785732ac8SCy Schubert }
274885732ac8SCy Schubert 
274985732ac8SCy Schubert 
275085732ac8SCy Schubert static void
275185732ac8SCy Schubert wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src,
275285732ac8SCy Schubert 				   const u8 *hdr, const u8 *buf, size_t len,
275385732ac8SCy Schubert 				   unsigned int freq)
275485732ac8SCy Schubert {
275585732ac8SCy Schubert 	struct wpabuf *msg;
275685732ac8SCy Schubert 	unsigned int wait_time;
275785732ac8SCy Schubert 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
275885732ac8SCy Schubert 
275985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR,
276085732ac8SCy Schubert 		   MAC2STR(src));
276185732ac8SCy Schubert 
276285732ac8SCy Schubert 	if (!pkex || pkex->initiator || !pkex->exchange_done) {
276385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
276485732ac8SCy Schubert 		return;
276585732ac8SCy Schubert 	}
276685732ac8SCy Schubert 
276785732ac8SCy Schubert 	msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
276885732ac8SCy Schubert 	if (!msg) {
276985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
277085732ac8SCy Schubert 		if (pkex->failed) {
277185732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
277285732ac8SCy Schubert 			if (pkex->t > pkex->own_bi->pkex_t)
277385732ac8SCy Schubert 				pkex->own_bi->pkex_t = pkex->t;
277485732ac8SCy Schubert 			dpp_pkex_free(wpa_s->dpp_pkex);
277585732ac8SCy Schubert 			wpa_s->dpp_pkex = NULL;
277685732ac8SCy Schubert 		}
277785732ac8SCy Schubert 		return;
277885732ac8SCy Schubert 	}
277985732ac8SCy Schubert 
278085732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to "
278185732ac8SCy Schubert 		   MACSTR, MAC2STR(src));
278285732ac8SCy Schubert 
278385732ac8SCy Schubert 	wait_time = wpa_s->max_remain_on_chan;
278485732ac8SCy Schubert 	if (wait_time > 2000)
278585732ac8SCy Schubert 		wait_time = 2000;
278685732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
278785732ac8SCy Schubert 		MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_RESP);
278885732ac8SCy Schubert 	offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
278985732ac8SCy Schubert 			       broadcast,
279085732ac8SCy Schubert 			       wpabuf_head(msg), wpabuf_len(msg),
279185732ac8SCy Schubert 			       wait_time, wpas_dpp_tx_pkex_status, 0);
279285732ac8SCy Schubert 	wpabuf_free(msg);
279385732ac8SCy Schubert 
279485732ac8SCy Schubert 	wpas_dpp_pkex_finish(wpa_s, src, freq);
279585732ac8SCy Schubert }
279685732ac8SCy Schubert 
279785732ac8SCy Schubert 
279885732ac8SCy Schubert static void
279985732ac8SCy Schubert wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant *wpa_s, const u8 *src,
280085732ac8SCy Schubert 				    const u8 *hdr, const u8 *buf, size_t len,
280185732ac8SCy Schubert 				    unsigned int freq)
280285732ac8SCy Schubert {
280385732ac8SCy Schubert 	int res;
280485732ac8SCy Schubert 	struct dpp_bootstrap_info *bi;
280585732ac8SCy Schubert 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
280685732ac8SCy Schubert 	char cmd[500];
280785732ac8SCy Schubert 
280885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR,
280985732ac8SCy Schubert 		   MAC2STR(src));
281085732ac8SCy Schubert 
281185732ac8SCy Schubert 	if (!pkex || !pkex->initiator || !pkex->exchange_done) {
281285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
281385732ac8SCy Schubert 		return;
281485732ac8SCy Schubert 	}
281585732ac8SCy Schubert 
281685732ac8SCy Schubert 	res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len);
281785732ac8SCy Schubert 	if (res < 0) {
281885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
281985732ac8SCy Schubert 		return;
282085732ac8SCy Schubert 	}
282185732ac8SCy Schubert 
282285732ac8SCy Schubert 	bi = wpas_dpp_pkex_finish(wpa_s, src, freq);
282385732ac8SCy Schubert 	if (!bi)
282485732ac8SCy Schubert 		return;
282585732ac8SCy Schubert 
282685732ac8SCy Schubert 	os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
282785732ac8SCy Schubert 		    bi->id,
282885732ac8SCy Schubert 		    wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : "");
282985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
283085732ac8SCy Schubert 		   "DPP: Start authentication after PKEX with parameters: %s",
283185732ac8SCy Schubert 		   cmd);
283285732ac8SCy Schubert 	if (wpas_dpp_auth_init(wpa_s, cmd) < 0) {
283385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
283485732ac8SCy Schubert 			   "DPP: Authentication initialization failed");
2835c1d255d3SCy Schubert 		offchannel_send_action_done(wpa_s);
283685732ac8SCy Schubert 		return;
283785732ac8SCy Schubert 	}
283885732ac8SCy Schubert }
283985732ac8SCy Schubert 
284085732ac8SCy Schubert 
284185732ac8SCy Schubert void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
284285732ac8SCy Schubert 			const u8 *buf, size_t len, unsigned int freq)
284385732ac8SCy Schubert {
284485732ac8SCy Schubert 	u8 crypto_suite;
284585732ac8SCy Schubert 	enum dpp_public_action_frame_type type;
284685732ac8SCy Schubert 	const u8 *hdr;
284785732ac8SCy Schubert 	unsigned int pkex_t;
284885732ac8SCy Schubert 
284985732ac8SCy Schubert 	if (len < DPP_HDR_LEN)
285085732ac8SCy Schubert 		return;
285185732ac8SCy Schubert 	if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE)
285285732ac8SCy Schubert 		return;
285385732ac8SCy Schubert 	hdr = buf;
285485732ac8SCy Schubert 	buf += 4;
285585732ac8SCy Schubert 	len -= 4;
285685732ac8SCy Schubert 	crypto_suite = *buf++;
285785732ac8SCy Schubert 	type = *buf++;
285885732ac8SCy Schubert 	len -= 2;
285985732ac8SCy Schubert 
286085732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
286185732ac8SCy Schubert 		   "DPP: Received DPP Public Action frame crypto suite %u type %d from "
286285732ac8SCy Schubert 		   MACSTR " freq=%u",
286385732ac8SCy Schubert 		   crypto_suite, type, MAC2STR(src), freq);
286485732ac8SCy Schubert 	if (crypto_suite != 1) {
286585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
286685732ac8SCy Schubert 			   crypto_suite);
286785732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
286885732ac8SCy Schubert 			" freq=%u type=%d ignore=unsupported-crypto-suite",
286985732ac8SCy Schubert 			MAC2STR(src), freq, type);
287085732ac8SCy Schubert 		return;
287185732ac8SCy Schubert 	}
287285732ac8SCy Schubert 	wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
287385732ac8SCy Schubert 	if (dpp_check_attrs(buf, len) < 0) {
287485732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
287585732ac8SCy Schubert 			" freq=%u type=%d ignore=invalid-attributes",
287685732ac8SCy Schubert 			MAC2STR(src), freq, type);
287785732ac8SCy Schubert 		return;
287885732ac8SCy Schubert 	}
287985732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR " freq=%u type=%d",
288085732ac8SCy Schubert 		MAC2STR(src), freq, type);
288185732ac8SCy Schubert 
288285732ac8SCy Schubert 	switch (type) {
288385732ac8SCy Schubert 	case DPP_PA_AUTHENTICATION_REQ:
288485732ac8SCy Schubert 		wpas_dpp_rx_auth_req(wpa_s, src, hdr, buf, len, freq);
288585732ac8SCy Schubert 		break;
288685732ac8SCy Schubert 	case DPP_PA_AUTHENTICATION_RESP:
288785732ac8SCy Schubert 		wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len, freq);
288885732ac8SCy Schubert 		break;
288985732ac8SCy Schubert 	case DPP_PA_AUTHENTICATION_CONF:
289085732ac8SCy Schubert 		wpas_dpp_rx_auth_conf(wpa_s, src, hdr, buf, len);
289185732ac8SCy Schubert 		break;
289285732ac8SCy Schubert 	case DPP_PA_PEER_DISCOVERY_RESP:
289385732ac8SCy Schubert 		wpas_dpp_rx_peer_disc_resp(wpa_s, src, buf, len);
289485732ac8SCy Schubert 		break;
2895*32a95656SCy Schubert #ifdef CONFIG_DPP3
289685732ac8SCy Schubert 	case DPP_PA_PKEX_EXCHANGE_REQ:
2897*32a95656SCy Schubert 		/* This is for PKEXv2, but for now, process only with
2898*32a95656SCy Schubert 		 * CONFIG_DPP3 to avoid issues with a capability that has not
2899*32a95656SCy Schubert 		 * been tested with other implementations. */
2900*32a95656SCy Schubert 		wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq, true);
2901*32a95656SCy Schubert 		break;
2902*32a95656SCy Schubert #endif /* CONFIG_DPP3 */
2903*32a95656SCy Schubert 	case DPP_PA_PKEX_V1_EXCHANGE_REQ:
2904*32a95656SCy Schubert 		wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq,
2905*32a95656SCy Schubert 					      false);
290685732ac8SCy Schubert 		break;
290785732ac8SCy Schubert 	case DPP_PA_PKEX_EXCHANGE_RESP:
290885732ac8SCy Schubert 		wpas_dpp_rx_pkex_exchange_resp(wpa_s, src, buf, len, freq);
290985732ac8SCy Schubert 		break;
291085732ac8SCy Schubert 	case DPP_PA_PKEX_COMMIT_REVEAL_REQ:
291185732ac8SCy Schubert 		wpas_dpp_rx_pkex_commit_reveal_req(wpa_s, src, hdr, buf, len,
291285732ac8SCy Schubert 						   freq);
291385732ac8SCy Schubert 		break;
291485732ac8SCy Schubert 	case DPP_PA_PKEX_COMMIT_REVEAL_RESP:
291585732ac8SCy Schubert 		wpas_dpp_rx_pkex_commit_reveal_resp(wpa_s, src, hdr, buf, len,
291685732ac8SCy Schubert 						    freq);
291785732ac8SCy Schubert 		break;
29184bc52338SCy Schubert #ifdef CONFIG_DPP2
29194bc52338SCy Schubert 	case DPP_PA_CONFIGURATION_RESULT:
29204bc52338SCy Schubert 		wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len);
29214bc52338SCy Schubert 		break;
2922c1d255d3SCy Schubert 	case DPP_PA_CONNECTION_STATUS_RESULT:
2923c1d255d3SCy Schubert 		wpas_dpp_rx_conn_status_result(wpa_s, src, hdr, buf, len);
2924c1d255d3SCy Schubert 		break;
2925c1d255d3SCy Schubert 	case DPP_PA_PRESENCE_ANNOUNCEMENT:
2926c1d255d3SCy Schubert 		wpas_dpp_rx_presence_announcement(wpa_s, src, hdr, buf, len,
2927c1d255d3SCy Schubert 						  freq);
2928c1d255d3SCy Schubert 		break;
2929c1d255d3SCy Schubert 	case DPP_PA_RECONFIG_ANNOUNCEMENT:
2930c1d255d3SCy Schubert 		wpas_dpp_rx_reconfig_announcement(wpa_s, src, hdr, buf, len,
2931c1d255d3SCy Schubert 						  freq);
2932c1d255d3SCy Schubert 		break;
2933c1d255d3SCy Schubert 	case DPP_PA_RECONFIG_AUTH_REQ:
2934c1d255d3SCy Schubert 		wpas_dpp_rx_reconfig_auth_req(wpa_s, src, hdr, buf, len, freq);
2935c1d255d3SCy Schubert 		break;
2936c1d255d3SCy Schubert 	case DPP_PA_RECONFIG_AUTH_RESP:
2937c1d255d3SCy Schubert 		wpas_dpp_rx_reconfig_auth_resp(wpa_s, src, hdr, buf, len, freq);
2938c1d255d3SCy Schubert 		break;
2939c1d255d3SCy Schubert 	case DPP_PA_RECONFIG_AUTH_CONF:
2940c1d255d3SCy Schubert 		wpas_dpp_rx_reconfig_auth_conf(wpa_s, src, hdr, buf, len, freq);
2941c1d255d3SCy Schubert 		break;
29424bc52338SCy Schubert #endif /* CONFIG_DPP2 */
294385732ac8SCy Schubert 	default:
294485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
294585732ac8SCy Schubert 			   "DPP: Ignored unsupported frame subtype %d", type);
294685732ac8SCy Schubert 		break;
294785732ac8SCy Schubert 	}
294885732ac8SCy Schubert 
294985732ac8SCy Schubert 	if (wpa_s->dpp_pkex)
295085732ac8SCy Schubert 		pkex_t = wpa_s->dpp_pkex->t;
295185732ac8SCy Schubert 	else if (wpa_s->dpp_pkex_bi)
295285732ac8SCy Schubert 		pkex_t = wpa_s->dpp_pkex_bi->pkex_t;
295385732ac8SCy Schubert 	else
295485732ac8SCy Schubert 		pkex_t = 0;
295585732ac8SCy Schubert 	if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
295685732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
295785732ac8SCy Schubert 		wpas_dpp_pkex_remove(wpa_s, "*");
295885732ac8SCy Schubert 	}
295985732ac8SCy Schubert }
296085732ac8SCy Schubert 
296185732ac8SCy Schubert 
296285732ac8SCy Schubert static struct wpabuf *
2963c1d255d3SCy Schubert wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa,
2964c1d255d3SCy Schubert 			 const u8 *query, size_t query_len, u16 *comeback_delay)
296585732ac8SCy Schubert {
296685732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = ctx;
296785732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
296885732ac8SCy Schubert 	struct wpabuf *resp;
296985732ac8SCy Schubert 
297085732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR,
297185732ac8SCy Schubert 		   MAC2STR(sa));
2972c1d255d3SCy Schubert 	if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
297385732ac8SCy Schubert 	    os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
297485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
297585732ac8SCy Schubert 		return NULL;
297685732ac8SCy Schubert 	}
2977206b73d0SCy Schubert 
2978206b73d0SCy Schubert 	if (wpa_s->dpp_auth_ok_on_ack && auth->configurator) {
2979206b73d0SCy Schubert 		wpa_printf(MSG_DEBUG,
2980206b73d0SCy Schubert 			   "DPP: Have not received ACK for Auth Confirm yet - assume it was received based on this GAS request");
2981206b73d0SCy Schubert 		/* wpas_dpp_auth_success() would normally have been called from
2982206b73d0SCy Schubert 		 * TX status handler, but since there was no such handler call
2983206b73d0SCy Schubert 		 * yet, simply send out the event message and proceed with
2984206b73d0SCy Schubert 		 * exchange. */
2985206b73d0SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=1");
2986206b73d0SCy Schubert 		wpa_s->dpp_auth_ok_on_ack = 0;
2987206b73d0SCy Schubert 	}
2988206b73d0SCy Schubert 
298985732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG,
299085732ac8SCy Schubert 		    "DPP: Received Configuration Request (GAS Query Request)",
299185732ac8SCy Schubert 		    query, query_len);
299285732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
299385732ac8SCy Schubert 		MAC2STR(sa));
299485732ac8SCy Schubert 	resp = dpp_conf_req_rx(auth, query, query_len);
2995c1d255d3SCy Schubert 
2996c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2997c1d255d3SCy Schubert 	if (!resp && auth->waiting_cert) {
2998c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
2999c1d255d3SCy Schubert 		auth->cert_resp_ctx = resp_ctx;
3000c1d255d3SCy Schubert 		*comeback_delay = 500;
3001c1d255d3SCy Schubert 		return NULL;
3002c1d255d3SCy Schubert 	}
3003c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
3004c1d255d3SCy Schubert 
300585732ac8SCy Schubert 	if (!resp)
300685732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
300785732ac8SCy Schubert 	auth->conf_resp = resp;
3008c1d255d3SCy Schubert 	auth->gas_server_ctx = resp_ctx;
300985732ac8SCy Schubert 	return resp;
301085732ac8SCy Schubert }
301185732ac8SCy Schubert 
301285732ac8SCy Schubert 
301385732ac8SCy Schubert static void
301485732ac8SCy Schubert wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
301585732ac8SCy Schubert {
301685732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = ctx;
301785732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
301885732ac8SCy Schubert 
301985732ac8SCy Schubert 	if (!auth) {
302085732ac8SCy Schubert 		wpabuf_free(resp);
302185732ac8SCy Schubert 		return;
302285732ac8SCy Schubert 	}
302385732ac8SCy Schubert 	if (auth->conf_resp != resp) {
302485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
302585732ac8SCy Schubert 			   "DPP: Ignore GAS status report (ok=%d) for unknown response",
302685732ac8SCy Schubert 			ok);
302785732ac8SCy Schubert 		wpabuf_free(resp);
302885732ac8SCy Schubert 		return;
302985732ac8SCy Schubert 	}
303085732ac8SCy Schubert 
3031c1d255d3SCy Schubert #ifdef CONFIG_DPP2
3032c1d255d3SCy Schubert 	if (auth->waiting_csr && ok) {
3033c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Waiting for CSR");
3034c1d255d3SCy Schubert 		wpabuf_free(resp);
3035c1d255d3SCy Schubert 		return;
3036c1d255d3SCy Schubert 	}
3037c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
3038c1d255d3SCy Schubert 
303985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
304085732ac8SCy Schubert 		   ok);
304185732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
3042c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s, NULL);
304385732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
30444bc52338SCy Schubert #ifdef CONFIG_DPP2
30454bc52338SCy Schubert 	if (ok && auth->peer_version >= 2 &&
3046c1d255d3SCy Schubert 	    auth->conf_resp_status == DPP_STATUS_OK &&
3047c1d255d3SCy Schubert 	    !auth->waiting_conf_result) {
30484bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
30494bc52338SCy Schubert 		auth->waiting_conf_result = 1;
30504bc52338SCy Schubert 		auth->conf_resp = NULL;
30514bc52338SCy Schubert 		wpabuf_free(resp);
30524bc52338SCy Schubert 		eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
30534bc52338SCy Schubert 				     wpa_s, NULL);
30544bc52338SCy Schubert 		eloop_register_timeout(2, 0,
30554bc52338SCy Schubert 				       wpas_dpp_config_result_wait_timeout,
30564bc52338SCy Schubert 				       wpa_s, NULL);
30574bc52338SCy Schubert 		return;
30584bc52338SCy Schubert 	}
30594bc52338SCy Schubert #endif /* CONFIG_DPP2 */
306085732ac8SCy Schubert 	offchannel_send_action_done(wpa_s);
306185732ac8SCy Schubert 	wpas_dpp_listen_stop(wpa_s);
306285732ac8SCy Schubert 	if (ok)
306385732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
306485732ac8SCy Schubert 	else
306585732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
306685732ac8SCy Schubert 	dpp_auth_deinit(wpa_s->dpp_auth);
306785732ac8SCy Schubert 	wpa_s->dpp_auth = NULL;
306885732ac8SCy Schubert 	wpabuf_free(resp);
306985732ac8SCy Schubert }
307085732ac8SCy Schubert 
307185732ac8SCy Schubert 
307285732ac8SCy Schubert int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd)
307385732ac8SCy Schubert {
307485732ac8SCy Schubert 	struct dpp_authentication *auth;
307585732ac8SCy Schubert 	int ret = -1;
307685732ac8SCy Schubert 	char *curve = NULL;
307785732ac8SCy Schubert 
3078c1d255d3SCy Schubert 	auth = dpp_alloc_auth(wpa_s->dpp, wpa_s);
307985732ac8SCy Schubert 	if (!auth)
308085732ac8SCy Schubert 		return -1;
308185732ac8SCy Schubert 
308285732ac8SCy Schubert 	curve = get_param(cmd, " curve=");
308385732ac8SCy Schubert 	wpas_dpp_set_testing_options(wpa_s, auth);
3084c1d255d3SCy Schubert 	if (dpp_set_configurator(auth, cmd) == 0 &&
30854bc52338SCy Schubert 	    dpp_configurator_own_config(auth, curve, 0) == 0)
3086c1d255d3SCy Schubert 		ret = wpas_dpp_handle_config_obj(wpa_s, auth,
3087c1d255d3SCy Schubert 						 &auth->conf_obj[0]);
3088c1d255d3SCy Schubert 	if (!ret)
3089c1d255d3SCy Schubert 		wpas_dpp_post_process_config(wpa_s, auth);
309085732ac8SCy Schubert 
309185732ac8SCy Schubert 	dpp_auth_deinit(auth);
309285732ac8SCy Schubert 	os_free(curve);
309385732ac8SCy Schubert 
309485732ac8SCy Schubert 	return ret;
309585732ac8SCy Schubert }
309685732ac8SCy Schubert 
309785732ac8SCy Schubert 
309885732ac8SCy Schubert static void
309985732ac8SCy Schubert wpas_dpp_tx_introduction_status(struct wpa_supplicant *wpa_s,
310085732ac8SCy Schubert 				unsigned int freq, const u8 *dst,
310185732ac8SCy Schubert 				const u8 *src, const u8 *bssid,
310285732ac8SCy Schubert 				const u8 *data, size_t data_len,
310385732ac8SCy Schubert 				enum offchannel_send_action_result result)
310485732ac8SCy Schubert {
310585732ac8SCy Schubert 	const char *res_txt;
310685732ac8SCy Schubert 
310785732ac8SCy Schubert 	res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
310885732ac8SCy Schubert 		(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
310985732ac8SCy Schubert 		 "FAILED");
311085732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
311185732ac8SCy Schubert 		   " result=%s (DPP Peer Discovery Request)",
311285732ac8SCy Schubert 		   freq, MAC2STR(dst), res_txt);
311385732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
311485732ac8SCy Schubert 		" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
311585732ac8SCy Schubert 	/* TODO: Time out wait for response more quickly in error cases? */
311685732ac8SCy Schubert }
311785732ac8SCy Schubert 
311885732ac8SCy Schubert 
311985732ac8SCy Schubert int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
312085732ac8SCy Schubert 			   struct wpa_bss *bss)
312185732ac8SCy Schubert {
312285732ac8SCy Schubert 	struct os_time now;
312385732ac8SCy Schubert 	struct wpabuf *msg;
312485732ac8SCy Schubert 	unsigned int wait_time;
31254bc52338SCy Schubert 	const u8 *rsn;
31264bc52338SCy Schubert 	struct wpa_ie_data ied;
3127c1d255d3SCy Schubert 	size_t len;
312885732ac8SCy Schubert 
312985732ac8SCy Schubert 	if (!(ssid->key_mgmt & WPA_KEY_MGMT_DPP) || !bss)
313085732ac8SCy Schubert 		return 0; /* Not using DPP AKM - continue */
31314bc52338SCy Schubert 	rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
31324bc52338SCy Schubert 	if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
31334bc52338SCy Schubert 	    !(ied.key_mgmt & WPA_KEY_MGMT_DPP))
31344bc52338SCy Schubert 		return 0; /* AP does not support DPP AKM - continue */
313585732ac8SCy Schubert 	if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid))
313685732ac8SCy Schubert 		return 0; /* PMKSA exists for DPP AKM - continue */
313785732ac8SCy Schubert 
313885732ac8SCy Schubert 	if (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
313985732ac8SCy Schubert 	    !ssid->dpp_csign) {
314085732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR
314185732ac8SCy Schubert 			"missing %s",
314285732ac8SCy Schubert 			!ssid->dpp_connector ? "Connector" :
314385732ac8SCy Schubert 			(!ssid->dpp_netaccesskey ? "netAccessKey" :
314485732ac8SCy Schubert 			 "C-sign-key"));
314585732ac8SCy Schubert 		return -1;
314685732ac8SCy Schubert 	}
314785732ac8SCy Schubert 
314885732ac8SCy Schubert 	os_get_time(&now);
314985732ac8SCy Schubert 
315085732ac8SCy Schubert 	if (ssid->dpp_netaccesskey_expiry &&
315185732ac8SCy Schubert 	    (os_time_t) ssid->dpp_netaccesskey_expiry < now.sec) {
315285732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR
315385732ac8SCy Schubert 			"netAccessKey expired");
315485732ac8SCy Schubert 		return -1;
315585732ac8SCy Schubert 	}
315685732ac8SCy Schubert 
315785732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
315885732ac8SCy Schubert 		   "DPP: Starting network introduction protocol to derive PMKSA for "
315985732ac8SCy Schubert 		   MACSTR, MAC2STR(bss->bssid));
316085732ac8SCy Schubert 
3161c1d255d3SCy Schubert 	len = 5 + 4 + os_strlen(ssid->dpp_connector);
3162c1d255d3SCy Schubert #ifdef CONFIG_DPP2
3163c1d255d3SCy Schubert 	len += 5;
3164c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
3165c1d255d3SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ, len);
316685732ac8SCy Schubert 	if (!msg)
316785732ac8SCy Schubert 		return -1;
316885732ac8SCy Schubert 
316985732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
317085732ac8SCy Schubert 	if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ) {
317185732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
317285732ac8SCy Schubert 		goto skip_trans_id;
317385732ac8SCy Schubert 	}
317485732ac8SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ) {
317585732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
317685732ac8SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
317785732ac8SCy Schubert 		wpabuf_put_le16(msg, 0);
317885732ac8SCy Schubert 		goto skip_trans_id;
317985732ac8SCy Schubert 	}
318085732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
318185732ac8SCy Schubert 
318285732ac8SCy Schubert 	/* Transaction ID */
318385732ac8SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
318485732ac8SCy Schubert 	wpabuf_put_le16(msg, 1);
318585732ac8SCy Schubert 	wpabuf_put_u8(msg, TRANSACTION_ID);
318685732ac8SCy Schubert 
318785732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
318885732ac8SCy Schubert skip_trans_id:
318985732ac8SCy Schubert 	if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ) {
319085732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
319185732ac8SCy Schubert 		goto skip_connector;
319285732ac8SCy Schubert 	}
319385732ac8SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ) {
319485732ac8SCy Schubert 		char *connector;
319585732ac8SCy Schubert 
319685732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
319785732ac8SCy Schubert 		connector = dpp_corrupt_connector_signature(
319885732ac8SCy Schubert 			ssid->dpp_connector);
319985732ac8SCy Schubert 		if (!connector) {
320085732ac8SCy Schubert 			wpabuf_free(msg);
320185732ac8SCy Schubert 			return -1;
320285732ac8SCy Schubert 		}
320385732ac8SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
320485732ac8SCy Schubert 		wpabuf_put_le16(msg, os_strlen(connector));
320585732ac8SCy Schubert 		wpabuf_put_str(msg, connector);
320685732ac8SCy Schubert 		os_free(connector);
320785732ac8SCy Schubert 		goto skip_connector;
320885732ac8SCy Schubert 	}
320985732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
321085732ac8SCy Schubert 
321185732ac8SCy Schubert 	/* DPP Connector */
321285732ac8SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
321385732ac8SCy Schubert 	wpabuf_put_le16(msg, os_strlen(ssid->dpp_connector));
321485732ac8SCy Schubert 	wpabuf_put_str(msg, ssid->dpp_connector);
321585732ac8SCy Schubert 
321685732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
321785732ac8SCy Schubert skip_connector:
3218*32a95656SCy Schubert 	if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_REQ) {
3219*32a95656SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version");
3220*32a95656SCy Schubert 		goto skip_proto_ver;
3221*32a95656SCy Schubert 	}
322285732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
322385732ac8SCy Schubert 
3224c1d255d3SCy Schubert #ifdef CONFIG_DPP2
3225c1d255d3SCy Schubert 	if (DPP_VERSION > 1) {
3226*32a95656SCy Schubert 		u8 ver = DPP_VERSION;
3227*32a95656SCy Schubert #ifdef CONFIG_DPP3
3228*32a95656SCy Schubert 		int conn_ver;
3229*32a95656SCy Schubert 
3230*32a95656SCy Schubert 		conn_ver = dpp_get_connector_version(ssid->dpp_connector);
3231*32a95656SCy Schubert 		if (conn_ver > 0 && ver != conn_ver) {
3232*32a95656SCy Schubert 			wpa_printf(MSG_DEBUG,
3233*32a95656SCy Schubert 				   "DPP: Use Connector version %d instead of current protocol version %d",
3234*32a95656SCy Schubert 				   conn_ver, ver);
3235*32a95656SCy Schubert 			ver = conn_ver;
3236*32a95656SCy Schubert 		}
3237*32a95656SCy Schubert #endif /* CONFIG_DPP3 */
3238*32a95656SCy Schubert 
3239c1d255d3SCy Schubert 		/* Protocol Version */
3240c1d255d3SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
3241c1d255d3SCy Schubert 		wpabuf_put_le16(msg, 1);
3242*32a95656SCy Schubert 		wpabuf_put_u8(msg, ver);
3243c1d255d3SCy Schubert 	}
3244c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
3245c1d255d3SCy Schubert 
3246*32a95656SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
3247*32a95656SCy Schubert skip_proto_ver:
3248*32a95656SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
3249*32a95656SCy Schubert 
325085732ac8SCy Schubert 	/* TODO: Timeout on AP response */
325185732ac8SCy Schubert 	wait_time = wpa_s->max_remain_on_chan;
325285732ac8SCy Schubert 	if (wait_time > 2000)
325385732ac8SCy Schubert 		wait_time = 2000;
325485732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
325585732ac8SCy Schubert 		MAC2STR(bss->bssid), bss->freq, DPP_PA_PEER_DISCOVERY_REQ);
325685732ac8SCy Schubert 	offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr,
325785732ac8SCy Schubert 			       broadcast,
325885732ac8SCy Schubert 			       wpabuf_head(msg), wpabuf_len(msg),
325985732ac8SCy Schubert 			       wait_time, wpas_dpp_tx_introduction_status, 0);
326085732ac8SCy Schubert 	wpabuf_free(msg);
326185732ac8SCy Schubert 
326285732ac8SCy Schubert 	/* Request this connection attempt to terminate - new one will be
326385732ac8SCy Schubert 	 * started when network introduction protocol completes */
326485732ac8SCy Schubert 	os_memcpy(wpa_s->dpp_intro_bssid, bss->bssid, ETH_ALEN);
326585732ac8SCy Schubert 	wpa_s->dpp_intro_network = ssid;
326685732ac8SCy Schubert 	return 1;
326785732ac8SCy Schubert }
326885732ac8SCy Schubert 
326985732ac8SCy Schubert 
327085732ac8SCy Schubert int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
327185732ac8SCy Schubert {
327285732ac8SCy Schubert 	struct dpp_bootstrap_info *own_bi;
327385732ac8SCy Schubert 	const char *pos, *end;
327485732ac8SCy Schubert 	unsigned int wait_time;
327585732ac8SCy Schubert 
327685732ac8SCy Schubert 	pos = os_strstr(cmd, " own=");
327785732ac8SCy Schubert 	if (!pos)
327885732ac8SCy Schubert 		return -1;
327985732ac8SCy Schubert 	pos += 5;
32804bc52338SCy Schubert 	own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
328185732ac8SCy Schubert 	if (!own_bi) {
328285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
328385732ac8SCy Schubert 			   "DPP: Identified bootstrap info not found");
328485732ac8SCy Schubert 		return -1;
328585732ac8SCy Schubert 	}
328685732ac8SCy Schubert 	if (own_bi->type != DPP_BOOTSTRAP_PKEX) {
328785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
328885732ac8SCy Schubert 			   "DPP: Identified bootstrap info not for PKEX");
328985732ac8SCy Schubert 		return -1;
329085732ac8SCy Schubert 	}
329185732ac8SCy Schubert 	wpa_s->dpp_pkex_bi = own_bi;
329285732ac8SCy Schubert 	own_bi->pkex_t = 0; /* clear pending errors on new code */
329385732ac8SCy Schubert 
329485732ac8SCy Schubert 	os_free(wpa_s->dpp_pkex_identifier);
329585732ac8SCy Schubert 	wpa_s->dpp_pkex_identifier = NULL;
329685732ac8SCy Schubert 	pos = os_strstr(cmd, " identifier=");
329785732ac8SCy Schubert 	if (pos) {
329885732ac8SCy Schubert 		pos += 12;
329985732ac8SCy Schubert 		end = os_strchr(pos, ' ');
330085732ac8SCy Schubert 		if (!end)
330185732ac8SCy Schubert 			return -1;
330285732ac8SCy Schubert 		wpa_s->dpp_pkex_identifier = os_malloc(end - pos + 1);
330385732ac8SCy Schubert 		if (!wpa_s->dpp_pkex_identifier)
330485732ac8SCy Schubert 			return -1;
330585732ac8SCy Schubert 		os_memcpy(wpa_s->dpp_pkex_identifier, pos, end - pos);
330685732ac8SCy Schubert 		wpa_s->dpp_pkex_identifier[end - pos] = '\0';
330785732ac8SCy Schubert 	}
330885732ac8SCy Schubert 
330985732ac8SCy Schubert 	pos = os_strstr(cmd, " code=");
331085732ac8SCy Schubert 	if (!pos)
331185732ac8SCy Schubert 		return -1;
331285732ac8SCy Schubert 	os_free(wpa_s->dpp_pkex_code);
331385732ac8SCy Schubert 	wpa_s->dpp_pkex_code = os_strdup(pos + 6);
331485732ac8SCy Schubert 	if (!wpa_s->dpp_pkex_code)
331585732ac8SCy Schubert 		return -1;
331685732ac8SCy Schubert 
3317*32a95656SCy Schubert 	if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) {
331885732ac8SCy Schubert 		struct dpp_pkex *pkex;
331985732ac8SCy Schubert 		struct wpabuf *msg;
3320*32a95656SCy Schubert 		bool v2 = os_strstr(cmd, " init=2") != NULL;
332185732ac8SCy Schubert 
332285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
332385732ac8SCy Schubert 		dpp_pkex_free(wpa_s->dpp_pkex);
332485732ac8SCy Schubert 		wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr,
332585732ac8SCy Schubert 						wpa_s->dpp_pkex_identifier,
3326*32a95656SCy Schubert 						wpa_s->dpp_pkex_code, v2);
332785732ac8SCy Schubert 		pkex = wpa_s->dpp_pkex;
332885732ac8SCy Schubert 		if (!pkex)
332985732ac8SCy Schubert 			return -1;
333085732ac8SCy Schubert 
333185732ac8SCy Schubert 		msg = pkex->exchange_req;
333285732ac8SCy Schubert 		wait_time = wpa_s->max_remain_on_chan;
333385732ac8SCy Schubert 		if (wait_time > 2000)
333485732ac8SCy Schubert 			wait_time = 2000;
333585732ac8SCy Schubert 		pkex->freq = 2437;
333685732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
333785732ac8SCy Schubert 			" freq=%u type=%d",
333885732ac8SCy Schubert 			MAC2STR(broadcast), pkex->freq,
3339*32a95656SCy Schubert 			v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
3340*32a95656SCy Schubert 			DPP_PA_PKEX_V1_EXCHANGE_REQ);
334185732ac8SCy Schubert 		offchannel_send_action(wpa_s, pkex->freq, broadcast,
334285732ac8SCy Schubert 				       wpa_s->own_addr, broadcast,
334385732ac8SCy Schubert 				       wpabuf_head(msg), wpabuf_len(msg),
334485732ac8SCy Schubert 				       wait_time, wpas_dpp_tx_pkex_status, 0);
334585732ac8SCy Schubert 		if (wait_time == 0)
334685732ac8SCy Schubert 			wait_time = 2000;
334785732ac8SCy Schubert 		pkex->exch_req_wait_time = wait_time;
334885732ac8SCy Schubert 		pkex->exch_req_tries = 1;
334985732ac8SCy Schubert 	}
335085732ac8SCy Schubert 
335185732ac8SCy Schubert 	/* TODO: Support multiple PKEX info entries */
335285732ac8SCy Schubert 
335385732ac8SCy Schubert 	os_free(wpa_s->dpp_pkex_auth_cmd);
335485732ac8SCy Schubert 	wpa_s->dpp_pkex_auth_cmd = os_strdup(cmd);
335585732ac8SCy Schubert 
335685732ac8SCy Schubert 	return 1;
335785732ac8SCy Schubert }
335885732ac8SCy Schubert 
335985732ac8SCy Schubert 
336085732ac8SCy Schubert int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id)
336185732ac8SCy Schubert {
336285732ac8SCy Schubert 	unsigned int id_val;
336385732ac8SCy Schubert 
336485732ac8SCy Schubert 	if (os_strcmp(id, "*") == 0) {
336585732ac8SCy Schubert 		id_val = 0;
336685732ac8SCy Schubert 	} else {
336785732ac8SCy Schubert 		id_val = atoi(id);
336885732ac8SCy Schubert 		if (id_val == 0)
336985732ac8SCy Schubert 			return -1;
337085732ac8SCy Schubert 	}
337185732ac8SCy Schubert 
337285732ac8SCy Schubert 	if ((id_val != 0 && id_val != 1) || !wpa_s->dpp_pkex_code)
337385732ac8SCy Schubert 		return -1;
337485732ac8SCy Schubert 
337585732ac8SCy Schubert 	/* TODO: Support multiple PKEX entries */
337685732ac8SCy Schubert 	os_free(wpa_s->dpp_pkex_code);
337785732ac8SCy Schubert 	wpa_s->dpp_pkex_code = NULL;
337885732ac8SCy Schubert 	os_free(wpa_s->dpp_pkex_identifier);
337985732ac8SCy Schubert 	wpa_s->dpp_pkex_identifier = NULL;
338085732ac8SCy Schubert 	os_free(wpa_s->dpp_pkex_auth_cmd);
338185732ac8SCy Schubert 	wpa_s->dpp_pkex_auth_cmd = NULL;
338285732ac8SCy Schubert 	wpa_s->dpp_pkex_bi = NULL;
338385732ac8SCy Schubert 	/* TODO: Remove dpp_pkex only if it is for the identified PKEX code */
338485732ac8SCy Schubert 	dpp_pkex_free(wpa_s->dpp_pkex);
338585732ac8SCy Schubert 	wpa_s->dpp_pkex = NULL;
338685732ac8SCy Schubert 	return 0;
338785732ac8SCy Schubert }
338885732ac8SCy Schubert 
338985732ac8SCy Schubert 
339085732ac8SCy Schubert void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
339185732ac8SCy Schubert {
3392c1d255d3SCy Schubert 	if (wpa_s->dpp_auth || wpa_s->dpp_pkex)
3393c1d255d3SCy Schubert 		offchannel_send_action_done(wpa_s);
339485732ac8SCy Schubert 	dpp_auth_deinit(wpa_s->dpp_auth);
339585732ac8SCy Schubert 	wpa_s->dpp_auth = NULL;
339685732ac8SCy Schubert 	dpp_pkex_free(wpa_s->dpp_pkex);
339785732ac8SCy Schubert 	wpa_s->dpp_pkex = NULL;
339885732ac8SCy Schubert 	if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0)
339985732ac8SCy Schubert 		gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token);
340085732ac8SCy Schubert }
340185732ac8SCy Schubert 
340285732ac8SCy Schubert 
340385732ac8SCy Schubert int wpas_dpp_init(struct wpa_supplicant *wpa_s)
340485732ac8SCy Schubert {
3405206b73d0SCy Schubert 	struct dpp_global_config config;
340685732ac8SCy Schubert 	u8 adv_proto_id[7];
340785732ac8SCy Schubert 
340885732ac8SCy Schubert 	adv_proto_id[0] = WLAN_EID_VENDOR_SPECIFIC;
340985732ac8SCy Schubert 	adv_proto_id[1] = 5;
341085732ac8SCy Schubert 	WPA_PUT_BE24(&adv_proto_id[2], OUI_WFA);
341185732ac8SCy Schubert 	adv_proto_id[5] = DPP_OUI_TYPE;
341285732ac8SCy Schubert 	adv_proto_id[6] = 0x01;
341385732ac8SCy Schubert 
341485732ac8SCy Schubert 	if (gas_server_register(wpa_s->gas_server, adv_proto_id,
341585732ac8SCy Schubert 				sizeof(adv_proto_id), wpas_dpp_gas_req_handler,
341685732ac8SCy Schubert 				wpas_dpp_gas_status_handler, wpa_s) < 0)
341785732ac8SCy Schubert 		return -1;
3418206b73d0SCy Schubert 
3419206b73d0SCy Schubert 	os_memset(&config, 0, sizeof(config));
3420206b73d0SCy Schubert 	config.cb_ctx = wpa_s;
3421206b73d0SCy Schubert #ifdef CONFIG_DPP2
3422c1d255d3SCy Schubert 	config.remove_bi = wpas_dpp_remove_bi;
3423206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
3424206b73d0SCy Schubert 	wpa_s->dpp = dpp_global_init(&config);
34254bc52338SCy Schubert 	return wpa_s->dpp ? 0 : -1;
342685732ac8SCy Schubert }
342785732ac8SCy Schubert 
342885732ac8SCy Schubert 
342985732ac8SCy Schubert void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
343085732ac8SCy Schubert {
343185732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
343285732ac8SCy Schubert 	os_free(wpa_s->dpp_config_obj_override);
343385732ac8SCy Schubert 	wpa_s->dpp_config_obj_override = NULL;
343485732ac8SCy Schubert 	os_free(wpa_s->dpp_discovery_override);
343585732ac8SCy Schubert 	wpa_s->dpp_discovery_override = NULL;
343685732ac8SCy Schubert 	os_free(wpa_s->dpp_groups_override);
343785732ac8SCy Schubert 	wpa_s->dpp_groups_override = NULL;
343885732ac8SCy Schubert 	wpa_s->dpp_ignore_netaccesskey_mismatch = 0;
343985732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
34404bc52338SCy Schubert 	if (!wpa_s->dpp)
344185732ac8SCy Schubert 		return;
344285732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
344385732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
3444c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s, NULL);
344585732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
344685732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
34474bc52338SCy Schubert #ifdef CONFIG_DPP2
34484bc52338SCy Schubert 	eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
3449c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
3450c1d255d3SCy Schubert 			     wpa_s, NULL);
3451c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
3452c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
3453c1d255d3SCy Schubert 			     wpa_s, NULL);
3454c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_dpp_build_csr, wpa_s, NULL);
34554bc52338SCy Schubert 	dpp_pfs_free(wpa_s->dpp_pfs);
34564bc52338SCy Schubert 	wpa_s->dpp_pfs = NULL;
3457c1d255d3SCy Schubert 	wpas_dpp_chirp_stop(wpa_s);
3458c1d255d3SCy Schubert 	dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
3459c1d255d3SCy Schubert 	wpa_s->dpp_reconfig_id = NULL;
34604bc52338SCy Schubert #endif /* CONFIG_DPP2 */
346185732ac8SCy Schubert 	offchannel_send_action_done(wpa_s);
346285732ac8SCy Schubert 	wpas_dpp_listen_stop(wpa_s);
346385732ac8SCy Schubert 	wpas_dpp_stop(wpa_s);
346485732ac8SCy Schubert 	wpas_dpp_pkex_remove(wpa_s, "*");
346585732ac8SCy Schubert 	os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN);
346685732ac8SCy Schubert 	os_free(wpa_s->dpp_configurator_params);
346785732ac8SCy Schubert 	wpa_s->dpp_configurator_params = NULL;
3468c1d255d3SCy Schubert 	dpp_global_clear(wpa_s->dpp);
346985732ac8SCy Schubert }
3470206b73d0SCy Schubert 
3471206b73d0SCy Schubert 
3472206b73d0SCy Schubert #ifdef CONFIG_DPP2
3473c1d255d3SCy Schubert 
3474206b73d0SCy Schubert int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
3475206b73d0SCy Schubert {
3476206b73d0SCy Schubert 	struct dpp_controller_config config;
3477206b73d0SCy Schubert 	const char *pos;
3478206b73d0SCy Schubert 
3479206b73d0SCy Schubert 	os_memset(&config, 0, sizeof(config));
3480c1d255d3SCy Schubert 	config.allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
3481c1d255d3SCy Schubert 	config.netrole = DPP_NETROLE_STA;
3482c1d255d3SCy Schubert 	config.msg_ctx = wpa_s;
3483c1d255d3SCy Schubert 	config.cb_ctx = wpa_s;
3484c1d255d3SCy Schubert 	config.process_conf_obj = wpas_dpp_process_conf_obj;
3485206b73d0SCy Schubert 	if (cmd) {
3486206b73d0SCy Schubert 		pos = os_strstr(cmd, " tcp_port=");
3487206b73d0SCy Schubert 		if (pos) {
3488206b73d0SCy Schubert 			pos += 10;
3489206b73d0SCy Schubert 			config.tcp_port = atoi(pos);
3490206b73d0SCy Schubert 		}
3491c1d255d3SCy Schubert 
3492c1d255d3SCy Schubert 		pos = os_strstr(cmd, " role=");
3493c1d255d3SCy Schubert 		if (pos) {
3494c1d255d3SCy Schubert 			pos += 6;
3495c1d255d3SCy Schubert 			if (os_strncmp(pos, "configurator", 12) == 0)
3496c1d255d3SCy Schubert 				config.allowed_roles = DPP_CAPAB_CONFIGURATOR;
3497c1d255d3SCy Schubert 			else if (os_strncmp(pos, "enrollee", 8) == 0)
3498c1d255d3SCy Schubert 				config.allowed_roles = DPP_CAPAB_ENROLLEE;
3499c1d255d3SCy Schubert 			else if (os_strncmp(pos, "either", 6) == 0)
3500c1d255d3SCy Schubert 				config.allowed_roles = DPP_CAPAB_CONFIGURATOR |
3501c1d255d3SCy Schubert 					DPP_CAPAB_ENROLLEE;
3502c1d255d3SCy Schubert 			else
3503c1d255d3SCy Schubert 				return -1;
3504c1d255d3SCy Schubert 		}
3505c1d255d3SCy Schubert 
3506c1d255d3SCy Schubert 		config.qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
3507206b73d0SCy Schubert 	}
3508206b73d0SCy Schubert 	config.configurator_params = wpa_s->dpp_configurator_params;
3509206b73d0SCy Schubert 	return dpp_controller_start(wpa_s->dpp, &config);
3510206b73d0SCy Schubert }
3511c1d255d3SCy Schubert 
3512c1d255d3SCy Schubert 
3513c1d255d3SCy Schubert static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
3514c1d255d3SCy Schubert 
3515c1d255d3SCy Schubert static void wpas_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
3516c1d255d3SCy Schubert {
3517c1d255d3SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
3518c1d255d3SCy Schubert 
3519c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: No chirp response received");
3520c1d255d3SCy Schubert 	offchannel_send_action_done(wpa_s);
3521c1d255d3SCy Schubert 	wpas_dpp_chirp_next(wpa_s, NULL);
3522c1d255d3SCy Schubert }
3523c1d255d3SCy Schubert 
3524c1d255d3SCy Schubert 
3525c1d255d3SCy Schubert static void wpas_dpp_chirp_tx_status(struct wpa_supplicant *wpa_s,
3526c1d255d3SCy Schubert 				     unsigned int freq, const u8 *dst,
3527c1d255d3SCy Schubert 				     const u8 *src, const u8 *bssid,
3528c1d255d3SCy Schubert 				     const u8 *data, size_t data_len,
3529c1d255d3SCy Schubert 				     enum offchannel_send_action_result result)
3530c1d255d3SCy Schubert {
3531c1d255d3SCy Schubert 	if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
3532c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to send chirp on %d MHz",
3533c1d255d3SCy Schubert 			   wpa_s->dpp_chirp_freq);
3534c1d255d3SCy Schubert 		if (eloop_register_timeout(0, 0, wpas_dpp_chirp_next,
3535c1d255d3SCy Schubert 					   wpa_s, NULL) < 0)
3536c1d255d3SCy Schubert 			wpas_dpp_chirp_stop(wpa_s);
3537c1d255d3SCy Schubert 		return;
3538c1d255d3SCy Schubert 	}
3539c1d255d3SCy Schubert 
3540c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Chirp send completed - wait for response");
3541c1d255d3SCy Schubert 	if (eloop_register_timeout(2, 0, wpas_dpp_chirp_timeout,
3542c1d255d3SCy Schubert 				   wpa_s, NULL) < 0)
3543c1d255d3SCy Schubert 		wpas_dpp_chirp_stop(wpa_s);
3544c1d255d3SCy Schubert }
3545c1d255d3SCy Schubert 
3546c1d255d3SCy Schubert 
3547c1d255d3SCy Schubert static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
3548c1d255d3SCy Schubert {
3549c1d255d3SCy Schubert 	struct wpabuf *msg, *announce = NULL;
3550c1d255d3SCy Schubert 	int type;
3551c1d255d3SCy Schubert 
3552c1d255d3SCy Schubert 	msg = wpa_s->dpp_presence_announcement;
3553c1d255d3SCy Schubert 	type = DPP_PA_PRESENCE_ANNOUNCEMENT;
3554c1d255d3SCy Schubert 	if (!msg) {
3555c1d255d3SCy Schubert 		struct wpa_ssid *ssid = wpa_s->dpp_reconfig_ssid;
3556c1d255d3SCy Schubert 
3557c1d255d3SCy Schubert 		if (ssid && wpa_s->dpp_reconfig_id &&
3558c1d255d3SCy Schubert 		    wpa_config_get_network(wpa_s->conf,
3559c1d255d3SCy Schubert 					   wpa_s->dpp_reconfig_ssid_id) ==
3560c1d255d3SCy Schubert 		    ssid) {
3561c1d255d3SCy Schubert 			announce = dpp_build_reconfig_announcement(
3562c1d255d3SCy Schubert 				ssid->dpp_csign,
3563c1d255d3SCy Schubert 				ssid->dpp_csign_len,
3564c1d255d3SCy Schubert 				ssid->dpp_netaccesskey,
3565c1d255d3SCy Schubert 				ssid->dpp_netaccesskey_len,
3566c1d255d3SCy Schubert 				wpa_s->dpp_reconfig_id);
3567c1d255d3SCy Schubert 			msg = announce;
3568c1d255d3SCy Schubert 		}
3569c1d255d3SCy Schubert 		if (!msg)
3570c1d255d3SCy Schubert 			return;
3571c1d255d3SCy Schubert 		type = DPP_PA_RECONFIG_ANNOUNCEMENT;
3572c1d255d3SCy Schubert 	}
3573c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", wpa_s->dpp_chirp_freq);
3574c1d255d3SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
3575c1d255d3SCy Schubert 		MAC2STR(broadcast), wpa_s->dpp_chirp_freq, type);
3576c1d255d3SCy Schubert 	if (offchannel_send_action(
3577c1d255d3SCy Schubert 		    wpa_s, wpa_s->dpp_chirp_freq, broadcast,
3578c1d255d3SCy Schubert 		    wpa_s->own_addr, broadcast,
3579c1d255d3SCy Schubert 		    wpabuf_head(msg), wpabuf_len(msg),
3580c1d255d3SCy Schubert 		    2000, wpas_dpp_chirp_tx_status, 0) < 0)
3581c1d255d3SCy Schubert 		wpas_dpp_chirp_stop(wpa_s);
3582c1d255d3SCy Schubert 
3583c1d255d3SCy Schubert 	wpabuf_free(announce);
3584c1d255d3SCy Schubert }
3585c1d255d3SCy Schubert 
3586c1d255d3SCy Schubert 
3587c1d255d3SCy Schubert static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
3588c1d255d3SCy Schubert 					    struct wpa_scan_results *scan_res)
3589c1d255d3SCy Schubert {
3590c1d255d3SCy Schubert 	struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi;
3591c1d255d3SCy Schubert 	unsigned int i;
3592c1d255d3SCy Schubert 	struct hostapd_hw_modes *mode;
3593c1d255d3SCy Schubert 	int c;
3594c1d255d3SCy Schubert 	struct wpa_bss *bss;
3595c1d255d3SCy Schubert 	bool chan6 = wpa_s->hw.modes == NULL;
3596c1d255d3SCy Schubert 
3597c1d255d3SCy Schubert 	if (!bi && !wpa_s->dpp_reconfig_ssid)
3598c1d255d3SCy Schubert 		return;
3599c1d255d3SCy Schubert 
3600c1d255d3SCy Schubert 	wpa_s->dpp_chirp_scan_done = 1;
3601c1d255d3SCy Schubert 
3602c1d255d3SCy Schubert 	os_free(wpa_s->dpp_chirp_freqs);
3603c1d255d3SCy Schubert 	wpa_s->dpp_chirp_freqs = NULL;
3604c1d255d3SCy Schubert 
3605c1d255d3SCy Schubert 	/* Channels from own bootstrapping info */
3606c1d255d3SCy Schubert 	if (bi) {
3607c1d255d3SCy Schubert 		for (i = 0; i < bi->num_freq; i++)
3608c1d255d3SCy Schubert 			int_array_add_unique(&wpa_s->dpp_chirp_freqs,
3609c1d255d3SCy Schubert 					     bi->freq[i]);
3610c1d255d3SCy Schubert 	}
3611c1d255d3SCy Schubert 
3612c1d255d3SCy Schubert 	/* Preferred chirping channels */
3613c1d255d3SCy Schubert 	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
3614c1d255d3SCy Schubert 			HOSTAPD_MODE_IEEE80211G, false);
3615c1d255d3SCy Schubert 	if (mode) {
3616c1d255d3SCy Schubert 		for (c = 0; c < mode->num_channels; c++) {
3617c1d255d3SCy Schubert 			struct hostapd_channel_data *chan = &mode->channels[c];
3618c1d255d3SCy Schubert 
3619c1d255d3SCy Schubert 			if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
3620c1d255d3SCy Schubert 			    chan->freq != 2437)
3621c1d255d3SCy Schubert 				continue;
3622c1d255d3SCy Schubert 			chan6 = true;
3623c1d255d3SCy Schubert 			break;
3624c1d255d3SCy Schubert 		}
3625c1d255d3SCy Schubert 	}
3626c1d255d3SCy Schubert 	if (chan6)
3627c1d255d3SCy Schubert 		int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
3628c1d255d3SCy Schubert 
3629c1d255d3SCy Schubert 	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
3630c1d255d3SCy Schubert 			HOSTAPD_MODE_IEEE80211A, false);
3631c1d255d3SCy Schubert 	if (mode) {
3632c1d255d3SCy Schubert 		int chan44 = 0, chan149 = 0;
3633c1d255d3SCy Schubert 
3634c1d255d3SCy Schubert 		for (c = 0; c < mode->num_channels; c++) {
3635c1d255d3SCy Schubert 			struct hostapd_channel_data *chan = &mode->channels[c];
3636c1d255d3SCy Schubert 
3637c1d255d3SCy Schubert 			if (chan->flag & (HOSTAPD_CHAN_DISABLED |
3638c1d255d3SCy Schubert 					  HOSTAPD_CHAN_RADAR))
3639c1d255d3SCy Schubert 				continue;
3640c1d255d3SCy Schubert 			if (chan->freq == 5220)
3641c1d255d3SCy Schubert 				chan44 = 1;
3642c1d255d3SCy Schubert 			if (chan->freq == 5745)
3643c1d255d3SCy Schubert 				chan149 = 1;
3644c1d255d3SCy Schubert 		}
3645c1d255d3SCy Schubert 		if (chan149)
3646c1d255d3SCy Schubert 			int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5745);
3647c1d255d3SCy Schubert 		else if (chan44)
3648c1d255d3SCy Schubert 			int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5220);
3649c1d255d3SCy Schubert 	}
3650c1d255d3SCy Schubert 
3651c1d255d3SCy Schubert 	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
3652c1d255d3SCy Schubert 			HOSTAPD_MODE_IEEE80211AD, false);
3653c1d255d3SCy Schubert 	if (mode) {
3654c1d255d3SCy Schubert 		for (c = 0; c < mode->num_channels; c++) {
3655c1d255d3SCy Schubert 			struct hostapd_channel_data *chan = &mode->channels[c];
3656c1d255d3SCy Schubert 
3657c1d255d3SCy Schubert 			if ((chan->flag & (HOSTAPD_CHAN_DISABLED |
3658c1d255d3SCy Schubert 					   HOSTAPD_CHAN_RADAR)) ||
3659c1d255d3SCy Schubert 			    chan->freq != 60480)
3660c1d255d3SCy Schubert 				continue;
3661c1d255d3SCy Schubert 			int_array_add_unique(&wpa_s->dpp_chirp_freqs, 60480);
3662c1d255d3SCy Schubert 			break;
3663c1d255d3SCy Schubert 		}
3664c1d255d3SCy Schubert 	}
3665c1d255d3SCy Schubert 
3666c1d255d3SCy Schubert 	/* Add channels from scan results for APs that advertise Configurator
3667c1d255d3SCy Schubert 	 * Connectivity element */
3668c1d255d3SCy Schubert 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
3669c1d255d3SCy Schubert 		if (wpa_bss_get_vendor_ie(bss, DPP_CC_IE_VENDOR_TYPE))
3670c1d255d3SCy Schubert 			int_array_add_unique(&wpa_s->dpp_chirp_freqs,
3671c1d255d3SCy Schubert 					     bss->freq);
3672c1d255d3SCy Schubert 	}
3673c1d255d3SCy Schubert 
3674c1d255d3SCy Schubert 	if (!wpa_s->dpp_chirp_freqs ||
3675c1d255d3SCy Schubert 	    eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL) < 0)
3676c1d255d3SCy Schubert 		wpas_dpp_chirp_stop(wpa_s);
3677c1d255d3SCy Schubert }
3678c1d255d3SCy Schubert 
3679c1d255d3SCy Schubert 
3680c1d255d3SCy Schubert static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx)
3681c1d255d3SCy Schubert {
3682c1d255d3SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
3683c1d255d3SCy Schubert 	int i;
3684c1d255d3SCy Schubert 
3685c1d255d3SCy Schubert 	if (wpa_s->dpp_chirp_listen)
3686c1d255d3SCy Schubert 		wpas_dpp_listen_stop(wpa_s);
3687c1d255d3SCy Schubert 
3688c1d255d3SCy Schubert 	if (wpa_s->dpp_chirp_freq == 0) {
3689c1d255d3SCy Schubert 		if (wpa_s->dpp_chirp_round % 4 == 0 &&
3690c1d255d3SCy Schubert 		    !wpa_s->dpp_chirp_scan_done) {
3691c1d255d3SCy Schubert 			if (wpas_scan_scheduled(wpa_s)) {
3692c1d255d3SCy Schubert 				wpa_printf(MSG_DEBUG,
3693c1d255d3SCy Schubert 					   "DPP: Deferring chirp scan because another scan is planned already");
3694c1d255d3SCy Schubert 				if (eloop_register_timeout(1, 0,
3695c1d255d3SCy Schubert 							   wpas_dpp_chirp_next,
3696c1d255d3SCy Schubert 							   wpa_s, NULL) < 0) {
3697c1d255d3SCy Schubert 					wpas_dpp_chirp_stop(wpa_s);
3698c1d255d3SCy Schubert 					return;
3699c1d255d3SCy Schubert 				}
3700c1d255d3SCy Schubert 				return;
3701c1d255d3SCy Schubert 			}
3702c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
3703c1d255d3SCy Schubert 				   "DPP: Update channel list for chirping");
3704c1d255d3SCy Schubert 			wpa_s->scan_req = MANUAL_SCAN_REQ;
3705c1d255d3SCy Schubert 			wpa_s->scan_res_handler =
3706c1d255d3SCy Schubert 				wpas_dpp_chirp_scan_res_handler;
3707c1d255d3SCy Schubert 			wpa_supplicant_req_scan(wpa_s, 0, 0);
3708c1d255d3SCy Schubert 			return;
3709c1d255d3SCy Schubert 		}
3710c1d255d3SCy Schubert 		wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[0];
3711c1d255d3SCy Schubert 		wpa_s->dpp_chirp_round++;
3712c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Start chirping round %d",
3713c1d255d3SCy Schubert 			   wpa_s->dpp_chirp_round);
3714c1d255d3SCy Schubert 	} else {
3715c1d255d3SCy Schubert 		for (i = 0; wpa_s->dpp_chirp_freqs[i]; i++)
3716c1d255d3SCy Schubert 			if (wpa_s->dpp_chirp_freqs[i] == wpa_s->dpp_chirp_freq)
3717c1d255d3SCy Schubert 				break;
3718c1d255d3SCy Schubert 		if (!wpa_s->dpp_chirp_freqs[i]) {
3719c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
3720c1d255d3SCy Schubert 				   "DPP: Previous chirp freq %d not found",
3721c1d255d3SCy Schubert 				   wpa_s->dpp_chirp_freq);
3722c1d255d3SCy Schubert 			return;
3723c1d255d3SCy Schubert 		}
3724c1d255d3SCy Schubert 		i++;
3725c1d255d3SCy Schubert 		if (wpa_s->dpp_chirp_freqs[i]) {
3726c1d255d3SCy Schubert 			wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[i];
3727c1d255d3SCy Schubert 		} else {
3728c1d255d3SCy Schubert 			wpa_s->dpp_chirp_iter--;
3729c1d255d3SCy Schubert 			if (wpa_s->dpp_chirp_iter <= 0) {
3730c1d255d3SCy Schubert 				wpa_printf(MSG_DEBUG,
3731c1d255d3SCy Schubert 					   "DPP: Chirping iterations completed");
3732c1d255d3SCy Schubert 				wpas_dpp_chirp_stop(wpa_s);
3733c1d255d3SCy Schubert 				return;
3734c1d255d3SCy Schubert 			}
3735c1d255d3SCy Schubert 			wpa_s->dpp_chirp_freq = 0;
3736c1d255d3SCy Schubert 			wpa_s->dpp_chirp_scan_done = 0;
3737c1d255d3SCy Schubert 			if (eloop_register_timeout(30, 0, wpas_dpp_chirp_next,
3738c1d255d3SCy Schubert 						   wpa_s, NULL) < 0) {
3739c1d255d3SCy Schubert 				wpas_dpp_chirp_stop(wpa_s);
3740c1d255d3SCy Schubert 				return;
3741c1d255d3SCy Schubert 			}
3742c1d255d3SCy Schubert 			if (wpa_s->dpp_chirp_listen) {
3743c1d255d3SCy Schubert 				wpa_printf(MSG_DEBUG,
3744c1d255d3SCy Schubert 					   "DPP: Listen on %d MHz during chirp 30 second wait",
3745c1d255d3SCy Schubert 					wpa_s->dpp_chirp_listen);
3746c1d255d3SCy Schubert 				wpas_dpp_listen_start(wpa_s,
3747c1d255d3SCy Schubert 						      wpa_s->dpp_chirp_listen);
3748c1d255d3SCy Schubert 			} else {
3749c1d255d3SCy Schubert 				wpa_printf(MSG_DEBUG,
3750c1d255d3SCy Schubert 					   "DPP: Wait 30 seconds before starting the next chirping round");
3751c1d255d3SCy Schubert 			}
3752c1d255d3SCy Schubert 			return;
3753c1d255d3SCy Schubert 		}
3754c1d255d3SCy Schubert 	}
3755c1d255d3SCy Schubert 
3756c1d255d3SCy Schubert 	wpas_dpp_chirp_start(wpa_s);
3757c1d255d3SCy Schubert }
3758c1d255d3SCy Schubert 
3759c1d255d3SCy Schubert 
3760c1d255d3SCy Schubert int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd)
3761c1d255d3SCy Schubert {
3762c1d255d3SCy Schubert 	const char *pos;
3763c1d255d3SCy Schubert 	int iter = 1, listen_freq = 0;
3764c1d255d3SCy Schubert 	struct dpp_bootstrap_info *bi;
3765c1d255d3SCy Schubert 
3766c1d255d3SCy Schubert 	pos = os_strstr(cmd, " own=");
3767c1d255d3SCy Schubert 	if (!pos)
3768c1d255d3SCy Schubert 		return -1;
3769c1d255d3SCy Schubert 	pos += 5;
3770c1d255d3SCy Schubert 	bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
3771c1d255d3SCy Schubert 	if (!bi) {
3772c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
3773c1d255d3SCy Schubert 			   "DPP: Identified bootstrap info not found");
3774c1d255d3SCy Schubert 		return -1;
3775c1d255d3SCy Schubert 	}
3776c1d255d3SCy Schubert 
3777c1d255d3SCy Schubert 	pos = os_strstr(cmd, " iter=");
3778c1d255d3SCy Schubert 	if (pos) {
3779c1d255d3SCy Schubert 		iter = atoi(pos + 6);
3780c1d255d3SCy Schubert 		if (iter <= 0)
3781c1d255d3SCy Schubert 			return -1;
3782c1d255d3SCy Schubert 	}
3783c1d255d3SCy Schubert 
3784c1d255d3SCy Schubert 	pos = os_strstr(cmd, " listen=");
3785c1d255d3SCy Schubert 	if (pos) {
3786c1d255d3SCy Schubert 		listen_freq = atoi(pos + 8);
3787c1d255d3SCy Schubert 		if (listen_freq <= 0)
3788c1d255d3SCy Schubert 			return -1;
3789c1d255d3SCy Schubert 	}
3790c1d255d3SCy Schubert 
3791c1d255d3SCy Schubert 	wpas_dpp_chirp_stop(wpa_s);
3792c1d255d3SCy Schubert 	wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
3793c1d255d3SCy Schubert 	wpa_s->dpp_qr_mutual = 0;
3794c1d255d3SCy Schubert 	wpa_s->dpp_chirp_bi = bi;
3795c1d255d3SCy Schubert 	wpa_s->dpp_presence_announcement = dpp_build_presence_announcement(bi);
3796c1d255d3SCy Schubert 	if (!wpa_s->dpp_presence_announcement)
3797c1d255d3SCy Schubert 		return -1;
3798c1d255d3SCy Schubert 	wpa_s->dpp_chirp_iter = iter;
3799c1d255d3SCy Schubert 	wpa_s->dpp_chirp_round = 0;
3800c1d255d3SCy Schubert 	wpa_s->dpp_chirp_scan_done = 0;
3801c1d255d3SCy Schubert 	wpa_s->dpp_chirp_listen = listen_freq;
3802c1d255d3SCy Schubert 
3803c1d255d3SCy Schubert 	return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
3804c1d255d3SCy Schubert }
3805c1d255d3SCy Schubert 
3806c1d255d3SCy Schubert 
3807c1d255d3SCy Schubert void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
3808c1d255d3SCy Schubert {
3809c1d255d3SCy Schubert 	if (wpa_s->dpp_presence_announcement ||
3810c1d255d3SCy Schubert 	    wpa_s->dpp_reconfig_ssid) {
3811c1d255d3SCy Schubert 		offchannel_send_action_done(wpa_s);
3812c1d255d3SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
3813c1d255d3SCy Schubert 	}
3814c1d255d3SCy Schubert 	wpa_s->dpp_chirp_bi = NULL;
3815c1d255d3SCy Schubert 	wpabuf_free(wpa_s->dpp_presence_announcement);
3816c1d255d3SCy Schubert 	wpa_s->dpp_presence_announcement = NULL;
3817c1d255d3SCy Schubert 	if (wpa_s->dpp_chirp_listen)
3818c1d255d3SCy Schubert 		wpas_dpp_listen_stop(wpa_s);
3819c1d255d3SCy Schubert 	wpa_s->dpp_chirp_listen = 0;
3820c1d255d3SCy Schubert 	wpa_s->dpp_chirp_freq = 0;
3821c1d255d3SCy Schubert 	os_free(wpa_s->dpp_chirp_freqs);
3822c1d255d3SCy Schubert 	wpa_s->dpp_chirp_freqs = NULL;
3823c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_dpp_chirp_next, wpa_s, NULL);
3824c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_dpp_chirp_timeout, wpa_s, NULL);
3825c1d255d3SCy Schubert 	if (wpa_s->scan_res_handler == wpas_dpp_chirp_scan_res_handler) {
3826c1d255d3SCy Schubert 		wpas_abort_ongoing_scan(wpa_s);
3827c1d255d3SCy Schubert 		wpa_s->scan_res_handler = NULL;
3828c1d255d3SCy Schubert 	}
3829c1d255d3SCy Schubert }
3830c1d255d3SCy Schubert 
3831c1d255d3SCy Schubert 
3832c1d255d3SCy Schubert int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd)
3833c1d255d3SCy Schubert {
3834c1d255d3SCy Schubert 	struct wpa_ssid *ssid;
3835c1d255d3SCy Schubert 	int iter = 1;
3836c1d255d3SCy Schubert 	const char *pos;
3837c1d255d3SCy Schubert 
3838c1d255d3SCy Schubert 	ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
3839c1d255d3SCy Schubert 	if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
3840c1d255d3SCy Schubert 	    !ssid->dpp_csign) {
3841c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
3842c1d255d3SCy Schubert 			   "DPP: Not a valid network profile for reconfiguration");
3843c1d255d3SCy Schubert 		return -1;
3844c1d255d3SCy Schubert 	}
3845c1d255d3SCy Schubert 
3846c1d255d3SCy Schubert 	pos = os_strstr(cmd, " iter=");
3847c1d255d3SCy Schubert 	if (pos) {
3848c1d255d3SCy Schubert 		iter = atoi(pos + 6);
3849c1d255d3SCy Schubert 		if (iter <= 0)
3850c1d255d3SCy Schubert 			return -1;
3851c1d255d3SCy Schubert 	}
3852c1d255d3SCy Schubert 
3853c1d255d3SCy Schubert 	if (wpa_s->dpp_auth) {
3854c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
3855c1d255d3SCy Schubert 			   "DPP: Not ready to start reconfiguration - pending authentication exchange in progress");
3856c1d255d3SCy Schubert 		return -1;
3857c1d255d3SCy Schubert 	}
3858c1d255d3SCy Schubert 
3859c1d255d3SCy Schubert 	dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
3860c1d255d3SCy Schubert 	wpa_s->dpp_reconfig_id = dpp_gen_reconfig_id(ssid->dpp_csign,
3861c1d255d3SCy Schubert 						     ssid->dpp_csign_len,
3862c1d255d3SCy Schubert 						     ssid->dpp_pp_key,
3863c1d255d3SCy Schubert 						     ssid->dpp_pp_key_len);
3864c1d255d3SCy Schubert 	if (!wpa_s->dpp_reconfig_id) {
3865c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
3866c1d255d3SCy Schubert 			   "DPP: Failed to generate E-id for reconfiguration");
3867c1d255d3SCy Schubert 		return -1;
3868c1d255d3SCy Schubert 	}
3869c1d255d3SCy Schubert 	if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
3870c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Disconnect for reconfiguration");
3871c1d255d3SCy Schubert 		wpa_s->own_disconnect_req = 1;
3872c1d255d3SCy Schubert 		wpa_supplicant_deauthenticate(
3873c1d255d3SCy Schubert 			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
3874c1d255d3SCy Schubert 	}
3875c1d255d3SCy Schubert 	wpas_dpp_chirp_stop(wpa_s);
3876c1d255d3SCy Schubert 	wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
3877c1d255d3SCy Schubert 	wpa_s->dpp_qr_mutual = 0;
3878c1d255d3SCy Schubert 	wpa_s->dpp_reconfig_ssid = ssid;
3879c1d255d3SCy Schubert 	wpa_s->dpp_reconfig_ssid_id = ssid->id;
3880c1d255d3SCy Schubert 	wpa_s->dpp_chirp_iter = iter;
3881c1d255d3SCy Schubert 	wpa_s->dpp_chirp_round = 0;
3882c1d255d3SCy Schubert 	wpa_s->dpp_chirp_scan_done = 0;
3883c1d255d3SCy Schubert 	wpa_s->dpp_chirp_listen = 0;
3884c1d255d3SCy Schubert 
3885c1d255d3SCy Schubert 	return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
3886c1d255d3SCy Schubert }
3887c1d255d3SCy Schubert 
3888c1d255d3SCy Schubert 
3889c1d255d3SCy Schubert static int wpas_dpp_build_conf_resp(struct wpa_supplicant *wpa_s,
3890c1d255d3SCy Schubert 				    struct dpp_authentication *auth, bool tcp)
3891c1d255d3SCy Schubert {
3892c1d255d3SCy Schubert 	struct wpabuf *resp;
3893c1d255d3SCy Schubert 
3894c1d255d3SCy Schubert 	resp = dpp_build_conf_resp(auth, auth->e_nonce, auth->curve->nonce_len,
3895c1d255d3SCy Schubert 				   auth->e_netrole, true);
3896c1d255d3SCy Schubert 	if (!resp)
3897c1d255d3SCy Schubert 		return -1;
3898c1d255d3SCy Schubert 
3899c1d255d3SCy Schubert 	if (tcp) {
3900c1d255d3SCy Schubert 		auth->conf_resp_tcp = resp;
3901c1d255d3SCy Schubert 		return 0;
3902c1d255d3SCy Schubert 	}
3903c1d255d3SCy Schubert 
3904c1d255d3SCy Schubert 	if (gas_server_set_resp(wpa_s->gas_server, auth->cert_resp_ctx,
3905c1d255d3SCy Schubert 				resp) < 0) {
3906c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
3907c1d255d3SCy Schubert 			   "DPP: Could not find pending GAS response");
3908c1d255d3SCy Schubert 		wpabuf_free(resp);
3909c1d255d3SCy Schubert 		return -1;
3910c1d255d3SCy Schubert 	}
3911c1d255d3SCy Schubert 	auth->conf_resp = resp;
3912c1d255d3SCy Schubert 	return 0;
3913c1d255d3SCy Schubert }
3914c1d255d3SCy Schubert 
3915c1d255d3SCy Schubert 
3916c1d255d3SCy Schubert int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd)
3917c1d255d3SCy Schubert {
3918c1d255d3SCy Schubert 	int peer = -1;
3919c1d255d3SCy Schubert 	const char *pos, *value;
3920c1d255d3SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
3921c1d255d3SCy Schubert 	u8 *bin;
3922c1d255d3SCy Schubert 	size_t bin_len;
3923c1d255d3SCy Schubert 	struct wpabuf *buf;
3924c1d255d3SCy Schubert 	bool tcp = false;
3925c1d255d3SCy Schubert 
3926c1d255d3SCy Schubert 	pos = os_strstr(cmd, " peer=");
3927c1d255d3SCy Schubert 	if (pos) {
3928c1d255d3SCy Schubert 		peer = atoi(pos + 6);
3929c1d255d3SCy Schubert 		if (!auth || !auth->waiting_cert ||
3930c1d255d3SCy Schubert 		    (auth->peer_bi &&
3931c1d255d3SCy Schubert 		     (unsigned int) peer != auth->peer_bi->id)) {
3932c1d255d3SCy Schubert 			auth = dpp_controller_get_auth(wpa_s->dpp, peer);
3933c1d255d3SCy Schubert 			tcp = true;
3934c1d255d3SCy Schubert 		}
3935c1d255d3SCy Schubert 	}
3936c1d255d3SCy Schubert 
3937c1d255d3SCy Schubert 	if (!auth || !auth->waiting_cert) {
3938c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
3939c1d255d3SCy Schubert 			   "DPP: No authentication exchange waiting for certificate information");
3940c1d255d3SCy Schubert 		return -1;
3941c1d255d3SCy Schubert 	}
3942c1d255d3SCy Schubert 
3943c1d255d3SCy Schubert 	if (peer >= 0 &&
3944c1d255d3SCy Schubert 	    (!auth->peer_bi ||
3945c1d255d3SCy Schubert 	     (unsigned int) peer != auth->peer_bi->id) &&
3946c1d255d3SCy Schubert 	    (!auth->tmp_peer_bi ||
3947c1d255d3SCy Schubert 	     (unsigned int) peer != auth->tmp_peer_bi->id)) {
3948c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Peer mismatch");
3949c1d255d3SCy Schubert 		return -1;
3950c1d255d3SCy Schubert 	}
3951c1d255d3SCy Schubert 
3952c1d255d3SCy Schubert 	pos = os_strstr(cmd, " value=");
3953c1d255d3SCy Schubert 	if (!pos)
3954c1d255d3SCy Schubert 		return -1;
3955c1d255d3SCy Schubert 	value = pos + 7;
3956c1d255d3SCy Schubert 
3957c1d255d3SCy Schubert 	pos = os_strstr(cmd, " name=");
3958c1d255d3SCy Schubert 	if (!pos)
3959c1d255d3SCy Schubert 		return -1;
3960c1d255d3SCy Schubert 	pos += 6;
3961c1d255d3SCy Schubert 
3962c1d255d3SCy Schubert 	if (os_strncmp(pos, "status ", 7) == 0) {
3963c1d255d3SCy Schubert 		auth->force_conf_resp_status = atoi(value);
3964c1d255d3SCy Schubert 		return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
3965c1d255d3SCy Schubert 	}
3966c1d255d3SCy Schubert 
3967c1d255d3SCy Schubert 	if (os_strncmp(pos, "trustedEapServerName ", 21) == 0) {
3968c1d255d3SCy Schubert 		os_free(auth->trusted_eap_server_name);
3969c1d255d3SCy Schubert 		auth->trusted_eap_server_name = os_strdup(value);
3970c1d255d3SCy Schubert 		return auth->trusted_eap_server_name ? 0 : -1;
3971c1d255d3SCy Schubert 	}
3972c1d255d3SCy Schubert 
3973c1d255d3SCy Schubert 	bin = base64_decode(value, os_strlen(value), &bin_len);
3974c1d255d3SCy Schubert 	if (!bin)
3975c1d255d3SCy Schubert 		return -1;
3976c1d255d3SCy Schubert 	buf = wpabuf_alloc_copy(bin, bin_len);
3977c1d255d3SCy Schubert 	os_free(bin);
3978c1d255d3SCy Schubert 
3979c1d255d3SCy Schubert 	if (os_strncmp(pos, "caCert ", 7) == 0) {
3980c1d255d3SCy Schubert 		wpabuf_free(auth->cacert);
3981c1d255d3SCy Schubert 		auth->cacert = buf;
3982c1d255d3SCy Schubert 		return 0;
3983c1d255d3SCy Schubert 	}
3984c1d255d3SCy Schubert 
3985c1d255d3SCy Schubert 	if (os_strncmp(pos, "certBag ", 8) == 0) {
3986c1d255d3SCy Schubert 		wpabuf_free(auth->certbag);
3987c1d255d3SCy Schubert 		auth->certbag = buf;
3988c1d255d3SCy Schubert 		return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
3989c1d255d3SCy Schubert 	}
3990c1d255d3SCy Schubert 
3991c1d255d3SCy Schubert 	wpabuf_free(buf);
3992c1d255d3SCy Schubert 	return -1;
3993c1d255d3SCy Schubert }
3994c1d255d3SCy Schubert 
3995206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
3996