xref: /freebsd/contrib/wpa/wpa_supplicant/dpp_supplicant.c (revision 206b73d0429edb7c49b612537544e677fa568e83)
185732ac8SCy Schubert /*
285732ac8SCy Schubert  * wpa_supplicant - DPP
385732ac8SCy Schubert  * Copyright (c) 2017, Qualcomm Atheros, Inc.
44bc52338SCy Schubert  * Copyright (c) 2018-2019, 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"
14*206b73d0SCy Schubert #include "utils/ip_addr.h"
1585732ac8SCy Schubert #include "common/dpp.h"
1685732ac8SCy Schubert #include "common/gas.h"
1785732ac8SCy Schubert #include "common/gas_server.h"
1885732ac8SCy Schubert #include "rsn_supp/wpa.h"
1985732ac8SCy Schubert #include "rsn_supp/pmksa_cache.h"
2085732ac8SCy Schubert #include "wpa_supplicant_i.h"
2185732ac8SCy Schubert #include "config.h"
2285732ac8SCy Schubert #include "driver_i.h"
2385732ac8SCy Schubert #include "offchannel.h"
2485732ac8SCy Schubert #include "gas_query.h"
2585732ac8SCy Schubert #include "bss.h"
2685732ac8SCy Schubert #include "scan.h"
2785732ac8SCy Schubert #include "notify.h"
2885732ac8SCy Schubert #include "dpp_supplicant.h"
2985732ac8SCy Schubert 
3085732ac8SCy Schubert 
3185732ac8SCy Schubert static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
3285732ac8SCy Schubert 				 unsigned int freq);
3385732ac8SCy Schubert static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
3485732ac8SCy Schubert static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator);
3585732ac8SCy Schubert static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
3685732ac8SCy Schubert 			       unsigned int freq, const u8 *dst,
3785732ac8SCy Schubert 			       const u8 *src, const u8 *bssid,
3885732ac8SCy Schubert 			       const u8 *data, size_t data_len,
3985732ac8SCy Schubert 			       enum offchannel_send_action_result result);
4085732ac8SCy Schubert static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
4185732ac8SCy Schubert static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s);
4285732ac8SCy Schubert static void
4385732ac8SCy Schubert wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
4485732ac8SCy Schubert 			unsigned int freq, const u8 *dst,
4585732ac8SCy Schubert 			const u8 *src, const u8 *bssid,
4685732ac8SCy Schubert 			const u8 *data, size_t data_len,
4785732ac8SCy Schubert 			enum offchannel_send_action_result result);
4885732ac8SCy Schubert 
4985732ac8SCy Schubert static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
5085732ac8SCy Schubert 
5185732ac8SCy Schubert /* Use a hardcoded Transaction ID 1 in Peer Discovery frames since there is only
5285732ac8SCy Schubert  * a single transaction in progress at any point in time. */
5385732ac8SCy Schubert static const u8 TRANSACTION_ID = 1;
5485732ac8SCy Schubert 
5585732ac8SCy Schubert 
5685732ac8SCy Schubert /**
5785732ac8SCy Schubert  * wpas_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
5885732ac8SCy Schubert  * @wpa_s: Pointer to wpa_supplicant data
5985732ac8SCy Schubert  * @cmd: DPP URI read from a QR Code
6085732ac8SCy Schubert  * Returns: Identifier of the stored info or -1 on failure
6185732ac8SCy Schubert  */
6285732ac8SCy Schubert int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd)
6385732ac8SCy Schubert {
6485732ac8SCy Schubert 	struct dpp_bootstrap_info *bi;
6585732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
6685732ac8SCy Schubert 
674bc52338SCy Schubert 	bi = dpp_add_qr_code(wpa_s->dpp, cmd);
6885732ac8SCy Schubert 	if (!bi)
6985732ac8SCy Schubert 		return -1;
7085732ac8SCy Schubert 
7185732ac8SCy Schubert 	if (auth && auth->response_pending &&
7285732ac8SCy Schubert 	    dpp_notify_new_qr_code(auth, bi) == 1) {
7385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
7485732ac8SCy Schubert 			   "DPP: Sending out pending authentication response");
7585732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
7685732ac8SCy Schubert 			" freq=%u type=%d",
7785732ac8SCy Schubert 			MAC2STR(auth->peer_mac_addr), auth->curr_freq,
7885732ac8SCy Schubert 			DPP_PA_AUTHENTICATION_RESP);
7985732ac8SCy Schubert 		offchannel_send_action(wpa_s, auth->curr_freq,
8085732ac8SCy Schubert 				       auth->peer_mac_addr, wpa_s->own_addr,
8185732ac8SCy Schubert 				       broadcast,
8285732ac8SCy Schubert 				       wpabuf_head(auth->resp_msg),
8385732ac8SCy Schubert 				       wpabuf_len(auth->resp_msg),
8485732ac8SCy Schubert 				       500, wpas_dpp_tx_status, 0);
8585732ac8SCy Schubert 	}
8685732ac8SCy Schubert 
8785732ac8SCy Schubert 	return bi->id;
8885732ac8SCy Schubert }
8985732ac8SCy Schubert 
9085732ac8SCy Schubert 
9185732ac8SCy Schubert static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
9285732ac8SCy Schubert {
9385732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
9485732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
9585732ac8SCy Schubert 
9685732ac8SCy Schubert 	if (!auth || !auth->resp_msg)
9785732ac8SCy Schubert 		return;
9885732ac8SCy Schubert 
9985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
10085732ac8SCy Schubert 		   "DPP: Retry Authentication Response after timeout");
10185732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
10285732ac8SCy Schubert 		" freq=%u type=%d",
10385732ac8SCy Schubert 		MAC2STR(auth->peer_mac_addr), auth->curr_freq,
10485732ac8SCy Schubert 		DPP_PA_AUTHENTICATION_RESP);
10585732ac8SCy Schubert 	offchannel_send_action(wpa_s, auth->curr_freq, auth->peer_mac_addr,
10685732ac8SCy Schubert 			       wpa_s->own_addr, broadcast,
10785732ac8SCy Schubert 			       wpabuf_head(auth->resp_msg),
10885732ac8SCy Schubert 			       wpabuf_len(auth->resp_msg),
10985732ac8SCy Schubert 			       500, wpas_dpp_tx_status, 0);
11085732ac8SCy Schubert }
11185732ac8SCy Schubert 
11285732ac8SCy Schubert 
11385732ac8SCy Schubert static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s)
11485732ac8SCy Schubert {
11585732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
11685732ac8SCy Schubert 	unsigned int wait_time, max_tries;
11785732ac8SCy Schubert 
11885732ac8SCy Schubert 	if (!auth || !auth->resp_msg)
11985732ac8SCy Schubert 		return;
12085732ac8SCy Schubert 
12185732ac8SCy Schubert 	if (wpa_s->dpp_resp_max_tries)
12285732ac8SCy Schubert 		max_tries = wpa_s->dpp_resp_max_tries;
12385732ac8SCy Schubert 	else
12485732ac8SCy Schubert 		max_tries = 5;
12585732ac8SCy Schubert 	auth->auth_resp_tries++;
12685732ac8SCy Schubert 	if (auth->auth_resp_tries >= max_tries) {
12785732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: No confirm received from initiator - stopping exchange");
12885732ac8SCy Schubert 		offchannel_send_action_done(wpa_s);
12985732ac8SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
13085732ac8SCy Schubert 		wpa_s->dpp_auth = NULL;
13185732ac8SCy Schubert 		return;
13285732ac8SCy Schubert 	}
13385732ac8SCy Schubert 
13485732ac8SCy Schubert 	if (wpa_s->dpp_resp_retry_time)
13585732ac8SCy Schubert 		wait_time = wpa_s->dpp_resp_retry_time;
13685732ac8SCy Schubert 	else
13785732ac8SCy Schubert 		wait_time = 1000;
13885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
13985732ac8SCy Schubert 		   "DPP: Schedule retransmission of Authentication Response frame in %u ms",
14085732ac8SCy Schubert 		wait_time);
14185732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
14285732ac8SCy Schubert 	eloop_register_timeout(wait_time / 1000,
14385732ac8SCy Schubert 			       (wait_time % 1000) * 1000,
14485732ac8SCy Schubert 			       wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
14585732ac8SCy Schubert }
14685732ac8SCy Schubert 
14785732ac8SCy Schubert 
1484bc52338SCy Schubert static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
1494bc52338SCy Schubert {
1504bc52338SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
1514bc52338SCy Schubert 	wpa_s->disconnected = 0;
1524bc52338SCy Schubert 	wpa_s->reassociate = 1;
1534bc52338SCy Schubert 	wpa_s->scan_runs = 0;
1544bc52338SCy Schubert 	wpa_s->normal_scans = 0;
1554bc52338SCy Schubert 	wpa_supplicant_cancel_sched_scan(wpa_s);
1564bc52338SCy Schubert 	wpa_supplicant_req_scan(wpa_s, 0, 0);
1574bc52338SCy Schubert }
1584bc52338SCy Schubert 
1594bc52338SCy Schubert 
16085732ac8SCy Schubert static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
16185732ac8SCy Schubert 			       unsigned int freq, const u8 *dst,
16285732ac8SCy Schubert 			       const u8 *src, const u8 *bssid,
16385732ac8SCy Schubert 			       const u8 *data, size_t data_len,
16485732ac8SCy Schubert 			       enum offchannel_send_action_result result)
16585732ac8SCy Schubert {
16685732ac8SCy Schubert 	const char *res_txt;
16785732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
16885732ac8SCy Schubert 
16985732ac8SCy Schubert 	res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
17085732ac8SCy Schubert 		(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
17185732ac8SCy Schubert 		 "FAILED");
17285732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
17385732ac8SCy Schubert 		   " result=%s", freq, MAC2STR(dst), res_txt);
17485732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
17585732ac8SCy Schubert 		" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
17685732ac8SCy Schubert 
17785732ac8SCy Schubert 	if (!wpa_s->dpp_auth) {
17885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
17985732ac8SCy Schubert 			   "DPP: Ignore TX status since there is no ongoing authentication exchange");
18085732ac8SCy Schubert 		return;
18185732ac8SCy Schubert 	}
18285732ac8SCy Schubert 
1834bc52338SCy Schubert #ifdef CONFIG_DPP2
1844bc52338SCy Schubert 	if (auth->connect_on_tx_status) {
1854bc52338SCy Schubert 		wpa_printf(MSG_DEBUG,
1864bc52338SCy Schubert 			   "DPP: Try to connect after completed configuration result");
1874bc52338SCy Schubert 		wpas_dpp_try_to_connect(wpa_s);
1884bc52338SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
1894bc52338SCy Schubert 		wpa_s->dpp_auth = NULL;
1904bc52338SCy Schubert 		return;
1914bc52338SCy Schubert 	}
1924bc52338SCy Schubert #endif /* CONFIG_DPP2 */
1934bc52338SCy Schubert 
19485732ac8SCy Schubert 	if (wpa_s->dpp_auth->remove_on_tx_status) {
19585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
19685732ac8SCy Schubert 			   "DPP: Terminate authentication exchange due to an earlier error");
19785732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
19885732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
19985732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
20085732ac8SCy Schubert 				     NULL);
20185732ac8SCy Schubert 		offchannel_send_action_done(wpa_s);
20285732ac8SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
20385732ac8SCy Schubert 		wpa_s->dpp_auth = NULL;
20485732ac8SCy Schubert 		return;
20585732ac8SCy Schubert 	}
20685732ac8SCy Schubert 
20785732ac8SCy Schubert 	if (wpa_s->dpp_auth_ok_on_ack)
20885732ac8SCy Schubert 		wpas_dpp_auth_success(wpa_s, 1);
20985732ac8SCy Schubert 
21085732ac8SCy Schubert 	if (!is_broadcast_ether_addr(dst) &&
21185732ac8SCy Schubert 	    result != OFFCHANNEL_SEND_ACTION_SUCCESS) {
21285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
21385732ac8SCy Schubert 			   "DPP: Unicast DPP Action frame was not ACKed");
21485732ac8SCy Schubert 		if (auth->waiting_auth_resp) {
21585732ac8SCy Schubert 			/* In case of DPP Authentication Request frame, move to
21685732ac8SCy Schubert 			 * the next channel immediately. */
21785732ac8SCy Schubert 			offchannel_send_action_done(wpa_s);
21885732ac8SCy Schubert 			wpas_dpp_auth_init_next(wpa_s);
21985732ac8SCy Schubert 			return;
22085732ac8SCy Schubert 		}
22185732ac8SCy Schubert 		if (auth->waiting_auth_conf) {
22285732ac8SCy Schubert 			wpas_dpp_auth_resp_retry(wpa_s);
22385732ac8SCy Schubert 			return;
22485732ac8SCy Schubert 		}
22585732ac8SCy Schubert 	}
22685732ac8SCy Schubert 
22785732ac8SCy Schubert 	if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp &&
22885732ac8SCy Schubert 	    result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
22985732ac8SCy Schubert 		/* Allow timeout handling to stop iteration if no response is
23085732ac8SCy Schubert 		 * received from a peer that has ACKed a request. */
23185732ac8SCy Schubert 		auth->auth_req_ack = 1;
23285732ac8SCy Schubert 	}
23385732ac8SCy Schubert 
23485732ac8SCy Schubert 	if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 &&
23585732ac8SCy Schubert 	    wpa_s->dpp_auth->curr_freq != wpa_s->dpp_auth->neg_freq) {
23685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
23785732ac8SCy Schubert 			   "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
23885732ac8SCy Schubert 			   wpa_s->dpp_auth->curr_freq,
23985732ac8SCy Schubert 			   wpa_s->dpp_auth->neg_freq);
24085732ac8SCy Schubert 		offchannel_send_action_done(wpa_s);
24185732ac8SCy Schubert 		wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->neg_freq);
24285732ac8SCy Schubert 	}
24385732ac8SCy Schubert 
24485732ac8SCy Schubert 	if (wpa_s->dpp_auth_ok_on_ack)
24585732ac8SCy Schubert 		wpa_s->dpp_auth_ok_on_ack = 0;
24685732ac8SCy Schubert }
24785732ac8SCy Schubert 
24885732ac8SCy Schubert 
24985732ac8SCy Schubert static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
25085732ac8SCy Schubert {
25185732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
25285732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
25385732ac8SCy Schubert 	unsigned int freq;
25485732ac8SCy Schubert 	struct os_reltime now, diff;
25585732ac8SCy Schubert 	unsigned int wait_time, diff_ms;
25685732ac8SCy Schubert 
25785732ac8SCy Schubert 	if (!auth || !auth->waiting_auth_resp)
25885732ac8SCy Schubert 		return;
25985732ac8SCy Schubert 
26085732ac8SCy Schubert 	wait_time = wpa_s->dpp_resp_wait_time ?
26185732ac8SCy Schubert 		wpa_s->dpp_resp_wait_time : 2000;
26285732ac8SCy Schubert 	os_get_reltime(&now);
26385732ac8SCy Schubert 	os_reltime_sub(&now, &wpa_s->dpp_last_init, &diff);
26485732ac8SCy Schubert 	diff_ms = diff.sec * 1000 + diff.usec / 1000;
26585732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
26685732ac8SCy Schubert 		   "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
26785732ac8SCy Schubert 		   wait_time, diff_ms);
26885732ac8SCy Schubert 
26985732ac8SCy Schubert 	if (auth->auth_req_ack && diff_ms >= wait_time) {
27085732ac8SCy Schubert 		/* Peer ACK'ed Authentication Request frame, but did not reply
27185732ac8SCy Schubert 		 * with Authentication Response frame within two seconds. */
27285732ac8SCy Schubert 		wpa_printf(MSG_INFO,
27385732ac8SCy Schubert 			   "DPP: No response received from responder - stopping initiation attempt");
27485732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
27585732ac8SCy Schubert 		offchannel_send_action_done(wpa_s);
27685732ac8SCy Schubert 		wpas_dpp_listen_stop(wpa_s);
27785732ac8SCy Schubert 		dpp_auth_deinit(auth);
27885732ac8SCy Schubert 		wpa_s->dpp_auth = NULL;
27985732ac8SCy Schubert 		return;
28085732ac8SCy Schubert 	}
28185732ac8SCy Schubert 
28285732ac8SCy Schubert 	if (diff_ms >= wait_time) {
28385732ac8SCy Schubert 		/* Authentication Request frame was not ACK'ed and no reply
28485732ac8SCy Schubert 		 * was receiving within two seconds. */
28585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
28685732ac8SCy Schubert 			   "DPP: Continue Initiator channel iteration");
28785732ac8SCy Schubert 		offchannel_send_action_done(wpa_s);
28885732ac8SCy Schubert 		wpas_dpp_listen_stop(wpa_s);
28985732ac8SCy Schubert 		wpas_dpp_auth_init_next(wpa_s);
29085732ac8SCy Schubert 		return;
29185732ac8SCy Schubert 	}
29285732ac8SCy Schubert 
29385732ac8SCy Schubert 	/* Driver did not support 2000 ms long wait_time with TX command, so
29485732ac8SCy Schubert 	 * schedule listen operation to continue waiting for the response.
29585732ac8SCy Schubert 	 *
29685732ac8SCy Schubert 	 * DPP listen operations continue until stopped, so simply schedule a
29785732ac8SCy Schubert 	 * new call to this function at the point when the two second reply
29885732ac8SCy Schubert 	 * wait has expired. */
29985732ac8SCy Schubert 	wait_time -= diff_ms;
30085732ac8SCy Schubert 
30185732ac8SCy Schubert 	freq = auth->curr_freq;
30285732ac8SCy Schubert 	if (auth->neg_freq > 0)
30385732ac8SCy Schubert 		freq = auth->neg_freq;
30485732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
30585732ac8SCy Schubert 		   "DPP: Continue reply wait on channel %u MHz for %u ms",
30685732ac8SCy Schubert 		   freq, wait_time);
30785732ac8SCy Schubert 	wpa_s->dpp_in_response_listen = 1;
30885732ac8SCy Schubert 	wpas_dpp_listen_start(wpa_s, freq);
30985732ac8SCy Schubert 
31085732ac8SCy Schubert 	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
31185732ac8SCy Schubert 			       wpas_dpp_reply_wait_timeout, wpa_s, NULL);
31285732ac8SCy Schubert }
31385732ac8SCy Schubert 
31485732ac8SCy Schubert 
31585732ac8SCy Schubert static void wpas_dpp_set_testing_options(struct wpa_supplicant *wpa_s,
31685732ac8SCy Schubert 					 struct dpp_authentication *auth)
31785732ac8SCy Schubert {
31885732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
31985732ac8SCy Schubert 	if (wpa_s->dpp_config_obj_override)
32085732ac8SCy Schubert 		auth->config_obj_override =
32185732ac8SCy Schubert 			os_strdup(wpa_s->dpp_config_obj_override);
32285732ac8SCy Schubert 	if (wpa_s->dpp_discovery_override)
32385732ac8SCy Schubert 		auth->discovery_override =
32485732ac8SCy Schubert 			os_strdup(wpa_s->dpp_discovery_override);
32585732ac8SCy Schubert 	if (wpa_s->dpp_groups_override)
32685732ac8SCy Schubert 		auth->groups_override =
32785732ac8SCy Schubert 			os_strdup(wpa_s->dpp_groups_override);
32885732ac8SCy Schubert 	auth->ignore_netaccesskey_mismatch =
32985732ac8SCy Schubert 		wpa_s->dpp_ignore_netaccesskey_mismatch;
33085732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
33185732ac8SCy Schubert }
33285732ac8SCy Schubert 
33385732ac8SCy Schubert 
33485732ac8SCy Schubert static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
33585732ac8SCy Schubert {
33685732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
33785732ac8SCy Schubert 
33885732ac8SCy Schubert 	if (!wpa_s->dpp_auth)
33985732ac8SCy Schubert 		return;
34085732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
34185732ac8SCy Schubert 	wpas_dpp_auth_init_next(wpa_s);
34285732ac8SCy Schubert }
34385732ac8SCy Schubert 
34485732ac8SCy Schubert 
34585732ac8SCy Schubert static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s)
34685732ac8SCy Schubert {
34785732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
34885732ac8SCy Schubert 	const u8 *dst;
34985732ac8SCy Schubert 	unsigned int wait_time, max_wait_time, freq, max_tries, used;
35085732ac8SCy Schubert 	struct os_reltime now, diff;
35185732ac8SCy Schubert 
35285732ac8SCy Schubert 	wpa_s->dpp_in_response_listen = 0;
35385732ac8SCy Schubert 	if (!auth)
35485732ac8SCy Schubert 		return -1;
35585732ac8SCy Schubert 
35685732ac8SCy Schubert 	if (auth->freq_idx == 0)
35785732ac8SCy Schubert 		os_get_reltime(&wpa_s->dpp_init_iter_start);
35885732ac8SCy Schubert 
35985732ac8SCy Schubert 	if (auth->freq_idx >= auth->num_freq) {
36085732ac8SCy Schubert 		auth->num_freq_iters++;
36185732ac8SCy Schubert 		if (wpa_s->dpp_init_max_tries)
36285732ac8SCy Schubert 			max_tries = wpa_s->dpp_init_max_tries;
36385732ac8SCy Schubert 		else
36485732ac8SCy Schubert 			max_tries = 5;
36585732ac8SCy Schubert 		if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
36685732ac8SCy Schubert 			wpa_printf(MSG_INFO,
36785732ac8SCy Schubert 				   "DPP: No response received from responder - stopping initiation attempt");
36885732ac8SCy Schubert 			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
36985732ac8SCy Schubert 			eloop_cancel_timeout(wpas_dpp_reply_wait_timeout,
37085732ac8SCy Schubert 					     wpa_s, NULL);
37185732ac8SCy Schubert 			offchannel_send_action_done(wpa_s);
37285732ac8SCy Schubert 			dpp_auth_deinit(wpa_s->dpp_auth);
37385732ac8SCy Schubert 			wpa_s->dpp_auth = NULL;
37485732ac8SCy Schubert 			return -1;
37585732ac8SCy Schubert 		}
37685732ac8SCy Schubert 		auth->freq_idx = 0;
37785732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
37885732ac8SCy Schubert 		if (wpa_s->dpp_init_retry_time)
37985732ac8SCy Schubert 			wait_time = wpa_s->dpp_init_retry_time;
38085732ac8SCy Schubert 		else
38185732ac8SCy Schubert 			wait_time = 10000;
38285732ac8SCy Schubert 		os_get_reltime(&now);
38385732ac8SCy Schubert 		os_reltime_sub(&now, &wpa_s->dpp_init_iter_start, &diff);
38485732ac8SCy Schubert 		used = diff.sec * 1000 + diff.usec / 1000;
38585732ac8SCy Schubert 		if (used > wait_time)
38685732ac8SCy Schubert 			wait_time = 0;
38785732ac8SCy Schubert 		else
38885732ac8SCy Schubert 			wait_time -= used;
38985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
39085732ac8SCy Schubert 			   wait_time);
39185732ac8SCy Schubert 		eloop_register_timeout(wait_time / 1000,
39285732ac8SCy Schubert 				       (wait_time % 1000) * 1000,
39385732ac8SCy Schubert 				       wpas_dpp_init_timeout, wpa_s,
39485732ac8SCy Schubert 				       NULL);
39585732ac8SCy Schubert 		return 0;
39685732ac8SCy Schubert 	}
39785732ac8SCy Schubert 	freq = auth->freq[auth->freq_idx++];
39885732ac8SCy Schubert 	auth->curr_freq = freq;
39985732ac8SCy Schubert 
40085732ac8SCy Schubert 	if (is_zero_ether_addr(auth->peer_bi->mac_addr))
40185732ac8SCy Schubert 		dst = broadcast;
40285732ac8SCy Schubert 	else
40385732ac8SCy Schubert 		dst = auth->peer_bi->mac_addr;
40485732ac8SCy Schubert 	wpa_s->dpp_auth_ok_on_ack = 0;
40585732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
40685732ac8SCy Schubert 	wait_time = wpa_s->max_remain_on_chan;
40785732ac8SCy Schubert 	max_wait_time = wpa_s->dpp_resp_wait_time ?
40885732ac8SCy Schubert 		wpa_s->dpp_resp_wait_time : 2000;
40985732ac8SCy Schubert 	if (wait_time > max_wait_time)
41085732ac8SCy Schubert 		wait_time = max_wait_time;
41185732ac8SCy Schubert 	wait_time += 10; /* give the driver some extra time to complete */
41285732ac8SCy Schubert 	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
41385732ac8SCy Schubert 			       wpas_dpp_reply_wait_timeout,
41485732ac8SCy Schubert 			       wpa_s, NULL);
41585732ac8SCy Schubert 	wait_time -= 10;
41685732ac8SCy Schubert 	if (auth->neg_freq > 0 && freq != auth->neg_freq) {
41785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
41885732ac8SCy Schubert 			   "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
41985732ac8SCy Schubert 			   freq, auth->neg_freq);
42085732ac8SCy Schubert 	}
42185732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
42285732ac8SCy Schubert 		MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
42385732ac8SCy Schubert 	auth->auth_req_ack = 0;
42485732ac8SCy Schubert 	os_get_reltime(&wpa_s->dpp_last_init);
42585732ac8SCy Schubert 	return offchannel_send_action(wpa_s, freq, dst,
42685732ac8SCy Schubert 				      wpa_s->own_addr, broadcast,
42785732ac8SCy Schubert 				      wpabuf_head(auth->req_msg),
42885732ac8SCy Schubert 				      wpabuf_len(auth->req_msg),
42985732ac8SCy Schubert 				      wait_time, wpas_dpp_tx_status, 0);
43085732ac8SCy Schubert }
43185732ac8SCy Schubert 
43285732ac8SCy Schubert 
43385732ac8SCy Schubert int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
43485732ac8SCy Schubert {
43585732ac8SCy Schubert 	const char *pos;
43685732ac8SCy Schubert 	struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
437*206b73d0SCy Schubert 	struct dpp_authentication *auth;
43885732ac8SCy Schubert 	u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
43985732ac8SCy Schubert 	unsigned int neg_freq = 0;
440*206b73d0SCy Schubert 	int tcp = 0;
441*206b73d0SCy Schubert #ifdef CONFIG_DPP2
442*206b73d0SCy Schubert 	int tcp_port = DPP_TCP_PORT;
443*206b73d0SCy Schubert 	struct hostapd_ip_addr ipaddr;
444*206b73d0SCy Schubert 	char *addr;
445*206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
44685732ac8SCy Schubert 
44785732ac8SCy Schubert 	wpa_s->dpp_gas_client = 0;
44885732ac8SCy Schubert 
44985732ac8SCy Schubert 	pos = os_strstr(cmd, " peer=");
45085732ac8SCy Schubert 	if (!pos)
45185732ac8SCy Schubert 		return -1;
45285732ac8SCy Schubert 	pos += 6;
4534bc52338SCy Schubert 	peer_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
45485732ac8SCy Schubert 	if (!peer_bi) {
45585732ac8SCy Schubert 		wpa_printf(MSG_INFO,
45685732ac8SCy Schubert 			   "DPP: Could not find bootstrapping info for the identified peer");
45785732ac8SCy Schubert 		return -1;
45885732ac8SCy Schubert 	}
45985732ac8SCy Schubert 
460*206b73d0SCy Schubert #ifdef CONFIG_DPP2
461*206b73d0SCy Schubert 	pos = os_strstr(cmd, " tcp_port=");
462*206b73d0SCy Schubert 	if (pos) {
463*206b73d0SCy Schubert 		pos += 10;
464*206b73d0SCy Schubert 		tcp_port = atoi(pos);
465*206b73d0SCy Schubert 	}
466*206b73d0SCy Schubert 
467*206b73d0SCy Schubert 	addr = get_param(cmd, " tcp_addr=");
468*206b73d0SCy Schubert 	if (addr) {
469*206b73d0SCy Schubert 		int res;
470*206b73d0SCy Schubert 
471*206b73d0SCy Schubert 		res = hostapd_parse_ip_addr(addr, &ipaddr);
472*206b73d0SCy Schubert 		os_free(addr);
473*206b73d0SCy Schubert 		if (res)
474*206b73d0SCy Schubert 			return -1;
475*206b73d0SCy Schubert 		tcp = 1;
476*206b73d0SCy Schubert 	}
477*206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
478*206b73d0SCy Schubert 
47985732ac8SCy Schubert 	pos = os_strstr(cmd, " own=");
48085732ac8SCy Schubert 	if (pos) {
48185732ac8SCy Schubert 		pos += 5;
4824bc52338SCy Schubert 		own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
48385732ac8SCy Schubert 		if (!own_bi) {
48485732ac8SCy Schubert 			wpa_printf(MSG_INFO,
48585732ac8SCy Schubert 				   "DPP: Could not find bootstrapping info for the identified local entry");
48685732ac8SCy Schubert 			return -1;
48785732ac8SCy Schubert 		}
48885732ac8SCy Schubert 
48985732ac8SCy Schubert 		if (peer_bi->curve != own_bi->curve) {
49085732ac8SCy Schubert 			wpa_printf(MSG_INFO,
49185732ac8SCy Schubert 				   "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
49285732ac8SCy Schubert 				   peer_bi->curve->name, own_bi->curve->name);
49385732ac8SCy Schubert 			return -1;
49485732ac8SCy Schubert 		}
49585732ac8SCy Schubert 	}
49685732ac8SCy Schubert 
49785732ac8SCy Schubert 	pos = os_strstr(cmd, " role=");
49885732ac8SCy Schubert 	if (pos) {
49985732ac8SCy Schubert 		pos += 6;
50085732ac8SCy Schubert 		if (os_strncmp(pos, "configurator", 12) == 0)
50185732ac8SCy Schubert 			allowed_roles = DPP_CAPAB_CONFIGURATOR;
50285732ac8SCy Schubert 		else if (os_strncmp(pos, "enrollee", 8) == 0)
50385732ac8SCy Schubert 			allowed_roles = DPP_CAPAB_ENROLLEE;
50485732ac8SCy Schubert 		else if (os_strncmp(pos, "either", 6) == 0)
50585732ac8SCy Schubert 			allowed_roles = DPP_CAPAB_CONFIGURATOR |
50685732ac8SCy Schubert 				DPP_CAPAB_ENROLLEE;
50785732ac8SCy Schubert 		else
50885732ac8SCy Schubert 			goto fail;
50985732ac8SCy Schubert 	}
51085732ac8SCy Schubert 
51185732ac8SCy Schubert 	pos = os_strstr(cmd, " netrole=");
51285732ac8SCy Schubert 	if (pos) {
51385732ac8SCy Schubert 		pos += 9;
51485732ac8SCy Schubert 		wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0;
51585732ac8SCy Schubert 	}
51685732ac8SCy Schubert 
51785732ac8SCy Schubert 	pos = os_strstr(cmd, " neg_freq=");
51885732ac8SCy Schubert 	if (pos)
51985732ac8SCy Schubert 		neg_freq = atoi(pos + 10);
52085732ac8SCy Schubert 
521*206b73d0SCy Schubert 	if (!tcp && wpa_s->dpp_auth) {
52285732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
52385732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
52485732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
52585732ac8SCy Schubert 				     NULL);
52685732ac8SCy Schubert 		offchannel_send_action_done(wpa_s);
52785732ac8SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
52885732ac8SCy Schubert 		wpa_s->dpp_auth = NULL;
529*206b73d0SCy Schubert 	}
530*206b73d0SCy Schubert 
531*206b73d0SCy Schubert 	auth = dpp_auth_init(wpa_s, peer_bi, own_bi, allowed_roles, neg_freq,
532*206b73d0SCy Schubert 			     wpa_s->hw.modes, wpa_s->hw.num_modes);
533*206b73d0SCy Schubert 	if (!auth)
534*206b73d0SCy Schubert 		goto fail;
535*206b73d0SCy Schubert 	wpas_dpp_set_testing_options(wpa_s, auth);
536*206b73d0SCy Schubert 	if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) < 0) {
537*206b73d0SCy Schubert 		dpp_auth_deinit(auth);
53885732ac8SCy Schubert 		goto fail;
53985732ac8SCy Schubert 	}
54085732ac8SCy Schubert 
541*206b73d0SCy Schubert 	auth->neg_freq = neg_freq;
54285732ac8SCy Schubert 
54385732ac8SCy Schubert 	if (!is_zero_ether_addr(peer_bi->mac_addr))
544*206b73d0SCy Schubert 		os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
54585732ac8SCy Schubert 
546*206b73d0SCy Schubert #ifdef CONFIG_DPP2
547*206b73d0SCy Schubert 	if (tcp)
548*206b73d0SCy Schubert 		return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port);
549*206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
550*206b73d0SCy Schubert 
551*206b73d0SCy Schubert 	wpa_s->dpp_auth = auth;
55285732ac8SCy Schubert 	return wpas_dpp_auth_init_next(wpa_s);
55385732ac8SCy Schubert fail:
55485732ac8SCy Schubert 	return -1;
55585732ac8SCy Schubert }
55685732ac8SCy Schubert 
55785732ac8SCy Schubert 
55885732ac8SCy Schubert struct wpas_dpp_listen_work {
55985732ac8SCy Schubert 	unsigned int freq;
56085732ac8SCy Schubert 	unsigned int duration;
56185732ac8SCy Schubert 	struct wpabuf *probe_resp_ie;
56285732ac8SCy Schubert };
56385732ac8SCy Schubert 
56485732ac8SCy Schubert 
56585732ac8SCy Schubert static void wpas_dpp_listen_work_free(struct wpas_dpp_listen_work *lwork)
56685732ac8SCy Schubert {
56785732ac8SCy Schubert 	if (!lwork)
56885732ac8SCy Schubert 		return;
56985732ac8SCy Schubert 	os_free(lwork);
57085732ac8SCy Schubert }
57185732ac8SCy Schubert 
57285732ac8SCy Schubert 
57385732ac8SCy Schubert static void wpas_dpp_listen_work_done(struct wpa_supplicant *wpa_s)
57485732ac8SCy Schubert {
57585732ac8SCy Schubert 	struct wpas_dpp_listen_work *lwork;
57685732ac8SCy Schubert 
57785732ac8SCy Schubert 	if (!wpa_s->dpp_listen_work)
57885732ac8SCy Schubert 		return;
57985732ac8SCy Schubert 
58085732ac8SCy Schubert 	lwork = wpa_s->dpp_listen_work->ctx;
58185732ac8SCy Schubert 	wpas_dpp_listen_work_free(lwork);
58285732ac8SCy Schubert 	radio_work_done(wpa_s->dpp_listen_work);
58385732ac8SCy Schubert 	wpa_s->dpp_listen_work = NULL;
58485732ac8SCy Schubert }
58585732ac8SCy Schubert 
58685732ac8SCy Schubert 
58785732ac8SCy Schubert static void dpp_start_listen_cb(struct wpa_radio_work *work, int deinit)
58885732ac8SCy Schubert {
58985732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = work->wpa_s;
59085732ac8SCy Schubert 	struct wpas_dpp_listen_work *lwork = work->ctx;
59185732ac8SCy Schubert 
59285732ac8SCy Schubert 	if (deinit) {
59385732ac8SCy Schubert 		if (work->started) {
59485732ac8SCy Schubert 			wpa_s->dpp_listen_work = NULL;
59585732ac8SCy Schubert 			wpas_dpp_listen_stop(wpa_s);
59685732ac8SCy Schubert 		}
59785732ac8SCy Schubert 		wpas_dpp_listen_work_free(lwork);
59885732ac8SCy Schubert 		return;
59985732ac8SCy Schubert 	}
60085732ac8SCy Schubert 
60185732ac8SCy Schubert 	wpa_s->dpp_listen_work = work;
60285732ac8SCy Schubert 
60385732ac8SCy Schubert 	wpa_s->dpp_pending_listen_freq = lwork->freq;
60485732ac8SCy Schubert 
60585732ac8SCy Schubert 	if (wpa_drv_remain_on_channel(wpa_s, lwork->freq,
60685732ac8SCy Schubert 				      wpa_s->max_remain_on_chan) < 0) {
60785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
60885732ac8SCy Schubert 			   "DPP: Failed to request the driver to remain on channel (%u MHz) for listen",
60985732ac8SCy Schubert 			   lwork->freq);
6104bc52338SCy Schubert 		wpa_s->dpp_listen_freq = 0;
61185732ac8SCy Schubert 		wpas_dpp_listen_work_done(wpa_s);
61285732ac8SCy Schubert 		wpa_s->dpp_pending_listen_freq = 0;
61385732ac8SCy Schubert 		return;
61485732ac8SCy Schubert 	}
61585732ac8SCy Schubert 	wpa_s->off_channel_freq = 0;
61685732ac8SCy Schubert 	wpa_s->roc_waiting_drv_freq = lwork->freq;
61785732ac8SCy Schubert }
61885732ac8SCy Schubert 
61985732ac8SCy Schubert 
62085732ac8SCy Schubert static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
62185732ac8SCy Schubert 				 unsigned int freq)
62285732ac8SCy Schubert {
62385732ac8SCy Schubert 	struct wpas_dpp_listen_work *lwork;
62485732ac8SCy Schubert 
62585732ac8SCy Schubert 	if (wpa_s->dpp_listen_work) {
62685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
62785732ac8SCy Schubert 			   "DPP: Reject start_listen since dpp_listen_work already exists");
62885732ac8SCy Schubert 		return -1;
62985732ac8SCy Schubert 	}
63085732ac8SCy Schubert 
63185732ac8SCy Schubert 	if (wpa_s->dpp_listen_freq)
63285732ac8SCy Schubert 		wpas_dpp_listen_stop(wpa_s);
63385732ac8SCy Schubert 	wpa_s->dpp_listen_freq = freq;
63485732ac8SCy Schubert 
63585732ac8SCy Schubert 	lwork = os_zalloc(sizeof(*lwork));
63685732ac8SCy Schubert 	if (!lwork)
63785732ac8SCy Schubert 		return -1;
63885732ac8SCy Schubert 	lwork->freq = freq;
63985732ac8SCy Schubert 
64085732ac8SCy Schubert 	if (radio_add_work(wpa_s, freq, "dpp-listen", 0, dpp_start_listen_cb,
64185732ac8SCy Schubert 			   lwork) < 0) {
64285732ac8SCy Schubert 		wpas_dpp_listen_work_free(lwork);
64385732ac8SCy Schubert 		return -1;
64485732ac8SCy Schubert 	}
64585732ac8SCy Schubert 
64685732ac8SCy Schubert 	return 0;
64785732ac8SCy Schubert }
64885732ac8SCy Schubert 
64985732ac8SCy Schubert 
65085732ac8SCy Schubert int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd)
65185732ac8SCy Schubert {
65285732ac8SCy Schubert 	int freq;
65385732ac8SCy Schubert 
65485732ac8SCy Schubert 	freq = atoi(cmd);
65585732ac8SCy Schubert 	if (freq <= 0)
65685732ac8SCy Schubert 		return -1;
65785732ac8SCy Schubert 
65885732ac8SCy Schubert 	if (os_strstr(cmd, " role=configurator"))
65985732ac8SCy Schubert 		wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR;
66085732ac8SCy Schubert 	else if (os_strstr(cmd, " role=enrollee"))
66185732ac8SCy Schubert 		wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
66285732ac8SCy Schubert 	else
66385732ac8SCy Schubert 		wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
66485732ac8SCy Schubert 			DPP_CAPAB_ENROLLEE;
66585732ac8SCy Schubert 	wpa_s->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
66685732ac8SCy Schubert 	wpa_s->dpp_netrole_ap = os_strstr(cmd, " netrole=ap") != NULL;
66785732ac8SCy Schubert 	if (wpa_s->dpp_listen_freq == (unsigned int) freq) {
66885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz",
66985732ac8SCy Schubert 			   freq);
67085732ac8SCy Schubert 		return 0;
67185732ac8SCy Schubert 	}
67285732ac8SCy Schubert 
67385732ac8SCy Schubert 	return wpas_dpp_listen_start(wpa_s, freq);
67485732ac8SCy Schubert }
67585732ac8SCy Schubert 
67685732ac8SCy Schubert 
67785732ac8SCy Schubert void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s)
67885732ac8SCy Schubert {
67985732ac8SCy Schubert 	wpa_s->dpp_in_response_listen = 0;
68085732ac8SCy Schubert 	if (!wpa_s->dpp_listen_freq)
68185732ac8SCy Schubert 		return;
68285732ac8SCy Schubert 
68385732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Stop listen on %u MHz",
68485732ac8SCy Schubert 		   wpa_s->dpp_listen_freq);
68585732ac8SCy Schubert 	wpa_drv_cancel_remain_on_channel(wpa_s);
68685732ac8SCy Schubert 	wpa_s->dpp_listen_freq = 0;
68785732ac8SCy Schubert 	wpas_dpp_listen_work_done(wpa_s);
68885732ac8SCy Schubert }
68985732ac8SCy Schubert 
69085732ac8SCy Schubert 
69185732ac8SCy Schubert void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
69285732ac8SCy Schubert 					  unsigned int freq)
69385732ac8SCy Schubert {
69485732ac8SCy Schubert 	wpas_dpp_listen_work_done(wpa_s);
69585732ac8SCy Schubert 
69685732ac8SCy Schubert 	if (wpa_s->dpp_auth && wpa_s->dpp_in_response_listen) {
69785732ac8SCy Schubert 		unsigned int new_freq;
69885732ac8SCy Schubert 
69985732ac8SCy Schubert 		/* Continue listen with a new remain-on-channel */
70085732ac8SCy Schubert 		if (wpa_s->dpp_auth->neg_freq > 0)
70185732ac8SCy Schubert 			new_freq = wpa_s->dpp_auth->neg_freq;
70285732ac8SCy Schubert 		else
70385732ac8SCy Schubert 			new_freq = wpa_s->dpp_auth->curr_freq;
70485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
70585732ac8SCy Schubert 			   "DPP: Continue wait on %u MHz for the ongoing DPP provisioning session",
70685732ac8SCy Schubert 			   new_freq);
70785732ac8SCy Schubert 		wpas_dpp_listen_start(wpa_s, new_freq);
70885732ac8SCy Schubert 		return;
70985732ac8SCy Schubert 	}
71085732ac8SCy Schubert 
71185732ac8SCy Schubert 	if (wpa_s->dpp_listen_freq) {
71285732ac8SCy Schubert 		/* Continue listen with a new remain-on-channel */
71385732ac8SCy Schubert 		wpas_dpp_listen_start(wpa_s, wpa_s->dpp_listen_freq);
71485732ac8SCy Schubert 	}
71585732ac8SCy Schubert }
71685732ac8SCy Schubert 
71785732ac8SCy Schubert 
71885732ac8SCy Schubert static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
71985732ac8SCy Schubert 				 const u8 *hdr, const u8 *buf, size_t len,
72085732ac8SCy Schubert 				 unsigned int freq)
72185732ac8SCy Schubert {
72285732ac8SCy Schubert 	const u8 *r_bootstrap, *i_bootstrap;
72385732ac8SCy Schubert 	u16 r_bootstrap_len, i_bootstrap_len;
7244bc52338SCy Schubert 	struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
7254bc52338SCy Schubert 
7264bc52338SCy Schubert 	if (!wpa_s->dpp)
7274bc52338SCy Schubert 		return;
72885732ac8SCy Schubert 
72985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
73085732ac8SCy Schubert 		   MAC2STR(src));
73185732ac8SCy Schubert 
73285732ac8SCy Schubert 	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
73385732ac8SCy Schubert 				   &r_bootstrap_len);
73485732ac8SCy Schubert 	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
73585732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
73685732ac8SCy Schubert 			"Missing or invalid required Responder Bootstrapping Key Hash attribute");
73785732ac8SCy Schubert 		return;
73885732ac8SCy Schubert 	}
73985732ac8SCy Schubert 	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
74085732ac8SCy Schubert 		    r_bootstrap, r_bootstrap_len);
74185732ac8SCy Schubert 
74285732ac8SCy Schubert 	i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
74385732ac8SCy Schubert 				   &i_bootstrap_len);
74485732ac8SCy Schubert 	if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
74585732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
74685732ac8SCy Schubert 			"Missing or invalid required Initiator Bootstrapping Key Hash attribute");
74785732ac8SCy Schubert 		return;
74885732ac8SCy Schubert 	}
74985732ac8SCy Schubert 	wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
75085732ac8SCy Schubert 		    i_bootstrap, i_bootstrap_len);
75185732ac8SCy Schubert 
75285732ac8SCy Schubert 	/* Try to find own and peer bootstrapping key matches based on the
75385732ac8SCy Schubert 	 * received hash values */
7544bc52338SCy Schubert 	dpp_bootstrap_find_pair(wpa_s->dpp, i_bootstrap, r_bootstrap,
7554bc52338SCy Schubert 				&own_bi, &peer_bi);
75685732ac8SCy Schubert 	if (!own_bi) {
75785732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
75885732ac8SCy Schubert 			"No matching own bootstrapping key found - ignore message");
75985732ac8SCy Schubert 		return;
76085732ac8SCy Schubert 	}
76185732ac8SCy Schubert 
76285732ac8SCy Schubert 	if (wpa_s->dpp_auth) {
76385732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
76485732ac8SCy Schubert 			"Already in DPP authentication exchange - ignore new one");
76585732ac8SCy Schubert 		return;
76685732ac8SCy Schubert 	}
76785732ac8SCy Schubert 
76885732ac8SCy Schubert 	wpa_s->dpp_gas_client = 0;
76985732ac8SCy Schubert 	wpa_s->dpp_auth_ok_on_ack = 0;
77085732ac8SCy Schubert 	wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s, wpa_s->dpp_allowed_roles,
77185732ac8SCy Schubert 					  wpa_s->dpp_qr_mutual,
77285732ac8SCy Schubert 					  peer_bi, own_bi, freq, hdr, buf, len);
77385732ac8SCy Schubert 	if (!wpa_s->dpp_auth) {
77485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No response generated");
77585732ac8SCy Schubert 		return;
77685732ac8SCy Schubert 	}
77785732ac8SCy Schubert 	wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
7784bc52338SCy Schubert 	if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth,
77985732ac8SCy Schubert 				 wpa_s->dpp_configurator_params) < 0) {
78085732ac8SCy Schubert 		dpp_auth_deinit(wpa_s->dpp_auth);
78185732ac8SCy Schubert 		wpa_s->dpp_auth = NULL;
78285732ac8SCy Schubert 		return;
78385732ac8SCy Schubert 	}
78485732ac8SCy Schubert 	os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN);
78585732ac8SCy Schubert 
78685732ac8SCy Schubert 	if (wpa_s->dpp_listen_freq &&
78785732ac8SCy Schubert 	    wpa_s->dpp_listen_freq != wpa_s->dpp_auth->curr_freq) {
78885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
78985732ac8SCy Schubert 			   "DPP: Stop listen on %u MHz to allow response on the request %u MHz",
79085732ac8SCy Schubert 			   wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq);
79185732ac8SCy Schubert 		wpas_dpp_listen_stop(wpa_s);
79285732ac8SCy Schubert 	}
79385732ac8SCy Schubert 
79485732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
79585732ac8SCy Schubert 		MAC2STR(src), wpa_s->dpp_auth->curr_freq,
79685732ac8SCy Schubert 		DPP_PA_AUTHENTICATION_RESP);
79785732ac8SCy Schubert 	offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq,
79885732ac8SCy Schubert 			       src, wpa_s->own_addr, broadcast,
79985732ac8SCy Schubert 			       wpabuf_head(wpa_s->dpp_auth->resp_msg),
80085732ac8SCy Schubert 			       wpabuf_len(wpa_s->dpp_auth->resp_msg),
80185732ac8SCy Schubert 			       500, wpas_dpp_tx_status, 0);
80285732ac8SCy Schubert }
80385732ac8SCy Schubert 
80485732ac8SCy Schubert 
80585732ac8SCy Schubert static void wpas_dpp_start_gas_server(struct wpa_supplicant *wpa_s)
80685732ac8SCy Schubert {
80785732ac8SCy Schubert 	/* TODO: stop wait and start ROC */
80885732ac8SCy Schubert }
80985732ac8SCy Schubert 
81085732ac8SCy Schubert 
81185732ac8SCy Schubert static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
81285732ac8SCy Schubert 					      struct dpp_authentication *auth)
81385732ac8SCy Schubert {
81485732ac8SCy Schubert 	struct wpa_ssid *ssid;
81585732ac8SCy Schubert 
8164bc52338SCy Schubert #ifdef CONFIG_DPP2
8174bc52338SCy Schubert 	if (auth->akm == DPP_AKM_SAE) {
8184bc52338SCy Schubert #ifdef CONFIG_SAE
8194bc52338SCy Schubert 		struct wpa_driver_capa capa;
8204bc52338SCy Schubert 		int res;
8214bc52338SCy Schubert 
8224bc52338SCy Schubert 		res = wpa_drv_get_capa(wpa_s, &capa);
8234bc52338SCy Schubert 		if (res == 0 &&
8244bc52338SCy Schubert 		    !(capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
8254bc52338SCy Schubert 		    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
8264bc52338SCy Schubert 			wpa_printf(MSG_DEBUG,
8274bc52338SCy Schubert 				   "DPP: SAE not supported by the driver");
8284bc52338SCy Schubert 			return NULL;
8294bc52338SCy Schubert 		}
8304bc52338SCy Schubert #else /* CONFIG_SAE */
8314bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: SAE not supported in the build");
8324bc52338SCy Schubert 		return NULL;
8334bc52338SCy Schubert #endif /* CONFIG_SAE */
8344bc52338SCy Schubert 	}
8354bc52338SCy Schubert #endif /* CONFIG_DPP2 */
8364bc52338SCy Schubert 
83785732ac8SCy Schubert 	ssid = wpa_config_add_network(wpa_s->conf);
83885732ac8SCy Schubert 	if (!ssid)
83985732ac8SCy Schubert 		return NULL;
84085732ac8SCy Schubert 	wpas_notify_network_added(wpa_s, ssid);
84185732ac8SCy Schubert 	wpa_config_set_network_defaults(ssid);
84285732ac8SCy Schubert 	ssid->disabled = 1;
84385732ac8SCy Schubert 
84485732ac8SCy Schubert 	ssid->ssid = os_malloc(auth->ssid_len);
84585732ac8SCy Schubert 	if (!ssid->ssid)
84685732ac8SCy Schubert 		goto fail;
84785732ac8SCy Schubert 	os_memcpy(ssid->ssid, auth->ssid, auth->ssid_len);
84885732ac8SCy Schubert 	ssid->ssid_len = auth->ssid_len;
84985732ac8SCy Schubert 
85085732ac8SCy Schubert 	if (auth->connector) {
85185732ac8SCy Schubert 		ssid->key_mgmt = WPA_KEY_MGMT_DPP;
85285732ac8SCy Schubert 		ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
85385732ac8SCy Schubert 		ssid->dpp_connector = os_strdup(auth->connector);
85485732ac8SCy Schubert 		if (!ssid->dpp_connector)
85585732ac8SCy Schubert 			goto fail;
85685732ac8SCy Schubert 	}
85785732ac8SCy Schubert 
85885732ac8SCy Schubert 	if (auth->c_sign_key) {
85985732ac8SCy Schubert 		ssid->dpp_csign = os_malloc(wpabuf_len(auth->c_sign_key));
86085732ac8SCy Schubert 		if (!ssid->dpp_csign)
86185732ac8SCy Schubert 			goto fail;
86285732ac8SCy Schubert 		os_memcpy(ssid->dpp_csign, wpabuf_head(auth->c_sign_key),
86385732ac8SCy Schubert 			  wpabuf_len(auth->c_sign_key));
86485732ac8SCy Schubert 		ssid->dpp_csign_len = wpabuf_len(auth->c_sign_key);
86585732ac8SCy Schubert 	}
86685732ac8SCy Schubert 
86785732ac8SCy Schubert 	if (auth->net_access_key) {
86885732ac8SCy Schubert 		ssid->dpp_netaccesskey =
86985732ac8SCy Schubert 			os_malloc(wpabuf_len(auth->net_access_key));
87085732ac8SCy Schubert 		if (!ssid->dpp_netaccesskey)
87185732ac8SCy Schubert 			goto fail;
87285732ac8SCy Schubert 		os_memcpy(ssid->dpp_netaccesskey,
87385732ac8SCy Schubert 			  wpabuf_head(auth->net_access_key),
87485732ac8SCy Schubert 			  wpabuf_len(auth->net_access_key));
87585732ac8SCy Schubert 		ssid->dpp_netaccesskey_len = wpabuf_len(auth->net_access_key);
87685732ac8SCy Schubert 		ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
87785732ac8SCy Schubert 	}
87885732ac8SCy Schubert 
8794bc52338SCy Schubert 	if (!auth->connector || dpp_akm_psk(auth->akm) ||
8804bc52338SCy Schubert 	    dpp_akm_sae(auth->akm)) {
8814bc52338SCy Schubert 		if (!auth->connector)
88285732ac8SCy Schubert 			ssid->key_mgmt = 0;
8834bc52338SCy Schubert 		if (dpp_akm_psk(auth->akm))
88485732ac8SCy Schubert 			ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
88585732ac8SCy Schubert 				WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
8864bc52338SCy Schubert 		if (dpp_akm_sae(auth->akm))
88785732ac8SCy Schubert 			ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
88885732ac8SCy Schubert 				WPA_KEY_MGMT_FT_SAE;
88985732ac8SCy Schubert 		ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
89085732ac8SCy Schubert 		if (auth->passphrase[0]) {
89185732ac8SCy Schubert 			if (wpa_config_set_quoted(ssid, "psk",
89285732ac8SCy Schubert 						  auth->passphrase) < 0)
89385732ac8SCy Schubert 				goto fail;
89485732ac8SCy Schubert 			wpa_config_update_psk(ssid);
89585732ac8SCy Schubert 			ssid->export_keys = 1;
89685732ac8SCy Schubert 		} else {
89785732ac8SCy Schubert 			ssid->psk_set = auth->psk_set;
89885732ac8SCy Schubert 			os_memcpy(ssid->psk, auth->psk, PMK_LEN);
89985732ac8SCy Schubert 		}
90085732ac8SCy Schubert 	}
90185732ac8SCy Schubert 
90285732ac8SCy Schubert 	return ssid;
90385732ac8SCy Schubert fail:
90485732ac8SCy Schubert 	wpas_notify_network_removed(wpa_s, ssid);
90585732ac8SCy Schubert 	wpa_config_remove_network(wpa_s->conf, ssid->id);
90685732ac8SCy Schubert 	return NULL;
90785732ac8SCy Schubert }
90885732ac8SCy Schubert 
90985732ac8SCy Schubert 
9104bc52338SCy Schubert static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
91185732ac8SCy Schubert 				   struct dpp_authentication *auth)
91285732ac8SCy Schubert {
91385732ac8SCy Schubert 	struct wpa_ssid *ssid;
91485732ac8SCy Schubert 
91585732ac8SCy Schubert 	if (wpa_s->conf->dpp_config_processing < 1)
9164bc52338SCy Schubert 		return 0;
91785732ac8SCy Schubert 
91885732ac8SCy Schubert 	ssid = wpas_dpp_add_network(wpa_s, auth);
91985732ac8SCy Schubert 	if (!ssid)
9204bc52338SCy Schubert 		return -1;
92185732ac8SCy Schubert 
92285732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id);
9234bc52338SCy Schubert 	if (wpa_s->conf->dpp_config_processing == 2)
92485732ac8SCy Schubert 		ssid->disabled = 0;
9254bc52338SCy Schubert 
9264bc52338SCy Schubert #ifndef CONFIG_NO_CONFIG_WRITE
9274bc52338SCy Schubert 	if (wpa_s->conf->update_config &&
9284bc52338SCy Schubert 	    wpa_config_write(wpa_s->confname, wpa_s->conf))
9294bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration");
9304bc52338SCy Schubert #endif /* CONFIG_NO_CONFIG_WRITE */
9314bc52338SCy Schubert 
9324bc52338SCy Schubert 	if (wpa_s->conf->dpp_config_processing < 2)
9334bc52338SCy Schubert 		return 0;
9344bc52338SCy Schubert 
9354bc52338SCy Schubert #ifdef CONFIG_DPP2
9364bc52338SCy Schubert 	if (auth->peer_version >= 2) {
9374bc52338SCy Schubert 		wpa_printf(MSG_DEBUG,
9384bc52338SCy Schubert 			   "DPP: Postpone connection attempt to wait for completion of DPP Configuration Result");
9394bc52338SCy Schubert 		auth->connect_on_tx_status = 1;
9404bc52338SCy Schubert 		return 0;
9414bc52338SCy Schubert 	}
9424bc52338SCy Schubert #endif /* CONFIG_DPP2 */
9434bc52338SCy Schubert 
9444bc52338SCy Schubert 	wpas_dpp_try_to_connect(wpa_s);
9454bc52338SCy Schubert 	return 0;
94685732ac8SCy Schubert }
94785732ac8SCy Schubert 
94885732ac8SCy Schubert 
9494bc52338SCy Schubert static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
95085732ac8SCy Schubert 				      struct dpp_authentication *auth)
95185732ac8SCy Schubert {
95285732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
95385732ac8SCy Schubert 	if (auth->ssid_len)
95485732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
95585732ac8SCy Schubert 			wpa_ssid_txt(auth->ssid, auth->ssid_len));
95685732ac8SCy Schubert 	if (auth->connector) {
95785732ac8SCy Schubert 		/* TODO: Save the Connector and consider using a command
95885732ac8SCy Schubert 		 * to fetch the value instead of sending an event with
95985732ac8SCy Schubert 		 * it. The Connector could end up being larger than what
96085732ac8SCy Schubert 		 * most clients are ready to receive as an event
96185732ac8SCy Schubert 		 * message. */
96285732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
96385732ac8SCy Schubert 			auth->connector);
96485732ac8SCy Schubert 	}
96585732ac8SCy Schubert 	if (auth->c_sign_key) {
96685732ac8SCy Schubert 		char *hex;
96785732ac8SCy Schubert 		size_t hexlen;
96885732ac8SCy Schubert 
96985732ac8SCy Schubert 		hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
97085732ac8SCy Schubert 		hex = os_malloc(hexlen);
97185732ac8SCy Schubert 		if (hex) {
97285732ac8SCy Schubert 			wpa_snprintf_hex(hex, hexlen,
97385732ac8SCy Schubert 					 wpabuf_head(auth->c_sign_key),
97485732ac8SCy Schubert 					 wpabuf_len(auth->c_sign_key));
97585732ac8SCy Schubert 			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s",
97685732ac8SCy Schubert 				hex);
97785732ac8SCy Schubert 			os_free(hex);
97885732ac8SCy Schubert 		}
97985732ac8SCy Schubert 	}
98085732ac8SCy Schubert 	if (auth->net_access_key) {
98185732ac8SCy Schubert 		char *hex;
98285732ac8SCy Schubert 		size_t hexlen;
98385732ac8SCy Schubert 
98485732ac8SCy Schubert 		hexlen = 2 * wpabuf_len(auth->net_access_key) + 1;
98585732ac8SCy Schubert 		hex = os_malloc(hexlen);
98685732ac8SCy Schubert 		if (hex) {
98785732ac8SCy Schubert 			wpa_snprintf_hex(hex, hexlen,
98885732ac8SCy Schubert 					 wpabuf_head(auth->net_access_key),
98985732ac8SCy Schubert 					 wpabuf_len(auth->net_access_key));
99085732ac8SCy Schubert 			if (auth->net_access_key_expiry)
99185732ac8SCy Schubert 				wpa_msg(wpa_s, MSG_INFO,
99285732ac8SCy Schubert 					DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex,
99385732ac8SCy Schubert 					(long unsigned)
99485732ac8SCy Schubert 					auth->net_access_key_expiry);
99585732ac8SCy Schubert 			else
99685732ac8SCy Schubert 				wpa_msg(wpa_s, MSG_INFO,
99785732ac8SCy Schubert 					DPP_EVENT_NET_ACCESS_KEY "%s", hex);
99885732ac8SCy Schubert 			os_free(hex);
99985732ac8SCy Schubert 		}
100085732ac8SCy Schubert 	}
100185732ac8SCy Schubert 
10024bc52338SCy Schubert 	return wpas_dpp_process_config(wpa_s, auth);
100385732ac8SCy Schubert }
100485732ac8SCy Schubert 
100585732ac8SCy Schubert 
100685732ac8SCy Schubert static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
100785732ac8SCy Schubert 				 enum gas_query_result result,
100885732ac8SCy Schubert 				 const struct wpabuf *adv_proto,
100985732ac8SCy Schubert 				 const struct wpabuf *resp, u16 status_code)
101085732ac8SCy Schubert {
101185732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = ctx;
101285732ac8SCy Schubert 	const u8 *pos;
101385732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
10144bc52338SCy Schubert 	int res;
10154bc52338SCy Schubert 	enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
101685732ac8SCy Schubert 
101785732ac8SCy Schubert 	wpa_s->dpp_gas_dialog_token = -1;
101885732ac8SCy Schubert 
101985732ac8SCy Schubert 	if (!auth || !auth->auth_success) {
102085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
102185732ac8SCy Schubert 		return;
102285732ac8SCy Schubert 	}
102385732ac8SCy Schubert 	if (result != GAS_QUERY_SUCCESS ||
102485732ac8SCy Schubert 	    !resp || status_code != WLAN_STATUS_SUCCESS) {
102585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
102685732ac8SCy Schubert 		goto fail;
102785732ac8SCy Schubert 	}
102885732ac8SCy Schubert 
102985732ac8SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
103085732ac8SCy Schubert 			adv_proto);
103185732ac8SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
103285732ac8SCy Schubert 			resp);
103385732ac8SCy Schubert 
103485732ac8SCy Schubert 	if (wpabuf_len(adv_proto) != 10 ||
103585732ac8SCy Schubert 	    !(pos = wpabuf_head(adv_proto)) ||
103685732ac8SCy Schubert 	    pos[0] != WLAN_EID_ADV_PROTO ||
103785732ac8SCy Schubert 	    pos[1] != 8 ||
103885732ac8SCy Schubert 	    pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
103985732ac8SCy Schubert 	    pos[4] != 5 ||
104085732ac8SCy Schubert 	    WPA_GET_BE24(&pos[5]) != OUI_WFA ||
104185732ac8SCy Schubert 	    pos[8] != 0x1a ||
104285732ac8SCy Schubert 	    pos[9] != 1) {
104385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
104485732ac8SCy Schubert 			   "DPP: Not a DPP Advertisement Protocol ID");
104585732ac8SCy Schubert 		goto fail;
104685732ac8SCy Schubert 	}
104785732ac8SCy Schubert 
104885732ac8SCy Schubert 	if (dpp_conf_resp_rx(auth, resp) < 0) {
104985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
105085732ac8SCy Schubert 		goto fail;
105185732ac8SCy Schubert 	}
105285732ac8SCy Schubert 
10534bc52338SCy Schubert 	res = wpas_dpp_handle_config_obj(wpa_s, auth);
10544bc52338SCy Schubert 	if (res < 0)
10554bc52338SCy Schubert 		goto fail;
105685732ac8SCy Schubert 
10574bc52338SCy Schubert 	status = DPP_STATUS_OK;
10584bc52338SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
10594bc52338SCy Schubert 	if (dpp_test == DPP_TEST_REJECT_CONFIG) {
10604bc52338SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
10614bc52338SCy Schubert 		status = DPP_STATUS_CONFIG_REJECTED;
10624bc52338SCy Schubert 	}
10634bc52338SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
106485732ac8SCy Schubert fail:
10654bc52338SCy Schubert 	if (status != DPP_STATUS_OK)
106685732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
10674bc52338SCy Schubert #ifdef CONFIG_DPP2
10684bc52338SCy Schubert 	if (auth->peer_version >= 2 &&
10694bc52338SCy Schubert 	    auth->conf_resp_status == DPP_STATUS_OK) {
10704bc52338SCy Schubert 		struct wpabuf *msg;
10714bc52338SCy Schubert 
10724bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
10734bc52338SCy Schubert 		msg = dpp_build_conf_result(auth, status);
10744bc52338SCy Schubert 		if (!msg)
10754bc52338SCy Schubert 			goto fail2;
10764bc52338SCy Schubert 
10774bc52338SCy Schubert 		wpa_msg(wpa_s, MSG_INFO,
10784bc52338SCy Schubert 			DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
10794bc52338SCy Schubert 			MAC2STR(addr), auth->curr_freq,
10804bc52338SCy Schubert 			DPP_PA_CONFIGURATION_RESULT);
10814bc52338SCy Schubert 		offchannel_send_action(wpa_s, auth->curr_freq,
10824bc52338SCy Schubert 				       addr, wpa_s->own_addr, broadcast,
10834bc52338SCy Schubert 				       wpabuf_head(msg),
10844bc52338SCy Schubert 				       wpabuf_len(msg),
10854bc52338SCy Schubert 				       500, wpas_dpp_tx_status, 0);
10864bc52338SCy Schubert 		wpabuf_free(msg);
10874bc52338SCy Schubert 
10884bc52338SCy Schubert 		/* This exchange will be terminated in the TX status handler */
10894bc52338SCy Schubert 		return;
10904bc52338SCy Schubert 	}
10914bc52338SCy Schubert fail2:
10924bc52338SCy Schubert #endif /* CONFIG_DPP2 */
109385732ac8SCy Schubert 	dpp_auth_deinit(wpa_s->dpp_auth);
109485732ac8SCy Schubert 	wpa_s->dpp_auth = NULL;
109585732ac8SCy Schubert }
109685732ac8SCy Schubert 
109785732ac8SCy Schubert 
109885732ac8SCy Schubert static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s)
109985732ac8SCy Schubert {
110085732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
11014bc52338SCy Schubert 	struct wpabuf *buf;
110285732ac8SCy Schubert 	char json[100];
110385732ac8SCy Schubert 	int res;
110485732ac8SCy Schubert 
110585732ac8SCy Schubert 	wpa_s->dpp_gas_client = 1;
110685732ac8SCy Schubert 	os_snprintf(json, sizeof(json),
110785732ac8SCy Schubert 		    "{\"name\":\"Test\","
110885732ac8SCy Schubert 		    "\"wi-fi_tech\":\"infra\","
110985732ac8SCy Schubert 		    "\"netRole\":\"%s\"}",
111085732ac8SCy Schubert 		    wpa_s->dpp_netrole_ap ? "ap" : "sta");
111185732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
111285732ac8SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
111385732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
111485732ac8SCy Schubert 		json[29] = 'k'; /* replace "infra" with "knfra" */
111585732ac8SCy Schubert 	}
111685732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
111785732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
111885732ac8SCy Schubert 
111985732ac8SCy Schubert 	offchannel_send_action_done(wpa_s);
112085732ac8SCy Schubert 	wpas_dpp_listen_stop(wpa_s);
112185732ac8SCy Schubert 
11224bc52338SCy Schubert 	buf = dpp_build_conf_req(auth, json);
11234bc52338SCy Schubert 	if (!buf) {
112485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
112585732ac8SCy Schubert 			   "DPP: No configuration request data available");
112685732ac8SCy Schubert 		return;
112785732ac8SCy Schubert 	}
112885732ac8SCy Schubert 
112985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
113085732ac8SCy Schubert 		   MAC2STR(auth->peer_mac_addr), auth->curr_freq);
113185732ac8SCy Schubert 
113285732ac8SCy Schubert 	res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq,
113385732ac8SCy Schubert 			    1, buf, wpas_dpp_gas_resp_cb, wpa_s);
113485732ac8SCy Schubert 	if (res < 0) {
113585732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
113685732ac8SCy Schubert 		wpabuf_free(buf);
113785732ac8SCy Schubert 	} else {
113885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
113985732ac8SCy Schubert 			   "DPP: GAS query started with dialog token %u", res);
114085732ac8SCy Schubert 		wpa_s->dpp_gas_dialog_token = res;
114185732ac8SCy Schubert 	}
114285732ac8SCy Schubert }
114385732ac8SCy Schubert 
114485732ac8SCy Schubert 
114585732ac8SCy Schubert static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator)
114685732ac8SCy Schubert {
114785732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
114885732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
114985732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
115085732ac8SCy Schubert 	if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
115185732ac8SCy Schubert 		wpa_printf(MSG_INFO,
115285732ac8SCy Schubert 			   "DPP: TESTING - stop at Authentication Confirm");
115385732ac8SCy Schubert 		if (wpa_s->dpp_auth->configurator) {
115485732ac8SCy Schubert 			/* Prevent GAS response */
115585732ac8SCy Schubert 			wpa_s->dpp_auth->auth_success = 0;
115685732ac8SCy Schubert 		}
115785732ac8SCy Schubert 		return;
115885732ac8SCy Schubert 	}
115985732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
116085732ac8SCy Schubert 
116185732ac8SCy Schubert 	if (wpa_s->dpp_auth->configurator)
116285732ac8SCy Schubert 		wpas_dpp_start_gas_server(wpa_s);
116385732ac8SCy Schubert 	else
116485732ac8SCy Schubert 		wpas_dpp_start_gas_client(wpa_s);
116585732ac8SCy Schubert }
116685732ac8SCy Schubert 
116785732ac8SCy Schubert 
116885732ac8SCy Schubert static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
116985732ac8SCy Schubert 				  const u8 *hdr, const u8 *buf, size_t len,
117085732ac8SCy Schubert 				  unsigned int freq)
117185732ac8SCy Schubert {
117285732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
117385732ac8SCy Schubert 	struct wpabuf *msg;
117485732ac8SCy Schubert 
117585732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR
117685732ac8SCy Schubert 		   " (freq %u MHz)", MAC2STR(src), freq);
117785732ac8SCy Schubert 
117885732ac8SCy Schubert 	if (!auth) {
117985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
118085732ac8SCy Schubert 			   "DPP: No DPP Authentication in progress - drop");
118185732ac8SCy Schubert 		return;
118285732ac8SCy Schubert 	}
118385732ac8SCy Schubert 
118485732ac8SCy Schubert 	if (!is_zero_ether_addr(auth->peer_mac_addr) &&
118585732ac8SCy Schubert 	    os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
118685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
118785732ac8SCy Schubert 			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
118885732ac8SCy Schubert 		return;
118985732ac8SCy Schubert 	}
119085732ac8SCy Schubert 
119185732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
119285732ac8SCy Schubert 
119385732ac8SCy Schubert 	if (auth->curr_freq != freq && auth->neg_freq == freq) {
119485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
119585732ac8SCy Schubert 			   "DPP: Responder accepted request for different negotiation channel");
119685732ac8SCy Schubert 		auth->curr_freq = freq;
119785732ac8SCy Schubert 	}
119885732ac8SCy Schubert 
119985732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
120085732ac8SCy Schubert 	msg = dpp_auth_resp_rx(auth, hdr, buf, len);
120185732ac8SCy Schubert 	if (!msg) {
120285732ac8SCy Schubert 		if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
120385732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
120485732ac8SCy Schubert 				   "DPP: Start wait for full response");
120585732ac8SCy Schubert 			offchannel_send_action_done(wpa_s);
120685732ac8SCy Schubert 			wpas_dpp_listen_start(wpa_s, auth->curr_freq);
120785732ac8SCy Schubert 			return;
120885732ac8SCy Schubert 		}
120985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
121085732ac8SCy Schubert 		return;
121185732ac8SCy Schubert 	}
121285732ac8SCy Schubert 	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
121385732ac8SCy Schubert 
121485732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
121585732ac8SCy Schubert 		MAC2STR(src), auth->curr_freq, DPP_PA_AUTHENTICATION_CONF);
121685732ac8SCy Schubert 	offchannel_send_action(wpa_s, auth->curr_freq,
121785732ac8SCy Schubert 			       src, wpa_s->own_addr, broadcast,
121885732ac8SCy Schubert 			       wpabuf_head(msg), wpabuf_len(msg),
121985732ac8SCy Schubert 			       500, wpas_dpp_tx_status, 0);
122085732ac8SCy Schubert 	wpabuf_free(msg);
122185732ac8SCy Schubert 	wpa_s->dpp_auth_ok_on_ack = 1;
122285732ac8SCy Schubert }
122385732ac8SCy Schubert 
122485732ac8SCy Schubert 
122585732ac8SCy Schubert static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
122685732ac8SCy Schubert 				  const u8 *hdr, const u8 *buf, size_t len)
122785732ac8SCy Schubert {
122885732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
122985732ac8SCy Schubert 
123085732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
123185732ac8SCy Schubert 		   MAC2STR(src));
123285732ac8SCy Schubert 
123385732ac8SCy Schubert 	if (!auth) {
123485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
123585732ac8SCy Schubert 			   "DPP: No DPP Authentication in progress - drop");
123685732ac8SCy Schubert 		return;
123785732ac8SCy Schubert 	}
123885732ac8SCy Schubert 
123985732ac8SCy Schubert 	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
124085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
124185732ac8SCy Schubert 			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
124285732ac8SCy Schubert 		return;
124385732ac8SCy Schubert 	}
124485732ac8SCy Schubert 
124585732ac8SCy Schubert 	if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
124685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
124785732ac8SCy Schubert 		return;
124885732ac8SCy Schubert 	}
124985732ac8SCy Schubert 
125085732ac8SCy Schubert 	wpas_dpp_auth_success(wpa_s, 0);
125185732ac8SCy Schubert }
125285732ac8SCy Schubert 
125385732ac8SCy Schubert 
12544bc52338SCy Schubert #ifdef CONFIG_DPP2
12554bc52338SCy Schubert 
12564bc52338SCy Schubert static void wpas_dpp_config_result_wait_timeout(void *eloop_ctx,
12574bc52338SCy Schubert 						void *timeout_ctx)
12584bc52338SCy Schubert {
12594bc52338SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
12604bc52338SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
12614bc52338SCy Schubert 
12624bc52338SCy Schubert 	if (!auth || !auth->waiting_conf_result)
12634bc52338SCy Schubert 		return;
12644bc52338SCy Schubert 
12654bc52338SCy Schubert 	wpa_printf(MSG_DEBUG,
12664bc52338SCy Schubert 		   "DPP: Timeout while waiting for Configuration Result");
12674bc52338SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
12684bc52338SCy Schubert 	dpp_auth_deinit(auth);
12694bc52338SCy Schubert 	wpa_s->dpp_auth = NULL;
12704bc52338SCy Schubert }
12714bc52338SCy Schubert 
12724bc52338SCy Schubert 
12734bc52338SCy Schubert static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
12744bc52338SCy Schubert 				    const u8 *hdr, const u8 *buf, size_t len)
12754bc52338SCy Schubert {
12764bc52338SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
12774bc52338SCy Schubert 	enum dpp_status_error status;
12784bc52338SCy Schubert 
12794bc52338SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
12804bc52338SCy Schubert 		   MAC2STR(src));
12814bc52338SCy Schubert 
12824bc52338SCy Schubert 	if (!auth || !auth->waiting_conf_result) {
12834bc52338SCy Schubert 		wpa_printf(MSG_DEBUG,
12844bc52338SCy Schubert 			   "DPP: No DPP Configuration waiting for result - drop");
12854bc52338SCy Schubert 		return;
12864bc52338SCy Schubert 	}
12874bc52338SCy Schubert 
12884bc52338SCy Schubert 	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
12894bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
12904bc52338SCy Schubert 			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
12914bc52338SCy Schubert 		return;
12924bc52338SCy Schubert 	}
12934bc52338SCy Schubert 
12944bc52338SCy Schubert 	status = dpp_conf_result_rx(auth, hdr, buf, len);
12954bc52338SCy Schubert 
12964bc52338SCy Schubert 	offchannel_send_action_done(wpa_s);
12974bc52338SCy Schubert 	wpas_dpp_listen_stop(wpa_s);
12984bc52338SCy Schubert 	if (status == DPP_STATUS_OK)
12994bc52338SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
13004bc52338SCy Schubert 	else
13014bc52338SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
13024bc52338SCy Schubert 	dpp_auth_deinit(auth);
13034bc52338SCy Schubert 	wpa_s->dpp_auth = NULL;
13044bc52338SCy Schubert 	eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
13054bc52338SCy Schubert }
13064bc52338SCy Schubert 
1307*206b73d0SCy Schubert 
1308*206b73d0SCy Schubert static int wpas_dpp_process_conf_obj(void *ctx,
1309*206b73d0SCy Schubert 				     struct dpp_authentication *auth)
1310*206b73d0SCy Schubert {
1311*206b73d0SCy Schubert 	struct wpa_supplicant *wpa_s = ctx;
1312*206b73d0SCy Schubert 
1313*206b73d0SCy Schubert 	return wpas_dpp_handle_config_obj(wpa_s, auth);
1314*206b73d0SCy Schubert }
1315*206b73d0SCy Schubert 
13164bc52338SCy Schubert #endif /* CONFIG_DPP2 */
13174bc52338SCy Schubert 
13184bc52338SCy Schubert 
131985732ac8SCy Schubert static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
132085732ac8SCy Schubert 				       const u8 *src,
132185732ac8SCy Schubert 				       const u8 *buf, size_t len)
132285732ac8SCy Schubert {
132385732ac8SCy Schubert 	struct wpa_ssid *ssid;
132485732ac8SCy Schubert 	const u8 *connector, *trans_id, *status;
132585732ac8SCy Schubert 	u16 connector_len, trans_id_len, status_len;
132685732ac8SCy Schubert 	struct dpp_introduction intro;
132785732ac8SCy Schubert 	struct rsn_pmksa_cache_entry *entry;
132885732ac8SCy Schubert 	struct os_time now;
132985732ac8SCy Schubert 	struct os_reltime rnow;
133085732ac8SCy Schubert 	os_time_t expiry;
133185732ac8SCy Schubert 	unsigned int seconds;
133285732ac8SCy Schubert 	enum dpp_status_error res;
133385732ac8SCy Schubert 
133485732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Response from " MACSTR,
133585732ac8SCy Schubert 		   MAC2STR(src));
133685732ac8SCy Schubert 	if (is_zero_ether_addr(wpa_s->dpp_intro_bssid) ||
133785732ac8SCy Schubert 	    os_memcmp(src, wpa_s->dpp_intro_bssid, ETH_ALEN) != 0) {
133885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Not waiting for response from "
133985732ac8SCy Schubert 			   MACSTR " - drop", MAC2STR(src));
134085732ac8SCy Schubert 		return;
134185732ac8SCy Schubert 	}
134285732ac8SCy Schubert 	offchannel_send_action_done(wpa_s);
134385732ac8SCy Schubert 
134485732ac8SCy Schubert 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
134585732ac8SCy Schubert 		if (ssid == wpa_s->dpp_intro_network)
134685732ac8SCy Schubert 			break;
134785732ac8SCy Schubert 	}
134885732ac8SCy Schubert 	if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
134985732ac8SCy Schubert 	    !ssid->dpp_csign) {
135085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
135185732ac8SCy Schubert 			   "DPP: Profile not found for network introduction");
135285732ac8SCy Schubert 		return;
135385732ac8SCy Schubert 	}
135485732ac8SCy Schubert 
135585732ac8SCy Schubert 	trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
135685732ac8SCy Schubert 			       &trans_id_len);
135785732ac8SCy Schubert 	if (!trans_id || trans_id_len != 1) {
135885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
135985732ac8SCy Schubert 			   "DPP: Peer did not include Transaction ID");
136085732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
136185732ac8SCy Schubert 			" fail=missing_transaction_id", MAC2STR(src));
136285732ac8SCy Schubert 		goto fail;
136385732ac8SCy Schubert 	}
136485732ac8SCy Schubert 	if (trans_id[0] != TRANSACTION_ID) {
136585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
136685732ac8SCy Schubert 			   "DPP: Ignore frame with unexpected Transaction ID %u",
136785732ac8SCy Schubert 			   trans_id[0]);
136885732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
136985732ac8SCy Schubert 			" fail=transaction_id_mismatch", MAC2STR(src));
137085732ac8SCy Schubert 		goto fail;
137185732ac8SCy Schubert 	}
137285732ac8SCy Schubert 
137385732ac8SCy Schubert 	status = dpp_get_attr(buf, len, DPP_ATTR_STATUS, &status_len);
137485732ac8SCy Schubert 	if (!status || status_len != 1) {
137585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Peer did not include Status");
137685732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
137785732ac8SCy Schubert 			" fail=missing_status", MAC2STR(src));
137885732ac8SCy Schubert 		goto fail;
137985732ac8SCy Schubert 	}
138085732ac8SCy Schubert 	if (status[0] != DPP_STATUS_OK) {
138185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
138285732ac8SCy Schubert 			   "DPP: Peer rejected network introduction: Status %u",
138385732ac8SCy Schubert 			   status[0]);
138485732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
138585732ac8SCy Schubert 			" status=%u", MAC2STR(src), status[0]);
138685732ac8SCy Schubert 		goto fail;
138785732ac8SCy Schubert 	}
138885732ac8SCy Schubert 
138985732ac8SCy Schubert 	connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len);
139085732ac8SCy Schubert 	if (!connector) {
139185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
139285732ac8SCy Schubert 			   "DPP: Peer did not include its Connector");
139385732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
139485732ac8SCy Schubert 			" fail=missing_connector", MAC2STR(src));
139585732ac8SCy Schubert 		goto fail;
139685732ac8SCy Schubert 	}
139785732ac8SCy Schubert 
139885732ac8SCy Schubert 	res = dpp_peer_intro(&intro, ssid->dpp_connector,
139985732ac8SCy Schubert 			     ssid->dpp_netaccesskey,
140085732ac8SCy Schubert 			     ssid->dpp_netaccesskey_len,
140185732ac8SCy Schubert 			     ssid->dpp_csign,
140285732ac8SCy Schubert 			     ssid->dpp_csign_len,
140385732ac8SCy Schubert 			     connector, connector_len, &expiry);
140485732ac8SCy Schubert 	if (res != DPP_STATUS_OK) {
140585732ac8SCy Schubert 		wpa_printf(MSG_INFO,
140685732ac8SCy Schubert 			   "DPP: Network Introduction protocol resulted in failure");
140785732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
140885732ac8SCy Schubert 			" fail=peer_connector_validation_failed", MAC2STR(src));
140985732ac8SCy Schubert 		goto fail;
141085732ac8SCy Schubert 	}
141185732ac8SCy Schubert 
141285732ac8SCy Schubert 	entry = os_zalloc(sizeof(*entry));
141385732ac8SCy Schubert 	if (!entry)
141485732ac8SCy Schubert 		goto fail;
141585732ac8SCy Schubert 	os_memcpy(entry->aa, src, ETH_ALEN);
141685732ac8SCy Schubert 	os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN);
141785732ac8SCy Schubert 	os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
141885732ac8SCy Schubert 	entry->pmk_len = intro.pmk_len;
141985732ac8SCy Schubert 	entry->akmp = WPA_KEY_MGMT_DPP;
142085732ac8SCy Schubert 	if (expiry) {
142185732ac8SCy Schubert 		os_get_time(&now);
142285732ac8SCy Schubert 		seconds = expiry - now.sec;
142385732ac8SCy Schubert 	} else {
142485732ac8SCy Schubert 		seconds = 86400 * 7;
142585732ac8SCy Schubert 	}
142685732ac8SCy Schubert 	os_get_reltime(&rnow);
142785732ac8SCy Schubert 	entry->expiration = rnow.sec + seconds;
142885732ac8SCy Schubert 	entry->reauth_time = rnow.sec + seconds;
142985732ac8SCy Schubert 	entry->network_ctx = ssid;
143085732ac8SCy Schubert 	wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
143185732ac8SCy Schubert 
143285732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
143385732ac8SCy Schubert 		" status=%u", MAC2STR(src), status[0]);
143485732ac8SCy Schubert 
143585732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
143685732ac8SCy Schubert 		   "DPP: Try connection again after successful network introduction");
143785732ac8SCy Schubert 	if (wpa_supplicant_fast_associate(wpa_s) != 1) {
143885732ac8SCy Schubert 		wpa_supplicant_cancel_sched_scan(wpa_s);
143985732ac8SCy Schubert 		wpa_supplicant_req_scan(wpa_s, 0, 0);
144085732ac8SCy Schubert 	}
144185732ac8SCy Schubert fail:
144285732ac8SCy Schubert 	os_memset(&intro, 0, sizeof(intro));
144385732ac8SCy Schubert }
144485732ac8SCy Schubert 
144585732ac8SCy Schubert 
144685732ac8SCy Schubert static int wpas_dpp_allow_ir(struct wpa_supplicant *wpa_s, unsigned int freq)
144785732ac8SCy Schubert {
144885732ac8SCy Schubert 	int i, j;
144985732ac8SCy Schubert 
145085732ac8SCy Schubert 	if (!wpa_s->hw.modes)
145185732ac8SCy Schubert 		return -1;
145285732ac8SCy Schubert 
145385732ac8SCy Schubert 	for (i = 0; i < wpa_s->hw.num_modes; i++) {
145485732ac8SCy Schubert 		struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
145585732ac8SCy Schubert 
145685732ac8SCy Schubert 		for (j = 0; j < mode->num_channels; j++) {
145785732ac8SCy Schubert 			struct hostapd_channel_data *chan = &mode->channels[j];
145885732ac8SCy Schubert 
145985732ac8SCy Schubert 			if (chan->freq != (int) freq)
146085732ac8SCy Schubert 				continue;
146185732ac8SCy Schubert 
146285732ac8SCy Schubert 			if (chan->flag & (HOSTAPD_CHAN_DISABLED |
146385732ac8SCy Schubert 					  HOSTAPD_CHAN_NO_IR |
146485732ac8SCy Schubert 					  HOSTAPD_CHAN_RADAR))
146585732ac8SCy Schubert 				continue;
146685732ac8SCy Schubert 
146785732ac8SCy Schubert 			return 1;
146885732ac8SCy Schubert 		}
146985732ac8SCy Schubert 	}
147085732ac8SCy Schubert 
147185732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
147285732ac8SCy Schubert 		   "DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list",
147385732ac8SCy Schubert 		   freq);
147485732ac8SCy Schubert 
147585732ac8SCy Schubert 	return 0;
147685732ac8SCy Schubert }
147785732ac8SCy Schubert 
147885732ac8SCy Schubert 
147985732ac8SCy Schubert static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s,
148085732ac8SCy Schubert 				      struct dpp_pkex *pkex)
148185732ac8SCy Schubert {
148285732ac8SCy Schubert 	if (pkex->freq == 2437)
148385732ac8SCy Schubert 		pkex->freq = 5745;
148485732ac8SCy Schubert 	else if (pkex->freq == 5745)
148585732ac8SCy Schubert 		pkex->freq = 5220;
148685732ac8SCy Schubert 	else if (pkex->freq == 5220)
148785732ac8SCy Schubert 		pkex->freq = 60480;
148885732ac8SCy Schubert 	else
148985732ac8SCy Schubert 		return -1; /* no more channels to try */
149085732ac8SCy Schubert 
149185732ac8SCy Schubert 	if (wpas_dpp_allow_ir(wpa_s, pkex->freq) == 1) {
149285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz",
149385732ac8SCy Schubert 			   pkex->freq);
149485732ac8SCy Schubert 		return 0;
149585732ac8SCy Schubert 	}
149685732ac8SCy Schubert 
149785732ac8SCy Schubert 	/* Could not use this channel - try the next one */
149885732ac8SCy Schubert 	return wpas_dpp_pkex_next_channel(wpa_s, pkex);
149985732ac8SCy Schubert }
150085732ac8SCy Schubert 
150185732ac8SCy Schubert 
150285732ac8SCy Schubert static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
150385732ac8SCy Schubert {
150485732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
150585732ac8SCy Schubert 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
150685732ac8SCy Schubert 
150785732ac8SCy Schubert 	if (!pkex || !pkex->exchange_req)
150885732ac8SCy Schubert 		return;
150985732ac8SCy Schubert 	if (pkex->exch_req_tries >= 5) {
151085732ac8SCy Schubert 		if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) {
151185732ac8SCy Schubert 			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
151285732ac8SCy Schubert 				"No response from PKEX peer");
151385732ac8SCy Schubert 			dpp_pkex_free(pkex);
151485732ac8SCy Schubert 			wpa_s->dpp_pkex = NULL;
151585732ac8SCy Schubert 			return;
151685732ac8SCy Schubert 		}
151785732ac8SCy Schubert 		pkex->exch_req_tries = 0;
151885732ac8SCy Schubert 	}
151985732ac8SCy Schubert 
152085732ac8SCy Schubert 	pkex->exch_req_tries++;
152185732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)",
152285732ac8SCy Schubert 		   pkex->exch_req_tries);
152385732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
152485732ac8SCy Schubert 		MAC2STR(broadcast), pkex->freq, DPP_PA_PKEX_EXCHANGE_REQ);
152585732ac8SCy Schubert 	offchannel_send_action(wpa_s, pkex->freq, broadcast,
152685732ac8SCy Schubert 			       wpa_s->own_addr, broadcast,
152785732ac8SCy Schubert 			       wpabuf_head(pkex->exchange_req),
152885732ac8SCy Schubert 			       wpabuf_len(pkex->exchange_req),
152985732ac8SCy Schubert 			       pkex->exch_req_wait_time,
153085732ac8SCy Schubert 			       wpas_dpp_tx_pkex_status, 0);
153185732ac8SCy Schubert }
153285732ac8SCy Schubert 
153385732ac8SCy Schubert 
153485732ac8SCy Schubert static void
153585732ac8SCy Schubert wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
153685732ac8SCy Schubert 			unsigned int freq, const u8 *dst,
153785732ac8SCy Schubert 			const u8 *src, const u8 *bssid,
153885732ac8SCy Schubert 			const u8 *data, size_t data_len,
153985732ac8SCy Schubert 			enum offchannel_send_action_result result)
154085732ac8SCy Schubert {
154185732ac8SCy Schubert 	const char *res_txt;
154285732ac8SCy Schubert 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
154385732ac8SCy Schubert 
154485732ac8SCy Schubert 	res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
154585732ac8SCy Schubert 		(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
154685732ac8SCy Schubert 		 "FAILED");
154785732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
154885732ac8SCy Schubert 		   " result=%s (PKEX)",
154985732ac8SCy Schubert 		   freq, MAC2STR(dst), res_txt);
155085732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
155185732ac8SCy Schubert 		" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
155285732ac8SCy Schubert 
155385732ac8SCy Schubert 	if (!pkex) {
155485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
155585732ac8SCy Schubert 			   "DPP: Ignore TX status since there is no ongoing PKEX exchange");
155685732ac8SCy Schubert 		return;
155785732ac8SCy Schubert 	}
155885732ac8SCy Schubert 
155985732ac8SCy Schubert 	if (pkex->failed) {
156085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
156185732ac8SCy Schubert 			   "DPP: Terminate PKEX exchange due to an earlier error");
156285732ac8SCy Schubert 		if (pkex->t > pkex->own_bi->pkex_t)
156385732ac8SCy Schubert 			pkex->own_bi->pkex_t = pkex->t;
156485732ac8SCy Schubert 		dpp_pkex_free(pkex);
156585732ac8SCy Schubert 		wpa_s->dpp_pkex = NULL;
156685732ac8SCy Schubert 		return;
156785732ac8SCy Schubert 	}
156885732ac8SCy Schubert 
156985732ac8SCy Schubert 	if (pkex->exch_req_wait_time && pkex->exchange_req) {
157085732ac8SCy Schubert 		/* Wait for PKEX Exchange Response frame and retry request if
157185732ac8SCy Schubert 		 * no response is seen. */
157285732ac8SCy Schubert 		eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
157385732ac8SCy Schubert 		eloop_register_timeout(pkex->exch_req_wait_time / 1000,
157485732ac8SCy Schubert 				       (pkex->exch_req_wait_time % 1000) * 1000,
157585732ac8SCy Schubert 				       wpas_dpp_pkex_retry_timeout, wpa_s,
157685732ac8SCy Schubert 				       NULL);
157785732ac8SCy Schubert 	}
157885732ac8SCy Schubert }
157985732ac8SCy Schubert 
158085732ac8SCy Schubert 
158185732ac8SCy Schubert static void
158285732ac8SCy Schubert wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src,
158385732ac8SCy Schubert 			      const u8 *buf, size_t len, unsigned int freq)
158485732ac8SCy Schubert {
158585732ac8SCy Schubert 	struct wpabuf *msg;
158685732ac8SCy Schubert 	unsigned int wait_time;
158785732ac8SCy Schubert 
158885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR,
158985732ac8SCy Schubert 		   MAC2STR(src));
159085732ac8SCy Schubert 
159185732ac8SCy Schubert 	/* TODO: Support multiple PKEX codes by iterating over all the enabled
159285732ac8SCy Schubert 	 * values here */
159385732ac8SCy Schubert 
159485732ac8SCy Schubert 	if (!wpa_s->dpp_pkex_code || !wpa_s->dpp_pkex_bi) {
159585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
159685732ac8SCy Schubert 			   "DPP: No PKEX code configured - ignore request");
159785732ac8SCy Schubert 		return;
159885732ac8SCy Schubert 	}
159985732ac8SCy Schubert 
160085732ac8SCy Schubert 	if (wpa_s->dpp_pkex) {
160185732ac8SCy Schubert 		/* TODO: Support parallel operations */
160285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
160385732ac8SCy Schubert 			   "DPP: Already in PKEX session - ignore new request");
160485732ac8SCy Schubert 		return;
160585732ac8SCy Schubert 	}
160685732ac8SCy Schubert 
160785732ac8SCy Schubert 	wpa_s->dpp_pkex = dpp_pkex_rx_exchange_req(wpa_s, wpa_s->dpp_pkex_bi,
160885732ac8SCy Schubert 						   wpa_s->own_addr, src,
160985732ac8SCy Schubert 						   wpa_s->dpp_pkex_identifier,
161085732ac8SCy Schubert 						   wpa_s->dpp_pkex_code,
161185732ac8SCy Schubert 						   buf, len);
161285732ac8SCy Schubert 	if (!wpa_s->dpp_pkex) {
161385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
161485732ac8SCy Schubert 			   "DPP: Failed to process the request - ignore it");
161585732ac8SCy Schubert 		return;
161685732ac8SCy Schubert 	}
161785732ac8SCy Schubert 
161885732ac8SCy Schubert 	msg = wpa_s->dpp_pkex->exchange_resp;
161985732ac8SCy Schubert 	wait_time = wpa_s->max_remain_on_chan;
162085732ac8SCy Schubert 	if (wait_time > 2000)
162185732ac8SCy Schubert 		wait_time = 2000;
162285732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
162385732ac8SCy Schubert 		MAC2STR(src), freq, DPP_PA_PKEX_EXCHANGE_RESP);
162485732ac8SCy Schubert 	offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
162585732ac8SCy Schubert 			       broadcast,
162685732ac8SCy Schubert 			       wpabuf_head(msg), wpabuf_len(msg),
162785732ac8SCy Schubert 			       wait_time, wpas_dpp_tx_pkex_status, 0);
162885732ac8SCy Schubert }
162985732ac8SCy Schubert 
163085732ac8SCy Schubert 
163185732ac8SCy Schubert static void
163285732ac8SCy Schubert wpas_dpp_rx_pkex_exchange_resp(struct wpa_supplicant *wpa_s, const u8 *src,
163385732ac8SCy Schubert 			       const u8 *buf, size_t len, unsigned int freq)
163485732ac8SCy Schubert {
163585732ac8SCy Schubert 	struct wpabuf *msg;
163685732ac8SCy Schubert 	unsigned int wait_time;
163785732ac8SCy Schubert 
163885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR,
163985732ac8SCy Schubert 		   MAC2STR(src));
164085732ac8SCy Schubert 
164185732ac8SCy Schubert 	/* TODO: Support multiple PKEX codes by iterating over all the enabled
164285732ac8SCy Schubert 	 * values here */
164385732ac8SCy Schubert 
164485732ac8SCy Schubert 	if (!wpa_s->dpp_pkex || !wpa_s->dpp_pkex->initiator ||
164585732ac8SCy Schubert 	    wpa_s->dpp_pkex->exchange_done) {
164685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
164785732ac8SCy Schubert 		return;
164885732ac8SCy Schubert 	}
164985732ac8SCy Schubert 
165085732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
165185732ac8SCy Schubert 	wpa_s->dpp_pkex->exch_req_wait_time = 0;
165285732ac8SCy Schubert 
165385732ac8SCy Schubert 	msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, src, buf, len);
165485732ac8SCy Schubert 	if (!msg) {
165585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
165685732ac8SCy Schubert 		return;
165785732ac8SCy Schubert 	}
165885732ac8SCy Schubert 
165985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR,
166085732ac8SCy Schubert 		   MAC2STR(src));
166185732ac8SCy Schubert 
166285732ac8SCy Schubert 	wait_time = wpa_s->max_remain_on_chan;
166385732ac8SCy Schubert 	if (wait_time > 2000)
166485732ac8SCy Schubert 		wait_time = 2000;
166585732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
166685732ac8SCy Schubert 		MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_REQ);
166785732ac8SCy Schubert 	offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
166885732ac8SCy Schubert 			       broadcast,
166985732ac8SCy Schubert 			       wpabuf_head(msg), wpabuf_len(msg),
167085732ac8SCy Schubert 			       wait_time, wpas_dpp_tx_pkex_status, 0);
167185732ac8SCy Schubert 	wpabuf_free(msg);
167285732ac8SCy Schubert }
167385732ac8SCy Schubert 
167485732ac8SCy Schubert 
167585732ac8SCy Schubert static struct dpp_bootstrap_info *
167685732ac8SCy Schubert wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer,
167785732ac8SCy Schubert 		     unsigned int freq)
167885732ac8SCy Schubert {
167985732ac8SCy Schubert 	struct dpp_bootstrap_info *bi;
168085732ac8SCy Schubert 
16814bc52338SCy Schubert 	bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq);
168285732ac8SCy Schubert 	if (!bi)
168385732ac8SCy Schubert 		return NULL;
168485732ac8SCy Schubert 	wpa_s->dpp_pkex = NULL;
168585732ac8SCy Schubert 	return bi;
168685732ac8SCy Schubert }
168785732ac8SCy Schubert 
168885732ac8SCy Schubert 
168985732ac8SCy Schubert static void
169085732ac8SCy Schubert wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src,
169185732ac8SCy Schubert 				   const u8 *hdr, const u8 *buf, size_t len,
169285732ac8SCy Schubert 				   unsigned int freq)
169385732ac8SCy Schubert {
169485732ac8SCy Schubert 	struct wpabuf *msg;
169585732ac8SCy Schubert 	unsigned int wait_time;
169685732ac8SCy Schubert 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
169785732ac8SCy Schubert 
169885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR,
169985732ac8SCy Schubert 		   MAC2STR(src));
170085732ac8SCy Schubert 
170185732ac8SCy Schubert 	if (!pkex || pkex->initiator || !pkex->exchange_done) {
170285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
170385732ac8SCy Schubert 		return;
170485732ac8SCy Schubert 	}
170585732ac8SCy Schubert 
170685732ac8SCy Schubert 	msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
170785732ac8SCy Schubert 	if (!msg) {
170885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
170985732ac8SCy Schubert 		if (pkex->failed) {
171085732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
171185732ac8SCy Schubert 			if (pkex->t > pkex->own_bi->pkex_t)
171285732ac8SCy Schubert 				pkex->own_bi->pkex_t = pkex->t;
171385732ac8SCy Schubert 			dpp_pkex_free(wpa_s->dpp_pkex);
171485732ac8SCy Schubert 			wpa_s->dpp_pkex = NULL;
171585732ac8SCy Schubert 		}
171685732ac8SCy Schubert 		return;
171785732ac8SCy Schubert 	}
171885732ac8SCy Schubert 
171985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to "
172085732ac8SCy Schubert 		   MACSTR, MAC2STR(src));
172185732ac8SCy Schubert 
172285732ac8SCy Schubert 	wait_time = wpa_s->max_remain_on_chan;
172385732ac8SCy Schubert 	if (wait_time > 2000)
172485732ac8SCy Schubert 		wait_time = 2000;
172585732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
172685732ac8SCy Schubert 		MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_RESP);
172785732ac8SCy Schubert 	offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
172885732ac8SCy Schubert 			       broadcast,
172985732ac8SCy Schubert 			       wpabuf_head(msg), wpabuf_len(msg),
173085732ac8SCy Schubert 			       wait_time, wpas_dpp_tx_pkex_status, 0);
173185732ac8SCy Schubert 	wpabuf_free(msg);
173285732ac8SCy Schubert 
173385732ac8SCy Schubert 	wpas_dpp_pkex_finish(wpa_s, src, freq);
173485732ac8SCy Schubert }
173585732ac8SCy Schubert 
173685732ac8SCy Schubert 
173785732ac8SCy Schubert static void
173885732ac8SCy Schubert wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant *wpa_s, const u8 *src,
173985732ac8SCy Schubert 				    const u8 *hdr, const u8 *buf, size_t len,
174085732ac8SCy Schubert 				    unsigned int freq)
174185732ac8SCy Schubert {
174285732ac8SCy Schubert 	int res;
174385732ac8SCy Schubert 	struct dpp_bootstrap_info *bi;
174485732ac8SCy Schubert 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
174585732ac8SCy Schubert 	char cmd[500];
174685732ac8SCy Schubert 
174785732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR,
174885732ac8SCy Schubert 		   MAC2STR(src));
174985732ac8SCy Schubert 
175085732ac8SCy Schubert 	if (!pkex || !pkex->initiator || !pkex->exchange_done) {
175185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
175285732ac8SCy Schubert 		return;
175385732ac8SCy Schubert 	}
175485732ac8SCy Schubert 
175585732ac8SCy Schubert 	res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len);
175685732ac8SCy Schubert 	if (res < 0) {
175785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
175885732ac8SCy Schubert 		return;
175985732ac8SCy Schubert 	}
176085732ac8SCy Schubert 
176185732ac8SCy Schubert 	bi = wpas_dpp_pkex_finish(wpa_s, src, freq);
176285732ac8SCy Schubert 	if (!bi)
176385732ac8SCy Schubert 		return;
176485732ac8SCy Schubert 
176585732ac8SCy Schubert 	os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
176685732ac8SCy Schubert 		    bi->id,
176785732ac8SCy Schubert 		    wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : "");
176885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
176985732ac8SCy Schubert 		   "DPP: Start authentication after PKEX with parameters: %s",
177085732ac8SCy Schubert 		   cmd);
177185732ac8SCy Schubert 	if (wpas_dpp_auth_init(wpa_s, cmd) < 0) {
177285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
177385732ac8SCy Schubert 			   "DPP: Authentication initialization failed");
177485732ac8SCy Schubert 		return;
177585732ac8SCy Schubert 	}
177685732ac8SCy Schubert }
177785732ac8SCy Schubert 
177885732ac8SCy Schubert 
177985732ac8SCy Schubert void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
178085732ac8SCy Schubert 			const u8 *buf, size_t len, unsigned int freq)
178185732ac8SCy Schubert {
178285732ac8SCy Schubert 	u8 crypto_suite;
178385732ac8SCy Schubert 	enum dpp_public_action_frame_type type;
178485732ac8SCy Schubert 	const u8 *hdr;
178585732ac8SCy Schubert 	unsigned int pkex_t;
178685732ac8SCy Schubert 
178785732ac8SCy Schubert 	if (len < DPP_HDR_LEN)
178885732ac8SCy Schubert 		return;
178985732ac8SCy Schubert 	if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE)
179085732ac8SCy Schubert 		return;
179185732ac8SCy Schubert 	hdr = buf;
179285732ac8SCy Schubert 	buf += 4;
179385732ac8SCy Schubert 	len -= 4;
179485732ac8SCy Schubert 	crypto_suite = *buf++;
179585732ac8SCy Schubert 	type = *buf++;
179685732ac8SCy Schubert 	len -= 2;
179785732ac8SCy Schubert 
179885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
179985732ac8SCy Schubert 		   "DPP: Received DPP Public Action frame crypto suite %u type %d from "
180085732ac8SCy Schubert 		   MACSTR " freq=%u",
180185732ac8SCy Schubert 		   crypto_suite, type, MAC2STR(src), freq);
180285732ac8SCy Schubert 	if (crypto_suite != 1) {
180385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
180485732ac8SCy Schubert 			   crypto_suite);
180585732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
180685732ac8SCy Schubert 			" freq=%u type=%d ignore=unsupported-crypto-suite",
180785732ac8SCy Schubert 			MAC2STR(src), freq, type);
180885732ac8SCy Schubert 		return;
180985732ac8SCy Schubert 	}
181085732ac8SCy Schubert 	wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
181185732ac8SCy Schubert 	if (dpp_check_attrs(buf, len) < 0) {
181285732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
181385732ac8SCy Schubert 			" freq=%u type=%d ignore=invalid-attributes",
181485732ac8SCy Schubert 			MAC2STR(src), freq, type);
181585732ac8SCy Schubert 		return;
181685732ac8SCy Schubert 	}
181785732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR " freq=%u type=%d",
181885732ac8SCy Schubert 		MAC2STR(src), freq, type);
181985732ac8SCy Schubert 
182085732ac8SCy Schubert 	switch (type) {
182185732ac8SCy Schubert 	case DPP_PA_AUTHENTICATION_REQ:
182285732ac8SCy Schubert 		wpas_dpp_rx_auth_req(wpa_s, src, hdr, buf, len, freq);
182385732ac8SCy Schubert 		break;
182485732ac8SCy Schubert 	case DPP_PA_AUTHENTICATION_RESP:
182585732ac8SCy Schubert 		wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len, freq);
182685732ac8SCy Schubert 		break;
182785732ac8SCy Schubert 	case DPP_PA_AUTHENTICATION_CONF:
182885732ac8SCy Schubert 		wpas_dpp_rx_auth_conf(wpa_s, src, hdr, buf, len);
182985732ac8SCy Schubert 		break;
183085732ac8SCy Schubert 	case DPP_PA_PEER_DISCOVERY_RESP:
183185732ac8SCy Schubert 		wpas_dpp_rx_peer_disc_resp(wpa_s, src, buf, len);
183285732ac8SCy Schubert 		break;
183385732ac8SCy Schubert 	case DPP_PA_PKEX_EXCHANGE_REQ:
183485732ac8SCy Schubert 		wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq);
183585732ac8SCy Schubert 		break;
183685732ac8SCy Schubert 	case DPP_PA_PKEX_EXCHANGE_RESP:
183785732ac8SCy Schubert 		wpas_dpp_rx_pkex_exchange_resp(wpa_s, src, buf, len, freq);
183885732ac8SCy Schubert 		break;
183985732ac8SCy Schubert 	case DPP_PA_PKEX_COMMIT_REVEAL_REQ:
184085732ac8SCy Schubert 		wpas_dpp_rx_pkex_commit_reveal_req(wpa_s, src, hdr, buf, len,
184185732ac8SCy Schubert 						   freq);
184285732ac8SCy Schubert 		break;
184385732ac8SCy Schubert 	case DPP_PA_PKEX_COMMIT_REVEAL_RESP:
184485732ac8SCy Schubert 		wpas_dpp_rx_pkex_commit_reveal_resp(wpa_s, src, hdr, buf, len,
184585732ac8SCy Schubert 						    freq);
184685732ac8SCy Schubert 		break;
18474bc52338SCy Schubert #ifdef CONFIG_DPP2
18484bc52338SCy Schubert 	case DPP_PA_CONFIGURATION_RESULT:
18494bc52338SCy Schubert 		wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len);
18504bc52338SCy Schubert 		break;
18514bc52338SCy Schubert #endif /* CONFIG_DPP2 */
185285732ac8SCy Schubert 	default:
185385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
185485732ac8SCy Schubert 			   "DPP: Ignored unsupported frame subtype %d", type);
185585732ac8SCy Schubert 		break;
185685732ac8SCy Schubert 	}
185785732ac8SCy Schubert 
185885732ac8SCy Schubert 	if (wpa_s->dpp_pkex)
185985732ac8SCy Schubert 		pkex_t = wpa_s->dpp_pkex->t;
186085732ac8SCy Schubert 	else if (wpa_s->dpp_pkex_bi)
186185732ac8SCy Schubert 		pkex_t = wpa_s->dpp_pkex_bi->pkex_t;
186285732ac8SCy Schubert 	else
186385732ac8SCy Schubert 		pkex_t = 0;
186485732ac8SCy Schubert 	if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
186585732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
186685732ac8SCy Schubert 		wpas_dpp_pkex_remove(wpa_s, "*");
186785732ac8SCy Schubert 	}
186885732ac8SCy Schubert }
186985732ac8SCy Schubert 
187085732ac8SCy Schubert 
187185732ac8SCy Schubert static struct wpabuf *
187285732ac8SCy Schubert wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
187385732ac8SCy Schubert 			 size_t query_len)
187485732ac8SCy Schubert {
187585732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = ctx;
187685732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
187785732ac8SCy Schubert 	struct wpabuf *resp;
187885732ac8SCy Schubert 
187985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR,
188085732ac8SCy Schubert 		   MAC2STR(sa));
188185732ac8SCy Schubert 	if (!auth || !auth->auth_success ||
188285732ac8SCy Schubert 	    os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
188385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
188485732ac8SCy Schubert 		return NULL;
188585732ac8SCy Schubert 	}
1886*206b73d0SCy Schubert 
1887*206b73d0SCy Schubert 	if (wpa_s->dpp_auth_ok_on_ack && auth->configurator) {
1888*206b73d0SCy Schubert 		wpa_printf(MSG_DEBUG,
1889*206b73d0SCy Schubert 			   "DPP: Have not received ACK for Auth Confirm yet - assume it was received based on this GAS request");
1890*206b73d0SCy Schubert 		/* wpas_dpp_auth_success() would normally have been called from
1891*206b73d0SCy Schubert 		 * TX status handler, but since there was no such handler call
1892*206b73d0SCy Schubert 		 * yet, simply send out the event message and proceed with
1893*206b73d0SCy Schubert 		 * exchange. */
1894*206b73d0SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=1");
1895*206b73d0SCy Schubert 		wpa_s->dpp_auth_ok_on_ack = 0;
1896*206b73d0SCy Schubert 	}
1897*206b73d0SCy Schubert 
189885732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG,
189985732ac8SCy Schubert 		    "DPP: Received Configuration Request (GAS Query Request)",
190085732ac8SCy Schubert 		    query, query_len);
190185732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
190285732ac8SCy Schubert 		MAC2STR(sa));
190385732ac8SCy Schubert 	resp = dpp_conf_req_rx(auth, query, query_len);
190485732ac8SCy Schubert 	if (!resp)
190585732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
190685732ac8SCy Schubert 	auth->conf_resp = resp;
190785732ac8SCy Schubert 	return resp;
190885732ac8SCy Schubert }
190985732ac8SCy Schubert 
191085732ac8SCy Schubert 
191185732ac8SCy Schubert static void
191285732ac8SCy Schubert wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
191385732ac8SCy Schubert {
191485732ac8SCy Schubert 	struct wpa_supplicant *wpa_s = ctx;
191585732ac8SCy Schubert 	struct dpp_authentication *auth = wpa_s->dpp_auth;
191685732ac8SCy Schubert 
191785732ac8SCy Schubert 	if (!auth) {
191885732ac8SCy Schubert 		wpabuf_free(resp);
191985732ac8SCy Schubert 		return;
192085732ac8SCy Schubert 	}
192185732ac8SCy Schubert 	if (auth->conf_resp != resp) {
192285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
192385732ac8SCy Schubert 			   "DPP: Ignore GAS status report (ok=%d) for unknown response",
192485732ac8SCy Schubert 			ok);
192585732ac8SCy Schubert 		wpabuf_free(resp);
192685732ac8SCy Schubert 		return;
192785732ac8SCy Schubert 	}
192885732ac8SCy Schubert 
192985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
193085732ac8SCy Schubert 		   ok);
193185732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
193285732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
19334bc52338SCy Schubert #ifdef CONFIG_DPP2
19344bc52338SCy Schubert 	if (ok && auth->peer_version >= 2 &&
19354bc52338SCy Schubert 	    auth->conf_resp_status == DPP_STATUS_OK) {
19364bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
19374bc52338SCy Schubert 		auth->waiting_conf_result = 1;
19384bc52338SCy Schubert 		auth->conf_resp = NULL;
19394bc52338SCy Schubert 		wpabuf_free(resp);
19404bc52338SCy Schubert 		eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
19414bc52338SCy Schubert 				     wpa_s, NULL);
19424bc52338SCy Schubert 		eloop_register_timeout(2, 0,
19434bc52338SCy Schubert 				       wpas_dpp_config_result_wait_timeout,
19444bc52338SCy Schubert 				       wpa_s, NULL);
19454bc52338SCy Schubert 		return;
19464bc52338SCy Schubert 	}
19474bc52338SCy Schubert #endif /* CONFIG_DPP2 */
194885732ac8SCy Schubert 	offchannel_send_action_done(wpa_s);
194985732ac8SCy Schubert 	wpas_dpp_listen_stop(wpa_s);
195085732ac8SCy Schubert 	if (ok)
195185732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
195285732ac8SCy Schubert 	else
195385732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
195485732ac8SCy Schubert 	dpp_auth_deinit(wpa_s->dpp_auth);
195585732ac8SCy Schubert 	wpa_s->dpp_auth = NULL;
195685732ac8SCy Schubert 	wpabuf_free(resp);
195785732ac8SCy Schubert }
195885732ac8SCy Schubert 
195985732ac8SCy Schubert 
196085732ac8SCy Schubert int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd)
196185732ac8SCy Schubert {
196285732ac8SCy Schubert 	struct dpp_authentication *auth;
196385732ac8SCy Schubert 	int ret = -1;
196485732ac8SCy Schubert 	char *curve = NULL;
196585732ac8SCy Schubert 
196685732ac8SCy Schubert 	auth = os_zalloc(sizeof(*auth));
196785732ac8SCy Schubert 	if (!auth)
196885732ac8SCy Schubert 		return -1;
196985732ac8SCy Schubert 
197085732ac8SCy Schubert 	curve = get_param(cmd, " curve=");
197185732ac8SCy Schubert 	wpas_dpp_set_testing_options(wpa_s, auth);
19724bc52338SCy Schubert 	if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) == 0 &&
19734bc52338SCy Schubert 	    dpp_configurator_own_config(auth, curve, 0) == 0)
19744bc52338SCy Schubert 		ret = wpas_dpp_handle_config_obj(wpa_s, auth);
197585732ac8SCy Schubert 
197685732ac8SCy Schubert 	dpp_auth_deinit(auth);
197785732ac8SCy Schubert 	os_free(curve);
197885732ac8SCy Schubert 
197985732ac8SCy Schubert 	return ret;
198085732ac8SCy Schubert }
198185732ac8SCy Schubert 
198285732ac8SCy Schubert 
198385732ac8SCy Schubert static void
198485732ac8SCy Schubert wpas_dpp_tx_introduction_status(struct wpa_supplicant *wpa_s,
198585732ac8SCy Schubert 				unsigned int freq, const u8 *dst,
198685732ac8SCy Schubert 				const u8 *src, const u8 *bssid,
198785732ac8SCy Schubert 				const u8 *data, size_t data_len,
198885732ac8SCy Schubert 				enum offchannel_send_action_result result)
198985732ac8SCy Schubert {
199085732ac8SCy Schubert 	const char *res_txt;
199185732ac8SCy Schubert 
199285732ac8SCy Schubert 	res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
199385732ac8SCy Schubert 		(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
199485732ac8SCy Schubert 		 "FAILED");
199585732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
199685732ac8SCy Schubert 		   " result=%s (DPP Peer Discovery Request)",
199785732ac8SCy Schubert 		   freq, MAC2STR(dst), res_txt);
199885732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
199985732ac8SCy Schubert 		" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
200085732ac8SCy Schubert 	/* TODO: Time out wait for response more quickly in error cases? */
200185732ac8SCy Schubert }
200285732ac8SCy Schubert 
200385732ac8SCy Schubert 
200485732ac8SCy Schubert int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
200585732ac8SCy Schubert 			   struct wpa_bss *bss)
200685732ac8SCy Schubert {
200785732ac8SCy Schubert 	struct os_time now;
200885732ac8SCy Schubert 	struct wpabuf *msg;
200985732ac8SCy Schubert 	unsigned int wait_time;
20104bc52338SCy Schubert 	const u8 *rsn;
20114bc52338SCy Schubert 	struct wpa_ie_data ied;
201285732ac8SCy Schubert 
201385732ac8SCy Schubert 	if (!(ssid->key_mgmt & WPA_KEY_MGMT_DPP) || !bss)
201485732ac8SCy Schubert 		return 0; /* Not using DPP AKM - continue */
20154bc52338SCy Schubert 	rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
20164bc52338SCy Schubert 	if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
20174bc52338SCy Schubert 	    !(ied.key_mgmt & WPA_KEY_MGMT_DPP))
20184bc52338SCy Schubert 		return 0; /* AP does not support DPP AKM - continue */
201985732ac8SCy Schubert 	if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid))
202085732ac8SCy Schubert 		return 0; /* PMKSA exists for DPP AKM - continue */
202185732ac8SCy Schubert 
202285732ac8SCy Schubert 	if (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
202385732ac8SCy Schubert 	    !ssid->dpp_csign) {
202485732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR
202585732ac8SCy Schubert 			"missing %s",
202685732ac8SCy Schubert 			!ssid->dpp_connector ? "Connector" :
202785732ac8SCy Schubert 			(!ssid->dpp_netaccesskey ? "netAccessKey" :
202885732ac8SCy Schubert 			 "C-sign-key"));
202985732ac8SCy Schubert 		return -1;
203085732ac8SCy Schubert 	}
203185732ac8SCy Schubert 
203285732ac8SCy Schubert 	os_get_time(&now);
203385732ac8SCy Schubert 
203485732ac8SCy Schubert 	if (ssid->dpp_netaccesskey_expiry &&
203585732ac8SCy Schubert 	    (os_time_t) ssid->dpp_netaccesskey_expiry < now.sec) {
203685732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR
203785732ac8SCy Schubert 			"netAccessKey expired");
203885732ac8SCy Schubert 		return -1;
203985732ac8SCy Schubert 	}
204085732ac8SCy Schubert 
204185732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
204285732ac8SCy Schubert 		   "DPP: Starting network introduction protocol to derive PMKSA for "
204385732ac8SCy Schubert 		   MACSTR, MAC2STR(bss->bssid));
204485732ac8SCy Schubert 
204585732ac8SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ,
204685732ac8SCy Schubert 			    5 + 4 + os_strlen(ssid->dpp_connector));
204785732ac8SCy Schubert 	if (!msg)
204885732ac8SCy Schubert 		return -1;
204985732ac8SCy Schubert 
205085732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
205185732ac8SCy Schubert 	if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ) {
205285732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
205385732ac8SCy Schubert 		goto skip_trans_id;
205485732ac8SCy Schubert 	}
205585732ac8SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ) {
205685732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
205785732ac8SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
205885732ac8SCy Schubert 		wpabuf_put_le16(msg, 0);
205985732ac8SCy Schubert 		goto skip_trans_id;
206085732ac8SCy Schubert 	}
206185732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
206285732ac8SCy Schubert 
206385732ac8SCy Schubert 	/* Transaction ID */
206485732ac8SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
206585732ac8SCy Schubert 	wpabuf_put_le16(msg, 1);
206685732ac8SCy Schubert 	wpabuf_put_u8(msg, TRANSACTION_ID);
206785732ac8SCy Schubert 
206885732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
206985732ac8SCy Schubert skip_trans_id:
207085732ac8SCy Schubert 	if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ) {
207185732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
207285732ac8SCy Schubert 		goto skip_connector;
207385732ac8SCy Schubert 	}
207485732ac8SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ) {
207585732ac8SCy Schubert 		char *connector;
207685732ac8SCy Schubert 
207785732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
207885732ac8SCy Schubert 		connector = dpp_corrupt_connector_signature(
207985732ac8SCy Schubert 			ssid->dpp_connector);
208085732ac8SCy Schubert 		if (!connector) {
208185732ac8SCy Schubert 			wpabuf_free(msg);
208285732ac8SCy Schubert 			return -1;
208385732ac8SCy Schubert 		}
208485732ac8SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
208585732ac8SCy Schubert 		wpabuf_put_le16(msg, os_strlen(connector));
208685732ac8SCy Schubert 		wpabuf_put_str(msg, connector);
208785732ac8SCy Schubert 		os_free(connector);
208885732ac8SCy Schubert 		goto skip_connector;
208985732ac8SCy Schubert 	}
209085732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
209185732ac8SCy Schubert 
209285732ac8SCy Schubert 	/* DPP Connector */
209385732ac8SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
209485732ac8SCy Schubert 	wpabuf_put_le16(msg, os_strlen(ssid->dpp_connector));
209585732ac8SCy Schubert 	wpabuf_put_str(msg, ssid->dpp_connector);
209685732ac8SCy Schubert 
209785732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
209885732ac8SCy Schubert skip_connector:
209985732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
210085732ac8SCy Schubert 
210185732ac8SCy Schubert 	/* TODO: Timeout on AP response */
210285732ac8SCy Schubert 	wait_time = wpa_s->max_remain_on_chan;
210385732ac8SCy Schubert 	if (wait_time > 2000)
210485732ac8SCy Schubert 		wait_time = 2000;
210585732ac8SCy Schubert 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
210685732ac8SCy Schubert 		MAC2STR(bss->bssid), bss->freq, DPP_PA_PEER_DISCOVERY_REQ);
210785732ac8SCy Schubert 	offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr,
210885732ac8SCy Schubert 			       broadcast,
210985732ac8SCy Schubert 			       wpabuf_head(msg), wpabuf_len(msg),
211085732ac8SCy Schubert 			       wait_time, wpas_dpp_tx_introduction_status, 0);
211185732ac8SCy Schubert 	wpabuf_free(msg);
211285732ac8SCy Schubert 
211385732ac8SCy Schubert 	/* Request this connection attempt to terminate - new one will be
211485732ac8SCy Schubert 	 * started when network introduction protocol completes */
211585732ac8SCy Schubert 	os_memcpy(wpa_s->dpp_intro_bssid, bss->bssid, ETH_ALEN);
211685732ac8SCy Schubert 	wpa_s->dpp_intro_network = ssid;
211785732ac8SCy Schubert 	return 1;
211885732ac8SCy Schubert }
211985732ac8SCy Schubert 
212085732ac8SCy Schubert 
212185732ac8SCy Schubert int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
212285732ac8SCy Schubert {
212385732ac8SCy Schubert 	struct dpp_bootstrap_info *own_bi;
212485732ac8SCy Schubert 	const char *pos, *end;
212585732ac8SCy Schubert 	unsigned int wait_time;
212685732ac8SCy Schubert 
212785732ac8SCy Schubert 	pos = os_strstr(cmd, " own=");
212885732ac8SCy Schubert 	if (!pos)
212985732ac8SCy Schubert 		return -1;
213085732ac8SCy Schubert 	pos += 5;
21314bc52338SCy Schubert 	own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
213285732ac8SCy Schubert 	if (!own_bi) {
213385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
213485732ac8SCy Schubert 			   "DPP: Identified bootstrap info not found");
213585732ac8SCy Schubert 		return -1;
213685732ac8SCy Schubert 	}
213785732ac8SCy Schubert 	if (own_bi->type != DPP_BOOTSTRAP_PKEX) {
213885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
213985732ac8SCy Schubert 			   "DPP: Identified bootstrap info not for PKEX");
214085732ac8SCy Schubert 		return -1;
214185732ac8SCy Schubert 	}
214285732ac8SCy Schubert 	wpa_s->dpp_pkex_bi = own_bi;
214385732ac8SCy Schubert 	own_bi->pkex_t = 0; /* clear pending errors on new code */
214485732ac8SCy Schubert 
214585732ac8SCy Schubert 	os_free(wpa_s->dpp_pkex_identifier);
214685732ac8SCy Schubert 	wpa_s->dpp_pkex_identifier = NULL;
214785732ac8SCy Schubert 	pos = os_strstr(cmd, " identifier=");
214885732ac8SCy Schubert 	if (pos) {
214985732ac8SCy Schubert 		pos += 12;
215085732ac8SCy Schubert 		end = os_strchr(pos, ' ');
215185732ac8SCy Schubert 		if (!end)
215285732ac8SCy Schubert 			return -1;
215385732ac8SCy Schubert 		wpa_s->dpp_pkex_identifier = os_malloc(end - pos + 1);
215485732ac8SCy Schubert 		if (!wpa_s->dpp_pkex_identifier)
215585732ac8SCy Schubert 			return -1;
215685732ac8SCy Schubert 		os_memcpy(wpa_s->dpp_pkex_identifier, pos, end - pos);
215785732ac8SCy Schubert 		wpa_s->dpp_pkex_identifier[end - pos] = '\0';
215885732ac8SCy Schubert 	}
215985732ac8SCy Schubert 
216085732ac8SCy Schubert 	pos = os_strstr(cmd, " code=");
216185732ac8SCy Schubert 	if (!pos)
216285732ac8SCy Schubert 		return -1;
216385732ac8SCy Schubert 	os_free(wpa_s->dpp_pkex_code);
216485732ac8SCy Schubert 	wpa_s->dpp_pkex_code = os_strdup(pos + 6);
216585732ac8SCy Schubert 	if (!wpa_s->dpp_pkex_code)
216685732ac8SCy Schubert 		return -1;
216785732ac8SCy Schubert 
216885732ac8SCy Schubert 	if (os_strstr(cmd, " init=1")) {
216985732ac8SCy Schubert 		struct dpp_pkex *pkex;
217085732ac8SCy Schubert 		struct wpabuf *msg;
217185732ac8SCy Schubert 
217285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
217385732ac8SCy Schubert 		dpp_pkex_free(wpa_s->dpp_pkex);
217485732ac8SCy Schubert 		wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr,
217585732ac8SCy Schubert 						wpa_s->dpp_pkex_identifier,
217685732ac8SCy Schubert 						wpa_s->dpp_pkex_code);
217785732ac8SCy Schubert 		pkex = wpa_s->dpp_pkex;
217885732ac8SCy Schubert 		if (!pkex)
217985732ac8SCy Schubert 			return -1;
218085732ac8SCy Schubert 
218185732ac8SCy Schubert 		msg = pkex->exchange_req;
218285732ac8SCy Schubert 		wait_time = wpa_s->max_remain_on_chan;
218385732ac8SCy Schubert 		if (wait_time > 2000)
218485732ac8SCy Schubert 			wait_time = 2000;
218585732ac8SCy Schubert 		pkex->freq = 2437;
218685732ac8SCy Schubert 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
218785732ac8SCy Schubert 			" freq=%u type=%d",
218885732ac8SCy Schubert 			MAC2STR(broadcast), pkex->freq,
218985732ac8SCy Schubert 			DPP_PA_PKEX_EXCHANGE_REQ);
219085732ac8SCy Schubert 		offchannel_send_action(wpa_s, pkex->freq, broadcast,
219185732ac8SCy Schubert 				       wpa_s->own_addr, broadcast,
219285732ac8SCy Schubert 				       wpabuf_head(msg), wpabuf_len(msg),
219385732ac8SCy Schubert 				       wait_time, wpas_dpp_tx_pkex_status, 0);
219485732ac8SCy Schubert 		if (wait_time == 0)
219585732ac8SCy Schubert 			wait_time = 2000;
219685732ac8SCy Schubert 		pkex->exch_req_wait_time = wait_time;
219785732ac8SCy Schubert 		pkex->exch_req_tries = 1;
219885732ac8SCy Schubert 	}
219985732ac8SCy Schubert 
220085732ac8SCy Schubert 	/* TODO: Support multiple PKEX info entries */
220185732ac8SCy Schubert 
220285732ac8SCy Schubert 	os_free(wpa_s->dpp_pkex_auth_cmd);
220385732ac8SCy Schubert 	wpa_s->dpp_pkex_auth_cmd = os_strdup(cmd);
220485732ac8SCy Schubert 
220585732ac8SCy Schubert 	return 1;
220685732ac8SCy Schubert }
220785732ac8SCy Schubert 
220885732ac8SCy Schubert 
220985732ac8SCy Schubert int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id)
221085732ac8SCy Schubert {
221185732ac8SCy Schubert 	unsigned int id_val;
221285732ac8SCy Schubert 
221385732ac8SCy Schubert 	if (os_strcmp(id, "*") == 0) {
221485732ac8SCy Schubert 		id_val = 0;
221585732ac8SCy Schubert 	} else {
221685732ac8SCy Schubert 		id_val = atoi(id);
221785732ac8SCy Schubert 		if (id_val == 0)
221885732ac8SCy Schubert 			return -1;
221985732ac8SCy Schubert 	}
222085732ac8SCy Schubert 
222185732ac8SCy Schubert 	if ((id_val != 0 && id_val != 1) || !wpa_s->dpp_pkex_code)
222285732ac8SCy Schubert 		return -1;
222385732ac8SCy Schubert 
222485732ac8SCy Schubert 	/* TODO: Support multiple PKEX entries */
222585732ac8SCy Schubert 	os_free(wpa_s->dpp_pkex_code);
222685732ac8SCy Schubert 	wpa_s->dpp_pkex_code = NULL;
222785732ac8SCy Schubert 	os_free(wpa_s->dpp_pkex_identifier);
222885732ac8SCy Schubert 	wpa_s->dpp_pkex_identifier = NULL;
222985732ac8SCy Schubert 	os_free(wpa_s->dpp_pkex_auth_cmd);
223085732ac8SCy Schubert 	wpa_s->dpp_pkex_auth_cmd = NULL;
223185732ac8SCy Schubert 	wpa_s->dpp_pkex_bi = NULL;
223285732ac8SCy Schubert 	/* TODO: Remove dpp_pkex only if it is for the identified PKEX code */
223385732ac8SCy Schubert 	dpp_pkex_free(wpa_s->dpp_pkex);
223485732ac8SCy Schubert 	wpa_s->dpp_pkex = NULL;
223585732ac8SCy Schubert 	return 0;
223685732ac8SCy Schubert }
223785732ac8SCy Schubert 
223885732ac8SCy Schubert 
223985732ac8SCy Schubert void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
224085732ac8SCy Schubert {
224185732ac8SCy Schubert 	dpp_auth_deinit(wpa_s->dpp_auth);
224285732ac8SCy Schubert 	wpa_s->dpp_auth = NULL;
224385732ac8SCy Schubert 	dpp_pkex_free(wpa_s->dpp_pkex);
224485732ac8SCy Schubert 	wpa_s->dpp_pkex = NULL;
224585732ac8SCy Schubert 	if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0)
224685732ac8SCy Schubert 		gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token);
224785732ac8SCy Schubert }
224885732ac8SCy Schubert 
224985732ac8SCy Schubert 
225085732ac8SCy Schubert int wpas_dpp_init(struct wpa_supplicant *wpa_s)
225185732ac8SCy Schubert {
2252*206b73d0SCy Schubert 	struct dpp_global_config config;
225385732ac8SCy Schubert 	u8 adv_proto_id[7];
225485732ac8SCy Schubert 
225585732ac8SCy Schubert 	adv_proto_id[0] = WLAN_EID_VENDOR_SPECIFIC;
225685732ac8SCy Schubert 	adv_proto_id[1] = 5;
225785732ac8SCy Schubert 	WPA_PUT_BE24(&adv_proto_id[2], OUI_WFA);
225885732ac8SCy Schubert 	adv_proto_id[5] = DPP_OUI_TYPE;
225985732ac8SCy Schubert 	adv_proto_id[6] = 0x01;
226085732ac8SCy Schubert 
226185732ac8SCy Schubert 	if (gas_server_register(wpa_s->gas_server, adv_proto_id,
226285732ac8SCy Schubert 				sizeof(adv_proto_id), wpas_dpp_gas_req_handler,
226385732ac8SCy Schubert 				wpas_dpp_gas_status_handler, wpa_s) < 0)
226485732ac8SCy Schubert 		return -1;
2265*206b73d0SCy Schubert 
2266*206b73d0SCy Schubert 	os_memset(&config, 0, sizeof(config));
2267*206b73d0SCy Schubert 	config.msg_ctx = wpa_s;
2268*206b73d0SCy Schubert 	config.cb_ctx = wpa_s;
2269*206b73d0SCy Schubert #ifdef CONFIG_DPP2
2270*206b73d0SCy Schubert 	config.process_conf_obj = wpas_dpp_process_conf_obj;
2271*206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
2272*206b73d0SCy Schubert 	wpa_s->dpp = dpp_global_init(&config);
22734bc52338SCy Schubert 	return wpa_s->dpp ? 0 : -1;
227485732ac8SCy Schubert }
227585732ac8SCy Schubert 
227685732ac8SCy Schubert 
227785732ac8SCy Schubert void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
227885732ac8SCy Schubert {
227985732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
228085732ac8SCy Schubert 	os_free(wpa_s->dpp_config_obj_override);
228185732ac8SCy Schubert 	wpa_s->dpp_config_obj_override = NULL;
228285732ac8SCy Schubert 	os_free(wpa_s->dpp_discovery_override);
228385732ac8SCy Schubert 	wpa_s->dpp_discovery_override = NULL;
228485732ac8SCy Schubert 	os_free(wpa_s->dpp_groups_override);
228585732ac8SCy Schubert 	wpa_s->dpp_groups_override = NULL;
228685732ac8SCy Schubert 	wpa_s->dpp_ignore_netaccesskey_mismatch = 0;
228785732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
22884bc52338SCy Schubert 	if (!wpa_s->dpp)
228985732ac8SCy Schubert 		return;
22904bc52338SCy Schubert 	dpp_global_clear(wpa_s->dpp);
229185732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
229285732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
229385732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
229485732ac8SCy Schubert 	eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
22954bc52338SCy Schubert #ifdef CONFIG_DPP2
22964bc52338SCy Schubert 	eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
22974bc52338SCy Schubert 	dpp_pfs_free(wpa_s->dpp_pfs);
22984bc52338SCy Schubert 	wpa_s->dpp_pfs = NULL;
22994bc52338SCy Schubert #endif /* CONFIG_DPP2 */
230085732ac8SCy Schubert 	offchannel_send_action_done(wpa_s);
230185732ac8SCy Schubert 	wpas_dpp_listen_stop(wpa_s);
230285732ac8SCy Schubert 	wpas_dpp_stop(wpa_s);
230385732ac8SCy Schubert 	wpas_dpp_pkex_remove(wpa_s, "*");
230485732ac8SCy Schubert 	os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN);
230585732ac8SCy Schubert 	os_free(wpa_s->dpp_configurator_params);
230685732ac8SCy Schubert 	wpa_s->dpp_configurator_params = NULL;
230785732ac8SCy Schubert }
2308*206b73d0SCy Schubert 
2309*206b73d0SCy Schubert 
2310*206b73d0SCy Schubert #ifdef CONFIG_DPP2
2311*206b73d0SCy Schubert int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
2312*206b73d0SCy Schubert {
2313*206b73d0SCy Schubert 	struct dpp_controller_config config;
2314*206b73d0SCy Schubert 	const char *pos;
2315*206b73d0SCy Schubert 
2316*206b73d0SCy Schubert 	os_memset(&config, 0, sizeof(config));
2317*206b73d0SCy Schubert 	if (cmd) {
2318*206b73d0SCy Schubert 		pos = os_strstr(cmd, " tcp_port=");
2319*206b73d0SCy Schubert 		if (pos) {
2320*206b73d0SCy Schubert 			pos += 10;
2321*206b73d0SCy Schubert 			config.tcp_port = atoi(pos);
2322*206b73d0SCy Schubert 		}
2323*206b73d0SCy Schubert 	}
2324*206b73d0SCy Schubert 	config.configurator_params = wpa_s->dpp_configurator_params;
2325*206b73d0SCy Schubert 	return dpp_controller_start(wpa_s->dpp, &config);
2326*206b73d0SCy Schubert }
2327*206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
2328