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