185732ac8SCy Schubert /*
285732ac8SCy Schubert * wpa_supplicant - DPP
385732ac8SCy Schubert * Copyright (c) 2017, Qualcomm Atheros, Inc.
4c1d255d3SCy Schubert * Copyright (c) 2018-2020, The Linux Foundation
5*a90b9d01SCy Schubert * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc.
685732ac8SCy Schubert *
785732ac8SCy Schubert * This software may be distributed under the terms of the BSD license.
885732ac8SCy Schubert * See README for more details.
985732ac8SCy Schubert */
1085732ac8SCy Schubert
1185732ac8SCy Schubert #include "utils/includes.h"
1285732ac8SCy Schubert
1385732ac8SCy Schubert #include "utils/common.h"
1485732ac8SCy Schubert #include "utils/eloop.h"
15206b73d0SCy Schubert #include "utils/ip_addr.h"
16c1d255d3SCy Schubert #include "utils/base64.h"
1785732ac8SCy Schubert #include "common/dpp.h"
1885732ac8SCy Schubert #include "common/gas.h"
1985732ac8SCy Schubert #include "common/gas_server.h"
20*a90b9d01SCy Schubert #include "crypto/random.h"
2185732ac8SCy Schubert #include "rsn_supp/wpa.h"
2285732ac8SCy Schubert #include "rsn_supp/pmksa_cache.h"
2385732ac8SCy Schubert #include "wpa_supplicant_i.h"
2485732ac8SCy Schubert #include "config.h"
2585732ac8SCy Schubert #include "driver_i.h"
2685732ac8SCy Schubert #include "offchannel.h"
2785732ac8SCy Schubert #include "gas_query.h"
2885732ac8SCy Schubert #include "bss.h"
2985732ac8SCy Schubert #include "scan.h"
3085732ac8SCy Schubert #include "notify.h"
3185732ac8SCy Schubert #include "dpp_supplicant.h"
3285732ac8SCy Schubert
3385732ac8SCy Schubert
3485732ac8SCy Schubert static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
3585732ac8SCy Schubert unsigned int freq);
3685732ac8SCy Schubert static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
37c1d255d3SCy Schubert static void wpas_dpp_auth_conf_wait_timeout(void *eloop_ctx, void *timeout_ctx);
3885732ac8SCy Schubert static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator);
3985732ac8SCy Schubert static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
4085732ac8SCy Schubert unsigned int freq, const u8 *dst,
4185732ac8SCy Schubert const u8 *src, const u8 *bssid,
4285732ac8SCy Schubert const u8 *data, size_t data_len,
4385732ac8SCy Schubert enum offchannel_send_action_result result);
4485732ac8SCy Schubert static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
4585732ac8SCy Schubert static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s);
4685732ac8SCy Schubert static void
4785732ac8SCy Schubert wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
4885732ac8SCy Schubert unsigned int freq, const u8 *dst,
4985732ac8SCy Schubert const u8 *src, const u8 *bssid,
5085732ac8SCy Schubert const u8 *data, size_t data_len,
5185732ac8SCy Schubert enum offchannel_send_action_result result);
52*a90b9d01SCy Schubert static void wpas_dpp_gas_client_timeout(void *eloop_ctx, void *timeout_ctx);
53c1d255d3SCy Schubert #ifdef CONFIG_DPP2
54c1d255d3SCy Schubert static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
55c1d255d3SCy Schubert void *timeout_ctx);
56c1d255d3SCy Schubert static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s);
57c1d255d3SCy Schubert static int wpas_dpp_process_conf_obj(void *ctx,
58c1d255d3SCy Schubert struct dpp_authentication *auth);
59*a90b9d01SCy Schubert static bool wpas_dpp_tcp_msg_sent(void *ctx, struct dpp_authentication *auth);
60c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
6185732ac8SCy Schubert
6285732ac8SCy Schubert static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
6385732ac8SCy Schubert
6485732ac8SCy Schubert /* Use a hardcoded Transaction ID 1 in Peer Discovery frames since there is only
6585732ac8SCy Schubert * a single transaction in progress at any point in time. */
6685732ac8SCy Schubert static const u8 TRANSACTION_ID = 1;
6785732ac8SCy Schubert
6885732ac8SCy Schubert
6985732ac8SCy Schubert /**
7085732ac8SCy Schubert * wpas_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
7185732ac8SCy Schubert * @wpa_s: Pointer to wpa_supplicant data
7285732ac8SCy Schubert * @cmd: DPP URI read from a QR Code
7385732ac8SCy Schubert * Returns: Identifier of the stored info or -1 on failure
7485732ac8SCy Schubert */
wpas_dpp_qr_code(struct wpa_supplicant * wpa_s,const char * cmd)7585732ac8SCy Schubert int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd)
7685732ac8SCy Schubert {
7785732ac8SCy Schubert struct dpp_bootstrap_info *bi;
7885732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
7985732ac8SCy Schubert
804bc52338SCy Schubert bi = dpp_add_qr_code(wpa_s->dpp, cmd);
8185732ac8SCy Schubert if (!bi)
8285732ac8SCy Schubert return -1;
8385732ac8SCy Schubert
8485732ac8SCy Schubert if (auth && auth->response_pending &&
8585732ac8SCy Schubert dpp_notify_new_qr_code(auth, bi) == 1) {
8685732ac8SCy Schubert wpa_printf(MSG_DEBUG,
8785732ac8SCy Schubert "DPP: Sending out pending authentication response");
8885732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
8985732ac8SCy Schubert " freq=%u type=%d",
9085732ac8SCy Schubert MAC2STR(auth->peer_mac_addr), auth->curr_freq,
9185732ac8SCy Schubert DPP_PA_AUTHENTICATION_RESP);
9285732ac8SCy Schubert offchannel_send_action(wpa_s, auth->curr_freq,
9385732ac8SCy Schubert auth->peer_mac_addr, wpa_s->own_addr,
9485732ac8SCy Schubert broadcast,
9585732ac8SCy Schubert wpabuf_head(auth->resp_msg),
9685732ac8SCy Schubert wpabuf_len(auth->resp_msg),
9785732ac8SCy Schubert 500, wpas_dpp_tx_status, 0);
9885732ac8SCy Schubert }
9985732ac8SCy Schubert
100c1d255d3SCy Schubert #ifdef CONFIG_DPP2
101c1d255d3SCy Schubert dpp_controller_new_qr_code(wpa_s->dpp, bi);
102c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
103c1d255d3SCy Schubert
10485732ac8SCy Schubert return bi->id;
10585732ac8SCy Schubert }
10685732ac8SCy Schubert
10785732ac8SCy Schubert
108c1d255d3SCy Schubert /**
109c1d255d3SCy Schubert * wpas_dpp_nfc_uri - Parse and add DPP bootstrapping info from NFC Tag (URI)
110c1d255d3SCy Schubert * @wpa_s: Pointer to wpa_supplicant data
111c1d255d3SCy Schubert * @cmd: DPP URI read from a NFC Tag (URI NDEF message)
112c1d255d3SCy Schubert * Returns: Identifier of the stored info or -1 on failure
113c1d255d3SCy Schubert */
wpas_dpp_nfc_uri(struct wpa_supplicant * wpa_s,const char * cmd)114c1d255d3SCy Schubert int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd)
115c1d255d3SCy Schubert {
116c1d255d3SCy Schubert struct dpp_bootstrap_info *bi;
117c1d255d3SCy Schubert
118c1d255d3SCy Schubert bi = dpp_add_nfc_uri(wpa_s->dpp, cmd);
119c1d255d3SCy Schubert if (!bi)
120c1d255d3SCy Schubert return -1;
121c1d255d3SCy Schubert
122c1d255d3SCy Schubert return bi->id;
123c1d255d3SCy Schubert }
124c1d255d3SCy Schubert
125c1d255d3SCy Schubert
wpas_dpp_nfc_handover_req(struct wpa_supplicant * wpa_s,const char * cmd)126c1d255d3SCy Schubert int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd)
127c1d255d3SCy Schubert {
128c1d255d3SCy Schubert const char *pos;
129c1d255d3SCy Schubert struct dpp_bootstrap_info *peer_bi, *own_bi;
130c1d255d3SCy Schubert
131c1d255d3SCy Schubert pos = os_strstr(cmd, " own=");
132c1d255d3SCy Schubert if (!pos)
133c1d255d3SCy Schubert return -1;
134c1d255d3SCy Schubert pos += 5;
135c1d255d3SCy Schubert own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
136c1d255d3SCy Schubert if (!own_bi)
137c1d255d3SCy Schubert return -1;
138c1d255d3SCy Schubert own_bi->nfc_negotiated = 1;
139c1d255d3SCy Schubert
140c1d255d3SCy Schubert pos = os_strstr(cmd, " uri=");
141c1d255d3SCy Schubert if (!pos)
142c1d255d3SCy Schubert return -1;
143c1d255d3SCy Schubert pos += 5;
144c1d255d3SCy Schubert peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
145c1d255d3SCy Schubert if (!peer_bi) {
146c1d255d3SCy Schubert wpa_printf(MSG_INFO,
147c1d255d3SCy Schubert "DPP: Failed to parse URI from NFC Handover Request");
148c1d255d3SCy Schubert return -1;
149c1d255d3SCy Schubert }
150c1d255d3SCy Schubert
151c1d255d3SCy Schubert if (dpp_nfc_update_bi(own_bi, peer_bi) < 0)
152c1d255d3SCy Schubert return -1;
153c1d255d3SCy Schubert
154c1d255d3SCy Schubert return peer_bi->id;
155c1d255d3SCy Schubert }
156c1d255d3SCy Schubert
157c1d255d3SCy Schubert
wpas_dpp_nfc_handover_sel(struct wpa_supplicant * wpa_s,const char * cmd)158c1d255d3SCy Schubert int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd)
159c1d255d3SCy Schubert {
160c1d255d3SCy Schubert const char *pos;
161c1d255d3SCy Schubert struct dpp_bootstrap_info *peer_bi, *own_bi;
162c1d255d3SCy Schubert
163c1d255d3SCy Schubert pos = os_strstr(cmd, " own=");
164c1d255d3SCy Schubert if (!pos)
165c1d255d3SCy Schubert return -1;
166c1d255d3SCy Schubert pos += 5;
167c1d255d3SCy Schubert own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
168c1d255d3SCy Schubert if (!own_bi)
169c1d255d3SCy Schubert return -1;
170c1d255d3SCy Schubert own_bi->nfc_negotiated = 1;
171c1d255d3SCy Schubert
172c1d255d3SCy Schubert pos = os_strstr(cmd, " uri=");
173c1d255d3SCy Schubert if (!pos)
174c1d255d3SCy Schubert return -1;
175c1d255d3SCy Schubert pos += 5;
176c1d255d3SCy Schubert peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
177c1d255d3SCy Schubert if (!peer_bi) {
178c1d255d3SCy Schubert wpa_printf(MSG_INFO,
179c1d255d3SCy Schubert "DPP: Failed to parse URI from NFC Handover Select");
180c1d255d3SCy Schubert return -1;
181c1d255d3SCy Schubert }
182c1d255d3SCy Schubert
183c1d255d3SCy Schubert if (peer_bi->curve != own_bi->curve) {
184c1d255d3SCy Schubert wpa_printf(MSG_INFO,
185c1d255d3SCy Schubert "DPP: Peer (NFC Handover Selector) used different curve");
186c1d255d3SCy Schubert return -1;
187c1d255d3SCy Schubert }
188c1d255d3SCy Schubert
189c1d255d3SCy Schubert return peer_bi->id;
190c1d255d3SCy Schubert }
191c1d255d3SCy Schubert
192c1d255d3SCy Schubert
wpas_dpp_auth_resp_retry_timeout(void * eloop_ctx,void * timeout_ctx)19385732ac8SCy Schubert static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
19485732ac8SCy Schubert {
19585732ac8SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
19685732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
19785732ac8SCy Schubert
19885732ac8SCy Schubert if (!auth || !auth->resp_msg)
19985732ac8SCy Schubert return;
20085732ac8SCy Schubert
20185732ac8SCy Schubert wpa_printf(MSG_DEBUG,
20285732ac8SCy Schubert "DPP: Retry Authentication Response after timeout");
20385732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
20485732ac8SCy Schubert " freq=%u type=%d",
20585732ac8SCy Schubert MAC2STR(auth->peer_mac_addr), auth->curr_freq,
20685732ac8SCy Schubert DPP_PA_AUTHENTICATION_RESP);
20785732ac8SCy Schubert offchannel_send_action(wpa_s, auth->curr_freq, auth->peer_mac_addr,
20885732ac8SCy Schubert wpa_s->own_addr, broadcast,
20985732ac8SCy Schubert wpabuf_head(auth->resp_msg),
21085732ac8SCy Schubert wpabuf_len(auth->resp_msg),
21185732ac8SCy Schubert 500, wpas_dpp_tx_status, 0);
21285732ac8SCy Schubert }
21385732ac8SCy Schubert
21485732ac8SCy Schubert
wpas_dpp_auth_resp_retry(struct wpa_supplicant * wpa_s)21585732ac8SCy Schubert static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s)
21685732ac8SCy Schubert {
21785732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
21885732ac8SCy Schubert unsigned int wait_time, max_tries;
21985732ac8SCy Schubert
22085732ac8SCy Schubert if (!auth || !auth->resp_msg)
22185732ac8SCy Schubert return;
22285732ac8SCy Schubert
22385732ac8SCy Schubert if (wpa_s->dpp_resp_max_tries)
22485732ac8SCy Schubert max_tries = wpa_s->dpp_resp_max_tries;
22585732ac8SCy Schubert else
22685732ac8SCy Schubert max_tries = 5;
22785732ac8SCy Schubert auth->auth_resp_tries++;
22885732ac8SCy Schubert if (auth->auth_resp_tries >= max_tries) {
22985732ac8SCy Schubert wpa_printf(MSG_INFO, "DPP: No confirm received from initiator - stopping exchange");
23085732ac8SCy Schubert offchannel_send_action_done(wpa_s);
23185732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
23285732ac8SCy Schubert wpa_s->dpp_auth = NULL;
23385732ac8SCy Schubert return;
23485732ac8SCy Schubert }
23585732ac8SCy Schubert
23685732ac8SCy Schubert if (wpa_s->dpp_resp_retry_time)
23785732ac8SCy Schubert wait_time = wpa_s->dpp_resp_retry_time;
23885732ac8SCy Schubert else
23985732ac8SCy Schubert wait_time = 1000;
240*a90b9d01SCy Schubert if (wpa_s->dpp_tx_chan_change) {
241*a90b9d01SCy Schubert wpa_s->dpp_tx_chan_change = false;
242*a90b9d01SCy Schubert if (wait_time > 100)
243*a90b9d01SCy Schubert wait_time = 100;
244*a90b9d01SCy Schubert }
245*a90b9d01SCy Schubert
24685732ac8SCy Schubert wpa_printf(MSG_DEBUG,
24785732ac8SCy Schubert "DPP: Schedule retransmission of Authentication Response frame in %u ms",
24885732ac8SCy Schubert wait_time);
24985732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
25085732ac8SCy Schubert eloop_register_timeout(wait_time / 1000,
25185732ac8SCy Schubert (wait_time % 1000) * 1000,
25285732ac8SCy Schubert wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
25385732ac8SCy Schubert }
25485732ac8SCy Schubert
25585732ac8SCy Schubert
wpas_dpp_try_to_connect(struct wpa_supplicant * wpa_s)2564bc52338SCy Schubert static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
2574bc52338SCy Schubert {
2584bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
259c1d255d3SCy Schubert wpa_s->suitable_network = 0;
260c1d255d3SCy Schubert wpa_s->no_suitable_network = 0;
2614bc52338SCy Schubert wpa_s->disconnected = 0;
2624bc52338SCy Schubert wpa_s->reassociate = 1;
2634bc52338SCy Schubert wpa_s->scan_runs = 0;
2644bc52338SCy Schubert wpa_s->normal_scans = 0;
2654bc52338SCy Schubert wpa_supplicant_cancel_sched_scan(wpa_s);
2664bc52338SCy Schubert wpa_supplicant_req_scan(wpa_s, 0, 0);
2674bc52338SCy Schubert }
2684bc52338SCy Schubert
2694bc52338SCy Schubert
270c1d255d3SCy Schubert #ifdef CONFIG_DPP2
271c1d255d3SCy Schubert
wpas_dpp_stop_listen_for_tx(struct wpa_supplicant * wpa_s,unsigned int freq,unsigned int wait_time)272c1d255d3SCy Schubert static void wpas_dpp_stop_listen_for_tx(struct wpa_supplicant *wpa_s,
273c1d255d3SCy Schubert unsigned int freq,
274c1d255d3SCy Schubert unsigned int wait_time)
275c1d255d3SCy Schubert {
276c1d255d3SCy Schubert struct os_reltime now, res;
277c1d255d3SCy Schubert unsigned int remaining;
278c1d255d3SCy Schubert
279c1d255d3SCy Schubert if (!wpa_s->dpp_listen_freq)
280c1d255d3SCy Schubert return;
281c1d255d3SCy Schubert
282c1d255d3SCy Schubert os_get_reltime(&now);
283c1d255d3SCy Schubert if (os_reltime_before(&now, &wpa_s->dpp_listen_end)) {
284c1d255d3SCy Schubert os_reltime_sub(&wpa_s->dpp_listen_end, &now, &res);
285c1d255d3SCy Schubert remaining = res.sec * 1000 + res.usec / 1000;
286c1d255d3SCy Schubert } else {
287c1d255d3SCy Schubert remaining = 0;
288c1d255d3SCy Schubert }
289c1d255d3SCy Schubert if (wpa_s->dpp_listen_freq == freq && remaining > wait_time)
290c1d255d3SCy Schubert return;
291c1d255d3SCy Schubert
292c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
293c1d255d3SCy Schubert "DPP: Stop listen on %u MHz ending in %u ms to allow immediate TX on %u MHz for %u ms",
294c1d255d3SCy Schubert wpa_s->dpp_listen_freq, remaining, freq, wait_time);
295c1d255d3SCy Schubert wpas_dpp_listen_stop(wpa_s);
296c1d255d3SCy Schubert
297c1d255d3SCy Schubert /* TODO: Restart listen in some cases after TX? */
298c1d255d3SCy Schubert }
299c1d255d3SCy Schubert
300c1d255d3SCy Schubert
wpas_dpp_conn_status_result_timeout(void * eloop_ctx,void * timeout_ctx)301c1d255d3SCy Schubert static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx,
302c1d255d3SCy Schubert void *timeout_ctx)
303c1d255d3SCy Schubert {
304c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
305c1d255d3SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
306c1d255d3SCy Schubert enum dpp_status_error result;
307c1d255d3SCy Schubert
308*a90b9d01SCy Schubert if ((!auth || !auth->conn_status_requested) &&
309*a90b9d01SCy Schubert !dpp_tcp_conn_status_requested(wpa_s->dpp))
310c1d255d3SCy Schubert return;
311c1d255d3SCy Schubert
312c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
313c1d255d3SCy Schubert "DPP: Connection timeout - report Connection Status Result");
314c1d255d3SCy Schubert if (wpa_s->suitable_network)
315c1d255d3SCy Schubert result = DPP_STATUS_AUTH_FAILURE;
316c1d255d3SCy Schubert else if (wpa_s->no_suitable_network)
317c1d255d3SCy Schubert result = DPP_STATUS_NO_AP;
318c1d255d3SCy Schubert else
319c1d255d3SCy Schubert result = 255; /* What to report here for unexpected state? */
320c1d255d3SCy Schubert if (wpa_s->wpa_state == WPA_SCANNING)
321c1d255d3SCy Schubert wpas_abort_ongoing_scan(wpa_s);
322c1d255d3SCy Schubert wpas_dpp_send_conn_status_result(wpa_s, result);
323c1d255d3SCy Schubert }
324c1d255d3SCy Schubert
325c1d255d3SCy Schubert
wpas_dpp_scan_channel_list(struct wpa_supplicant * wpa_s)326c1d255d3SCy Schubert static char * wpas_dpp_scan_channel_list(struct wpa_supplicant *wpa_s)
327c1d255d3SCy Schubert {
328c1d255d3SCy Schubert char *str, *end, *pos;
329c1d255d3SCy Schubert size_t len;
330c1d255d3SCy Schubert unsigned int i;
331c1d255d3SCy Schubert u8 last_op_class = 0;
332c1d255d3SCy Schubert int res;
333c1d255d3SCy Schubert
334c1d255d3SCy Schubert if (!wpa_s->last_scan_freqs || !wpa_s->num_last_scan_freqs)
335c1d255d3SCy Schubert return NULL;
336c1d255d3SCy Schubert
337c1d255d3SCy Schubert len = wpa_s->num_last_scan_freqs * 8;
338c1d255d3SCy Schubert str = os_zalloc(len);
339c1d255d3SCy Schubert if (!str)
340c1d255d3SCy Schubert return NULL;
341c1d255d3SCy Schubert end = str + len;
342c1d255d3SCy Schubert pos = str;
343c1d255d3SCy Schubert
344c1d255d3SCy Schubert for (i = 0; i < wpa_s->num_last_scan_freqs; i++) {
345c1d255d3SCy Schubert enum hostapd_hw_mode mode;
346c1d255d3SCy Schubert u8 op_class, channel;
347c1d255d3SCy Schubert
348c1d255d3SCy Schubert mode = ieee80211_freq_to_channel_ext(wpa_s->last_scan_freqs[i],
349c1d255d3SCy Schubert 0, 0, &op_class, &channel);
350c1d255d3SCy Schubert if (mode == NUM_HOSTAPD_MODES)
351c1d255d3SCy Schubert continue;
352c1d255d3SCy Schubert if (op_class == last_op_class)
353c1d255d3SCy Schubert res = os_snprintf(pos, end - pos, ",%d", channel);
354c1d255d3SCy Schubert else
355c1d255d3SCy Schubert res = os_snprintf(pos, end - pos, "%s%d/%d",
356c1d255d3SCy Schubert pos == str ? "" : ",",
357c1d255d3SCy Schubert op_class, channel);
358c1d255d3SCy Schubert if (os_snprintf_error(end - pos, res)) {
359c1d255d3SCy Schubert *pos = '\0';
360c1d255d3SCy Schubert break;
361c1d255d3SCy Schubert }
362c1d255d3SCy Schubert pos += res;
363c1d255d3SCy Schubert last_op_class = op_class;
364c1d255d3SCy Schubert }
365c1d255d3SCy Schubert
366c1d255d3SCy Schubert if (pos == str) {
367c1d255d3SCy Schubert os_free(str);
368c1d255d3SCy Schubert str = NULL;
369c1d255d3SCy Schubert }
370c1d255d3SCy Schubert return str;
371c1d255d3SCy Schubert }
372c1d255d3SCy Schubert
373c1d255d3SCy Schubert
wpas_dpp_send_conn_status_result(struct wpa_supplicant * wpa_s,enum dpp_status_error result)374c1d255d3SCy Schubert void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
375c1d255d3SCy Schubert enum dpp_status_error result)
376c1d255d3SCy Schubert {
377c1d255d3SCy Schubert struct wpabuf *msg;
378c1d255d3SCy Schubert const char *channel_list = NULL;
379c1d255d3SCy Schubert char *channel_list_buf = NULL;
380c1d255d3SCy Schubert struct wpa_ssid *ssid = wpa_s->current_ssid;
381c1d255d3SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
382c1d255d3SCy Schubert
383c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
384c1d255d3SCy Schubert
385*a90b9d01SCy Schubert if ((!auth || !auth->conn_status_requested) &&
386*a90b9d01SCy Schubert !dpp_tcp_conn_status_requested(wpa_s->dpp))
387c1d255d3SCy Schubert return;
388*a90b9d01SCy Schubert
389c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Report connection status result %d",
390c1d255d3SCy Schubert result);
391c1d255d3SCy Schubert
392c1d255d3SCy Schubert if (result == DPP_STATUS_NO_AP) {
393c1d255d3SCy Schubert channel_list_buf = wpas_dpp_scan_channel_list(wpa_s);
394c1d255d3SCy Schubert channel_list = channel_list_buf;
395c1d255d3SCy Schubert }
396c1d255d3SCy Schubert
397*a90b9d01SCy Schubert if (!auth || !auth->conn_status_requested) {
398*a90b9d01SCy Schubert dpp_tcp_send_conn_status(wpa_s->dpp, result,
399*a90b9d01SCy Schubert ssid ? ssid->ssid :
400*a90b9d01SCy Schubert wpa_s->dpp_last_ssid,
401*a90b9d01SCy Schubert ssid ? ssid->ssid_len :
402*a90b9d01SCy Schubert wpa_s->dpp_last_ssid_len,
403*a90b9d01SCy Schubert channel_list);
404*a90b9d01SCy Schubert os_free(channel_list_buf);
405*a90b9d01SCy Schubert return;
406*a90b9d01SCy Schubert }
407*a90b9d01SCy Schubert
408*a90b9d01SCy Schubert auth->conn_status_requested = 0;
409*a90b9d01SCy Schubert
410c1d255d3SCy Schubert msg = dpp_build_conn_status_result(auth, result,
411c1d255d3SCy Schubert ssid ? ssid->ssid :
412c1d255d3SCy Schubert wpa_s->dpp_last_ssid,
413c1d255d3SCy Schubert ssid ? ssid->ssid_len :
414c1d255d3SCy Schubert wpa_s->dpp_last_ssid_len,
415c1d255d3SCy Schubert channel_list);
416c1d255d3SCy Schubert os_free(channel_list_buf);
417c1d255d3SCy Schubert if (!msg) {
418c1d255d3SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
419c1d255d3SCy Schubert wpa_s->dpp_auth = NULL;
420c1d255d3SCy Schubert return;
421c1d255d3SCy Schubert }
422c1d255d3SCy Schubert
423c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO,
424c1d255d3SCy Schubert DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
425c1d255d3SCy Schubert MAC2STR(auth->peer_mac_addr), auth->curr_freq,
426c1d255d3SCy Schubert DPP_PA_CONNECTION_STATUS_RESULT);
427c1d255d3SCy Schubert offchannel_send_action(wpa_s, auth->curr_freq,
428c1d255d3SCy Schubert auth->peer_mac_addr, wpa_s->own_addr, broadcast,
429c1d255d3SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
430c1d255d3SCy Schubert 500, wpas_dpp_tx_status, 0);
431c1d255d3SCy Schubert wpabuf_free(msg);
432c1d255d3SCy Schubert
433c1d255d3SCy Schubert /* This exchange will be terminated in the TX status handler */
434c1d255d3SCy Schubert auth->remove_on_tx_status = 1;
435c1d255d3SCy Schubert
436c1d255d3SCy Schubert return;
437c1d255d3SCy Schubert }
438c1d255d3SCy Schubert
439c1d255d3SCy Schubert
wpas_dpp_connected_timeout(void * eloop_ctx,void * timeout_ctx)440*a90b9d01SCy Schubert static void wpas_dpp_connected_timeout(void *eloop_ctx, void *timeout_ctx)
441*a90b9d01SCy Schubert {
442*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
443*a90b9d01SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
444*a90b9d01SCy Schubert
445*a90b9d01SCy Schubert if ((auth && auth->conn_status_requested) ||
446*a90b9d01SCy Schubert dpp_tcp_conn_status_requested(wpa_s->dpp))
447*a90b9d01SCy Schubert wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_OK);
448*a90b9d01SCy Schubert }
449*a90b9d01SCy Schubert
450*a90b9d01SCy Schubert
wpas_dpp_connected(struct wpa_supplicant * wpa_s)451c1d255d3SCy Schubert void wpas_dpp_connected(struct wpa_supplicant *wpa_s)
452c1d255d3SCy Schubert {
453c1d255d3SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
454c1d255d3SCy Schubert
455*a90b9d01SCy Schubert if ((auth && auth->conn_status_requested) ||
456*a90b9d01SCy Schubert dpp_tcp_conn_status_requested(wpa_s->dpp)) {
457*a90b9d01SCy Schubert /* Report connection result from an eloop timeout to avoid delay
458*a90b9d01SCy Schubert * to completing all connection completion steps since this
459*a90b9d01SCy Schubert * function is called in a middle of the post 4-way handshake
460*a90b9d01SCy Schubert * processing. */
461*a90b9d01SCy Schubert eloop_register_timeout(0, 0, wpas_dpp_connected_timeout,
462*a90b9d01SCy Schubert wpa_s, NULL);
463*a90b9d01SCy Schubert }
464c1d255d3SCy Schubert }
465c1d255d3SCy Schubert
466c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
467c1d255d3SCy Schubert
468c1d255d3SCy Schubert
wpas_dpp_drv_wait_timeout(void * eloop_ctx,void * timeout_ctx)469*a90b9d01SCy Schubert static void wpas_dpp_drv_wait_timeout(void *eloop_ctx, void *timeout_ctx)
470*a90b9d01SCy Schubert {
471*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
472*a90b9d01SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
473*a90b9d01SCy Schubert
474*a90b9d01SCy Schubert if (auth && auth->waiting_auth_resp) {
475*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
476*a90b9d01SCy Schubert "DPP: Call wpas_dpp_auth_init_next() from %s",
477*a90b9d01SCy Schubert __func__);
478*a90b9d01SCy Schubert wpas_dpp_auth_init_next(wpa_s);
479*a90b9d01SCy Schubert } else {
480*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: %s, but no waiting_auth_resp",
481*a90b9d01SCy Schubert __func__);
482*a90b9d01SCy Schubert }
483*a90b9d01SCy Schubert }
484*a90b9d01SCy Schubert
485*a90b9d01SCy Schubert
wpas_dpp_neg_freq_timeout(void * eloop_ctx,void * timeout_ctx)486*a90b9d01SCy Schubert static void wpas_dpp_neg_freq_timeout(void *eloop_ctx, void *timeout_ctx)
487*a90b9d01SCy Schubert {
488*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
489*a90b9d01SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
490*a90b9d01SCy Schubert
491*a90b9d01SCy Schubert if (!wpa_s->dpp_listen_on_tx_expire || !auth || !auth->neg_freq)
492*a90b9d01SCy Schubert return;
493*a90b9d01SCy Schubert
494*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
495*a90b9d01SCy Schubert "DPP: Start listen on neg_freq %u MHz based on timeout for TX wait expiration",
496*a90b9d01SCy Schubert auth->neg_freq);
497*a90b9d01SCy Schubert wpas_dpp_listen_start(wpa_s, auth->neg_freq);
498*a90b9d01SCy Schubert }
499*a90b9d01SCy Schubert
500*a90b9d01SCy Schubert
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)50185732ac8SCy Schubert static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
50285732ac8SCy Schubert unsigned int freq, const u8 *dst,
50385732ac8SCy Schubert const u8 *src, const u8 *bssid,
50485732ac8SCy Schubert const u8 *data, size_t data_len,
50585732ac8SCy Schubert enum offchannel_send_action_result result)
50685732ac8SCy Schubert {
50785732ac8SCy Schubert const char *res_txt;
50885732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
50985732ac8SCy Schubert
51085732ac8SCy Schubert res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
51185732ac8SCy Schubert (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
51285732ac8SCy Schubert "FAILED");
51385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
51485732ac8SCy Schubert " result=%s", freq, MAC2STR(dst), res_txt);
51585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
51685732ac8SCy Schubert " freq=%u result=%s", MAC2STR(dst), freq, res_txt);
51785732ac8SCy Schubert
51885732ac8SCy Schubert if (!wpa_s->dpp_auth) {
51985732ac8SCy Schubert wpa_printf(MSG_DEBUG,
52085732ac8SCy Schubert "DPP: Ignore TX status since there is no ongoing authentication exchange");
52185732ac8SCy Schubert return;
52285732ac8SCy Schubert }
52385732ac8SCy Schubert
5244bc52338SCy Schubert #ifdef CONFIG_DPP2
5254bc52338SCy Schubert if (auth->connect_on_tx_status) {
526c1d255d3SCy Schubert auth->connect_on_tx_status = 0;
5274bc52338SCy Schubert wpa_printf(MSG_DEBUG,
5284bc52338SCy Schubert "DPP: Try to connect after completed configuration result");
5294bc52338SCy Schubert wpas_dpp_try_to_connect(wpa_s);
530c1d255d3SCy Schubert if (auth->conn_status_requested) {
531c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
532c1d255d3SCy Schubert "DPP: Start 15 second timeout for reporting connection status result");
533c1d255d3SCy Schubert eloop_cancel_timeout(
534c1d255d3SCy Schubert wpas_dpp_conn_status_result_timeout,
535c1d255d3SCy Schubert wpa_s, NULL);
536c1d255d3SCy Schubert eloop_register_timeout(
537c1d255d3SCy Schubert 15, 0, wpas_dpp_conn_status_result_timeout,
538c1d255d3SCy Schubert wpa_s, NULL);
539c1d255d3SCy Schubert } else {
5404bc52338SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
5414bc52338SCy Schubert wpa_s->dpp_auth = NULL;
542c1d255d3SCy Schubert }
5434bc52338SCy Schubert return;
5444bc52338SCy Schubert }
5454bc52338SCy Schubert #endif /* CONFIG_DPP2 */
5464bc52338SCy Schubert
54785732ac8SCy Schubert if (wpa_s->dpp_auth->remove_on_tx_status) {
54885732ac8SCy Schubert wpa_printf(MSG_DEBUG,
549c1d255d3SCy Schubert "DPP: Terminate authentication exchange due to a request to do so on TX status");
55085732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
55185732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
552c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s,
553c1d255d3SCy Schubert NULL);
55485732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
55585732ac8SCy Schubert NULL);
556c1d255d3SCy Schubert #ifdef CONFIG_DPP2
557c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
558c1d255d3SCy Schubert wpa_s, NULL);
559c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
56085732ac8SCy Schubert offchannel_send_action_done(wpa_s);
56185732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
56285732ac8SCy Schubert wpa_s->dpp_auth = NULL;
56385732ac8SCy Schubert return;
56485732ac8SCy Schubert }
56585732ac8SCy Schubert
56685732ac8SCy Schubert if (wpa_s->dpp_auth_ok_on_ack)
56785732ac8SCy Schubert wpas_dpp_auth_success(wpa_s, 1);
56885732ac8SCy Schubert
56985732ac8SCy Schubert if (!is_broadcast_ether_addr(dst) &&
57085732ac8SCy Schubert result != OFFCHANNEL_SEND_ACTION_SUCCESS) {
57185732ac8SCy Schubert wpa_printf(MSG_DEBUG,
57285732ac8SCy Schubert "DPP: Unicast DPP Action frame was not ACKed");
57385732ac8SCy Schubert if (auth->waiting_auth_resp) {
57485732ac8SCy Schubert /* In case of DPP Authentication Request frame, move to
57585732ac8SCy Schubert * the next channel immediately. */
57685732ac8SCy Schubert offchannel_send_action_done(wpa_s);
577*a90b9d01SCy Schubert /* Call wpas_dpp_auth_init_next(wpa_s) from driver event
578*a90b9d01SCy Schubert * notifying frame wait was completed or from eloop
579*a90b9d01SCy Schubert * timeout. */
580*a90b9d01SCy Schubert eloop_register_timeout(0, 10000,
581*a90b9d01SCy Schubert wpas_dpp_drv_wait_timeout,
582*a90b9d01SCy Schubert wpa_s, NULL);
58385732ac8SCy Schubert return;
58485732ac8SCy Schubert }
58585732ac8SCy Schubert if (auth->waiting_auth_conf) {
58685732ac8SCy Schubert wpas_dpp_auth_resp_retry(wpa_s);
58785732ac8SCy Schubert return;
58885732ac8SCy Schubert }
58985732ac8SCy Schubert }
59085732ac8SCy Schubert
591c1d255d3SCy Schubert if (auth->waiting_auth_conf &&
592c1d255d3SCy Schubert auth->auth_resp_status == DPP_STATUS_OK) {
593c1d255d3SCy Schubert /* Make sure we do not get stuck waiting for Auth Confirm
594c1d255d3SCy Schubert * indefinitely after successfully transmitted Auth Response to
595c1d255d3SCy Schubert * allow new authentication exchanges to be started. */
596c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s,
597c1d255d3SCy Schubert NULL);
598c1d255d3SCy Schubert eloop_register_timeout(1, 0, wpas_dpp_auth_conf_wait_timeout,
599c1d255d3SCy Schubert wpa_s, NULL);
600c1d255d3SCy Schubert }
601c1d255d3SCy Schubert
60285732ac8SCy Schubert if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp &&
60385732ac8SCy Schubert result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
60485732ac8SCy Schubert /* Allow timeout handling to stop iteration if no response is
60585732ac8SCy Schubert * received from a peer that has ACKed a request. */
60685732ac8SCy Schubert auth->auth_req_ack = 1;
60785732ac8SCy Schubert }
60885732ac8SCy Schubert
60985732ac8SCy Schubert if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 &&
61085732ac8SCy Schubert wpa_s->dpp_auth->curr_freq != wpa_s->dpp_auth->neg_freq) {
61185732ac8SCy Schubert wpa_printf(MSG_DEBUG,
61285732ac8SCy Schubert "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
61385732ac8SCy Schubert wpa_s->dpp_auth->curr_freq,
61485732ac8SCy Schubert wpa_s->dpp_auth->neg_freq);
61585732ac8SCy Schubert offchannel_send_action_done(wpa_s);
616*a90b9d01SCy Schubert wpa_s->dpp_listen_on_tx_expire = true;
617*a90b9d01SCy Schubert eloop_register_timeout(0, 100000, wpas_dpp_neg_freq_timeout,
618*a90b9d01SCy Schubert wpa_s, NULL);
61985732ac8SCy Schubert }
62085732ac8SCy Schubert
62185732ac8SCy Schubert if (wpa_s->dpp_auth_ok_on_ack)
62285732ac8SCy Schubert wpa_s->dpp_auth_ok_on_ack = 0;
62385732ac8SCy Schubert }
62485732ac8SCy Schubert
62585732ac8SCy Schubert
wpas_dpp_reply_wait_timeout(void * eloop_ctx,void * timeout_ctx)62685732ac8SCy Schubert static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
62785732ac8SCy Schubert {
62885732ac8SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
62985732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
63085732ac8SCy Schubert unsigned int freq;
63185732ac8SCy Schubert struct os_reltime now, diff;
63285732ac8SCy Schubert unsigned int wait_time, diff_ms;
63385732ac8SCy Schubert
63485732ac8SCy Schubert if (!auth || !auth->waiting_auth_resp)
63585732ac8SCy Schubert return;
63685732ac8SCy Schubert
63785732ac8SCy Schubert wait_time = wpa_s->dpp_resp_wait_time ?
63885732ac8SCy Schubert wpa_s->dpp_resp_wait_time : 2000;
63985732ac8SCy Schubert os_get_reltime(&now);
64085732ac8SCy Schubert os_reltime_sub(&now, &wpa_s->dpp_last_init, &diff);
64185732ac8SCy Schubert diff_ms = diff.sec * 1000 + diff.usec / 1000;
64285732ac8SCy Schubert wpa_printf(MSG_DEBUG,
64385732ac8SCy Schubert "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
64485732ac8SCy Schubert wait_time, diff_ms);
64585732ac8SCy Schubert
64685732ac8SCy Schubert if (auth->auth_req_ack && diff_ms >= wait_time) {
64785732ac8SCy Schubert /* Peer ACK'ed Authentication Request frame, but did not reply
64885732ac8SCy Schubert * with Authentication Response frame within two seconds. */
64985732ac8SCy Schubert wpa_printf(MSG_INFO,
65085732ac8SCy Schubert "DPP: No response received from responder - stopping initiation attempt");
65185732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
65285732ac8SCy Schubert offchannel_send_action_done(wpa_s);
65385732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s);
65485732ac8SCy Schubert dpp_auth_deinit(auth);
65585732ac8SCy Schubert wpa_s->dpp_auth = NULL;
65685732ac8SCy Schubert return;
65785732ac8SCy Schubert }
65885732ac8SCy Schubert
65985732ac8SCy Schubert if (diff_ms >= wait_time) {
66085732ac8SCy Schubert /* Authentication Request frame was not ACK'ed and no reply
66185732ac8SCy Schubert * was receiving within two seconds. */
66285732ac8SCy Schubert wpa_printf(MSG_DEBUG,
66385732ac8SCy Schubert "DPP: Continue Initiator channel iteration");
66485732ac8SCy Schubert offchannel_send_action_done(wpa_s);
66585732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s);
66685732ac8SCy Schubert wpas_dpp_auth_init_next(wpa_s);
66785732ac8SCy Schubert return;
66885732ac8SCy Schubert }
66985732ac8SCy Schubert
67085732ac8SCy Schubert /* Driver did not support 2000 ms long wait_time with TX command, so
67185732ac8SCy Schubert * schedule listen operation to continue waiting for the response.
67285732ac8SCy Schubert *
67385732ac8SCy Schubert * DPP listen operations continue until stopped, so simply schedule a
67485732ac8SCy Schubert * new call to this function at the point when the two second reply
67585732ac8SCy Schubert * wait has expired. */
67685732ac8SCy Schubert wait_time -= diff_ms;
67785732ac8SCy Schubert
67885732ac8SCy Schubert freq = auth->curr_freq;
67985732ac8SCy Schubert if (auth->neg_freq > 0)
68085732ac8SCy Schubert freq = auth->neg_freq;
68185732ac8SCy Schubert wpa_printf(MSG_DEBUG,
68285732ac8SCy Schubert "DPP: Continue reply wait on channel %u MHz for %u ms",
68385732ac8SCy Schubert freq, wait_time);
68485732ac8SCy Schubert wpa_s->dpp_in_response_listen = 1;
68585732ac8SCy Schubert wpas_dpp_listen_start(wpa_s, freq);
68685732ac8SCy Schubert
68785732ac8SCy Schubert eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
68885732ac8SCy Schubert wpas_dpp_reply_wait_timeout, wpa_s, NULL);
68985732ac8SCy Schubert }
69085732ac8SCy Schubert
69185732ac8SCy Schubert
wpas_dpp_auth_conf_wait_timeout(void * eloop_ctx,void * timeout_ctx)692c1d255d3SCy Schubert static void wpas_dpp_auth_conf_wait_timeout(void *eloop_ctx, void *timeout_ctx)
693c1d255d3SCy Schubert {
694c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
695c1d255d3SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
696c1d255d3SCy Schubert
697c1d255d3SCy Schubert if (!auth || !auth->waiting_auth_conf)
698c1d255d3SCy Schubert return;
699c1d255d3SCy Schubert
700c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
701c1d255d3SCy Schubert "DPP: Terminate authentication exchange due to Auth Confirm timeout");
702c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL "No Auth Confirm received");
703c1d255d3SCy Schubert offchannel_send_action_done(wpa_s);
704c1d255d3SCy Schubert dpp_auth_deinit(auth);
705c1d255d3SCy Schubert wpa_s->dpp_auth = NULL;
706c1d255d3SCy Schubert }
707c1d255d3SCy Schubert
708c1d255d3SCy Schubert
wpas_dpp_set_testing_options(struct wpa_supplicant * wpa_s,struct dpp_authentication * auth)70985732ac8SCy Schubert static void wpas_dpp_set_testing_options(struct wpa_supplicant *wpa_s,
71085732ac8SCy Schubert struct dpp_authentication *auth)
71185732ac8SCy Schubert {
71285732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
71385732ac8SCy Schubert if (wpa_s->dpp_config_obj_override)
71485732ac8SCy Schubert auth->config_obj_override =
71585732ac8SCy Schubert os_strdup(wpa_s->dpp_config_obj_override);
71685732ac8SCy Schubert if (wpa_s->dpp_discovery_override)
71785732ac8SCy Schubert auth->discovery_override =
71885732ac8SCy Schubert os_strdup(wpa_s->dpp_discovery_override);
71985732ac8SCy Schubert if (wpa_s->dpp_groups_override)
72085732ac8SCy Schubert auth->groups_override =
72185732ac8SCy Schubert os_strdup(wpa_s->dpp_groups_override);
72285732ac8SCy Schubert auth->ignore_netaccesskey_mismatch =
72385732ac8SCy Schubert wpa_s->dpp_ignore_netaccesskey_mismatch;
72485732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
72585732ac8SCy Schubert }
72685732ac8SCy Schubert
72785732ac8SCy Schubert
wpas_dpp_init_timeout(void * eloop_ctx,void * timeout_ctx)72885732ac8SCy Schubert static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
72985732ac8SCy Schubert {
73085732ac8SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
73185732ac8SCy Schubert
73285732ac8SCy Schubert if (!wpa_s->dpp_auth)
73385732ac8SCy Schubert return;
73485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
73585732ac8SCy Schubert wpas_dpp_auth_init_next(wpa_s);
73685732ac8SCy Schubert }
73785732ac8SCy Schubert
73885732ac8SCy Schubert
wpas_dpp_auth_init_next(struct wpa_supplicant * wpa_s)73985732ac8SCy Schubert static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s)
74085732ac8SCy Schubert {
74185732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
74285732ac8SCy Schubert const u8 *dst;
74385732ac8SCy Schubert unsigned int wait_time, max_wait_time, freq, max_tries, used;
74485732ac8SCy Schubert struct os_reltime now, diff;
74585732ac8SCy Schubert
746*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_drv_wait_timeout, wpa_s, NULL);
747*a90b9d01SCy Schubert
74885732ac8SCy Schubert wpa_s->dpp_in_response_listen = 0;
74985732ac8SCy Schubert if (!auth)
75085732ac8SCy Schubert return -1;
75185732ac8SCy Schubert
75285732ac8SCy Schubert if (auth->freq_idx == 0)
75385732ac8SCy Schubert os_get_reltime(&wpa_s->dpp_init_iter_start);
75485732ac8SCy Schubert
75585732ac8SCy Schubert if (auth->freq_idx >= auth->num_freq) {
75685732ac8SCy Schubert auth->num_freq_iters++;
75785732ac8SCy Schubert if (wpa_s->dpp_init_max_tries)
75885732ac8SCy Schubert max_tries = wpa_s->dpp_init_max_tries;
75985732ac8SCy Schubert else
76085732ac8SCy Schubert max_tries = 5;
76185732ac8SCy Schubert if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
76285732ac8SCy Schubert wpa_printf(MSG_INFO,
76385732ac8SCy Schubert "DPP: No response received from responder - stopping initiation attempt");
76485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
76585732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout,
76685732ac8SCy Schubert wpa_s, NULL);
76785732ac8SCy Schubert offchannel_send_action_done(wpa_s);
76885732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
76985732ac8SCy Schubert wpa_s->dpp_auth = NULL;
77085732ac8SCy Schubert return -1;
77185732ac8SCy Schubert }
77285732ac8SCy Schubert auth->freq_idx = 0;
77385732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
77485732ac8SCy Schubert if (wpa_s->dpp_init_retry_time)
77585732ac8SCy Schubert wait_time = wpa_s->dpp_init_retry_time;
77685732ac8SCy Schubert else
77785732ac8SCy Schubert wait_time = 10000;
77885732ac8SCy Schubert os_get_reltime(&now);
77985732ac8SCy Schubert os_reltime_sub(&now, &wpa_s->dpp_init_iter_start, &diff);
78085732ac8SCy Schubert used = diff.sec * 1000 + diff.usec / 1000;
78185732ac8SCy Schubert if (used > wait_time)
78285732ac8SCy Schubert wait_time = 0;
78385732ac8SCy Schubert else
78485732ac8SCy Schubert wait_time -= used;
78585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
78685732ac8SCy Schubert wait_time);
78785732ac8SCy Schubert eloop_register_timeout(wait_time / 1000,
78885732ac8SCy Schubert (wait_time % 1000) * 1000,
78985732ac8SCy Schubert wpas_dpp_init_timeout, wpa_s,
79085732ac8SCy Schubert NULL);
79185732ac8SCy Schubert return 0;
79285732ac8SCy Schubert }
79385732ac8SCy Schubert freq = auth->freq[auth->freq_idx++];
79485732ac8SCy Schubert auth->curr_freq = freq;
79585732ac8SCy Schubert
796c1d255d3SCy Schubert if (!is_zero_ether_addr(auth->peer_mac_addr))
797c1d255d3SCy Schubert dst = auth->peer_mac_addr;
798c1d255d3SCy Schubert else if (is_zero_ether_addr(auth->peer_bi->mac_addr))
79985732ac8SCy Schubert dst = broadcast;
80085732ac8SCy Schubert else
80185732ac8SCy Schubert dst = auth->peer_bi->mac_addr;
80285732ac8SCy Schubert wpa_s->dpp_auth_ok_on_ack = 0;
80385732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
80485732ac8SCy Schubert wait_time = wpa_s->max_remain_on_chan;
80585732ac8SCy Schubert max_wait_time = wpa_s->dpp_resp_wait_time ?
80685732ac8SCy Schubert wpa_s->dpp_resp_wait_time : 2000;
80785732ac8SCy Schubert if (wait_time > max_wait_time)
80885732ac8SCy Schubert wait_time = max_wait_time;
80985732ac8SCy Schubert wait_time += 10; /* give the driver some extra time to complete */
81085732ac8SCy Schubert eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
81185732ac8SCy Schubert wpas_dpp_reply_wait_timeout,
81285732ac8SCy Schubert wpa_s, NULL);
81385732ac8SCy Schubert wait_time -= 10;
81485732ac8SCy Schubert if (auth->neg_freq > 0 && freq != auth->neg_freq) {
81585732ac8SCy Schubert wpa_printf(MSG_DEBUG,
81685732ac8SCy Schubert "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
81785732ac8SCy Schubert freq, auth->neg_freq);
81885732ac8SCy Schubert }
81985732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
82085732ac8SCy Schubert MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
82185732ac8SCy Schubert auth->auth_req_ack = 0;
82285732ac8SCy Schubert os_get_reltime(&wpa_s->dpp_last_init);
82385732ac8SCy Schubert return offchannel_send_action(wpa_s, freq, dst,
82485732ac8SCy Schubert wpa_s->own_addr, broadcast,
82585732ac8SCy Schubert wpabuf_head(auth->req_msg),
82685732ac8SCy Schubert wpabuf_len(auth->req_msg),
82785732ac8SCy Schubert wait_time, wpas_dpp_tx_status, 0);
82885732ac8SCy Schubert }
82985732ac8SCy Schubert
83085732ac8SCy Schubert
wpas_dpp_auth_init(struct wpa_supplicant * wpa_s,const char * cmd)83185732ac8SCy Schubert int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
83285732ac8SCy Schubert {
83385732ac8SCy Schubert const char *pos;
83485732ac8SCy Schubert struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
835206b73d0SCy Schubert struct dpp_authentication *auth;
83685732ac8SCy Schubert u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
83785732ac8SCy Schubert unsigned int neg_freq = 0;
838206b73d0SCy Schubert int tcp = 0;
839206b73d0SCy Schubert #ifdef CONFIG_DPP2
840206b73d0SCy Schubert int tcp_port = DPP_TCP_PORT;
841206b73d0SCy Schubert struct hostapd_ip_addr ipaddr;
842206b73d0SCy Schubert char *addr;
843206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
84485732ac8SCy Schubert
84585732ac8SCy Schubert wpa_s->dpp_gas_client = 0;
846*a90b9d01SCy Schubert wpa_s->dpp_gas_server = 0;
84785732ac8SCy Schubert
84885732ac8SCy Schubert pos = os_strstr(cmd, " peer=");
84985732ac8SCy Schubert if (!pos)
85085732ac8SCy Schubert return -1;
85185732ac8SCy Schubert pos += 6;
8524bc52338SCy Schubert peer_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
85385732ac8SCy Schubert if (!peer_bi) {
85485732ac8SCy Schubert wpa_printf(MSG_INFO,
85585732ac8SCy Schubert "DPP: Could not find bootstrapping info for the identified peer");
85685732ac8SCy Schubert return -1;
85785732ac8SCy Schubert }
85885732ac8SCy Schubert
859206b73d0SCy Schubert #ifdef CONFIG_DPP2
860206b73d0SCy Schubert pos = os_strstr(cmd, " tcp_port=");
861206b73d0SCy Schubert if (pos) {
862206b73d0SCy Schubert pos += 10;
863206b73d0SCy Schubert tcp_port = atoi(pos);
864206b73d0SCy Schubert }
865206b73d0SCy Schubert
866206b73d0SCy Schubert addr = get_param(cmd, " tcp_addr=");
867*a90b9d01SCy Schubert if (addr && os_strcmp(addr, "from-uri") == 0) {
868*a90b9d01SCy Schubert os_free(addr);
869*a90b9d01SCy Schubert if (!peer_bi->host) {
870*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
871*a90b9d01SCy Schubert "DPP: TCP address not available in peer URI");
872*a90b9d01SCy Schubert return -1;
873*a90b9d01SCy Schubert }
874*a90b9d01SCy Schubert tcp = 1;
875*a90b9d01SCy Schubert os_memcpy(&ipaddr, peer_bi->host, sizeof(ipaddr));
876*a90b9d01SCy Schubert tcp_port = peer_bi->port;
877*a90b9d01SCy Schubert } else if (addr) {
878206b73d0SCy Schubert int res;
879206b73d0SCy Schubert
880206b73d0SCy Schubert res = hostapd_parse_ip_addr(addr, &ipaddr);
881206b73d0SCy Schubert os_free(addr);
882206b73d0SCy Schubert if (res)
883206b73d0SCy Schubert return -1;
884206b73d0SCy Schubert tcp = 1;
885206b73d0SCy Schubert }
886206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
887206b73d0SCy Schubert
88885732ac8SCy Schubert pos = os_strstr(cmd, " own=");
88985732ac8SCy Schubert if (pos) {
89085732ac8SCy Schubert pos += 5;
8914bc52338SCy Schubert own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
89285732ac8SCy Schubert if (!own_bi) {
89385732ac8SCy Schubert wpa_printf(MSG_INFO,
89485732ac8SCy Schubert "DPP: Could not find bootstrapping info for the identified local entry");
89585732ac8SCy Schubert return -1;
89685732ac8SCy Schubert }
89785732ac8SCy Schubert
89885732ac8SCy Schubert if (peer_bi->curve != own_bi->curve) {
89985732ac8SCy Schubert wpa_printf(MSG_INFO,
90085732ac8SCy Schubert "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
90185732ac8SCy Schubert peer_bi->curve->name, own_bi->curve->name);
90285732ac8SCy Schubert return -1;
90385732ac8SCy Schubert }
90485732ac8SCy Schubert }
90585732ac8SCy Schubert
90685732ac8SCy Schubert pos = os_strstr(cmd, " role=");
90785732ac8SCy Schubert if (pos) {
90885732ac8SCy Schubert pos += 6;
90985732ac8SCy Schubert if (os_strncmp(pos, "configurator", 12) == 0)
91085732ac8SCy Schubert allowed_roles = DPP_CAPAB_CONFIGURATOR;
91185732ac8SCy Schubert else if (os_strncmp(pos, "enrollee", 8) == 0)
91285732ac8SCy Schubert allowed_roles = DPP_CAPAB_ENROLLEE;
91385732ac8SCy Schubert else if (os_strncmp(pos, "either", 6) == 0)
91485732ac8SCy Schubert allowed_roles = DPP_CAPAB_CONFIGURATOR |
91585732ac8SCy Schubert DPP_CAPAB_ENROLLEE;
91685732ac8SCy Schubert else
91785732ac8SCy Schubert goto fail;
91885732ac8SCy Schubert }
91985732ac8SCy Schubert
92085732ac8SCy Schubert pos = os_strstr(cmd, " netrole=");
92185732ac8SCy Schubert if (pos) {
92285732ac8SCy Schubert pos += 9;
923c1d255d3SCy Schubert if (os_strncmp(pos, "ap", 2) == 0)
924c1d255d3SCy Schubert wpa_s->dpp_netrole = DPP_NETROLE_AP;
925c1d255d3SCy Schubert else if (os_strncmp(pos, "configurator", 12) == 0)
926c1d255d3SCy Schubert wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
927c1d255d3SCy Schubert else
928c1d255d3SCy Schubert wpa_s->dpp_netrole = DPP_NETROLE_STA;
929c1d255d3SCy Schubert } else {
930c1d255d3SCy Schubert wpa_s->dpp_netrole = DPP_NETROLE_STA;
93185732ac8SCy Schubert }
93285732ac8SCy Schubert
93385732ac8SCy Schubert pos = os_strstr(cmd, " neg_freq=");
93485732ac8SCy Schubert if (pos)
93585732ac8SCy Schubert neg_freq = atoi(pos + 10);
93685732ac8SCy Schubert
937206b73d0SCy Schubert if (!tcp && wpa_s->dpp_auth) {
93885732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
93985732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
940c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s,
941c1d255d3SCy Schubert NULL);
94285732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
94385732ac8SCy Schubert NULL);
944c1d255d3SCy Schubert #ifdef CONFIG_DPP2
945c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
946c1d255d3SCy Schubert wpa_s, NULL);
947c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
94885732ac8SCy Schubert offchannel_send_action_done(wpa_s);
94985732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
95085732ac8SCy Schubert wpa_s->dpp_auth = NULL;
951206b73d0SCy Schubert }
952206b73d0SCy Schubert
953c1d255d3SCy Schubert auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, own_bi, allowed_roles,
954c1d255d3SCy Schubert neg_freq, wpa_s->hw.modes, wpa_s->hw.num_modes);
955206b73d0SCy Schubert if (!auth)
956206b73d0SCy Schubert goto fail;
957206b73d0SCy Schubert wpas_dpp_set_testing_options(wpa_s, auth);
958c1d255d3SCy Schubert if (dpp_set_configurator(auth, cmd) < 0) {
959206b73d0SCy Schubert dpp_auth_deinit(auth);
96085732ac8SCy Schubert goto fail;
96185732ac8SCy Schubert }
96285732ac8SCy Schubert
963206b73d0SCy Schubert auth->neg_freq = neg_freq;
96485732ac8SCy Schubert
96585732ac8SCy Schubert if (!is_zero_ether_addr(peer_bi->mac_addr))
966206b73d0SCy Schubert os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
96785732ac8SCy Schubert
968206b73d0SCy Schubert #ifdef CONFIG_DPP2
969206b73d0SCy Schubert if (tcp)
970c1d255d3SCy Schubert return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port,
971c1d255d3SCy Schubert wpa_s->conf->dpp_name, DPP_NETROLE_STA,
972*a90b9d01SCy Schubert wpa_s->conf->dpp_mud_url,
973*a90b9d01SCy Schubert wpa_s->conf->dpp_extra_conf_req_name,
974*a90b9d01SCy Schubert wpa_s->conf->dpp_extra_conf_req_value,
975*a90b9d01SCy Schubert wpa_s, wpa_s, wpas_dpp_process_conf_obj,
976*a90b9d01SCy Schubert wpas_dpp_tcp_msg_sent);
977206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
978206b73d0SCy Schubert
979206b73d0SCy Schubert wpa_s->dpp_auth = auth;
98085732ac8SCy Schubert return wpas_dpp_auth_init_next(wpa_s);
98185732ac8SCy Schubert fail:
98285732ac8SCy Schubert return -1;
98385732ac8SCy Schubert }
98485732ac8SCy Schubert
98585732ac8SCy Schubert
98685732ac8SCy Schubert struct wpas_dpp_listen_work {
98785732ac8SCy Schubert unsigned int freq;
98885732ac8SCy Schubert unsigned int duration;
98985732ac8SCy Schubert struct wpabuf *probe_resp_ie;
99085732ac8SCy Schubert };
99185732ac8SCy Schubert
99285732ac8SCy Schubert
wpas_dpp_listen_work_free(struct wpas_dpp_listen_work * lwork)99385732ac8SCy Schubert static void wpas_dpp_listen_work_free(struct wpas_dpp_listen_work *lwork)
99485732ac8SCy Schubert {
99585732ac8SCy Schubert if (!lwork)
99685732ac8SCy Schubert return;
99785732ac8SCy Schubert os_free(lwork);
99885732ac8SCy Schubert }
99985732ac8SCy Schubert
100085732ac8SCy Schubert
wpas_dpp_listen_work_done(struct wpa_supplicant * wpa_s)100185732ac8SCy Schubert static void wpas_dpp_listen_work_done(struct wpa_supplicant *wpa_s)
100285732ac8SCy Schubert {
100385732ac8SCy Schubert struct wpas_dpp_listen_work *lwork;
100485732ac8SCy Schubert
100585732ac8SCy Schubert if (!wpa_s->dpp_listen_work)
100685732ac8SCy Schubert return;
100785732ac8SCy Schubert
100885732ac8SCy Schubert lwork = wpa_s->dpp_listen_work->ctx;
100985732ac8SCy Schubert wpas_dpp_listen_work_free(lwork);
101085732ac8SCy Schubert radio_work_done(wpa_s->dpp_listen_work);
101185732ac8SCy Schubert wpa_s->dpp_listen_work = NULL;
101285732ac8SCy Schubert }
101385732ac8SCy Schubert
101485732ac8SCy Schubert
dpp_start_listen_cb(struct wpa_radio_work * work,int deinit)101585732ac8SCy Schubert static void dpp_start_listen_cb(struct wpa_radio_work *work, int deinit)
101685732ac8SCy Schubert {
101785732ac8SCy Schubert struct wpa_supplicant *wpa_s = work->wpa_s;
101885732ac8SCy Schubert struct wpas_dpp_listen_work *lwork = work->ctx;
101985732ac8SCy Schubert
102085732ac8SCy Schubert if (deinit) {
102185732ac8SCy Schubert if (work->started) {
102285732ac8SCy Schubert wpa_s->dpp_listen_work = NULL;
102385732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s);
102485732ac8SCy Schubert }
102585732ac8SCy Schubert wpas_dpp_listen_work_free(lwork);
102685732ac8SCy Schubert return;
102785732ac8SCy Schubert }
102885732ac8SCy Schubert
102985732ac8SCy Schubert wpa_s->dpp_listen_work = work;
103085732ac8SCy Schubert
103185732ac8SCy Schubert wpa_s->dpp_pending_listen_freq = lwork->freq;
103285732ac8SCy Schubert
103385732ac8SCy Schubert if (wpa_drv_remain_on_channel(wpa_s, lwork->freq,
103485732ac8SCy Schubert wpa_s->max_remain_on_chan) < 0) {
103585732ac8SCy Schubert wpa_printf(MSG_DEBUG,
103685732ac8SCy Schubert "DPP: Failed to request the driver to remain on channel (%u MHz) for listen",
103785732ac8SCy Schubert lwork->freq);
10384bc52338SCy Schubert wpa_s->dpp_listen_freq = 0;
103985732ac8SCy Schubert wpas_dpp_listen_work_done(wpa_s);
104085732ac8SCy Schubert wpa_s->dpp_pending_listen_freq = 0;
104185732ac8SCy Schubert return;
104285732ac8SCy Schubert }
104385732ac8SCy Schubert wpa_s->off_channel_freq = 0;
104485732ac8SCy Schubert wpa_s->roc_waiting_drv_freq = lwork->freq;
1045c1d255d3SCy Schubert wpa_drv_dpp_listen(wpa_s, true);
1046*a90b9d01SCy Schubert wpa_s->dpp_tx_auth_resp_on_roc_stop = false;
1047*a90b9d01SCy Schubert wpa_s->dpp_tx_chan_change = false;
104885732ac8SCy Schubert }
104985732ac8SCy Schubert
105085732ac8SCy Schubert
wpas_dpp_listen_start(struct wpa_supplicant * wpa_s,unsigned int freq)105185732ac8SCy Schubert static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
105285732ac8SCy Schubert unsigned int freq)
105385732ac8SCy Schubert {
105485732ac8SCy Schubert struct wpas_dpp_listen_work *lwork;
105585732ac8SCy Schubert
105685732ac8SCy Schubert if (wpa_s->dpp_listen_work) {
105785732ac8SCy Schubert wpa_printf(MSG_DEBUG,
105885732ac8SCy Schubert "DPP: Reject start_listen since dpp_listen_work already exists");
105985732ac8SCy Schubert return -1;
106085732ac8SCy Schubert }
106185732ac8SCy Schubert
106285732ac8SCy Schubert if (wpa_s->dpp_listen_freq)
106385732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s);
106485732ac8SCy Schubert wpa_s->dpp_listen_freq = freq;
106585732ac8SCy Schubert
106685732ac8SCy Schubert lwork = os_zalloc(sizeof(*lwork));
106785732ac8SCy Schubert if (!lwork)
106885732ac8SCy Schubert return -1;
106985732ac8SCy Schubert lwork->freq = freq;
107085732ac8SCy Schubert
107185732ac8SCy Schubert if (radio_add_work(wpa_s, freq, "dpp-listen", 0, dpp_start_listen_cb,
107285732ac8SCy Schubert lwork) < 0) {
107385732ac8SCy Schubert wpas_dpp_listen_work_free(lwork);
107485732ac8SCy Schubert return -1;
107585732ac8SCy Schubert }
107685732ac8SCy Schubert
107785732ac8SCy Schubert return 0;
107885732ac8SCy Schubert }
107985732ac8SCy Schubert
108085732ac8SCy Schubert
wpas_dpp_listen(struct wpa_supplicant * wpa_s,const char * cmd)108185732ac8SCy Schubert int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd)
108285732ac8SCy Schubert {
108385732ac8SCy Schubert int freq;
108485732ac8SCy Schubert
108585732ac8SCy Schubert freq = atoi(cmd);
108685732ac8SCy Schubert if (freq <= 0)
108785732ac8SCy Schubert return -1;
108885732ac8SCy Schubert
108985732ac8SCy Schubert if (os_strstr(cmd, " role=configurator"))
109085732ac8SCy Schubert wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR;
109185732ac8SCy Schubert else if (os_strstr(cmd, " role=enrollee"))
109285732ac8SCy Schubert wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
109385732ac8SCy Schubert else
109485732ac8SCy Schubert wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
109585732ac8SCy Schubert DPP_CAPAB_ENROLLEE;
109685732ac8SCy Schubert wpa_s->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
1097c1d255d3SCy Schubert if (os_strstr(cmd, " netrole=ap"))
1098c1d255d3SCy Schubert wpa_s->dpp_netrole = DPP_NETROLE_AP;
1099c1d255d3SCy Schubert else if (os_strstr(cmd, " netrole=configurator"))
1100c1d255d3SCy Schubert wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
1101c1d255d3SCy Schubert else
1102c1d255d3SCy Schubert wpa_s->dpp_netrole = DPP_NETROLE_STA;
110385732ac8SCy Schubert if (wpa_s->dpp_listen_freq == (unsigned int) freq) {
110485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz",
110585732ac8SCy Schubert freq);
110685732ac8SCy Schubert return 0;
110785732ac8SCy Schubert }
110885732ac8SCy Schubert
110985732ac8SCy Schubert return wpas_dpp_listen_start(wpa_s, freq);
111085732ac8SCy Schubert }
111185732ac8SCy Schubert
111285732ac8SCy Schubert
wpas_dpp_listen_stop(struct wpa_supplicant * wpa_s)111385732ac8SCy Schubert void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s)
111485732ac8SCy Schubert {
111585732ac8SCy Schubert wpa_s->dpp_in_response_listen = 0;
111685732ac8SCy Schubert if (!wpa_s->dpp_listen_freq)
111785732ac8SCy Schubert return;
111885732ac8SCy Schubert
111985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Stop listen on %u MHz",
112085732ac8SCy Schubert wpa_s->dpp_listen_freq);
112185732ac8SCy Schubert wpa_drv_cancel_remain_on_channel(wpa_s);
1122c1d255d3SCy Schubert wpa_drv_dpp_listen(wpa_s, false);
112385732ac8SCy Schubert wpa_s->dpp_listen_freq = 0;
112485732ac8SCy Schubert wpas_dpp_listen_work_done(wpa_s);
112532a95656SCy Schubert radio_remove_works(wpa_s, "dpp-listen", 0);
112685732ac8SCy Schubert }
112785732ac8SCy Schubert
112885732ac8SCy Schubert
wpas_dpp_remain_on_channel_cb(struct wpa_supplicant * wpa_s,unsigned int freq,unsigned int duration)1129c1d255d3SCy Schubert void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
1130c1d255d3SCy Schubert unsigned int freq, unsigned int duration)
1131c1d255d3SCy Schubert {
1132c1d255d3SCy Schubert if (wpa_s->dpp_listen_freq != freq)
1133c1d255d3SCy Schubert return;
1134c1d255d3SCy Schubert
1135c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1136c1d255d3SCy Schubert "DPP: Remain-on-channel started for listen on %u MHz for %u ms",
1137c1d255d3SCy Schubert freq, duration);
1138c1d255d3SCy Schubert os_get_reltime(&wpa_s->dpp_listen_end);
1139c1d255d3SCy Schubert wpa_s->dpp_listen_end.usec += duration * 1000;
1140c1d255d3SCy Schubert while (wpa_s->dpp_listen_end.usec >= 1000000) {
1141c1d255d3SCy Schubert wpa_s->dpp_listen_end.sec++;
1142c1d255d3SCy Schubert wpa_s->dpp_listen_end.usec -= 1000000;
1143c1d255d3SCy Schubert }
1144c1d255d3SCy Schubert }
1145c1d255d3SCy Schubert
1146c1d255d3SCy Schubert
wpas_dpp_tx_auth_resp(struct wpa_supplicant * wpa_s)1147*a90b9d01SCy Schubert static void wpas_dpp_tx_auth_resp(struct wpa_supplicant *wpa_s)
1148*a90b9d01SCy Schubert {
1149*a90b9d01SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
1150*a90b9d01SCy Schubert
1151*a90b9d01SCy Schubert if (!auth)
1152*a90b9d01SCy Schubert return;
1153*a90b9d01SCy Schubert
1154*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
1155*a90b9d01SCy Schubert MAC2STR(auth->peer_mac_addr), auth->curr_freq,
1156*a90b9d01SCy Schubert DPP_PA_AUTHENTICATION_RESP);
1157*a90b9d01SCy Schubert offchannel_send_action(wpa_s, auth->curr_freq,
1158*a90b9d01SCy Schubert auth->peer_mac_addr, wpa_s->own_addr, broadcast,
1159*a90b9d01SCy Schubert wpabuf_head(auth->resp_msg),
1160*a90b9d01SCy Schubert wpabuf_len(auth->resp_msg),
1161*a90b9d01SCy Schubert 500, wpas_dpp_tx_status, 0);
1162*a90b9d01SCy Schubert }
1163*a90b9d01SCy Schubert
1164*a90b9d01SCy Schubert
wpas_dpp_tx_auth_resp_roc_timeout(void * eloop_ctx,void * timeout_ctx)1165*a90b9d01SCy Schubert static void wpas_dpp_tx_auth_resp_roc_timeout(void *eloop_ctx,
1166*a90b9d01SCy Schubert void *timeout_ctx)
1167*a90b9d01SCy Schubert {
1168*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
1169*a90b9d01SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
1170*a90b9d01SCy Schubert
1171*a90b9d01SCy Schubert if (!auth || !wpa_s->dpp_tx_auth_resp_on_roc_stop)
1172*a90b9d01SCy Schubert return;
1173*a90b9d01SCy Schubert
1174*a90b9d01SCy Schubert wpa_s->dpp_tx_auth_resp_on_roc_stop = false;
1175*a90b9d01SCy Schubert wpa_s->dpp_tx_chan_change = true;
1176*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1177*a90b9d01SCy Schubert "DPP: Send postponed Authentication Response on remain-on-channel termination timeout");
1178*a90b9d01SCy Schubert wpas_dpp_tx_auth_resp(wpa_s);
1179*a90b9d01SCy Schubert }
1180*a90b9d01SCy Schubert
1181*a90b9d01SCy Schubert
wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant * wpa_s,unsigned int freq)118285732ac8SCy Schubert void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
118385732ac8SCy Schubert unsigned int freq)
118485732ac8SCy Schubert {
1185*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Remain on channel cancel for %u MHz", freq);
118685732ac8SCy Schubert wpas_dpp_listen_work_done(wpa_s);
118785732ac8SCy Schubert
1188*a90b9d01SCy Schubert if (wpa_s->dpp_auth && wpa_s->dpp_tx_auth_resp_on_roc_stop) {
1189*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_tx_auth_resp_roc_timeout,
1190*a90b9d01SCy Schubert wpa_s, NULL);
1191*a90b9d01SCy Schubert wpa_s->dpp_tx_auth_resp_on_roc_stop = false;
1192*a90b9d01SCy Schubert wpa_s->dpp_tx_chan_change = true;
1193*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1194*a90b9d01SCy Schubert "DPP: Send postponed Authentication Response on remain-on-channel termination");
1195*a90b9d01SCy Schubert wpas_dpp_tx_auth_resp(wpa_s);
1196*a90b9d01SCy Schubert return;
1197*a90b9d01SCy Schubert }
1198*a90b9d01SCy Schubert
119985732ac8SCy Schubert if (wpa_s->dpp_auth && wpa_s->dpp_in_response_listen) {
120085732ac8SCy Schubert unsigned int new_freq;
120185732ac8SCy Schubert
120285732ac8SCy Schubert /* Continue listen with a new remain-on-channel */
120385732ac8SCy Schubert if (wpa_s->dpp_auth->neg_freq > 0)
120485732ac8SCy Schubert new_freq = wpa_s->dpp_auth->neg_freq;
120585732ac8SCy Schubert else
120685732ac8SCy Schubert new_freq = wpa_s->dpp_auth->curr_freq;
120785732ac8SCy Schubert wpa_printf(MSG_DEBUG,
120885732ac8SCy Schubert "DPP: Continue wait on %u MHz for the ongoing DPP provisioning session",
120985732ac8SCy Schubert new_freq);
121085732ac8SCy Schubert wpas_dpp_listen_start(wpa_s, new_freq);
121185732ac8SCy Schubert return;
121285732ac8SCy Schubert }
121385732ac8SCy Schubert
121485732ac8SCy Schubert if (wpa_s->dpp_listen_freq) {
121585732ac8SCy Schubert /* Continue listen with a new remain-on-channel */
121685732ac8SCy Schubert wpas_dpp_listen_start(wpa_s, wpa_s->dpp_listen_freq);
121785732ac8SCy Schubert }
121885732ac8SCy Schubert }
121985732ac8SCy Schubert
122085732ac8SCy Schubert
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)122185732ac8SCy Schubert static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
122285732ac8SCy Schubert const u8 *hdr, const u8 *buf, size_t len,
122385732ac8SCy Schubert unsigned int freq)
122485732ac8SCy Schubert {
122585732ac8SCy Schubert const u8 *r_bootstrap, *i_bootstrap;
122685732ac8SCy Schubert u16 r_bootstrap_len, i_bootstrap_len;
12274bc52338SCy Schubert struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
12284bc52338SCy Schubert
12294bc52338SCy Schubert if (!wpa_s->dpp)
12304bc52338SCy Schubert return;
123185732ac8SCy Schubert
123285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
123385732ac8SCy Schubert MAC2STR(src));
123485732ac8SCy Schubert
1235c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1236c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
1237c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1238c1d255d3SCy Schubert
123985732ac8SCy Schubert r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
124085732ac8SCy Schubert &r_bootstrap_len);
124185732ac8SCy Schubert if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
124285732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
124385732ac8SCy Schubert "Missing or invalid required Responder Bootstrapping Key Hash attribute");
124485732ac8SCy Schubert return;
124585732ac8SCy Schubert }
124685732ac8SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
124785732ac8SCy Schubert r_bootstrap, r_bootstrap_len);
124885732ac8SCy Schubert
124985732ac8SCy Schubert i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
125085732ac8SCy Schubert &i_bootstrap_len);
125185732ac8SCy Schubert if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
125285732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
125385732ac8SCy Schubert "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
125485732ac8SCy Schubert return;
125585732ac8SCy Schubert }
125685732ac8SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
125785732ac8SCy Schubert i_bootstrap, i_bootstrap_len);
125885732ac8SCy Schubert
125985732ac8SCy Schubert /* Try to find own and peer bootstrapping key matches based on the
126085732ac8SCy Schubert * received hash values */
12614bc52338SCy Schubert dpp_bootstrap_find_pair(wpa_s->dpp, i_bootstrap, r_bootstrap,
12624bc52338SCy Schubert &own_bi, &peer_bi);
126385732ac8SCy Schubert if (!own_bi) {
126485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
126585732ac8SCy Schubert "No matching own bootstrapping key found - ignore message");
126685732ac8SCy Schubert return;
126785732ac8SCy Schubert }
126885732ac8SCy Schubert
1269*a90b9d01SCy Schubert if (own_bi->type == DPP_BOOTSTRAP_PKEX) {
1270*a90b9d01SCy Schubert if (!peer_bi || peer_bi->type != DPP_BOOTSTRAP_PKEX) {
1271*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
1272*a90b9d01SCy Schubert "No matching peer bootstrapping key found for PKEX - ignore message");
1273*a90b9d01SCy Schubert return;
1274*a90b9d01SCy Schubert }
1275*a90b9d01SCy Schubert
1276*a90b9d01SCy Schubert if (os_memcmp(peer_bi->pubkey_hash, own_bi->peer_pubkey_hash,
1277*a90b9d01SCy Schubert SHA256_MAC_LEN) != 0) {
1278*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
1279*a90b9d01SCy Schubert "Mismatching peer PKEX bootstrapping key - ignore message");
1280*a90b9d01SCy Schubert return;
1281*a90b9d01SCy Schubert }
1282*a90b9d01SCy Schubert }
1283*a90b9d01SCy Schubert
128485732ac8SCy Schubert if (wpa_s->dpp_auth) {
128585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
128685732ac8SCy Schubert "Already in DPP authentication exchange - ignore new one");
128785732ac8SCy Schubert return;
128885732ac8SCy Schubert }
128985732ac8SCy Schubert
1290*a90b9d01SCy Schubert wpa_s->dpp_pkex_wait_auth_req = false;
129185732ac8SCy Schubert wpa_s->dpp_gas_client = 0;
1292*a90b9d01SCy Schubert wpa_s->dpp_gas_server = 0;
129385732ac8SCy Schubert wpa_s->dpp_auth_ok_on_ack = 0;
1294c1d255d3SCy Schubert wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s->dpp, wpa_s,
1295c1d255d3SCy Schubert wpa_s->dpp_allowed_roles,
129685732ac8SCy Schubert wpa_s->dpp_qr_mutual,
129785732ac8SCy Schubert peer_bi, own_bi, freq, hdr, buf, len);
129885732ac8SCy Schubert if (!wpa_s->dpp_auth) {
129985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No response generated");
130085732ac8SCy Schubert return;
130185732ac8SCy Schubert }
130285732ac8SCy Schubert wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
1303c1d255d3SCy Schubert if (dpp_set_configurator(wpa_s->dpp_auth,
130485732ac8SCy Schubert wpa_s->dpp_configurator_params) < 0) {
130585732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
130685732ac8SCy Schubert wpa_s->dpp_auth = NULL;
130785732ac8SCy Schubert return;
130885732ac8SCy Schubert }
130985732ac8SCy Schubert os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN);
131085732ac8SCy Schubert
131185732ac8SCy Schubert if (wpa_s->dpp_listen_freq &&
131285732ac8SCy Schubert wpa_s->dpp_listen_freq != wpa_s->dpp_auth->curr_freq) {
131385732ac8SCy Schubert wpa_printf(MSG_DEBUG,
131485732ac8SCy Schubert "DPP: Stop listen on %u MHz to allow response on the request %u MHz",
131585732ac8SCy Schubert wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq);
1316*a90b9d01SCy Schubert wpa_s->dpp_tx_auth_resp_on_roc_stop = true;
1317*a90b9d01SCy Schubert eloop_register_timeout(0, 100000,
1318*a90b9d01SCy Schubert wpas_dpp_tx_auth_resp_roc_timeout,
1319*a90b9d01SCy Schubert wpa_s, NULL);
132085732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s);
1321*a90b9d01SCy Schubert return;
1322*a90b9d01SCy Schubert }
1323*a90b9d01SCy Schubert wpa_s->dpp_tx_auth_resp_on_roc_stop = false;
1324*a90b9d01SCy Schubert wpa_s->dpp_tx_chan_change = false;
1325*a90b9d01SCy Schubert
1326*a90b9d01SCy Schubert wpas_dpp_tx_auth_resp(wpa_s);
132785732ac8SCy Schubert }
132885732ac8SCy Schubert
1329*a90b9d01SCy Schubert
wpas_dpp_tx_wait_expire(struct wpa_supplicant * wpa_s)1330*a90b9d01SCy Schubert void wpas_dpp_tx_wait_expire(struct wpa_supplicant *wpa_s)
1331*a90b9d01SCy Schubert {
1332*a90b9d01SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
1333*a90b9d01SCy Schubert int freq;
1334*a90b9d01SCy Schubert
1335*a90b9d01SCy Schubert if (wpa_s->dpp_listen_on_tx_expire && auth && auth->neg_freq) {
1336*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1337*a90b9d01SCy Schubert "DPP: Start listen on neg_freq %u MHz based on TX wait expiration on the previous channel",
1338*a90b9d01SCy Schubert auth->neg_freq);
1339*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_neg_freq_timeout, wpa_s, NULL);
1340*a90b9d01SCy Schubert wpas_dpp_listen_start(wpa_s, auth->neg_freq);
1341*a90b9d01SCy Schubert return;
1342*a90b9d01SCy Schubert }
1343*a90b9d01SCy Schubert
1344*a90b9d01SCy Schubert if (!wpa_s->dpp_gas_server || !auth) {
1345*a90b9d01SCy Schubert if (auth && auth->waiting_auth_resp &&
1346*a90b9d01SCy Schubert eloop_is_timeout_registered(wpas_dpp_drv_wait_timeout,
1347*a90b9d01SCy Schubert wpa_s, NULL)) {
1348*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_drv_wait_timeout,
1349*a90b9d01SCy Schubert wpa_s, NULL);
1350*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1351*a90b9d01SCy Schubert "DPP: Call wpas_dpp_auth_init_next() from %s",
1352*a90b9d01SCy Schubert __func__);
1353*a90b9d01SCy Schubert wpas_dpp_auth_init_next(wpa_s);
1354*a90b9d01SCy Schubert }
1355*a90b9d01SCy Schubert return;
1356*a90b9d01SCy Schubert }
1357*a90b9d01SCy Schubert
1358*a90b9d01SCy Schubert freq = auth->neg_freq > 0 ? auth->neg_freq : auth->curr_freq;
1359*a90b9d01SCy Schubert if (wpa_s->dpp_listen_work || (int) wpa_s->dpp_listen_freq == freq)
1360*a90b9d01SCy Schubert return; /* listen state is already in progress */
1361*a90b9d01SCy Schubert
1362*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Start listen on %u MHz for GAS", freq);
1363*a90b9d01SCy Schubert wpa_s->dpp_in_response_listen = 1;
1364*a90b9d01SCy Schubert wpas_dpp_listen_start(wpa_s, freq);
136585732ac8SCy Schubert }
136685732ac8SCy Schubert
136785732ac8SCy Schubert
wpas_dpp_start_gas_server(struct wpa_supplicant * wpa_s)136885732ac8SCy Schubert static void wpas_dpp_start_gas_server(struct wpa_supplicant *wpa_s)
136985732ac8SCy Schubert {
1370*a90b9d01SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
1371*a90b9d01SCy Schubert
1372*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1373*a90b9d01SCy Schubert "DPP: Starting GAS server (curr_freq=%d neg_freq=%d dpp_listen_freq=%d dpp_listen_work=%d)",
1374*a90b9d01SCy Schubert auth->curr_freq, auth->neg_freq, wpa_s->dpp_listen_freq,
1375*a90b9d01SCy Schubert !!wpa_s->dpp_listen_work);
1376*a90b9d01SCy Schubert wpa_s->dpp_gas_server = 1;
137785732ac8SCy Schubert }
137885732ac8SCy Schubert
137985732ac8SCy Schubert
wpas_dpp_add_network(struct wpa_supplicant * wpa_s,struct dpp_authentication * auth,struct dpp_config_obj * conf)138085732ac8SCy Schubert static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
1381c1d255d3SCy Schubert struct dpp_authentication *auth,
1382c1d255d3SCy Schubert struct dpp_config_obj *conf)
138385732ac8SCy Schubert {
138485732ac8SCy Schubert struct wpa_ssid *ssid;
138585732ac8SCy Schubert
13864bc52338SCy Schubert #ifdef CONFIG_DPP2
1387c1d255d3SCy Schubert if (conf->akm == DPP_AKM_SAE) {
13884bc52338SCy Schubert #ifdef CONFIG_SAE
13894bc52338SCy Schubert struct wpa_driver_capa capa;
13904bc52338SCy Schubert int res;
13914bc52338SCy Schubert
13924bc52338SCy Schubert res = wpa_drv_get_capa(wpa_s, &capa);
13934bc52338SCy Schubert if (res == 0 &&
1394c1d255d3SCy Schubert !(capa.key_mgmt_iftype[WPA_IF_STATION] &
1395c1d255d3SCy Schubert WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
13964bc52338SCy Schubert !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
13974bc52338SCy Schubert wpa_printf(MSG_DEBUG,
13984bc52338SCy Schubert "DPP: SAE not supported by the driver");
13994bc52338SCy Schubert return NULL;
14004bc52338SCy Schubert }
14014bc52338SCy Schubert #else /* CONFIG_SAE */
14024bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: SAE not supported in the build");
14034bc52338SCy Schubert return NULL;
14044bc52338SCy Schubert #endif /* CONFIG_SAE */
14054bc52338SCy Schubert }
14064bc52338SCy Schubert #endif /* CONFIG_DPP2 */
14074bc52338SCy Schubert
140885732ac8SCy Schubert ssid = wpa_config_add_network(wpa_s->conf);
140985732ac8SCy Schubert if (!ssid)
141085732ac8SCy Schubert return NULL;
141185732ac8SCy Schubert wpas_notify_network_added(wpa_s, ssid);
141285732ac8SCy Schubert wpa_config_set_network_defaults(ssid);
141385732ac8SCy Schubert ssid->disabled = 1;
141485732ac8SCy Schubert
1415c1d255d3SCy Schubert ssid->ssid = os_malloc(conf->ssid_len);
141685732ac8SCy Schubert if (!ssid->ssid)
141785732ac8SCy Schubert goto fail;
1418c1d255d3SCy Schubert os_memcpy(ssid->ssid, conf->ssid, conf->ssid_len);
1419c1d255d3SCy Schubert ssid->ssid_len = conf->ssid_len;
142085732ac8SCy Schubert
1421c1d255d3SCy Schubert if (conf->connector) {
1422c1d255d3SCy Schubert if (dpp_akm_dpp(conf->akm)) {
142385732ac8SCy Schubert ssid->key_mgmt = WPA_KEY_MGMT_DPP;
142485732ac8SCy Schubert ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
1425c1d255d3SCy Schubert }
1426c1d255d3SCy Schubert ssid->dpp_connector = os_strdup(conf->connector);
142785732ac8SCy Schubert if (!ssid->dpp_connector)
142885732ac8SCy Schubert goto fail;
1429*a90b9d01SCy Schubert
1430*a90b9d01SCy Schubert ssid->dpp_connector_privacy =
1431*a90b9d01SCy Schubert wpa_s->conf->dpp_connector_privacy_default;
143285732ac8SCy Schubert }
143385732ac8SCy Schubert
1434c1d255d3SCy Schubert if (conf->c_sign_key) {
1435c1d255d3SCy Schubert ssid->dpp_csign = os_malloc(wpabuf_len(conf->c_sign_key));
143685732ac8SCy Schubert if (!ssid->dpp_csign)
143785732ac8SCy Schubert goto fail;
1438c1d255d3SCy Schubert os_memcpy(ssid->dpp_csign, wpabuf_head(conf->c_sign_key),
1439c1d255d3SCy Schubert wpabuf_len(conf->c_sign_key));
1440c1d255d3SCy Schubert ssid->dpp_csign_len = wpabuf_len(conf->c_sign_key);
1441c1d255d3SCy Schubert }
1442c1d255d3SCy Schubert
1443c1d255d3SCy Schubert if (conf->pp_key) {
1444c1d255d3SCy Schubert ssid->dpp_pp_key = os_malloc(wpabuf_len(conf->pp_key));
1445c1d255d3SCy Schubert if (!ssid->dpp_pp_key)
1446c1d255d3SCy Schubert goto fail;
1447c1d255d3SCy Schubert os_memcpy(ssid->dpp_pp_key, wpabuf_head(conf->pp_key),
1448c1d255d3SCy Schubert wpabuf_len(conf->pp_key));
1449c1d255d3SCy Schubert ssid->dpp_pp_key_len = wpabuf_len(conf->pp_key);
145085732ac8SCy Schubert }
145185732ac8SCy Schubert
145285732ac8SCy Schubert if (auth->net_access_key) {
145385732ac8SCy Schubert ssid->dpp_netaccesskey =
145485732ac8SCy Schubert os_malloc(wpabuf_len(auth->net_access_key));
145585732ac8SCy Schubert if (!ssid->dpp_netaccesskey)
145685732ac8SCy Schubert goto fail;
145785732ac8SCy Schubert os_memcpy(ssid->dpp_netaccesskey,
145885732ac8SCy Schubert wpabuf_head(auth->net_access_key),
145985732ac8SCy Schubert wpabuf_len(auth->net_access_key));
146085732ac8SCy Schubert ssid->dpp_netaccesskey_len = wpabuf_len(auth->net_access_key);
146185732ac8SCy Schubert ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
146285732ac8SCy Schubert }
146385732ac8SCy Schubert
1464c1d255d3SCy Schubert if (!conf->connector || dpp_akm_psk(conf->akm) ||
1465c1d255d3SCy Schubert dpp_akm_sae(conf->akm)) {
1466c1d255d3SCy Schubert if (!conf->connector || !dpp_akm_dpp(conf->akm))
146785732ac8SCy Schubert ssid->key_mgmt = 0;
1468c1d255d3SCy Schubert if (dpp_akm_psk(conf->akm))
146985732ac8SCy Schubert ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
147085732ac8SCy Schubert WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
1471c1d255d3SCy Schubert if (dpp_akm_sae(conf->akm))
147285732ac8SCy Schubert ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
147385732ac8SCy Schubert WPA_KEY_MGMT_FT_SAE;
1474*a90b9d01SCy Schubert if (dpp_akm_psk(conf->akm))
147585732ac8SCy Schubert ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
1476*a90b9d01SCy Schubert else
1477*a90b9d01SCy Schubert ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
1478c1d255d3SCy Schubert if (conf->passphrase[0]) {
147985732ac8SCy Schubert if (wpa_config_set_quoted(ssid, "psk",
1480c1d255d3SCy Schubert conf->passphrase) < 0)
148185732ac8SCy Schubert goto fail;
148285732ac8SCy Schubert wpa_config_update_psk(ssid);
148385732ac8SCy Schubert ssid->export_keys = 1;
148485732ac8SCy Schubert } else {
1485c1d255d3SCy Schubert ssid->psk_set = conf->psk_set;
1486c1d255d3SCy Schubert os_memcpy(ssid->psk, conf->psk, PMK_LEN);
148785732ac8SCy Schubert }
148885732ac8SCy Schubert }
148985732ac8SCy Schubert
1490c1d255d3SCy Schubert #if defined(CONFIG_DPP2) && defined(IEEE8021X_EAPOL)
1491c1d255d3SCy Schubert if (conf->akm == DPP_AKM_DOT1X) {
1492c1d255d3SCy Schubert int i;
1493c1d255d3SCy Schubert char name[100], blobname[128];
1494c1d255d3SCy Schubert struct wpa_config_blob *blob;
1495c1d255d3SCy Schubert
1496c1d255d3SCy Schubert ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X |
1497c1d255d3SCy Schubert WPA_KEY_MGMT_IEEE8021X_SHA256 |
1498*a90b9d01SCy Schubert WPA_KEY_MGMT_IEEE8021X_SHA384;
1499c1d255d3SCy Schubert ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
1500c1d255d3SCy Schubert
1501c1d255d3SCy Schubert if (conf->cacert) {
1502c1d255d3SCy Schubert /* caCert is DER-encoded X.509v3 certificate for the
1503c1d255d3SCy Schubert * server certificate if that is different from the
1504c1d255d3SCy Schubert * trust root included in certBag. */
1505c1d255d3SCy Schubert /* TODO: ssid->eap.cert.ca_cert */
1506c1d255d3SCy Schubert }
1507c1d255d3SCy Schubert
1508c1d255d3SCy Schubert if (conf->certs) {
1509c1d255d3SCy Schubert for (i = 0; ; i++) {
1510c1d255d3SCy Schubert os_snprintf(name, sizeof(name), "dpp-certs-%d",
1511c1d255d3SCy Schubert i);
1512c1d255d3SCy Schubert if (!wpa_config_get_blob(wpa_s->conf, name))
1513c1d255d3SCy Schubert break;
1514c1d255d3SCy Schubert }
1515c1d255d3SCy Schubert
1516c1d255d3SCy Schubert blob = os_zalloc(sizeof(*blob));
1517c1d255d3SCy Schubert if (!blob)
1518c1d255d3SCy Schubert goto fail;
1519c1d255d3SCy Schubert blob->len = wpabuf_len(conf->certs);
1520c1d255d3SCy Schubert blob->name = os_strdup(name);
1521c1d255d3SCy Schubert blob->data = os_malloc(blob->len);
1522c1d255d3SCy Schubert if (!blob->name || !blob->data) {
1523c1d255d3SCy Schubert wpa_config_free_blob(blob);
1524c1d255d3SCy Schubert goto fail;
1525c1d255d3SCy Schubert }
1526c1d255d3SCy Schubert os_memcpy(blob->data, wpabuf_head(conf->certs),
1527c1d255d3SCy Schubert blob->len);
1528c1d255d3SCy Schubert os_snprintf(blobname, sizeof(blobname), "blob://%s",
1529c1d255d3SCy Schubert name);
1530c1d255d3SCy Schubert wpa_config_set_blob(wpa_s->conf, blob);
1531c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Added certificate blob %s",
1532c1d255d3SCy Schubert name);
1533c1d255d3SCy Schubert ssid->eap.cert.client_cert = os_strdup(blobname);
1534c1d255d3SCy Schubert if (!ssid->eap.cert.client_cert)
1535c1d255d3SCy Schubert goto fail;
1536c1d255d3SCy Schubert
1537c1d255d3SCy Schubert /* TODO: ssid->eap.identity from own certificate */
1538c1d255d3SCy Schubert if (wpa_config_set(ssid, "identity", "\"dpp-ent\"",
1539c1d255d3SCy Schubert 0) < 0)
1540c1d255d3SCy Schubert goto fail;
1541c1d255d3SCy Schubert }
1542c1d255d3SCy Schubert
1543c1d255d3SCy Schubert if (auth->priv_key) {
1544c1d255d3SCy Schubert for (i = 0; ; i++) {
1545c1d255d3SCy Schubert os_snprintf(name, sizeof(name), "dpp-key-%d",
1546c1d255d3SCy Schubert i);
1547c1d255d3SCy Schubert if (!wpa_config_get_blob(wpa_s->conf, name))
1548c1d255d3SCy Schubert break;
1549c1d255d3SCy Schubert }
1550c1d255d3SCy Schubert
1551c1d255d3SCy Schubert blob = os_zalloc(sizeof(*blob));
1552c1d255d3SCy Schubert if (!blob)
1553c1d255d3SCy Schubert goto fail;
1554c1d255d3SCy Schubert blob->len = wpabuf_len(auth->priv_key);
1555c1d255d3SCy Schubert blob->name = os_strdup(name);
1556c1d255d3SCy Schubert blob->data = os_malloc(blob->len);
1557c1d255d3SCy Schubert if (!blob->name || !blob->data) {
1558c1d255d3SCy Schubert wpa_config_free_blob(blob);
1559c1d255d3SCy Schubert goto fail;
1560c1d255d3SCy Schubert }
1561c1d255d3SCy Schubert os_memcpy(blob->data, wpabuf_head(auth->priv_key),
1562c1d255d3SCy Schubert blob->len);
1563c1d255d3SCy Schubert os_snprintf(blobname, sizeof(blobname), "blob://%s",
1564c1d255d3SCy Schubert name);
1565c1d255d3SCy Schubert wpa_config_set_blob(wpa_s->conf, blob);
1566c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Added private key blob %s",
1567c1d255d3SCy Schubert name);
1568c1d255d3SCy Schubert ssid->eap.cert.private_key = os_strdup(blobname);
1569c1d255d3SCy Schubert if (!ssid->eap.cert.private_key)
1570c1d255d3SCy Schubert goto fail;
1571c1d255d3SCy Schubert }
1572c1d255d3SCy Schubert
1573c1d255d3SCy Schubert if (conf->server_name) {
1574c1d255d3SCy Schubert ssid->eap.cert.domain_suffix_match =
1575c1d255d3SCy Schubert os_strdup(conf->server_name);
1576c1d255d3SCy Schubert if (!ssid->eap.cert.domain_suffix_match)
1577c1d255d3SCy Schubert goto fail;
1578c1d255d3SCy Schubert }
1579c1d255d3SCy Schubert
1580c1d255d3SCy Schubert /* TODO: Use entCreds::eapMethods */
1581c1d255d3SCy Schubert if (wpa_config_set(ssid, "eap", "TLS", 0) < 0)
1582c1d255d3SCy Schubert goto fail;
1583c1d255d3SCy Schubert }
1584c1d255d3SCy Schubert #endif /* CONFIG_DPP2 && IEEE8021X_EAPOL */
1585c1d255d3SCy Schubert
1586c1d255d3SCy Schubert os_memcpy(wpa_s->dpp_last_ssid, conf->ssid, conf->ssid_len);
1587c1d255d3SCy Schubert wpa_s->dpp_last_ssid_len = conf->ssid_len;
1588c1d255d3SCy Schubert
158985732ac8SCy Schubert return ssid;
159085732ac8SCy Schubert fail:
159185732ac8SCy Schubert wpas_notify_network_removed(wpa_s, ssid);
159285732ac8SCy Schubert wpa_config_remove_network(wpa_s->conf, ssid->id);
159385732ac8SCy Schubert return NULL;
159485732ac8SCy Schubert }
159585732ac8SCy Schubert
159685732ac8SCy Schubert
wpas_dpp_process_config(struct wpa_supplicant * wpa_s,struct dpp_authentication * auth,struct dpp_config_obj * conf)15974bc52338SCy Schubert static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
1598c1d255d3SCy Schubert struct dpp_authentication *auth,
1599c1d255d3SCy Schubert struct dpp_config_obj *conf)
160085732ac8SCy Schubert {
160185732ac8SCy Schubert struct wpa_ssid *ssid;
160285732ac8SCy Schubert
160385732ac8SCy Schubert if (wpa_s->conf->dpp_config_processing < 1)
16044bc52338SCy Schubert return 0;
160585732ac8SCy Schubert
1606c1d255d3SCy Schubert ssid = wpas_dpp_add_network(wpa_s, auth, conf);
160785732ac8SCy Schubert if (!ssid)
16084bc52338SCy Schubert return -1;
160985732ac8SCy Schubert
161085732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id);
16114bc52338SCy Schubert if (wpa_s->conf->dpp_config_processing == 2)
161285732ac8SCy Schubert ssid->disabled = 0;
16134bc52338SCy Schubert
16144bc52338SCy Schubert #ifndef CONFIG_NO_CONFIG_WRITE
16154bc52338SCy Schubert if (wpa_s->conf->update_config &&
16164bc52338SCy Schubert wpa_config_write(wpa_s->confname, wpa_s->conf))
16174bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration");
16184bc52338SCy Schubert #endif /* CONFIG_NO_CONFIG_WRITE */
16194bc52338SCy Schubert
16204bc52338SCy Schubert return 0;
1621c1d255d3SCy Schubert }
1622c1d255d3SCy Schubert
1623c1d255d3SCy Schubert
wpas_dpp_post_process_config(struct wpa_supplicant * wpa_s,struct dpp_authentication * auth)1624c1d255d3SCy Schubert static void wpas_dpp_post_process_config(struct wpa_supplicant *wpa_s,
1625c1d255d3SCy Schubert struct dpp_authentication *auth)
1626c1d255d3SCy Schubert {
1627c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1628c1d255d3SCy Schubert if (auth->reconfig && wpa_s->dpp_reconfig_ssid &&
1629c1d255d3SCy Schubert wpa_config_get_network(wpa_s->conf, wpa_s->dpp_reconfig_ssid_id) ==
1630c1d255d3SCy Schubert wpa_s->dpp_reconfig_ssid) {
1631c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1632c1d255d3SCy Schubert "DPP: Remove reconfigured network profile");
1633c1d255d3SCy Schubert wpas_notify_network_removed(wpa_s, wpa_s->dpp_reconfig_ssid);
1634c1d255d3SCy Schubert wpa_config_remove_network(wpa_s->conf,
1635c1d255d3SCy Schubert wpa_s->dpp_reconfig_ssid_id);
1636c1d255d3SCy Schubert wpa_s->dpp_reconfig_ssid = NULL;
1637c1d255d3SCy Schubert wpa_s->dpp_reconfig_ssid_id = -1;
1638c1d255d3SCy Schubert }
1639c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1640c1d255d3SCy Schubert
1641c1d255d3SCy Schubert if (wpa_s->conf->dpp_config_processing < 2)
1642c1d255d3SCy Schubert return;
16434bc52338SCy Schubert
16444bc52338SCy Schubert #ifdef CONFIG_DPP2
16454bc52338SCy Schubert if (auth->peer_version >= 2) {
16464bc52338SCy Schubert wpa_printf(MSG_DEBUG,
16474bc52338SCy Schubert "DPP: Postpone connection attempt to wait for completion of DPP Configuration Result");
16484bc52338SCy Schubert auth->connect_on_tx_status = 1;
1649c1d255d3SCy Schubert return;
16504bc52338SCy Schubert }
16514bc52338SCy Schubert #endif /* CONFIG_DPP2 */
16524bc52338SCy Schubert
16534bc52338SCy Schubert wpas_dpp_try_to_connect(wpa_s);
165485732ac8SCy Schubert }
165585732ac8SCy Schubert
165685732ac8SCy Schubert
wpas_dpp_handle_config_obj(struct wpa_supplicant * wpa_s,struct dpp_authentication * auth,struct dpp_config_obj * conf)16574bc52338SCy Schubert static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
1658c1d255d3SCy Schubert struct dpp_authentication *auth,
1659c1d255d3SCy Schubert struct dpp_config_obj *conf)
166085732ac8SCy Schubert {
166185732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
1662c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
1663c1d255d3SCy Schubert dpp_akm_str(conf->akm));
1664c1d255d3SCy Schubert if (conf->ssid_len)
166585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
1666c1d255d3SCy Schubert wpa_ssid_txt(conf->ssid, conf->ssid_len));
1667c1d255d3SCy Schubert if (conf->ssid_charset)
1668c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID_CHARSET "%d",
1669c1d255d3SCy Schubert conf->ssid_charset);
1670c1d255d3SCy Schubert if (conf->connector) {
167185732ac8SCy Schubert /* TODO: Save the Connector and consider using a command
167285732ac8SCy Schubert * to fetch the value instead of sending an event with
167385732ac8SCy Schubert * it. The Connector could end up being larger than what
167485732ac8SCy Schubert * most clients are ready to receive as an event
167585732ac8SCy Schubert * message. */
167685732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
1677c1d255d3SCy Schubert conf->connector);
167885732ac8SCy Schubert }
1679c1d255d3SCy Schubert if (conf->passphrase[0]) {
1680c1d255d3SCy Schubert char hex[64 * 2 + 1];
1681c1d255d3SCy Schubert
1682c1d255d3SCy Schubert wpa_snprintf_hex(hex, sizeof(hex),
1683c1d255d3SCy Schubert (const u8 *) conf->passphrase,
1684c1d255d3SCy Schubert os_strlen(conf->passphrase));
1685c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s",
1686c1d255d3SCy Schubert hex);
1687c1d255d3SCy Schubert } else if (conf->psk_set) {
1688c1d255d3SCy Schubert char hex[PMK_LEN * 2 + 1];
1689c1d255d3SCy Schubert
1690c1d255d3SCy Schubert wpa_snprintf_hex(hex, sizeof(hex), conf->psk, PMK_LEN);
1691c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
1692c1d255d3SCy Schubert hex);
1693c1d255d3SCy Schubert }
1694c1d255d3SCy Schubert if (conf->c_sign_key) {
169585732ac8SCy Schubert char *hex;
169685732ac8SCy Schubert size_t hexlen;
169785732ac8SCy Schubert
1698c1d255d3SCy Schubert hexlen = 2 * wpabuf_len(conf->c_sign_key) + 1;
169985732ac8SCy Schubert hex = os_malloc(hexlen);
170085732ac8SCy Schubert if (hex) {
170185732ac8SCy Schubert wpa_snprintf_hex(hex, hexlen,
1702c1d255d3SCy Schubert wpabuf_head(conf->c_sign_key),
1703c1d255d3SCy Schubert wpabuf_len(conf->c_sign_key));
170485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s",
170585732ac8SCy Schubert hex);
170685732ac8SCy Schubert os_free(hex);
170785732ac8SCy Schubert }
170885732ac8SCy Schubert }
1709c1d255d3SCy Schubert if (conf->pp_key) {
1710c1d255d3SCy Schubert char *hex;
1711c1d255d3SCy Schubert size_t hexlen;
1712c1d255d3SCy Schubert
1713c1d255d3SCy Schubert hexlen = 2 * wpabuf_len(conf->pp_key) + 1;
1714c1d255d3SCy Schubert hex = os_malloc(hexlen);
1715c1d255d3SCy Schubert if (hex) {
1716c1d255d3SCy Schubert wpa_snprintf_hex(hex, hexlen,
1717c1d255d3SCy Schubert wpabuf_head(conf->pp_key),
1718c1d255d3SCy Schubert wpabuf_len(conf->pp_key));
1719c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PP_KEY "%s", hex);
1720c1d255d3SCy Schubert os_free(hex);
1721c1d255d3SCy Schubert }
1722c1d255d3SCy Schubert }
172385732ac8SCy Schubert if (auth->net_access_key) {
172485732ac8SCy Schubert char *hex;
172585732ac8SCy Schubert size_t hexlen;
172685732ac8SCy Schubert
172785732ac8SCy Schubert hexlen = 2 * wpabuf_len(auth->net_access_key) + 1;
172885732ac8SCy Schubert hex = os_malloc(hexlen);
172985732ac8SCy Schubert if (hex) {
173085732ac8SCy Schubert wpa_snprintf_hex(hex, hexlen,
173185732ac8SCy Schubert wpabuf_head(auth->net_access_key),
173285732ac8SCy Schubert wpabuf_len(auth->net_access_key));
173385732ac8SCy Schubert if (auth->net_access_key_expiry)
173485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO,
173585732ac8SCy Schubert DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex,
173685732ac8SCy Schubert (long unsigned)
173785732ac8SCy Schubert auth->net_access_key_expiry);
173885732ac8SCy Schubert else
173985732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO,
174085732ac8SCy Schubert DPP_EVENT_NET_ACCESS_KEY "%s", hex);
174185732ac8SCy Schubert os_free(hex);
174285732ac8SCy Schubert }
174385732ac8SCy Schubert }
174485732ac8SCy Schubert
1745c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1746c1d255d3SCy Schubert if (conf->certbag) {
1747c1d255d3SCy Schubert char *b64;
1748c1d255d3SCy Schubert
1749c1d255d3SCy Schubert b64 = base64_encode_no_lf(wpabuf_head(conf->certbag),
1750c1d255d3SCy Schubert wpabuf_len(conf->certbag), NULL);
1751c1d255d3SCy Schubert if (b64)
1752c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CERTBAG "%s", b64);
1753c1d255d3SCy Schubert os_free(b64);
175485732ac8SCy Schubert }
175585732ac8SCy Schubert
1756c1d255d3SCy Schubert if (conf->cacert) {
1757c1d255d3SCy Schubert char *b64;
1758c1d255d3SCy Schubert
1759c1d255d3SCy Schubert b64 = base64_encode_no_lf(wpabuf_head(conf->cacert),
1760c1d255d3SCy Schubert wpabuf_len(conf->cacert), NULL);
1761c1d255d3SCy Schubert if (b64)
1762c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CACERT "%s", b64);
1763c1d255d3SCy Schubert os_free(b64);
1764c1d255d3SCy Schubert }
1765c1d255d3SCy Schubert
1766c1d255d3SCy Schubert if (conf->server_name)
1767c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_SERVER_NAME "%s",
1768c1d255d3SCy Schubert conf->server_name);
1769c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1770c1d255d3SCy Schubert
1771*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
1772*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_result_indicated) {
1773*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT "success");
1774*a90b9d01SCy Schubert wpa_s->dpp_pb_result_indicated = true;
1775*a90b9d01SCy Schubert }
1776*a90b9d01SCy Schubert
1777*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
1778*a90b9d01SCy Schubert
1779c1d255d3SCy Schubert return wpas_dpp_process_config(wpa_s, auth, conf);
1780c1d255d3SCy Schubert }
1781c1d255d3SCy Schubert
1782c1d255d3SCy Schubert
wpas_dpp_handle_key_pkg(struct wpa_supplicant * wpa_s,struct dpp_asymmetric_key * key)1783c1d255d3SCy Schubert static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
1784c1d255d3SCy Schubert struct dpp_asymmetric_key *key)
1785c1d255d3SCy Schubert {
1786c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1787c1d255d3SCy Schubert int res;
1788c1d255d3SCy Schubert
1789c1d255d3SCy Schubert if (!key)
1790c1d255d3SCy Schubert return 0;
1791c1d255d3SCy Schubert
1792c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
1793c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
1794c1d255d3SCy Schubert wpa_s->dpp_conf_backup_received = true;
1795c1d255d3SCy Schubert
1796c1d255d3SCy Schubert while (key) {
1797c1d255d3SCy Schubert res = dpp_configurator_from_backup(wpa_s->dpp, key);
1798c1d255d3SCy Schubert if (res < 0)
1799c1d255d3SCy Schubert return -1;
1800c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d",
1801c1d255d3SCy Schubert res);
1802c1d255d3SCy Schubert key = key->next;
1803c1d255d3SCy Schubert }
1804c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1805c1d255d3SCy Schubert
1806c1d255d3SCy Schubert return 0;
1807c1d255d3SCy Schubert }
1808c1d255d3SCy Schubert
1809c1d255d3SCy Schubert
1810c1d255d3SCy Schubert #ifdef CONFIG_DPP2
wpas_dpp_build_csr(void * eloop_ctx,void * timeout_ctx)1811c1d255d3SCy Schubert static void wpas_dpp_build_csr(void *eloop_ctx, void *timeout_ctx)
1812c1d255d3SCy Schubert {
1813c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
1814c1d255d3SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
1815c1d255d3SCy Schubert
1816c1d255d3SCy Schubert if (!auth || !auth->csrattrs)
1817c1d255d3SCy Schubert return;
1818c1d255d3SCy Schubert
1819c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Build CSR");
1820c1d255d3SCy Schubert wpabuf_free(auth->csr);
1821c1d255d3SCy Schubert /* TODO: Additional information needed for CSR based on csrAttrs */
1822c1d255d3SCy Schubert auth->csr = dpp_build_csr(auth, wpa_s->conf->dpp_name ?
1823c1d255d3SCy Schubert wpa_s->conf->dpp_name : "Test");
1824c1d255d3SCy Schubert if (!auth->csr) {
1825c1d255d3SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
1826c1d255d3SCy Schubert wpa_s->dpp_auth = NULL;
1827c1d255d3SCy Schubert return;
1828c1d255d3SCy Schubert }
1829c1d255d3SCy Schubert
1830c1d255d3SCy Schubert wpas_dpp_start_gas_client(wpa_s);
1831c1d255d3SCy Schubert }
1832c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1833c1d255d3SCy Schubert
183485732ac8SCy Schubert
1835*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
wpas_dpp_build_new_key(void * eloop_ctx,void * timeout_ctx)1836*a90b9d01SCy Schubert static void wpas_dpp_build_new_key(void *eloop_ctx, void *timeout_ctx)
1837*a90b9d01SCy Schubert {
1838*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
1839*a90b9d01SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
1840*a90b9d01SCy Schubert
1841*a90b9d01SCy Schubert if (!auth || !auth->waiting_new_key)
1842*a90b9d01SCy Schubert return;
1843*a90b9d01SCy Schubert
1844*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key");
1845*a90b9d01SCy Schubert wpas_dpp_start_gas_client(wpa_s);
1846*a90b9d01SCy Schubert }
1847*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
1848*a90b9d01SCy Schubert
1849*a90b9d01SCy Schubert
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)185085732ac8SCy Schubert static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
185185732ac8SCy Schubert enum gas_query_result result,
185285732ac8SCy Schubert const struct wpabuf *adv_proto,
185385732ac8SCy Schubert const struct wpabuf *resp, u16 status_code)
185485732ac8SCy Schubert {
185585732ac8SCy Schubert struct wpa_supplicant *wpa_s = ctx;
185685732ac8SCy Schubert const u8 *pos;
185785732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
18584bc52338SCy Schubert int res;
18594bc52338SCy Schubert enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
1860c1d255d3SCy Schubert unsigned int i;
186185732ac8SCy Schubert
1862*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_gas_client_timeout, wpa_s, NULL);
186385732ac8SCy Schubert wpa_s->dpp_gas_dialog_token = -1;
186485732ac8SCy Schubert
1865c1d255d3SCy Schubert if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
1866*a90b9d01SCy Schubert !ether_addr_equal(addr, auth->peer_mac_addr)) {
186785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
186885732ac8SCy Schubert return;
186985732ac8SCy Schubert }
187085732ac8SCy Schubert if (result != GAS_QUERY_SUCCESS ||
187185732ac8SCy Schubert !resp || status_code != WLAN_STATUS_SUCCESS) {
187285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
187385732ac8SCy Schubert goto fail;
187485732ac8SCy Schubert }
187585732ac8SCy Schubert
187685732ac8SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
187785732ac8SCy Schubert adv_proto);
187885732ac8SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
187985732ac8SCy Schubert resp);
188085732ac8SCy Schubert
188185732ac8SCy Schubert if (wpabuf_len(adv_proto) != 10 ||
188285732ac8SCy Schubert !(pos = wpabuf_head(adv_proto)) ||
188385732ac8SCy Schubert pos[0] != WLAN_EID_ADV_PROTO ||
188485732ac8SCy Schubert pos[1] != 8 ||
188585732ac8SCy Schubert pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
188685732ac8SCy Schubert pos[4] != 5 ||
188785732ac8SCy Schubert WPA_GET_BE24(&pos[5]) != OUI_WFA ||
188885732ac8SCy Schubert pos[8] != 0x1a ||
188985732ac8SCy Schubert pos[9] != 1) {
189085732ac8SCy Schubert wpa_printf(MSG_DEBUG,
189185732ac8SCy Schubert "DPP: Not a DPP Advertisement Protocol ID");
189285732ac8SCy Schubert goto fail;
189385732ac8SCy Schubert }
189485732ac8SCy Schubert
1895c1d255d3SCy Schubert res = dpp_conf_resp_rx(auth, resp);
1896c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1897c1d255d3SCy Schubert if (res == -2) {
1898c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: CSR needed");
1899c1d255d3SCy Schubert eloop_register_timeout(0, 0, wpas_dpp_build_csr, wpa_s, NULL);
1900c1d255d3SCy Schubert return;
1901c1d255d3SCy Schubert }
1902c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1903*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
1904*a90b9d01SCy Schubert if (res == -3) {
1905*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: New protocol key needed");
1906*a90b9d01SCy Schubert eloop_register_timeout(0, 0, wpas_dpp_build_new_key, wpa_s,
1907*a90b9d01SCy Schubert NULL);
1908*a90b9d01SCy Schubert return;
1909*a90b9d01SCy Schubert }
1910*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
1911c1d255d3SCy Schubert if (res < 0) {
191285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
191385732ac8SCy Schubert goto fail;
191485732ac8SCy Schubert }
191585732ac8SCy Schubert
1916c1d255d3SCy Schubert wpa_s->dpp_conf_backup_received = false;
1917c1d255d3SCy Schubert for (i = 0; i < auth->num_conf_obj; i++) {
1918c1d255d3SCy Schubert res = wpas_dpp_handle_config_obj(wpa_s, auth,
1919c1d255d3SCy Schubert &auth->conf_obj[i]);
19204bc52338SCy Schubert if (res < 0)
19214bc52338SCy Schubert goto fail;
1922c1d255d3SCy Schubert }
1923c1d255d3SCy Schubert if (auth->num_conf_obj)
1924c1d255d3SCy Schubert wpas_dpp_post_process_config(wpa_s, auth);
1925c1d255d3SCy Schubert if (wpas_dpp_handle_key_pkg(wpa_s, auth->conf_key_pkg) < 0)
1926c1d255d3SCy Schubert goto fail;
192785732ac8SCy Schubert
19284bc52338SCy Schubert status = DPP_STATUS_OK;
19294bc52338SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
19304bc52338SCy Schubert if (dpp_test == DPP_TEST_REJECT_CONFIG) {
19314bc52338SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
19324bc52338SCy Schubert status = DPP_STATUS_CONFIG_REJECTED;
19334bc52338SCy Schubert }
19344bc52338SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
193585732ac8SCy Schubert fail:
19364bc52338SCy Schubert if (status != DPP_STATUS_OK)
193785732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
19384bc52338SCy Schubert #ifdef CONFIG_DPP2
19394bc52338SCy Schubert if (auth->peer_version >= 2 &&
19404bc52338SCy Schubert auth->conf_resp_status == DPP_STATUS_OK) {
19414bc52338SCy Schubert struct wpabuf *msg;
19424bc52338SCy Schubert
19434bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
19444bc52338SCy Schubert msg = dpp_build_conf_result(auth, status);
19454bc52338SCy Schubert if (!msg)
19464bc52338SCy Schubert goto fail2;
19474bc52338SCy Schubert
19484bc52338SCy Schubert wpa_msg(wpa_s, MSG_INFO,
19494bc52338SCy Schubert DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
19504bc52338SCy Schubert MAC2STR(addr), auth->curr_freq,
19514bc52338SCy Schubert DPP_PA_CONFIGURATION_RESULT);
19524bc52338SCy Schubert offchannel_send_action(wpa_s, auth->curr_freq,
19534bc52338SCy Schubert addr, wpa_s->own_addr, broadcast,
19544bc52338SCy Schubert wpabuf_head(msg),
19554bc52338SCy Schubert wpabuf_len(msg),
19564bc52338SCy Schubert 500, wpas_dpp_tx_status, 0);
19574bc52338SCy Schubert wpabuf_free(msg);
19584bc52338SCy Schubert
19594bc52338SCy Schubert /* This exchange will be terminated in the TX status handler */
1960c1d255d3SCy Schubert if (wpa_s->conf->dpp_config_processing < 2 ||
1961c1d255d3SCy Schubert wpa_s->dpp_conf_backup_received)
1962c1d255d3SCy Schubert auth->remove_on_tx_status = 1;
19634bc52338SCy Schubert return;
19644bc52338SCy Schubert }
19654bc52338SCy Schubert fail2:
19664bc52338SCy Schubert #endif /* CONFIG_DPP2 */
196785732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
196885732ac8SCy Schubert wpa_s->dpp_auth = NULL;
196985732ac8SCy Schubert }
197085732ac8SCy Schubert
197185732ac8SCy Schubert
wpas_dpp_gas_client_timeout(void * eloop_ctx,void * timeout_ctx)1972*a90b9d01SCy Schubert static void wpas_dpp_gas_client_timeout(void *eloop_ctx, void *timeout_ctx)
1973*a90b9d01SCy Schubert {
1974*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
1975*a90b9d01SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
1976*a90b9d01SCy Schubert
1977*a90b9d01SCy Schubert if (!wpa_s->dpp_gas_client || !auth ||
1978*a90b9d01SCy Schubert (!auth->auth_success && !auth->reconfig_success))
1979*a90b9d01SCy Schubert return;
1980*a90b9d01SCy Schubert
1981*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Timeout while waiting for Config Response");
1982*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
1983*a90b9d01SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
1984*a90b9d01SCy Schubert wpa_s->dpp_auth = NULL;
1985*a90b9d01SCy Schubert }
1986*a90b9d01SCy Schubert
1987*a90b9d01SCy Schubert
wpas_dpp_start_gas_client(struct wpa_supplicant * wpa_s)198885732ac8SCy Schubert static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s)
198985732ac8SCy Schubert {
199085732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
19914bc52338SCy Schubert struct wpabuf *buf;
199285732ac8SCy Schubert int res;
1993c1d255d3SCy Schubert int *supp_op_classes;
199485732ac8SCy Schubert
199585732ac8SCy Schubert wpa_s->dpp_gas_client = 1;
199685732ac8SCy Schubert offchannel_send_action_done(wpa_s);
199785732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s);
199885732ac8SCy Schubert
1999*a90b9d01SCy Schubert #ifdef CONFIG_NO_RRM
2000*a90b9d01SCy Schubert supp_op_classes = NULL;
2001*a90b9d01SCy Schubert #else /* CONFIG_NO_RRM */
2002c1d255d3SCy Schubert supp_op_classes = wpas_supp_op_classes(wpa_s);
2003*a90b9d01SCy Schubert #endif /* CONFIG_NO_RRM */
2004c1d255d3SCy Schubert buf = dpp_build_conf_req_helper(auth, wpa_s->conf->dpp_name,
2005c1d255d3SCy Schubert wpa_s->dpp_netrole,
2006c1d255d3SCy Schubert wpa_s->conf->dpp_mud_url,
2007*a90b9d01SCy Schubert supp_op_classes,
2008*a90b9d01SCy Schubert wpa_s->conf->dpp_extra_conf_req_name,
2009*a90b9d01SCy Schubert wpa_s->conf->dpp_extra_conf_req_value);
2010c1d255d3SCy Schubert os_free(supp_op_classes);
20114bc52338SCy Schubert if (!buf) {
201285732ac8SCy Schubert wpa_printf(MSG_DEBUG,
201385732ac8SCy Schubert "DPP: No configuration request data available");
201485732ac8SCy Schubert return;
201585732ac8SCy Schubert }
201685732ac8SCy Schubert
201785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
201885732ac8SCy Schubert MAC2STR(auth->peer_mac_addr), auth->curr_freq);
201985732ac8SCy Schubert
2020*a90b9d01SCy Schubert /* Use a 120 second timeout since the gas_query_req() operation could
2021*a90b9d01SCy Schubert * remain waiting indefinitely for the response if the Configurator
2022*a90b9d01SCy Schubert * keeps sending out comeback responses with additional delay. The
2023*a90b9d01SCy Schubert * DPP technical specification expects the Enrollee to continue sending
2024*a90b9d01SCy Schubert * out new Config Requests for 60 seconds, so this gives an extra 60
2025*a90b9d01SCy Schubert * second time after the last expected new Config Request for the
2026*a90b9d01SCy Schubert * Configurator to determine what kind of configuration to provide. */
2027*a90b9d01SCy Schubert eloop_register_timeout(120, 0, wpas_dpp_gas_client_timeout,
2028*a90b9d01SCy Schubert wpa_s, NULL);
2029*a90b9d01SCy Schubert
203085732ac8SCy Schubert res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq,
2031c1d255d3SCy Schubert 1, 1, buf, wpas_dpp_gas_resp_cb, wpa_s);
203285732ac8SCy Schubert if (res < 0) {
203385732ac8SCy Schubert wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
203485732ac8SCy Schubert wpabuf_free(buf);
203585732ac8SCy Schubert } else {
203685732ac8SCy Schubert wpa_printf(MSG_DEBUG,
203785732ac8SCy Schubert "DPP: GAS query started with dialog token %u", res);
203885732ac8SCy Schubert wpa_s->dpp_gas_dialog_token = res;
203985732ac8SCy Schubert }
204085732ac8SCy Schubert }
204185732ac8SCy Schubert
204285732ac8SCy Schubert
wpas_dpp_auth_success(struct wpa_supplicant * wpa_s,int initiator)204385732ac8SCy Schubert static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator)
204485732ac8SCy Schubert {
204585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
2046*a90b9d01SCy Schubert dpp_notify_auth_success(wpa_s->dpp_auth, initiator);
204785732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
204885732ac8SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
204985732ac8SCy Schubert wpa_printf(MSG_INFO,
205085732ac8SCy Schubert "DPP: TESTING - stop at Authentication Confirm");
205185732ac8SCy Schubert if (wpa_s->dpp_auth->configurator) {
205285732ac8SCy Schubert /* Prevent GAS response */
205385732ac8SCy Schubert wpa_s->dpp_auth->auth_success = 0;
205485732ac8SCy Schubert }
205585732ac8SCy Schubert return;
205685732ac8SCy Schubert }
205785732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
205885732ac8SCy Schubert
205985732ac8SCy Schubert if (wpa_s->dpp_auth->configurator)
206085732ac8SCy Schubert wpas_dpp_start_gas_server(wpa_s);
206185732ac8SCy Schubert else
206285732ac8SCy Schubert wpas_dpp_start_gas_client(wpa_s);
206385732ac8SCy Schubert }
206485732ac8SCy Schubert
206585732ac8SCy Schubert
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)206685732ac8SCy Schubert static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
206785732ac8SCy Schubert const u8 *hdr, const u8 *buf, size_t len,
206885732ac8SCy Schubert unsigned int freq)
206985732ac8SCy Schubert {
207085732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
207185732ac8SCy Schubert struct wpabuf *msg;
207285732ac8SCy Schubert
207385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR
207485732ac8SCy Schubert " (freq %u MHz)", MAC2STR(src), freq);
207585732ac8SCy Schubert
207685732ac8SCy Schubert if (!auth) {
207785732ac8SCy Schubert wpa_printf(MSG_DEBUG,
207885732ac8SCy Schubert "DPP: No DPP Authentication in progress - drop");
207985732ac8SCy Schubert return;
208085732ac8SCy Schubert }
208185732ac8SCy Schubert
208285732ac8SCy Schubert if (!is_zero_ether_addr(auth->peer_mac_addr) &&
2083*a90b9d01SCy Schubert !ether_addr_equal(src, auth->peer_mac_addr)) {
208485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
208585732ac8SCy Schubert MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
208685732ac8SCy Schubert return;
208785732ac8SCy Schubert }
208885732ac8SCy Schubert
208985732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
209085732ac8SCy Schubert
209185732ac8SCy Schubert if (auth->curr_freq != freq && auth->neg_freq == freq) {
209285732ac8SCy Schubert wpa_printf(MSG_DEBUG,
209385732ac8SCy Schubert "DPP: Responder accepted request for different negotiation channel");
209485732ac8SCy Schubert auth->curr_freq = freq;
209585732ac8SCy Schubert }
209685732ac8SCy Schubert
209785732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
209885732ac8SCy Schubert msg = dpp_auth_resp_rx(auth, hdr, buf, len);
209985732ac8SCy Schubert if (!msg) {
210085732ac8SCy Schubert if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
210185732ac8SCy Schubert wpa_printf(MSG_DEBUG,
210285732ac8SCy Schubert "DPP: Start wait for full response");
210385732ac8SCy Schubert offchannel_send_action_done(wpa_s);
210485732ac8SCy Schubert wpas_dpp_listen_start(wpa_s, auth->curr_freq);
210585732ac8SCy Schubert return;
210685732ac8SCy Schubert }
210785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
210885732ac8SCy Schubert return;
210985732ac8SCy Schubert }
211085732ac8SCy Schubert os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
211185732ac8SCy Schubert
211285732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
211385732ac8SCy Schubert MAC2STR(src), auth->curr_freq, DPP_PA_AUTHENTICATION_CONF);
211485732ac8SCy Schubert offchannel_send_action(wpa_s, auth->curr_freq,
211585732ac8SCy Schubert src, wpa_s->own_addr, broadcast,
211685732ac8SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
211785732ac8SCy Schubert 500, wpas_dpp_tx_status, 0);
211885732ac8SCy Schubert wpabuf_free(msg);
211985732ac8SCy Schubert wpa_s->dpp_auth_ok_on_ack = 1;
212085732ac8SCy Schubert }
212185732ac8SCy Schubert
212285732ac8SCy Schubert
wpas_dpp_rx_auth_conf(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len)212385732ac8SCy Schubert static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
212485732ac8SCy Schubert const u8 *hdr, const u8 *buf, size_t len)
212585732ac8SCy Schubert {
212685732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
212785732ac8SCy Schubert
212885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
212985732ac8SCy Schubert MAC2STR(src));
213085732ac8SCy Schubert
213185732ac8SCy Schubert if (!auth) {
213285732ac8SCy Schubert wpa_printf(MSG_DEBUG,
213385732ac8SCy Schubert "DPP: No DPP Authentication in progress - drop");
213485732ac8SCy Schubert return;
213585732ac8SCy Schubert }
213685732ac8SCy Schubert
2137*a90b9d01SCy Schubert if (!ether_addr_equal(src, auth->peer_mac_addr)) {
213885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
213985732ac8SCy Schubert MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
214085732ac8SCy Schubert return;
214185732ac8SCy Schubert }
214285732ac8SCy Schubert
2143c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s, NULL);
2144c1d255d3SCy Schubert
214585732ac8SCy Schubert if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
214685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
214785732ac8SCy Schubert return;
214885732ac8SCy Schubert }
214985732ac8SCy Schubert
215085732ac8SCy Schubert wpas_dpp_auth_success(wpa_s, 0);
215185732ac8SCy Schubert }
215285732ac8SCy Schubert
215385732ac8SCy Schubert
21544bc52338SCy Schubert #ifdef CONFIG_DPP2
21554bc52338SCy Schubert
wpas_dpp_config_result_wait_timeout(void * eloop_ctx,void * timeout_ctx)21564bc52338SCy Schubert static void wpas_dpp_config_result_wait_timeout(void *eloop_ctx,
21574bc52338SCy Schubert void *timeout_ctx)
21584bc52338SCy Schubert {
21594bc52338SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
21604bc52338SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
21614bc52338SCy Schubert
21624bc52338SCy Schubert if (!auth || !auth->waiting_conf_result)
21634bc52338SCy Schubert return;
21644bc52338SCy Schubert
21654bc52338SCy Schubert wpa_printf(MSG_DEBUG,
21664bc52338SCy Schubert "DPP: Timeout while waiting for Configuration Result");
21674bc52338SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
21684bc52338SCy Schubert dpp_auth_deinit(auth);
21694bc52338SCy Schubert wpa_s->dpp_auth = NULL;
21704bc52338SCy Schubert }
21714bc52338SCy Schubert
21724bc52338SCy Schubert
wpas_dpp_conn_status_result_wait_timeout(void * eloop_ctx,void * timeout_ctx)2173c1d255d3SCy Schubert static void wpas_dpp_conn_status_result_wait_timeout(void *eloop_ctx,
2174c1d255d3SCy Schubert void *timeout_ctx)
2175c1d255d3SCy Schubert {
2176c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
2177c1d255d3SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
2178c1d255d3SCy Schubert
2179c1d255d3SCy Schubert if (!auth || !auth->waiting_conn_status_result)
2180c1d255d3SCy Schubert return;
2181c1d255d3SCy Schubert
2182c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2183c1d255d3SCy Schubert "DPP: Timeout while waiting for Connection Status Result");
2184c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT "timeout");
2185c1d255d3SCy Schubert wpas_dpp_listen_stop(wpa_s);
2186c1d255d3SCy Schubert dpp_auth_deinit(auth);
2187c1d255d3SCy Schubert wpa_s->dpp_auth = NULL;
2188c1d255d3SCy Schubert }
2189c1d255d3SCy Schubert
2190c1d255d3SCy Schubert
2191*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
2192*a90b9d01SCy Schubert
wpas_dpp_pb_active(struct wpa_supplicant * wpa_s)2193*a90b9d01SCy Schubert static bool wpas_dpp_pb_active(struct wpa_supplicant *wpa_s)
2194*a90b9d01SCy Schubert {
2195*a90b9d01SCy Schubert return (wpa_s->dpp_pb_time.sec || wpa_s->dpp_pb_time.usec) &&
2196*a90b9d01SCy Schubert wpa_s->dpp_pb_configurator;
2197*a90b9d01SCy Schubert }
2198*a90b9d01SCy Schubert
2199*a90b9d01SCy Schubert
wpas_dpp_remove_pb_hash(struct wpa_supplicant * wpa_s)2200*a90b9d01SCy Schubert static void wpas_dpp_remove_pb_hash(struct wpa_supplicant *wpa_s)
2201*a90b9d01SCy Schubert {
2202*a90b9d01SCy Schubert int i;
2203*a90b9d01SCy Schubert
2204*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_bi)
2205*a90b9d01SCy Schubert return;
2206*a90b9d01SCy Schubert for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
2207*a90b9d01SCy Schubert struct dpp_pb_info *info = &wpa_s->dpp_pb[i];
2208*a90b9d01SCy Schubert
2209*a90b9d01SCy Schubert if (info->rx_time.sec == 0 && info->rx_time.usec == 0)
2210*a90b9d01SCy Schubert continue;
2211*a90b9d01SCy Schubert if (os_memcmp(info->hash, wpa_s->dpp_pb_resp_hash,
2212*a90b9d01SCy Schubert SHA256_MAC_LEN) == 0) {
2213*a90b9d01SCy Schubert /* Allow a new push button session to be established
2214*a90b9d01SCy Schubert * immediately without the successfully completed
2215*a90b9d01SCy Schubert * session triggering session overlap. */
2216*a90b9d01SCy Schubert info->rx_time.sec = 0;
2217*a90b9d01SCy Schubert info->rx_time.usec = 0;
2218*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
2219*a90b9d01SCy Schubert "DPP: Removed PB hash from session overlap detection due to successfully completed provisioning");
2220*a90b9d01SCy Schubert }
2221*a90b9d01SCy Schubert }
2222*a90b9d01SCy Schubert }
2223*a90b9d01SCy Schubert
2224*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
2225*a90b9d01SCy Schubert
2226*a90b9d01SCy Schubert
wpas_dpp_rx_conf_result(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len)22274bc52338SCy Schubert static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
22284bc52338SCy Schubert const u8 *hdr, const u8 *buf, size_t len)
22294bc52338SCy Schubert {
22304bc52338SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
22314bc52338SCy Schubert enum dpp_status_error status;
22324bc52338SCy Schubert
22334bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
22344bc52338SCy Schubert MAC2STR(src));
22354bc52338SCy Schubert
22364bc52338SCy Schubert if (!auth || !auth->waiting_conf_result) {
2237c1d255d3SCy Schubert if (auth &&
2238*a90b9d01SCy Schubert ether_addr_equal(src, auth->peer_mac_addr) &&
2239c1d255d3SCy Schubert gas_server_response_sent(wpa_s->gas_server,
2240c1d255d3SCy Schubert auth->gas_server_ctx)) {
2241c1d255d3SCy Schubert /* This could happen if the TX status event gets delayed
2242c1d255d3SCy Schubert * long enough for the Enrollee to have time to send
2243c1d255d3SCy Schubert * the next frame before the TX status gets processed
2244c1d255d3SCy Schubert * locally. */
2245c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2246c1d255d3SCy Schubert "DPP: GAS response was sent but TX status not yet received - assume it was ACKed since the Enrollee sent the next frame in the sequence");
2247c1d255d3SCy Schubert auth->waiting_conf_result = 1;
2248c1d255d3SCy Schubert } else {
22494bc52338SCy Schubert wpa_printf(MSG_DEBUG,
22504bc52338SCy Schubert "DPP: No DPP Configuration waiting for result - drop");
22514bc52338SCy Schubert return;
22524bc52338SCy Schubert }
2253c1d255d3SCy Schubert }
22544bc52338SCy Schubert
2255*a90b9d01SCy Schubert if (!ether_addr_equal(src, auth->peer_mac_addr)) {
22564bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
22574bc52338SCy Schubert MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
22584bc52338SCy Schubert return;
22594bc52338SCy Schubert }
22604bc52338SCy Schubert
22614bc52338SCy Schubert status = dpp_conf_result_rx(auth, hdr, buf, len);
22624bc52338SCy Schubert
2263c1d255d3SCy Schubert if (status == DPP_STATUS_OK && auth->send_conn_status) {
2264*a90b9d01SCy Schubert int freq;
2265*a90b9d01SCy Schubert
2266c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO,
2267*a90b9d01SCy Schubert DPP_EVENT_CONF_SENT "wait_conn_status=1 conf_status=%d",
2268*a90b9d01SCy Schubert auth->conf_resp_status);
2269c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
2270c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
2271c1d255d3SCy Schubert wpa_s, NULL);
2272c1d255d3SCy Schubert auth->waiting_conn_status_result = 1;
2273c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
2274c1d255d3SCy Schubert wpa_s, NULL);
2275c1d255d3SCy Schubert eloop_register_timeout(16, 0,
2276c1d255d3SCy Schubert wpas_dpp_conn_status_result_wait_timeout,
2277c1d255d3SCy Schubert wpa_s, NULL);
2278c1d255d3SCy Schubert offchannel_send_action_done(wpa_s);
2279*a90b9d01SCy Schubert freq = auth->neg_freq ? auth->neg_freq : auth->curr_freq;
2280*a90b9d01SCy Schubert if (!wpa_s->dpp_in_response_listen ||
2281*a90b9d01SCy Schubert (int) wpa_s->dpp_listen_freq != freq)
2282*a90b9d01SCy Schubert wpas_dpp_listen_start(wpa_s, freq);
2283c1d255d3SCy Schubert return;
2284c1d255d3SCy Schubert }
22854bc52338SCy Schubert offchannel_send_action_done(wpa_s);
22864bc52338SCy Schubert wpas_dpp_listen_stop(wpa_s);
22874bc52338SCy Schubert if (status == DPP_STATUS_OK)
2288*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT "conf_status=%d",
2289*a90b9d01SCy Schubert auth->conf_resp_status);
22904bc52338SCy Schubert else
22914bc52338SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
22924bc52338SCy Schubert dpp_auth_deinit(auth);
22934bc52338SCy Schubert wpa_s->dpp_auth = NULL;
22944bc52338SCy Schubert eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
2295*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
2296*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_result_indicated && wpas_dpp_pb_active(wpa_s)) {
2297*a90b9d01SCy Schubert if (status == DPP_STATUS_OK)
2298*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT
2299*a90b9d01SCy Schubert "success");
2300*a90b9d01SCy Schubert else
2301*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT
2302*a90b9d01SCy Schubert "no-configuration-available");
2303*a90b9d01SCy Schubert wpa_s->dpp_pb_result_indicated = true;
2304*a90b9d01SCy Schubert if (status == DPP_STATUS_OK)
2305*a90b9d01SCy Schubert wpas_dpp_remove_pb_hash(wpa_s);
2306*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
2307*a90b9d01SCy Schubert }
2308*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
23094bc52338SCy Schubert }
23104bc52338SCy Schubert
2311206b73d0SCy Schubert
wpas_dpp_rx_conn_status_result(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len)2312c1d255d3SCy Schubert static void wpas_dpp_rx_conn_status_result(struct wpa_supplicant *wpa_s,
2313c1d255d3SCy Schubert const u8 *src, const u8 *hdr,
2314c1d255d3SCy Schubert const u8 *buf, size_t len)
2315c1d255d3SCy Schubert {
2316c1d255d3SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
2317c1d255d3SCy Schubert enum dpp_status_error status;
2318c1d255d3SCy Schubert u8 ssid[SSID_MAX_LEN];
2319c1d255d3SCy Schubert size_t ssid_len = 0;
2320c1d255d3SCy Schubert char *channel_list = NULL;
2321c1d255d3SCy Schubert
2322c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
2323c1d255d3SCy Schubert
2324c1d255d3SCy Schubert if (!auth || !auth->waiting_conn_status_result) {
2325c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2326c1d255d3SCy Schubert "DPP: No DPP Configuration waiting for connection status result - drop");
2327c1d255d3SCy Schubert return;
2328c1d255d3SCy Schubert }
2329c1d255d3SCy Schubert
2330c1d255d3SCy Schubert status = dpp_conn_status_result_rx(auth, hdr, buf, len,
2331c1d255d3SCy Schubert ssid, &ssid_len, &channel_list);
2332c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
2333c1d255d3SCy Schubert "result=%d ssid=%s channel_list=%s",
2334c1d255d3SCy Schubert status, wpa_ssid_txt(ssid, ssid_len),
2335c1d255d3SCy Schubert channel_list ? channel_list : "N/A");
2336c1d255d3SCy Schubert os_free(channel_list);
2337c1d255d3SCy Schubert offchannel_send_action_done(wpa_s);
2338c1d255d3SCy Schubert wpas_dpp_listen_stop(wpa_s);
2339c1d255d3SCy Schubert dpp_auth_deinit(auth);
2340c1d255d3SCy Schubert wpa_s->dpp_auth = NULL;
2341c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
2342c1d255d3SCy Schubert wpa_s, NULL);
2343c1d255d3SCy Schubert }
2344c1d255d3SCy Schubert
2345c1d255d3SCy Schubert
wpas_dpp_process_conf_obj(void * ctx,struct dpp_authentication * auth)2346206b73d0SCy Schubert static int wpas_dpp_process_conf_obj(void *ctx,
2347206b73d0SCy Schubert struct dpp_authentication *auth)
2348206b73d0SCy Schubert {
2349206b73d0SCy Schubert struct wpa_supplicant *wpa_s = ctx;
2350c1d255d3SCy Schubert unsigned int i;
2351c1d255d3SCy Schubert int res = -1;
2352206b73d0SCy Schubert
2353c1d255d3SCy Schubert for (i = 0; i < auth->num_conf_obj; i++) {
2354c1d255d3SCy Schubert res = wpas_dpp_handle_config_obj(wpa_s, auth,
2355c1d255d3SCy Schubert &auth->conf_obj[i]);
2356c1d255d3SCy Schubert if (res)
2357c1d255d3SCy Schubert break;
2358c1d255d3SCy Schubert }
2359c1d255d3SCy Schubert if (!res)
2360c1d255d3SCy Schubert wpas_dpp_post_process_config(wpa_s, auth);
2361c1d255d3SCy Schubert
2362c1d255d3SCy Schubert return res;
2363c1d255d3SCy Schubert }
2364c1d255d3SCy Schubert
2365c1d255d3SCy Schubert
wpas_dpp_tcp_msg_sent(void * ctx,struct dpp_authentication * auth)2366*a90b9d01SCy Schubert static bool wpas_dpp_tcp_msg_sent(void *ctx, struct dpp_authentication *auth)
2367*a90b9d01SCy Schubert {
2368*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = ctx;
2369*a90b9d01SCy Schubert
2370*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: TCP message sent callback");
2371*a90b9d01SCy Schubert
2372*a90b9d01SCy Schubert if (auth->connect_on_tx_status) {
2373*a90b9d01SCy Schubert auth->connect_on_tx_status = 0;
2374*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
2375*a90b9d01SCy Schubert "DPP: Try to connect after completed configuration result");
2376*a90b9d01SCy Schubert wpas_dpp_try_to_connect(wpa_s);
2377*a90b9d01SCy Schubert if (auth->conn_status_requested) {
2378*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
2379*a90b9d01SCy Schubert "DPP: Start 15 second timeout for reporting connection status result");
2380*a90b9d01SCy Schubert eloop_cancel_timeout(
2381*a90b9d01SCy Schubert wpas_dpp_conn_status_result_timeout,
2382*a90b9d01SCy Schubert wpa_s, NULL);
2383*a90b9d01SCy Schubert eloop_register_timeout(
2384*a90b9d01SCy Schubert 15, 0, wpas_dpp_conn_status_result_timeout,
2385*a90b9d01SCy Schubert wpa_s, NULL);
2386*a90b9d01SCy Schubert return true;
2387*a90b9d01SCy Schubert }
2388*a90b9d01SCy Schubert }
2389*a90b9d01SCy Schubert
2390*a90b9d01SCy Schubert return false;
2391*a90b9d01SCy Schubert }
2392*a90b9d01SCy Schubert
2393*a90b9d01SCy Schubert
wpas_dpp_remove_bi(void * ctx,struct dpp_bootstrap_info * bi)2394c1d255d3SCy Schubert static void wpas_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi)
2395c1d255d3SCy Schubert {
2396c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = ctx;
2397c1d255d3SCy Schubert
2398c1d255d3SCy Schubert if (bi == wpa_s->dpp_chirp_bi)
2399c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
2400c1d255d3SCy Schubert }
2401c1d255d3SCy Schubert
2402c1d255d3SCy Schubert
2403c1d255d3SCy Schubert static void
wpas_dpp_rx_presence_announcement(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq)2404c1d255d3SCy Schubert wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
2405c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, size_t len,
2406c1d255d3SCy Schubert unsigned int freq)
2407c1d255d3SCy Schubert {
2408c1d255d3SCy Schubert const u8 *r_bootstrap;
2409c1d255d3SCy Schubert u16 r_bootstrap_len;
2410c1d255d3SCy Schubert struct dpp_bootstrap_info *peer_bi;
2411c1d255d3SCy Schubert struct dpp_authentication *auth;
2412*a90b9d01SCy Schubert unsigned int wait_time, max_wait_time;
2413c1d255d3SCy Schubert
2414c1d255d3SCy Schubert if (!wpa_s->dpp)
2415c1d255d3SCy Schubert return;
2416c1d255d3SCy Schubert
2417c1d255d3SCy Schubert if (wpa_s->dpp_auth) {
2418c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2419c1d255d3SCy Schubert "DPP: Ignore Presence Announcement during ongoing Authentication");
2420c1d255d3SCy Schubert return;
2421c1d255d3SCy Schubert }
2422c1d255d3SCy Schubert
2423c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
2424c1d255d3SCy Schubert MAC2STR(src));
2425c1d255d3SCy Schubert
2426c1d255d3SCy Schubert r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
2427c1d255d3SCy Schubert &r_bootstrap_len);
2428c1d255d3SCy Schubert if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
2429c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
2430c1d255d3SCy Schubert "Missing or invalid required Responder Bootstrapping Key Hash attribute");
2431c1d255d3SCy Schubert return;
2432c1d255d3SCy Schubert }
2433c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
2434c1d255d3SCy Schubert r_bootstrap, r_bootstrap_len);
2435c1d255d3SCy Schubert peer_bi = dpp_bootstrap_find_chirp(wpa_s->dpp, r_bootstrap);
2436c1d255d3SCy Schubert dpp_notify_chirp_received(wpa_s, peer_bi ? (int) peer_bi->id : -1, src,
2437c1d255d3SCy Schubert freq, r_bootstrap);
2438c1d255d3SCy Schubert if (!peer_bi) {
2439c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2440c1d255d3SCy Schubert "DPP: No matching bootstrapping information found");
2441c1d255d3SCy Schubert return;
2442c1d255d3SCy Schubert }
2443c1d255d3SCy Schubert
2444*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Start Authentication exchange with " MACSTR
2445*a90b9d01SCy Schubert " based on the received Presence Announcement",
2446*a90b9d01SCy Schubert MAC2STR(src));
2447c1d255d3SCy Schubert auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, NULL,
2448c1d255d3SCy Schubert DPP_CAPAB_CONFIGURATOR, freq, NULL, 0);
2449c1d255d3SCy Schubert if (!auth)
2450c1d255d3SCy Schubert return;
2451c1d255d3SCy Schubert wpas_dpp_set_testing_options(wpa_s, auth);
2452c1d255d3SCy Schubert if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) {
2453c1d255d3SCy Schubert dpp_auth_deinit(auth);
2454c1d255d3SCy Schubert return;
2455c1d255d3SCy Schubert }
2456c1d255d3SCy Schubert
2457c1d255d3SCy Schubert auth->neg_freq = freq;
2458c1d255d3SCy Schubert
2459c1d255d3SCy Schubert /* The source address of the Presence Announcement frame overrides any
2460c1d255d3SCy Schubert * MAC address information from the bootstrapping information. */
2461c1d255d3SCy Schubert os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
2462c1d255d3SCy Schubert
2463*a90b9d01SCy Schubert wait_time = wpa_s->max_remain_on_chan;
2464*a90b9d01SCy Schubert max_wait_time = wpa_s->dpp_resp_wait_time ?
2465*a90b9d01SCy Schubert wpa_s->dpp_resp_wait_time : 2000;
2466*a90b9d01SCy Schubert if (wait_time > max_wait_time)
2467*a90b9d01SCy Schubert wait_time = max_wait_time;
2468*a90b9d01SCy Schubert wpas_dpp_stop_listen_for_tx(wpa_s, freq, wait_time);
2469*a90b9d01SCy Schubert
2470c1d255d3SCy Schubert wpa_s->dpp_auth = auth;
2471c1d255d3SCy Schubert if (wpas_dpp_auth_init_next(wpa_s) < 0) {
2472c1d255d3SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
2473c1d255d3SCy Schubert wpa_s->dpp_auth = NULL;
2474c1d255d3SCy Schubert }
2475c1d255d3SCy Schubert }
2476c1d255d3SCy Schubert
2477c1d255d3SCy Schubert
wpas_dpp_reconfig_reply_wait_timeout(void * eloop_ctx,void * timeout_ctx)2478c1d255d3SCy Schubert static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
2479c1d255d3SCy Schubert void *timeout_ctx)
2480c1d255d3SCy Schubert {
2481c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
2482c1d255d3SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
2483c1d255d3SCy Schubert
2484c1d255d3SCy Schubert if (!auth)
2485c1d255d3SCy Schubert return;
2486c1d255d3SCy Schubert
2487c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Reconfig Reply wait timeout");
2488c1d255d3SCy Schubert offchannel_send_action_done(wpa_s);
2489c1d255d3SCy Schubert wpas_dpp_listen_stop(wpa_s);
2490c1d255d3SCy Schubert dpp_auth_deinit(auth);
2491c1d255d3SCy Schubert wpa_s->dpp_auth = NULL;
2492c1d255d3SCy Schubert }
2493c1d255d3SCy Schubert
2494c1d255d3SCy Schubert
2495c1d255d3SCy Schubert static void
wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq)2496c1d255d3SCy Schubert wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
2497c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, size_t len,
2498c1d255d3SCy Schubert unsigned int freq)
2499c1d255d3SCy Schubert {
2500c1d255d3SCy Schubert const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
2501c1d255d3SCy Schubert u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
2502c1d255d3SCy Schubert struct dpp_configurator *conf;
2503c1d255d3SCy Schubert struct dpp_authentication *auth;
2504c1d255d3SCy Schubert unsigned int wait_time, max_wait_time;
2505c1d255d3SCy Schubert u16 group;
2506c1d255d3SCy Schubert
2507c1d255d3SCy Schubert if (!wpa_s->dpp)
2508c1d255d3SCy Schubert return;
2509c1d255d3SCy Schubert
2510c1d255d3SCy Schubert if (wpa_s->dpp_auth) {
2511c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2512c1d255d3SCy Schubert "DPP: Ignore Reconfig Announcement during ongoing Authentication");
2513c1d255d3SCy Schubert return;
2514c1d255d3SCy Schubert }
2515c1d255d3SCy Schubert
2516c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Reconfig Announcement from " MACSTR,
2517c1d255d3SCy Schubert MAC2STR(src));
2518c1d255d3SCy Schubert
2519c1d255d3SCy Schubert csign_hash = dpp_get_attr(buf, len, DPP_ATTR_C_SIGN_KEY_HASH,
2520c1d255d3SCy Schubert &csign_hash_len);
2521c1d255d3SCy Schubert if (!csign_hash || csign_hash_len != SHA256_MAC_LEN) {
2522c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
2523c1d255d3SCy Schubert "Missing or invalid required Configurator C-sign key Hash attribute");
2524c1d255d3SCy Schubert return;
2525c1d255d3SCy Schubert }
2526c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator C-sign key Hash (kid)",
2527c1d255d3SCy Schubert csign_hash, csign_hash_len);
2528c1d255d3SCy Schubert conf = dpp_configurator_find_kid(wpa_s->dpp, csign_hash);
2529c1d255d3SCy Schubert if (!conf) {
2530c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2531c1d255d3SCy Schubert "DPP: No matching Configurator information found");
2532c1d255d3SCy Schubert return;
2533c1d255d3SCy Schubert }
2534c1d255d3SCy Schubert
2535c1d255d3SCy Schubert fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
2536c1d255d3SCy Schubert &fcgroup_len);
2537c1d255d3SCy Schubert if (!fcgroup || fcgroup_len != 2) {
2538c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
2539c1d255d3SCy Schubert "Missing or invalid required Finite Cyclic Group attribute");
2540c1d255d3SCy Schubert return;
2541c1d255d3SCy Schubert }
2542c1d255d3SCy Schubert group = WPA_GET_LE16(fcgroup);
2543c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
2544c1d255d3SCy Schubert
2545c1d255d3SCy Schubert a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
2546c1d255d3SCy Schubert e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
2547c1d255d3SCy Schubert
2548c1d255d3SCy Schubert auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq, group,
2549c1d255d3SCy Schubert a_nonce, a_nonce_len, e_id, e_id_len);
2550c1d255d3SCy Schubert if (!auth)
2551c1d255d3SCy Schubert return;
2552c1d255d3SCy Schubert wpas_dpp_set_testing_options(wpa_s, auth);
2553c1d255d3SCy Schubert if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) {
2554c1d255d3SCy Schubert dpp_auth_deinit(auth);
2555c1d255d3SCy Schubert return;
2556c1d255d3SCy Schubert }
2557c1d255d3SCy Schubert
2558c1d255d3SCy Schubert os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
2559c1d255d3SCy Schubert wpa_s->dpp_auth = auth;
2560c1d255d3SCy Schubert
2561c1d255d3SCy Schubert wpa_s->dpp_in_response_listen = 0;
2562c1d255d3SCy Schubert wpa_s->dpp_auth_ok_on_ack = 0;
2563c1d255d3SCy Schubert wait_time = wpa_s->max_remain_on_chan;
2564c1d255d3SCy Schubert max_wait_time = wpa_s->dpp_resp_wait_time ?
2565c1d255d3SCy Schubert wpa_s->dpp_resp_wait_time : 2000;
2566c1d255d3SCy Schubert if (wait_time > max_wait_time)
2567c1d255d3SCy Schubert wait_time = max_wait_time;
2568c1d255d3SCy Schubert wait_time += 10; /* give the driver some extra time to complete */
2569c1d255d3SCy Schubert eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
2570c1d255d3SCy Schubert wpas_dpp_reconfig_reply_wait_timeout,
2571c1d255d3SCy Schubert wpa_s, NULL);
2572c1d255d3SCy Schubert wait_time -= 10;
2573c1d255d3SCy Schubert
2574c1d255d3SCy Schubert wpas_dpp_stop_listen_for_tx(wpa_s, freq, wait_time);
2575c1d255d3SCy Schubert
2576c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
2577c1d255d3SCy Schubert MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_REQ);
2578c1d255d3SCy Schubert if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
2579c1d255d3SCy Schubert wpabuf_head(auth->reconfig_req_msg),
2580c1d255d3SCy Schubert wpabuf_len(auth->reconfig_req_msg),
2581c1d255d3SCy Schubert wait_time, wpas_dpp_tx_status, 0) < 0) {
2582c1d255d3SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
2583c1d255d3SCy Schubert wpa_s->dpp_auth = NULL;
2584c1d255d3SCy Schubert }
2585c1d255d3SCy Schubert }
2586c1d255d3SCy Schubert
2587c1d255d3SCy Schubert
2588c1d255d3SCy Schubert static void
wpas_dpp_rx_reconfig_auth_req(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq)2589c1d255d3SCy Schubert wpas_dpp_rx_reconfig_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
2590c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, size_t len,
2591c1d255d3SCy Schubert unsigned int freq)
2592c1d255d3SCy Schubert {
2593c1d255d3SCy Schubert struct wpa_ssid *ssid;
2594c1d255d3SCy Schubert struct dpp_authentication *auth;
2595c1d255d3SCy Schubert
2596c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Request from "
2597c1d255d3SCy Schubert MACSTR, MAC2STR(src));
2598c1d255d3SCy Schubert
2599c1d255d3SCy Schubert if (!wpa_s->dpp)
2600c1d255d3SCy Schubert return;
2601c1d255d3SCy Schubert if (wpa_s->dpp_auth) {
2602c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2603c1d255d3SCy Schubert "DPP: Not ready for reconfiguration - pending authentication exchange in progress");
2604c1d255d3SCy Schubert return;
2605c1d255d3SCy Schubert }
2606c1d255d3SCy Schubert if (!wpa_s->dpp_reconfig_ssid) {
2607c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2608c1d255d3SCy Schubert "DPP: Not ready for reconfiguration - not requested");
2609c1d255d3SCy Schubert return;
2610c1d255d3SCy Schubert }
2611c1d255d3SCy Schubert for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
2612c1d255d3SCy Schubert if (ssid == wpa_s->dpp_reconfig_ssid &&
2613c1d255d3SCy Schubert ssid->id == wpa_s->dpp_reconfig_ssid_id)
2614c1d255d3SCy Schubert break;
2615c1d255d3SCy Schubert }
2616c1d255d3SCy Schubert if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
2617c1d255d3SCy Schubert !ssid->dpp_csign) {
2618c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2619c1d255d3SCy Schubert "DPP: Not ready for reconfiguration - no matching network profile with Connector found");
2620c1d255d3SCy Schubert return;
2621c1d255d3SCy Schubert }
2622c1d255d3SCy Schubert
2623c1d255d3SCy Schubert auth = dpp_reconfig_auth_req_rx(wpa_s->dpp, wpa_s, ssid->dpp_connector,
2624c1d255d3SCy Schubert ssid->dpp_netaccesskey,
2625c1d255d3SCy Schubert ssid->dpp_netaccesskey_len,
2626c1d255d3SCy Schubert ssid->dpp_csign, ssid->dpp_csign_len,
2627c1d255d3SCy Schubert freq, hdr, buf, len);
2628c1d255d3SCy Schubert if (!auth)
2629c1d255d3SCy Schubert return;
2630c1d255d3SCy Schubert os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
2631c1d255d3SCy Schubert wpa_s->dpp_auth = auth;
2632c1d255d3SCy Schubert
2633c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
2634c1d255d3SCy Schubert
2635c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
2636c1d255d3SCy Schubert MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_RESP);
2637c1d255d3SCy Schubert if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
2638c1d255d3SCy Schubert wpabuf_head(auth->reconfig_resp_msg),
2639c1d255d3SCy Schubert wpabuf_len(auth->reconfig_resp_msg),
2640c1d255d3SCy Schubert 500, wpas_dpp_tx_status, 0) < 0) {
2641c1d255d3SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
2642c1d255d3SCy Schubert wpa_s->dpp_auth = NULL;
2643c1d255d3SCy Schubert }
2644c1d255d3SCy Schubert }
2645c1d255d3SCy Schubert
2646c1d255d3SCy Schubert
2647c1d255d3SCy Schubert static void
wpas_dpp_rx_reconfig_auth_resp(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq)2648c1d255d3SCy Schubert wpas_dpp_rx_reconfig_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
2649c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, size_t len,
2650c1d255d3SCy Schubert unsigned int freq)
2651c1d255d3SCy Schubert {
2652c1d255d3SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
2653c1d255d3SCy Schubert struct wpabuf *conf;
2654c1d255d3SCy Schubert
2655c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Response from "
2656c1d255d3SCy Schubert MACSTR, MAC2STR(src));
2657c1d255d3SCy Schubert
2658c1d255d3SCy Schubert if (!auth || !auth->reconfig || !auth->configurator) {
2659c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2660c1d255d3SCy Schubert "DPP: No DPP Reconfig Authentication in progress - drop");
2661c1d255d3SCy Schubert return;
2662c1d255d3SCy Schubert }
2663c1d255d3SCy Schubert
2664*a90b9d01SCy Schubert if (!ether_addr_equal(src, auth->peer_mac_addr)) {
2665c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
2666c1d255d3SCy Schubert MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
2667c1d255d3SCy Schubert return;
2668c1d255d3SCy Schubert }
2669c1d255d3SCy Schubert
2670c1d255d3SCy Schubert conf = dpp_reconfig_auth_resp_rx(auth, hdr, buf, len);
2671c1d255d3SCy Schubert if (!conf)
2672c1d255d3SCy Schubert return;
2673c1d255d3SCy Schubert
2674c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout, wpa_s, NULL);
2675c1d255d3SCy Schubert
2676c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
2677c1d255d3SCy Schubert MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_CONF);
2678c1d255d3SCy Schubert if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
2679c1d255d3SCy Schubert wpabuf_head(conf), wpabuf_len(conf),
2680c1d255d3SCy Schubert 500, wpas_dpp_tx_status, 0) < 0) {
2681c1d255d3SCy Schubert wpabuf_free(conf);
2682c1d255d3SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
2683c1d255d3SCy Schubert wpa_s->dpp_auth = NULL;
2684c1d255d3SCy Schubert return;
2685c1d255d3SCy Schubert }
2686c1d255d3SCy Schubert wpabuf_free(conf);
2687c1d255d3SCy Schubert
2688c1d255d3SCy Schubert wpas_dpp_start_gas_server(wpa_s);
2689c1d255d3SCy Schubert }
2690c1d255d3SCy Schubert
2691c1d255d3SCy Schubert
2692c1d255d3SCy Schubert static void
wpas_dpp_rx_reconfig_auth_conf(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq)2693c1d255d3SCy Schubert wpas_dpp_rx_reconfig_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
2694c1d255d3SCy Schubert const u8 *hdr, const u8 *buf, size_t len,
2695c1d255d3SCy Schubert unsigned int freq)
2696c1d255d3SCy Schubert {
2697c1d255d3SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
2698c1d255d3SCy Schubert
2699c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Confirm from "
2700c1d255d3SCy Schubert MACSTR, MAC2STR(src));
2701c1d255d3SCy Schubert
2702c1d255d3SCy Schubert if (!auth || !auth->reconfig || auth->configurator) {
2703c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2704c1d255d3SCy Schubert "DPP: No DPP Reconfig Authentication in progress - drop");
2705c1d255d3SCy Schubert return;
2706c1d255d3SCy Schubert }
2707c1d255d3SCy Schubert
2708*a90b9d01SCy Schubert if (!ether_addr_equal(src, auth->peer_mac_addr)) {
2709c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
2710c1d255d3SCy Schubert MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
2711c1d255d3SCy Schubert return;
2712c1d255d3SCy Schubert }
2713c1d255d3SCy Schubert
2714c1d255d3SCy Schubert if (dpp_reconfig_auth_conf_rx(auth, hdr, buf, len) < 0)
2715c1d255d3SCy Schubert return;
2716c1d255d3SCy Schubert
2717c1d255d3SCy Schubert wpas_dpp_start_gas_client(wpa_s);
2718206b73d0SCy Schubert }
2719206b73d0SCy Schubert
27204bc52338SCy Schubert #endif /* CONFIG_DPP2 */
27214bc52338SCy Schubert
27224bc52338SCy Schubert
wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * buf,size_t len)272385732ac8SCy Schubert static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
272485732ac8SCy Schubert const u8 *src,
272585732ac8SCy Schubert const u8 *buf, size_t len)
272685732ac8SCy Schubert {
272785732ac8SCy Schubert struct wpa_ssid *ssid;
272885732ac8SCy Schubert const u8 *connector, *trans_id, *status;
272985732ac8SCy Schubert u16 connector_len, trans_id_len, status_len;
2730c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2731c1d255d3SCy Schubert const u8 *version;
2732c1d255d3SCy Schubert u16 version_len;
2733c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
2734c1d255d3SCy Schubert u8 peer_version = 1;
273585732ac8SCy Schubert struct dpp_introduction intro;
273685732ac8SCy Schubert struct rsn_pmksa_cache_entry *entry;
273785732ac8SCy Schubert struct os_time now;
273885732ac8SCy Schubert struct os_reltime rnow;
273985732ac8SCy Schubert os_time_t expiry;
274085732ac8SCy Schubert unsigned int seconds;
274185732ac8SCy Schubert enum dpp_status_error res;
274285732ac8SCy Schubert
274385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Response from " MACSTR,
274485732ac8SCy Schubert MAC2STR(src));
274585732ac8SCy Schubert if (is_zero_ether_addr(wpa_s->dpp_intro_bssid) ||
2746*a90b9d01SCy Schubert !ether_addr_equal(src, wpa_s->dpp_intro_bssid)) {
274785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Not waiting for response from "
274885732ac8SCy Schubert MACSTR " - drop", MAC2STR(src));
274985732ac8SCy Schubert return;
275085732ac8SCy Schubert }
275185732ac8SCy Schubert offchannel_send_action_done(wpa_s);
275285732ac8SCy Schubert
275385732ac8SCy Schubert for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
275485732ac8SCy Schubert if (ssid == wpa_s->dpp_intro_network)
275585732ac8SCy Schubert break;
275685732ac8SCy Schubert }
275785732ac8SCy Schubert if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
275885732ac8SCy Schubert !ssid->dpp_csign) {
275985732ac8SCy Schubert wpa_printf(MSG_DEBUG,
276085732ac8SCy Schubert "DPP: Profile not found for network introduction");
276185732ac8SCy Schubert return;
276285732ac8SCy Schubert }
276385732ac8SCy Schubert
2764*a90b9d01SCy Schubert os_memset(&intro, 0, sizeof(intro));
2765*a90b9d01SCy Schubert
276685732ac8SCy Schubert trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
276785732ac8SCy Schubert &trans_id_len);
276885732ac8SCy Schubert if (!trans_id || trans_id_len != 1) {
276985732ac8SCy Schubert wpa_printf(MSG_DEBUG,
277085732ac8SCy Schubert "DPP: Peer did not include Transaction ID");
277185732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
277285732ac8SCy Schubert " fail=missing_transaction_id", MAC2STR(src));
277385732ac8SCy Schubert goto fail;
277485732ac8SCy Schubert }
277585732ac8SCy Schubert if (trans_id[0] != TRANSACTION_ID) {
277685732ac8SCy Schubert wpa_printf(MSG_DEBUG,
277785732ac8SCy Schubert "DPP: Ignore frame with unexpected Transaction ID %u",
277885732ac8SCy Schubert trans_id[0]);
277985732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
278085732ac8SCy Schubert " fail=transaction_id_mismatch", MAC2STR(src));
278185732ac8SCy Schubert goto fail;
278285732ac8SCy Schubert }
278385732ac8SCy Schubert
278485732ac8SCy Schubert status = dpp_get_attr(buf, len, DPP_ATTR_STATUS, &status_len);
278585732ac8SCy Schubert if (!status || status_len != 1) {
278685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer did not include Status");
278785732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
278885732ac8SCy Schubert " fail=missing_status", MAC2STR(src));
278985732ac8SCy Schubert goto fail;
279085732ac8SCy Schubert }
279185732ac8SCy Schubert if (status[0] != DPP_STATUS_OK) {
279285732ac8SCy Schubert wpa_printf(MSG_DEBUG,
279385732ac8SCy Schubert "DPP: Peer rejected network introduction: Status %u",
279485732ac8SCy Schubert status[0]);
279585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
279685732ac8SCy Schubert " status=%u", MAC2STR(src), status[0]);
2797c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2798c1d255d3SCy Schubert wpas_dpp_send_conn_status_result(wpa_s, status[0]);
2799c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
280085732ac8SCy Schubert goto fail;
280185732ac8SCy Schubert }
280285732ac8SCy Schubert
280385732ac8SCy Schubert connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len);
280485732ac8SCy Schubert if (!connector) {
280585732ac8SCy Schubert wpa_printf(MSG_DEBUG,
280685732ac8SCy Schubert "DPP: Peer did not include its Connector");
280785732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
280885732ac8SCy Schubert " fail=missing_connector", MAC2STR(src));
280985732ac8SCy Schubert goto fail;
281085732ac8SCy Schubert }
281185732ac8SCy Schubert
281285732ac8SCy Schubert res = dpp_peer_intro(&intro, ssid->dpp_connector,
281385732ac8SCy Schubert ssid->dpp_netaccesskey,
281485732ac8SCy Schubert ssid->dpp_netaccesskey_len,
281585732ac8SCy Schubert ssid->dpp_csign,
281685732ac8SCy Schubert ssid->dpp_csign_len,
2817*a90b9d01SCy Schubert connector, connector_len, &expiry, NULL);
281885732ac8SCy Schubert if (res != DPP_STATUS_OK) {
281985732ac8SCy Schubert wpa_printf(MSG_INFO,
282085732ac8SCy Schubert "DPP: Network Introduction protocol resulted in failure");
282185732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
282285732ac8SCy Schubert " fail=peer_connector_validation_failed", MAC2STR(src));
2823c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2824c1d255d3SCy Schubert wpas_dpp_send_conn_status_result(wpa_s, res);
2825c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
282685732ac8SCy Schubert goto fail;
282785732ac8SCy Schubert }
282885732ac8SCy Schubert
282985732ac8SCy Schubert entry = os_zalloc(sizeof(*entry));
283085732ac8SCy Schubert if (!entry)
283185732ac8SCy Schubert goto fail;
283285732ac8SCy Schubert os_memcpy(entry->aa, src, ETH_ALEN);
2833*a90b9d01SCy Schubert os_memcpy(entry->spa, wpa_s->own_addr, ETH_ALEN);
283485732ac8SCy Schubert os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN);
283585732ac8SCy Schubert os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
283685732ac8SCy Schubert entry->pmk_len = intro.pmk_len;
283785732ac8SCy Schubert entry->akmp = WPA_KEY_MGMT_DPP;
2838c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2839c1d255d3SCy Schubert version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
2840c1d255d3SCy Schubert &version_len);
2841c1d255d3SCy Schubert if (version && version_len >= 1)
2842c1d255d3SCy Schubert peer_version = version[0];
284332a95656SCy Schubert #ifdef CONFIG_DPP3
284432a95656SCy Schubert if (intro.peer_version && intro.peer_version >= 2 &&
284532a95656SCy Schubert peer_version != intro.peer_version) {
284632a95656SCy Schubert wpa_printf(MSG_INFO,
284732a95656SCy Schubert "DPP: Protocol version mismatch (Connector: %d Attribute: %d",
284832a95656SCy Schubert intro.peer_version, peer_version);
284932a95656SCy Schubert wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_NO_MATCH);
285032a95656SCy Schubert goto fail;
285132a95656SCy Schubert }
285232a95656SCy Schubert #endif /* CONFIG_DPP3 */
2853c1d255d3SCy Schubert entry->dpp_pfs = peer_version >= 2;
2854c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
285585732ac8SCy Schubert if (expiry) {
285685732ac8SCy Schubert os_get_time(&now);
285785732ac8SCy Schubert seconds = expiry - now.sec;
285885732ac8SCy Schubert } else {
285985732ac8SCy Schubert seconds = 86400 * 7;
286085732ac8SCy Schubert }
286185732ac8SCy Schubert os_get_reltime(&rnow);
286285732ac8SCy Schubert entry->expiration = rnow.sec + seconds;
286385732ac8SCy Schubert entry->reauth_time = rnow.sec + seconds;
286485732ac8SCy Schubert entry->network_ctx = ssid;
286585732ac8SCy Schubert wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
286685732ac8SCy Schubert
286785732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
2868c1d255d3SCy Schubert " status=%u version=%u", MAC2STR(src), status[0], peer_version);
286985732ac8SCy Schubert
287085732ac8SCy Schubert wpa_printf(MSG_DEBUG,
287185732ac8SCy Schubert "DPP: Try connection again after successful network introduction");
287285732ac8SCy Schubert if (wpa_supplicant_fast_associate(wpa_s) != 1) {
287385732ac8SCy Schubert wpa_supplicant_cancel_sched_scan(wpa_s);
287485732ac8SCy Schubert wpa_supplicant_req_scan(wpa_s, 0, 0);
287585732ac8SCy Schubert }
287685732ac8SCy Schubert fail:
2877*a90b9d01SCy Schubert dpp_peer_intro_deinit(&intro);
287885732ac8SCy Schubert }
287985732ac8SCy Schubert
288085732ac8SCy Schubert
wpas_dpp_allow_ir(struct wpa_supplicant * wpa_s,unsigned int freq)288185732ac8SCy Schubert static int wpas_dpp_allow_ir(struct wpa_supplicant *wpa_s, unsigned int freq)
288285732ac8SCy Schubert {
288385732ac8SCy Schubert int i, j;
288485732ac8SCy Schubert
288585732ac8SCy Schubert if (!wpa_s->hw.modes)
288685732ac8SCy Schubert return -1;
288785732ac8SCy Schubert
288885732ac8SCy Schubert for (i = 0; i < wpa_s->hw.num_modes; i++) {
288985732ac8SCy Schubert struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
289085732ac8SCy Schubert
289185732ac8SCy Schubert for (j = 0; j < mode->num_channels; j++) {
289285732ac8SCy Schubert struct hostapd_channel_data *chan = &mode->channels[j];
289385732ac8SCy Schubert
289485732ac8SCy Schubert if (chan->freq != (int) freq)
289585732ac8SCy Schubert continue;
289685732ac8SCy Schubert
289785732ac8SCy Schubert if (chan->flag & (HOSTAPD_CHAN_DISABLED |
289885732ac8SCy Schubert HOSTAPD_CHAN_NO_IR |
289985732ac8SCy Schubert HOSTAPD_CHAN_RADAR))
290085732ac8SCy Schubert continue;
290185732ac8SCy Schubert
290285732ac8SCy Schubert return 1;
290385732ac8SCy Schubert }
290485732ac8SCy Schubert }
290585732ac8SCy Schubert
290685732ac8SCy Schubert wpa_printf(MSG_DEBUG,
290785732ac8SCy Schubert "DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list",
290885732ac8SCy Schubert freq);
290985732ac8SCy Schubert
291085732ac8SCy Schubert return 0;
291185732ac8SCy Schubert }
291285732ac8SCy Schubert
291385732ac8SCy Schubert
wpas_dpp_pkex_next_channel(struct wpa_supplicant * wpa_s,struct dpp_pkex * pkex)291485732ac8SCy Schubert static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s,
291585732ac8SCy Schubert struct dpp_pkex *pkex)
291685732ac8SCy Schubert {
291785732ac8SCy Schubert if (pkex->freq == 2437)
291885732ac8SCy Schubert pkex->freq = 5745;
291985732ac8SCy Schubert else if (pkex->freq == 5745)
292085732ac8SCy Schubert pkex->freq = 5220;
292185732ac8SCy Schubert else if (pkex->freq == 5220)
292285732ac8SCy Schubert pkex->freq = 60480;
292385732ac8SCy Schubert else
292485732ac8SCy Schubert return -1; /* no more channels to try */
292585732ac8SCy Schubert
292685732ac8SCy Schubert if (wpas_dpp_allow_ir(wpa_s, pkex->freq) == 1) {
292785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz",
292885732ac8SCy Schubert pkex->freq);
292985732ac8SCy Schubert return 0;
293085732ac8SCy Schubert }
293185732ac8SCy Schubert
293285732ac8SCy Schubert /* Could not use this channel - try the next one */
293385732ac8SCy Schubert return wpas_dpp_pkex_next_channel(wpa_s, pkex);
293485732ac8SCy Schubert }
293585732ac8SCy Schubert
293685732ac8SCy Schubert
wpas_dpp_pkex_clear_code(struct wpa_supplicant * wpa_s)2937*a90b9d01SCy Schubert static void wpas_dpp_pkex_clear_code(struct wpa_supplicant *wpa_s)
2938*a90b9d01SCy Schubert {
2939*a90b9d01SCy Schubert if (!wpa_s->dpp_pkex_code && !wpa_s->dpp_pkex_identifier)
2940*a90b9d01SCy Schubert return;
2941*a90b9d01SCy Schubert
2942*a90b9d01SCy Schubert /* Delete PKEX code and identifier on successful completion of
2943*a90b9d01SCy Schubert * PKEX. We are not supposed to reuse these without being
2944*a90b9d01SCy Schubert * explicitly requested to perform PKEX again. */
2945*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Delete PKEX code/identifier");
2946*a90b9d01SCy Schubert os_free(wpa_s->dpp_pkex_code);
2947*a90b9d01SCy Schubert wpa_s->dpp_pkex_code = NULL;
2948*a90b9d01SCy Schubert os_free(wpa_s->dpp_pkex_identifier);
2949*a90b9d01SCy Schubert wpa_s->dpp_pkex_identifier = NULL;
2950*a90b9d01SCy Schubert
2951*a90b9d01SCy Schubert }
2952*a90b9d01SCy Schubert
2953*a90b9d01SCy Schubert
2954*a90b9d01SCy Schubert #ifdef CONFIG_DPP2
wpas_dpp_pkex_done(void * ctx,void * conn,struct dpp_bootstrap_info * peer_bi)2955*a90b9d01SCy Schubert static int wpas_dpp_pkex_done(void *ctx, void *conn,
2956*a90b9d01SCy Schubert struct dpp_bootstrap_info *peer_bi)
2957*a90b9d01SCy Schubert {
2958*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = ctx;
2959*a90b9d01SCy Schubert char cmd[500];
2960*a90b9d01SCy Schubert const char *pos;
2961*a90b9d01SCy Schubert u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
2962*a90b9d01SCy Schubert struct dpp_bootstrap_info *own_bi = NULL;
2963*a90b9d01SCy Schubert struct dpp_authentication *auth;
2964*a90b9d01SCy Schubert
2965*a90b9d01SCy Schubert wpas_dpp_pkex_clear_code(wpa_s);
2966*a90b9d01SCy Schubert
2967*a90b9d01SCy Schubert os_snprintf(cmd, sizeof(cmd), " peer=%u %s", peer_bi->id,
2968*a90b9d01SCy Schubert wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : "");
2969*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Start authentication after PKEX (cmd: %s)",
2970*a90b9d01SCy Schubert cmd);
2971*a90b9d01SCy Schubert
2972*a90b9d01SCy Schubert pos = os_strstr(cmd, " own=");
2973*a90b9d01SCy Schubert if (pos) {
2974*a90b9d01SCy Schubert pos += 5;
2975*a90b9d01SCy Schubert own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
2976*a90b9d01SCy Schubert if (!own_bi) {
2977*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
2978*a90b9d01SCy Schubert "DPP: Could not find bootstrapping info for the identified local entry");
2979*a90b9d01SCy Schubert return -1;
2980*a90b9d01SCy Schubert }
2981*a90b9d01SCy Schubert
2982*a90b9d01SCy Schubert if (peer_bi->curve != own_bi->curve) {
2983*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
2984*a90b9d01SCy Schubert "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
2985*a90b9d01SCy Schubert peer_bi->curve->name, own_bi->curve->name);
2986*a90b9d01SCy Schubert return -1;
2987*a90b9d01SCy Schubert }
2988*a90b9d01SCy Schubert }
2989*a90b9d01SCy Schubert
2990*a90b9d01SCy Schubert pos = os_strstr(cmd, " role=");
2991*a90b9d01SCy Schubert if (pos) {
2992*a90b9d01SCy Schubert pos += 6;
2993*a90b9d01SCy Schubert if (os_strncmp(pos, "configurator", 12) == 0)
2994*a90b9d01SCy Schubert allowed_roles = DPP_CAPAB_CONFIGURATOR;
2995*a90b9d01SCy Schubert else if (os_strncmp(pos, "enrollee", 8) == 0)
2996*a90b9d01SCy Schubert allowed_roles = DPP_CAPAB_ENROLLEE;
2997*a90b9d01SCy Schubert else if (os_strncmp(pos, "either", 6) == 0)
2998*a90b9d01SCy Schubert allowed_roles = DPP_CAPAB_CONFIGURATOR |
2999*a90b9d01SCy Schubert DPP_CAPAB_ENROLLEE;
3000*a90b9d01SCy Schubert else
3001*a90b9d01SCy Schubert return -1;
3002*a90b9d01SCy Schubert }
3003*a90b9d01SCy Schubert
3004*a90b9d01SCy Schubert auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, own_bi, allowed_roles,
3005*a90b9d01SCy Schubert 0, wpa_s->hw.modes, wpa_s->hw.num_modes);
3006*a90b9d01SCy Schubert if (!auth)
3007*a90b9d01SCy Schubert return -1;
3008*a90b9d01SCy Schubert
3009*a90b9d01SCy Schubert wpas_dpp_set_testing_options(wpa_s, auth);
3010*a90b9d01SCy Schubert if (dpp_set_configurator(auth, cmd) < 0) {
3011*a90b9d01SCy Schubert dpp_auth_deinit(auth);
3012*a90b9d01SCy Schubert return -1;
3013*a90b9d01SCy Schubert }
3014*a90b9d01SCy Schubert
3015*a90b9d01SCy Schubert return dpp_tcp_auth(wpa_s->dpp, conn, auth, wpa_s->conf->dpp_name,
3016*a90b9d01SCy Schubert DPP_NETROLE_STA,
3017*a90b9d01SCy Schubert wpa_s->conf->dpp_mud_url,
3018*a90b9d01SCy Schubert wpa_s->conf->dpp_extra_conf_req_name,
3019*a90b9d01SCy Schubert wpa_s->conf->dpp_extra_conf_req_value,
3020*a90b9d01SCy Schubert wpas_dpp_process_conf_obj,
3021*a90b9d01SCy Schubert wpas_dpp_tcp_msg_sent);
3022*a90b9d01SCy Schubert }
3023*a90b9d01SCy Schubert #endif /* CONFIG_DPP2 */
3024*a90b9d01SCy Schubert
3025*a90b9d01SCy Schubert
wpas_dpp_pkex_init(struct wpa_supplicant * wpa_s,enum dpp_pkex_ver ver,const struct hostapd_ip_addr * ipaddr,int tcp_port)3026*a90b9d01SCy Schubert static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s,
3027*a90b9d01SCy Schubert enum dpp_pkex_ver ver,
3028*a90b9d01SCy Schubert const struct hostapd_ip_addr *ipaddr,
3029*a90b9d01SCy Schubert int tcp_port)
3030*a90b9d01SCy Schubert {
3031*a90b9d01SCy Schubert struct dpp_pkex *pkex;
3032*a90b9d01SCy Schubert struct wpabuf *msg;
3033*a90b9d01SCy Schubert unsigned int wait_time;
3034*a90b9d01SCy Schubert bool v2 = ver != PKEX_VER_ONLY_1;
3035*a90b9d01SCy Schubert
3036*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1);
3037*a90b9d01SCy Schubert dpp_pkex_free(wpa_s->dpp_pkex);
3038*a90b9d01SCy Schubert wpa_s->dpp_pkex = NULL;
3039*a90b9d01SCy Schubert pkex = dpp_pkex_init(wpa_s, wpa_s->dpp_pkex_bi, wpa_s->own_addr,
3040*a90b9d01SCy Schubert wpa_s->dpp_pkex_identifier,
3041*a90b9d01SCy Schubert wpa_s->dpp_pkex_code, wpa_s->dpp_pkex_code_len,
3042*a90b9d01SCy Schubert v2);
3043*a90b9d01SCy Schubert if (!pkex)
3044*a90b9d01SCy Schubert return -1;
3045*a90b9d01SCy Schubert pkex->forced_ver = ver != PKEX_VER_AUTO;
3046*a90b9d01SCy Schubert
3047*a90b9d01SCy Schubert if (ipaddr) {
3048*a90b9d01SCy Schubert #ifdef CONFIG_DPP2
3049*a90b9d01SCy Schubert return dpp_tcp_pkex_init(wpa_s->dpp, pkex, ipaddr, tcp_port,
3050*a90b9d01SCy Schubert wpa_s, wpa_s, wpas_dpp_pkex_done);
3051*a90b9d01SCy Schubert #else /* CONFIG_DPP2 */
3052*a90b9d01SCy Schubert return -1;
3053*a90b9d01SCy Schubert #endif /* CONFIG_DPP2 */
3054*a90b9d01SCy Schubert }
3055*a90b9d01SCy Schubert
3056*a90b9d01SCy Schubert wpa_s->dpp_pkex = pkex;
3057*a90b9d01SCy Schubert msg = pkex->exchange_req;
3058*a90b9d01SCy Schubert wait_time = wpa_s->max_remain_on_chan;
3059*a90b9d01SCy Schubert if (wait_time > 2000)
3060*a90b9d01SCy Schubert wait_time = 2000;
3061*a90b9d01SCy Schubert pkex->freq = 2437;
3062*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
3063*a90b9d01SCy Schubert " freq=%u type=%d",
3064*a90b9d01SCy Schubert MAC2STR(broadcast), pkex->freq,
3065*a90b9d01SCy Schubert v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
3066*a90b9d01SCy Schubert DPP_PA_PKEX_V1_EXCHANGE_REQ);
3067*a90b9d01SCy Schubert offchannel_send_action(wpa_s, pkex->freq, broadcast,
3068*a90b9d01SCy Schubert wpa_s->own_addr, broadcast,
3069*a90b9d01SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
3070*a90b9d01SCy Schubert wait_time, wpas_dpp_tx_pkex_status, 0);
3071*a90b9d01SCy Schubert if (wait_time == 0)
3072*a90b9d01SCy Schubert wait_time = 2000;
3073*a90b9d01SCy Schubert pkex->exch_req_wait_time = wait_time;
3074*a90b9d01SCy Schubert pkex->exch_req_tries = 1;
3075*a90b9d01SCy Schubert
3076*a90b9d01SCy Schubert return 0;
3077*a90b9d01SCy Schubert }
3078*a90b9d01SCy Schubert
3079*a90b9d01SCy Schubert
wpas_dpp_pkex_retry_timeout(void * eloop_ctx,void * timeout_ctx)308085732ac8SCy Schubert static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
308185732ac8SCy Schubert {
308285732ac8SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
308385732ac8SCy Schubert struct dpp_pkex *pkex = wpa_s->dpp_pkex;
308485732ac8SCy Schubert
308585732ac8SCy Schubert if (!pkex || !pkex->exchange_req)
308685732ac8SCy Schubert return;
308785732ac8SCy Schubert if (pkex->exch_req_tries >= 5) {
308885732ac8SCy Schubert if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) {
3089*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
3090*a90b9d01SCy Schubert if (pkex->v2 && !pkex->forced_ver) {
3091*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3092*a90b9d01SCy Schubert "DPP: Fall back to PKEXv1");
3093*a90b9d01SCy Schubert wpas_dpp_pkex_init(wpa_s, PKEX_VER_ONLY_1,
3094*a90b9d01SCy Schubert NULL, 0);
3095*a90b9d01SCy Schubert return;
3096*a90b9d01SCy Schubert }
3097*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
309885732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
309985732ac8SCy Schubert "No response from PKEX peer");
310085732ac8SCy Schubert dpp_pkex_free(pkex);
310185732ac8SCy Schubert wpa_s->dpp_pkex = NULL;
310285732ac8SCy Schubert return;
310385732ac8SCy Schubert }
310485732ac8SCy Schubert pkex->exch_req_tries = 0;
310585732ac8SCy Schubert }
310685732ac8SCy Schubert
310785732ac8SCy Schubert pkex->exch_req_tries++;
310885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)",
310985732ac8SCy Schubert pkex->exch_req_tries);
311085732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
311132a95656SCy Schubert MAC2STR(broadcast), pkex->freq,
311232a95656SCy Schubert pkex->v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
311332a95656SCy Schubert DPP_PA_PKEX_V1_EXCHANGE_REQ);
311485732ac8SCy Schubert offchannel_send_action(wpa_s, pkex->freq, broadcast,
311585732ac8SCy Schubert wpa_s->own_addr, broadcast,
311685732ac8SCy Schubert wpabuf_head(pkex->exchange_req),
311785732ac8SCy Schubert wpabuf_len(pkex->exchange_req),
311885732ac8SCy Schubert pkex->exch_req_wait_time,
311985732ac8SCy Schubert wpas_dpp_tx_pkex_status, 0);
312085732ac8SCy Schubert }
312185732ac8SCy Schubert
312285732ac8SCy Schubert
312385732ac8SCy Schubert 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)312485732ac8SCy Schubert wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
312585732ac8SCy Schubert unsigned int freq, const u8 *dst,
312685732ac8SCy Schubert const u8 *src, const u8 *bssid,
312785732ac8SCy Schubert const u8 *data, size_t data_len,
312885732ac8SCy Schubert enum offchannel_send_action_result result)
312985732ac8SCy Schubert {
313085732ac8SCy Schubert const char *res_txt;
313185732ac8SCy Schubert struct dpp_pkex *pkex = wpa_s->dpp_pkex;
313285732ac8SCy Schubert
313385732ac8SCy Schubert res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
313485732ac8SCy Schubert (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
313585732ac8SCy Schubert "FAILED");
313685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
313785732ac8SCy Schubert " result=%s (PKEX)",
313885732ac8SCy Schubert freq, MAC2STR(dst), res_txt);
313985732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
314085732ac8SCy Schubert " freq=%u result=%s", MAC2STR(dst), freq, res_txt);
314185732ac8SCy Schubert
314285732ac8SCy Schubert if (!pkex) {
314385732ac8SCy Schubert wpa_printf(MSG_DEBUG,
314485732ac8SCy Schubert "DPP: Ignore TX status since there is no ongoing PKEX exchange");
314585732ac8SCy Schubert return;
314685732ac8SCy Schubert }
314785732ac8SCy Schubert
314885732ac8SCy Schubert if (pkex->failed) {
314985732ac8SCy Schubert wpa_printf(MSG_DEBUG,
315085732ac8SCy Schubert "DPP: Terminate PKEX exchange due to an earlier error");
315185732ac8SCy Schubert if (pkex->t > pkex->own_bi->pkex_t)
315285732ac8SCy Schubert pkex->own_bi->pkex_t = pkex->t;
315385732ac8SCy Schubert dpp_pkex_free(pkex);
315485732ac8SCy Schubert wpa_s->dpp_pkex = NULL;
315585732ac8SCy Schubert return;
315685732ac8SCy Schubert }
315785732ac8SCy Schubert
315885732ac8SCy Schubert if (pkex->exch_req_wait_time && pkex->exchange_req) {
315985732ac8SCy Schubert /* Wait for PKEX Exchange Response frame and retry request if
316085732ac8SCy Schubert * no response is seen. */
316185732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
316285732ac8SCy Schubert eloop_register_timeout(pkex->exch_req_wait_time / 1000,
316385732ac8SCy Schubert (pkex->exch_req_wait_time % 1000) * 1000,
316485732ac8SCy Schubert wpas_dpp_pkex_retry_timeout, wpa_s,
316585732ac8SCy Schubert NULL);
316685732ac8SCy Schubert }
316785732ac8SCy Schubert }
316885732ac8SCy Schubert
316985732ac8SCy Schubert
317085732ac8SCy Schubert 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,bool v2)317185732ac8SCy Schubert wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src,
317232a95656SCy Schubert const u8 *buf, size_t len, unsigned int freq,
317332a95656SCy Schubert bool v2)
317485732ac8SCy Schubert {
317585732ac8SCy Schubert struct wpabuf *msg;
317685732ac8SCy Schubert unsigned int wait_time;
317785732ac8SCy Schubert
317885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR,
317985732ac8SCy Schubert MAC2STR(src));
318085732ac8SCy Schubert
3181*a90b9d01SCy Schubert if (wpa_s->dpp_pkex_ver == PKEX_VER_ONLY_1 && v2) {
3182*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3183*a90b9d01SCy Schubert "DPP: Ignore PKEXv2 Exchange Request when configured to be PKEX v1 only");
3184*a90b9d01SCy Schubert return;
3185*a90b9d01SCy Schubert }
3186*a90b9d01SCy Schubert if (wpa_s->dpp_pkex_ver == PKEX_VER_ONLY_2 && !v2) {
3187*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3188*a90b9d01SCy Schubert "DPP: Ignore PKEXv1 Exchange Request when configured to be PKEX v2 only");
3189*a90b9d01SCy Schubert return;
3190*a90b9d01SCy Schubert }
3191*a90b9d01SCy Schubert
319285732ac8SCy Schubert /* TODO: Support multiple PKEX codes by iterating over all the enabled
319385732ac8SCy Schubert * values here */
319485732ac8SCy Schubert
319585732ac8SCy Schubert if (!wpa_s->dpp_pkex_code || !wpa_s->dpp_pkex_bi) {
319685732ac8SCy Schubert wpa_printf(MSG_DEBUG,
319785732ac8SCy Schubert "DPP: No PKEX code configured - ignore request");
319885732ac8SCy Schubert return;
319985732ac8SCy Schubert }
320085732ac8SCy Schubert
3201*a90b9d01SCy Schubert #ifdef CONFIG_DPP2
3202*a90b9d01SCy Schubert if (dpp_controller_is_own_pkex_req(wpa_s->dpp, buf, len)) {
3203*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3204*a90b9d01SCy Schubert "DPP: PKEX Exchange Request is from local Controller - ignore request");
3205*a90b9d01SCy Schubert return;
3206*a90b9d01SCy Schubert }
3207*a90b9d01SCy Schubert #endif /* CONFIG_DPP2 */
3208*a90b9d01SCy Schubert
320985732ac8SCy Schubert if (wpa_s->dpp_pkex) {
321085732ac8SCy Schubert /* TODO: Support parallel operations */
321185732ac8SCy Schubert wpa_printf(MSG_DEBUG,
321285732ac8SCy Schubert "DPP: Already in PKEX session - ignore new request");
321385732ac8SCy Schubert return;
321485732ac8SCy Schubert }
321585732ac8SCy Schubert
321685732ac8SCy Schubert wpa_s->dpp_pkex = dpp_pkex_rx_exchange_req(wpa_s, wpa_s->dpp_pkex_bi,
321785732ac8SCy Schubert wpa_s->own_addr, src,
321885732ac8SCy Schubert wpa_s->dpp_pkex_identifier,
321985732ac8SCy Schubert wpa_s->dpp_pkex_code,
3220*a90b9d01SCy Schubert wpa_s->dpp_pkex_code_len,
322132a95656SCy Schubert buf, len, v2);
322285732ac8SCy Schubert if (!wpa_s->dpp_pkex) {
322385732ac8SCy Schubert wpa_printf(MSG_DEBUG,
322485732ac8SCy Schubert "DPP: Failed to process the request - ignore it");
322585732ac8SCy Schubert return;
322685732ac8SCy Schubert }
322785732ac8SCy Schubert
3228*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
3229*a90b9d01SCy Schubert if (wpa_s->dpp_pb_bi && wpa_s->dpp_pb_announcement) {
3230*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3231*a90b9d01SCy Schubert "DPP: Started PB PKEX (no more PB announcements)");
3232*a90b9d01SCy Schubert wpabuf_free(wpa_s->dpp_pb_announcement);
3233*a90b9d01SCy Schubert wpa_s->dpp_pb_announcement = NULL;
3234*a90b9d01SCy Schubert }
3235*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
3236*a90b9d01SCy Schubert wpa_s->dpp_pkex_wait_auth_req = false;
323785732ac8SCy Schubert msg = wpa_s->dpp_pkex->exchange_resp;
323885732ac8SCy Schubert wait_time = wpa_s->max_remain_on_chan;
323985732ac8SCy Schubert if (wait_time > 2000)
324085732ac8SCy Schubert wait_time = 2000;
324185732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
324285732ac8SCy Schubert MAC2STR(src), freq, DPP_PA_PKEX_EXCHANGE_RESP);
324385732ac8SCy Schubert offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
324485732ac8SCy Schubert broadcast,
324585732ac8SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
324685732ac8SCy Schubert wait_time, wpas_dpp_tx_pkex_status, 0);
324785732ac8SCy Schubert }
324885732ac8SCy Schubert
324985732ac8SCy Schubert
325085732ac8SCy Schubert 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)325185732ac8SCy Schubert wpas_dpp_rx_pkex_exchange_resp(struct wpa_supplicant *wpa_s, const u8 *src,
325285732ac8SCy Schubert const u8 *buf, size_t len, unsigned int freq)
325385732ac8SCy Schubert {
325485732ac8SCy Schubert struct wpabuf *msg;
325585732ac8SCy Schubert unsigned int wait_time;
325685732ac8SCy Schubert
325785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR,
325885732ac8SCy Schubert MAC2STR(src));
325985732ac8SCy Schubert
326085732ac8SCy Schubert /* TODO: Support multiple PKEX codes by iterating over all the enabled
326185732ac8SCy Schubert * values here */
326285732ac8SCy Schubert
326385732ac8SCy Schubert if (!wpa_s->dpp_pkex || !wpa_s->dpp_pkex->initiator ||
326485732ac8SCy Schubert wpa_s->dpp_pkex->exchange_done) {
326585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
326685732ac8SCy Schubert return;
326785732ac8SCy Schubert }
326885732ac8SCy Schubert
326985732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
327085732ac8SCy Schubert wpa_s->dpp_pkex->exch_req_wait_time = 0;
327185732ac8SCy Schubert
327285732ac8SCy Schubert msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, src, buf, len);
327385732ac8SCy Schubert if (!msg) {
327485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
327585732ac8SCy Schubert return;
327685732ac8SCy Schubert }
327785732ac8SCy Schubert
327885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR,
327985732ac8SCy Schubert MAC2STR(src));
328085732ac8SCy Schubert
328185732ac8SCy Schubert wait_time = wpa_s->max_remain_on_chan;
328285732ac8SCy Schubert if (wait_time > 2000)
328385732ac8SCy Schubert wait_time = 2000;
328485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
328585732ac8SCy Schubert MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_REQ);
328685732ac8SCy Schubert offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
328785732ac8SCy Schubert broadcast,
328885732ac8SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
328985732ac8SCy Schubert wait_time, wpas_dpp_tx_pkex_status, 0);
329085732ac8SCy Schubert wpabuf_free(msg);
329185732ac8SCy Schubert }
329285732ac8SCy Schubert
329385732ac8SCy Schubert
329485732ac8SCy Schubert static struct dpp_bootstrap_info *
wpas_dpp_pkex_finish(struct wpa_supplicant * wpa_s,const u8 * peer,unsigned int freq)329585732ac8SCy Schubert wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer,
329685732ac8SCy Schubert unsigned int freq)
329785732ac8SCy Schubert {
329885732ac8SCy Schubert struct dpp_bootstrap_info *bi;
329985732ac8SCy Schubert
3300*a90b9d01SCy Schubert wpas_dpp_pkex_clear_code(wpa_s);
33014bc52338SCy Schubert bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq);
330285732ac8SCy Schubert if (!bi)
330385732ac8SCy Schubert return NULL;
3304*a90b9d01SCy Schubert
330585732ac8SCy Schubert wpa_s->dpp_pkex = NULL;
3306*a90b9d01SCy Schubert
3307*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
3308*a90b9d01SCy Schubert if (wpa_s->dpp_pb_bi && !wpa_s->dpp_pb_configurator &&
3309*a90b9d01SCy Schubert os_memcmp(bi->pubkey_hash_chirp, wpa_s->dpp_pb_init_hash,
3310*a90b9d01SCy Schubert SHA256_MAC_LEN) != 0) {
3311*a90b9d01SCy Schubert char id[20];
3312*a90b9d01SCy Schubert
3313*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3314*a90b9d01SCy Schubert "DPP: Peer bootstrap key from PKEX does not match PB announcement response hash");
3315*a90b9d01SCy Schubert wpa_hexdump(MSG_DEBUG,
3316*a90b9d01SCy Schubert "DPP: Peer provided bootstrap key hash(chirp) from PB PKEX",
3317*a90b9d01SCy Schubert bi->pubkey_hash_chirp, SHA256_MAC_LEN);
3318*a90b9d01SCy Schubert wpa_hexdump(MSG_DEBUG,
3319*a90b9d01SCy Schubert "DPP: Peer provided bootstrap key hash(chirp) from PB announcement response",
3320*a90b9d01SCy Schubert wpa_s->dpp_pb_init_hash, SHA256_MAC_LEN);
3321*a90b9d01SCy Schubert
3322*a90b9d01SCy Schubert os_snprintf(id, sizeof(id), "%u", bi->id);
3323*a90b9d01SCy Schubert dpp_bootstrap_remove(wpa_s->dpp, id);
3324*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
3325*a90b9d01SCy Schubert return NULL;
3326*a90b9d01SCy Schubert }
3327*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
3328*a90b9d01SCy Schubert
332985732ac8SCy Schubert return bi;
333085732ac8SCy Schubert }
333185732ac8SCy Schubert
333285732ac8SCy Schubert
333385732ac8SCy Schubert 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)333485732ac8SCy Schubert wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src,
333585732ac8SCy Schubert const u8 *hdr, const u8 *buf, size_t len,
333685732ac8SCy Schubert unsigned int freq)
333785732ac8SCy Schubert {
333885732ac8SCy Schubert struct wpabuf *msg;
333985732ac8SCy Schubert unsigned int wait_time;
334085732ac8SCy Schubert struct dpp_pkex *pkex = wpa_s->dpp_pkex;
334185732ac8SCy Schubert
334285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR,
334385732ac8SCy Schubert MAC2STR(src));
334485732ac8SCy Schubert
334585732ac8SCy Schubert if (!pkex || pkex->initiator || !pkex->exchange_done) {
334685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
334785732ac8SCy Schubert return;
334885732ac8SCy Schubert }
334985732ac8SCy Schubert
335085732ac8SCy Schubert msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
335185732ac8SCy Schubert if (!msg) {
335285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
335385732ac8SCy Schubert if (pkex->failed) {
335485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
335585732ac8SCy Schubert if (pkex->t > pkex->own_bi->pkex_t)
335685732ac8SCy Schubert pkex->own_bi->pkex_t = pkex->t;
335785732ac8SCy Schubert dpp_pkex_free(wpa_s->dpp_pkex);
335885732ac8SCy Schubert wpa_s->dpp_pkex = NULL;
335985732ac8SCy Schubert }
336085732ac8SCy Schubert return;
336185732ac8SCy Schubert }
336285732ac8SCy Schubert
336385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to "
336485732ac8SCy Schubert MACSTR, MAC2STR(src));
336585732ac8SCy Schubert
336685732ac8SCy Schubert wait_time = wpa_s->max_remain_on_chan;
336785732ac8SCy Schubert if (wait_time > 2000)
336885732ac8SCy Schubert wait_time = 2000;
336985732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
337085732ac8SCy Schubert MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_RESP);
337185732ac8SCy Schubert offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
337285732ac8SCy Schubert broadcast,
337385732ac8SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
337485732ac8SCy Schubert wait_time, wpas_dpp_tx_pkex_status, 0);
337585732ac8SCy Schubert wpabuf_free(msg);
337685732ac8SCy Schubert
337785732ac8SCy Schubert wpas_dpp_pkex_finish(wpa_s, src, freq);
3378*a90b9d01SCy Schubert wpa_s->dpp_pkex_wait_auth_req = true;
337985732ac8SCy Schubert }
338085732ac8SCy Schubert
338185732ac8SCy Schubert
338285732ac8SCy Schubert 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)338385732ac8SCy Schubert wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant *wpa_s, const u8 *src,
338485732ac8SCy Schubert const u8 *hdr, const u8 *buf, size_t len,
338585732ac8SCy Schubert unsigned int freq)
338685732ac8SCy Schubert {
338785732ac8SCy Schubert int res;
338885732ac8SCy Schubert struct dpp_bootstrap_info *bi;
338985732ac8SCy Schubert struct dpp_pkex *pkex = wpa_s->dpp_pkex;
339085732ac8SCy Schubert char cmd[500];
339185732ac8SCy Schubert
339285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR,
339385732ac8SCy Schubert MAC2STR(src));
339485732ac8SCy Schubert
339585732ac8SCy Schubert if (!pkex || !pkex->initiator || !pkex->exchange_done) {
339685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
339785732ac8SCy Schubert return;
339885732ac8SCy Schubert }
339985732ac8SCy Schubert
340085732ac8SCy Schubert res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len);
340185732ac8SCy Schubert if (res < 0) {
340285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
340385732ac8SCy Schubert return;
340485732ac8SCy Schubert }
340585732ac8SCy Schubert
340685732ac8SCy Schubert bi = wpas_dpp_pkex_finish(wpa_s, src, freq);
340785732ac8SCy Schubert if (!bi)
340885732ac8SCy Schubert return;
340985732ac8SCy Schubert
3410*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
3411*a90b9d01SCy Schubert if (wpa_s->dpp_pb_bi && wpa_s->dpp_pb_configurator &&
3412*a90b9d01SCy Schubert os_memcmp(bi->pubkey_hash_chirp, wpa_s->dpp_pb_resp_hash,
3413*a90b9d01SCy Schubert SHA256_MAC_LEN) != 0) {
3414*a90b9d01SCy Schubert char id[20];
3415*a90b9d01SCy Schubert
3416*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3417*a90b9d01SCy Schubert "DPP: Peer bootstrap key from PKEX does not match PB announcement hash");
3418*a90b9d01SCy Schubert wpa_hexdump(MSG_DEBUG,
3419*a90b9d01SCy Schubert "DPP: Peer provided bootstrap key hash(chirp) from PB PKEX",
3420*a90b9d01SCy Schubert bi->pubkey_hash_chirp, SHA256_MAC_LEN);
3421*a90b9d01SCy Schubert wpa_hexdump(MSG_DEBUG,
3422*a90b9d01SCy Schubert "DPP: Peer provided bootstrap key hash(chirp) from PB announcement",
3423*a90b9d01SCy Schubert wpa_s->dpp_pb_resp_hash, SHA256_MAC_LEN);
3424*a90b9d01SCy Schubert
3425*a90b9d01SCy Schubert os_snprintf(id, sizeof(id), "%u", bi->id);
3426*a90b9d01SCy Schubert dpp_bootstrap_remove(wpa_s->dpp, id);
3427*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
3428*a90b9d01SCy Schubert return;
3429*a90b9d01SCy Schubert }
3430*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
3431*a90b9d01SCy Schubert
343285732ac8SCy Schubert os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
343385732ac8SCy Schubert bi->id,
343485732ac8SCy Schubert wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : "");
343585732ac8SCy Schubert wpa_printf(MSG_DEBUG,
343685732ac8SCy Schubert "DPP: Start authentication after PKEX with parameters: %s",
343785732ac8SCy Schubert cmd);
343885732ac8SCy Schubert if (wpas_dpp_auth_init(wpa_s, cmd) < 0) {
343985732ac8SCy Schubert wpa_printf(MSG_DEBUG,
344085732ac8SCy Schubert "DPP: Authentication initialization failed");
3441c1d255d3SCy Schubert offchannel_send_action_done(wpa_s);
344285732ac8SCy Schubert return;
344385732ac8SCy Schubert }
344485732ac8SCy Schubert }
344585732ac8SCy Schubert
344685732ac8SCy Schubert
3447*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
3448*a90b9d01SCy Schubert
wpas_dpp_pb_pkex_init(struct wpa_supplicant * wpa_s,unsigned int freq,const u8 * src,const u8 * r_hash)3449*a90b9d01SCy Schubert static void wpas_dpp_pb_pkex_init(struct wpa_supplicant *wpa_s,
3450*a90b9d01SCy Schubert unsigned int freq, const u8 *src,
3451*a90b9d01SCy Schubert const u8 *r_hash)
3452*a90b9d01SCy Schubert {
3453*a90b9d01SCy Schubert struct dpp_pkex *pkex;
3454*a90b9d01SCy Schubert struct wpabuf *msg;
3455*a90b9d01SCy Schubert unsigned int wait_time;
3456*a90b9d01SCy Schubert size_t len;
3457*a90b9d01SCy Schubert
3458*a90b9d01SCy Schubert if (wpa_s->dpp_pkex) {
3459*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3460*a90b9d01SCy Schubert "DPP: Sending previously generated PKEX Exchange Request to "
3461*a90b9d01SCy Schubert MACSTR, MAC2STR(src));
3462*a90b9d01SCy Schubert msg = wpa_s->dpp_pkex->exchange_req;
3463*a90b9d01SCy Schubert wait_time = wpa_s->max_remain_on_chan;
3464*a90b9d01SCy Schubert if (wait_time > 2000)
3465*a90b9d01SCy Schubert wait_time = 2000;
3466*a90b9d01SCy Schubert offchannel_send_action(wpa_s, freq, src,
3467*a90b9d01SCy Schubert wpa_s->own_addr, broadcast,
3468*a90b9d01SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
3469*a90b9d01SCy Schubert wait_time, wpas_dpp_tx_pkex_status, 0);
3470*a90b9d01SCy Schubert return;
3471*a90b9d01SCy Schubert }
3472*a90b9d01SCy Schubert
3473*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Initiate PKEX for push button with "
3474*a90b9d01SCy Schubert MACSTR, MAC2STR(src));
3475*a90b9d01SCy Schubert
3476*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_cmd) {
3477*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3478*a90b9d01SCy Schubert "DPP: No configuration to provision as push button Configurator");
3479*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
3480*a90b9d01SCy Schubert return;
3481*a90b9d01SCy Schubert }
3482*a90b9d01SCy Schubert
3483*a90b9d01SCy Schubert wpa_s->dpp_pkex_bi = wpa_s->dpp_pb_bi;
3484*a90b9d01SCy Schubert os_memcpy(wpa_s->dpp_pb_resp_hash, r_hash, SHA256_MAC_LEN);
3485*a90b9d01SCy Schubert
3486*a90b9d01SCy Schubert pkex = dpp_pkex_init(wpa_s, wpa_s->dpp_pkex_bi, wpa_s->own_addr,
3487*a90b9d01SCy Schubert "PBPKEX", (const char *) wpa_s->dpp_pb_c_nonce,
3488*a90b9d01SCy Schubert wpa_s->dpp_pb_bi->curve->nonce_len,
3489*a90b9d01SCy Schubert true);
3490*a90b9d01SCy Schubert if (!pkex) {
3491*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
3492*a90b9d01SCy Schubert return;
3493*a90b9d01SCy Schubert }
3494*a90b9d01SCy Schubert pkex->freq = freq;
3495*a90b9d01SCy Schubert
3496*a90b9d01SCy Schubert wpa_s->dpp_pkex = pkex;
3497*a90b9d01SCy Schubert msg = wpa_s->dpp_pkex->exchange_req;
3498*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
3499*a90b9d01SCy Schubert " freq=%u type=%d", MAC2STR(src), freq,
3500*a90b9d01SCy Schubert DPP_PA_PKEX_EXCHANGE_REQ);
3501*a90b9d01SCy Schubert wait_time = wpa_s->max_remain_on_chan;
3502*a90b9d01SCy Schubert if (wait_time > 2000)
3503*a90b9d01SCy Schubert wait_time = 2000;
3504*a90b9d01SCy Schubert offchannel_send_action(wpa_s, pkex->freq, src,
3505*a90b9d01SCy Schubert wpa_s->own_addr, broadcast,
3506*a90b9d01SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
3507*a90b9d01SCy Schubert wait_time, wpas_dpp_tx_pkex_status, 0);
3508*a90b9d01SCy Schubert pkex->exch_req_wait_time = 2000;
3509*a90b9d01SCy Schubert pkex->exch_req_tries = 1;
3510*a90b9d01SCy Schubert
3511*a90b9d01SCy Schubert /* Use the externally provided configuration */
3512*a90b9d01SCy Schubert os_free(wpa_s->dpp_pkex_auth_cmd);
3513*a90b9d01SCy Schubert len = 30 + os_strlen(wpa_s->dpp_pb_cmd);
3514*a90b9d01SCy Schubert wpa_s->dpp_pkex_auth_cmd = os_malloc(len);
3515*a90b9d01SCy Schubert if (wpa_s->dpp_pkex_auth_cmd)
3516*a90b9d01SCy Schubert os_snprintf(wpa_s->dpp_pkex_auth_cmd, len, " own=%d %s",
3517*a90b9d01SCy Schubert wpa_s->dpp_pkex_bi->id, wpa_s->dpp_pb_cmd);
3518*a90b9d01SCy Schubert else
3519*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
3520*a90b9d01SCy Schubert }
3521*a90b9d01SCy Schubert
3522*a90b9d01SCy Schubert
3523*a90b9d01SCy Schubert static void
wpas_dpp_rx_pb_presence_announcement(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq)3524*a90b9d01SCy Schubert wpas_dpp_rx_pb_presence_announcement(struct wpa_supplicant *wpa_s,
3525*a90b9d01SCy Schubert const u8 *src, const u8 *hdr,
3526*a90b9d01SCy Schubert const u8 *buf, size_t len,
3527*a90b9d01SCy Schubert unsigned int freq)
3528*a90b9d01SCy Schubert {
3529*a90b9d01SCy Schubert const u8 *r_hash;
3530*a90b9d01SCy Schubert u16 r_hash_len;
3531*a90b9d01SCy Schubert unsigned int i;
3532*a90b9d01SCy Schubert bool found = false;
3533*a90b9d01SCy Schubert struct dpp_pb_info *info, *tmp;
3534*a90b9d01SCy Schubert struct os_reltime now, age;
3535*a90b9d01SCy Schubert struct wpabuf *msg;
3536*a90b9d01SCy Schubert
3537*a90b9d01SCy Schubert os_get_reltime(&now);
3538*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Push Button Presence Announcement from "
3539*a90b9d01SCy Schubert MACSTR, MAC2STR(src));
3540*a90b9d01SCy Schubert
3541*a90b9d01SCy Schubert r_hash = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3542*a90b9d01SCy Schubert &r_hash_len);
3543*a90b9d01SCy Schubert if (!r_hash || r_hash_len != SHA256_MAC_LEN) {
3544*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3545*a90b9d01SCy Schubert "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
3546*a90b9d01SCy Schubert return;
3547*a90b9d01SCy Schubert }
3548*a90b9d01SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
3549*a90b9d01SCy Schubert r_hash, r_hash_len);
3550*a90b9d01SCy Schubert
3551*a90b9d01SCy Schubert for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
3552*a90b9d01SCy Schubert info = &wpa_s->dpp_pb[i];
3553*a90b9d01SCy Schubert if ((info->rx_time.sec == 0 && info->rx_time.usec == 0) ||
3554*a90b9d01SCy Schubert os_memcmp(r_hash, info->hash, SHA256_MAC_LEN) != 0)
3555*a90b9d01SCy Schubert continue;
3556*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3557*a90b9d01SCy Schubert "DPP: Active push button Enrollee already known");
3558*a90b9d01SCy Schubert found = true;
3559*a90b9d01SCy Schubert info->rx_time = now;
3560*a90b9d01SCy Schubert }
3561*a90b9d01SCy Schubert
3562*a90b9d01SCy Schubert if (!found) {
3563*a90b9d01SCy Schubert for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
3564*a90b9d01SCy Schubert tmp = &wpa_s->dpp_pb[i];
3565*a90b9d01SCy Schubert if (tmp->rx_time.sec == 0 && tmp->rx_time.usec == 0)
3566*a90b9d01SCy Schubert continue;
3567*a90b9d01SCy Schubert
3568*a90b9d01SCy Schubert if (os_reltime_expired(&now, &tmp->rx_time, 120)) {
3569*a90b9d01SCy Schubert wpa_hexdump(MSG_DEBUG,
3570*a90b9d01SCy Schubert "DPP: Push button Enrollee hash expired",
3571*a90b9d01SCy Schubert tmp->hash, SHA256_MAC_LEN);
3572*a90b9d01SCy Schubert tmp->rx_time.sec = 0;
3573*a90b9d01SCy Schubert tmp->rx_time.usec = 0;
3574*a90b9d01SCy Schubert continue;
3575*a90b9d01SCy Schubert }
3576*a90b9d01SCy Schubert
3577*a90b9d01SCy Schubert wpa_hexdump(MSG_DEBUG,
3578*a90b9d01SCy Schubert "DPP: Push button session overlap with hash",
3579*a90b9d01SCy Schubert tmp->hash, SHA256_MAC_LEN);
3580*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_result_indicated &&
3581*a90b9d01SCy Schubert wpas_dpp_pb_active(wpa_s)) {
3582*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO,
3583*a90b9d01SCy Schubert DPP_EVENT_PB_RESULT "session-overlap");
3584*a90b9d01SCy Schubert wpa_s->dpp_pb_result_indicated = true;
3585*a90b9d01SCy Schubert }
3586*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
3587*a90b9d01SCy Schubert return;
3588*a90b9d01SCy Schubert }
3589*a90b9d01SCy Schubert
3590*a90b9d01SCy Schubert /* Replace the oldest entry */
3591*a90b9d01SCy Schubert info = &wpa_s->dpp_pb[0];
3592*a90b9d01SCy Schubert for (i = 1; i < DPP_PB_INFO_COUNT; i++) {
3593*a90b9d01SCy Schubert tmp = &wpa_s->dpp_pb[i];
3594*a90b9d01SCy Schubert if (os_reltime_before(&tmp->rx_time, &info->rx_time))
3595*a90b9d01SCy Schubert info = tmp;
3596*a90b9d01SCy Schubert }
3597*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: New active push button Enrollee");
3598*a90b9d01SCy Schubert os_memcpy(info->hash, r_hash, SHA256_MAC_LEN);
3599*a90b9d01SCy Schubert info->rx_time = now;
3600*a90b9d01SCy Schubert }
3601*a90b9d01SCy Schubert
3602*a90b9d01SCy Schubert if (!wpas_dpp_pb_active(wpa_s)) {
3603*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3604*a90b9d01SCy Schubert "DPP: Discard message since own push button has not been pressed");
3605*a90b9d01SCy Schubert return;
3606*a90b9d01SCy Schubert }
3607*a90b9d01SCy Schubert
3608*a90b9d01SCy Schubert if (wpa_s->dpp_pb_announce_time.sec == 0 &&
3609*a90b9d01SCy Schubert wpa_s->dpp_pb_announce_time.usec == 0) {
3610*a90b9d01SCy Schubert /* Start a wait before allowing PKEX to be initiated */
3611*a90b9d01SCy Schubert wpa_s->dpp_pb_announce_time = now;
3612*a90b9d01SCy Schubert }
3613*a90b9d01SCy Schubert
3614*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_bi) {
3615*a90b9d01SCy Schubert int res;
3616*a90b9d01SCy Schubert
3617*a90b9d01SCy Schubert res = dpp_bootstrap_gen(wpa_s->dpp, "type=pkex");
3618*a90b9d01SCy Schubert if (res < 0)
3619*a90b9d01SCy Schubert return;
3620*a90b9d01SCy Schubert wpa_s->dpp_pb_bi = dpp_bootstrap_get_id(wpa_s->dpp, res);
3621*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_bi)
3622*a90b9d01SCy Schubert return;
3623*a90b9d01SCy Schubert
3624*a90b9d01SCy Schubert if (random_get_bytes(wpa_s->dpp_pb_c_nonce,
3625*a90b9d01SCy Schubert wpa_s->dpp_pb_bi->curve->nonce_len)) {
3626*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
3627*a90b9d01SCy Schubert "DPP: Failed to generate C-nonce");
3628*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
3629*a90b9d01SCy Schubert return;
3630*a90b9d01SCy Schubert }
3631*a90b9d01SCy Schubert }
3632*a90b9d01SCy Schubert
3633*a90b9d01SCy Schubert /* Skip the response if one was sent within last 50 ms since the
3634*a90b9d01SCy Schubert * Enrollee is going to send out at least three announcement messages.
3635*a90b9d01SCy Schubert */
3636*a90b9d01SCy Schubert os_reltime_sub(&now, &wpa_s->dpp_pb_last_resp, &age);
3637*a90b9d01SCy Schubert if (age.sec == 0 && age.usec < 50000) {
3638*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3639*a90b9d01SCy Schubert "DPP: Skip Push Button Presence Announcement Response frame immediately after having sent one");
3640*a90b9d01SCy Schubert return;
3641*a90b9d01SCy Schubert }
3642*a90b9d01SCy Schubert
3643*a90b9d01SCy Schubert msg = dpp_build_pb_announcement_resp(
3644*a90b9d01SCy Schubert wpa_s->dpp_pb_bi, r_hash, wpa_s->dpp_pb_c_nonce,
3645*a90b9d01SCy Schubert wpa_s->dpp_pb_bi->curve->nonce_len);
3646*a90b9d01SCy Schubert if (!msg) {
3647*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
3648*a90b9d01SCy Schubert return;
3649*a90b9d01SCy Schubert }
3650*a90b9d01SCy Schubert
3651*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3652*a90b9d01SCy Schubert "DPP: Send Push Button Presence Announcement Response to "
3653*a90b9d01SCy Schubert MACSTR, MAC2STR(src));
3654*a90b9d01SCy Schubert wpa_s->dpp_pb_last_resp = now;
3655*a90b9d01SCy Schubert
3656*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
3657*a90b9d01SCy Schubert MAC2STR(src), freq, DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP);
3658*a90b9d01SCy Schubert offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
3659*a90b9d01SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
3660*a90b9d01SCy Schubert 0, NULL, 0);
3661*a90b9d01SCy Schubert wpabuf_free(msg);
3662*a90b9d01SCy Schubert
3663*a90b9d01SCy Schubert if (os_reltime_expired(&now, &wpa_s->dpp_pb_announce_time, 15))
3664*a90b9d01SCy Schubert wpas_dpp_pb_pkex_init(wpa_s, freq, src, r_hash);
3665*a90b9d01SCy Schubert }
3666*a90b9d01SCy Schubert
3667*a90b9d01SCy Schubert
3668*a90b9d01SCy Schubert static void
wpas_dpp_rx_pb_presence_announcement_resp(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq)3669*a90b9d01SCy Schubert wpas_dpp_rx_pb_presence_announcement_resp(struct wpa_supplicant *wpa_s,
3670*a90b9d01SCy Schubert const u8 *src, const u8 *hdr,
3671*a90b9d01SCy Schubert const u8 *buf, size_t len,
3672*a90b9d01SCy Schubert unsigned int freq)
3673*a90b9d01SCy Schubert {
3674*a90b9d01SCy Schubert const u8 *i_hash, *r_hash, *c_nonce;
3675*a90b9d01SCy Schubert u16 i_hash_len, r_hash_len, c_nonce_len;
3676*a90b9d01SCy Schubert bool overlap = false;
3677*a90b9d01SCy Schubert
3678*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_announcement || !wpa_s->dpp_pb_bi ||
3679*a90b9d01SCy Schubert wpa_s->dpp_pb_configurator) {
3680*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3681*a90b9d01SCy Schubert "DPP: Not in active push button Enrollee mode - discard Push Button Presence Announcement Response from "
3682*a90b9d01SCy Schubert MACSTR, MAC2STR(src));
3683*a90b9d01SCy Schubert return;
3684*a90b9d01SCy Schubert }
3685*a90b9d01SCy Schubert
3686*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3687*a90b9d01SCy Schubert "DPP: Push Button Presence Announcement Response from "
3688*a90b9d01SCy Schubert MACSTR, MAC2STR(src));
3689*a90b9d01SCy Schubert
3690*a90b9d01SCy Schubert i_hash = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3691*a90b9d01SCy Schubert &i_hash_len);
3692*a90b9d01SCy Schubert r_hash = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3693*a90b9d01SCy Schubert &r_hash_len);
3694*a90b9d01SCy Schubert c_nonce = dpp_get_attr(buf, len, DPP_ATTR_CONFIGURATOR_NONCE,
3695*a90b9d01SCy Schubert &c_nonce_len);
3696*a90b9d01SCy Schubert if (!i_hash || i_hash_len != SHA256_MAC_LEN ||
3697*a90b9d01SCy Schubert !r_hash || r_hash_len != SHA256_MAC_LEN ||
3698*a90b9d01SCy Schubert !c_nonce || c_nonce_len > DPP_MAX_NONCE_LEN) {
3699*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3700*a90b9d01SCy Schubert "DPP: Missing or invalid required attribute");
3701*a90b9d01SCy Schubert return;
3702*a90b9d01SCy Schubert }
3703*a90b9d01SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
3704*a90b9d01SCy Schubert i_hash, i_hash_len);
3705*a90b9d01SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
3706*a90b9d01SCy Schubert r_hash, r_hash_len);
3707*a90b9d01SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator Nonce",
3708*a90b9d01SCy Schubert c_nonce, c_nonce_len);
3709*a90b9d01SCy Schubert
3710*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
3711*a90b9d01SCy Schubert if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ &&
3712*a90b9d01SCy Schubert os_memcmp(r_hash, wpa_s->dpp_pb_bi->pubkey_hash_chirp,
3713*a90b9d01SCy Schubert SHA256_MAC_LEN - 1) == 0)
3714*a90b9d01SCy Schubert goto skip_hash_check;
3715*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
3716*a90b9d01SCy Schubert if (os_memcmp(r_hash, wpa_s->dpp_pb_bi->pubkey_hash_chirp,
3717*a90b9d01SCy Schubert SHA256_MAC_LEN) != 0) {
3718*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3719*a90b9d01SCy Schubert "DPP: Unexpected push button Responder hash - abort");
3720*a90b9d01SCy Schubert overlap = true;
3721*a90b9d01SCy Schubert }
3722*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
3723*a90b9d01SCy Schubert skip_hash_check:
3724*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
3725*a90b9d01SCy Schubert
3726*a90b9d01SCy Schubert if (wpa_s->dpp_pb_resp_freq &&
3727*a90b9d01SCy Schubert os_memcmp(i_hash, wpa_s->dpp_pb_init_hash, SHA256_MAC_LEN) != 0) {
3728*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3729*a90b9d01SCy Schubert "DPP: Push button session overlap detected - abort");
3730*a90b9d01SCy Schubert overlap = true;
3731*a90b9d01SCy Schubert }
3732*a90b9d01SCy Schubert
3733*a90b9d01SCy Schubert if (overlap) {
3734*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_result_indicated) {
3735*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT
3736*a90b9d01SCy Schubert "session-overlap");
3737*a90b9d01SCy Schubert wpa_s->dpp_pb_result_indicated = true;
3738*a90b9d01SCy Schubert }
3739*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
3740*a90b9d01SCy Schubert return;
3741*a90b9d01SCy Schubert }
3742*a90b9d01SCy Schubert
3743*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_resp_freq) {
3744*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS
3745*a90b9d01SCy Schubert "discovered push button AP/Configurator " MACSTR,
3746*a90b9d01SCy Schubert MAC2STR(src));
3747*a90b9d01SCy Schubert wpa_s->dpp_pb_resp_freq = freq;
3748*a90b9d01SCy Schubert os_memcpy(wpa_s->dpp_pb_init_hash, i_hash, SHA256_MAC_LEN);
3749*a90b9d01SCy Schubert os_memcpy(wpa_s->dpp_pb_c_nonce, c_nonce, c_nonce_len);
3750*a90b9d01SCy Schubert wpa_s->dpp_pb_c_nonce_len = c_nonce_len;
3751*a90b9d01SCy Schubert /* Stop announcement iterations after at least one more full
3752*a90b9d01SCy Schubert * round and one extra round for postponed session overlap
3753*a90b9d01SCy Schubert * detection. */
3754*a90b9d01SCy Schubert wpa_s->dpp_pb_stop_iter = 3;
3755*a90b9d01SCy Schubert }
3756*a90b9d01SCy Schubert }
3757*a90b9d01SCy Schubert
3758*a90b9d01SCy Schubert
3759*a90b9d01SCy Schubert static void
wpas_dpp_tx_priv_intro_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)3760*a90b9d01SCy Schubert wpas_dpp_tx_priv_intro_status(struct wpa_supplicant *wpa_s,
3761*a90b9d01SCy Schubert unsigned int freq, const u8 *dst,
3762*a90b9d01SCy Schubert const u8 *src, const u8 *bssid,
3763*a90b9d01SCy Schubert const u8 *data, size_t data_len,
3764*a90b9d01SCy Schubert enum offchannel_send_action_result result)
3765*a90b9d01SCy Schubert {
3766*a90b9d01SCy Schubert const char *res_txt;
3767*a90b9d01SCy Schubert
3768*a90b9d01SCy Schubert res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
3769*a90b9d01SCy Schubert (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
3770*a90b9d01SCy Schubert "FAILED");
3771*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
3772*a90b9d01SCy Schubert " result=%s (DPP Private Peer Introduction Update)",
3773*a90b9d01SCy Schubert freq, MAC2STR(dst), res_txt);
3774*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
3775*a90b9d01SCy Schubert " freq=%u result=%s", MAC2STR(dst), freq, res_txt);
3776*a90b9d01SCy Schubert
3777*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR " version=%u",
3778*a90b9d01SCy Schubert MAC2STR(src), wpa_s->dpp_intro_peer_version);
3779*a90b9d01SCy Schubert
3780*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3781*a90b9d01SCy Schubert "DPP: Try connection again after successful network introduction");
3782*a90b9d01SCy Schubert if (wpa_supplicant_fast_associate(wpa_s) != 1) {
3783*a90b9d01SCy Schubert wpa_supplicant_cancel_sched_scan(wpa_s);
3784*a90b9d01SCy Schubert wpa_supplicant_req_scan(wpa_s, 0, 0);
3785*a90b9d01SCy Schubert }
3786*a90b9d01SCy Schubert }
3787*a90b9d01SCy Schubert
3788*a90b9d01SCy Schubert
3789*a90b9d01SCy Schubert static int
wpas_dpp_send_private_peer_intro_update(struct wpa_supplicant * wpa_s,struct dpp_introduction * intro,struct wpa_ssid * ssid,const u8 * dst,unsigned int freq)3790*a90b9d01SCy Schubert wpas_dpp_send_private_peer_intro_update(struct wpa_supplicant *wpa_s,
3791*a90b9d01SCy Schubert struct dpp_introduction *intro,
3792*a90b9d01SCy Schubert struct wpa_ssid *ssid,
3793*a90b9d01SCy Schubert const u8 *dst, unsigned int freq)
3794*a90b9d01SCy Schubert {
3795*a90b9d01SCy Schubert struct wpabuf *pt, *msg, *enc_ct;
3796*a90b9d01SCy Schubert size_t len;
3797*a90b9d01SCy Schubert u8 ver = DPP_VERSION;
3798*a90b9d01SCy Schubert int conn_ver;
3799*a90b9d01SCy Schubert const u8 *aad;
3800*a90b9d01SCy Schubert size_t aad_len;
3801*a90b9d01SCy Schubert unsigned int wait_time;
3802*a90b9d01SCy Schubert
3803*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "HPKE(kem_id=%u kdf_id=%u aead_id=%u)",
3804*a90b9d01SCy Schubert intro->kem_id, intro->kdf_id, intro->aead_id);
3805*a90b9d01SCy Schubert
3806*a90b9d01SCy Schubert /* Plaintext for HPKE */
3807*a90b9d01SCy Schubert len = 5 + 4 + os_strlen(ssid->dpp_connector);
3808*a90b9d01SCy Schubert pt = wpabuf_alloc(len);
3809*a90b9d01SCy Schubert if (!pt)
3810*a90b9d01SCy Schubert return -1;
3811*a90b9d01SCy Schubert
3812*a90b9d01SCy Schubert /* Protocol Version */
3813*a90b9d01SCy Schubert conn_ver = dpp_get_connector_version(ssid->dpp_connector);
3814*a90b9d01SCy Schubert if (conn_ver > 0 && ver != conn_ver) {
3815*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3816*a90b9d01SCy Schubert "DPP: Use Connector version %d instead of current protocol version %d",
3817*a90b9d01SCy Schubert conn_ver, ver);
3818*a90b9d01SCy Schubert ver = conn_ver;
3819*a90b9d01SCy Schubert }
3820*a90b9d01SCy Schubert wpabuf_put_le16(pt, DPP_ATTR_PROTOCOL_VERSION);
3821*a90b9d01SCy Schubert wpabuf_put_le16(pt, 1);
3822*a90b9d01SCy Schubert wpabuf_put_u8(pt, ver);
3823*a90b9d01SCy Schubert
3824*a90b9d01SCy Schubert /* Connector */
3825*a90b9d01SCy Schubert wpabuf_put_le16(pt, DPP_ATTR_CONNECTOR);
3826*a90b9d01SCy Schubert wpabuf_put_le16(pt, os_strlen(ssid->dpp_connector));
3827*a90b9d01SCy Schubert wpabuf_put_str(pt, ssid->dpp_connector);
3828*a90b9d01SCy Schubert wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Plaintext for HPKE", pt);
3829*a90b9d01SCy Schubert
3830*a90b9d01SCy Schubert /* HPKE(pt) using AP's public key (from its Connector) */
3831*a90b9d01SCy Schubert msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_UPDATE, 0);
3832*a90b9d01SCy Schubert if (!msg) {
3833*a90b9d01SCy Schubert wpabuf_free(pt);
3834*a90b9d01SCy Schubert return -1;
3835*a90b9d01SCy Schubert }
3836*a90b9d01SCy Schubert aad = wpabuf_head_u8(msg) + 2; /* from the OUI field (inclusive) */
3837*a90b9d01SCy Schubert aad_len = DPP_HDR_LEN; /* to the DPP Frame Type field (inclusive) */
3838*a90b9d01SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: AAD for HPKE", aad, aad_len);
3839*a90b9d01SCy Schubert
3840*a90b9d01SCy Schubert enc_ct = hpke_base_seal(intro->kem_id, intro->kdf_id, intro->aead_id,
3841*a90b9d01SCy Schubert intro->peer_key, NULL, 0, aad, aad_len,
3842*a90b9d01SCy Schubert wpabuf_head(pt), wpabuf_len(pt));
3843*a90b9d01SCy Schubert wpabuf_free(pt);
3844*a90b9d01SCy Schubert wpabuf_free(msg);
3845*a90b9d01SCy Schubert if (!enc_ct) {
3846*a90b9d01SCy Schubert wpa_printf(MSG_INFO, "DPP: HPKE Seal(Connector) failed");
3847*a90b9d01SCy Schubert return -1;
3848*a90b9d01SCy Schubert }
3849*a90b9d01SCy Schubert wpa_hexdump_buf(MSG_MSGDUMP, "DPP: HPKE enc|ct", enc_ct);
3850*a90b9d01SCy Schubert
3851*a90b9d01SCy Schubert /* HPKE(pt) to generate payload for Wrapped Data */
3852*a90b9d01SCy Schubert len = 5 + 4 + wpabuf_len(enc_ct);
3853*a90b9d01SCy Schubert msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_UPDATE, len);
3854*a90b9d01SCy Schubert if (!msg) {
3855*a90b9d01SCy Schubert wpabuf_free(enc_ct);
3856*a90b9d01SCy Schubert return -1;
3857*a90b9d01SCy Schubert }
3858*a90b9d01SCy Schubert
3859*a90b9d01SCy Schubert /* Transaction ID */
3860*a90b9d01SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
3861*a90b9d01SCy Schubert wpabuf_put_le16(msg, 1);
3862*a90b9d01SCy Schubert wpabuf_put_u8(msg, TRANSACTION_ID);
3863*a90b9d01SCy Schubert
3864*a90b9d01SCy Schubert /* Wrapped Data */
3865*a90b9d01SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3866*a90b9d01SCy Schubert wpabuf_put_le16(msg, wpabuf_len(enc_ct));
3867*a90b9d01SCy Schubert wpabuf_put_buf(msg, enc_ct);
3868*a90b9d01SCy Schubert wpabuf_free(enc_ct);
3869*a90b9d01SCy Schubert
3870*a90b9d01SCy Schubert wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Private Peer Intro Update", msg);
3871*a90b9d01SCy Schubert
3872*a90b9d01SCy Schubert /* TODO: Timeout on AP response */
3873*a90b9d01SCy Schubert wait_time = wpa_s->max_remain_on_chan;
3874*a90b9d01SCy Schubert if (wait_time > 2000)
3875*a90b9d01SCy Schubert wait_time = 2000;
3876*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
3877*a90b9d01SCy Schubert MAC2STR(dst), freq, DPP_PA_PRIV_PEER_INTRO_QUERY);
3878*a90b9d01SCy Schubert offchannel_send_action(wpa_s, freq, dst, wpa_s->own_addr, broadcast,
3879*a90b9d01SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
3880*a90b9d01SCy Schubert wait_time, wpas_dpp_tx_priv_intro_status, 0);
3881*a90b9d01SCy Schubert wpabuf_free(msg);
3882*a90b9d01SCy Schubert
3883*a90b9d01SCy Schubert return 0;
3884*a90b9d01SCy Schubert }
3885*a90b9d01SCy Schubert
3886*a90b9d01SCy Schubert
3887*a90b9d01SCy Schubert static void
wpas_dpp_rx_priv_peer_intro_notify(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * hdr,const u8 * buf,size_t len,unsigned int freq)3888*a90b9d01SCy Schubert wpas_dpp_rx_priv_peer_intro_notify(struct wpa_supplicant *wpa_s,
3889*a90b9d01SCy Schubert const u8 *src, const u8 *hdr,
3890*a90b9d01SCy Schubert const u8 *buf, size_t len,
3891*a90b9d01SCy Schubert unsigned int freq)
3892*a90b9d01SCy Schubert {
3893*a90b9d01SCy Schubert struct wpa_ssid *ssid;
3894*a90b9d01SCy Schubert const u8 *connector, *trans_id, *version;
3895*a90b9d01SCy Schubert u16 connector_len, trans_id_len, version_len;
3896*a90b9d01SCy Schubert u8 peer_version = 1;
3897*a90b9d01SCy Schubert struct dpp_introduction intro;
3898*a90b9d01SCy Schubert struct rsn_pmksa_cache_entry *entry;
3899*a90b9d01SCy Schubert struct os_time now;
3900*a90b9d01SCy Schubert struct os_reltime rnow;
3901*a90b9d01SCy Schubert os_time_t expiry;
3902*a90b9d01SCy Schubert unsigned int seconds;
3903*a90b9d01SCy Schubert enum dpp_status_error res;
3904*a90b9d01SCy Schubert
3905*a90b9d01SCy Schubert os_memset(&intro, 0, sizeof(intro));
3906*a90b9d01SCy Schubert
3907*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction Notify from "
3908*a90b9d01SCy Schubert MACSTR, MAC2STR(src));
3909*a90b9d01SCy Schubert if (is_zero_ether_addr(wpa_s->dpp_intro_bssid) ||
3910*a90b9d01SCy Schubert !ether_addr_equal(src, wpa_s->dpp_intro_bssid)) {
3911*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Not waiting for response from "
3912*a90b9d01SCy Schubert MACSTR " - drop", MAC2STR(src));
3913*a90b9d01SCy Schubert return;
3914*a90b9d01SCy Schubert }
3915*a90b9d01SCy Schubert offchannel_send_action_done(wpa_s);
3916*a90b9d01SCy Schubert
3917*a90b9d01SCy Schubert for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
3918*a90b9d01SCy Schubert if (ssid == wpa_s->dpp_intro_network)
3919*a90b9d01SCy Schubert break;
3920*a90b9d01SCy Schubert }
3921*a90b9d01SCy Schubert if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
3922*a90b9d01SCy Schubert !ssid->dpp_csign) {
3923*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3924*a90b9d01SCy Schubert "DPP: Profile not found for network introduction");
3925*a90b9d01SCy Schubert return;
3926*a90b9d01SCy Schubert }
3927*a90b9d01SCy Schubert
3928*a90b9d01SCy Schubert trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
3929*a90b9d01SCy Schubert &trans_id_len);
3930*a90b9d01SCy Schubert if (!trans_id || trans_id_len != 1) {
3931*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3932*a90b9d01SCy Schubert "DPP: Peer did not include Transaction ID");
3933*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
3934*a90b9d01SCy Schubert " fail=missing_transaction_id", MAC2STR(src));
3935*a90b9d01SCy Schubert goto fail;
3936*a90b9d01SCy Schubert }
3937*a90b9d01SCy Schubert if (trans_id[0] != TRANSACTION_ID) {
3938*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3939*a90b9d01SCy Schubert "DPP: Ignore frame with unexpected Transaction ID %u",
3940*a90b9d01SCy Schubert trans_id[0]);
3941*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
3942*a90b9d01SCy Schubert " fail=transaction_id_mismatch", MAC2STR(src));
3943*a90b9d01SCy Schubert goto fail;
3944*a90b9d01SCy Schubert }
3945*a90b9d01SCy Schubert
3946*a90b9d01SCy Schubert connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len);
3947*a90b9d01SCy Schubert if (!connector) {
3948*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3949*a90b9d01SCy Schubert "DPP: Peer did not include its Connector");
3950*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
3951*a90b9d01SCy Schubert " fail=missing_connector", MAC2STR(src));
3952*a90b9d01SCy Schubert goto fail;
3953*a90b9d01SCy Schubert }
3954*a90b9d01SCy Schubert
3955*a90b9d01SCy Schubert version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
3956*a90b9d01SCy Schubert &version_len);
3957*a90b9d01SCy Schubert if (!version || version_len < 1) {
3958*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
3959*a90b9d01SCy Schubert "DPP: Peer did not include valid Version");
3960*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
3961*a90b9d01SCy Schubert " fail=missing_version", MAC2STR(src));
3962*a90b9d01SCy Schubert goto fail;
3963*a90b9d01SCy Schubert }
3964*a90b9d01SCy Schubert
3965*a90b9d01SCy Schubert res = dpp_peer_intro(&intro, ssid->dpp_connector,
3966*a90b9d01SCy Schubert ssid->dpp_netaccesskey,
3967*a90b9d01SCy Schubert ssid->dpp_netaccesskey_len,
3968*a90b9d01SCy Schubert ssid->dpp_csign,
3969*a90b9d01SCy Schubert ssid->dpp_csign_len,
3970*a90b9d01SCy Schubert connector, connector_len, &expiry, NULL);
3971*a90b9d01SCy Schubert if (res != DPP_STATUS_OK) {
3972*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3973*a90b9d01SCy Schubert "DPP: Network Introduction protocol resulted in failure");
3974*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
3975*a90b9d01SCy Schubert " fail=peer_connector_validation_failed", MAC2STR(src));
3976*a90b9d01SCy Schubert wpas_dpp_send_conn_status_result(wpa_s, res);
3977*a90b9d01SCy Schubert goto fail;
3978*a90b9d01SCy Schubert }
3979*a90b9d01SCy Schubert
3980*a90b9d01SCy Schubert peer_version = version[0];
3981*a90b9d01SCy Schubert if (intro.peer_version && intro.peer_version >= 2 &&
3982*a90b9d01SCy Schubert peer_version != intro.peer_version) {
3983*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3984*a90b9d01SCy Schubert "DPP: Protocol version mismatch (Connector: %d Attribute: %d",
3985*a90b9d01SCy Schubert intro.peer_version, peer_version);
3986*a90b9d01SCy Schubert wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_NO_MATCH);
3987*a90b9d01SCy Schubert goto fail;
3988*a90b9d01SCy Schubert }
3989*a90b9d01SCy Schubert wpa_s->dpp_intro_peer_version = peer_version;
3990*a90b9d01SCy Schubert
3991*a90b9d01SCy Schubert entry = os_zalloc(sizeof(*entry));
3992*a90b9d01SCy Schubert if (!entry)
3993*a90b9d01SCy Schubert goto fail;
3994*a90b9d01SCy Schubert entry->dpp_pfs = peer_version >= 2;
3995*a90b9d01SCy Schubert os_memcpy(entry->aa, src, ETH_ALEN);
3996*a90b9d01SCy Schubert os_memcpy(entry->spa, wpa_s->own_addr, ETH_ALEN);
3997*a90b9d01SCy Schubert os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN);
3998*a90b9d01SCy Schubert os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
3999*a90b9d01SCy Schubert entry->pmk_len = intro.pmk_len;
4000*a90b9d01SCy Schubert entry->akmp = WPA_KEY_MGMT_DPP;
4001*a90b9d01SCy Schubert if (expiry) {
4002*a90b9d01SCy Schubert os_get_time(&now);
4003*a90b9d01SCy Schubert seconds = expiry - now.sec;
4004*a90b9d01SCy Schubert } else {
4005*a90b9d01SCy Schubert seconds = 86400 * 7;
4006*a90b9d01SCy Schubert }
4007*a90b9d01SCy Schubert
4008*a90b9d01SCy Schubert if (wpas_dpp_send_private_peer_intro_update(wpa_s, &intro, ssid, src,
4009*a90b9d01SCy Schubert freq) < 0) {
4010*a90b9d01SCy Schubert os_free(entry);
4011*a90b9d01SCy Schubert goto fail;
4012*a90b9d01SCy Schubert }
4013*a90b9d01SCy Schubert
4014*a90b9d01SCy Schubert os_get_reltime(&rnow);
4015*a90b9d01SCy Schubert entry->expiration = rnow.sec + seconds;
4016*a90b9d01SCy Schubert entry->reauth_time = rnow.sec + seconds;
4017*a90b9d01SCy Schubert entry->network_ctx = ssid;
4018*a90b9d01SCy Schubert wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
4019*a90b9d01SCy Schubert
4020*a90b9d01SCy Schubert /* Association will be initiated from TX status handler for the Private
4021*a90b9d01SCy Schubert * Peer Intro Update: wpas_dpp_tx_priv_intro_status() */
4022*a90b9d01SCy Schubert
4023*a90b9d01SCy Schubert fail:
4024*a90b9d01SCy Schubert dpp_peer_intro_deinit(&intro);
4025*a90b9d01SCy Schubert }
4026*a90b9d01SCy Schubert
4027*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
4028*a90b9d01SCy Schubert
4029*a90b9d01SCy Schubert
wpas_dpp_rx_action(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * buf,size_t len,unsigned int freq)403085732ac8SCy Schubert void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
403185732ac8SCy Schubert const u8 *buf, size_t len, unsigned int freq)
403285732ac8SCy Schubert {
403385732ac8SCy Schubert u8 crypto_suite;
403485732ac8SCy Schubert enum dpp_public_action_frame_type type;
403585732ac8SCy Schubert const u8 *hdr;
403685732ac8SCy Schubert unsigned int pkex_t;
403785732ac8SCy Schubert
403885732ac8SCy Schubert if (len < DPP_HDR_LEN)
403985732ac8SCy Schubert return;
404085732ac8SCy Schubert if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE)
404185732ac8SCy Schubert return;
404285732ac8SCy Schubert hdr = buf;
404385732ac8SCy Schubert buf += 4;
404485732ac8SCy Schubert len -= 4;
404585732ac8SCy Schubert crypto_suite = *buf++;
404685732ac8SCy Schubert type = *buf++;
404785732ac8SCy Schubert len -= 2;
404885732ac8SCy Schubert
404985732ac8SCy Schubert wpa_printf(MSG_DEBUG,
405085732ac8SCy Schubert "DPP: Received DPP Public Action frame crypto suite %u type %d from "
405185732ac8SCy Schubert MACSTR " freq=%u",
405285732ac8SCy Schubert crypto_suite, type, MAC2STR(src), freq);
4053*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
4054*a90b9d01SCy Schubert if (wpa_s->dpp_discard_public_action &&
4055*a90b9d01SCy Schubert type != DPP_PA_PEER_DISCOVERY_RESP &&
4056*a90b9d01SCy Schubert type != DPP_PA_PRIV_PEER_INTRO_NOTIFY) {
4057*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
4058*a90b9d01SCy Schubert "TESTING: Discard received DPP Public Action frame");
4059*a90b9d01SCy Schubert return;
4060*a90b9d01SCy Schubert }
4061*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
406285732ac8SCy Schubert if (crypto_suite != 1) {
406385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
406485732ac8SCy Schubert crypto_suite);
406585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
406685732ac8SCy Schubert " freq=%u type=%d ignore=unsupported-crypto-suite",
406785732ac8SCy Schubert MAC2STR(src), freq, type);
406885732ac8SCy Schubert return;
406985732ac8SCy Schubert }
407085732ac8SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
407185732ac8SCy Schubert if (dpp_check_attrs(buf, len) < 0) {
407285732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
407385732ac8SCy Schubert " freq=%u type=%d ignore=invalid-attributes",
407485732ac8SCy Schubert MAC2STR(src), freq, type);
407585732ac8SCy Schubert return;
407685732ac8SCy Schubert }
407785732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR " freq=%u type=%d",
407885732ac8SCy Schubert MAC2STR(src), freq, type);
407985732ac8SCy Schubert
408085732ac8SCy Schubert switch (type) {
408185732ac8SCy Schubert case DPP_PA_AUTHENTICATION_REQ:
408285732ac8SCy Schubert wpas_dpp_rx_auth_req(wpa_s, src, hdr, buf, len, freq);
408385732ac8SCy Schubert break;
408485732ac8SCy Schubert case DPP_PA_AUTHENTICATION_RESP:
408585732ac8SCy Schubert wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len, freq);
408685732ac8SCy Schubert break;
408785732ac8SCy Schubert case DPP_PA_AUTHENTICATION_CONF:
408885732ac8SCy Schubert wpas_dpp_rx_auth_conf(wpa_s, src, hdr, buf, len);
408985732ac8SCy Schubert break;
409085732ac8SCy Schubert case DPP_PA_PEER_DISCOVERY_RESP:
409185732ac8SCy Schubert wpas_dpp_rx_peer_disc_resp(wpa_s, src, buf, len);
409285732ac8SCy Schubert break;
409332a95656SCy Schubert #ifdef CONFIG_DPP3
409485732ac8SCy Schubert case DPP_PA_PKEX_EXCHANGE_REQ:
409532a95656SCy Schubert /* This is for PKEXv2, but for now, process only with
409632a95656SCy Schubert * CONFIG_DPP3 to avoid issues with a capability that has not
409732a95656SCy Schubert * been tested with other implementations. */
409832a95656SCy Schubert wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq, true);
409932a95656SCy Schubert break;
410032a95656SCy Schubert #endif /* CONFIG_DPP3 */
410132a95656SCy Schubert case DPP_PA_PKEX_V1_EXCHANGE_REQ:
410232a95656SCy Schubert wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq,
410332a95656SCy Schubert false);
410485732ac8SCy Schubert break;
410585732ac8SCy Schubert case DPP_PA_PKEX_EXCHANGE_RESP:
410685732ac8SCy Schubert wpas_dpp_rx_pkex_exchange_resp(wpa_s, src, buf, len, freq);
410785732ac8SCy Schubert break;
410885732ac8SCy Schubert case DPP_PA_PKEX_COMMIT_REVEAL_REQ:
410985732ac8SCy Schubert wpas_dpp_rx_pkex_commit_reveal_req(wpa_s, src, hdr, buf, len,
411085732ac8SCy Schubert freq);
411185732ac8SCy Schubert break;
411285732ac8SCy Schubert case DPP_PA_PKEX_COMMIT_REVEAL_RESP:
411385732ac8SCy Schubert wpas_dpp_rx_pkex_commit_reveal_resp(wpa_s, src, hdr, buf, len,
411485732ac8SCy Schubert freq);
411585732ac8SCy Schubert break;
41164bc52338SCy Schubert #ifdef CONFIG_DPP2
41174bc52338SCy Schubert case DPP_PA_CONFIGURATION_RESULT:
41184bc52338SCy Schubert wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len);
41194bc52338SCy Schubert break;
4120c1d255d3SCy Schubert case DPP_PA_CONNECTION_STATUS_RESULT:
4121c1d255d3SCy Schubert wpas_dpp_rx_conn_status_result(wpa_s, src, hdr, buf, len);
4122c1d255d3SCy Schubert break;
4123c1d255d3SCy Schubert case DPP_PA_PRESENCE_ANNOUNCEMENT:
4124c1d255d3SCy Schubert wpas_dpp_rx_presence_announcement(wpa_s, src, hdr, buf, len,
4125c1d255d3SCy Schubert freq);
4126c1d255d3SCy Schubert break;
4127c1d255d3SCy Schubert case DPP_PA_RECONFIG_ANNOUNCEMENT:
4128c1d255d3SCy Schubert wpas_dpp_rx_reconfig_announcement(wpa_s, src, hdr, buf, len,
4129c1d255d3SCy Schubert freq);
4130c1d255d3SCy Schubert break;
4131c1d255d3SCy Schubert case DPP_PA_RECONFIG_AUTH_REQ:
4132c1d255d3SCy Schubert wpas_dpp_rx_reconfig_auth_req(wpa_s, src, hdr, buf, len, freq);
4133c1d255d3SCy Schubert break;
4134c1d255d3SCy Schubert case DPP_PA_RECONFIG_AUTH_RESP:
4135c1d255d3SCy Schubert wpas_dpp_rx_reconfig_auth_resp(wpa_s, src, hdr, buf, len, freq);
4136c1d255d3SCy Schubert break;
4137c1d255d3SCy Schubert case DPP_PA_RECONFIG_AUTH_CONF:
4138c1d255d3SCy Schubert wpas_dpp_rx_reconfig_auth_conf(wpa_s, src, hdr, buf, len, freq);
4139c1d255d3SCy Schubert break;
41404bc52338SCy Schubert #endif /* CONFIG_DPP2 */
4141*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
4142*a90b9d01SCy Schubert case DPP_PA_PB_PRESENCE_ANNOUNCEMENT:
4143*a90b9d01SCy Schubert wpas_dpp_rx_pb_presence_announcement(wpa_s, src, hdr,
4144*a90b9d01SCy Schubert buf, len, freq);
4145*a90b9d01SCy Schubert break;
4146*a90b9d01SCy Schubert case DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP:
4147*a90b9d01SCy Schubert wpas_dpp_rx_pb_presence_announcement_resp(wpa_s, src, hdr,
4148*a90b9d01SCy Schubert buf, len, freq);
4149*a90b9d01SCy Schubert break;
4150*a90b9d01SCy Schubert case DPP_PA_PRIV_PEER_INTRO_NOTIFY:
4151*a90b9d01SCy Schubert wpas_dpp_rx_priv_peer_intro_notify(wpa_s, src, hdr,
4152*a90b9d01SCy Schubert buf, len, freq);
4153*a90b9d01SCy Schubert break;
4154*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
415585732ac8SCy Schubert default:
415685732ac8SCy Schubert wpa_printf(MSG_DEBUG,
415785732ac8SCy Schubert "DPP: Ignored unsupported frame subtype %d", type);
415885732ac8SCy Schubert break;
415985732ac8SCy Schubert }
416085732ac8SCy Schubert
416185732ac8SCy Schubert if (wpa_s->dpp_pkex)
416285732ac8SCy Schubert pkex_t = wpa_s->dpp_pkex->t;
416385732ac8SCy Schubert else if (wpa_s->dpp_pkex_bi)
416485732ac8SCy Schubert pkex_t = wpa_s->dpp_pkex_bi->pkex_t;
416585732ac8SCy Schubert else
416685732ac8SCy Schubert pkex_t = 0;
416785732ac8SCy Schubert if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
416885732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
416985732ac8SCy Schubert wpas_dpp_pkex_remove(wpa_s, "*");
417085732ac8SCy Schubert }
417185732ac8SCy Schubert }
417285732ac8SCy Schubert
417385732ac8SCy Schubert
wpas_dpp_gas_initial_resp_timeout(void * eloop_ctx,void * timeout_ctx)4174*a90b9d01SCy Schubert static void wpas_dpp_gas_initial_resp_timeout(void *eloop_ctx,
4175*a90b9d01SCy Schubert void *timeout_ctx)
4176*a90b9d01SCy Schubert {
4177*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
4178*a90b9d01SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
4179*a90b9d01SCy Schubert
4180*a90b9d01SCy Schubert if (!auth || !auth->waiting_config || !auth->config_resp_ctx)
4181*a90b9d01SCy Schubert return;
4182*a90b9d01SCy Schubert
4183*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
4184*a90b9d01SCy Schubert "DPP: No configuration available from upper layers - send initial response with comeback delay");
4185*a90b9d01SCy Schubert gas_server_set_comeback_delay(wpa_s->gas_server, auth->config_resp_ctx,
4186*a90b9d01SCy Schubert 500);
4187*a90b9d01SCy Schubert }
4188*a90b9d01SCy Schubert
4189*a90b9d01SCy Schubert
419085732ac8SCy Schubert static struct wpabuf *
wpas_dpp_gas_req_handler(void * ctx,void * resp_ctx,const u8 * sa,const u8 * query,size_t query_len,int * comeback_delay)4191c1d255d3SCy Schubert wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa,
4192*a90b9d01SCy Schubert const u8 *query, size_t query_len, int *comeback_delay)
419385732ac8SCy Schubert {
419485732ac8SCy Schubert struct wpa_supplicant *wpa_s = ctx;
419585732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
419685732ac8SCy Schubert struct wpabuf *resp;
419785732ac8SCy Schubert
419885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR,
419985732ac8SCy Schubert MAC2STR(sa));
4200c1d255d3SCy Schubert if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
4201*a90b9d01SCy Schubert !ether_addr_equal(sa, auth->peer_mac_addr)) {
420285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
420385732ac8SCy Schubert return NULL;
420485732ac8SCy Schubert }
4205206b73d0SCy Schubert
4206206b73d0SCy Schubert if (wpa_s->dpp_auth_ok_on_ack && auth->configurator) {
4207206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
4208206b73d0SCy Schubert "DPP: Have not received ACK for Auth Confirm yet - assume it was received based on this GAS request");
4209206b73d0SCy Schubert /* wpas_dpp_auth_success() would normally have been called from
4210206b73d0SCy Schubert * TX status handler, but since there was no such handler call
4211206b73d0SCy Schubert * yet, simply send out the event message and proceed with
4212206b73d0SCy Schubert * exchange. */
4213*a90b9d01SCy Schubert dpp_notify_auth_success(auth, 1);
4214206b73d0SCy Schubert wpa_s->dpp_auth_ok_on_ack = 0;
4215*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
4216*a90b9d01SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
4217*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
4218*a90b9d01SCy Schubert "DPP: TESTING - stop at Authentication Confirm");
4219*a90b9d01SCy Schubert return NULL;
4220*a90b9d01SCy Schubert }
4221*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
4222206b73d0SCy Schubert }
4223206b73d0SCy Schubert
422485732ac8SCy Schubert wpa_hexdump(MSG_DEBUG,
422585732ac8SCy Schubert "DPP: Received Configuration Request (GAS Query Request)",
422685732ac8SCy Schubert query, query_len);
422785732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
422885732ac8SCy Schubert MAC2STR(sa));
422985732ac8SCy Schubert resp = dpp_conf_req_rx(auth, query, query_len);
4230c1d255d3SCy Schubert
4231*a90b9d01SCy Schubert auth->gas_server_ctx = resp_ctx;
4232*a90b9d01SCy Schubert
4233c1d255d3SCy Schubert #ifdef CONFIG_DPP2
4234c1d255d3SCy Schubert if (!resp && auth->waiting_cert) {
4235c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
4236*a90b9d01SCy Schubert auth->config_resp_ctx = resp_ctx;
4237c1d255d3SCy Schubert *comeback_delay = 500;
4238c1d255d3SCy Schubert return NULL;
4239c1d255d3SCy Schubert }
4240c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
4241c1d255d3SCy Schubert
4242*a90b9d01SCy Schubert if (!resp && auth->waiting_config &&
4243*a90b9d01SCy Schubert (auth->peer_bi || auth->tmp_peer_bi)) {
4244*a90b9d01SCy Schubert char *buf = NULL, *name = "";
4245*a90b9d01SCy Schubert char band[200], *pos, *end;
4246*a90b9d01SCy Schubert int i, res, *opclass = auth->e_band_support;
4247*a90b9d01SCy Schubert char *mud_url = "N/A";
4248*a90b9d01SCy Schubert
4249*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Configuration not yet ready");
4250*a90b9d01SCy Schubert auth->config_resp_ctx = resp_ctx;
4251*a90b9d01SCy Schubert *comeback_delay = -1;
4252*a90b9d01SCy Schubert if (auth->e_name) {
4253*a90b9d01SCy Schubert size_t len = os_strlen(auth->e_name);
4254*a90b9d01SCy Schubert
4255*a90b9d01SCy Schubert buf = os_malloc(len * 4 + 1);
4256*a90b9d01SCy Schubert if (buf) {
4257*a90b9d01SCy Schubert printf_encode(buf, len * 4 + 1,
4258*a90b9d01SCy Schubert (const u8 *) auth->e_name, len);
4259*a90b9d01SCy Schubert name = buf;
4260*a90b9d01SCy Schubert }
4261*a90b9d01SCy Schubert }
4262*a90b9d01SCy Schubert band[0] = '\0';
4263*a90b9d01SCy Schubert pos = band;
4264*a90b9d01SCy Schubert end = band + sizeof(band);
4265*a90b9d01SCy Schubert for (i = 0; opclass && opclass[i]; i++) {
4266*a90b9d01SCy Schubert res = os_snprintf(pos, end - pos, "%s%d",
4267*a90b9d01SCy Schubert pos == band ? "" : ",", opclass[i]);
4268*a90b9d01SCy Schubert if (os_snprintf_error(end - pos, res)) {
4269*a90b9d01SCy Schubert *pos = '\0';
4270*a90b9d01SCy Schubert break;
4271*a90b9d01SCy Schubert }
4272*a90b9d01SCy Schubert pos += res;
4273*a90b9d01SCy Schubert }
4274*a90b9d01SCy Schubert if (auth->e_mud_url) {
4275*a90b9d01SCy Schubert size_t len = os_strlen(auth->e_mud_url);
4276*a90b9d01SCy Schubert
4277*a90b9d01SCy Schubert if (!has_ctrl_char((const u8 *) auth->e_mud_url, len))
4278*a90b9d01SCy Schubert mud_url = auth->e_mud_url;
4279*a90b9d01SCy Schubert }
4280*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_NEEDED "peer=%d src="
4281*a90b9d01SCy Schubert MACSTR " net_role=%s name=\"%s\" opclass=%s mud_url=%s",
4282*a90b9d01SCy Schubert auth->peer_bi ? auth->peer_bi->id :
4283*a90b9d01SCy Schubert auth->tmp_peer_bi->id, MAC2STR(sa),
4284*a90b9d01SCy Schubert dpp_netrole_str(auth->e_netrole), name, band, mud_url);
4285*a90b9d01SCy Schubert os_free(buf);
4286*a90b9d01SCy Schubert
4287*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s,
4288*a90b9d01SCy Schubert NULL);
4289*a90b9d01SCy Schubert eloop_register_timeout(0, 50000,
4290*a90b9d01SCy Schubert wpas_dpp_gas_initial_resp_timeout, wpa_s,
4291*a90b9d01SCy Schubert NULL);
4292*a90b9d01SCy Schubert return NULL;
4293*a90b9d01SCy Schubert }
4294*a90b9d01SCy Schubert
429585732ac8SCy Schubert auth->conf_resp = resp;
4296*a90b9d01SCy Schubert if (!resp) {
4297*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
4298*a90b9d01SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
4299*a90b9d01SCy Schubert wpa_s->dpp_auth = NULL;
4300*a90b9d01SCy Schubert }
430185732ac8SCy Schubert return resp;
430285732ac8SCy Schubert }
430385732ac8SCy Schubert
430485732ac8SCy Schubert
430585732ac8SCy Schubert static void
wpas_dpp_gas_status_handler(void * ctx,struct wpabuf * resp,int ok)430685732ac8SCy Schubert wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
430785732ac8SCy Schubert {
430885732ac8SCy Schubert struct wpa_supplicant *wpa_s = ctx;
430985732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
431085732ac8SCy Schubert
431185732ac8SCy Schubert if (!auth) {
431285732ac8SCy Schubert wpabuf_free(resp);
431385732ac8SCy Schubert return;
431485732ac8SCy Schubert }
431585732ac8SCy Schubert if (auth->conf_resp != resp) {
431685732ac8SCy Schubert wpa_printf(MSG_DEBUG,
431785732ac8SCy Schubert "DPP: Ignore GAS status report (ok=%d) for unknown response",
431885732ac8SCy Schubert ok);
431985732ac8SCy Schubert wpabuf_free(resp);
432085732ac8SCy Schubert return;
432185732ac8SCy Schubert }
432285732ac8SCy Schubert
4323c1d255d3SCy Schubert #ifdef CONFIG_DPP2
4324c1d255d3SCy Schubert if (auth->waiting_csr && ok) {
4325c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Waiting for CSR");
4326c1d255d3SCy Schubert wpabuf_free(resp);
4327c1d255d3SCy Schubert return;
4328c1d255d3SCy Schubert }
4329c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
4330c1d255d3SCy Schubert
4331*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
4332*a90b9d01SCy Schubert if (auth->waiting_new_key && ok) {
4333*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key");
4334*a90b9d01SCy Schubert wpabuf_free(resp);
4335*a90b9d01SCy Schubert return;
4336*a90b9d01SCy Schubert }
4337*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
4338*a90b9d01SCy Schubert
433985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
434085732ac8SCy Schubert ok);
434185732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
4342c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s, NULL);
434385732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
43444bc52338SCy Schubert #ifdef CONFIG_DPP2
43454bc52338SCy Schubert if (ok && auth->peer_version >= 2 &&
4346c1d255d3SCy Schubert auth->conf_resp_status == DPP_STATUS_OK &&
4347c1d255d3SCy Schubert !auth->waiting_conf_result) {
43484bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
43494bc52338SCy Schubert auth->waiting_conf_result = 1;
43504bc52338SCy Schubert auth->conf_resp = NULL;
43514bc52338SCy Schubert wpabuf_free(resp);
43524bc52338SCy Schubert eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
43534bc52338SCy Schubert wpa_s, NULL);
43544bc52338SCy Schubert eloop_register_timeout(2, 0,
43554bc52338SCy Schubert wpas_dpp_config_result_wait_timeout,
43564bc52338SCy Schubert wpa_s, NULL);
43574bc52338SCy Schubert return;
43584bc52338SCy Schubert }
43594bc52338SCy Schubert #endif /* CONFIG_DPP2 */
436085732ac8SCy Schubert offchannel_send_action_done(wpa_s);
436185732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s);
436285732ac8SCy Schubert if (ok)
4363*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT "conf_status=%d",
4364*a90b9d01SCy Schubert auth->conf_resp_status);
436585732ac8SCy Schubert else
436685732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
436785732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
436885732ac8SCy Schubert wpa_s->dpp_auth = NULL;
436985732ac8SCy Schubert wpabuf_free(resp);
4370*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
4371*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_result_indicated && wpas_dpp_pb_active(wpa_s)) {
4372*a90b9d01SCy Schubert if (ok)
4373*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT
4374*a90b9d01SCy Schubert "success");
4375*a90b9d01SCy Schubert else
4376*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT
4377*a90b9d01SCy Schubert "could-not-connect");
4378*a90b9d01SCy Schubert wpa_s->dpp_pb_result_indicated = true;
4379*a90b9d01SCy Schubert if (ok)
4380*a90b9d01SCy Schubert wpas_dpp_remove_pb_hash(wpa_s);
4381*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
4382*a90b9d01SCy Schubert }
4383*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
438485732ac8SCy Schubert }
438585732ac8SCy Schubert
438685732ac8SCy Schubert
wpas_dpp_configurator_sign(struct wpa_supplicant * wpa_s,const char * cmd)438785732ac8SCy Schubert int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd)
438885732ac8SCy Schubert {
438985732ac8SCy Schubert struct dpp_authentication *auth;
439085732ac8SCy Schubert int ret = -1;
439185732ac8SCy Schubert char *curve = NULL;
439285732ac8SCy Schubert
4393c1d255d3SCy Schubert auth = dpp_alloc_auth(wpa_s->dpp, wpa_s);
439485732ac8SCy Schubert if (!auth)
439585732ac8SCy Schubert return -1;
439685732ac8SCy Schubert
439785732ac8SCy Schubert curve = get_param(cmd, " curve=");
439885732ac8SCy Schubert wpas_dpp_set_testing_options(wpa_s, auth);
4399c1d255d3SCy Schubert if (dpp_set_configurator(auth, cmd) == 0 &&
44004bc52338SCy Schubert dpp_configurator_own_config(auth, curve, 0) == 0)
4401c1d255d3SCy Schubert ret = wpas_dpp_handle_config_obj(wpa_s, auth,
4402c1d255d3SCy Schubert &auth->conf_obj[0]);
4403c1d255d3SCy Schubert if (!ret)
4404c1d255d3SCy Schubert wpas_dpp_post_process_config(wpa_s, auth);
440585732ac8SCy Schubert
440685732ac8SCy Schubert dpp_auth_deinit(auth);
440785732ac8SCy Schubert os_free(curve);
440885732ac8SCy Schubert
440985732ac8SCy Schubert return ret;
441085732ac8SCy Schubert }
441185732ac8SCy Schubert
441285732ac8SCy Schubert
441385732ac8SCy Schubert 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)441485732ac8SCy Schubert wpas_dpp_tx_introduction_status(struct wpa_supplicant *wpa_s,
441585732ac8SCy Schubert unsigned int freq, const u8 *dst,
441685732ac8SCy Schubert const u8 *src, const u8 *bssid,
441785732ac8SCy Schubert const u8 *data, size_t data_len,
441885732ac8SCy Schubert enum offchannel_send_action_result result)
441985732ac8SCy Schubert {
442085732ac8SCy Schubert const char *res_txt;
442185732ac8SCy Schubert
442285732ac8SCy Schubert res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
442385732ac8SCy Schubert (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
442485732ac8SCy Schubert "FAILED");
442585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
442685732ac8SCy Schubert " result=%s (DPP Peer Discovery Request)",
442785732ac8SCy Schubert freq, MAC2STR(dst), res_txt);
442885732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
442985732ac8SCy Schubert " freq=%u result=%s", MAC2STR(dst), freq, res_txt);
443085732ac8SCy Schubert /* TODO: Time out wait for response more quickly in error cases? */
443185732ac8SCy Schubert }
443285732ac8SCy Schubert
443385732ac8SCy Schubert
4434*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
wpas_dpp_start_private_peer_intro(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,struct wpa_bss * bss)4435*a90b9d01SCy Schubert static int wpas_dpp_start_private_peer_intro(struct wpa_supplicant *wpa_s,
4436*a90b9d01SCy Schubert struct wpa_ssid *ssid,
4437*a90b9d01SCy Schubert struct wpa_bss *bss)
4438*a90b9d01SCy Schubert {
4439*a90b9d01SCy Schubert struct wpabuf *msg;
4440*a90b9d01SCy Schubert unsigned int wait_time;
4441*a90b9d01SCy Schubert size_t len;
4442*a90b9d01SCy Schubert u8 ver = DPP_VERSION;
4443*a90b9d01SCy Schubert int conn_ver;
4444*a90b9d01SCy Schubert
4445*a90b9d01SCy Schubert len = 5 + 5;
4446*a90b9d01SCy Schubert msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_QUERY, len);
4447*a90b9d01SCy Schubert if (!msg)
4448*a90b9d01SCy Schubert return -1;
4449*a90b9d01SCy Schubert
4450*a90b9d01SCy Schubert /* Transaction ID */
4451*a90b9d01SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
4452*a90b9d01SCy Schubert wpabuf_put_le16(msg, 1);
4453*a90b9d01SCy Schubert wpabuf_put_u8(msg, TRANSACTION_ID);
4454*a90b9d01SCy Schubert
4455*a90b9d01SCy Schubert conn_ver = dpp_get_connector_version(ssid->dpp_connector);
4456*a90b9d01SCy Schubert if (conn_ver > 0 && ver != conn_ver) {
4457*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
4458*a90b9d01SCy Schubert "DPP: Use Connector version %d instead of current protocol version %d",
4459*a90b9d01SCy Schubert conn_ver, ver);
4460*a90b9d01SCy Schubert ver = conn_ver;
4461*a90b9d01SCy Schubert }
4462*a90b9d01SCy Schubert
4463*a90b9d01SCy Schubert /* Protocol Version */
4464*a90b9d01SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
4465*a90b9d01SCy Schubert wpabuf_put_le16(msg, 1);
4466*a90b9d01SCy Schubert wpabuf_put_u8(msg, ver);
4467*a90b9d01SCy Schubert
4468*a90b9d01SCy Schubert wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Private Peer Intro Query", msg);
4469*a90b9d01SCy Schubert
4470*a90b9d01SCy Schubert /* TODO: Timeout on AP response */
4471*a90b9d01SCy Schubert wait_time = wpa_s->max_remain_on_chan;
4472*a90b9d01SCy Schubert if (wait_time > 2000)
4473*a90b9d01SCy Schubert wait_time = 2000;
4474*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
4475*a90b9d01SCy Schubert MAC2STR(bss->bssid), bss->freq, DPP_PA_PRIV_PEER_INTRO_QUERY);
4476*a90b9d01SCy Schubert offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr,
4477*a90b9d01SCy Schubert broadcast,
4478*a90b9d01SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
4479*a90b9d01SCy Schubert wait_time, wpas_dpp_tx_introduction_status, 0);
4480*a90b9d01SCy Schubert wpabuf_free(msg);
4481*a90b9d01SCy Schubert
4482*a90b9d01SCy Schubert /* Request this connection attempt to terminate - new one will be
4483*a90b9d01SCy Schubert * started when network introduction protocol completes */
4484*a90b9d01SCy Schubert os_memcpy(wpa_s->dpp_intro_bssid, bss->bssid, ETH_ALEN);
4485*a90b9d01SCy Schubert wpa_s->dpp_intro_network = ssid;
4486*a90b9d01SCy Schubert return 1;
4487*a90b9d01SCy Schubert }
4488*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
4489*a90b9d01SCy Schubert
4490*a90b9d01SCy Schubert
wpas_dpp_check_connect(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,struct wpa_bss * bss)449185732ac8SCy Schubert int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
449285732ac8SCy Schubert struct wpa_bss *bss)
449385732ac8SCy Schubert {
449485732ac8SCy Schubert struct os_time now;
449585732ac8SCy Schubert struct wpabuf *msg;
449685732ac8SCy Schubert unsigned int wait_time;
44974bc52338SCy Schubert const u8 *rsn;
44984bc52338SCy Schubert struct wpa_ie_data ied;
4499c1d255d3SCy Schubert size_t len;
450085732ac8SCy Schubert
450185732ac8SCy Schubert if (!(ssid->key_mgmt & WPA_KEY_MGMT_DPP) || !bss)
450285732ac8SCy Schubert return 0; /* Not using DPP AKM - continue */
45034bc52338SCy Schubert rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
45044bc52338SCy Schubert if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
45054bc52338SCy Schubert !(ied.key_mgmt & WPA_KEY_MGMT_DPP))
45064bc52338SCy Schubert return 0; /* AP does not support DPP AKM - continue */
4507*a90b9d01SCy Schubert if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, wpa_s->own_addr, ssid))
450885732ac8SCy Schubert return 0; /* PMKSA exists for DPP AKM - continue */
450985732ac8SCy Schubert
451085732ac8SCy Schubert if (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
451185732ac8SCy Schubert !ssid->dpp_csign) {
451285732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR
451385732ac8SCy Schubert "missing %s",
451485732ac8SCy Schubert !ssid->dpp_connector ? "Connector" :
451585732ac8SCy Schubert (!ssid->dpp_netaccesskey ? "netAccessKey" :
451685732ac8SCy Schubert "C-sign-key"));
451785732ac8SCy Schubert return -1;
451885732ac8SCy Schubert }
451985732ac8SCy Schubert
452085732ac8SCy Schubert os_get_time(&now);
452185732ac8SCy Schubert
452285732ac8SCy Schubert if (ssid->dpp_netaccesskey_expiry &&
452385732ac8SCy Schubert (os_time_t) ssid->dpp_netaccesskey_expiry < now.sec) {
452485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR
452585732ac8SCy Schubert "netAccessKey expired");
452685732ac8SCy Schubert return -1;
452785732ac8SCy Schubert }
452885732ac8SCy Schubert
452985732ac8SCy Schubert wpa_printf(MSG_DEBUG,
4530*a90b9d01SCy Schubert "DPP: Starting %snetwork introduction protocol to derive PMKSA for "
4531*a90b9d01SCy Schubert MACSTR,
4532*a90b9d01SCy Schubert ssid->dpp_connector_privacy ? "private " : "",
4533*a90b9d01SCy Schubert MAC2STR(bss->bssid));
4534*a90b9d01SCy Schubert if (wpa_s->wpa_state == WPA_SCANNING)
4535*a90b9d01SCy Schubert wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state);
4536*a90b9d01SCy Schubert
4537*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
4538*a90b9d01SCy Schubert if (ssid->dpp_connector_privacy)
4539*a90b9d01SCy Schubert return wpas_dpp_start_private_peer_intro(wpa_s, ssid, bss);
4540*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
454185732ac8SCy Schubert
4542c1d255d3SCy Schubert len = 5 + 4 + os_strlen(ssid->dpp_connector);
4543c1d255d3SCy Schubert #ifdef CONFIG_DPP2
4544c1d255d3SCy Schubert len += 5;
4545c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
4546c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ, len);
454785732ac8SCy Schubert if (!msg)
454885732ac8SCy Schubert return -1;
454985732ac8SCy Schubert
455085732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
455185732ac8SCy Schubert if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ) {
455285732ac8SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
455385732ac8SCy Schubert goto skip_trans_id;
455485732ac8SCy Schubert }
455585732ac8SCy Schubert if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ) {
455685732ac8SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
455785732ac8SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
455885732ac8SCy Schubert wpabuf_put_le16(msg, 0);
455985732ac8SCy Schubert goto skip_trans_id;
456085732ac8SCy Schubert }
456185732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
456285732ac8SCy Schubert
456385732ac8SCy Schubert /* Transaction ID */
456485732ac8SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
456585732ac8SCy Schubert wpabuf_put_le16(msg, 1);
456685732ac8SCy Schubert wpabuf_put_u8(msg, TRANSACTION_ID);
456785732ac8SCy Schubert
456885732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
456985732ac8SCy Schubert skip_trans_id:
457085732ac8SCy Schubert if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ) {
457185732ac8SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
457285732ac8SCy Schubert goto skip_connector;
457385732ac8SCy Schubert }
457485732ac8SCy Schubert if (dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ) {
457585732ac8SCy Schubert char *connector;
457685732ac8SCy Schubert
457785732ac8SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
457885732ac8SCy Schubert connector = dpp_corrupt_connector_signature(
457985732ac8SCy Schubert ssid->dpp_connector);
458085732ac8SCy Schubert if (!connector) {
458185732ac8SCy Schubert wpabuf_free(msg);
458285732ac8SCy Schubert return -1;
458385732ac8SCy Schubert }
458485732ac8SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
458585732ac8SCy Schubert wpabuf_put_le16(msg, os_strlen(connector));
458685732ac8SCy Schubert wpabuf_put_str(msg, connector);
458785732ac8SCy Schubert os_free(connector);
458885732ac8SCy Schubert goto skip_connector;
458985732ac8SCy Schubert }
459085732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
459185732ac8SCy Schubert
459285732ac8SCy Schubert /* DPP Connector */
459385732ac8SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
459485732ac8SCy Schubert wpabuf_put_le16(msg, os_strlen(ssid->dpp_connector));
459585732ac8SCy Schubert wpabuf_put_str(msg, ssid->dpp_connector);
459685732ac8SCy Schubert
459785732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
459885732ac8SCy Schubert skip_connector:
459932a95656SCy Schubert if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_REQ) {
460032a95656SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version");
460132a95656SCy Schubert goto skip_proto_ver;
460232a95656SCy Schubert }
460385732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
460485732ac8SCy Schubert
4605c1d255d3SCy Schubert #ifdef CONFIG_DPP2
4606c1d255d3SCy Schubert if (DPP_VERSION > 1) {
460732a95656SCy Schubert u8 ver = DPP_VERSION;
460832a95656SCy Schubert #ifdef CONFIG_DPP3
460932a95656SCy Schubert int conn_ver;
461032a95656SCy Schubert
461132a95656SCy Schubert conn_ver = dpp_get_connector_version(ssid->dpp_connector);
461232a95656SCy Schubert if (conn_ver > 0 && ver != conn_ver) {
461332a95656SCy Schubert wpa_printf(MSG_DEBUG,
461432a95656SCy Schubert "DPP: Use Connector version %d instead of current protocol version %d",
461532a95656SCy Schubert conn_ver, ver);
461632a95656SCy Schubert ver = conn_ver;
461732a95656SCy Schubert }
461832a95656SCy Schubert #endif /* CONFIG_DPP3 */
461932a95656SCy Schubert
4620*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
4621*a90b9d01SCy Schubert if (dpp_test == DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_REQ) {
4622*a90b9d01SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Protocol Version");
4623*a90b9d01SCy Schubert ver = 1;
4624*a90b9d01SCy Schubert }
4625*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
4626*a90b9d01SCy Schubert
4627c1d255d3SCy Schubert /* Protocol Version */
4628c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
4629c1d255d3SCy Schubert wpabuf_put_le16(msg, 1);
463032a95656SCy Schubert wpabuf_put_u8(msg, ver);
4631c1d255d3SCy Schubert }
4632c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
4633c1d255d3SCy Schubert
463432a95656SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
463532a95656SCy Schubert skip_proto_ver:
463632a95656SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
463732a95656SCy Schubert
463885732ac8SCy Schubert /* TODO: Timeout on AP response */
463985732ac8SCy Schubert wait_time = wpa_s->max_remain_on_chan;
464085732ac8SCy Schubert if (wait_time > 2000)
464185732ac8SCy Schubert wait_time = 2000;
464285732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
464385732ac8SCy Schubert MAC2STR(bss->bssid), bss->freq, DPP_PA_PEER_DISCOVERY_REQ);
464485732ac8SCy Schubert offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr,
464585732ac8SCy Schubert broadcast,
464685732ac8SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
464785732ac8SCy Schubert wait_time, wpas_dpp_tx_introduction_status, 0);
464885732ac8SCy Schubert wpabuf_free(msg);
464985732ac8SCy Schubert
465085732ac8SCy Schubert /* Request this connection attempt to terminate - new one will be
465185732ac8SCy Schubert * started when network introduction protocol completes */
465285732ac8SCy Schubert os_memcpy(wpa_s->dpp_intro_bssid, bss->bssid, ETH_ALEN);
465385732ac8SCy Schubert wpa_s->dpp_intro_network = ssid;
465485732ac8SCy Schubert return 1;
465585732ac8SCy Schubert }
465685732ac8SCy Schubert
465785732ac8SCy Schubert
wpas_dpp_pkex_add(struct wpa_supplicant * wpa_s,const char * cmd)465885732ac8SCy Schubert int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
465985732ac8SCy Schubert {
466085732ac8SCy Schubert struct dpp_bootstrap_info *own_bi;
466185732ac8SCy Schubert const char *pos, *end;
4662*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
4663*a90b9d01SCy Schubert enum dpp_pkex_ver ver = PKEX_VER_AUTO;
4664*a90b9d01SCy Schubert #else /* CONFIG_DPP3 */
4665*a90b9d01SCy Schubert enum dpp_pkex_ver ver = PKEX_VER_ONLY_1;
4666*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
4667*a90b9d01SCy Schubert int tcp_port = DPP_TCP_PORT;
4668*a90b9d01SCy Schubert struct hostapd_ip_addr *ipaddr = NULL;
4669*a90b9d01SCy Schubert #ifdef CONFIG_DPP2
4670*a90b9d01SCy Schubert struct hostapd_ip_addr ipaddr_buf;
4671*a90b9d01SCy Schubert char *addr;
4672*a90b9d01SCy Schubert
4673*a90b9d01SCy Schubert pos = os_strstr(cmd, " tcp_port=");
4674*a90b9d01SCy Schubert if (pos) {
4675*a90b9d01SCy Schubert pos += 10;
4676*a90b9d01SCy Schubert tcp_port = atoi(pos);
4677*a90b9d01SCy Schubert }
4678*a90b9d01SCy Schubert
4679*a90b9d01SCy Schubert addr = get_param(cmd, " tcp_addr=");
4680*a90b9d01SCy Schubert if (addr) {
4681*a90b9d01SCy Schubert int res;
4682*a90b9d01SCy Schubert
4683*a90b9d01SCy Schubert res = hostapd_parse_ip_addr(addr, &ipaddr_buf);
4684*a90b9d01SCy Schubert os_free(addr);
4685*a90b9d01SCy Schubert if (res)
4686*a90b9d01SCy Schubert return -1;
4687*a90b9d01SCy Schubert ipaddr = &ipaddr_buf;
4688*a90b9d01SCy Schubert }
4689*a90b9d01SCy Schubert #endif /* CONFIG_DPP2 */
469085732ac8SCy Schubert
469185732ac8SCy Schubert pos = os_strstr(cmd, " own=");
469285732ac8SCy Schubert if (!pos)
469385732ac8SCy Schubert return -1;
469485732ac8SCy Schubert pos += 5;
46954bc52338SCy Schubert own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
469685732ac8SCy Schubert if (!own_bi) {
469785732ac8SCy Schubert wpa_printf(MSG_DEBUG,
469885732ac8SCy Schubert "DPP: Identified bootstrap info not found");
469985732ac8SCy Schubert return -1;
470085732ac8SCy Schubert }
470185732ac8SCy Schubert if (own_bi->type != DPP_BOOTSTRAP_PKEX) {
470285732ac8SCy Schubert wpa_printf(MSG_DEBUG,
470385732ac8SCy Schubert "DPP: Identified bootstrap info not for PKEX");
470485732ac8SCy Schubert return -1;
470585732ac8SCy Schubert }
470685732ac8SCy Schubert wpa_s->dpp_pkex_bi = own_bi;
470785732ac8SCy Schubert own_bi->pkex_t = 0; /* clear pending errors on new code */
470885732ac8SCy Schubert
470985732ac8SCy Schubert os_free(wpa_s->dpp_pkex_identifier);
471085732ac8SCy Schubert wpa_s->dpp_pkex_identifier = NULL;
471185732ac8SCy Schubert pos = os_strstr(cmd, " identifier=");
471285732ac8SCy Schubert if (pos) {
471385732ac8SCy Schubert pos += 12;
471485732ac8SCy Schubert end = os_strchr(pos, ' ');
471585732ac8SCy Schubert if (!end)
471685732ac8SCy Schubert return -1;
471785732ac8SCy Schubert wpa_s->dpp_pkex_identifier = os_malloc(end - pos + 1);
471885732ac8SCy Schubert if (!wpa_s->dpp_pkex_identifier)
471985732ac8SCy Schubert return -1;
472085732ac8SCy Schubert os_memcpy(wpa_s->dpp_pkex_identifier, pos, end - pos);
472185732ac8SCy Schubert wpa_s->dpp_pkex_identifier[end - pos] = '\0';
472285732ac8SCy Schubert }
472385732ac8SCy Schubert
472485732ac8SCy Schubert pos = os_strstr(cmd, " code=");
472585732ac8SCy Schubert if (!pos)
472685732ac8SCy Schubert return -1;
472785732ac8SCy Schubert os_free(wpa_s->dpp_pkex_code);
472885732ac8SCy Schubert wpa_s->dpp_pkex_code = os_strdup(pos + 6);
472985732ac8SCy Schubert if (!wpa_s->dpp_pkex_code)
473085732ac8SCy Schubert return -1;
4731*a90b9d01SCy Schubert wpa_s->dpp_pkex_code_len = os_strlen(wpa_s->dpp_pkex_code);
473285732ac8SCy Schubert
4733*a90b9d01SCy Schubert pos = os_strstr(cmd, " ver=");
4734*a90b9d01SCy Schubert if (pos) {
4735*a90b9d01SCy Schubert int v;
473685732ac8SCy Schubert
4737*a90b9d01SCy Schubert pos += 5;
4738*a90b9d01SCy Schubert v = atoi(pos);
4739*a90b9d01SCy Schubert if (v == 1)
4740*a90b9d01SCy Schubert ver = PKEX_VER_ONLY_1;
4741*a90b9d01SCy Schubert else if (v == 2)
4742*a90b9d01SCy Schubert ver = PKEX_VER_ONLY_2;
4743*a90b9d01SCy Schubert else
474485732ac8SCy Schubert return -1;
4745*a90b9d01SCy Schubert }
4746*a90b9d01SCy Schubert wpa_s->dpp_pkex_ver = ver;
474785732ac8SCy Schubert
4748*a90b9d01SCy Schubert if (os_strstr(cmd, " init=1")) {
4749*a90b9d01SCy Schubert if (wpas_dpp_pkex_init(wpa_s, ver, ipaddr, tcp_port) < 0)
4750*a90b9d01SCy Schubert return -1;
4751*a90b9d01SCy Schubert } else {
4752*a90b9d01SCy Schubert #ifdef CONFIG_DPP2
4753*a90b9d01SCy Schubert dpp_controller_pkex_add(wpa_s->dpp, own_bi,
4754*a90b9d01SCy Schubert wpa_s->dpp_pkex_code,
4755*a90b9d01SCy Schubert wpa_s->dpp_pkex_identifier);
4756*a90b9d01SCy Schubert #endif /* CONFIG_DPP2 */
475785732ac8SCy Schubert }
475885732ac8SCy Schubert
475985732ac8SCy Schubert /* TODO: Support multiple PKEX info entries */
476085732ac8SCy Schubert
476185732ac8SCy Schubert os_free(wpa_s->dpp_pkex_auth_cmd);
476285732ac8SCy Schubert wpa_s->dpp_pkex_auth_cmd = os_strdup(cmd);
476385732ac8SCy Schubert
476485732ac8SCy Schubert return 1;
476585732ac8SCy Schubert }
476685732ac8SCy Schubert
476785732ac8SCy Schubert
wpas_dpp_pkex_remove(struct wpa_supplicant * wpa_s,const char * id)476885732ac8SCy Schubert int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id)
476985732ac8SCy Schubert {
477085732ac8SCy Schubert unsigned int id_val;
477185732ac8SCy Schubert
477285732ac8SCy Schubert if (os_strcmp(id, "*") == 0) {
477385732ac8SCy Schubert id_val = 0;
477485732ac8SCy Schubert } else {
477585732ac8SCy Schubert id_val = atoi(id);
477685732ac8SCy Schubert if (id_val == 0)
477785732ac8SCy Schubert return -1;
477885732ac8SCy Schubert }
477985732ac8SCy Schubert
4780*a90b9d01SCy Schubert if ((id_val != 0 && id_val != 1))
478185732ac8SCy Schubert return -1;
478285732ac8SCy Schubert
478385732ac8SCy Schubert /* TODO: Support multiple PKEX entries */
478485732ac8SCy Schubert os_free(wpa_s->dpp_pkex_code);
478585732ac8SCy Schubert wpa_s->dpp_pkex_code = NULL;
478685732ac8SCy Schubert os_free(wpa_s->dpp_pkex_identifier);
478785732ac8SCy Schubert wpa_s->dpp_pkex_identifier = NULL;
478885732ac8SCy Schubert os_free(wpa_s->dpp_pkex_auth_cmd);
478985732ac8SCy Schubert wpa_s->dpp_pkex_auth_cmd = NULL;
479085732ac8SCy Schubert wpa_s->dpp_pkex_bi = NULL;
479185732ac8SCy Schubert /* TODO: Remove dpp_pkex only if it is for the identified PKEX code */
479285732ac8SCy Schubert dpp_pkex_free(wpa_s->dpp_pkex);
479385732ac8SCy Schubert wpa_s->dpp_pkex = NULL;
479485732ac8SCy Schubert return 0;
479585732ac8SCy Schubert }
479685732ac8SCy Schubert
479785732ac8SCy Schubert
wpas_dpp_stop(struct wpa_supplicant * wpa_s)479885732ac8SCy Schubert void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
479985732ac8SCy Schubert {
4800*a90b9d01SCy Schubert if (wpa_s->dpp_auth || wpa_s->dpp_pkex || wpa_s->dpp_pkex_wait_auth_req)
4801c1d255d3SCy Schubert offchannel_send_action_done(wpa_s);
480285732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth);
480385732ac8SCy Schubert wpa_s->dpp_auth = NULL;
480485732ac8SCy Schubert dpp_pkex_free(wpa_s->dpp_pkex);
480585732ac8SCy Schubert wpa_s->dpp_pkex = NULL;
4806*a90b9d01SCy Schubert wpa_s->dpp_pkex_wait_auth_req = false;
480785732ac8SCy Schubert if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0)
480885732ac8SCy Schubert gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token);
4809*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
4810*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
4811*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
481285732ac8SCy Schubert }
481385732ac8SCy Schubert
481485732ac8SCy Schubert
wpas_dpp_init(struct wpa_supplicant * wpa_s)481585732ac8SCy Schubert int wpas_dpp_init(struct wpa_supplicant *wpa_s)
481685732ac8SCy Schubert {
4817206b73d0SCy Schubert struct dpp_global_config config;
481885732ac8SCy Schubert u8 adv_proto_id[7];
481985732ac8SCy Schubert
482085732ac8SCy Schubert adv_proto_id[0] = WLAN_EID_VENDOR_SPECIFIC;
482185732ac8SCy Schubert adv_proto_id[1] = 5;
482285732ac8SCy Schubert WPA_PUT_BE24(&adv_proto_id[2], OUI_WFA);
482385732ac8SCy Schubert adv_proto_id[5] = DPP_OUI_TYPE;
482485732ac8SCy Schubert adv_proto_id[6] = 0x01;
482585732ac8SCy Schubert
482685732ac8SCy Schubert if (gas_server_register(wpa_s->gas_server, adv_proto_id,
482785732ac8SCy Schubert sizeof(adv_proto_id), wpas_dpp_gas_req_handler,
482885732ac8SCy Schubert wpas_dpp_gas_status_handler, wpa_s) < 0)
482985732ac8SCy Schubert return -1;
4830206b73d0SCy Schubert
4831206b73d0SCy Schubert os_memset(&config, 0, sizeof(config));
4832206b73d0SCy Schubert config.cb_ctx = wpa_s;
4833206b73d0SCy Schubert #ifdef CONFIG_DPP2
4834c1d255d3SCy Schubert config.remove_bi = wpas_dpp_remove_bi;
4835206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
4836206b73d0SCy Schubert wpa_s->dpp = dpp_global_init(&config);
48374bc52338SCy Schubert return wpa_s->dpp ? 0 : -1;
483885732ac8SCy Schubert }
483985732ac8SCy Schubert
484085732ac8SCy Schubert
wpas_dpp_deinit(struct wpa_supplicant * wpa_s)484185732ac8SCy Schubert void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
484285732ac8SCy Schubert {
484385732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
484485732ac8SCy Schubert os_free(wpa_s->dpp_config_obj_override);
484585732ac8SCy Schubert wpa_s->dpp_config_obj_override = NULL;
484685732ac8SCy Schubert os_free(wpa_s->dpp_discovery_override);
484785732ac8SCy Schubert wpa_s->dpp_discovery_override = NULL;
484885732ac8SCy Schubert os_free(wpa_s->dpp_groups_override);
484985732ac8SCy Schubert wpa_s->dpp_groups_override = NULL;
485085732ac8SCy Schubert wpa_s->dpp_ignore_netaccesskey_mismatch = 0;
485185732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
48524bc52338SCy Schubert if (!wpa_s->dpp)
485385732ac8SCy Schubert return;
485485732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
485585732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
4856c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s, NULL);
485785732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
485885732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
4859*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, NULL);
4860*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_gas_client_timeout, wpa_s, NULL);
4861*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_drv_wait_timeout, wpa_s, NULL);
4862*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_tx_auth_resp_roc_timeout, wpa_s, NULL);
4863*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_neg_freq_timeout, wpa_s, NULL);
48644bc52338SCy Schubert #ifdef CONFIG_DPP2
48654bc52338SCy Schubert eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
4866c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
4867c1d255d3SCy Schubert wpa_s, NULL);
4868c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
4869c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
4870c1d255d3SCy Schubert wpa_s, NULL);
4871c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_build_csr, wpa_s, NULL);
4872*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_connected_timeout, wpa_s, NULL);
48734bc52338SCy Schubert dpp_pfs_free(wpa_s->dpp_pfs);
48744bc52338SCy Schubert wpa_s->dpp_pfs = NULL;
4875c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
4876c1d255d3SCy Schubert dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
4877c1d255d3SCy Schubert wpa_s->dpp_reconfig_id = NULL;
48784bc52338SCy Schubert #endif /* CONFIG_DPP2 */
4879*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
4880*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_build_new_key, wpa_s, NULL);
4881*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
488285732ac8SCy Schubert offchannel_send_action_done(wpa_s);
488385732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s);
488485732ac8SCy Schubert wpas_dpp_stop(wpa_s);
488585732ac8SCy Schubert wpas_dpp_pkex_remove(wpa_s, "*");
488685732ac8SCy Schubert os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN);
488785732ac8SCy Schubert os_free(wpa_s->dpp_configurator_params);
488885732ac8SCy Schubert wpa_s->dpp_configurator_params = NULL;
4889c1d255d3SCy Schubert dpp_global_clear(wpa_s->dpp);
489085732ac8SCy Schubert }
4891206b73d0SCy Schubert
4892206b73d0SCy Schubert
wpas_dpp_build_conf_resp(struct wpa_supplicant * wpa_s,struct dpp_authentication * auth,bool tcp)4893*a90b9d01SCy Schubert static int wpas_dpp_build_conf_resp(struct wpa_supplicant *wpa_s,
4894*a90b9d01SCy Schubert struct dpp_authentication *auth, bool tcp)
4895*a90b9d01SCy Schubert {
4896*a90b9d01SCy Schubert struct wpabuf *resp;
4897*a90b9d01SCy Schubert
4898*a90b9d01SCy Schubert resp = dpp_build_conf_resp(auth, auth->e_nonce, auth->curve->nonce_len,
4899*a90b9d01SCy Schubert auth->e_netrole, true);
4900*a90b9d01SCy Schubert if (!resp)
4901*a90b9d01SCy Schubert return -1;
4902*a90b9d01SCy Schubert
4903*a90b9d01SCy Schubert if (tcp) {
4904*a90b9d01SCy Schubert auth->conf_resp_tcp = resp;
4905*a90b9d01SCy Schubert return 0;
4906*a90b9d01SCy Schubert }
4907*a90b9d01SCy Schubert
4908*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, NULL);
4909*a90b9d01SCy Schubert if (gas_server_set_resp(wpa_s->gas_server, auth->config_resp_ctx,
4910*a90b9d01SCy Schubert resp) < 0) {
4911*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
4912*a90b9d01SCy Schubert "DPP: Could not find pending GAS response");
4913*a90b9d01SCy Schubert wpabuf_free(resp);
4914*a90b9d01SCy Schubert return -1;
4915*a90b9d01SCy Schubert }
4916*a90b9d01SCy Schubert auth->conf_resp = resp;
4917*a90b9d01SCy Schubert return 0;
4918*a90b9d01SCy Schubert }
4919*a90b9d01SCy Schubert
4920*a90b9d01SCy Schubert
wpas_dpp_conf_set(struct wpa_supplicant * wpa_s,const char * cmd)4921*a90b9d01SCy Schubert int wpas_dpp_conf_set(struct wpa_supplicant *wpa_s, const char *cmd)
4922*a90b9d01SCy Schubert {
4923*a90b9d01SCy Schubert int peer;
4924*a90b9d01SCy Schubert const char *pos;
4925*a90b9d01SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
4926*a90b9d01SCy Schubert bool tcp = false;
4927*a90b9d01SCy Schubert
4928*a90b9d01SCy Schubert pos = os_strstr(cmd, " peer=");
4929*a90b9d01SCy Schubert if (!pos)
4930*a90b9d01SCy Schubert return -1;
4931*a90b9d01SCy Schubert peer = atoi(pos + 6);
4932*a90b9d01SCy Schubert #ifdef CONFIG_DPP2
4933*a90b9d01SCy Schubert if (!auth || !auth->waiting_config ||
4934*a90b9d01SCy Schubert (auth->peer_bi &&
4935*a90b9d01SCy Schubert (unsigned int) peer != auth->peer_bi->id)) {
4936*a90b9d01SCy Schubert auth = dpp_controller_get_auth(wpa_s->dpp, peer);
4937*a90b9d01SCy Schubert tcp = true;
4938*a90b9d01SCy Schubert }
4939*a90b9d01SCy Schubert #endif /* CONFIG_DPP2 */
4940*a90b9d01SCy Schubert
4941*a90b9d01SCy Schubert if (!auth || !auth->waiting_config) {
4942*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
4943*a90b9d01SCy Schubert "DPP: No authentication exchange waiting for configuration information");
4944*a90b9d01SCy Schubert return -1;
4945*a90b9d01SCy Schubert }
4946*a90b9d01SCy Schubert
4947*a90b9d01SCy Schubert if ((!auth->peer_bi ||
4948*a90b9d01SCy Schubert (unsigned int) peer != auth->peer_bi->id) &&
4949*a90b9d01SCy Schubert (!auth->tmp_peer_bi ||
4950*a90b9d01SCy Schubert (unsigned int) peer != auth->tmp_peer_bi->id)) {
4951*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer mismatch");
4952*a90b9d01SCy Schubert return -1;
4953*a90b9d01SCy Schubert }
4954*a90b9d01SCy Schubert
4955*a90b9d01SCy Schubert pos = os_strstr(cmd, " comeback=");
4956*a90b9d01SCy Schubert if (pos) {
4957*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s,
4958*a90b9d01SCy Schubert NULL);
4959*a90b9d01SCy Schubert gas_server_set_comeback_delay(wpa_s->gas_server,
4960*a90b9d01SCy Schubert auth->config_resp_ctx,
4961*a90b9d01SCy Schubert atoi(pos + 10));
4962*a90b9d01SCy Schubert return 0;
4963*a90b9d01SCy Schubert }
4964*a90b9d01SCy Schubert
4965*a90b9d01SCy Schubert if (dpp_set_configurator(auth, cmd) < 0)
4966*a90b9d01SCy Schubert return -1;
4967*a90b9d01SCy Schubert
4968*a90b9d01SCy Schubert auth->use_config_query = false;
4969*a90b9d01SCy Schubert auth->waiting_config = false;
4970*a90b9d01SCy Schubert return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
4971*a90b9d01SCy Schubert }
4972*a90b9d01SCy Schubert
4973*a90b9d01SCy Schubert
4974206b73d0SCy Schubert #ifdef CONFIG_DPP2
4975c1d255d3SCy Schubert
wpas_dpp_controller_start(struct wpa_supplicant * wpa_s,const char * cmd)4976206b73d0SCy Schubert int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
4977206b73d0SCy Schubert {
4978206b73d0SCy Schubert struct dpp_controller_config config;
4979206b73d0SCy Schubert const char *pos;
4980206b73d0SCy Schubert
4981206b73d0SCy Schubert os_memset(&config, 0, sizeof(config));
4982c1d255d3SCy Schubert config.allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
4983c1d255d3SCy Schubert config.netrole = DPP_NETROLE_STA;
4984c1d255d3SCy Schubert config.msg_ctx = wpa_s;
4985c1d255d3SCy Schubert config.cb_ctx = wpa_s;
4986c1d255d3SCy Schubert config.process_conf_obj = wpas_dpp_process_conf_obj;
4987*a90b9d01SCy Schubert config.tcp_msg_sent = wpas_dpp_tcp_msg_sent;
4988206b73d0SCy Schubert if (cmd) {
4989206b73d0SCy Schubert pos = os_strstr(cmd, " tcp_port=");
4990206b73d0SCy Schubert if (pos) {
4991206b73d0SCy Schubert pos += 10;
4992206b73d0SCy Schubert config.tcp_port = atoi(pos);
4993206b73d0SCy Schubert }
4994c1d255d3SCy Schubert
4995c1d255d3SCy Schubert pos = os_strstr(cmd, " role=");
4996c1d255d3SCy Schubert if (pos) {
4997c1d255d3SCy Schubert pos += 6;
4998c1d255d3SCy Schubert if (os_strncmp(pos, "configurator", 12) == 0)
4999c1d255d3SCy Schubert config.allowed_roles = DPP_CAPAB_CONFIGURATOR;
5000c1d255d3SCy Schubert else if (os_strncmp(pos, "enrollee", 8) == 0)
5001c1d255d3SCy Schubert config.allowed_roles = DPP_CAPAB_ENROLLEE;
5002c1d255d3SCy Schubert else if (os_strncmp(pos, "either", 6) == 0)
5003c1d255d3SCy Schubert config.allowed_roles = DPP_CAPAB_CONFIGURATOR |
5004c1d255d3SCy Schubert DPP_CAPAB_ENROLLEE;
5005c1d255d3SCy Schubert else
5006c1d255d3SCy Schubert return -1;
5007c1d255d3SCy Schubert }
5008c1d255d3SCy Schubert
5009c1d255d3SCy Schubert config.qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
5010206b73d0SCy Schubert }
5011206b73d0SCy Schubert config.configurator_params = wpa_s->dpp_configurator_params;
5012206b73d0SCy Schubert return dpp_controller_start(wpa_s->dpp, &config);
5013206b73d0SCy Schubert }
5014c1d255d3SCy Schubert
5015c1d255d3SCy Schubert
5016c1d255d3SCy Schubert static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
5017c1d255d3SCy Schubert
wpas_dpp_chirp_timeout(void * eloop_ctx,void * timeout_ctx)5018c1d255d3SCy Schubert static void wpas_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
5019c1d255d3SCy Schubert {
5020c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
5021c1d255d3SCy Schubert
5022c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No chirp response received");
5023c1d255d3SCy Schubert offchannel_send_action_done(wpa_s);
5024c1d255d3SCy Schubert wpas_dpp_chirp_next(wpa_s, NULL);
5025c1d255d3SCy Schubert }
5026c1d255d3SCy Schubert
5027c1d255d3SCy Schubert
wpas_dpp_chirp_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)5028c1d255d3SCy Schubert static void wpas_dpp_chirp_tx_status(struct wpa_supplicant *wpa_s,
5029c1d255d3SCy Schubert unsigned int freq, const u8 *dst,
5030c1d255d3SCy Schubert const u8 *src, const u8 *bssid,
5031c1d255d3SCy Schubert const u8 *data, size_t data_len,
5032c1d255d3SCy Schubert enum offchannel_send_action_result result)
5033c1d255d3SCy Schubert {
5034c1d255d3SCy Schubert if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
5035c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to send chirp on %d MHz",
5036c1d255d3SCy Schubert wpa_s->dpp_chirp_freq);
5037c1d255d3SCy Schubert if (eloop_register_timeout(0, 0, wpas_dpp_chirp_next,
5038c1d255d3SCy Schubert wpa_s, NULL) < 0)
5039c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
5040c1d255d3SCy Schubert return;
5041c1d255d3SCy Schubert }
5042c1d255d3SCy Schubert
5043c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Chirp send completed - wait for response");
5044c1d255d3SCy Schubert if (eloop_register_timeout(2, 0, wpas_dpp_chirp_timeout,
5045c1d255d3SCy Schubert wpa_s, NULL) < 0)
5046c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
5047c1d255d3SCy Schubert }
5048c1d255d3SCy Schubert
5049c1d255d3SCy Schubert
wpas_dpp_chirp_start(struct wpa_supplicant * wpa_s)5050c1d255d3SCy Schubert static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
5051c1d255d3SCy Schubert {
5052c1d255d3SCy Schubert struct wpabuf *msg, *announce = NULL;
5053c1d255d3SCy Schubert int type;
5054c1d255d3SCy Schubert
5055c1d255d3SCy Schubert msg = wpa_s->dpp_presence_announcement;
5056c1d255d3SCy Schubert type = DPP_PA_PRESENCE_ANNOUNCEMENT;
5057c1d255d3SCy Schubert if (!msg) {
5058c1d255d3SCy Schubert struct wpa_ssid *ssid = wpa_s->dpp_reconfig_ssid;
5059c1d255d3SCy Schubert
5060c1d255d3SCy Schubert if (ssid && wpa_s->dpp_reconfig_id &&
5061c1d255d3SCy Schubert wpa_config_get_network(wpa_s->conf,
5062c1d255d3SCy Schubert wpa_s->dpp_reconfig_ssid_id) ==
5063c1d255d3SCy Schubert ssid) {
5064c1d255d3SCy Schubert announce = dpp_build_reconfig_announcement(
5065c1d255d3SCy Schubert ssid->dpp_csign,
5066c1d255d3SCy Schubert ssid->dpp_csign_len,
5067c1d255d3SCy Schubert ssid->dpp_netaccesskey,
5068c1d255d3SCy Schubert ssid->dpp_netaccesskey_len,
5069c1d255d3SCy Schubert wpa_s->dpp_reconfig_id);
5070c1d255d3SCy Schubert msg = announce;
5071c1d255d3SCy Schubert }
5072c1d255d3SCy Schubert if (!msg)
5073c1d255d3SCy Schubert return;
5074c1d255d3SCy Schubert type = DPP_PA_RECONFIG_ANNOUNCEMENT;
5075c1d255d3SCy Schubert }
5076c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", wpa_s->dpp_chirp_freq);
5077c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
5078c1d255d3SCy Schubert MAC2STR(broadcast), wpa_s->dpp_chirp_freq, type);
5079c1d255d3SCy Schubert if (offchannel_send_action(
5080c1d255d3SCy Schubert wpa_s, wpa_s->dpp_chirp_freq, broadcast,
5081c1d255d3SCy Schubert wpa_s->own_addr, broadcast,
5082c1d255d3SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
5083c1d255d3SCy Schubert 2000, wpas_dpp_chirp_tx_status, 0) < 0)
5084c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
5085c1d255d3SCy Schubert
5086c1d255d3SCy Schubert wpabuf_free(announce);
5087c1d255d3SCy Schubert }
5088c1d255d3SCy Schubert
5089c1d255d3SCy Schubert
wpas_dpp_presence_ann_channels(struct wpa_supplicant * wpa_s,struct dpp_bootstrap_info * bi)5090*a90b9d01SCy Schubert static int * wpas_dpp_presence_ann_channels(struct wpa_supplicant *wpa_s,
5091*a90b9d01SCy Schubert struct dpp_bootstrap_info *bi)
5092c1d255d3SCy Schubert {
5093c1d255d3SCy Schubert unsigned int i;
5094c1d255d3SCy Schubert struct hostapd_hw_modes *mode;
5095c1d255d3SCy Schubert int c;
5096c1d255d3SCy Schubert struct wpa_bss *bss;
5097c1d255d3SCy Schubert bool chan6 = wpa_s->hw.modes == NULL;
5098*a90b9d01SCy Schubert int *freqs = NULL;
5099c1d255d3SCy Schubert
5100c1d255d3SCy Schubert /* Channels from own bootstrapping info */
5101c1d255d3SCy Schubert if (bi) {
5102c1d255d3SCy Schubert for (i = 0; i < bi->num_freq; i++)
5103*a90b9d01SCy Schubert int_array_add_unique(&freqs, bi->freq[i]);
5104c1d255d3SCy Schubert }
5105c1d255d3SCy Schubert
5106c1d255d3SCy Schubert /* Preferred chirping channels */
5107c1d255d3SCy Schubert mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
5108c1d255d3SCy Schubert HOSTAPD_MODE_IEEE80211G, false);
5109c1d255d3SCy Schubert if (mode) {
5110c1d255d3SCy Schubert for (c = 0; c < mode->num_channels; c++) {
5111c1d255d3SCy Schubert struct hostapd_channel_data *chan = &mode->channels[c];
5112c1d255d3SCy Schubert
5113c1d255d3SCy Schubert if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
5114c1d255d3SCy Schubert chan->freq != 2437)
5115c1d255d3SCy Schubert continue;
5116c1d255d3SCy Schubert chan6 = true;
5117c1d255d3SCy Schubert break;
5118c1d255d3SCy Schubert }
5119c1d255d3SCy Schubert }
5120c1d255d3SCy Schubert if (chan6)
5121*a90b9d01SCy Schubert int_array_add_unique(&freqs, 2437);
5122c1d255d3SCy Schubert
5123c1d255d3SCy Schubert mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
5124c1d255d3SCy Schubert HOSTAPD_MODE_IEEE80211A, false);
5125c1d255d3SCy Schubert if (mode) {
5126c1d255d3SCy Schubert int chan44 = 0, chan149 = 0;
5127c1d255d3SCy Schubert
5128c1d255d3SCy Schubert for (c = 0; c < mode->num_channels; c++) {
5129c1d255d3SCy Schubert struct hostapd_channel_data *chan = &mode->channels[c];
5130c1d255d3SCy Schubert
5131c1d255d3SCy Schubert if (chan->flag & (HOSTAPD_CHAN_DISABLED |
5132c1d255d3SCy Schubert HOSTAPD_CHAN_RADAR))
5133c1d255d3SCy Schubert continue;
5134c1d255d3SCy Schubert if (chan->freq == 5220)
5135c1d255d3SCy Schubert chan44 = 1;
5136c1d255d3SCy Schubert if (chan->freq == 5745)
5137c1d255d3SCy Schubert chan149 = 1;
5138c1d255d3SCy Schubert }
5139c1d255d3SCy Schubert if (chan149)
5140*a90b9d01SCy Schubert int_array_add_unique(&freqs, 5745);
5141c1d255d3SCy Schubert else if (chan44)
5142*a90b9d01SCy Schubert int_array_add_unique(&freqs, 5220);
5143c1d255d3SCy Schubert }
5144c1d255d3SCy Schubert
5145c1d255d3SCy Schubert mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
5146c1d255d3SCy Schubert HOSTAPD_MODE_IEEE80211AD, false);
5147c1d255d3SCy Schubert if (mode) {
5148c1d255d3SCy Schubert for (c = 0; c < mode->num_channels; c++) {
5149c1d255d3SCy Schubert struct hostapd_channel_data *chan = &mode->channels[c];
5150c1d255d3SCy Schubert
5151c1d255d3SCy Schubert if ((chan->flag & (HOSTAPD_CHAN_DISABLED |
5152c1d255d3SCy Schubert HOSTAPD_CHAN_RADAR)) ||
5153c1d255d3SCy Schubert chan->freq != 60480)
5154c1d255d3SCy Schubert continue;
5155*a90b9d01SCy Schubert int_array_add_unique(&freqs, 60480);
5156c1d255d3SCy Schubert break;
5157c1d255d3SCy Schubert }
5158c1d255d3SCy Schubert }
5159c1d255d3SCy Schubert
5160c1d255d3SCy Schubert /* Add channels from scan results for APs that advertise Configurator
5161c1d255d3SCy Schubert * Connectivity element */
5162c1d255d3SCy Schubert dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
5163c1d255d3SCy Schubert if (wpa_bss_get_vendor_ie(bss, DPP_CC_IE_VENDOR_TYPE))
5164*a90b9d01SCy Schubert int_array_add_unique(&freqs, bss->freq);
5165c1d255d3SCy Schubert }
5166c1d255d3SCy Schubert
5167*a90b9d01SCy Schubert return freqs;
5168*a90b9d01SCy Schubert }
5169*a90b9d01SCy Schubert
5170*a90b9d01SCy Schubert
wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant * wpa_s,struct wpa_scan_results * scan_res)5171*a90b9d01SCy Schubert static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
5172*a90b9d01SCy Schubert struct wpa_scan_results *scan_res)
5173*a90b9d01SCy Schubert {
5174*a90b9d01SCy Schubert struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi;
5175*a90b9d01SCy Schubert
5176*a90b9d01SCy Schubert if (!bi && !wpa_s->dpp_reconfig_ssid)
5177*a90b9d01SCy Schubert return;
5178*a90b9d01SCy Schubert
5179*a90b9d01SCy Schubert wpa_s->dpp_chirp_scan_done = 1;
5180*a90b9d01SCy Schubert
5181*a90b9d01SCy Schubert os_free(wpa_s->dpp_chirp_freqs);
5182*a90b9d01SCy Schubert wpa_s->dpp_chirp_freqs = wpas_dpp_presence_ann_channels(wpa_s, bi);
5183*a90b9d01SCy Schubert
5184c1d255d3SCy Schubert if (!wpa_s->dpp_chirp_freqs ||
5185c1d255d3SCy Schubert eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL) < 0)
5186c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
5187c1d255d3SCy Schubert }
5188c1d255d3SCy Schubert
5189c1d255d3SCy Schubert
wpas_dpp_chirp_next(void * eloop_ctx,void * timeout_ctx)5190c1d255d3SCy Schubert static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx)
5191c1d255d3SCy Schubert {
5192c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
5193c1d255d3SCy Schubert int i;
5194c1d255d3SCy Schubert
5195c1d255d3SCy Schubert if (wpa_s->dpp_chirp_listen)
5196c1d255d3SCy Schubert wpas_dpp_listen_stop(wpa_s);
5197c1d255d3SCy Schubert
5198c1d255d3SCy Schubert if (wpa_s->dpp_chirp_freq == 0) {
5199c1d255d3SCy Schubert if (wpa_s->dpp_chirp_round % 4 == 0 &&
5200c1d255d3SCy Schubert !wpa_s->dpp_chirp_scan_done) {
5201c1d255d3SCy Schubert if (wpas_scan_scheduled(wpa_s)) {
5202c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
5203c1d255d3SCy Schubert "DPP: Deferring chirp scan because another scan is planned already");
5204c1d255d3SCy Schubert if (eloop_register_timeout(1, 0,
5205c1d255d3SCy Schubert wpas_dpp_chirp_next,
5206c1d255d3SCy Schubert wpa_s, NULL) < 0) {
5207c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
5208c1d255d3SCy Schubert return;
5209c1d255d3SCy Schubert }
5210c1d255d3SCy Schubert return;
5211c1d255d3SCy Schubert }
5212c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
5213c1d255d3SCy Schubert "DPP: Update channel list for chirping");
5214c1d255d3SCy Schubert wpa_s->scan_req = MANUAL_SCAN_REQ;
5215c1d255d3SCy Schubert wpa_s->scan_res_handler =
5216c1d255d3SCy Schubert wpas_dpp_chirp_scan_res_handler;
5217c1d255d3SCy Schubert wpa_supplicant_req_scan(wpa_s, 0, 0);
5218c1d255d3SCy Schubert return;
5219c1d255d3SCy Schubert }
5220c1d255d3SCy Schubert wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[0];
5221c1d255d3SCy Schubert wpa_s->dpp_chirp_round++;
5222c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Start chirping round %d",
5223c1d255d3SCy Schubert wpa_s->dpp_chirp_round);
5224c1d255d3SCy Schubert } else {
5225c1d255d3SCy Schubert for (i = 0; wpa_s->dpp_chirp_freqs[i]; i++)
5226c1d255d3SCy Schubert if (wpa_s->dpp_chirp_freqs[i] == wpa_s->dpp_chirp_freq)
5227c1d255d3SCy Schubert break;
5228c1d255d3SCy Schubert if (!wpa_s->dpp_chirp_freqs[i]) {
5229c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
5230c1d255d3SCy Schubert "DPP: Previous chirp freq %d not found",
5231c1d255d3SCy Schubert wpa_s->dpp_chirp_freq);
5232c1d255d3SCy Schubert return;
5233c1d255d3SCy Schubert }
5234c1d255d3SCy Schubert i++;
5235c1d255d3SCy Schubert if (wpa_s->dpp_chirp_freqs[i]) {
5236c1d255d3SCy Schubert wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[i];
5237c1d255d3SCy Schubert } else {
5238c1d255d3SCy Schubert wpa_s->dpp_chirp_iter--;
5239c1d255d3SCy Schubert if (wpa_s->dpp_chirp_iter <= 0) {
5240c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
5241c1d255d3SCy Schubert "DPP: Chirping iterations completed");
5242c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
5243c1d255d3SCy Schubert return;
5244c1d255d3SCy Schubert }
5245c1d255d3SCy Schubert wpa_s->dpp_chirp_freq = 0;
5246c1d255d3SCy Schubert wpa_s->dpp_chirp_scan_done = 0;
5247c1d255d3SCy Schubert if (eloop_register_timeout(30, 0, wpas_dpp_chirp_next,
5248c1d255d3SCy Schubert wpa_s, NULL) < 0) {
5249c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
5250c1d255d3SCy Schubert return;
5251c1d255d3SCy Schubert }
5252c1d255d3SCy Schubert if (wpa_s->dpp_chirp_listen) {
5253c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
5254c1d255d3SCy Schubert "DPP: Listen on %d MHz during chirp 30 second wait",
5255c1d255d3SCy Schubert wpa_s->dpp_chirp_listen);
5256c1d255d3SCy Schubert wpas_dpp_listen_start(wpa_s,
5257c1d255d3SCy Schubert wpa_s->dpp_chirp_listen);
5258c1d255d3SCy Schubert } else {
5259c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
5260c1d255d3SCy Schubert "DPP: Wait 30 seconds before starting the next chirping round");
5261c1d255d3SCy Schubert }
5262c1d255d3SCy Schubert return;
5263c1d255d3SCy Schubert }
5264c1d255d3SCy Schubert }
5265c1d255d3SCy Schubert
5266c1d255d3SCy Schubert wpas_dpp_chirp_start(wpa_s);
5267c1d255d3SCy Schubert }
5268c1d255d3SCy Schubert
5269c1d255d3SCy Schubert
wpas_dpp_chirp(struct wpa_supplicant * wpa_s,const char * cmd)5270c1d255d3SCy Schubert int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd)
5271c1d255d3SCy Schubert {
5272c1d255d3SCy Schubert const char *pos;
5273c1d255d3SCy Schubert int iter = 1, listen_freq = 0;
5274c1d255d3SCy Schubert struct dpp_bootstrap_info *bi;
5275c1d255d3SCy Schubert
5276c1d255d3SCy Schubert pos = os_strstr(cmd, " own=");
5277c1d255d3SCy Schubert if (!pos)
5278c1d255d3SCy Schubert return -1;
5279c1d255d3SCy Schubert pos += 5;
5280c1d255d3SCy Schubert bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
5281c1d255d3SCy Schubert if (!bi) {
5282c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
5283c1d255d3SCy Schubert "DPP: Identified bootstrap info not found");
5284c1d255d3SCy Schubert return -1;
5285c1d255d3SCy Schubert }
5286c1d255d3SCy Schubert
5287c1d255d3SCy Schubert pos = os_strstr(cmd, " iter=");
5288c1d255d3SCy Schubert if (pos) {
5289c1d255d3SCy Schubert iter = atoi(pos + 6);
5290c1d255d3SCy Schubert if (iter <= 0)
5291c1d255d3SCy Schubert return -1;
5292c1d255d3SCy Schubert }
5293c1d255d3SCy Schubert
5294c1d255d3SCy Schubert pos = os_strstr(cmd, " listen=");
5295c1d255d3SCy Schubert if (pos) {
5296c1d255d3SCy Schubert listen_freq = atoi(pos + 8);
5297c1d255d3SCy Schubert if (listen_freq <= 0)
5298c1d255d3SCy Schubert return -1;
5299c1d255d3SCy Schubert }
5300c1d255d3SCy Schubert
5301c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
5302c1d255d3SCy Schubert wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
5303*a90b9d01SCy Schubert wpa_s->dpp_netrole = DPP_NETROLE_STA;
5304c1d255d3SCy Schubert wpa_s->dpp_qr_mutual = 0;
5305c1d255d3SCy Schubert wpa_s->dpp_chirp_bi = bi;
5306c1d255d3SCy Schubert wpa_s->dpp_presence_announcement = dpp_build_presence_announcement(bi);
5307c1d255d3SCy Schubert if (!wpa_s->dpp_presence_announcement)
5308c1d255d3SCy Schubert return -1;
5309c1d255d3SCy Schubert wpa_s->dpp_chirp_iter = iter;
5310c1d255d3SCy Schubert wpa_s->dpp_chirp_round = 0;
5311c1d255d3SCy Schubert wpa_s->dpp_chirp_scan_done = 0;
5312c1d255d3SCy Schubert wpa_s->dpp_chirp_listen = listen_freq;
5313c1d255d3SCy Schubert
5314c1d255d3SCy Schubert return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
5315c1d255d3SCy Schubert }
5316c1d255d3SCy Schubert
5317c1d255d3SCy Schubert
wpas_dpp_chirp_stop(struct wpa_supplicant * wpa_s)5318c1d255d3SCy Schubert void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
5319c1d255d3SCy Schubert {
5320c1d255d3SCy Schubert if (wpa_s->dpp_presence_announcement ||
5321c1d255d3SCy Schubert wpa_s->dpp_reconfig_ssid) {
5322c1d255d3SCy Schubert offchannel_send_action_done(wpa_s);
5323c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
5324c1d255d3SCy Schubert }
5325c1d255d3SCy Schubert wpa_s->dpp_chirp_bi = NULL;
5326c1d255d3SCy Schubert wpabuf_free(wpa_s->dpp_presence_announcement);
5327c1d255d3SCy Schubert wpa_s->dpp_presence_announcement = NULL;
5328c1d255d3SCy Schubert if (wpa_s->dpp_chirp_listen)
5329c1d255d3SCy Schubert wpas_dpp_listen_stop(wpa_s);
5330c1d255d3SCy Schubert wpa_s->dpp_chirp_listen = 0;
5331c1d255d3SCy Schubert wpa_s->dpp_chirp_freq = 0;
5332c1d255d3SCy Schubert os_free(wpa_s->dpp_chirp_freqs);
5333c1d255d3SCy Schubert wpa_s->dpp_chirp_freqs = NULL;
5334c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_chirp_next, wpa_s, NULL);
5335c1d255d3SCy Schubert eloop_cancel_timeout(wpas_dpp_chirp_timeout, wpa_s, NULL);
5336c1d255d3SCy Schubert if (wpa_s->scan_res_handler == wpas_dpp_chirp_scan_res_handler) {
5337c1d255d3SCy Schubert wpas_abort_ongoing_scan(wpa_s);
5338c1d255d3SCy Schubert wpa_s->scan_res_handler = NULL;
5339c1d255d3SCy Schubert }
5340c1d255d3SCy Schubert }
5341c1d255d3SCy Schubert
5342c1d255d3SCy Schubert
wpas_dpp_reconfig(struct wpa_supplicant * wpa_s,const char * cmd)5343c1d255d3SCy Schubert int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd)
5344c1d255d3SCy Schubert {
5345c1d255d3SCy Schubert struct wpa_ssid *ssid;
5346c1d255d3SCy Schubert int iter = 1;
5347c1d255d3SCy Schubert const char *pos;
5348c1d255d3SCy Schubert
5349c1d255d3SCy Schubert ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
5350c1d255d3SCy Schubert if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
5351c1d255d3SCy Schubert !ssid->dpp_csign) {
5352c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
5353c1d255d3SCy Schubert "DPP: Not a valid network profile for reconfiguration");
5354c1d255d3SCy Schubert return -1;
5355c1d255d3SCy Schubert }
5356c1d255d3SCy Schubert
5357c1d255d3SCy Schubert pos = os_strstr(cmd, " iter=");
5358c1d255d3SCy Schubert if (pos) {
5359c1d255d3SCy Schubert iter = atoi(pos + 6);
5360c1d255d3SCy Schubert if (iter <= 0)
5361c1d255d3SCy Schubert return -1;
5362c1d255d3SCy Schubert }
5363c1d255d3SCy Schubert
5364c1d255d3SCy Schubert if (wpa_s->dpp_auth) {
5365c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
5366c1d255d3SCy Schubert "DPP: Not ready to start reconfiguration - pending authentication exchange in progress");
5367c1d255d3SCy Schubert return -1;
5368c1d255d3SCy Schubert }
5369c1d255d3SCy Schubert
5370c1d255d3SCy Schubert dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
5371c1d255d3SCy Schubert wpa_s->dpp_reconfig_id = dpp_gen_reconfig_id(ssid->dpp_csign,
5372c1d255d3SCy Schubert ssid->dpp_csign_len,
5373c1d255d3SCy Schubert ssid->dpp_pp_key,
5374c1d255d3SCy Schubert ssid->dpp_pp_key_len);
5375c1d255d3SCy Schubert if (!wpa_s->dpp_reconfig_id) {
5376c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
5377c1d255d3SCy Schubert "DPP: Failed to generate E-id for reconfiguration");
5378c1d255d3SCy Schubert return -1;
5379c1d255d3SCy Schubert }
5380c1d255d3SCy Schubert if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
5381c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Disconnect for reconfiguration");
5382c1d255d3SCy Schubert wpa_s->own_disconnect_req = 1;
5383c1d255d3SCy Schubert wpa_supplicant_deauthenticate(
5384c1d255d3SCy Schubert wpa_s, WLAN_REASON_DEAUTH_LEAVING);
5385c1d255d3SCy Schubert }
5386c1d255d3SCy Schubert wpas_dpp_chirp_stop(wpa_s);
5387c1d255d3SCy Schubert wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
5388*a90b9d01SCy Schubert wpa_s->dpp_netrole = DPP_NETROLE_STA;
5389c1d255d3SCy Schubert wpa_s->dpp_qr_mutual = 0;
5390c1d255d3SCy Schubert wpa_s->dpp_reconfig_ssid = ssid;
5391c1d255d3SCy Schubert wpa_s->dpp_reconfig_ssid_id = ssid->id;
5392c1d255d3SCy Schubert wpa_s->dpp_chirp_iter = iter;
5393c1d255d3SCy Schubert wpa_s->dpp_chirp_round = 0;
5394c1d255d3SCy Schubert wpa_s->dpp_chirp_scan_done = 0;
5395c1d255d3SCy Schubert wpa_s->dpp_chirp_listen = 0;
5396c1d255d3SCy Schubert
5397c1d255d3SCy Schubert return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
5398c1d255d3SCy Schubert }
5399c1d255d3SCy Schubert
5400c1d255d3SCy Schubert
wpas_dpp_ca_set(struct wpa_supplicant * wpa_s,const char * cmd)5401c1d255d3SCy Schubert int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd)
5402c1d255d3SCy Schubert {
5403c1d255d3SCy Schubert int peer = -1;
5404c1d255d3SCy Schubert const char *pos, *value;
5405c1d255d3SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth;
5406c1d255d3SCy Schubert u8 *bin;
5407c1d255d3SCy Schubert size_t bin_len;
5408c1d255d3SCy Schubert struct wpabuf *buf;
5409c1d255d3SCy Schubert bool tcp = false;
5410c1d255d3SCy Schubert
5411c1d255d3SCy Schubert pos = os_strstr(cmd, " peer=");
5412c1d255d3SCy Schubert if (pos) {
5413c1d255d3SCy Schubert peer = atoi(pos + 6);
5414c1d255d3SCy Schubert if (!auth || !auth->waiting_cert ||
5415c1d255d3SCy Schubert (auth->peer_bi &&
5416c1d255d3SCy Schubert (unsigned int) peer != auth->peer_bi->id)) {
5417c1d255d3SCy Schubert auth = dpp_controller_get_auth(wpa_s->dpp, peer);
5418c1d255d3SCy Schubert tcp = true;
5419c1d255d3SCy Schubert }
5420c1d255d3SCy Schubert }
5421c1d255d3SCy Schubert
5422c1d255d3SCy Schubert if (!auth || !auth->waiting_cert) {
5423c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
5424c1d255d3SCy Schubert "DPP: No authentication exchange waiting for certificate information");
5425c1d255d3SCy Schubert return -1;
5426c1d255d3SCy Schubert }
5427c1d255d3SCy Schubert
5428c1d255d3SCy Schubert if (peer >= 0 &&
5429c1d255d3SCy Schubert (!auth->peer_bi ||
5430c1d255d3SCy Schubert (unsigned int) peer != auth->peer_bi->id) &&
5431c1d255d3SCy Schubert (!auth->tmp_peer_bi ||
5432c1d255d3SCy Schubert (unsigned int) peer != auth->tmp_peer_bi->id)) {
5433c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer mismatch");
5434c1d255d3SCy Schubert return -1;
5435c1d255d3SCy Schubert }
5436c1d255d3SCy Schubert
5437c1d255d3SCy Schubert pos = os_strstr(cmd, " value=");
5438c1d255d3SCy Schubert if (!pos)
5439c1d255d3SCy Schubert return -1;
5440c1d255d3SCy Schubert value = pos + 7;
5441c1d255d3SCy Schubert
5442c1d255d3SCy Schubert pos = os_strstr(cmd, " name=");
5443c1d255d3SCy Schubert if (!pos)
5444c1d255d3SCy Schubert return -1;
5445c1d255d3SCy Schubert pos += 6;
5446c1d255d3SCy Schubert
5447c1d255d3SCy Schubert if (os_strncmp(pos, "status ", 7) == 0) {
5448c1d255d3SCy Schubert auth->force_conf_resp_status = atoi(value);
5449c1d255d3SCy Schubert return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
5450c1d255d3SCy Schubert }
5451c1d255d3SCy Schubert
5452c1d255d3SCy Schubert if (os_strncmp(pos, "trustedEapServerName ", 21) == 0) {
5453c1d255d3SCy Schubert os_free(auth->trusted_eap_server_name);
5454c1d255d3SCy Schubert auth->trusted_eap_server_name = os_strdup(value);
5455c1d255d3SCy Schubert return auth->trusted_eap_server_name ? 0 : -1;
5456c1d255d3SCy Schubert }
5457c1d255d3SCy Schubert
5458c1d255d3SCy Schubert bin = base64_decode(value, os_strlen(value), &bin_len);
5459c1d255d3SCy Schubert if (!bin)
5460c1d255d3SCy Schubert return -1;
5461c1d255d3SCy Schubert buf = wpabuf_alloc_copy(bin, bin_len);
5462c1d255d3SCy Schubert os_free(bin);
5463c1d255d3SCy Schubert
5464c1d255d3SCy Schubert if (os_strncmp(pos, "caCert ", 7) == 0) {
5465c1d255d3SCy Schubert wpabuf_free(auth->cacert);
5466c1d255d3SCy Schubert auth->cacert = buf;
5467c1d255d3SCy Schubert return 0;
5468c1d255d3SCy Schubert }
5469c1d255d3SCy Schubert
5470c1d255d3SCy Schubert if (os_strncmp(pos, "certBag ", 8) == 0) {
5471c1d255d3SCy Schubert wpabuf_free(auth->certbag);
5472c1d255d3SCy Schubert auth->certbag = buf;
5473c1d255d3SCy Schubert return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
5474c1d255d3SCy Schubert }
5475c1d255d3SCy Schubert
5476c1d255d3SCy Schubert wpabuf_free(buf);
5477c1d255d3SCy Schubert return -1;
5478c1d255d3SCy Schubert }
5479c1d255d3SCy Schubert
5480206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
5481*a90b9d01SCy Schubert
5482*a90b9d01SCy Schubert
5483*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
5484*a90b9d01SCy Schubert
5485*a90b9d01SCy Schubert #define DPP_PB_ANNOUNCE_PER_CHAN 3
5486*a90b9d01SCy Schubert
5487*a90b9d01SCy Schubert static int wpas_dpp_pb_announce(struct wpa_supplicant *wpa_s, int freq);
5488*a90b9d01SCy Schubert static void wpas_dpp_pb_next(void *eloop_ctx, void *timeout_ctx);
5489*a90b9d01SCy Schubert
5490*a90b9d01SCy Schubert
wpas_dpp_pb_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)5491*a90b9d01SCy Schubert static void wpas_dpp_pb_tx_status(struct wpa_supplicant *wpa_s,
5492*a90b9d01SCy Schubert unsigned int freq, const u8 *dst,
5493*a90b9d01SCy Schubert const u8 *src, const u8 *bssid,
5494*a90b9d01SCy Schubert const u8 *data, size_t data_len,
5495*a90b9d01SCy Schubert enum offchannel_send_action_result result)
5496*a90b9d01SCy Schubert {
5497*a90b9d01SCy Schubert if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
5498*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
5499*a90b9d01SCy Schubert "DPP: Failed to send push button announcement on %d MHz",
5500*a90b9d01SCy Schubert freq);
5501*a90b9d01SCy Schubert if (eloop_register_timeout(0, 0, wpas_dpp_pb_next,
5502*a90b9d01SCy Schubert wpa_s, NULL) < 0)
5503*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
5504*a90b9d01SCy Schubert return;
5505*a90b9d01SCy Schubert }
5506*a90b9d01SCy Schubert
5507*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Push button announcement on %d MHz sent",
5508*a90b9d01SCy Schubert freq);
5509*a90b9d01SCy Schubert if (wpa_s->dpp_pb_discovery_done) {
5510*a90b9d01SCy Schubert wpa_s->dpp_pb_announce_count = 0;
5511*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
5512*a90b9d01SCy Schubert "DPP: Wait for push button announcement response and PKEX on %d MHz",
5513*a90b9d01SCy Schubert freq);
5514*a90b9d01SCy Schubert if (eloop_register_timeout(0, 500000, wpas_dpp_pb_next,
5515*a90b9d01SCy Schubert wpa_s, NULL) < 0)
5516*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
5517*a90b9d01SCy Schubert return;
5518*a90b9d01SCy Schubert } else if (wpa_s->dpp_pb_announce_count >= DPP_PB_ANNOUNCE_PER_CHAN) {
5519*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
5520*a90b9d01SCy Schubert "DPP: Wait for push button announcement response on %d MHz",
5521*a90b9d01SCy Schubert freq);
5522*a90b9d01SCy Schubert if (eloop_register_timeout(0, 50000, wpas_dpp_pb_next,
5523*a90b9d01SCy Schubert wpa_s, NULL) < 0)
5524*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
5525*a90b9d01SCy Schubert return;
5526*a90b9d01SCy Schubert }
5527*a90b9d01SCy Schubert
5528*a90b9d01SCy Schubert if (wpas_dpp_pb_announce(wpa_s, freq) < 0)
5529*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
5530*a90b9d01SCy Schubert }
5531*a90b9d01SCy Schubert
5532*a90b9d01SCy Schubert
wpas_dpp_pb_announce(struct wpa_supplicant * wpa_s,int freq)5533*a90b9d01SCy Schubert static int wpas_dpp_pb_announce(struct wpa_supplicant *wpa_s, int freq)
5534*a90b9d01SCy Schubert {
5535*a90b9d01SCy Schubert struct wpabuf *msg;
5536*a90b9d01SCy Schubert int type;
5537*a90b9d01SCy Schubert
5538*a90b9d01SCy Schubert msg = wpa_s->dpp_pb_announcement;
5539*a90b9d01SCy Schubert if (!msg)
5540*a90b9d01SCy Schubert return -1;
5541*a90b9d01SCy Schubert
5542*a90b9d01SCy Schubert wpa_s->dpp_pb_announce_count++;
5543*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
5544*a90b9d01SCy Schubert "DPP: Send push button announcement %d/%d (%d MHz)",
5545*a90b9d01SCy Schubert wpa_s->dpp_pb_announce_count, DPP_PB_ANNOUNCE_PER_CHAN,
5546*a90b9d01SCy Schubert freq);
5547*a90b9d01SCy Schubert
5548*a90b9d01SCy Schubert type = DPP_PA_PB_PRESENCE_ANNOUNCEMENT;
5549*a90b9d01SCy Schubert if (wpa_s->dpp_pb_announce_count == 1)
5550*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO,
5551*a90b9d01SCy Schubert DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
5552*a90b9d01SCy Schubert MAC2STR(broadcast), freq, type);
5553*a90b9d01SCy Schubert if (offchannel_send_action(
5554*a90b9d01SCy Schubert wpa_s, freq, broadcast, wpa_s->own_addr, broadcast,
5555*a90b9d01SCy Schubert wpabuf_head(msg), wpabuf_len(msg),
5556*a90b9d01SCy Schubert 1000, wpas_dpp_pb_tx_status, 0) < 0)
5557*a90b9d01SCy Schubert return -1;
5558*a90b9d01SCy Schubert
5559*a90b9d01SCy Schubert return 0;
5560*a90b9d01SCy Schubert }
5561*a90b9d01SCy Schubert
5562*a90b9d01SCy Schubert
wpas_dpp_pb_next(void * eloop_ctx,void * timeout_ctx)5563*a90b9d01SCy Schubert static void wpas_dpp_pb_next(void *eloop_ctx, void *timeout_ctx)
5564*a90b9d01SCy Schubert {
5565*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
5566*a90b9d01SCy Schubert struct os_reltime now;
5567*a90b9d01SCy Schubert int freq;
5568*a90b9d01SCy Schubert
5569*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_freqs)
5570*a90b9d01SCy Schubert return;
5571*a90b9d01SCy Schubert
5572*a90b9d01SCy Schubert os_get_reltime(&now);
5573*a90b9d01SCy Schubert offchannel_send_action_done(wpa_s);
5574*a90b9d01SCy Schubert
5575*a90b9d01SCy Schubert if (os_reltime_expired(&now, &wpa_s->dpp_pb_time, 100)) {
5576*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Push button wait time expired");
5577*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
5578*a90b9d01SCy Schubert return;
5579*a90b9d01SCy Schubert }
5580*a90b9d01SCy Schubert
5581*a90b9d01SCy Schubert if (wpa_s->dpp_pb_freq_idx >= int_array_len(wpa_s->dpp_pb_freqs)) {
5582*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
5583*a90b9d01SCy Schubert "DPP: Completed push button announcement round");
5584*a90b9d01SCy Schubert wpa_s->dpp_pb_freq_idx = 0;
5585*a90b9d01SCy Schubert if (wpa_s->dpp_pb_stop_iter > 0) {
5586*a90b9d01SCy Schubert wpa_s->dpp_pb_stop_iter--;
5587*a90b9d01SCy Schubert
5588*a90b9d01SCy Schubert if (wpa_s->dpp_pb_stop_iter == 1) {
5589*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS
5590*a90b9d01SCy Schubert "wait for AP/Configurator to allow PKEX to be initiated");
5591*a90b9d01SCy Schubert if (eloop_register_timeout(10, 0,
5592*a90b9d01SCy Schubert wpas_dpp_pb_next,
5593*a90b9d01SCy Schubert wpa_s, NULL) < 0) {
5594*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
5595*a90b9d01SCy Schubert return;
5596*a90b9d01SCy Schubert }
5597*a90b9d01SCy Schubert return;
5598*a90b9d01SCy Schubert }
5599*a90b9d01SCy Schubert
5600*a90b9d01SCy Schubert if (wpa_s->dpp_pb_stop_iter == 0) {
5601*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS
5602*a90b9d01SCy Schubert "start push button PKEX responder on the discovered channel (%d MHz)",
5603*a90b9d01SCy Schubert wpa_s->dpp_pb_resp_freq);
5604*a90b9d01SCy Schubert wpa_s->dpp_pb_discovery_done = true;
5605*a90b9d01SCy Schubert
5606*a90b9d01SCy Schubert wpa_s->dpp_pkex_bi = wpa_s->dpp_pb_bi;
5607*a90b9d01SCy Schubert
5608*a90b9d01SCy Schubert os_free(wpa_s->dpp_pkex_code);
5609*a90b9d01SCy Schubert wpa_s->dpp_pkex_code = os_memdup(
5610*a90b9d01SCy Schubert wpa_s->dpp_pb_c_nonce,
5611*a90b9d01SCy Schubert wpa_s->dpp_pb_c_nonce_len);
5612*a90b9d01SCy Schubert wpa_s->dpp_pkex_code_len =
5613*a90b9d01SCy Schubert wpa_s->dpp_pb_c_nonce_len;
5614*a90b9d01SCy Schubert
5615*a90b9d01SCy Schubert os_free(wpa_s->dpp_pkex_identifier);
5616*a90b9d01SCy Schubert wpa_s->dpp_pkex_identifier =
5617*a90b9d01SCy Schubert os_strdup("PBPKEX");
5618*a90b9d01SCy Schubert
5619*a90b9d01SCy Schubert if (!wpa_s->dpp_pkex_code ||
5620*a90b9d01SCy Schubert !wpa_s->dpp_pkex_identifier) {
5621*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
5622*a90b9d01SCy Schubert return;
5623*a90b9d01SCy Schubert }
5624*a90b9d01SCy Schubert
5625*a90b9d01SCy Schubert wpa_s->dpp_pkex_ver = PKEX_VER_ONLY_2;
5626*a90b9d01SCy Schubert
5627*a90b9d01SCy Schubert os_free(wpa_s->dpp_pkex_auth_cmd);
5628*a90b9d01SCy Schubert wpa_s->dpp_pkex_auth_cmd = NULL;
5629*a90b9d01SCy Schubert }
5630*a90b9d01SCy Schubert }
5631*a90b9d01SCy Schubert }
5632*a90b9d01SCy Schubert
5633*a90b9d01SCy Schubert if (wpa_s->dpp_pb_discovery_done)
5634*a90b9d01SCy Schubert freq = wpa_s->dpp_pb_resp_freq;
5635*a90b9d01SCy Schubert else
5636*a90b9d01SCy Schubert freq = wpa_s->dpp_pb_freqs[wpa_s->dpp_pb_freq_idx++];
5637*a90b9d01SCy Schubert wpa_s->dpp_pb_announce_count = 0;
5638*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_announcement) {
5639*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Push button announcements stopped");
5640*a90b9d01SCy Schubert return;
5641*a90b9d01SCy Schubert }
5642*a90b9d01SCy Schubert if (wpas_dpp_pb_announce(wpa_s, freq) < 0) {
5643*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
5644*a90b9d01SCy Schubert return;
5645*a90b9d01SCy Schubert }
5646*a90b9d01SCy Schubert }
5647*a90b9d01SCy Schubert
5648*a90b9d01SCy Schubert
wpas_dpp_push_button_expire(void * eloop_ctx,void * timeout_ctx)5649*a90b9d01SCy Schubert static void wpas_dpp_push_button_expire(void *eloop_ctx, void *timeout_ctx)
5650*a90b9d01SCy Schubert {
5651*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
5652*a90b9d01SCy Schubert
5653*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
5654*a90b9d01SCy Schubert "DPP: Active push button Configurator mode expired");
5655*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
5656*a90b9d01SCy Schubert }
5657*a90b9d01SCy Schubert
5658*a90b9d01SCy Schubert
wpas_dpp_push_button_configurator(struct wpa_supplicant * wpa_s,const char * cmd)5659*a90b9d01SCy Schubert static int wpas_dpp_push_button_configurator(struct wpa_supplicant *wpa_s,
5660*a90b9d01SCy Schubert const char *cmd)
5661*a90b9d01SCy Schubert {
5662*a90b9d01SCy Schubert wpa_s->dpp_pb_configurator = true;
5663*a90b9d01SCy Schubert wpa_s->dpp_pb_announce_time.sec = 0;
5664*a90b9d01SCy Schubert wpa_s->dpp_pb_announce_time.usec = 0;
5665*a90b9d01SCy Schubert str_clear_free(wpa_s->dpp_pb_cmd);
5666*a90b9d01SCy Schubert wpa_s->dpp_pb_cmd = NULL;
5667*a90b9d01SCy Schubert if (cmd) {
5668*a90b9d01SCy Schubert wpa_s->dpp_pb_cmd = os_strdup(cmd);
5669*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_cmd)
5670*a90b9d01SCy Schubert return -1;
5671*a90b9d01SCy Schubert }
5672*a90b9d01SCy Schubert eloop_register_timeout(100, 0, wpas_dpp_push_button_expire,
5673*a90b9d01SCy Schubert wpa_s, NULL);
5674*a90b9d01SCy Schubert
5675*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS "started");
5676*a90b9d01SCy Schubert return 0;
5677*a90b9d01SCy Schubert }
5678*a90b9d01SCy Schubert
5679*a90b9d01SCy Schubert
wpas_dpp_pb_scan_res_handler(struct wpa_supplicant * wpa_s,struct wpa_scan_results * scan_res)5680*a90b9d01SCy Schubert static void wpas_dpp_pb_scan_res_handler(struct wpa_supplicant *wpa_s,
5681*a90b9d01SCy Schubert struct wpa_scan_results *scan_res)
5682*a90b9d01SCy Schubert {
5683*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_time.sec && !wpa_s->dpp_pb_time.usec)
5684*a90b9d01SCy Schubert return;
5685*a90b9d01SCy Schubert
5686*a90b9d01SCy Schubert os_free(wpa_s->dpp_pb_freqs);
5687*a90b9d01SCy Schubert wpa_s->dpp_pb_freqs = wpas_dpp_presence_ann_channels(wpa_s, NULL);
5688*a90b9d01SCy Schubert
5689*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Scan completed for PB discovery");
5690*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_freqs ||
5691*a90b9d01SCy Schubert eloop_register_timeout(0, 0, wpas_dpp_pb_next, wpa_s, NULL) < 0)
5692*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
5693*a90b9d01SCy Schubert }
5694*a90b9d01SCy Schubert
5695*a90b9d01SCy Schubert
wpas_dpp_push_button(struct wpa_supplicant * wpa_s,const char * cmd)5696*a90b9d01SCy Schubert int wpas_dpp_push_button(struct wpa_supplicant *wpa_s, const char *cmd)
5697*a90b9d01SCy Schubert {
5698*a90b9d01SCy Schubert int res;
5699*a90b9d01SCy Schubert
5700*a90b9d01SCy Schubert if (!wpa_s->dpp)
5701*a90b9d01SCy Schubert return -1;
5702*a90b9d01SCy Schubert wpas_dpp_push_button_stop(wpa_s);
5703*a90b9d01SCy Schubert wpas_dpp_stop(wpa_s);
5704*a90b9d01SCy Schubert wpas_dpp_chirp_stop(wpa_s);
5705*a90b9d01SCy Schubert
5706*a90b9d01SCy Schubert os_get_reltime(&wpa_s->dpp_pb_time);
5707*a90b9d01SCy Schubert
5708*a90b9d01SCy Schubert if (cmd &&
5709*a90b9d01SCy Schubert (os_strstr(cmd, " role=configurator") ||
5710*a90b9d01SCy Schubert os_strstr(cmd, " conf=")))
5711*a90b9d01SCy Schubert return wpas_dpp_push_button_configurator(wpa_s, cmd);
5712*a90b9d01SCy Schubert
5713*a90b9d01SCy Schubert wpa_s->dpp_pb_configurator = false;
5714*a90b9d01SCy Schubert
5715*a90b9d01SCy Schubert wpa_s->dpp_pb_freq_idx = 0;
5716*a90b9d01SCy Schubert
5717*a90b9d01SCy Schubert res = dpp_bootstrap_gen(wpa_s->dpp, "type=pkex");
5718*a90b9d01SCy Schubert if (res < 0)
5719*a90b9d01SCy Schubert return -1;
5720*a90b9d01SCy Schubert wpa_s->dpp_pb_bi = dpp_bootstrap_get_id(wpa_s->dpp, res);
5721*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_bi)
5722*a90b9d01SCy Schubert return -1;
5723*a90b9d01SCy Schubert
5724*a90b9d01SCy Schubert wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
5725*a90b9d01SCy Schubert wpa_s->dpp_netrole = DPP_NETROLE_STA;
5726*a90b9d01SCy Schubert wpa_s->dpp_qr_mutual = 0;
5727*a90b9d01SCy Schubert wpa_s->dpp_pb_announcement =
5728*a90b9d01SCy Schubert dpp_build_pb_announcement(wpa_s->dpp_pb_bi);
5729*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_announcement)
5730*a90b9d01SCy Schubert return -1;
5731*a90b9d01SCy Schubert
5732*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
5733*a90b9d01SCy Schubert "DPP: Scan to create channel list for PB discovery");
5734*a90b9d01SCy Schubert wpa_s->scan_req = MANUAL_SCAN_REQ;
5735*a90b9d01SCy Schubert wpa_s->scan_res_handler = wpas_dpp_pb_scan_res_handler;
5736*a90b9d01SCy Schubert wpa_supplicant_req_scan(wpa_s, 0, 0);
5737*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS "started");
5738*a90b9d01SCy Schubert return 0;
5739*a90b9d01SCy Schubert }
5740*a90b9d01SCy Schubert
5741*a90b9d01SCy Schubert
wpas_dpp_push_button_stop(struct wpa_supplicant * wpa_s)5742*a90b9d01SCy Schubert void wpas_dpp_push_button_stop(struct wpa_supplicant *wpa_s)
5743*a90b9d01SCy Schubert {
5744*a90b9d01SCy Schubert if (!wpa_s->dpp)
5745*a90b9d01SCy Schubert return;
5746*a90b9d01SCy Schubert os_free(wpa_s->dpp_pb_freqs);
5747*a90b9d01SCy Schubert wpa_s->dpp_pb_freqs = NULL;
5748*a90b9d01SCy Schubert wpabuf_free(wpa_s->dpp_pb_announcement);
5749*a90b9d01SCy Schubert wpa_s->dpp_pb_announcement = NULL;
5750*a90b9d01SCy Schubert if (wpa_s->dpp_pb_bi) {
5751*a90b9d01SCy Schubert char id[20];
5752*a90b9d01SCy Schubert
5753*a90b9d01SCy Schubert if (wpa_s->dpp_pb_bi == wpa_s->dpp_pkex_bi)
5754*a90b9d01SCy Schubert wpa_s->dpp_pkex_bi = NULL;
5755*a90b9d01SCy Schubert os_snprintf(id, sizeof(id), "%u", wpa_s->dpp_pb_bi->id);
5756*a90b9d01SCy Schubert dpp_bootstrap_remove(wpa_s->dpp, id);
5757*a90b9d01SCy Schubert wpa_s->dpp_pb_bi = NULL;
5758*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_result_indicated) {
5759*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT "failed");
5760*a90b9d01SCy Schubert wpa_s->dpp_pb_result_indicated = true;
5761*a90b9d01SCy Schubert }
5762*a90b9d01SCy Schubert }
5763*a90b9d01SCy Schubert
5764*a90b9d01SCy Schubert wpa_s->dpp_pb_resp_freq = 0;
5765*a90b9d01SCy Schubert wpa_s->dpp_pb_stop_iter = 0;
5766*a90b9d01SCy Schubert wpa_s->dpp_pb_discovery_done = false;
5767*a90b9d01SCy Schubert os_free(wpa_s->dpp_pb_cmd);
5768*a90b9d01SCy Schubert wpa_s->dpp_pb_cmd = NULL;
5769*a90b9d01SCy Schubert
5770*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_pb_next, wpa_s, NULL);
5771*a90b9d01SCy Schubert eloop_cancel_timeout(wpas_dpp_push_button_expire, wpa_s, NULL);
5772*a90b9d01SCy Schubert if (wpas_dpp_pb_active(wpa_s)) {
5773*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Stop active push button mode");
5774*a90b9d01SCy Schubert if (!wpa_s->dpp_pb_result_indicated)
5775*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT "failed");
5776*a90b9d01SCy Schubert }
5777*a90b9d01SCy Schubert wpa_s->dpp_pb_time.sec = 0;
5778*a90b9d01SCy Schubert wpa_s->dpp_pb_time.usec = 0;
5779*a90b9d01SCy Schubert dpp_pkex_free(wpa_s->dpp_pkex);
5780*a90b9d01SCy Schubert wpa_s->dpp_pkex = NULL;
5781*a90b9d01SCy Schubert os_free(wpa_s->dpp_pkex_auth_cmd);
5782*a90b9d01SCy Schubert wpa_s->dpp_pkex_auth_cmd = NULL;
5783*a90b9d01SCy Schubert
5784*a90b9d01SCy Schubert wpa_s->dpp_pb_result_indicated = false;
5785*a90b9d01SCy Schubert
5786*a90b9d01SCy Schubert str_clear_free(wpa_s->dpp_pb_cmd);
5787*a90b9d01SCy Schubert wpa_s->dpp_pb_cmd = NULL;
5788*a90b9d01SCy Schubert
5789*a90b9d01SCy Schubert if (wpa_s->scan_res_handler == wpas_dpp_pb_scan_res_handler) {
5790*a90b9d01SCy Schubert wpas_abort_ongoing_scan(wpa_s);
5791*a90b9d01SCy Schubert wpa_s->scan_res_handler = NULL;
5792*a90b9d01SCy Schubert }
5793*a90b9d01SCy Schubert }
5794*a90b9d01SCy Schubert
5795*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
5796