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