1341618Scy/*
2341618Scy * hostapd / DPP integration
3341618Scy * Copyright (c) 2017, Qualcomm Atheros, Inc.
4341618Scy *
5341618Scy * This software may be distributed under the terms of the BSD license.
6341618Scy * See README for more details.
7341618Scy */
8341618Scy
9341618Scy#include "utils/includes.h"
10341618Scy
11341618Scy#include "utils/common.h"
12341618Scy#include "utils/eloop.h"
13341618Scy#include "common/dpp.h"
14341618Scy#include "common/gas.h"
15341618Scy#include "common/wpa_ctrl.h"
16341618Scy#include "hostapd.h"
17341618Scy#include "ap_drv_ops.h"
18341618Scy#include "gas_query_ap.h"
19351611Scy#include "gas_serv.h"
20341618Scy#include "wpa_auth.h"
21341618Scy#include "dpp_hostapd.h"
22341618Scy
23341618Scy
24341618Scystatic void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
25341618Scystatic void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
26341618Scystatic void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
27341618Scystatic int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
28341618Scy
29341618Scystatic const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
30341618Scy
31341618Scy
32341618Scy/**
33341618Scy * hostapd_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
34341618Scy * @hapd: Pointer to hostapd_data
35341618Scy * @cmd: DPP URI read from a QR Code
36341618Scy * Returns: Identifier of the stored info or -1 on failure
37341618Scy */
38341618Scyint hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd)
39341618Scy{
40341618Scy	struct dpp_bootstrap_info *bi;
41341618Scy	struct dpp_authentication *auth = hapd->dpp_auth;
42341618Scy
43346981Scy	bi = dpp_add_qr_code(hapd->iface->interfaces->dpp, cmd);
44341618Scy	if (!bi)
45341618Scy		return -1;
46341618Scy
47341618Scy	if (auth && auth->response_pending &&
48341618Scy	    dpp_notify_new_qr_code(auth, bi) == 1) {
49341618Scy		wpa_printf(MSG_DEBUG,
50341618Scy			   "DPP: Sending out pending authentication response");
51341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
52341618Scy			" freq=%u type=%d",
53341618Scy			MAC2STR(auth->peer_mac_addr), auth->curr_freq,
54341618Scy			DPP_PA_AUTHENTICATION_RESP);
55341618Scy		hostapd_drv_send_action(hapd, auth->curr_freq, 0,
56341618Scy					auth->peer_mac_addr,
57341618Scy					wpabuf_head(hapd->dpp_auth->resp_msg),
58341618Scy					wpabuf_len(hapd->dpp_auth->resp_msg));
59341618Scy	}
60341618Scy
61341618Scy	return bi->id;
62341618Scy}
63341618Scy
64341618Scy
65341618Scystatic void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
66341618Scy						void *timeout_ctx)
67341618Scy{
68341618Scy	struct hostapd_data *hapd = eloop_ctx;
69341618Scy	struct dpp_authentication *auth = hapd->dpp_auth;
70341618Scy
71341618Scy	if (!auth || !auth->resp_msg)
72341618Scy		return;
73341618Scy
74341618Scy	wpa_printf(MSG_DEBUG,
75341618Scy		   "DPP: Retry Authentication Response after timeout");
76341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
77341618Scy		" freq=%u type=%d",
78341618Scy		MAC2STR(auth->peer_mac_addr), auth->curr_freq,
79341618Scy		DPP_PA_AUTHENTICATION_RESP);
80341618Scy	hostapd_drv_send_action(hapd, auth->curr_freq, 500, auth->peer_mac_addr,
81341618Scy				wpabuf_head(auth->resp_msg),
82341618Scy				wpabuf_len(auth->resp_msg));
83341618Scy}
84341618Scy
85341618Scy
86341618Scystatic void hostapd_dpp_auth_resp_retry(struct hostapd_data *hapd)
87341618Scy{
88341618Scy	struct dpp_authentication *auth = hapd->dpp_auth;
89341618Scy	unsigned int wait_time, max_tries;
90341618Scy
91341618Scy	if (!auth || !auth->resp_msg)
92341618Scy		return;
93341618Scy
94341618Scy	if (hapd->dpp_resp_max_tries)
95341618Scy		max_tries = hapd->dpp_resp_max_tries;
96341618Scy	else
97341618Scy		max_tries = 5;
98341618Scy	auth->auth_resp_tries++;
99341618Scy	if (auth->auth_resp_tries >= max_tries) {
100341618Scy		wpa_printf(MSG_INFO,
101341618Scy			   "DPP: No confirm received from initiator - stopping exchange");
102341618Scy		hostapd_drv_send_action_cancel_wait(hapd);
103341618Scy		dpp_auth_deinit(hapd->dpp_auth);
104341618Scy		hapd->dpp_auth = NULL;
105341618Scy		return;
106341618Scy	}
107341618Scy
108341618Scy	if (hapd->dpp_resp_retry_time)
109341618Scy		wait_time = hapd->dpp_resp_retry_time;
110341618Scy	else
111341618Scy		wait_time = 1000;
112341618Scy	wpa_printf(MSG_DEBUG,
113341618Scy		   "DPP: Schedule retransmission of Authentication Response frame in %u ms",
114341618Scy		wait_time);
115341618Scy	eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
116341618Scy	eloop_register_timeout(wait_time / 1000,
117341618Scy			       (wait_time % 1000) * 1000,
118341618Scy			       hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
119341618Scy}
120341618Scy
121341618Scy
122341618Scyvoid hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
123341618Scy			   const u8 *data, size_t data_len, int ok)
124341618Scy{
125341618Scy	struct dpp_authentication *auth = hapd->dpp_auth;
126341618Scy
127341618Scy	wpa_printf(MSG_DEBUG, "DPP: TX status: dst=" MACSTR " ok=%d",
128341618Scy		   MAC2STR(dst), ok);
129341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
130341618Scy		" result=%s", MAC2STR(dst), ok ? "SUCCESS" : "FAILED");
131341618Scy
132341618Scy	if (!hapd->dpp_auth) {
133341618Scy		wpa_printf(MSG_DEBUG,
134341618Scy			   "DPP: Ignore TX status since there is no ongoing authentication exchange");
135341618Scy		return;
136341618Scy	}
137341618Scy
138346981Scy#ifdef CONFIG_DPP2
139346981Scy	if (auth->connect_on_tx_status) {
140346981Scy		wpa_printf(MSG_DEBUG,
141346981Scy			   "DPP: Complete exchange on configuration result");
142346981Scy		dpp_auth_deinit(hapd->dpp_auth);
143346981Scy		hapd->dpp_auth = NULL;
144346981Scy		return;
145346981Scy	}
146346981Scy#endif /* CONFIG_DPP2 */
147346981Scy
148341618Scy	if (hapd->dpp_auth->remove_on_tx_status) {
149341618Scy		wpa_printf(MSG_DEBUG,
150341618Scy			   "DPP: Terminate authentication exchange due to an earlier error");
151341618Scy		eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
152341618Scy		eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
153341618Scy				     hapd, NULL);
154341618Scy		eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
155341618Scy				     NULL);
156341618Scy		hostapd_drv_send_action_cancel_wait(hapd);
157341618Scy		dpp_auth_deinit(hapd->dpp_auth);
158341618Scy		hapd->dpp_auth = NULL;
159341618Scy		return;
160341618Scy	}
161341618Scy
162341618Scy	if (hapd->dpp_auth_ok_on_ack)
163341618Scy		hostapd_dpp_auth_success(hapd, 1);
164341618Scy
165341618Scy	if (!is_broadcast_ether_addr(dst) && !ok) {
166341618Scy		wpa_printf(MSG_DEBUG,
167341618Scy			   "DPP: Unicast DPP Action frame was not ACKed");
168341618Scy		if (auth->waiting_auth_resp) {
169341618Scy			/* In case of DPP Authentication Request frame, move to
170341618Scy			 * the next channel immediately. */
171341618Scy			hostapd_drv_send_action_cancel_wait(hapd);
172341618Scy			hostapd_dpp_auth_init_next(hapd);
173341618Scy			return;
174341618Scy		}
175341618Scy		if (auth->waiting_auth_conf) {
176341618Scy			hostapd_dpp_auth_resp_retry(hapd);
177341618Scy			return;
178341618Scy		}
179341618Scy	}
180341618Scy
181341618Scy	if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && ok) {
182341618Scy		/* Allow timeout handling to stop iteration if no response is
183341618Scy		 * received from a peer that has ACKed a request. */
184341618Scy		auth->auth_req_ack = 1;
185341618Scy	}
186341618Scy
187341618Scy	if (!hapd->dpp_auth_ok_on_ack && hapd->dpp_auth->neg_freq > 0 &&
188341618Scy	    hapd->dpp_auth->curr_freq != hapd->dpp_auth->neg_freq) {
189341618Scy		wpa_printf(MSG_DEBUG,
190341618Scy			   "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
191341618Scy			   hapd->dpp_auth->curr_freq,
192341618Scy			   hapd->dpp_auth->neg_freq);
193341618Scy		hostapd_drv_send_action_cancel_wait(hapd);
194341618Scy
195341618Scy		if (hapd->dpp_auth->neg_freq !=
196341618Scy		    (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) {
197341618Scy			/* TODO: Listen operation on non-operating channel */
198341618Scy			wpa_printf(MSG_INFO,
199341618Scy				   "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
200341618Scy				   hapd->dpp_auth->neg_freq, hapd->iface->freq);
201341618Scy		}
202341618Scy	}
203341618Scy
204341618Scy	if (hapd->dpp_auth_ok_on_ack)
205341618Scy		hapd->dpp_auth_ok_on_ack = 0;
206341618Scy}
207341618Scy
208341618Scy
209341618Scystatic void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
210341618Scy{
211341618Scy	struct hostapd_data *hapd = eloop_ctx;
212341618Scy	struct dpp_authentication *auth = hapd->dpp_auth;
213341618Scy	unsigned int freq;
214341618Scy	struct os_reltime now, diff;
215341618Scy	unsigned int wait_time, diff_ms;
216341618Scy
217341618Scy	if (!auth || !auth->waiting_auth_resp)
218341618Scy		return;
219341618Scy
220341618Scy	wait_time = hapd->dpp_resp_wait_time ?
221341618Scy		hapd->dpp_resp_wait_time : 2000;
222341618Scy	os_get_reltime(&now);
223341618Scy	os_reltime_sub(&now, &hapd->dpp_last_init, &diff);
224341618Scy	diff_ms = diff.sec * 1000 + diff.usec / 1000;
225341618Scy	wpa_printf(MSG_DEBUG,
226341618Scy		   "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
227341618Scy		   wait_time, diff_ms);
228341618Scy
229341618Scy	if (auth->auth_req_ack && diff_ms >= wait_time) {
230341618Scy		/* Peer ACK'ed Authentication Request frame, but did not reply
231341618Scy		 * with Authentication Response frame within two seconds. */
232341618Scy		wpa_printf(MSG_INFO,
233341618Scy			   "DPP: No response received from responder - stopping initiation attempt");
234341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
235341618Scy		hostapd_drv_send_action_cancel_wait(hapd);
236341618Scy		hostapd_dpp_listen_stop(hapd);
237341618Scy		dpp_auth_deinit(auth);
238341618Scy		hapd->dpp_auth = NULL;
239341618Scy		return;
240341618Scy	}
241341618Scy
242341618Scy	if (diff_ms >= wait_time) {
243341618Scy		/* Authentication Request frame was not ACK'ed and no reply
244341618Scy		 * was receiving within two seconds. */
245341618Scy		wpa_printf(MSG_DEBUG,
246341618Scy			   "DPP: Continue Initiator channel iteration");
247341618Scy		hostapd_drv_send_action_cancel_wait(hapd);
248341618Scy		hostapd_dpp_listen_stop(hapd);
249341618Scy		hostapd_dpp_auth_init_next(hapd);
250341618Scy		return;
251341618Scy	}
252341618Scy
253341618Scy	/* Driver did not support 2000 ms long wait_time with TX command, so
254341618Scy	 * schedule listen operation to continue waiting for the response.
255341618Scy	 *
256341618Scy	 * DPP listen operations continue until stopped, so simply schedule a
257341618Scy	 * new call to this function at the point when the two second reply
258341618Scy	 * wait has expired. */
259341618Scy	wait_time -= diff_ms;
260341618Scy
261341618Scy	freq = auth->curr_freq;
262341618Scy	if (auth->neg_freq > 0)
263341618Scy		freq = auth->neg_freq;
264341618Scy	wpa_printf(MSG_DEBUG,
265341618Scy		   "DPP: Continue reply wait on channel %u MHz for %u ms",
266341618Scy		   freq, wait_time);
267341618Scy	hapd->dpp_in_response_listen = 1;
268341618Scy
269341618Scy	if (freq != (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) {
270341618Scy		/* TODO: Listen operation on non-operating channel */
271341618Scy		wpa_printf(MSG_INFO,
272341618Scy			   "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
273341618Scy			   freq, hapd->iface->freq);
274341618Scy	}
275341618Scy
276341618Scy	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
277341618Scy			       hostapd_dpp_reply_wait_timeout, hapd, NULL);
278341618Scy}
279341618Scy
280341618Scy
281341618Scystatic void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
282341618Scy					    struct dpp_authentication *auth)
283341618Scy{
284341618Scy#ifdef CONFIG_TESTING_OPTIONS
285341618Scy	if (hapd->dpp_config_obj_override)
286341618Scy		auth->config_obj_override =
287341618Scy			os_strdup(hapd->dpp_config_obj_override);
288341618Scy	if (hapd->dpp_discovery_override)
289341618Scy		auth->discovery_override =
290341618Scy			os_strdup(hapd->dpp_discovery_override);
291341618Scy	if (hapd->dpp_groups_override)
292341618Scy		auth->groups_override = os_strdup(hapd->dpp_groups_override);
293341618Scy	auth->ignore_netaccesskey_mismatch =
294341618Scy		hapd->dpp_ignore_netaccesskey_mismatch;
295341618Scy#endif /* CONFIG_TESTING_OPTIONS */
296341618Scy}
297341618Scy
298341618Scy
299341618Scystatic void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
300341618Scy{
301341618Scy	struct hostapd_data *hapd = eloop_ctx;
302341618Scy
303341618Scy	if (!hapd->dpp_auth)
304341618Scy		return;
305341618Scy	wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
306341618Scy	hostapd_dpp_auth_init_next(hapd);
307341618Scy}
308341618Scy
309341618Scy
310341618Scystatic int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
311341618Scy{
312341618Scy	struct dpp_authentication *auth = hapd->dpp_auth;
313341618Scy	const u8 *dst;
314341618Scy	unsigned int wait_time, max_wait_time, freq, max_tries, used;
315341618Scy	struct os_reltime now, diff;
316341618Scy
317341618Scy	if (!auth)
318341618Scy		return -1;
319341618Scy
320341618Scy	if (auth->freq_idx == 0)
321341618Scy		os_get_reltime(&hapd->dpp_init_iter_start);
322341618Scy
323341618Scy	if (auth->freq_idx >= auth->num_freq) {
324341618Scy		auth->num_freq_iters++;
325341618Scy		if (hapd->dpp_init_max_tries)
326341618Scy			max_tries = hapd->dpp_init_max_tries;
327341618Scy		else
328341618Scy			max_tries = 5;
329341618Scy		if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
330341618Scy			wpa_printf(MSG_INFO,
331341618Scy				   "DPP: No response received from responder - stopping initiation attempt");
332341618Scy			wpa_msg(hapd->msg_ctx, MSG_INFO,
333341618Scy				DPP_EVENT_AUTH_INIT_FAILED);
334341618Scy			eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
335341618Scy					     hapd, NULL);
336341618Scy			hostapd_drv_send_action_cancel_wait(hapd);
337341618Scy			dpp_auth_deinit(hapd->dpp_auth);
338341618Scy			hapd->dpp_auth = NULL;
339341618Scy			return -1;
340341618Scy		}
341341618Scy		auth->freq_idx = 0;
342341618Scy		eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
343341618Scy		if (hapd->dpp_init_retry_time)
344341618Scy			wait_time = hapd->dpp_init_retry_time;
345341618Scy		else
346341618Scy			wait_time = 10000;
347341618Scy		os_get_reltime(&now);
348341618Scy		os_reltime_sub(&now, &hapd->dpp_init_iter_start, &diff);
349341618Scy		used = diff.sec * 1000 + diff.usec / 1000;
350341618Scy		if (used > wait_time)
351341618Scy			wait_time = 0;
352341618Scy		else
353341618Scy			wait_time -= used;
354341618Scy		wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
355341618Scy			   wait_time);
356341618Scy		eloop_register_timeout(wait_time / 1000,
357341618Scy				       (wait_time % 1000) * 1000,
358341618Scy				       hostapd_dpp_init_timeout, hapd,
359341618Scy				       NULL);
360341618Scy		return 0;
361341618Scy	}
362341618Scy	freq = auth->freq[auth->freq_idx++];
363341618Scy	auth->curr_freq = freq;
364341618Scy
365341618Scy	if (is_zero_ether_addr(auth->peer_bi->mac_addr))
366341618Scy		dst = broadcast;
367341618Scy	else
368341618Scy		dst = auth->peer_bi->mac_addr;
369341618Scy	hapd->dpp_auth_ok_on_ack = 0;
370341618Scy	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
371341618Scy	wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
372341618Scy	max_wait_time = hapd->dpp_resp_wait_time ?
373341618Scy		hapd->dpp_resp_wait_time : 2000;
374341618Scy	if (wait_time > max_wait_time)
375341618Scy		wait_time = max_wait_time;
376341618Scy	wait_time += 10; /* give the driver some extra time to complete */
377341618Scy	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
378341618Scy			       hostapd_dpp_reply_wait_timeout, hapd, NULL);
379341618Scy	wait_time -= 10;
380341618Scy	if (auth->neg_freq > 0 && freq != auth->neg_freq) {
381341618Scy		wpa_printf(MSG_DEBUG,
382341618Scy			   "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
383341618Scy			   freq, auth->neg_freq);
384341618Scy	}
385341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
386341618Scy		" freq=%u type=%d",
387341618Scy		MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
388341618Scy	auth->auth_req_ack = 0;
389341618Scy	os_get_reltime(&hapd->dpp_last_init);
390341618Scy	return hostapd_drv_send_action(hapd, freq, wait_time,
391341618Scy				       dst,
392341618Scy				       wpabuf_head(hapd->dpp_auth->req_msg),
393341618Scy				       wpabuf_len(hapd->dpp_auth->req_msg));
394341618Scy}
395341618Scy
396341618Scy
397341618Scyint hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
398341618Scy{
399341618Scy	const char *pos;
400341618Scy	struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
401341618Scy	u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
402341618Scy	unsigned int neg_freq = 0;
403341618Scy
404341618Scy	pos = os_strstr(cmd, " peer=");
405341618Scy	if (!pos)
406341618Scy		return -1;
407341618Scy	pos += 6;
408346981Scy	peer_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
409341618Scy	if (!peer_bi) {
410341618Scy		wpa_printf(MSG_INFO,
411341618Scy			   "DPP: Could not find bootstrapping info for the identified peer");
412341618Scy		return -1;
413341618Scy	}
414341618Scy
415341618Scy	pos = os_strstr(cmd, " own=");
416341618Scy	if (pos) {
417341618Scy		pos += 5;
418346981Scy		own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp,
419346981Scy					      atoi(pos));
420341618Scy		if (!own_bi) {
421341618Scy			wpa_printf(MSG_INFO,
422341618Scy				   "DPP: Could not find bootstrapping info for the identified local entry");
423341618Scy			return -1;
424341618Scy		}
425341618Scy
426341618Scy		if (peer_bi->curve != own_bi->curve) {
427341618Scy			wpa_printf(MSG_INFO,
428341618Scy				   "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
429341618Scy				   peer_bi->curve->name, own_bi->curve->name);
430341618Scy			return -1;
431341618Scy		}
432341618Scy	}
433341618Scy
434341618Scy	pos = os_strstr(cmd, " role=");
435341618Scy	if (pos) {
436341618Scy		pos += 6;
437341618Scy		if (os_strncmp(pos, "configurator", 12) == 0)
438341618Scy			allowed_roles = DPP_CAPAB_CONFIGURATOR;
439341618Scy		else if (os_strncmp(pos, "enrollee", 8) == 0)
440341618Scy			allowed_roles = DPP_CAPAB_ENROLLEE;
441341618Scy		else if (os_strncmp(pos, "either", 6) == 0)
442341618Scy			allowed_roles = DPP_CAPAB_CONFIGURATOR |
443341618Scy				DPP_CAPAB_ENROLLEE;
444341618Scy		else
445341618Scy			goto fail;
446341618Scy	}
447341618Scy
448341618Scy	pos = os_strstr(cmd, " neg_freq=");
449341618Scy	if (pos)
450341618Scy		neg_freq = atoi(pos + 10);
451341618Scy
452341618Scy	if (hapd->dpp_auth) {
453341618Scy		eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
454341618Scy		eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
455341618Scy				     hapd, NULL);
456341618Scy		eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
457341618Scy				     NULL);
458341618Scy		hostapd_drv_send_action_cancel_wait(hapd);
459341618Scy		dpp_auth_deinit(hapd->dpp_auth);
460341618Scy	}
461341618Scy
462341618Scy	hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi,
463341618Scy				       allowed_roles, neg_freq,
464341618Scy				       hapd->iface->hw_features,
465341618Scy				       hapd->iface->num_hw_features);
466341618Scy	if (!hapd->dpp_auth)
467341618Scy		goto fail;
468341618Scy	hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
469346981Scy	if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
470346981Scy				 hapd->dpp_auth, cmd) < 0) {
471341618Scy		dpp_auth_deinit(hapd->dpp_auth);
472341618Scy		hapd->dpp_auth = NULL;
473341618Scy		goto fail;
474341618Scy	}
475341618Scy
476341618Scy	hapd->dpp_auth->neg_freq = neg_freq;
477341618Scy
478341618Scy	if (!is_zero_ether_addr(peer_bi->mac_addr))
479341618Scy		os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
480341618Scy			  ETH_ALEN);
481341618Scy
482341618Scy	return hostapd_dpp_auth_init_next(hapd);
483341618Scyfail:
484341618Scy	return -1;
485341618Scy}
486341618Scy
487341618Scy
488341618Scyint hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd)
489341618Scy{
490341618Scy	int freq;
491341618Scy
492341618Scy	freq = atoi(cmd);
493341618Scy	if (freq <= 0)
494341618Scy		return -1;
495341618Scy
496341618Scy	if (os_strstr(cmd, " role=configurator"))
497341618Scy		hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR;
498341618Scy	else if (os_strstr(cmd, " role=enrollee"))
499341618Scy		hapd->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
500341618Scy	else
501341618Scy		hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
502341618Scy			DPP_CAPAB_ENROLLEE;
503341618Scy	hapd->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
504341618Scy
505341618Scy	if (freq != hapd->iface->freq && hapd->iface->freq > 0) {
506341618Scy		/* TODO: Listen operation on non-operating channel */
507341618Scy		wpa_printf(MSG_INFO,
508341618Scy			   "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
509341618Scy			   freq, hapd->iface->freq);
510341618Scy		return -1;
511341618Scy	}
512341618Scy
513341618Scy	return 0;
514341618Scy}
515341618Scy
516341618Scy
517341618Scyvoid hostapd_dpp_listen_stop(struct hostapd_data *hapd)
518341618Scy{
519341618Scy	/* TODO: Stop listen operation on non-operating channel */
520341618Scy}
521341618Scy
522341618Scy
523341618Scystatic void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
524341618Scy				    const u8 *hdr, const u8 *buf, size_t len,
525341618Scy				    unsigned int freq)
526341618Scy{
527341618Scy	const u8 *r_bootstrap, *i_bootstrap;
528341618Scy	u16 r_bootstrap_len, i_bootstrap_len;
529346981Scy	struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
530341618Scy
531346981Scy	if (!hapd->iface->interfaces->dpp)
532346981Scy		return;
533346981Scy
534341618Scy	wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
535341618Scy		   MAC2STR(src));
536341618Scy
537341618Scy	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
538341618Scy				   &r_bootstrap_len);
539341618Scy	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
540341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
541341618Scy			"Missing or invalid required Responder Bootstrapping Key Hash attribute");
542341618Scy		return;
543341618Scy	}
544341618Scy	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
545341618Scy		    r_bootstrap, r_bootstrap_len);
546341618Scy
547341618Scy	i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
548341618Scy				   &i_bootstrap_len);
549341618Scy	if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
550341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
551341618Scy			"Missing or invalid required Initiator Bootstrapping Key Hash attribute");
552341618Scy		return;
553341618Scy	}
554341618Scy	wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
555341618Scy		    i_bootstrap, i_bootstrap_len);
556341618Scy
557341618Scy	/* Try to find own and peer bootstrapping key matches based on the
558341618Scy	 * received hash values */
559346981Scy	dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap,
560346981Scy				r_bootstrap, &own_bi, &peer_bi);
561351611Scy#ifdef CONFIG_DPP2
562341618Scy	if (!own_bi) {
563351611Scy		if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
564351611Scy					src, hdr, buf, len, freq, i_bootstrap,
565351611Scy					r_bootstrap) == 0)
566351611Scy			return;
567351611Scy	}
568351611Scy#endif /* CONFIG_DPP2 */
569351611Scy	if (!own_bi) {
570341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
571341618Scy			"No matching own bootstrapping key found - ignore message");
572341618Scy		return;
573341618Scy	}
574341618Scy
575341618Scy	if (hapd->dpp_auth) {
576341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
577341618Scy			"Already in DPP authentication exchange - ignore new one");
578341618Scy		return;
579341618Scy	}
580341618Scy
581341618Scy	hapd->dpp_auth_ok_on_ack = 0;
582341618Scy	hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles,
583341618Scy					 hapd->dpp_qr_mutual,
584341618Scy					 peer_bi, own_bi, freq, hdr, buf, len);
585341618Scy	if (!hapd->dpp_auth) {
586341618Scy		wpa_printf(MSG_DEBUG, "DPP: No response generated");
587341618Scy		return;
588341618Scy	}
589341618Scy	hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
590346981Scy	if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
591346981Scy				 hapd->dpp_auth,
592346981Scy				 hapd->dpp_configurator_params) < 0) {
593341618Scy		dpp_auth_deinit(hapd->dpp_auth);
594341618Scy		hapd->dpp_auth = NULL;
595341618Scy		return;
596341618Scy	}
597341618Scy	os_memcpy(hapd->dpp_auth->peer_mac_addr, src, ETH_ALEN);
598341618Scy
599341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
600341618Scy		" freq=%u type=%d",
601341618Scy		MAC2STR(src), hapd->dpp_auth->curr_freq,
602341618Scy		DPP_PA_AUTHENTICATION_RESP);
603341618Scy	hostapd_drv_send_action(hapd, hapd->dpp_auth->curr_freq, 0,
604341618Scy				src, wpabuf_head(hapd->dpp_auth->resp_msg),
605341618Scy				wpabuf_len(hapd->dpp_auth->resp_msg));
606341618Scy}
607341618Scy
608341618Scy
609341618Scystatic void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
610341618Scy					  struct dpp_authentication *auth)
611341618Scy{
612341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
613341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
614341618Scy		dpp_akm_str(auth->akm));
615341618Scy	if (auth->ssid_len)
616341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
617341618Scy			wpa_ssid_txt(auth->ssid, auth->ssid_len));
618341618Scy	if (auth->connector) {
619341618Scy		/* TODO: Save the Connector and consider using a command
620341618Scy		 * to fetch the value instead of sending an event with
621341618Scy		 * it. The Connector could end up being larger than what
622341618Scy		 * most clients are ready to receive as an event
623341618Scy		 * message. */
624341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
625341618Scy			auth->connector);
626341618Scy	} else if (auth->passphrase[0]) {
627341618Scy		char hex[64 * 2 + 1];
628341618Scy
629341618Scy		wpa_snprintf_hex(hex, sizeof(hex),
630341618Scy				 (const u8 *) auth->passphrase,
631341618Scy				 os_strlen(auth->passphrase));
632341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s",
633341618Scy			hex);
634341618Scy	} else if (auth->psk_set) {
635341618Scy		char hex[PMK_LEN * 2 + 1];
636341618Scy
637341618Scy		wpa_snprintf_hex(hex, sizeof(hex), auth->psk, PMK_LEN);
638341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
639341618Scy			hex);
640341618Scy	}
641341618Scy	if (auth->c_sign_key) {
642341618Scy		char *hex;
643341618Scy		size_t hexlen;
644341618Scy
645341618Scy		hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
646341618Scy		hex = os_malloc(hexlen);
647341618Scy		if (hex) {
648341618Scy			wpa_snprintf_hex(hex, hexlen,
649341618Scy					 wpabuf_head(auth->c_sign_key),
650341618Scy					 wpabuf_len(auth->c_sign_key));
651341618Scy			wpa_msg(hapd->msg_ctx, MSG_INFO,
652341618Scy				DPP_EVENT_C_SIGN_KEY "%s", hex);
653341618Scy			os_free(hex);
654341618Scy		}
655341618Scy	}
656341618Scy	if (auth->net_access_key) {
657341618Scy		char *hex;
658341618Scy		size_t hexlen;
659341618Scy
660341618Scy		hexlen = 2 * wpabuf_len(auth->net_access_key) + 1;
661341618Scy		hex = os_malloc(hexlen);
662341618Scy		if (hex) {
663341618Scy			wpa_snprintf_hex(hex, hexlen,
664341618Scy					 wpabuf_head(auth->net_access_key),
665341618Scy					 wpabuf_len(auth->net_access_key));
666341618Scy			if (auth->net_access_key_expiry)
667341618Scy				wpa_msg(hapd->msg_ctx, MSG_INFO,
668341618Scy					DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex,
669341618Scy					(unsigned long)
670341618Scy					auth->net_access_key_expiry);
671341618Scy			else
672341618Scy				wpa_msg(hapd->msg_ctx, MSG_INFO,
673341618Scy					DPP_EVENT_NET_ACCESS_KEY "%s", hex);
674341618Scy			os_free(hex);
675341618Scy		}
676341618Scy	}
677341618Scy}
678341618Scy
679341618Scy
680341618Scystatic void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
681341618Scy				    enum gas_query_ap_result result,
682341618Scy				    const struct wpabuf *adv_proto,
683341618Scy				    const struct wpabuf *resp, u16 status_code)
684341618Scy{
685341618Scy	struct hostapd_data *hapd = ctx;
686341618Scy	const u8 *pos;
687341618Scy	struct dpp_authentication *auth = hapd->dpp_auth;
688346981Scy	enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
689341618Scy
690341618Scy	if (!auth || !auth->auth_success) {
691341618Scy		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
692341618Scy		return;
693341618Scy	}
694341618Scy	if (!resp || status_code != WLAN_STATUS_SUCCESS) {
695341618Scy		wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
696341618Scy		goto fail;
697341618Scy	}
698341618Scy
699341618Scy	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
700341618Scy			adv_proto);
701341618Scy	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
702341618Scy			resp);
703341618Scy
704341618Scy	if (wpabuf_len(adv_proto) != 10 ||
705341618Scy	    !(pos = wpabuf_head(adv_proto)) ||
706341618Scy	    pos[0] != WLAN_EID_ADV_PROTO ||
707341618Scy	    pos[1] != 8 ||
708341618Scy	    pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
709341618Scy	    pos[4] != 5 ||
710341618Scy	    WPA_GET_BE24(&pos[5]) != OUI_WFA ||
711341618Scy	    pos[8] != 0x1a ||
712341618Scy	    pos[9] != 1) {
713341618Scy		wpa_printf(MSG_DEBUG,
714341618Scy			   "DPP: Not a DPP Advertisement Protocol ID");
715341618Scy		goto fail;
716341618Scy	}
717341618Scy
718341618Scy	if (dpp_conf_resp_rx(auth, resp) < 0) {
719341618Scy		wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
720341618Scy		goto fail;
721341618Scy	}
722341618Scy
723341618Scy	hostapd_dpp_handle_config_obj(hapd, auth);
724346981Scy	status = DPP_STATUS_OK;
725346981Scy#ifdef CONFIG_TESTING_OPTIONS
726346981Scy	if (dpp_test == DPP_TEST_REJECT_CONFIG) {
727346981Scy		wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
728346981Scy		status = DPP_STATUS_CONFIG_REJECTED;
729346981Scy	}
730346981Scy#endif /* CONFIG_TESTING_OPTIONS */
731346981Scyfail:
732346981Scy	if (status != DPP_STATUS_OK)
733346981Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
734346981Scy#ifdef CONFIG_DPP2
735346981Scy	if (auth->peer_version >= 2 &&
736346981Scy	    auth->conf_resp_status == DPP_STATUS_OK) {
737346981Scy		struct wpabuf *msg;
738341618Scy
739346981Scy		wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
740346981Scy		msg = dpp_build_conf_result(auth, status);
741346981Scy		if (!msg)
742346981Scy			goto fail2;
743346981Scy
744346981Scy		wpa_msg(hapd->msg_ctx, MSG_INFO,
745346981Scy			DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
746346981Scy			MAC2STR(addr), auth->curr_freq,
747346981Scy			DPP_PA_CONFIGURATION_RESULT);
748346981Scy		hostapd_drv_send_action(hapd, auth->curr_freq, 0,
749346981Scy					addr, wpabuf_head(msg),
750346981Scy					wpabuf_len(msg));
751346981Scy		wpabuf_free(msg);
752346981Scy
753346981Scy		/* This exchange will be terminated in the TX status handler */
754346981Scy		auth->connect_on_tx_status = 1;
755346981Scy		return;
756346981Scy	}
757346981Scyfail2:
758346981Scy#endif /* CONFIG_DPP2 */
759341618Scy	dpp_auth_deinit(hapd->dpp_auth);
760341618Scy	hapd->dpp_auth = NULL;
761341618Scy}
762341618Scy
763341618Scy
764341618Scystatic void hostapd_dpp_start_gas_client(struct hostapd_data *hapd)
765341618Scy{
766341618Scy	struct dpp_authentication *auth = hapd->dpp_auth;
767346981Scy	struct wpabuf *buf;
768341618Scy	char json[100];
769341618Scy	int res;
770341618Scy	int netrole_ap = 1;
771341618Scy
772341618Scy	os_snprintf(json, sizeof(json),
773341618Scy		    "{\"name\":\"Test\","
774341618Scy		    "\"wi-fi_tech\":\"infra\","
775341618Scy		    "\"netRole\":\"%s\"}",
776341618Scy		    netrole_ap ? "ap" : "sta");
777341618Scy	wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
778341618Scy
779346981Scy	buf = dpp_build_conf_req(auth, json);
780346981Scy	if (!buf) {
781341618Scy		wpa_printf(MSG_DEBUG,
782341618Scy			   "DPP: No configuration request data available");
783341618Scy		return;
784341618Scy	}
785341618Scy
786341618Scy	wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
787341618Scy		   MAC2STR(auth->peer_mac_addr), auth->curr_freq);
788341618Scy
789341618Scy	res = gas_query_ap_req(hapd->gas, auth->peer_mac_addr, auth->curr_freq,
790341618Scy			       buf, hostapd_dpp_gas_resp_cb, hapd);
791341618Scy	if (res < 0) {
792341618Scy		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
793341618Scy			"GAS: Failed to send Query Request");
794341618Scy		wpabuf_free(buf);
795341618Scy	} else {
796341618Scy		wpa_printf(MSG_DEBUG,
797341618Scy			   "DPP: GAS query started with dialog token %u", res);
798341618Scy	}
799341618Scy}
800341618Scy
801341618Scy
802341618Scystatic void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator)
803341618Scy{
804341618Scy	wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
805341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d",
806341618Scy		initiator);
807341618Scy#ifdef CONFIG_TESTING_OPTIONS
808341618Scy	if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
809341618Scy		wpa_printf(MSG_INFO,
810341618Scy			   "DPP: TESTING - stop at Authentication Confirm");
811341618Scy		if (hapd->dpp_auth->configurator) {
812341618Scy			/* Prevent GAS response */
813341618Scy			hapd->dpp_auth->auth_success = 0;
814341618Scy		}
815341618Scy		return;
816341618Scy	}
817341618Scy#endif /* CONFIG_TESTING_OPTIONS */
818341618Scy
819341618Scy	if (!hapd->dpp_auth->configurator)
820341618Scy		hostapd_dpp_start_gas_client(hapd);
821341618Scy}
822341618Scy
823341618Scy
824341618Scystatic void hostapd_dpp_rx_auth_resp(struct hostapd_data *hapd, const u8 *src,
825341618Scy				     const u8 *hdr, const u8 *buf, size_t len,
826341618Scy				     unsigned int freq)
827341618Scy{
828341618Scy	struct dpp_authentication *auth = hapd->dpp_auth;
829341618Scy	struct wpabuf *msg;
830341618Scy
831341618Scy	wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR,
832341618Scy		   MAC2STR(src));
833341618Scy
834341618Scy	if (!auth) {
835341618Scy		wpa_printf(MSG_DEBUG,
836341618Scy			   "DPP: No DPP Authentication in progress - drop");
837341618Scy		return;
838341618Scy	}
839341618Scy
840341618Scy	if (!is_zero_ether_addr(auth->peer_mac_addr) &&
841341618Scy	    os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
842341618Scy		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
843341618Scy			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
844341618Scy		return;
845341618Scy	}
846341618Scy
847341618Scy	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
848341618Scy
849341618Scy	if (auth->curr_freq != freq && auth->neg_freq == freq) {
850341618Scy		wpa_printf(MSG_DEBUG,
851341618Scy			   "DPP: Responder accepted request for different negotiation channel");
852341618Scy		auth->curr_freq = freq;
853341618Scy	}
854341618Scy
855341618Scy	eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
856341618Scy	msg = dpp_auth_resp_rx(auth, hdr, buf, len);
857341618Scy	if (!msg) {
858341618Scy		if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
859341618Scy			wpa_printf(MSG_DEBUG, "DPP: Wait for full response");
860341618Scy			return;
861341618Scy		}
862341618Scy		wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
863341618Scy		return;
864341618Scy	}
865341618Scy	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
866341618Scy
867341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
868341618Scy		" freq=%u type=%d", MAC2STR(src), auth->curr_freq,
869341618Scy		DPP_PA_AUTHENTICATION_CONF);
870341618Scy	hostapd_drv_send_action(hapd, auth->curr_freq, 0, src,
871341618Scy				wpabuf_head(msg), wpabuf_len(msg));
872341618Scy	wpabuf_free(msg);
873341618Scy	hapd->dpp_auth_ok_on_ack = 1;
874341618Scy}
875341618Scy
876341618Scy
877341618Scystatic void hostapd_dpp_rx_auth_conf(struct hostapd_data *hapd, const u8 *src,
878341618Scy				     const u8 *hdr, const u8 *buf, size_t len)
879341618Scy{
880341618Scy	struct dpp_authentication *auth = hapd->dpp_auth;
881341618Scy
882341618Scy	wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
883341618Scy		   MAC2STR(src));
884341618Scy
885341618Scy	if (!auth) {
886341618Scy		wpa_printf(MSG_DEBUG,
887341618Scy			   "DPP: No DPP Authentication in progress - drop");
888341618Scy		return;
889341618Scy	}
890341618Scy
891341618Scy	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
892341618Scy		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
893341618Scy			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
894341618Scy		return;
895341618Scy	}
896341618Scy
897341618Scy	if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
898341618Scy		wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
899341618Scy		return;
900341618Scy	}
901341618Scy
902341618Scy	hostapd_dpp_auth_success(hapd, 0);
903341618Scy}
904341618Scy
905341618Scy
906346981Scy#ifdef CONFIG_DPP2
907346981Scy
908346981Scystatic void hostapd_dpp_config_result_wait_timeout(void *eloop_ctx,
909346981Scy						   void *timeout_ctx)
910346981Scy{
911346981Scy	struct hostapd_data *hapd = eloop_ctx;
912346981Scy	struct dpp_authentication *auth = hapd->dpp_auth;
913346981Scy
914346981Scy	if (!auth || !auth->waiting_conf_result)
915346981Scy		return;
916346981Scy
917346981Scy	wpa_printf(MSG_DEBUG,
918346981Scy		   "DPP: Timeout while waiting for Configuration Result");
919346981Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
920346981Scy	dpp_auth_deinit(auth);
921346981Scy	hapd->dpp_auth = NULL;
922346981Scy}
923346981Scy
924346981Scy
925346981Scystatic void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
926346981Scy				       const u8 *hdr, const u8 *buf, size_t len)
927346981Scy{
928346981Scy	struct dpp_authentication *auth = hapd->dpp_auth;
929346981Scy	enum dpp_status_error status;
930346981Scy
931346981Scy	wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
932346981Scy		   MAC2STR(src));
933346981Scy
934346981Scy	if (!auth || !auth->waiting_conf_result) {
935346981Scy		wpa_printf(MSG_DEBUG,
936346981Scy			   "DPP: No DPP Configuration waiting for result - drop");
937346981Scy		return;
938346981Scy	}
939346981Scy
940346981Scy	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
941346981Scy		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
942346981Scy			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
943346981Scy		return;
944346981Scy	}
945346981Scy
946346981Scy	status = dpp_conf_result_rx(auth, hdr, buf, len);
947346981Scy
948346981Scy	hostapd_drv_send_action_cancel_wait(hapd);
949346981Scy	hostapd_dpp_listen_stop(hapd);
950346981Scy	if (status == DPP_STATUS_OK)
951346981Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
952346981Scy	else
953346981Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
954346981Scy	dpp_auth_deinit(auth);
955346981Scy	hapd->dpp_auth = NULL;
956346981Scy	eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
957346981Scy			     NULL);
958346981Scy}
959346981Scy
960346981Scy#endif /* CONFIG_DPP2 */
961346981Scy
962346981Scy
963341618Scystatic void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
964341618Scy					    const u8 *src, unsigned int freq,
965341618Scy					    u8 trans_id,
966341618Scy					    enum dpp_status_error status)
967341618Scy{
968341618Scy	struct wpabuf *msg;
969341618Scy
970341618Scy	msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP,
971341618Scy			    5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector));
972341618Scy	if (!msg)
973341618Scy		return;
974341618Scy
975341618Scy#ifdef CONFIG_TESTING_OPTIONS
976341618Scy	if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_RESP) {
977341618Scy		wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
978341618Scy		goto skip_trans_id;
979341618Scy	}
980341618Scy	if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_RESP) {
981341618Scy		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
982341618Scy		trans_id ^= 0x01;
983341618Scy	}
984341618Scy#endif /* CONFIG_TESTING_OPTIONS */
985341618Scy
986341618Scy	/* Transaction ID */
987341618Scy	wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
988341618Scy	wpabuf_put_le16(msg, 1);
989341618Scy	wpabuf_put_u8(msg, trans_id);
990341618Scy
991341618Scy#ifdef CONFIG_TESTING_OPTIONS
992341618Scyskip_trans_id:
993341618Scy	if (dpp_test == DPP_TEST_NO_STATUS_PEER_DISC_RESP) {
994341618Scy		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
995341618Scy		goto skip_status;
996341618Scy	}
997341618Scy	if (dpp_test == DPP_TEST_INVALID_STATUS_PEER_DISC_RESP) {
998341618Scy		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
999341618Scy		status = 254;
1000341618Scy	}
1001341618Scy#endif /* CONFIG_TESTING_OPTIONS */
1002341618Scy
1003341618Scy	/* DPP Status */
1004341618Scy	wpabuf_put_le16(msg, DPP_ATTR_STATUS);
1005341618Scy	wpabuf_put_le16(msg, 1);
1006341618Scy	wpabuf_put_u8(msg, status);
1007341618Scy
1008341618Scy#ifdef CONFIG_TESTING_OPTIONS
1009341618Scyskip_status:
1010341618Scy	if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_RESP) {
1011341618Scy		wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
1012341618Scy		goto skip_connector;
1013341618Scy	}
1014341618Scy	if (status == DPP_STATUS_OK &&
1015341618Scy	    dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_RESP) {
1016341618Scy		char *connector;
1017341618Scy
1018341618Scy		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
1019341618Scy		connector = dpp_corrupt_connector_signature(
1020341618Scy			hapd->conf->dpp_connector);
1021341618Scy		if (!connector) {
1022341618Scy			wpabuf_free(msg);
1023341618Scy			return;
1024341618Scy		}
1025341618Scy		wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
1026341618Scy		wpabuf_put_le16(msg, os_strlen(connector));
1027341618Scy		wpabuf_put_str(msg, connector);
1028341618Scy		os_free(connector);
1029341618Scy		goto skip_connector;
1030341618Scy	}
1031341618Scy#endif /* CONFIG_TESTING_OPTIONS */
1032341618Scy
1033341618Scy	/* DPP Connector */
1034341618Scy	if (status == DPP_STATUS_OK) {
1035341618Scy		wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
1036341618Scy		wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector));
1037341618Scy		wpabuf_put_str(msg, hapd->conf->dpp_connector);
1038341618Scy	}
1039341618Scy
1040341618Scy#ifdef CONFIG_TESTING_OPTIONS
1041341618Scyskip_connector:
1042341618Scy#endif /* CONFIG_TESTING_OPTIONS */
1043341618Scy
1044341618Scy	wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR
1045341618Scy		   " status=%d", MAC2STR(src), status);
1046341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1047341618Scy		" freq=%u type=%d status=%d", MAC2STR(src), freq,
1048341618Scy		DPP_PA_PEER_DISCOVERY_RESP, status);
1049341618Scy	hostapd_drv_send_action(hapd, freq, 0, src,
1050341618Scy				wpabuf_head(msg), wpabuf_len(msg));
1051341618Scy	wpabuf_free(msg);
1052341618Scy}
1053341618Scy
1054341618Scy
1055341618Scystatic void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
1056341618Scy					 const u8 *src,
1057341618Scy					 const u8 *buf, size_t len,
1058341618Scy					 unsigned int freq)
1059341618Scy{
1060341618Scy	const u8 *connector, *trans_id;
1061341618Scy	u16 connector_len, trans_id_len;
1062341618Scy	struct os_time now;
1063341618Scy	struct dpp_introduction intro;
1064341618Scy	os_time_t expire;
1065341618Scy	int expiration;
1066341618Scy	enum dpp_status_error res;
1067341618Scy
1068341618Scy	wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR,
1069341618Scy		   MAC2STR(src));
1070341618Scy	if (!hapd->wpa_auth ||
1071341618Scy	    !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) ||
1072341618Scy	    !(hapd->conf->wpa & WPA_PROTO_RSN)) {
1073341618Scy		wpa_printf(MSG_DEBUG, "DPP: DPP AKM not in use");
1074341618Scy		return;
1075341618Scy	}
1076341618Scy
1077341618Scy	if (!hapd->conf->dpp_connector || !hapd->conf->dpp_netaccesskey ||
1078341618Scy	    !hapd->conf->dpp_csign) {
1079341618Scy		wpa_printf(MSG_DEBUG, "DPP: No own Connector/keys set");
1080341618Scy		return;
1081341618Scy	}
1082341618Scy
1083341618Scy	os_get_time(&now);
1084341618Scy
1085341618Scy	if (hapd->conf->dpp_netaccesskey_expiry &&
1086341618Scy	    (os_time_t) hapd->conf->dpp_netaccesskey_expiry < now.sec) {
1087341618Scy		wpa_printf(MSG_INFO, "DPP: Own netAccessKey expired");
1088341618Scy		return;
1089341618Scy	}
1090341618Scy
1091341618Scy	trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
1092341618Scy			       &trans_id_len);
1093341618Scy	if (!trans_id || trans_id_len != 1) {
1094341618Scy		wpa_printf(MSG_DEBUG,
1095341618Scy			   "DPP: Peer did not include Transaction ID");
1096341618Scy		return;
1097341618Scy	}
1098341618Scy
1099341618Scy	connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len);
1100341618Scy	if (!connector) {
1101341618Scy		wpa_printf(MSG_DEBUG,
1102341618Scy			   "DPP: Peer did not include its Connector");
1103341618Scy		return;
1104341618Scy	}
1105341618Scy
1106341618Scy	res = dpp_peer_intro(&intro, hapd->conf->dpp_connector,
1107341618Scy			     wpabuf_head(hapd->conf->dpp_netaccesskey),
1108341618Scy			     wpabuf_len(hapd->conf->dpp_netaccesskey),
1109341618Scy			     wpabuf_head(hapd->conf->dpp_csign),
1110341618Scy			     wpabuf_len(hapd->conf->dpp_csign),
1111341618Scy			     connector, connector_len, &expire);
1112341618Scy	if (res == 255) {
1113341618Scy		wpa_printf(MSG_INFO,
1114341618Scy			   "DPP: Network Introduction protocol resulted in internal failure (peer "
1115341618Scy			   MACSTR ")", MAC2STR(src));
1116341618Scy		return;
1117341618Scy	}
1118341618Scy	if (res != DPP_STATUS_OK) {
1119341618Scy		wpa_printf(MSG_INFO,
1120341618Scy			   "DPP: Network Introduction protocol resulted in failure (peer "
1121341618Scy			   MACSTR " status %d)", MAC2STR(src), res);
1122341618Scy		hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
1123341618Scy						res);
1124341618Scy		return;
1125341618Scy	}
1126341618Scy
1127341618Scy	if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire)
1128341618Scy		expire = hapd->conf->dpp_netaccesskey_expiry;
1129341618Scy	if (expire)
1130341618Scy		expiration = expire - now.sec;
1131341618Scy	else
1132341618Scy		expiration = 0;
1133341618Scy
1134341618Scy	if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
1135341618Scy				intro.pmkid, expiration,
1136341618Scy				WPA_KEY_MGMT_DPP) < 0) {
1137341618Scy		wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
1138341618Scy		return;
1139341618Scy	}
1140341618Scy
1141341618Scy	hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
1142341618Scy					DPP_STATUS_OK);
1143341618Scy}
1144341618Scy
1145341618Scy
1146341618Scystatic void
1147341618Scyhostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
1148341618Scy				 const u8 *buf, size_t len,
1149341618Scy				 unsigned int freq)
1150341618Scy{
1151341618Scy	struct wpabuf *msg;
1152341618Scy
1153341618Scy	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR,
1154341618Scy		   MAC2STR(src));
1155341618Scy
1156341618Scy	/* TODO: Support multiple PKEX codes by iterating over all the enabled
1157341618Scy	 * values here */
1158341618Scy
1159341618Scy	if (!hapd->dpp_pkex_code || !hapd->dpp_pkex_bi) {
1160341618Scy		wpa_printf(MSG_DEBUG,
1161341618Scy			   "DPP: No PKEX code configured - ignore request");
1162341618Scy		return;
1163341618Scy	}
1164341618Scy
1165341618Scy	if (hapd->dpp_pkex) {
1166341618Scy		/* TODO: Support parallel operations */
1167341618Scy		wpa_printf(MSG_DEBUG,
1168341618Scy			   "DPP: Already in PKEX session - ignore new request");
1169341618Scy		return;
1170341618Scy	}
1171341618Scy
1172341618Scy	hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->msg_ctx,
1173341618Scy						  hapd->dpp_pkex_bi,
1174341618Scy						  hapd->own_addr, src,
1175341618Scy						  hapd->dpp_pkex_identifier,
1176341618Scy						  hapd->dpp_pkex_code,
1177341618Scy						  buf, len);
1178341618Scy	if (!hapd->dpp_pkex) {
1179341618Scy		wpa_printf(MSG_DEBUG,
1180341618Scy			   "DPP: Failed to process the request - ignore it");
1181341618Scy		return;
1182341618Scy	}
1183341618Scy
1184341618Scy	msg = hapd->dpp_pkex->exchange_resp;
1185341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1186341618Scy		" freq=%u type=%d", MAC2STR(src), freq,
1187341618Scy		DPP_PA_PKEX_EXCHANGE_RESP);
1188341618Scy	hostapd_drv_send_action(hapd, freq, 0, src,
1189341618Scy				wpabuf_head(msg), wpabuf_len(msg));
1190341618Scy	if (hapd->dpp_pkex->failed) {
1191341618Scy		wpa_printf(MSG_DEBUG,
1192341618Scy			   "DPP: Terminate PKEX exchange due to an earlier error");
1193341618Scy		if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
1194341618Scy			hapd->dpp_pkex->own_bi->pkex_t = hapd->dpp_pkex->t;
1195341618Scy		dpp_pkex_free(hapd->dpp_pkex);
1196341618Scy		hapd->dpp_pkex = NULL;
1197341618Scy	}
1198341618Scy}
1199341618Scy
1200341618Scy
1201341618Scystatic void
1202341618Scyhostapd_dpp_rx_pkex_exchange_resp(struct hostapd_data *hapd, const u8 *src,
1203341618Scy				  const u8 *buf, size_t len, unsigned int freq)
1204341618Scy{
1205341618Scy	struct wpabuf *msg;
1206341618Scy
1207341618Scy	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR,
1208341618Scy		   MAC2STR(src));
1209341618Scy
1210341618Scy	/* TODO: Support multiple PKEX codes by iterating over all the enabled
1211341618Scy	 * values here */
1212341618Scy
1213341618Scy	if (!hapd->dpp_pkex || !hapd->dpp_pkex->initiator ||
1214341618Scy	    hapd->dpp_pkex->exchange_done) {
1215341618Scy		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
1216341618Scy		return;
1217341618Scy	}
1218341618Scy
1219341618Scy	msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, src, buf, len);
1220341618Scy	if (!msg) {
1221341618Scy		wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
1222341618Scy		return;
1223341618Scy	}
1224341618Scy
1225341618Scy	wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR,
1226341618Scy		   MAC2STR(src));
1227341618Scy
1228341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1229341618Scy		" freq=%u type=%d", MAC2STR(src), freq,
1230341618Scy		DPP_PA_PKEX_COMMIT_REVEAL_REQ);
1231341618Scy	hostapd_drv_send_action(hapd, freq, 0, src,
1232341618Scy				wpabuf_head(msg), wpabuf_len(msg));
1233341618Scy	wpabuf_free(msg);
1234341618Scy}
1235341618Scy
1236341618Scy
1237341618Scystatic void
1238341618Scyhostapd_dpp_rx_pkex_commit_reveal_req(struct hostapd_data *hapd, const u8 *src,
1239341618Scy				      const u8 *hdr, const u8 *buf, size_t len,
1240341618Scy				      unsigned int freq)
1241341618Scy{
1242341618Scy	struct wpabuf *msg;
1243341618Scy	struct dpp_pkex *pkex = hapd->dpp_pkex;
1244341618Scy	struct dpp_bootstrap_info *bi;
1245341618Scy
1246341618Scy	wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR,
1247341618Scy		   MAC2STR(src));
1248341618Scy
1249341618Scy	if (!pkex || pkex->initiator || !pkex->exchange_done) {
1250341618Scy		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
1251341618Scy		return;
1252341618Scy	}
1253341618Scy
1254341618Scy	msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
1255341618Scy	if (!msg) {
1256341618Scy		wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
1257341618Scy		if (hapd->dpp_pkex->failed) {
1258341618Scy			wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
1259341618Scy			if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
1260341618Scy				hapd->dpp_pkex->own_bi->pkex_t =
1261341618Scy					hapd->dpp_pkex->t;
1262341618Scy			dpp_pkex_free(hapd->dpp_pkex);
1263341618Scy			hapd->dpp_pkex = NULL;
1264341618Scy		}
1265341618Scy		return;
1266341618Scy	}
1267341618Scy
1268341618Scy	wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to "
1269341618Scy		   MACSTR, MAC2STR(src));
1270341618Scy
1271341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1272341618Scy		" freq=%u type=%d", MAC2STR(src), freq,
1273341618Scy		DPP_PA_PKEX_COMMIT_REVEAL_RESP);
1274341618Scy	hostapd_drv_send_action(hapd, freq, 0, src,
1275341618Scy				wpabuf_head(msg), wpabuf_len(msg));
1276341618Scy	wpabuf_free(msg);
1277341618Scy
1278346981Scy	bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
1279341618Scy	if (!bi)
1280341618Scy		return;
1281341618Scy	hapd->dpp_pkex = NULL;
1282341618Scy}
1283341618Scy
1284341618Scy
1285341618Scystatic void
1286341618Scyhostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src,
1287341618Scy				       const u8 *hdr, const u8 *buf, size_t len,
1288341618Scy				       unsigned int freq)
1289341618Scy{
1290341618Scy	int res;
1291346981Scy	struct dpp_bootstrap_info *bi;
1292341618Scy	struct dpp_pkex *pkex = hapd->dpp_pkex;
1293341618Scy	char cmd[500];
1294341618Scy
1295341618Scy	wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR,
1296341618Scy		   MAC2STR(src));
1297341618Scy
1298341618Scy	if (!pkex || !pkex->initiator || !pkex->exchange_done) {
1299341618Scy		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
1300341618Scy		return;
1301341618Scy	}
1302341618Scy
1303341618Scy	res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len);
1304341618Scy	if (res < 0) {
1305341618Scy		wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
1306341618Scy		return;
1307341618Scy	}
1308341618Scy
1309346981Scy	bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
1310341618Scy	if (!bi)
1311341618Scy		return;
1312341618Scy	hapd->dpp_pkex = NULL;
1313341618Scy
1314341618Scy	os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
1315341618Scy		    bi->id,
1316341618Scy		    hapd->dpp_pkex_auth_cmd ? hapd->dpp_pkex_auth_cmd : "");
1317341618Scy	wpa_printf(MSG_DEBUG,
1318341618Scy		   "DPP: Start authentication after PKEX with parameters: %s",
1319341618Scy		   cmd);
1320341618Scy	if (hostapd_dpp_auth_init(hapd, cmd) < 0) {
1321341618Scy		wpa_printf(MSG_DEBUG,
1322341618Scy			   "DPP: Authentication initialization failed");
1323341618Scy		return;
1324341618Scy	}
1325341618Scy}
1326341618Scy
1327341618Scy
1328341618Scyvoid hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
1329341618Scy			   const u8 *buf, size_t len, unsigned int freq)
1330341618Scy{
1331341618Scy	u8 crypto_suite;
1332341618Scy	enum dpp_public_action_frame_type type;
1333341618Scy	const u8 *hdr;
1334341618Scy	unsigned int pkex_t;
1335341618Scy
1336341618Scy	if (len < DPP_HDR_LEN)
1337341618Scy		return;
1338341618Scy	if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE)
1339341618Scy		return;
1340341618Scy	hdr = buf;
1341341618Scy	buf += 4;
1342341618Scy	len -= 4;
1343341618Scy	crypto_suite = *buf++;
1344341618Scy	type = *buf++;
1345341618Scy	len -= 2;
1346341618Scy
1347341618Scy	wpa_printf(MSG_DEBUG,
1348341618Scy		   "DPP: Received DPP Public Action frame crypto suite %u type %d from "
1349341618Scy		   MACSTR " freq=%u",
1350341618Scy		   crypto_suite, type, MAC2STR(src), freq);
1351341618Scy	if (crypto_suite != 1) {
1352341618Scy		wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
1353341618Scy			   crypto_suite);
1354341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
1355341618Scy			" freq=%u type=%d ignore=unsupported-crypto-suite",
1356341618Scy			MAC2STR(src), freq, type);
1357341618Scy		return;
1358341618Scy	}
1359341618Scy	wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
1360341618Scy	if (dpp_check_attrs(buf, len) < 0) {
1361341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
1362341618Scy			" freq=%u type=%d ignore=invalid-attributes",
1363341618Scy			MAC2STR(src), freq, type);
1364341618Scy		return;
1365341618Scy	}
1366341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
1367341618Scy		" freq=%u type=%d", MAC2STR(src), freq, type);
1368341618Scy
1369351611Scy#ifdef CONFIG_DPP2
1370351611Scy	if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
1371351611Scy				src, hdr, buf, len, freq, NULL, NULL) == 0)
1372351611Scy		return;
1373351611Scy#endif /* CONFIG_DPP2 */
1374351611Scy
1375341618Scy	switch (type) {
1376341618Scy	case DPP_PA_AUTHENTICATION_REQ:
1377341618Scy		hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq);
1378341618Scy		break;
1379341618Scy	case DPP_PA_AUTHENTICATION_RESP:
1380341618Scy		hostapd_dpp_rx_auth_resp(hapd, src, hdr, buf, len, freq);
1381341618Scy		break;
1382341618Scy	case DPP_PA_AUTHENTICATION_CONF:
1383341618Scy		hostapd_dpp_rx_auth_conf(hapd, src, hdr, buf, len);
1384341618Scy		break;
1385341618Scy	case DPP_PA_PEER_DISCOVERY_REQ:
1386341618Scy		hostapd_dpp_rx_peer_disc_req(hapd, src, buf, len, freq);
1387341618Scy		break;
1388341618Scy	case DPP_PA_PKEX_EXCHANGE_REQ:
1389341618Scy		hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq);
1390341618Scy		break;
1391341618Scy	case DPP_PA_PKEX_EXCHANGE_RESP:
1392341618Scy		hostapd_dpp_rx_pkex_exchange_resp(hapd, src, buf, len, freq);
1393341618Scy		break;
1394341618Scy	case DPP_PA_PKEX_COMMIT_REVEAL_REQ:
1395341618Scy		hostapd_dpp_rx_pkex_commit_reveal_req(hapd, src, hdr, buf, len,
1396341618Scy						      freq);
1397341618Scy		break;
1398341618Scy	case DPP_PA_PKEX_COMMIT_REVEAL_RESP:
1399341618Scy		hostapd_dpp_rx_pkex_commit_reveal_resp(hapd, src, hdr, buf, len,
1400341618Scy						       freq);
1401341618Scy		break;
1402346981Scy#ifdef CONFIG_DPP2
1403346981Scy	case DPP_PA_CONFIGURATION_RESULT:
1404346981Scy		hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len);
1405346981Scy		break;
1406346981Scy#endif /* CONFIG_DPP2 */
1407341618Scy	default:
1408341618Scy		wpa_printf(MSG_DEBUG,
1409341618Scy			   "DPP: Ignored unsupported frame subtype %d", type);
1410341618Scy		break;
1411341618Scy	}
1412341618Scy
1413341618Scy	if (hapd->dpp_pkex)
1414341618Scy		pkex_t = hapd->dpp_pkex->t;
1415341618Scy	else if (hapd->dpp_pkex_bi)
1416341618Scy		pkex_t = hapd->dpp_pkex_bi->pkex_t;
1417341618Scy	else
1418341618Scy		pkex_t = 0;
1419341618Scy	if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
1420341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
1421341618Scy		hostapd_dpp_pkex_remove(hapd, "*");
1422341618Scy	}
1423341618Scy}
1424341618Scy
1425341618Scy
1426341618Scystruct wpabuf *
1427341618Scyhostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
1428351611Scy			    const u8 *query, size_t query_len,
1429351611Scy			    const u8 *data, size_t data_len)
1430341618Scy{
1431341618Scy	struct dpp_authentication *auth = hapd->dpp_auth;
1432341618Scy	struct wpabuf *resp;
1433341618Scy
1434341618Scy	wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
1435341618Scy	if (!auth || !auth->auth_success ||
1436341618Scy	    os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
1437351611Scy#ifdef CONFIG_DPP2
1438351611Scy		if (dpp_relay_rx_gas_req(hapd->iface->interfaces->dpp, sa, data,
1439351611Scy				     data_len) == 0) {
1440351611Scy			/* Response will be forwarded once received over TCP */
1441351611Scy			return NULL;
1442351611Scy		}
1443351611Scy#endif /* CONFIG_DPP2 */
1444341618Scy		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
1445341618Scy		return NULL;
1446341618Scy	}
1447341618Scy	wpa_hexdump(MSG_DEBUG,
1448341618Scy		    "DPP: Received Configuration Request (GAS Query Request)",
1449341618Scy		    query, query_len);
1450341618Scy	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
1451341618Scy		MAC2STR(sa));
1452341618Scy	resp = dpp_conf_req_rx(auth, query, query_len);
1453341618Scy	if (!resp)
1454341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
1455341618Scy	return resp;
1456341618Scy}
1457341618Scy
1458341618Scy
1459341618Scyvoid hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
1460341618Scy{
1461346981Scy	struct dpp_authentication *auth = hapd->dpp_auth;
1462346981Scy
1463346981Scy	if (!auth)
1464341618Scy		return;
1465341618Scy
1466346981Scy	wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
1467346981Scy		   ok);
1468341618Scy	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
1469341618Scy	eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
1470346981Scy#ifdef CONFIG_DPP2
1471346981Scy	if (ok && auth->peer_version >= 2 &&
1472346981Scy	    auth->conf_resp_status == DPP_STATUS_OK) {
1473346981Scy		wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
1474346981Scy		auth->waiting_conf_result = 1;
1475346981Scy		eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout,
1476346981Scy				     hapd, NULL);
1477346981Scy		eloop_register_timeout(2, 0,
1478346981Scy				       hostapd_dpp_config_result_wait_timeout,
1479346981Scy				       hapd, NULL);
1480346981Scy		return;
1481346981Scy	}
1482346981Scy#endif /* CONFIG_DPP2 */
1483341618Scy	hostapd_drv_send_action_cancel_wait(hapd);
1484341618Scy
1485341618Scy	if (ok)
1486341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
1487341618Scy	else
1488341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
1489341618Scy	dpp_auth_deinit(hapd->dpp_auth);
1490341618Scy	hapd->dpp_auth = NULL;
1491341618Scy}
1492341618Scy
1493341618Scy
1494341618Scyint hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
1495341618Scy{
1496341618Scy	struct dpp_authentication *auth;
1497341618Scy	int ret = -1;
1498341618Scy	char *curve = NULL;
1499341618Scy
1500341618Scy	auth = os_zalloc(sizeof(*auth));
1501341618Scy	if (!auth)
1502341618Scy		return -1;
1503341618Scy
1504341618Scy	curve = get_param(cmd, " curve=");
1505341618Scy	hostapd_dpp_set_testing_options(hapd, auth);
1506346981Scy	if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
1507346981Scy				 auth, cmd) == 0 &&
1508341618Scy	    dpp_configurator_own_config(auth, curve, 1) == 0) {
1509341618Scy		hostapd_dpp_handle_config_obj(hapd, auth);
1510341618Scy		ret = 0;
1511341618Scy	}
1512341618Scy
1513341618Scy	dpp_auth_deinit(auth);
1514341618Scy	os_free(curve);
1515341618Scy
1516341618Scy	return ret;
1517341618Scy}
1518341618Scy
1519341618Scy
1520341618Scyint hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
1521341618Scy{
1522341618Scy	struct dpp_bootstrap_info *own_bi;
1523341618Scy	const char *pos, *end;
1524341618Scy
1525341618Scy	pos = os_strstr(cmd, " own=");
1526341618Scy	if (!pos)
1527341618Scy		return -1;
1528341618Scy	pos += 5;
1529346981Scy	own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
1530341618Scy	if (!own_bi) {
1531341618Scy		wpa_printf(MSG_DEBUG,
1532341618Scy			   "DPP: Identified bootstrap info not found");
1533341618Scy		return -1;
1534341618Scy	}
1535341618Scy	if (own_bi->type != DPP_BOOTSTRAP_PKEX) {
1536341618Scy		wpa_printf(MSG_DEBUG,
1537341618Scy			   "DPP: Identified bootstrap info not for PKEX");
1538341618Scy		return -1;
1539341618Scy	}
1540341618Scy	hapd->dpp_pkex_bi = own_bi;
1541341618Scy	own_bi->pkex_t = 0; /* clear pending errors on new code */
1542341618Scy
1543341618Scy	os_free(hapd->dpp_pkex_identifier);
1544341618Scy	hapd->dpp_pkex_identifier = NULL;
1545341618Scy	pos = os_strstr(cmd, " identifier=");
1546341618Scy	if (pos) {
1547341618Scy		pos += 12;
1548341618Scy		end = os_strchr(pos, ' ');
1549341618Scy		if (!end)
1550341618Scy			return -1;
1551341618Scy		hapd->dpp_pkex_identifier = os_malloc(end - pos + 1);
1552341618Scy		if (!hapd->dpp_pkex_identifier)
1553341618Scy			return -1;
1554341618Scy		os_memcpy(hapd->dpp_pkex_identifier, pos, end - pos);
1555341618Scy		hapd->dpp_pkex_identifier[end - pos] = '\0';
1556341618Scy	}
1557341618Scy
1558341618Scy	pos = os_strstr(cmd, " code=");
1559341618Scy	if (!pos)
1560341618Scy		return -1;
1561341618Scy	os_free(hapd->dpp_pkex_code);
1562341618Scy	hapd->dpp_pkex_code = os_strdup(pos + 6);
1563341618Scy	if (!hapd->dpp_pkex_code)
1564341618Scy		return -1;
1565341618Scy
1566341618Scy	if (os_strstr(cmd, " init=1")) {
1567341618Scy		struct wpabuf *msg;
1568341618Scy
1569341618Scy		wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
1570341618Scy		dpp_pkex_free(hapd->dpp_pkex);
1571341618Scy		hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi,
1572341618Scy					       hapd->own_addr,
1573341618Scy					       hapd->dpp_pkex_identifier,
1574341618Scy					       hapd->dpp_pkex_code);
1575341618Scy		if (!hapd->dpp_pkex)
1576341618Scy			return -1;
1577341618Scy
1578341618Scy		msg = hapd->dpp_pkex->exchange_req;
1579341618Scy		/* TODO: Which channel to use? */
1580341618Scy		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1581341618Scy			" freq=%u type=%d", MAC2STR(broadcast), 2437,
1582341618Scy			DPP_PA_PKEX_EXCHANGE_REQ);
1583341618Scy		hostapd_drv_send_action(hapd, 2437, 0, broadcast,
1584341618Scy					wpabuf_head(msg), wpabuf_len(msg));
1585341618Scy	}
1586341618Scy
1587341618Scy	/* TODO: Support multiple PKEX info entries */
1588341618Scy
1589341618Scy	os_free(hapd->dpp_pkex_auth_cmd);
1590341618Scy	hapd->dpp_pkex_auth_cmd = os_strdup(cmd);
1591341618Scy
1592341618Scy	return 1;
1593341618Scy}
1594341618Scy
1595341618Scy
1596341618Scyint hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id)
1597341618Scy{
1598341618Scy	unsigned int id_val;
1599341618Scy
1600341618Scy	if (os_strcmp(id, "*") == 0) {
1601341618Scy		id_val = 0;
1602341618Scy	} else {
1603341618Scy		id_val = atoi(id);
1604341618Scy		if (id_val == 0)
1605341618Scy			return -1;
1606341618Scy	}
1607341618Scy
1608341618Scy	if ((id_val != 0 && id_val != 1) || !hapd->dpp_pkex_code)
1609341618Scy		return -1;
1610341618Scy
1611341618Scy	/* TODO: Support multiple PKEX entries */
1612341618Scy	os_free(hapd->dpp_pkex_code);
1613341618Scy	hapd->dpp_pkex_code = NULL;
1614341618Scy	os_free(hapd->dpp_pkex_identifier);
1615341618Scy	hapd->dpp_pkex_identifier = NULL;
1616341618Scy	os_free(hapd->dpp_pkex_auth_cmd);
1617341618Scy	hapd->dpp_pkex_auth_cmd = NULL;
1618341618Scy	hapd->dpp_pkex_bi = NULL;
1619341618Scy	/* TODO: Remove dpp_pkex only if it is for the identified PKEX code */
1620341618Scy	dpp_pkex_free(hapd->dpp_pkex);
1621341618Scy	hapd->dpp_pkex = NULL;
1622341618Scy	return 0;
1623341618Scy}
1624341618Scy
1625341618Scy
1626341618Scyvoid hostapd_dpp_stop(struct hostapd_data *hapd)
1627341618Scy{
1628341618Scy	dpp_auth_deinit(hapd->dpp_auth);
1629341618Scy	hapd->dpp_auth = NULL;
1630341618Scy	dpp_pkex_free(hapd->dpp_pkex);
1631341618Scy	hapd->dpp_pkex = NULL;
1632341618Scy}
1633341618Scy
1634341618Scy
1635351611Scy#ifdef CONFIG_DPP2
1636351611Scy
1637351611Scystatic void hostapd_dpp_relay_tx(void *ctx, const u8 *addr, unsigned int freq,
1638351611Scy				 const u8 *msg, size_t len)
1639351611Scy{
1640351611Scy	struct hostapd_data *hapd = ctx;
1641351611Scy	u8 *buf;
1642351611Scy
1643351611Scy	wpa_printf(MSG_DEBUG, "DPP: Send action frame dst=" MACSTR " freq=%u",
1644351611Scy		   MAC2STR(addr), freq);
1645351611Scy	buf = os_malloc(2 + len);
1646351611Scy	if (!buf)
1647351611Scy		return;
1648351611Scy	buf[0] = WLAN_ACTION_PUBLIC;
1649351611Scy	buf[1] = WLAN_PA_VENDOR_SPECIFIC;
1650351611Scy	os_memcpy(buf + 2, msg, len);
1651351611Scy	hostapd_drv_send_action(hapd, freq, 0, addr, buf, 2 + len);
1652351611Scy	os_free(buf);
1653351611Scy}
1654351611Scy
1655351611Scy
1656351611Scystatic void hostapd_dpp_relay_gas_resp_tx(void *ctx, const u8 *addr,
1657351611Scy					  u8 dialog_token, int prot,
1658351611Scy					  struct wpabuf *buf)
1659351611Scy{
1660351611Scy	struct hostapd_data *hapd = ctx;
1661351611Scy
1662351611Scy	gas_serv_req_dpp_processing(hapd, addr, dialog_token, prot, buf);
1663351611Scy}
1664351611Scy
1665351611Scy#endif /* CONFIG_DPP2 */
1666351611Scy
1667351611Scy
1668351611Scystatic int hostapd_dpp_add_controllers(struct hostapd_data *hapd)
1669351611Scy{
1670351611Scy#ifdef CONFIG_DPP2
1671351611Scy	struct dpp_controller_conf *ctrl;
1672351611Scy	struct dpp_relay_config config;
1673351611Scy
1674351611Scy	os_memset(&config, 0, sizeof(config));
1675351611Scy	config.cb_ctx = hapd;
1676351611Scy	config.tx = hostapd_dpp_relay_tx;
1677351611Scy	config.gas_resp_tx = hostapd_dpp_relay_gas_resp_tx;
1678351611Scy	for (ctrl = hapd->conf->dpp_controller; ctrl; ctrl = ctrl->next) {
1679351611Scy		config.ipaddr = &ctrl->ipaddr;
1680351611Scy		config.pkhash = ctrl->pkhash;
1681351611Scy		if (dpp_relay_add_controller(hapd->iface->interfaces->dpp,
1682351611Scy					     &config) < 0)
1683351611Scy			return -1;
1684351611Scy	}
1685351611Scy#endif /* CONFIG_DPP2 */
1686351611Scy
1687351611Scy	return 0;
1688351611Scy}
1689351611Scy
1690351611Scy
1691341618Scyint hostapd_dpp_init(struct hostapd_data *hapd)
1692341618Scy{
1693341618Scy	hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
1694341618Scy	hapd->dpp_init_done = 1;
1695351611Scy	return hostapd_dpp_add_controllers(hapd);
1696341618Scy}
1697341618Scy
1698341618Scy
1699341618Scyvoid hostapd_dpp_deinit(struct hostapd_data *hapd)
1700341618Scy{
1701341618Scy#ifdef CONFIG_TESTING_OPTIONS
1702341618Scy	os_free(hapd->dpp_config_obj_override);
1703341618Scy	hapd->dpp_config_obj_override = NULL;
1704341618Scy	os_free(hapd->dpp_discovery_override);
1705341618Scy	hapd->dpp_discovery_override = NULL;
1706341618Scy	os_free(hapd->dpp_groups_override);
1707341618Scy	hapd->dpp_groups_override = NULL;
1708341618Scy	hapd->dpp_ignore_netaccesskey_mismatch = 0;
1709341618Scy#endif /* CONFIG_TESTING_OPTIONS */
1710341618Scy	if (!hapd->dpp_init_done)
1711341618Scy		return;
1712341618Scy	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
1713341618Scy	eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
1714341618Scy	eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
1715346981Scy#ifdef CONFIG_DPP2
1716346981Scy	eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
1717346981Scy			     NULL);
1718346981Scy#endif /* CONFIG_DPP2 */
1719341618Scy	dpp_auth_deinit(hapd->dpp_auth);
1720341618Scy	hapd->dpp_auth = NULL;
1721341618Scy	hostapd_dpp_pkex_remove(hapd, "*");
1722341618Scy	hapd->dpp_pkex = NULL;
1723341618Scy	os_free(hapd->dpp_configurator_params);
1724341618Scy	hapd->dpp_configurator_params = NULL;
1725341618Scy}
1726