1ebb5671cSchristos /*
2ebb5671cSchristos  * wpa_supplicant - DPP
3ebb5671cSchristos  * Copyright (c) 2017, Qualcomm Atheros, Inc.
4*0d69f216Schristos  * Copyright (c) 2018-2019, The Linux Foundation
5ebb5671cSchristos  *
6ebb5671cSchristos  * This software may be distributed under the terms of the BSD license.
7ebb5671cSchristos  * See README for more details.
8ebb5671cSchristos  */
9ebb5671cSchristos 
10ebb5671cSchristos #include "utils/includes.h"
11ebb5671cSchristos 
12ebb5671cSchristos #include "utils/common.h"
13ebb5671cSchristos #include "utils/eloop.h"
14*0d69f216Schristos #include "utils/ip_addr.h"
15ebb5671cSchristos #include "common/dpp.h"
16ebb5671cSchristos #include "common/gas.h"
17ebb5671cSchristos #include "common/gas_server.h"
18ebb5671cSchristos #include "rsn_supp/wpa.h"
19ebb5671cSchristos #include "rsn_supp/pmksa_cache.h"
20ebb5671cSchristos #include "wpa_supplicant_i.h"
21ebb5671cSchristos #include "config.h"
22ebb5671cSchristos #include "driver_i.h"
23ebb5671cSchristos #include "offchannel.h"
24ebb5671cSchristos #include "gas_query.h"
25ebb5671cSchristos #include "bss.h"
26ebb5671cSchristos #include "scan.h"
27ebb5671cSchristos #include "notify.h"
28ebb5671cSchristos #include "dpp_supplicant.h"
29ebb5671cSchristos 
30ebb5671cSchristos 
31ebb5671cSchristos static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
32ebb5671cSchristos 				 unsigned int freq);
33ebb5671cSchristos static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
34ebb5671cSchristos static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator);
35ebb5671cSchristos static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
36ebb5671cSchristos 			       unsigned int freq, const u8 *dst,
37ebb5671cSchristos 			       const u8 *src, const u8 *bssid,
38ebb5671cSchristos 			       const u8 *data, size_t data_len,
39ebb5671cSchristos 			       enum offchannel_send_action_result result);
40ebb5671cSchristos static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
41ebb5671cSchristos static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s);
42ebb5671cSchristos static void
43ebb5671cSchristos wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
44ebb5671cSchristos 			unsigned int freq, const u8 *dst,
45ebb5671cSchristos 			const u8 *src, const u8 *bssid,
46ebb5671cSchristos 			const u8 *data, size_t data_len,
47ebb5671cSchristos 			enum offchannel_send_action_result result);
48ebb5671cSchristos 
49ebb5671cSchristos static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
50ebb5671cSchristos 
51ebb5671cSchristos /* Use a hardcoded Transaction ID 1 in Peer Discovery frames since there is only
52ebb5671cSchristos  * a single transaction in progress at any point in time. */
53ebb5671cSchristos static const u8 TRANSACTION_ID = 1;
54ebb5671cSchristos 
55ebb5671cSchristos 
56ebb5671cSchristos /**
57ebb5671cSchristos  * wpas_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
58ebb5671cSchristos  * @wpa_s: Pointer to wpa_supplicant data
59ebb5671cSchristos  * @cmd: DPP URI read from a QR Code
60ebb5671cSchristos  * Returns: Identifier of the stored info or -1 on failure
61ebb5671cSchristos  */
wpas_dpp_qr_code(struct wpa_supplicant * wpa_s,const char * cmd)62ebb5671cSchristos int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd)
63ebb5671cSchristos {
64ebb5671cSchristos 	struct dpp_bootstrap_info *bi;
65ebb5671cSchristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
66ebb5671cSchristos 
67*0d69f216Schristos 	bi = dpp_add_qr_code(wpa_s->dpp, cmd);
68ebb5671cSchristos 	if (!bi)
69ebb5671cSchristos 		return -1;
70ebb5671cSchristos 
71ebb5671cSchristos 	if (auth && auth->response_pending &&
72ebb5671cSchristos 	    dpp_notify_new_qr_code(auth, bi) == 1) {
73ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
74ebb5671cSchristos 			   "DPP: Sending out pending authentication response");
75ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
76ebb5671cSchristos 			" freq=%u type=%d",
77ebb5671cSchristos 			MAC2STR(auth->peer_mac_addr), auth->curr_freq,
78ebb5671cSchristos 			DPP_PA_AUTHENTICATION_RESP);
79ebb5671cSchristos 		offchannel_send_action(wpa_s, auth->curr_freq,
80ebb5671cSchristos 				       auth->peer_mac_addr, wpa_s->own_addr,
81ebb5671cSchristos 				       broadcast,
82ebb5671cSchristos 				       wpabuf_head(auth->resp_msg),
83ebb5671cSchristos 				       wpabuf_len(auth->resp_msg),
84ebb5671cSchristos 				       500, wpas_dpp_tx_status, 0);
85ebb5671cSchristos 	}
86ebb5671cSchristos 
87ebb5671cSchristos 	return bi->id;
88ebb5671cSchristos }
89ebb5671cSchristos 
90ebb5671cSchristos 
wpas_dpp_auth_resp_retry_timeout(void * eloop_ctx,void * timeout_ctx)91ebb5671cSchristos static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
92ebb5671cSchristos {
93ebb5671cSchristos 	struct wpa_supplicant *wpa_s = eloop_ctx;
94ebb5671cSchristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
95ebb5671cSchristos 
96ebb5671cSchristos 	if (!auth || !auth->resp_msg)
97ebb5671cSchristos 		return;
98ebb5671cSchristos 
99ebb5671cSchristos 	wpa_printf(MSG_DEBUG,
100ebb5671cSchristos 		   "DPP: Retry Authentication Response after timeout");
101ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
102ebb5671cSchristos 		" freq=%u type=%d",
103ebb5671cSchristos 		MAC2STR(auth->peer_mac_addr), auth->curr_freq,
104ebb5671cSchristos 		DPP_PA_AUTHENTICATION_RESP);
105ebb5671cSchristos 	offchannel_send_action(wpa_s, auth->curr_freq, auth->peer_mac_addr,
106ebb5671cSchristos 			       wpa_s->own_addr, broadcast,
107ebb5671cSchristos 			       wpabuf_head(auth->resp_msg),
108ebb5671cSchristos 			       wpabuf_len(auth->resp_msg),
109ebb5671cSchristos 			       500, wpas_dpp_tx_status, 0);
110ebb5671cSchristos }
111ebb5671cSchristos 
112ebb5671cSchristos 
wpas_dpp_auth_resp_retry(struct wpa_supplicant * wpa_s)113ebb5671cSchristos static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s)
114ebb5671cSchristos {
115ebb5671cSchristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
116ebb5671cSchristos 	unsigned int wait_time, max_tries;
117ebb5671cSchristos 
118ebb5671cSchristos 	if (!auth || !auth->resp_msg)
119ebb5671cSchristos 		return;
120ebb5671cSchristos 
121ebb5671cSchristos 	if (wpa_s->dpp_resp_max_tries)
122ebb5671cSchristos 		max_tries = wpa_s->dpp_resp_max_tries;
123ebb5671cSchristos 	else
124ebb5671cSchristos 		max_tries = 5;
125ebb5671cSchristos 	auth->auth_resp_tries++;
126ebb5671cSchristos 	if (auth->auth_resp_tries >= max_tries) {
127ebb5671cSchristos 		wpa_printf(MSG_INFO, "DPP: No confirm received from initiator - stopping exchange");
128ebb5671cSchristos 		offchannel_send_action_done(wpa_s);
129ebb5671cSchristos 		dpp_auth_deinit(wpa_s->dpp_auth);
130ebb5671cSchristos 		wpa_s->dpp_auth = NULL;
131ebb5671cSchristos 		return;
132ebb5671cSchristos 	}
133ebb5671cSchristos 
134ebb5671cSchristos 	if (wpa_s->dpp_resp_retry_time)
135ebb5671cSchristos 		wait_time = wpa_s->dpp_resp_retry_time;
136ebb5671cSchristos 	else
137ebb5671cSchristos 		wait_time = 1000;
138ebb5671cSchristos 	wpa_printf(MSG_DEBUG,
139ebb5671cSchristos 		   "DPP: Schedule retransmission of Authentication Response frame in %u ms",
140ebb5671cSchristos 		wait_time);
141ebb5671cSchristos 	eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
142ebb5671cSchristos 	eloop_register_timeout(wait_time / 1000,
143ebb5671cSchristos 			       (wait_time % 1000) * 1000,
144ebb5671cSchristos 			       wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
145ebb5671cSchristos }
146ebb5671cSchristos 
147ebb5671cSchristos 
wpas_dpp_try_to_connect(struct wpa_supplicant * wpa_s)148*0d69f216Schristos static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
149*0d69f216Schristos {
150*0d69f216Schristos 	wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
151*0d69f216Schristos 	wpa_s->disconnected = 0;
152*0d69f216Schristos 	wpa_s->reassociate = 1;
153*0d69f216Schristos 	wpa_s->scan_runs = 0;
154*0d69f216Schristos 	wpa_s->normal_scans = 0;
155*0d69f216Schristos 	wpa_supplicant_cancel_sched_scan(wpa_s);
156*0d69f216Schristos 	wpa_supplicant_req_scan(wpa_s, 0, 0);
157*0d69f216Schristos }
158*0d69f216Schristos 
159*0d69f216Schristos 
wpas_dpp_tx_status(struct wpa_supplicant * wpa_s,unsigned int freq,const u8 * dst,const u8 * src,const u8 * bssid,const u8 * data,size_t data_len,enum offchannel_send_action_result result)160ebb5671cSchristos static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
161ebb5671cSchristos 			       unsigned int freq, const u8 *dst,
162ebb5671cSchristos 			       const u8 *src, const u8 *bssid,
163ebb5671cSchristos 			       const u8 *data, size_t data_len,
164ebb5671cSchristos 			       enum offchannel_send_action_result result)
165ebb5671cSchristos {
166ebb5671cSchristos 	const char *res_txt;
167ebb5671cSchristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
168ebb5671cSchristos 
169ebb5671cSchristos 	res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
170ebb5671cSchristos 		(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
171ebb5671cSchristos 		 "FAILED");
172ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
173ebb5671cSchristos 		   " result=%s", freq, MAC2STR(dst), res_txt);
174ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
175ebb5671cSchristos 		" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
176ebb5671cSchristos 
177ebb5671cSchristos 	if (!wpa_s->dpp_auth) {
178ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
179ebb5671cSchristos 			   "DPP: Ignore TX status since there is no ongoing authentication exchange");
180ebb5671cSchristos 		return;
181ebb5671cSchristos 	}
182ebb5671cSchristos 
183*0d69f216Schristos #ifdef CONFIG_DPP2
184*0d69f216Schristos 	if (auth->connect_on_tx_status) {
185*0d69f216Schristos 		wpa_printf(MSG_DEBUG,
186*0d69f216Schristos 			   "DPP: Try to connect after completed configuration result");
187*0d69f216Schristos 		wpas_dpp_try_to_connect(wpa_s);
188*0d69f216Schristos 		dpp_auth_deinit(wpa_s->dpp_auth);
189*0d69f216Schristos 		wpa_s->dpp_auth = NULL;
190*0d69f216Schristos 		return;
191*0d69f216Schristos 	}
192*0d69f216Schristos #endif /* CONFIG_DPP2 */
193*0d69f216Schristos 
194ebb5671cSchristos 	if (wpa_s->dpp_auth->remove_on_tx_status) {
195ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
196ebb5671cSchristos 			   "DPP: Terminate authentication exchange due to an earlier error");
197ebb5671cSchristos 		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
198ebb5671cSchristos 		eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
199ebb5671cSchristos 		eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
200ebb5671cSchristos 				     NULL);
201ebb5671cSchristos 		offchannel_send_action_done(wpa_s);
202ebb5671cSchristos 		dpp_auth_deinit(wpa_s->dpp_auth);
203ebb5671cSchristos 		wpa_s->dpp_auth = NULL;
204ebb5671cSchristos 		return;
205ebb5671cSchristos 	}
206ebb5671cSchristos 
207ebb5671cSchristos 	if (wpa_s->dpp_auth_ok_on_ack)
208ebb5671cSchristos 		wpas_dpp_auth_success(wpa_s, 1);
209ebb5671cSchristos 
210ebb5671cSchristos 	if (!is_broadcast_ether_addr(dst) &&
211ebb5671cSchristos 	    result != OFFCHANNEL_SEND_ACTION_SUCCESS) {
212ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
213ebb5671cSchristos 			   "DPP: Unicast DPP Action frame was not ACKed");
214ebb5671cSchristos 		if (auth->waiting_auth_resp) {
215ebb5671cSchristos 			/* In case of DPP Authentication Request frame, move to
216ebb5671cSchristos 			 * the next channel immediately. */
217ebb5671cSchristos 			offchannel_send_action_done(wpa_s);
218ebb5671cSchristos 			wpas_dpp_auth_init_next(wpa_s);
219ebb5671cSchristos 			return;
220ebb5671cSchristos 		}
221ebb5671cSchristos 		if (auth->waiting_auth_conf) {
222ebb5671cSchristos 			wpas_dpp_auth_resp_retry(wpa_s);
223ebb5671cSchristos 			return;
224ebb5671cSchristos 		}
225ebb5671cSchristos 	}
226ebb5671cSchristos 
227ebb5671cSchristos 	if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp &&
228ebb5671cSchristos 	    result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
229ebb5671cSchristos 		/* Allow timeout handling to stop iteration if no response is
230ebb5671cSchristos 		 * received from a peer that has ACKed a request. */
231ebb5671cSchristos 		auth->auth_req_ack = 1;
232ebb5671cSchristos 	}
233ebb5671cSchristos 
234ebb5671cSchristos 	if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 &&
235ebb5671cSchristos 	    wpa_s->dpp_auth->curr_freq != wpa_s->dpp_auth->neg_freq) {
236ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
237ebb5671cSchristos 			   "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
238ebb5671cSchristos 			   wpa_s->dpp_auth->curr_freq,
239ebb5671cSchristos 			   wpa_s->dpp_auth->neg_freq);
240ebb5671cSchristos 		offchannel_send_action_done(wpa_s);
241ebb5671cSchristos 		wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->neg_freq);
242ebb5671cSchristos 	}
243ebb5671cSchristos 
244ebb5671cSchristos 	if (wpa_s->dpp_auth_ok_on_ack)
245ebb5671cSchristos 		wpa_s->dpp_auth_ok_on_ack = 0;
246ebb5671cSchristos }
247ebb5671cSchristos 
248ebb5671cSchristos 
wpas_dpp_reply_wait_timeout(void * eloop_ctx,void * timeout_ctx)249ebb5671cSchristos static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
250ebb5671cSchristos {
251ebb5671cSchristos 	struct wpa_supplicant *wpa_s = eloop_ctx;
252ebb5671cSchristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
253ebb5671cSchristos 	unsigned int freq;
254ebb5671cSchristos 	struct os_reltime now, diff;
255ebb5671cSchristos 	unsigned int wait_time, diff_ms;
256ebb5671cSchristos 
257ebb5671cSchristos 	if (!auth || !auth->waiting_auth_resp)
258ebb5671cSchristos 		return;
259ebb5671cSchristos 
260ebb5671cSchristos 	wait_time = wpa_s->dpp_resp_wait_time ?
261ebb5671cSchristos 		wpa_s->dpp_resp_wait_time : 2000;
262ebb5671cSchristos 	os_get_reltime(&now);
263ebb5671cSchristos 	os_reltime_sub(&now, &wpa_s->dpp_last_init, &diff);
264ebb5671cSchristos 	diff_ms = diff.sec * 1000 + diff.usec / 1000;
265ebb5671cSchristos 	wpa_printf(MSG_DEBUG,
266ebb5671cSchristos 		   "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
267ebb5671cSchristos 		   wait_time, diff_ms);
268ebb5671cSchristos 
269ebb5671cSchristos 	if (auth->auth_req_ack && diff_ms >= wait_time) {
270ebb5671cSchristos 		/* Peer ACK'ed Authentication Request frame, but did not reply
271ebb5671cSchristos 		 * with Authentication Response frame within two seconds. */
272ebb5671cSchristos 		wpa_printf(MSG_INFO,
273ebb5671cSchristos 			   "DPP: No response received from responder - stopping initiation attempt");
274ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
275ebb5671cSchristos 		offchannel_send_action_done(wpa_s);
276ebb5671cSchristos 		wpas_dpp_listen_stop(wpa_s);
277ebb5671cSchristos 		dpp_auth_deinit(auth);
278ebb5671cSchristos 		wpa_s->dpp_auth = NULL;
279ebb5671cSchristos 		return;
280ebb5671cSchristos 	}
281ebb5671cSchristos 
282ebb5671cSchristos 	if (diff_ms >= wait_time) {
283ebb5671cSchristos 		/* Authentication Request frame was not ACK'ed and no reply
284ebb5671cSchristos 		 * was receiving within two seconds. */
285ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
286ebb5671cSchristos 			   "DPP: Continue Initiator channel iteration");
287ebb5671cSchristos 		offchannel_send_action_done(wpa_s);
288ebb5671cSchristos 		wpas_dpp_listen_stop(wpa_s);
289ebb5671cSchristos 		wpas_dpp_auth_init_next(wpa_s);
290ebb5671cSchristos 		return;
291ebb5671cSchristos 	}
292ebb5671cSchristos 
293ebb5671cSchristos 	/* Driver did not support 2000 ms long wait_time with TX command, so
294ebb5671cSchristos 	 * schedule listen operation to continue waiting for the response.
295ebb5671cSchristos 	 *
296ebb5671cSchristos 	 * DPP listen operations continue until stopped, so simply schedule a
297ebb5671cSchristos 	 * new call to this function at the point when the two second reply
298ebb5671cSchristos 	 * wait has expired. */
299ebb5671cSchristos 	wait_time -= diff_ms;
300ebb5671cSchristos 
301ebb5671cSchristos 	freq = auth->curr_freq;
302ebb5671cSchristos 	if (auth->neg_freq > 0)
303ebb5671cSchristos 		freq = auth->neg_freq;
304ebb5671cSchristos 	wpa_printf(MSG_DEBUG,
305ebb5671cSchristos 		   "DPP: Continue reply wait on channel %u MHz for %u ms",
306ebb5671cSchristos 		   freq, wait_time);
307ebb5671cSchristos 	wpa_s->dpp_in_response_listen = 1;
308ebb5671cSchristos 	wpas_dpp_listen_start(wpa_s, freq);
309ebb5671cSchristos 
310ebb5671cSchristos 	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
311ebb5671cSchristos 			       wpas_dpp_reply_wait_timeout, wpa_s, NULL);
312ebb5671cSchristos }
313ebb5671cSchristos 
314ebb5671cSchristos 
wpas_dpp_set_testing_options(struct wpa_supplicant * wpa_s,struct dpp_authentication * auth)315ebb5671cSchristos static void wpas_dpp_set_testing_options(struct wpa_supplicant *wpa_s,
316ebb5671cSchristos 					 struct dpp_authentication *auth)
317ebb5671cSchristos {
318ebb5671cSchristos #ifdef CONFIG_TESTING_OPTIONS
319ebb5671cSchristos 	if (wpa_s->dpp_config_obj_override)
320ebb5671cSchristos 		auth->config_obj_override =
321ebb5671cSchristos 			os_strdup(wpa_s->dpp_config_obj_override);
322ebb5671cSchristos 	if (wpa_s->dpp_discovery_override)
323ebb5671cSchristos 		auth->discovery_override =
324ebb5671cSchristos 			os_strdup(wpa_s->dpp_discovery_override);
325ebb5671cSchristos 	if (wpa_s->dpp_groups_override)
326ebb5671cSchristos 		auth->groups_override =
327ebb5671cSchristos 			os_strdup(wpa_s->dpp_groups_override);
328ebb5671cSchristos 	auth->ignore_netaccesskey_mismatch =
329ebb5671cSchristos 		wpa_s->dpp_ignore_netaccesskey_mismatch;
330ebb5671cSchristos #endif /* CONFIG_TESTING_OPTIONS */
331ebb5671cSchristos }
332ebb5671cSchristos 
333ebb5671cSchristos 
wpas_dpp_init_timeout(void * eloop_ctx,void * timeout_ctx)334ebb5671cSchristos static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
335ebb5671cSchristos {
336ebb5671cSchristos 	struct wpa_supplicant *wpa_s = eloop_ctx;
337ebb5671cSchristos 
338ebb5671cSchristos 	if (!wpa_s->dpp_auth)
339ebb5671cSchristos 		return;
340ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
341ebb5671cSchristos 	wpas_dpp_auth_init_next(wpa_s);
342ebb5671cSchristos }
343ebb5671cSchristos 
344ebb5671cSchristos 
wpas_dpp_auth_init_next(struct wpa_supplicant * wpa_s)345ebb5671cSchristos static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s)
346ebb5671cSchristos {
347ebb5671cSchristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
348ebb5671cSchristos 	const u8 *dst;
349ebb5671cSchristos 	unsigned int wait_time, max_wait_time, freq, max_tries, used;
350ebb5671cSchristos 	struct os_reltime now, diff;
351ebb5671cSchristos 
352ebb5671cSchristos 	wpa_s->dpp_in_response_listen = 0;
353ebb5671cSchristos 	if (!auth)
354ebb5671cSchristos 		return -1;
355ebb5671cSchristos 
356ebb5671cSchristos 	if (auth->freq_idx == 0)
357ebb5671cSchristos 		os_get_reltime(&wpa_s->dpp_init_iter_start);
358ebb5671cSchristos 
359ebb5671cSchristos 	if (auth->freq_idx >= auth->num_freq) {
360ebb5671cSchristos 		auth->num_freq_iters++;
361ebb5671cSchristos 		if (wpa_s->dpp_init_max_tries)
362ebb5671cSchristos 			max_tries = wpa_s->dpp_init_max_tries;
363ebb5671cSchristos 		else
364ebb5671cSchristos 			max_tries = 5;
365ebb5671cSchristos 		if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
366ebb5671cSchristos 			wpa_printf(MSG_INFO,
367ebb5671cSchristos 				   "DPP: No response received from responder - stopping initiation attempt");
368ebb5671cSchristos 			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
369ebb5671cSchristos 			eloop_cancel_timeout(wpas_dpp_reply_wait_timeout,
370ebb5671cSchristos 					     wpa_s, NULL);
371ebb5671cSchristos 			offchannel_send_action_done(wpa_s);
372ebb5671cSchristos 			dpp_auth_deinit(wpa_s->dpp_auth);
373ebb5671cSchristos 			wpa_s->dpp_auth = NULL;
374ebb5671cSchristos 			return -1;
375ebb5671cSchristos 		}
376ebb5671cSchristos 		auth->freq_idx = 0;
377ebb5671cSchristos 		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
378ebb5671cSchristos 		if (wpa_s->dpp_init_retry_time)
379ebb5671cSchristos 			wait_time = wpa_s->dpp_init_retry_time;
380ebb5671cSchristos 		else
381ebb5671cSchristos 			wait_time = 10000;
382ebb5671cSchristos 		os_get_reltime(&now);
383ebb5671cSchristos 		os_reltime_sub(&now, &wpa_s->dpp_init_iter_start, &diff);
384ebb5671cSchristos 		used = diff.sec * 1000 + diff.usec / 1000;
385ebb5671cSchristos 		if (used > wait_time)
386ebb5671cSchristos 			wait_time = 0;
387ebb5671cSchristos 		else
388ebb5671cSchristos 			wait_time -= used;
389ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
390ebb5671cSchristos 			   wait_time);
391ebb5671cSchristos 		eloop_register_timeout(wait_time / 1000,
392ebb5671cSchristos 				       (wait_time % 1000) * 1000,
393ebb5671cSchristos 				       wpas_dpp_init_timeout, wpa_s,
394ebb5671cSchristos 				       NULL);
395ebb5671cSchristos 		return 0;
396ebb5671cSchristos 	}
397ebb5671cSchristos 	freq = auth->freq[auth->freq_idx++];
398ebb5671cSchristos 	auth->curr_freq = freq;
399ebb5671cSchristos 
400ebb5671cSchristos 	if (is_zero_ether_addr(auth->peer_bi->mac_addr))
401ebb5671cSchristos 		dst = broadcast;
402ebb5671cSchristos 	else
403ebb5671cSchristos 		dst = auth->peer_bi->mac_addr;
404ebb5671cSchristos 	wpa_s->dpp_auth_ok_on_ack = 0;
405ebb5671cSchristos 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
406ebb5671cSchristos 	wait_time = wpa_s->max_remain_on_chan;
407ebb5671cSchristos 	max_wait_time = wpa_s->dpp_resp_wait_time ?
408ebb5671cSchristos 		wpa_s->dpp_resp_wait_time : 2000;
409ebb5671cSchristos 	if (wait_time > max_wait_time)
410ebb5671cSchristos 		wait_time = max_wait_time;
411ebb5671cSchristos 	wait_time += 10; /* give the driver some extra time to complete */
412ebb5671cSchristos 	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
413ebb5671cSchristos 			       wpas_dpp_reply_wait_timeout,
414ebb5671cSchristos 			       wpa_s, NULL);
415ebb5671cSchristos 	wait_time -= 10;
416ebb5671cSchristos 	if (auth->neg_freq > 0 && freq != auth->neg_freq) {
417ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
418ebb5671cSchristos 			   "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
419ebb5671cSchristos 			   freq, auth->neg_freq);
420ebb5671cSchristos 	}
421ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
422ebb5671cSchristos 		MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
423ebb5671cSchristos 	auth->auth_req_ack = 0;
424ebb5671cSchristos 	os_get_reltime(&wpa_s->dpp_last_init);
425ebb5671cSchristos 	return offchannel_send_action(wpa_s, freq, dst,
426ebb5671cSchristos 				      wpa_s->own_addr, broadcast,
427ebb5671cSchristos 				      wpabuf_head(auth->req_msg),
428ebb5671cSchristos 				      wpabuf_len(auth->req_msg),
429ebb5671cSchristos 				      wait_time, wpas_dpp_tx_status, 0);
430ebb5671cSchristos }
431ebb5671cSchristos 
432ebb5671cSchristos 
wpas_dpp_auth_init(struct wpa_supplicant * wpa_s,const char * cmd)433ebb5671cSchristos int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
434ebb5671cSchristos {
435ebb5671cSchristos 	const char *pos;
436ebb5671cSchristos 	struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
437*0d69f216Schristos 	struct dpp_authentication *auth;
438ebb5671cSchristos 	u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
439ebb5671cSchristos 	unsigned int neg_freq = 0;
440*0d69f216Schristos 	int tcp = 0;
441*0d69f216Schristos #ifdef CONFIG_DPP2
442*0d69f216Schristos 	int tcp_port = DPP_TCP_PORT;
443*0d69f216Schristos 	struct hostapd_ip_addr ipaddr;
444*0d69f216Schristos 	char *addr;
445*0d69f216Schristos #endif /* CONFIG_DPP2 */
446ebb5671cSchristos 
447ebb5671cSchristos 	wpa_s->dpp_gas_client = 0;
448ebb5671cSchristos 
449ebb5671cSchristos 	pos = os_strstr(cmd, " peer=");
450ebb5671cSchristos 	if (!pos)
451ebb5671cSchristos 		return -1;
452ebb5671cSchristos 	pos += 6;
453*0d69f216Schristos 	peer_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
454ebb5671cSchristos 	if (!peer_bi) {
455ebb5671cSchristos 		wpa_printf(MSG_INFO,
456ebb5671cSchristos 			   "DPP: Could not find bootstrapping info for the identified peer");
457ebb5671cSchristos 		return -1;
458ebb5671cSchristos 	}
459ebb5671cSchristos 
460*0d69f216Schristos #ifdef CONFIG_DPP2
461*0d69f216Schristos 	pos = os_strstr(cmd, " tcp_port=");
462*0d69f216Schristos 	if (pos) {
463*0d69f216Schristos 		pos += 10;
464*0d69f216Schristos 		tcp_port = atoi(pos);
465*0d69f216Schristos 	}
466*0d69f216Schristos 
467*0d69f216Schristos 	addr = get_param(cmd, " tcp_addr=");
468*0d69f216Schristos 	if (addr) {
469*0d69f216Schristos 		int res;
470*0d69f216Schristos 
471*0d69f216Schristos 		res = hostapd_parse_ip_addr(addr, &ipaddr);
472*0d69f216Schristos 		os_free(addr);
473*0d69f216Schristos 		if (res)
474*0d69f216Schristos 			return -1;
475*0d69f216Schristos 		tcp = 1;
476*0d69f216Schristos 	}
477*0d69f216Schristos #endif /* CONFIG_DPP2 */
478*0d69f216Schristos 
479ebb5671cSchristos 	pos = os_strstr(cmd, " own=");
480ebb5671cSchristos 	if (pos) {
481ebb5671cSchristos 		pos += 5;
482*0d69f216Schristos 		own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
483ebb5671cSchristos 		if (!own_bi) {
484ebb5671cSchristos 			wpa_printf(MSG_INFO,
485ebb5671cSchristos 				   "DPP: Could not find bootstrapping info for the identified local entry");
486ebb5671cSchristos 			return -1;
487ebb5671cSchristos 		}
488ebb5671cSchristos 
489ebb5671cSchristos 		if (peer_bi->curve != own_bi->curve) {
490ebb5671cSchristos 			wpa_printf(MSG_INFO,
491ebb5671cSchristos 				   "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
492ebb5671cSchristos 				   peer_bi->curve->name, own_bi->curve->name);
493ebb5671cSchristos 			return -1;
494ebb5671cSchristos 		}
495ebb5671cSchristos 	}
496ebb5671cSchristos 
497ebb5671cSchristos 	pos = os_strstr(cmd, " role=");
498ebb5671cSchristos 	if (pos) {
499ebb5671cSchristos 		pos += 6;
500ebb5671cSchristos 		if (os_strncmp(pos, "configurator", 12) == 0)
501ebb5671cSchristos 			allowed_roles = DPP_CAPAB_CONFIGURATOR;
502ebb5671cSchristos 		else if (os_strncmp(pos, "enrollee", 8) == 0)
503ebb5671cSchristos 			allowed_roles = DPP_CAPAB_ENROLLEE;
504ebb5671cSchristos 		else if (os_strncmp(pos, "either", 6) == 0)
505ebb5671cSchristos 			allowed_roles = DPP_CAPAB_CONFIGURATOR |
506ebb5671cSchristos 				DPP_CAPAB_ENROLLEE;
507ebb5671cSchristos 		else
508ebb5671cSchristos 			goto fail;
509ebb5671cSchristos 	}
510ebb5671cSchristos 
511ebb5671cSchristos 	pos = os_strstr(cmd, " netrole=");
512ebb5671cSchristos 	if (pos) {
513ebb5671cSchristos 		pos += 9;
514ebb5671cSchristos 		wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0;
515ebb5671cSchristos 	}
516ebb5671cSchristos 
517ebb5671cSchristos 	pos = os_strstr(cmd, " neg_freq=");
518ebb5671cSchristos 	if (pos)
519ebb5671cSchristos 		neg_freq = atoi(pos + 10);
520ebb5671cSchristos 
521*0d69f216Schristos 	if (!tcp && wpa_s->dpp_auth) {
522ebb5671cSchristos 		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
523ebb5671cSchristos 		eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
524ebb5671cSchristos 		eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
525ebb5671cSchristos 				     NULL);
526ebb5671cSchristos 		offchannel_send_action_done(wpa_s);
527ebb5671cSchristos 		dpp_auth_deinit(wpa_s->dpp_auth);
528ebb5671cSchristos 		wpa_s->dpp_auth = NULL;
529*0d69f216Schristos 	}
530*0d69f216Schristos 
531*0d69f216Schristos 	auth = dpp_auth_init(wpa_s, peer_bi, own_bi, allowed_roles, neg_freq,
532*0d69f216Schristos 			     wpa_s->hw.modes, wpa_s->hw.num_modes);
533*0d69f216Schristos 	if (!auth)
534*0d69f216Schristos 		goto fail;
535*0d69f216Schristos 	wpas_dpp_set_testing_options(wpa_s, auth);
536*0d69f216Schristos 	if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) < 0) {
537*0d69f216Schristos 		dpp_auth_deinit(auth);
538ebb5671cSchristos 		goto fail;
539ebb5671cSchristos 	}
540ebb5671cSchristos 
541*0d69f216Schristos 	auth->neg_freq = neg_freq;
542ebb5671cSchristos 
543ebb5671cSchristos 	if (!is_zero_ether_addr(peer_bi->mac_addr))
544*0d69f216Schristos 		os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
545ebb5671cSchristos 
546*0d69f216Schristos #ifdef CONFIG_DPP2
547*0d69f216Schristos 	if (tcp)
548*0d69f216Schristos 		return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port);
549*0d69f216Schristos #endif /* CONFIG_DPP2 */
550*0d69f216Schristos 
551*0d69f216Schristos 	wpa_s->dpp_auth = auth;
552ebb5671cSchristos 	return wpas_dpp_auth_init_next(wpa_s);
553ebb5671cSchristos fail:
554ebb5671cSchristos 	return -1;
555ebb5671cSchristos }
556ebb5671cSchristos 
557ebb5671cSchristos 
558ebb5671cSchristos struct wpas_dpp_listen_work {
559ebb5671cSchristos 	unsigned int freq;
560ebb5671cSchristos 	unsigned int duration;
561ebb5671cSchristos 	struct wpabuf *probe_resp_ie;
562ebb5671cSchristos };
563ebb5671cSchristos 
564ebb5671cSchristos 
wpas_dpp_listen_work_free(struct wpas_dpp_listen_work * lwork)565ebb5671cSchristos static void wpas_dpp_listen_work_free(struct wpas_dpp_listen_work *lwork)
566ebb5671cSchristos {
567ebb5671cSchristos 	if (!lwork)
568ebb5671cSchristos 		return;
569ebb5671cSchristos 	os_free(lwork);
570ebb5671cSchristos }
571ebb5671cSchristos 
572ebb5671cSchristos 
wpas_dpp_listen_work_done(struct wpa_supplicant * wpa_s)573ebb5671cSchristos static void wpas_dpp_listen_work_done(struct wpa_supplicant *wpa_s)
574ebb5671cSchristos {
575ebb5671cSchristos 	struct wpas_dpp_listen_work *lwork;
576ebb5671cSchristos 
577ebb5671cSchristos 	if (!wpa_s->dpp_listen_work)
578ebb5671cSchristos 		return;
579ebb5671cSchristos 
580ebb5671cSchristos 	lwork = wpa_s->dpp_listen_work->ctx;
581ebb5671cSchristos 	wpas_dpp_listen_work_free(lwork);
582ebb5671cSchristos 	radio_work_done(wpa_s->dpp_listen_work);
583ebb5671cSchristos 	wpa_s->dpp_listen_work = NULL;
584ebb5671cSchristos }
585ebb5671cSchristos 
586ebb5671cSchristos 
dpp_start_listen_cb(struct wpa_radio_work * work,int deinit)587ebb5671cSchristos static void dpp_start_listen_cb(struct wpa_radio_work *work, int deinit)
588ebb5671cSchristos {
589ebb5671cSchristos 	struct wpa_supplicant *wpa_s = work->wpa_s;
590ebb5671cSchristos 	struct wpas_dpp_listen_work *lwork = work->ctx;
591ebb5671cSchristos 
592ebb5671cSchristos 	if (deinit) {
593ebb5671cSchristos 		if (work->started) {
594ebb5671cSchristos 			wpa_s->dpp_listen_work = NULL;
595ebb5671cSchristos 			wpas_dpp_listen_stop(wpa_s);
596ebb5671cSchristos 		}
597ebb5671cSchristos 		wpas_dpp_listen_work_free(lwork);
598ebb5671cSchristos 		return;
599ebb5671cSchristos 	}
600ebb5671cSchristos 
601ebb5671cSchristos 	wpa_s->dpp_listen_work = work;
602ebb5671cSchristos 
603ebb5671cSchristos 	wpa_s->dpp_pending_listen_freq = lwork->freq;
604ebb5671cSchristos 
605ebb5671cSchristos 	if (wpa_drv_remain_on_channel(wpa_s, lwork->freq,
606ebb5671cSchristos 				      wpa_s->max_remain_on_chan) < 0) {
607ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
608ebb5671cSchristos 			   "DPP: Failed to request the driver to remain on channel (%u MHz) for listen",
609ebb5671cSchristos 			   lwork->freq);
610*0d69f216Schristos 		wpa_s->dpp_listen_freq = 0;
611ebb5671cSchristos 		wpas_dpp_listen_work_done(wpa_s);
612ebb5671cSchristos 		wpa_s->dpp_pending_listen_freq = 0;
613ebb5671cSchristos 		return;
614ebb5671cSchristos 	}
615ebb5671cSchristos 	wpa_s->off_channel_freq = 0;
616ebb5671cSchristos 	wpa_s->roc_waiting_drv_freq = lwork->freq;
617ebb5671cSchristos }
618ebb5671cSchristos 
619ebb5671cSchristos 
wpas_dpp_listen_start(struct wpa_supplicant * wpa_s,unsigned int freq)620ebb5671cSchristos static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
621ebb5671cSchristos 				 unsigned int freq)
622ebb5671cSchristos {
623ebb5671cSchristos 	struct wpas_dpp_listen_work *lwork;
624ebb5671cSchristos 
625ebb5671cSchristos 	if (wpa_s->dpp_listen_work) {
626ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
627ebb5671cSchristos 			   "DPP: Reject start_listen since dpp_listen_work already exists");
628ebb5671cSchristos 		return -1;
629ebb5671cSchristos 	}
630ebb5671cSchristos 
631ebb5671cSchristos 	if (wpa_s->dpp_listen_freq)
632ebb5671cSchristos 		wpas_dpp_listen_stop(wpa_s);
633ebb5671cSchristos 	wpa_s->dpp_listen_freq = freq;
634ebb5671cSchristos 
635ebb5671cSchristos 	lwork = os_zalloc(sizeof(*lwork));
636ebb5671cSchristos 	if (!lwork)
637ebb5671cSchristos 		return -1;
638ebb5671cSchristos 	lwork->freq = freq;
639ebb5671cSchristos 
640ebb5671cSchristos 	if (radio_add_work(wpa_s, freq, "dpp-listen", 0, dpp_start_listen_cb,
641ebb5671cSchristos 			   lwork) < 0) {
642ebb5671cSchristos 		wpas_dpp_listen_work_free(lwork);
643ebb5671cSchristos 		return -1;
644ebb5671cSchristos 	}
645ebb5671cSchristos 
646ebb5671cSchristos 	return 0;
647ebb5671cSchristos }
648ebb5671cSchristos 
649ebb5671cSchristos 
wpas_dpp_listen(struct wpa_supplicant * wpa_s,const char * cmd)650ebb5671cSchristos int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd)
651ebb5671cSchristos {
652ebb5671cSchristos 	int freq;
653ebb5671cSchristos 
654ebb5671cSchristos 	freq = atoi(cmd);
655ebb5671cSchristos 	if (freq <= 0)
656ebb5671cSchristos 		return -1;
657ebb5671cSchristos 
658ebb5671cSchristos 	if (os_strstr(cmd, " role=configurator"))
659ebb5671cSchristos 		wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR;
660ebb5671cSchristos 	else if (os_strstr(cmd, " role=enrollee"))
661ebb5671cSchristos 		wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
662ebb5671cSchristos 	else
663ebb5671cSchristos 		wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
664ebb5671cSchristos 			DPP_CAPAB_ENROLLEE;
665ebb5671cSchristos 	wpa_s->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
666ebb5671cSchristos 	wpa_s->dpp_netrole_ap = os_strstr(cmd, " netrole=ap") != NULL;
667ebb5671cSchristos 	if (wpa_s->dpp_listen_freq == (unsigned int) freq) {
668ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz",
669ebb5671cSchristos 			   freq);
670ebb5671cSchristos 		return 0;
671ebb5671cSchristos 	}
672ebb5671cSchristos 
673ebb5671cSchristos 	return wpas_dpp_listen_start(wpa_s, freq);
674ebb5671cSchristos }
675ebb5671cSchristos 
676ebb5671cSchristos 
wpas_dpp_listen_stop(struct wpa_supplicant * wpa_s)677ebb5671cSchristos void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s)
678ebb5671cSchristos {
679ebb5671cSchristos 	wpa_s->dpp_in_response_listen = 0;
680ebb5671cSchristos 	if (!wpa_s->dpp_listen_freq)
681ebb5671cSchristos 		return;
682ebb5671cSchristos 
683ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: Stop listen on %u MHz",
684ebb5671cSchristos 		   wpa_s->dpp_listen_freq);
685ebb5671cSchristos 	wpa_drv_cancel_remain_on_channel(wpa_s);
686ebb5671cSchristos 	wpa_s->dpp_listen_freq = 0;
687ebb5671cSchristos 	wpas_dpp_listen_work_done(wpa_s);
688ebb5671cSchristos }
689ebb5671cSchristos 
690ebb5671cSchristos 
wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant * wpa_s,unsigned int freq)691ebb5671cSchristos void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
692ebb5671cSchristos 					  unsigned int freq)
693ebb5671cSchristos {
694ebb5671cSchristos 	wpas_dpp_listen_work_done(wpa_s);
695ebb5671cSchristos 
696ebb5671cSchristos 	if (wpa_s->dpp_auth && wpa_s->dpp_in_response_listen) {
697ebb5671cSchristos 		unsigned int new_freq;
698ebb5671cSchristos 
699ebb5671cSchristos 		/* Continue listen with a new remain-on-channel */
700ebb5671cSchristos 		if (wpa_s->dpp_auth->neg_freq > 0)
701ebb5671cSchristos 			new_freq = wpa_s->dpp_auth->neg_freq;
702ebb5671cSchristos 		else
703ebb5671cSchristos 			new_freq = wpa_s->dpp_auth->curr_freq;
704ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
705ebb5671cSchristos 			   "DPP: Continue wait on %u MHz for the ongoing DPP provisioning session",
706ebb5671cSchristos 			   new_freq);
707ebb5671cSchristos 		wpas_dpp_listen_start(wpa_s, new_freq);
708ebb5671cSchristos 		return;
709ebb5671cSchristos 	}
710ebb5671cSchristos 
711ebb5671cSchristos 	if (wpa_s->dpp_listen_freq) {
712ebb5671cSchristos 		/* Continue listen with a new remain-on-channel */
713ebb5671cSchristos 		wpas_dpp_listen_start(wpa_s, wpa_s->dpp_listen_freq);
714ebb5671cSchristos 	}
715ebb5671cSchristos }
716ebb5671cSchristos 
717ebb5671cSchristos 
wpas_dpp_rx_auth_req(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq)718ebb5671cSchristos static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
719ebb5671cSchristos 				 const u8 *hdr, const u8 *buf, size_t len,
720ebb5671cSchristos 				 unsigned int freq)
721ebb5671cSchristos {
722ebb5671cSchristos 	const u8 *r_bootstrap, *i_bootstrap;
723ebb5671cSchristos 	u16 r_bootstrap_len, i_bootstrap_len;
724*0d69f216Schristos 	struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
725*0d69f216Schristos 
726*0d69f216Schristos 	if (!wpa_s->dpp)
727*0d69f216Schristos 		return;
728ebb5671cSchristos 
729ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
730ebb5671cSchristos 		   MAC2STR(src));
731ebb5671cSchristos 
732ebb5671cSchristos 	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
733ebb5671cSchristos 				   &r_bootstrap_len);
734ebb5671cSchristos 	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
735ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
736ebb5671cSchristos 			"Missing or invalid required Responder Bootstrapping Key Hash attribute");
737ebb5671cSchristos 		return;
738ebb5671cSchristos 	}
739ebb5671cSchristos 	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
740ebb5671cSchristos 		    r_bootstrap, r_bootstrap_len);
741ebb5671cSchristos 
742ebb5671cSchristos 	i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
743ebb5671cSchristos 				   &i_bootstrap_len);
744ebb5671cSchristos 	if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
745ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
746ebb5671cSchristos 			"Missing or invalid required Initiator Bootstrapping Key Hash attribute");
747ebb5671cSchristos 		return;
748ebb5671cSchristos 	}
749ebb5671cSchristos 	wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
750ebb5671cSchristos 		    i_bootstrap, i_bootstrap_len);
751ebb5671cSchristos 
752ebb5671cSchristos 	/* Try to find own and peer bootstrapping key matches based on the
753ebb5671cSchristos 	 * received hash values */
754*0d69f216Schristos 	dpp_bootstrap_find_pair(wpa_s->dpp, i_bootstrap, r_bootstrap,
755*0d69f216Schristos 				&own_bi, &peer_bi);
756ebb5671cSchristos 	if (!own_bi) {
757ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
758ebb5671cSchristos 			"No matching own bootstrapping key found - ignore message");
759ebb5671cSchristos 		return;
760ebb5671cSchristos 	}
761ebb5671cSchristos 
762ebb5671cSchristos 	if (wpa_s->dpp_auth) {
763ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
764ebb5671cSchristos 			"Already in DPP authentication exchange - ignore new one");
765ebb5671cSchristos 		return;
766ebb5671cSchristos 	}
767ebb5671cSchristos 
768ebb5671cSchristos 	wpa_s->dpp_gas_client = 0;
769ebb5671cSchristos 	wpa_s->dpp_auth_ok_on_ack = 0;
770ebb5671cSchristos 	wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s, wpa_s->dpp_allowed_roles,
771ebb5671cSchristos 					  wpa_s->dpp_qr_mutual,
772ebb5671cSchristos 					  peer_bi, own_bi, freq, hdr, buf, len);
773ebb5671cSchristos 	if (!wpa_s->dpp_auth) {
774ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: No response generated");
775ebb5671cSchristos 		return;
776ebb5671cSchristos 	}
777ebb5671cSchristos 	wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
778*0d69f216Schristos 	if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth,
779ebb5671cSchristos 				 wpa_s->dpp_configurator_params) < 0) {
780ebb5671cSchristos 		dpp_auth_deinit(wpa_s->dpp_auth);
781ebb5671cSchristos 		wpa_s->dpp_auth = NULL;
782ebb5671cSchristos 		return;
783ebb5671cSchristos 	}
784ebb5671cSchristos 	os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN);
785ebb5671cSchristos 
786ebb5671cSchristos 	if (wpa_s->dpp_listen_freq &&
787ebb5671cSchristos 	    wpa_s->dpp_listen_freq != wpa_s->dpp_auth->curr_freq) {
788ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
789ebb5671cSchristos 			   "DPP: Stop listen on %u MHz to allow response on the request %u MHz",
790ebb5671cSchristos 			   wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq);
791ebb5671cSchristos 		wpas_dpp_listen_stop(wpa_s);
792ebb5671cSchristos 	}
793ebb5671cSchristos 
794ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
795ebb5671cSchristos 		MAC2STR(src), wpa_s->dpp_auth->curr_freq,
796ebb5671cSchristos 		DPP_PA_AUTHENTICATION_RESP);
797ebb5671cSchristos 	offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq,
798ebb5671cSchristos 			       src, wpa_s->own_addr, broadcast,
799ebb5671cSchristos 			       wpabuf_head(wpa_s->dpp_auth->resp_msg),
800ebb5671cSchristos 			       wpabuf_len(wpa_s->dpp_auth->resp_msg),
801ebb5671cSchristos 			       500, wpas_dpp_tx_status, 0);
802ebb5671cSchristos }
803ebb5671cSchristos 
804ebb5671cSchristos 
wpas_dpp_start_gas_server(struct wpa_supplicant * wpa_s)805ebb5671cSchristos static void wpas_dpp_start_gas_server(struct wpa_supplicant *wpa_s)
806ebb5671cSchristos {
807ebb5671cSchristos 	/* TODO: stop wait and start ROC */
808ebb5671cSchristos }
809ebb5671cSchristos 
810ebb5671cSchristos 
wpas_dpp_add_network(struct wpa_supplicant * wpa_s,struct dpp_authentication * auth)811ebb5671cSchristos static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
812ebb5671cSchristos 					      struct dpp_authentication *auth)
813ebb5671cSchristos {
814ebb5671cSchristos 	struct wpa_ssid *ssid;
815ebb5671cSchristos 
816*0d69f216Schristos #ifdef CONFIG_DPP2
817*0d69f216Schristos 	if (auth->akm == DPP_AKM_SAE) {
818*0d69f216Schristos #ifdef CONFIG_SAE
819*0d69f216Schristos 		struct wpa_driver_capa capa;
820*0d69f216Schristos 		int res;
821*0d69f216Schristos 
822*0d69f216Schristos 		res = wpa_drv_get_capa(wpa_s, &capa);
823*0d69f216Schristos 		if (res == 0 &&
824*0d69f216Schristos 		    !(capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
825*0d69f216Schristos 		    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
826*0d69f216Schristos 			wpa_printf(MSG_DEBUG,
827*0d69f216Schristos 				   "DPP: SAE not supported by the driver");
828*0d69f216Schristos 			return NULL;
829*0d69f216Schristos 		}
830*0d69f216Schristos #else /* CONFIG_SAE */
831*0d69f216Schristos 		wpa_printf(MSG_DEBUG, "DPP: SAE not supported in the build");
832*0d69f216Schristos 		return NULL;
833*0d69f216Schristos #endif /* CONFIG_SAE */
834*0d69f216Schristos 	}
835*0d69f216Schristos #endif /* CONFIG_DPP2 */
836*0d69f216Schristos 
837ebb5671cSchristos 	ssid = wpa_config_add_network(wpa_s->conf);
838ebb5671cSchristos 	if (!ssid)
839ebb5671cSchristos 		return NULL;
840ebb5671cSchristos 	wpas_notify_network_added(wpa_s, ssid);
841ebb5671cSchristos 	wpa_config_set_network_defaults(ssid);
842ebb5671cSchristos 	ssid->disabled = 1;
843ebb5671cSchristos 
844ebb5671cSchristos 	ssid->ssid = os_malloc(auth->ssid_len);
845ebb5671cSchristos 	if (!ssid->ssid)
846ebb5671cSchristos 		goto fail;
847ebb5671cSchristos 	os_memcpy(ssid->ssid, auth->ssid, auth->ssid_len);
848ebb5671cSchristos 	ssid->ssid_len = auth->ssid_len;
849ebb5671cSchristos 
850ebb5671cSchristos 	if (auth->connector) {
851ebb5671cSchristos 		ssid->key_mgmt = WPA_KEY_MGMT_DPP;
852ebb5671cSchristos 		ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
853ebb5671cSchristos 		ssid->dpp_connector = os_strdup(auth->connector);
854ebb5671cSchristos 		if (!ssid->dpp_connector)
855ebb5671cSchristos 			goto fail;
856ebb5671cSchristos 	}
857ebb5671cSchristos 
858ebb5671cSchristos 	if (auth->c_sign_key) {
859ebb5671cSchristos 		ssid->dpp_csign = os_malloc(wpabuf_len(auth->c_sign_key));
860ebb5671cSchristos 		if (!ssid->dpp_csign)
861ebb5671cSchristos 			goto fail;
862ebb5671cSchristos 		os_memcpy(ssid->dpp_csign, wpabuf_head(auth->c_sign_key),
863ebb5671cSchristos 			  wpabuf_len(auth->c_sign_key));
864ebb5671cSchristos 		ssid->dpp_csign_len = wpabuf_len(auth->c_sign_key);
865ebb5671cSchristos 	}
866ebb5671cSchristos 
867ebb5671cSchristos 	if (auth->net_access_key) {
868ebb5671cSchristos 		ssid->dpp_netaccesskey =
869ebb5671cSchristos 			os_malloc(wpabuf_len(auth->net_access_key));
870ebb5671cSchristos 		if (!ssid->dpp_netaccesskey)
871ebb5671cSchristos 			goto fail;
872ebb5671cSchristos 		os_memcpy(ssid->dpp_netaccesskey,
873ebb5671cSchristos 			  wpabuf_head(auth->net_access_key),
874ebb5671cSchristos 			  wpabuf_len(auth->net_access_key));
875ebb5671cSchristos 		ssid->dpp_netaccesskey_len = wpabuf_len(auth->net_access_key);
876ebb5671cSchristos 		ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
877ebb5671cSchristos 	}
878ebb5671cSchristos 
879*0d69f216Schristos 	if (!auth->connector || dpp_akm_psk(auth->akm) ||
880*0d69f216Schristos 	    dpp_akm_sae(auth->akm)) {
881*0d69f216Schristos 		if (!auth->connector)
882ebb5671cSchristos 			ssid->key_mgmt = 0;
883*0d69f216Schristos 		if (dpp_akm_psk(auth->akm))
884ebb5671cSchristos 			ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
885ebb5671cSchristos 				WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
886*0d69f216Schristos 		if (dpp_akm_sae(auth->akm))
887ebb5671cSchristos 			ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
888ebb5671cSchristos 				WPA_KEY_MGMT_FT_SAE;
889ebb5671cSchristos 		ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
890ebb5671cSchristos 		if (auth->passphrase[0]) {
891ebb5671cSchristos 			if (wpa_config_set_quoted(ssid, "psk",
892ebb5671cSchristos 						  auth->passphrase) < 0)
893ebb5671cSchristos 				goto fail;
894ebb5671cSchristos 			wpa_config_update_psk(ssid);
895ebb5671cSchristos 			ssid->export_keys = 1;
896ebb5671cSchristos 		} else {
897ebb5671cSchristos 			ssid->psk_set = auth->psk_set;
898ebb5671cSchristos 			os_memcpy(ssid->psk, auth->psk, PMK_LEN);
899ebb5671cSchristos 		}
900ebb5671cSchristos 	}
901ebb5671cSchristos 
902ebb5671cSchristos 	return ssid;
903ebb5671cSchristos fail:
904ebb5671cSchristos 	wpas_notify_network_removed(wpa_s, ssid);
905ebb5671cSchristos 	wpa_config_remove_network(wpa_s->conf, ssid->id);
906ebb5671cSchristos 	return NULL;
907ebb5671cSchristos }
908ebb5671cSchristos 
909ebb5671cSchristos 
wpas_dpp_process_config(struct wpa_supplicant * wpa_s,struct dpp_authentication * auth)910*0d69f216Schristos static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
911ebb5671cSchristos 				   struct dpp_authentication *auth)
912ebb5671cSchristos {
913ebb5671cSchristos 	struct wpa_ssid *ssid;
914ebb5671cSchristos 
915ebb5671cSchristos 	if (wpa_s->conf->dpp_config_processing < 1)
916*0d69f216Schristos 		return 0;
917ebb5671cSchristos 
918ebb5671cSchristos 	ssid = wpas_dpp_add_network(wpa_s, auth);
919ebb5671cSchristos 	if (!ssid)
920*0d69f216Schristos 		return -1;
921ebb5671cSchristos 
922ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id);
923*0d69f216Schristos 	if (wpa_s->conf->dpp_config_processing == 2)
924ebb5671cSchristos 		ssid->disabled = 0;
925*0d69f216Schristos 
926*0d69f216Schristos #ifndef CONFIG_NO_CONFIG_WRITE
927*0d69f216Schristos 	if (wpa_s->conf->update_config &&
928*0d69f216Schristos 	    wpa_config_write(wpa_s->confname, wpa_s->conf))
929*0d69f216Schristos 		wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration");
930*0d69f216Schristos #endif /* CONFIG_NO_CONFIG_WRITE */
931*0d69f216Schristos 
932*0d69f216Schristos 	if (wpa_s->conf->dpp_config_processing < 2)
933*0d69f216Schristos 		return 0;
934*0d69f216Schristos 
935*0d69f216Schristos #ifdef CONFIG_DPP2
936*0d69f216Schristos 	if (auth->peer_version >= 2) {
937*0d69f216Schristos 		wpa_printf(MSG_DEBUG,
938*0d69f216Schristos 			   "DPP: Postpone connection attempt to wait for completion of DPP Configuration Result");
939*0d69f216Schristos 		auth->connect_on_tx_status = 1;
940*0d69f216Schristos 		return 0;
941*0d69f216Schristos 	}
942*0d69f216Schristos #endif /* CONFIG_DPP2 */
943*0d69f216Schristos 
944*0d69f216Schristos 	wpas_dpp_try_to_connect(wpa_s);
945*0d69f216Schristos 	return 0;
946ebb5671cSchristos }
947ebb5671cSchristos 
948ebb5671cSchristos 
wpas_dpp_handle_config_obj(struct wpa_supplicant * wpa_s,struct dpp_authentication * auth)949*0d69f216Schristos static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
950ebb5671cSchristos 				      struct dpp_authentication *auth)
951ebb5671cSchristos {
952ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
953ebb5671cSchristos 	if (auth->ssid_len)
954ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
955ebb5671cSchristos 			wpa_ssid_txt(auth->ssid, auth->ssid_len));
956ebb5671cSchristos 	if (auth->connector) {
957ebb5671cSchristos 		/* TODO: Save the Connector and consider using a command
958ebb5671cSchristos 		 * to fetch the value instead of sending an event with
959ebb5671cSchristos 		 * it. The Connector could end up being larger than what
960ebb5671cSchristos 		 * most clients are ready to receive as an event
961ebb5671cSchristos 		 * message. */
962ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
963ebb5671cSchristos 			auth->connector);
964ebb5671cSchristos 	}
965ebb5671cSchristos 	if (auth->c_sign_key) {
966ebb5671cSchristos 		char *hex;
967ebb5671cSchristos 		size_t hexlen;
968ebb5671cSchristos 
969ebb5671cSchristos 		hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
970ebb5671cSchristos 		hex = os_malloc(hexlen);
971ebb5671cSchristos 		if (hex) {
972ebb5671cSchristos 			wpa_snprintf_hex(hex, hexlen,
973ebb5671cSchristos 					 wpabuf_head(auth->c_sign_key),
974ebb5671cSchristos 					 wpabuf_len(auth->c_sign_key));
975ebb5671cSchristos 			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s",
976ebb5671cSchristos 				hex);
977ebb5671cSchristos 			os_free(hex);
978ebb5671cSchristos 		}
979ebb5671cSchristos 	}
980ebb5671cSchristos 	if (auth->net_access_key) {
981ebb5671cSchristos 		char *hex;
982ebb5671cSchristos 		size_t hexlen;
983ebb5671cSchristos 
984ebb5671cSchristos 		hexlen = 2 * wpabuf_len(auth->net_access_key) + 1;
985ebb5671cSchristos 		hex = os_malloc(hexlen);
986ebb5671cSchristos 		if (hex) {
987ebb5671cSchristos 			wpa_snprintf_hex(hex, hexlen,
988ebb5671cSchristos 					 wpabuf_head(auth->net_access_key),
989ebb5671cSchristos 					 wpabuf_len(auth->net_access_key));
990ebb5671cSchristos 			if (auth->net_access_key_expiry)
991ebb5671cSchristos 				wpa_msg(wpa_s, MSG_INFO,
992ebb5671cSchristos 					DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex,
993ebb5671cSchristos 					(long unsigned)
994ebb5671cSchristos 					auth->net_access_key_expiry);
995ebb5671cSchristos 			else
996ebb5671cSchristos 				wpa_msg(wpa_s, MSG_INFO,
997ebb5671cSchristos 					DPP_EVENT_NET_ACCESS_KEY "%s", hex);
998ebb5671cSchristos 			os_free(hex);
999ebb5671cSchristos 		}
1000ebb5671cSchristos 	}
1001ebb5671cSchristos 
1002*0d69f216Schristos 	return wpas_dpp_process_config(wpa_s, auth);
1003ebb5671cSchristos }
1004ebb5671cSchristos 
1005ebb5671cSchristos 
wpas_dpp_gas_resp_cb(void * ctx,const u8 * addr,u8 dialog_token,enum gas_query_result result,const struct wpabuf * adv_proto,const struct wpabuf * resp,u16 status_code)1006ebb5671cSchristos static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
1007ebb5671cSchristos 				 enum gas_query_result result,
1008ebb5671cSchristos 				 const struct wpabuf *adv_proto,
1009ebb5671cSchristos 				 const struct wpabuf *resp, u16 status_code)
1010ebb5671cSchristos {
1011ebb5671cSchristos 	struct wpa_supplicant *wpa_s = ctx;
1012ebb5671cSchristos 	const u8 *pos;
1013ebb5671cSchristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
1014*0d69f216Schristos 	int res;
1015*0d69f216Schristos 	enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
1016ebb5671cSchristos 
1017ebb5671cSchristos 	wpa_s->dpp_gas_dialog_token = -1;
1018ebb5671cSchristos 
1019ebb5671cSchristos 	if (!auth || !auth->auth_success) {
1020ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
1021ebb5671cSchristos 		return;
1022ebb5671cSchristos 	}
1023ebb5671cSchristos 	if (result != GAS_QUERY_SUCCESS ||
1024ebb5671cSchristos 	    !resp || status_code != WLAN_STATUS_SUCCESS) {
1025ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
1026ebb5671cSchristos 		goto fail;
1027ebb5671cSchristos 	}
1028ebb5671cSchristos 
1029ebb5671cSchristos 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
1030ebb5671cSchristos 			adv_proto);
1031ebb5671cSchristos 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
1032ebb5671cSchristos 			resp);
1033ebb5671cSchristos 
1034ebb5671cSchristos 	if (wpabuf_len(adv_proto) != 10 ||
1035ebb5671cSchristos 	    !(pos = wpabuf_head(adv_proto)) ||
1036ebb5671cSchristos 	    pos[0] != WLAN_EID_ADV_PROTO ||
1037ebb5671cSchristos 	    pos[1] != 8 ||
1038ebb5671cSchristos 	    pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
1039ebb5671cSchristos 	    pos[4] != 5 ||
1040ebb5671cSchristos 	    WPA_GET_BE24(&pos[5]) != OUI_WFA ||
1041ebb5671cSchristos 	    pos[8] != 0x1a ||
1042ebb5671cSchristos 	    pos[9] != 1) {
1043ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1044ebb5671cSchristos 			   "DPP: Not a DPP Advertisement Protocol ID");
1045ebb5671cSchristos 		goto fail;
1046ebb5671cSchristos 	}
1047ebb5671cSchristos 
1048ebb5671cSchristos 	if (dpp_conf_resp_rx(auth, resp) < 0) {
1049ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
1050ebb5671cSchristos 		goto fail;
1051ebb5671cSchristos 	}
1052ebb5671cSchristos 
1053*0d69f216Schristos 	res = wpas_dpp_handle_config_obj(wpa_s, auth);
1054*0d69f216Schristos 	if (res < 0)
1055*0d69f216Schristos 		goto fail;
1056ebb5671cSchristos 
1057*0d69f216Schristos 	status = DPP_STATUS_OK;
1058*0d69f216Schristos #ifdef CONFIG_TESTING_OPTIONS
1059*0d69f216Schristos 	if (dpp_test == DPP_TEST_REJECT_CONFIG) {
1060*0d69f216Schristos 		wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
1061*0d69f216Schristos 		status = DPP_STATUS_CONFIG_REJECTED;
1062*0d69f216Schristos 	}
1063*0d69f216Schristos #endif /* CONFIG_TESTING_OPTIONS */
1064ebb5671cSchristos fail:
1065*0d69f216Schristos 	if (status != DPP_STATUS_OK)
1066ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
1067*0d69f216Schristos #ifdef CONFIG_DPP2
1068*0d69f216Schristos 	if (auth->peer_version >= 2 &&
1069*0d69f216Schristos 	    auth->conf_resp_status == DPP_STATUS_OK) {
1070*0d69f216Schristos 		struct wpabuf *msg;
1071*0d69f216Schristos 
1072*0d69f216Schristos 		wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
1073*0d69f216Schristos 		msg = dpp_build_conf_result(auth, status);
1074*0d69f216Schristos 		if (!msg)
1075*0d69f216Schristos 			goto fail2;
1076*0d69f216Schristos 
1077*0d69f216Schristos 		wpa_msg(wpa_s, MSG_INFO,
1078*0d69f216Schristos 			DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
1079*0d69f216Schristos 			MAC2STR(addr), auth->curr_freq,
1080*0d69f216Schristos 			DPP_PA_CONFIGURATION_RESULT);
1081*0d69f216Schristos 		offchannel_send_action(wpa_s, auth->curr_freq,
1082*0d69f216Schristos 				       addr, wpa_s->own_addr, broadcast,
1083*0d69f216Schristos 				       wpabuf_head(msg),
1084*0d69f216Schristos 				       wpabuf_len(msg),
1085*0d69f216Schristos 				       500, wpas_dpp_tx_status, 0);
1086*0d69f216Schristos 		wpabuf_free(msg);
1087*0d69f216Schristos 
1088*0d69f216Schristos 		/* This exchange will be terminated in the TX status handler */
1089*0d69f216Schristos 		return;
1090*0d69f216Schristos 	}
1091*0d69f216Schristos fail2:
1092*0d69f216Schristos #endif /* CONFIG_DPP2 */
1093ebb5671cSchristos 	dpp_auth_deinit(wpa_s->dpp_auth);
1094ebb5671cSchristos 	wpa_s->dpp_auth = NULL;
1095ebb5671cSchristos }
1096ebb5671cSchristos 
1097ebb5671cSchristos 
wpas_dpp_start_gas_client(struct wpa_supplicant * wpa_s)1098ebb5671cSchristos static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s)
1099ebb5671cSchristos {
1100ebb5671cSchristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
1101*0d69f216Schristos 	struct wpabuf *buf;
1102ebb5671cSchristos 	char json[100];
1103ebb5671cSchristos 	int res;
1104ebb5671cSchristos 
1105ebb5671cSchristos 	wpa_s->dpp_gas_client = 1;
1106ebb5671cSchristos 	os_snprintf(json, sizeof(json),
1107ebb5671cSchristos 		    "{\"name\":\"Test\","
1108ebb5671cSchristos 		    "\"wi-fi_tech\":\"infra\","
1109ebb5671cSchristos 		    "\"netRole\":\"%s\"}",
1110ebb5671cSchristos 		    wpa_s->dpp_netrole_ap ? "ap" : "sta");
1111ebb5671cSchristos #ifdef CONFIG_TESTING_OPTIONS
1112ebb5671cSchristos 	if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
1113ebb5671cSchristos 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
1114ebb5671cSchristos 		json[29] = 'k'; /* replace "infra" with "knfra" */
1115ebb5671cSchristos 	}
1116ebb5671cSchristos #endif /* CONFIG_TESTING_OPTIONS */
1117ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
1118ebb5671cSchristos 
1119ebb5671cSchristos 	offchannel_send_action_done(wpa_s);
1120ebb5671cSchristos 	wpas_dpp_listen_stop(wpa_s);
1121ebb5671cSchristos 
1122*0d69f216Schristos 	buf = dpp_build_conf_req(auth, json);
1123*0d69f216Schristos 	if (!buf) {
1124ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1125ebb5671cSchristos 			   "DPP: No configuration request data available");
1126ebb5671cSchristos 		return;
1127ebb5671cSchristos 	}
1128ebb5671cSchristos 
1129ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
1130ebb5671cSchristos 		   MAC2STR(auth->peer_mac_addr), auth->curr_freq);
1131ebb5671cSchristos 
1132ebb5671cSchristos 	res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq,
1133ebb5671cSchristos 			    1, buf, wpas_dpp_gas_resp_cb, wpa_s);
1134ebb5671cSchristos 	if (res < 0) {
1135ebb5671cSchristos 		wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
1136ebb5671cSchristos 		wpabuf_free(buf);
1137ebb5671cSchristos 	} else {
1138ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1139ebb5671cSchristos 			   "DPP: GAS query started with dialog token %u", res);
1140ebb5671cSchristos 		wpa_s->dpp_gas_dialog_token = res;
1141ebb5671cSchristos 	}
1142ebb5671cSchristos }
1143ebb5671cSchristos 
1144ebb5671cSchristos 
wpas_dpp_auth_success(struct wpa_supplicant * wpa_s,int initiator)1145ebb5671cSchristos static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator)
1146ebb5671cSchristos {
1147ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
1148ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
1149ebb5671cSchristos #ifdef CONFIG_TESTING_OPTIONS
1150ebb5671cSchristos 	if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
1151ebb5671cSchristos 		wpa_printf(MSG_INFO,
1152ebb5671cSchristos 			   "DPP: TESTING - stop at Authentication Confirm");
1153ebb5671cSchristos 		if (wpa_s->dpp_auth->configurator) {
1154ebb5671cSchristos 			/* Prevent GAS response */
1155ebb5671cSchristos 			wpa_s->dpp_auth->auth_success = 0;
1156ebb5671cSchristos 		}
1157ebb5671cSchristos 		return;
1158ebb5671cSchristos 	}
1159ebb5671cSchristos #endif /* CONFIG_TESTING_OPTIONS */
1160ebb5671cSchristos 
1161ebb5671cSchristos 	if (wpa_s->dpp_auth->configurator)
1162ebb5671cSchristos 		wpas_dpp_start_gas_server(wpa_s);
1163ebb5671cSchristos 	else
1164ebb5671cSchristos 		wpas_dpp_start_gas_client(wpa_s);
1165ebb5671cSchristos }
1166ebb5671cSchristos 
1167ebb5671cSchristos 
wpas_dpp_rx_auth_resp(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq)1168ebb5671cSchristos static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
1169ebb5671cSchristos 				  const u8 *hdr, const u8 *buf, size_t len,
1170ebb5671cSchristos 				  unsigned int freq)
1171ebb5671cSchristos {
1172ebb5671cSchristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
1173ebb5671cSchristos 	struct wpabuf *msg;
1174ebb5671cSchristos 
1175ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR
1176ebb5671cSchristos 		   " (freq %u MHz)", MAC2STR(src), freq);
1177ebb5671cSchristos 
1178ebb5671cSchristos 	if (!auth) {
1179ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1180ebb5671cSchristos 			   "DPP: No DPP Authentication in progress - drop");
1181ebb5671cSchristos 		return;
1182ebb5671cSchristos 	}
1183ebb5671cSchristos 
1184ebb5671cSchristos 	if (!is_zero_ether_addr(auth->peer_mac_addr) &&
1185ebb5671cSchristos 	    os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
1186ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
1187ebb5671cSchristos 			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
1188ebb5671cSchristos 		return;
1189ebb5671cSchristos 	}
1190ebb5671cSchristos 
1191ebb5671cSchristos 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
1192ebb5671cSchristos 
1193ebb5671cSchristos 	if (auth->curr_freq != freq && auth->neg_freq == freq) {
1194ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1195ebb5671cSchristos 			   "DPP: Responder accepted request for different negotiation channel");
1196ebb5671cSchristos 		auth->curr_freq = freq;
1197ebb5671cSchristos 	}
1198ebb5671cSchristos 
1199ebb5671cSchristos 	eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
1200ebb5671cSchristos 	msg = dpp_auth_resp_rx(auth, hdr, buf, len);
1201ebb5671cSchristos 	if (!msg) {
1202ebb5671cSchristos 		if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
1203ebb5671cSchristos 			wpa_printf(MSG_DEBUG,
1204ebb5671cSchristos 				   "DPP: Start wait for full response");
1205ebb5671cSchristos 			offchannel_send_action_done(wpa_s);
1206ebb5671cSchristos 			wpas_dpp_listen_start(wpa_s, auth->curr_freq);
1207ebb5671cSchristos 			return;
1208ebb5671cSchristos 		}
1209ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
1210ebb5671cSchristos 		return;
1211ebb5671cSchristos 	}
1212ebb5671cSchristos 	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
1213ebb5671cSchristos 
1214ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
1215ebb5671cSchristos 		MAC2STR(src), auth->curr_freq, DPP_PA_AUTHENTICATION_CONF);
1216ebb5671cSchristos 	offchannel_send_action(wpa_s, auth->curr_freq,
1217ebb5671cSchristos 			       src, wpa_s->own_addr, broadcast,
1218ebb5671cSchristos 			       wpabuf_head(msg), wpabuf_len(msg),
1219ebb5671cSchristos 			       500, wpas_dpp_tx_status, 0);
1220ebb5671cSchristos 	wpabuf_free(msg);
1221ebb5671cSchristos 	wpa_s->dpp_auth_ok_on_ack = 1;
1222ebb5671cSchristos }
1223ebb5671cSchristos 
1224ebb5671cSchristos 
wpas_dpp_rx_auth_conf(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len)1225ebb5671cSchristos static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
1226ebb5671cSchristos 				  const u8 *hdr, const u8 *buf, size_t len)
1227ebb5671cSchristos {
1228ebb5671cSchristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
1229ebb5671cSchristos 
1230ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
1231ebb5671cSchristos 		   MAC2STR(src));
1232ebb5671cSchristos 
1233ebb5671cSchristos 	if (!auth) {
1234ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1235ebb5671cSchristos 			   "DPP: No DPP Authentication in progress - drop");
1236ebb5671cSchristos 		return;
1237ebb5671cSchristos 	}
1238ebb5671cSchristos 
1239ebb5671cSchristos 	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
1240ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
1241ebb5671cSchristos 			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
1242ebb5671cSchristos 		return;
1243ebb5671cSchristos 	}
1244ebb5671cSchristos 
1245ebb5671cSchristos 	if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
1246ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
1247ebb5671cSchristos 		return;
1248ebb5671cSchristos 	}
1249ebb5671cSchristos 
1250ebb5671cSchristos 	wpas_dpp_auth_success(wpa_s, 0);
1251ebb5671cSchristos }
1252ebb5671cSchristos 
1253ebb5671cSchristos 
1254*0d69f216Schristos #ifdef CONFIG_DPP2
1255*0d69f216Schristos 
wpas_dpp_config_result_wait_timeout(void * eloop_ctx,void * timeout_ctx)1256*0d69f216Schristos static void wpas_dpp_config_result_wait_timeout(void *eloop_ctx,
1257*0d69f216Schristos 						void *timeout_ctx)
1258*0d69f216Schristos {
1259*0d69f216Schristos 	struct wpa_supplicant *wpa_s = eloop_ctx;
1260*0d69f216Schristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
1261*0d69f216Schristos 
1262*0d69f216Schristos 	if (!auth || !auth->waiting_conf_result)
1263*0d69f216Schristos 		return;
1264*0d69f216Schristos 
1265*0d69f216Schristos 	wpa_printf(MSG_DEBUG,
1266*0d69f216Schristos 		   "DPP: Timeout while waiting for Configuration Result");
1267*0d69f216Schristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
1268*0d69f216Schristos 	dpp_auth_deinit(auth);
1269*0d69f216Schristos 	wpa_s->dpp_auth = NULL;
1270*0d69f216Schristos }
1271*0d69f216Schristos 
1272*0d69f216Schristos 
wpas_dpp_rx_conf_result(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len)1273*0d69f216Schristos static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
1274*0d69f216Schristos 				    const u8 *hdr, const u8 *buf, size_t len)
1275*0d69f216Schristos {
1276*0d69f216Schristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
1277*0d69f216Schristos 	enum dpp_status_error status;
1278*0d69f216Schristos 
1279*0d69f216Schristos 	wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
1280*0d69f216Schristos 		   MAC2STR(src));
1281*0d69f216Schristos 
1282*0d69f216Schristos 	if (!auth || !auth->waiting_conf_result) {
1283*0d69f216Schristos 		wpa_printf(MSG_DEBUG,
1284*0d69f216Schristos 			   "DPP: No DPP Configuration waiting for result - drop");
1285*0d69f216Schristos 		return;
1286*0d69f216Schristos 	}
1287*0d69f216Schristos 
1288*0d69f216Schristos 	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
1289*0d69f216Schristos 		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
1290*0d69f216Schristos 			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
1291*0d69f216Schristos 		return;
1292*0d69f216Schristos 	}
1293*0d69f216Schristos 
1294*0d69f216Schristos 	status = dpp_conf_result_rx(auth, hdr, buf, len);
1295*0d69f216Schristos 
1296*0d69f216Schristos 	offchannel_send_action_done(wpa_s);
1297*0d69f216Schristos 	wpas_dpp_listen_stop(wpa_s);
1298*0d69f216Schristos 	if (status == DPP_STATUS_OK)
1299*0d69f216Schristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
1300*0d69f216Schristos 	else
1301*0d69f216Schristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
1302*0d69f216Schristos 	dpp_auth_deinit(auth);
1303*0d69f216Schristos 	wpa_s->dpp_auth = NULL;
1304*0d69f216Schristos 	eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
1305*0d69f216Schristos }
1306*0d69f216Schristos 
1307*0d69f216Schristos 
wpas_dpp_process_conf_obj(void * ctx,struct dpp_authentication * auth)1308*0d69f216Schristos static int wpas_dpp_process_conf_obj(void *ctx,
1309*0d69f216Schristos 				     struct dpp_authentication *auth)
1310*0d69f216Schristos {
1311*0d69f216Schristos 	struct wpa_supplicant *wpa_s = ctx;
1312*0d69f216Schristos 
1313*0d69f216Schristos 	return wpas_dpp_handle_config_obj(wpa_s, auth);
1314*0d69f216Schristos }
1315*0d69f216Schristos 
1316*0d69f216Schristos #endif /* CONFIG_DPP2 */
1317*0d69f216Schristos 
1318*0d69f216Schristos 
wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * buf,size_t len)1319ebb5671cSchristos static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
1320ebb5671cSchristos 				       const u8 *src,
1321ebb5671cSchristos 				       const u8 *buf, size_t len)
1322ebb5671cSchristos {
1323ebb5671cSchristos 	struct wpa_ssid *ssid;
1324ebb5671cSchristos 	const u8 *connector, *trans_id, *status;
1325ebb5671cSchristos 	u16 connector_len, trans_id_len, status_len;
1326ebb5671cSchristos 	struct dpp_introduction intro;
1327ebb5671cSchristos 	struct rsn_pmksa_cache_entry *entry;
1328ebb5671cSchristos 	struct os_time now;
1329ebb5671cSchristos 	struct os_reltime rnow;
1330ebb5671cSchristos 	os_time_t expiry;
1331ebb5671cSchristos 	unsigned int seconds;
1332ebb5671cSchristos 	enum dpp_status_error res;
1333ebb5671cSchristos 
1334ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Response from " MACSTR,
1335ebb5671cSchristos 		   MAC2STR(src));
1336ebb5671cSchristos 	if (is_zero_ether_addr(wpa_s->dpp_intro_bssid) ||
1337ebb5671cSchristos 	    os_memcmp(src, wpa_s->dpp_intro_bssid, ETH_ALEN) != 0) {
1338ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: Not waiting for response from "
1339ebb5671cSchristos 			   MACSTR " - drop", MAC2STR(src));
1340ebb5671cSchristos 		return;
1341ebb5671cSchristos 	}
1342ebb5671cSchristos 	offchannel_send_action_done(wpa_s);
1343ebb5671cSchristos 
1344ebb5671cSchristos 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1345ebb5671cSchristos 		if (ssid == wpa_s->dpp_intro_network)
1346ebb5671cSchristos 			break;
1347ebb5671cSchristos 	}
1348ebb5671cSchristos 	if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
1349ebb5671cSchristos 	    !ssid->dpp_csign) {
1350ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1351ebb5671cSchristos 			   "DPP: Profile not found for network introduction");
1352ebb5671cSchristos 		return;
1353ebb5671cSchristos 	}
1354ebb5671cSchristos 
1355ebb5671cSchristos 	trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
1356ebb5671cSchristos 			       &trans_id_len);
1357ebb5671cSchristos 	if (!trans_id || trans_id_len != 1) {
1358ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1359ebb5671cSchristos 			   "DPP: Peer did not include Transaction ID");
1360ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
1361ebb5671cSchristos 			" fail=missing_transaction_id", MAC2STR(src));
1362ebb5671cSchristos 		goto fail;
1363ebb5671cSchristos 	}
1364ebb5671cSchristos 	if (trans_id[0] != TRANSACTION_ID) {
1365ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1366ebb5671cSchristos 			   "DPP: Ignore frame with unexpected Transaction ID %u",
1367ebb5671cSchristos 			   trans_id[0]);
1368ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
1369ebb5671cSchristos 			" fail=transaction_id_mismatch", MAC2STR(src));
1370ebb5671cSchristos 		goto fail;
1371ebb5671cSchristos 	}
1372ebb5671cSchristos 
1373ebb5671cSchristos 	status = dpp_get_attr(buf, len, DPP_ATTR_STATUS, &status_len);
1374ebb5671cSchristos 	if (!status || status_len != 1) {
1375ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: Peer did not include Status");
1376ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
1377ebb5671cSchristos 			" fail=missing_status", MAC2STR(src));
1378ebb5671cSchristos 		goto fail;
1379ebb5671cSchristos 	}
1380ebb5671cSchristos 	if (status[0] != DPP_STATUS_OK) {
1381ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1382ebb5671cSchristos 			   "DPP: Peer rejected network introduction: Status %u",
1383ebb5671cSchristos 			   status[0]);
1384ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
1385ebb5671cSchristos 			" status=%u", MAC2STR(src), status[0]);
1386ebb5671cSchristos 		goto fail;
1387ebb5671cSchristos 	}
1388ebb5671cSchristos 
1389ebb5671cSchristos 	connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len);
1390ebb5671cSchristos 	if (!connector) {
1391ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1392ebb5671cSchristos 			   "DPP: Peer did not include its Connector");
1393ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
1394ebb5671cSchristos 			" fail=missing_connector", MAC2STR(src));
1395ebb5671cSchristos 		goto fail;
1396ebb5671cSchristos 	}
1397ebb5671cSchristos 
1398ebb5671cSchristos 	res = dpp_peer_intro(&intro, ssid->dpp_connector,
1399ebb5671cSchristos 			     ssid->dpp_netaccesskey,
1400ebb5671cSchristos 			     ssid->dpp_netaccesskey_len,
1401ebb5671cSchristos 			     ssid->dpp_csign,
1402ebb5671cSchristos 			     ssid->dpp_csign_len,
1403ebb5671cSchristos 			     connector, connector_len, &expiry);
1404ebb5671cSchristos 	if (res != DPP_STATUS_OK) {
1405ebb5671cSchristos 		wpa_printf(MSG_INFO,
1406ebb5671cSchristos 			   "DPP: Network Introduction protocol resulted in failure");
1407ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
1408ebb5671cSchristos 			" fail=peer_connector_validation_failed", MAC2STR(src));
1409ebb5671cSchristos 		goto fail;
1410ebb5671cSchristos 	}
1411ebb5671cSchristos 
1412ebb5671cSchristos 	entry = os_zalloc(sizeof(*entry));
1413ebb5671cSchristos 	if (!entry)
1414ebb5671cSchristos 		goto fail;
1415ebb5671cSchristos 	os_memcpy(entry->aa, src, ETH_ALEN);
1416ebb5671cSchristos 	os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN);
1417ebb5671cSchristos 	os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
1418ebb5671cSchristos 	entry->pmk_len = intro.pmk_len;
1419ebb5671cSchristos 	entry->akmp = WPA_KEY_MGMT_DPP;
1420ebb5671cSchristos 	if (expiry) {
1421ebb5671cSchristos 		os_get_time(&now);
1422ebb5671cSchristos 		seconds = expiry - now.sec;
1423ebb5671cSchristos 	} else {
1424ebb5671cSchristos 		seconds = 86400 * 7;
1425ebb5671cSchristos 	}
1426ebb5671cSchristos 	os_get_reltime(&rnow);
1427ebb5671cSchristos 	entry->expiration = rnow.sec + seconds;
1428ebb5671cSchristos 	entry->reauth_time = rnow.sec + seconds;
1429ebb5671cSchristos 	entry->network_ctx = ssid;
1430ebb5671cSchristos 	wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
1431ebb5671cSchristos 
1432ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
1433ebb5671cSchristos 		" status=%u", MAC2STR(src), status[0]);
1434ebb5671cSchristos 
1435ebb5671cSchristos 	wpa_printf(MSG_DEBUG,
1436ebb5671cSchristos 		   "DPP: Try connection again after successful network introduction");
1437ebb5671cSchristos 	if (wpa_supplicant_fast_associate(wpa_s) != 1) {
1438ebb5671cSchristos 		wpa_supplicant_cancel_sched_scan(wpa_s);
1439ebb5671cSchristos 		wpa_supplicant_req_scan(wpa_s, 0, 0);
1440ebb5671cSchristos 	}
1441ebb5671cSchristos fail:
1442ebb5671cSchristos 	os_memset(&intro, 0, sizeof(intro));
1443ebb5671cSchristos }
1444ebb5671cSchristos 
1445ebb5671cSchristos 
wpas_dpp_allow_ir(struct wpa_supplicant * wpa_s,unsigned int freq)1446ebb5671cSchristos static int wpas_dpp_allow_ir(struct wpa_supplicant *wpa_s, unsigned int freq)
1447ebb5671cSchristos {
1448ebb5671cSchristos 	int i, j;
1449ebb5671cSchristos 
1450ebb5671cSchristos 	if (!wpa_s->hw.modes)
1451ebb5671cSchristos 		return -1;
1452ebb5671cSchristos 
1453ebb5671cSchristos 	for (i = 0; i < wpa_s->hw.num_modes; i++) {
1454ebb5671cSchristos 		struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
1455ebb5671cSchristos 
1456ebb5671cSchristos 		for (j = 0; j < mode->num_channels; j++) {
1457ebb5671cSchristos 			struct hostapd_channel_data *chan = &mode->channels[j];
1458ebb5671cSchristos 
1459ebb5671cSchristos 			if (chan->freq != (int) freq)
1460ebb5671cSchristos 				continue;
1461ebb5671cSchristos 
1462ebb5671cSchristos 			if (chan->flag & (HOSTAPD_CHAN_DISABLED |
1463ebb5671cSchristos 					  HOSTAPD_CHAN_NO_IR |
1464ebb5671cSchristos 					  HOSTAPD_CHAN_RADAR))
1465ebb5671cSchristos 				continue;
1466ebb5671cSchristos 
1467ebb5671cSchristos 			return 1;
1468ebb5671cSchristos 		}
1469ebb5671cSchristos 	}
1470ebb5671cSchristos 
1471ebb5671cSchristos 	wpa_printf(MSG_DEBUG,
1472ebb5671cSchristos 		   "DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list",
1473ebb5671cSchristos 		   freq);
1474ebb5671cSchristos 
1475ebb5671cSchristos 	return 0;
1476ebb5671cSchristos }
1477ebb5671cSchristos 
1478ebb5671cSchristos 
wpas_dpp_pkex_next_channel(struct wpa_supplicant * wpa_s,struct dpp_pkex * pkex)1479ebb5671cSchristos static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s,
1480ebb5671cSchristos 				      struct dpp_pkex *pkex)
1481ebb5671cSchristos {
1482ebb5671cSchristos 	if (pkex->freq == 2437)
1483ebb5671cSchristos 		pkex->freq = 5745;
1484ebb5671cSchristos 	else if (pkex->freq == 5745)
1485ebb5671cSchristos 		pkex->freq = 5220;
1486ebb5671cSchristos 	else if (pkex->freq == 5220)
1487ebb5671cSchristos 		pkex->freq = 60480;
1488ebb5671cSchristos 	else
1489ebb5671cSchristos 		return -1; /* no more channels to try */
1490ebb5671cSchristos 
1491ebb5671cSchristos 	if (wpas_dpp_allow_ir(wpa_s, pkex->freq) == 1) {
1492ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz",
1493ebb5671cSchristos 			   pkex->freq);
1494ebb5671cSchristos 		return 0;
1495ebb5671cSchristos 	}
1496ebb5671cSchristos 
1497ebb5671cSchristos 	/* Could not use this channel - try the next one */
1498ebb5671cSchristos 	return wpas_dpp_pkex_next_channel(wpa_s, pkex);
1499ebb5671cSchristos }
1500ebb5671cSchristos 
1501ebb5671cSchristos 
wpas_dpp_pkex_retry_timeout(void * eloop_ctx,void * timeout_ctx)1502ebb5671cSchristos static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
1503ebb5671cSchristos {
1504ebb5671cSchristos 	struct wpa_supplicant *wpa_s = eloop_ctx;
1505ebb5671cSchristos 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
1506ebb5671cSchristos 
1507ebb5671cSchristos 	if (!pkex || !pkex->exchange_req)
1508ebb5671cSchristos 		return;
1509ebb5671cSchristos 	if (pkex->exch_req_tries >= 5) {
1510ebb5671cSchristos 		if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) {
1511ebb5671cSchristos 			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
1512ebb5671cSchristos 				"No response from PKEX peer");
1513ebb5671cSchristos 			dpp_pkex_free(pkex);
1514ebb5671cSchristos 			wpa_s->dpp_pkex = NULL;
1515ebb5671cSchristos 			return;
1516ebb5671cSchristos 		}
1517ebb5671cSchristos 		pkex->exch_req_tries = 0;
1518ebb5671cSchristos 	}
1519ebb5671cSchristos 
1520ebb5671cSchristos 	pkex->exch_req_tries++;
1521ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)",
1522ebb5671cSchristos 		   pkex->exch_req_tries);
1523ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
1524ebb5671cSchristos 		MAC2STR(broadcast), pkex->freq, DPP_PA_PKEX_EXCHANGE_REQ);
1525ebb5671cSchristos 	offchannel_send_action(wpa_s, pkex->freq, broadcast,
1526ebb5671cSchristos 			       wpa_s->own_addr, broadcast,
1527ebb5671cSchristos 			       wpabuf_head(pkex->exchange_req),
1528ebb5671cSchristos 			       wpabuf_len(pkex->exchange_req),
1529ebb5671cSchristos 			       pkex->exch_req_wait_time,
1530ebb5671cSchristos 			       wpas_dpp_tx_pkex_status, 0);
1531ebb5671cSchristos }
1532ebb5671cSchristos 
1533ebb5671cSchristos 
1534ebb5671cSchristos static void
wpas_dpp_tx_pkex_status(struct wpa_supplicant * wpa_s,unsigned int freq,const u8 * dst,const u8 * src,const u8 * bssid,const u8 * data,size_t data_len,enum offchannel_send_action_result result)1535ebb5671cSchristos wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
1536ebb5671cSchristos 			unsigned int freq, const u8 *dst,
1537ebb5671cSchristos 			const u8 *src, const u8 *bssid,
1538ebb5671cSchristos 			const u8 *data, size_t data_len,
1539ebb5671cSchristos 			enum offchannel_send_action_result result)
1540ebb5671cSchristos {
1541ebb5671cSchristos 	const char *res_txt;
1542ebb5671cSchristos 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
1543ebb5671cSchristos 
1544ebb5671cSchristos 	res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
1545ebb5671cSchristos 		(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
1546ebb5671cSchristos 		 "FAILED");
1547ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
1548ebb5671cSchristos 		   " result=%s (PKEX)",
1549ebb5671cSchristos 		   freq, MAC2STR(dst), res_txt);
1550ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
1551ebb5671cSchristos 		" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
1552ebb5671cSchristos 
1553ebb5671cSchristos 	if (!pkex) {
1554ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1555ebb5671cSchristos 			   "DPP: Ignore TX status since there is no ongoing PKEX exchange");
1556ebb5671cSchristos 		return;
1557ebb5671cSchristos 	}
1558ebb5671cSchristos 
1559ebb5671cSchristos 	if (pkex->failed) {
1560ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1561ebb5671cSchristos 			   "DPP: Terminate PKEX exchange due to an earlier error");
1562ebb5671cSchristos 		if (pkex->t > pkex->own_bi->pkex_t)
1563ebb5671cSchristos 			pkex->own_bi->pkex_t = pkex->t;
1564ebb5671cSchristos 		dpp_pkex_free(pkex);
1565ebb5671cSchristos 		wpa_s->dpp_pkex = NULL;
1566ebb5671cSchristos 		return;
1567ebb5671cSchristos 	}
1568ebb5671cSchristos 
1569ebb5671cSchristos 	if (pkex->exch_req_wait_time && pkex->exchange_req) {
1570ebb5671cSchristos 		/* Wait for PKEX Exchange Response frame and retry request if
1571ebb5671cSchristos 		 * no response is seen. */
1572ebb5671cSchristos 		eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
1573ebb5671cSchristos 		eloop_register_timeout(pkex->exch_req_wait_time / 1000,
1574ebb5671cSchristos 				       (pkex->exch_req_wait_time % 1000) * 1000,
1575ebb5671cSchristos 				       wpas_dpp_pkex_retry_timeout, wpa_s,
1576ebb5671cSchristos 				       NULL);
1577ebb5671cSchristos 	}
1578ebb5671cSchristos }
1579ebb5671cSchristos 
1580ebb5671cSchristos 
1581ebb5671cSchristos static void
wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * buf,size_t len,unsigned int freq)1582ebb5671cSchristos wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src,
1583ebb5671cSchristos 			      const u8 *buf, size_t len, unsigned int freq)
1584ebb5671cSchristos {
1585ebb5671cSchristos 	struct wpabuf *msg;
1586ebb5671cSchristos 	unsigned int wait_time;
1587ebb5671cSchristos 
1588ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR,
1589ebb5671cSchristos 		   MAC2STR(src));
1590ebb5671cSchristos 
1591ebb5671cSchristos 	/* TODO: Support multiple PKEX codes by iterating over all the enabled
1592ebb5671cSchristos 	 * values here */
1593ebb5671cSchristos 
1594ebb5671cSchristos 	if (!wpa_s->dpp_pkex_code || !wpa_s->dpp_pkex_bi) {
1595ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1596ebb5671cSchristos 			   "DPP: No PKEX code configured - ignore request");
1597ebb5671cSchristos 		return;
1598ebb5671cSchristos 	}
1599ebb5671cSchristos 
1600ebb5671cSchristos 	if (wpa_s->dpp_pkex) {
1601ebb5671cSchristos 		/* TODO: Support parallel operations */
1602ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1603ebb5671cSchristos 			   "DPP: Already in PKEX session - ignore new request");
1604ebb5671cSchristos 		return;
1605ebb5671cSchristos 	}
1606ebb5671cSchristos 
1607ebb5671cSchristos 	wpa_s->dpp_pkex = dpp_pkex_rx_exchange_req(wpa_s, wpa_s->dpp_pkex_bi,
1608ebb5671cSchristos 						   wpa_s->own_addr, src,
1609ebb5671cSchristos 						   wpa_s->dpp_pkex_identifier,
1610ebb5671cSchristos 						   wpa_s->dpp_pkex_code,
1611ebb5671cSchristos 						   buf, len);
1612ebb5671cSchristos 	if (!wpa_s->dpp_pkex) {
1613ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1614ebb5671cSchristos 			   "DPP: Failed to process the request - ignore it");
1615ebb5671cSchristos 		return;
1616ebb5671cSchristos 	}
1617ebb5671cSchristos 
1618ebb5671cSchristos 	msg = wpa_s->dpp_pkex->exchange_resp;
1619ebb5671cSchristos 	wait_time = wpa_s->max_remain_on_chan;
1620ebb5671cSchristos 	if (wait_time > 2000)
1621ebb5671cSchristos 		wait_time = 2000;
1622ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
1623ebb5671cSchristos 		MAC2STR(src), freq, DPP_PA_PKEX_EXCHANGE_RESP);
1624ebb5671cSchristos 	offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
1625ebb5671cSchristos 			       broadcast,
1626ebb5671cSchristos 			       wpabuf_head(msg), wpabuf_len(msg),
1627ebb5671cSchristos 			       wait_time, wpas_dpp_tx_pkex_status, 0);
1628ebb5671cSchristos }
1629ebb5671cSchristos 
1630ebb5671cSchristos 
1631ebb5671cSchristos static void
wpas_dpp_rx_pkex_exchange_resp(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * buf,size_t len,unsigned int freq)1632ebb5671cSchristos wpas_dpp_rx_pkex_exchange_resp(struct wpa_supplicant *wpa_s, const u8 *src,
1633ebb5671cSchristos 			       const u8 *buf, size_t len, unsigned int freq)
1634ebb5671cSchristos {
1635ebb5671cSchristos 	struct wpabuf *msg;
1636ebb5671cSchristos 	unsigned int wait_time;
1637ebb5671cSchristos 
1638ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR,
1639ebb5671cSchristos 		   MAC2STR(src));
1640ebb5671cSchristos 
1641ebb5671cSchristos 	/* TODO: Support multiple PKEX codes by iterating over all the enabled
1642ebb5671cSchristos 	 * values here */
1643ebb5671cSchristos 
1644ebb5671cSchristos 	if (!wpa_s->dpp_pkex || !wpa_s->dpp_pkex->initiator ||
1645ebb5671cSchristos 	    wpa_s->dpp_pkex->exchange_done) {
1646ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
1647ebb5671cSchristos 		return;
1648ebb5671cSchristos 	}
1649ebb5671cSchristos 
1650ebb5671cSchristos 	eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
1651ebb5671cSchristos 	wpa_s->dpp_pkex->exch_req_wait_time = 0;
1652ebb5671cSchristos 
1653ebb5671cSchristos 	msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, src, buf, len);
1654ebb5671cSchristos 	if (!msg) {
1655ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
1656ebb5671cSchristos 		return;
1657ebb5671cSchristos 	}
1658ebb5671cSchristos 
1659ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR,
1660ebb5671cSchristos 		   MAC2STR(src));
1661ebb5671cSchristos 
1662ebb5671cSchristos 	wait_time = wpa_s->max_remain_on_chan;
1663ebb5671cSchristos 	if (wait_time > 2000)
1664ebb5671cSchristos 		wait_time = 2000;
1665ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
1666ebb5671cSchristos 		MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_REQ);
1667ebb5671cSchristos 	offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
1668ebb5671cSchristos 			       broadcast,
1669ebb5671cSchristos 			       wpabuf_head(msg), wpabuf_len(msg),
1670ebb5671cSchristos 			       wait_time, wpas_dpp_tx_pkex_status, 0);
1671ebb5671cSchristos 	wpabuf_free(msg);
1672ebb5671cSchristos }
1673ebb5671cSchristos 
1674ebb5671cSchristos 
1675ebb5671cSchristos static struct dpp_bootstrap_info *
wpas_dpp_pkex_finish(struct wpa_supplicant * wpa_s,const u8 * peer,unsigned int freq)1676ebb5671cSchristos wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer,
1677ebb5671cSchristos 		     unsigned int freq)
1678ebb5671cSchristos {
1679ebb5671cSchristos 	struct dpp_bootstrap_info *bi;
1680ebb5671cSchristos 
1681*0d69f216Schristos 	bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq);
1682ebb5671cSchristos 	if (!bi)
1683ebb5671cSchristos 		return NULL;
1684ebb5671cSchristos 	wpa_s->dpp_pkex = NULL;
1685ebb5671cSchristos 	return bi;
1686ebb5671cSchristos }
1687ebb5671cSchristos 
1688ebb5671cSchristos 
1689ebb5671cSchristos static void
wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq)1690ebb5671cSchristos wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src,
1691ebb5671cSchristos 				   const u8 *hdr, const u8 *buf, size_t len,
1692ebb5671cSchristos 				   unsigned int freq)
1693ebb5671cSchristos {
1694ebb5671cSchristos 	struct wpabuf *msg;
1695ebb5671cSchristos 	unsigned int wait_time;
1696ebb5671cSchristos 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
1697ebb5671cSchristos 
1698ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR,
1699ebb5671cSchristos 		   MAC2STR(src));
1700ebb5671cSchristos 
1701ebb5671cSchristos 	if (!pkex || pkex->initiator || !pkex->exchange_done) {
1702ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
1703ebb5671cSchristos 		return;
1704ebb5671cSchristos 	}
1705ebb5671cSchristos 
1706ebb5671cSchristos 	msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
1707ebb5671cSchristos 	if (!msg) {
1708ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
1709ebb5671cSchristos 		if (pkex->failed) {
1710ebb5671cSchristos 			wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
1711ebb5671cSchristos 			if (pkex->t > pkex->own_bi->pkex_t)
1712ebb5671cSchristos 				pkex->own_bi->pkex_t = pkex->t;
1713ebb5671cSchristos 			dpp_pkex_free(wpa_s->dpp_pkex);
1714ebb5671cSchristos 			wpa_s->dpp_pkex = NULL;
1715ebb5671cSchristos 		}
1716ebb5671cSchristos 		return;
1717ebb5671cSchristos 	}
1718ebb5671cSchristos 
1719ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to "
1720ebb5671cSchristos 		   MACSTR, MAC2STR(src));
1721ebb5671cSchristos 
1722ebb5671cSchristos 	wait_time = wpa_s->max_remain_on_chan;
1723ebb5671cSchristos 	if (wait_time > 2000)
1724ebb5671cSchristos 		wait_time = 2000;
1725ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
1726ebb5671cSchristos 		MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_RESP);
1727ebb5671cSchristos 	offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
1728ebb5671cSchristos 			       broadcast,
1729ebb5671cSchristos 			       wpabuf_head(msg), wpabuf_len(msg),
1730ebb5671cSchristos 			       wait_time, wpas_dpp_tx_pkex_status, 0);
1731ebb5671cSchristos 	wpabuf_free(msg);
1732ebb5671cSchristos 
1733ebb5671cSchristos 	wpas_dpp_pkex_finish(wpa_s, src, freq);
1734ebb5671cSchristos }
1735ebb5671cSchristos 
1736ebb5671cSchristos 
1737ebb5671cSchristos static void
wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq)1738ebb5671cSchristos wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant *wpa_s, const u8 *src,
1739ebb5671cSchristos 				    const u8 *hdr, const u8 *buf, size_t len,
1740ebb5671cSchristos 				    unsigned int freq)
1741ebb5671cSchristos {
1742ebb5671cSchristos 	int res;
1743ebb5671cSchristos 	struct dpp_bootstrap_info *bi;
1744ebb5671cSchristos 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
1745ebb5671cSchristos 	char cmd[500];
1746ebb5671cSchristos 
1747ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR,
1748ebb5671cSchristos 		   MAC2STR(src));
1749ebb5671cSchristos 
1750ebb5671cSchristos 	if (!pkex || !pkex->initiator || !pkex->exchange_done) {
1751ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
1752ebb5671cSchristos 		return;
1753ebb5671cSchristos 	}
1754ebb5671cSchristos 
1755ebb5671cSchristos 	res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len);
1756ebb5671cSchristos 	if (res < 0) {
1757ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
1758ebb5671cSchristos 		return;
1759ebb5671cSchristos 	}
1760ebb5671cSchristos 
1761ebb5671cSchristos 	bi = wpas_dpp_pkex_finish(wpa_s, src, freq);
1762ebb5671cSchristos 	if (!bi)
1763ebb5671cSchristos 		return;
1764ebb5671cSchristos 
1765ebb5671cSchristos 	os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
1766ebb5671cSchristos 		    bi->id,
1767ebb5671cSchristos 		    wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : "");
1768ebb5671cSchristos 	wpa_printf(MSG_DEBUG,
1769ebb5671cSchristos 		   "DPP: Start authentication after PKEX with parameters: %s",
1770ebb5671cSchristos 		   cmd);
1771ebb5671cSchristos 	if (wpas_dpp_auth_init(wpa_s, cmd) < 0) {
1772ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1773ebb5671cSchristos 			   "DPP: Authentication initialization failed");
1774ebb5671cSchristos 		return;
1775ebb5671cSchristos 	}
1776ebb5671cSchristos }
1777ebb5671cSchristos 
1778ebb5671cSchristos 
wpas_dpp_rx_action(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * buf,size_t len,unsigned int freq)1779ebb5671cSchristos void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
1780ebb5671cSchristos 			const u8 *buf, size_t len, unsigned int freq)
1781ebb5671cSchristos {
1782ebb5671cSchristos 	u8 crypto_suite;
1783ebb5671cSchristos 	enum dpp_public_action_frame_type type;
1784ebb5671cSchristos 	const u8 *hdr;
1785ebb5671cSchristos 	unsigned int pkex_t;
1786ebb5671cSchristos 
1787ebb5671cSchristos 	if (len < DPP_HDR_LEN)
1788ebb5671cSchristos 		return;
1789ebb5671cSchristos 	if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE)
1790ebb5671cSchristos 		return;
1791ebb5671cSchristos 	hdr = buf;
1792ebb5671cSchristos 	buf += 4;
1793ebb5671cSchristos 	len -= 4;
1794ebb5671cSchristos 	crypto_suite = *buf++;
1795ebb5671cSchristos 	type = *buf++;
1796ebb5671cSchristos 	len -= 2;
1797ebb5671cSchristos 
1798ebb5671cSchristos 	wpa_printf(MSG_DEBUG,
1799ebb5671cSchristos 		   "DPP: Received DPP Public Action frame crypto suite %u type %d from "
1800ebb5671cSchristos 		   MACSTR " freq=%u",
1801ebb5671cSchristos 		   crypto_suite, type, MAC2STR(src), freq);
1802ebb5671cSchristos 	if (crypto_suite != 1) {
1803ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
1804ebb5671cSchristos 			   crypto_suite);
1805ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
1806ebb5671cSchristos 			" freq=%u type=%d ignore=unsupported-crypto-suite",
1807ebb5671cSchristos 			MAC2STR(src), freq, type);
1808ebb5671cSchristos 		return;
1809ebb5671cSchristos 	}
1810ebb5671cSchristos 	wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
1811ebb5671cSchristos 	if (dpp_check_attrs(buf, len) < 0) {
1812ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
1813ebb5671cSchristos 			" freq=%u type=%d ignore=invalid-attributes",
1814ebb5671cSchristos 			MAC2STR(src), freq, type);
1815ebb5671cSchristos 		return;
1816ebb5671cSchristos 	}
1817ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR " freq=%u type=%d",
1818ebb5671cSchristos 		MAC2STR(src), freq, type);
1819ebb5671cSchristos 
1820ebb5671cSchristos 	switch (type) {
1821ebb5671cSchristos 	case DPP_PA_AUTHENTICATION_REQ:
1822ebb5671cSchristos 		wpas_dpp_rx_auth_req(wpa_s, src, hdr, buf, len, freq);
1823ebb5671cSchristos 		break;
1824ebb5671cSchristos 	case DPP_PA_AUTHENTICATION_RESP:
1825ebb5671cSchristos 		wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len, freq);
1826ebb5671cSchristos 		break;
1827ebb5671cSchristos 	case DPP_PA_AUTHENTICATION_CONF:
1828ebb5671cSchristos 		wpas_dpp_rx_auth_conf(wpa_s, src, hdr, buf, len);
1829ebb5671cSchristos 		break;
1830ebb5671cSchristos 	case DPP_PA_PEER_DISCOVERY_RESP:
1831ebb5671cSchristos 		wpas_dpp_rx_peer_disc_resp(wpa_s, src, buf, len);
1832ebb5671cSchristos 		break;
1833ebb5671cSchristos 	case DPP_PA_PKEX_EXCHANGE_REQ:
1834ebb5671cSchristos 		wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq);
1835ebb5671cSchristos 		break;
1836ebb5671cSchristos 	case DPP_PA_PKEX_EXCHANGE_RESP:
1837ebb5671cSchristos 		wpas_dpp_rx_pkex_exchange_resp(wpa_s, src, buf, len, freq);
1838ebb5671cSchristos 		break;
1839ebb5671cSchristos 	case DPP_PA_PKEX_COMMIT_REVEAL_REQ:
1840ebb5671cSchristos 		wpas_dpp_rx_pkex_commit_reveal_req(wpa_s, src, hdr, buf, len,
1841ebb5671cSchristos 						   freq);
1842ebb5671cSchristos 		break;
1843ebb5671cSchristos 	case DPP_PA_PKEX_COMMIT_REVEAL_RESP:
1844ebb5671cSchristos 		wpas_dpp_rx_pkex_commit_reveal_resp(wpa_s, src, hdr, buf, len,
1845ebb5671cSchristos 						    freq);
1846ebb5671cSchristos 		break;
1847*0d69f216Schristos #ifdef CONFIG_DPP2
1848*0d69f216Schristos 	case DPP_PA_CONFIGURATION_RESULT:
1849*0d69f216Schristos 		wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len);
1850*0d69f216Schristos 		break;
1851*0d69f216Schristos #endif /* CONFIG_DPP2 */
1852ebb5671cSchristos 	default:
1853ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1854ebb5671cSchristos 			   "DPP: Ignored unsupported frame subtype %d", type);
1855ebb5671cSchristos 		break;
1856ebb5671cSchristos 	}
1857ebb5671cSchristos 
1858ebb5671cSchristos 	if (wpa_s->dpp_pkex)
1859ebb5671cSchristos 		pkex_t = wpa_s->dpp_pkex->t;
1860ebb5671cSchristos 	else if (wpa_s->dpp_pkex_bi)
1861ebb5671cSchristos 		pkex_t = wpa_s->dpp_pkex_bi->pkex_t;
1862ebb5671cSchristos 	else
1863ebb5671cSchristos 		pkex_t = 0;
1864ebb5671cSchristos 	if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
1865ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
1866ebb5671cSchristos 		wpas_dpp_pkex_remove(wpa_s, "*");
1867ebb5671cSchristos 	}
1868ebb5671cSchristos }
1869ebb5671cSchristos 
1870ebb5671cSchristos 
1871ebb5671cSchristos static struct wpabuf *
wpas_dpp_gas_req_handler(void * ctx,const u8 * sa,const u8 * query,size_t query_len)1872ebb5671cSchristos wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
1873ebb5671cSchristos 			 size_t query_len)
1874ebb5671cSchristos {
1875ebb5671cSchristos 	struct wpa_supplicant *wpa_s = ctx;
1876ebb5671cSchristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
1877ebb5671cSchristos 	struct wpabuf *resp;
1878ebb5671cSchristos 
1879ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR,
1880ebb5671cSchristos 		   MAC2STR(sa));
1881ebb5671cSchristos 	if (!auth || !auth->auth_success ||
1882ebb5671cSchristos 	    os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
1883ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
1884ebb5671cSchristos 		return NULL;
1885ebb5671cSchristos 	}
1886*0d69f216Schristos 
1887*0d69f216Schristos 	if (wpa_s->dpp_auth_ok_on_ack && auth->configurator) {
1888*0d69f216Schristos 		wpa_printf(MSG_DEBUG,
1889*0d69f216Schristos 			   "DPP: Have not received ACK for Auth Confirm yet - assume it was received based on this GAS request");
1890*0d69f216Schristos 		/* wpas_dpp_auth_success() would normally have been called from
1891*0d69f216Schristos 		 * TX status handler, but since there was no such handler call
1892*0d69f216Schristos 		 * yet, simply send out the event message and proceed with
1893*0d69f216Schristos 		 * exchange. */
1894*0d69f216Schristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=1");
1895*0d69f216Schristos 		wpa_s->dpp_auth_ok_on_ack = 0;
1896*0d69f216Schristos 	}
1897*0d69f216Schristos 
1898ebb5671cSchristos 	wpa_hexdump(MSG_DEBUG,
1899ebb5671cSchristos 		    "DPP: Received Configuration Request (GAS Query Request)",
1900ebb5671cSchristos 		    query, query_len);
1901ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
1902ebb5671cSchristos 		MAC2STR(sa));
1903ebb5671cSchristos 	resp = dpp_conf_req_rx(auth, query, query_len);
1904ebb5671cSchristos 	if (!resp)
1905ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
1906ebb5671cSchristos 	auth->conf_resp = resp;
1907ebb5671cSchristos 	return resp;
1908ebb5671cSchristos }
1909ebb5671cSchristos 
1910ebb5671cSchristos 
1911ebb5671cSchristos static void
wpas_dpp_gas_status_handler(void * ctx,struct wpabuf * resp,int ok)1912ebb5671cSchristos wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
1913ebb5671cSchristos {
1914ebb5671cSchristos 	struct wpa_supplicant *wpa_s = ctx;
1915ebb5671cSchristos 	struct dpp_authentication *auth = wpa_s->dpp_auth;
1916ebb5671cSchristos 
1917ebb5671cSchristos 	if (!auth) {
1918ebb5671cSchristos 		wpabuf_free(resp);
1919ebb5671cSchristos 		return;
1920ebb5671cSchristos 	}
1921ebb5671cSchristos 	if (auth->conf_resp != resp) {
1922ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
1923ebb5671cSchristos 			   "DPP: Ignore GAS status report (ok=%d) for unknown response",
1924ebb5671cSchristos 			ok);
1925ebb5671cSchristos 		wpabuf_free(resp);
1926ebb5671cSchristos 		return;
1927ebb5671cSchristos 	}
1928ebb5671cSchristos 
1929ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
1930ebb5671cSchristos 		   ok);
1931ebb5671cSchristos 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
1932ebb5671cSchristos 	eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
1933*0d69f216Schristos #ifdef CONFIG_DPP2
1934*0d69f216Schristos 	if (ok && auth->peer_version >= 2 &&
1935*0d69f216Schristos 	    auth->conf_resp_status == DPP_STATUS_OK) {
1936*0d69f216Schristos 		wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
1937*0d69f216Schristos 		auth->waiting_conf_result = 1;
1938*0d69f216Schristos 		auth->conf_resp = NULL;
1939*0d69f216Schristos 		wpabuf_free(resp);
1940*0d69f216Schristos 		eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
1941*0d69f216Schristos 				     wpa_s, NULL);
1942*0d69f216Schristos 		eloop_register_timeout(2, 0,
1943*0d69f216Schristos 				       wpas_dpp_config_result_wait_timeout,
1944*0d69f216Schristos 				       wpa_s, NULL);
1945*0d69f216Schristos 		return;
1946*0d69f216Schristos 	}
1947*0d69f216Schristos #endif /* CONFIG_DPP2 */
1948ebb5671cSchristos 	offchannel_send_action_done(wpa_s);
1949ebb5671cSchristos 	wpas_dpp_listen_stop(wpa_s);
1950ebb5671cSchristos 	if (ok)
1951ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
1952ebb5671cSchristos 	else
1953ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
1954ebb5671cSchristos 	dpp_auth_deinit(wpa_s->dpp_auth);
1955ebb5671cSchristos 	wpa_s->dpp_auth = NULL;
1956ebb5671cSchristos 	wpabuf_free(resp);
1957ebb5671cSchristos }
1958ebb5671cSchristos 
1959ebb5671cSchristos 
wpas_dpp_configurator_sign(struct wpa_supplicant * wpa_s,const char * cmd)1960ebb5671cSchristos int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd)
1961ebb5671cSchristos {
1962ebb5671cSchristos 	struct dpp_authentication *auth;
1963ebb5671cSchristos 	int ret = -1;
1964ebb5671cSchristos 	char *curve = NULL;
1965ebb5671cSchristos 
1966ebb5671cSchristos 	auth = os_zalloc(sizeof(*auth));
1967ebb5671cSchristos 	if (!auth)
1968ebb5671cSchristos 		return -1;
1969ebb5671cSchristos 
1970ebb5671cSchristos 	curve = get_param(cmd, " curve=");
1971ebb5671cSchristos 	wpas_dpp_set_testing_options(wpa_s, auth);
1972*0d69f216Schristos 	if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) == 0 &&
1973*0d69f216Schristos 	    dpp_configurator_own_config(auth, curve, 0) == 0)
1974*0d69f216Schristos 		ret = wpas_dpp_handle_config_obj(wpa_s, auth);
1975ebb5671cSchristos 
1976ebb5671cSchristos 	dpp_auth_deinit(auth);
1977ebb5671cSchristos 	os_free(curve);
1978ebb5671cSchristos 
1979ebb5671cSchristos 	return ret;
1980ebb5671cSchristos }
1981ebb5671cSchristos 
1982ebb5671cSchristos 
1983ebb5671cSchristos static void
wpas_dpp_tx_introduction_status(struct wpa_supplicant * wpa_s,unsigned int freq,const u8 * dst,const u8 * src,const u8 * bssid,const u8 * data,size_t data_len,enum offchannel_send_action_result result)1984ebb5671cSchristos wpas_dpp_tx_introduction_status(struct wpa_supplicant *wpa_s,
1985ebb5671cSchristos 				unsigned int freq, const u8 *dst,
1986ebb5671cSchristos 				const u8 *src, const u8 *bssid,
1987ebb5671cSchristos 				const u8 *data, size_t data_len,
1988ebb5671cSchristos 				enum offchannel_send_action_result result)
1989ebb5671cSchristos {
1990ebb5671cSchristos 	const char *res_txt;
1991ebb5671cSchristos 
1992ebb5671cSchristos 	res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
1993ebb5671cSchristos 		(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
1994ebb5671cSchristos 		 "FAILED");
1995ebb5671cSchristos 	wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
1996ebb5671cSchristos 		   " result=%s (DPP Peer Discovery Request)",
1997ebb5671cSchristos 		   freq, MAC2STR(dst), res_txt);
1998ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
1999ebb5671cSchristos 		" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
2000ebb5671cSchristos 	/* TODO: Time out wait for response more quickly in error cases? */
2001ebb5671cSchristos }
2002ebb5671cSchristos 
2003ebb5671cSchristos 
wpas_dpp_check_connect(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,struct wpa_bss * bss)2004ebb5671cSchristos int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
2005ebb5671cSchristos 			   struct wpa_bss *bss)
2006ebb5671cSchristos {
2007ebb5671cSchristos 	struct os_time now;
2008ebb5671cSchristos 	struct wpabuf *msg;
2009ebb5671cSchristos 	unsigned int wait_time;
2010*0d69f216Schristos 	const u8 *rsn;
2011*0d69f216Schristos 	struct wpa_ie_data ied;
2012ebb5671cSchristos 
2013ebb5671cSchristos 	if (!(ssid->key_mgmt & WPA_KEY_MGMT_DPP) || !bss)
2014ebb5671cSchristos 		return 0; /* Not using DPP AKM - continue */
2015*0d69f216Schristos 	rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
2016*0d69f216Schristos 	if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
2017*0d69f216Schristos 	    !(ied.key_mgmt & WPA_KEY_MGMT_DPP))
2018*0d69f216Schristos 		return 0; /* AP does not support DPP AKM - continue */
2019ebb5671cSchristos 	if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid))
2020ebb5671cSchristos 		return 0; /* PMKSA exists for DPP AKM - continue */
2021ebb5671cSchristos 
2022ebb5671cSchristos 	if (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
2023ebb5671cSchristos 	    !ssid->dpp_csign) {
2024ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR
2025ebb5671cSchristos 			"missing %s",
2026ebb5671cSchristos 			!ssid->dpp_connector ? "Connector" :
2027ebb5671cSchristos 			(!ssid->dpp_netaccesskey ? "netAccessKey" :
2028ebb5671cSchristos 			 "C-sign-key"));
2029ebb5671cSchristos 		return -1;
2030ebb5671cSchristos 	}
2031ebb5671cSchristos 
2032ebb5671cSchristos 	os_get_time(&now);
2033ebb5671cSchristos 
2034ebb5671cSchristos 	if (ssid->dpp_netaccesskey_expiry &&
2035ebb5671cSchristos 	    (os_time_t) ssid->dpp_netaccesskey_expiry < now.sec) {
2036ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR
2037ebb5671cSchristos 			"netAccessKey expired");
2038ebb5671cSchristos 		return -1;
2039ebb5671cSchristos 	}
2040ebb5671cSchristos 
2041ebb5671cSchristos 	wpa_printf(MSG_DEBUG,
2042ebb5671cSchristos 		   "DPP: Starting network introduction protocol to derive PMKSA for "
2043ebb5671cSchristos 		   MACSTR, MAC2STR(bss->bssid));
2044ebb5671cSchristos 
2045ebb5671cSchristos 	msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ,
2046ebb5671cSchristos 			    5 + 4 + os_strlen(ssid->dpp_connector));
2047ebb5671cSchristos 	if (!msg)
2048ebb5671cSchristos 		return -1;
2049ebb5671cSchristos 
2050ebb5671cSchristos #ifdef CONFIG_TESTING_OPTIONS
2051ebb5671cSchristos 	if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ) {
2052ebb5671cSchristos 		wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
2053ebb5671cSchristos 		goto skip_trans_id;
2054ebb5671cSchristos 	}
2055ebb5671cSchristos 	if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ) {
2056ebb5671cSchristos 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
2057ebb5671cSchristos 		wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
2058ebb5671cSchristos 		wpabuf_put_le16(msg, 0);
2059ebb5671cSchristos 		goto skip_trans_id;
2060ebb5671cSchristos 	}
2061ebb5671cSchristos #endif /* CONFIG_TESTING_OPTIONS */
2062ebb5671cSchristos 
2063ebb5671cSchristos 	/* Transaction ID */
2064ebb5671cSchristos 	wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
2065ebb5671cSchristos 	wpabuf_put_le16(msg, 1);
2066ebb5671cSchristos 	wpabuf_put_u8(msg, TRANSACTION_ID);
2067ebb5671cSchristos 
2068ebb5671cSchristos #ifdef CONFIG_TESTING_OPTIONS
2069ebb5671cSchristos skip_trans_id:
2070ebb5671cSchristos 	if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ) {
2071ebb5671cSchristos 		wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
2072ebb5671cSchristos 		goto skip_connector;
2073ebb5671cSchristos 	}
2074ebb5671cSchristos 	if (dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ) {
2075ebb5671cSchristos 		char *connector;
2076ebb5671cSchristos 
2077ebb5671cSchristos 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
2078ebb5671cSchristos 		connector = dpp_corrupt_connector_signature(
2079ebb5671cSchristos 			ssid->dpp_connector);
2080ebb5671cSchristos 		if (!connector) {
2081ebb5671cSchristos 			wpabuf_free(msg);
2082ebb5671cSchristos 			return -1;
2083ebb5671cSchristos 		}
2084ebb5671cSchristos 		wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
2085ebb5671cSchristos 		wpabuf_put_le16(msg, os_strlen(connector));
2086ebb5671cSchristos 		wpabuf_put_str(msg, connector);
2087ebb5671cSchristos 		os_free(connector);
2088ebb5671cSchristos 		goto skip_connector;
2089ebb5671cSchristos 	}
2090ebb5671cSchristos #endif /* CONFIG_TESTING_OPTIONS */
2091ebb5671cSchristos 
2092ebb5671cSchristos 	/* DPP Connector */
2093ebb5671cSchristos 	wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
2094ebb5671cSchristos 	wpabuf_put_le16(msg, os_strlen(ssid->dpp_connector));
2095ebb5671cSchristos 	wpabuf_put_str(msg, ssid->dpp_connector);
2096ebb5671cSchristos 
2097ebb5671cSchristos #ifdef CONFIG_TESTING_OPTIONS
2098ebb5671cSchristos skip_connector:
2099ebb5671cSchristos #endif /* CONFIG_TESTING_OPTIONS */
2100ebb5671cSchristos 
2101ebb5671cSchristos 	/* TODO: Timeout on AP response */
2102ebb5671cSchristos 	wait_time = wpa_s->max_remain_on_chan;
2103ebb5671cSchristos 	if (wait_time > 2000)
2104ebb5671cSchristos 		wait_time = 2000;
2105ebb5671cSchristos 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
2106ebb5671cSchristos 		MAC2STR(bss->bssid), bss->freq, DPP_PA_PEER_DISCOVERY_REQ);
2107ebb5671cSchristos 	offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr,
2108ebb5671cSchristos 			       broadcast,
2109ebb5671cSchristos 			       wpabuf_head(msg), wpabuf_len(msg),
2110ebb5671cSchristos 			       wait_time, wpas_dpp_tx_introduction_status, 0);
2111ebb5671cSchristos 	wpabuf_free(msg);
2112ebb5671cSchristos 
2113ebb5671cSchristos 	/* Request this connection attempt to terminate - new one will be
2114ebb5671cSchristos 	 * started when network introduction protocol completes */
2115ebb5671cSchristos 	os_memcpy(wpa_s->dpp_intro_bssid, bss->bssid, ETH_ALEN);
2116ebb5671cSchristos 	wpa_s->dpp_intro_network = ssid;
2117ebb5671cSchristos 	return 1;
2118ebb5671cSchristos }
2119ebb5671cSchristos 
2120ebb5671cSchristos 
wpas_dpp_pkex_add(struct wpa_supplicant * wpa_s,const char * cmd)2121ebb5671cSchristos int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
2122ebb5671cSchristos {
2123ebb5671cSchristos 	struct dpp_bootstrap_info *own_bi;
2124ebb5671cSchristos 	const char *pos, *end;
2125ebb5671cSchristos 	unsigned int wait_time;
2126ebb5671cSchristos 
2127ebb5671cSchristos 	pos = os_strstr(cmd, " own=");
2128ebb5671cSchristos 	if (!pos)
2129ebb5671cSchristos 		return -1;
2130ebb5671cSchristos 	pos += 5;
2131*0d69f216Schristos 	own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
2132ebb5671cSchristos 	if (!own_bi) {
2133ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
2134ebb5671cSchristos 			   "DPP: Identified bootstrap info not found");
2135ebb5671cSchristos 		return -1;
2136ebb5671cSchristos 	}
2137ebb5671cSchristos 	if (own_bi->type != DPP_BOOTSTRAP_PKEX) {
2138ebb5671cSchristos 		wpa_printf(MSG_DEBUG,
2139ebb5671cSchristos 			   "DPP: Identified bootstrap info not for PKEX");
2140ebb5671cSchristos 		return -1;
2141ebb5671cSchristos 	}
2142ebb5671cSchristos 	wpa_s->dpp_pkex_bi = own_bi;
2143ebb5671cSchristos 	own_bi->pkex_t = 0; /* clear pending errors on new code */
2144ebb5671cSchristos 
2145ebb5671cSchristos 	os_free(wpa_s->dpp_pkex_identifier);
2146ebb5671cSchristos 	wpa_s->dpp_pkex_identifier = NULL;
2147ebb5671cSchristos 	pos = os_strstr(cmd, " identifier=");
2148ebb5671cSchristos 	if (pos) {
2149ebb5671cSchristos 		pos += 12;
2150ebb5671cSchristos 		end = os_strchr(pos, ' ');
2151ebb5671cSchristos 		if (!end)
2152ebb5671cSchristos 			return -1;
2153ebb5671cSchristos 		wpa_s->dpp_pkex_identifier = os_malloc(end - pos + 1);
2154ebb5671cSchristos 		if (!wpa_s->dpp_pkex_identifier)
2155ebb5671cSchristos 			return -1;
2156ebb5671cSchristos 		os_memcpy(wpa_s->dpp_pkex_identifier, pos, end - pos);
2157ebb5671cSchristos 		wpa_s->dpp_pkex_identifier[end - pos] = '\0';
2158ebb5671cSchristos 	}
2159ebb5671cSchristos 
2160ebb5671cSchristos 	pos = os_strstr(cmd, " code=");
2161ebb5671cSchristos 	if (!pos)
2162ebb5671cSchristos 		return -1;
2163ebb5671cSchristos 	os_free(wpa_s->dpp_pkex_code);
2164ebb5671cSchristos 	wpa_s->dpp_pkex_code = os_strdup(pos + 6);
2165ebb5671cSchristos 	if (!wpa_s->dpp_pkex_code)
2166ebb5671cSchristos 		return -1;
2167ebb5671cSchristos 
2168ebb5671cSchristos 	if (os_strstr(cmd, " init=1")) {
2169ebb5671cSchristos 		struct dpp_pkex *pkex;
2170ebb5671cSchristos 		struct wpabuf *msg;
2171ebb5671cSchristos 
2172ebb5671cSchristos 		wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
2173ebb5671cSchristos 		dpp_pkex_free(wpa_s->dpp_pkex);
2174ebb5671cSchristos 		wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr,
2175ebb5671cSchristos 						wpa_s->dpp_pkex_identifier,
2176ebb5671cSchristos 						wpa_s->dpp_pkex_code);
2177ebb5671cSchristos 		pkex = wpa_s->dpp_pkex;
2178ebb5671cSchristos 		if (!pkex)
2179ebb5671cSchristos 			return -1;
2180ebb5671cSchristos 
2181ebb5671cSchristos 		msg = pkex->exchange_req;
2182ebb5671cSchristos 		wait_time = wpa_s->max_remain_on_chan;
2183ebb5671cSchristos 		if (wait_time > 2000)
2184ebb5671cSchristos 			wait_time = 2000;
2185ebb5671cSchristos 		pkex->freq = 2437;
2186ebb5671cSchristos 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
2187ebb5671cSchristos 			" freq=%u type=%d",
2188ebb5671cSchristos 			MAC2STR(broadcast), pkex->freq,
2189ebb5671cSchristos 			DPP_PA_PKEX_EXCHANGE_REQ);
2190ebb5671cSchristos 		offchannel_send_action(wpa_s, pkex->freq, broadcast,
2191ebb5671cSchristos 				       wpa_s->own_addr, broadcast,
2192ebb5671cSchristos 				       wpabuf_head(msg), wpabuf_len(msg),
2193ebb5671cSchristos 				       wait_time, wpas_dpp_tx_pkex_status, 0);
2194ebb5671cSchristos 		if (wait_time == 0)
2195ebb5671cSchristos 			wait_time = 2000;
2196ebb5671cSchristos 		pkex->exch_req_wait_time = wait_time;
2197ebb5671cSchristos 		pkex->exch_req_tries = 1;
2198ebb5671cSchristos 	}
2199ebb5671cSchristos 
2200ebb5671cSchristos 	/* TODO: Support multiple PKEX info entries */
2201ebb5671cSchristos 
2202ebb5671cSchristos 	os_free(wpa_s->dpp_pkex_auth_cmd);
2203ebb5671cSchristos 	wpa_s->dpp_pkex_auth_cmd = os_strdup(cmd);
2204ebb5671cSchristos 
2205ebb5671cSchristos 	return 1;
2206ebb5671cSchristos }
2207ebb5671cSchristos 
2208ebb5671cSchristos 
wpas_dpp_pkex_remove(struct wpa_supplicant * wpa_s,const char * id)2209ebb5671cSchristos int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id)
2210ebb5671cSchristos {
2211ebb5671cSchristos 	unsigned int id_val;
2212ebb5671cSchristos 
2213ebb5671cSchristos 	if (os_strcmp(id, "*") == 0) {
2214ebb5671cSchristos 		id_val = 0;
2215ebb5671cSchristos 	} else {
2216ebb5671cSchristos 		id_val = atoi(id);
2217ebb5671cSchristos 		if (id_val == 0)
2218ebb5671cSchristos 			return -1;
2219ebb5671cSchristos 	}
2220ebb5671cSchristos 
2221ebb5671cSchristos 	if ((id_val != 0 && id_val != 1) || !wpa_s->dpp_pkex_code)
2222ebb5671cSchristos 		return -1;
2223ebb5671cSchristos 
2224ebb5671cSchristos 	/* TODO: Support multiple PKEX entries */
2225ebb5671cSchristos 	os_free(wpa_s->dpp_pkex_code);
2226ebb5671cSchristos 	wpa_s->dpp_pkex_code = NULL;
2227ebb5671cSchristos 	os_free(wpa_s->dpp_pkex_identifier);
2228ebb5671cSchristos 	wpa_s->dpp_pkex_identifier = NULL;
2229ebb5671cSchristos 	os_free(wpa_s->dpp_pkex_auth_cmd);
2230ebb5671cSchristos 	wpa_s->dpp_pkex_auth_cmd = NULL;
2231ebb5671cSchristos 	wpa_s->dpp_pkex_bi = NULL;
2232ebb5671cSchristos 	/* TODO: Remove dpp_pkex only if it is for the identified PKEX code */
2233ebb5671cSchristos 	dpp_pkex_free(wpa_s->dpp_pkex);
2234ebb5671cSchristos 	wpa_s->dpp_pkex = NULL;
2235ebb5671cSchristos 	return 0;
2236ebb5671cSchristos }
2237ebb5671cSchristos 
2238ebb5671cSchristos 
wpas_dpp_stop(struct wpa_supplicant * wpa_s)2239ebb5671cSchristos void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
2240ebb5671cSchristos {
2241ebb5671cSchristos 	dpp_auth_deinit(wpa_s->dpp_auth);
2242ebb5671cSchristos 	wpa_s->dpp_auth = NULL;
2243ebb5671cSchristos 	dpp_pkex_free(wpa_s->dpp_pkex);
2244ebb5671cSchristos 	wpa_s->dpp_pkex = NULL;
2245ebb5671cSchristos 	if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0)
2246ebb5671cSchristos 		gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token);
2247ebb5671cSchristos }
2248ebb5671cSchristos 
2249ebb5671cSchristos 
wpas_dpp_init(struct wpa_supplicant * wpa_s)2250ebb5671cSchristos int wpas_dpp_init(struct wpa_supplicant *wpa_s)
2251ebb5671cSchristos {
2252*0d69f216Schristos 	struct dpp_global_config config;
2253ebb5671cSchristos 	u8 adv_proto_id[7];
2254ebb5671cSchristos 
2255ebb5671cSchristos 	adv_proto_id[0] = WLAN_EID_VENDOR_SPECIFIC;
2256ebb5671cSchristos 	adv_proto_id[1] = 5;
2257ebb5671cSchristos 	WPA_PUT_BE24(&adv_proto_id[2], OUI_WFA);
2258ebb5671cSchristos 	adv_proto_id[5] = DPP_OUI_TYPE;
2259ebb5671cSchristos 	adv_proto_id[6] = 0x01;
2260ebb5671cSchristos 
2261ebb5671cSchristos 	if (gas_server_register(wpa_s->gas_server, adv_proto_id,
2262ebb5671cSchristos 				sizeof(adv_proto_id), wpas_dpp_gas_req_handler,
2263ebb5671cSchristos 				wpas_dpp_gas_status_handler, wpa_s) < 0)
2264ebb5671cSchristos 		return -1;
2265*0d69f216Schristos 
2266*0d69f216Schristos 	os_memset(&config, 0, sizeof(config));
2267*0d69f216Schristos 	config.msg_ctx = wpa_s;
2268*0d69f216Schristos 	config.cb_ctx = wpa_s;
2269*0d69f216Schristos #ifdef CONFIG_DPP2
2270*0d69f216Schristos 	config.process_conf_obj = wpas_dpp_process_conf_obj;
2271*0d69f216Schristos #endif /* CONFIG_DPP2 */
2272*0d69f216Schristos 	wpa_s->dpp = dpp_global_init(&config);
2273*0d69f216Schristos 	return wpa_s->dpp ? 0 : -1;
2274ebb5671cSchristos }
2275ebb5671cSchristos 
2276ebb5671cSchristos 
wpas_dpp_deinit(struct wpa_supplicant * wpa_s)2277ebb5671cSchristos void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
2278ebb5671cSchristos {
2279ebb5671cSchristos #ifdef CONFIG_TESTING_OPTIONS
2280ebb5671cSchristos 	os_free(wpa_s->dpp_config_obj_override);
2281ebb5671cSchristos 	wpa_s->dpp_config_obj_override = NULL;
2282ebb5671cSchristos 	os_free(wpa_s->dpp_discovery_override);
2283ebb5671cSchristos 	wpa_s->dpp_discovery_override = NULL;
2284ebb5671cSchristos 	os_free(wpa_s->dpp_groups_override);
2285ebb5671cSchristos 	wpa_s->dpp_groups_override = NULL;
2286ebb5671cSchristos 	wpa_s->dpp_ignore_netaccesskey_mismatch = 0;
2287ebb5671cSchristos #endif /* CONFIG_TESTING_OPTIONS */
2288*0d69f216Schristos 	if (!wpa_s->dpp)
2289ebb5671cSchristos 		return;
2290*0d69f216Schristos 	dpp_global_clear(wpa_s->dpp);
2291ebb5671cSchristos 	eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
2292ebb5671cSchristos 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
2293ebb5671cSchristos 	eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
2294ebb5671cSchristos 	eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
2295*0d69f216Schristos #ifdef CONFIG_DPP2
2296*0d69f216Schristos 	eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
2297*0d69f216Schristos 	dpp_pfs_free(wpa_s->dpp_pfs);
2298*0d69f216Schristos 	wpa_s->dpp_pfs = NULL;
2299*0d69f216Schristos #endif /* CONFIG_DPP2 */
2300ebb5671cSchristos 	offchannel_send_action_done(wpa_s);
2301ebb5671cSchristos 	wpas_dpp_listen_stop(wpa_s);
2302ebb5671cSchristos 	wpas_dpp_stop(wpa_s);
2303ebb5671cSchristos 	wpas_dpp_pkex_remove(wpa_s, "*");
2304ebb5671cSchristos 	os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN);
2305ebb5671cSchristos 	os_free(wpa_s->dpp_configurator_params);
2306ebb5671cSchristos 	wpa_s->dpp_configurator_params = NULL;
2307ebb5671cSchristos }
2308*0d69f216Schristos 
2309*0d69f216Schristos 
2310*0d69f216Schristos #ifdef CONFIG_DPP2
wpas_dpp_controller_start(struct wpa_supplicant * wpa_s,const char * cmd)2311*0d69f216Schristos int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
2312*0d69f216Schristos {
2313*0d69f216Schristos 	struct dpp_controller_config config;
2314*0d69f216Schristos 	const char *pos;
2315*0d69f216Schristos 
2316*0d69f216Schristos 	os_memset(&config, 0, sizeof(config));
2317*0d69f216Schristos 	if (cmd) {
2318*0d69f216Schristos 		pos = os_strstr(cmd, " tcp_port=");
2319*0d69f216Schristos 		if (pos) {
2320*0d69f216Schristos 			pos += 10;
2321*0d69f216Schristos 			config.tcp_port = atoi(pos);
2322*0d69f216Schristos 		}
2323*0d69f216Schristos 	}
2324*0d69f216Schristos 	config.configurator_params = wpa_s->dpp_configurator_params;
2325*0d69f216Schristos 	return dpp_controller_start(wpa_s->dpp, &config);
2326*0d69f216Schristos }
2327*0d69f216Schristos #endif /* CONFIG_DPP2 */
2328