1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * hostapd / DPP integration
3e5b75505Sopenharmony_ci * Copyright (c) 2017, Qualcomm Atheros, Inc.
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "utils/includes.h"
10e5b75505Sopenharmony_ci
11e5b75505Sopenharmony_ci#include "utils/common.h"
12e5b75505Sopenharmony_ci#include "utils/eloop.h"
13e5b75505Sopenharmony_ci#include "common/dpp.h"
14e5b75505Sopenharmony_ci#include "common/gas.h"
15e5b75505Sopenharmony_ci#include "common/wpa_ctrl.h"
16e5b75505Sopenharmony_ci#include "hostapd.h"
17e5b75505Sopenharmony_ci#include "ap_drv_ops.h"
18e5b75505Sopenharmony_ci#include "gas_query_ap.h"
19e5b75505Sopenharmony_ci#include "gas_serv.h"
20e5b75505Sopenharmony_ci#include "wpa_auth.h"
21e5b75505Sopenharmony_ci#include "dpp_hostapd.h"
22e5b75505Sopenharmony_ci
23e5b75505Sopenharmony_ci
24e5b75505Sopenharmony_cistatic void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
25e5b75505Sopenharmony_cistatic void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
26e5b75505Sopenharmony_cistatic void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
27e5b75505Sopenharmony_cistatic int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
28e5b75505Sopenharmony_ci
29e5b75505Sopenharmony_cistatic const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
30e5b75505Sopenharmony_ci
31e5b75505Sopenharmony_ci
32e5b75505Sopenharmony_ci/**
33e5b75505Sopenharmony_ci * hostapd_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
34e5b75505Sopenharmony_ci * @hapd: Pointer to hostapd_data
35e5b75505Sopenharmony_ci * @cmd: DPP URI read from a QR Code
36e5b75505Sopenharmony_ci * Returns: Identifier of the stored info or -1 on failure
37e5b75505Sopenharmony_ci */
38e5b75505Sopenharmony_ciint hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd)
39e5b75505Sopenharmony_ci{
40e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
41e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
42e5b75505Sopenharmony_ci
43e5b75505Sopenharmony_ci	bi = dpp_add_qr_code(hapd->iface->interfaces->dpp, cmd);
44e5b75505Sopenharmony_ci	if (!bi)
45e5b75505Sopenharmony_ci		return -1;
46e5b75505Sopenharmony_ci
47e5b75505Sopenharmony_ci	if (auth && auth->response_pending &&
48e5b75505Sopenharmony_ci	    dpp_notify_new_qr_code(auth, bi) == 1) {
49e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
50e5b75505Sopenharmony_ci			   "DPP: Sending out pending authentication response");
51e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
52e5b75505Sopenharmony_ci			" freq=%u type=%d",
53e5b75505Sopenharmony_ci			MAC2STR(auth->peer_mac_addr), auth->curr_freq,
54e5b75505Sopenharmony_ci			DPP_PA_AUTHENTICATION_RESP);
55e5b75505Sopenharmony_ci		hostapd_drv_send_action(hapd, auth->curr_freq, 0,
56e5b75505Sopenharmony_ci					auth->peer_mac_addr,
57e5b75505Sopenharmony_ci					wpabuf_head(hapd->dpp_auth->resp_msg),
58e5b75505Sopenharmony_ci					wpabuf_len(hapd->dpp_auth->resp_msg));
59e5b75505Sopenharmony_ci	}
60e5b75505Sopenharmony_ci
61e5b75505Sopenharmony_ci	return bi->id;
62e5b75505Sopenharmony_ci}
63e5b75505Sopenharmony_ci
64e5b75505Sopenharmony_ci
65e5b75505Sopenharmony_cistatic void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
66e5b75505Sopenharmony_ci						void *timeout_ctx)
67e5b75505Sopenharmony_ci{
68e5b75505Sopenharmony_ci	struct hostapd_data *hapd = eloop_ctx;
69e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
70e5b75505Sopenharmony_ci
71e5b75505Sopenharmony_ci	if (!auth || !auth->resp_msg)
72e5b75505Sopenharmony_ci		return;
73e5b75505Sopenharmony_ci
74e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
75e5b75505Sopenharmony_ci		   "DPP: Retry Authentication Response after timeout");
76e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
77e5b75505Sopenharmony_ci		" freq=%u type=%d",
78e5b75505Sopenharmony_ci		MAC2STR(auth->peer_mac_addr), auth->curr_freq,
79e5b75505Sopenharmony_ci		DPP_PA_AUTHENTICATION_RESP);
80e5b75505Sopenharmony_ci	hostapd_drv_send_action(hapd, auth->curr_freq, 500, auth->peer_mac_addr,
81e5b75505Sopenharmony_ci				wpabuf_head(auth->resp_msg),
82e5b75505Sopenharmony_ci				wpabuf_len(auth->resp_msg));
83e5b75505Sopenharmony_ci}
84e5b75505Sopenharmony_ci
85e5b75505Sopenharmony_ci
86e5b75505Sopenharmony_cistatic void hostapd_dpp_auth_resp_retry(struct hostapd_data *hapd)
87e5b75505Sopenharmony_ci{
88e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
89e5b75505Sopenharmony_ci	unsigned int wait_time, max_tries;
90e5b75505Sopenharmony_ci
91e5b75505Sopenharmony_ci	if (!auth || !auth->resp_msg)
92e5b75505Sopenharmony_ci		return;
93e5b75505Sopenharmony_ci
94e5b75505Sopenharmony_ci	if (hapd->dpp_resp_max_tries)
95e5b75505Sopenharmony_ci		max_tries = hapd->dpp_resp_max_tries;
96e5b75505Sopenharmony_ci	else
97e5b75505Sopenharmony_ci		max_tries = 5;
98e5b75505Sopenharmony_ci	auth->auth_resp_tries++;
99e5b75505Sopenharmony_ci	if (auth->auth_resp_tries >= max_tries) {
100e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
101e5b75505Sopenharmony_ci			   "DPP: No confirm received from initiator - stopping exchange");
102e5b75505Sopenharmony_ci		hostapd_drv_send_action_cancel_wait(hapd);
103e5b75505Sopenharmony_ci		dpp_auth_deinit(hapd->dpp_auth);
104e5b75505Sopenharmony_ci		hapd->dpp_auth = NULL;
105e5b75505Sopenharmony_ci		return;
106e5b75505Sopenharmony_ci	}
107e5b75505Sopenharmony_ci
108e5b75505Sopenharmony_ci	if (hapd->dpp_resp_retry_time)
109e5b75505Sopenharmony_ci		wait_time = hapd->dpp_resp_retry_time;
110e5b75505Sopenharmony_ci	else
111e5b75505Sopenharmony_ci		wait_time = 1000;
112e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
113e5b75505Sopenharmony_ci		   "DPP: Schedule retransmission of Authentication Response frame in %u ms",
114e5b75505Sopenharmony_ci		wait_time);
115e5b75505Sopenharmony_ci	eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
116e5b75505Sopenharmony_ci	eloop_register_timeout(wait_time / 1000,
117e5b75505Sopenharmony_ci			       (wait_time % 1000) * 1000,
118e5b75505Sopenharmony_ci			       hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
119e5b75505Sopenharmony_ci}
120e5b75505Sopenharmony_ci
121e5b75505Sopenharmony_ci
122e5b75505Sopenharmony_civoid hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
123e5b75505Sopenharmony_ci			   const u8 *data, size_t data_len, int ok)
124e5b75505Sopenharmony_ci{
125e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
126e5b75505Sopenharmony_ci
127e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: TX status: dst=" MACSTR " ok=%d",
128e5b75505Sopenharmony_ci		   MAC2STR(dst), ok);
129e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
130e5b75505Sopenharmony_ci		" result=%s", MAC2STR(dst), ok ? "SUCCESS" : "FAILED");
131e5b75505Sopenharmony_ci
132e5b75505Sopenharmony_ci	if (!hapd->dpp_auth) {
133e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
134e5b75505Sopenharmony_ci			   "DPP: Ignore TX status since there is no ongoing authentication exchange");
135e5b75505Sopenharmony_ci		return;
136e5b75505Sopenharmony_ci	}
137e5b75505Sopenharmony_ci
138e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
139e5b75505Sopenharmony_ci	if (auth->connect_on_tx_status) {
140e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
141e5b75505Sopenharmony_ci			   "DPP: Complete exchange on configuration result");
142e5b75505Sopenharmony_ci		dpp_auth_deinit(hapd->dpp_auth);
143e5b75505Sopenharmony_ci		hapd->dpp_auth = NULL;
144e5b75505Sopenharmony_ci		return;
145e5b75505Sopenharmony_ci	}
146e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
147e5b75505Sopenharmony_ci
148e5b75505Sopenharmony_ci	if (hapd->dpp_auth->remove_on_tx_status) {
149e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
150e5b75505Sopenharmony_ci			   "DPP: Terminate authentication exchange due to an earlier error");
151e5b75505Sopenharmony_ci		eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
152e5b75505Sopenharmony_ci		eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
153e5b75505Sopenharmony_ci				     hapd, NULL);
154e5b75505Sopenharmony_ci		eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
155e5b75505Sopenharmony_ci				     NULL);
156e5b75505Sopenharmony_ci		hostapd_drv_send_action_cancel_wait(hapd);
157e5b75505Sopenharmony_ci		dpp_auth_deinit(hapd->dpp_auth);
158e5b75505Sopenharmony_ci		hapd->dpp_auth = NULL;
159e5b75505Sopenharmony_ci		return;
160e5b75505Sopenharmony_ci	}
161e5b75505Sopenharmony_ci
162e5b75505Sopenharmony_ci	if (hapd->dpp_auth_ok_on_ack)
163e5b75505Sopenharmony_ci		hostapd_dpp_auth_success(hapd, 1);
164e5b75505Sopenharmony_ci
165e5b75505Sopenharmony_ci	if (!is_broadcast_ether_addr(dst) && !ok) {
166e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
167e5b75505Sopenharmony_ci			   "DPP: Unicast DPP Action frame was not ACKed");
168e5b75505Sopenharmony_ci		if (auth->waiting_auth_resp) {
169e5b75505Sopenharmony_ci			/* In case of DPP Authentication Request frame, move to
170e5b75505Sopenharmony_ci			 * the next channel immediately. */
171e5b75505Sopenharmony_ci			hostapd_drv_send_action_cancel_wait(hapd);
172e5b75505Sopenharmony_ci			hostapd_dpp_auth_init_next(hapd);
173e5b75505Sopenharmony_ci			return;
174e5b75505Sopenharmony_ci		}
175e5b75505Sopenharmony_ci		if (auth->waiting_auth_conf) {
176e5b75505Sopenharmony_ci			hostapd_dpp_auth_resp_retry(hapd);
177e5b75505Sopenharmony_ci			return;
178e5b75505Sopenharmony_ci		}
179e5b75505Sopenharmony_ci	}
180e5b75505Sopenharmony_ci
181e5b75505Sopenharmony_ci	if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && ok) {
182e5b75505Sopenharmony_ci		/* Allow timeout handling to stop iteration if no response is
183e5b75505Sopenharmony_ci		 * received from a peer that has ACKed a request. */
184e5b75505Sopenharmony_ci		auth->auth_req_ack = 1;
185e5b75505Sopenharmony_ci	}
186e5b75505Sopenharmony_ci
187e5b75505Sopenharmony_ci	if (!hapd->dpp_auth_ok_on_ack && hapd->dpp_auth->neg_freq > 0 &&
188e5b75505Sopenharmony_ci	    hapd->dpp_auth->curr_freq != hapd->dpp_auth->neg_freq) {
189e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
190e5b75505Sopenharmony_ci			   "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
191e5b75505Sopenharmony_ci			   hapd->dpp_auth->curr_freq,
192e5b75505Sopenharmony_ci			   hapd->dpp_auth->neg_freq);
193e5b75505Sopenharmony_ci		hostapd_drv_send_action_cancel_wait(hapd);
194e5b75505Sopenharmony_ci
195e5b75505Sopenharmony_ci		if (hapd->dpp_auth->neg_freq !=
196e5b75505Sopenharmony_ci		    (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) {
197e5b75505Sopenharmony_ci			/* TODO: Listen operation on non-operating channel */
198e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO,
199e5b75505Sopenharmony_ci				   "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
200e5b75505Sopenharmony_ci				   hapd->dpp_auth->neg_freq, hapd->iface->freq);
201e5b75505Sopenharmony_ci		}
202e5b75505Sopenharmony_ci	}
203e5b75505Sopenharmony_ci
204e5b75505Sopenharmony_ci	if (hapd->dpp_auth_ok_on_ack)
205e5b75505Sopenharmony_ci		hapd->dpp_auth_ok_on_ack = 0;
206e5b75505Sopenharmony_ci}
207e5b75505Sopenharmony_ci
208e5b75505Sopenharmony_ci
209e5b75505Sopenharmony_cistatic void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
210e5b75505Sopenharmony_ci{
211e5b75505Sopenharmony_ci	struct hostapd_data *hapd = eloop_ctx;
212e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
213e5b75505Sopenharmony_ci	unsigned int freq;
214e5b75505Sopenharmony_ci	struct os_reltime now, diff;
215e5b75505Sopenharmony_ci	unsigned int wait_time, diff_ms;
216e5b75505Sopenharmony_ci
217e5b75505Sopenharmony_ci	if (!auth || !auth->waiting_auth_resp)
218e5b75505Sopenharmony_ci		return;
219e5b75505Sopenharmony_ci
220e5b75505Sopenharmony_ci	wait_time = hapd->dpp_resp_wait_time ?
221e5b75505Sopenharmony_ci		hapd->dpp_resp_wait_time : 2000;
222e5b75505Sopenharmony_ci	os_get_reltime(&now);
223e5b75505Sopenharmony_ci	os_reltime_sub(&now, &hapd->dpp_last_init, &diff);
224e5b75505Sopenharmony_ci	diff_ms = diff.sec * 1000 + diff.usec / 1000;
225e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
226e5b75505Sopenharmony_ci		   "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
227e5b75505Sopenharmony_ci		   wait_time, diff_ms);
228e5b75505Sopenharmony_ci
229e5b75505Sopenharmony_ci	if (auth->auth_req_ack && diff_ms >= wait_time) {
230e5b75505Sopenharmony_ci		/* Peer ACK'ed Authentication Request frame, but did not reply
231e5b75505Sopenharmony_ci		 * with Authentication Response frame within two seconds. */
232e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
233e5b75505Sopenharmony_ci			   "DPP: No response received from responder - stopping initiation attempt");
234e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
235e5b75505Sopenharmony_ci		hostapd_drv_send_action_cancel_wait(hapd);
236e5b75505Sopenharmony_ci		hostapd_dpp_listen_stop(hapd);
237e5b75505Sopenharmony_ci		dpp_auth_deinit(auth);
238e5b75505Sopenharmony_ci		hapd->dpp_auth = NULL;
239e5b75505Sopenharmony_ci		return;
240e5b75505Sopenharmony_ci	}
241e5b75505Sopenharmony_ci
242e5b75505Sopenharmony_ci	if (diff_ms >= wait_time) {
243e5b75505Sopenharmony_ci		/* Authentication Request frame was not ACK'ed and no reply
244e5b75505Sopenharmony_ci		 * was receiving within two seconds. */
245e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
246e5b75505Sopenharmony_ci			   "DPP: Continue Initiator channel iteration");
247e5b75505Sopenharmony_ci		hostapd_drv_send_action_cancel_wait(hapd);
248e5b75505Sopenharmony_ci		hostapd_dpp_listen_stop(hapd);
249e5b75505Sopenharmony_ci		hostapd_dpp_auth_init_next(hapd);
250e5b75505Sopenharmony_ci		return;
251e5b75505Sopenharmony_ci	}
252e5b75505Sopenharmony_ci
253e5b75505Sopenharmony_ci	/* Driver did not support 2000 ms long wait_time with TX command, so
254e5b75505Sopenharmony_ci	 * schedule listen operation to continue waiting for the response.
255e5b75505Sopenharmony_ci	 *
256e5b75505Sopenharmony_ci	 * DPP listen operations continue until stopped, so simply schedule a
257e5b75505Sopenharmony_ci	 * new call to this function at the point when the two second reply
258e5b75505Sopenharmony_ci	 * wait has expired. */
259e5b75505Sopenharmony_ci	wait_time -= diff_ms;
260e5b75505Sopenharmony_ci
261e5b75505Sopenharmony_ci	freq = auth->curr_freq;
262e5b75505Sopenharmony_ci	if (auth->neg_freq > 0)
263e5b75505Sopenharmony_ci		freq = auth->neg_freq;
264e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
265e5b75505Sopenharmony_ci		   "DPP: Continue reply wait on channel %u MHz for %u ms",
266e5b75505Sopenharmony_ci		   freq, wait_time);
267e5b75505Sopenharmony_ci	hapd->dpp_in_response_listen = 1;
268e5b75505Sopenharmony_ci
269e5b75505Sopenharmony_ci	if (freq != (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) {
270e5b75505Sopenharmony_ci		/* TODO: Listen operation on non-operating channel */
271e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
272e5b75505Sopenharmony_ci			   "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
273e5b75505Sopenharmony_ci			   freq, hapd->iface->freq);
274e5b75505Sopenharmony_ci	}
275e5b75505Sopenharmony_ci
276e5b75505Sopenharmony_ci	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
277e5b75505Sopenharmony_ci			       hostapd_dpp_reply_wait_timeout, hapd, NULL);
278e5b75505Sopenharmony_ci}
279e5b75505Sopenharmony_ci
280e5b75505Sopenharmony_ci
281e5b75505Sopenharmony_cistatic void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
282e5b75505Sopenharmony_ci					    struct dpp_authentication *auth)
283e5b75505Sopenharmony_ci{
284e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
285e5b75505Sopenharmony_ci	if (hapd->dpp_config_obj_override)
286e5b75505Sopenharmony_ci		auth->config_obj_override =
287e5b75505Sopenharmony_ci			os_strdup(hapd->dpp_config_obj_override);
288e5b75505Sopenharmony_ci	if (hapd->dpp_discovery_override)
289e5b75505Sopenharmony_ci		auth->discovery_override =
290e5b75505Sopenharmony_ci			os_strdup(hapd->dpp_discovery_override);
291e5b75505Sopenharmony_ci	if (hapd->dpp_groups_override)
292e5b75505Sopenharmony_ci		auth->groups_override = os_strdup(hapd->dpp_groups_override);
293e5b75505Sopenharmony_ci	auth->ignore_netaccesskey_mismatch =
294e5b75505Sopenharmony_ci		hapd->dpp_ignore_netaccesskey_mismatch;
295e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
296e5b75505Sopenharmony_ci}
297e5b75505Sopenharmony_ci
298e5b75505Sopenharmony_ci
299e5b75505Sopenharmony_cistatic void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
300e5b75505Sopenharmony_ci{
301e5b75505Sopenharmony_ci	struct hostapd_data *hapd = eloop_ctx;
302e5b75505Sopenharmony_ci
303e5b75505Sopenharmony_ci	if (!hapd->dpp_auth)
304e5b75505Sopenharmony_ci		return;
305e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
306e5b75505Sopenharmony_ci	hostapd_dpp_auth_init_next(hapd);
307e5b75505Sopenharmony_ci}
308e5b75505Sopenharmony_ci
309e5b75505Sopenharmony_ci
310e5b75505Sopenharmony_cistatic int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
311e5b75505Sopenharmony_ci{
312e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
313e5b75505Sopenharmony_ci	const u8 *dst;
314e5b75505Sopenharmony_ci	unsigned int wait_time, max_wait_time, freq, max_tries, used;
315e5b75505Sopenharmony_ci	struct os_reltime now, diff;
316e5b75505Sopenharmony_ci
317e5b75505Sopenharmony_ci	if (!auth)
318e5b75505Sopenharmony_ci		return -1;
319e5b75505Sopenharmony_ci
320e5b75505Sopenharmony_ci	if (auth->freq_idx == 0)
321e5b75505Sopenharmony_ci		os_get_reltime(&hapd->dpp_init_iter_start);
322e5b75505Sopenharmony_ci
323e5b75505Sopenharmony_ci	if (auth->freq_idx >= auth->num_freq) {
324e5b75505Sopenharmony_ci		auth->num_freq_iters++;
325e5b75505Sopenharmony_ci		if (hapd->dpp_init_max_tries)
326e5b75505Sopenharmony_ci			max_tries = hapd->dpp_init_max_tries;
327e5b75505Sopenharmony_ci		else
328e5b75505Sopenharmony_ci			max_tries = 5;
329e5b75505Sopenharmony_ci		if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
330e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO,
331e5b75505Sopenharmony_ci				   "DPP: No response received from responder - stopping initiation attempt");
332e5b75505Sopenharmony_ci			wpa_msg(hapd->msg_ctx, MSG_INFO,
333e5b75505Sopenharmony_ci				DPP_EVENT_AUTH_INIT_FAILED);
334e5b75505Sopenharmony_ci			eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
335e5b75505Sopenharmony_ci					     hapd, NULL);
336e5b75505Sopenharmony_ci			hostapd_drv_send_action_cancel_wait(hapd);
337e5b75505Sopenharmony_ci			dpp_auth_deinit(hapd->dpp_auth);
338e5b75505Sopenharmony_ci			hapd->dpp_auth = NULL;
339e5b75505Sopenharmony_ci			return -1;
340e5b75505Sopenharmony_ci		}
341e5b75505Sopenharmony_ci		auth->freq_idx = 0;
342e5b75505Sopenharmony_ci		eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
343e5b75505Sopenharmony_ci		if (hapd->dpp_init_retry_time)
344e5b75505Sopenharmony_ci			wait_time = hapd->dpp_init_retry_time;
345e5b75505Sopenharmony_ci		else
346e5b75505Sopenharmony_ci			wait_time = 10000;
347e5b75505Sopenharmony_ci		os_get_reltime(&now);
348e5b75505Sopenharmony_ci		os_reltime_sub(&now, &hapd->dpp_init_iter_start, &diff);
349e5b75505Sopenharmony_ci		used = diff.sec * 1000 + diff.usec / 1000;
350e5b75505Sopenharmony_ci		if (used > wait_time)
351e5b75505Sopenharmony_ci			wait_time = 0;
352e5b75505Sopenharmony_ci		else
353e5b75505Sopenharmony_ci			wait_time -= used;
354e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
355e5b75505Sopenharmony_ci			   wait_time);
356e5b75505Sopenharmony_ci		eloop_register_timeout(wait_time / 1000,
357e5b75505Sopenharmony_ci				       (wait_time % 1000) * 1000,
358e5b75505Sopenharmony_ci				       hostapd_dpp_init_timeout, hapd,
359e5b75505Sopenharmony_ci				       NULL);
360e5b75505Sopenharmony_ci		return 0;
361e5b75505Sopenharmony_ci	}
362e5b75505Sopenharmony_ci	freq = auth->freq[auth->freq_idx++];
363e5b75505Sopenharmony_ci	auth->curr_freq = freq;
364e5b75505Sopenharmony_ci
365e5b75505Sopenharmony_ci	if (is_zero_ether_addr(auth->peer_bi->mac_addr))
366e5b75505Sopenharmony_ci		dst = broadcast;
367e5b75505Sopenharmony_ci	else
368e5b75505Sopenharmony_ci		dst = auth->peer_bi->mac_addr;
369e5b75505Sopenharmony_ci	hapd->dpp_auth_ok_on_ack = 0;
370e5b75505Sopenharmony_ci	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
371e5b75505Sopenharmony_ci	wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
372e5b75505Sopenharmony_ci	max_wait_time = hapd->dpp_resp_wait_time ?
373e5b75505Sopenharmony_ci		hapd->dpp_resp_wait_time : 2000;
374e5b75505Sopenharmony_ci	if (wait_time > max_wait_time)
375e5b75505Sopenharmony_ci		wait_time = max_wait_time;
376e5b75505Sopenharmony_ci	wait_time += 10; /* give the driver some extra time to complete */
377e5b75505Sopenharmony_ci	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
378e5b75505Sopenharmony_ci			       hostapd_dpp_reply_wait_timeout, hapd, NULL);
379e5b75505Sopenharmony_ci	wait_time -= 10;
380e5b75505Sopenharmony_ci	if (auth->neg_freq > 0 && freq != auth->neg_freq) {
381e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
382e5b75505Sopenharmony_ci			   "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
383e5b75505Sopenharmony_ci			   freq, auth->neg_freq);
384e5b75505Sopenharmony_ci	}
385e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
386e5b75505Sopenharmony_ci		" freq=%u type=%d",
387e5b75505Sopenharmony_ci		MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
388e5b75505Sopenharmony_ci	auth->auth_req_ack = 0;
389e5b75505Sopenharmony_ci	os_get_reltime(&hapd->dpp_last_init);
390e5b75505Sopenharmony_ci	return hostapd_drv_send_action(hapd, freq, wait_time,
391e5b75505Sopenharmony_ci				       dst,
392e5b75505Sopenharmony_ci				       wpabuf_head(hapd->dpp_auth->req_msg),
393e5b75505Sopenharmony_ci				       wpabuf_len(hapd->dpp_auth->req_msg));
394e5b75505Sopenharmony_ci}
395e5b75505Sopenharmony_ci
396e5b75505Sopenharmony_ci
397e5b75505Sopenharmony_ciint hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
398e5b75505Sopenharmony_ci{
399e5b75505Sopenharmony_ci	const char *pos;
400e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
401e5b75505Sopenharmony_ci	u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
402e5b75505Sopenharmony_ci	unsigned int neg_freq = 0;
403e5b75505Sopenharmony_ci
404e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " peer=");
405e5b75505Sopenharmony_ci	if (!pos)
406e5b75505Sopenharmony_ci		return -1;
407e5b75505Sopenharmony_ci	pos += 6;
408e5b75505Sopenharmony_ci	peer_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
409e5b75505Sopenharmony_ci	if (!peer_bi) {
410e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
411e5b75505Sopenharmony_ci			   "DPP: Could not find bootstrapping info for the identified peer");
412e5b75505Sopenharmony_ci		return -1;
413e5b75505Sopenharmony_ci	}
414e5b75505Sopenharmony_ci
415e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " own=");
416e5b75505Sopenharmony_ci	if (pos) {
417e5b75505Sopenharmony_ci		pos += 5;
418e5b75505Sopenharmony_ci		own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp,
419e5b75505Sopenharmony_ci					      atoi(pos));
420e5b75505Sopenharmony_ci		if (!own_bi) {
421e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO,
422e5b75505Sopenharmony_ci				   "DPP: Could not find bootstrapping info for the identified local entry");
423e5b75505Sopenharmony_ci			return -1;
424e5b75505Sopenharmony_ci		}
425e5b75505Sopenharmony_ci
426e5b75505Sopenharmony_ci		if (peer_bi->curve != own_bi->curve) {
427e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO,
428e5b75505Sopenharmony_ci				   "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
429e5b75505Sopenharmony_ci				   peer_bi->curve->name, own_bi->curve->name);
430e5b75505Sopenharmony_ci			return -1;
431e5b75505Sopenharmony_ci		}
432e5b75505Sopenharmony_ci	}
433e5b75505Sopenharmony_ci
434e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " role=");
435e5b75505Sopenharmony_ci	if (pos) {
436e5b75505Sopenharmony_ci		pos += 6;
437e5b75505Sopenharmony_ci		if (os_strncmp(pos, "configurator", 12) == 0)
438e5b75505Sopenharmony_ci			allowed_roles = DPP_CAPAB_CONFIGURATOR;
439e5b75505Sopenharmony_ci		else if (os_strncmp(pos, "enrollee", 8) == 0)
440e5b75505Sopenharmony_ci			allowed_roles = DPP_CAPAB_ENROLLEE;
441e5b75505Sopenharmony_ci		else if (os_strncmp(pos, "either", 6) == 0)
442e5b75505Sopenharmony_ci			allowed_roles = DPP_CAPAB_CONFIGURATOR |
443e5b75505Sopenharmony_ci				DPP_CAPAB_ENROLLEE;
444e5b75505Sopenharmony_ci		else
445e5b75505Sopenharmony_ci			goto fail;
446e5b75505Sopenharmony_ci	}
447e5b75505Sopenharmony_ci
448e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " neg_freq=");
449e5b75505Sopenharmony_ci	if (pos)
450e5b75505Sopenharmony_ci		neg_freq = atoi(pos + 10);
451e5b75505Sopenharmony_ci
452e5b75505Sopenharmony_ci	if (hapd->dpp_auth) {
453e5b75505Sopenharmony_ci		eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
454e5b75505Sopenharmony_ci		eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
455e5b75505Sopenharmony_ci				     hapd, NULL);
456e5b75505Sopenharmony_ci		eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
457e5b75505Sopenharmony_ci				     NULL);
458e5b75505Sopenharmony_ci		hostapd_drv_send_action_cancel_wait(hapd);
459e5b75505Sopenharmony_ci		dpp_auth_deinit(hapd->dpp_auth);
460e5b75505Sopenharmony_ci	}
461e5b75505Sopenharmony_ci
462e5b75505Sopenharmony_ci	hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi,
463e5b75505Sopenharmony_ci				       allowed_roles, neg_freq,
464e5b75505Sopenharmony_ci				       hapd->iface->hw_features,
465e5b75505Sopenharmony_ci				       hapd->iface->num_hw_features);
466e5b75505Sopenharmony_ci	if (!hapd->dpp_auth)
467e5b75505Sopenharmony_ci		goto fail;
468e5b75505Sopenharmony_ci	hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
469e5b75505Sopenharmony_ci	if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
470e5b75505Sopenharmony_ci				 hapd->dpp_auth, cmd) < 0) {
471e5b75505Sopenharmony_ci		dpp_auth_deinit(hapd->dpp_auth);
472e5b75505Sopenharmony_ci		hapd->dpp_auth = NULL;
473e5b75505Sopenharmony_ci		goto fail;
474e5b75505Sopenharmony_ci	}
475e5b75505Sopenharmony_ci
476e5b75505Sopenharmony_ci	hapd->dpp_auth->neg_freq = neg_freq;
477e5b75505Sopenharmony_ci
478e5b75505Sopenharmony_ci	if (!is_zero_ether_addr(peer_bi->mac_addr))
479e5b75505Sopenharmony_ci		os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
480e5b75505Sopenharmony_ci			  ETH_ALEN);
481e5b75505Sopenharmony_ci
482e5b75505Sopenharmony_ci	return hostapd_dpp_auth_init_next(hapd);
483e5b75505Sopenharmony_cifail:
484e5b75505Sopenharmony_ci	return -1;
485e5b75505Sopenharmony_ci}
486e5b75505Sopenharmony_ci
487e5b75505Sopenharmony_ci
488e5b75505Sopenharmony_ciint hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd)
489e5b75505Sopenharmony_ci{
490e5b75505Sopenharmony_ci	int freq;
491e5b75505Sopenharmony_ci
492e5b75505Sopenharmony_ci	freq = atoi(cmd);
493e5b75505Sopenharmony_ci	if (freq <= 0)
494e5b75505Sopenharmony_ci		return -1;
495e5b75505Sopenharmony_ci
496e5b75505Sopenharmony_ci	if (os_strstr(cmd, " role=configurator"))
497e5b75505Sopenharmony_ci		hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR;
498e5b75505Sopenharmony_ci	else if (os_strstr(cmd, " role=enrollee"))
499e5b75505Sopenharmony_ci		hapd->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
500e5b75505Sopenharmony_ci	else
501e5b75505Sopenharmony_ci		hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
502e5b75505Sopenharmony_ci			DPP_CAPAB_ENROLLEE;
503e5b75505Sopenharmony_ci	hapd->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
504e5b75505Sopenharmony_ci
505e5b75505Sopenharmony_ci	if (freq != hapd->iface->freq && hapd->iface->freq > 0) {
506e5b75505Sopenharmony_ci		/* TODO: Listen operation on non-operating channel */
507e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
508e5b75505Sopenharmony_ci			   "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
509e5b75505Sopenharmony_ci			   freq, hapd->iface->freq);
510e5b75505Sopenharmony_ci		return -1;
511e5b75505Sopenharmony_ci	}
512e5b75505Sopenharmony_ci
513e5b75505Sopenharmony_ci	return 0;
514e5b75505Sopenharmony_ci}
515e5b75505Sopenharmony_ci
516e5b75505Sopenharmony_ci
517e5b75505Sopenharmony_civoid hostapd_dpp_listen_stop(struct hostapd_data *hapd)
518e5b75505Sopenharmony_ci{
519e5b75505Sopenharmony_ci	/* TODO: Stop listen operation on non-operating channel */
520e5b75505Sopenharmony_ci}
521e5b75505Sopenharmony_ci
522e5b75505Sopenharmony_ci
523e5b75505Sopenharmony_cistatic void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
524e5b75505Sopenharmony_ci				    const u8 *hdr, const u8 *buf, size_t len,
525e5b75505Sopenharmony_ci				    unsigned int freq)
526e5b75505Sopenharmony_ci{
527e5b75505Sopenharmony_ci	const u8 *r_bootstrap, *i_bootstrap;
528e5b75505Sopenharmony_ci	u16 r_bootstrap_len, i_bootstrap_len;
529e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
530e5b75505Sopenharmony_ci
531e5b75505Sopenharmony_ci	if (!hapd->iface->interfaces->dpp)
532e5b75505Sopenharmony_ci		return;
533e5b75505Sopenharmony_ci
534e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
535e5b75505Sopenharmony_ci		   MAC2STR(src));
536e5b75505Sopenharmony_ci
537e5b75505Sopenharmony_ci	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
538e5b75505Sopenharmony_ci				   &r_bootstrap_len);
539e5b75505Sopenharmony_ci	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
540e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
541e5b75505Sopenharmony_ci			"Missing or invalid required Responder Bootstrapping Key Hash attribute");
542e5b75505Sopenharmony_ci		return;
543e5b75505Sopenharmony_ci	}
544e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
545e5b75505Sopenharmony_ci		    r_bootstrap, r_bootstrap_len);
546e5b75505Sopenharmony_ci
547e5b75505Sopenharmony_ci	i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
548e5b75505Sopenharmony_ci				   &i_bootstrap_len);
549e5b75505Sopenharmony_ci	if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
550e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
551e5b75505Sopenharmony_ci			"Missing or invalid required Initiator Bootstrapping Key Hash attribute");
552e5b75505Sopenharmony_ci		return;
553e5b75505Sopenharmony_ci	}
554e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
555e5b75505Sopenharmony_ci		    i_bootstrap, i_bootstrap_len);
556e5b75505Sopenharmony_ci
557e5b75505Sopenharmony_ci	/* Try to find own and peer bootstrapping key matches based on the
558e5b75505Sopenharmony_ci	 * received hash values */
559e5b75505Sopenharmony_ci	dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap,
560e5b75505Sopenharmony_ci				r_bootstrap, &own_bi, &peer_bi);
561e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
562e5b75505Sopenharmony_ci	if (!own_bi) {
563e5b75505Sopenharmony_ci		if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
564e5b75505Sopenharmony_ci					src, hdr, buf, len, freq, i_bootstrap,
565e5b75505Sopenharmony_ci					r_bootstrap) == 0)
566e5b75505Sopenharmony_ci			return;
567e5b75505Sopenharmony_ci	}
568e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
569e5b75505Sopenharmony_ci	if (!own_bi) {
570e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
571e5b75505Sopenharmony_ci			"No matching own bootstrapping key found - ignore message");
572e5b75505Sopenharmony_ci		return;
573e5b75505Sopenharmony_ci	}
574e5b75505Sopenharmony_ci
575e5b75505Sopenharmony_ci	if (hapd->dpp_auth) {
576e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
577e5b75505Sopenharmony_ci			"Already in DPP authentication exchange - ignore new one");
578e5b75505Sopenharmony_ci		return;
579e5b75505Sopenharmony_ci	}
580e5b75505Sopenharmony_ci
581e5b75505Sopenharmony_ci	hapd->dpp_auth_ok_on_ack = 0;
582e5b75505Sopenharmony_ci	hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles,
583e5b75505Sopenharmony_ci					 hapd->dpp_qr_mutual,
584e5b75505Sopenharmony_ci					 peer_bi, own_bi, freq, hdr, buf, len);
585e5b75505Sopenharmony_ci	if (!hapd->dpp_auth) {
586e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No response generated");
587e5b75505Sopenharmony_ci		return;
588e5b75505Sopenharmony_ci	}
589e5b75505Sopenharmony_ci	hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
590e5b75505Sopenharmony_ci	if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
591e5b75505Sopenharmony_ci				 hapd->dpp_auth,
592e5b75505Sopenharmony_ci				 hapd->dpp_configurator_params) < 0) {
593e5b75505Sopenharmony_ci		dpp_auth_deinit(hapd->dpp_auth);
594e5b75505Sopenharmony_ci		hapd->dpp_auth = NULL;
595e5b75505Sopenharmony_ci		return;
596e5b75505Sopenharmony_ci	}
597e5b75505Sopenharmony_ci	os_memcpy(hapd->dpp_auth->peer_mac_addr, src, ETH_ALEN);
598e5b75505Sopenharmony_ci
599e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
600e5b75505Sopenharmony_ci		" freq=%u type=%d",
601e5b75505Sopenharmony_ci		MAC2STR(src), hapd->dpp_auth->curr_freq,
602e5b75505Sopenharmony_ci		DPP_PA_AUTHENTICATION_RESP);
603e5b75505Sopenharmony_ci	hostapd_drv_send_action(hapd, hapd->dpp_auth->curr_freq, 0,
604e5b75505Sopenharmony_ci				src, wpabuf_head(hapd->dpp_auth->resp_msg),
605e5b75505Sopenharmony_ci				wpabuf_len(hapd->dpp_auth->resp_msg));
606e5b75505Sopenharmony_ci}
607e5b75505Sopenharmony_ci
608e5b75505Sopenharmony_ci
609e5b75505Sopenharmony_cistatic void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
610e5b75505Sopenharmony_ci					  struct dpp_authentication *auth)
611e5b75505Sopenharmony_ci{
612e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
613e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
614e5b75505Sopenharmony_ci		dpp_akm_str(auth->akm));
615e5b75505Sopenharmony_ci	if (auth->ssid_len)
616e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
617e5b75505Sopenharmony_ci			wpa_ssid_txt(auth->ssid, auth->ssid_len));
618e5b75505Sopenharmony_ci	if (auth->connector) {
619e5b75505Sopenharmony_ci		/* TODO: Save the Connector and consider using a command
620e5b75505Sopenharmony_ci		 * to fetch the value instead of sending an event with
621e5b75505Sopenharmony_ci		 * it. The Connector could end up being larger than what
622e5b75505Sopenharmony_ci		 * most clients are ready to receive as an event
623e5b75505Sopenharmony_ci		 * message. */
624e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
625e5b75505Sopenharmony_ci			auth->connector);
626e5b75505Sopenharmony_ci	} else if (auth->passphrase[0]) {
627e5b75505Sopenharmony_ci		char hex[64 * 2 + 1];
628e5b75505Sopenharmony_ci
629e5b75505Sopenharmony_ci		wpa_snprintf_hex(hex, sizeof(hex),
630e5b75505Sopenharmony_ci				 (const u8 *) auth->passphrase,
631e5b75505Sopenharmony_ci				 os_strlen(auth->passphrase));
632e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s",
633e5b75505Sopenharmony_ci			hex);
634e5b75505Sopenharmony_ci	} else if (auth->psk_set) {
635e5b75505Sopenharmony_ci		char hex[PMK_LEN * 2 + 1];
636e5b75505Sopenharmony_ci
637e5b75505Sopenharmony_ci		wpa_snprintf_hex(hex, sizeof(hex), auth->psk, PMK_LEN);
638e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
639e5b75505Sopenharmony_ci			hex);
640e5b75505Sopenharmony_ci	}
641e5b75505Sopenharmony_ci	if (auth->c_sign_key) {
642e5b75505Sopenharmony_ci		char *hex;
643e5b75505Sopenharmony_ci		size_t hexlen;
644e5b75505Sopenharmony_ci
645e5b75505Sopenharmony_ci		hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
646e5b75505Sopenharmony_ci		hex = os_malloc(hexlen);
647e5b75505Sopenharmony_ci		if (hex) {
648e5b75505Sopenharmony_ci			wpa_snprintf_hex(hex, hexlen,
649e5b75505Sopenharmony_ci					 wpabuf_head(auth->c_sign_key),
650e5b75505Sopenharmony_ci					 wpabuf_len(auth->c_sign_key));
651e5b75505Sopenharmony_ci			wpa_msg(hapd->msg_ctx, MSG_INFO,
652e5b75505Sopenharmony_ci				DPP_EVENT_C_SIGN_KEY "%s", hex);
653e5b75505Sopenharmony_ci			os_free(hex);
654e5b75505Sopenharmony_ci		}
655e5b75505Sopenharmony_ci	}
656e5b75505Sopenharmony_ci	if (auth->net_access_key) {
657e5b75505Sopenharmony_ci		char *hex;
658e5b75505Sopenharmony_ci		size_t hexlen;
659e5b75505Sopenharmony_ci
660e5b75505Sopenharmony_ci		hexlen = 2 * wpabuf_len(auth->net_access_key) + 1;
661e5b75505Sopenharmony_ci		hex = os_malloc(hexlen);
662e5b75505Sopenharmony_ci		if (hex) {
663e5b75505Sopenharmony_ci			wpa_snprintf_hex(hex, hexlen,
664e5b75505Sopenharmony_ci					 wpabuf_head(auth->net_access_key),
665e5b75505Sopenharmony_ci					 wpabuf_len(auth->net_access_key));
666e5b75505Sopenharmony_ci			if (auth->net_access_key_expiry)
667e5b75505Sopenharmony_ci				wpa_msg(hapd->msg_ctx, MSG_INFO,
668e5b75505Sopenharmony_ci					DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex,
669e5b75505Sopenharmony_ci					(unsigned long)
670e5b75505Sopenharmony_ci					auth->net_access_key_expiry);
671e5b75505Sopenharmony_ci			else
672e5b75505Sopenharmony_ci				wpa_msg(hapd->msg_ctx, MSG_INFO,
673e5b75505Sopenharmony_ci					DPP_EVENT_NET_ACCESS_KEY "%s", hex);
674e5b75505Sopenharmony_ci			os_free(hex);
675e5b75505Sopenharmony_ci		}
676e5b75505Sopenharmony_ci	}
677e5b75505Sopenharmony_ci}
678e5b75505Sopenharmony_ci
679e5b75505Sopenharmony_ci
680e5b75505Sopenharmony_cistatic void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
681e5b75505Sopenharmony_ci				    enum gas_query_ap_result result,
682e5b75505Sopenharmony_ci				    const struct wpabuf *adv_proto,
683e5b75505Sopenharmony_ci				    const struct wpabuf *resp, u16 status_code)
684e5b75505Sopenharmony_ci{
685e5b75505Sopenharmony_ci	struct hostapd_data *hapd = ctx;
686e5b75505Sopenharmony_ci	const u8 *pos;
687e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
688e5b75505Sopenharmony_ci	enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
689e5b75505Sopenharmony_ci
690e5b75505Sopenharmony_ci	if (!auth || !auth->auth_success) {
691e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
692e5b75505Sopenharmony_ci		return;
693e5b75505Sopenharmony_ci	}
694e5b75505Sopenharmony_ci	if (!resp || status_code != WLAN_STATUS_SUCCESS) {
695e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
696e5b75505Sopenharmony_ci		goto fail;
697e5b75505Sopenharmony_ci	}
698e5b75505Sopenharmony_ci
699e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
700e5b75505Sopenharmony_ci			adv_proto);
701e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
702e5b75505Sopenharmony_ci			resp);
703e5b75505Sopenharmony_ci
704e5b75505Sopenharmony_ci	if (wpabuf_len(adv_proto) != 10 ||
705e5b75505Sopenharmony_ci	    !(pos = wpabuf_head(adv_proto)) ||
706e5b75505Sopenharmony_ci	    pos[0] != WLAN_EID_ADV_PROTO ||
707e5b75505Sopenharmony_ci	    pos[1] != 8 ||
708e5b75505Sopenharmony_ci	    pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
709e5b75505Sopenharmony_ci	    pos[4] != 5 ||
710e5b75505Sopenharmony_ci	    WPA_GET_BE24(&pos[5]) != OUI_WFA ||
711e5b75505Sopenharmony_ci	    pos[8] != 0x1a ||
712e5b75505Sopenharmony_ci	    pos[9] != 1) {
713e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
714e5b75505Sopenharmony_ci			   "DPP: Not a DPP Advertisement Protocol ID");
715e5b75505Sopenharmony_ci		goto fail;
716e5b75505Sopenharmony_ci	}
717e5b75505Sopenharmony_ci
718e5b75505Sopenharmony_ci	if (dpp_conf_resp_rx(auth, resp) < 0) {
719e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
720e5b75505Sopenharmony_ci		goto fail;
721e5b75505Sopenharmony_ci	}
722e5b75505Sopenharmony_ci
723e5b75505Sopenharmony_ci	hostapd_dpp_handle_config_obj(hapd, auth);
724e5b75505Sopenharmony_ci	status = DPP_STATUS_OK;
725e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
726e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_REJECT_CONFIG) {
727e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
728e5b75505Sopenharmony_ci		status = DPP_STATUS_CONFIG_REJECTED;
729e5b75505Sopenharmony_ci	}
730e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
731e5b75505Sopenharmony_cifail:
732e5b75505Sopenharmony_ci	if (status != DPP_STATUS_OK)
733e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
734e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
735e5b75505Sopenharmony_ci	if (auth->peer_version >= 2 &&
736e5b75505Sopenharmony_ci	    auth->conf_resp_status == DPP_STATUS_OK) {
737e5b75505Sopenharmony_ci		struct wpabuf *msg;
738e5b75505Sopenharmony_ci
739e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
740e5b75505Sopenharmony_ci		msg = dpp_build_conf_result(auth, status);
741e5b75505Sopenharmony_ci		if (!msg)
742e5b75505Sopenharmony_ci			goto fail2;
743e5b75505Sopenharmony_ci
744e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO,
745e5b75505Sopenharmony_ci			DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
746e5b75505Sopenharmony_ci			MAC2STR(addr), auth->curr_freq,
747e5b75505Sopenharmony_ci			DPP_PA_CONFIGURATION_RESULT);
748e5b75505Sopenharmony_ci		hostapd_drv_send_action(hapd, auth->curr_freq, 0,
749e5b75505Sopenharmony_ci					addr, wpabuf_head(msg),
750e5b75505Sopenharmony_ci					wpabuf_len(msg));
751e5b75505Sopenharmony_ci		wpabuf_free(msg);
752e5b75505Sopenharmony_ci
753e5b75505Sopenharmony_ci		/* This exchange will be terminated in the TX status handler */
754e5b75505Sopenharmony_ci		auth->connect_on_tx_status = 1;
755e5b75505Sopenharmony_ci		return;
756e5b75505Sopenharmony_ci	}
757e5b75505Sopenharmony_cifail2:
758e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
759e5b75505Sopenharmony_ci	dpp_auth_deinit(hapd->dpp_auth);
760e5b75505Sopenharmony_ci	hapd->dpp_auth = NULL;
761e5b75505Sopenharmony_ci}
762e5b75505Sopenharmony_ci
763e5b75505Sopenharmony_ci
764e5b75505Sopenharmony_cistatic void hostapd_dpp_start_gas_client(struct hostapd_data *hapd)
765e5b75505Sopenharmony_ci{
766e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
767e5b75505Sopenharmony_ci	struct wpabuf *buf;
768e5b75505Sopenharmony_ci	char json[100];
769e5b75505Sopenharmony_ci	int res;
770e5b75505Sopenharmony_ci	int netrole_ap = 1;
771e5b75505Sopenharmony_ci
772e5b75505Sopenharmony_ci	os_snprintf(json, sizeof(json),
773e5b75505Sopenharmony_ci		    "{\"name\":\"Test\","
774e5b75505Sopenharmony_ci		    "\"wi-fi_tech\":\"infra\","
775e5b75505Sopenharmony_ci		    "\"netRole\":\"%s\"}",
776e5b75505Sopenharmony_ci		    netrole_ap ? "ap" : "sta");
777e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
778e5b75505Sopenharmony_ci
779e5b75505Sopenharmony_ci	buf = dpp_build_conf_req(auth, json);
780e5b75505Sopenharmony_ci	if (!buf) {
781e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
782e5b75505Sopenharmony_ci			   "DPP: No configuration request data available");
783e5b75505Sopenharmony_ci		return;
784e5b75505Sopenharmony_ci	}
785e5b75505Sopenharmony_ci
786e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
787e5b75505Sopenharmony_ci		   MAC2STR(auth->peer_mac_addr), auth->curr_freq);
788e5b75505Sopenharmony_ci
789e5b75505Sopenharmony_ci	res = gas_query_ap_req(hapd->gas, auth->peer_mac_addr, auth->curr_freq,
790e5b75505Sopenharmony_ci			       buf, hostapd_dpp_gas_resp_cb, hapd);
791e5b75505Sopenharmony_ci	if (res < 0) {
792e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
793e5b75505Sopenharmony_ci			"GAS: Failed to send Query Request");
794e5b75505Sopenharmony_ci		wpabuf_free(buf);
795e5b75505Sopenharmony_ci	} else {
796e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
797e5b75505Sopenharmony_ci			   "DPP: GAS query started with dialog token %u", res);
798e5b75505Sopenharmony_ci	}
799e5b75505Sopenharmony_ci}
800e5b75505Sopenharmony_ci
801e5b75505Sopenharmony_ci
802e5b75505Sopenharmony_cistatic void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator)
803e5b75505Sopenharmony_ci{
804e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
805e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d",
806e5b75505Sopenharmony_ci		initiator);
807e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
808e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
809e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
810e5b75505Sopenharmony_ci			   "DPP: TESTING - stop at Authentication Confirm");
811e5b75505Sopenharmony_ci		if (hapd->dpp_auth->configurator) {
812e5b75505Sopenharmony_ci			/* Prevent GAS response */
813e5b75505Sopenharmony_ci			hapd->dpp_auth->auth_success = 0;
814e5b75505Sopenharmony_ci		}
815e5b75505Sopenharmony_ci		return;
816e5b75505Sopenharmony_ci	}
817e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
818e5b75505Sopenharmony_ci
819e5b75505Sopenharmony_ci	if (!hapd->dpp_auth->configurator)
820e5b75505Sopenharmony_ci		hostapd_dpp_start_gas_client(hapd);
821e5b75505Sopenharmony_ci}
822e5b75505Sopenharmony_ci
823e5b75505Sopenharmony_ci
824e5b75505Sopenharmony_cistatic void hostapd_dpp_rx_auth_resp(struct hostapd_data *hapd, const u8 *src,
825e5b75505Sopenharmony_ci				     const u8 *hdr, const u8 *buf, size_t len,
826e5b75505Sopenharmony_ci				     unsigned int freq)
827e5b75505Sopenharmony_ci{
828e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
829e5b75505Sopenharmony_ci	struct wpabuf *msg;
830e5b75505Sopenharmony_ci
831e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR,
832e5b75505Sopenharmony_ci		   MAC2STR(src));
833e5b75505Sopenharmony_ci
834e5b75505Sopenharmony_ci	if (!auth) {
835e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
836e5b75505Sopenharmony_ci			   "DPP: No DPP Authentication in progress - drop");
837e5b75505Sopenharmony_ci		return;
838e5b75505Sopenharmony_ci	}
839e5b75505Sopenharmony_ci
840e5b75505Sopenharmony_ci	if (!is_zero_ether_addr(auth->peer_mac_addr) &&
841e5b75505Sopenharmony_ci	    os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
842e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
843e5b75505Sopenharmony_ci			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
844e5b75505Sopenharmony_ci		return;
845e5b75505Sopenharmony_ci	}
846e5b75505Sopenharmony_ci
847e5b75505Sopenharmony_ci	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
848e5b75505Sopenharmony_ci
849e5b75505Sopenharmony_ci	if (auth->curr_freq != freq && auth->neg_freq == freq) {
850e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
851e5b75505Sopenharmony_ci			   "DPP: Responder accepted request for different negotiation channel");
852e5b75505Sopenharmony_ci		auth->curr_freq = freq;
853e5b75505Sopenharmony_ci	}
854e5b75505Sopenharmony_ci
855e5b75505Sopenharmony_ci	eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
856e5b75505Sopenharmony_ci	msg = dpp_auth_resp_rx(auth, hdr, buf, len);
857e5b75505Sopenharmony_ci	if (!msg) {
858e5b75505Sopenharmony_ci		if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
859e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "DPP: Wait for full response");
860e5b75505Sopenharmony_ci			return;
861e5b75505Sopenharmony_ci		}
862e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
863e5b75505Sopenharmony_ci		return;
864e5b75505Sopenharmony_ci	}
865e5b75505Sopenharmony_ci	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
866e5b75505Sopenharmony_ci
867e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
868e5b75505Sopenharmony_ci		" freq=%u type=%d", MAC2STR(src), auth->curr_freq,
869e5b75505Sopenharmony_ci		DPP_PA_AUTHENTICATION_CONF);
870e5b75505Sopenharmony_ci	hostapd_drv_send_action(hapd, auth->curr_freq, 0, src,
871e5b75505Sopenharmony_ci				wpabuf_head(msg), wpabuf_len(msg));
872e5b75505Sopenharmony_ci	wpabuf_free(msg);
873e5b75505Sopenharmony_ci	hapd->dpp_auth_ok_on_ack = 1;
874e5b75505Sopenharmony_ci}
875e5b75505Sopenharmony_ci
876e5b75505Sopenharmony_ci
877e5b75505Sopenharmony_cistatic void hostapd_dpp_rx_auth_conf(struct hostapd_data *hapd, const u8 *src,
878e5b75505Sopenharmony_ci				     const u8 *hdr, const u8 *buf, size_t len)
879e5b75505Sopenharmony_ci{
880e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
881e5b75505Sopenharmony_ci
882e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
883e5b75505Sopenharmony_ci		   MAC2STR(src));
884e5b75505Sopenharmony_ci
885e5b75505Sopenharmony_ci	if (!auth) {
886e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
887e5b75505Sopenharmony_ci			   "DPP: No DPP Authentication in progress - drop");
888e5b75505Sopenharmony_ci		return;
889e5b75505Sopenharmony_ci	}
890e5b75505Sopenharmony_ci
891e5b75505Sopenharmony_ci	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
892e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
893e5b75505Sopenharmony_ci			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
894e5b75505Sopenharmony_ci		return;
895e5b75505Sopenharmony_ci	}
896e5b75505Sopenharmony_ci
897e5b75505Sopenharmony_ci	if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
898e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
899e5b75505Sopenharmony_ci		return;
900e5b75505Sopenharmony_ci	}
901e5b75505Sopenharmony_ci
902e5b75505Sopenharmony_ci	hostapd_dpp_auth_success(hapd, 0);
903e5b75505Sopenharmony_ci}
904e5b75505Sopenharmony_ci
905e5b75505Sopenharmony_ci
906e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
907e5b75505Sopenharmony_ci
908e5b75505Sopenharmony_cistatic void hostapd_dpp_config_result_wait_timeout(void *eloop_ctx,
909e5b75505Sopenharmony_ci						   void *timeout_ctx)
910e5b75505Sopenharmony_ci{
911e5b75505Sopenharmony_ci	struct hostapd_data *hapd = eloop_ctx;
912e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
913e5b75505Sopenharmony_ci
914e5b75505Sopenharmony_ci	if (!auth || !auth->waiting_conf_result)
915e5b75505Sopenharmony_ci		return;
916e5b75505Sopenharmony_ci
917e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
918e5b75505Sopenharmony_ci		   "DPP: Timeout while waiting for Configuration Result");
919e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
920e5b75505Sopenharmony_ci	dpp_auth_deinit(auth);
921e5b75505Sopenharmony_ci	hapd->dpp_auth = NULL;
922e5b75505Sopenharmony_ci}
923e5b75505Sopenharmony_ci
924e5b75505Sopenharmony_ci
925e5b75505Sopenharmony_cistatic void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
926e5b75505Sopenharmony_ci				       const u8 *hdr, const u8 *buf, size_t len)
927e5b75505Sopenharmony_ci{
928e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
929e5b75505Sopenharmony_ci	enum dpp_status_error status;
930e5b75505Sopenharmony_ci
931e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
932e5b75505Sopenharmony_ci		   MAC2STR(src));
933e5b75505Sopenharmony_ci
934e5b75505Sopenharmony_ci	if (!auth || !auth->waiting_conf_result) {
935e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
936e5b75505Sopenharmony_ci			   "DPP: No DPP Configuration waiting for result - drop");
937e5b75505Sopenharmony_ci		return;
938e5b75505Sopenharmony_ci	}
939e5b75505Sopenharmony_ci
940e5b75505Sopenharmony_ci	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
941e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
942e5b75505Sopenharmony_ci			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
943e5b75505Sopenharmony_ci		return;
944e5b75505Sopenharmony_ci	}
945e5b75505Sopenharmony_ci
946e5b75505Sopenharmony_ci	status = dpp_conf_result_rx(auth, hdr, buf, len);
947e5b75505Sopenharmony_ci
948e5b75505Sopenharmony_ci	hostapd_drv_send_action_cancel_wait(hapd);
949e5b75505Sopenharmony_ci	hostapd_dpp_listen_stop(hapd);
950e5b75505Sopenharmony_ci	if (status == DPP_STATUS_OK)
951e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
952e5b75505Sopenharmony_ci	else
953e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
954e5b75505Sopenharmony_ci	dpp_auth_deinit(auth);
955e5b75505Sopenharmony_ci	hapd->dpp_auth = NULL;
956e5b75505Sopenharmony_ci	eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
957e5b75505Sopenharmony_ci			     NULL);
958e5b75505Sopenharmony_ci}
959e5b75505Sopenharmony_ci
960e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
961e5b75505Sopenharmony_ci
962e5b75505Sopenharmony_ci
963e5b75505Sopenharmony_cistatic void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
964e5b75505Sopenharmony_ci					    const u8 *src, unsigned int freq,
965e5b75505Sopenharmony_ci					    u8 trans_id,
966e5b75505Sopenharmony_ci					    enum dpp_status_error status)
967e5b75505Sopenharmony_ci{
968e5b75505Sopenharmony_ci	struct wpabuf *msg;
969e5b75505Sopenharmony_ci
970e5b75505Sopenharmony_ci	msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP,
971e5b75505Sopenharmony_ci			    5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector));
972e5b75505Sopenharmony_ci	if (!msg)
973e5b75505Sopenharmony_ci		return;
974e5b75505Sopenharmony_ci
975e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
976e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_RESP) {
977e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
978e5b75505Sopenharmony_ci		goto skip_trans_id;
979e5b75505Sopenharmony_ci	}
980e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_RESP) {
981e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
982e5b75505Sopenharmony_ci		trans_id ^= 0x01;
983e5b75505Sopenharmony_ci	}
984e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
985e5b75505Sopenharmony_ci
986e5b75505Sopenharmony_ci	/* Transaction ID */
987e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
988e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, 1);
989e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, trans_id);
990e5b75505Sopenharmony_ci
991e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
992e5b75505Sopenharmony_ciskip_trans_id:
993e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_STATUS_PEER_DISC_RESP) {
994e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
995e5b75505Sopenharmony_ci		goto skip_status;
996e5b75505Sopenharmony_ci	}
997e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_INVALID_STATUS_PEER_DISC_RESP) {
998e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
999e5b75505Sopenharmony_ci		status = 254;
1000e5b75505Sopenharmony_ci	}
1001e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1002e5b75505Sopenharmony_ci
1003e5b75505Sopenharmony_ci	/* DPP Status */
1004e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_STATUS);
1005e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, 1);
1006e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, status);
1007e5b75505Sopenharmony_ci
1008e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1009e5b75505Sopenharmony_ciskip_status:
1010e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_RESP) {
1011e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
1012e5b75505Sopenharmony_ci		goto skip_connector;
1013e5b75505Sopenharmony_ci	}
1014e5b75505Sopenharmony_ci	if (status == DPP_STATUS_OK &&
1015e5b75505Sopenharmony_ci	    dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_RESP) {
1016e5b75505Sopenharmony_ci		char *connector;
1017e5b75505Sopenharmony_ci
1018e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
1019e5b75505Sopenharmony_ci		connector = dpp_corrupt_connector_signature(
1020e5b75505Sopenharmony_ci			hapd->conf->dpp_connector);
1021e5b75505Sopenharmony_ci		if (!connector) {
1022e5b75505Sopenharmony_ci			wpabuf_free(msg);
1023e5b75505Sopenharmony_ci			return;
1024e5b75505Sopenharmony_ci		}
1025e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
1026e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, os_strlen(connector));
1027e5b75505Sopenharmony_ci		wpabuf_put_str(msg, connector);
1028e5b75505Sopenharmony_ci		os_free(connector);
1029e5b75505Sopenharmony_ci		goto skip_connector;
1030e5b75505Sopenharmony_ci	}
1031e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1032e5b75505Sopenharmony_ci
1033e5b75505Sopenharmony_ci	/* DPP Connector */
1034e5b75505Sopenharmony_ci	if (status == DPP_STATUS_OK) {
1035e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
1036e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector));
1037e5b75505Sopenharmony_ci		wpabuf_put_str(msg, hapd->conf->dpp_connector);
1038e5b75505Sopenharmony_ci	}
1039e5b75505Sopenharmony_ci
1040e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1041e5b75505Sopenharmony_ciskip_connector:
1042e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1043e5b75505Sopenharmony_ci
1044e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR
1045e5b75505Sopenharmony_ci		   " status=%d", MAC2STR(src), status);
1046e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1047e5b75505Sopenharmony_ci		" freq=%u type=%d status=%d", MAC2STR(src), freq,
1048e5b75505Sopenharmony_ci		DPP_PA_PEER_DISCOVERY_RESP, status);
1049e5b75505Sopenharmony_ci	hostapd_drv_send_action(hapd, freq, 0, src,
1050e5b75505Sopenharmony_ci				wpabuf_head(msg), wpabuf_len(msg));
1051e5b75505Sopenharmony_ci	wpabuf_free(msg);
1052e5b75505Sopenharmony_ci}
1053e5b75505Sopenharmony_ci
1054e5b75505Sopenharmony_ci
1055e5b75505Sopenharmony_cistatic void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
1056e5b75505Sopenharmony_ci					 const u8 *src,
1057e5b75505Sopenharmony_ci					 const u8 *buf, size_t len,
1058e5b75505Sopenharmony_ci					 unsigned int freq)
1059e5b75505Sopenharmony_ci{
1060e5b75505Sopenharmony_ci	const u8 *connector, *trans_id;
1061e5b75505Sopenharmony_ci	u16 connector_len, trans_id_len;
1062e5b75505Sopenharmony_ci	struct os_time now;
1063e5b75505Sopenharmony_ci	struct dpp_introduction intro;
1064e5b75505Sopenharmony_ci	os_time_t expire;
1065e5b75505Sopenharmony_ci	int expiration;
1066e5b75505Sopenharmony_ci	enum dpp_status_error res;
1067e5b75505Sopenharmony_ci
1068e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR,
1069e5b75505Sopenharmony_ci		   MAC2STR(src));
1070e5b75505Sopenharmony_ci	if (!hapd->wpa_auth ||
1071e5b75505Sopenharmony_ci	    !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) ||
1072e5b75505Sopenharmony_ci	    !(hapd->conf->wpa & WPA_PROTO_RSN)) {
1073e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: DPP AKM not in use");
1074e5b75505Sopenharmony_ci		return;
1075e5b75505Sopenharmony_ci	}
1076e5b75505Sopenharmony_ci
1077e5b75505Sopenharmony_ci	if (!hapd->conf->dpp_connector || !hapd->conf->dpp_netaccesskey ||
1078e5b75505Sopenharmony_ci	    !hapd->conf->dpp_csign) {
1079e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No own Connector/keys set");
1080e5b75505Sopenharmony_ci		return;
1081e5b75505Sopenharmony_ci	}
1082e5b75505Sopenharmony_ci
1083e5b75505Sopenharmony_ci	os_get_time(&now);
1084e5b75505Sopenharmony_ci
1085e5b75505Sopenharmony_ci	if (hapd->conf->dpp_netaccesskey_expiry &&
1086e5b75505Sopenharmony_ci	    (os_time_t) hapd->conf->dpp_netaccesskey_expiry < now.sec) {
1087e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: Own netAccessKey expired");
1088e5b75505Sopenharmony_ci		return;
1089e5b75505Sopenharmony_ci	}
1090e5b75505Sopenharmony_ci
1091e5b75505Sopenharmony_ci	trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
1092e5b75505Sopenharmony_ci			       &trans_id_len);
1093e5b75505Sopenharmony_ci	if (!trans_id || trans_id_len != 1) {
1094e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1095e5b75505Sopenharmony_ci			   "DPP: Peer did not include Transaction ID");
1096e5b75505Sopenharmony_ci		return;
1097e5b75505Sopenharmony_ci	}
1098e5b75505Sopenharmony_ci
1099e5b75505Sopenharmony_ci	connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len);
1100e5b75505Sopenharmony_ci	if (!connector) {
1101e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1102e5b75505Sopenharmony_ci			   "DPP: Peer did not include its Connector");
1103e5b75505Sopenharmony_ci		return;
1104e5b75505Sopenharmony_ci	}
1105e5b75505Sopenharmony_ci
1106e5b75505Sopenharmony_ci	res = dpp_peer_intro(&intro, hapd->conf->dpp_connector,
1107e5b75505Sopenharmony_ci			     wpabuf_head(hapd->conf->dpp_netaccesskey),
1108e5b75505Sopenharmony_ci			     wpabuf_len(hapd->conf->dpp_netaccesskey),
1109e5b75505Sopenharmony_ci			     wpabuf_head(hapd->conf->dpp_csign),
1110e5b75505Sopenharmony_ci			     wpabuf_len(hapd->conf->dpp_csign),
1111e5b75505Sopenharmony_ci			     connector, connector_len, &expire);
1112e5b75505Sopenharmony_ci	if (res == 255) {
1113e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
1114e5b75505Sopenharmony_ci			   "DPP: Network Introduction protocol resulted in internal failure (peer "
1115e5b75505Sopenharmony_ci			   MACSTR ")", MAC2STR(src));
1116e5b75505Sopenharmony_ci		return;
1117e5b75505Sopenharmony_ci	}
1118e5b75505Sopenharmony_ci	if (res != DPP_STATUS_OK) {
1119e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
1120e5b75505Sopenharmony_ci			   "DPP: Network Introduction protocol resulted in failure (peer "
1121e5b75505Sopenharmony_ci			   MACSTR " status %d)", MAC2STR(src), res);
1122e5b75505Sopenharmony_ci		hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
1123e5b75505Sopenharmony_ci						res);
1124e5b75505Sopenharmony_ci		return;
1125e5b75505Sopenharmony_ci	}
1126e5b75505Sopenharmony_ci
1127e5b75505Sopenharmony_ci	if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire)
1128e5b75505Sopenharmony_ci		expire = hapd->conf->dpp_netaccesskey_expiry;
1129e5b75505Sopenharmony_ci	if (expire)
1130e5b75505Sopenharmony_ci		expiration = expire - now.sec;
1131e5b75505Sopenharmony_ci	else
1132e5b75505Sopenharmony_ci		expiration = 0;
1133e5b75505Sopenharmony_ci
1134e5b75505Sopenharmony_ci	if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
1135e5b75505Sopenharmony_ci				intro.pmkid, expiration,
1136e5b75505Sopenharmony_ci				WPA_KEY_MGMT_DPP) < 0) {
1137e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
1138e5b75505Sopenharmony_ci		return;
1139e5b75505Sopenharmony_ci	}
1140e5b75505Sopenharmony_ci
1141e5b75505Sopenharmony_ci	hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
1142e5b75505Sopenharmony_ci					DPP_STATUS_OK);
1143e5b75505Sopenharmony_ci}
1144e5b75505Sopenharmony_ci
1145e5b75505Sopenharmony_ci
1146e5b75505Sopenharmony_cistatic void
1147e5b75505Sopenharmony_cihostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
1148e5b75505Sopenharmony_ci				 const u8 *buf, size_t len,
1149e5b75505Sopenharmony_ci				 unsigned int freq)
1150e5b75505Sopenharmony_ci{
1151e5b75505Sopenharmony_ci	struct wpabuf *msg;
1152e5b75505Sopenharmony_ci
1153e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR,
1154e5b75505Sopenharmony_ci		   MAC2STR(src));
1155e5b75505Sopenharmony_ci
1156e5b75505Sopenharmony_ci	/* TODO: Support multiple PKEX codes by iterating over all the enabled
1157e5b75505Sopenharmony_ci	 * values here */
1158e5b75505Sopenharmony_ci
1159e5b75505Sopenharmony_ci	if (!hapd->dpp_pkex_code || !hapd->dpp_pkex_bi) {
1160e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1161e5b75505Sopenharmony_ci			   "DPP: No PKEX code configured - ignore request");
1162e5b75505Sopenharmony_ci		return;
1163e5b75505Sopenharmony_ci	}
1164e5b75505Sopenharmony_ci
1165e5b75505Sopenharmony_ci	if (hapd->dpp_pkex) {
1166e5b75505Sopenharmony_ci		/* TODO: Support parallel operations */
1167e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1168e5b75505Sopenharmony_ci			   "DPP: Already in PKEX session - ignore new request");
1169e5b75505Sopenharmony_ci		return;
1170e5b75505Sopenharmony_ci	}
1171e5b75505Sopenharmony_ci
1172e5b75505Sopenharmony_ci	hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->msg_ctx,
1173e5b75505Sopenharmony_ci						  hapd->dpp_pkex_bi,
1174e5b75505Sopenharmony_ci						  hapd->own_addr, src,
1175e5b75505Sopenharmony_ci						  hapd->dpp_pkex_identifier,
1176e5b75505Sopenharmony_ci						  hapd->dpp_pkex_code,
1177e5b75505Sopenharmony_ci						  buf, len);
1178e5b75505Sopenharmony_ci	if (!hapd->dpp_pkex) {
1179e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1180e5b75505Sopenharmony_ci			   "DPP: Failed to process the request - ignore it");
1181e5b75505Sopenharmony_ci		return;
1182e5b75505Sopenharmony_ci	}
1183e5b75505Sopenharmony_ci
1184e5b75505Sopenharmony_ci	msg = hapd->dpp_pkex->exchange_resp;
1185e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1186e5b75505Sopenharmony_ci		" freq=%u type=%d", MAC2STR(src), freq,
1187e5b75505Sopenharmony_ci		DPP_PA_PKEX_EXCHANGE_RESP);
1188e5b75505Sopenharmony_ci	hostapd_drv_send_action(hapd, freq, 0, src,
1189e5b75505Sopenharmony_ci				wpabuf_head(msg), wpabuf_len(msg));
1190e5b75505Sopenharmony_ci	if (hapd->dpp_pkex->failed) {
1191e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1192e5b75505Sopenharmony_ci			   "DPP: Terminate PKEX exchange due to an earlier error");
1193e5b75505Sopenharmony_ci		if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
1194e5b75505Sopenharmony_ci			hapd->dpp_pkex->own_bi->pkex_t = hapd->dpp_pkex->t;
1195e5b75505Sopenharmony_ci		dpp_pkex_free(hapd->dpp_pkex);
1196e5b75505Sopenharmony_ci		hapd->dpp_pkex = NULL;
1197e5b75505Sopenharmony_ci	}
1198e5b75505Sopenharmony_ci}
1199e5b75505Sopenharmony_ci
1200e5b75505Sopenharmony_ci
1201e5b75505Sopenharmony_cistatic void
1202e5b75505Sopenharmony_cihostapd_dpp_rx_pkex_exchange_resp(struct hostapd_data *hapd, const u8 *src,
1203e5b75505Sopenharmony_ci				  const u8 *buf, size_t len, unsigned int freq)
1204e5b75505Sopenharmony_ci{
1205e5b75505Sopenharmony_ci	struct wpabuf *msg;
1206e5b75505Sopenharmony_ci
1207e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR,
1208e5b75505Sopenharmony_ci		   MAC2STR(src));
1209e5b75505Sopenharmony_ci
1210e5b75505Sopenharmony_ci	/* TODO: Support multiple PKEX codes by iterating over all the enabled
1211e5b75505Sopenharmony_ci	 * values here */
1212e5b75505Sopenharmony_ci
1213e5b75505Sopenharmony_ci	if (!hapd->dpp_pkex || !hapd->dpp_pkex->initiator ||
1214e5b75505Sopenharmony_ci	    hapd->dpp_pkex->exchange_done) {
1215e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
1216e5b75505Sopenharmony_ci		return;
1217e5b75505Sopenharmony_ci	}
1218e5b75505Sopenharmony_ci
1219e5b75505Sopenharmony_ci	msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, src, buf, len);
1220e5b75505Sopenharmony_ci	if (!msg) {
1221e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
1222e5b75505Sopenharmony_ci		return;
1223e5b75505Sopenharmony_ci	}
1224e5b75505Sopenharmony_ci
1225e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR,
1226e5b75505Sopenharmony_ci		   MAC2STR(src));
1227e5b75505Sopenharmony_ci
1228e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1229e5b75505Sopenharmony_ci		" freq=%u type=%d", MAC2STR(src), freq,
1230e5b75505Sopenharmony_ci		DPP_PA_PKEX_COMMIT_REVEAL_REQ);
1231e5b75505Sopenharmony_ci	hostapd_drv_send_action(hapd, freq, 0, src,
1232e5b75505Sopenharmony_ci				wpabuf_head(msg), wpabuf_len(msg));
1233e5b75505Sopenharmony_ci	wpabuf_free(msg);
1234e5b75505Sopenharmony_ci}
1235e5b75505Sopenharmony_ci
1236e5b75505Sopenharmony_ci
1237e5b75505Sopenharmony_cistatic void
1238e5b75505Sopenharmony_cihostapd_dpp_rx_pkex_commit_reveal_req(struct hostapd_data *hapd, const u8 *src,
1239e5b75505Sopenharmony_ci				      const u8 *hdr, const u8 *buf, size_t len,
1240e5b75505Sopenharmony_ci				      unsigned int freq)
1241e5b75505Sopenharmony_ci{
1242e5b75505Sopenharmony_ci	struct wpabuf *msg;
1243e5b75505Sopenharmony_ci	struct dpp_pkex *pkex = hapd->dpp_pkex;
1244e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
1245e5b75505Sopenharmony_ci
1246e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR,
1247e5b75505Sopenharmony_ci		   MAC2STR(src));
1248e5b75505Sopenharmony_ci
1249e5b75505Sopenharmony_ci	if (!pkex || pkex->initiator || !pkex->exchange_done) {
1250e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
1251e5b75505Sopenharmony_ci		return;
1252e5b75505Sopenharmony_ci	}
1253e5b75505Sopenharmony_ci
1254e5b75505Sopenharmony_ci	msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
1255e5b75505Sopenharmony_ci	if (!msg) {
1256e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
1257e5b75505Sopenharmony_ci		if (hapd->dpp_pkex->failed) {
1258e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
1259e5b75505Sopenharmony_ci			if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
1260e5b75505Sopenharmony_ci				hapd->dpp_pkex->own_bi->pkex_t =
1261e5b75505Sopenharmony_ci					hapd->dpp_pkex->t;
1262e5b75505Sopenharmony_ci			dpp_pkex_free(hapd->dpp_pkex);
1263e5b75505Sopenharmony_ci			hapd->dpp_pkex = NULL;
1264e5b75505Sopenharmony_ci		}
1265e5b75505Sopenharmony_ci		return;
1266e5b75505Sopenharmony_ci	}
1267e5b75505Sopenharmony_ci
1268e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to "
1269e5b75505Sopenharmony_ci		   MACSTR, MAC2STR(src));
1270e5b75505Sopenharmony_ci
1271e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1272e5b75505Sopenharmony_ci		" freq=%u type=%d", MAC2STR(src), freq,
1273e5b75505Sopenharmony_ci		DPP_PA_PKEX_COMMIT_REVEAL_RESP);
1274e5b75505Sopenharmony_ci	hostapd_drv_send_action(hapd, freq, 0, src,
1275e5b75505Sopenharmony_ci				wpabuf_head(msg), wpabuf_len(msg));
1276e5b75505Sopenharmony_ci	wpabuf_free(msg);
1277e5b75505Sopenharmony_ci
1278e5b75505Sopenharmony_ci	bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
1279e5b75505Sopenharmony_ci	if (!bi)
1280e5b75505Sopenharmony_ci		return;
1281e5b75505Sopenharmony_ci	hapd->dpp_pkex = NULL;
1282e5b75505Sopenharmony_ci}
1283e5b75505Sopenharmony_ci
1284e5b75505Sopenharmony_ci
1285e5b75505Sopenharmony_cistatic void
1286e5b75505Sopenharmony_cihostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src,
1287e5b75505Sopenharmony_ci				       const u8 *hdr, const u8 *buf, size_t len,
1288e5b75505Sopenharmony_ci				       unsigned int freq)
1289e5b75505Sopenharmony_ci{
1290e5b75505Sopenharmony_ci	int res;
1291e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
1292e5b75505Sopenharmony_ci	struct dpp_pkex *pkex = hapd->dpp_pkex;
1293e5b75505Sopenharmony_ci	char cmd[500];
1294e5b75505Sopenharmony_ci
1295e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR,
1296e5b75505Sopenharmony_ci		   MAC2STR(src));
1297e5b75505Sopenharmony_ci
1298e5b75505Sopenharmony_ci	if (!pkex || !pkex->initiator || !pkex->exchange_done) {
1299e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
1300e5b75505Sopenharmony_ci		return;
1301e5b75505Sopenharmony_ci	}
1302e5b75505Sopenharmony_ci
1303e5b75505Sopenharmony_ci	res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len);
1304e5b75505Sopenharmony_ci	if (res < 0) {
1305e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
1306e5b75505Sopenharmony_ci		return;
1307e5b75505Sopenharmony_ci	}
1308e5b75505Sopenharmony_ci
1309e5b75505Sopenharmony_ci	bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
1310e5b75505Sopenharmony_ci	if (!bi)
1311e5b75505Sopenharmony_ci		return;
1312e5b75505Sopenharmony_ci	hapd->dpp_pkex = NULL;
1313e5b75505Sopenharmony_ci
1314e5b75505Sopenharmony_ci	os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
1315e5b75505Sopenharmony_ci		    bi->id,
1316e5b75505Sopenharmony_ci		    hapd->dpp_pkex_auth_cmd ? hapd->dpp_pkex_auth_cmd : "");
1317e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
1318e5b75505Sopenharmony_ci		   "DPP: Start authentication after PKEX with parameters: %s",
1319e5b75505Sopenharmony_ci		   cmd);
1320e5b75505Sopenharmony_ci	if (hostapd_dpp_auth_init(hapd, cmd) < 0) {
1321e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1322e5b75505Sopenharmony_ci			   "DPP: Authentication initialization failed");
1323e5b75505Sopenharmony_ci		return;
1324e5b75505Sopenharmony_ci	}
1325e5b75505Sopenharmony_ci}
1326e5b75505Sopenharmony_ci
1327e5b75505Sopenharmony_ci
1328e5b75505Sopenharmony_civoid hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
1329e5b75505Sopenharmony_ci			   const u8 *buf, size_t len, unsigned int freq)
1330e5b75505Sopenharmony_ci{
1331e5b75505Sopenharmony_ci	u8 crypto_suite;
1332e5b75505Sopenharmony_ci	enum dpp_public_action_frame_type type;
1333e5b75505Sopenharmony_ci	const u8 *hdr;
1334e5b75505Sopenharmony_ci	unsigned int pkex_t;
1335e5b75505Sopenharmony_ci
1336e5b75505Sopenharmony_ci	if (len < DPP_HDR_LEN)
1337e5b75505Sopenharmony_ci		return;
1338e5b75505Sopenharmony_ci	if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE)
1339e5b75505Sopenharmony_ci		return;
1340e5b75505Sopenharmony_ci	hdr = buf;
1341e5b75505Sopenharmony_ci	buf += 4;
1342e5b75505Sopenharmony_ci	len -= 4;
1343e5b75505Sopenharmony_ci	crypto_suite = *buf++;
1344e5b75505Sopenharmony_ci	type = *buf++;
1345e5b75505Sopenharmony_ci	len -= 2;
1346e5b75505Sopenharmony_ci
1347e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
1348e5b75505Sopenharmony_ci		   "DPP: Received DPP Public Action frame crypto suite %u type %d from "
1349e5b75505Sopenharmony_ci		   MACSTR " freq=%u",
1350e5b75505Sopenharmony_ci		   crypto_suite, type, MAC2STR(src), freq);
1351e5b75505Sopenharmony_ci	if (crypto_suite != 1) {
1352e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
1353e5b75505Sopenharmony_ci			   crypto_suite);
1354e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
1355e5b75505Sopenharmony_ci			" freq=%u type=%d ignore=unsupported-crypto-suite",
1356e5b75505Sopenharmony_ci			MAC2STR(src), freq, type);
1357e5b75505Sopenharmony_ci		return;
1358e5b75505Sopenharmony_ci	}
1359e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
1360e5b75505Sopenharmony_ci	if (dpp_check_attrs(buf, len) < 0) {
1361e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
1362e5b75505Sopenharmony_ci			" freq=%u type=%d ignore=invalid-attributes",
1363e5b75505Sopenharmony_ci			MAC2STR(src), freq, type);
1364e5b75505Sopenharmony_ci		return;
1365e5b75505Sopenharmony_ci	}
1366e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
1367e5b75505Sopenharmony_ci		" freq=%u type=%d", MAC2STR(src), freq, type);
1368e5b75505Sopenharmony_ci
1369e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
1370e5b75505Sopenharmony_ci	if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
1371e5b75505Sopenharmony_ci				src, hdr, buf, len, freq, NULL, NULL) == 0)
1372e5b75505Sopenharmony_ci		return;
1373e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
1374e5b75505Sopenharmony_ci
1375e5b75505Sopenharmony_ci	switch (type) {
1376e5b75505Sopenharmony_ci	case DPP_PA_AUTHENTICATION_REQ:
1377e5b75505Sopenharmony_ci		hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq);
1378e5b75505Sopenharmony_ci		break;
1379e5b75505Sopenharmony_ci	case DPP_PA_AUTHENTICATION_RESP:
1380e5b75505Sopenharmony_ci		hostapd_dpp_rx_auth_resp(hapd, src, hdr, buf, len, freq);
1381e5b75505Sopenharmony_ci		break;
1382e5b75505Sopenharmony_ci	case DPP_PA_AUTHENTICATION_CONF:
1383e5b75505Sopenharmony_ci		hostapd_dpp_rx_auth_conf(hapd, src, hdr, buf, len);
1384e5b75505Sopenharmony_ci		break;
1385e5b75505Sopenharmony_ci	case DPP_PA_PEER_DISCOVERY_REQ:
1386e5b75505Sopenharmony_ci		hostapd_dpp_rx_peer_disc_req(hapd, src, buf, len, freq);
1387e5b75505Sopenharmony_ci		break;
1388e5b75505Sopenharmony_ci	case DPP_PA_PKEX_EXCHANGE_REQ:
1389e5b75505Sopenharmony_ci		hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq);
1390e5b75505Sopenharmony_ci		break;
1391e5b75505Sopenharmony_ci	case DPP_PA_PKEX_EXCHANGE_RESP:
1392e5b75505Sopenharmony_ci		hostapd_dpp_rx_pkex_exchange_resp(hapd, src, buf, len, freq);
1393e5b75505Sopenharmony_ci		break;
1394e5b75505Sopenharmony_ci	case DPP_PA_PKEX_COMMIT_REVEAL_REQ:
1395e5b75505Sopenharmony_ci		hostapd_dpp_rx_pkex_commit_reveal_req(hapd, src, hdr, buf, len,
1396e5b75505Sopenharmony_ci						      freq);
1397e5b75505Sopenharmony_ci		break;
1398e5b75505Sopenharmony_ci	case DPP_PA_PKEX_COMMIT_REVEAL_RESP:
1399e5b75505Sopenharmony_ci		hostapd_dpp_rx_pkex_commit_reveal_resp(hapd, src, hdr, buf, len,
1400e5b75505Sopenharmony_ci						       freq);
1401e5b75505Sopenharmony_ci		break;
1402e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
1403e5b75505Sopenharmony_ci	case DPP_PA_CONFIGURATION_RESULT:
1404e5b75505Sopenharmony_ci		hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len);
1405e5b75505Sopenharmony_ci		break;
1406e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
1407e5b75505Sopenharmony_ci	default:
1408e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1409e5b75505Sopenharmony_ci			   "DPP: Ignored unsupported frame subtype %d", type);
1410e5b75505Sopenharmony_ci		break;
1411e5b75505Sopenharmony_ci	}
1412e5b75505Sopenharmony_ci
1413e5b75505Sopenharmony_ci	if (hapd->dpp_pkex)
1414e5b75505Sopenharmony_ci		pkex_t = hapd->dpp_pkex->t;
1415e5b75505Sopenharmony_ci	else if (hapd->dpp_pkex_bi)
1416e5b75505Sopenharmony_ci		pkex_t = hapd->dpp_pkex_bi->pkex_t;
1417e5b75505Sopenharmony_ci	else
1418e5b75505Sopenharmony_ci		pkex_t = 0;
1419e5b75505Sopenharmony_ci	if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
1420e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
1421e5b75505Sopenharmony_ci		hostapd_dpp_pkex_remove(hapd, "*");
1422e5b75505Sopenharmony_ci	}
1423e5b75505Sopenharmony_ci}
1424e5b75505Sopenharmony_ci
1425e5b75505Sopenharmony_ci
1426e5b75505Sopenharmony_cistruct wpabuf *
1427e5b75505Sopenharmony_cihostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
1428e5b75505Sopenharmony_ci			    const u8 *query, size_t query_len,
1429e5b75505Sopenharmony_ci			    const u8 *data, size_t data_len)
1430e5b75505Sopenharmony_ci{
1431e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
1432e5b75505Sopenharmony_ci	struct wpabuf *resp;
1433e5b75505Sopenharmony_ci
1434e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
1435e5b75505Sopenharmony_ci	if (!auth || !auth->auth_success ||
1436e5b75505Sopenharmony_ci	    os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
1437e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
1438e5b75505Sopenharmony_ci		if (dpp_relay_rx_gas_req(hapd->iface->interfaces->dpp, sa, data,
1439e5b75505Sopenharmony_ci				     data_len) == 0) {
1440e5b75505Sopenharmony_ci			/* Response will be forwarded once received over TCP */
1441e5b75505Sopenharmony_ci			return NULL;
1442e5b75505Sopenharmony_ci		}
1443e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
1444e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
1445e5b75505Sopenharmony_ci		return NULL;
1446e5b75505Sopenharmony_ci	}
1447e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG,
1448e5b75505Sopenharmony_ci		    "DPP: Received Configuration Request (GAS Query Request)",
1449e5b75505Sopenharmony_ci		    query, query_len);
1450e5b75505Sopenharmony_ci	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
1451e5b75505Sopenharmony_ci		MAC2STR(sa));
1452e5b75505Sopenharmony_ci	resp = dpp_conf_req_rx(auth, query, query_len);
1453e5b75505Sopenharmony_ci	if (!resp)
1454e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
1455e5b75505Sopenharmony_ci	return resp;
1456e5b75505Sopenharmony_ci}
1457e5b75505Sopenharmony_ci
1458e5b75505Sopenharmony_ci
1459e5b75505Sopenharmony_civoid hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
1460e5b75505Sopenharmony_ci{
1461e5b75505Sopenharmony_ci	struct dpp_authentication *auth = hapd->dpp_auth;
1462e5b75505Sopenharmony_ci
1463e5b75505Sopenharmony_ci	if (!auth)
1464e5b75505Sopenharmony_ci		return;
1465e5b75505Sopenharmony_ci
1466e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
1467e5b75505Sopenharmony_ci		   ok);
1468e5b75505Sopenharmony_ci	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
1469e5b75505Sopenharmony_ci	eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
1470e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
1471e5b75505Sopenharmony_ci	if (ok && auth->peer_version >= 2 &&
1472e5b75505Sopenharmony_ci	    auth->conf_resp_status == DPP_STATUS_OK) {
1473e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
1474e5b75505Sopenharmony_ci		auth->waiting_conf_result = 1;
1475e5b75505Sopenharmony_ci		eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout,
1476e5b75505Sopenharmony_ci				     hapd, NULL);
1477e5b75505Sopenharmony_ci		eloop_register_timeout(2, 0,
1478e5b75505Sopenharmony_ci				       hostapd_dpp_config_result_wait_timeout,
1479e5b75505Sopenharmony_ci				       hapd, NULL);
1480e5b75505Sopenharmony_ci		return;
1481e5b75505Sopenharmony_ci	}
1482e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
1483e5b75505Sopenharmony_ci	hostapd_drv_send_action_cancel_wait(hapd);
1484e5b75505Sopenharmony_ci
1485e5b75505Sopenharmony_ci	if (ok)
1486e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
1487e5b75505Sopenharmony_ci	else
1488e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
1489e5b75505Sopenharmony_ci	dpp_auth_deinit(hapd->dpp_auth);
1490e5b75505Sopenharmony_ci	hapd->dpp_auth = NULL;
1491e5b75505Sopenharmony_ci}
1492e5b75505Sopenharmony_ci
1493e5b75505Sopenharmony_ci
1494e5b75505Sopenharmony_ciint hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
1495e5b75505Sopenharmony_ci{
1496e5b75505Sopenharmony_ci	struct dpp_authentication *auth;
1497e5b75505Sopenharmony_ci	int ret = -1;
1498e5b75505Sopenharmony_ci	char *curve = NULL;
1499e5b75505Sopenharmony_ci
1500e5b75505Sopenharmony_ci	auth = os_zalloc(sizeof(*auth));
1501e5b75505Sopenharmony_ci	if (!auth)
1502e5b75505Sopenharmony_ci		return -1;
1503e5b75505Sopenharmony_ci
1504e5b75505Sopenharmony_ci	curve = get_param(cmd, " curve=");
1505e5b75505Sopenharmony_ci	hostapd_dpp_set_testing_options(hapd, auth);
1506e5b75505Sopenharmony_ci	if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
1507e5b75505Sopenharmony_ci				 auth, cmd) == 0 &&
1508e5b75505Sopenharmony_ci	    dpp_configurator_own_config(auth, curve, 1) == 0) {
1509e5b75505Sopenharmony_ci		hostapd_dpp_handle_config_obj(hapd, auth);
1510e5b75505Sopenharmony_ci		ret = 0;
1511e5b75505Sopenharmony_ci	}
1512e5b75505Sopenharmony_ci
1513e5b75505Sopenharmony_ci	dpp_auth_deinit(auth);
1514e5b75505Sopenharmony_ci	os_free(curve);
1515e5b75505Sopenharmony_ci
1516e5b75505Sopenharmony_ci	return ret;
1517e5b75505Sopenharmony_ci}
1518e5b75505Sopenharmony_ci
1519e5b75505Sopenharmony_ci
1520e5b75505Sopenharmony_ciint hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
1521e5b75505Sopenharmony_ci{
1522e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *own_bi;
1523e5b75505Sopenharmony_ci	const char *pos, *end;
1524e5b75505Sopenharmony_ci
1525e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " own=");
1526e5b75505Sopenharmony_ci	if (!pos)
1527e5b75505Sopenharmony_ci		return -1;
1528e5b75505Sopenharmony_ci	pos += 5;
1529e5b75505Sopenharmony_ci	own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
1530e5b75505Sopenharmony_ci	if (!own_bi) {
1531e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1532e5b75505Sopenharmony_ci			   "DPP: Identified bootstrap info not found");
1533e5b75505Sopenharmony_ci		return -1;
1534e5b75505Sopenharmony_ci	}
1535e5b75505Sopenharmony_ci	if (own_bi->type != DPP_BOOTSTRAP_PKEX) {
1536e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1537e5b75505Sopenharmony_ci			   "DPP: Identified bootstrap info not for PKEX");
1538e5b75505Sopenharmony_ci		return -1;
1539e5b75505Sopenharmony_ci	}
1540e5b75505Sopenharmony_ci	hapd->dpp_pkex_bi = own_bi;
1541e5b75505Sopenharmony_ci	own_bi->pkex_t = 0; /* clear pending errors on new code */
1542e5b75505Sopenharmony_ci
1543e5b75505Sopenharmony_ci	os_free(hapd->dpp_pkex_identifier);
1544e5b75505Sopenharmony_ci	hapd->dpp_pkex_identifier = NULL;
1545e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " identifier=");
1546e5b75505Sopenharmony_ci	if (pos) {
1547e5b75505Sopenharmony_ci		pos += 12;
1548e5b75505Sopenharmony_ci		end = os_strchr(pos, ' ');
1549e5b75505Sopenharmony_ci		if (!end)
1550e5b75505Sopenharmony_ci			return -1;
1551e5b75505Sopenharmony_ci		hapd->dpp_pkex_identifier = os_malloc(end - pos + 1);
1552e5b75505Sopenharmony_ci		if (!hapd->dpp_pkex_identifier)
1553e5b75505Sopenharmony_ci			return -1;
1554e5b75505Sopenharmony_ci		os_memcpy(hapd->dpp_pkex_identifier, pos, end - pos);
1555e5b75505Sopenharmony_ci		hapd->dpp_pkex_identifier[end - pos] = '\0';
1556e5b75505Sopenharmony_ci	}
1557e5b75505Sopenharmony_ci
1558e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " code=");
1559e5b75505Sopenharmony_ci	if (!pos)
1560e5b75505Sopenharmony_ci		return -1;
1561e5b75505Sopenharmony_ci	os_free(hapd->dpp_pkex_code);
1562e5b75505Sopenharmony_ci	hapd->dpp_pkex_code = os_strdup(pos + 6);
1563e5b75505Sopenharmony_ci	if (!hapd->dpp_pkex_code)
1564e5b75505Sopenharmony_ci		return -1;
1565e5b75505Sopenharmony_ci
1566e5b75505Sopenharmony_ci	if (os_strstr(cmd, " init=1")) {
1567e5b75505Sopenharmony_ci		struct wpabuf *msg;
1568e5b75505Sopenharmony_ci
1569e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
1570e5b75505Sopenharmony_ci		dpp_pkex_free(hapd->dpp_pkex);
1571e5b75505Sopenharmony_ci		hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi,
1572e5b75505Sopenharmony_ci					       hapd->own_addr,
1573e5b75505Sopenharmony_ci					       hapd->dpp_pkex_identifier,
1574e5b75505Sopenharmony_ci					       hapd->dpp_pkex_code);
1575e5b75505Sopenharmony_ci		if (!hapd->dpp_pkex)
1576e5b75505Sopenharmony_ci			return -1;
1577e5b75505Sopenharmony_ci
1578e5b75505Sopenharmony_ci		msg = hapd->dpp_pkex->exchange_req;
1579e5b75505Sopenharmony_ci		/* TODO: Which channel to use? */
1580e5b75505Sopenharmony_ci		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
1581e5b75505Sopenharmony_ci			" freq=%u type=%d", MAC2STR(broadcast), 2437,
1582e5b75505Sopenharmony_ci			DPP_PA_PKEX_EXCHANGE_REQ);
1583e5b75505Sopenharmony_ci		hostapd_drv_send_action(hapd, 2437, 0, broadcast,
1584e5b75505Sopenharmony_ci					wpabuf_head(msg), wpabuf_len(msg));
1585e5b75505Sopenharmony_ci	}
1586e5b75505Sopenharmony_ci
1587e5b75505Sopenharmony_ci	/* TODO: Support multiple PKEX info entries */
1588e5b75505Sopenharmony_ci
1589e5b75505Sopenharmony_ci	os_free(hapd->dpp_pkex_auth_cmd);
1590e5b75505Sopenharmony_ci	hapd->dpp_pkex_auth_cmd = os_strdup(cmd);
1591e5b75505Sopenharmony_ci
1592e5b75505Sopenharmony_ci	return 1;
1593e5b75505Sopenharmony_ci}
1594e5b75505Sopenharmony_ci
1595e5b75505Sopenharmony_ci
1596e5b75505Sopenharmony_ciint hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id)
1597e5b75505Sopenharmony_ci{
1598e5b75505Sopenharmony_ci	unsigned int id_val;
1599e5b75505Sopenharmony_ci
1600e5b75505Sopenharmony_ci	if (os_strcmp(id, "*") == 0) {
1601e5b75505Sopenharmony_ci		id_val = 0;
1602e5b75505Sopenharmony_ci	} else {
1603e5b75505Sopenharmony_ci		id_val = atoi(id);
1604e5b75505Sopenharmony_ci		if (id_val == 0)
1605e5b75505Sopenharmony_ci			return -1;
1606e5b75505Sopenharmony_ci	}
1607e5b75505Sopenharmony_ci
1608e5b75505Sopenharmony_ci	if ((id_val != 0 && id_val != 1) || !hapd->dpp_pkex_code)
1609e5b75505Sopenharmony_ci		return -1;
1610e5b75505Sopenharmony_ci
1611e5b75505Sopenharmony_ci	/* TODO: Support multiple PKEX entries */
1612e5b75505Sopenharmony_ci	os_free(hapd->dpp_pkex_code);
1613e5b75505Sopenharmony_ci	hapd->dpp_pkex_code = NULL;
1614e5b75505Sopenharmony_ci	os_free(hapd->dpp_pkex_identifier);
1615e5b75505Sopenharmony_ci	hapd->dpp_pkex_identifier = NULL;
1616e5b75505Sopenharmony_ci	os_free(hapd->dpp_pkex_auth_cmd);
1617e5b75505Sopenharmony_ci	hapd->dpp_pkex_auth_cmd = NULL;
1618e5b75505Sopenharmony_ci	hapd->dpp_pkex_bi = NULL;
1619e5b75505Sopenharmony_ci	/* TODO: Remove dpp_pkex only if it is for the identified PKEX code */
1620e5b75505Sopenharmony_ci	dpp_pkex_free(hapd->dpp_pkex);
1621e5b75505Sopenharmony_ci	hapd->dpp_pkex = NULL;
1622e5b75505Sopenharmony_ci	return 0;
1623e5b75505Sopenharmony_ci}
1624e5b75505Sopenharmony_ci
1625e5b75505Sopenharmony_ci
1626e5b75505Sopenharmony_civoid hostapd_dpp_stop(struct hostapd_data *hapd)
1627e5b75505Sopenharmony_ci{
1628e5b75505Sopenharmony_ci	dpp_auth_deinit(hapd->dpp_auth);
1629e5b75505Sopenharmony_ci	hapd->dpp_auth = NULL;
1630e5b75505Sopenharmony_ci	dpp_pkex_free(hapd->dpp_pkex);
1631e5b75505Sopenharmony_ci	hapd->dpp_pkex = NULL;
1632e5b75505Sopenharmony_ci}
1633e5b75505Sopenharmony_ci
1634e5b75505Sopenharmony_ci
1635e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
1636e5b75505Sopenharmony_ci
1637e5b75505Sopenharmony_cistatic void hostapd_dpp_relay_tx(void *ctx, const u8 *addr, unsigned int freq,
1638e5b75505Sopenharmony_ci				 const u8 *msg, size_t len)
1639e5b75505Sopenharmony_ci{
1640e5b75505Sopenharmony_ci	struct hostapd_data *hapd = ctx;
1641e5b75505Sopenharmony_ci	u8 *buf;
1642e5b75505Sopenharmony_ci
1643e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Send action frame dst=" MACSTR " freq=%u",
1644e5b75505Sopenharmony_ci		   MAC2STR(addr), freq);
1645e5b75505Sopenharmony_ci	buf = os_malloc(2 + len);
1646e5b75505Sopenharmony_ci	if (!buf)
1647e5b75505Sopenharmony_ci		return;
1648e5b75505Sopenharmony_ci	buf[0] = WLAN_ACTION_PUBLIC;
1649e5b75505Sopenharmony_ci	buf[1] = WLAN_PA_VENDOR_SPECIFIC;
1650e5b75505Sopenharmony_ci	os_memcpy(buf + 2, msg, len);
1651e5b75505Sopenharmony_ci	hostapd_drv_send_action(hapd, freq, 0, addr, buf, 2 + len);
1652e5b75505Sopenharmony_ci	os_free(buf);
1653e5b75505Sopenharmony_ci}
1654e5b75505Sopenharmony_ci
1655e5b75505Sopenharmony_ci
1656e5b75505Sopenharmony_cistatic void hostapd_dpp_relay_gas_resp_tx(void *ctx, const u8 *addr,
1657e5b75505Sopenharmony_ci					  u8 dialog_token, int prot,
1658e5b75505Sopenharmony_ci					  struct wpabuf *buf)
1659e5b75505Sopenharmony_ci{
1660e5b75505Sopenharmony_ci	struct hostapd_data *hapd = ctx;
1661e5b75505Sopenharmony_ci
1662e5b75505Sopenharmony_ci	gas_serv_req_dpp_processing(hapd, addr, dialog_token, prot, buf);
1663e5b75505Sopenharmony_ci}
1664e5b75505Sopenharmony_ci
1665e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
1666e5b75505Sopenharmony_ci
1667e5b75505Sopenharmony_ci
1668e5b75505Sopenharmony_cistatic int hostapd_dpp_add_controllers(struct hostapd_data *hapd)
1669e5b75505Sopenharmony_ci{
1670e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
1671e5b75505Sopenharmony_ci	struct dpp_controller_conf *ctrl;
1672e5b75505Sopenharmony_ci	struct dpp_relay_config config;
1673e5b75505Sopenharmony_ci
1674e5b75505Sopenharmony_ci	os_memset(&config, 0, sizeof(config));
1675e5b75505Sopenharmony_ci	config.cb_ctx = hapd;
1676e5b75505Sopenharmony_ci	config.tx = hostapd_dpp_relay_tx;
1677e5b75505Sopenharmony_ci	config.gas_resp_tx = hostapd_dpp_relay_gas_resp_tx;
1678e5b75505Sopenharmony_ci	for (ctrl = hapd->conf->dpp_controller; ctrl; ctrl = ctrl->next) {
1679e5b75505Sopenharmony_ci		config.ipaddr = &ctrl->ipaddr;
1680e5b75505Sopenharmony_ci		config.pkhash = ctrl->pkhash;
1681e5b75505Sopenharmony_ci		if (dpp_relay_add_controller(hapd->iface->interfaces->dpp,
1682e5b75505Sopenharmony_ci					     &config) < 0)
1683e5b75505Sopenharmony_ci			return -1;
1684e5b75505Sopenharmony_ci	}
1685e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
1686e5b75505Sopenharmony_ci
1687e5b75505Sopenharmony_ci	return 0;
1688e5b75505Sopenharmony_ci}
1689e5b75505Sopenharmony_ci
1690e5b75505Sopenharmony_ci
1691e5b75505Sopenharmony_ciint hostapd_dpp_init(struct hostapd_data *hapd)
1692e5b75505Sopenharmony_ci{
1693e5b75505Sopenharmony_ci	hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
1694e5b75505Sopenharmony_ci	hapd->dpp_init_done = 1;
1695e5b75505Sopenharmony_ci	return hostapd_dpp_add_controllers(hapd);
1696e5b75505Sopenharmony_ci}
1697e5b75505Sopenharmony_ci
1698e5b75505Sopenharmony_ci
1699e5b75505Sopenharmony_civoid hostapd_dpp_deinit(struct hostapd_data *hapd)
1700e5b75505Sopenharmony_ci{
1701e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1702e5b75505Sopenharmony_ci	os_free(hapd->dpp_config_obj_override);
1703e5b75505Sopenharmony_ci	hapd->dpp_config_obj_override = NULL;
1704e5b75505Sopenharmony_ci	os_free(hapd->dpp_discovery_override);
1705e5b75505Sopenharmony_ci	hapd->dpp_discovery_override = NULL;
1706e5b75505Sopenharmony_ci	os_free(hapd->dpp_groups_override);
1707e5b75505Sopenharmony_ci	hapd->dpp_groups_override = NULL;
1708e5b75505Sopenharmony_ci	hapd->dpp_ignore_netaccesskey_mismatch = 0;
1709e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1710e5b75505Sopenharmony_ci	if (!hapd->dpp_init_done)
1711e5b75505Sopenharmony_ci		return;
1712e5b75505Sopenharmony_ci	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
1713e5b75505Sopenharmony_ci	eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
1714e5b75505Sopenharmony_ci	eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
1715e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
1716e5b75505Sopenharmony_ci	eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
1717e5b75505Sopenharmony_ci			     NULL);
1718e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
1719e5b75505Sopenharmony_ci	dpp_auth_deinit(hapd->dpp_auth);
1720e5b75505Sopenharmony_ci	hapd->dpp_auth = NULL;
1721e5b75505Sopenharmony_ci	hostapd_dpp_pkex_remove(hapd, "*");
1722e5b75505Sopenharmony_ci	hapd->dpp_pkex = NULL;
1723e5b75505Sopenharmony_ci	os_free(hapd->dpp_configurator_params);
1724e5b75505Sopenharmony_ci	hapd->dpp_configurator_params = NULL;
1725e5b75505Sopenharmony_ci}
1726