185732ac8SCy Schubert /* 285732ac8SCy Schubert * wpa_supplicant - DPP 385732ac8SCy Schubert * Copyright (c) 2017, Qualcomm Atheros, Inc. 44bc52338SCy Schubert * Copyright (c) 2018-2019, The Linux Foundation 585732ac8SCy Schubert * 685732ac8SCy Schubert * This software may be distributed under the terms of the BSD license. 785732ac8SCy Schubert * See README for more details. 885732ac8SCy Schubert */ 985732ac8SCy Schubert 1085732ac8SCy Schubert #include "utils/includes.h" 1185732ac8SCy Schubert 1285732ac8SCy Schubert #include "utils/common.h" 1385732ac8SCy Schubert #include "utils/eloop.h" 14*206b73d0SCy Schubert #include "utils/ip_addr.h" 1585732ac8SCy Schubert #include "common/dpp.h" 1685732ac8SCy Schubert #include "common/gas.h" 1785732ac8SCy Schubert #include "common/gas_server.h" 1885732ac8SCy Schubert #include "rsn_supp/wpa.h" 1985732ac8SCy Schubert #include "rsn_supp/pmksa_cache.h" 2085732ac8SCy Schubert #include "wpa_supplicant_i.h" 2185732ac8SCy Schubert #include "config.h" 2285732ac8SCy Schubert #include "driver_i.h" 2385732ac8SCy Schubert #include "offchannel.h" 2485732ac8SCy Schubert #include "gas_query.h" 2585732ac8SCy Schubert #include "bss.h" 2685732ac8SCy Schubert #include "scan.h" 2785732ac8SCy Schubert #include "notify.h" 2885732ac8SCy Schubert #include "dpp_supplicant.h" 2985732ac8SCy Schubert 3085732ac8SCy Schubert 3185732ac8SCy Schubert static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s, 3285732ac8SCy Schubert unsigned int freq); 3385732ac8SCy Schubert static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx); 3485732ac8SCy Schubert static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator); 3585732ac8SCy Schubert static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s, 3685732ac8SCy Schubert unsigned int freq, const u8 *dst, 3785732ac8SCy Schubert const u8 *src, const u8 *bssid, 3885732ac8SCy Schubert const u8 *data, size_t data_len, 3985732ac8SCy Schubert enum offchannel_send_action_result result); 4085732ac8SCy Schubert static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx); 4185732ac8SCy Schubert static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s); 4285732ac8SCy Schubert static void 4385732ac8SCy Schubert wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, 4485732ac8SCy Schubert unsigned int freq, const u8 *dst, 4585732ac8SCy Schubert const u8 *src, const u8 *bssid, 4685732ac8SCy Schubert const u8 *data, size_t data_len, 4785732ac8SCy Schubert enum offchannel_send_action_result result); 4885732ac8SCy Schubert 4985732ac8SCy Schubert static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 5085732ac8SCy Schubert 5185732ac8SCy Schubert /* Use a hardcoded Transaction ID 1 in Peer Discovery frames since there is only 5285732ac8SCy Schubert * a single transaction in progress at any point in time. */ 5385732ac8SCy Schubert static const u8 TRANSACTION_ID = 1; 5485732ac8SCy Schubert 5585732ac8SCy Schubert 5685732ac8SCy Schubert /** 5785732ac8SCy Schubert * wpas_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code 5885732ac8SCy Schubert * @wpa_s: Pointer to wpa_supplicant data 5985732ac8SCy Schubert * @cmd: DPP URI read from a QR Code 6085732ac8SCy Schubert * Returns: Identifier of the stored info or -1 on failure 6185732ac8SCy Schubert */ 6285732ac8SCy Schubert int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd) 6385732ac8SCy Schubert { 6485732ac8SCy Schubert struct dpp_bootstrap_info *bi; 6585732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 6685732ac8SCy Schubert 674bc52338SCy Schubert bi = dpp_add_qr_code(wpa_s->dpp, cmd); 6885732ac8SCy Schubert if (!bi) 6985732ac8SCy Schubert return -1; 7085732ac8SCy Schubert 7185732ac8SCy Schubert if (auth && auth->response_pending && 7285732ac8SCy Schubert dpp_notify_new_qr_code(auth, bi) == 1) { 7385732ac8SCy Schubert wpa_printf(MSG_DEBUG, 7485732ac8SCy Schubert "DPP: Sending out pending authentication response"); 7585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 7685732ac8SCy Schubert " freq=%u type=%d", 7785732ac8SCy Schubert MAC2STR(auth->peer_mac_addr), auth->curr_freq, 7885732ac8SCy Schubert DPP_PA_AUTHENTICATION_RESP); 7985732ac8SCy Schubert offchannel_send_action(wpa_s, auth->curr_freq, 8085732ac8SCy Schubert auth->peer_mac_addr, wpa_s->own_addr, 8185732ac8SCy Schubert broadcast, 8285732ac8SCy Schubert wpabuf_head(auth->resp_msg), 8385732ac8SCy Schubert wpabuf_len(auth->resp_msg), 8485732ac8SCy Schubert 500, wpas_dpp_tx_status, 0); 8585732ac8SCy Schubert } 8685732ac8SCy Schubert 8785732ac8SCy Schubert return bi->id; 8885732ac8SCy Schubert } 8985732ac8SCy Schubert 9085732ac8SCy Schubert 9185732ac8SCy Schubert static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx) 9285732ac8SCy Schubert { 9385732ac8SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx; 9485732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 9585732ac8SCy Schubert 9685732ac8SCy Schubert if (!auth || !auth->resp_msg) 9785732ac8SCy Schubert return; 9885732ac8SCy Schubert 9985732ac8SCy Schubert wpa_printf(MSG_DEBUG, 10085732ac8SCy Schubert "DPP: Retry Authentication Response after timeout"); 10185732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 10285732ac8SCy Schubert " freq=%u type=%d", 10385732ac8SCy Schubert MAC2STR(auth->peer_mac_addr), auth->curr_freq, 10485732ac8SCy Schubert DPP_PA_AUTHENTICATION_RESP); 10585732ac8SCy Schubert offchannel_send_action(wpa_s, auth->curr_freq, auth->peer_mac_addr, 10685732ac8SCy Schubert wpa_s->own_addr, broadcast, 10785732ac8SCy Schubert wpabuf_head(auth->resp_msg), 10885732ac8SCy Schubert wpabuf_len(auth->resp_msg), 10985732ac8SCy Schubert 500, wpas_dpp_tx_status, 0); 11085732ac8SCy Schubert } 11185732ac8SCy Schubert 11285732ac8SCy Schubert 11385732ac8SCy Schubert static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s) 11485732ac8SCy Schubert { 11585732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 11685732ac8SCy Schubert unsigned int wait_time, max_tries; 11785732ac8SCy Schubert 11885732ac8SCy Schubert if (!auth || !auth->resp_msg) 11985732ac8SCy Schubert return; 12085732ac8SCy Schubert 12185732ac8SCy Schubert if (wpa_s->dpp_resp_max_tries) 12285732ac8SCy Schubert max_tries = wpa_s->dpp_resp_max_tries; 12385732ac8SCy Schubert else 12485732ac8SCy Schubert max_tries = 5; 12585732ac8SCy Schubert auth->auth_resp_tries++; 12685732ac8SCy Schubert if (auth->auth_resp_tries >= max_tries) { 12785732ac8SCy Schubert wpa_printf(MSG_INFO, "DPP: No confirm received from initiator - stopping exchange"); 12885732ac8SCy Schubert offchannel_send_action_done(wpa_s); 12985732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth); 13085732ac8SCy Schubert wpa_s->dpp_auth = NULL; 13185732ac8SCy Schubert return; 13285732ac8SCy Schubert } 13385732ac8SCy Schubert 13485732ac8SCy Schubert if (wpa_s->dpp_resp_retry_time) 13585732ac8SCy Schubert wait_time = wpa_s->dpp_resp_retry_time; 13685732ac8SCy Schubert else 13785732ac8SCy Schubert wait_time = 1000; 13885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 13985732ac8SCy Schubert "DPP: Schedule retransmission of Authentication Response frame in %u ms", 14085732ac8SCy Schubert wait_time); 14185732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); 14285732ac8SCy Schubert eloop_register_timeout(wait_time / 1000, 14385732ac8SCy Schubert (wait_time % 1000) * 1000, 14485732ac8SCy Schubert wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); 14585732ac8SCy Schubert } 14685732ac8SCy Schubert 14785732ac8SCy Schubert 1484bc52338SCy Schubert static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s) 1494bc52338SCy Schubert { 1504bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network"); 1514bc52338SCy Schubert wpa_s->disconnected = 0; 1524bc52338SCy Schubert wpa_s->reassociate = 1; 1534bc52338SCy Schubert wpa_s->scan_runs = 0; 1544bc52338SCy Schubert wpa_s->normal_scans = 0; 1554bc52338SCy Schubert wpa_supplicant_cancel_sched_scan(wpa_s); 1564bc52338SCy Schubert wpa_supplicant_req_scan(wpa_s, 0, 0); 1574bc52338SCy Schubert } 1584bc52338SCy Schubert 1594bc52338SCy Schubert 16085732ac8SCy Schubert static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s, 16185732ac8SCy Schubert unsigned int freq, const u8 *dst, 16285732ac8SCy Schubert const u8 *src, const u8 *bssid, 16385732ac8SCy Schubert const u8 *data, size_t data_len, 16485732ac8SCy Schubert enum offchannel_send_action_result result) 16585732ac8SCy Schubert { 16685732ac8SCy Schubert const char *res_txt; 16785732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 16885732ac8SCy Schubert 16985732ac8SCy Schubert res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" : 17085732ac8SCy Schubert (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" : 17185732ac8SCy Schubert "FAILED"); 17285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR 17385732ac8SCy Schubert " result=%s", freq, MAC2STR(dst), res_txt); 17485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR 17585732ac8SCy Schubert " freq=%u result=%s", MAC2STR(dst), freq, res_txt); 17685732ac8SCy Schubert 17785732ac8SCy Schubert if (!wpa_s->dpp_auth) { 17885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 17985732ac8SCy Schubert "DPP: Ignore TX status since there is no ongoing authentication exchange"); 18085732ac8SCy Schubert return; 18185732ac8SCy Schubert } 18285732ac8SCy Schubert 1834bc52338SCy Schubert #ifdef CONFIG_DPP2 1844bc52338SCy Schubert if (auth->connect_on_tx_status) { 1854bc52338SCy Schubert wpa_printf(MSG_DEBUG, 1864bc52338SCy Schubert "DPP: Try to connect after completed configuration result"); 1874bc52338SCy Schubert wpas_dpp_try_to_connect(wpa_s); 1884bc52338SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth); 1894bc52338SCy Schubert wpa_s->dpp_auth = NULL; 1904bc52338SCy Schubert return; 1914bc52338SCy Schubert } 1924bc52338SCy Schubert #endif /* CONFIG_DPP2 */ 1934bc52338SCy Schubert 19485732ac8SCy Schubert if (wpa_s->dpp_auth->remove_on_tx_status) { 19585732ac8SCy Schubert wpa_printf(MSG_DEBUG, 19685732ac8SCy Schubert "DPP: Terminate authentication exchange due to an earlier error"); 19785732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); 19885732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); 19985732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, 20085732ac8SCy Schubert NULL); 20185732ac8SCy Schubert offchannel_send_action_done(wpa_s); 20285732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth); 20385732ac8SCy Schubert wpa_s->dpp_auth = NULL; 20485732ac8SCy Schubert return; 20585732ac8SCy Schubert } 20685732ac8SCy Schubert 20785732ac8SCy Schubert if (wpa_s->dpp_auth_ok_on_ack) 20885732ac8SCy Schubert wpas_dpp_auth_success(wpa_s, 1); 20985732ac8SCy Schubert 21085732ac8SCy Schubert if (!is_broadcast_ether_addr(dst) && 21185732ac8SCy Schubert result != OFFCHANNEL_SEND_ACTION_SUCCESS) { 21285732ac8SCy Schubert wpa_printf(MSG_DEBUG, 21385732ac8SCy Schubert "DPP: Unicast DPP Action frame was not ACKed"); 21485732ac8SCy Schubert if (auth->waiting_auth_resp) { 21585732ac8SCy Schubert /* In case of DPP Authentication Request frame, move to 21685732ac8SCy Schubert * the next channel immediately. */ 21785732ac8SCy Schubert offchannel_send_action_done(wpa_s); 21885732ac8SCy Schubert wpas_dpp_auth_init_next(wpa_s); 21985732ac8SCy Schubert return; 22085732ac8SCy Schubert } 22185732ac8SCy Schubert if (auth->waiting_auth_conf) { 22285732ac8SCy Schubert wpas_dpp_auth_resp_retry(wpa_s); 22385732ac8SCy Schubert return; 22485732ac8SCy Schubert } 22585732ac8SCy Schubert } 22685732ac8SCy Schubert 22785732ac8SCy Schubert if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && 22885732ac8SCy Schubert result == OFFCHANNEL_SEND_ACTION_SUCCESS) { 22985732ac8SCy Schubert /* Allow timeout handling to stop iteration if no response is 23085732ac8SCy Schubert * received from a peer that has ACKed a request. */ 23185732ac8SCy Schubert auth->auth_req_ack = 1; 23285732ac8SCy Schubert } 23385732ac8SCy Schubert 23485732ac8SCy Schubert if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 && 23585732ac8SCy Schubert wpa_s->dpp_auth->curr_freq != wpa_s->dpp_auth->neg_freq) { 23685732ac8SCy Schubert wpa_printf(MSG_DEBUG, 23785732ac8SCy Schubert "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response", 23885732ac8SCy Schubert wpa_s->dpp_auth->curr_freq, 23985732ac8SCy Schubert wpa_s->dpp_auth->neg_freq); 24085732ac8SCy Schubert offchannel_send_action_done(wpa_s); 24185732ac8SCy Schubert wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->neg_freq); 24285732ac8SCy Schubert } 24385732ac8SCy Schubert 24485732ac8SCy Schubert if (wpa_s->dpp_auth_ok_on_ack) 24585732ac8SCy Schubert wpa_s->dpp_auth_ok_on_ack = 0; 24685732ac8SCy Schubert } 24785732ac8SCy Schubert 24885732ac8SCy Schubert 24985732ac8SCy Schubert static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx) 25085732ac8SCy Schubert { 25185732ac8SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx; 25285732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 25385732ac8SCy Schubert unsigned int freq; 25485732ac8SCy Schubert struct os_reltime now, diff; 25585732ac8SCy Schubert unsigned int wait_time, diff_ms; 25685732ac8SCy Schubert 25785732ac8SCy Schubert if (!auth || !auth->waiting_auth_resp) 25885732ac8SCy Schubert return; 25985732ac8SCy Schubert 26085732ac8SCy Schubert wait_time = wpa_s->dpp_resp_wait_time ? 26185732ac8SCy Schubert wpa_s->dpp_resp_wait_time : 2000; 26285732ac8SCy Schubert os_get_reltime(&now); 26385732ac8SCy Schubert os_reltime_sub(&now, &wpa_s->dpp_last_init, &diff); 26485732ac8SCy Schubert diff_ms = diff.sec * 1000 + diff.usec / 1000; 26585732ac8SCy Schubert wpa_printf(MSG_DEBUG, 26685732ac8SCy Schubert "DPP: Reply wait timeout - wait_time=%u diff_ms=%u", 26785732ac8SCy Schubert wait_time, diff_ms); 26885732ac8SCy Schubert 26985732ac8SCy Schubert if (auth->auth_req_ack && diff_ms >= wait_time) { 27085732ac8SCy Schubert /* Peer ACK'ed Authentication Request frame, but did not reply 27185732ac8SCy Schubert * with Authentication Response frame within two seconds. */ 27285732ac8SCy Schubert wpa_printf(MSG_INFO, 27385732ac8SCy Schubert "DPP: No response received from responder - stopping initiation attempt"); 27485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED); 27585732ac8SCy Schubert offchannel_send_action_done(wpa_s); 27685732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s); 27785732ac8SCy Schubert dpp_auth_deinit(auth); 27885732ac8SCy Schubert wpa_s->dpp_auth = NULL; 27985732ac8SCy Schubert return; 28085732ac8SCy Schubert } 28185732ac8SCy Schubert 28285732ac8SCy Schubert if (diff_ms >= wait_time) { 28385732ac8SCy Schubert /* Authentication Request frame was not ACK'ed and no reply 28485732ac8SCy Schubert * was receiving within two seconds. */ 28585732ac8SCy Schubert wpa_printf(MSG_DEBUG, 28685732ac8SCy Schubert "DPP: Continue Initiator channel iteration"); 28785732ac8SCy Schubert offchannel_send_action_done(wpa_s); 28885732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s); 28985732ac8SCy Schubert wpas_dpp_auth_init_next(wpa_s); 29085732ac8SCy Schubert return; 29185732ac8SCy Schubert } 29285732ac8SCy Schubert 29385732ac8SCy Schubert /* Driver did not support 2000 ms long wait_time with TX command, so 29485732ac8SCy Schubert * schedule listen operation to continue waiting for the response. 29585732ac8SCy Schubert * 29685732ac8SCy Schubert * DPP listen operations continue until stopped, so simply schedule a 29785732ac8SCy Schubert * new call to this function at the point when the two second reply 29885732ac8SCy Schubert * wait has expired. */ 29985732ac8SCy Schubert wait_time -= diff_ms; 30085732ac8SCy Schubert 30185732ac8SCy Schubert freq = auth->curr_freq; 30285732ac8SCy Schubert if (auth->neg_freq > 0) 30385732ac8SCy Schubert freq = auth->neg_freq; 30485732ac8SCy Schubert wpa_printf(MSG_DEBUG, 30585732ac8SCy Schubert "DPP: Continue reply wait on channel %u MHz for %u ms", 30685732ac8SCy Schubert freq, wait_time); 30785732ac8SCy Schubert wpa_s->dpp_in_response_listen = 1; 30885732ac8SCy Schubert wpas_dpp_listen_start(wpa_s, freq); 30985732ac8SCy Schubert 31085732ac8SCy Schubert eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000, 31185732ac8SCy Schubert wpas_dpp_reply_wait_timeout, wpa_s, NULL); 31285732ac8SCy Schubert } 31385732ac8SCy Schubert 31485732ac8SCy Schubert 31585732ac8SCy Schubert static void wpas_dpp_set_testing_options(struct wpa_supplicant *wpa_s, 31685732ac8SCy Schubert struct dpp_authentication *auth) 31785732ac8SCy Schubert { 31885732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 31985732ac8SCy Schubert if (wpa_s->dpp_config_obj_override) 32085732ac8SCy Schubert auth->config_obj_override = 32185732ac8SCy Schubert os_strdup(wpa_s->dpp_config_obj_override); 32285732ac8SCy Schubert if (wpa_s->dpp_discovery_override) 32385732ac8SCy Schubert auth->discovery_override = 32485732ac8SCy Schubert os_strdup(wpa_s->dpp_discovery_override); 32585732ac8SCy Schubert if (wpa_s->dpp_groups_override) 32685732ac8SCy Schubert auth->groups_override = 32785732ac8SCy Schubert os_strdup(wpa_s->dpp_groups_override); 32885732ac8SCy Schubert auth->ignore_netaccesskey_mismatch = 32985732ac8SCy Schubert wpa_s->dpp_ignore_netaccesskey_mismatch; 33085732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 33185732ac8SCy Schubert } 33285732ac8SCy Schubert 33385732ac8SCy Schubert 33485732ac8SCy Schubert static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx) 33585732ac8SCy Schubert { 33685732ac8SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx; 33785732ac8SCy Schubert 33885732ac8SCy Schubert if (!wpa_s->dpp_auth) 33985732ac8SCy Schubert return; 34085732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout"); 34185732ac8SCy Schubert wpas_dpp_auth_init_next(wpa_s); 34285732ac8SCy Schubert } 34385732ac8SCy Schubert 34485732ac8SCy Schubert 34585732ac8SCy Schubert static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s) 34685732ac8SCy Schubert { 34785732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 34885732ac8SCy Schubert const u8 *dst; 34985732ac8SCy Schubert unsigned int wait_time, max_wait_time, freq, max_tries, used; 35085732ac8SCy Schubert struct os_reltime now, diff; 35185732ac8SCy Schubert 35285732ac8SCy Schubert wpa_s->dpp_in_response_listen = 0; 35385732ac8SCy Schubert if (!auth) 35485732ac8SCy Schubert return -1; 35585732ac8SCy Schubert 35685732ac8SCy Schubert if (auth->freq_idx == 0) 35785732ac8SCy Schubert os_get_reltime(&wpa_s->dpp_init_iter_start); 35885732ac8SCy Schubert 35985732ac8SCy Schubert if (auth->freq_idx >= auth->num_freq) { 36085732ac8SCy Schubert auth->num_freq_iters++; 36185732ac8SCy Schubert if (wpa_s->dpp_init_max_tries) 36285732ac8SCy Schubert max_tries = wpa_s->dpp_init_max_tries; 36385732ac8SCy Schubert else 36485732ac8SCy Schubert max_tries = 5; 36585732ac8SCy Schubert if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) { 36685732ac8SCy Schubert wpa_printf(MSG_INFO, 36785732ac8SCy Schubert "DPP: No response received from responder - stopping initiation attempt"); 36885732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED); 36985732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, 37085732ac8SCy Schubert wpa_s, NULL); 37185732ac8SCy Schubert offchannel_send_action_done(wpa_s); 37285732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth); 37385732ac8SCy Schubert wpa_s->dpp_auth = NULL; 37485732ac8SCy Schubert return -1; 37585732ac8SCy Schubert } 37685732ac8SCy Schubert auth->freq_idx = 0; 37785732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); 37885732ac8SCy Schubert if (wpa_s->dpp_init_retry_time) 37985732ac8SCy Schubert wait_time = wpa_s->dpp_init_retry_time; 38085732ac8SCy Schubert else 38185732ac8SCy Schubert wait_time = 10000; 38285732ac8SCy Schubert os_get_reltime(&now); 38385732ac8SCy Schubert os_reltime_sub(&now, &wpa_s->dpp_init_iter_start, &diff); 38485732ac8SCy Schubert used = diff.sec * 1000 + diff.usec / 1000; 38585732ac8SCy Schubert if (used > wait_time) 38685732ac8SCy Schubert wait_time = 0; 38785732ac8SCy Schubert else 38885732ac8SCy Schubert wait_time -= used; 38985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms", 39085732ac8SCy Schubert wait_time); 39185732ac8SCy Schubert eloop_register_timeout(wait_time / 1000, 39285732ac8SCy Schubert (wait_time % 1000) * 1000, 39385732ac8SCy Schubert wpas_dpp_init_timeout, wpa_s, 39485732ac8SCy Schubert NULL); 39585732ac8SCy Schubert return 0; 39685732ac8SCy Schubert } 39785732ac8SCy Schubert freq = auth->freq[auth->freq_idx++]; 39885732ac8SCy Schubert auth->curr_freq = freq; 39985732ac8SCy Schubert 40085732ac8SCy Schubert if (is_zero_ether_addr(auth->peer_bi->mac_addr)) 40185732ac8SCy Schubert dst = broadcast; 40285732ac8SCy Schubert else 40385732ac8SCy Schubert dst = auth->peer_bi->mac_addr; 40485732ac8SCy Schubert wpa_s->dpp_auth_ok_on_ack = 0; 40585732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); 40685732ac8SCy Schubert wait_time = wpa_s->max_remain_on_chan; 40785732ac8SCy Schubert max_wait_time = wpa_s->dpp_resp_wait_time ? 40885732ac8SCy Schubert wpa_s->dpp_resp_wait_time : 2000; 40985732ac8SCy Schubert if (wait_time > max_wait_time) 41085732ac8SCy Schubert wait_time = max_wait_time; 41185732ac8SCy Schubert wait_time += 10; /* give the driver some extra time to complete */ 41285732ac8SCy Schubert eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000, 41385732ac8SCy Schubert wpas_dpp_reply_wait_timeout, 41485732ac8SCy Schubert wpa_s, NULL); 41585732ac8SCy Schubert wait_time -= 10; 41685732ac8SCy Schubert if (auth->neg_freq > 0 && freq != auth->neg_freq) { 41785732ac8SCy Schubert wpa_printf(MSG_DEBUG, 41885732ac8SCy Schubert "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response", 41985732ac8SCy Schubert freq, auth->neg_freq); 42085732ac8SCy Schubert } 42185732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", 42285732ac8SCy Schubert MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ); 42385732ac8SCy Schubert auth->auth_req_ack = 0; 42485732ac8SCy Schubert os_get_reltime(&wpa_s->dpp_last_init); 42585732ac8SCy Schubert return offchannel_send_action(wpa_s, freq, dst, 42685732ac8SCy Schubert wpa_s->own_addr, broadcast, 42785732ac8SCy Schubert wpabuf_head(auth->req_msg), 42885732ac8SCy Schubert wpabuf_len(auth->req_msg), 42985732ac8SCy Schubert wait_time, wpas_dpp_tx_status, 0); 43085732ac8SCy Schubert } 43185732ac8SCy Schubert 43285732ac8SCy Schubert 43385732ac8SCy Schubert int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) 43485732ac8SCy Schubert { 43585732ac8SCy Schubert const char *pos; 43685732ac8SCy Schubert struct dpp_bootstrap_info *peer_bi, *own_bi = NULL; 437*206b73d0SCy Schubert struct dpp_authentication *auth; 43885732ac8SCy Schubert u8 allowed_roles = DPP_CAPAB_CONFIGURATOR; 43985732ac8SCy Schubert unsigned int neg_freq = 0; 440*206b73d0SCy Schubert int tcp = 0; 441*206b73d0SCy Schubert #ifdef CONFIG_DPP2 442*206b73d0SCy Schubert int tcp_port = DPP_TCP_PORT; 443*206b73d0SCy Schubert struct hostapd_ip_addr ipaddr; 444*206b73d0SCy Schubert char *addr; 445*206b73d0SCy Schubert #endif /* CONFIG_DPP2 */ 44685732ac8SCy Schubert 44785732ac8SCy Schubert wpa_s->dpp_gas_client = 0; 44885732ac8SCy Schubert 44985732ac8SCy Schubert pos = os_strstr(cmd, " peer="); 45085732ac8SCy Schubert if (!pos) 45185732ac8SCy Schubert return -1; 45285732ac8SCy Schubert pos += 6; 4534bc52338SCy Schubert peer_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos)); 45485732ac8SCy Schubert if (!peer_bi) { 45585732ac8SCy Schubert wpa_printf(MSG_INFO, 45685732ac8SCy Schubert "DPP: Could not find bootstrapping info for the identified peer"); 45785732ac8SCy Schubert return -1; 45885732ac8SCy Schubert } 45985732ac8SCy Schubert 460*206b73d0SCy Schubert #ifdef CONFIG_DPP2 461*206b73d0SCy Schubert pos = os_strstr(cmd, " tcp_port="); 462*206b73d0SCy Schubert if (pos) { 463*206b73d0SCy Schubert pos += 10; 464*206b73d0SCy Schubert tcp_port = atoi(pos); 465*206b73d0SCy Schubert } 466*206b73d0SCy Schubert 467*206b73d0SCy Schubert addr = get_param(cmd, " tcp_addr="); 468*206b73d0SCy Schubert if (addr) { 469*206b73d0SCy Schubert int res; 470*206b73d0SCy Schubert 471*206b73d0SCy Schubert res = hostapd_parse_ip_addr(addr, &ipaddr); 472*206b73d0SCy Schubert os_free(addr); 473*206b73d0SCy Schubert if (res) 474*206b73d0SCy Schubert return -1; 475*206b73d0SCy Schubert tcp = 1; 476*206b73d0SCy Schubert } 477*206b73d0SCy Schubert #endif /* CONFIG_DPP2 */ 478*206b73d0SCy Schubert 47985732ac8SCy Schubert pos = os_strstr(cmd, " own="); 48085732ac8SCy Schubert if (pos) { 48185732ac8SCy Schubert pos += 5; 4824bc52338SCy Schubert own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos)); 48385732ac8SCy Schubert if (!own_bi) { 48485732ac8SCy Schubert wpa_printf(MSG_INFO, 48585732ac8SCy Schubert "DPP: Could not find bootstrapping info for the identified local entry"); 48685732ac8SCy Schubert return -1; 48785732ac8SCy Schubert } 48885732ac8SCy Schubert 48985732ac8SCy Schubert if (peer_bi->curve != own_bi->curve) { 49085732ac8SCy Schubert wpa_printf(MSG_INFO, 49185732ac8SCy Schubert "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)", 49285732ac8SCy Schubert peer_bi->curve->name, own_bi->curve->name); 49385732ac8SCy Schubert return -1; 49485732ac8SCy Schubert } 49585732ac8SCy Schubert } 49685732ac8SCy Schubert 49785732ac8SCy Schubert pos = os_strstr(cmd, " role="); 49885732ac8SCy Schubert if (pos) { 49985732ac8SCy Schubert pos += 6; 50085732ac8SCy Schubert if (os_strncmp(pos, "configurator", 12) == 0) 50185732ac8SCy Schubert allowed_roles = DPP_CAPAB_CONFIGURATOR; 50285732ac8SCy Schubert else if (os_strncmp(pos, "enrollee", 8) == 0) 50385732ac8SCy Schubert allowed_roles = DPP_CAPAB_ENROLLEE; 50485732ac8SCy Schubert else if (os_strncmp(pos, "either", 6) == 0) 50585732ac8SCy Schubert allowed_roles = DPP_CAPAB_CONFIGURATOR | 50685732ac8SCy Schubert DPP_CAPAB_ENROLLEE; 50785732ac8SCy Schubert else 50885732ac8SCy Schubert goto fail; 50985732ac8SCy Schubert } 51085732ac8SCy Schubert 51185732ac8SCy Schubert pos = os_strstr(cmd, " netrole="); 51285732ac8SCy Schubert if (pos) { 51385732ac8SCy Schubert pos += 9; 51485732ac8SCy Schubert wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0; 51585732ac8SCy Schubert } 51685732ac8SCy Schubert 51785732ac8SCy Schubert pos = os_strstr(cmd, " neg_freq="); 51885732ac8SCy Schubert if (pos) 51985732ac8SCy Schubert neg_freq = atoi(pos + 10); 52085732ac8SCy Schubert 521*206b73d0SCy Schubert if (!tcp && wpa_s->dpp_auth) { 52285732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); 52385732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); 52485732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, 52585732ac8SCy Schubert NULL); 52685732ac8SCy Schubert offchannel_send_action_done(wpa_s); 52785732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth); 52885732ac8SCy Schubert wpa_s->dpp_auth = NULL; 529*206b73d0SCy Schubert } 530*206b73d0SCy Schubert 531*206b73d0SCy Schubert auth = dpp_auth_init(wpa_s, peer_bi, own_bi, allowed_roles, neg_freq, 532*206b73d0SCy Schubert wpa_s->hw.modes, wpa_s->hw.num_modes); 533*206b73d0SCy Schubert if (!auth) 534*206b73d0SCy Schubert goto fail; 535*206b73d0SCy Schubert wpas_dpp_set_testing_options(wpa_s, auth); 536*206b73d0SCy Schubert if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) < 0) { 537*206b73d0SCy Schubert dpp_auth_deinit(auth); 53885732ac8SCy Schubert goto fail; 53985732ac8SCy Schubert } 54085732ac8SCy Schubert 541*206b73d0SCy Schubert auth->neg_freq = neg_freq; 54285732ac8SCy Schubert 54385732ac8SCy Schubert if (!is_zero_ether_addr(peer_bi->mac_addr)) 544*206b73d0SCy Schubert os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN); 54585732ac8SCy Schubert 546*206b73d0SCy Schubert #ifdef CONFIG_DPP2 547*206b73d0SCy Schubert if (tcp) 548*206b73d0SCy Schubert return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port); 549*206b73d0SCy Schubert #endif /* CONFIG_DPP2 */ 550*206b73d0SCy Schubert 551*206b73d0SCy Schubert wpa_s->dpp_auth = auth; 55285732ac8SCy Schubert return wpas_dpp_auth_init_next(wpa_s); 55385732ac8SCy Schubert fail: 55485732ac8SCy Schubert return -1; 55585732ac8SCy Schubert } 55685732ac8SCy Schubert 55785732ac8SCy Schubert 55885732ac8SCy Schubert struct wpas_dpp_listen_work { 55985732ac8SCy Schubert unsigned int freq; 56085732ac8SCy Schubert unsigned int duration; 56185732ac8SCy Schubert struct wpabuf *probe_resp_ie; 56285732ac8SCy Schubert }; 56385732ac8SCy Schubert 56485732ac8SCy Schubert 56585732ac8SCy Schubert static void wpas_dpp_listen_work_free(struct wpas_dpp_listen_work *lwork) 56685732ac8SCy Schubert { 56785732ac8SCy Schubert if (!lwork) 56885732ac8SCy Schubert return; 56985732ac8SCy Schubert os_free(lwork); 57085732ac8SCy Schubert } 57185732ac8SCy Schubert 57285732ac8SCy Schubert 57385732ac8SCy Schubert static void wpas_dpp_listen_work_done(struct wpa_supplicant *wpa_s) 57485732ac8SCy Schubert { 57585732ac8SCy Schubert struct wpas_dpp_listen_work *lwork; 57685732ac8SCy Schubert 57785732ac8SCy Schubert if (!wpa_s->dpp_listen_work) 57885732ac8SCy Schubert return; 57985732ac8SCy Schubert 58085732ac8SCy Schubert lwork = wpa_s->dpp_listen_work->ctx; 58185732ac8SCy Schubert wpas_dpp_listen_work_free(lwork); 58285732ac8SCy Schubert radio_work_done(wpa_s->dpp_listen_work); 58385732ac8SCy Schubert wpa_s->dpp_listen_work = NULL; 58485732ac8SCy Schubert } 58585732ac8SCy Schubert 58685732ac8SCy Schubert 58785732ac8SCy Schubert static void dpp_start_listen_cb(struct wpa_radio_work *work, int deinit) 58885732ac8SCy Schubert { 58985732ac8SCy Schubert struct wpa_supplicant *wpa_s = work->wpa_s; 59085732ac8SCy Schubert struct wpas_dpp_listen_work *lwork = work->ctx; 59185732ac8SCy Schubert 59285732ac8SCy Schubert if (deinit) { 59385732ac8SCy Schubert if (work->started) { 59485732ac8SCy Schubert wpa_s->dpp_listen_work = NULL; 59585732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s); 59685732ac8SCy Schubert } 59785732ac8SCy Schubert wpas_dpp_listen_work_free(lwork); 59885732ac8SCy Schubert return; 59985732ac8SCy Schubert } 60085732ac8SCy Schubert 60185732ac8SCy Schubert wpa_s->dpp_listen_work = work; 60285732ac8SCy Schubert 60385732ac8SCy Schubert wpa_s->dpp_pending_listen_freq = lwork->freq; 60485732ac8SCy Schubert 60585732ac8SCy Schubert if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, 60685732ac8SCy Schubert wpa_s->max_remain_on_chan) < 0) { 60785732ac8SCy Schubert wpa_printf(MSG_DEBUG, 60885732ac8SCy Schubert "DPP: Failed to request the driver to remain on channel (%u MHz) for listen", 60985732ac8SCy Schubert lwork->freq); 6104bc52338SCy Schubert wpa_s->dpp_listen_freq = 0; 61185732ac8SCy Schubert wpas_dpp_listen_work_done(wpa_s); 61285732ac8SCy Schubert wpa_s->dpp_pending_listen_freq = 0; 61385732ac8SCy Schubert return; 61485732ac8SCy Schubert } 61585732ac8SCy Schubert wpa_s->off_channel_freq = 0; 61685732ac8SCy Schubert wpa_s->roc_waiting_drv_freq = lwork->freq; 61785732ac8SCy Schubert } 61885732ac8SCy Schubert 61985732ac8SCy Schubert 62085732ac8SCy Schubert static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s, 62185732ac8SCy Schubert unsigned int freq) 62285732ac8SCy Schubert { 62385732ac8SCy Schubert struct wpas_dpp_listen_work *lwork; 62485732ac8SCy Schubert 62585732ac8SCy Schubert if (wpa_s->dpp_listen_work) { 62685732ac8SCy Schubert wpa_printf(MSG_DEBUG, 62785732ac8SCy Schubert "DPP: Reject start_listen since dpp_listen_work already exists"); 62885732ac8SCy Schubert return -1; 62985732ac8SCy Schubert } 63085732ac8SCy Schubert 63185732ac8SCy Schubert if (wpa_s->dpp_listen_freq) 63285732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s); 63385732ac8SCy Schubert wpa_s->dpp_listen_freq = freq; 63485732ac8SCy Schubert 63585732ac8SCy Schubert lwork = os_zalloc(sizeof(*lwork)); 63685732ac8SCy Schubert if (!lwork) 63785732ac8SCy Schubert return -1; 63885732ac8SCy Schubert lwork->freq = freq; 63985732ac8SCy Schubert 64085732ac8SCy Schubert if (radio_add_work(wpa_s, freq, "dpp-listen", 0, dpp_start_listen_cb, 64185732ac8SCy Schubert lwork) < 0) { 64285732ac8SCy Schubert wpas_dpp_listen_work_free(lwork); 64385732ac8SCy Schubert return -1; 64485732ac8SCy Schubert } 64585732ac8SCy Schubert 64685732ac8SCy Schubert return 0; 64785732ac8SCy Schubert } 64885732ac8SCy Schubert 64985732ac8SCy Schubert 65085732ac8SCy Schubert int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd) 65185732ac8SCy Schubert { 65285732ac8SCy Schubert int freq; 65385732ac8SCy Schubert 65485732ac8SCy Schubert freq = atoi(cmd); 65585732ac8SCy Schubert if (freq <= 0) 65685732ac8SCy Schubert return -1; 65785732ac8SCy Schubert 65885732ac8SCy Schubert if (os_strstr(cmd, " role=configurator")) 65985732ac8SCy Schubert wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR; 66085732ac8SCy Schubert else if (os_strstr(cmd, " role=enrollee")) 66185732ac8SCy Schubert wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE; 66285732ac8SCy Schubert else 66385732ac8SCy Schubert wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | 66485732ac8SCy Schubert DPP_CAPAB_ENROLLEE; 66585732ac8SCy Schubert wpa_s->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL; 66685732ac8SCy Schubert wpa_s->dpp_netrole_ap = os_strstr(cmd, " netrole=ap") != NULL; 66785732ac8SCy Schubert if (wpa_s->dpp_listen_freq == (unsigned int) freq) { 66885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz", 66985732ac8SCy Schubert freq); 67085732ac8SCy Schubert return 0; 67185732ac8SCy Schubert } 67285732ac8SCy Schubert 67385732ac8SCy Schubert return wpas_dpp_listen_start(wpa_s, freq); 67485732ac8SCy Schubert } 67585732ac8SCy Schubert 67685732ac8SCy Schubert 67785732ac8SCy Schubert void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s) 67885732ac8SCy Schubert { 67985732ac8SCy Schubert wpa_s->dpp_in_response_listen = 0; 68085732ac8SCy Schubert if (!wpa_s->dpp_listen_freq) 68185732ac8SCy Schubert return; 68285732ac8SCy Schubert 68385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Stop listen on %u MHz", 68485732ac8SCy Schubert wpa_s->dpp_listen_freq); 68585732ac8SCy Schubert wpa_drv_cancel_remain_on_channel(wpa_s); 68685732ac8SCy Schubert wpa_s->dpp_listen_freq = 0; 68785732ac8SCy Schubert wpas_dpp_listen_work_done(wpa_s); 68885732ac8SCy Schubert } 68985732ac8SCy Schubert 69085732ac8SCy Schubert 69185732ac8SCy Schubert void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, 69285732ac8SCy Schubert unsigned int freq) 69385732ac8SCy Schubert { 69485732ac8SCy Schubert wpas_dpp_listen_work_done(wpa_s); 69585732ac8SCy Schubert 69685732ac8SCy Schubert if (wpa_s->dpp_auth && wpa_s->dpp_in_response_listen) { 69785732ac8SCy Schubert unsigned int new_freq; 69885732ac8SCy Schubert 69985732ac8SCy Schubert /* Continue listen with a new remain-on-channel */ 70085732ac8SCy Schubert if (wpa_s->dpp_auth->neg_freq > 0) 70185732ac8SCy Schubert new_freq = wpa_s->dpp_auth->neg_freq; 70285732ac8SCy Schubert else 70385732ac8SCy Schubert new_freq = wpa_s->dpp_auth->curr_freq; 70485732ac8SCy Schubert wpa_printf(MSG_DEBUG, 70585732ac8SCy Schubert "DPP: Continue wait on %u MHz for the ongoing DPP provisioning session", 70685732ac8SCy Schubert new_freq); 70785732ac8SCy Schubert wpas_dpp_listen_start(wpa_s, new_freq); 70885732ac8SCy Schubert return; 70985732ac8SCy Schubert } 71085732ac8SCy Schubert 71185732ac8SCy Schubert if (wpa_s->dpp_listen_freq) { 71285732ac8SCy Schubert /* Continue listen with a new remain-on-channel */ 71385732ac8SCy Schubert wpas_dpp_listen_start(wpa_s, wpa_s->dpp_listen_freq); 71485732ac8SCy Schubert } 71585732ac8SCy Schubert } 71685732ac8SCy Schubert 71785732ac8SCy Schubert 71885732ac8SCy Schubert static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src, 71985732ac8SCy Schubert const u8 *hdr, const u8 *buf, size_t len, 72085732ac8SCy Schubert unsigned int freq) 72185732ac8SCy Schubert { 72285732ac8SCy Schubert const u8 *r_bootstrap, *i_bootstrap; 72385732ac8SCy Schubert u16 r_bootstrap_len, i_bootstrap_len; 7244bc52338SCy Schubert struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL; 7254bc52338SCy Schubert 7264bc52338SCy Schubert if (!wpa_s->dpp) 7274bc52338SCy Schubert return; 72885732ac8SCy Schubert 72985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR, 73085732ac8SCy Schubert MAC2STR(src)); 73185732ac8SCy Schubert 73285732ac8SCy Schubert r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, 73385732ac8SCy Schubert &r_bootstrap_len); 73485732ac8SCy Schubert if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { 73585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL 73685732ac8SCy Schubert "Missing or invalid required Responder Bootstrapping Key Hash attribute"); 73785732ac8SCy Schubert return; 73885732ac8SCy Schubert } 73985732ac8SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", 74085732ac8SCy Schubert r_bootstrap, r_bootstrap_len); 74185732ac8SCy Schubert 74285732ac8SCy Schubert i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH, 74385732ac8SCy Schubert &i_bootstrap_len); 74485732ac8SCy Schubert if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) { 74585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL 74685732ac8SCy Schubert "Missing or invalid required Initiator Bootstrapping Key Hash attribute"); 74785732ac8SCy Schubert return; 74885732ac8SCy Schubert } 74985732ac8SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash", 75085732ac8SCy Schubert i_bootstrap, i_bootstrap_len); 75185732ac8SCy Schubert 75285732ac8SCy Schubert /* Try to find own and peer bootstrapping key matches based on the 75385732ac8SCy Schubert * received hash values */ 7544bc52338SCy Schubert dpp_bootstrap_find_pair(wpa_s->dpp, i_bootstrap, r_bootstrap, 7554bc52338SCy Schubert &own_bi, &peer_bi); 75685732ac8SCy Schubert if (!own_bi) { 75785732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL 75885732ac8SCy Schubert "No matching own bootstrapping key found - ignore message"); 75985732ac8SCy Schubert return; 76085732ac8SCy Schubert } 76185732ac8SCy Schubert 76285732ac8SCy Schubert if (wpa_s->dpp_auth) { 76385732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL 76485732ac8SCy Schubert "Already in DPP authentication exchange - ignore new one"); 76585732ac8SCy Schubert return; 76685732ac8SCy Schubert } 76785732ac8SCy Schubert 76885732ac8SCy Schubert wpa_s->dpp_gas_client = 0; 76985732ac8SCy Schubert wpa_s->dpp_auth_ok_on_ack = 0; 77085732ac8SCy Schubert wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s, wpa_s->dpp_allowed_roles, 77185732ac8SCy Schubert wpa_s->dpp_qr_mutual, 77285732ac8SCy Schubert peer_bi, own_bi, freq, hdr, buf, len); 77385732ac8SCy Schubert if (!wpa_s->dpp_auth) { 77485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No response generated"); 77585732ac8SCy Schubert return; 77685732ac8SCy Schubert } 77785732ac8SCy Schubert wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth); 7784bc52338SCy Schubert if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth, 77985732ac8SCy Schubert wpa_s->dpp_configurator_params) < 0) { 78085732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth); 78185732ac8SCy Schubert wpa_s->dpp_auth = NULL; 78285732ac8SCy Schubert return; 78385732ac8SCy Schubert } 78485732ac8SCy Schubert os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN); 78585732ac8SCy Schubert 78685732ac8SCy Schubert if (wpa_s->dpp_listen_freq && 78785732ac8SCy Schubert wpa_s->dpp_listen_freq != wpa_s->dpp_auth->curr_freq) { 78885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 78985732ac8SCy Schubert "DPP: Stop listen on %u MHz to allow response on the request %u MHz", 79085732ac8SCy Schubert wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq); 79185732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s); 79285732ac8SCy Schubert } 79385732ac8SCy Schubert 79485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", 79585732ac8SCy Schubert MAC2STR(src), wpa_s->dpp_auth->curr_freq, 79685732ac8SCy Schubert DPP_PA_AUTHENTICATION_RESP); 79785732ac8SCy Schubert offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq, 79885732ac8SCy Schubert src, wpa_s->own_addr, broadcast, 79985732ac8SCy Schubert wpabuf_head(wpa_s->dpp_auth->resp_msg), 80085732ac8SCy Schubert wpabuf_len(wpa_s->dpp_auth->resp_msg), 80185732ac8SCy Schubert 500, wpas_dpp_tx_status, 0); 80285732ac8SCy Schubert } 80385732ac8SCy Schubert 80485732ac8SCy Schubert 80585732ac8SCy Schubert static void wpas_dpp_start_gas_server(struct wpa_supplicant *wpa_s) 80685732ac8SCy Schubert { 80785732ac8SCy Schubert /* TODO: stop wait and start ROC */ 80885732ac8SCy Schubert } 80985732ac8SCy Schubert 81085732ac8SCy Schubert 81185732ac8SCy Schubert static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s, 81285732ac8SCy Schubert struct dpp_authentication *auth) 81385732ac8SCy Schubert { 81485732ac8SCy Schubert struct wpa_ssid *ssid; 81585732ac8SCy Schubert 8164bc52338SCy Schubert #ifdef CONFIG_DPP2 8174bc52338SCy Schubert if (auth->akm == DPP_AKM_SAE) { 8184bc52338SCy Schubert #ifdef CONFIG_SAE 8194bc52338SCy Schubert struct wpa_driver_capa capa; 8204bc52338SCy Schubert int res; 8214bc52338SCy Schubert 8224bc52338SCy Schubert res = wpa_drv_get_capa(wpa_s, &capa); 8234bc52338SCy Schubert if (res == 0 && 8244bc52338SCy Schubert !(capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) && 8254bc52338SCy Schubert !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) { 8264bc52338SCy Schubert wpa_printf(MSG_DEBUG, 8274bc52338SCy Schubert "DPP: SAE not supported by the driver"); 8284bc52338SCy Schubert return NULL; 8294bc52338SCy Schubert } 8304bc52338SCy Schubert #else /* CONFIG_SAE */ 8314bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: SAE not supported in the build"); 8324bc52338SCy Schubert return NULL; 8334bc52338SCy Schubert #endif /* CONFIG_SAE */ 8344bc52338SCy Schubert } 8354bc52338SCy Schubert #endif /* CONFIG_DPP2 */ 8364bc52338SCy Schubert 83785732ac8SCy Schubert ssid = wpa_config_add_network(wpa_s->conf); 83885732ac8SCy Schubert if (!ssid) 83985732ac8SCy Schubert return NULL; 84085732ac8SCy Schubert wpas_notify_network_added(wpa_s, ssid); 84185732ac8SCy Schubert wpa_config_set_network_defaults(ssid); 84285732ac8SCy Schubert ssid->disabled = 1; 84385732ac8SCy Schubert 84485732ac8SCy Schubert ssid->ssid = os_malloc(auth->ssid_len); 84585732ac8SCy Schubert if (!ssid->ssid) 84685732ac8SCy Schubert goto fail; 84785732ac8SCy Schubert os_memcpy(ssid->ssid, auth->ssid, auth->ssid_len); 84885732ac8SCy Schubert ssid->ssid_len = auth->ssid_len; 84985732ac8SCy Schubert 85085732ac8SCy Schubert if (auth->connector) { 85185732ac8SCy Schubert ssid->key_mgmt = WPA_KEY_MGMT_DPP; 85285732ac8SCy Schubert ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED; 85385732ac8SCy Schubert ssid->dpp_connector = os_strdup(auth->connector); 85485732ac8SCy Schubert if (!ssid->dpp_connector) 85585732ac8SCy Schubert goto fail; 85685732ac8SCy Schubert } 85785732ac8SCy Schubert 85885732ac8SCy Schubert if (auth->c_sign_key) { 85985732ac8SCy Schubert ssid->dpp_csign = os_malloc(wpabuf_len(auth->c_sign_key)); 86085732ac8SCy Schubert if (!ssid->dpp_csign) 86185732ac8SCy Schubert goto fail; 86285732ac8SCy Schubert os_memcpy(ssid->dpp_csign, wpabuf_head(auth->c_sign_key), 86385732ac8SCy Schubert wpabuf_len(auth->c_sign_key)); 86485732ac8SCy Schubert ssid->dpp_csign_len = wpabuf_len(auth->c_sign_key); 86585732ac8SCy Schubert } 86685732ac8SCy Schubert 86785732ac8SCy Schubert if (auth->net_access_key) { 86885732ac8SCy Schubert ssid->dpp_netaccesskey = 86985732ac8SCy Schubert os_malloc(wpabuf_len(auth->net_access_key)); 87085732ac8SCy Schubert if (!ssid->dpp_netaccesskey) 87185732ac8SCy Schubert goto fail; 87285732ac8SCy Schubert os_memcpy(ssid->dpp_netaccesskey, 87385732ac8SCy Schubert wpabuf_head(auth->net_access_key), 87485732ac8SCy Schubert wpabuf_len(auth->net_access_key)); 87585732ac8SCy Schubert ssid->dpp_netaccesskey_len = wpabuf_len(auth->net_access_key); 87685732ac8SCy Schubert ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry; 87785732ac8SCy Schubert } 87885732ac8SCy Schubert 8794bc52338SCy Schubert if (!auth->connector || dpp_akm_psk(auth->akm) || 8804bc52338SCy Schubert dpp_akm_sae(auth->akm)) { 8814bc52338SCy Schubert if (!auth->connector) 88285732ac8SCy Schubert ssid->key_mgmt = 0; 8834bc52338SCy Schubert if (dpp_akm_psk(auth->akm)) 88485732ac8SCy Schubert ssid->key_mgmt |= WPA_KEY_MGMT_PSK | 88585732ac8SCy Schubert WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK; 8864bc52338SCy Schubert if (dpp_akm_sae(auth->akm)) 88785732ac8SCy Schubert ssid->key_mgmt |= WPA_KEY_MGMT_SAE | 88885732ac8SCy Schubert WPA_KEY_MGMT_FT_SAE; 88985732ac8SCy Schubert ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL; 89085732ac8SCy Schubert if (auth->passphrase[0]) { 89185732ac8SCy Schubert if (wpa_config_set_quoted(ssid, "psk", 89285732ac8SCy Schubert auth->passphrase) < 0) 89385732ac8SCy Schubert goto fail; 89485732ac8SCy Schubert wpa_config_update_psk(ssid); 89585732ac8SCy Schubert ssid->export_keys = 1; 89685732ac8SCy Schubert } else { 89785732ac8SCy Schubert ssid->psk_set = auth->psk_set; 89885732ac8SCy Schubert os_memcpy(ssid->psk, auth->psk, PMK_LEN); 89985732ac8SCy Schubert } 90085732ac8SCy Schubert } 90185732ac8SCy Schubert 90285732ac8SCy Schubert return ssid; 90385732ac8SCy Schubert fail: 90485732ac8SCy Schubert wpas_notify_network_removed(wpa_s, ssid); 90585732ac8SCy Schubert wpa_config_remove_network(wpa_s->conf, ssid->id); 90685732ac8SCy Schubert return NULL; 90785732ac8SCy Schubert } 90885732ac8SCy Schubert 90985732ac8SCy Schubert 9104bc52338SCy Schubert static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s, 91185732ac8SCy Schubert struct dpp_authentication *auth) 91285732ac8SCy Schubert { 91385732ac8SCy Schubert struct wpa_ssid *ssid; 91485732ac8SCy Schubert 91585732ac8SCy Schubert if (wpa_s->conf->dpp_config_processing < 1) 9164bc52338SCy Schubert return 0; 91785732ac8SCy Schubert 91885732ac8SCy Schubert ssid = wpas_dpp_add_network(wpa_s, auth); 91985732ac8SCy Schubert if (!ssid) 9204bc52338SCy Schubert return -1; 92185732ac8SCy Schubert 92285732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id); 9234bc52338SCy Schubert if (wpa_s->conf->dpp_config_processing == 2) 92485732ac8SCy Schubert ssid->disabled = 0; 9254bc52338SCy Schubert 9264bc52338SCy Schubert #ifndef CONFIG_NO_CONFIG_WRITE 9274bc52338SCy Schubert if (wpa_s->conf->update_config && 9284bc52338SCy Schubert wpa_config_write(wpa_s->confname, wpa_s->conf)) 9294bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration"); 9304bc52338SCy Schubert #endif /* CONFIG_NO_CONFIG_WRITE */ 9314bc52338SCy Schubert 9324bc52338SCy Schubert if (wpa_s->conf->dpp_config_processing < 2) 9334bc52338SCy Schubert return 0; 9344bc52338SCy Schubert 9354bc52338SCy Schubert #ifdef CONFIG_DPP2 9364bc52338SCy Schubert if (auth->peer_version >= 2) { 9374bc52338SCy Schubert wpa_printf(MSG_DEBUG, 9384bc52338SCy Schubert "DPP: Postpone connection attempt to wait for completion of DPP Configuration Result"); 9394bc52338SCy Schubert auth->connect_on_tx_status = 1; 9404bc52338SCy Schubert return 0; 9414bc52338SCy Schubert } 9424bc52338SCy Schubert #endif /* CONFIG_DPP2 */ 9434bc52338SCy Schubert 9444bc52338SCy Schubert wpas_dpp_try_to_connect(wpa_s); 9454bc52338SCy Schubert return 0; 94685732ac8SCy Schubert } 94785732ac8SCy Schubert 94885732ac8SCy Schubert 9494bc52338SCy Schubert static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s, 95085732ac8SCy Schubert struct dpp_authentication *auth) 95185732ac8SCy Schubert { 95285732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED); 95385732ac8SCy Schubert if (auth->ssid_len) 95485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s", 95585732ac8SCy Schubert wpa_ssid_txt(auth->ssid, auth->ssid_len)); 95685732ac8SCy Schubert if (auth->connector) { 95785732ac8SCy Schubert /* TODO: Save the Connector and consider using a command 95885732ac8SCy Schubert * to fetch the value instead of sending an event with 95985732ac8SCy Schubert * it. The Connector could end up being larger than what 96085732ac8SCy Schubert * most clients are ready to receive as an event 96185732ac8SCy Schubert * message. */ 96285732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s", 96385732ac8SCy Schubert auth->connector); 96485732ac8SCy Schubert } 96585732ac8SCy Schubert if (auth->c_sign_key) { 96685732ac8SCy Schubert char *hex; 96785732ac8SCy Schubert size_t hexlen; 96885732ac8SCy Schubert 96985732ac8SCy Schubert hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1; 97085732ac8SCy Schubert hex = os_malloc(hexlen); 97185732ac8SCy Schubert if (hex) { 97285732ac8SCy Schubert wpa_snprintf_hex(hex, hexlen, 97385732ac8SCy Schubert wpabuf_head(auth->c_sign_key), 97485732ac8SCy Schubert wpabuf_len(auth->c_sign_key)); 97585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s", 97685732ac8SCy Schubert hex); 97785732ac8SCy Schubert os_free(hex); 97885732ac8SCy Schubert } 97985732ac8SCy Schubert } 98085732ac8SCy Schubert if (auth->net_access_key) { 98185732ac8SCy Schubert char *hex; 98285732ac8SCy Schubert size_t hexlen; 98385732ac8SCy Schubert 98485732ac8SCy Schubert hexlen = 2 * wpabuf_len(auth->net_access_key) + 1; 98585732ac8SCy Schubert hex = os_malloc(hexlen); 98685732ac8SCy Schubert if (hex) { 98785732ac8SCy Schubert wpa_snprintf_hex(hex, hexlen, 98885732ac8SCy Schubert wpabuf_head(auth->net_access_key), 98985732ac8SCy Schubert wpabuf_len(auth->net_access_key)); 99085732ac8SCy Schubert if (auth->net_access_key_expiry) 99185732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, 99285732ac8SCy Schubert DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex, 99385732ac8SCy Schubert (long unsigned) 99485732ac8SCy Schubert auth->net_access_key_expiry); 99585732ac8SCy Schubert else 99685732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, 99785732ac8SCy Schubert DPP_EVENT_NET_ACCESS_KEY "%s", hex); 99885732ac8SCy Schubert os_free(hex); 99985732ac8SCy Schubert } 100085732ac8SCy Schubert } 100185732ac8SCy Schubert 10024bc52338SCy Schubert return wpas_dpp_process_config(wpa_s, auth); 100385732ac8SCy Schubert } 100485732ac8SCy Schubert 100585732ac8SCy Schubert 100685732ac8SCy Schubert static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, 100785732ac8SCy Schubert enum gas_query_result result, 100885732ac8SCy Schubert const struct wpabuf *adv_proto, 100985732ac8SCy Schubert const struct wpabuf *resp, u16 status_code) 101085732ac8SCy Schubert { 101185732ac8SCy Schubert struct wpa_supplicant *wpa_s = ctx; 101285732ac8SCy Schubert const u8 *pos; 101385732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 10144bc52338SCy Schubert int res; 10154bc52338SCy Schubert enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED; 101685732ac8SCy Schubert 101785732ac8SCy Schubert wpa_s->dpp_gas_dialog_token = -1; 101885732ac8SCy Schubert 101985732ac8SCy Schubert if (!auth || !auth->auth_success) { 102085732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); 102185732ac8SCy Schubert return; 102285732ac8SCy Schubert } 102385732ac8SCy Schubert if (result != GAS_QUERY_SUCCESS || 102485732ac8SCy Schubert !resp || status_code != WLAN_STATUS_SUCCESS) { 102585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed"); 102685732ac8SCy Schubert goto fail; 102785732ac8SCy Schubert } 102885732ac8SCy Schubert 102985732ac8SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto", 103085732ac8SCy Schubert adv_proto); 103185732ac8SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)", 103285732ac8SCy Schubert resp); 103385732ac8SCy Schubert 103485732ac8SCy Schubert if (wpabuf_len(adv_proto) != 10 || 103585732ac8SCy Schubert !(pos = wpabuf_head(adv_proto)) || 103685732ac8SCy Schubert pos[0] != WLAN_EID_ADV_PROTO || 103785732ac8SCy Schubert pos[1] != 8 || 103885732ac8SCy Schubert pos[3] != WLAN_EID_VENDOR_SPECIFIC || 103985732ac8SCy Schubert pos[4] != 5 || 104085732ac8SCy Schubert WPA_GET_BE24(&pos[5]) != OUI_WFA || 104185732ac8SCy Schubert pos[8] != 0x1a || 104285732ac8SCy Schubert pos[9] != 1) { 104385732ac8SCy Schubert wpa_printf(MSG_DEBUG, 104485732ac8SCy Schubert "DPP: Not a DPP Advertisement Protocol ID"); 104585732ac8SCy Schubert goto fail; 104685732ac8SCy Schubert } 104785732ac8SCy Schubert 104885732ac8SCy Schubert if (dpp_conf_resp_rx(auth, resp) < 0) { 104985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); 105085732ac8SCy Schubert goto fail; 105185732ac8SCy Schubert } 105285732ac8SCy Schubert 10534bc52338SCy Schubert res = wpas_dpp_handle_config_obj(wpa_s, auth); 10544bc52338SCy Schubert if (res < 0) 10554bc52338SCy Schubert goto fail; 105685732ac8SCy Schubert 10574bc52338SCy Schubert status = DPP_STATUS_OK; 10584bc52338SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 10594bc52338SCy Schubert if (dpp_test == DPP_TEST_REJECT_CONFIG) { 10604bc52338SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object"); 10614bc52338SCy Schubert status = DPP_STATUS_CONFIG_REJECTED; 10624bc52338SCy Schubert } 10634bc52338SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 106485732ac8SCy Schubert fail: 10654bc52338SCy Schubert if (status != DPP_STATUS_OK) 106685732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); 10674bc52338SCy Schubert #ifdef CONFIG_DPP2 10684bc52338SCy Schubert if (auth->peer_version >= 2 && 10694bc52338SCy Schubert auth->conf_resp_status == DPP_STATUS_OK) { 10704bc52338SCy Schubert struct wpabuf *msg; 10714bc52338SCy Schubert 10724bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result"); 10734bc52338SCy Schubert msg = dpp_build_conf_result(auth, status); 10744bc52338SCy Schubert if (!msg) 10754bc52338SCy Schubert goto fail2; 10764bc52338SCy Schubert 10774bc52338SCy Schubert wpa_msg(wpa_s, MSG_INFO, 10784bc52338SCy Schubert DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", 10794bc52338SCy Schubert MAC2STR(addr), auth->curr_freq, 10804bc52338SCy Schubert DPP_PA_CONFIGURATION_RESULT); 10814bc52338SCy Schubert offchannel_send_action(wpa_s, auth->curr_freq, 10824bc52338SCy Schubert addr, wpa_s->own_addr, broadcast, 10834bc52338SCy Schubert wpabuf_head(msg), 10844bc52338SCy Schubert wpabuf_len(msg), 10854bc52338SCy Schubert 500, wpas_dpp_tx_status, 0); 10864bc52338SCy Schubert wpabuf_free(msg); 10874bc52338SCy Schubert 10884bc52338SCy Schubert /* This exchange will be terminated in the TX status handler */ 10894bc52338SCy Schubert return; 10904bc52338SCy Schubert } 10914bc52338SCy Schubert fail2: 10924bc52338SCy Schubert #endif /* CONFIG_DPP2 */ 109385732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth); 109485732ac8SCy Schubert wpa_s->dpp_auth = NULL; 109585732ac8SCy Schubert } 109685732ac8SCy Schubert 109785732ac8SCy Schubert 109885732ac8SCy Schubert static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s) 109985732ac8SCy Schubert { 110085732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 11014bc52338SCy Schubert struct wpabuf *buf; 110285732ac8SCy Schubert char json[100]; 110385732ac8SCy Schubert int res; 110485732ac8SCy Schubert 110585732ac8SCy Schubert wpa_s->dpp_gas_client = 1; 110685732ac8SCy Schubert os_snprintf(json, sizeof(json), 110785732ac8SCy Schubert "{\"name\":\"Test\"," 110885732ac8SCy Schubert "\"wi-fi_tech\":\"infra\"," 110985732ac8SCy Schubert "\"netRole\":\"%s\"}", 111085732ac8SCy Schubert wpa_s->dpp_netrole_ap ? "ap" : "sta"); 111185732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 111285732ac8SCy Schubert if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) { 111385732ac8SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr"); 111485732ac8SCy Schubert json[29] = 'k'; /* replace "infra" with "knfra" */ 111585732ac8SCy Schubert } 111685732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 111785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json); 111885732ac8SCy Schubert 111985732ac8SCy Schubert offchannel_send_action_done(wpa_s); 112085732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s); 112185732ac8SCy Schubert 11224bc52338SCy Schubert buf = dpp_build_conf_req(auth, json); 11234bc52338SCy Schubert if (!buf) { 112485732ac8SCy Schubert wpa_printf(MSG_DEBUG, 112585732ac8SCy Schubert "DPP: No configuration request data available"); 112685732ac8SCy Schubert return; 112785732ac8SCy Schubert } 112885732ac8SCy Schubert 112985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)", 113085732ac8SCy Schubert MAC2STR(auth->peer_mac_addr), auth->curr_freq); 113185732ac8SCy Schubert 113285732ac8SCy Schubert res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq, 113385732ac8SCy Schubert 1, buf, wpas_dpp_gas_resp_cb, wpa_s); 113485732ac8SCy Schubert if (res < 0) { 113585732ac8SCy Schubert wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request"); 113685732ac8SCy Schubert wpabuf_free(buf); 113785732ac8SCy Schubert } else { 113885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 113985732ac8SCy Schubert "DPP: GAS query started with dialog token %u", res); 114085732ac8SCy Schubert wpa_s->dpp_gas_dialog_token = res; 114185732ac8SCy Schubert } 114285732ac8SCy Schubert } 114385732ac8SCy Schubert 114485732ac8SCy Schubert 114585732ac8SCy Schubert static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator) 114685732ac8SCy Schubert { 114785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded"); 114885732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", initiator); 114985732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 115085732ac8SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) { 115185732ac8SCy Schubert wpa_printf(MSG_INFO, 115285732ac8SCy Schubert "DPP: TESTING - stop at Authentication Confirm"); 115385732ac8SCy Schubert if (wpa_s->dpp_auth->configurator) { 115485732ac8SCy Schubert /* Prevent GAS response */ 115585732ac8SCy Schubert wpa_s->dpp_auth->auth_success = 0; 115685732ac8SCy Schubert } 115785732ac8SCy Schubert return; 115885732ac8SCy Schubert } 115985732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 116085732ac8SCy Schubert 116185732ac8SCy Schubert if (wpa_s->dpp_auth->configurator) 116285732ac8SCy Schubert wpas_dpp_start_gas_server(wpa_s); 116385732ac8SCy Schubert else 116485732ac8SCy Schubert wpas_dpp_start_gas_client(wpa_s); 116585732ac8SCy Schubert } 116685732ac8SCy Schubert 116785732ac8SCy Schubert 116885732ac8SCy Schubert static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src, 116985732ac8SCy Schubert const u8 *hdr, const u8 *buf, size_t len, 117085732ac8SCy Schubert unsigned int freq) 117185732ac8SCy Schubert { 117285732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 117385732ac8SCy Schubert struct wpabuf *msg; 117485732ac8SCy Schubert 117585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR 117685732ac8SCy Schubert " (freq %u MHz)", MAC2STR(src), freq); 117785732ac8SCy Schubert 117885732ac8SCy Schubert if (!auth) { 117985732ac8SCy Schubert wpa_printf(MSG_DEBUG, 118085732ac8SCy Schubert "DPP: No DPP Authentication in progress - drop"); 118185732ac8SCy Schubert return; 118285732ac8SCy Schubert } 118385732ac8SCy Schubert 118485732ac8SCy Schubert if (!is_zero_ether_addr(auth->peer_mac_addr) && 118585732ac8SCy Schubert os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { 118685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " 118785732ac8SCy Schubert MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); 118885732ac8SCy Schubert return; 118985732ac8SCy Schubert } 119085732ac8SCy Schubert 119185732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); 119285732ac8SCy Schubert 119385732ac8SCy Schubert if (auth->curr_freq != freq && auth->neg_freq == freq) { 119485732ac8SCy Schubert wpa_printf(MSG_DEBUG, 119585732ac8SCy Schubert "DPP: Responder accepted request for different negotiation channel"); 119685732ac8SCy Schubert auth->curr_freq = freq; 119785732ac8SCy Schubert } 119885732ac8SCy Schubert 119985732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); 120085732ac8SCy Schubert msg = dpp_auth_resp_rx(auth, hdr, buf, len); 120185732ac8SCy Schubert if (!msg) { 120285732ac8SCy Schubert if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) { 120385732ac8SCy Schubert wpa_printf(MSG_DEBUG, 120485732ac8SCy Schubert "DPP: Start wait for full response"); 120585732ac8SCy Schubert offchannel_send_action_done(wpa_s); 120685732ac8SCy Schubert wpas_dpp_listen_start(wpa_s, auth->curr_freq); 120785732ac8SCy Schubert return; 120885732ac8SCy Schubert } 120985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No confirm generated"); 121085732ac8SCy Schubert return; 121185732ac8SCy Schubert } 121285732ac8SCy Schubert os_memcpy(auth->peer_mac_addr, src, ETH_ALEN); 121385732ac8SCy Schubert 121485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", 121585732ac8SCy Schubert MAC2STR(src), auth->curr_freq, DPP_PA_AUTHENTICATION_CONF); 121685732ac8SCy Schubert offchannel_send_action(wpa_s, auth->curr_freq, 121785732ac8SCy Schubert src, wpa_s->own_addr, broadcast, 121885732ac8SCy Schubert wpabuf_head(msg), wpabuf_len(msg), 121985732ac8SCy Schubert 500, wpas_dpp_tx_status, 0); 122085732ac8SCy Schubert wpabuf_free(msg); 122185732ac8SCy Schubert wpa_s->dpp_auth_ok_on_ack = 1; 122285732ac8SCy Schubert } 122385732ac8SCy Schubert 122485732ac8SCy Schubert 122585732ac8SCy Schubert static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src, 122685732ac8SCy Schubert const u8 *hdr, const u8 *buf, size_t len) 122785732ac8SCy Schubert { 122885732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 122985732ac8SCy Schubert 123085732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR, 123185732ac8SCy Schubert MAC2STR(src)); 123285732ac8SCy Schubert 123385732ac8SCy Schubert if (!auth) { 123485732ac8SCy Schubert wpa_printf(MSG_DEBUG, 123585732ac8SCy Schubert "DPP: No DPP Authentication in progress - drop"); 123685732ac8SCy Schubert return; 123785732ac8SCy Schubert } 123885732ac8SCy Schubert 123985732ac8SCy Schubert if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { 124085732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " 124185732ac8SCy Schubert MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); 124285732ac8SCy Schubert return; 124385732ac8SCy Schubert } 124485732ac8SCy Schubert 124585732ac8SCy Schubert if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) { 124685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Authentication failed"); 124785732ac8SCy Schubert return; 124885732ac8SCy Schubert } 124985732ac8SCy Schubert 125085732ac8SCy Schubert wpas_dpp_auth_success(wpa_s, 0); 125185732ac8SCy Schubert } 125285732ac8SCy Schubert 125385732ac8SCy Schubert 12544bc52338SCy Schubert #ifdef CONFIG_DPP2 12554bc52338SCy Schubert 12564bc52338SCy Schubert static void wpas_dpp_config_result_wait_timeout(void *eloop_ctx, 12574bc52338SCy Schubert void *timeout_ctx) 12584bc52338SCy Schubert { 12594bc52338SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx; 12604bc52338SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 12614bc52338SCy Schubert 12624bc52338SCy Schubert if (!auth || !auth->waiting_conf_result) 12634bc52338SCy Schubert return; 12644bc52338SCy Schubert 12654bc52338SCy Schubert wpa_printf(MSG_DEBUG, 12664bc52338SCy Schubert "DPP: Timeout while waiting for Configuration Result"); 12674bc52338SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); 12684bc52338SCy Schubert dpp_auth_deinit(auth); 12694bc52338SCy Schubert wpa_s->dpp_auth = NULL; 12704bc52338SCy Schubert } 12714bc52338SCy Schubert 12724bc52338SCy Schubert 12734bc52338SCy Schubert static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src, 12744bc52338SCy Schubert const u8 *hdr, const u8 *buf, size_t len) 12754bc52338SCy Schubert { 12764bc52338SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 12774bc52338SCy Schubert enum dpp_status_error status; 12784bc52338SCy Schubert 12794bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR, 12804bc52338SCy Schubert MAC2STR(src)); 12814bc52338SCy Schubert 12824bc52338SCy Schubert if (!auth || !auth->waiting_conf_result) { 12834bc52338SCy Schubert wpa_printf(MSG_DEBUG, 12844bc52338SCy Schubert "DPP: No DPP Configuration waiting for result - drop"); 12854bc52338SCy Schubert return; 12864bc52338SCy Schubert } 12874bc52338SCy Schubert 12884bc52338SCy Schubert if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { 12894bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " 12904bc52338SCy Schubert MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); 12914bc52338SCy Schubert return; 12924bc52338SCy Schubert } 12934bc52338SCy Schubert 12944bc52338SCy Schubert status = dpp_conf_result_rx(auth, hdr, buf, len); 12954bc52338SCy Schubert 12964bc52338SCy Schubert offchannel_send_action_done(wpa_s); 12974bc52338SCy Schubert wpas_dpp_listen_stop(wpa_s); 12984bc52338SCy Schubert if (status == DPP_STATUS_OK) 12994bc52338SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT); 13004bc52338SCy Schubert else 13014bc52338SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); 13024bc52338SCy Schubert dpp_auth_deinit(auth); 13034bc52338SCy Schubert wpa_s->dpp_auth = NULL; 13044bc52338SCy Schubert eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL); 13054bc52338SCy Schubert } 13064bc52338SCy Schubert 1307*206b73d0SCy Schubert 1308*206b73d0SCy Schubert static int wpas_dpp_process_conf_obj(void *ctx, 1309*206b73d0SCy Schubert struct dpp_authentication *auth) 1310*206b73d0SCy Schubert { 1311*206b73d0SCy Schubert struct wpa_supplicant *wpa_s = ctx; 1312*206b73d0SCy Schubert 1313*206b73d0SCy Schubert return wpas_dpp_handle_config_obj(wpa_s, auth); 1314*206b73d0SCy Schubert } 1315*206b73d0SCy Schubert 13164bc52338SCy Schubert #endif /* CONFIG_DPP2 */ 13174bc52338SCy Schubert 13184bc52338SCy Schubert 131985732ac8SCy Schubert static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, 132085732ac8SCy Schubert const u8 *src, 132185732ac8SCy Schubert const u8 *buf, size_t len) 132285732ac8SCy Schubert { 132385732ac8SCy Schubert struct wpa_ssid *ssid; 132485732ac8SCy Schubert const u8 *connector, *trans_id, *status; 132585732ac8SCy Schubert u16 connector_len, trans_id_len, status_len; 132685732ac8SCy Schubert struct dpp_introduction intro; 132785732ac8SCy Schubert struct rsn_pmksa_cache_entry *entry; 132885732ac8SCy Schubert struct os_time now; 132985732ac8SCy Schubert struct os_reltime rnow; 133085732ac8SCy Schubert os_time_t expiry; 133185732ac8SCy Schubert unsigned int seconds; 133285732ac8SCy Schubert enum dpp_status_error res; 133385732ac8SCy Schubert 133485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Response from " MACSTR, 133585732ac8SCy Schubert MAC2STR(src)); 133685732ac8SCy Schubert if (is_zero_ether_addr(wpa_s->dpp_intro_bssid) || 133785732ac8SCy Schubert os_memcmp(src, wpa_s->dpp_intro_bssid, ETH_ALEN) != 0) { 133885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Not waiting for response from " 133985732ac8SCy Schubert MACSTR " - drop", MAC2STR(src)); 134085732ac8SCy Schubert return; 134185732ac8SCy Schubert } 134285732ac8SCy Schubert offchannel_send_action_done(wpa_s); 134385732ac8SCy Schubert 134485732ac8SCy Schubert for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { 134585732ac8SCy Schubert if (ssid == wpa_s->dpp_intro_network) 134685732ac8SCy Schubert break; 134785732ac8SCy Schubert } 134885732ac8SCy Schubert if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey || 134985732ac8SCy Schubert !ssid->dpp_csign) { 135085732ac8SCy Schubert wpa_printf(MSG_DEBUG, 135185732ac8SCy Schubert "DPP: Profile not found for network introduction"); 135285732ac8SCy Schubert return; 135385732ac8SCy Schubert } 135485732ac8SCy Schubert 135585732ac8SCy Schubert trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID, 135685732ac8SCy Schubert &trans_id_len); 135785732ac8SCy Schubert if (!trans_id || trans_id_len != 1) { 135885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 135985732ac8SCy Schubert "DPP: Peer did not include Transaction ID"); 136085732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR 136185732ac8SCy Schubert " fail=missing_transaction_id", MAC2STR(src)); 136285732ac8SCy Schubert goto fail; 136385732ac8SCy Schubert } 136485732ac8SCy Schubert if (trans_id[0] != TRANSACTION_ID) { 136585732ac8SCy Schubert wpa_printf(MSG_DEBUG, 136685732ac8SCy Schubert "DPP: Ignore frame with unexpected Transaction ID %u", 136785732ac8SCy Schubert trans_id[0]); 136885732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR 136985732ac8SCy Schubert " fail=transaction_id_mismatch", MAC2STR(src)); 137085732ac8SCy Schubert goto fail; 137185732ac8SCy Schubert } 137285732ac8SCy Schubert 137385732ac8SCy Schubert status = dpp_get_attr(buf, len, DPP_ATTR_STATUS, &status_len); 137485732ac8SCy Schubert if (!status || status_len != 1) { 137585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer did not include Status"); 137685732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR 137785732ac8SCy Schubert " fail=missing_status", MAC2STR(src)); 137885732ac8SCy Schubert goto fail; 137985732ac8SCy Schubert } 138085732ac8SCy Schubert if (status[0] != DPP_STATUS_OK) { 138185732ac8SCy Schubert wpa_printf(MSG_DEBUG, 138285732ac8SCy Schubert "DPP: Peer rejected network introduction: Status %u", 138385732ac8SCy Schubert status[0]); 138485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR 138585732ac8SCy Schubert " status=%u", MAC2STR(src), status[0]); 138685732ac8SCy Schubert goto fail; 138785732ac8SCy Schubert } 138885732ac8SCy Schubert 138985732ac8SCy Schubert connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len); 139085732ac8SCy Schubert if (!connector) { 139185732ac8SCy Schubert wpa_printf(MSG_DEBUG, 139285732ac8SCy Schubert "DPP: Peer did not include its Connector"); 139385732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR 139485732ac8SCy Schubert " fail=missing_connector", MAC2STR(src)); 139585732ac8SCy Schubert goto fail; 139685732ac8SCy Schubert } 139785732ac8SCy Schubert 139885732ac8SCy Schubert res = dpp_peer_intro(&intro, ssid->dpp_connector, 139985732ac8SCy Schubert ssid->dpp_netaccesskey, 140085732ac8SCy Schubert ssid->dpp_netaccesskey_len, 140185732ac8SCy Schubert ssid->dpp_csign, 140285732ac8SCy Schubert ssid->dpp_csign_len, 140385732ac8SCy Schubert connector, connector_len, &expiry); 140485732ac8SCy Schubert if (res != DPP_STATUS_OK) { 140585732ac8SCy Schubert wpa_printf(MSG_INFO, 140685732ac8SCy Schubert "DPP: Network Introduction protocol resulted in failure"); 140785732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR 140885732ac8SCy Schubert " fail=peer_connector_validation_failed", MAC2STR(src)); 140985732ac8SCy Schubert goto fail; 141085732ac8SCy Schubert } 141185732ac8SCy Schubert 141285732ac8SCy Schubert entry = os_zalloc(sizeof(*entry)); 141385732ac8SCy Schubert if (!entry) 141485732ac8SCy Schubert goto fail; 141585732ac8SCy Schubert os_memcpy(entry->aa, src, ETH_ALEN); 141685732ac8SCy Schubert os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN); 141785732ac8SCy Schubert os_memcpy(entry->pmk, intro.pmk, intro.pmk_len); 141885732ac8SCy Schubert entry->pmk_len = intro.pmk_len; 141985732ac8SCy Schubert entry->akmp = WPA_KEY_MGMT_DPP; 142085732ac8SCy Schubert if (expiry) { 142185732ac8SCy Schubert os_get_time(&now); 142285732ac8SCy Schubert seconds = expiry - now.sec; 142385732ac8SCy Schubert } else { 142485732ac8SCy Schubert seconds = 86400 * 7; 142585732ac8SCy Schubert } 142685732ac8SCy Schubert os_get_reltime(&rnow); 142785732ac8SCy Schubert entry->expiration = rnow.sec + seconds; 142885732ac8SCy Schubert entry->reauth_time = rnow.sec + seconds; 142985732ac8SCy Schubert entry->network_ctx = ssid; 143085732ac8SCy Schubert wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry); 143185732ac8SCy Schubert 143285732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR 143385732ac8SCy Schubert " status=%u", MAC2STR(src), status[0]); 143485732ac8SCy Schubert 143585732ac8SCy Schubert wpa_printf(MSG_DEBUG, 143685732ac8SCy Schubert "DPP: Try connection again after successful network introduction"); 143785732ac8SCy Schubert if (wpa_supplicant_fast_associate(wpa_s) != 1) { 143885732ac8SCy Schubert wpa_supplicant_cancel_sched_scan(wpa_s); 143985732ac8SCy Schubert wpa_supplicant_req_scan(wpa_s, 0, 0); 144085732ac8SCy Schubert } 144185732ac8SCy Schubert fail: 144285732ac8SCy Schubert os_memset(&intro, 0, sizeof(intro)); 144385732ac8SCy Schubert } 144485732ac8SCy Schubert 144585732ac8SCy Schubert 144685732ac8SCy Schubert static int wpas_dpp_allow_ir(struct wpa_supplicant *wpa_s, unsigned int freq) 144785732ac8SCy Schubert { 144885732ac8SCy Schubert int i, j; 144985732ac8SCy Schubert 145085732ac8SCy Schubert if (!wpa_s->hw.modes) 145185732ac8SCy Schubert return -1; 145285732ac8SCy Schubert 145385732ac8SCy Schubert for (i = 0; i < wpa_s->hw.num_modes; i++) { 145485732ac8SCy Schubert struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; 145585732ac8SCy Schubert 145685732ac8SCy Schubert for (j = 0; j < mode->num_channels; j++) { 145785732ac8SCy Schubert struct hostapd_channel_data *chan = &mode->channels[j]; 145885732ac8SCy Schubert 145985732ac8SCy Schubert if (chan->freq != (int) freq) 146085732ac8SCy Schubert continue; 146185732ac8SCy Schubert 146285732ac8SCy Schubert if (chan->flag & (HOSTAPD_CHAN_DISABLED | 146385732ac8SCy Schubert HOSTAPD_CHAN_NO_IR | 146485732ac8SCy Schubert HOSTAPD_CHAN_RADAR)) 146585732ac8SCy Schubert continue; 146685732ac8SCy Schubert 146785732ac8SCy Schubert return 1; 146885732ac8SCy Schubert } 146985732ac8SCy Schubert } 147085732ac8SCy Schubert 147185732ac8SCy Schubert wpa_printf(MSG_DEBUG, 147285732ac8SCy Schubert "DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list", 147385732ac8SCy Schubert freq); 147485732ac8SCy Schubert 147585732ac8SCy Schubert return 0; 147685732ac8SCy Schubert } 147785732ac8SCy Schubert 147885732ac8SCy Schubert 147985732ac8SCy Schubert static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s, 148085732ac8SCy Schubert struct dpp_pkex *pkex) 148185732ac8SCy Schubert { 148285732ac8SCy Schubert if (pkex->freq == 2437) 148385732ac8SCy Schubert pkex->freq = 5745; 148485732ac8SCy Schubert else if (pkex->freq == 5745) 148585732ac8SCy Schubert pkex->freq = 5220; 148685732ac8SCy Schubert else if (pkex->freq == 5220) 148785732ac8SCy Schubert pkex->freq = 60480; 148885732ac8SCy Schubert else 148985732ac8SCy Schubert return -1; /* no more channels to try */ 149085732ac8SCy Schubert 149185732ac8SCy Schubert if (wpas_dpp_allow_ir(wpa_s, pkex->freq) == 1) { 149285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz", 149385732ac8SCy Schubert pkex->freq); 149485732ac8SCy Schubert return 0; 149585732ac8SCy Schubert } 149685732ac8SCy Schubert 149785732ac8SCy Schubert /* Could not use this channel - try the next one */ 149885732ac8SCy Schubert return wpas_dpp_pkex_next_channel(wpa_s, pkex); 149985732ac8SCy Schubert } 150085732ac8SCy Schubert 150185732ac8SCy Schubert 150285732ac8SCy Schubert static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx) 150385732ac8SCy Schubert { 150485732ac8SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx; 150585732ac8SCy Schubert struct dpp_pkex *pkex = wpa_s->dpp_pkex; 150685732ac8SCy Schubert 150785732ac8SCy Schubert if (!pkex || !pkex->exchange_req) 150885732ac8SCy Schubert return; 150985732ac8SCy Schubert if (pkex->exch_req_tries >= 5) { 151085732ac8SCy Schubert if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) { 151185732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL 151285732ac8SCy Schubert "No response from PKEX peer"); 151385732ac8SCy Schubert dpp_pkex_free(pkex); 151485732ac8SCy Schubert wpa_s->dpp_pkex = NULL; 151585732ac8SCy Schubert return; 151685732ac8SCy Schubert } 151785732ac8SCy Schubert pkex->exch_req_tries = 0; 151885732ac8SCy Schubert } 151985732ac8SCy Schubert 152085732ac8SCy Schubert pkex->exch_req_tries++; 152185732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)", 152285732ac8SCy Schubert pkex->exch_req_tries); 152385732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", 152485732ac8SCy Schubert MAC2STR(broadcast), pkex->freq, DPP_PA_PKEX_EXCHANGE_REQ); 152585732ac8SCy Schubert offchannel_send_action(wpa_s, pkex->freq, broadcast, 152685732ac8SCy Schubert wpa_s->own_addr, broadcast, 152785732ac8SCy Schubert wpabuf_head(pkex->exchange_req), 152885732ac8SCy Schubert wpabuf_len(pkex->exchange_req), 152985732ac8SCy Schubert pkex->exch_req_wait_time, 153085732ac8SCy Schubert wpas_dpp_tx_pkex_status, 0); 153185732ac8SCy Schubert } 153285732ac8SCy Schubert 153385732ac8SCy Schubert 153485732ac8SCy Schubert static void 153585732ac8SCy Schubert wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, 153685732ac8SCy Schubert unsigned int freq, const u8 *dst, 153785732ac8SCy Schubert const u8 *src, const u8 *bssid, 153885732ac8SCy Schubert const u8 *data, size_t data_len, 153985732ac8SCy Schubert enum offchannel_send_action_result result) 154085732ac8SCy Schubert { 154185732ac8SCy Schubert const char *res_txt; 154285732ac8SCy Schubert struct dpp_pkex *pkex = wpa_s->dpp_pkex; 154385732ac8SCy Schubert 154485732ac8SCy Schubert res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" : 154585732ac8SCy Schubert (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" : 154685732ac8SCy Schubert "FAILED"); 154785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR 154885732ac8SCy Schubert " result=%s (PKEX)", 154985732ac8SCy Schubert freq, MAC2STR(dst), res_txt); 155085732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR 155185732ac8SCy Schubert " freq=%u result=%s", MAC2STR(dst), freq, res_txt); 155285732ac8SCy Schubert 155385732ac8SCy Schubert if (!pkex) { 155485732ac8SCy Schubert wpa_printf(MSG_DEBUG, 155585732ac8SCy Schubert "DPP: Ignore TX status since there is no ongoing PKEX exchange"); 155685732ac8SCy Schubert return; 155785732ac8SCy Schubert } 155885732ac8SCy Schubert 155985732ac8SCy Schubert if (pkex->failed) { 156085732ac8SCy Schubert wpa_printf(MSG_DEBUG, 156185732ac8SCy Schubert "DPP: Terminate PKEX exchange due to an earlier error"); 156285732ac8SCy Schubert if (pkex->t > pkex->own_bi->pkex_t) 156385732ac8SCy Schubert pkex->own_bi->pkex_t = pkex->t; 156485732ac8SCy Schubert dpp_pkex_free(pkex); 156585732ac8SCy Schubert wpa_s->dpp_pkex = NULL; 156685732ac8SCy Schubert return; 156785732ac8SCy Schubert } 156885732ac8SCy Schubert 156985732ac8SCy Schubert if (pkex->exch_req_wait_time && pkex->exchange_req) { 157085732ac8SCy Schubert /* Wait for PKEX Exchange Response frame and retry request if 157185732ac8SCy Schubert * no response is seen. */ 157285732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL); 157385732ac8SCy Schubert eloop_register_timeout(pkex->exch_req_wait_time / 1000, 157485732ac8SCy Schubert (pkex->exch_req_wait_time % 1000) * 1000, 157585732ac8SCy Schubert wpas_dpp_pkex_retry_timeout, wpa_s, 157685732ac8SCy Schubert NULL); 157785732ac8SCy Schubert } 157885732ac8SCy Schubert } 157985732ac8SCy Schubert 158085732ac8SCy Schubert 158185732ac8SCy Schubert static void 158285732ac8SCy Schubert wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src, 158385732ac8SCy Schubert const u8 *buf, size_t len, unsigned int freq) 158485732ac8SCy Schubert { 158585732ac8SCy Schubert struct wpabuf *msg; 158685732ac8SCy Schubert unsigned int wait_time; 158785732ac8SCy Schubert 158885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR, 158985732ac8SCy Schubert MAC2STR(src)); 159085732ac8SCy Schubert 159185732ac8SCy Schubert /* TODO: Support multiple PKEX codes by iterating over all the enabled 159285732ac8SCy Schubert * values here */ 159385732ac8SCy Schubert 159485732ac8SCy Schubert if (!wpa_s->dpp_pkex_code || !wpa_s->dpp_pkex_bi) { 159585732ac8SCy Schubert wpa_printf(MSG_DEBUG, 159685732ac8SCy Schubert "DPP: No PKEX code configured - ignore request"); 159785732ac8SCy Schubert return; 159885732ac8SCy Schubert } 159985732ac8SCy Schubert 160085732ac8SCy Schubert if (wpa_s->dpp_pkex) { 160185732ac8SCy Schubert /* TODO: Support parallel operations */ 160285732ac8SCy Schubert wpa_printf(MSG_DEBUG, 160385732ac8SCy Schubert "DPP: Already in PKEX session - ignore new request"); 160485732ac8SCy Schubert return; 160585732ac8SCy Schubert } 160685732ac8SCy Schubert 160785732ac8SCy Schubert wpa_s->dpp_pkex = dpp_pkex_rx_exchange_req(wpa_s, wpa_s->dpp_pkex_bi, 160885732ac8SCy Schubert wpa_s->own_addr, src, 160985732ac8SCy Schubert wpa_s->dpp_pkex_identifier, 161085732ac8SCy Schubert wpa_s->dpp_pkex_code, 161185732ac8SCy Schubert buf, len); 161285732ac8SCy Schubert if (!wpa_s->dpp_pkex) { 161385732ac8SCy Schubert wpa_printf(MSG_DEBUG, 161485732ac8SCy Schubert "DPP: Failed to process the request - ignore it"); 161585732ac8SCy Schubert return; 161685732ac8SCy Schubert } 161785732ac8SCy Schubert 161885732ac8SCy Schubert msg = wpa_s->dpp_pkex->exchange_resp; 161985732ac8SCy Schubert wait_time = wpa_s->max_remain_on_chan; 162085732ac8SCy Schubert if (wait_time > 2000) 162185732ac8SCy Schubert wait_time = 2000; 162285732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", 162385732ac8SCy Schubert MAC2STR(src), freq, DPP_PA_PKEX_EXCHANGE_RESP); 162485732ac8SCy Schubert offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, 162585732ac8SCy Schubert broadcast, 162685732ac8SCy Schubert wpabuf_head(msg), wpabuf_len(msg), 162785732ac8SCy Schubert wait_time, wpas_dpp_tx_pkex_status, 0); 162885732ac8SCy Schubert } 162985732ac8SCy Schubert 163085732ac8SCy Schubert 163185732ac8SCy Schubert static void 163285732ac8SCy Schubert wpas_dpp_rx_pkex_exchange_resp(struct wpa_supplicant *wpa_s, const u8 *src, 163385732ac8SCy Schubert const u8 *buf, size_t len, unsigned int freq) 163485732ac8SCy Schubert { 163585732ac8SCy Schubert struct wpabuf *msg; 163685732ac8SCy Schubert unsigned int wait_time; 163785732ac8SCy Schubert 163885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR, 163985732ac8SCy Schubert MAC2STR(src)); 164085732ac8SCy Schubert 164185732ac8SCy Schubert /* TODO: Support multiple PKEX codes by iterating over all the enabled 164285732ac8SCy Schubert * values here */ 164385732ac8SCy Schubert 164485732ac8SCy Schubert if (!wpa_s->dpp_pkex || !wpa_s->dpp_pkex->initiator || 164585732ac8SCy Schubert wpa_s->dpp_pkex->exchange_done) { 164685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); 164785732ac8SCy Schubert return; 164885732ac8SCy Schubert } 164985732ac8SCy Schubert 165085732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL); 165185732ac8SCy Schubert wpa_s->dpp_pkex->exch_req_wait_time = 0; 165285732ac8SCy Schubert 165385732ac8SCy Schubert msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, src, buf, len); 165485732ac8SCy Schubert if (!msg) { 165585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); 165685732ac8SCy Schubert return; 165785732ac8SCy Schubert } 165885732ac8SCy Schubert 165985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR, 166085732ac8SCy Schubert MAC2STR(src)); 166185732ac8SCy Schubert 166285732ac8SCy Schubert wait_time = wpa_s->max_remain_on_chan; 166385732ac8SCy Schubert if (wait_time > 2000) 166485732ac8SCy Schubert wait_time = 2000; 166585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", 166685732ac8SCy Schubert MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_REQ); 166785732ac8SCy Schubert offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, 166885732ac8SCy Schubert broadcast, 166985732ac8SCy Schubert wpabuf_head(msg), wpabuf_len(msg), 167085732ac8SCy Schubert wait_time, wpas_dpp_tx_pkex_status, 0); 167185732ac8SCy Schubert wpabuf_free(msg); 167285732ac8SCy Schubert } 167385732ac8SCy Schubert 167485732ac8SCy Schubert 167585732ac8SCy Schubert static struct dpp_bootstrap_info * 167685732ac8SCy Schubert wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer, 167785732ac8SCy Schubert unsigned int freq) 167885732ac8SCy Schubert { 167985732ac8SCy Schubert struct dpp_bootstrap_info *bi; 168085732ac8SCy Schubert 16814bc52338SCy Schubert bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq); 168285732ac8SCy Schubert if (!bi) 168385732ac8SCy Schubert return NULL; 168485732ac8SCy Schubert wpa_s->dpp_pkex = NULL; 168585732ac8SCy Schubert return bi; 168685732ac8SCy Schubert } 168785732ac8SCy Schubert 168885732ac8SCy Schubert 168985732ac8SCy Schubert static void 169085732ac8SCy Schubert wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src, 169185732ac8SCy Schubert const u8 *hdr, const u8 *buf, size_t len, 169285732ac8SCy Schubert unsigned int freq) 169385732ac8SCy Schubert { 169485732ac8SCy Schubert struct wpabuf *msg; 169585732ac8SCy Schubert unsigned int wait_time; 169685732ac8SCy Schubert struct dpp_pkex *pkex = wpa_s->dpp_pkex; 169785732ac8SCy Schubert 169885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR, 169985732ac8SCy Schubert MAC2STR(src)); 170085732ac8SCy Schubert 170185732ac8SCy Schubert if (!pkex || pkex->initiator || !pkex->exchange_done) { 170285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); 170385732ac8SCy Schubert return; 170485732ac8SCy Schubert } 170585732ac8SCy Schubert 170685732ac8SCy Schubert msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len); 170785732ac8SCy Schubert if (!msg) { 170885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to process the request"); 170985732ac8SCy Schubert if (pkex->failed) { 171085732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange"); 171185732ac8SCy Schubert if (pkex->t > pkex->own_bi->pkex_t) 171285732ac8SCy Schubert pkex->own_bi->pkex_t = pkex->t; 171385732ac8SCy Schubert dpp_pkex_free(wpa_s->dpp_pkex); 171485732ac8SCy Schubert wpa_s->dpp_pkex = NULL; 171585732ac8SCy Schubert } 171685732ac8SCy Schubert return; 171785732ac8SCy Schubert } 171885732ac8SCy Schubert 171985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to " 172085732ac8SCy Schubert MACSTR, MAC2STR(src)); 172185732ac8SCy Schubert 172285732ac8SCy Schubert wait_time = wpa_s->max_remain_on_chan; 172385732ac8SCy Schubert if (wait_time > 2000) 172485732ac8SCy Schubert wait_time = 2000; 172585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", 172685732ac8SCy Schubert MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_RESP); 172785732ac8SCy Schubert offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, 172885732ac8SCy Schubert broadcast, 172985732ac8SCy Schubert wpabuf_head(msg), wpabuf_len(msg), 173085732ac8SCy Schubert wait_time, wpas_dpp_tx_pkex_status, 0); 173185732ac8SCy Schubert wpabuf_free(msg); 173285732ac8SCy Schubert 173385732ac8SCy Schubert wpas_dpp_pkex_finish(wpa_s, src, freq); 173485732ac8SCy Schubert } 173585732ac8SCy Schubert 173685732ac8SCy Schubert 173785732ac8SCy Schubert static void 173885732ac8SCy Schubert wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant *wpa_s, const u8 *src, 173985732ac8SCy Schubert const u8 *hdr, const u8 *buf, size_t len, 174085732ac8SCy Schubert unsigned int freq) 174185732ac8SCy Schubert { 174285732ac8SCy Schubert int res; 174385732ac8SCy Schubert struct dpp_bootstrap_info *bi; 174485732ac8SCy Schubert struct dpp_pkex *pkex = wpa_s->dpp_pkex; 174585732ac8SCy Schubert char cmd[500]; 174685732ac8SCy Schubert 174785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR, 174885732ac8SCy Schubert MAC2STR(src)); 174985732ac8SCy Schubert 175085732ac8SCy Schubert if (!pkex || !pkex->initiator || !pkex->exchange_done) { 175185732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); 175285732ac8SCy Schubert return; 175385732ac8SCy Schubert } 175485732ac8SCy Schubert 175585732ac8SCy Schubert res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len); 175685732ac8SCy Schubert if (res < 0) { 175785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); 175885732ac8SCy Schubert return; 175985732ac8SCy Schubert } 176085732ac8SCy Schubert 176185732ac8SCy Schubert bi = wpas_dpp_pkex_finish(wpa_s, src, freq); 176285732ac8SCy Schubert if (!bi) 176385732ac8SCy Schubert return; 176485732ac8SCy Schubert 176585732ac8SCy Schubert os_snprintf(cmd, sizeof(cmd), " peer=%u %s", 176685732ac8SCy Schubert bi->id, 176785732ac8SCy Schubert wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : ""); 176885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 176985732ac8SCy Schubert "DPP: Start authentication after PKEX with parameters: %s", 177085732ac8SCy Schubert cmd); 177185732ac8SCy Schubert if (wpas_dpp_auth_init(wpa_s, cmd) < 0) { 177285732ac8SCy Schubert wpa_printf(MSG_DEBUG, 177385732ac8SCy Schubert "DPP: Authentication initialization failed"); 177485732ac8SCy Schubert return; 177585732ac8SCy Schubert } 177685732ac8SCy Schubert } 177785732ac8SCy Schubert 177885732ac8SCy Schubert 177985732ac8SCy Schubert void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, 178085732ac8SCy Schubert const u8 *buf, size_t len, unsigned int freq) 178185732ac8SCy Schubert { 178285732ac8SCy Schubert u8 crypto_suite; 178385732ac8SCy Schubert enum dpp_public_action_frame_type type; 178485732ac8SCy Schubert const u8 *hdr; 178585732ac8SCy Schubert unsigned int pkex_t; 178685732ac8SCy Schubert 178785732ac8SCy Schubert if (len < DPP_HDR_LEN) 178885732ac8SCy Schubert return; 178985732ac8SCy Schubert if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE) 179085732ac8SCy Schubert return; 179185732ac8SCy Schubert hdr = buf; 179285732ac8SCy Schubert buf += 4; 179385732ac8SCy Schubert len -= 4; 179485732ac8SCy Schubert crypto_suite = *buf++; 179585732ac8SCy Schubert type = *buf++; 179685732ac8SCy Schubert len -= 2; 179785732ac8SCy Schubert 179885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 179985732ac8SCy Schubert "DPP: Received DPP Public Action frame crypto suite %u type %d from " 180085732ac8SCy Schubert MACSTR " freq=%u", 180185732ac8SCy Schubert crypto_suite, type, MAC2STR(src), freq); 180285732ac8SCy Schubert if (crypto_suite != 1) { 180385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u", 180485732ac8SCy Schubert crypto_suite); 180585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR 180685732ac8SCy Schubert " freq=%u type=%d ignore=unsupported-crypto-suite", 180785732ac8SCy Schubert MAC2STR(src), freq, type); 180885732ac8SCy Schubert return; 180985732ac8SCy Schubert } 181085732ac8SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len); 181185732ac8SCy Schubert if (dpp_check_attrs(buf, len) < 0) { 181285732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR 181385732ac8SCy Schubert " freq=%u type=%d ignore=invalid-attributes", 181485732ac8SCy Schubert MAC2STR(src), freq, type); 181585732ac8SCy Schubert return; 181685732ac8SCy Schubert } 181785732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR " freq=%u type=%d", 181885732ac8SCy Schubert MAC2STR(src), freq, type); 181985732ac8SCy Schubert 182085732ac8SCy Schubert switch (type) { 182185732ac8SCy Schubert case DPP_PA_AUTHENTICATION_REQ: 182285732ac8SCy Schubert wpas_dpp_rx_auth_req(wpa_s, src, hdr, buf, len, freq); 182385732ac8SCy Schubert break; 182485732ac8SCy Schubert case DPP_PA_AUTHENTICATION_RESP: 182585732ac8SCy Schubert wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len, freq); 182685732ac8SCy Schubert break; 182785732ac8SCy Schubert case DPP_PA_AUTHENTICATION_CONF: 182885732ac8SCy Schubert wpas_dpp_rx_auth_conf(wpa_s, src, hdr, buf, len); 182985732ac8SCy Schubert break; 183085732ac8SCy Schubert case DPP_PA_PEER_DISCOVERY_RESP: 183185732ac8SCy Schubert wpas_dpp_rx_peer_disc_resp(wpa_s, src, buf, len); 183285732ac8SCy Schubert break; 183385732ac8SCy Schubert case DPP_PA_PKEX_EXCHANGE_REQ: 183485732ac8SCy Schubert wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq); 183585732ac8SCy Schubert break; 183685732ac8SCy Schubert case DPP_PA_PKEX_EXCHANGE_RESP: 183785732ac8SCy Schubert wpas_dpp_rx_pkex_exchange_resp(wpa_s, src, buf, len, freq); 183885732ac8SCy Schubert break; 183985732ac8SCy Schubert case DPP_PA_PKEX_COMMIT_REVEAL_REQ: 184085732ac8SCy Schubert wpas_dpp_rx_pkex_commit_reveal_req(wpa_s, src, hdr, buf, len, 184185732ac8SCy Schubert freq); 184285732ac8SCy Schubert break; 184385732ac8SCy Schubert case DPP_PA_PKEX_COMMIT_REVEAL_RESP: 184485732ac8SCy Schubert wpas_dpp_rx_pkex_commit_reveal_resp(wpa_s, src, hdr, buf, len, 184585732ac8SCy Schubert freq); 184685732ac8SCy Schubert break; 18474bc52338SCy Schubert #ifdef CONFIG_DPP2 18484bc52338SCy Schubert case DPP_PA_CONFIGURATION_RESULT: 18494bc52338SCy Schubert wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len); 18504bc52338SCy Schubert break; 18514bc52338SCy Schubert #endif /* CONFIG_DPP2 */ 185285732ac8SCy Schubert default: 185385732ac8SCy Schubert wpa_printf(MSG_DEBUG, 185485732ac8SCy Schubert "DPP: Ignored unsupported frame subtype %d", type); 185585732ac8SCy Schubert break; 185685732ac8SCy Schubert } 185785732ac8SCy Schubert 185885732ac8SCy Schubert if (wpa_s->dpp_pkex) 185985732ac8SCy Schubert pkex_t = wpa_s->dpp_pkex->t; 186085732ac8SCy Schubert else if (wpa_s->dpp_pkex_bi) 186185732ac8SCy Schubert pkex_t = wpa_s->dpp_pkex_bi->pkex_t; 186285732ac8SCy Schubert else 186385732ac8SCy Schubert pkex_t = 0; 186485732ac8SCy Schubert if (pkex_t >= PKEX_COUNTER_T_LIMIT) { 186585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0"); 186685732ac8SCy Schubert wpas_dpp_pkex_remove(wpa_s, "*"); 186785732ac8SCy Schubert } 186885732ac8SCy Schubert } 186985732ac8SCy Schubert 187085732ac8SCy Schubert 187185732ac8SCy Schubert static struct wpabuf * 187285732ac8SCy Schubert wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query, 187385732ac8SCy Schubert size_t query_len) 187485732ac8SCy Schubert { 187585732ac8SCy Schubert struct wpa_supplicant *wpa_s = ctx; 187685732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 187785732ac8SCy Schubert struct wpabuf *resp; 187885732ac8SCy Schubert 187985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, 188085732ac8SCy Schubert MAC2STR(sa)); 188185732ac8SCy Schubert if (!auth || !auth->auth_success || 188285732ac8SCy Schubert os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) { 188385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); 188485732ac8SCy Schubert return NULL; 188585732ac8SCy Schubert } 1886*206b73d0SCy Schubert 1887*206b73d0SCy Schubert if (wpa_s->dpp_auth_ok_on_ack && auth->configurator) { 1888*206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1889*206b73d0SCy Schubert "DPP: Have not received ACK for Auth Confirm yet - assume it was received based on this GAS request"); 1890*206b73d0SCy Schubert /* wpas_dpp_auth_success() would normally have been called from 1891*206b73d0SCy Schubert * TX status handler, but since there was no such handler call 1892*206b73d0SCy Schubert * yet, simply send out the event message and proceed with 1893*206b73d0SCy Schubert * exchange. */ 1894*206b73d0SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=1"); 1895*206b73d0SCy Schubert wpa_s->dpp_auth_ok_on_ack = 0; 1896*206b73d0SCy Schubert } 1897*206b73d0SCy Schubert 189885732ac8SCy Schubert wpa_hexdump(MSG_DEBUG, 189985732ac8SCy Schubert "DPP: Received Configuration Request (GAS Query Request)", 190085732ac8SCy Schubert query, query_len); 190185732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR, 190285732ac8SCy Schubert MAC2STR(sa)); 190385732ac8SCy Schubert resp = dpp_conf_req_rx(auth, query, query_len); 190485732ac8SCy Schubert if (!resp) 190585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); 190685732ac8SCy Schubert auth->conf_resp = resp; 190785732ac8SCy Schubert return resp; 190885732ac8SCy Schubert } 190985732ac8SCy Schubert 191085732ac8SCy Schubert 191185732ac8SCy Schubert static void 191285732ac8SCy Schubert wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok) 191385732ac8SCy Schubert { 191485732ac8SCy Schubert struct wpa_supplicant *wpa_s = ctx; 191585732ac8SCy Schubert struct dpp_authentication *auth = wpa_s->dpp_auth; 191685732ac8SCy Schubert 191785732ac8SCy Schubert if (!auth) { 191885732ac8SCy Schubert wpabuf_free(resp); 191985732ac8SCy Schubert return; 192085732ac8SCy Schubert } 192185732ac8SCy Schubert if (auth->conf_resp != resp) { 192285732ac8SCy Schubert wpa_printf(MSG_DEBUG, 192385732ac8SCy Schubert "DPP: Ignore GAS status report (ok=%d) for unknown response", 192485732ac8SCy Schubert ok); 192585732ac8SCy Schubert wpabuf_free(resp); 192685732ac8SCy Schubert return; 192785732ac8SCy Schubert } 192885732ac8SCy Schubert 192985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)", 193085732ac8SCy Schubert ok); 193185732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); 193285732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); 19334bc52338SCy Schubert #ifdef CONFIG_DPP2 19344bc52338SCy Schubert if (ok && auth->peer_version >= 2 && 19354bc52338SCy Schubert auth->conf_resp_status == DPP_STATUS_OK) { 19364bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); 19374bc52338SCy Schubert auth->waiting_conf_result = 1; 19384bc52338SCy Schubert auth->conf_resp = NULL; 19394bc52338SCy Schubert wpabuf_free(resp); 19404bc52338SCy Schubert eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, 19414bc52338SCy Schubert wpa_s, NULL); 19424bc52338SCy Schubert eloop_register_timeout(2, 0, 19434bc52338SCy Schubert wpas_dpp_config_result_wait_timeout, 19444bc52338SCy Schubert wpa_s, NULL); 19454bc52338SCy Schubert return; 19464bc52338SCy Schubert } 19474bc52338SCy Schubert #endif /* CONFIG_DPP2 */ 194885732ac8SCy Schubert offchannel_send_action_done(wpa_s); 194985732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s); 195085732ac8SCy Schubert if (ok) 195185732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT); 195285732ac8SCy Schubert else 195385732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); 195485732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth); 195585732ac8SCy Schubert wpa_s->dpp_auth = NULL; 195685732ac8SCy Schubert wpabuf_free(resp); 195785732ac8SCy Schubert } 195885732ac8SCy Schubert 195985732ac8SCy Schubert 196085732ac8SCy Schubert int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd) 196185732ac8SCy Schubert { 196285732ac8SCy Schubert struct dpp_authentication *auth; 196385732ac8SCy Schubert int ret = -1; 196485732ac8SCy Schubert char *curve = NULL; 196585732ac8SCy Schubert 196685732ac8SCy Schubert auth = os_zalloc(sizeof(*auth)); 196785732ac8SCy Schubert if (!auth) 196885732ac8SCy Schubert return -1; 196985732ac8SCy Schubert 197085732ac8SCy Schubert curve = get_param(cmd, " curve="); 197185732ac8SCy Schubert wpas_dpp_set_testing_options(wpa_s, auth); 19724bc52338SCy Schubert if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) == 0 && 19734bc52338SCy Schubert dpp_configurator_own_config(auth, curve, 0) == 0) 19744bc52338SCy Schubert ret = wpas_dpp_handle_config_obj(wpa_s, auth); 197585732ac8SCy Schubert 197685732ac8SCy Schubert dpp_auth_deinit(auth); 197785732ac8SCy Schubert os_free(curve); 197885732ac8SCy Schubert 197985732ac8SCy Schubert return ret; 198085732ac8SCy Schubert } 198185732ac8SCy Schubert 198285732ac8SCy Schubert 198385732ac8SCy Schubert static void 198485732ac8SCy Schubert wpas_dpp_tx_introduction_status(struct wpa_supplicant *wpa_s, 198585732ac8SCy Schubert unsigned int freq, const u8 *dst, 198685732ac8SCy Schubert const u8 *src, const u8 *bssid, 198785732ac8SCy Schubert const u8 *data, size_t data_len, 198885732ac8SCy Schubert enum offchannel_send_action_result result) 198985732ac8SCy Schubert { 199085732ac8SCy Schubert const char *res_txt; 199185732ac8SCy Schubert 199285732ac8SCy Schubert res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" : 199385732ac8SCy Schubert (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" : 199485732ac8SCy Schubert "FAILED"); 199585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR 199685732ac8SCy Schubert " result=%s (DPP Peer Discovery Request)", 199785732ac8SCy Schubert freq, MAC2STR(dst), res_txt); 199885732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR 199985732ac8SCy Schubert " freq=%u result=%s", MAC2STR(dst), freq, res_txt); 200085732ac8SCy Schubert /* TODO: Time out wait for response more quickly in error cases? */ 200185732ac8SCy Schubert } 200285732ac8SCy Schubert 200385732ac8SCy Schubert 200485732ac8SCy Schubert int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, 200585732ac8SCy Schubert struct wpa_bss *bss) 200685732ac8SCy Schubert { 200785732ac8SCy Schubert struct os_time now; 200885732ac8SCy Schubert struct wpabuf *msg; 200985732ac8SCy Schubert unsigned int wait_time; 20104bc52338SCy Schubert const u8 *rsn; 20114bc52338SCy Schubert struct wpa_ie_data ied; 201285732ac8SCy Schubert 201385732ac8SCy Schubert if (!(ssid->key_mgmt & WPA_KEY_MGMT_DPP) || !bss) 201485732ac8SCy Schubert return 0; /* Not using DPP AKM - continue */ 20154bc52338SCy Schubert rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); 20164bc52338SCy Schubert if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 && 20174bc52338SCy Schubert !(ied.key_mgmt & WPA_KEY_MGMT_DPP)) 20184bc52338SCy Schubert return 0; /* AP does not support DPP AKM - continue */ 201985732ac8SCy Schubert if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid)) 202085732ac8SCy Schubert return 0; /* PMKSA exists for DPP AKM - continue */ 202185732ac8SCy Schubert 202285732ac8SCy Schubert if (!ssid->dpp_connector || !ssid->dpp_netaccesskey || 202385732ac8SCy Schubert !ssid->dpp_csign) { 202485732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR 202585732ac8SCy Schubert "missing %s", 202685732ac8SCy Schubert !ssid->dpp_connector ? "Connector" : 202785732ac8SCy Schubert (!ssid->dpp_netaccesskey ? "netAccessKey" : 202885732ac8SCy Schubert "C-sign-key")); 202985732ac8SCy Schubert return -1; 203085732ac8SCy Schubert } 203185732ac8SCy Schubert 203285732ac8SCy Schubert os_get_time(&now); 203385732ac8SCy Schubert 203485732ac8SCy Schubert if (ssid->dpp_netaccesskey_expiry && 203585732ac8SCy Schubert (os_time_t) ssid->dpp_netaccesskey_expiry < now.sec) { 203685732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR 203785732ac8SCy Schubert "netAccessKey expired"); 203885732ac8SCy Schubert return -1; 203985732ac8SCy Schubert } 204085732ac8SCy Schubert 204185732ac8SCy Schubert wpa_printf(MSG_DEBUG, 204285732ac8SCy Schubert "DPP: Starting network introduction protocol to derive PMKSA for " 204385732ac8SCy Schubert MACSTR, MAC2STR(bss->bssid)); 204485732ac8SCy Schubert 204585732ac8SCy Schubert msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ, 204685732ac8SCy Schubert 5 + 4 + os_strlen(ssid->dpp_connector)); 204785732ac8SCy Schubert if (!msg) 204885732ac8SCy Schubert return -1; 204985732ac8SCy Schubert 205085732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 205185732ac8SCy Schubert if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ) { 205285732ac8SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID"); 205385732ac8SCy Schubert goto skip_trans_id; 205485732ac8SCy Schubert } 205585732ac8SCy Schubert if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ) { 205685732ac8SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID"); 205785732ac8SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); 205885732ac8SCy Schubert wpabuf_put_le16(msg, 0); 205985732ac8SCy Schubert goto skip_trans_id; 206085732ac8SCy Schubert } 206185732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 206285732ac8SCy Schubert 206385732ac8SCy Schubert /* Transaction ID */ 206485732ac8SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); 206585732ac8SCy Schubert wpabuf_put_le16(msg, 1); 206685732ac8SCy Schubert wpabuf_put_u8(msg, TRANSACTION_ID); 206785732ac8SCy Schubert 206885732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 206985732ac8SCy Schubert skip_trans_id: 207085732ac8SCy Schubert if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ) { 207185732ac8SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Connector"); 207285732ac8SCy Schubert goto skip_connector; 207385732ac8SCy Schubert } 207485732ac8SCy Schubert if (dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ) { 207585732ac8SCy Schubert char *connector; 207685732ac8SCy Schubert 207785732ac8SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector"); 207885732ac8SCy Schubert connector = dpp_corrupt_connector_signature( 207985732ac8SCy Schubert ssid->dpp_connector); 208085732ac8SCy Schubert if (!connector) { 208185732ac8SCy Schubert wpabuf_free(msg); 208285732ac8SCy Schubert return -1; 208385732ac8SCy Schubert } 208485732ac8SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); 208585732ac8SCy Schubert wpabuf_put_le16(msg, os_strlen(connector)); 208685732ac8SCy Schubert wpabuf_put_str(msg, connector); 208785732ac8SCy Schubert os_free(connector); 208885732ac8SCy Schubert goto skip_connector; 208985732ac8SCy Schubert } 209085732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 209185732ac8SCy Schubert 209285732ac8SCy Schubert /* DPP Connector */ 209385732ac8SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); 209485732ac8SCy Schubert wpabuf_put_le16(msg, os_strlen(ssid->dpp_connector)); 209585732ac8SCy Schubert wpabuf_put_str(msg, ssid->dpp_connector); 209685732ac8SCy Schubert 209785732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 209885732ac8SCy Schubert skip_connector: 209985732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 210085732ac8SCy Schubert 210185732ac8SCy Schubert /* TODO: Timeout on AP response */ 210285732ac8SCy Schubert wait_time = wpa_s->max_remain_on_chan; 210385732ac8SCy Schubert if (wait_time > 2000) 210485732ac8SCy Schubert wait_time = 2000; 210585732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", 210685732ac8SCy Schubert MAC2STR(bss->bssid), bss->freq, DPP_PA_PEER_DISCOVERY_REQ); 210785732ac8SCy Schubert offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr, 210885732ac8SCy Schubert broadcast, 210985732ac8SCy Schubert wpabuf_head(msg), wpabuf_len(msg), 211085732ac8SCy Schubert wait_time, wpas_dpp_tx_introduction_status, 0); 211185732ac8SCy Schubert wpabuf_free(msg); 211285732ac8SCy Schubert 211385732ac8SCy Schubert /* Request this connection attempt to terminate - new one will be 211485732ac8SCy Schubert * started when network introduction protocol completes */ 211585732ac8SCy Schubert os_memcpy(wpa_s->dpp_intro_bssid, bss->bssid, ETH_ALEN); 211685732ac8SCy Schubert wpa_s->dpp_intro_network = ssid; 211785732ac8SCy Schubert return 1; 211885732ac8SCy Schubert } 211985732ac8SCy Schubert 212085732ac8SCy Schubert 212185732ac8SCy Schubert int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd) 212285732ac8SCy Schubert { 212385732ac8SCy Schubert struct dpp_bootstrap_info *own_bi; 212485732ac8SCy Schubert const char *pos, *end; 212585732ac8SCy Schubert unsigned int wait_time; 212685732ac8SCy Schubert 212785732ac8SCy Schubert pos = os_strstr(cmd, " own="); 212885732ac8SCy Schubert if (!pos) 212985732ac8SCy Schubert return -1; 213085732ac8SCy Schubert pos += 5; 21314bc52338SCy Schubert own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos)); 213285732ac8SCy Schubert if (!own_bi) { 213385732ac8SCy Schubert wpa_printf(MSG_DEBUG, 213485732ac8SCy Schubert "DPP: Identified bootstrap info not found"); 213585732ac8SCy Schubert return -1; 213685732ac8SCy Schubert } 213785732ac8SCy Schubert if (own_bi->type != DPP_BOOTSTRAP_PKEX) { 213885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 213985732ac8SCy Schubert "DPP: Identified bootstrap info not for PKEX"); 214085732ac8SCy Schubert return -1; 214185732ac8SCy Schubert } 214285732ac8SCy Schubert wpa_s->dpp_pkex_bi = own_bi; 214385732ac8SCy Schubert own_bi->pkex_t = 0; /* clear pending errors on new code */ 214485732ac8SCy Schubert 214585732ac8SCy Schubert os_free(wpa_s->dpp_pkex_identifier); 214685732ac8SCy Schubert wpa_s->dpp_pkex_identifier = NULL; 214785732ac8SCy Schubert pos = os_strstr(cmd, " identifier="); 214885732ac8SCy Schubert if (pos) { 214985732ac8SCy Schubert pos += 12; 215085732ac8SCy Schubert end = os_strchr(pos, ' '); 215185732ac8SCy Schubert if (!end) 215285732ac8SCy Schubert return -1; 215385732ac8SCy Schubert wpa_s->dpp_pkex_identifier = os_malloc(end - pos + 1); 215485732ac8SCy Schubert if (!wpa_s->dpp_pkex_identifier) 215585732ac8SCy Schubert return -1; 215685732ac8SCy Schubert os_memcpy(wpa_s->dpp_pkex_identifier, pos, end - pos); 215785732ac8SCy Schubert wpa_s->dpp_pkex_identifier[end - pos] = '\0'; 215885732ac8SCy Schubert } 215985732ac8SCy Schubert 216085732ac8SCy Schubert pos = os_strstr(cmd, " code="); 216185732ac8SCy Schubert if (!pos) 216285732ac8SCy Schubert return -1; 216385732ac8SCy Schubert os_free(wpa_s->dpp_pkex_code); 216485732ac8SCy Schubert wpa_s->dpp_pkex_code = os_strdup(pos + 6); 216585732ac8SCy Schubert if (!wpa_s->dpp_pkex_code) 216685732ac8SCy Schubert return -1; 216785732ac8SCy Schubert 216885732ac8SCy Schubert if (os_strstr(cmd, " init=1")) { 216985732ac8SCy Schubert struct dpp_pkex *pkex; 217085732ac8SCy Schubert struct wpabuf *msg; 217185732ac8SCy Schubert 217285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX"); 217385732ac8SCy Schubert dpp_pkex_free(wpa_s->dpp_pkex); 217485732ac8SCy Schubert wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr, 217585732ac8SCy Schubert wpa_s->dpp_pkex_identifier, 217685732ac8SCy Schubert wpa_s->dpp_pkex_code); 217785732ac8SCy Schubert pkex = wpa_s->dpp_pkex; 217885732ac8SCy Schubert if (!pkex) 217985732ac8SCy Schubert return -1; 218085732ac8SCy Schubert 218185732ac8SCy Schubert msg = pkex->exchange_req; 218285732ac8SCy Schubert wait_time = wpa_s->max_remain_on_chan; 218385732ac8SCy Schubert if (wait_time > 2000) 218485732ac8SCy Schubert wait_time = 2000; 218585732ac8SCy Schubert pkex->freq = 2437; 218685732ac8SCy Schubert wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 218785732ac8SCy Schubert " freq=%u type=%d", 218885732ac8SCy Schubert MAC2STR(broadcast), pkex->freq, 218985732ac8SCy Schubert DPP_PA_PKEX_EXCHANGE_REQ); 219085732ac8SCy Schubert offchannel_send_action(wpa_s, pkex->freq, broadcast, 219185732ac8SCy Schubert wpa_s->own_addr, broadcast, 219285732ac8SCy Schubert wpabuf_head(msg), wpabuf_len(msg), 219385732ac8SCy Schubert wait_time, wpas_dpp_tx_pkex_status, 0); 219485732ac8SCy Schubert if (wait_time == 0) 219585732ac8SCy Schubert wait_time = 2000; 219685732ac8SCy Schubert pkex->exch_req_wait_time = wait_time; 219785732ac8SCy Schubert pkex->exch_req_tries = 1; 219885732ac8SCy Schubert } 219985732ac8SCy Schubert 220085732ac8SCy Schubert /* TODO: Support multiple PKEX info entries */ 220185732ac8SCy Schubert 220285732ac8SCy Schubert os_free(wpa_s->dpp_pkex_auth_cmd); 220385732ac8SCy Schubert wpa_s->dpp_pkex_auth_cmd = os_strdup(cmd); 220485732ac8SCy Schubert 220585732ac8SCy Schubert return 1; 220685732ac8SCy Schubert } 220785732ac8SCy Schubert 220885732ac8SCy Schubert 220985732ac8SCy Schubert int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id) 221085732ac8SCy Schubert { 221185732ac8SCy Schubert unsigned int id_val; 221285732ac8SCy Schubert 221385732ac8SCy Schubert if (os_strcmp(id, "*") == 0) { 221485732ac8SCy Schubert id_val = 0; 221585732ac8SCy Schubert } else { 221685732ac8SCy Schubert id_val = atoi(id); 221785732ac8SCy Schubert if (id_val == 0) 221885732ac8SCy Schubert return -1; 221985732ac8SCy Schubert } 222085732ac8SCy Schubert 222185732ac8SCy Schubert if ((id_val != 0 && id_val != 1) || !wpa_s->dpp_pkex_code) 222285732ac8SCy Schubert return -1; 222385732ac8SCy Schubert 222485732ac8SCy Schubert /* TODO: Support multiple PKEX entries */ 222585732ac8SCy Schubert os_free(wpa_s->dpp_pkex_code); 222685732ac8SCy Schubert wpa_s->dpp_pkex_code = NULL; 222785732ac8SCy Schubert os_free(wpa_s->dpp_pkex_identifier); 222885732ac8SCy Schubert wpa_s->dpp_pkex_identifier = NULL; 222985732ac8SCy Schubert os_free(wpa_s->dpp_pkex_auth_cmd); 223085732ac8SCy Schubert wpa_s->dpp_pkex_auth_cmd = NULL; 223185732ac8SCy Schubert wpa_s->dpp_pkex_bi = NULL; 223285732ac8SCy Schubert /* TODO: Remove dpp_pkex only if it is for the identified PKEX code */ 223385732ac8SCy Schubert dpp_pkex_free(wpa_s->dpp_pkex); 223485732ac8SCy Schubert wpa_s->dpp_pkex = NULL; 223585732ac8SCy Schubert return 0; 223685732ac8SCy Schubert } 223785732ac8SCy Schubert 223885732ac8SCy Schubert 223985732ac8SCy Schubert void wpas_dpp_stop(struct wpa_supplicant *wpa_s) 224085732ac8SCy Schubert { 224185732ac8SCy Schubert dpp_auth_deinit(wpa_s->dpp_auth); 224285732ac8SCy Schubert wpa_s->dpp_auth = NULL; 224385732ac8SCy Schubert dpp_pkex_free(wpa_s->dpp_pkex); 224485732ac8SCy Schubert wpa_s->dpp_pkex = NULL; 224585732ac8SCy Schubert if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0) 224685732ac8SCy Schubert gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token); 224785732ac8SCy Schubert } 224885732ac8SCy Schubert 224985732ac8SCy Schubert 225085732ac8SCy Schubert int wpas_dpp_init(struct wpa_supplicant *wpa_s) 225185732ac8SCy Schubert { 2252*206b73d0SCy Schubert struct dpp_global_config config; 225385732ac8SCy Schubert u8 adv_proto_id[7]; 225485732ac8SCy Schubert 225585732ac8SCy Schubert adv_proto_id[0] = WLAN_EID_VENDOR_SPECIFIC; 225685732ac8SCy Schubert adv_proto_id[1] = 5; 225785732ac8SCy Schubert WPA_PUT_BE24(&adv_proto_id[2], OUI_WFA); 225885732ac8SCy Schubert adv_proto_id[5] = DPP_OUI_TYPE; 225985732ac8SCy Schubert adv_proto_id[6] = 0x01; 226085732ac8SCy Schubert 226185732ac8SCy Schubert if (gas_server_register(wpa_s->gas_server, adv_proto_id, 226285732ac8SCy Schubert sizeof(adv_proto_id), wpas_dpp_gas_req_handler, 226385732ac8SCy Schubert wpas_dpp_gas_status_handler, wpa_s) < 0) 226485732ac8SCy Schubert return -1; 2265*206b73d0SCy Schubert 2266*206b73d0SCy Schubert os_memset(&config, 0, sizeof(config)); 2267*206b73d0SCy Schubert config.msg_ctx = wpa_s; 2268*206b73d0SCy Schubert config.cb_ctx = wpa_s; 2269*206b73d0SCy Schubert #ifdef CONFIG_DPP2 2270*206b73d0SCy Schubert config.process_conf_obj = wpas_dpp_process_conf_obj; 2271*206b73d0SCy Schubert #endif /* CONFIG_DPP2 */ 2272*206b73d0SCy Schubert wpa_s->dpp = dpp_global_init(&config); 22734bc52338SCy Schubert return wpa_s->dpp ? 0 : -1; 227485732ac8SCy Schubert } 227585732ac8SCy Schubert 227685732ac8SCy Schubert 227785732ac8SCy Schubert void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) 227885732ac8SCy Schubert { 227985732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 228085732ac8SCy Schubert os_free(wpa_s->dpp_config_obj_override); 228185732ac8SCy Schubert wpa_s->dpp_config_obj_override = NULL; 228285732ac8SCy Schubert os_free(wpa_s->dpp_discovery_override); 228385732ac8SCy Schubert wpa_s->dpp_discovery_override = NULL; 228485732ac8SCy Schubert os_free(wpa_s->dpp_groups_override); 228585732ac8SCy Schubert wpa_s->dpp_groups_override = NULL; 228685732ac8SCy Schubert wpa_s->dpp_ignore_netaccesskey_mismatch = 0; 228785732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 22884bc52338SCy Schubert if (!wpa_s->dpp) 228985732ac8SCy Schubert return; 22904bc52338SCy Schubert dpp_global_clear(wpa_s->dpp); 229185732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL); 229285732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); 229385732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); 229485732ac8SCy Schubert eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); 22954bc52338SCy Schubert #ifdef CONFIG_DPP2 22964bc52338SCy Schubert eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL); 22974bc52338SCy Schubert dpp_pfs_free(wpa_s->dpp_pfs); 22984bc52338SCy Schubert wpa_s->dpp_pfs = NULL; 22994bc52338SCy Schubert #endif /* CONFIG_DPP2 */ 230085732ac8SCy Schubert offchannel_send_action_done(wpa_s); 230185732ac8SCy Schubert wpas_dpp_listen_stop(wpa_s); 230285732ac8SCy Schubert wpas_dpp_stop(wpa_s); 230385732ac8SCy Schubert wpas_dpp_pkex_remove(wpa_s, "*"); 230485732ac8SCy Schubert os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN); 230585732ac8SCy Schubert os_free(wpa_s->dpp_configurator_params); 230685732ac8SCy Schubert wpa_s->dpp_configurator_params = NULL; 230785732ac8SCy Schubert } 2308*206b73d0SCy Schubert 2309*206b73d0SCy Schubert 2310*206b73d0SCy Schubert #ifdef CONFIG_DPP2 2311*206b73d0SCy Schubert int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd) 2312*206b73d0SCy Schubert { 2313*206b73d0SCy Schubert struct dpp_controller_config config; 2314*206b73d0SCy Schubert const char *pos; 2315*206b73d0SCy Schubert 2316*206b73d0SCy Schubert os_memset(&config, 0, sizeof(config)); 2317*206b73d0SCy Schubert if (cmd) { 2318*206b73d0SCy Schubert pos = os_strstr(cmd, " tcp_port="); 2319*206b73d0SCy Schubert if (pos) { 2320*206b73d0SCy Schubert pos += 10; 2321*206b73d0SCy Schubert config.tcp_port = atoi(pos); 2322*206b73d0SCy Schubert } 2323*206b73d0SCy Schubert } 2324*206b73d0SCy Schubert config.configurator_params = wpa_s->dpp_configurator_params; 2325*206b73d0SCy Schubert return dpp_controller_start(wpa_s->dpp, &config); 2326*206b73d0SCy Schubert } 2327*206b73d0SCy Schubert #endif /* CONFIG_DPP2 */ 2328