blob: b8c6f55e04f63a975c5a7c3e11d8fb02b6dbdb74 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * WPA Supplicant
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003 * Copyright (c) 2003-2024, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 *
8 * This file implements functions for registering and unregistering
9 * %wpa_supplicant interfaces. In addition, this file contains number of
10 * functions for managing network connections.
11 */
12
13#include "includes.h"
Dmitry Shmidte4663042016-04-04 10:07:49 -070014#ifdef CONFIG_MATCH_IFACE
15#include <net/if.h>
16#include <fnmatch.h>
17#endif /* CONFIG_MATCH_IFACE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070018
19#include "common.h"
Sunil8cd6f4d2022-06-28 18:40:46 +000020#include "crypto/crypto.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021#include "crypto/random.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080022#include "crypto/sha1.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070023#include "eapol_supp/eapol_supp_sm.h"
24#include "eap_peer/eap.h"
Dmitry Shmidt34af3062013-07-11 10:46:32 -070025#include "eap_peer/eap_proxy.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070026#include "eap_server/eap_methods.h"
27#include "rsn_supp/wpa.h"
28#include "eloop.h"
29#include "config.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070030#include "utils/ext_password.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070031#include "l2_packet/l2_packet.h"
32#include "wpa_supplicant_i.h"
33#include "driver_i.h"
34#include "ctrl_iface.h"
35#include "pcsc_funcs.h"
36#include "common/version.h"
37#include "rsn_supp/preauth.h"
38#include "rsn_supp/pmksa_cache.h"
39#include "common/wpa_ctrl.h"
Hai Shalom81f62d82019-07-22 12:10:00 -070040#include "common/ieee802_11_common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070041#include "common/ieee802_11_defs.h"
Dmitry Shmidtff787d52015-01-12 13:01:47 -080042#include "common/hw_features_common.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070043#include "common/gas_server.h"
Hai Shalom021b0b52019-04-10 11:17:58 -070044#include "common/dpp.h"
Hai Shalom60840252021-02-19 19:02:11 -080045#include "common/ptksa_cache.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070046#include "p2p/p2p.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080047#include "fst/fst.h"
Hai Shalom60840252021-02-19 19:02:11 -080048#include "bssid_ignore.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070049#include "wpas_glue.h"
50#include "wps_supplicant.h"
51#include "ibss_rsn.h"
52#include "sme.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080053#include "gas_query.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070054#include "ap.h"
55#include "p2p_supplicant.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070056#include "wifi_display.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070057#include "notify.h"
58#include "bgscan.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070059#include "autoscan.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070060#include "bss.h"
61#include "scan.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080062#include "offchannel.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070063#include "hs20_supplicant.h"
Dmitry Shmidt44c95782013-05-17 09:51:35 -070064#include "wnm_sta.h"
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -070065#include "wpas_kay.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080066#include "mesh.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070067#include "dpp_supplicant.h"
Sunil Ravib0ac25f2024-07-12 01:42:03 +000068#include "nan_usd.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070069#ifdef CONFIG_MESH
70#include "ap/ap_config.h"
71#include "ap/hostapd.h"
72#endif /* CONFIG_MESH */
Gabriel Biren3c401c52024-10-10 20:11:18 +000073#include "aidl/vendor/aidl.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070074
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070075const char *const wpa_supplicant_version =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070076"wpa_supplicant v" VERSION_STR "\n"
Sunil Ravi7f769292024-07-23 22:21:32 +000077"Copyright (c) 2003-2024, Jouni Malinen <j@w1.fi> and contributors";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070078
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070079const char *const wpa_supplicant_license =
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080080"This software may be distributed under the terms of the BSD license.\n"
81"See README for more details.\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070082#ifdef EAP_TLS_OPENSSL
83"\nThis product includes software developed by the OpenSSL Project\n"
84"for use in the OpenSSL Toolkit (http://www.openssl.org/)\n"
85#endif /* EAP_TLS_OPENSSL */
86;
87
88#ifndef CONFIG_NO_STDOUT_DEBUG
89/* Long text divided into parts in order to fit in C89 strings size limits. */
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070090const char *const wpa_supplicant_full_license1 =
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080091"";
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070092const char *const wpa_supplicant_full_license2 =
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080093"This software may be distributed under the terms of the BSD license.\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070094"\n"
95"Redistribution and use in source and binary forms, with or without\n"
96"modification, are permitted provided that the following conditions are\n"
97"met:\n"
98"\n";
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070099const char *const wpa_supplicant_full_license3 =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700100"1. Redistributions of source code must retain the above copyright\n"
101" notice, this list of conditions and the following disclaimer.\n"
102"\n"
103"2. Redistributions in binary form must reproduce the above copyright\n"
104" notice, this list of conditions and the following disclaimer in the\n"
105" documentation and/or other materials provided with the distribution.\n"
106"\n";
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700107const char *const wpa_supplicant_full_license4 =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700108"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
109" names of its contributors may be used to endorse or promote products\n"
110" derived from this software without specific prior written permission.\n"
111"\n"
112"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
113"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
114"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
115"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n";
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700116const char *const wpa_supplicant_full_license5 =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700117"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
118"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
119"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
120"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
121"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
122"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
123"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
124"\n";
125#endif /* CONFIG_NO_STDOUT_DEBUG */
126
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700127
128static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx);
Sunil Ravi7f769292024-07-23 22:21:32 +0000129static void wpas_verify_ssid_beacon(void *eloop_ctx, void *timeout_ctx);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700130#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
131static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s);
132#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
Hai Shalomc3565922019-10-28 11:58:20 -0700133#ifdef CONFIG_OWE
134static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s);
135#endif /* CONFIG_OWE */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700136
137
Hai Shalomfdcde762020-04-02 11:19:20 -0700138#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700139/* Configure default/group WEP keys for static WEP */
140int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
141{
142 int i, set = 0;
143
144 for (i = 0; i < NUM_WEP_KEYS; i++) {
145 if (ssid->wep_key_len[i] == 0)
146 continue;
147
148 set = 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000149 wpa_drv_set_key(wpa_s, -1, WPA_ALG_WEP, NULL,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700150 i, i == ssid->wep_tx_keyidx, NULL, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -0700151 ssid->wep_key[i], ssid->wep_key_len[i],
152 i == ssid->wep_tx_keyidx ?
153 KEY_FLAG_GROUP_RX_TX_DEFAULT :
154 KEY_FLAG_GROUP_RX_TX);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700155 }
156
157 return set;
158}
Hai Shalomfdcde762020-04-02 11:19:20 -0700159#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700160
161
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700162int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
163 struct wpa_ssid *ssid)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700164{
165 u8 key[32];
166 size_t keylen;
167 enum wpa_alg alg;
168 u8 seq[6] = { 0 };
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800169 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700170
171 /* IBSS/WPA-None uses only one key (Group) for both receiving and
172 * sending unicast and multicast packets. */
173
174 if (ssid->mode != WPAS_MODE_IBSS) {
175 wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid mode %d (not "
176 "IBSS/ad-hoc) for WPA-None", ssid->mode);
177 return -1;
178 }
179
180 if (!ssid->psk_set) {
181 wpa_msg(wpa_s, MSG_INFO, "WPA: No PSK configured for "
182 "WPA-None");
183 return -1;
184 }
185
186 switch (wpa_s->group_cipher) {
187 case WPA_CIPHER_CCMP:
188 os_memcpy(key, ssid->psk, 16);
189 keylen = 16;
190 alg = WPA_ALG_CCMP;
191 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700192 case WPA_CIPHER_GCMP:
193 os_memcpy(key, ssid->psk, 16);
194 keylen = 16;
195 alg = WPA_ALG_GCMP;
196 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700197 case WPA_CIPHER_TKIP:
198 /* WPA-None uses the same Michael MIC key for both TX and RX */
199 os_memcpy(key, ssid->psk, 16 + 8);
200 os_memcpy(key + 16 + 8, ssid->psk + 16, 8);
201 keylen = 32;
202 alg = WPA_ALG_TKIP;
203 break;
204 default:
205 wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid group cipher %d for "
206 "WPA-None", wpa_s->group_cipher);
207 return -1;
208 }
209
210 /* TODO: should actually remember the previously used seq#, both for TX
211 * and RX from each STA.. */
212
Sunil Ravi77d572f2023-01-17 23:58:31 +0000213 ret = wpa_drv_set_key(wpa_s, -1, alg, NULL, 0, 1, seq, 6, key, keylen,
Hai Shalomfdcde762020-04-02 11:19:20 -0700214 KEY_FLAG_GROUP_RX_TX_DEFAULT);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800215 os_memset(key, 0, sizeof(key));
216 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700217}
218
219
220static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
221{
222 struct wpa_supplicant *wpa_s = eloop_ctx;
223 const u8 *bssid = wpa_s->bssid;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -0700224 if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
225 (wpa_s->wpa_state == WPA_AUTHENTICATING ||
226 wpa_s->wpa_state == WPA_ASSOCIATING))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700227 bssid = wpa_s->pending_bssid;
228 wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
229 MAC2STR(bssid));
Hai Shalom60840252021-02-19 19:02:11 -0800230 wpa_bssid_ignore_add(wpa_s, bssid);
Roshan Pius92cbe442020-10-08 16:15:13 -0700231 wpas_notify_auth_timeout(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700232 wpa_sm_notify_disassoc(wpa_s->wpa);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800233 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700234 wpa_s->reassociate = 1;
235
236 /*
237 * If we timed out, the AP or the local radio may be busy.
238 * So, wait a second until scanning again.
239 */
240 wpa_supplicant_req_scan(wpa_s, 1, 0);
241}
242
243
244/**
245 * wpa_supplicant_req_auth_timeout - Schedule a timeout for authentication
246 * @wpa_s: Pointer to wpa_supplicant data
247 * @sec: Number of seconds after which to time out authentication
248 * @usec: Number of microseconds after which to time out authentication
249 *
250 * This function is used to schedule a timeout for the current authentication
251 * attempt.
252 */
253void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
254 int sec, int usec)
255{
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700256 if (wpa_s->conf->ap_scan == 0 &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700257 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
258 return;
259
260 wpa_dbg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
261 "%d usec", sec, usec);
262 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700263 wpa_s->last_auth_timeout_sec = sec;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700264 eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL);
265}
266
267
Roshan Pius3a1667e2018-07-03 15:17:14 -0700268/*
269 * wpas_auth_timeout_restart - Restart and change timeout for authentication
270 * @wpa_s: Pointer to wpa_supplicant data
271 * @sec_diff: difference in seconds applied to original timeout value
272 */
273void wpas_auth_timeout_restart(struct wpa_supplicant *wpa_s, int sec_diff)
274{
275 int new_sec = wpa_s->last_auth_timeout_sec + sec_diff;
276
277 if (eloop_is_timeout_registered(wpa_supplicant_timeout, wpa_s, NULL)) {
278 wpa_dbg(wpa_s, MSG_DEBUG,
279 "Authentication timeout restart: %d sec", new_sec);
280 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
281 eloop_register_timeout(new_sec, 0, wpa_supplicant_timeout,
282 wpa_s, NULL);
283 }
284}
285
286
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700287/**
288 * wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout
289 * @wpa_s: Pointer to wpa_supplicant data
290 *
291 * This function is used to cancel authentication timeout scheduled with
292 * wpa_supplicant_req_auth_timeout() and it is called when authentication has
293 * been completed.
294 */
295void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
296{
297 wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
298 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
Hai Shalom60840252021-02-19 19:02:11 -0800299 wpa_bssid_ignore_del(wpa_s, wpa_s->bssid);
Hai Shalomce48b4a2018-09-05 11:41:35 -0700300 os_free(wpa_s->last_con_fail_realm);
301 wpa_s->last_con_fail_realm = NULL;
302 wpa_s->last_con_fail_realm_len = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700303}
304
305
306/**
307 * wpa_supplicant_initiate_eapol - Configure EAPOL state machine
308 * @wpa_s: Pointer to wpa_supplicant data
309 *
310 * This function is used to configure EAPOL state machine based on the selected
311 * authentication mode.
312 */
313void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
314{
315#ifdef IEEE8021X_EAPOL
316 struct eapol_config eapol_conf;
317 struct wpa_ssid *ssid = wpa_s->current_ssid;
318
319#ifdef CONFIG_IBSS_RSN
320 if (ssid->mode == WPAS_MODE_IBSS &&
321 wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
322 wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
323 /*
324 * RSN IBSS authentication is per-STA and we can disable the
325 * per-BSSID EAPOL authentication.
326 */
327 eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
Hai Shalome21d4e82020-04-29 16:34:06 -0700328 eapol_sm_notify_eap_success(wpa_s->eapol, true);
329 eapol_sm_notify_eap_fail(wpa_s->eapol, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700330 return;
331 }
332#endif /* CONFIG_IBSS_RSN */
333
Hai Shalome21d4e82020-04-29 16:34:06 -0700334 eapol_sm_notify_eap_success(wpa_s->eapol, false);
335 eapol_sm_notify_eap_fail(wpa_s->eapol, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700336
337 if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
338 wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
339 eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
340 else
341 eapol_sm_notify_portControl(wpa_s->eapol, Auto);
342
343 os_memset(&eapol_conf, 0, sizeof(eapol_conf));
344 if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
345 eapol_conf.accept_802_1x_keys = 1;
346 eapol_conf.required_keys = 0;
347 if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_UNICAST) {
348 eapol_conf.required_keys |= EAPOL_REQUIRE_KEY_UNICAST;
349 }
350 if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_BROADCAST) {
351 eapol_conf.required_keys |=
352 EAPOL_REQUIRE_KEY_BROADCAST;
353 }
354
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700355 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700356 eapol_conf.required_keys = 0;
357 }
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700358 eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700359 eapol_conf.workaround = ssid->eap_workaround;
360 eapol_conf.eap_disabled =
361 !wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
362 wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
363 wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700364 eapol_conf.external_sim = wpa_s->conf->external_sim;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800365
366#ifdef CONFIG_WPS
367 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
368 eapol_conf.wps |= EAPOL_LOCAL_WPS_IN_USE;
369 if (wpa_s->current_bss) {
370 struct wpabuf *ie;
371 ie = wpa_bss_get_vendor_ie_multi(wpa_s->current_bss,
372 WPS_IE_VENDOR_TYPE);
373 if (ie) {
374 if (wps_is_20(ie))
375 eapol_conf.wps |=
376 EAPOL_PEER_IS_WPS20_AP;
377 wpabuf_free(ie);
378 }
379 }
380 }
381#endif /* CONFIG_WPS */
382
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700383 eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -0700384
Dmitry Shmidtabb90a32016-12-05 15:34:39 -0800385#ifdef CONFIG_MACSEC
386 if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set)
387 ieee802_1x_create_preshared_mka(wpa_s, ssid);
388 else
389 ieee802_1x_alloc_kay_sm(wpa_s, ssid);
390#endif /* CONFIG_MACSEC */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800391#endif /* IEEE8021X_EAPOL */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700392}
393
394
395/**
396 * wpa_supplicant_set_non_wpa_policy - Set WPA parameters to non-WPA mode
397 * @wpa_s: Pointer to wpa_supplicant data
398 * @ssid: Configuration data for the network
399 *
400 * This function is used to configure WPA state machine and related parameters
401 * to a mode where WPA is not enabled. This is called as part of the
402 * authentication configuration when the selected network does not use WPA.
403 */
404void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
405 struct wpa_ssid *ssid)
406{
Hai Shalomfdcde762020-04-02 11:19:20 -0700407#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700408 int i;
Hai Shalomfdcde762020-04-02 11:19:20 -0700409#endif /* CONFIG_WEP */
Sunil Ravi77d572f2023-01-17 23:58:31 +0000410 struct wpa_sm_mlo mlo;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700411
412 if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
413 wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
414 else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
415 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
416 else
417 wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
418 wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
419 wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
Hai Shalomc3565922019-10-28 11:58:20 -0700420 wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
Sunil Ravic0f5d412024-09-11 22:12:49 +0000421 wpa_sm_set_ap_rsne_override(wpa_s->wpa, NULL, 0);
422 wpa_sm_set_ap_rsne_override_2(wpa_s->wpa, NULL, 0);
423 wpa_sm_set_ap_rsnxe_override(wpa_s->wpa, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700424 wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
Matthew Wang9ed1c792024-12-02 14:05:18 +0000425#ifndef CONFIG_NO_WPA
Hai Shalomc3565922019-10-28 11:58:20 -0700426 wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
Matthew Wang9ed1c792024-12-02 14:05:18 +0000427#endif /* CONFIG_NO_WPA */
Hai Shalomc3565922019-10-28 11:58:20 -0700428 wpa_s->rsnxe_len = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700429 wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
430 wpa_s->group_cipher = WPA_CIPHER_NONE;
431 wpa_s->mgmt_group_cipher = 0;
432
Hai Shalomfdcde762020-04-02 11:19:20 -0700433#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700434 for (i = 0; i < NUM_WEP_KEYS; i++) {
435 if (ssid->wep_key_len[i] > 5) {
436 wpa_s->pairwise_cipher = WPA_CIPHER_WEP104;
437 wpa_s->group_cipher = WPA_CIPHER_WEP104;
438 break;
439 } else if (ssid->wep_key_len[i] > 0) {
440 wpa_s->pairwise_cipher = WPA_CIPHER_WEP40;
441 wpa_s->group_cipher = WPA_CIPHER_WEP40;
442 break;
443 }
444 }
Hai Shalomfdcde762020-04-02 11:19:20 -0700445#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700446
447 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0);
448 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
449 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
450 wpa_s->pairwise_cipher);
451 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700452 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
453 wpa_s->mgmt_group_cipher);
Sunil Ravi7f769292024-07-23 22:21:32 +0000454 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700455
456 pmksa_cache_clear_current(wpa_s->wpa);
Sunil Ravi77d572f2023-01-17 23:58:31 +0000457 os_memset(&mlo, 0, sizeof(mlo));
458 wpa_sm_set_mlo_params(wpa_s->wpa, &mlo);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700459}
460
461
Dmitry Shmidt04949592012-07-19 12:16:46 -0700462void free_hw_features(struct wpa_supplicant *wpa_s)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800463{
464 int i;
465 if (wpa_s->hw.modes == NULL)
466 return;
467
468 for (i = 0; i < wpa_s->hw.num_modes; i++) {
469 os_free(wpa_s->hw.modes[i].channels);
470 os_free(wpa_s->hw.modes[i].rates);
471 }
472
473 os_free(wpa_s->hw.modes);
474 wpa_s->hw.modes = NULL;
475}
476
477
Hai Shalomc1a21442022-02-04 13:43:00 -0800478static void remove_bss_tmp_disallowed_entry(struct wpa_supplicant *wpa_s,
479 struct wpa_bss_tmp_disallowed *bss)
480{
481 eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
482 dl_list_del(&bss->list);
483 os_free(bss);
484}
485
486
Hai Shalom74f70d42019-02-11 14:42:39 -0800487void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800488{
489 struct wpa_bss_tmp_disallowed *bss, *prev;
490
491 dl_list_for_each_safe(bss, prev, &wpa_s->bss_tmp_disallowed,
Hai Shalomc1a21442022-02-04 13:43:00 -0800492 struct wpa_bss_tmp_disallowed, list)
493 remove_bss_tmp_disallowed_entry(wpa_s, bss);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800494}
495
496
Paul Stewart092955c2017-02-06 09:13:09 -0800497void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
498{
499 struct fils_hlp_req *req;
500
501 while ((req = dl_list_first(&wpa_s->fils_hlp_req, struct fils_hlp_req,
502 list)) != NULL) {
503 dl_list_del(&req->list);
504 wpabuf_free(req->pkt);
505 os_free(req);
506 }
507}
508
509
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000510static struct wpabuf * wpas_wfa_gen_capab_attr(struct wpa_supplicant *wpa_s)
511{
512 struct wpabuf *attr;
513 size_t gen_len, supp_len;
514 const u8 *supp;
515 u8 supp_buf[1];
516 bool add_cert;
517
518 if (wpa_s->conf->wfa_gen_capa == WFA_GEN_CAPA_DISABLED)
519 return NULL;
520
521 if (!wpa_s->conf->wfa_gen_capa_supp ||
522 wpabuf_len(wpa_s->conf->wfa_gen_capa_supp) == 0) {
523 supp_len = 1;
524 supp_buf[0] = 0;
525 if (wpa_s->hw_capab & BIT(CAPAB_HT))
526 supp_buf[0] |= BIT(0); /* Wi-Fi 4 */
527 if (wpa_s->hw_capab & BIT(CAPAB_VHT))
528 supp_buf[0] |= BIT(1); /* Wi-Fi 5 */
529 if (wpa_s->hw_capab & BIT(CAPAB_HE))
530 supp_buf[0] |= BIT(2); /* Wi-Fi 6 */
531 if (wpa_s->hw_capab & BIT(CAPAB_EHT))
532 supp_buf[0] |= BIT(3); /* Wi-Fi 7 */
533 supp = supp_buf;
534 } else {
535 supp_len = wpabuf_len(wpa_s->conf->wfa_gen_capa_supp);
536 supp = wpabuf_head(wpa_s->conf->wfa_gen_capa_supp);
537 }
538
539 add_cert = wpa_s->conf->wfa_gen_capa_cert &&
540 wpabuf_len(wpa_s->conf->wfa_gen_capa_cert) == supp_len;
541
542 gen_len = 1 + supp_len;
543 if (add_cert) {
544 gen_len++;
545 gen_len += wpabuf_len(wpa_s->conf->wfa_gen_capa_cert);
546 }
547
548 attr = wpabuf_alloc(2 + gen_len);
549 if (!attr)
550 return NULL;
551
552 wpabuf_put_u8(attr, WFA_CAPA_ATTR_GENERATIONAL_CAPAB);
553 wpabuf_put_u8(attr, gen_len);
554 wpabuf_put_u8(attr, supp_len);
555 wpabuf_put_data(attr, supp, supp_len);
556 if (add_cert) {
557 wpabuf_put_u8(attr,
558 wpabuf_len(wpa_s->conf->wfa_gen_capa_cert));
559 wpabuf_put_buf(attr, wpa_s->conf->wfa_gen_capa_cert);
560 }
561
562 return attr;
563}
564
565
566
567static void wpas_wfa_capab_tx(void *eloop_ctx, void *timeout_ctx)
568{
569 struct wpa_supplicant *wpa_s = eloop_ctx;
570 struct wpabuf *attr, *buf;
571 size_t buf_len;
572
573 if (wpa_s->conf->wfa_gen_capa != WFA_GEN_CAPA_PROTECTED ||
574 wpa_s->wpa_state != WPA_COMPLETED ||
575 !pmf_in_use(wpa_s, wpa_s->bssid))
576 return;
577
578 attr = wpas_wfa_gen_capab_attr(wpa_s);
579 if (!attr)
580 return;
581
582 buf_len = 1 + 3 + 1 + 1 + wpabuf_len(attr);
583 buf = wpabuf_alloc(buf_len);
584 if (!buf) {
585 wpabuf_free(attr);
586 return;
587 }
588
589 wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED);
590 wpabuf_put_be32(buf, WFA_CAPAB_VENDOR_TYPE);
591 wpabuf_put_u8(buf, 0); /* Capabilities Length */
592 wpabuf_put_buf(buf, attr);
593 wpabuf_free(attr);
594
595 wpa_printf(MSG_DEBUG, "WFA: Send WFA Capabilities frame");
596 if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
597 wpa_s->own_addr, wpa_s->bssid,
598 wpabuf_head(buf), wpabuf_len(buf), 0) < 0)
599 wpa_printf(MSG_DEBUG,
600 "WFA: Failed to send WFA Capabilities frame");
601
602 wpabuf_free(buf);
603}
604
605
Hai Shalomfdcde762020-04-02 11:19:20 -0700606void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx)
607{
608 struct wpa_supplicant *wpa_s = eloop_ctx;
609
610 if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
611 return;
612 wpa_dbg(wpa_s, MSG_DEBUG, "Clear cached state on disabled interface");
613 wpa_bss_flush(wpa_s);
614}
615
616
617#ifdef CONFIG_TESTING_OPTIONS
618void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s)
619{
620 struct driver_signal_override *dso;
621
622 while ((dso = dl_list_first(&wpa_s->drv_signal_override,
623 struct driver_signal_override, list))) {
624 dl_list_del(&dso->list);
625 os_free(dso);
626 }
627}
628#endif /* CONFIG_TESTING_OPTIONS */
629
630
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700631static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
632{
Dmitry Shmidt2e67f062014-07-16 09:55:28 -0700633 int i;
634
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700635 bgscan_deinit(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700636 autoscan_deinit(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700637 scard_deinit(wpa_s->scard);
638 wpa_s->scard = NULL;
639 wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
640 eapol_sm_register_scard_ctx(wpa_s->eapol, NULL);
641 l2_packet_deinit(wpa_s->l2);
642 wpa_s->l2 = NULL;
643 if (wpa_s->l2_br) {
644 l2_packet_deinit(wpa_s->l2_br);
645 wpa_s->l2_br = NULL;
646 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800647#ifdef CONFIG_TESTING_OPTIONS
648 l2_packet_deinit(wpa_s->l2_test);
649 wpa_s->l2_test = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800650 os_free(wpa_s->get_pref_freq_list_override);
651 wpa_s->get_pref_freq_list_override = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700652 wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
653 wpa_s->last_assoc_req_wpa_ie = NULL;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800654 os_free(wpa_s->extra_sae_rejected_groups);
655 wpa_s->extra_sae_rejected_groups = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -0700656 wpabuf_free(wpa_s->rsne_override_eapol);
657 wpa_s->rsne_override_eapol = NULL;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800658 wpabuf_free(wpa_s->rsnxe_override_assoc);
659 wpa_s->rsnxe_override_assoc = NULL;
660 wpabuf_free(wpa_s->rsnxe_override_eapol);
661 wpa_s->rsnxe_override_eapol = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -0700662 wpas_clear_driver_signal_override(wpa_s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800663#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700664
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700665 if (wpa_s->conf != NULL) {
666 struct wpa_ssid *ssid;
667 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
668 wpas_notify_network_removed(wpa_s, ssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700669 }
670
671 os_free(wpa_s->confname);
672 wpa_s->confname = NULL;
673
Jouni Malinen5d1c8ad2013-04-23 12:34:56 -0700674 os_free(wpa_s->confanother);
675 wpa_s->confanother = NULL;
676
Hai Shalomce48b4a2018-09-05 11:41:35 -0700677 os_free(wpa_s->last_con_fail_realm);
678 wpa_s->last_con_fail_realm = NULL;
679 wpa_s->last_con_fail_realm_len = 0;
680
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700681 wpa_sm_set_eapol(wpa_s->wpa, NULL);
682 eapol_sm_deinit(wpa_s->eapol);
683 wpa_s->eapol = NULL;
684
685 rsn_preauth_deinit(wpa_s->wpa);
686
687#ifdef CONFIG_TDLS
688 wpa_tdls_deinit(wpa_s->wpa);
689#endif /* CONFIG_TDLS */
690
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000691#ifndef CONFIG_NO_WMM_AC
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800692 wmm_ac_clear_saved_tspecs(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000693#endif /* CONFIG_NO_WMM_AC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700694 pmksa_candidate_free(wpa_s->wpa);
Hai Shalom60840252021-02-19 19:02:11 -0800695 ptksa_cache_deinit(wpa_s->ptksa);
696 wpa_s->ptksa = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700697 wpa_sm_deinit(wpa_s->wpa);
698 wpa_s->wpa = NULL;
Hai Shalom60840252021-02-19 19:02:11 -0800699 wpa_bssid_ignore_clear(wpa_s);
700
701#ifdef CONFIG_PASN
702 wpas_pasn_auth_stop(wpa_s);
703#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700704
705 wpa_bss_deinit(wpa_s);
706
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -0700707 wpa_supplicant_cancel_delayed_sched_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700708 wpa_supplicant_cancel_scan(wpa_s);
709 wpa_supplicant_cancel_auth_timeout(wpa_s);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800710 eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
711#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
712 eloop_cancel_timeout(wpa_supplicant_delayed_mic_error_report,
713 wpa_s, NULL);
714#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700715
Dmitry Shmidtdda10c22015-03-24 16:05:01 -0700716 eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -0700717 eloop_cancel_timeout(wpas_clear_disabled_interface, wpa_s, NULL);
Sunil Ravi7f769292024-07-23 22:21:32 +0000718 eloop_cancel_timeout(wpas_verify_ssid_beacon, wpa_s, NULL);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000719 eloop_cancel_timeout(wpas_wfa_capab_tx, wpa_s, NULL);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -0700720
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700721 wpas_wps_deinit(wpa_s);
722
723 wpabuf_free(wpa_s->pending_eapol_rx);
724 wpa_s->pending_eapol_rx = NULL;
725
726#ifdef CONFIG_IBSS_RSN
727 ibss_rsn_deinit(wpa_s->ibss_rsn);
728 wpa_s->ibss_rsn = NULL;
729#endif /* CONFIG_IBSS_RSN */
730
731 sme_deinit(wpa_s);
732
733#ifdef CONFIG_AP
734 wpa_supplicant_ap_deinit(wpa_s);
735#endif /* CONFIG_AP */
736
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700737 wpas_p2p_deinit(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700738
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800739#ifdef CONFIG_OFFCHANNEL
740 offchannel_deinit(wpa_s);
741#endif /* CONFIG_OFFCHANNEL */
742
743 wpa_supplicant_cancel_sched_scan(wpa_s);
744
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700745 os_free(wpa_s->next_scan_freqs);
746 wpa_s->next_scan_freqs = NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800747
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800748 os_free(wpa_s->manual_scan_freqs);
749 wpa_s->manual_scan_freqs = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700750 os_free(wpa_s->select_network_scan_freqs);
751 wpa_s->select_network_scan_freqs = NULL;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800752
Dmitry Shmidtd11f0192014-03-24 12:09:47 -0700753 os_free(wpa_s->manual_sched_scan_freqs);
754 wpa_s->manual_sched_scan_freqs = NULL;
755
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800756 wpas_mac_addr_rand_scan_clear(wpa_s, MAC_ADDR_RAND_ALL);
757
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -0700758 /*
759 * Need to remove any pending gas-query radio work before the
760 * gas_query_deinit() call because gas_query::work has not yet been set
761 * for works that have not been started. gas_query_free() will be unable
762 * to cancel such pending radio works and once the pending gas-query
763 * radio work eventually gets removed, the deinit notification call to
764 * gas_query_start_cb() would result in dereferencing freed memory.
765 */
766 if (wpa_s->radio)
767 radio_remove_works(wpa_s, "gas-query", 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800768 gas_query_deinit(wpa_s->gas);
769 wpa_s->gas = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700770 gas_server_deinit(wpa_s->gas_server);
771 wpa_s->gas_server = NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800772
773 free_hw_features(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700774
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -0700775 ieee802_1x_dealloc_kay_sm(wpa_s);
776
Dmitry Shmidt04949592012-07-19 12:16:46 -0700777 os_free(wpa_s->bssid_filter);
778 wpa_s->bssid_filter = NULL;
779
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800780 os_free(wpa_s->disallow_aps_bssid);
781 wpa_s->disallow_aps_bssid = NULL;
782 os_free(wpa_s->disallow_aps_ssid);
783 wpa_s->disallow_aps_ssid = NULL;
784
Dmitry Shmidt04949592012-07-19 12:16:46 -0700785 wnm_bss_keep_alive_deinit(wpa_s);
Sunil Ravi99c035e2024-07-12 01:42:03 +0000786 wnm_btm_reset(wpa_s);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700787
788 ext_password_deinit(wpa_s->ext_pw);
789 wpa_s->ext_pw = NULL;
790
791 wpabuf_free(wpa_s->last_gas_resp);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800792 wpa_s->last_gas_resp = NULL;
793 wpabuf_free(wpa_s->prev_gas_resp);
794 wpa_s->prev_gas_resp = NULL;
Dmitry Shmidt9bce59c2012-09-11 15:06:38 -0700795
796 os_free(wpa_s->last_scan_res);
797 wpa_s->last_scan_res = NULL;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800798
799#ifdef CONFIG_HS20
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700800 if (wpa_s->drv_priv)
801 wpa_drv_configure_frame_filters(wpa_s, 0);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800802#endif /* CONFIG_HS20 */
Dmitry Shmidt2e67f062014-07-16 09:55:28 -0700803
804 for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
805 wpabuf_free(wpa_s->vendor_elem[i]);
806 wpa_s->vendor_elem[i] = NULL;
807 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800808
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000809#ifndef CONFIG_NO_WMM_AC
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800810 wmm_ac_notify_disassoc(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000811#endif /* CONFIG_NO_WMM_AC */
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800812
813 wpa_s->sched_scan_plans_num = 0;
814 os_free(wpa_s->sched_scan_plans);
815 wpa_s->sched_scan_plans = NULL;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800816
817#ifdef CONFIG_MBO
818 wpa_s->non_pref_chan_num = 0;
819 os_free(wpa_s->non_pref_chan);
820 wpa_s->non_pref_chan = NULL;
821#endif /* CONFIG_MBO */
822
823 free_bss_tmp_disallowed(wpa_s);
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700824
825 wpabuf_free(wpa_s->lci);
826 wpa_s->lci = NULL;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000827#ifndef CONFIG_NO_RRM
Dmitry Shmidt29333592017-01-09 12:27:11 -0800828 wpas_clear_beacon_rep_data(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000829#endif /* CONFIG_NO_RRM */
Paul Stewart092955c2017-02-06 09:13:09 -0800830
831#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
832#ifdef CONFIG_MESH
833 {
834 struct external_pmksa_cache *entry;
835
836 while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
837 struct external_pmksa_cache,
838 list)) != NULL) {
839 dl_list_del(&entry->list);
840 os_free(entry->pmksa_cache);
841 os_free(entry);
842 }
843 }
844#endif /* CONFIG_MESH */
845#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
846
847 wpas_flush_fils_hlp_req(wpa_s);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800848
849 wpabuf_free(wpa_s->ric_ies);
850 wpa_s->ric_ies = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700851
852#ifdef CONFIG_DPP
853 wpas_dpp_deinit(wpa_s);
Hai Shalom021b0b52019-04-10 11:17:58 -0700854 dpp_global_deinit(wpa_s->dpp);
855 wpa_s->dpp = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700856#endif /* CONFIG_DPP */
Hai Shalom60840252021-02-19 19:02:11 -0800857
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000858#ifdef CONFIG_NAN_USD
859 wpas_nan_usd_deinit(wpa_s);
860#endif /* CONFIG_NAN_USD */
861
Hai Shalom60840252021-02-19 19:02:11 -0800862#ifdef CONFIG_PASN
863 wpas_pasn_auth_stop(wpa_s);
864#endif /* CONFIG_PASN */
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000865#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -0800866 wpas_scs_deinit(wpa_s);
867 wpas_dscp_deinit(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000868#endif /* CONFIG_NO_ROBUST_AV */
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000869
870#ifdef CONFIG_OWE
871 os_free(wpa_s->owe_trans_scan_freq);
872 wpa_s->owe_trans_scan_freq = NULL;
873#endif /* CONFIG_OWE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700874}
875
876
877/**
878 * wpa_clear_keys - Clear keys configured for the driver
879 * @wpa_s: Pointer to wpa_supplicant data
880 * @addr: Previously used BSSID or %NULL if not available
881 *
882 * This function clears the encryption keys that has been previously configured
883 * for the driver.
884 */
885void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
886{
Hai Shalomc3565922019-10-28 11:58:20 -0700887 int i, max = 6;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700888
889 /* MLME-DELETEKEYS.request */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800890 for (i = 0; i < max; i++) {
891 if (wpa_s->keys_cleared & BIT(i))
892 continue;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000893 wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -0700894 NULL, 0, KEY_FLAG_GROUP);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800895 }
Hai Shalomfdcde762020-04-02 11:19:20 -0700896 /* Pairwise Key ID 1 for Extended Key ID is tracked in bit 15 */
897 if (~wpa_s->keys_cleared & (BIT(0) | BIT(15)) && addr &&
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800898 !is_zero_ether_addr(addr)) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700899 if (!(wpa_s->keys_cleared & BIT(0)))
Sunil Ravi77d572f2023-01-17 23:58:31 +0000900 wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, addr, 0, 0,
901 NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
Hai Shalomfdcde762020-04-02 11:19:20 -0700902 if (!(wpa_s->keys_cleared & BIT(15)))
Sunil Ravi77d572f2023-01-17 23:58:31 +0000903 wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, addr, 1, 0,
904 NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700905 /* MLME-SETPROTECTION.request(None) */
906 wpa_drv_mlme_setprotection(
907 wpa_s, addr,
908 MLME_SETPROTECTION_PROTECT_TYPE_NONE,
909 MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
910 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800911 wpa_s->keys_cleared = (u32) -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700912}
913
914
915/**
916 * wpa_supplicant_state_txt - Get the connection state name as a text string
917 * @state: State (wpa_state; WPA_*)
918 * Returns: The state name as a printable text string
919 */
920const char * wpa_supplicant_state_txt(enum wpa_states state)
921{
922 switch (state) {
923 case WPA_DISCONNECTED:
924 return "DISCONNECTED";
925 case WPA_INACTIVE:
926 return "INACTIVE";
927 case WPA_INTERFACE_DISABLED:
928 return "INTERFACE_DISABLED";
929 case WPA_SCANNING:
930 return "SCANNING";
931 case WPA_AUTHENTICATING:
932 return "AUTHENTICATING";
933 case WPA_ASSOCIATING:
934 return "ASSOCIATING";
935 case WPA_ASSOCIATED:
936 return "ASSOCIATED";
937 case WPA_4WAY_HANDSHAKE:
938 return "4WAY_HANDSHAKE";
939 case WPA_GROUP_HANDSHAKE:
940 return "GROUP_HANDSHAKE";
941 case WPA_COMPLETED:
942 return "COMPLETED";
943 default:
944 return "UNKNOWN";
945 }
946}
947
948
949#ifdef CONFIG_BGSCAN
950
Hai Shalom899fcc72020-10-19 14:38:18 -0700951static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
952{
953 if (wpa_s->bgscan_ssid) {
954 bgscan_deinit(wpa_s);
955 wpa_s->bgscan_ssid = NULL;
956 }
957}
958
959
960/**
961 * wpa_supplicant_reset_bgscan - Reset the bgscan for the current SSID.
962 * @wpa_s: Pointer to the wpa_supplicant data
963 *
964 * Stop, start, or reconfigure the scan parameters depending on the method.
965 */
966void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700967{
Dmitry Shmidtb96dad42013-11-05 10:07:29 -0800968 const char *name;
969
970 if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan)
971 name = wpa_s->current_ssid->bgscan;
972 else
973 name = wpa_s->conf->bgscan;
Hai Shalom899fcc72020-10-19 14:38:18 -0700974 if (!name || name[0] == '\0') {
975 wpa_supplicant_stop_bgscan(wpa_s);
Dmitry Shmidtb96dad42013-11-05 10:07:29 -0800976 return;
Hai Shalom899fcc72020-10-19 14:38:18 -0700977 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800978 if (wpas_driver_bss_selection(wpa_s))
979 return;
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800980#ifdef CONFIG_P2P
981 if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
982 return;
983#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700984
985 bgscan_deinit(wpa_s);
Dmitry Shmidtb96dad42013-11-05 10:07:29 -0800986 if (wpa_s->current_ssid) {
987 if (bgscan_init(wpa_s, wpa_s->current_ssid, name)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700988 wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
989 "bgscan");
990 /*
991 * Live without bgscan; it is only used as a roaming
992 * optimization, so the initial connection is not
993 * affected.
994 */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700995 } else {
996 struct wpa_scan_results *scan_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700997 wpa_s->bgscan_ssid = wpa_s->current_ssid;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700998 scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL,
Sunil Ravi99c035e2024-07-12 01:42:03 +0000999 0, NULL);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001000 if (scan_res) {
1001 bgscan_notify_scan(wpa_s, scan_res);
1002 wpa_scan_results_free(scan_res);
1003 }
1004 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001005 } else
1006 wpa_s->bgscan_ssid = NULL;
1007}
1008
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001009#endif /* CONFIG_BGSCAN */
1010
1011
Dmitry Shmidt04949592012-07-19 12:16:46 -07001012static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
1013{
1014 if (autoscan_init(wpa_s, 0))
1015 wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan");
1016}
1017
1018
1019static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)
1020{
1021 autoscan_deinit(wpa_s);
1022}
1023
1024
1025void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s)
1026{
1027 if (wpa_s->wpa_state == WPA_DISCONNECTED ||
1028 wpa_s->wpa_state == WPA_SCANNING) {
1029 autoscan_deinit(wpa_s);
1030 wpa_supplicant_start_autoscan(wpa_s);
1031 }
1032}
1033
1034
Sunil Ravi7f769292024-07-23 22:21:32 +00001035static void wpas_verify_ssid_beacon(void *eloop_ctx, void *timeout_ctx)
1036{
1037 struct wpa_supplicant *wpa_s = eloop_ctx;
1038 struct wpa_bss *bss;
1039 const u8 *ssid;
1040 size_t ssid_len;
1041
1042 if (!wpa_s->current_ssid || !wpa_s->current_bss)
1043 return;
1044
1045 ssid = wpa_s->current_bss->ssid;
1046 ssid_len = wpa_s->current_bss->ssid_len;
1047
1048 if (wpa_s->current_ssid->ssid_len &&
1049 (wpa_s->current_ssid->ssid_len != ssid_len ||
1050 os_memcmp(wpa_s->current_ssid->ssid, ssid, ssid_len) != 0))
1051 return;
1052
1053 if (wpa_s->wpa_state < WPA_4WAY_HANDSHAKE ||
1054 !wpa_s->bigtk_set || wpa_s->ssid_verified)
1055 return;
1056
1057 wpa_printf(MSG_DEBUG,
1058 "SSID not yet verified; check if the driver has received a verified Beacon frame");
1059 if (wpa_supplicant_update_scan_results(wpa_s, wpa_s->bssid) < 0)
1060 return;
1061
Sunil Ravi876a49b2025-02-03 19:18:32 +00001062 /* wpa->current_bss might have changed due to memory reallocation, so
1063 * need to update ssid/ssid_len */
1064 if (!wpa_s->current_bss)
1065 return;
1066 ssid = wpa_s->current_bss->ssid;
1067 ssid_len = wpa_s->current_bss->ssid_len;
1068
Sunil Ravi7f769292024-07-23 22:21:32 +00001069 bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->bssid);
1070 if (!bss)
1071 return;
1072 wpa_printf(MSG_DEBUG, "The current beacon time stamp: 0x%llx",
1073 (long long unsigned int) bss->tsf);
1074 if (bss->tsf > wpa_s->first_beacon_tsf) {
1075 const u8 *ie;
1076
1077 wpa_printf(MSG_DEBUG,
1078 "Verified Beacon frame has been received");
1079 wpa_s->beacons_checked++;
1080
1081 ie = wpa_bss_get_ie_beacon(bss, WLAN_EID_SSID);
1082 if (ie && ie[1] == ssid_len &&
1083 os_memcmp(&ie[2], ssid, ssid_len) == 0) {
1084 wpa_printf(MSG_DEBUG,
1085 "SSID verified based on a Beacon frame and beacon protection");
1086 wpa_s->ssid_verified = true;
1087 return;
1088 }
1089
1090 /* TODO: Multiple BSSID element */
1091 }
1092
1093 if (wpa_s->beacons_checked < 16) {
1094 eloop_register_timeout(wpa_s->next_beacon_check, 0,
1095 wpas_verify_ssid_beacon, wpa_s, NULL);
1096 wpa_s->next_beacon_check++;
1097 }
1098}
1099
1100
1101static void wpas_verify_ssid_beacon_prot(struct wpa_supplicant *wpa_s)
1102{
1103 struct wpa_bss *bss;
1104
1105 wpa_printf(MSG_DEBUG,
1106 "SSID not yet verified; try to verify using beacon protection");
1107 /* Fetch the current scan result which is likely based on not yet
1108 * verified payload since the current BIGTK was just received. Any
1109 * newer update in the future with a larger timestamp value is an
1110 * indication that a verified Beacon frame has been received. */
1111 if (wpa_supplicant_update_scan_results(wpa_s, wpa_s->bssid) < 0)
1112 return;
1113
1114 bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->bssid);
1115 if (!bss)
1116 return;
1117 wpa_printf(MSG_DEBUG, "The initial beacon time stamp: 0x%llx",
1118 (long long unsigned int) bss->tsf);
1119 wpa_s->first_beacon_tsf = bss->tsf;
1120 wpa_s->beacons_checked = 0;
1121 wpa_s->next_beacon_check = 1;
1122 eloop_cancel_timeout(wpas_verify_ssid_beacon, wpa_s, NULL);
1123 eloop_register_timeout(1, 0, wpas_verify_ssid_beacon, wpa_s, NULL);
1124}
1125
1126
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001127/**
1128 * wpa_supplicant_set_state - Set current connection state
1129 * @wpa_s: Pointer to wpa_supplicant data
1130 * @state: The new connection state
1131 *
1132 * This function is called whenever the connection state changes, e.g.,
1133 * association is completed for WPA/WPA2 4-Way Handshake is started.
1134 */
1135void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
1136 enum wpa_states state)
1137{
1138 enum wpa_states old_state = wpa_s->wpa_state;
Hai Shalomc3565922019-10-28 11:58:20 -07001139#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
Hai Shalome21d4e82020-04-29 16:34:06 -07001140 bool update_fils_connect_params = false;
Hai Shalomc3565922019-10-28 11:58:20 -07001141#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001142
1143 wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
1144 wpa_supplicant_state_txt(wpa_s->wpa_state),
1145 wpa_supplicant_state_txt(state));
1146
Hai Shalom74f70d42019-02-11 14:42:39 -08001147 if (state == WPA_COMPLETED &&
1148 os_reltime_initialized(&wpa_s->roam_start)) {
1149 os_reltime_age(&wpa_s->roam_start, &wpa_s->roam_time);
1150 wpa_s->roam_start.sec = 0;
1151 wpa_s->roam_start.usec = 0;
1152 wpas_notify_auth_changed(wpa_s);
1153 wpas_notify_roam_time(wpa_s);
1154 wpas_notify_roam_complete(wpa_s);
1155 } else if (state == WPA_DISCONNECTED &&
1156 os_reltime_initialized(&wpa_s->roam_start)) {
1157 wpa_s->roam_start.sec = 0;
1158 wpa_s->roam_start.usec = 0;
1159 wpa_s->roam_time.sec = 0;
1160 wpa_s->roam_time.usec = 0;
1161 wpas_notify_roam_complete(wpa_s);
1162 }
1163
Dmitry Shmidt9e3f8ee2014-01-17 10:52:01 -08001164 if (state == WPA_INTERFACE_DISABLED) {
1165 /* Assure normal scan when interface is restored */
1166 wpa_s->normal_scans = 0;
1167 }
1168
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07001169 if (state == WPA_COMPLETED) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001170 wpas_connect_work_done(wpa_s);
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07001171 /* Reinitialize normal_scan counter */
1172 wpa_s->normal_scans = 0;
1173 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001174
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07001175#ifdef CONFIG_P2P
1176 /*
1177 * P2PS client has to reply to Probe Request frames received on the
1178 * group operating channel. Enable Probe Request frame reporting for
1179 * P2P connected client in case p2p_cli_probe configuration property is
1180 * set to 1.
1181 */
1182 if (wpa_s->conf->p2p_cli_probe && wpa_s->current_ssid &&
1183 wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
1184 wpa_s->current_ssid->p2p_group) {
1185 if (state == WPA_COMPLETED && !wpa_s->p2p_cli_probe) {
1186 wpa_dbg(wpa_s, MSG_DEBUG,
1187 "P2P: Enable CLI Probe Request RX reporting");
1188 wpa_s->p2p_cli_probe =
1189 wpa_drv_probe_req_report(wpa_s, 1) >= 0;
1190 } else if (state != WPA_COMPLETED && wpa_s->p2p_cli_probe) {
1191 wpa_dbg(wpa_s, MSG_DEBUG,
1192 "P2P: Disable CLI Probe Request RX reporting");
1193 wpa_s->p2p_cli_probe = 0;
1194 wpa_drv_probe_req_report(wpa_s, 0);
1195 }
1196 }
1197#endif /* CONFIG_P2P */
1198
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001199 if (state != WPA_SCANNING)
1200 wpa_supplicant_notify_scanning(wpa_s, 0);
1201
1202 if (state == WPA_COMPLETED && wpa_s->new_connection) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001203 struct wpa_ssid *ssid = wpa_s->current_ssid;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001204 int fils_hlp_sent = 0;
Sunil Ravi89eba102022-09-13 21:04:37 -07001205 char mld_addr[50];
1206
1207 mld_addr[0] = '\0';
1208 if (wpa_s->valid_links)
1209 os_snprintf(mld_addr, sizeof(mld_addr),
1210 " ap_mld_addr=" MACSTR,
1211 MAC2STR(wpa_s->ap_mld_addr));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001212
1213#ifdef CONFIG_SME
1214 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
1215 wpa_auth_alg_fils(wpa_s->sme.auth_alg))
1216 fils_hlp_sent = 1;
1217#endif /* CONFIG_SME */
1218 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
1219 wpa_auth_alg_fils(wpa_s->auth_alg))
1220 fils_hlp_sent = 1;
1221
Dmitry Shmidt700a1372013-03-15 14:14:44 -07001222#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001223 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
Sunil Ravi89eba102022-09-13 21:04:37 -07001224 MACSTR " completed [id=%d id_str=%s%s]%s",
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001225 MAC2STR(wpa_s->bssid),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001226 ssid ? ssid->id : -1,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001227 ssid && ssid->id_str ? ssid->id_str : "",
Sunil Ravi89eba102022-09-13 21:04:37 -07001228 fils_hlp_sent ? " FILS_HLP_SENT" : "", mld_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001229#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001230 wpas_clear_temp_disabled(wpa_s, ssid, 1);
Hai Shalom899fcc72020-10-19 14:38:18 -07001231 wpa_s->consecutive_conn_failures = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001232 wpa_s->new_connection = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001233 wpa_drv_set_operstate(wpa_s, 1);
1234#ifndef IEEE8021X_EAPOL
1235 wpa_drv_set_supp_port(wpa_s, 1);
1236#endif /* IEEE8021X_EAPOL */
1237 wpa_s->after_wps = 0;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001238 wpa_s->known_wps_freq = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001239 wpas_p2p_completed(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001240
1241 sme_sched_obss_scan(wpa_s, 1);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001242
1243#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
1244 if (!fils_hlp_sent && ssid && ssid->eap.erp)
Hai Shalome21d4e82020-04-29 16:34:06 -07001245 update_fils_connect_params = true;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001246#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
Hai Shalomc3565922019-10-28 11:58:20 -07001247#ifdef CONFIG_OWE
1248 if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE))
1249 wpas_update_owe_connect_params(wpa_s);
1250#endif /* CONFIG_OWE */
Hai Shalom2cbbcd12021-03-08 18:33:38 -08001251#ifdef CONFIG_HS20
1252 hs20_configure_frame_filters(wpa_s);
1253#endif
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001254 if (wpa_s->conf->wfa_gen_capa == WFA_GEN_CAPA_PROTECTED &&
1255 pmf_in_use(wpa_s, wpa_s->bssid)) {
1256 eloop_cancel_timeout(wpas_wfa_capab_tx, wpa_s, NULL);
1257 eloop_register_timeout(0, 100000, wpas_wfa_capab_tx,
1258 wpa_s, NULL);
1259 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001260 } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
1261 state == WPA_ASSOCIATED) {
1262 wpa_s->new_connection = 1;
1263 wpa_drv_set_operstate(wpa_s, 0);
1264#ifndef IEEE8021X_EAPOL
1265 wpa_drv_set_supp_port(wpa_s, 0);
1266#endif /* IEEE8021X_EAPOL */
Dmitry Shmidt04949592012-07-19 12:16:46 -07001267 sme_sched_obss_scan(wpa_s, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001268 }
1269 wpa_s->wpa_state = state;
1270
1271#ifdef CONFIG_BGSCAN
Hai Shalom899fcc72020-10-19 14:38:18 -07001272 if (state == WPA_COMPLETED && wpa_s->current_ssid != wpa_s->bgscan_ssid)
1273 wpa_supplicant_reset_bgscan(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001274 else if (state < WPA_ASSOCIATED)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001275 wpa_supplicant_stop_bgscan(wpa_s);
1276#endif /* CONFIG_BGSCAN */
1277
Hai Shalom5f92bc92019-04-18 11:54:11 -07001278 if (state > WPA_SCANNING)
Dmitry Shmidt04949592012-07-19 12:16:46 -07001279 wpa_supplicant_stop_autoscan(wpa_s);
1280
1281 if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
1282 wpa_supplicant_start_autoscan(wpa_s);
1283
Sunil Ravi99c035e2024-07-12 01:42:03 +00001284 if (state == WPA_COMPLETED || state == WPA_INTERFACE_DISABLED ||
1285 state == WPA_INACTIVE)
1286 wnm_btm_reset(wpa_s);
1287
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001288#ifndef CONFIG_NO_WMM_AC
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001289 if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED)
1290 wmm_ac_notify_disassoc(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001291#endif /* CONFIG_NO_WMM_AC */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001292
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001293 if (wpa_s->wpa_state != old_state) {
1294 wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
1295
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07001296 /*
1297 * Notify the P2P Device interface about a state change in one
1298 * of the interfaces.
1299 */
1300 wpas_p2p_indicate_state_change(wpa_s);
1301
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001302 if (wpa_s->wpa_state == WPA_COMPLETED ||
1303 old_state == WPA_COMPLETED)
1304 wpas_notify_auth_changed(wpa_s);
Hai Shalomc3565922019-10-28 11:58:20 -07001305#ifdef CONFIG_DPP2
1306 if (wpa_s->wpa_state == WPA_COMPLETED)
1307 wpas_dpp_connected(wpa_s);
1308#endif /* CONFIG_DPP2 */
Sunil Ravi7f769292024-07-23 22:21:32 +00001309
1310 if (wpa_s->wpa_state == WPA_COMPLETED &&
1311 wpa_s->bigtk_set && !wpa_s->ssid_verified)
1312 wpas_verify_ssid_beacon_prot(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001313 }
Hai Shalomc3565922019-10-28 11:58:20 -07001314#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
1315 if (update_fils_connect_params)
1316 wpas_update_fils_connect_params(wpa_s);
1317#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001318}
1319
1320
1321void wpa_supplicant_terminate_proc(struct wpa_global *global)
1322{
1323 int pending = 0;
1324#ifdef CONFIG_WPS
1325 struct wpa_supplicant *wpa_s = global->ifaces;
1326 while (wpa_s) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001327 struct wpa_supplicant *next = wpa_s->next;
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07001328 if (wpas_wps_terminate_pending(wpa_s) == 1)
1329 pending = 1;
Dmitry Shmidt56052862013-10-04 10:23:25 -07001330#ifdef CONFIG_P2P
1331 if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE ||
1332 (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group))
1333 wpas_p2p_disconnect(wpa_s);
1334#endif /* CONFIG_P2P */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001335 wpa_s = next;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001336 }
1337#endif /* CONFIG_WPS */
1338 if (pending)
1339 return;
1340 eloop_terminate();
1341}
1342
1343
1344static void wpa_supplicant_terminate(int sig, void *signal_ctx)
1345{
1346 struct wpa_global *global = signal_ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001347 wpa_supplicant_terminate_proc(global);
1348}
1349
1350
1351void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
1352{
1353 enum wpa_states old_state = wpa_s->wpa_state;
Hai Shalom60840252021-02-19 19:02:11 -08001354 enum wpa_states new_state;
1355
1356 if (old_state == WPA_SCANNING)
1357 new_state = WPA_SCANNING;
1358 else
1359 new_state = WPA_DISCONNECTED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001360
1361 wpa_s->pairwise_cipher = 0;
1362 wpa_s->group_cipher = 0;
1363 wpa_s->mgmt_group_cipher = 0;
1364 wpa_s->key_mgmt = 0;
Sunil Ravi89eba102022-09-13 21:04:37 -07001365 wpa_s->allowed_key_mgmts = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001366 if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
Hai Shalom60840252021-02-19 19:02:11 -08001367 wpa_supplicant_set_state(wpa_s, new_state);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001368
1369 if (wpa_s->wpa_state != old_state)
1370 wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
1371}
1372
1373
1374/**
1375 * wpa_supplicant_reload_configuration - Reload configuration data
1376 * @wpa_s: Pointer to wpa_supplicant data
1377 * Returns: 0 on success or -1 if configuration parsing failed
1378 *
1379 * This function can be used to request that the configuration data is reloaded
1380 * (e.g., after configuration file change). This function is reloading
1381 * configuration only for one interface, so this may need to be called multiple
1382 * times if %wpa_supplicant is controlling multiple interfaces and all
1383 * interfaces need reconfiguration.
1384 */
1385int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
1386{
1387 struct wpa_config *conf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001388 int reconf_ctrl;
1389 int old_ap_scan;
1390
1391 if (wpa_s->confname == NULL)
1392 return -1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001393 conf = wpa_config_read(wpa_s->confname, NULL, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001394 if (conf == NULL) {
1395 wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
1396 "file '%s' - exiting", wpa_s->confname);
1397 return -1;
1398 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001399 if (wpa_s->confanother &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00001400 !wpa_config_read(wpa_s->confanother, conf, true)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001401 wpa_msg(wpa_s, MSG_ERROR,
1402 "Failed to parse the configuration file '%s' - exiting",
1403 wpa_s->confanother);
1404 return -1;
1405 }
Dmitry Shmidt64f47c52013-04-16 10:41:54 -07001406
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001407 conf->changed_parameters = (unsigned int) -1;
1408
1409 reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
1410 || (conf->ctrl_interface && wpa_s->conf->ctrl_interface &&
1411 os_strcmp(conf->ctrl_interface,
1412 wpa_s->conf->ctrl_interface) != 0);
1413
Jouni Malinenf3f8d3c2021-02-05 00:28:17 +02001414 if (reconf_ctrl) {
1415 wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001416 wpa_s->ctrl_iface = NULL;
1417 }
1418
1419 eapol_sm_invalidate_cached_session(wpa_s->eapol);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001420 if (wpa_s->current_ssid) {
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07001421 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
1422 wpa_s->own_disconnect_req = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001423 wpa_supplicant_deauthenticate(wpa_s,
1424 WLAN_REASON_DEAUTH_LEAVING);
1425 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001426
1427 /*
1428 * TODO: should notify EAPOL SM about changes in opensc_engine_path,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001429 * pkcs11_engine_path, pkcs11_module_path, openssl_ciphers.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001430 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001431 if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
1432 wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
1433 wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001434 /*
1435 * Clear forced success to clear EAP state for next
1436 * authentication.
1437 */
Hai Shalome21d4e82020-04-29 16:34:06 -07001438 eapol_sm_notify_eap_success(wpa_s->eapol, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001439 }
1440 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
1441 wpa_sm_set_config(wpa_s->wpa, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001442 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001443 wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
1444 rsn_preauth_deinit(wpa_s->wpa);
1445
1446 old_ap_scan = wpa_s->conf->ap_scan;
1447 wpa_config_free(wpa_s->conf);
1448 wpa_s->conf = conf;
1449 if (old_ap_scan != wpa_s->conf->ap_scan)
1450 wpas_notify_ap_scan_changed(wpa_s);
1451
1452 if (reconf_ctrl)
1453 wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
1454
1455 wpa_supplicant_update_config(wpa_s);
1456
1457 wpa_supplicant_clear_status(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001458 if (wpa_supplicant_enabled_networks(wpa_s)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001459 wpa_s->reassociate = 1;
1460 wpa_supplicant_req_scan(wpa_s, 0, 0);
1461 }
Hai Shalom60840252021-02-19 19:02:11 -08001462 wpa_bssid_ignore_clear(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001463 wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
1464 return 0;
1465}
1466
1467
1468static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
1469{
1470 struct wpa_global *global = signal_ctx;
1471 struct wpa_supplicant *wpa_s;
1472 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
1473 wpa_dbg(wpa_s, MSG_DEBUG, "Signal %d received - reconfiguring",
1474 sig);
1475 if (wpa_supplicant_reload_configuration(wpa_s) < 0) {
1476 wpa_supplicant_terminate_proc(global);
1477 }
1478 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001479
1480 if (wpa_debug_reopen_file() < 0) {
1481 /* Ignore errors since we cannot really do much to fix this */
1482 wpa_printf(MSG_DEBUG, "Could not reopen debug log file");
1483 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001484}
1485
1486
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001487static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
1488 struct wpa_ssid *ssid,
1489 struct wpa_ie_data *ie)
1490{
1491 int ret = wpa_sm_parse_own_wpa_ie(wpa_s->wpa, ie);
1492 if (ret) {
1493 if (ret == -2) {
1494 wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE "
1495 "from association info");
1496 }
1497 return -1;
1498 }
1499
1500 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set "
1501 "cipher suites");
1502 if (!(ie->group_cipher & ssid->group_cipher)) {
1503 wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group "
1504 "cipher 0x%x (mask 0x%x) - reject",
1505 ie->group_cipher, ssid->group_cipher);
1506 return -1;
1507 }
1508 if (!(ie->pairwise_cipher & ssid->pairwise_cipher)) {
1509 wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled pairwise "
1510 "cipher 0x%x (mask 0x%x) - reject",
1511 ie->pairwise_cipher, ssid->pairwise_cipher);
1512 return -1;
1513 }
1514 if (!(ie->key_mgmt & ssid->key_mgmt)) {
1515 wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled key "
1516 "management 0x%x (mask 0x%x) - reject",
1517 ie->key_mgmt, ssid->key_mgmt);
1518 return -1;
1519 }
1520
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001521 if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001522 wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001523 wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
1524 "that does not support management frame protection - "
1525 "reject");
1526 return -1;
1527 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001528
1529 return 0;
1530}
1531
1532
Hai Shalom021b0b52019-04-10 11:17:58 -07001533static int matching_ciphers(struct wpa_ssid *ssid, struct wpa_ie_data *ie,
1534 int freq)
1535{
1536 if (!ie->has_group)
1537 ie->group_cipher = wpa_default_rsn_cipher(freq);
1538 if (!ie->has_pairwise)
1539 ie->pairwise_cipher = wpa_default_rsn_cipher(freq);
1540 return (ie->group_cipher & ssid->group_cipher) &&
1541 (ie->pairwise_cipher & ssid->pairwise_cipher);
1542}
1543
1544
Hai Shalomc1a21442022-02-04 13:43:00 -08001545void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s,
1546 struct wpa_ssid *ssid, struct wpa_ie_data *ie)
1547{
1548 int sel;
1549
1550 sel = ie->mgmt_group_cipher;
1551 if (ssid->group_mgmt_cipher)
1552 sel &= ssid->group_mgmt_cipher;
1553 if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
1554 !(ie->capabilities & WPA_CAPABILITY_MFPC))
1555 sel = 0;
1556 wpa_dbg(wpa_s, MSG_DEBUG,
1557 "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x",
1558 ie->mgmt_group_cipher, ssid->group_mgmt_cipher, sel);
1559 if (sel & WPA_CIPHER_AES_128_CMAC) {
1560 wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
1561 wpa_dbg(wpa_s, MSG_DEBUG,
1562 "WPA: using MGMT group cipher AES-128-CMAC");
1563 } else if (sel & WPA_CIPHER_BIP_GMAC_128) {
1564 wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128;
1565 wpa_dbg(wpa_s, MSG_DEBUG,
1566 "WPA: using MGMT group cipher BIP-GMAC-128");
1567 } else if (sel & WPA_CIPHER_BIP_GMAC_256) {
1568 wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256;
1569 wpa_dbg(wpa_s, MSG_DEBUG,
1570 "WPA: using MGMT group cipher BIP-GMAC-256");
1571 } else if (sel & WPA_CIPHER_BIP_CMAC_256) {
1572 wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256;
1573 wpa_dbg(wpa_s, MSG_DEBUG,
1574 "WPA: using MGMT group cipher BIP-CMAC-256");
1575 } else {
1576 wpa_s->mgmt_group_cipher = 0;
1577 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
1578 }
1579 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
1580 wpa_s->mgmt_group_cipher);
1581 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
1582 wpas_get_ssid_pmf(wpa_s, ssid));
1583}
1584
Sunil Ravi77d572f2023-01-17 23:58:31 +00001585/**
1586 * wpa_supplicant_get_psk - Get PSK from config or external database
1587 * @wpa_s: Pointer to wpa_supplicant data
1588 * @bss: Scan results for the selected BSS, or %NULL if not available
1589 * @ssid: Configuration data for the selected network
1590 * @psk: Buffer for the PSK
1591 * Returns: 0 on success or -1 if configuration parsing failed
1592 *
1593 * This function obtains the PSK for a network, either included inline in the
1594 * config or retrieved from an external database.
1595 */
1596static int wpa_supplicant_get_psk(struct wpa_supplicant *wpa_s,
1597 struct wpa_bss *bss, struct wpa_ssid *ssid,
1598 u8 *psk)
1599{
1600 if (ssid->psk_set) {
1601 wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)",
1602 ssid->psk, PMK_LEN);
1603 os_memcpy(psk, ssid->psk, PMK_LEN);
1604 return 0;
1605 }
1606
1607#ifndef CONFIG_NO_PBKDF2
1608 if (bss && ssid->bssid_set && ssid->ssid_len == 0 && ssid->passphrase) {
1609 if (pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
1610 4096, psk, PMK_LEN) != 0) {
1611 wpa_msg(wpa_s, MSG_WARNING, "Error in pbkdf2_sha1()");
1612 return -1;
1613 }
1614 wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
1615 psk, PMK_LEN);
1616 return 0;
1617 }
1618#endif /* CONFIG_NO_PBKDF2 */
1619
1620#ifdef CONFIG_EXT_PASSWORD
1621 if (ssid->ext_psk) {
1622 struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
1623 ssid->ext_psk);
1624 char pw_str[64 + 1];
1625
1626 if (!pw) {
1627 wpa_msg(wpa_s, MSG_INFO,
1628 "EXT PW: No PSK found from external storage");
1629 return -1;
1630 }
1631
1632 if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
1633 wpa_msg(wpa_s, MSG_INFO,
1634 "EXT PW: Unexpected PSK length %d in external storage",
1635 (int) wpabuf_len(pw));
1636 ext_password_free(pw);
1637 return -1;
1638 }
1639
1640 os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
1641 pw_str[wpabuf_len(pw)] = '\0';
1642
1643#ifndef CONFIG_NO_PBKDF2
1644 if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
1645 {
1646 if (pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
1647 4096, psk, PMK_LEN) != 0) {
1648 wpa_msg(wpa_s, MSG_WARNING,
1649 "Error in pbkdf2_sha1()");
1650 forced_memzero(pw_str, sizeof(pw_str));
1651 ext_password_free(pw);
1652 return -1;
1653 }
1654 wpa_hexdump_key(MSG_MSGDUMP,
1655 "PSK (from external passphrase)",
1656 psk, PMK_LEN);
1657 } else
1658#endif /* CONFIG_NO_PBKDF2 */
1659 if (wpabuf_len(pw) == 2 * PMK_LEN) {
1660 if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
1661 wpa_msg(wpa_s, MSG_INFO,
1662 "EXT PW: Invalid PSK hex string");
1663 forced_memzero(pw_str, sizeof(pw_str));
1664 ext_password_free(pw);
1665 return -1;
1666 }
1667 wpa_hexdump_key(MSG_MSGDUMP, "PSK (from external PSK)",
1668 psk, PMK_LEN);
1669 } else {
1670 wpa_msg(wpa_s, MSG_INFO,
1671 "EXT PW: No suitable PSK available");
1672 forced_memzero(pw_str, sizeof(pw_str));
1673 ext_password_free(pw);
1674 return -1;
1675 }
1676
1677 forced_memzero(pw_str, sizeof(pw_str));
1678 ext_password_free(pw);
1679
1680 return 0;
1681 }
1682#endif /* CONFIG_EXT_PASSWORD */
1683
1684 return -1;
1685}
1686
Hai Shalomc1a21442022-02-04 13:43:00 -08001687
Sunil Ravi89eba102022-09-13 21:04:37 -07001688static void wpas_update_allowed_key_mgmt(struct wpa_supplicant *wpa_s,
1689 struct wpa_ssid *ssid)
1690{
1691 int akm_count = wpa_s->max_num_akms;
1692 u8 capab = 0;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001693#ifdef CONFIG_SAE
1694 enum sae_pwe sae_pwe;
1695#endif /* CONFIG_SAE */
Sunil Ravi89eba102022-09-13 21:04:37 -07001696
1697 if (akm_count < 2)
1698 return;
1699
1700 akm_count--;
1701 wpa_s->allowed_key_mgmts = 0;
1702 switch (wpa_s->key_mgmt) {
1703 case WPA_KEY_MGMT_PSK:
1704 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
1705 akm_count--;
1706 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
1707 }
1708 if (!akm_count)
1709 break;
1710 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
1711 akm_count--;
1712 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
1713 }
1714 if (!akm_count)
1715 break;
1716 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
1717 wpa_s->allowed_key_mgmts |=
1718 WPA_KEY_MGMT_PSK_SHA256;
1719 break;
1720 case WPA_KEY_MGMT_PSK_SHA256:
1721 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
1722 akm_count--;
1723 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
1724 }
1725 if (!akm_count)
1726 break;
1727 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
1728 akm_count--;
1729 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
1730 }
1731 if (!akm_count)
1732 break;
1733 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
1734 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
1735 break;
1736 case WPA_KEY_MGMT_SAE:
1737 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
1738 akm_count--;
1739 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
1740 }
1741 if (!akm_count)
1742 break;
1743 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
1744 akm_count--;
1745 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
1746 }
1747 if (!akm_count)
1748 break;
1749 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
1750 wpa_s->allowed_key_mgmts |=
1751 WPA_KEY_MGMT_PSK_SHA256;
1752 break;
1753 case WPA_KEY_MGMT_SAE_EXT_KEY:
1754 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
1755 akm_count--;
1756 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
1757 }
1758 if (!akm_count)
1759 break;
1760 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
1761 akm_count--;
1762 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
1763 }
1764 if (!akm_count)
1765 break;
1766 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
1767 wpa_s->allowed_key_mgmts |=
1768 WPA_KEY_MGMT_PSK_SHA256;
1769 break;
1770 default:
1771 return;
1772 }
1773
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001774#ifdef CONFIG_SAE
1775 sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
1776 if (sae_pwe != SAE_PWE_HUNT_AND_PECK &&
1777 sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
Sunil Ravi89eba102022-09-13 21:04:37 -07001778 capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
1779#ifdef CONFIG_SAE_PK
1780 if (ssid->sae_pk)
1781 capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
1782#endif /* CONFIG_SAE_PK */
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001783#endif /* CONFIG_SAE */
Sunil Ravi89eba102022-09-13 21:04:37 -07001784
1785 if (!((wpa_s->allowed_key_mgmts &
1786 (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY)) && capab))
1787 return;
1788
1789 if (!wpa_s->rsnxe_len) {
1790 wpa_s->rsnxe_len = 3;
1791 wpa_s->rsnxe[0] = WLAN_EID_RSNX;
1792 wpa_s->rsnxe[1] = 1;
1793 wpa_s->rsnxe[2] = 0;
1794 }
1795
1796 wpa_s->rsnxe[2] |= capab;
1797}
1798
1799
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001800/**
1801 * wpa_supplicant_set_suites - Set authentication and encryption parameters
1802 * @wpa_s: Pointer to wpa_supplicant data
1803 * @bss: Scan results for the selected BSS, or %NULL if not available
1804 * @ssid: Configuration data for the selected network
1805 * @wpa_ie: Buffer for the WPA/RSN IE
1806 * @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the
1807 * used buffer length in case the functions returns success.
Sunil Ravi77d572f2023-01-17 23:58:31 +00001808 * @skip_default_rsne: Whether to skip setting of the default RSNE/RSNXE
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001809 * Returns: 0 on success or -1 on failure
1810 *
1811 * This function is used to configure authentication and encryption parameters
1812 * based on the network configuration and scan result for the selected BSS (if
1813 * available).
1814 */
1815int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
1816 struct wpa_bss *bss, struct wpa_ssid *ssid,
Sunil Ravi77d572f2023-01-17 23:58:31 +00001817 u8 *wpa_ie, size_t *wpa_ie_len,
1818 bool skip_default_rsne)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001819{
1820 struct wpa_ie_data ie;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001821 int sel, proto;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001822#ifdef CONFIG_SAE
Sunil Ravi77d572f2023-01-17 23:58:31 +00001823 enum sae_pwe sae_pwe;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001824#endif /* CONFIG_SAE */
Sunil Ravi876a49b2025-02-03 19:18:32 +00001825 const u8 *bss_wpa, *bss_rsn, *bss_rsnx;
Sunil Ravi640215c2023-06-28 23:08:09 +00001826 bool wmm;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001827
1828 if (bss) {
1829 bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
Sunil Ravi7f769292024-07-23 22:21:32 +00001830 bss_rsn = wpa_bss_get_rsne(wpa_s, bss, ssid, false);
1831 bss_rsnx = wpa_bss_get_rsnxe(wpa_s, bss, ssid, false);
Hai Shalomc3565922019-10-28 11:58:20 -07001832 } else {
Sunil Ravi876a49b2025-02-03 19:18:32 +00001833 bss_wpa = bss_rsn = bss_rsnx = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -07001834 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001835
1836 if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
1837 wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
Hai Shalom021b0b52019-04-10 11:17:58 -07001838 matching_ciphers(ssid, &ie, bss->freq) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001839 (ie.key_mgmt & ssid->key_mgmt)) {
1840 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
1841 proto = WPA_PROTO_RSN;
1842 } else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001843 wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie) == 0 &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001844 (ie.group_cipher & ssid->group_cipher) &&
1845 (ie.pairwise_cipher & ssid->pairwise_cipher) &&
1846 (ie.key_mgmt & ssid->key_mgmt)) {
1847 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
1848 proto = WPA_PROTO_WPA;
1849 } else if (bss) {
1850 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001851 wpa_dbg(wpa_s, MSG_DEBUG,
1852 "WPA: ssid proto=0x%x pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
1853 ssid->proto, ssid->pairwise_cipher, ssid->group_cipher,
1854 ssid->key_mgmt);
Sunil Ravi876a49b2025-02-03 19:18:32 +00001855 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: BSS " MACSTR " ssid='%s'%s%s",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001856 MAC2STR(bss->bssid),
1857 wpa_ssid_txt(bss->ssid, bss->ssid_len),
1858 bss_wpa ? " WPA" : "",
Sunil Ravi876a49b2025-02-03 19:18:32 +00001859 bss_rsn ? " RSN" : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001860 if (bss_rsn) {
1861 wpa_hexdump(MSG_DEBUG, "RSN", bss_rsn, 2 + bss_rsn[1]);
1862 if (wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie)) {
1863 wpa_dbg(wpa_s, MSG_DEBUG,
1864 "Could not parse RSN element");
1865 } else {
1866 wpa_dbg(wpa_s, MSG_DEBUG,
1867 "RSN: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
1868 ie.pairwise_cipher, ie.group_cipher,
1869 ie.key_mgmt);
1870 }
1871 }
1872 if (bss_wpa) {
1873 wpa_hexdump(MSG_DEBUG, "WPA", bss_wpa, 2 + bss_wpa[1]);
1874 if (wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie)) {
1875 wpa_dbg(wpa_s, MSG_DEBUG,
1876 "Could not parse WPA element");
1877 } else {
1878 wpa_dbg(wpa_s, MSG_DEBUG,
1879 "WPA: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
1880 ie.pairwise_cipher, ie.group_cipher,
1881 ie.key_mgmt);
1882 }
1883 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001884 return -1;
1885 } else {
Sunil Ravi876a49b2025-02-03 19:18:32 +00001886 if (ssid->proto & WPA_PROTO_RSN)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001887 proto = WPA_PROTO_RSN;
1888 else
1889 proto = WPA_PROTO_WPA;
1890 if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) {
1891 os_memset(&ie, 0, sizeof(ie));
1892 ie.group_cipher = ssid->group_cipher;
1893 ie.pairwise_cipher = ssid->pairwise_cipher;
1894 ie.key_mgmt = ssid->key_mgmt;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001895 ie.mgmt_group_cipher = 0;
1896 if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
1897 if (ssid->group_mgmt_cipher &
1898 WPA_CIPHER_BIP_GMAC_256)
1899 ie.mgmt_group_cipher =
1900 WPA_CIPHER_BIP_GMAC_256;
1901 else if (ssid->group_mgmt_cipher &
1902 WPA_CIPHER_BIP_CMAC_256)
1903 ie.mgmt_group_cipher =
1904 WPA_CIPHER_BIP_CMAC_256;
1905 else if (ssid->group_mgmt_cipher &
1906 WPA_CIPHER_BIP_GMAC_128)
1907 ie.mgmt_group_cipher =
1908 WPA_CIPHER_BIP_GMAC_128;
1909 else
1910 ie.mgmt_group_cipher =
1911 WPA_CIPHER_AES_128_CMAC;
1912 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001913#ifdef CONFIG_OWE
1914 if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
1915 !ssid->owe_only &&
Sunil Ravi876a49b2025-02-03 19:18:32 +00001916 !bss_wpa && !bss_rsn) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001917 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
1918 wpa_s->wpa_proto = 0;
1919 *wpa_ie_len = 0;
1920 return 0;
1921 }
1922#endif /* CONFIG_OWE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001923 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
1924 "based on configuration");
1925 } else
1926 proto = ie.proto;
1927 }
1928
1929 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
1930 "pairwise %d key_mgmt %d proto %d",
1931 ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001932 if (ssid->ieee80211w) {
1933 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
1934 ie.mgmt_group_cipher);
1935 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001936
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001937 wpa_s->wpa_proto = proto;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001938 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
1939 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
Sunil Ravi876a49b2025-02-03 19:18:32 +00001940 !!(ssid->proto & WPA_PROTO_RSN));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001941
1942 if (bss || !wpa_s->ap_ies_from_associnfo) {
Sunil Ravic0f5d412024-09-11 22:12:49 +00001943 const u8 *rsnoe = NULL, *rsno2e = NULL, *rsnxoe = NULL;
1944
1945 if (bss) {
1946 bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
1947 bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
1948 rsnoe = wpa_bss_get_vendor_ie(
1949 bss, RSNE_OVERRIDE_IE_VENDOR_TYPE);
1950 rsno2e = wpa_bss_get_vendor_ie(
1951 bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
1952 rsnxoe = wpa_bss_get_vendor_ie(
1953 bss, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
1954 }
1955
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001956 if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
1957 bss_wpa ? 2 + bss_wpa[1] : 0) ||
1958 wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
Hai Shalomc3565922019-10-28 11:58:20 -07001959 bss_rsn ? 2 + bss_rsn[1] : 0) ||
1960 wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001961 bss_rsnx ? 2 + bss_rsnx[1] : 0) ||
1962 wpa_sm_set_ap_rsne_override(wpa_s->wpa, rsnoe,
1963 rsnoe ? 2 + rsnoe[1] : 0) ||
1964 wpa_sm_set_ap_rsne_override_2(wpa_s->wpa, rsno2e,
1965 rsno2e ? 2 + rsno2e[1] : 0) ||
1966 wpa_sm_set_ap_rsnxe_override(wpa_s->wpa, rsnxoe,
1967 rsnxoe ? 2 + rsnxoe[1] : 0))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001968 return -1;
1969 }
1970
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001971#ifdef CONFIG_NO_WPA
1972 wpa_s->group_cipher = WPA_CIPHER_NONE;
1973 wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
1974#else /* CONFIG_NO_WPA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001975 sel = ie.group_cipher & ssid->group_cipher;
Hai Shalom021b0b52019-04-10 11:17:58 -07001976 wpa_dbg(wpa_s, MSG_DEBUG,
1977 "WPA: AP group 0x%x network profile group 0x%x; available group 0x%x",
1978 ie.group_cipher, ssid->group_cipher, sel);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001979 wpa_s->group_cipher = wpa_pick_group_cipher(sel);
1980 if (wpa_s->group_cipher < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001981 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
1982 "cipher");
1983 return -1;
1984 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001985 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK %s",
1986 wpa_cipher_txt(wpa_s->group_cipher));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001987
1988 sel = ie.pairwise_cipher & ssid->pairwise_cipher;
Hai Shalom021b0b52019-04-10 11:17:58 -07001989 wpa_dbg(wpa_s, MSG_DEBUG,
1990 "WPA: AP pairwise 0x%x network profile pairwise 0x%x; available pairwise 0x%x",
1991 ie.pairwise_cipher, ssid->pairwise_cipher, sel);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001992 wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
1993 if (wpa_s->pairwise_cipher < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001994 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
1995 "cipher");
1996 return -1;
1997 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001998 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s",
1999 wpa_cipher_txt(wpa_s->pairwise_cipher));
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002000#endif /* CONFIG_NO_WPA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002001
2002 sel = ie.key_mgmt & ssid->key_mgmt;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002003#ifdef CONFIG_SAE
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002004 if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) &&
2005 !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA)) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00002006 wpas_is_sae_avoided(wpa_s, ssid, &ie))
Sunil Ravi89eba102022-09-13 21:04:37 -07002007 sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY |
2008 WPA_KEY_MGMT_FT_SAE | WPA_KEY_MGMT_FT_SAE_EXT_KEY);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002009#endif /* CONFIG_SAE */
Hai Shalomfdcde762020-04-02 11:19:20 -07002010#ifdef CONFIG_IEEE80211R
2011 if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME |
2012 WPA_DRIVER_FLAGS_UPDATE_FT_IES)))
2013 sel &= ~WPA_KEY_MGMT_FT;
2014#endif /* CONFIG_IEEE80211R */
2015 wpa_dbg(wpa_s, MSG_DEBUG,
2016 "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
2017 ie.key_mgmt, ssid->key_mgmt, sel);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002018 if (0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07002019#ifdef CONFIG_IEEE80211R
2020#ifdef CONFIG_SHA384
Hai Shalomc3565922019-10-28 11:58:20 -07002021 } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
2022 os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07002023 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
2024 wpa_dbg(wpa_s, MSG_DEBUG,
2025 "WPA: using KEY_MGMT FT/802.1X-SHA384");
Hai Shalom81f62d82019-07-22 12:10:00 -07002026 if (!ssid->ft_eap_pmksa_caching &&
2027 pmksa_cache_get_current(wpa_s->wpa)) {
2028 /* PMKSA caching with FT may have interoperability
2029 * issues, so disable that case by default for now. */
Hai Shalom021b0b52019-04-10 11:17:58 -07002030 wpa_dbg(wpa_s, MSG_DEBUG,
2031 "WPA: Disable PMKSA caching for FT/802.1X connection");
2032 pmksa_cache_clear_current(wpa_s->wpa);
2033 }
2034#endif /* CONFIG_SHA384 */
2035#endif /* CONFIG_IEEE80211R */
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002036#ifdef CONFIG_SUITEB192
2037 } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
2038 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
2039 wpa_dbg(wpa_s, MSG_DEBUG,
2040 "WPA: using KEY_MGMT 802.1X with Suite B (192-bit)");
2041#endif /* CONFIG_SUITEB192 */
2042#ifdef CONFIG_SUITEB
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002043 } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
2044 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
2045 wpa_dbg(wpa_s, MSG_DEBUG,
2046 "WPA: using KEY_MGMT 802.1X with Suite B");
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002047#endif /* CONFIG_SUITEB */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002048#ifdef CONFIG_SHA384
2049 } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA384) {
2050 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA384;
2051 wpa_dbg(wpa_s, MSG_DEBUG,
2052 "WPA: using KEY_MGMT 802.1X with SHA384");
2053#endif /* CONFIG_SHA384 */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002054#ifdef CONFIG_FILS
2055#ifdef CONFIG_IEEE80211R
2056 } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA384) {
2057 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
2058 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA384");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002059#endif /* CONFIG_IEEE80211R */
2060 } else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
2061 wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
2062 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA384");
Sunil Ravi89eba102022-09-13 21:04:37 -07002063#ifdef CONFIG_IEEE80211R
2064 } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) {
2065 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
2066 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256");
2067#endif /* CONFIG_IEEE80211R */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002068 } else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
2069 wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
2070 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
2071#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002072#ifdef CONFIG_IEEE80211R
Hai Shalomc3565922019-10-28 11:58:20 -07002073 } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) &&
2074 os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002075 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
2076 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
Hai Shalom81f62d82019-07-22 12:10:00 -07002077 if (!ssid->ft_eap_pmksa_caching &&
2078 pmksa_cache_get_current(wpa_s->wpa)) {
2079 /* PMKSA caching with FT may have interoperability
2080 * issues, so disable that case by default for now. */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002081 wpa_dbg(wpa_s, MSG_DEBUG,
2082 "WPA: Disable PMKSA caching for FT/802.1X connection");
2083 pmksa_cache_clear_current(wpa_s->wpa);
2084 }
Hai Shalom021b0b52019-04-10 11:17:58 -07002085#endif /* CONFIG_IEEE80211R */
2086#ifdef CONFIG_DPP
2087 } else if (sel & WPA_KEY_MGMT_DPP) {
2088 wpa_s->key_mgmt = WPA_KEY_MGMT_DPP;
2089 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP");
2090#endif /* CONFIG_DPP */
2091#ifdef CONFIG_SAE
Sunil Ravi89eba102022-09-13 21:04:37 -07002092 } else if (sel & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
2093 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE_EXT_KEY;
2094 wpa_dbg(wpa_s, MSG_DEBUG,
2095 "RSN: using KEY_MGMT FT/SAE (ext key)");
2096 } else if (sel & WPA_KEY_MGMT_SAE_EXT_KEY) {
2097 wpa_s->key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
2098 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE (ext key)");
Hai Shalom021b0b52019-04-10 11:17:58 -07002099 } else if (sel & WPA_KEY_MGMT_FT_SAE) {
2100 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
2101 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
2102 } else if (sel & WPA_KEY_MGMT_SAE) {
2103 wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
2104 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
2105#endif /* CONFIG_SAE */
2106#ifdef CONFIG_IEEE80211R
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002107 } else if (sel & WPA_KEY_MGMT_FT_PSK) {
2108 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
2109 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
2110#endif /* CONFIG_IEEE80211R */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002111 } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
2112 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
2113 wpa_dbg(wpa_s, MSG_DEBUG,
2114 "WPA: using KEY_MGMT 802.1X with SHA256");
2115 } else if (sel & WPA_KEY_MGMT_PSK_SHA256) {
2116 wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
2117 wpa_dbg(wpa_s, MSG_DEBUG,
2118 "WPA: using KEY_MGMT PSK with SHA256");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002119 } else if (sel & WPA_KEY_MGMT_IEEE8021X) {
2120 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
2121 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
2122 } else if (sel & WPA_KEY_MGMT_PSK) {
2123 wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
2124 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK");
2125 } else if (sel & WPA_KEY_MGMT_WPA_NONE) {
2126 wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
2127 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002128#ifdef CONFIG_OWE
2129 } else if (sel & WPA_KEY_MGMT_OWE) {
2130 wpa_s->key_mgmt = WPA_KEY_MGMT_OWE;
2131 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT OWE");
2132#endif /* CONFIG_OWE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002133 } else {
2134 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
2135 "authenticated key management type");
2136 return -1;
2137 }
2138
2139 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
2140 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
2141 wpa_s->pairwise_cipher);
2142 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
2143
Hai Shalomc3565922019-10-28 11:58:20 -07002144 if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00002145 (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED ||
2146 (bss && is_6ghz_freq(bss->freq)))) {
Hai Shalomc3565922019-10-28 11:58:20 -07002147 wpa_msg(wpa_s, MSG_INFO,
2148 "RSN: Management frame protection required but the selected AP does not enable it");
2149 return -1;
2150 }
2151
Hai Shalomc1a21442022-02-04 13:43:00 -08002152 wpas_set_mgmt_group_cipher(wpa_s, ssid, &ie);
Hai Shalom74f70d42019-02-11 14:42:39 -08002153#ifdef CONFIG_OCV
Hai Shalom60840252021-02-19 19:02:11 -08002154 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
2155 (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OCV))
2156 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
Hai Shalom74f70d42019-02-11 14:42:39 -08002157#endif /* CONFIG_OCV */
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002158#ifdef CONFIG_SAE
2159 sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
Sunil Ravi89eba102022-09-13 21:04:37 -07002160 if ((ssid->sae_password_id ||
2161 wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt)) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00002162 sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
2163 sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
2164 if (bss && is_6ghz_freq(bss->freq) &&
2165 sae_pwe == SAE_PWE_HUNT_AND_PECK) {
2166 wpa_dbg(wpa_s, MSG_DEBUG,
2167 "RSN: Enable SAE hash-to-element mode for 6 GHz BSS");
2168 sae_pwe = SAE_PWE_BOTH;
Jimmy Chenaace8cd2021-04-13 14:55:52 +08002169 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002170 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe);
Hai Shalom899fcc72020-10-19 14:38:18 -07002171#ifdef CONFIG_SAE_PK
2172 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PK,
2173 wpa_key_mgmt_sae(ssid->key_mgmt) &&
2174 ssid->sae_pk != SAE_PK_MODE_DISABLED &&
2175 ((ssid->sae_password &&
2176 sae_pk_valid_password(ssid->sae_password)) ||
2177 (!ssid->sae_password && ssid->passphrase &&
2178 sae_pk_valid_password(ssid->passphrase))));
2179#endif /* CONFIG_SAE_PK */
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002180#endif /* CONFIG_SAE */
Sunil Ravi77d572f2023-01-17 23:58:31 +00002181 if (bss && is_6ghz_freq(bss->freq) &&
2182 wpas_get_ssid_pmf(wpa_s, ssid) != MGMT_FRAME_PROTECTION_REQUIRED) {
2183 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Force MFPR=1 on 6 GHz");
2184 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
2185 MGMT_FRAME_PROTECTION_REQUIRED);
2186 }
Hai Shalomb755a2a2020-04-23 21:49:02 -07002187#ifdef CONFIG_TESTING_OPTIONS
2188 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_RSNXE_USED,
2189 wpa_s->ft_rsnxe_used);
Hai Shalom899fcc72020-10-19 14:38:18 -07002190 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL,
2191 wpa_s->oci_freq_override_eapol);
2192 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
2193 wpa_s->oci_freq_override_eapol_g2);
2194 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
2195 wpa_s->oci_freq_override_ft_assoc);
2196 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FILS_ASSOC,
2197 wpa_s->oci_freq_override_fils_assoc);
Sunil Ravia04bd252022-05-02 22:54:18 -07002198 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DISABLE_EAPOL_G2_TX,
2199 wpa_s->disable_eapol_g2_tx);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002200 wpa_sm_set_param(wpa_s->wpa,
2201 WPA_PARAM_EAPOL_2_KEY_INFO_SET_MASK,
2202 wpa_s->eapol_2_key_info_set_mask);
Hai Shalomb755a2a2020-04-23 21:49:02 -07002203#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomfdcde762020-04-02 11:19:20 -07002204
2205 /* Extended Key ID is only supported in infrastructure BSS so far */
2206 if (ssid->mode == WPAS_MODE_INFRA && wpa_s->conf->extended_key_id &&
2207 (ssid->proto & WPA_PROTO_RSN) &&
2208 ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
2209 WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256) &&
2210 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)) {
2211 int use_ext_key_id = 0;
2212
2213 wpa_msg(wpa_s, MSG_DEBUG,
2214 "WPA: Enable Extended Key ID support");
2215 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID,
2216 wpa_s->conf->extended_key_id);
2217 if (bss_rsn &&
2218 wpa_s->conf->extended_key_id &&
2219 wpa_s->pairwise_cipher != WPA_CIPHER_TKIP &&
2220 (ie.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST))
2221 use_ext_key_id = 1;
2222 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID,
2223 use_ext_key_id);
2224 } else {
2225 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID, 0);
2226 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0);
2227 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002228
Sunil Ravi640215c2023-06-28 23:08:09 +00002229 /* Mark WMM enabled for any HT/VHT/HE/EHT association to get more
2230 * appropriate advertisement of the supported number of PTKSA receive
2231 * counters. In theory, this could be based on a driver capability, but
2232 * in practice all cases using WMM support at least eight replay
2233 * counters, so use a hardcoded value for now since there is no explicit
2234 * driver capability indication for this.
2235 *
2236 * In addition, claim WMM to be enabled if the AP supports it since it
2237 * is far more likely for any current device to support WMM. */
2238 wmm = wpa_s->connection_set &&
2239 (wpa_s->connection_ht || wpa_s->connection_vht ||
2240 wpa_s->connection_he || wpa_s->connection_eht);
2241 if (!wmm && bss)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002242 wmm = !!wpa_bss_get_vendor_ie(bss, WMM_IE_VENDOR_TYPE);
Sunil Ravi640215c2023-06-28 23:08:09 +00002243 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_WMM_ENABLED, wmm);
2244
Sunil Ravi7f769292024-07-23 22:21:32 +00002245 if (ssid->ssid_protection && proto == WPA_PROTO_RSN) {
2246 bool ssid_prot;
2247
2248 /* Enable SSID protection based on the AP advertising support
2249 * for it to avoid potential interoperability issues with
2250 * incorrect AP behavior if we were to send an "unexpected"
2251 * RSNXE with multiple octets of payload. */
2252 ssid_prot = ieee802_11_rsnx_capab(
2253 bss_rsnx, WLAN_RSNX_CAPAB_SSID_PROTECTION);
2254 if (!skip_default_rsne)
2255 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION,
2256 proto == WPA_PROTO_RSN && ssid_prot);
2257 } else {
2258 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION, false);
2259 }
2260
Sunil Ravi876a49b2025-02-03 19:18:32 +00002261 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SPP_AMSDU,
2262 (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SPP_AMSDU) &&
2263 ieee802_11_rsnx_capab(bss_rsnx,
2264 WLAN_RSNX_CAPAB_SPP_A_MSDU) &&
2265 wpa_s->pairwise_cipher & (WPA_CIPHER_CCMP_256 |
2266 WPA_CIPHER_GCMP_256 |
2267 WPA_CIPHER_CCMP |
2268 WPA_CIPHER_GCMP) &&
2269 (wpa_s->wpa_proto & WPA_PROTO_RSN));
2270
Sunil Ravi77d572f2023-01-17 23:58:31 +00002271 if (!skip_default_rsne) {
2272 if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie,
2273 wpa_ie_len)) {
2274 wpa_msg(wpa_s, MSG_WARNING,
2275 "RSN: Failed to generate RSNE/WPA IE");
2276 return -1;
2277 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002278
Matthew Wang9ed1c792024-12-02 14:05:18 +00002279#ifndef CONFIG_NO_WPA
Sunil Ravi77d572f2023-01-17 23:58:31 +00002280 wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
2281 if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
2282 &wpa_s->rsnxe_len)) {
2283 wpa_msg(wpa_s, MSG_WARNING,
2284 "RSN: Failed to generate RSNXE");
2285 return -1;
2286 }
Matthew Wang9ed1c792024-12-02 14:05:18 +00002287#endif /* CONFIG_NO_WPA */
Hai Shalomc3565922019-10-28 11:58:20 -07002288 }
2289
Hai Shalom021b0b52019-04-10 11:17:58 -07002290 if (0) {
2291#ifdef CONFIG_DPP
2292 } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
2293 /* Use PMK from DPP network introduction (PMKSA entry) */
2294 wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002295#ifdef CONFIG_DPP2
2296 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DPP_PFS, ssid->dpp_pfs);
2297#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07002298#endif /* CONFIG_DPP */
2299 } else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002300 int psk_set = 0;
2301
Sunil Ravi77d572f2023-01-17 23:58:31 +00002302 if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt)) {
2303 u8 psk[PMK_LEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -07002304
Sunil Ravi77d572f2023-01-17 23:58:31 +00002305 if (wpa_supplicant_get_psk(wpa_s, bss, ssid,
2306 psk) == 0) {
2307 wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
2308 NULL);
2309 psk_set = 1;
2310 }
2311 forced_memzero(psk, sizeof(psk));
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002312 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002313
Roshan Pius3a1667e2018-07-03 15:17:14 -07002314 if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00002315 (ssid->sae_password || ssid->passphrase || ssid->ext_psk))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002316 psk_set = 1;
2317
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002318 if (!psk_set && !ssid->pmk_valid) {
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002319 wpa_msg(wpa_s, MSG_INFO,
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002320 "No PSK/PMK available for association");
Sunil Ravi77d572f2023-01-17 23:58:31 +00002321 wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE", NULL);
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002322 return -1;
2323 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002324#ifdef CONFIG_OWE
2325 } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) {
2326 /* OWE Diffie-Hellman exchange in (Re)Association
2327 * Request/Response frames set the PMK, so do not override it
2328 * here. */
2329#endif /* CONFIG_OWE */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002330 } else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002331 wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
2332
Hai Shalomfdcde762020-04-02 11:19:20 -07002333 if (ssid->mode != WPAS_MODE_IBSS &&
2334 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
2335 (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
2336 (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
2337 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
2338 wpa_msg(wpa_s, MSG_INFO,
2339 "Disable PTK0 rekey support - replaced with reconnect");
2340 wpa_s->deny_ptk0_rekey = 1;
2341 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 1);
2342 } else {
2343 wpa_s->deny_ptk0_rekey = 0;
2344 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0);
2345 }
2346
Isaac Chiou6ce580d2024-04-24 17:07:24 +08002347#if (defined(CONFIG_DRIVER_NL80211_BRCM) && !defined(WIFI_BRCM_OPEN_SOURCE_MULTI_AKM)) || \
2348 defined(CONFIG_DRIVER_NL80211_SYNA)
Vinayak Yadawad14709082022-03-17 14:25:11 +05302349 if ((wpa_s->key_mgmt & WPA_KEY_MGMT_CROSS_AKM_ROAM) &&
Dennis Jeon2a960552022-07-05 13:56:50 +09002350 IS_CROSS_AKM_ROAM_KEY_MGMT(ssid->key_mgmt) &&
2351 (wpa_s->group_cipher == WPA_CIPHER_CCMP) &&
Dennis Jeona3930812022-10-24 15:31:04 +09002352 (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP) &&
2353 (wpa_s->wpa_proto == WPA_PROTO_RSN)) {
Vinayak Yadawad14709082022-03-17 14:25:11 +05302354 wpa_s->key_mgmt = WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_PSK;
2355 wpa_dbg(wpa_s, MSG_INFO,
2356 "WPA: Updating to KEY_MGMT SAE+PSK for seamless roaming");
2357 }
Sunil Ravif42be322022-11-04 03:31:21 +00002358#else
2359 if (wpa_key_mgmt_cross_akm(wpa_s->key_mgmt) &&
2360 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
2361 wpas_update_allowed_key_mgmt(wpa_s, ssid);
Isaac Chiou6ce580d2024-04-24 17:07:24 +08002362#endif /* (CONFIG_DRIVER_NL80211_BRCM && !WIFI_BRCM_OPEN_SOURCE_MULTI_AKM) ||
2363 * CONFIG_DRIVER_NL80211_SYNA */
Vinayak Yadawad14709082022-03-17 14:25:11 +05302364
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002365 return 0;
2366}
2367
2368
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002369static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx,
2370 struct wpa_bss *bss)
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002371{
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002372#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08002373 bool scs = true, mscs = true;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002374#endif /* CONFIG_NO_ROBUST_AV */
Hai Shalomc1a21442022-02-04 13:43:00 -08002375
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002376 *pos = 0x00;
2377
2378 switch (idx) {
2379 case 0: /* Bits 0-7 */
2380 break;
2381 case 1: /* Bits 8-15 */
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002382 if (wpa_s->conf->coloc_intf_reporting) {
2383 /* Bit 13 - Collocated Interference Reporting */
2384 *pos |= 0x20;
2385 }
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002386 break;
2387 case 2: /* Bits 16-23 */
2388#ifdef CONFIG_WNM
2389 *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002390 if ((wpas_driver_bss_selection(wpa_s) ||
2391 !wpa_s->disable_mbo_oce) &&
2392 !wpa_s->conf->disable_btm)
Hai Shalom81f62d82019-07-22 12:10:00 -07002393 *pos |= 0x08; /* Bit 19 - BSS Transition */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002394#endif /* CONFIG_WNM */
2395 break;
2396 case 3: /* Bits 24-31 */
2397#ifdef CONFIG_WNM
2398 *pos |= 0x02; /* Bit 25 - SSID List */
2399#endif /* CONFIG_WNM */
2400#ifdef CONFIG_INTERWORKING
2401 if (wpa_s->conf->interworking)
2402 *pos |= 0x80; /* Bit 31 - Interworking */
2403#endif /* CONFIG_INTERWORKING */
2404 break;
2405 case 4: /* Bits 32-39 */
Dmitry Shmidt051af732013-10-22 13:52:46 -07002406#ifdef CONFIG_INTERWORKING
Hai Shalomce48b4a2018-09-05 11:41:35 -07002407 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002408 *pos |= 0x01; /* Bit 32 - QoS Map */
Dmitry Shmidt051af732013-10-22 13:52:46 -07002409#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002410 break;
2411 case 5: /* Bits 40-47 */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002412#ifdef CONFIG_HS20
2413 if (wpa_s->conf->hs20)
2414 *pos |= 0x40; /* Bit 46 - WNM-Notification */
2415#endif /* CONFIG_HS20 */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002416#ifdef CONFIG_MBO
2417 *pos |= 0x40; /* Bit 46 - WNM-Notification */
2418#endif /* CONFIG_MBO */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002419 break;
2420 case 6: /* Bits 48-55 */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002421#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08002422#ifdef CONFIG_TESTING_OPTIONS
2423 if (wpa_s->disable_scs_support)
2424 scs = false;
2425#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002426 if (bss && !wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_SCS)) {
2427 /* Drop own SCS capability indication since the AP does
2428 * not support it. This is needed to avoid
2429 * interoperability issues with APs that get confused
2430 * with Extended Capabilities element. */
2431 scs = false;
2432 }
Hai Shalomc1a21442022-02-04 13:43:00 -08002433 if (scs)
2434 *pos |= 0x40; /* Bit 54 - SCS */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002435#endif /* CONFIG_NO_ROBUST_AV */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002436 break;
Dmitry Shmidt7d175302016-09-06 13:11:34 -07002437 case 7: /* Bits 56-63 */
2438 break;
2439 case 8: /* Bits 64-71 */
2440 if (wpa_s->conf->ftm_responder)
2441 *pos |= 0x40; /* Bit 70 - FTM responder */
2442 if (wpa_s->conf->ftm_initiator)
2443 *pos |= 0x80; /* Bit 71 - FTM initiator */
2444 break;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002445 case 9: /* Bits 72-79 */
2446#ifdef CONFIG_FILS
Roshan Pius3a1667e2018-07-03 15:17:14 -07002447 if (!wpa_s->disable_fils)
2448 *pos |= 0x01;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002449#endif /* CONFIG_FILS */
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002450 if (wpa_s->conf->twt_requester)
2451 *pos |= 0x20; /* Bit 77 - TWT Requester Support */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002452 break;
Hai Shalom899fcc72020-10-19 14:38:18 -07002453 case 10: /* Bits 80-87 */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002454#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08002455#ifdef CONFIG_TESTING_OPTIONS
2456 if (wpa_s->disable_mscs_support)
2457 mscs = false;
2458#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002459 if (bss && !wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS)) {
2460 /* Drop own MSCS capability indication since the AP does
2461 * not support it. This is needed to avoid
2462 * interoperability issues with APs that get confused
2463 * with Extended Capabilities element. */
2464 mscs = false;
2465 }
Hai Shalomc1a21442022-02-04 13:43:00 -08002466 if (mscs)
2467 *pos |= 0x20; /* Bit 85 - Mirrored SCS */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002468#endif /* CONFIG_NO_ROBUST_AV */
Hai Shalom899fcc72020-10-19 14:38:18 -07002469 break;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002470 }
2471}
2472
2473
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002474int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf,
2475 size_t buflen, struct wpa_bss *bss)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002476{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002477 u8 *pos = buf;
Hai Shalom899fcc72020-10-19 14:38:18 -07002478 u8 len = 11, i;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002479
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002480 if (len < wpa_s->extended_capa_len)
2481 len = wpa_s->extended_capa_len;
Dmitry Shmidt09f57ba2014-06-10 16:07:13 -07002482 if (buflen < (size_t) len + 2) {
2483 wpa_printf(MSG_INFO,
2484 "Not enough room for building extended capabilities element");
2485 return -1;
2486 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002487
2488 *pos++ = WLAN_EID_EXT_CAPAB;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002489 *pos++ = len;
2490 for (i = 0; i < len; i++, pos++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002491 wpas_ext_capab_byte(wpa_s, pos, i, bss);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002492
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002493 if (i < wpa_s->extended_capa_len) {
2494 *pos &= ~wpa_s->extended_capa_mask[i];
2495 *pos |= wpa_s->extended_capa[i];
2496 }
2497 }
2498
2499 while (len > 0 && buf[1 + len] == 0) {
2500 len--;
2501 buf[1] = len;
2502 }
2503 if (len == 0)
2504 return 0;
2505
2506 return 2 + len;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002507}
2508
2509
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002510static int wpas_valid_bss(struct wpa_supplicant *wpa_s,
2511 struct wpa_bss *test_bss)
2512{
2513 struct wpa_bss *bss;
2514
2515 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
2516 if (bss == test_bss)
2517 return 1;
2518 }
2519
2520 return 0;
2521}
2522
2523
2524static int wpas_valid_ssid(struct wpa_supplicant *wpa_s,
2525 struct wpa_ssid *test_ssid)
2526{
2527 struct wpa_ssid *ssid;
2528
2529 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
2530 if (ssid == test_ssid)
2531 return 1;
2532 }
2533
2534 return 0;
2535}
2536
2537
2538int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss,
2539 struct wpa_ssid *test_ssid)
2540{
2541 if (test_bss && !wpas_valid_bss(wpa_s, test_bss))
2542 return 0;
2543
2544 return test_ssid == NULL || wpas_valid_ssid(wpa_s, test_ssid);
2545}
2546
2547
2548void wpas_connect_work_free(struct wpa_connect_work *cwork)
2549{
2550 if (cwork == NULL)
2551 return;
2552 os_free(cwork);
2553}
2554
2555
2556void wpas_connect_work_done(struct wpa_supplicant *wpa_s)
2557{
2558 struct wpa_connect_work *cwork;
2559 struct wpa_radio_work *work = wpa_s->connect_work;
2560
2561 if (!work)
2562 return;
2563
2564 wpa_s->connect_work = NULL;
2565 cwork = work->ctx;
2566 work->ctx = NULL;
2567 wpas_connect_work_free(cwork);
2568 radio_work_done(work);
2569}
2570
2571
Sunil Ravi77d572f2023-01-17 23:58:31 +00002572int wpas_update_random_addr(struct wpa_supplicant *wpa_s,
2573 enum wpas_mac_addr_style style,
2574 struct wpa_ssid *ssid)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002575{
2576 struct os_reltime now;
2577 u8 addr[ETH_ALEN];
2578
2579 os_get_reltime(&now);
Sunil Ravi77d572f2023-01-17 23:58:31 +00002580 /* Random addresses are valid within a given ESS so check
2581 * expiration/value only when continuing to use the same ESS. */
2582 if (wpa_s->last_mac_addr_style == style && wpa_s->reassoc_same_ess) {
2583 if (style == WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS) {
2584 /* Pregenerated addresses do not expire but their value
2585 * might have changed, so let's check that. */
Sunil Ravi876a49b2025-02-03 19:18:32 +00002586 if (ssid &&
2587 ether_addr_equal(wpa_s->own_addr, ssid->mac_value))
Sunil Ravi77d572f2023-01-17 23:58:31 +00002588 return 0;
2589 } else if ((wpa_s->last_mac_addr_change.sec != 0 ||
2590 wpa_s->last_mac_addr_change.usec != 0) &&
2591 !os_reltime_expired(
2592 &now,
2593 &wpa_s->last_mac_addr_change,
2594 wpa_s->conf->rand_addr_lifetime)) {
2595 wpa_msg(wpa_s, MSG_DEBUG,
2596 "Previously selected random MAC address has not yet expired");
2597 return 0;
2598 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002599 }
2600
2601 switch (style) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002602 case WPAS_MAC_ADDR_STYLE_RANDOM:
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002603 if (random_mac_addr(addr) < 0)
2604 return -1;
2605 break;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002606 case WPAS_MAC_ADDR_STYLE_RANDOM_SAME_OUI:
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002607 os_memcpy(addr, wpa_s->perm_addr, ETH_ALEN);
2608 if (random_mac_addr_keep_oui(addr) < 0)
2609 return -1;
2610 break;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002611 case WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS:
2612 if (!ssid) {
2613 wpa_msg(wpa_s, MSG_INFO,
2614 "Invalid 'ssid' for address policy 3");
2615 return -1;
2616 }
2617 os_memcpy(addr, ssid->mac_value, ETH_ALEN);
2618 break;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002619 default:
2620 return -1;
2621 }
2622
2623 if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
2624 wpa_msg(wpa_s, MSG_INFO,
2625 "Failed to set random MAC address");
2626 return -1;
2627 }
2628
2629 os_get_reltime(&wpa_s->last_mac_addr_change);
2630 wpa_s->mac_addr_changed = 1;
2631 wpa_s->last_mac_addr_style = style;
2632
2633 if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
2634 wpa_msg(wpa_s, MSG_INFO,
2635 "Could not update MAC address information");
2636 return -1;
2637 }
2638
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002639 wpas_p2p_update_dev_addr(wpa_s);
2640
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002641 wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
2642 MAC2STR(addr));
2643
Sunil Ravi77d572f2023-01-17 23:58:31 +00002644 return 1;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002645}
2646
2647
2648int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
2649{
2650 if (wpa_s->wpa_state >= WPA_AUTHENTICATING ||
2651 !wpa_s->conf->preassoc_mac_addr)
2652 return 0;
2653
Sunil Ravi77d572f2023-01-17 23:58:31 +00002654 return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr,
2655 NULL);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002656}
2657
2658
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002659void wpa_s_setup_sae_pt(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
Sunil Ravi036cec52023-03-29 11:35:17 -07002660 bool force)
Hai Shalomc3565922019-10-28 11:58:20 -07002661{
2662#ifdef CONFIG_SAE
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002663 struct wpa_config *conf = wpa_s->conf;
Hai Shalomc3565922019-10-28 11:58:20 -07002664 int *groups = conf->sae_groups;
2665 int default_groups[] = { 19, 20, 21, 0 };
2666 const char *password;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002667 enum sae_pwe sae_pwe;
Hai Shalomc3565922019-10-28 11:58:20 -07002668
2669 if (!groups || groups[0] <= 0)
2670 groups = default_groups;
2671
2672 password = ssid->sae_password;
2673 if (!password)
2674 password = ssid->passphrase;
2675
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002676 sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
2677
Hai Shalom899fcc72020-10-19 14:38:18 -07002678 if (!password ||
Sunil Ravi7f769292024-07-23 22:21:32 +00002679 !wpa_key_mgmt_sae(ssid->key_mgmt) ||
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002680 (sae_pwe == SAE_PWE_HUNT_AND_PECK && !ssid->sae_password_id &&
Sunil Ravi89eba102022-09-13 21:04:37 -07002681 !wpa_key_mgmt_sae_ext_key(ssid->key_mgmt) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07002682 !force &&
Hai Shalom899fcc72020-10-19 14:38:18 -07002683 !sae_pk_valid_password(password)) ||
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002684 sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) {
Hai Shalomc3565922019-10-28 11:58:20 -07002685 /* PT derivation not needed */
2686 sae_deinit_pt(ssid->pt);
2687 ssid->pt = NULL;
2688 return;
2689 }
2690
2691 if (ssid->pt)
2692 return; /* PT already derived */
2693 ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
2694 (const u8 *) password, os_strlen(password),
2695 ssid->sae_password_id);
2696#endif /* CONFIG_SAE */
2697}
2698
2699
Sunil Ravi7f769292024-07-23 22:21:32 +00002700void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s)
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002701{
2702#if defined(CONFIG_SAE) && defined(CONFIG_SME)
2703 os_free(wpa_s->sme.sae_rejected_groups);
2704 wpa_s->sme.sae_rejected_groups = NULL;
2705#ifdef CONFIG_TESTING_OPTIONS
2706 if (wpa_s->extra_sae_rejected_groups) {
2707 int i, *groups = wpa_s->extra_sae_rejected_groups;
2708
2709 for (i = 0; groups[i]; i++) {
2710 wpa_printf(MSG_DEBUG,
2711 "TESTING: Indicate rejection of an extra SAE group %d",
2712 groups[i]);
2713 int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
2714 groups[i]);
2715 }
2716 }
2717#endif /* CONFIG_TESTING_OPTIONS */
2718#endif /* CONFIG_SAE && CONFIG_SME */
2719}
2720
2721
Hai Shalom60840252021-02-19 19:02:11 -08002722int wpas_restore_permanent_mac_addr(struct wpa_supplicant *wpa_s)
2723{
2724 if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
2725 wpa_msg(wpa_s, MSG_INFO,
2726 "Could not restore permanent MAC address");
2727 return -1;
2728 }
2729 wpa_s->mac_addr_changed = 0;
2730 if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
2731 wpa_msg(wpa_s, MSG_INFO,
2732 "Could not update MAC address information");
2733 return -1;
2734 }
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002735
2736 wpas_p2p_update_dev_addr(wpa_s);
2737
Hai Shalom60840252021-02-19 19:02:11 -08002738 wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
2739 return 0;
2740}
2741
2742
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002743static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
2744
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002745/**
2746 * wpa_supplicant_associate - Request association
2747 * @wpa_s: Pointer to wpa_supplicant data
2748 * @bss: Scan results for the selected BSS, or %NULL if not available
2749 * @ssid: Configuration data for the selected network
2750 *
2751 * This function is used to request %wpa_supplicant to associate with a BSS.
2752 */
2753void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
2754 struct wpa_bss *bss, struct wpa_ssid *ssid)
2755{
Sunil Ravi7f769292024-07-23 22:21:32 +00002756 bool clear_rejected = true;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002757 struct wpa_connect_work *cwork;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002758 enum wpas_mac_addr_style rand_style;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002759
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002760 wpa_s->own_disconnect_req = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07002761 wpa_s->own_reconnect_req = 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002762
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002763 /*
2764 * If we are starting a new connection, any previously pending EAPOL
2765 * RX cannot be valid anymore.
2766 */
2767 wpabuf_free(wpa_s->pending_eapol_rx);
2768 wpa_s->pending_eapol_rx = NULL;
2769
Sunil Ravi77d572f2023-01-17 23:58:31 +00002770 if (ssid->mac_addr == WPAS_MAC_ADDR_STYLE_NOT_SET)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002771 rand_style = wpa_s->conf->mac_addr;
2772 else
2773 rand_style = ssid->mac_addr;
2774
Sunil Ravia04bd252022-05-02 22:54:18 -07002775 wpa_s->eapol_failed = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07002776 wpa_s->multi_ap_ie = 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002777#ifndef CONFIG_NO_WMM_AC
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002778 wmm_ac_clear_saved_tspecs(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002779#endif /* CONFIG_NO_WMM_AC */
2780#ifdef CONFIG_WNM
2781 wpa_s->wnm_mode = 0;
Sunil Ravi99c035e2024-07-12 01:42:03 +00002782 wpa_s->wnm_target_bss = NULL;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002783#endif /* CONFIG_WNM */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002784 wpa_s->reassoc_same_bss = 0;
Dmitry Shmidte4663042016-04-04 10:07:49 -07002785 wpa_s->reassoc_same_ess = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002786#ifdef CONFIG_TESTING_OPTIONS
2787 wpa_s->testing_resend_assoc = 0;
2788#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002789
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002790 if (wpa_s->last_ssid == ssid) {
2791 wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
Dmitry Shmidte4663042016-04-04 10:07:49 -07002792 wpa_s->reassoc_same_ess = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002793 if (wpa_s->current_bss && wpa_s->current_bss == bss) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002794#ifndef CONFIG_NO_WMM_AC
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002795 wmm_ac_save_tspecs(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002796#endif /* CONFIG_NO_WMM_AC */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002797 wpa_s->reassoc_same_bss = 1;
Sunil Ravi7f769292024-07-23 22:21:32 +00002798 clear_rejected = false;
Hai Shalom74f70d42019-02-11 14:42:39 -08002799 } else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
2800 os_get_reltime(&wpa_s->roam_start);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002801 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002802 }
Sunil Ravi7f769292024-07-23 22:21:32 +00002803
2804 if (clear_rejected)
2805 wpa_s_clear_sae_rejected(wpa_s);
2806
Hai Shalomc1a21442022-02-04 13:43:00 -08002807#ifdef CONFIG_SAE
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002808 wpa_s_setup_sae_pt(wpa_s, ssid, false);
Hai Shalomc1a21442022-02-04 13:43:00 -08002809#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002810
Sunil Ravi77d572f2023-01-17 23:58:31 +00002811 if (rand_style > WPAS_MAC_ADDR_STYLE_PERMANENT) {
2812 int status = wpas_update_random_addr(wpa_s, rand_style, ssid);
2813
2814 if (status < 0)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002815 return;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002816 if (rand_style != WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS &&
2817 status > 0) /* MAC changed */
2818 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
2819 } else if (rand_style == WPAS_MAC_ADDR_STYLE_PERMANENT &&
2820 wpa_s->mac_addr_changed) {
Hai Shalom60840252021-02-19 19:02:11 -08002821 if (wpas_restore_permanent_mac_addr(wpa_s) < 0)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002822 return;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002823 }
2824 wpa_s->last_ssid = ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002825
2826#ifdef CONFIG_IBSS_RSN
2827 ibss_rsn_deinit(wpa_s->ibss_rsn);
2828 wpa_s->ibss_rsn = NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002829#else /* CONFIG_IBSS_RSN */
2830 if (ssid->mode == WPAS_MODE_IBSS &&
2831 !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
2832 wpa_msg(wpa_s, MSG_INFO,
2833 "IBSS RSN not supported in the build");
2834 return;
2835 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002836#endif /* CONFIG_IBSS_RSN */
2837
2838 if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
2839 ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
2840#ifdef CONFIG_AP
2841 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
2842 wpa_msg(wpa_s, MSG_INFO, "Driver does not support AP "
2843 "mode");
2844 return;
2845 }
Dmitry Shmidtaa532512012-09-24 10:35:31 -07002846 if (wpa_supplicant_create_ap(wpa_s, ssid) < 0) {
2847 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
Ajay Davanageri10b3c662024-05-02 19:19:24 +05302848 if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
2849 ssid->mode == WPAS_MODE_P2P_GO) {
2850 wpa_msg(wpa_s, MSG_ERROR, "create ap failed. clean up the states");
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07002851 wpas_p2p_ap_setup_failed(wpa_s);
Ajay Davanageri10b3c662024-05-02 19:19:24 +05302852 }
Dmitry Shmidtaa532512012-09-24 10:35:31 -07002853 return;
2854 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002855 wpa_s->current_bss = bss;
2856#else /* CONFIG_AP */
2857 wpa_msg(wpa_s, MSG_ERROR, "AP mode support not included in "
2858 "the build");
2859#endif /* CONFIG_AP */
2860 return;
2861 }
2862
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002863 if (ssid->mode == WPAS_MODE_MESH) {
2864#ifdef CONFIG_MESH
2865 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MESH)) {
2866 wpa_msg(wpa_s, MSG_INFO,
2867 "Driver does not support mesh mode");
2868 return;
2869 }
2870 if (bss)
2871 ssid->frequency = bss->freq;
2872 if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) {
Sunil Ravi036cec52023-03-29 11:35:17 -07002873 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002874 wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh");
2875 return;
2876 }
2877 wpa_s->current_bss = bss;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002878#else /* CONFIG_MESH */
2879 wpa_msg(wpa_s, MSG_ERROR,
2880 "mesh mode support not included in the build");
2881#endif /* CONFIG_MESH */
2882 return;
2883 }
2884
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002885 /*
2886 * Set WPA state machine configuration to match the selected network now
2887 * so that the information is available before wpas_start_assoc_cb()
2888 * gets called. This is needed at least for RSN pre-authentication where
2889 * candidate APs are added to a list based on scan result processing
2890 * before completion of the first association.
2891 */
2892 wpa_supplicant_rsn_supp_set_config(wpa_s, ssid);
2893
2894#ifdef CONFIG_DPP
2895 if (wpas_dpp_check_connect(wpa_s, ssid, bss) != 0)
2896 return;
2897#endif /* CONFIG_DPP */
2898
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002899#ifdef CONFIG_TDLS
2900 if (bss)
Hai Shalom60840252021-02-19 19:02:11 -08002901 wpa_tdls_ap_ies(wpa_s->wpa, wpa_bss_ie_ptr(bss), bss->ie_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002902#endif /* CONFIG_TDLS */
2903
Hai Shalomc3565922019-10-28 11:58:20 -07002904#ifdef CONFIG_MBO
2905 wpas_mbo_check_pmf(wpa_s, bss, ssid);
2906#endif /* CONFIG_MBO */
2907
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002908 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
Hai Shalom81f62d82019-07-22 12:10:00 -07002909 ssid->mode == WPAS_MODE_INFRA) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002910 sme_authenticate(wpa_s, bss, ssid);
2911 return;
2912 }
2913
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002914 if (wpa_s->connect_work) {
2915 wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist");
2916 return;
2917 }
2918
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002919 if (radio_work_pending(wpa_s, "connect")) {
2920 wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since pending work exist");
2921 return;
2922 }
2923
Dmitry Shmidt29333592017-01-09 12:27:11 -08002924#ifdef CONFIG_SME
2925 if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) {
2926 /* Clear possibly set auth_alg, if any, from last attempt. */
2927 wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN;
2928 }
2929#endif /* CONFIG_SME */
2930
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002931 wpas_abort_ongoing_scan(wpa_s);
2932
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002933 cwork = os_zalloc(sizeof(*cwork));
2934 if (cwork == NULL)
2935 return;
2936
2937 cwork->bss = bss;
2938 cwork->ssid = ssid;
2939
2940 if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1,
2941 wpas_start_assoc_cb, cwork) < 0) {
2942 os_free(cwork);
2943 }
2944}
2945
2946
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002947static int bss_is_ibss(struct wpa_bss *bss)
2948{
2949 return (bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) ==
2950 IEEE80211_CAP_IBSS;
2951}
2952
2953
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002954static int drv_supports_vht(struct wpa_supplicant *wpa_s,
2955 const struct wpa_ssid *ssid)
2956{
2957 enum hostapd_hw_mode hw_mode;
2958 struct hostapd_hw_modes *mode = NULL;
2959 u8 channel;
2960 int i;
2961
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002962 hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
2963 if (hw_mode == NUM_HOSTAPD_MODES)
2964 return 0;
2965 for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
2966 if (wpa_s->hw.modes[i].mode == hw_mode) {
2967 mode = &wpa_s->hw.modes[i];
2968 break;
2969 }
2970 }
2971
2972 if (!mode)
2973 return 0;
2974
2975 return mode->vht_capab != 0;
2976}
2977
2978
Hai Shalomc1a21442022-02-04 13:43:00 -08002979static bool ibss_mesh_is_80mhz_avail(int channel, struct hostapd_hw_modes *mode)
2980{
2981 int i;
2982
2983 for (i = channel; i < channel + 16; i += 4) {
2984 struct hostapd_channel_data *chan;
2985
2986 chan = hw_get_channel_chan(mode, i, NULL);
2987 if (!chan ||
2988 chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
2989 return false;
2990 }
2991
2992 return true;
2993}
2994
2995
Sunil Ravi036cec52023-03-29 11:35:17 -07002996static struct wpa_bss * ibss_find_existing_bss(struct wpa_supplicant *wpa_s,
2997 const struct wpa_ssid *ssid)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002998{
Sunil Ravi036cec52023-03-29 11:35:17 -07002999 unsigned int j;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003000
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003001 for (j = 0; j < wpa_s->last_scan_res_used; j++) {
3002 struct wpa_bss *bss = wpa_s->last_scan_res[j];
3003
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003004 if (!bss_is_ibss(bss))
3005 continue;
3006
3007 if (ssid->ssid_len == bss->ssid_len &&
Sunil Ravi036cec52023-03-29 11:35:17 -07003008 os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) == 0)
3009 return bss;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003010 }
Sunil Ravi036cec52023-03-29 11:35:17 -07003011 return NULL;
3012}
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003013
Sunil Ravi036cec52023-03-29 11:35:17 -07003014
3015static bool ibss_mesh_can_use_ht(struct wpa_supplicant *wpa_s,
3016 const struct wpa_ssid *ssid,
3017 struct hostapd_hw_modes *mode)
3018{
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003019 /* For IBSS check HT_IBSS flag */
3020 if (ssid->mode == WPAS_MODE_IBSS &&
3021 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_HT_IBSS))
Sunil Ravi036cec52023-03-29 11:35:17 -07003022 return false;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003023
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003024 if (wpa_s->group_cipher == WPA_CIPHER_WEP40 ||
3025 wpa_s->group_cipher == WPA_CIPHER_WEP104 ||
3026 wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) {
3027 wpa_printf(MSG_DEBUG,
3028 "IBSS: WEP/TKIP detected, do not try to enable HT");
Sunil Ravi036cec52023-03-29 11:35:17 -07003029 return false;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003030 }
3031
Sunil Ravi036cec52023-03-29 11:35:17 -07003032 if (!ht_supported(mode))
3033 return false;
Hai Shalomc1a21442022-02-04 13:43:00 -08003034
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003035#ifdef CONFIG_HT_OVERRIDES
Sunil Ravi036cec52023-03-29 11:35:17 -07003036 if (ssid->disable_ht)
3037 return false;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003038#endif /* CONFIG_HT_OVERRIDES */
3039
Sunil Ravi036cec52023-03-29 11:35:17 -07003040 return true;
3041}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003042
Sunil Ravi036cec52023-03-29 11:35:17 -07003043
3044static bool ibss_mesh_can_use_vht(struct wpa_supplicant *wpa_s,
3045 const struct wpa_ssid *ssid,
3046 struct hostapd_hw_modes *mode)
3047{
3048 if (mode->mode != HOSTAPD_MODE_IEEE80211A)
3049 return false;
3050
3051 if (!drv_supports_vht(wpa_s, ssid))
3052 return false;
3053
3054 /* For IBSS check VHT_IBSS flag */
3055 if (ssid->mode == WPAS_MODE_IBSS &&
3056 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
3057 return false;
3058
3059 if (!vht_supported(mode))
3060 return false;
3061
3062#ifdef CONFIG_VHT_OVERRIDES
3063 if (ssid->disable_vht)
3064 return false;
3065#endif /* CONFIG_VHT_OVERRIDES */
3066
3067 return true;
3068}
3069
3070
3071static bool ibss_mesh_can_use_he(struct wpa_supplicant *wpa_s,
3072 const struct wpa_ssid *ssid,
3073 const struct hostapd_hw_modes *mode,
3074 int ieee80211_mode)
3075{
Hai Shalomfdcde762020-04-02 11:19:20 -07003076#ifdef CONFIG_HE_OVERRIDES
Sunil Ravi036cec52023-03-29 11:35:17 -07003077 if (ssid->disable_he)
3078 return false;
Hai Shalomfdcde762020-04-02 11:19:20 -07003079#endif /* CONFIG_HE_OVERRIDES */
Hai Shalomc3565922019-10-28 11:58:20 -07003080
Sunil Ravi036cec52023-03-29 11:35:17 -07003081 switch (mode->mode) {
3082 case HOSTAPD_MODE_IEEE80211G:
3083 case HOSTAPD_MODE_IEEE80211B:
3084 case HOSTAPD_MODE_IEEE80211A:
3085 return mode->he_capab[ieee80211_mode].he_supported;
3086 default:
3087 return false;
3088 }
3089}
3090
3091
3092static bool ibss_mesh_can_use_eht(struct wpa_supplicant *wpa_s,
3093 const struct wpa_ssid *ssid,
3094 const struct hostapd_hw_modes *mode,
3095 int ieee80211_mode)
3096{
3097 if (ssid->disable_eht)
3098 return false;
3099
3100 switch(mode->mode) {
3101 case HOSTAPD_MODE_IEEE80211G:
3102 case HOSTAPD_MODE_IEEE80211B:
3103 case HOSTAPD_MODE_IEEE80211A:
3104 return mode->eht_capab[ieee80211_mode].eht_supported;
3105 default:
3106 return false;
3107 }
3108}
3109
3110
3111static void ibss_mesh_select_40mhz(struct wpa_supplicant *wpa_s,
3112 const struct wpa_ssid *ssid,
3113 struct hostapd_hw_modes *mode,
3114 struct hostapd_freq_params *freq,
3115 int obss_scan) {
3116 int chan_idx;
3117 struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
3118 int i, res;
3119 unsigned int j;
3120 static const int ht40plus[] = {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003121 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
3122 149, 157, 165, 173, 184, 192
Sunil Ravi036cec52023-03-29 11:35:17 -07003123 };
3124 int ht40 = -1;
3125
3126 if (!freq->ht_enabled)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003127 return;
3128
3129 for (chan_idx = 0; chan_idx < mode->num_channels; chan_idx++) {
3130 pri_chan = &mode->channels[chan_idx];
Sunil Ravi036cec52023-03-29 11:35:17 -07003131 if (pri_chan->chan == freq->channel)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003132 break;
3133 pri_chan = NULL;
3134 }
3135 if (!pri_chan)
3136 return;
3137
3138 /* Check primary channel flags */
3139 if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
3140 return;
3141
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003142#ifdef CONFIG_HT_OVERRIDES
Sunil Ravi036cec52023-03-29 11:35:17 -07003143 if (ssid->disable_ht40)
3144 return;
3145#endif
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003146
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003147 /* Check/setup HT40+/HT40- */
3148 for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
Sunil Ravi036cec52023-03-29 11:35:17 -07003149 if (ht40plus[j] == freq->channel) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003150 ht40 = 1;
3151 break;
3152 }
3153 }
3154
3155 /* Find secondary channel */
3156 for (i = 0; i < mode->num_channels; i++) {
3157 sec_chan = &mode->channels[i];
Sunil Ravi036cec52023-03-29 11:35:17 -07003158 if (sec_chan->chan == freq->channel + ht40 * 4)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003159 break;
3160 sec_chan = NULL;
3161 }
3162 if (!sec_chan)
3163 return;
3164
3165 /* Check secondary channel flags */
3166 if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
3167 return;
3168
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003169 if (ht40 == -1) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003170 if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
3171 return;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003172 } else {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003173 if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
3174 return;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003175 }
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003176 freq->sec_channel_offset = ht40;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003177
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003178 if (obss_scan) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003179 struct wpa_scan_results *scan_res;
3180
Sunil Ravi99c035e2024-07-12 01:42:03 +00003181 scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0,
3182 NULL);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003183 if (scan_res == NULL) {
3184 /* Back to HT20 */
3185 freq->sec_channel_offset = 0;
3186 return;
3187 }
3188
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003189 res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003190 switch (res) {
3191 case 0:
3192 /* Back to HT20 */
3193 freq->sec_channel_offset = 0;
3194 break;
3195 case 1:
3196 /* Configuration allowed */
3197 break;
3198 case 2:
3199 /* Switch pri/sec channels */
3200 freq->freq = hw_get_freq(mode, sec_chan->chan);
3201 freq->sec_channel_offset = -freq->sec_channel_offset;
3202 freq->channel = sec_chan->chan;
3203 break;
3204 default:
3205 freq->sec_channel_offset = 0;
3206 break;
3207 }
3208
3209 wpa_scan_results_free(scan_res);
3210 }
3211
3212 wpa_printf(MSG_DEBUG,
3213 "IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
3214 freq->channel, freq->sec_channel_offset);
Sunil Ravi036cec52023-03-29 11:35:17 -07003215}
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003216
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003217
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003218static int ibss_get_center_320mhz(int channel)
3219{
3220 int seg0;
3221
3222 if (channel >= 1 && channel <= 45)
3223 seg0 = 31;
3224 else if (channel >= 49 && channel <= 77)
3225 seg0 = 63;
3226 else if (channel >= 81 && channel <= 109)
3227 seg0 = 95;
3228 else if (channel >= 113 && channel <= 141)
3229 seg0 = 127;
3230 else if (channel >= 145 && channel <= 173)
3231 seg0 = 159;
3232 else
3233 seg0 = 191;
3234
3235 return seg0;
3236}
3237
3238
Sunil Ravi036cec52023-03-29 11:35:17 -07003239static bool ibss_mesh_select_80_160mhz(struct wpa_supplicant *wpa_s,
3240 const struct wpa_ssid *ssid,
3241 struct hostapd_hw_modes *mode,
3242 struct hostapd_freq_params *freq,
3243 int ieee80211_mode, bool is_6ghz) {
3244 static const int bw80[] = {
3245 5180, 5260, 5500, 5580, 5660, 5745, 5825,
3246 5955, 6035, 6115, 6195, 6275, 6355, 6435,
3247 6515, 6595, 6675, 6755, 6835, 6915, 6995
3248 };
3249 static const int bw160[] = {
3250 5955, 6115, 6275, 6435, 6595, 6755, 6915
3251 };
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003252 static const int bw320[]= {
3253 5955, 6255, 6115, 6415, 6275, 6575, 6435,
3254 6735, 6595, 6895, 6755, 7055
3255 };
3256
Sunil Ravi036cec52023-03-29 11:35:17 -07003257 struct hostapd_freq_params vht_freq;
3258 int i;
3259 unsigned int j, k;
3260 int chwidth, seg0, seg1;
3261 u32 vht_caps = 0;
3262 u8 channel = freq->channel;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003263
Sunil Ravi036cec52023-03-29 11:35:17 -07003264 if (!freq->vht_enabled && !freq->he_enabled)
3265 return true;
Paul Stewart092955c2017-02-06 09:13:09 -08003266
Hai Shalomc1a21442022-02-04 13:43:00 -08003267 vht_freq = *freq;
3268
Sunil Ravi036cec52023-03-29 11:35:17 -07003269 chwidth = CONF_OPER_CHWIDTH_USE_HT;
3270 seg0 = freq->channel + 2 * freq->sec_channel_offset;
3271 seg1 = 0;
3272 if (freq->sec_channel_offset == 0) {
3273 seg0 = 0;
3274 /* Don't try 80 MHz if 40 MHz failed, except in 6 GHz */
3275 if (freq->ht_enabled && !is_6ghz)
3276 goto skip_80mhz;
3277 }
3278 if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
3279 goto skip_80mhz;
Hai Shalomc3565922019-10-28 11:58:20 -07003280
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003281 /* setup center_freq1, bandwidth */
Hai Shalomc1a21442022-02-04 13:43:00 -08003282 for (j = 0; j < ARRAY_SIZE(bw80); j++) {
3283 if (freq->freq >= bw80[j] &&
3284 freq->freq < bw80[j] + 80)
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003285 break;
3286 }
3287
Hai Shalomc1a21442022-02-04 13:43:00 -08003288 if (j == ARRAY_SIZE(bw80) ||
3289 ieee80211_freq_to_chan(bw80[j], &channel) == NUM_HOSTAPD_MODES)
Sunil Ravi036cec52023-03-29 11:35:17 -07003290 goto skip_80mhz;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003291
Sunil Ravi036cec52023-03-29 11:35:17 -07003292 /* Use 40 MHz if channel not usable */
Hai Shalomc1a21442022-02-04 13:43:00 -08003293 if (!ibss_mesh_is_80mhz_avail(channel, mode))
Sunil Ravi036cec52023-03-29 11:35:17 -07003294 goto skip_80mhz;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003295
Sunil8cd6f4d2022-06-28 18:40:46 +00003296 chwidth = CONF_OPER_CHWIDTH_80MHZ;
Hai Shalomc1a21442022-02-04 13:43:00 -08003297 seg0 = channel + 6;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003298 seg1 = 0;
3299
Sunil Ravi036cec52023-03-29 11:35:17 -07003300 /* In 160 MHz, the initial four 20 MHz channels were validated
3301 * above. If 160 MHz is supported, check the remaining four 20 MHz
3302 * channels for the total of 160 MHz bandwidth for 6 GHz.
3303 */
Hai Shalomc1a21442022-02-04 13:43:00 -08003304 if ((mode->he_capab[ieee80211_mode].phy_cap[
3305 HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
Sunil Ravi036cec52023-03-29 11:35:17 -07003306 HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G) && is_6ghz &&
3307 ibss_mesh_is_80mhz_avail(channel + 16, mode)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08003308 for (j = 0; j < ARRAY_SIZE(bw160); j++) {
3309 if (freq->freq == bw160[j]) {
Sunil8cd6f4d2022-06-28 18:40:46 +00003310 chwidth = CONF_OPER_CHWIDTH_160MHZ;
Hai Shalomc1a21442022-02-04 13:43:00 -08003311 seg0 = channel + 14;
3312 break;
3313 }
3314 }
3315 }
3316
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003317 /* In 320 MHz, the initial four 20 MHz channels were validated
3318 * above. If 320 MHz is supported, check the remaining 12 20 MHz
3319 * channels for the total of 320 MHz bandwidth for 6 GHz.
3320 */
3321 if ((mode->eht_capab[ieee80211_mode].phy_cap[
3322 EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
3323 EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK) && is_6ghz &&
3324 ibss_mesh_is_80mhz_avail(channel + 16, mode) &&
3325 ibss_mesh_is_80mhz_avail(channel + 32, mode) &&
3326 ibss_mesh_is_80mhz_avail(channel + 48, mode)) {
3327 for (j = 0; j < ARRAY_SIZE(bw320); j += 2) {
3328 if (freq->freq >= bw320[j] &&
3329 freq->freq <= bw320[j + 1]) {
3330 chwidth = CONF_OPER_CHWIDTH_320MHZ;
3331 seg0 = ibss_get_center_320mhz(freq->channel);
3332 break;
3333 }
3334 }
3335 }
3336
Sunil8cd6f4d2022-06-28 18:40:46 +00003337 if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003338 /* setup center_freq2, bandwidth */
Hai Shalomc1a21442022-02-04 13:43:00 -08003339 for (k = 0; k < ARRAY_SIZE(bw80); k++) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003340 /* Only accept 80 MHz segments separated by a gap */
Hai Shalomc1a21442022-02-04 13:43:00 -08003341 if (j == k || abs(bw80[j] - bw80[k]) == 80)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003342 continue;
Hai Shalomc1a21442022-02-04 13:43:00 -08003343
3344 if (ieee80211_freq_to_chan(bw80[k], &channel) ==
3345 NUM_HOSTAPD_MODES)
Sunil Ravi036cec52023-03-29 11:35:17 -07003346 break;
Hai Shalomc1a21442022-02-04 13:43:00 -08003347
3348 for (i = channel; i < channel + 16; i += 4) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003349 struct hostapd_channel_data *chan;
3350
3351 chan = hw_get_channel_chan(mode, i, NULL);
3352 if (!chan)
3353 continue;
3354
3355 if (chan->flag & (HOSTAPD_CHAN_DISABLED |
3356 HOSTAPD_CHAN_NO_IR |
3357 HOSTAPD_CHAN_RADAR))
3358 continue;
3359
3360 /* Found a suitable second segment for 80+80 */
Sunil8cd6f4d2022-06-28 18:40:46 +00003361 chwidth = CONF_OPER_CHWIDTH_80P80MHZ;
Hai Shalomc1a21442022-02-04 13:43:00 -08003362 if (!is_6ghz)
3363 vht_caps |=
3364 VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
3365 seg1 = channel + 6;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003366 }
3367
Sunil8cd6f4d2022-06-28 18:40:46 +00003368 if (chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003369 break;
3370 }
Sunil8cd6f4d2022-06-28 18:40:46 +00003371 } else if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003372 if (freq->freq == 5180) {
Sunil8cd6f4d2022-06-28 18:40:46 +00003373 chwidth = CONF_OPER_CHWIDTH_160MHZ;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003374 vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
3375 seg0 = 50;
3376 } else if (freq->freq == 5520) {
Sunil8cd6f4d2022-06-28 18:40:46 +00003377 chwidth = CONF_OPER_CHWIDTH_160MHZ;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003378 vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
3379 seg0 = 114;
3380 }
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003381 }
3382
Sunil Ravi036cec52023-03-29 11:35:17 -07003383skip_80mhz:
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003384 if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
Hai Shalomc3565922019-10-28 11:58:20 -07003385 freq->channel, ssid->enable_edmg,
3386 ssid->edmg_channel, freq->ht_enabled,
Sunil Ravi036cec52023-03-29 11:35:17 -07003387 freq->vht_enabled, freq->he_enabled,
3388 freq->eht_enabled,
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003389 freq->sec_channel_offset,
Hai Shalom81f62d82019-07-22 12:10:00 -07003390 chwidth, seg0, seg1, vht_caps,
Sunil Ravia04bd252022-05-02 22:54:18 -07003391 &mode->he_capab[ieee80211_mode],
Sunil Ravi99c035e2024-07-12 01:42:03 +00003392 &mode->eht_capab[ieee80211_mode], 0) != 0)
Sunil Ravi036cec52023-03-29 11:35:17 -07003393 return false;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003394
3395 *freq = vht_freq;
3396
3397 wpa_printf(MSG_DEBUG, "IBSS: VHT setup freq cf1 %d, cf2 %d, bw %d",
3398 freq->center_freq1, freq->center_freq2, freq->bandwidth);
Sunil Ravi036cec52023-03-29 11:35:17 -07003399 return true;
3400}
3401
3402
3403void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
3404 const struct wpa_ssid *ssid,
3405 struct hostapd_freq_params *freq)
3406{
3407 int ieee80211_mode = wpas_mode_to_ieee80211_mode(ssid->mode);
3408 enum hostapd_hw_mode hw_mode;
3409 struct hostapd_hw_modes *mode = NULL;
Sunil Ravi7f769292024-07-23 22:21:32 +00003410 int obss_scan = 1;
Sunil Ravi036cec52023-03-29 11:35:17 -07003411 u8 channel;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003412 bool is_6ghz, is_24ghz;
Sunil Ravi036cec52023-03-29 11:35:17 -07003413
3414 freq->freq = ssid->frequency;
3415
3416 if (ssid->mode == WPAS_MODE_IBSS && !ssid->fixed_freq) {
3417 struct wpa_bss *bss = ibss_find_existing_bss(wpa_s, ssid);
3418
3419 if (bss) {
3420 wpa_printf(MSG_DEBUG,
3421 "IBSS already found in scan results, adjust control freq: %d",
3422 bss->freq);
3423 freq->freq = bss->freq;
3424 obss_scan = 0;
3425 }
3426 }
3427
3428 hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
Sunil Ravi7f769292024-07-23 22:21:32 +00003429 mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
3430 hw_mode, is_6ghz_freq(ssid->frequency));
Sunil Ravi036cec52023-03-29 11:35:17 -07003431
3432 if (!mode)
3433 return;
3434
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003435 is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
3436 hw_mode == HOSTAPD_MODE_IEEE80211B;
3437
Sunil Ravi036cec52023-03-29 11:35:17 -07003438 is_6ghz = is_6ghz_freq(freq->freq);
3439
3440 freq->ht_enabled = 0;
3441 freq->vht_enabled = 0;
3442 freq->he_enabled = 0;
3443 freq->eht_enabled = 0;
3444
3445 if (!is_6ghz)
3446 freq->ht_enabled = ibss_mesh_can_use_ht(wpa_s, ssid, mode);
3447 if (freq->ht_enabled)
3448 freq->vht_enabled = ibss_mesh_can_use_vht(wpa_s, ssid, mode);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003449 if (freq->vht_enabled || (freq->ht_enabled && is_24ghz) || is_6ghz)
Sunil Ravi036cec52023-03-29 11:35:17 -07003450 freq->he_enabled = ibss_mesh_can_use_he(wpa_s, ssid, mode,
3451 ieee80211_mode);
3452 freq->channel = channel;
3453 /* Setup higher BW only for 5 GHz */
3454 if (mode->mode == HOSTAPD_MODE_IEEE80211A) {
3455 ibss_mesh_select_40mhz(wpa_s, ssid, mode, freq, obss_scan);
3456 if (!ibss_mesh_select_80_160mhz(wpa_s, ssid, mode, freq,
3457 ieee80211_mode, is_6ghz))
3458 freq->he_enabled = freq->vht_enabled = false;
3459 }
3460
3461 if (freq->he_enabled)
3462 freq->eht_enabled = ibss_mesh_can_use_eht(wpa_s, ssid, mode,
3463 ieee80211_mode);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003464}
3465
3466
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003467#ifdef CONFIG_FILS
3468static size_t wpas_add_fils_hlp_req(struct wpa_supplicant *wpa_s, u8 *ie_buf,
3469 size_t ie_buf_len)
3470{
3471 struct fils_hlp_req *req;
3472 size_t rem_len, hdr_len, hlp_len, len, ie_len = 0;
3473 const u8 *pos;
3474 u8 *buf = ie_buf;
3475
3476 dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
3477 list) {
3478 rem_len = ie_buf_len - ie_len;
3479 pos = wpabuf_head(req->pkt);
3480 hdr_len = 1 + 2 * ETH_ALEN + 6;
3481 hlp_len = wpabuf_len(req->pkt);
3482
3483 if (rem_len < 2 + hdr_len + hlp_len) {
3484 wpa_printf(MSG_ERROR,
3485 "FILS: Cannot fit HLP - rem_len=%lu to_fill=%lu",
3486 (unsigned long) rem_len,
3487 (unsigned long) (2 + hdr_len + hlp_len));
3488 break;
3489 }
3490
3491 len = (hdr_len + hlp_len) > 255 ? 255 : hdr_len + hlp_len;
3492 /* Element ID */
3493 *buf++ = WLAN_EID_EXTENSION;
3494 /* Length */
3495 *buf++ = len;
3496 /* Element ID Extension */
3497 *buf++ = WLAN_EID_EXT_FILS_HLP_CONTAINER;
3498 /* Destination MAC address */
3499 os_memcpy(buf, req->dst, ETH_ALEN);
3500 buf += ETH_ALEN;
3501 /* Source MAC address */
3502 os_memcpy(buf, wpa_s->own_addr, ETH_ALEN);
3503 buf += ETH_ALEN;
3504 /* LLC/SNAP Header */
3505 os_memcpy(buf, "\xaa\xaa\x03\x00\x00\x00", 6);
3506 buf += 6;
3507 /* HLP Packet */
3508 os_memcpy(buf, pos, len - hdr_len);
3509 buf += len - hdr_len;
3510 pos += len - hdr_len;
3511
3512 hlp_len -= len - hdr_len;
3513 ie_len += 2 + len;
3514 rem_len -= 2 + len;
3515
3516 while (hlp_len) {
3517 len = (hlp_len > 255) ? 255 : hlp_len;
3518 if (rem_len < 2 + len)
3519 break;
3520 *buf++ = WLAN_EID_FRAGMENT;
3521 *buf++ = len;
3522 os_memcpy(buf, pos, len);
3523 buf += len;
3524 pos += len;
3525
3526 hlp_len -= len;
3527 ie_len += 2 + len;
3528 rem_len -= 2 + len;
3529 }
3530 }
3531
3532 return ie_len;
3533}
Roshan Pius3a1667e2018-07-03 15:17:14 -07003534
3535
3536int wpa_is_fils_supported(struct wpa_supplicant *wpa_s)
3537{
3538 return (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
3539 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) ||
3540 (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
3541 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)));
3542}
3543
3544
3545int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s)
3546{
3547#ifdef CONFIG_FILS_SK_PFS
3548 return (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
3549 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS);
3550#else /* CONFIG_FILS_SK_PFS */
3551 return 0;
3552#endif /* CONFIG_FILS_SK_PFS */
3553}
3554
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003555#endif /* CONFIG_FILS */
3556
3557
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003558bool wpa_is_non_eht_scs_traffic_desc_supported(struct wpa_bss *bss)
3559{
3560 const u8 *wfa_capa;
3561
3562 if (!bss)
3563 return false;
3564
3565 /* Get WFA capability from Beacon or Probe Response frame elements */
3566 wfa_capa = wpa_bss_get_vendor_ie(bss, WFA_CAPA_IE_VENDOR_TYPE);
3567 if (!wfa_capa)
3568 wfa_capa = wpa_bss_get_vendor_ie_beacon(
3569 bss, WFA_CAPA_IE_VENDOR_TYPE);
3570
3571 if (!wfa_capa || wfa_capa[1] < 6 || wfa_capa[6] < 1 ||
3572 !(wfa_capa[7] & WFA_CAPA_QM_NON_EHT_SCS_TRAFFIC_DESC)) {
3573 /* AP does not enable QM non EHT traffic description policy */
3574 return false;
3575 }
3576
3577 return true;
3578}
3579
3580
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003581int wpas_populate_wfa_capa(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
3582 u8 *wpa_ie, size_t wpa_ie_len, size_t max_wpa_ie_len)
Hai Shalomc1a21442022-02-04 13:43:00 -08003583{
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003584 struct wpabuf *wfa_ie = NULL, *attr = NULL;
Hai Shalomc1a21442022-02-04 13:43:00 -08003585 u8 wfa_capa[1];
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003586 u8 capab_len = 0;
Hai Shalomc1a21442022-02-04 13:43:00 -08003587 size_t wfa_ie_len, buf_len;
3588
3589 os_memset(wfa_capa, 0, sizeof(wfa_capa));
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003590#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08003591 if (wpa_s->enable_dscp_policy_capa)
3592 wfa_capa[0] |= WFA_CAPA_QM_DSCP_POLICY;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003593#endif /* CONFIG_NO_ROBUST_AV */
Hai Shalomc1a21442022-02-04 13:43:00 -08003594
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003595 if (wpa_is_non_eht_scs_traffic_desc_supported(bss))
3596 wfa_capa[0] |= WFA_CAPA_QM_NON_EHT_SCS_TRAFFIC_DESC;
3597
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003598 if (wfa_capa[0])
3599 capab_len = 1;
3600
3601 if (wpa_s->conf->wfa_gen_capa == WFA_GEN_CAPA_UNPROTECTED)
3602 attr = wpas_wfa_gen_capab_attr(wpa_s);
3603
3604 if (capab_len == 0 && !attr)
Hai Shalomc1a21442022-02-04 13:43:00 -08003605 return wpa_ie_len;
3606
3607 /* Wi-Fi Alliance element */
3608 buf_len = 1 + /* Element ID */
3609 1 + /* Length */
3610 3 + /* OUI */
3611 1 + /* OUI Type */
3612 1 + /* Capabilities Length */
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003613 capab_len + /* Capabilities */
3614 (attr ? wpabuf_len(attr) : 0) /* Attributes */;
Hai Shalomc1a21442022-02-04 13:43:00 -08003615 wfa_ie = wpabuf_alloc(buf_len);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003616 if (!wfa_ie) {
3617 wpabuf_free(attr);
Hai Shalomc1a21442022-02-04 13:43:00 -08003618 return wpa_ie_len;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003619 }
Hai Shalomc1a21442022-02-04 13:43:00 -08003620
3621 wpabuf_put_u8(wfa_ie, WLAN_EID_VENDOR_SPECIFIC);
3622 wpabuf_put_u8(wfa_ie, buf_len - 2);
3623 wpabuf_put_be24(wfa_ie, OUI_WFA);
3624 wpabuf_put_u8(wfa_ie, WFA_CAPA_OUI_TYPE);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003625 wpabuf_put_u8(wfa_ie, capab_len);
3626 wpabuf_put_data(wfa_ie, wfa_capa, capab_len);
3627 if (attr)
3628 wpabuf_put_buf(wfa_ie, attr);
3629 wpabuf_free(attr);
Hai Shalomc1a21442022-02-04 13:43:00 -08003630
3631 wfa_ie_len = wpabuf_len(wfa_ie);
3632 if (wpa_ie_len + wfa_ie_len <= max_wpa_ie_len) {
3633 wpa_hexdump_buf(MSG_MSGDUMP, "WFA Capabilities element",
3634 wfa_ie);
3635 os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(wfa_ie),
3636 wfa_ie_len);
3637 wpa_ie_len += wfa_ie_len;
3638 }
3639
3640 wpabuf_free(wfa_ie);
3641 return wpa_ie_len;
3642}
3643
3644
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003645static u8 * wpas_populate_assoc_ies(
3646 struct wpa_supplicant *wpa_s,
3647 struct wpa_bss *bss, struct wpa_ssid *ssid,
3648 struct wpa_driver_associate_params *params,
3649 enum wpa_drv_update_connect_params_mask *mask)
3650{
3651 u8 *wpa_ie;
3652 size_t max_wpa_ie_len = 500;
3653 size_t wpa_ie_len;
3654 int algs = WPA_AUTH_ALG_OPEN;
Hai Shalomce48b4a2018-09-05 11:41:35 -07003655#ifdef CONFIG_MBO
3656 const u8 *mbo_ie;
3657#endif
Vinita S. Maloofb3a4442020-05-19 17:43:22 +05303658#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
3659 int pmksa_cached = 0;
3660#endif /* CONFIG_SAE || CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003661#ifdef CONFIG_FILS
3662 const u8 *realm, *username, *rrk;
3663 size_t realm_len, username_len, rrk_len;
3664 u16 next_seq_num;
3665 struct fils_hlp_req *req;
3666
3667 dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
3668 list) {
3669 max_wpa_ie_len += 3 + 2 * ETH_ALEN + 6 + wpabuf_len(req->pkt) +
3670 2 + 2 * wpabuf_len(req->pkt) / 255;
3671 }
3672#endif /* CONFIG_FILS */
3673
3674 wpa_ie = os_malloc(max_wpa_ie_len);
3675 if (!wpa_ie) {
3676 wpa_printf(MSG_ERROR,
3677 "Failed to allocate connect IE buffer for %lu bytes",
3678 (unsigned long) max_wpa_ie_len);
3679 return NULL;
3680 }
3681
3682 if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
Sunil Ravi7f769292024-07-23 22:21:32 +00003683 wpa_bss_get_rsne(wpa_s, bss, ssid, false)) &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003684 wpa_key_mgmt_wpa(ssid->key_mgmt)) {
3685 int try_opportunistic;
3686 const u8 *cache_id = NULL;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003687 const u8 *addr = bss->bssid;
3688
Sunil Ravi036cec52023-03-29 11:35:17 -07003689 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
3690 (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) &&
3691 !is_zero_ether_addr(bss->mld_addr))
3692 addr = bss->mld_addr;
3693
3694 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
3695 wpa_s->valid_links)
Sunil Ravi77d572f2023-01-17 23:58:31 +00003696 addr = wpa_s->ap_mld_addr;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003697
3698 try_opportunistic = (ssid->proactive_key_caching < 0 ?
3699 wpa_s->conf->okc :
3700 ssid->proactive_key_caching) &&
3701 (ssid->proto & WPA_PROTO_RSN);
3702#ifdef CONFIG_FILS
3703 if (wpa_key_mgmt_fils(ssid->key_mgmt))
3704 cache_id = wpa_bss_get_fils_cache_id(bss);
3705#endif /* CONFIG_FILS */
Sunil Ravi77d572f2023-01-17 23:58:31 +00003706 if (pmksa_cache_set_current(wpa_s->wpa, NULL, addr,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003707 ssid, try_opportunistic,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003708 cache_id, 0, false) == 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003709 eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
Vinita S. Maloofb3a4442020-05-19 17:43:22 +05303710#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
3711 pmksa_cached = 1;
3712#endif /* CONFIG_SAE || CONFIG_FILS */
Hai Shalom5f92bc92019-04-18 11:54:11 -07003713 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003714 wpa_ie_len = max_wpa_ie_len;
3715 if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
Sunil Ravi77d572f2023-01-17 23:58:31 +00003716 wpa_ie, &wpa_ie_len, false)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003717 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
3718 "key management and encryption suites");
3719 os_free(wpa_ie);
3720 return NULL;
3721 }
3722 } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
3723 wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
3724 /*
3725 * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
3726 * use non-WPA since the scan results did not indicate that the
3727 * AP is using WPA or WPA2.
3728 */
3729 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
3730 wpa_ie_len = 0;
3731 wpa_s->wpa_proto = 0;
3732 } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
3733 wpa_ie_len = max_wpa_ie_len;
3734 if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
Sunil Ravi77d572f2023-01-17 23:58:31 +00003735 wpa_ie, &wpa_ie_len, false)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003736 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
3737 "key management and encryption suites (no "
3738 "scan results)");
3739 os_free(wpa_ie);
3740 return NULL;
3741 }
3742#ifdef CONFIG_WPS
3743 } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
3744 struct wpabuf *wps_ie;
3745 wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
3746 if (wps_ie && wpabuf_len(wps_ie) <= max_wpa_ie_len) {
3747 wpa_ie_len = wpabuf_len(wps_ie);
3748 os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
3749 } else
3750 wpa_ie_len = 0;
3751 wpabuf_free(wps_ie);
3752 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
3753 if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY))
3754 params->wps = WPS_MODE_PRIVACY;
3755 else
3756 params->wps = WPS_MODE_OPEN;
3757 wpa_s->wpa_proto = 0;
3758#endif /* CONFIG_WPS */
3759 } else {
3760 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
3761 wpa_ie_len = 0;
3762 wpa_s->wpa_proto = 0;
3763 }
3764
3765#ifdef IEEE8021X_EAPOL
3766 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
3767 if (ssid->leap) {
3768 if (ssid->non_leap == 0)
3769 algs = WPA_AUTH_ALG_LEAP;
3770 else
3771 algs |= WPA_AUTH_ALG_LEAP;
3772 }
3773 }
3774
3775#ifdef CONFIG_FILS
3776 /* Clear FILS association */
3777 wpa_sm_set_reset_fils_completed(wpa_s->wpa, 0);
3778
3779 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
3780 ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
3781 eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, &username,
3782 &username_len, &realm, &realm_len,
Hai Shalomce48b4a2018-09-05 11:41:35 -07003783 &next_seq_num, &rrk, &rrk_len) == 0 &&
3784 (!wpa_s->last_con_fail_realm ||
3785 wpa_s->last_con_fail_realm_len != realm_len ||
3786 os_memcmp(wpa_s->last_con_fail_realm, realm, realm_len) != 0)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003787 algs = WPA_AUTH_ALG_FILS;
3788 params->fils_erp_username = username;
3789 params->fils_erp_username_len = username_len;
3790 params->fils_erp_realm = realm;
3791 params->fils_erp_realm_len = realm_len;
3792 params->fils_erp_next_seq_num = next_seq_num;
3793 params->fils_erp_rrk = rrk;
3794 params->fils_erp_rrk_len = rrk_len;
3795
3796 if (mask)
3797 *mask |= WPA_DRV_UPDATE_FILS_ERP_INFO;
Vinita S. Maloofb3a4442020-05-19 17:43:22 +05303798 } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
3799 ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
3800 pmksa_cached) {
3801 algs = WPA_AUTH_ALG_FILS;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003802 }
3803#endif /* CONFIG_FILS */
3804#endif /* IEEE8021X_EAPOL */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003805#ifdef CONFIG_SAE
Sunil Ravi89eba102022-09-13 21:04:37 -07003806 if (wpa_key_mgmt_sae(wpa_s->key_mgmt))
Roshan Pius3a1667e2018-07-03 15:17:14 -07003807 algs = WPA_AUTH_ALG_SAE;
3808#endif /* CONFIG_SAE */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003809
3810 wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
3811 if (ssid->auth_alg) {
3812 algs = ssid->auth_alg;
3813 wpa_dbg(wpa_s, MSG_DEBUG,
3814 "Overriding auth_alg selection: 0x%x", algs);
3815 }
3816
Hai Shalom5f92bc92019-04-18 11:54:11 -07003817#ifdef CONFIG_SAE
Vinita S. Maloofb3a4442020-05-19 17:43:22 +05303818 if (pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
Hai Shalom5f92bc92019-04-18 11:54:11 -07003819 wpa_dbg(wpa_s, MSG_DEBUG,
3820 "SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt");
3821 algs = WPA_AUTH_ALG_OPEN;
3822 }
3823#endif /* CONFIG_SAE */
3824
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003825#ifdef CONFIG_P2P
3826 if (wpa_s->global->p2p) {
3827 u8 *pos;
3828 size_t len;
3829 int res;
3830 pos = wpa_ie + wpa_ie_len;
3831 len = max_wpa_ie_len - wpa_ie_len;
3832 res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
3833 ssid->p2p_group);
3834 if (res >= 0)
3835 wpa_ie_len += res;
3836 }
3837
3838 wpa_s->cross_connect_disallowed = 0;
3839 if (bss) {
3840 struct wpabuf *p2p;
3841 p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
3842 if (p2p) {
3843 wpa_s->cross_connect_disallowed =
3844 p2p_get_cross_connect_disallowed(p2p);
3845 wpabuf_free(p2p);
3846 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: WLAN AP %s cross "
3847 "connection",
3848 wpa_s->cross_connect_disallowed ?
3849 "disallows" : "allows");
3850 }
3851 }
3852
3853 os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
3854#endif /* CONFIG_P2P */
3855
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003856#ifndef CONFIG_NO_RRM
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003857 if (bss) {
Hai Shalomfdcde762020-04-02 11:19:20 -07003858 wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003859 wpa_ie + wpa_ie_len,
3860 max_wpa_ie_len -
3861 wpa_ie_len);
3862 }
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003863#endif /* CONFIG_NO_RRM */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003864
3865 /*
3866 * Workaround: Add Extended Capabilities element only if the AP
3867 * included this element in Beacon/Probe Response frames. Some older
3868 * APs seem to have interoperability issues if this element is
3869 * included, so while the standard may require us to include the
3870 * element in all cases, it is justifiable to skip it to avoid
3871 * interoperability issues.
3872 */
3873 if (ssid->p2p_group)
3874 wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
3875 else
3876 wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
3877
3878 if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
3879 u8 ext_capab[18];
3880 int ext_capab_len;
3881 ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003882 sizeof(ext_capab), bss);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003883 if (ext_capab_len > 0 &&
3884 wpa_ie_len + ext_capab_len <= max_wpa_ie_len) {
3885 u8 *pos = wpa_ie;
3886 if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
3887 pos += 2 + pos[1];
3888 os_memmove(pos + ext_capab_len, pos,
3889 wpa_ie_len - (pos - wpa_ie));
3890 wpa_ie_len += ext_capab_len;
3891 os_memcpy(pos, ext_capab, ext_capab_len);
3892 }
3893 }
3894
Sunil Ravi7f769292024-07-23 22:21:32 +00003895 if (ssid->max_idle && wpa_ie_len + 5 <= max_wpa_ie_len) {
3896 u8 *pos = wpa_ie;
3897
3898 *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
3899 *pos++ = 3;
3900 WPA_PUT_LE16(pos, ssid->max_idle);
3901 pos += 2;
3902 *pos = 0; /* Idle Options */
3903 wpa_ie_len += 5;
3904 }
3905
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003906#ifdef CONFIG_HS20
Hai Shalomcded4e22022-01-28 15:29:52 -08003907 if (is_hs20_network(wpa_s, ssid, bss)
3908#ifndef ANDROID /* Android does not use the native HS 2.0 config */
3909 && is_hs20_config(wpa_s)
3910#endif /* ANDROID */
3911 ) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003912 struct wpabuf *hs20;
3913
Roshan Pius3a1667e2018-07-03 15:17:14 -07003914 hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003915 if (hs20) {
3916 int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
3917 size_t len;
3918
Hai Shalom74f70d42019-02-11 14:42:39 -08003919 wpas_hs20_add_indication(hs20, pps_mo_id,
3920 get_hs20_version(bss));
Roshan Pius3a1667e2018-07-03 15:17:14 -07003921 wpas_hs20_add_roam_cons_sel(hs20, ssid);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003922 len = max_wpa_ie_len - wpa_ie_len;
3923 if (wpabuf_len(hs20) <= len) {
3924 os_memcpy(wpa_ie + wpa_ie_len,
3925 wpabuf_head(hs20), wpabuf_len(hs20));
3926 wpa_ie_len += wpabuf_len(hs20);
3927 }
3928 wpabuf_free(hs20);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003929 }
3930 }
Hai Shalom2cbbcd12021-03-08 18:33:38 -08003931 hs20_configure_frame_filters(wpa_s);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003932#endif /* CONFIG_HS20 */
3933
3934 if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
3935 struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
3936 size_t len;
3937
3938 len = max_wpa_ie_len - wpa_ie_len;
3939 if (wpabuf_len(buf) <= len) {
3940 os_memcpy(wpa_ie + wpa_ie_len,
3941 wpabuf_head(buf), wpabuf_len(buf));
3942 wpa_ie_len += wpabuf_len(buf);
3943 }
3944 }
3945
3946#ifdef CONFIG_FST
3947 if (wpa_s->fst_ies) {
3948 int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
3949
3950 if (wpa_ie_len + fst_ies_len <= max_wpa_ie_len) {
3951 os_memcpy(wpa_ie + wpa_ie_len,
3952 wpabuf_head(wpa_s->fst_ies), fst_ies_len);
3953 wpa_ie_len += fst_ies_len;
3954 }
3955 }
3956#endif /* CONFIG_FST */
3957
3958#ifdef CONFIG_MBO
Hai Shalomce48b4a2018-09-05 11:41:35 -07003959 mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
Hai Shalomc3565922019-10-28 11:58:20 -07003960 if (!wpa_s->disable_mbo_oce && mbo_ie) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003961 int len;
3962
3963 len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
Hai Shalomce48b4a2018-09-05 11:41:35 -07003964 max_wpa_ie_len - wpa_ie_len,
3965 !!mbo_attr_from_mbo_ie(mbo_ie,
3966 OCE_ATTR_ID_CAPA_IND));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003967 if (len >= 0)
3968 wpa_ie_len += len;
3969 }
3970#endif /* CONFIG_MBO */
3971
3972#ifdef CONFIG_FILS
3973 if (algs == WPA_AUTH_ALG_FILS) {
3974 size_t len;
3975
3976 len = wpas_add_fils_hlp_req(wpa_s, wpa_ie + wpa_ie_len,
3977 max_wpa_ie_len - wpa_ie_len);
3978 wpa_ie_len += len;
3979 }
3980#endif /* CONFIG_FILS */
3981
3982#ifdef CONFIG_OWE
Roshan Pius3a1667e2018-07-03 15:17:14 -07003983#ifdef CONFIG_TESTING_OPTIONS
3984 if (get_ie_ext(wpa_ie, wpa_ie_len, WLAN_EID_EXT_OWE_DH_PARAM)) {
3985 wpa_printf(MSG_INFO, "TESTING: Override OWE DH element");
3986 } else
3987#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003988 if (algs == WPA_AUTH_ALG_OPEN &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003989 ssid->key_mgmt == WPA_KEY_MGMT_OWE &&
3990 !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OWE_OFFLOAD_STA)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003991 struct wpabuf *owe_ie;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003992 u16 group;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003993
Roshan Pius3a1667e2018-07-03 15:17:14 -07003994 if (ssid->owe_group) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003995 group = ssid->owe_group;
Hai Shalom74f70d42019-02-11 14:42:39 -08003996 } else if (wpa_s->assoc_status_code ==
3997 WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003998 if (wpa_s->last_owe_group == 19)
3999 group = 20;
4000 else if (wpa_s->last_owe_group == 20)
4001 group = 21;
4002 else
4003 group = OWE_DH_GROUP;
Hai Shalom74f70d42019-02-11 14:42:39 -08004004 } else {
4005 group = OWE_DH_GROUP;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004006 }
Hai Shalom74f70d42019-02-11 14:42:39 -08004007
Roshan Pius3a1667e2018-07-03 15:17:14 -07004008 wpa_s->last_owe_group = group;
4009 wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004010 owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
4011 if (owe_ie &&
4012 wpabuf_len(owe_ie) <= max_wpa_ie_len - wpa_ie_len) {
4013 os_memcpy(wpa_ie + wpa_ie_len,
4014 wpabuf_head(owe_ie), wpabuf_len(owe_ie));
4015 wpa_ie_len += wpabuf_len(owe_ie);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004016 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004017 wpabuf_free(owe_ie);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004018 }
4019#endif /* CONFIG_OWE */
4020
Hai Shalom021b0b52019-04-10 11:17:58 -07004021#ifdef CONFIG_DPP2
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004022 if (DPP_VERSION > 1 &&
4023 wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
Hai Shalomfdcde762020-04-02 11:19:20 -07004024 ssid->dpp_netaccesskey &&
4025 ssid->dpp_pfs != 2 && !ssid->dpp_pfs_fallback) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004026 struct rsn_pmksa_cache_entry *pmksa;
4027
4028 pmksa = pmksa_cache_get_current(wpa_s->wpa);
4029 if (!pmksa || !pmksa->dpp_pfs)
4030 goto pfs_fail;
4031
Hai Shalom021b0b52019-04-10 11:17:58 -07004032 dpp_pfs_free(wpa_s->dpp_pfs);
4033 wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
4034 ssid->dpp_netaccesskey_len);
4035 if (!wpa_s->dpp_pfs) {
4036 wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS");
4037 /* Try to continue without PFS */
4038 goto pfs_fail;
4039 }
4040 if (wpabuf_len(wpa_s->dpp_pfs->ie) <=
4041 max_wpa_ie_len - wpa_ie_len) {
4042 os_memcpy(wpa_ie + wpa_ie_len,
4043 wpabuf_head(wpa_s->dpp_pfs->ie),
4044 wpabuf_len(wpa_s->dpp_pfs->ie));
4045 wpa_ie_len += wpabuf_len(wpa_s->dpp_pfs->ie);
4046 }
4047 }
4048pfs_fail:
4049#endif /* CONFIG_DPP2 */
4050
Roshan Pius3a1667e2018-07-03 15:17:14 -07004051#ifdef CONFIG_IEEE80211R
4052 /*
4053 * Add MDIE under these conditions: the network profile allows FT,
4054 * the AP supports FT, and the mobility domain ID matches.
4055 */
4056 if (bss && wpa_key_mgmt_ft(wpa_sm_get_key_mgmt(wpa_s->wpa))) {
4057 const u8 *mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
4058
4059 if (mdie && mdie[1] >= MOBILITY_DOMAIN_ID_LEN) {
4060 size_t len = 0;
4061 const u8 *md = mdie + 2;
4062 const u8 *wpa_md = wpa_sm_get_ft_md(wpa_s->wpa);
4063
4064 if (os_memcmp(md, wpa_md,
4065 MOBILITY_DOMAIN_ID_LEN) == 0) {
4066 /* Add mobility domain IE */
4067 len = wpa_ft_add_mdie(
4068 wpa_s->wpa, wpa_ie + wpa_ie_len,
4069 max_wpa_ie_len - wpa_ie_len, mdie);
4070 wpa_ie_len += len;
4071 }
4072#ifdef CONFIG_SME
4073 if (len > 0 && wpa_s->sme.ft_used &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00004074 wpa_sm_has_ft_keys(wpa_s->wpa, md)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004075 wpa_dbg(wpa_s, MSG_DEBUG,
4076 "SME: Trying to use FT over-the-air");
4077 algs |= WPA_AUTH_ALG_FT;
4078 }
4079#endif /* CONFIG_SME */
4080 }
4081 }
4082#endif /* CONFIG_IEEE80211R */
4083
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004084#ifdef CONFIG_TESTING_OPTIONS
4085 if (wpa_s->rsnxe_override_assoc &&
4086 wpabuf_len(wpa_s->rsnxe_override_assoc) <=
4087 max_wpa_ie_len - wpa_ie_len) {
4088 wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
4089 os_memcpy(wpa_ie + wpa_ie_len,
4090 wpabuf_head(wpa_s->rsnxe_override_assoc),
4091 wpabuf_len(wpa_s->rsnxe_override_assoc));
4092 wpa_ie_len += wpabuf_len(wpa_s->rsnxe_override_assoc);
4093 } else
4094#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomc3565922019-10-28 11:58:20 -07004095 if (wpa_s->rsnxe_len > 0 &&
4096 wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
4097 os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
4098 wpa_ie_len += wpa_s->rsnxe_len;
4099 }
4100
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004101#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08004102#ifdef CONFIG_TESTING_OPTIONS
4103 if (wpa_s->disable_mscs_support)
4104 goto mscs_end;
4105#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalom60840252021-02-19 19:02:11 -08004106 if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS) &&
4107 wpa_s->robust_av.valid_config) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004108 struct wpabuf *mscs_ie;
4109 size_t mscs_ie_len, buf_len;
4110
Hai Shalom899fcc72020-10-19 14:38:18 -07004111 buf_len = 3 + /* MSCS descriptor IE header */
4112 1 + /* Request type */
4113 2 + /* User priority control */
4114 4 + /* Stream timeout */
4115 3 + /* TCLAS Mask IE header */
4116 wpa_s->robust_av.frame_classifier_len;
4117 mscs_ie = wpabuf_alloc(buf_len);
4118 if (!mscs_ie) {
4119 wpa_printf(MSG_INFO,
4120 "MSCS: Failed to allocate MSCS IE");
Hai Shalomc1a21442022-02-04 13:43:00 -08004121 goto mscs_end;
Hai Shalom899fcc72020-10-19 14:38:18 -07004122 }
4123
4124 wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
4125 if ((wpa_ie_len + wpabuf_len(mscs_ie)) <= max_wpa_ie_len) {
4126 wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE", mscs_ie);
4127 mscs_ie_len = wpabuf_len(mscs_ie);
4128 os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(mscs_ie),
4129 mscs_ie_len);
4130 wpa_ie_len += mscs_ie_len;
4131 }
4132
4133 wpabuf_free(mscs_ie);
4134 }
Hai Shalomc1a21442022-02-04 13:43:00 -08004135mscs_end:
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004136#endif /* CONFIG_NO_ROBUST_AV */
Hai Shalomc1a21442022-02-04 13:43:00 -08004137
4138 wpa_ie_len = wpas_populate_wfa_capa(wpa_s, bss, wpa_ie, wpa_ie_len,
4139 max_wpa_ie_len);
Hai Shalom899fcc72020-10-19 14:38:18 -07004140
Hai Shalom74f70d42019-02-11 14:42:39 -08004141 if (ssid->multi_ap_backhaul_sta) {
4142 size_t multi_ap_ie_len;
Sunil Ravi99c035e2024-07-12 01:42:03 +00004143 struct multi_ap_params multi_ap = { 0 };
4144
4145 multi_ap.capability = MULTI_AP_BACKHAUL_STA;
4146 multi_ap.profile = ssid->multi_ap_profile;
Hai Shalom74f70d42019-02-11 14:42:39 -08004147
4148 multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len,
4149 max_wpa_ie_len - wpa_ie_len,
Sunil Ravi99c035e2024-07-12 01:42:03 +00004150 &multi_ap);
Hai Shalom74f70d42019-02-11 14:42:39 -08004151 if (multi_ap_ie_len == 0) {
4152 wpa_printf(MSG_ERROR,
4153 "Multi-AP: Failed to build Multi-AP IE");
4154 os_free(wpa_ie);
4155 return NULL;
4156 }
4157 wpa_ie_len += multi_ap_ie_len;
4158 }
4159
Sunil Ravic0f5d412024-09-11 22:12:49 +00004160 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE_SUPPORT,
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00004161 wpas_rsn_overriding(wpa_s, ssid));
Sunil Ravic0f5d412024-09-11 22:12:49 +00004162 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
4163 RSN_OVERRIDE_NOT_USED);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00004164 if (wpas_rsn_overriding(wpa_s, ssid) &&
Sunil Ravi7f769292024-07-23 22:21:32 +00004165 wpas_ap_supports_rsn_overriding(wpa_s, bss) &&
Sunil Ravic0f5d412024-09-11 22:12:49 +00004166 wpa_ie_len + 2 + 4 + 1 <= max_wpa_ie_len) {
4167 u8 *pos = wpa_ie + wpa_ie_len, *start = pos;
Sunil Ravi7f769292024-07-23 22:21:32 +00004168 const u8 *ie;
Sunil Ravic0f5d412024-09-11 22:12:49 +00004169 enum rsn_selection_variant variant = RSN_SELECTION_RSNE;
Sunil Ravi7f769292024-07-23 22:21:32 +00004170
Sunil Ravic0f5d412024-09-11 22:12:49 +00004171 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
4172 RSN_OVERRIDE_RSNE);
Sunil Ravi7f769292024-07-23 22:21:32 +00004173 ie = wpa_bss_get_rsne(wpa_s, bss, ssid, wpa_s->valid_links);
Sunil Ravic0f5d412024-09-11 22:12:49 +00004174 if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4) {
4175 u32 type;
4176
Sunil Ravi7f769292024-07-23 22:21:32 +00004177 type = WPA_GET_BE32(&ie[2]);
Sunil Ravic0f5d412024-09-11 22:12:49 +00004178 if (type == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
4179 variant = RSN_SELECTION_RSNE_OVERRIDE;
4180 wpa_sm_set_param(wpa_s->wpa,
4181 WPA_PARAM_RSN_OVERRIDE,
4182 RSN_OVERRIDE_RSNE_OVERRIDE);
4183 } else if (type == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
4184 variant = RSN_SELECTION_RSNE_OVERRIDE_2;
4185 wpa_sm_set_param(wpa_s->wpa,
4186 WPA_PARAM_RSN_OVERRIDE,
4187 RSN_OVERRIDE_RSNE_OVERRIDE_2);
4188 }
Sunil Ravi7f769292024-07-23 22:21:32 +00004189 }
Sunil Ravic0f5d412024-09-11 22:12:49 +00004190
4191 /* Indicate which RSNE variant was used */
4192 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
4193 *pos++ = 4 + 1;
4194 WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
4195 pos += 4;
4196 *pos++ = variant;
4197 wpa_hexdump(MSG_MSGDUMP, "RSN Selection", start, pos - start);
4198 wpa_ie_len += pos - start;
Sunil Ravi7f769292024-07-23 22:21:32 +00004199 }
4200
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00004201 params->rsn_overriding = wpas_rsn_overriding(wpa_s, ssid);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004202 params->wpa_ie = wpa_ie;
4203 params->wpa_ie_len = wpa_ie_len;
4204 params->auth_alg = algs;
4205 if (mask)
4206 *mask |= WPA_DRV_UPDATE_ASSOC_IES | WPA_DRV_UPDATE_AUTH_TYPE;
4207
4208 return wpa_ie;
4209}
4210
4211
Hai Shalomc3565922019-10-28 11:58:20 -07004212#ifdef CONFIG_OWE
4213static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s)
4214{
4215 struct wpa_driver_associate_params params;
4216 u8 *wpa_ie;
4217
4218 os_memset(&params, 0, sizeof(params));
4219 wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
4220 wpa_s->current_ssid, &params, NULL);
4221 if (!wpa_ie)
4222 return;
4223
4224 wpa_drv_update_connect_params(wpa_s, &params, WPA_DRV_UPDATE_ASSOC_IES);
4225 os_free(wpa_ie);
4226}
4227#endif /* CONFIG_OWE */
4228
4229
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004230#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
4231static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
4232{
4233 struct wpa_driver_associate_params params;
4234 enum wpa_drv_update_connect_params_mask mask = 0;
4235 u8 *wpa_ie;
4236
4237 if (wpa_s->auth_alg != WPA_AUTH_ALG_OPEN)
4238 return; /* nothing to do */
4239
4240 os_memset(&params, 0, sizeof(params));
4241 wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
4242 wpa_s->current_ssid, &params, &mask);
4243 if (!wpa_ie)
4244 return;
4245
Hai Shalomc1a21442022-02-04 13:43:00 -08004246 if (params.auth_alg == WPA_AUTH_ALG_FILS) {
4247 wpa_s->auth_alg = params.auth_alg;
4248 wpa_drv_update_connect_params(wpa_s, &params, mask);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004249 }
4250
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004251 os_free(wpa_ie);
4252}
4253#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
4254
4255
Hai Shalomc3565922019-10-28 11:58:20 -07004256static u8 wpa_ie_get_edmg_oper_chans(const u8 *edmg_ie)
4257{
4258 if (!edmg_ie || edmg_ie[1] < 6)
4259 return 0;
4260 return edmg_ie[EDMG_BSS_OPERATING_CHANNELS_OFFSET];
4261}
4262
4263
4264static u8 wpa_ie_get_edmg_oper_chan_width(const u8 *edmg_ie)
4265{
4266 if (!edmg_ie || edmg_ie[1] < 6)
4267 return 0;
4268 return edmg_ie[EDMG_OPERATING_CHANNEL_WIDTH_OFFSET];
4269}
4270
4271
4272/* Returns the intersection of two EDMG configurations.
4273 * Note: The current implementation is limited to CB2 only (CB1 included),
4274 * i.e., the implementation supports up to 2 contiguous channels.
4275 * For supporting non-contiguous (aggregated) channels and for supporting
4276 * CB3 and above, this function will need to be extended.
4277 */
4278static struct ieee80211_edmg_config
4279get_edmg_intersection(struct ieee80211_edmg_config a,
4280 struct ieee80211_edmg_config b,
4281 u8 primary_channel)
4282{
4283 struct ieee80211_edmg_config result;
4284 int i, contiguous = 0;
4285 int max_contiguous = 0;
4286
4287 result.channels = b.channels & a.channels;
4288 if (!result.channels) {
4289 wpa_printf(MSG_DEBUG,
4290 "EDMG not possible: cannot intersect channels 0x%x and 0x%x",
4291 a.channels, b.channels);
4292 goto fail;
4293 }
4294
4295 if (!(result.channels & BIT(primary_channel - 1))) {
4296 wpa_printf(MSG_DEBUG,
4297 "EDMG not possible: the primary channel %d is not one of the intersected channels 0x%x",
4298 primary_channel, result.channels);
4299 goto fail;
4300 }
4301
4302 /* Find max contiguous channels */
4303 for (i = 0; i < 6; i++) {
4304 if (result.channels & BIT(i))
4305 contiguous++;
4306 else
4307 contiguous = 0;
4308
4309 if (contiguous > max_contiguous)
4310 max_contiguous = contiguous;
4311 }
4312
4313 /* Assuming AP and STA supports ONLY contiguous channels,
4314 * bw configuration can have value between 4-7.
4315 */
4316 if ((b.bw_config < a.bw_config))
4317 result.bw_config = b.bw_config;
4318 else
4319 result.bw_config = a.bw_config;
4320
4321 if ((max_contiguous >= 2 && result.bw_config < EDMG_BW_CONFIG_5) ||
4322 (max_contiguous >= 1 && result.bw_config < EDMG_BW_CONFIG_4)) {
4323 wpa_printf(MSG_DEBUG,
4324 "EDMG not possible: not enough contiguous channels %d for supporting CB1 or CB2",
4325 max_contiguous);
4326 goto fail;
4327 }
4328
4329 return result;
4330
4331fail:
4332 result.channels = 0;
4333 result.bw_config = 0;
4334 return result;
4335}
4336
4337
4338static struct ieee80211_edmg_config
4339get_supported_edmg(struct wpa_supplicant *wpa_s,
4340 struct hostapd_freq_params *freq,
4341 struct ieee80211_edmg_config request_edmg)
4342{
4343 enum hostapd_hw_mode hw_mode;
4344 struct hostapd_hw_modes *mode = NULL;
4345 u8 primary_channel;
4346
4347 if (!wpa_s->hw.modes)
4348 goto fail;
4349
4350 hw_mode = ieee80211_freq_to_chan(freq->freq, &primary_channel);
4351 if (hw_mode == NUM_HOSTAPD_MODES)
4352 goto fail;
4353
Hai Shalom60840252021-02-19 19:02:11 -08004354 mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, false);
Hai Shalomc3565922019-10-28 11:58:20 -07004355 if (!mode)
4356 goto fail;
4357
4358 return get_edmg_intersection(mode->edmg, request_edmg, primary_channel);
4359
4360fail:
4361 request_edmg.channels = 0;
4362 request_edmg.bw_config = 0;
4363 return request_edmg;
4364}
4365
4366
Hai Shalom021b0b52019-04-10 11:17:58 -07004367#ifdef CONFIG_MBO
4368void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
4369{
4370 struct wpa_driver_associate_params params;
4371 u8 *wpa_ie;
4372
4373 /*
4374 * Update MBO connect params only in case of change of MBO attributes
4375 * when connected, if the AP support MBO.
4376 */
4377
4378 if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid ||
4379 !wpa_s->current_bss ||
4380 !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
4381 return;
4382
4383 os_memset(&params, 0, sizeof(params));
4384 wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
4385 wpa_s->current_ssid, &params, NULL);
4386 if (!wpa_ie)
4387 return;
4388
4389 wpa_drv_update_connect_params(wpa_s, &params, WPA_DRV_UPDATE_ASSOC_IES);
4390 os_free(wpa_ie);
4391}
4392#endif /* CONFIG_MBO */
4393
4394
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004395static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
4396{
4397 struct wpa_connect_work *cwork = work->ctx;
4398 struct wpa_bss *bss = cwork->bss;
4399 struct wpa_ssid *ssid = cwork->ssid;
4400 struct wpa_supplicant *wpa_s = work->wpa_s;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004401 u8 *wpa_ie;
Hai Shalomc3565922019-10-28 11:58:20 -07004402 const u8 *edmg_ie_oper;
Hai Shalomfdcde762020-04-02 11:19:20 -07004403 int use_crypt, ret, bssid_changed;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004404 unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004405 struct wpa_driver_associate_params params;
Sunil Ravi77d572f2023-01-17 23:58:31 +00004406 u8 psk[PMK_LEN];
Hai Shalomfdcde762020-04-02 11:19:20 -07004407#if defined(CONFIG_WEP) || defined(IEEE8021X_EAPOL)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004408 int wep_keys_set = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07004409#endif /* CONFIG_WEP || IEEE8021X_EAPOL */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004410 int assoc_failed = 0;
4411 struct wpa_ssid *old_ssid;
Dmitry Shmidte4663042016-04-04 10:07:49 -07004412 u8 prev_bssid[ETH_ALEN];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004413#ifdef CONFIG_HT_OVERRIDES
4414 struct ieee80211_ht_capabilities htcaps;
4415 struct ieee80211_ht_capabilities htcaps_mask;
4416#endif /* CONFIG_HT_OVERRIDES */
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07004417#ifdef CONFIG_VHT_OVERRIDES
4418 struct ieee80211_vht_capabilities vhtcaps;
4419 struct ieee80211_vht_capabilities vhtcaps_mask;
4420#endif /* CONFIG_VHT_OVERRIDES */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004421
Hai Shalomc1a21442022-02-04 13:43:00 -08004422 wpa_s->roam_in_progress = false;
4423#ifdef CONFIG_WNM
4424 wpa_s->bss_trans_mgmt_in_progress = false;
4425#endif /* CONFIG_WNM */
Sunil Ravi7f769292024-07-23 22:21:32 +00004426 wpa_s->no_suitable_network = 0;
Hai Shalomc1a21442022-02-04 13:43:00 -08004427
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004428 if (deinit) {
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08004429 if (work->started) {
4430 wpa_s->connect_work = NULL;
4431
4432 /* cancel possible auth. timeout */
4433 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s,
4434 NULL);
4435 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004436 wpas_connect_work_free(cwork);
4437 return;
4438 }
4439
4440 wpa_s->connect_work = work;
4441
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004442 if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid) ||
4443 wpas_network_disabled(wpa_s, ssid)) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004444 wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
4445 wpas_connect_work_done(wpa_s);
4446 return;
4447 }
4448
Sunil Ravi640215c2023-06-28 23:08:09 +00004449 /*
4450 * Set the current AP's BSSID (for non-MLO connection) or MLD address
4451 * (for MLO connection) as the previous BSSID for reassociation requests
4452 * handled by SME-in-driver. If wpa_supplicant is in disconnected state,
4453 * prev_bssid will be zero as both wpa_s->valid_links and wpa_s->bssid
4454 * will be zero.
4455 */
4456 os_memcpy(prev_bssid,
4457 wpa_s->valid_links ? wpa_s->ap_mld_addr : wpa_s->bssid,
4458 ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004459 os_memset(&params, 0, sizeof(params));
4460 wpa_s->reassociate = 0;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08004461 wpa_s->eap_expected_failure = 0;
Hai Shalom60840252021-02-19 19:02:11 -08004462
4463 /* Starting new association, so clear the possibly used WPA IE from the
4464 * previous association. */
4465 wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
Matthew Wang9ed1c792024-12-02 14:05:18 +00004466#ifndef CONFIG_NO_WPA
Hai Shalom60840252021-02-19 19:02:11 -08004467 wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
Matthew Wang9ed1c792024-12-02 14:05:18 +00004468#endif /* CONFIG_NO_WPA */
Hai Shalom60840252021-02-19 19:02:11 -08004469 wpa_s->rsnxe_len = 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004470#ifndef CONFIG_NO_ROBUST_AV
Hai Shalom60840252021-02-19 19:02:11 -08004471 wpa_s->mscs_setup_done = false;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004472#endif /* CONFIG_NO_ROBUST_AV */
Hai Shalom60840252021-02-19 19:02:11 -08004473
4474 wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
4475 if (!wpa_ie) {
4476 wpas_connect_work_done(wpa_s);
4477 return;
4478 }
4479
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004480 if (bss &&
4481 (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004482#ifdef CONFIG_IEEE80211R
4483 const u8 *ie, *md = NULL;
4484#endif /* CONFIG_IEEE80211R */
4485 wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
4486 " (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
4487 wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
4488 bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
4489 os_memset(wpa_s->bssid, 0, ETH_ALEN);
4490 os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
4491 if (bssid_changed)
4492 wpas_notify_bssid_changed(wpa_s);
4493#ifdef CONFIG_IEEE80211R
4494 ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
4495 if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
4496 md = ie + 2;
4497 wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
4498 if (md) {
4499 /* Prepare for the next transition */
4500 wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
4501 }
4502#endif /* CONFIG_IEEE80211R */
4503#ifdef CONFIG_WPS
4504 } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
4505 wpa_s->conf->ap_scan == 2 &&
4506 (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
4507 /* Use ap_scan==1 style network selection to find the network
4508 */
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08004509 wpas_connect_work_done(wpa_s);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004510 wpa_s->scan_req = MANUAL_SCAN_REQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004511 wpa_s->reassociate = 1;
4512 wpa_supplicant_req_scan(wpa_s, 0, 0);
Hai Shalomc1a21442022-02-04 13:43:00 -08004513 os_free(wpa_ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004514 return;
4515#endif /* CONFIG_WPS */
4516 } else {
4517 wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
4518 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07004519 if (bss)
4520 os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
4521 else
4522 os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004523 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004524 if (!wpa_s->pno)
4525 wpa_supplicant_cancel_sched_scan(wpa_s);
4526
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004527 wpa_supplicant_cancel_scan(wpa_s);
4528
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004529 wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
4530 use_crypt = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004531 cipher_pairwise = wpa_s->pairwise_cipher;
4532 cipher_group = wpa_s->group_cipher;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004533 cipher_group_mgmt = wpa_s->mgmt_group_cipher;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004534 if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
4535 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
4536 if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
4537 use_crypt = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07004538#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004539 if (wpa_set_wep_keys(wpa_s, ssid)) {
4540 use_crypt = 1;
4541 wep_keys_set = 1;
4542 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004543#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004544 }
4545 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
4546 use_crypt = 0;
4547
4548#ifdef IEEE8021X_EAPOL
4549 if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
4550 if ((ssid->eapol_flags &
4551 (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
4552 EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) == 0 &&
4553 !wep_keys_set) {
4554 use_crypt = 0;
4555 } else {
4556 /* Assume that dynamic WEP-104 keys will be used and
4557 * set cipher suites in order for drivers to expect
4558 * encryption. */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004559 cipher_pairwise = cipher_group = WPA_CIPHER_WEP104;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004560 }
4561 }
4562#endif /* IEEE8021X_EAPOL */
4563
4564 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
4565 /* Set the key before (and later after) association */
4566 wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
4567 }
4568
Sunil8cd6f4d2022-06-28 18:40:46 +00004569 /* Set current_ssid before changing state to ASSOCIATING, so that the
4570 * selected SSID is available to wpas_notify_state_changed(). */
4571 old_ssid = wpa_s->current_ssid;
4572 wpa_s->current_ssid = ssid;
4573
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004574 wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
4575 if (bss) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004576 params.ssid = bss->ssid;
4577 params.ssid_len = bss->ssid_len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004578 if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set ||
4579 wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07004580 wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
4581 MACSTR " freq=%u MHz based on scan results "
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004582 "(bssid_set=%d wps=%d)",
Dmitry Shmidt04949592012-07-19 12:16:46 -07004583 MAC2STR(bss->bssid), bss->freq,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004584 ssid->bssid_set,
4585 wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004586 params.bssid = bss->bssid;
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07004587 params.freq.freq = bss->freq;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004588 }
Dmitry Shmidt96be6222014-02-13 10:16:51 -08004589 params.bssid_hint = bss->bssid;
4590 params.freq_hint = bss->freq;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004591 params.pbss = bss_is_pbss(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004592 } else {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004593 if (ssid->bssid_hint_set)
4594 params.bssid_hint = ssid->bssid_hint;
4595
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004596 params.ssid = ssid->ssid;
4597 params.ssid_len = ssid->ssid_len;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004598 params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004599 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004600
4601 if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
4602 wpa_s->conf->ap_scan == 2) {
4603 params.bssid = ssid->bssid;
4604 params.fixed_bssid = 1;
4605 }
4606
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004607 /* Initial frequency for IBSS/mesh */
4608 if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004609 ssid->frequency > 0 && params.freq.freq == 0)
4610 ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
Dmitry Shmidt2ac5f602014-03-07 10:08:21 -08004611
4612 if (ssid->mode == WPAS_MODE_IBSS) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004613 params.fixed_freq = ssid->fixed_freq;
Dmitry Shmidt2ac5f602014-03-07 10:08:21 -08004614 if (ssid->beacon_int)
4615 params.beacon_int = ssid->beacon_int;
4616 else
4617 params.beacon_int = wpa_s->conf->beacon_int;
4618 }
4619
Hai Shalomc3565922019-10-28 11:58:20 -07004620 if (bss && ssid->enable_edmg)
Hai Shalom60840252021-02-19 19:02:11 -08004621 edmg_ie_oper = wpa_bss_get_ie_ext(bss,
4622 WLAN_EID_EXT_EDMG_OPERATION);
Hai Shalomc3565922019-10-28 11:58:20 -07004623 else
4624 edmg_ie_oper = NULL;
4625
4626 if (edmg_ie_oper) {
4627 params.freq.edmg.channels =
4628 wpa_ie_get_edmg_oper_chans(edmg_ie_oper);
4629 params.freq.edmg.bw_config =
4630 wpa_ie_get_edmg_oper_chan_width(edmg_ie_oper);
4631 wpa_printf(MSG_DEBUG,
4632 "AP supports EDMG channels 0x%x, bw_config %d",
4633 params.freq.edmg.channels,
4634 params.freq.edmg.bw_config);
4635
4636 /* User may ask for specific EDMG channel for EDMG connection
4637 * (must be supported by AP)
4638 */
4639 if (ssid->edmg_channel) {
4640 struct ieee80211_edmg_config configured_edmg;
4641 enum hostapd_hw_mode hw_mode;
4642 u8 primary_channel;
4643
4644 hw_mode = ieee80211_freq_to_chan(bss->freq,
4645 &primary_channel);
4646 if (hw_mode == NUM_HOSTAPD_MODES)
4647 goto edmg_fail;
4648
4649 hostapd_encode_edmg_chan(ssid->enable_edmg,
4650 ssid->edmg_channel,
4651 primary_channel,
4652 &configured_edmg);
4653
4654 if (ieee802_edmg_is_allowed(params.freq.edmg,
4655 configured_edmg)) {
4656 params.freq.edmg = configured_edmg;
4657 wpa_printf(MSG_DEBUG,
4658 "Use EDMG channel %d for connection",
4659 ssid->edmg_channel);
4660 } else {
4661 edmg_fail:
4662 params.freq.edmg.channels = 0;
4663 params.freq.edmg.bw_config = 0;
4664 wpa_printf(MSG_WARNING,
4665 "EDMG channel %d not supported by AP, fallback to DMG",
4666 ssid->edmg_channel);
4667 }
4668 }
4669
4670 if (params.freq.edmg.channels) {
4671 wpa_printf(MSG_DEBUG,
4672 "EDMG before: channels 0x%x, bw_config %d",
4673 params.freq.edmg.channels,
4674 params.freq.edmg.bw_config);
4675 params.freq.edmg = get_supported_edmg(wpa_s,
4676 &params.freq,
4677 params.freq.edmg);
4678 wpa_printf(MSG_DEBUG,
4679 "EDMG after: channels 0x%x, bw_config %d",
4680 params.freq.edmg.channels,
4681 params.freq.edmg.bw_config);
4682 }
4683 }
4684
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004685 params.pairwise_suite = cipher_pairwise;
4686 params.group_suite = cipher_group;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004687 params.mgmt_group_suite = cipher_group_mgmt;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004688 params.key_mgmt_suite = wpa_s->key_mgmt;
Sunil Ravi89eba102022-09-13 21:04:37 -07004689 params.allowed_key_mgmts = wpa_s->allowed_key_mgmts;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004690 params.wpa_proto = wpa_s->wpa_proto;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004691 wpa_s->auth_alg = params.auth_alg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004692 params.mode = ssid->mode;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004693 params.bg_scan_period = ssid->bg_scan_period;
Hai Shalomfdcde762020-04-02 11:19:20 -07004694#ifdef CONFIG_WEP
4695 {
4696 int i;
4697
4698 for (i = 0; i < NUM_WEP_KEYS; i++) {
4699 if (ssid->wep_key_len[i])
4700 params.wep_key[i] = ssid->wep_key[i];
4701 params.wep_key_len[i] = ssid->wep_key_len[i];
4702 }
4703 params.wep_tx_keyidx = ssid->wep_tx_keyidx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004704 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004705#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004706
Hai Shalom74f70d42019-02-11 14:42:39 -08004707 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
Isaac Chiou6ce580d2024-04-24 17:07:24 +08004708#if (defined(CONFIG_DRIVER_NL80211_BRCM) && !defined(WIFI_BRCM_OPEN_SOURCE_MULTI_AKM)) || \
4709 defined(CONFIG_DRIVER_NL80211_SYNA)
Sunil Ravi89eba102022-09-13 21:04:37 -07004710 ((params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
4711 (params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK))) {
Isaac Chiou6ce580d2024-04-24 17:07:24 +08004712#elif (defined(CONFIG_DRIVER_NL80211_BRCM) && defined(WIFI_BRCM_OPEN_SOURCE_MULTI_AKM)) || \
4713 defined(CONFIG_DRIVER_NL80211_SYNA)
4714 (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
4715 params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
4716 params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
4717 wpa_key_mgmt_wpa_psk_no_sae(params.allowed_key_mgmts))) {
Vinayak Yadawad14709082022-03-17 14:25:11 +05304718#else
Sunil Ravi89eba102022-09-13 21:04:37 -07004719 (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
4720 params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
4721 (params.allowed_key_mgmts &
4722 (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK)))) {
Isaac Chiou6ce580d2024-04-24 17:07:24 +08004723#endif /* (CONFIG_DRIVER_NL80211_BRCM && !WIFI_BRCM_OPEN_SOURCE_MULTI_AKM) ||
4724 * CONFIG_DRIVER_NL80211_SYNA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004725 params.passphrase = ssid->passphrase;
Sunil Ravi77d572f2023-01-17 23:58:31 +00004726 if (wpa_supplicant_get_psk(wpa_s, bss, ssid, psk) == 0)
4727 params.psk = psk;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004728 }
4729
Hai Shalom74f70d42019-02-11 14:42:39 -08004730 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
4731 (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
4732 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
4733 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004734 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
4735 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA384))
Hai Shalomc3565922019-10-28 11:58:20 -07004736 params.req_handshake_offload = 1;
Hai Shalom74f70d42019-02-11 14:42:39 -08004737
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004738 if (wpa_s->conf->key_mgmt_offload) {
4739 if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
4740 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
Dmitry Shmidt807291d2015-01-27 13:40:23 -08004741 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004742 params.key_mgmt_suite ==
4743 WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
4744 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA384)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004745 params.req_key_mgmt_offload =
4746 ssid->proactive_key_caching < 0 ?
4747 wpa_s->conf->okc : ssid->proactive_key_caching;
4748 else
4749 params.req_key_mgmt_offload = 1;
4750
Isaac Chiou6ce580d2024-04-24 17:07:24 +08004751#if (defined(CONFIG_DRIVER_NL80211_BRCM) && !defined(WIFI_BRCM_OPEN_SOURCE_MULTI_AKM)) || \
4752 defined(CONFIG_DRIVER_NL80211_SYNA)
Sunil Ravi89eba102022-09-13 21:04:37 -07004753 if (((params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004754 params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
4755 params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
Sunil Ravi89eba102022-09-13 21:04:37 -07004756#else
4757 if ((wpa_key_mgmt_wpa_psk_no_sae(params.key_mgmt_suite) ||
4758 wpa_key_mgmt_wpa_psk_no_sae(params.allowed_key_mgmts)) &&
Isaac Chiou6ce580d2024-04-24 17:07:24 +08004759#endif /* (CONFIG_DRIVER_NL80211_BRCM && !WIFI_BRCM_OPEN_SOURCE_MULTI_AKM) ||
4760 * CONFIG_DRIVER_NL80211_SYNA */
Sunil Ravi77d572f2023-01-17 23:58:31 +00004761 wpa_supplicant_get_psk(wpa_s, bss, ssid, psk) == 0)
4762 params.psk = psk;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004763 }
4764
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004765 if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA) &&
4766 wpa_key_mgmt_sae(params.key_mgmt_suite)) {
4767 params.auth_alg = WPA_AUTH_ALG_SAE;
4768 if (ssid->sae_password) {
4769 params.sae_password = ssid->sae_password;
4770 params.sae_password_id = ssid->sae_password_id;
4771 } else if (ssid->passphrase) {
4772 params.passphrase = ssid->passphrase;
4773 }
4774 }
4775
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004776 params.drop_unencrypted = use_crypt;
4777
Dmitry Shmidt807291d2015-01-27 13:40:23 -08004778 params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004779 if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
Sunil Ravi7f769292024-07-23 22:21:32 +00004780 const u8 *rsn = wpa_bss_get_rsne(wpa_s, bss, ssid, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004781 struct wpa_ie_data ie;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004782 if (!wpas_driver_bss_selection(wpa_s) && rsn &&
4783 wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004784 ie.capabilities &
4785 (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
4786 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected AP supports "
4787 "MFP: require MFP");
4788 params.mgmt_frame_protection =
4789 MGMT_FRAME_PROTECTION_REQUIRED;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08004790#ifdef CONFIG_OWE
4791 } else if (!rsn && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
4792 !ssid->owe_only) {
4793 params.mgmt_frame_protection = NO_MGMT_FRAME_PROTECTION;
4794#endif /* CONFIG_OWE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004795 }
4796 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004797
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004798 params.p2p = ssid->p2p_group;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004799
Dmitry Shmidt9c175262016-03-03 10:20:07 -08004800 if (wpa_s->p2pdev->set_sta_uapsd)
4801 params.uapsd = wpa_s->p2pdev->sta_uapsd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004802 else
4803 params.uapsd = -1;
4804
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004805#ifdef CONFIG_HT_OVERRIDES
4806 os_memset(&htcaps, 0, sizeof(htcaps));
4807 os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
4808 params.htcaps = (u8 *) &htcaps;
4809 params.htcaps_mask = (u8 *) &htcaps_mask;
4810 wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
4811#endif /* CONFIG_HT_OVERRIDES */
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07004812#ifdef CONFIG_VHT_OVERRIDES
4813 os_memset(&vhtcaps, 0, sizeof(vhtcaps));
4814 os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
4815 params.vhtcaps = &vhtcaps;
4816 params.vhtcaps_mask = &vhtcaps_mask;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004817 wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07004818#endif /* CONFIG_VHT_OVERRIDES */
Hai Shalomfdcde762020-04-02 11:19:20 -07004819#ifdef CONFIG_HE_OVERRIDES
4820 wpa_supplicant_apply_he_overrides(wpa_s, ssid, &params);
4821#endif /* CONFIG_HE_OVERRIDES */
Sunil Ravi77d572f2023-01-17 23:58:31 +00004822 wpa_supplicant_apply_eht_overrides(wpa_s, ssid, &params);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004823
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08004824#ifdef CONFIG_P2P
4825 /*
4826 * If multi-channel concurrency is not supported, check for any
4827 * frequency conflict. In case of any frequency conflict, remove the
4828 * least prioritized connection.
4829 */
4830 if (wpa_s->num_multichan_concurrent < 2) {
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07004831 int freq, num;
Sunil Ravi77d572f2023-01-17 23:58:31 +00004832 num = get_shared_radio_freqs(wpa_s, &freq, 1, false);
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07004833 if (num > 0 && freq > 0 && freq != params.freq.freq) {
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07004834 wpa_printf(MSG_DEBUG,
4835 "Assoc conflicting freq found (%d != %d)",
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07004836 freq, params.freq.freq);
4837 if (wpas_p2p_handle_frequency_conflicts(
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08004838 wpa_s, params.freq.freq, ssid) < 0) {
4839 wpas_connect_work_done(wpa_s);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004840 os_free(wpa_ie);
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08004841 return;
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08004842 }
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08004843 }
4844 }
4845#endif /* CONFIG_P2P */
4846
Dmitry Shmidte4663042016-04-04 10:07:49 -07004847 if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
Sunil8cd6f4d2022-06-28 18:40:46 +00004848 old_ssid)
Dmitry Shmidte4663042016-04-04 10:07:49 -07004849 params.prev_bssid = prev_bssid;
4850
Hai Shalom60840252021-02-19 19:02:11 -08004851#ifdef CONFIG_SAE
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00004852 params.sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
Hai Shalom60840252021-02-19 19:02:11 -08004853#endif /* CONFIG_SAE */
4854
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004855 ret = wpa_drv_associate(wpa_s, &params);
Sunil Ravi77d572f2023-01-17 23:58:31 +00004856 forced_memzero(psk, sizeof(psk));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004857 os_free(wpa_ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004858 if (ret < 0) {
4859 wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
4860 "failed");
Hai Shalomc1a21442022-02-04 13:43:00 -08004861 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_VALID_ERROR_CODES) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004862 /*
4863 * The driver is known to mean what is saying, so we
4864 * can stop right here; the association will not
4865 * succeed.
4866 */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004867 wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
4868 NULL);
Roger Wang4c09cc92020-11-05 18:57:12 +08004869 wpa_s->assoc_status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
Sunil Ravie06118e2021-01-03 08:39:46 -08004870 wpas_notify_assoc_status_code(wpa_s, wpa_s->pending_bssid, 0, NULL, 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004871 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004872 os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
4873 return;
4874 }
4875 /* try to continue anyway; new association will be tried again
4876 * after timeout */
4877 assoc_failed = 1;
4878 }
4879
4880 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
4881 /* Set the key after the association just in case association
4882 * cleared the previously configured key. */
4883 wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
4884 /* No need to timeout authentication since there is no key
4885 * management. */
4886 wpa_supplicant_cancel_auth_timeout(wpa_s);
4887 wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
4888#ifdef CONFIG_IBSS_RSN
4889 } else if (ssid->mode == WPAS_MODE_IBSS &&
4890 wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
4891 wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
4892 /*
4893 * RSN IBSS authentication is per-STA and we can disable the
4894 * per-BSSID authentication.
4895 */
4896 wpa_supplicant_cancel_auth_timeout(wpa_s);
4897#endif /* CONFIG_IBSS_RSN */
4898 } else {
4899 /* Timeout for IEEE 802.11 authentication and association */
4900 int timeout = 60;
4901
4902 if (assoc_failed) {
4903 /* give IBSS a bit more time */
4904 timeout = ssid->mode == WPAS_MODE_IBSS ? 10 : 5;
4905 } else if (wpa_s->conf->ap_scan == 1) {
4906 /* give IBSS a bit more time */
4907 timeout = ssid->mode == WPAS_MODE_IBSS ? 20 : 10;
4908 }
4909 wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
4910 }
4911
Hai Shalomfdcde762020-04-02 11:19:20 -07004912#ifdef CONFIG_WEP
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07004913 if (wep_keys_set &&
4914 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004915 /* Set static WEP keys again */
4916 wpa_set_wep_keys(wpa_s, ssid);
4917 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004918#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004919
Sunil8cd6f4d2022-06-28 18:40:46 +00004920 if (old_ssid && old_ssid != ssid) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004921 /*
4922 * Do not allow EAP session resumption between different
4923 * network configurations.
4924 */
4925 eapol_sm_invalidate_cached_session(wpa_s->eapol);
4926 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004927
mtk30479d7f89782024-01-24 11:51:43 +08004928 if (!wpas_driver_bss_selection(wpa_s) ||
4929#ifdef CONFIG_P2P
4930 wpa_s->p2p_in_invitation ||
4931#endif /* CONFIG_P2P */
4932 ssid->bssid_set) {
Dmitry Shmidtb1e52102015-05-29 12:36:29 -07004933 wpa_s->current_bss = bss;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004934#ifdef CONFIG_HS20
4935 hs20_configure_frame_filters(wpa_s);
4936#endif /* CONFIG_HS20 */
4937 }
4938
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004939 wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
Matthew Wang9ed1c792024-12-02 14:05:18 +00004940#ifndef CONFIG_NO_WPA
Sunil Ravi7f769292024-07-23 22:21:32 +00004941 if (bss)
4942 wpa_sm_set_ssid(wpa_s->wpa, bss->ssid, bss->ssid_len);
Matthew Wang9ed1c792024-12-02 14:05:18 +00004943#endif /* CONFIG_NO_WPA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004944 wpa_supplicant_initiate_eapol(wpa_s);
4945 if (old_ssid != wpa_s->current_ssid)
4946 wpas_notify_network_changed(wpa_s);
Sunil Ravi77d572f2023-01-17 23:58:31 +00004947 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
4948 wpas_notify_auth_changed(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004949}
4950
4951
4952static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
4953 const u8 *addr)
4954{
4955 struct wpa_ssid *old_ssid;
4956
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004957 wpa_s->ml_connect_probe_ssid = NULL;
4958 wpa_s->ml_connect_probe_bss = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004959 wpas_connect_work_done(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004960 wpa_clear_keys(wpa_s, addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004961 old_ssid = wpa_s->current_ssid;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004962 wpa_supplicant_mark_disassoc(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004963 wpa_sm_set_config(wpa_s->wpa, NULL);
4964 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
4965 if (old_ssid != wpa_s->current_ssid)
4966 wpas_notify_network_changed(wpa_s);
Hai Shalomc1a21442022-02-04 13:43:00 -08004967
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004968#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08004969 wpas_scs_deinit(wpa_s);
4970 wpas_dscp_deinit(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004971#endif /* CONFIG_NO_ROBUST_AV */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004972 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
4973}
4974
4975
4976/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004977 * wpa_supplicant_deauthenticate - Deauthenticate the current connection
4978 * @wpa_s: Pointer to wpa_supplicant data
4979 * @reason_code: IEEE 802.11 reason code for the deauthenticate frame
4980 *
4981 * This function is used to request %wpa_supplicant to deauthenticate from the
4982 * current AP.
4983 */
4984void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
Hai Shalom81f62d82019-07-22 12:10:00 -07004985 u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004986{
4987 u8 *addr = NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004988 union wpa_event_data event;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004989 int zero_addr = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004990
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004991 wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
Sunil Ravi7f769292024-07-23 22:21:32 +00004992 " pending_bssid=" MACSTR
4993 " reason=%d (%s) state=%s valid_links=0x%x ap_mld_addr=" MACSTR,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004994 MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
Hai Shalom81f62d82019-07-22 12:10:00 -07004995 reason_code, reason2str(reason_code),
Sunil Ravi7f769292024-07-23 22:21:32 +00004996 wpa_supplicant_state_txt(wpa_s->wpa_state), wpa_s->valid_links,
4997 MAC2STR(wpa_s->ap_mld_addr));
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004998
Sunil Ravi7f769292024-07-23 22:21:32 +00004999 if (wpa_s->valid_links && !is_zero_ether_addr(wpa_s->ap_mld_addr))
5000 addr = wpa_s->ap_mld_addr;
5001 else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
5002 (wpa_s->wpa_state == WPA_AUTHENTICATING ||
5003 wpa_s->wpa_state == WPA_ASSOCIATING))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005004 addr = wpa_s->pending_bssid;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005005 else if (!is_zero_ether_addr(wpa_s->bssid))
5006 addr = wpa_s->bssid;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005007 else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
5008 /*
5009 * When using driver-based BSS selection, we may not know the
5010 * BSSID with which we are currently trying to associate. We
5011 * need to notify the driver of this disconnection even in such
5012 * a case, so use the all zeros address here.
5013 */
5014 addr = wpa_s->bssid;
5015 zero_addr = 1;
5016 }
5017
Hai Shalom74f70d42019-02-11 14:42:39 -08005018 if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
5019 wpa_s->enabled_4addr_mode = 0;
5020
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005021#ifdef CONFIG_TDLS
5022 wpa_tdls_teardown_peers(wpa_s->wpa);
5023#endif /* CONFIG_TDLS */
5024
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005025#ifdef CONFIG_MESH
5026 if (wpa_s->ifmsh) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005027 struct mesh_conf *mconf;
5028
5029 mconf = wpa_s->ifmsh->mconf;
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005030 wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
5031 wpa_s->ifname);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005032 wpas_notify_mesh_group_removed(wpa_s, mconf->meshid,
5033 mconf->meshid_len, reason_code);
Hai Shalom60840252021-02-19 19:02:11 -08005034 wpa_supplicant_leave_mesh(wpa_s, true);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005035 }
5036#endif /* CONFIG_MESH */
5037
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005038 if (addr) {
5039 wpa_drv_deauthenticate(wpa_s, addr, reason_code);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005040 os_memset(&event, 0, sizeof(event));
Hai Shalom81f62d82019-07-22 12:10:00 -07005041 event.deauth_info.reason_code = reason_code;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005042 event.deauth_info.locally_generated = 1;
5043 wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005044 if (zero_addr)
5045 addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005046 }
5047
5048 wpa_supplicant_clear_connection(wpa_s, addr);
5049}
5050
Hai Shalomfdcde762020-04-02 11:19:20 -07005051
5052void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s)
5053{
5054 wpa_s->own_reconnect_req = 1;
5055 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
5056
5057}
5058
5059
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005060static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
5061 struct wpa_ssid *ssid)
5062{
5063 if (!ssid || !ssid->disabled || ssid->disabled == 2)
5064 return;
5065
5066 ssid->disabled = 0;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08005067 ssid->owe_transition_bss_select_count = 0;
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005068 wpas_clear_temp_disabled(wpa_s, ssid, 1);
5069 wpas_notify_network_enabled_changed(wpa_s, ssid);
5070
5071 /*
5072 * Try to reassociate since there is no current configuration and a new
5073 * network was made available.
5074 */
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07005075 if (!wpa_s->current_ssid && !wpa_s->disconnected)
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005076 wpa_s->reassociate = 1;
5077}
5078
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005079
Roshan Pius950bec92016-07-19 09:49:24 -07005080/**
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005081 * wpa_supplicant_add_network - Add a new network
Roshan Pius950bec92016-07-19 09:49:24 -07005082 * @wpa_s: wpa_supplicant structure for a network interface
5083 * Returns: The new network configuration or %NULL if operation failed
5084 *
5085 * This function performs the following operations:
5086 * 1. Adds a new network.
5087 * 2. Send network addition notification.
5088 * 3. Marks the network disabled.
5089 * 4. Set network default parameters.
5090 */
5091struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
5092{
5093 struct wpa_ssid *ssid;
5094
5095 ssid = wpa_config_add_network(wpa_s->conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005096 if (!ssid)
Roshan Pius950bec92016-07-19 09:49:24 -07005097 return NULL;
Roshan Pius950bec92016-07-19 09:49:24 -07005098 wpas_notify_network_added(wpa_s, ssid);
5099 ssid->disabled = 1;
5100 wpa_config_set_network_defaults(ssid);
5101
5102 return ssid;
5103}
5104
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005105
Roshan Pius950bec92016-07-19 09:49:24 -07005106/**
5107 * wpa_supplicant_remove_network - Remove a configured network based on id
5108 * @wpa_s: wpa_supplicant structure for a network interface
5109 * @id: Unique network id to search for
5110 * Returns: 0 on success, or -1 if the network was not found, -2 if the network
5111 * could not be removed
5112 *
5113 * This function performs the following operations:
5114 * 1. Removes the network.
5115 * 2. Send network removal notification.
5116 * 3. Update internal state machines.
5117 * 4. Stop any running sched scans.
5118 */
5119int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
5120{
Sunil Ravia04bd252022-05-02 22:54:18 -07005121 struct wpa_ssid *ssid, *prev = wpa_s->current_ssid;
Roshan Pius950bec92016-07-19 09:49:24 -07005122 int was_disabled;
5123
5124 ssid = wpa_config_get_network(wpa_s->conf, id);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005125 if (!ssid)
Roshan Pius950bec92016-07-19 09:49:24 -07005126 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005127 wpas_notify_network_removed(wpa_s, ssid);
Roshan Pius950bec92016-07-19 09:49:24 -07005128
Sunil Ravia04bd252022-05-02 22:54:18 -07005129 if (ssid == prev || !prev) {
Roshan Pius950bec92016-07-19 09:49:24 -07005130#ifdef CONFIG_SME
5131 wpa_s->sme.prev_bssid_set = 0;
5132#endif /* CONFIG_SME */
5133 /*
5134 * Invalidate the EAP session cache if the current or
5135 * previously used network is removed.
5136 */
5137 eapol_sm_invalidate_cached_session(wpa_s->eapol);
5138 }
5139
Sunil Ravia04bd252022-05-02 22:54:18 -07005140 if (ssid == prev) {
Roshan Pius950bec92016-07-19 09:49:24 -07005141 wpa_sm_set_config(wpa_s->wpa, NULL);
5142 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
5143
5144 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
5145 wpa_s->own_disconnect_req = 1;
5146 wpa_supplicant_deauthenticate(wpa_s,
5147 WLAN_REASON_DEAUTH_LEAVING);
5148 }
5149
5150 was_disabled = ssid->disabled;
5151
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005152 if (wpa_config_remove_network(wpa_s->conf, id) < 0)
Roshan Pius950bec92016-07-19 09:49:24 -07005153 return -2;
Roshan Pius950bec92016-07-19 09:49:24 -07005154
5155 if (!was_disabled && wpa_s->sched_scanning) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005156 wpa_printf(MSG_DEBUG,
5157 "Stop ongoing sched_scan to remove network from filters");
Roshan Pius950bec92016-07-19 09:49:24 -07005158 wpa_supplicant_cancel_sched_scan(wpa_s);
5159 wpa_supplicant_req_scan(wpa_s, 0, 0);
5160 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005161
Roshan Pius950bec92016-07-19 09:49:24 -07005162 return 0;
5163}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005164
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005165
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005166/**
Hai Shalom899fcc72020-10-19 14:38:18 -07005167 * wpa_supplicant_remove_all_networks - Remove all configured networks
5168 * @wpa_s: wpa_supplicant structure for a network interface
5169 * Returns: 0 on success (errors are currently ignored)
5170 *
5171 * This function performs the following operations:
5172 * 1. Remove all networks.
5173 * 2. Send network removal notifications.
5174 * 3. Update internal state machines.
5175 * 4. Stop any running sched scans.
5176 */
5177int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s)
5178{
5179 struct wpa_ssid *ssid;
5180
Vinayak Yadawad4222acc2023-12-15 17:39:27 +05305181 if (wpa_s->drv_flags2 &
5182 (WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA |
5183 WPA_DRIVER_FLAGS2_OWE_OFFLOAD_STA))
5184 wpa_drv_flush_pmkid(wpa_s);
5185
Hai Shalom899fcc72020-10-19 14:38:18 -07005186 if (wpa_s->sched_scanning)
5187 wpa_supplicant_cancel_sched_scan(wpa_s);
5188
5189 eapol_sm_invalidate_cached_session(wpa_s->eapol);
5190 if (wpa_s->current_ssid) {
5191#ifdef CONFIG_SME
5192 wpa_s->sme.prev_bssid_set = 0;
5193#endif /* CONFIG_SME */
5194 wpa_sm_set_config(wpa_s->wpa, NULL);
5195 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
5196 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
5197 wpa_s->own_disconnect_req = 1;
5198 wpa_supplicant_deauthenticate(
5199 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
5200 }
5201 ssid = wpa_s->conf->ssid;
5202 while (ssid) {
5203 struct wpa_ssid *remove_ssid = ssid;
5204 int id;
5205
5206 id = ssid->id;
5207 ssid = ssid->next;
Hai Shalom899fcc72020-10-19 14:38:18 -07005208 wpas_notify_network_removed(wpa_s, remove_ssid);
5209 wpa_config_remove_network(wpa_s->conf, id);
5210 }
5211 return 0;
5212}
5213
5214
5215/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005216 * wpa_supplicant_enable_network - Mark a configured network as enabled
5217 * @wpa_s: wpa_supplicant structure for a network interface
5218 * @ssid: wpa_ssid structure for a configured network or %NULL
5219 *
5220 * Enables the specified network or all networks if no network specified.
5221 */
5222void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
5223 struct wpa_ssid *ssid)
5224{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005225 if (ssid == NULL) {
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005226 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
5227 wpa_supplicant_enable_one_network(wpa_s, ssid);
5228 } else
5229 wpa_supplicant_enable_one_network(wpa_s, ssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005230
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005231 if (wpa_s->reassociate && !wpa_s->disconnected &&
5232 (!wpa_s->current_ssid ||
5233 wpa_s->wpa_state == WPA_DISCONNECTED ||
5234 wpa_s->wpa_state == WPA_SCANNING)) {
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005235 if (wpa_s->sched_scanning) {
5236 wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to add "
5237 "new network to scan filters");
5238 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005239 }
5240
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005241 if (wpa_supplicant_fast_associate(wpa_s) != 1) {
5242 wpa_s->scan_req = NORMAL_SCAN_REQ;
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07005243 wpa_supplicant_req_scan(wpa_s, 0, 0);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005244 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005245 }
5246}
5247
5248
5249/**
5250 * wpa_supplicant_disable_network - Mark a configured network as disabled
5251 * @wpa_s: wpa_supplicant structure for a network interface
5252 * @ssid: wpa_ssid structure for a configured network or %NULL
5253 *
5254 * Disables the specified network or all networks if no network specified.
5255 */
5256void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
5257 struct wpa_ssid *ssid)
5258{
5259 struct wpa_ssid *other_ssid;
5260 int was_disabled;
5261
5262 if (ssid == NULL) {
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005263 if (wpa_s->sched_scanning)
5264 wpa_supplicant_cancel_sched_scan(wpa_s);
5265
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005266 for (other_ssid = wpa_s->conf->ssid; other_ssid;
5267 other_ssid = other_ssid->next) {
5268 was_disabled = other_ssid->disabled;
5269 if (was_disabled == 2)
5270 continue; /* do not change persistent P2P group
5271 * data */
5272
5273 other_ssid->disabled = 1;
5274
5275 if (was_disabled != other_ssid->disabled)
5276 wpas_notify_network_enabled_changed(
5277 wpa_s, other_ssid);
5278 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005279 if (wpa_s->current_ssid) {
5280 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
5281 wpa_s->own_disconnect_req = 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005282 wpa_supplicant_deauthenticate(
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005283 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005284 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005285 } else if (ssid->disabled != 2) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005286 if (ssid == wpa_s->current_ssid) {
5287 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
5288 wpa_s->own_disconnect_req = 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005289 wpa_supplicant_deauthenticate(
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005290 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005291 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005292
5293 was_disabled = ssid->disabled;
5294
5295 ssid->disabled = 1;
5296
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005297 if (was_disabled != ssid->disabled) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005298 wpas_notify_network_enabled_changed(wpa_s, ssid);
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005299 if (wpa_s->sched_scanning) {
5300 wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan "
5301 "to remove network from filters");
5302 wpa_supplicant_cancel_sched_scan(wpa_s);
5303 wpa_supplicant_req_scan(wpa_s, 0, 0);
5304 }
5305 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005306 }
5307}
5308
5309
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00005310static bool ssid_in_last_scan(struct wpa_supplicant *wpa_s,
5311 struct wpa_ssid *ssid)
5312{
5313 size_t i;
5314
5315 /* Check if the previous scan included the selected network */
5316 if (wpa_s->last_scan_num_ssids <= 1 ||
5317 !ssid->ssid || ssid->ssid_len == 0)
5318 return false;
5319
5320 /* Iterate through the previous scan SSIDs */
5321 for (i = 0; i < wpa_s->last_scan_num_ssids; i++) {
5322 if (os_memcmp(wpa_s->last_scan_ssids[i].ssid, ssid->ssid,
5323 ssid->ssid_len) == 0)
5324 return true;
5325 }
5326
5327 return false;
5328}
5329
5330
5331/**
5332 * Checks whether an SSID was discovered in the last scan.
5333 * @wpa_s: wpa_supplicant structure for a network interface.
5334 * @ssid: wpa_ssid structure for a configured network.
5335 * Returns: true if ssid found, false otherwise.
5336 */
5337static bool ssid_in_last_scan_res(struct wpa_supplicant *wpa_s,
5338 struct wpa_ssid *ssid)
5339{
5340 size_t i;
5341
5342 if (!wpa_s->last_scan_res || !ssid->ssid || ssid->ssid_len == 0)
5343 return false;
5344
5345 for (i = 0; i < wpa_s->last_scan_res_used; i++) {
5346 if (os_memcmp(wpa_s->last_scan_res[i]->ssid,
5347 ssid->ssid, ssid->ssid_len) == 0)
5348 return true;
5349 }
5350
5351 return false;
5352}
5353
5354
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005355/**
5356 * wpa_supplicant_select_network - Attempt association with a network
5357 * @wpa_s: wpa_supplicant structure for a network interface
5358 * @ssid: wpa_ssid structure for a configured network or %NULL for any network
5359 */
5360void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
5361 struct wpa_ssid *ssid)
5362{
5363
5364 struct wpa_ssid *other_ssid;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005365 int disconnected = 0;
Sunil Ravi7f769292024-07-23 22:21:32 +00005366 bool request_new_scan = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005367
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005368 if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07005369 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
5370 wpa_s->own_disconnect_req = 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005371 wpa_supplicant_deauthenticate(
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005372 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005373 disconnected = 1;
5374 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005375
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005376 if (ssid)
5377 wpas_clear_temp_disabled(wpa_s, ssid, 1);
5378
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005379 /*
5380 * Mark all other networks disabled or mark all networks enabled if no
5381 * network specified.
5382 */
5383 for (other_ssid = wpa_s->conf->ssid; other_ssid;
5384 other_ssid = other_ssid->next) {
5385 int was_disabled = other_ssid->disabled;
5386 if (was_disabled == 2)
5387 continue; /* do not change persistent P2P group data */
5388
5389 other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005390 if (was_disabled && !other_ssid->disabled)
5391 wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005392
5393 if (was_disabled != other_ssid->disabled)
5394 wpas_notify_network_enabled_changed(wpa_s, other_ssid);
5395 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005396
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005397 if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid &&
5398 wpa_s->wpa_state >= WPA_AUTHENTICATING) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005399 /* We are already associated with the selected network */
5400 wpa_printf(MSG_DEBUG, "Already associated with the "
5401 "selected network - do nothing");
5402 return;
5403 }
5404
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07005405 if (ssid) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005406 wpa_s->current_ssid = ssid;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07005407 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005408 wpa_s->connect_without_scan =
Sunil Ravi640215c2023-06-28 23:08:09 +00005409 (ssid->mode == WPAS_MODE_MESH ||
5410 ssid->mode == WPAS_MODE_AP) ? ssid : NULL;
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07005411
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00005412 if (ssid->scan_ssid) {
5413 if (ssid_in_last_scan(wpa_s, ssid)) {
5414 wpa_printf(MSG_DEBUG,
5415 "Hidden network was scanned for in last scan");
5416 } else if (ssid_in_last_scan_res(wpa_s, ssid)) {
5417 wpa_printf(MSG_DEBUG,
5418 "Hidden network was found in last scan results");
5419 } else {
5420 request_new_scan = true;
5421 wpa_printf(MSG_DEBUG,
5422 "Request a new scan for hidden network");
5423 }
5424 }
5425
5426 if (!request_new_scan && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
5427 !ssid->owe_only) {
Sunil Ravi7f769292024-07-23 22:21:32 +00005428 wpa_printf(MSG_DEBUG,
5429 "Request a new scan for OWE transition SSID");
5430 request_new_scan = true;
5431 }
5432
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07005433 /*
5434 * Don't optimize next scan freqs since a new ESS has been
5435 * selected.
5436 */
5437 os_free(wpa_s->next_scan_freqs);
5438 wpa_s->next_scan_freqs = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005439 } else {
5440 wpa_s->connect_without_scan = NULL;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07005441 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005442
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005443 wpa_s->disconnected = 0;
5444 wpa_s->reassociate = 1;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005445 wpa_s_clear_sae_rejected(wpa_s);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005446 wpa_s->last_owe_group = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07005447 if (ssid) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08005448 ssid->owe_transition_bss_select_count = 0;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00005449 wpa_s_setup_sae_pt(wpa_s, ssid, false);
Hai Shalomc3565922019-10-28 11:58:20 -07005450 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08005451
Sunil Ravi7f769292024-07-23 22:21:32 +00005452 if (wpa_s->connect_without_scan || request_new_scan ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005453 wpa_supplicant_fast_associate(wpa_s) != 1) {
5454 wpa_s->scan_req = NORMAL_SCAN_REQ;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005455 wpas_scan_reset_sched_scan(wpa_s);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08005456 wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005457 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005458
5459 if (ssid)
5460 wpas_notify_network_selected(wpa_s, ssid);
5461}
5462
5463
5464/**
Hai Shalomc1a21442022-02-04 13:43:00 -08005465 * wpas_remove_cred - Remove the specified credential and all the network
5466 * entries created based on the removed credential
5467 * @wpa_s: wpa_supplicant structure for a network interface
5468 * @cred: The credential to remove
5469 * Returns: 0 on success, -1 on failure
5470 */
5471int wpas_remove_cred(struct wpa_supplicant *wpa_s, struct wpa_cred *cred)
5472{
5473 struct wpa_ssid *ssid, *next;
5474 int id;
5475
5476 if (!cred) {
5477 wpa_printf(MSG_DEBUG, "Could not find cred");
5478 return -1;
5479 }
5480
5481 id = cred->id;
5482 if (wpa_config_remove_cred(wpa_s->conf, id) < 0) {
5483 wpa_printf(MSG_DEBUG, "Could not find cred %d", id);
5484 return -1;
5485 }
5486
5487 wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id);
5488
5489 /* Remove any network entry created based on the removed credential */
5490 ssid = wpa_s->conf->ssid;
5491 while (ssid) {
5492 next = ssid->next;
5493
5494 if (ssid->parent_cred == cred) {
5495 wpa_printf(MSG_DEBUG,
5496 "Remove network id %d since it used the removed credential",
5497 ssid->id);
5498 if (wpa_supplicant_remove_network(wpa_s, ssid->id) ==
5499 -1) {
5500 wpa_printf(MSG_DEBUG,
5501 "Could not find network id=%d",
5502 ssid->id);
5503 }
5504 }
5505
5506 ssid = next;
5507 }
5508
5509 return 0;
5510}
5511
5512
5513/**
5514 * wpas_remove_cred - Remove all the Interworking credentials
5515 * @wpa_s: wpa_supplicant structure for a network interface
5516 * Returns: 0 on success, -1 on failure
5517 */
5518int wpas_remove_all_creds(struct wpa_supplicant *wpa_s)
5519{
5520 int res, ret = 0;
5521 struct wpa_cred *cred, *prev;
5522
5523 cred = wpa_s->conf->cred;
5524 while (cred) {
5525 prev = cred;
5526 cred = cred->next;
5527 res = wpas_remove_cred(wpa_s, prev);
5528 if (res < 0) {
5529 wpa_printf(MSG_DEBUG,
5530 "Removal of all credentials failed - failed to remove credential id=%d",
5531 prev->id);
5532 ret = -1;
5533 }
5534 }
5535
5536 return ret;
5537}
5538
5539
5540/**
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08005541 * wpas_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
5542 * @wpa_s: wpa_supplicant structure for a network interface
5543 * @pkcs11_engine_path: PKCS #11 engine path or NULL
5544 * @pkcs11_module_path: PKCS #11 module path or NULL
5545 * Returns: 0 on success; -1 on failure
5546 *
5547 * Sets the PKCS #11 engine and module path. Both have to be NULL or a valid
5548 * path. If resetting the EAPOL state machine with the new PKCS #11 engine and
5549 * module path fails the paths will be reset to the default value (NULL).
5550 */
5551int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s,
5552 const char *pkcs11_engine_path,
5553 const char *pkcs11_module_path)
5554{
5555 char *pkcs11_engine_path_copy = NULL;
5556 char *pkcs11_module_path_copy = NULL;
5557
5558 if (pkcs11_engine_path != NULL) {
5559 pkcs11_engine_path_copy = os_strdup(pkcs11_engine_path);
5560 if (pkcs11_engine_path_copy == NULL)
5561 return -1;
5562 }
5563 if (pkcs11_module_path != NULL) {
5564 pkcs11_module_path_copy = os_strdup(pkcs11_module_path);
Dmitry Shmidt97672262014-02-03 13:02:54 -08005565 if (pkcs11_module_path_copy == NULL) {
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08005566 os_free(pkcs11_engine_path_copy);
5567 return -1;
5568 }
5569 }
5570
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005571#ifndef CONFIG_PKCS11_ENGINE_PATH
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08005572 os_free(wpa_s->conf->pkcs11_engine_path);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08005573 wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path_copy;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005574#endif /* CONFIG_PKCS11_ENGINE_PATH */
5575#ifndef CONFIG_PKCS11_MODULE_PATH
5576 os_free(wpa_s->conf->pkcs11_module_path);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08005577 wpa_s->conf->pkcs11_module_path = pkcs11_module_path_copy;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005578#endif /* CONFIG_PKCS11_MODULE_PATH */
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08005579
5580 wpa_sm_set_eapol(wpa_s->wpa, NULL);
5581 eapol_sm_deinit(wpa_s->eapol);
5582 wpa_s->eapol = NULL;
5583 if (wpa_supplicant_init_eapol(wpa_s)) {
5584 /* Error -> Reset paths to the default value (NULL) once. */
5585 if (pkcs11_engine_path != NULL && pkcs11_module_path != NULL)
5586 wpas_set_pkcs11_engine_and_module_path(wpa_s, NULL,
5587 NULL);
5588
5589 return -1;
5590 }
5591 wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
5592
5593 return 0;
5594}
5595
5596
5597/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005598 * wpa_supplicant_set_ap_scan - Set AP scan mode for interface
5599 * @wpa_s: wpa_supplicant structure for a network interface
5600 * @ap_scan: AP scan mode
5601 * Returns: 0 if succeed or -1 if ap_scan has an invalid value
5602 *
5603 */
5604int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
5605{
5606
5607 int old_ap_scan;
5608
5609 if (ap_scan < 0 || ap_scan > 2)
5610 return -1;
5611
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005612 if (ap_scan == 2 && os_strcmp(wpa_s->driver->name, "nl80211") == 0) {
5613 wpa_printf(MSG_INFO,
5614 "Note: nl80211 driver interface is not designed to be used with ap_scan=2; this can result in connection failures");
5615 }
5616
Dmitry Shmidt114c3862011-08-16 11:52:06 -07005617#ifdef ANDROID
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005618 if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan &&
5619 wpa_s->wpa_state >= WPA_ASSOCIATING &&
5620 wpa_s->wpa_state < WPA_COMPLETED) {
5621 wpa_printf(MSG_ERROR, "ap_scan = %d (%d) rejected while "
5622 "associating", wpa_s->conf->ap_scan, ap_scan);
Dmitry Shmidt114c3862011-08-16 11:52:06 -07005623 return 0;
5624 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005625#endif /* ANDROID */
Dmitry Shmidt114c3862011-08-16 11:52:06 -07005626
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005627 old_ap_scan = wpa_s->conf->ap_scan;
5628 wpa_s->conf->ap_scan = ap_scan;
5629
5630 if (old_ap_scan != wpa_s->conf->ap_scan)
5631 wpas_notify_ap_scan_changed(wpa_s);
5632
5633 return 0;
5634}
5635
5636
5637/**
5638 * wpa_supplicant_set_bss_expiration_age - Set BSS entry expiration age
5639 * @wpa_s: wpa_supplicant structure for a network interface
5640 * @expire_age: Expiration age in seconds
5641 * Returns: 0 if succeed or -1 if expire_age has an invalid value
5642 *
5643 */
5644int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
5645 unsigned int bss_expire_age)
5646{
5647 if (bss_expire_age < 10) {
5648 wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration age %u",
5649 bss_expire_age);
5650 return -1;
5651 }
5652 wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration age: %d sec",
5653 bss_expire_age);
5654 wpa_s->conf->bss_expiration_age = bss_expire_age;
5655
5656 return 0;
5657}
5658
5659
5660/**
5661 * wpa_supplicant_set_bss_expiration_count - Set BSS entry expiration scan count
5662 * @wpa_s: wpa_supplicant structure for a network interface
5663 * @expire_count: number of scans after which an unseen BSS is reclaimed
5664 * Returns: 0 if succeed or -1 if expire_count has an invalid value
5665 *
5666 */
5667int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
5668 unsigned int bss_expire_count)
5669{
5670 if (bss_expire_count < 1) {
5671 wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration count %u",
5672 bss_expire_count);
5673 return -1;
5674 }
5675 wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration scan count: %u",
5676 bss_expire_count);
5677 wpa_s->conf->bss_expiration_scan_count = bss_expire_count;
5678
5679 return 0;
5680}
5681
5682
5683/**
Dmitry Shmidt04949592012-07-19 12:16:46 -07005684 * wpa_supplicant_set_scan_interval - Set scan interval
5685 * @wpa_s: wpa_supplicant structure for a network interface
5686 * @scan_interval: scan interval in seconds
5687 * Returns: 0 if succeed or -1 if scan_interval has an invalid value
5688 *
5689 */
5690int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
5691 int scan_interval)
5692{
5693 if (scan_interval < 0) {
5694 wpa_msg(wpa_s, MSG_ERROR, "Invalid scan interval %d",
5695 scan_interval);
5696 return -1;
5697 }
5698 wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
5699 scan_interval);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08005700 wpa_supplicant_update_scan_int(wpa_s, scan_interval);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005701
5702 return 0;
5703}
5704
5705
5706/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005707 * wpa_supplicant_set_debug_params - Set global debug params
5708 * @global: wpa_global structure
5709 * @debug_level: debug level
5710 * @debug_timestamp: determines if show timestamp in debug data
5711 * @debug_show_keys: determines if show keys in debug data
5712 * Returns: 0 if succeed or -1 if debug_level has wrong value
5713 */
5714int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
5715 int debug_timestamp, int debug_show_keys)
5716{
5717
5718 int old_level, old_timestamp, old_show_keys;
5719
5720 /* check for allowed debuglevels */
5721 if (debug_level != MSG_EXCESSIVE &&
5722 debug_level != MSG_MSGDUMP &&
5723 debug_level != MSG_DEBUG &&
5724 debug_level != MSG_INFO &&
5725 debug_level != MSG_WARNING &&
5726 debug_level != MSG_ERROR)
5727 return -1;
5728
5729 old_level = wpa_debug_level;
5730 old_timestamp = wpa_debug_timestamp;
5731 old_show_keys = wpa_debug_show_keys;
5732
5733 wpa_debug_level = debug_level;
5734 wpa_debug_timestamp = debug_timestamp ? 1 : 0;
5735 wpa_debug_show_keys = debug_show_keys ? 1 : 0;
5736
5737 if (wpa_debug_level != old_level)
5738 wpas_notify_debug_level_changed(global);
5739 if (wpa_debug_timestamp != old_timestamp)
5740 wpas_notify_debug_timestamp_changed(global);
5741 if (wpa_debug_show_keys != old_show_keys)
5742 wpas_notify_debug_show_keys_changed(global);
5743
5744 return 0;
5745}
5746
5747
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005748#ifdef CONFIG_OWE
5749static int owe_trans_ssid_match(struct wpa_supplicant *wpa_s, const u8 *bssid,
5750 const u8 *entry_ssid, size_t entry_ssid_len)
5751{
Sunil Ravic0f5d412024-09-11 22:12:49 +00005752 const u8 *owe, *owe_bssid, *owe_ssid;
5753 size_t owe_ssid_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005754 struct wpa_bss *bss;
5755
5756 /* Check network profile SSID aganst the SSID in the
5757 * OWE Transition Mode element. */
5758
5759 bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
5760 if (!bss)
5761 return 0;
5762
5763 owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
5764 if (!owe)
5765 return 0;
5766
Sunil Ravic0f5d412024-09-11 22:12:49 +00005767 if (wpas_get_owe_trans_network(owe, &owe_bssid, &owe_ssid,
5768 &owe_ssid_len))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005769 return 0;
5770
Sunil Ravic0f5d412024-09-11 22:12:49 +00005771 return entry_ssid_len == owe_ssid_len &&
5772 os_memcmp(owe_ssid, entry_ssid, owe_ssid_len) == 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005773}
5774#endif /* CONFIG_OWE */
5775
5776
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005777/**
5778 * wpa_supplicant_get_ssid - Get a pointer to the current network structure
5779 * @wpa_s: Pointer to wpa_supplicant data
5780 * Returns: A pointer to the current network structure or %NULL on failure
5781 */
5782struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
5783{
5784 struct wpa_ssid *entry;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07005785 u8 ssid[SSID_MAX_LEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005786 int res;
5787 size_t ssid_len;
5788 u8 bssid[ETH_ALEN];
5789 int wired;
5790
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005791 res = wpa_drv_get_ssid(wpa_s, ssid);
5792 if (res < 0) {
5793 wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
5794 "driver");
5795 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005796 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005797 ssid_len = res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005798
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005799 if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005800 wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from "
5801 "driver");
5802 return NULL;
5803 }
5804
5805 wired = wpa_s->conf->ap_scan == 0 &&
5806 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED);
5807
5808 entry = wpa_s->conf->ssid;
5809 while (entry) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07005810 if (!wpas_network_disabled(wpa_s, entry) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005811 ((ssid_len == entry->ssid_len &&
Hai Shalom021b0b52019-04-10 11:17:58 -07005812 (!entry->ssid ||
5813 os_memcmp(ssid, entry->ssid, ssid_len) == 0)) ||
5814 wired) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005815 (!entry->bssid_set ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005816 ether_addr_equal(bssid, entry->bssid)))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005817 return entry;
5818#ifdef CONFIG_WPS
Dmitry Shmidt04949592012-07-19 12:16:46 -07005819 if (!wpas_network_disabled(wpa_s, entry) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005820 (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
5821 (entry->ssid == NULL || entry->ssid_len == 0) &&
5822 (!entry->bssid_set ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005823 ether_addr_equal(bssid, entry->bssid)))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005824 return entry;
5825#endif /* CONFIG_WPS */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005826
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005827#ifdef CONFIG_OWE
5828 if (!wpas_network_disabled(wpa_s, entry) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005829 (entry->ssid &&
5830 owe_trans_ssid_match(wpa_s, bssid, entry->ssid,
5831 entry->ssid_len)) &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005832 (!entry->bssid_set ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005833 ether_addr_equal(bssid, entry->bssid)))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005834 return entry;
5835#endif /* CONFIG_OWE */
5836
Dmitry Shmidt04949592012-07-19 12:16:46 -07005837 if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005838 entry->ssid_len == 0 &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005839 ether_addr_equal(bssid, entry->bssid))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005840 return entry;
5841
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005842 entry = entry->next;
5843 }
5844
5845 return NULL;
5846}
5847
5848
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005849static int select_driver(struct wpa_supplicant *wpa_s, int i)
5850{
5851 struct wpa_global *global = wpa_s->global;
5852
5853 if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
Dmitry Shmidte4663042016-04-04 10:07:49 -07005854 global->drv_priv[i] = wpa_drivers[i]->global_init(global);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005855 if (global->drv_priv[i] == NULL) {
5856 wpa_printf(MSG_ERROR, "Failed to initialize driver "
5857 "'%s'", wpa_drivers[i]->name);
5858 return -1;
5859 }
5860 }
5861
5862 wpa_s->driver = wpa_drivers[i];
5863 wpa_s->global_drv_priv = global->drv_priv[i];
5864
5865 return 0;
5866}
5867
5868
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005869static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
5870 const char *name)
5871{
5872 int i;
5873 size_t len;
5874 const char *pos, *driver = name;
5875
5876 if (wpa_s == NULL)
5877 return -1;
5878
5879 if (wpa_drivers[0] == NULL) {
5880 wpa_msg(wpa_s, MSG_ERROR, "No driver interfaces build into "
5881 "wpa_supplicant");
5882 return -1;
5883 }
5884
5885 if (name == NULL) {
Hai Shalomc1a21442022-02-04 13:43:00 -08005886 /* Default to first successful driver in the list */
5887 for (i = 0; wpa_drivers[i]; i++) {
5888 if (select_driver(wpa_s, i) == 0)
5889 return 0;
5890 }
5891 /* Drivers have each reported failure, so no wpa_msg() here. */
5892 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005893 }
5894
5895 do {
5896 pos = os_strchr(driver, ',');
5897 if (pos)
5898 len = pos - driver;
5899 else
5900 len = os_strlen(driver);
5901
5902 for (i = 0; wpa_drivers[i]; i++) {
5903 if (os_strlen(wpa_drivers[i]->name) == len &&
5904 os_strncmp(driver, wpa_drivers[i]->name, len) ==
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005905 0) {
5906 /* First driver that succeeds wins */
5907 if (select_driver(wpa_s, i) == 0)
5908 return 0;
5909 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005910 }
5911
5912 driver = pos + 1;
5913 } while (pos);
5914
5915 wpa_msg(wpa_s, MSG_ERROR, "Unsupported driver '%s'", name);
5916 return -1;
5917}
5918
5919
5920/**
5921 * wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant
5922 * @ctx: Context pointer (wpa_s); this is the ctx variable registered
5923 * with struct wpa_driver_ops::init()
5924 * @src_addr: Source address of the EAPOL frame
5925 * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
5926 * @len: Length of the EAPOL data
Sunil8cd6f4d2022-06-28 18:40:46 +00005927 * @encrypted: Whether the frame was encrypted
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005928 *
5929 * This function is called for each received EAPOL frame. Most driver
5930 * interfaces rely on more generic OS mechanism for receiving frames through
5931 * l2_packet, but if such a mechanism is not available, the driver wrapper may
5932 * take care of received EAPOL frames and deliver them to the core supplicant
5933 * code by calling this function.
5934 */
5935void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
Sunil8cd6f4d2022-06-28 18:40:46 +00005936 const u8 *buf, size_t len,
5937 enum frame_encryption encrypted)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005938{
5939 struct wpa_supplicant *wpa_s = ctx;
Sunil Ravi77d572f2023-01-17 23:58:31 +00005940 const u8 *connected_addr = wpa_s->valid_links ?
5941 wpa_s->ap_mld_addr : wpa_s->bssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005942
Sunil8cd6f4d2022-06-28 18:40:46 +00005943 wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " (encrypted=%d)",
5944 MAC2STR(src_addr), encrypted);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005945 wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
5946
Hai Shalomc1a21442022-02-04 13:43:00 -08005947 if (wpa_s->own_disconnect_req) {
5948 wpa_printf(MSG_DEBUG,
5949 "Drop received EAPOL frame as we are disconnecting");
5950 return;
5951 }
5952
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005953#ifdef CONFIG_TESTING_OPTIONS
Hai Shalomc1a21442022-02-04 13:43:00 -08005954 wpa_msg_ctrl(wpa_s, MSG_INFO, "EAPOL-RX " MACSTR " %zu",
5955 MAC2STR(src_addr), len);
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005956 if (wpa_s->ignore_auth_resp) {
5957 wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
5958 return;
5959 }
5960#endif /* CONFIG_TESTING_OPTIONS */
5961
Jouni Malinena05074c2012-12-21 21:35:35 +02005962 if (wpa_s->wpa_state < WPA_ASSOCIATED ||
5963 (wpa_s->last_eapol_matches_bssid &&
5964#ifdef CONFIG_AP
5965 !wpa_s->ap_iface &&
5966#endif /* CONFIG_AP */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005967 !ether_addr_equal(src_addr, connected_addr))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005968 /*
5969 * There is possible race condition between receiving the
5970 * association event and the EAPOL frame since they are coming
5971 * through different paths from the driver. In order to avoid
5972 * issues in trying to process the EAPOL frame before receiving
5973 * association information, lets queue it for processing until
Jouni Malinena05074c2012-12-21 21:35:35 +02005974 * the association event is received. This may also be needed in
5975 * driver-based roaming case, so also use src_addr != BSSID as a
5976 * trigger if we have previously confirmed that the
5977 * Authenticator uses BSSID as the src_addr (which is not the
5978 * case with wired IEEE 802.1X).
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005979 */
Sunil Ravi77d572f2023-01-17 23:58:31 +00005980 wpa_dbg(wpa_s, MSG_DEBUG,
5981 "Not associated - Delay processing of received EAPOL frame (state=%s connected_addr="
5982 MACSTR ")",
Jouni Malinena05074c2012-12-21 21:35:35 +02005983 wpa_supplicant_state_txt(wpa_s->wpa_state),
Sunil Ravi77d572f2023-01-17 23:58:31 +00005984 MAC2STR(connected_addr));
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00005985 delay_processing:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005986 wpabuf_free(wpa_s->pending_eapol_rx);
5987 wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
5988 if (wpa_s->pending_eapol_rx) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005989 os_get_reltime(&wpa_s->pending_eapol_rx_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005990 os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
5991 ETH_ALEN);
Sunil8cd6f4d2022-06-28 18:40:46 +00005992 wpa_s->pending_eapol_encrypted = encrypted;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005993 }
5994 return;
5995 }
5996
Jouni Malinena05074c2012-12-21 21:35:35 +02005997 wpa_s->last_eapol_matches_bssid =
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005998 ether_addr_equal(src_addr, connected_addr);
Jouni Malinena05074c2012-12-21 21:35:35 +02005999
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006000#ifdef CONFIG_AP
6001 if (wpa_s->ap_iface) {
Sunil8cd6f4d2022-06-28 18:40:46 +00006002 wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len,
6003 encrypted);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006004 return;
6005 }
6006#endif /* CONFIG_AP */
6007
6008 if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
6009 wpa_dbg(wpa_s, MSG_DEBUG, "Ignored received EAPOL frame since "
6010 "no key management is configured");
6011 return;
6012 }
6013
6014 if (wpa_s->eapol_received == 0 &&
Hai Shalom74f70d42019-02-11 14:42:39 -08006015 (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006016 !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
6017 wpa_s->wpa_state != WPA_COMPLETED) &&
6018 (wpa_s->current_ssid == NULL ||
Hai Shalom81f62d82019-07-22 12:10:00 -07006019 wpa_s->current_ssid->mode != WPAS_MODE_IBSS)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006020 /* Timeout for completing IEEE 802.1X and WPA authentication */
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07006021 int timeout = 10;
6022
6023 if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
6024 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
6025 wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
6026 /* Use longer timeout for IEEE 802.1X/EAP */
6027 timeout = 70;
6028 }
6029
Dmitry Shmidt8bd70b72015-05-26 16:02:19 -07006030#ifdef CONFIG_WPS
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07006031 if (wpa_s->current_ssid && wpa_s->current_bss &&
6032 (wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
6033 eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
6034 /*
6035 * Use shorter timeout if going through WPS AP iteration
6036 * for PIN config method with an AP that does not
6037 * advertise Selected Registrar.
6038 */
6039 struct wpabuf *wps_ie;
6040
6041 wps_ie = wpa_bss_get_vendor_ie_multi(
6042 wpa_s->current_bss, WPS_IE_VENDOR_TYPE);
6043 if (wps_ie &&
6044 !wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1))
6045 timeout = 10;
6046 wpabuf_free(wps_ie);
6047 }
Dmitry Shmidt8bd70b72015-05-26 16:02:19 -07006048#endif /* CONFIG_WPS */
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07006049
6050 wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006051 }
6052 wpa_s->eapol_received++;
6053
6054 if (wpa_s->countermeasures) {
6055 wpa_msg(wpa_s, MSG_INFO, "WPA: Countermeasures - dropped "
6056 "EAPOL packet");
6057 return;
6058 }
6059
6060#ifdef CONFIG_IBSS_RSN
6061 if (wpa_s->current_ssid &&
6062 wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
Sunil8cd6f4d2022-06-28 18:40:46 +00006063 ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len,
6064 encrypted);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006065 return;
6066 }
6067#endif /* CONFIG_IBSS_RSN */
6068
6069 /* Source address of the incoming EAPOL frame could be compared to the
6070 * current BSSID. However, it is possible that a centralized
6071 * Authenticator could be using another MAC address than the BSSID of
6072 * an AP, so just allow any address to be used for now. The replies are
6073 * still sent to the current BSSID (if available), though. */
6074
6075 os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
6076 if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006077 wpa_s->key_mgmt != WPA_KEY_MGMT_OWE &&
6078 wpa_s->key_mgmt != WPA_KEY_MGMT_DPP &&
Sunil8cd6f4d2022-06-28 18:40:46 +00006079 eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len,
6080 encrypted) > 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006081 return;
6082 wpa_drv_poll(wpa_s);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00006083 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
6084 if (wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len,
6085 encrypted) == -2 &&
6086#ifdef CONFIG_AP
6087 !wpa_s->ap_iface &&
6088#endif /* CONFIG_AP */
6089 wpa_s->last_eapol_matches_bssid) {
6090 /* Handle the case where reassociation occurs to the
6091 * current connected AP */
6092 wpa_dbg(wpa_s, MSG_DEBUG,
6093 "Delay processing of received EAPOL frame for reassociation to the current connected AP (state=%s connected_addr="
6094 MACSTR ")",
6095 wpa_supplicant_state_txt(wpa_s->wpa_state),
6096 MAC2STR(connected_addr));
6097 goto delay_processing;
6098 }
6099 } else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006100 /*
Hai Shalome21d4e82020-04-29 16:34:06 -07006101 * Set portValid = true here since we are going to skip 4-way
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006102 * handshake processing which would normally set portValid. We
6103 * need this to allow the EAPOL state machines to be completed
6104 * without going through EAPOL-Key handshake.
6105 */
Hai Shalome21d4e82020-04-29 16:34:06 -07006106 eapol_sm_notify_portValid(wpa_s->eapol, true);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006107 }
6108}
6109
6110
Sunil8cd6f4d2022-06-28 18:40:46 +00006111static void wpa_supplicant_rx_eapol_cb(void *ctx, const u8 *src_addr,
6112 const u8 *buf, size_t len)
6113{
6114 wpa_supplicant_rx_eapol(ctx, src_addr, buf, len,
6115 FRAME_ENCRYPTION_UNKNOWN);
6116}
6117
6118
Hai Shalomb755a2a2020-04-23 21:49:02 -07006119static int wpas_eapol_needs_l2_packet(struct wpa_supplicant *wpa_s)
6120{
6121 return !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) ||
6122 !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX);
6123}
6124
6125
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006126int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006127{
Sunil Ravi77d572f2023-01-17 23:58:31 +00006128 u8 prev_mac_addr[ETH_ALEN];
6129
6130 os_memcpy(prev_mac_addr, wpa_s->own_addr, ETH_ALEN);
6131
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006132 if ((!wpa_s->p2p_mgmt ||
6133 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
6134 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006135 l2_packet_deinit(wpa_s->l2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006136 wpa_s->l2 = l2_packet_init(wpa_s->ifname,
6137 wpa_drv_get_mac_addr(wpa_s),
6138 ETH_P_EAPOL,
Hai Shalomb755a2a2020-04-23 21:49:02 -07006139 wpas_eapol_needs_l2_packet(wpa_s) ?
Sunil8cd6f4d2022-06-28 18:40:46 +00006140 wpa_supplicant_rx_eapol_cb : NULL,
Hai Shalomb755a2a2020-04-23 21:49:02 -07006141 wpa_s, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006142 if (wpa_s->l2 == NULL)
6143 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006144
6145 if (l2_packet_set_packet_filter(wpa_s->l2,
6146 L2_PACKET_FILTER_PKTTYPE))
6147 wpa_dbg(wpa_s, MSG_DEBUG,
6148 "Failed to attach pkt_type filter");
Hai Shalomb755a2a2020-04-23 21:49:02 -07006149
6150 if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
6151 wpa_msg(wpa_s, MSG_ERROR,
6152 "Failed to get own L2 address");
6153 return -1;
6154 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006155 } else {
6156 const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
6157 if (addr)
6158 os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
6159 }
6160
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006161 wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
Mikael Kanstrupcc779b82019-08-16 08:50:54 +02006162 wpas_wps_update_mac_addr(wpa_s);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006163
Hai Shalomc3565922019-10-28 11:58:20 -07006164#ifdef CONFIG_FST
6165 if (wpa_s->fst)
6166 fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
6167#endif /* CONFIG_FST */
6168
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006169 if (!ether_addr_equal(prev_mac_addr, wpa_s->own_addr))
Sunil Ravi77d572f2023-01-17 23:58:31 +00006170 wpas_notify_mac_address_changed(wpa_s);
6171
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006172 return 0;
6173}
6174
6175
Dmitry Shmidt04949592012-07-19 12:16:46 -07006176static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
6177 const u8 *buf, size_t len)
6178{
6179 struct wpa_supplicant *wpa_s = ctx;
6180 const struct l2_ethhdr *eth;
6181
6182 if (len < sizeof(*eth))
6183 return;
6184 eth = (const struct l2_ethhdr *) buf;
6185
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006186 if (!ether_addr_equal(eth->h_dest, wpa_s->own_addr) &&
Dmitry Shmidt04949592012-07-19 12:16:46 -07006187 !(eth->h_dest[0] & 0x01)) {
6188 wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
6189 " (bridge - not for this interface - ignore)",
6190 MAC2STR(src_addr), MAC2STR(eth->h_dest));
6191 return;
6192 }
6193
6194 wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
6195 " (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
6196 wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
Sunil8cd6f4d2022-06-28 18:40:46 +00006197 len - sizeof(*eth), FRAME_ENCRYPTION_UNKNOWN);
Dmitry Shmidt04949592012-07-19 12:16:46 -07006198}
6199
6200
Hai Shalom899fcc72020-10-19 14:38:18 -07006201int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s,
6202 const char *bridge_ifname)
6203{
6204 if (wpa_s->wpa_state > WPA_SCANNING)
6205 return -EBUSY;
6206
6207 if (bridge_ifname &&
6208 os_strlen(bridge_ifname) >= sizeof(wpa_s->bridge_ifname))
6209 return -EINVAL;
6210
6211 if (!bridge_ifname)
6212 bridge_ifname = "";
6213
6214 if (os_strcmp(wpa_s->bridge_ifname, bridge_ifname) == 0)
6215 return 0;
6216
6217 if (wpa_s->l2_br) {
6218 l2_packet_deinit(wpa_s->l2_br);
6219 wpa_s->l2_br = NULL;
6220 }
6221
6222 os_strlcpy(wpa_s->bridge_ifname, bridge_ifname,
6223 sizeof(wpa_s->bridge_ifname));
6224
6225 if (wpa_s->bridge_ifname[0]) {
6226 wpa_dbg(wpa_s, MSG_DEBUG,
6227 "Receiving packets from bridge interface '%s'",
6228 wpa_s->bridge_ifname);
6229 wpa_s->l2_br = l2_packet_init_bridge(
6230 wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
6231 ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
6232 if (!wpa_s->l2_br) {
6233 wpa_msg(wpa_s, MSG_ERROR,
6234 "Failed to open l2_packet connection for the bridge interface '%s'",
6235 wpa_s->bridge_ifname);
6236 goto fail;
6237 }
6238 }
6239
6240#ifdef CONFIG_TDLS
6241 if (!wpa_s->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
6242 goto fail;
6243#endif /* CONFIG_TDLS */
6244
6245 return 0;
6246fail:
6247 wpa_s->bridge_ifname[0] = 0;
6248 if (wpa_s->l2_br) {
6249 l2_packet_deinit(wpa_s->l2_br);
6250 wpa_s->l2_br = NULL;
6251 }
6252#ifdef CONFIG_TDLS
6253 if (!wpa_s->p2p_mgmt)
6254 wpa_tdls_init(wpa_s->wpa);
6255#endif /* CONFIG_TDLS */
6256 return -EIO;
6257}
6258
6259
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006260/**
6261 * wpa_supplicant_driver_init - Initialize driver interface parameters
6262 * @wpa_s: Pointer to wpa_supplicant data
6263 * Returns: 0 on success, -1 on failure
6264 *
6265 * This function is called to initialize driver interface parameters.
6266 * wpa_drv_init() must have been called before this function to initialize the
6267 * driver interface.
6268 */
6269int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
6270{
6271 static int interface_count = 0;
6272
6273 if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
6274 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006275
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006276 wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
6277 MAC2STR(wpa_s->own_addr));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006278 os_memcpy(wpa_s->perm_addr, wpa_s->own_addr, ETH_ALEN);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006279 wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
6280
Hai Shalomb755a2a2020-04-23 21:49:02 -07006281 if (wpa_s->bridge_ifname[0] && wpas_eapol_needs_l2_packet(wpa_s)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006282 wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
6283 "interface '%s'", wpa_s->bridge_ifname);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08006284 wpa_s->l2_br = l2_packet_init_bridge(
6285 wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
6286 ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006287 if (wpa_s->l2_br == NULL) {
6288 wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
6289 "connection for the bridge interface '%s'",
6290 wpa_s->bridge_ifname);
6291 return -1;
6292 }
6293 }
6294
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006295 if (wpa_s->conf->ap_scan == 2 &&
6296 os_strcmp(wpa_s->driver->name, "nl80211") == 0) {
6297 wpa_printf(MSG_INFO,
6298 "Note: nl80211 driver interface is not designed to be used with ap_scan=2; this can result in connection failures");
6299 }
6300
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006301 wpa_clear_keys(wpa_s, NULL);
6302
6303 /* Make sure that TKIP countermeasures are not left enabled (could
6304 * happen if wpa_supplicant is killed during countermeasures. */
6305 wpa_drv_set_countermeasures(wpa_s, 0);
6306
6307 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: flushing PMKID list in the driver");
6308 wpa_drv_flush_pmkid(wpa_s);
6309
6310 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006311 wpa_s->prev_scan_wildcard = 0;
6312
Dmitry Shmidt04949592012-07-19 12:16:46 -07006313 if (wpa_supplicant_enabled_networks(wpa_s)) {
Dmitry Shmidt9e3f8ee2014-01-17 10:52:01 -08006314 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
6315 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
6316 interface_count = 0;
6317 }
Keith Mok4389c282022-11-23 21:36:48 +00006318#ifndef CONFIG_CTRL_IFACE_AIDL
Dmitry Shmidta38abf92014-03-06 13:38:44 -08006319 if (!wpa_s->p2p_mgmt &&
Dmitry Shmidt98660862014-03-11 17:26:21 -07006320 wpa_supplicant_delayed_sched_scan(wpa_s,
6321 interface_count % 3,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006322 100000))
Dmitry Shmidt98660862014-03-11 17:26:21 -07006323 wpa_supplicant_req_scan(wpa_s, interface_count % 3,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006324 100000);
Keith Mok4389c282022-11-23 21:36:48 +00006325#endif /* CONFIG_CTRL_IFACE_AIDL */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006326 interface_count++;
6327 } else
6328 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
6329
6330 return 0;
6331}
6332
6333
6334static int wpa_supplicant_daemon(const char *pid_file)
6335{
6336 wpa_printf(MSG_DEBUG, "Daemonize..");
6337 return os_daemonize(pid_file);
6338}
6339
6340
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08006341static struct wpa_supplicant *
6342wpa_supplicant_alloc(struct wpa_supplicant *parent)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006343{
6344 struct wpa_supplicant *wpa_s;
6345
6346 wpa_s = os_zalloc(sizeof(*wpa_s));
6347 if (wpa_s == NULL)
6348 return NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006349 wpa_s->scan_req = INITIAL_SCAN_REQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006350 wpa_s->scan_interval = 5;
6351 wpa_s->new_connection = 1;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08006352 wpa_s->parent = parent ? parent : wpa_s;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08006353 wpa_s->p2pdev = wpa_s->parent;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00006354#ifdef CONFIG_P2P
6355 if (parent)
6356 wpa_s->p2p_mode = parent->p2p_mode;
6357#endif /* CONFIG_P2P */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006358 wpa_s->sched_scanning = 0;
Hai Shalom60840252021-02-19 19:02:11 -08006359 wpa_s->setband_mask = WPA_SETBAND_AUTO;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006360
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006361 dl_list_init(&wpa_s->bss_tmp_disallowed);
Paul Stewart092955c2017-02-06 09:13:09 -08006362 dl_list_init(&wpa_s->fils_hlp_req);
Hai Shalomfdcde762020-04-02 11:19:20 -07006363#ifdef CONFIG_TESTING_OPTIONS
6364 dl_list_init(&wpa_s->drv_signal_override);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006365 wpa_s->test_assoc_comeback_type = -1;
Hai Shalomfdcde762020-04-02 11:19:20 -07006366#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006367#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08006368 dl_list_init(&wpa_s->active_scs_ids);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006369#endif /* CONFIG_NO_ROBUST_AV */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006370 wpa_s->ml_probe_mld_id = -1;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006371
Sunil Ravi876a49b2025-02-03 19:18:32 +00006372#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
6373#ifdef CONFIG_MESH
6374 dl_list_init(&wpa_s->mesh_external_pmksa_cache);
6375#endif /* CONFIG_MESH */
6376#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
6377
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006378 return wpa_s;
6379}
6380
6381
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006382#ifdef CONFIG_HT_OVERRIDES
6383
6384static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
6385 struct ieee80211_ht_capabilities *htcaps,
6386 struct ieee80211_ht_capabilities *htcaps_mask,
6387 const char *ht_mcs)
6388{
6389 /* parse ht_mcs into hex array */
6390 int i;
6391 const char *tmp = ht_mcs;
6392 char *end = NULL;
6393
6394 /* If ht_mcs is null, do not set anything */
6395 if (!ht_mcs)
6396 return 0;
6397
6398 /* This is what we are setting in the kernel */
6399 os_memset(&htcaps->supported_mcs_set, 0, IEEE80211_HT_MCS_MASK_LEN);
6400
6401 wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
6402
6403 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
Paul Stewart092955c2017-02-06 09:13:09 -08006404 long v;
6405
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006406 errno = 0;
Paul Stewart092955c2017-02-06 09:13:09 -08006407 v = strtol(tmp, &end, 16);
6408
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006409 if (errno == 0) {
6410 wpa_msg(wpa_s, MSG_DEBUG,
6411 "htcap value[%i]: %ld end: %p tmp: %p",
6412 i, v, end, tmp);
6413 if (end == tmp)
6414 break;
6415
6416 htcaps->supported_mcs_set[i] = v;
6417 tmp = end;
6418 } else {
6419 wpa_msg(wpa_s, MSG_ERROR,
6420 "Failed to parse ht-mcs: %s, error: %s\n",
6421 ht_mcs, strerror(errno));
6422 return -1;
6423 }
6424 }
6425
6426 /*
6427 * If we were able to parse any values, then set mask for the MCS set.
6428 */
6429 if (i) {
6430 os_memset(&htcaps_mask->supported_mcs_set, 0xff,
6431 IEEE80211_HT_MCS_MASK_LEN - 1);
6432 /* skip the 3 reserved bits */
6433 htcaps_mask->supported_mcs_set[IEEE80211_HT_MCS_MASK_LEN - 1] =
6434 0x1f;
6435 }
6436
6437 return 0;
6438}
6439
6440
6441static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
6442 struct ieee80211_ht_capabilities *htcaps,
6443 struct ieee80211_ht_capabilities *htcaps_mask,
6444 int disabled)
6445{
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006446 le16 msk;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006447
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006448 if (disabled == -1)
6449 return 0;
6450
Hai Shalom74f70d42019-02-11 14:42:39 -08006451 wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
6452
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006453 msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
6454 htcaps_mask->ht_capabilities_info |= msk;
6455 if (disabled)
6456 htcaps->ht_capabilities_info &= msk;
6457 else
6458 htcaps->ht_capabilities_info |= msk;
6459
6460 return 0;
6461}
6462
6463
6464static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
6465 struct ieee80211_ht_capabilities *htcaps,
6466 struct ieee80211_ht_capabilities *htcaps_mask,
6467 int factor)
6468{
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006469 if (factor == -1)
6470 return 0;
6471
Hai Shalom74f70d42019-02-11 14:42:39 -08006472 wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
6473
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006474 if (factor < 0 || factor > 3) {
6475 wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
6476 "Must be 0-3 or -1", factor);
6477 return -EINVAL;
6478 }
6479
6480 htcaps_mask->a_mpdu_params |= 0x3; /* 2 bits for factor */
6481 htcaps->a_mpdu_params &= ~0x3;
6482 htcaps->a_mpdu_params |= factor & 0x3;
6483
6484 return 0;
6485}
6486
6487
6488static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
6489 struct ieee80211_ht_capabilities *htcaps,
6490 struct ieee80211_ht_capabilities *htcaps_mask,
6491 int density)
6492{
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006493 if (density == -1)
6494 return 0;
6495
Hai Shalom74f70d42019-02-11 14:42:39 -08006496 wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
6497
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006498 if (density < 0 || density > 7) {
6499 wpa_msg(wpa_s, MSG_ERROR,
6500 "ampdu_density: %d out of range. Must be 0-7 or -1.",
6501 density);
6502 return -EINVAL;
6503 }
6504
6505 htcaps_mask->a_mpdu_params |= 0x1C;
6506 htcaps->a_mpdu_params &= ~(0x1C);
6507 htcaps->a_mpdu_params |= (density << 2) & 0x1C;
6508
6509 return 0;
6510}
6511
6512
6513static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
6514 struct ieee80211_ht_capabilities *htcaps,
6515 struct ieee80211_ht_capabilities *htcaps_mask,
6516 int disabled)
6517{
Hai Shalom74f70d42019-02-11 14:42:39 -08006518 if (disabled)
6519 wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006520
Paul Stewart092955c2017-02-06 09:13:09 -08006521 set_disable_ht40(htcaps, disabled);
6522 set_disable_ht40(htcaps_mask, 0);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006523
6524 return 0;
6525}
6526
6527
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006528static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
6529 struct ieee80211_ht_capabilities *htcaps,
6530 struct ieee80211_ht_capabilities *htcaps_mask,
6531 int disabled)
6532{
6533 /* Masking these out disables SGI */
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006534 le16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
6535 HT_CAP_INFO_SHORT_GI40MHZ);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006536
Hai Shalom74f70d42019-02-11 14:42:39 -08006537 if (disabled)
6538 wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006539
6540 if (disabled)
6541 htcaps->ht_capabilities_info &= ~msk;
6542 else
6543 htcaps->ht_capabilities_info |= msk;
6544
6545 htcaps_mask->ht_capabilities_info |= msk;
6546
6547 return 0;
6548}
6549
6550
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006551static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s,
6552 struct ieee80211_ht_capabilities *htcaps,
6553 struct ieee80211_ht_capabilities *htcaps_mask,
6554 int disabled)
6555{
6556 /* Masking these out disables LDPC */
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006557 le16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006558
Hai Shalom74f70d42019-02-11 14:42:39 -08006559 if (disabled)
6560 wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006561
6562 if (disabled)
6563 htcaps->ht_capabilities_info &= ~msk;
6564 else
6565 htcaps->ht_capabilities_info |= msk;
6566
6567 htcaps_mask->ht_capabilities_info |= msk;
6568
6569 return 0;
6570}
6571
6572
Hai Shalom74f70d42019-02-11 14:42:39 -08006573static int wpa_set_tx_stbc(struct wpa_supplicant *wpa_s,
6574 struct ieee80211_ht_capabilities *htcaps,
6575 struct ieee80211_ht_capabilities *htcaps_mask,
6576 int tx_stbc)
6577{
6578 le16 msk = host_to_le16(HT_CAP_INFO_TX_STBC);
6579
6580 if (tx_stbc == -1)
6581 return 0;
6582
6583 wpa_msg(wpa_s, MSG_DEBUG, "set_tx_stbc: %d", tx_stbc);
6584
6585 if (tx_stbc < 0 || tx_stbc > 1) {
6586 wpa_msg(wpa_s, MSG_ERROR,
6587 "tx_stbc: %d out of range. Must be 0-1 or -1", tx_stbc);
6588 return -EINVAL;
6589 }
6590
6591 htcaps_mask->ht_capabilities_info |= msk;
6592 htcaps->ht_capabilities_info &= ~msk;
Sunil Ravi876a49b2025-02-03 19:18:32 +00006593 htcaps->ht_capabilities_info |= host_to_le16(tx_stbc << 7) & msk;
Hai Shalom74f70d42019-02-11 14:42:39 -08006594
6595 return 0;
6596}
6597
6598
6599static int wpa_set_rx_stbc(struct wpa_supplicant *wpa_s,
6600 struct ieee80211_ht_capabilities *htcaps,
6601 struct ieee80211_ht_capabilities *htcaps_mask,
6602 int rx_stbc)
6603{
6604 le16 msk = host_to_le16(HT_CAP_INFO_RX_STBC_MASK);
6605
6606 if (rx_stbc == -1)
6607 return 0;
6608
6609 wpa_msg(wpa_s, MSG_DEBUG, "set_rx_stbc: %d", rx_stbc);
6610
6611 if (rx_stbc < 0 || rx_stbc > 3) {
6612 wpa_msg(wpa_s, MSG_ERROR,
6613 "rx_stbc: %d out of range. Must be 0-3 or -1", rx_stbc);
6614 return -EINVAL;
6615 }
6616
6617 htcaps_mask->ht_capabilities_info |= msk;
6618 htcaps->ht_capabilities_info &= ~msk;
Sunil Ravi876a49b2025-02-03 19:18:32 +00006619 htcaps->ht_capabilities_info |= host_to_le16(rx_stbc << 8) & msk;
Hai Shalom74f70d42019-02-11 14:42:39 -08006620
6621 return 0;
6622}
6623
6624
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006625void wpa_supplicant_apply_ht_overrides(
6626 struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
6627 struct wpa_driver_associate_params *params)
6628{
6629 struct ieee80211_ht_capabilities *htcaps;
6630 struct ieee80211_ht_capabilities *htcaps_mask;
6631
6632 if (!ssid)
6633 return;
6634
6635 params->disable_ht = ssid->disable_ht;
6636 if (!params->htcaps || !params->htcaps_mask)
6637 return;
6638
6639 htcaps = (struct ieee80211_ht_capabilities *) params->htcaps;
6640 htcaps_mask = (struct ieee80211_ht_capabilities *) params->htcaps_mask;
6641 wpa_set_htcap_mcs(wpa_s, htcaps, htcaps_mask, ssid->ht_mcs);
6642 wpa_disable_max_amsdu(wpa_s, htcaps, htcaps_mask,
6643 ssid->disable_max_amsdu);
6644 wpa_set_ampdu_factor(wpa_s, htcaps, htcaps_mask, ssid->ampdu_factor);
6645 wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
6646 wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006647 wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006648 wpa_set_disable_ldpc(wpa_s, htcaps, htcaps_mask, ssid->disable_ldpc);
Hai Shalom74f70d42019-02-11 14:42:39 -08006649 wpa_set_rx_stbc(wpa_s, htcaps, htcaps_mask, ssid->rx_stbc);
6650 wpa_set_tx_stbc(wpa_s, htcaps, htcaps_mask, ssid->tx_stbc);
Dmitry Shmidt61593f02014-04-21 16:27:35 -07006651
6652 if (ssid->ht40_intolerant) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006653 le16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT);
Dmitry Shmidt61593f02014-04-21 16:27:35 -07006654 htcaps->ht_capabilities_info |= bit;
6655 htcaps_mask->ht_capabilities_info |= bit;
6656 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006657}
6658
6659#endif /* CONFIG_HT_OVERRIDES */
6660
6661
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006662#ifdef CONFIG_VHT_OVERRIDES
6663void wpa_supplicant_apply_vht_overrides(
6664 struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
6665 struct wpa_driver_associate_params *params)
6666{
6667 struct ieee80211_vht_capabilities *vhtcaps;
6668 struct ieee80211_vht_capabilities *vhtcaps_mask;
6669
6670 if (!ssid)
6671 return;
6672
6673 params->disable_vht = ssid->disable_vht;
6674
6675 vhtcaps = (void *) params->vhtcaps;
6676 vhtcaps_mask = (void *) params->vhtcaps_mask;
6677
6678 if (!vhtcaps || !vhtcaps_mask)
6679 return;
6680
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006681 vhtcaps->vht_capabilities_info = host_to_le32(ssid->vht_capa);
6682 vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask);
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006683
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006684#ifdef CONFIG_HT_OVERRIDES
Hai Shalom74f70d42019-02-11 14:42:39 -08006685 if (ssid->disable_sgi) {
Sunil Ravi876a49b2025-02-03 19:18:32 +00006686 vhtcaps_mask->vht_capabilities_info |=
6687 host_to_le32(VHT_CAP_SHORT_GI_80 |
6688 VHT_CAP_SHORT_GI_160);
6689 vhtcaps->vht_capabilities_info &=
6690 host_to_le32(~(VHT_CAP_SHORT_GI_80 |
6691 VHT_CAP_SHORT_GI_160));
Hai Shalom74f70d42019-02-11 14:42:39 -08006692 wpa_msg(wpa_s, MSG_DEBUG,
6693 "disable-sgi override specified, vht-caps: 0x%x",
Sunil Ravi876a49b2025-02-03 19:18:32 +00006694 le_to_host32(vhtcaps->vht_capabilities_info));
Hai Shalom74f70d42019-02-11 14:42:39 -08006695 }
6696
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006697 /* if max ampdu is <= 3, we have to make the HT cap the same */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006698 if (ssid->vht_capa_mask & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) {
6699 int max_ampdu;
6700
6701 max_ampdu = (ssid->vht_capa &
6702 VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) >>
6703 VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006704
6705 max_ampdu = max_ampdu < 3 ? max_ampdu : 3;
6706 wpa_set_ampdu_factor(wpa_s,
6707 (void *) params->htcaps,
6708 (void *) params->htcaps_mask,
6709 max_ampdu);
6710 }
6711#endif /* CONFIG_HT_OVERRIDES */
6712
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006713#define OVERRIDE_MCS(i) \
6714 if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \
6715 vhtcaps_mask->vht_supported_mcs_set.tx_map |= \
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006716 host_to_le16(3 << 2 * (i - 1)); \
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006717 vhtcaps->vht_supported_mcs_set.tx_map |= \
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006718 host_to_le16(ssid->vht_tx_mcs_nss_ ##i << \
6719 2 * (i - 1)); \
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006720 } \
6721 if (ssid->vht_rx_mcs_nss_ ##i >= 0) { \
6722 vhtcaps_mask->vht_supported_mcs_set.rx_map |= \
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006723 host_to_le16(3 << 2 * (i - 1)); \
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006724 vhtcaps->vht_supported_mcs_set.rx_map |= \
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006725 host_to_le16(ssid->vht_rx_mcs_nss_ ##i << \
6726 2 * (i - 1)); \
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006727 }
6728
6729 OVERRIDE_MCS(1);
6730 OVERRIDE_MCS(2);
6731 OVERRIDE_MCS(3);
6732 OVERRIDE_MCS(4);
6733 OVERRIDE_MCS(5);
6734 OVERRIDE_MCS(6);
6735 OVERRIDE_MCS(7);
6736 OVERRIDE_MCS(8);
6737}
6738#endif /* CONFIG_VHT_OVERRIDES */
6739
6740
Hai Shalomfdcde762020-04-02 11:19:20 -07006741#ifdef CONFIG_HE_OVERRIDES
6742void wpa_supplicant_apply_he_overrides(
6743 struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
6744 struct wpa_driver_associate_params *params)
6745{
6746 if (!ssid)
6747 return;
6748
6749 params->disable_he = ssid->disable_he;
6750}
6751#endif /* CONFIG_HE_OVERRIDES */
6752
6753
Sunil Ravi77d572f2023-01-17 23:58:31 +00006754void wpa_supplicant_apply_eht_overrides(
6755 struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
6756 struct wpa_driver_associate_params *params)
6757{
6758 if (!ssid)
6759 return;
6760
6761 params->disable_eht = ssid->disable_eht;
6762}
6763
6764
Dmitry Shmidt04949592012-07-19 12:16:46 -07006765static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
6766{
6767#ifdef PCSC_FUNCS
6768 size_t len;
6769
6770 if (!wpa_s->conf->pcsc_reader)
6771 return 0;
6772
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08006773 wpa_s->scard = scard_init(wpa_s->conf->pcsc_reader);
Dmitry Shmidt04949592012-07-19 12:16:46 -07006774 if (!wpa_s->scard)
6775 return 1;
6776
6777 if (wpa_s->conf->pcsc_pin &&
6778 scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) {
6779 scard_deinit(wpa_s->scard);
6780 wpa_s->scard = NULL;
6781 wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed");
6782 return -1;
6783 }
6784
6785 len = sizeof(wpa_s->imsi) - 1;
6786 if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
6787 scard_deinit(wpa_s->scard);
6788 wpa_s->scard = NULL;
6789 wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
6790 return -1;
6791 }
6792 wpa_s->imsi[len] = '\0';
6793
6794 wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
6795
6796 wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
6797 wpa_s->imsi, wpa_s->mnc_len);
6798
6799 wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
6800 eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
6801#endif /* PCSC_FUNCS */
6802
6803 return 0;
6804}
6805
6806
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006807int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
6808{
6809 char *val, *pos;
6810
6811 ext_password_deinit(wpa_s->ext_pw);
6812 wpa_s->ext_pw = NULL;
6813 eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL);
6814
6815 if (!wpa_s->conf->ext_password_backend)
6816 return 0;
6817
6818 val = os_strdup(wpa_s->conf->ext_password_backend);
6819 if (val == NULL)
6820 return -1;
6821 pos = os_strchr(val, ':');
6822 if (pos)
6823 *pos++ = '\0';
6824
6825 wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val);
6826
6827 wpa_s->ext_pw = ext_password_init(val, pos);
6828 os_free(val);
6829 if (wpa_s->ext_pw == NULL) {
6830 wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend");
6831 return -1;
6832 }
6833 eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw);
6834
6835 return 0;
6836}
6837
6838
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006839#ifdef CONFIG_FST
6840
6841static const u8 * wpas_fst_get_bssid_cb(void *ctx)
6842{
6843 struct wpa_supplicant *wpa_s = ctx;
6844
6845 return (is_zero_ether_addr(wpa_s->bssid) ||
6846 wpa_s->wpa_state != WPA_COMPLETED) ? NULL : wpa_s->bssid;
6847}
6848
6849
6850static void wpas_fst_get_channel_info_cb(void *ctx,
6851 enum hostapd_hw_mode *hw_mode,
6852 u8 *channel)
6853{
6854 struct wpa_supplicant *wpa_s = ctx;
6855
6856 if (wpa_s->current_bss) {
6857 *hw_mode = ieee80211_freq_to_chan(wpa_s->current_bss->freq,
6858 channel);
6859 } else if (wpa_s->hw.num_modes) {
6860 *hw_mode = wpa_s->hw.modes[0].mode;
6861 } else {
6862 WPA_ASSERT(0);
6863 *hw_mode = 0;
6864 }
6865}
6866
6867
6868static int wpas_fst_get_hw_modes(void *ctx, struct hostapd_hw_modes **modes)
6869{
6870 struct wpa_supplicant *wpa_s = ctx;
6871
6872 *modes = wpa_s->hw.modes;
6873 return wpa_s->hw.num_modes;
6874}
6875
6876
6877static void wpas_fst_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
6878{
6879 struct wpa_supplicant *wpa_s = ctx;
6880
6881 wpa_hexdump_buf(MSG_DEBUG, "FST: Set IEs", fst_ies);
6882 wpa_s->fst_ies = fst_ies;
6883}
6884
6885
6886static int wpas_fst_send_action_cb(void *ctx, const u8 *da, struct wpabuf *data)
6887{
6888 struct wpa_supplicant *wpa_s = ctx;
6889
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006890 if (!ether_addr_equal(wpa_s->bssid, da)) {
Paul Stewart092955c2017-02-06 09:13:09 -08006891 wpa_printf(MSG_INFO, "FST:%s:bssid=" MACSTR " != da=" MACSTR,
6892 __func__, MAC2STR(wpa_s->bssid), MAC2STR(da));
6893 return -1;
6894 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006895 return wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
Paul Stewart092955c2017-02-06 09:13:09 -08006896 wpa_s->own_addr, wpa_s->bssid,
6897 wpabuf_head(data), wpabuf_len(data),
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006898 0);
6899}
6900
6901
6902static const struct wpabuf * wpas_fst_get_mb_ie_cb(void *ctx, const u8 *addr)
6903{
6904 struct wpa_supplicant *wpa_s = ctx;
6905
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006906 WPA_ASSERT(ether_addr_equal(wpa_s->bssid, addr));
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006907 return wpa_s->received_mb_ies;
6908}
6909
6910
6911static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
6912 const u8 *buf, size_t size)
6913{
6914 struct wpa_supplicant *wpa_s = ctx;
6915 struct mb_ies_info info;
6916
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006917 WPA_ASSERT(ether_addr_equal(wpa_s->bssid, addr));
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006918
6919 if (!mb_ies_info_by_ies(&info, buf, size)) {
6920 wpabuf_free(wpa_s->received_mb_ies);
6921 wpa_s->received_mb_ies = mb_ies_by_info(&info);
6922 }
6923}
6924
6925
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006926static const u8 * wpas_fst_get_peer_first(void *ctx,
6927 struct fst_get_peer_ctx **get_ctx,
Hai Shalome21d4e82020-04-29 16:34:06 -07006928 bool mb_only)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006929{
6930 struct wpa_supplicant *wpa_s = ctx;
6931
6932 *get_ctx = NULL;
6933 if (!is_zero_ether_addr(wpa_s->bssid))
6934 return (wpa_s->received_mb_ies || !mb_only) ?
6935 wpa_s->bssid : NULL;
6936 return NULL;
6937}
6938
6939
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006940static const u8 * wpas_fst_get_peer_next(void *ctx,
6941 struct fst_get_peer_ctx **get_ctx,
Hai Shalome21d4e82020-04-29 16:34:06 -07006942 bool mb_only)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006943{
6944 return NULL;
6945}
6946
6947void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
6948 struct fst_wpa_obj *iface_obj)
6949{
Sunil8cd6f4d2022-06-28 18:40:46 +00006950 os_memset(iface_obj, 0, sizeof(*iface_obj));
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006951 iface_obj->ctx = wpa_s;
6952 iface_obj->get_bssid = wpas_fst_get_bssid_cb;
6953 iface_obj->get_channel_info = wpas_fst_get_channel_info_cb;
6954 iface_obj->get_hw_modes = wpas_fst_get_hw_modes;
6955 iface_obj->set_ies = wpas_fst_set_ies_cb;
6956 iface_obj->send_action = wpas_fst_send_action_cb;
6957 iface_obj->get_mb_ie = wpas_fst_get_mb_ie_cb;
6958 iface_obj->update_mb_ie = wpas_fst_update_mb_ie_cb;
6959 iface_obj->get_peer_first = wpas_fst_get_peer_first;
6960 iface_obj->get_peer_next = wpas_fst_get_peer_next;
6961}
6962#endif /* CONFIG_FST */
6963
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006964static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006965 const struct wpa_driver_capa *capa)
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07006966{
Dmitry Shmidt0207e232014-09-03 14:58:37 -07006967 struct wowlan_triggers *triggers;
6968 int ret = 0;
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07006969
6970 if (!wpa_s->conf->wowlan_triggers)
6971 return 0;
6972
Dmitry Shmidt0207e232014-09-03 14:58:37 -07006973 triggers = wpa_get_wowlan_triggers(wpa_s->conf->wowlan_triggers, capa);
6974 if (triggers) {
6975 ret = wpa_drv_wowlan(wpa_s, triggers);
6976 os_free(triggers);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07006977 }
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07006978 return ret;
6979}
6980
6981
Dmitry Shmidt9c175262016-03-03 10:20:07 -08006982enum wpa_radio_work_band wpas_freq_to_band(int freq)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006983{
6984 if (freq < 3000)
6985 return BAND_2_4_GHZ;
6986 if (freq > 50000)
6987 return BAND_60_GHZ;
6988 return BAND_5_GHZ;
6989}
6990
6991
Dmitry Shmidt9c175262016-03-03 10:20:07 -08006992unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006993{
6994 int i;
6995 unsigned int band = 0;
6996
6997 if (freqs) {
6998 /* freqs are specified for the radio work */
6999 for (i = 0; freqs[i]; i++)
7000 band |= wpas_freq_to_band(freqs[i]);
7001 } else {
7002 /*
7003 * freqs are not specified, implies all
7004 * the supported freqs by HW
7005 */
7006 for (i = 0; i < wpa_s->hw.num_modes; i++) {
7007 if (wpa_s->hw.modes[i].num_channels != 0) {
7008 if (wpa_s->hw.modes[i].mode ==
7009 HOSTAPD_MODE_IEEE80211B ||
7010 wpa_s->hw.modes[i].mode ==
7011 HOSTAPD_MODE_IEEE80211G)
7012 band |= BAND_2_4_GHZ;
7013 else if (wpa_s->hw.modes[i].mode ==
7014 HOSTAPD_MODE_IEEE80211A)
7015 band |= BAND_5_GHZ;
7016 else if (wpa_s->hw.modes[i].mode ==
7017 HOSTAPD_MODE_IEEE80211AD)
7018 band |= BAND_60_GHZ;
7019 else if (wpa_s->hw.modes[i].mode ==
7020 HOSTAPD_MODE_IEEE80211ANY)
7021 band = BAND_2_4_GHZ | BAND_5_GHZ |
7022 BAND_60_GHZ;
7023 }
7024 }
7025 }
7026
7027 return band;
7028}
7029
7030
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007031static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
7032 const char *rn)
7033{
7034 struct wpa_supplicant *iface = wpa_s->global->ifaces;
7035 struct wpa_radio *radio;
7036
7037 while (rn && iface) {
7038 radio = iface->radio;
7039 if (radio && os_strcmp(rn, radio->name) == 0) {
7040 wpa_printf(MSG_DEBUG, "Add interface %s to existing radio %s",
7041 wpa_s->ifname, rn);
7042 dl_list_add(&radio->ifaces, &wpa_s->radio_list);
7043 return radio;
7044 }
Dmitry Shmidt3cf6f792013-12-18 13:12:19 -08007045
7046 iface = iface->next;
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007047 }
7048
7049 wpa_printf(MSG_DEBUG, "Add interface %s to a new radio %s",
7050 wpa_s->ifname, rn ? rn : "N/A");
7051 radio = os_zalloc(sizeof(*radio));
7052 if (radio == NULL)
7053 return NULL;
7054
7055 if (rn)
7056 os_strlcpy(radio->name, rn, sizeof(radio->name));
7057 dl_list_init(&radio->ifaces);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007058 dl_list_init(&radio->work);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007059 dl_list_add(&radio->ifaces, &wpa_s->radio_list);
7060
7061 return radio;
7062}
7063
7064
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007065static void radio_work_free(struct wpa_radio_work *work)
7066{
7067 if (work->wpa_s->scan_work == work) {
7068 /* This should not really happen. */
7069 wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as scan_work",
7070 work->type, work, work->started);
7071 work->wpa_s->scan_work = NULL;
7072 }
7073
7074#ifdef CONFIG_P2P
7075 if (work->wpa_s->p2p_scan_work == work) {
7076 /* This should not really happen. */
7077 wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as p2p_scan_work",
7078 work->type, work, work->started);
7079 work->wpa_s->p2p_scan_work = NULL;
7080 }
7081#endif /* CONFIG_P2P */
7082
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007083 if (work->started) {
7084 work->wpa_s->radio->num_active_works--;
7085 wpa_dbg(work->wpa_s, MSG_DEBUG,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007086 "radio_work_free('%s'@%p): num_active_works --> %u",
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007087 work->type, work,
7088 work->wpa_s->radio->num_active_works);
7089 }
7090
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007091 dl_list_del(&work->list);
7092 os_free(work);
7093}
7094
7095
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08007096static int radio_work_is_connect(struct wpa_radio_work *work)
7097{
7098 return os_strcmp(work->type, "sme-connect") == 0 ||
7099 os_strcmp(work->type, "connect") == 0;
7100}
7101
7102
7103static int radio_work_is_scan(struct wpa_radio_work *work)
7104{
7105 return os_strcmp(work->type, "scan") == 0 ||
7106 os_strcmp(work->type, "p2p-scan") == 0;
7107}
7108
7109
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007110static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
7111{
7112 struct wpa_radio_work *active_work = NULL;
7113 struct wpa_radio_work *tmp;
7114
7115 /* Get the active work to know the type and band. */
7116 dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
7117 if (tmp->started) {
7118 active_work = tmp;
7119 break;
7120 }
7121 }
7122
7123 if (!active_work) {
7124 /* No active work, start one */
7125 radio->num_active_works = 0;
7126 dl_list_for_each(tmp, &radio->work, struct wpa_radio_work,
7127 list) {
7128 if (os_strcmp(tmp->type, "scan") == 0 &&
Hai Shalom60840252021-02-19 19:02:11 -08007129 external_scan_running(radio) &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007130 (((struct wpa_driver_scan_params *)
7131 tmp->ctx)->only_new_results ||
7132 tmp->wpa_s->clear_driver_scan_cache))
7133 continue;
7134 return tmp;
7135 }
7136 return NULL;
7137 }
7138
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08007139 if (radio_work_is_connect(active_work)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007140 /*
7141 * If the active work is either connect or sme-connect,
7142 * do not parallelize them with other radio works.
7143 */
7144 wpa_dbg(active_work->wpa_s, MSG_DEBUG,
7145 "Do not parallelize radio work with %s",
7146 active_work->type);
7147 return NULL;
7148 }
7149
7150 dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
7151 if (tmp->started)
7152 continue;
7153
7154 /*
7155 * If connect or sme-connect are enqueued, parallelize only
7156 * those operations ahead of them in the queue.
7157 */
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08007158 if (radio_work_is_connect(tmp))
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007159 break;
7160
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08007161 /* Serialize parallel scan and p2p_scan operations on the same
7162 * interface since the driver_nl80211 mechanism for tracking
7163 * scan cookies does not yet have support for this. */
7164 if (active_work->wpa_s == tmp->wpa_s &&
7165 radio_work_is_scan(active_work) &&
7166 radio_work_is_scan(tmp)) {
7167 wpa_dbg(active_work->wpa_s, MSG_DEBUG,
7168 "Do not start work '%s' when another work '%s' is already scheduled",
7169 tmp->type, active_work->type);
7170 continue;
7171 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007172 /*
7173 * Check that the radio works are distinct and
7174 * on different bands.
7175 */
7176 if (os_strcmp(active_work->type, tmp->type) != 0 &&
7177 (active_work->bands != tmp->bands)) {
7178 /*
7179 * If a scan has to be scheduled through nl80211 scan
7180 * interface and if an external scan is already running,
7181 * do not schedule the scan since it is likely to get
7182 * rejected by kernel.
7183 */
7184 if (os_strcmp(tmp->type, "scan") == 0 &&
Hai Shalom60840252021-02-19 19:02:11 -08007185 external_scan_running(radio) &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007186 (((struct wpa_driver_scan_params *)
7187 tmp->ctx)->only_new_results ||
7188 tmp->wpa_s->clear_driver_scan_cache))
7189 continue;
7190
7191 wpa_dbg(active_work->wpa_s, MSG_DEBUG,
7192 "active_work:%s new_work:%s",
7193 active_work->type, tmp->type);
7194 return tmp;
7195 }
7196 }
7197
7198 /* Did not find a radio work to schedule in parallel. */
7199 return NULL;
7200}
7201
7202
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007203static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
7204{
7205 struct wpa_radio *radio = eloop_ctx;
7206 struct wpa_radio_work *work;
7207 struct os_reltime now, diff;
7208 struct wpa_supplicant *wpa_s;
7209
7210 work = dl_list_first(&radio->work, struct wpa_radio_work, list);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007211 if (work == NULL) {
7212 radio->num_active_works = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007213 return;
7214 }
7215
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007216 wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant,
7217 radio_list);
7218
7219 if (!(wpa_s &&
7220 wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)) {
7221 if (work->started)
7222 return; /* already started and still in progress */
7223
Hai Shalom60840252021-02-19 19:02:11 -08007224 if (wpa_s && external_scan_running(wpa_s->radio)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007225 wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
7226 return;
7227 }
7228 } else {
7229 work = NULL;
7230 if (radio->num_active_works < MAX_ACTIVE_WORKS) {
7231 /* get the work to schedule next */
7232 work = radio_work_get_next_work(radio);
7233 }
7234 if (!work)
7235 return;
7236 }
7237
7238 wpa_s = work->wpa_s;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007239 os_get_reltime(&now);
7240 os_reltime_sub(&now, &work->time, &diff);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007241 wpa_dbg(wpa_s, MSG_DEBUG,
7242 "Starting radio work '%s'@%p after %ld.%06ld second wait",
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007243 work->type, work, diff.sec, diff.usec);
7244 work->started = 1;
7245 work->time = now;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007246 radio->num_active_works++;
7247
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007248 work->cb(work, 0);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007249
7250 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS) &&
7251 radio->num_active_works < MAX_ACTIVE_WORKS)
7252 radio_work_check_next(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007253}
7254
7255
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007256/*
7257 * This function removes both started and pending radio works running on
7258 * the provided interface's radio.
7259 * Prior to the removal of the radio work, its callback (cb) is called with
7260 * deinit set to be 1. Each work's callback is responsible for clearing its
7261 * internal data and restoring to a correct state.
7262 * @wpa_s: wpa_supplicant data
7263 * @type: type of works to be removed
7264 * @remove_all: 1 to remove all the works on this radio, 0 to remove only
7265 * this interface's works.
7266 */
7267void radio_remove_works(struct wpa_supplicant *wpa_s,
7268 const char *type, int remove_all)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007269{
7270 struct wpa_radio_work *work, *tmp;
7271 struct wpa_radio *radio = wpa_s->radio;
7272
7273 dl_list_for_each_safe(work, tmp, &radio->work, struct wpa_radio_work,
7274 list) {
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007275 if (type && os_strcmp(type, work->type) != 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007276 continue;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007277
7278 /* skip other ifaces' works */
7279 if (!remove_all && work->wpa_s != wpa_s)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007280 continue;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007281
7282 wpa_dbg(wpa_s, MSG_DEBUG, "Remove radio work '%s'@%p%s",
7283 work->type, work, work->started ? " (started)" : "");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007284 work->cb(work, 1);
7285 radio_work_free(work);
7286 }
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007287
7288 /* in case we removed the started work */
7289 radio_work_check_next(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007290}
7291
7292
Roshan Pius3a1667e2018-07-03 15:17:14 -07007293void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx)
7294{
7295 struct wpa_radio_work *work;
7296 struct wpa_radio *radio = wpa_s->radio;
7297
7298 dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
7299 if (work->ctx != ctx)
7300 continue;
7301 wpa_dbg(wpa_s, MSG_DEBUG, "Free pending radio work '%s'@%p%s",
7302 work->type, work, work->started ? " (started)" : "");
7303 radio_work_free(work);
7304 break;
7305 }
7306}
7307
7308
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007309static void radio_remove_interface(struct wpa_supplicant *wpa_s)
7310{
7311 struct wpa_radio *radio = wpa_s->radio;
7312
7313 if (!radio)
7314 return;
7315
7316 wpa_printf(MSG_DEBUG, "Remove interface %s from radio %s",
7317 wpa_s->ifname, radio->name);
7318 dl_list_del(&wpa_s->radio_list);
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07007319 radio_remove_works(wpa_s, NULL, 0);
Hai Shalom60840252021-02-19 19:02:11 -08007320 /* If the interface that triggered the external scan was removed, the
7321 * external scan is no longer running. */
7322 if (wpa_s == radio->external_scan_req_interface)
7323 radio->external_scan_req_interface = NULL;
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07007324 wpa_s->radio = NULL;
7325 if (!dl_list_empty(&radio->ifaces))
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007326 return; /* Interfaces remain for this radio */
7327
7328 wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007329 eloop_cancel_timeout(radio_start_next_work, radio, NULL);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007330 os_free(radio);
7331}
7332
7333
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007334void radio_work_check_next(struct wpa_supplicant *wpa_s)
7335{
7336 struct wpa_radio *radio = wpa_s->radio;
7337
7338 if (dl_list_empty(&radio->work))
7339 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007340 if (wpa_s->ext_work_in_progress) {
7341 wpa_printf(MSG_DEBUG,
7342 "External radio work in progress - delay start of pending item");
7343 return;
7344 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007345 eloop_cancel_timeout(radio_start_next_work, radio, NULL);
7346 eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL);
7347}
7348
7349
7350/**
7351 * radio_add_work - Add a radio work item
7352 * @wpa_s: Pointer to wpa_supplicant data
7353 * @freq: Frequency of the offchannel operation in MHz or 0
7354 * @type: Unique identifier for each type of work
7355 * @next: Force as the next work to be executed
7356 * @cb: Callback function for indicating when radio is available
7357 * @ctx: Context pointer for the work (work->ctx in cb())
7358 * Returns: 0 on success, -1 on failure
7359 *
7360 * This function is used to request time for an operation that requires
7361 * exclusive radio control. Once the radio is available, the registered callback
7362 * function will be called. radio_work_done() must be called once the exclusive
7363 * radio operation has been completed, so that the radio is freed for other
7364 * operations. The special case of deinit=1 is used to free the context data
7365 * during interface removal. That does not allow the callback function to start
7366 * the radio operation, i.e., it must free any resources allocated for the radio
7367 * work and return.
7368 *
7369 * The @freq parameter can be used to indicate a single channel on which the
7370 * offchannel operation will occur. This may allow multiple radio work
7371 * operations to be performed in parallel if they apply for the same channel.
7372 * Setting this to 0 indicates that the work item may use multiple channels or
7373 * requires exclusive control of the radio.
7374 */
7375int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
7376 const char *type, int next,
7377 void (*cb)(struct wpa_radio_work *work, int deinit),
7378 void *ctx)
7379{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007380 struct wpa_radio *radio = wpa_s->radio;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007381 struct wpa_radio_work *work;
7382 int was_empty;
7383
7384 work = os_zalloc(sizeof(*work));
7385 if (work == NULL)
7386 return -1;
7387 wpa_dbg(wpa_s, MSG_DEBUG, "Add radio work '%s'@%p", type, work);
7388 os_get_reltime(&work->time);
7389 work->freq = freq;
7390 work->type = type;
7391 work->wpa_s = wpa_s;
7392 work->cb = cb;
7393 work->ctx = ctx;
7394
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007395 if (freq)
7396 work->bands = wpas_freq_to_band(freq);
7397 else if (os_strcmp(type, "scan") == 0 ||
7398 os_strcmp(type, "p2p-scan") == 0)
7399 work->bands = wpas_get_bands(wpa_s,
7400 ((struct wpa_driver_scan_params *)
7401 ctx)->freqs);
7402 else
7403 work->bands = wpas_get_bands(wpa_s, NULL);
7404
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007405 was_empty = dl_list_empty(&wpa_s->radio->work);
7406 if (next)
7407 dl_list_add(&wpa_s->radio->work, &work->list);
7408 else
7409 dl_list_add_tail(&wpa_s->radio->work, &work->list);
7410 if (was_empty) {
7411 wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately");
7412 radio_work_check_next(wpa_s);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007413 } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)
7414 && radio->num_active_works < MAX_ACTIVE_WORKS) {
7415 wpa_dbg(wpa_s, MSG_DEBUG,
7416 "Try to schedule a radio work (num_active_works=%u)",
7417 radio->num_active_works);
7418 radio_work_check_next(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007419 }
7420
7421 return 0;
7422}
7423
7424
7425/**
7426 * radio_work_done - Indicate that a radio work item has been completed
7427 * @work: Completed work
7428 *
7429 * This function is called once the callback function registered with
7430 * radio_add_work() has completed its work.
7431 */
7432void radio_work_done(struct wpa_radio_work *work)
7433{
7434 struct wpa_supplicant *wpa_s = work->wpa_s;
7435 struct os_reltime now, diff;
7436 unsigned int started = work->started;
7437
7438 os_get_reltime(&now);
7439 os_reltime_sub(&now, &work->time, &diff);
7440 wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %ld.%06ld seconds",
7441 work->type, work, started ? "done" : "canceled",
7442 diff.sec, diff.usec);
7443 radio_work_free(work);
7444 if (started)
7445 radio_work_check_next(wpa_s);
7446}
7447
7448
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08007449struct wpa_radio_work *
7450radio_work_pending(struct wpa_supplicant *wpa_s, const char *type)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007451{
7452 struct wpa_radio_work *work;
7453 struct wpa_radio *radio = wpa_s->radio;
7454
7455 dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
7456 if (work->wpa_s == wpa_s && os_strcmp(work->type, type) == 0)
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08007457 return work;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007458 }
7459
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08007460 return NULL;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007461}
7462
7463
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007464static int wpas_init_driver(struct wpa_supplicant *wpa_s,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007465 const struct wpa_interface *iface)
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007466{
7467 const char *ifname, *driver, *rn;
7468
7469 driver = iface->driver;
7470next_driver:
7471 if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
7472 return -1;
7473
7474 wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
7475 if (wpa_s->drv_priv == NULL) {
7476 const char *pos;
Hai Shalom899fcc72020-10-19 14:38:18 -07007477 int level = MSG_ERROR;
7478
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007479 pos = driver ? os_strchr(driver, ',') : NULL;
7480 if (pos) {
7481 wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
7482 "driver interface - try next driver wrapper");
7483 driver = pos + 1;
7484 goto next_driver;
7485 }
Hai Shalom899fcc72020-10-19 14:38:18 -07007486
7487#ifdef CONFIG_MATCH_IFACE
7488 if (wpa_s->matched == WPA_IFACE_MATCHED_NULL)
7489 level = MSG_DEBUG;
7490#endif /* CONFIG_MATCH_IFACE */
7491 wpa_msg(wpa_s, level, "Failed to initialize driver interface");
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007492 return -1;
7493 }
7494 if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
7495 wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
7496 "driver_param '%s'", wpa_s->conf->driver_param);
7497 return -1;
7498 }
7499
7500 ifname = wpa_drv_get_ifname(wpa_s);
7501 if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
7502 wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
7503 "interface name with '%s'", ifname);
7504 os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
7505 }
7506
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07007507 rn = wpa_driver_get_radio_name(wpa_s);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007508 if (rn && rn[0] == '\0')
7509 rn = NULL;
7510
7511 wpa_s->radio = radio_add_interface(wpa_s, rn);
7512 if (wpa_s->radio == NULL)
7513 return -1;
7514
7515 return 0;
7516}
7517
7518
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007519#ifdef CONFIG_GAS_SERVER
7520
7521static void wpas_gas_server_tx_status(struct wpa_supplicant *wpa_s,
7522 unsigned int freq, const u8 *dst,
7523 const u8 *src, const u8 *bssid,
7524 const u8 *data, size_t data_len,
7525 enum offchannel_send_action_result result)
7526{
7527 wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
7528 " result=%s",
7529 freq, MAC2STR(dst),
7530 result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
7531 (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
7532 "FAILED"));
7533 gas_server_tx_status(wpa_s->gas_server, dst, data, data_len,
7534 result == OFFCHANNEL_SEND_ACTION_SUCCESS);
7535}
7536
7537
7538static void wpas_gas_server_tx(void *ctx, int freq, const u8 *da,
7539 struct wpabuf *buf, unsigned int wait_time)
7540{
7541 struct wpa_supplicant *wpa_s = ctx;
7542 const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
7543
7544 if (wait_time > wpa_s->max_remain_on_chan)
7545 wait_time = wpa_s->max_remain_on_chan;
7546
7547 offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, broadcast,
7548 wpabuf_head(buf), wpabuf_len(buf),
7549 wait_time, wpas_gas_server_tx_status, 0);
7550}
7551
7552#endif /* CONFIG_GAS_SERVER */
7553
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007554static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007555 const struct wpa_interface *iface)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007556{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007557 struct wpa_driver_capa capa;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007558 int capa_res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007559 u8 dfs_domain;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007560
7561 wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
7562 "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
7563 iface->confname ? iface->confname : "N/A",
7564 iface->driver ? iface->driver : "default",
7565 iface->ctrl_interface ? iface->ctrl_interface : "N/A",
7566 iface->bridge_ifname ? iface->bridge_ifname : "N/A");
7567
7568 if (iface->confname) {
7569#ifdef CONFIG_BACKEND_FILE
7570 wpa_s->confname = os_rel2abs_path(iface->confname);
7571 if (wpa_s->confname == NULL) {
7572 wpa_printf(MSG_ERROR, "Failed to get absolute path "
7573 "for configuration file '%s'.",
7574 iface->confname);
7575 return -1;
7576 }
7577 wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
7578 iface->confname, wpa_s->confname);
7579#else /* CONFIG_BACKEND_FILE */
7580 wpa_s->confname = os_strdup(iface->confname);
7581#endif /* CONFIG_BACKEND_FILE */
Sunil Ravi77d572f2023-01-17 23:58:31 +00007582 wpa_s->conf = wpa_config_read(wpa_s->confname, NULL, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007583 if (wpa_s->conf == NULL) {
7584 wpa_printf(MSG_ERROR, "Failed to read or parse "
7585 "configuration '%s'.", wpa_s->confname);
7586 return -1;
7587 }
Dmitry Shmidt64f47c52013-04-16 10:41:54 -07007588 wpa_s->confanother = os_rel2abs_path(iface->confanother);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007589 if (wpa_s->confanother &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00007590 !wpa_config_read(wpa_s->confanother, wpa_s->conf, true)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007591 wpa_printf(MSG_ERROR,
7592 "Failed to read or parse configuration '%s'.",
7593 wpa_s->confanother);
7594 return -1;
7595 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007596
7597 /*
7598 * Override ctrl_interface and driver_param if set on command
7599 * line.
7600 */
7601 if (iface->ctrl_interface) {
7602 os_free(wpa_s->conf->ctrl_interface);
7603 wpa_s->conf->ctrl_interface =
7604 os_strdup(iface->ctrl_interface);
Sunil Ravi77d572f2023-01-17 23:58:31 +00007605 if (!wpa_s->conf->ctrl_interface) {
7606 wpa_printf(MSG_ERROR,
7607 "Failed to duplicate control interface '%s'.",
7608 iface->ctrl_interface);
7609 return -1;
7610 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007611 }
7612
7613 if (iface->driver_param) {
7614 os_free(wpa_s->conf->driver_param);
7615 wpa_s->conf->driver_param =
7616 os_strdup(iface->driver_param);
Sunil Ravi77d572f2023-01-17 23:58:31 +00007617 if (!wpa_s->conf->driver_param) {
7618 wpa_printf(MSG_ERROR,
7619 "Failed to duplicate driver param '%s'.",
7620 iface->driver_param);
7621 return -1;
7622 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007623 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007624
7625 if (iface->p2p_mgmt && !iface->ctrl_interface) {
7626 os_free(wpa_s->conf->ctrl_interface);
7627 wpa_s->conf->ctrl_interface = NULL;
7628 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007629 } else
7630 wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
7631 iface->driver_param);
7632
7633 if (wpa_s->conf == NULL) {
7634 wpa_printf(MSG_ERROR, "\nNo configuration found.");
7635 return -1;
7636 }
7637
7638 if (iface->ifname == NULL) {
7639 wpa_printf(MSG_ERROR, "\nInterface name is required.");
7640 return -1;
7641 }
7642 if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
7643 wpa_printf(MSG_ERROR, "\nToo long interface name '%s'.",
7644 iface->ifname);
7645 return -1;
7646 }
7647 os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
Hai Shalom899fcc72020-10-19 14:38:18 -07007648#ifdef CONFIG_MATCH_IFACE
7649 wpa_s->matched = iface->matched;
7650#endif /* CONFIG_MATCH_IFACE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007651
7652 if (iface->bridge_ifname) {
7653 if (os_strlen(iface->bridge_ifname) >=
7654 sizeof(wpa_s->bridge_ifname)) {
7655 wpa_printf(MSG_ERROR, "\nToo long bridge interface "
7656 "name '%s'.", iface->bridge_ifname);
7657 return -1;
7658 }
7659 os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname,
7660 sizeof(wpa_s->bridge_ifname));
7661 }
7662
7663 /* RSNA Supplicant Key Management - INITIALIZE */
Hai Shalome21d4e82020-04-29 16:34:06 -07007664 eapol_sm_notify_portEnabled(wpa_s->eapol, false);
7665 eapol_sm_notify_portValid(wpa_s->eapol, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007666
7667 /* Initialize driver interface and register driver event handler before
7668 * L2 receive handler so that association events are processed before
7669 * EAPOL-Key packets if both become available for the same select()
7670 * call. */
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007671 if (wpas_init_driver(wpa_s, iface) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007672 return -1;
7673
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007674 if (wpa_supplicant_init_wpa(wpa_s) < 0)
7675 return -1;
7676
7677 wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,
7678 wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname :
7679 NULL);
7680 wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
7681
7682 if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
7683 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
7684 wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
7685 wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
7686 "dot11RSNAConfigPMKLifetime");
7687 return -1;
7688 }
7689
7690 if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
7691 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
7692 wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
7693 wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
7694 "dot11RSNAConfigPMKReauthThreshold");
7695 return -1;
7696 }
7697
7698 if (wpa_s->conf->dot11RSNAConfigSATimeout &&
7699 wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
7700 wpa_s->conf->dot11RSNAConfigSATimeout)) {
7701 wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
7702 "dot11RSNAConfigSATimeout");
7703 return -1;
7704 }
7705
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007706 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_PREPEND_PMKID,
7707 wpa_s->conf->ft_prepend_pmkid);
7708
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007709 wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
7710 &wpa_s->hw.num_modes,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007711 &wpa_s->hw.flags,
7712 &dfs_domain);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08007713 if (wpa_s->hw.modes) {
7714 u16 i;
7715
7716 for (i = 0; i < wpa_s->hw.num_modes; i++) {
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00007717 if (wpa_s->hw.modes[i].eht_capab[IEEE80211_MODE_INFRA].
7718 eht_supported)
7719 wpa_s->hw_capab |= BIT(CAPAB_EHT);
7720 if (wpa_s->hw.modes[i].he_capab[IEEE80211_MODE_INFRA].
7721 he_supported)
7722 wpa_s->hw_capab |= BIT(CAPAB_HE);
7723 if (wpa_s->hw.modes[i].vht_capab)
7724 wpa_s->hw_capab |= BIT(CAPAB_VHT);
7725 if (wpa_s->hw.modes[i].ht_capab)
7726 wpa_s->hw_capab |= BIT(CAPAB_HT);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08007727 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007728 wpa_s->support_6ghz = wpas_is_6ghz_supported(wpa_s, false);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08007729 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007730
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007731 capa_res = wpa_drv_get_capa(wpa_s, &capa);
7732 if (capa_res == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007733 wpa_s->drv_capa_known = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007734 wpa_s->drv_flags = capa.flags;
Hai Shalomb755a2a2020-04-23 21:49:02 -07007735 wpa_s->drv_flags2 = capa.flags2;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007736 wpa_s->drv_enc = capa.enc;
Sunil Ravi7f769292024-07-23 22:21:32 +00007737 wpa_s->drv_key_mgmt = capa.key_mgmt;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007738 wpa_s->drv_rrm_flags = capa.rrm_flags;
Sunil Ravia04bd252022-05-02 22:54:18 -07007739 wpa_s->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007740 wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007741 wpa_s->max_scan_ssids = capa.max_scan_ssids;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007742 wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007743 wpa_s->max_sched_scan_plans = capa.max_sched_scan_plans;
7744 wpa_s->max_sched_scan_plan_interval =
7745 capa.max_sched_scan_plan_interval;
7746 wpa_s->max_sched_scan_plan_iterations =
7747 capa.max_sched_scan_plan_iterations;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007748 wpa_s->sched_scan_supported = capa.sched_scan_supported;
7749 wpa_s->max_match_sets = capa.max_match_sets;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007750 wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
7751 wpa_s->max_stations = capa.max_stations;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007752 wpa_s->extended_capa = capa.extended_capa;
7753 wpa_s->extended_capa_mask = capa.extended_capa_mask;
7754 wpa_s->extended_capa_len = capa.extended_capa_len;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07007755 wpa_s->num_multichan_concurrent =
7756 capa.num_multichan_concurrent;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007757#ifndef CONFIG_NO_WMM_AC
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007758 wpa_s->wmm_ac_supported = capa.wmm_ac_supported;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007759#endif /* CONFIG_NO_WMM_AC */
Sunil Ravi89eba102022-09-13 21:04:37 -07007760 wpa_s->max_num_akms = capa.max_num_akms;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007761
7762 if (capa.mac_addr_rand_scan_supported)
7763 wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;
7764 if (wpa_s->sched_scan_supported &&
7765 capa.mac_addr_rand_sched_scan_supported)
7766 wpa_s->mac_addr_rand_supported |=
7767 (MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00007768 wpa_s->drv_max_probe_req_ie_len = capa.max_probe_req_ie_len;
Hai Shalom74f70d42019-02-11 14:42:39 -08007769
7770 wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
7771 if (wpa_s->extended_capa &&
7772 wpa_s->extended_capa_len >= 3 &&
7773 wpa_s->extended_capa[2] & 0x40)
7774 wpa_s->multi_bss_support = 1;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00007775 } else {
7776 wpa_s->drv_max_probe_req_ie_len = 1500;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007777 }
Sunil Ravi89eba102022-09-13 21:04:37 -07007778#ifdef CONFIG_PASN
7779 wpa_pasn_sm_set_caps(wpa_s->wpa, wpa_s->drv_flags2);
7780#endif /* CONFIG_PASN */
Matthew Wang9ed1c792024-12-02 14:05:18 +00007781#ifndef CONFIG_NO_WPA
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007782 wpa_sm_set_driver_bss_selection(wpa_s->wpa,
7783 !!(wpa_s->drv_flags &
7784 WPA_DRIVER_FLAGS_BSS_SELECTION));
Matthew Wang9ed1c792024-12-02 14:05:18 +00007785#endif /* CONFIG_NO_WPA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007786 if (wpa_s->max_remain_on_chan == 0)
7787 wpa_s->max_remain_on_chan = 1000;
7788
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007789 /*
7790 * Only take p2p_mgmt parameters when P2P Device is supported.
7791 * Doing it here as it determines whether l2_packet_init() will be done
7792 * during wpa_supplicant_driver_init().
7793 */
7794 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
7795 wpa_s->p2p_mgmt = iface->p2p_mgmt;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007796
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07007797 if (wpa_s->num_multichan_concurrent == 0)
7798 wpa_s->num_multichan_concurrent = 1;
7799
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007800 if (wpa_supplicant_driver_init(wpa_s) < 0)
7801 return -1;
7802
7803#ifdef CONFIG_TDLS
Roshan Pius3a1667e2018-07-03 15:17:14 -07007804 if (!iface->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007805 return -1;
7806#endif /* CONFIG_TDLS */
7807
7808 if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
7809 wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
7810 wpa_dbg(wpa_s, MSG_DEBUG, "Failed to set country");
7811 return -1;
7812 }
7813
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007814#ifdef CONFIG_FST
7815 if (wpa_s->conf->fst_group_id) {
7816 struct fst_iface_cfg cfg;
7817 struct fst_wpa_obj iface_obj;
7818
7819 fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj);
7820 os_strlcpy(cfg.group_id, wpa_s->conf->fst_group_id,
7821 sizeof(cfg.group_id));
7822 cfg.priority = wpa_s->conf->fst_priority;
7823 cfg.llt = wpa_s->conf->fst_llt;
7824
7825 wpa_s->fst = fst_attach(wpa_s->ifname, wpa_s->own_addr,
7826 &iface_obj, &cfg);
7827 if (!wpa_s->fst) {
7828 wpa_msg(wpa_s, MSG_ERROR,
7829 "FST: Cannot attach iface %s to group %s",
7830 wpa_s->ifname, cfg.group_id);
7831 return -1;
7832 }
7833 }
7834#endif /* CONFIG_FST */
7835
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007836 if (wpas_wps_init(wpa_s))
7837 return -1;
7838
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007839#ifdef CONFIG_GAS_SERVER
7840 wpa_s->gas_server = gas_server_init(wpa_s, wpas_gas_server_tx);
7841 if (!wpa_s->gas_server) {
7842 wpa_printf(MSG_ERROR, "Failed to initialize GAS server");
7843 return -1;
7844 }
7845#endif /* CONFIG_GAS_SERVER */
7846
7847#ifdef CONFIG_DPP
7848 if (wpas_dpp_init(wpa_s) < 0)
7849 return -1;
7850#endif /* CONFIG_DPP */
7851
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007852#ifdef CONFIG_NAN_USD
7853 if (wpas_nan_usd_init(wpa_s) < 0)
7854 return -1;
7855#endif /* CONFIG_NAN_USD */
7856
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007857 if (wpa_supplicant_init_eapol(wpa_s) < 0)
7858 return -1;
7859 wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
7860
7861 wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
7862 if (wpa_s->ctrl_iface == NULL) {
7863 wpa_printf(MSG_ERROR,
7864 "Failed to initialize control interface '%s'.\n"
7865 "You may have another wpa_supplicant process "
7866 "already running or the file was\n"
7867 "left by an unclean termination of wpa_supplicant "
7868 "in which case you will need\n"
7869 "to manually remove this file before starting "
7870 "wpa_supplicant again.\n",
7871 wpa_s->conf->ctrl_interface);
7872 return -1;
7873 }
7874
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007875 wpa_s->gas = gas_query_init(wpa_s);
7876 if (wpa_s->gas == NULL) {
7877 wpa_printf(MSG_ERROR, "Failed to initialize GAS query");
7878 return -1;
7879 }
7880
Roshan Pius3a1667e2018-07-03 15:17:14 -07007881 if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) ||
7882 wpa_s->p2p_mgmt) &&
7883 wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007884 wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
7885 return -1;
7886 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007887
7888 if (wpa_bss_init(wpa_s) < 0)
7889 return -1;
7890
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07007891 /*
7892 * Set Wake-on-WLAN triggers, if configured.
7893 * Note: We don't restore/remove the triggers on shutdown (it doesn't
7894 * have effect anyway when the interface is down).
7895 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007896 if (capa_res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07007897 return -1;
7898
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007899#ifdef CONFIG_EAP_PROXY
7900{
7901 size_t len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007902 wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1,
7903 wpa_s->imsi, &len);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007904 if (wpa_s->mnc_len > 0) {
7905 wpa_s->imsi[len] = '\0';
7906 wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
7907 wpa_s->imsi, wpa_s->mnc_len);
7908 } else {
7909 wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
7910 }
7911}
7912#endif /* CONFIG_EAP_PROXY */
7913
Dmitry Shmidt04949592012-07-19 12:16:46 -07007914 if (pcsc_reader_init(wpa_s) < 0)
7915 return -1;
7916
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007917 if (wpas_init_ext_pw(wpa_s) < 0)
7918 return -1;
7919
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007920#ifndef CONFIG_NO_RRM
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007921 wpas_rrm_reset(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007922#endif /* CONFIG_NO_RRM */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007923
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007924 wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
7925
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007926#ifdef CONFIG_MBO
Hai Shalomc3565922019-10-28 11:58:20 -07007927 if (!wpa_s->disable_mbo_oce && wpa_s->conf->oce) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007928 if ((wpa_s->conf->oce & OCE_STA) &&
7929 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
7930 wpa_s->enable_oce = OCE_STA;
7931 if ((wpa_s->conf->oce & OCE_STA_CFON) &&
7932 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON)) {
7933 /* TODO: Need to add STA-CFON support */
7934 wpa_printf(MSG_ERROR,
7935 "OCE STA-CFON feature is not yet supported");
7936 }
7937 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007938 wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan);
7939#endif /* CONFIG_MBO */
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08007940
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07007941 wpa_supplicant_set_default_scan_ies(wpa_s);
7942
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007943 return 0;
7944}
7945
7946
7947static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07007948 int notify, int terminate)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007949{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007950 struct wpa_global *global = wpa_s->global;
7951 struct wpa_supplicant *iface, *prev;
7952
Jimmy Chen0e73c002021-08-18 13:21:30 +08007953 if (wpa_s == wpa_s->parent || (wpa_s == wpa_s->p2pdev && wpa_s->p2p_mgmt))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007954 wpas_p2p_group_remove(wpa_s, "*");
7955
7956 iface = global->ifaces;
7957 while (iface) {
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007958 if (iface->p2pdev == wpa_s)
7959 iface->p2pdev = iface->parent;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007960 if (iface == wpa_s || iface->parent != wpa_s) {
7961 iface = iface->next;
7962 continue;
7963 }
7964 wpa_printf(MSG_DEBUG,
7965 "Remove remaining child interface %s from parent %s",
7966 iface->ifname, wpa_s->ifname);
7967 prev = iface;
7968 iface = iface->next;
7969 wpa_supplicant_remove_iface(global, prev, terminate);
7970 }
7971
Dmitry Shmidtea69e842013-05-13 14:52:28 -07007972 wpa_s->disconnected = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007973 if (wpa_s->drv_priv) {
Hai Shalom60840252021-02-19 19:02:11 -08007974 /*
7975 * Don't deauthenticate if WoWLAN is enable and not explicitly
7976 * been configured to disconnect.
7977 */
7978 if (!wpa_drv_get_wowlan(wpa_s) ||
7979 wpa_s->conf->wowlan_disconnect_on_deinit) {
Hai Shalomfdcde762020-04-02 11:19:20 -07007980 wpa_supplicant_deauthenticate(
7981 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007982
Hai Shalomfdcde762020-04-02 11:19:20 -07007983 wpa_drv_set_countermeasures(wpa_s, 0);
7984 wpa_clear_keys(wpa_s, NULL);
7985 } else {
7986 wpa_msg(wpa_s, MSG_INFO,
7987 "Do not deauthenticate as part of interface deinit since WoWLAN is enabled");
7988 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007989 }
7990
7991 wpa_supplicant_cleanup(wpa_s);
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07007992 wpas_p2p_deinit_iface(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007993
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007994 wpas_ctrl_radio_work_flush(wpa_s);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007995 radio_remove_interface(wpa_s);
7996
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007997#ifdef CONFIG_FST
7998 if (wpa_s->fst) {
7999 fst_detach(wpa_s->fst);
8000 wpa_s->fst = NULL;
8001 }
8002 if (wpa_s->received_mb_ies) {
8003 wpabuf_free(wpa_s->received_mb_ies);
8004 wpa_s->received_mb_ies = NULL;
8005 }
8006#endif /* CONFIG_FST */
8007
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008008 if (wpa_s->drv_priv)
8009 wpa_drv_deinit(wpa_s);
Irfan Sheriff622b66d2011-08-03 09:11:49 -07008010
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008011 if (notify)
8012 wpas_notify_iface_removed(wpa_s);
8013
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008014 if (terminate)
8015 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
Irfan Sheriff622b66d2011-08-03 09:11:49 -07008016
Jouni Malinenf3f8d3c2021-02-05 00:28:17 +02008017 wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
8018 wpa_s->ctrl_iface = NULL;
Irfan Sheriff622b66d2011-08-03 09:11:49 -07008019
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008020#ifdef CONFIG_MESH
8021 if (wpa_s->ifmsh) {
Hai Shalom60840252021-02-19 19:02:11 -08008022 wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh, true);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008023 wpa_s->ifmsh = NULL;
8024 }
8025#endif /* CONFIG_MESH */
8026
Irfan Sheriff622b66d2011-08-03 09:11:49 -07008027 if (wpa_s->conf != NULL) {
Irfan Sheriff622b66d2011-08-03 09:11:49 -07008028 wpa_config_free(wpa_s->conf);
8029 wpa_s->conf = NULL;
8030 }
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008031
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07008032 os_free(wpa_s->ssids_from_scan_req);
Hai Shalomc3565922019-10-28 11:58:20 -07008033 os_free(wpa_s->last_scan_freqs);
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07008034
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008035 os_free(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008036}
8037
8038
Dmitry Shmidte4663042016-04-04 10:07:49 -07008039#ifdef CONFIG_MATCH_IFACE
8040
8041/**
8042 * wpa_supplicant_match_iface - Match an interface description to a name
8043 * @global: Pointer to global data from wpa_supplicant_init()
8044 * @ifname: Name of the interface to match
8045 * Returns: Pointer to the created interface description or %NULL on failure
8046 */
8047struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
8048 const char *ifname)
8049{
8050 int i;
8051 struct wpa_interface *iface, *miface;
8052
8053 for (i = 0; i < global->params.match_iface_count; i++) {
8054 miface = &global->params.match_ifaces[i];
8055 if (!miface->ifname ||
8056 fnmatch(miface->ifname, ifname, 0) == 0) {
8057 iface = os_zalloc(sizeof(*iface));
8058 if (!iface)
8059 return NULL;
8060 *iface = *miface;
Hai Shalom899fcc72020-10-19 14:38:18 -07008061 if (!miface->ifname)
8062 iface->matched = WPA_IFACE_MATCHED_NULL;
8063 else
8064 iface->matched = WPA_IFACE_MATCHED;
Dmitry Shmidte4663042016-04-04 10:07:49 -07008065 iface->ifname = ifname;
8066 return iface;
8067 }
8068 }
8069
8070 return NULL;
8071}
8072
8073
8074/**
8075 * wpa_supplicant_match_existing - Match existing interfaces
8076 * @global: Pointer to global data from wpa_supplicant_init()
8077 * Returns: 0 on success, -1 on failure
8078 */
8079static int wpa_supplicant_match_existing(struct wpa_global *global)
8080{
8081 struct if_nameindex *ifi, *ifp;
8082 struct wpa_supplicant *wpa_s;
8083 struct wpa_interface *iface;
8084
8085 ifp = if_nameindex();
8086 if (!ifp) {
8087 wpa_printf(MSG_ERROR, "if_nameindex: %s", strerror(errno));
8088 return -1;
8089 }
8090
8091 for (ifi = ifp; ifi->if_name; ifi++) {
8092 wpa_s = wpa_supplicant_get_iface(global, ifi->if_name);
8093 if (wpa_s)
8094 continue;
8095 iface = wpa_supplicant_match_iface(global, ifi->if_name);
8096 if (iface) {
Hai Shalom60840252021-02-19 19:02:11 -08008097 wpa_supplicant_add_iface(global, iface, NULL);
Dmitry Shmidte4663042016-04-04 10:07:49 -07008098 os_free(iface);
Dmitry Shmidte4663042016-04-04 10:07:49 -07008099 }
8100 }
8101
8102 if_freenameindex(ifp);
8103 return 0;
8104}
8105
8106#endif /* CONFIG_MATCH_IFACE */
8107
8108
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008109/**
8110 * wpa_supplicant_add_iface - Add a new network interface
8111 * @global: Pointer to global data from wpa_supplicant_init()
8112 * @iface: Interface configuration options
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08008113 * @parent: Parent interface or %NULL to assign new interface as parent
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008114 * Returns: Pointer to the created interface or %NULL on failure
8115 *
8116 * This function is used to add new network interfaces for %wpa_supplicant.
8117 * This can be called before wpa_supplicant_run() to add interfaces before the
8118 * main event loop has been started. In addition, new interfaces can be added
8119 * dynamically while %wpa_supplicant is already running. This could happen,
8120 * e.g., when a hotplug network adapter is inserted.
8121 */
8122struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08008123 struct wpa_interface *iface,
8124 struct wpa_supplicant *parent)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008125{
8126 struct wpa_supplicant *wpa_s;
8127 struct wpa_interface t_iface;
8128 struct wpa_ssid *ssid;
8129
8130 if (global == NULL || iface == NULL)
8131 return NULL;
8132
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08008133 wpa_s = wpa_supplicant_alloc(parent);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008134 if (wpa_s == NULL)
8135 return NULL;
8136
8137 wpa_s->global = global;
8138
8139 t_iface = *iface;
8140 if (global->params.override_driver) {
8141 wpa_printf(MSG_DEBUG, "Override interface parameter: driver "
8142 "('%s' -> '%s')",
8143 iface->driver, global->params.override_driver);
8144 t_iface.driver = global->params.override_driver;
8145 }
8146 if (global->params.override_ctrl_interface) {
8147 wpa_printf(MSG_DEBUG, "Override interface parameter: "
8148 "ctrl_interface ('%s' -> '%s')",
8149 iface->ctrl_interface,
8150 global->params.override_ctrl_interface);
8151 t_iface.ctrl_interface =
8152 global->params.override_ctrl_interface;
8153 }
8154 if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
8155 wpa_printf(MSG_DEBUG, "Failed to add interface %s",
8156 iface->ifname);
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008157 wpa_supplicant_deinit_iface(wpa_s, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008158 return NULL;
8159 }
8160
Roshan Piusd6d8b8d2016-11-08 14:45:26 -08008161 /* Notify the control interfaces about new iface */
8162 if (wpas_notify_iface_added(wpa_s)) {
8163 wpa_supplicant_deinit_iface(wpa_s, 1, 0);
8164 return NULL;
8165 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008166
Jimmy Chene2206be2022-07-10 10:25:21 +08008167 /* Notify the control interfaces about new networks */
8168 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
8169 if (iface->p2p_mgmt == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008170 wpas_notify_network_added(wpa_s, ssid);
Jimmy Chene2206be2022-07-10 10:25:21 +08008171 } else if (ssid->ssid_len > P2P_WILDCARD_SSID_LEN
8172 && os_strncmp((const char *) ssid->ssid,
8173 P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0) {
8174 wpas_notify_persistent_group_added(wpa_s, ssid);
8175 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008176 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008177
8178 wpa_s->next = global->ifaces;
8179 global->ifaces = wpa_s;
8180
8181 wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
Dmitry Shmidt04949592012-07-19 12:16:46 -07008182 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008183
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008184#ifdef CONFIG_P2P
8185 if (wpa_s->global->p2p == NULL &&
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07008186 !wpa_s->global->p2p_disabled && !wpa_s->conf->p2p_disabled &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008187 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07008188 wpas_p2p_add_p2pdev_interface(
8189 wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008190 wpa_printf(MSG_INFO,
8191 "P2P: Failed to enable P2P Device interface");
8192 /* Try to continue without. P2P will be disabled. */
8193 }
8194#endif /* CONFIG_P2P */
8195
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008196 return wpa_s;
8197}
8198
8199
8200/**
8201 * wpa_supplicant_remove_iface - Remove a network interface
8202 * @global: Pointer to global data from wpa_supplicant_init()
8203 * @wpa_s: Pointer to the network interface to be removed
8204 * Returns: 0 if interface was removed, -1 if interface was not found
8205 *
8206 * This function can be used to dynamically remove network interfaces from
8207 * %wpa_supplicant, e.g., when a hotplug network adapter is ejected. In
8208 * addition, this function is used to remove all remaining interfaces when
8209 * %wpa_supplicant is terminated.
8210 */
8211int wpa_supplicant_remove_iface(struct wpa_global *global,
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008212 struct wpa_supplicant *wpa_s,
8213 int terminate)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008214{
8215 struct wpa_supplicant *prev;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008216#ifdef CONFIG_MESH
8217 unsigned int mesh_if_created = wpa_s->mesh_if_created;
8218 char *ifname = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008219 struct wpa_supplicant *parent = wpa_s->parent;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008220#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008221
8222 /* Remove interface from the global list of interfaces */
8223 prev = global->ifaces;
8224 if (prev == wpa_s) {
8225 global->ifaces = wpa_s->next;
8226 } else {
8227 while (prev && prev->next != wpa_s)
8228 prev = prev->next;
8229 if (prev == NULL)
8230 return -1;
8231 prev->next = wpa_s->next;
8232 }
8233
8234 wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
8235
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008236#ifdef CONFIG_MESH
8237 if (mesh_if_created) {
8238 ifname = os_strdup(wpa_s->ifname);
8239 if (ifname == NULL) {
8240 wpa_dbg(wpa_s, MSG_ERROR,
8241 "mesh: Failed to malloc ifname");
8242 return -1;
8243 }
8244 }
8245#endif /* CONFIG_MESH */
8246
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008247 if (global->p2p_group_formation == wpa_s)
8248 global->p2p_group_formation = NULL;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07008249 if (global->p2p_invite_group == wpa_s)
8250 global->p2p_invite_group = NULL;
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008251 wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008252
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008253#ifdef CONFIG_MESH
8254 if (mesh_if_created) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008255 wpa_drv_if_remove(parent, WPA_IF_MESH, ifname);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008256 os_free(ifname);
8257 }
8258#endif /* CONFIG_MESH */
8259
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008260 return 0;
8261}
8262
8263
8264/**
8265 * wpa_supplicant_get_eap_mode - Get the current EAP mode
8266 * @wpa_s: Pointer to the network interface
8267 * Returns: Pointer to the eap mode or the string "UNKNOWN" if not found
8268 */
8269const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s)
8270{
8271 const char *eapol_method;
8272
8273 if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) == 0 &&
8274 wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
8275 return "NO-EAP";
8276 }
8277
8278 eapol_method = eapol_sm_get_method_name(wpa_s->eapol);
8279 if (eapol_method == NULL)
8280 return "UNKNOWN-EAP";
8281
8282 return eapol_method;
8283}
8284
8285
8286/**
8287 * wpa_supplicant_get_iface - Get a new network interface
8288 * @global: Pointer to global data from wpa_supplicant_init()
8289 * @ifname: Interface name
8290 * Returns: Pointer to the interface or %NULL if not found
8291 */
8292struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
8293 const char *ifname)
8294{
8295 struct wpa_supplicant *wpa_s;
8296
8297 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
8298 if (os_strcmp(wpa_s->ifname, ifname) == 0)
8299 return wpa_s;
8300 }
8301 return NULL;
8302}
8303
8304
8305#ifndef CONFIG_NO_WPA_MSG
8306static const char * wpa_supplicant_msg_ifname_cb(void *ctx)
8307{
8308 struct wpa_supplicant *wpa_s = ctx;
8309 if (wpa_s == NULL)
8310 return NULL;
8311 return wpa_s->ifname;
8312}
8313#endif /* CONFIG_NO_WPA_MSG */
8314
8315
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008316#ifndef WPA_SUPPLICANT_CLEANUP_INTERVAL
8317#define WPA_SUPPLICANT_CLEANUP_INTERVAL 10
8318#endif /* WPA_SUPPLICANT_CLEANUP_INTERVAL */
8319
8320/* Periodic cleanup tasks */
8321static void wpas_periodic(void *eloop_ctx, void *timeout_ctx)
8322{
8323 struct wpa_global *global = eloop_ctx;
8324 struct wpa_supplicant *wpa_s;
8325
8326 eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
8327 wpas_periodic, global, NULL);
8328
8329#ifdef CONFIG_P2P
8330 if (global->p2p)
8331 p2p_expire_peers(global->p2p);
8332#endif /* CONFIG_P2P */
8333
8334 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
8335 wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
8336#ifdef CONFIG_AP
8337 ap_periodic(wpa_s);
8338#endif /* CONFIG_AP */
8339 }
8340}
8341
8342
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008343/**
8344 * wpa_supplicant_init - Initialize %wpa_supplicant
8345 * @params: Parameters for %wpa_supplicant
8346 * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
8347 *
8348 * This function is used to initialize %wpa_supplicant. After successful
8349 * initialization, the returned data pointer can be used to add and remove
8350 * network interfaces, and eventually, to deinitialize %wpa_supplicant.
8351 */
8352struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
8353{
8354 struct wpa_global *global;
8355 int ret, i;
8356
8357 if (params == NULL)
8358 return NULL;
8359
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008360#ifdef CONFIG_DRIVER_NDIS
8361 {
8362 void driver_ndis_init_ops(void);
8363 driver_ndis_init_ops();
8364 }
8365#endif /* CONFIG_DRIVER_NDIS */
8366
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008367#ifndef CONFIG_NO_WPA_MSG
8368 wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
8369#endif /* CONFIG_NO_WPA_MSG */
8370
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008371 if (params->wpa_debug_file_path)
8372 wpa_debug_open_file(params->wpa_debug_file_path);
Hai Shalomfdcde762020-04-02 11:19:20 -07008373 if (!params->wpa_debug_file_path && !params->wpa_debug_syslog)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008374 wpa_debug_setup_stdout();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008375 if (params->wpa_debug_syslog)
8376 wpa_debug_open_syslog();
Dmitry Shmidt04949592012-07-19 12:16:46 -07008377 if (params->wpa_debug_tracing) {
8378 ret = wpa_debug_open_linux_tracing();
8379 if (ret) {
8380 wpa_printf(MSG_ERROR,
8381 "Failed to enable trace logging");
8382 return NULL;
8383 }
8384 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008385
8386 ret = eap_register_methods();
8387 if (ret) {
8388 wpa_printf(MSG_ERROR, "Failed to register EAP methods");
8389 if (ret == -2)
8390 wpa_printf(MSG_ERROR, "Two or more EAP methods used "
8391 "the same EAP type.");
8392 return NULL;
8393 }
8394
8395 global = os_zalloc(sizeof(*global));
8396 if (global == NULL)
8397 return NULL;
8398 dl_list_init(&global->p2p_srv_bonjour);
8399 dl_list_init(&global->p2p_srv_upnp);
8400 global->params.daemonize = params->daemonize;
8401 global->params.wait_for_monitor = params->wait_for_monitor;
8402 global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
Sunil Ravi77d572f2023-01-17 23:58:31 +00008403
8404 if (params->pid_file) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008405 global->params.pid_file = os_strdup(params->pid_file);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008406 if (!global->params.pid_file) {
8407 wpa_supplicant_deinit(global);
8408 return NULL;
8409 }
8410 }
8411
8412 if (params->ctrl_interface) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008413 global->params.ctrl_interface =
8414 os_strdup(params->ctrl_interface);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008415 if (!global->params.ctrl_interface) {
8416 wpa_supplicant_deinit(global);
8417 return NULL;
8418 }
8419 }
8420
8421 if (params->ctrl_interface_group) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07008422 global->params.ctrl_interface_group =
8423 os_strdup(params->ctrl_interface_group);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008424 if (!global->params.ctrl_interface_group) {
8425 wpa_supplicant_deinit(global);
8426 return NULL;
8427 }
8428 }
8429
8430 if (params->override_driver) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008431 global->params.override_driver =
8432 os_strdup(params->override_driver);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008433 if (!global->params.override_driver) {
8434 wpa_supplicant_deinit(global);
8435 return NULL;
8436 }
8437 }
8438
8439 if (params->override_ctrl_interface) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008440 global->params.override_ctrl_interface =
8441 os_strdup(params->override_ctrl_interface);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008442 if (!global->params.override_ctrl_interface) {
8443 wpa_supplicant_deinit(global);
8444 return NULL;
8445 }
8446 }
8447
Dmitry Shmidte4663042016-04-04 10:07:49 -07008448#ifdef CONFIG_MATCH_IFACE
8449 global->params.match_iface_count = params->match_iface_count;
8450 if (params->match_iface_count) {
8451 global->params.match_ifaces =
8452 os_calloc(params->match_iface_count,
8453 sizeof(struct wpa_interface));
Sunil Ravi77d572f2023-01-17 23:58:31 +00008454 if (!global->params.match_ifaces) {
8455 wpa_printf(MSG_ERROR,
8456 "Failed to allocate match interfaces");
8457 wpa_supplicant_deinit(global);
8458 return NULL;
8459 }
Dmitry Shmidte4663042016-04-04 10:07:49 -07008460 os_memcpy(global->params.match_ifaces,
8461 params->match_ifaces,
8462 params->match_iface_count *
8463 sizeof(struct wpa_interface));
8464 }
8465#endif /* CONFIG_MATCH_IFACE */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008466#ifdef CONFIG_P2P
Sunil Ravi77d572f2023-01-17 23:58:31 +00008467 if (params->conf_p2p_dev) {
Sasha Levitskiydaa60e52015-08-05 13:02:59 -07008468 global->params.conf_p2p_dev =
8469 os_strdup(params->conf_p2p_dev);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008470 if (!global->params.conf_p2p_dev) {
8471 wpa_printf(MSG_ERROR, "Failed to allocate conf p2p");
8472 wpa_supplicant_deinit(global);
8473 return NULL;
8474 }
8475 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008476#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008477 wpa_debug_level = global->params.wpa_debug_level =
8478 params->wpa_debug_level;
8479 wpa_debug_show_keys = global->params.wpa_debug_show_keys =
8480 params->wpa_debug_show_keys;
8481 wpa_debug_timestamp = global->params.wpa_debug_timestamp =
8482 params->wpa_debug_timestamp;
8483
Hai Shalomfdcde762020-04-02 11:19:20 -07008484 wpa_printf(MSG_DEBUG, "wpa_supplicant v%s", VERSION_STR);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008485
8486 if (eloop_init()) {
8487 wpa_printf(MSG_ERROR, "Failed to initialize event loop");
8488 wpa_supplicant_deinit(global);
8489 return NULL;
8490 }
8491
Jouni Malinen75ecf522011-06-27 15:19:46 -07008492 random_init(params->entropy_file);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008493
8494 global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
8495 if (global->ctrl_iface == NULL) {
8496 wpa_supplicant_deinit(global);
8497 return NULL;
8498 }
8499
8500 if (wpas_notify_supplicant_initialized(global)) {
8501 wpa_supplicant_deinit(global);
8502 return NULL;
8503 }
8504
8505 for (i = 0; wpa_drivers[i]; i++)
8506 global->drv_count++;
8507 if (global->drv_count == 0) {
8508 wpa_printf(MSG_ERROR, "No drivers enabled");
8509 wpa_supplicant_deinit(global);
8510 return NULL;
8511 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008512 global->drv_priv = os_calloc(global->drv_count, sizeof(void *));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008513 if (global->drv_priv == NULL) {
8514 wpa_supplicant_deinit(global);
8515 return NULL;
8516 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008517
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008518#ifdef CONFIG_WIFI_DISPLAY
8519 if (wifi_display_init(global) < 0) {
8520 wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");
8521 wpa_supplicant_deinit(global);
8522 return NULL;
8523 }
8524#endif /* CONFIG_WIFI_DISPLAY */
8525
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008526 eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
8527 wpas_periodic, global, NULL);
8528
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008529 return global;
8530}
8531
8532
8533/**
8534 * wpa_supplicant_run - Run the %wpa_supplicant main event loop
8535 * @global: Pointer to global data from wpa_supplicant_init()
8536 * Returns: 0 after successful event loop run, -1 on failure
8537 *
8538 * This function starts the main event loop and continues running as long as
8539 * there are any remaining events. In most cases, this function is running as
8540 * long as the %wpa_supplicant process in still in use.
8541 */
8542int wpa_supplicant_run(struct wpa_global *global)
8543{
8544 struct wpa_supplicant *wpa_s;
8545
8546 if (global->params.daemonize &&
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08008547 (wpa_supplicant_daemon(global->params.pid_file) ||
8548 eloop_sock_requeue()))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008549 return -1;
8550
Dmitry Shmidte4663042016-04-04 10:07:49 -07008551#ifdef CONFIG_MATCH_IFACE
8552 if (wpa_supplicant_match_existing(global))
8553 return -1;
8554#endif
8555
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008556 if (global->params.wait_for_monitor) {
8557 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08008558 if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008559 wpa_supplicant_ctrl_iface_wait(
8560 wpa_s->ctrl_iface);
8561 }
8562
Kiran Kumar Lokerea9f98eb2023-03-17 13:01:12 -07008563#ifdef CONFIG_AIDL
Gabriel Biren7a30e7f2023-06-02 20:11:28 +00008564 // If daemonize is enabled, initialize AIDL here.
8565 if (global->params.daemonize) {
8566 global->aidl = wpas_aidl_init(global);
8567 if (!global->aidl)
8568 return -1;
8569 }
Kiran Kumar Lokerea9f98eb2023-03-17 13:01:12 -07008570#endif /* CONFIG_AIDL */
8571
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008572 eloop_register_signal_terminate(wpa_supplicant_terminate, global);
8573 eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
8574
8575 eloop_run();
8576
8577 return 0;
8578}
8579
8580
8581/**
8582 * wpa_supplicant_deinit - Deinitialize %wpa_supplicant
8583 * @global: Pointer to global data from wpa_supplicant_init()
8584 *
8585 * This function is called to deinitialize %wpa_supplicant and to free all
8586 * allocated resources. Remaining network interfaces will also be removed.
8587 */
8588void wpa_supplicant_deinit(struct wpa_global *global)
8589{
8590 int i;
8591
8592 if (global == NULL)
8593 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008594
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008595 eloop_cancel_timeout(wpas_periodic, global, NULL);
8596
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008597#ifdef CONFIG_WIFI_DISPLAY
8598 wifi_display_deinit(global);
8599#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008600
8601 while (global->ifaces)
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008602 wpa_supplicant_remove_iface(global, global->ifaces, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008603
8604 if (global->ctrl_iface)
8605 wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
8606
8607 wpas_notify_supplicant_deinitialized(global);
8608
8609 eap_peer_unregister_methods();
8610#ifdef CONFIG_AP
8611 eap_server_unregister_methods();
8612#endif /* CONFIG_AP */
8613
8614 for (i = 0; wpa_drivers[i] && global->drv_priv; i++) {
8615 if (!global->drv_priv[i])
8616 continue;
8617 wpa_drivers[i]->global_deinit(global->drv_priv[i]);
8618 }
8619 os_free(global->drv_priv);
8620
8621 random_deinit();
8622
8623 eloop_destroy();
8624
8625 if (global->params.pid_file) {
8626 os_daemonize_terminate(global->params.pid_file);
8627 os_free(global->params.pid_file);
8628 }
8629 os_free(global->params.ctrl_interface);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07008630 os_free(global->params.ctrl_interface_group);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008631 os_free(global->params.override_driver);
8632 os_free(global->params.override_ctrl_interface);
Dmitry Shmidte4663042016-04-04 10:07:49 -07008633#ifdef CONFIG_MATCH_IFACE
8634 os_free(global->params.match_ifaces);
8635#endif /* CONFIG_MATCH_IFACE */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008636#ifdef CONFIG_P2P
Sasha Levitskiydaa60e52015-08-05 13:02:59 -07008637 os_free(global->params.conf_p2p_dev);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008638#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008639
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07008640 os_free(global->p2p_disallow_freq.range);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08008641 os_free(global->p2p_go_avoid_freq.range);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07008642 os_free(global->add_psk);
Dmitry Shmidt04949592012-07-19 12:16:46 -07008643
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008644 os_free(global);
8645 wpa_debug_close_syslog();
8646 wpa_debug_close_file();
Dmitry Shmidt04949592012-07-19 12:16:46 -07008647 wpa_debug_close_linux_tracing();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008648}
8649
8650
8651void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
8652{
8653 if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
8654 wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
8655 char country[3];
8656 country[0] = wpa_s->conf->country[0];
8657 country[1] = wpa_s->conf->country[1];
8658 country[2] = '\0';
8659 if (wpa_drv_set_country(wpa_s, country) < 0) {
8660 wpa_printf(MSG_ERROR, "Failed to set country code "
8661 "'%s'", country);
8662 }
8663 }
8664
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008665 if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
8666 wpas_init_ext_pw(wpa_s);
8667
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008668 if (wpa_s->conf->changed_parameters & CFG_CHANGED_SCHED_SCAN_PLANS)
8669 wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
8670
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008671 if (wpa_s->conf->changed_parameters & CFG_CHANGED_WOWLAN_TRIGGERS) {
8672 struct wpa_driver_capa capa;
8673 int res = wpa_drv_get_capa(wpa_s, &capa);
8674
8675 if (res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
8676 wpa_printf(MSG_ERROR,
8677 "Failed to update wowlan_triggers to '%s'",
8678 wpa_s->conf->wowlan_triggers);
8679 }
8680
Hai Shalom81f62d82019-07-22 12:10:00 -07008681 if (wpa_s->conf->changed_parameters & CFG_CHANGED_DISABLE_BTM)
8682 wpa_supplicant_set_default_scan_ies(wpa_s);
8683
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008684 if (wpa_s->conf->changed_parameters & CFG_CHANGED_FT_PREPEND_PMKID)
8685 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_PREPEND_PMKID,
8686 wpa_s->conf->ft_prepend_pmkid);
8687
Hai Shalom899fcc72020-10-19 14:38:18 -07008688#ifdef CONFIG_BGSCAN
8689 /*
8690 * We default to global bgscan parameters only when per-network bgscan
8691 * parameters aren't set. Only bother resetting bgscan parameters if
8692 * this is the case.
8693 */
8694 if ((wpa_s->conf->changed_parameters & CFG_CHANGED_BGSCAN) &&
8695 wpa_s->current_ssid && !wpa_s->current_ssid->bgscan &&
8696 wpa_s->wpa_state == WPA_COMPLETED)
8697 wpa_supplicant_reset_bgscan(wpa_s);
8698#endif /* CONFIG_BGSCAN */
8699
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008700#ifdef CONFIG_WPS
8701 wpas_wps_update_config(wpa_s);
8702#endif /* CONFIG_WPS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008703 wpas_p2p_update_config(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008704 wpa_s->conf->changed_parameters = 0;
8705}
8706
8707
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008708void add_freq(int *freqs, int *num_freqs, int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008709{
8710 int i;
8711
8712 for (i = 0; i < *num_freqs; i++) {
8713 if (freqs[i] == freq)
8714 return;
8715 }
8716
8717 freqs[*num_freqs] = freq;
8718 (*num_freqs)++;
8719}
8720
8721
8722static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
8723{
8724 struct wpa_bss *bss, *cbss;
8725 const int max_freqs = 10;
8726 int *freqs;
8727 int num_freqs = 0;
8728
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008729 freqs = os_calloc(max_freqs + 1, sizeof(int));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008730 if (freqs == NULL)
8731 return NULL;
8732
8733 cbss = wpa_s->current_bss;
8734
8735 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
8736 if (bss == cbss)
8737 continue;
8738 if (bss->ssid_len == cbss->ssid_len &&
8739 os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
Hai Shalom60840252021-02-19 19:02:11 -08008740 !wpa_bssid_ignore_is_listed(wpa_s, bss->bssid)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008741 add_freq(freqs, &num_freqs, bss->freq);
8742 if (num_freqs == max_freqs)
8743 break;
8744 }
8745 }
8746
8747 if (num_freqs == 0) {
8748 os_free(freqs);
8749 freqs = NULL;
8750 }
8751
8752 return freqs;
8753}
8754
8755
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008756void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid,
8757 const u8 **link_bssids)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008758{
8759 int timeout;
8760 int count;
8761 int *freqs = NULL;
8762
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008763 wpas_connect_work_done(wpa_s);
8764
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008765 /*
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008766 * Remove possible authentication timeout since the connection failed.
8767 */
8768 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
8769
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08008770 /*
Hai Shalom60840252021-02-19 19:02:11 -08008771 * There is no point in ignoring the AP temporarily if this event is
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08008772 * generated based on local request to disconnect.
8773 */
Hai Shalomfdcde762020-04-02 11:19:20 -07008774 if (wpa_s->own_disconnect_req || wpa_s->own_reconnect_req) {
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08008775 wpa_s->own_disconnect_req = 0;
8776 wpa_dbg(wpa_s, MSG_DEBUG,
8777 "Ignore connection failure due to local request to disconnect");
8778 return;
8779 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008780 if (wpa_s->disconnected) {
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008781 wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
8782 "indication since interface has been put into "
8783 "disconnected state");
8784 return;
8785 }
Roshan Piusb1ae0fe2019-02-15 08:05:38 -08008786 if (wpa_s->auto_reconnect_disabled) {
8787 wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
8788 "indication since auto connect is disabled");
8789 return;
8790 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008791
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008792 /* Also mark links as failed */
8793 while (link_bssids && *link_bssids) {
8794 wpa_bssid_ignore_add(wpa_s, *link_bssids);
8795 link_bssids++;
8796 }
8797
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008798 /*
Hai Shalom60840252021-02-19 19:02:11 -08008799 * Add the failed BSSID into the ignore list and speed up next scan
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008800 * attempt if there could be other APs that could accept association.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008801 */
Hai Shalom60840252021-02-19 19:02:11 -08008802 count = wpa_bssid_ignore_add(wpa_s, bssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008803 if (count == 1 && wpa_s->current_bss) {
8804 /*
Hai Shalom60840252021-02-19 19:02:11 -08008805 * This BSS was not in the ignore list before. If there is
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008806 * another BSS available for the same ESS, we should try that
8807 * next. Otherwise, we may as well try this one once more
8808 * before allowing other, likely worse, ESSes to be considered.
8809 */
8810 freqs = get_bss_freqs_in_ess(wpa_s);
8811 if (freqs) {
8812 wpa_dbg(wpa_s, MSG_DEBUG, "Another BSS in this ESS "
8813 "has been seen; try it next");
Hai Shalom60840252021-02-19 19:02:11 -08008814 wpa_bssid_ignore_add(wpa_s, bssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008815 /*
8816 * On the next scan, go through only the known channels
8817 * used in this ESS based on previous scans to speed up
8818 * common load balancing use case.
8819 */
8820 os_free(wpa_s->next_scan_freqs);
8821 wpa_s->next_scan_freqs = freqs;
8822 }
8823 }
8824
Hai Shalom899fcc72020-10-19 14:38:18 -07008825 wpa_s->consecutive_conn_failures++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08008826
Hai Shalom899fcc72020-10-19 14:38:18 -07008827 if (wpa_s->consecutive_conn_failures > 3 && wpa_s->current_ssid) {
Dmitry Shmidt4b060592013-04-29 16:42:49 -07008828 wpa_printf(MSG_DEBUG, "Continuous association failures - "
8829 "consider temporary network disabling");
Sunil Ravi77d572f2023-01-17 23:58:31 +00008830 wpas_auth_failed(wpa_s, "CONN_FAILED", bssid);
Dmitry Shmidt4b060592013-04-29 16:42:49 -07008831 }
Hai Shalom899fcc72020-10-19 14:38:18 -07008832 /*
8833 * Multiple consecutive connection failures mean that other APs are
8834 * either not available or have already been tried, so we can start
8835 * increasing the delay here to avoid constant scanning.
8836 */
8837 switch (wpa_s->consecutive_conn_failures) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008838 case 1:
8839 timeout = 100;
8840 break;
8841 case 2:
8842 timeout = 500;
8843 break;
8844 case 3:
8845 timeout = 1000;
8846 break;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08008847 case 4:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008848 timeout = 5000;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08008849 break;
8850 default:
8851 timeout = 10000;
8852 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008853 }
8854
Hai Shalom899fcc72020-10-19 14:38:18 -07008855 wpa_dbg(wpa_s, MSG_DEBUG,
8856 "Consecutive connection failures: %d --> request scan in %d ms",
8857 wpa_s->consecutive_conn_failures, timeout);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08008858
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008859 /*
8860 * TODO: if more than one possible AP is available in scan results,
8861 * could try the other ones before requesting a new scan.
8862 */
Hai Shalom021b0b52019-04-10 11:17:58 -07008863
8864 /* speed up the connection attempt with normal scan */
8865 wpa_s->normal_scans = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008866 wpa_supplicant_req_scan(wpa_s, timeout / 1000,
8867 1000 * (timeout % 1000));
8868}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008869
8870
Hai Shalomce48b4a2018-09-05 11:41:35 -07008871#ifdef CONFIG_FILS
Hai Shalomc1a21442022-02-04 13:43:00 -08008872
8873void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s)
8874{
8875 struct wpa_ssid *ssid = wpa_s->current_ssid;
8876 const u8 *realm, *username, *rrk;
8877 size_t realm_len, username_len, rrk_len;
8878 u16 next_seq_num;
8879
8880 /* Clear the PMKSA cache entry if FILS authentication was rejected.
8881 * Check for ERP keys existing to limit when this can be done since
8882 * the rejection response is not protected and such triggers should
8883 * really not allow internal state to be modified unless required to
8884 * avoid significant issues in functionality. In addition, drop
8885 * externally configure PMKSA entries even without ERP keys since it
8886 * is possible for an external component to add PMKSA entries for FILS
8887 * authentication without restoring previously generated ERP keys.
8888 *
8889 * In this case, this is needed to allow recovery from cases where the
8890 * AP or authentication server has dropped PMKSAs and ERP keys. */
8891 if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt))
8892 return;
8893
8894 if (eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
8895 &username, &username_len,
8896 &realm, &realm_len, &next_seq_num,
8897 &rrk, &rrk_len) != 0 ||
8898 !realm) {
8899 wpa_dbg(wpa_s, MSG_DEBUG,
8900 "FILS: Drop external PMKSA cache entry");
8901 wpa_sm_aborted_external_cached(wpa_s->wpa);
8902 wpa_sm_external_pmksa_cache_flush(wpa_s->wpa, ssid);
8903 return;
8904 }
8905
8906 wpa_dbg(wpa_s, MSG_DEBUG, "FILS: Drop PMKSA cache entry");
8907 wpa_sm_aborted_cached(wpa_s->wpa);
8908 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
8909}
8910
8911
Hai Shalomce48b4a2018-09-05 11:41:35 -07008912void fils_connection_failure(struct wpa_supplicant *wpa_s)
8913{
8914 struct wpa_ssid *ssid = wpa_s->current_ssid;
8915 const u8 *realm, *username, *rrk;
8916 size_t realm_len, username_len, rrk_len;
8917 u16 next_seq_num;
8918
8919 if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt) ||
8920 eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
8921 &username, &username_len,
8922 &realm, &realm_len, &next_seq_num,
8923 &rrk, &rrk_len) != 0 ||
8924 !realm)
8925 return;
8926
8927 wpa_hexdump_ascii(MSG_DEBUG,
8928 "FILS: Store last connection failure realm",
8929 realm, realm_len);
8930 os_free(wpa_s->last_con_fail_realm);
8931 wpa_s->last_con_fail_realm = os_malloc(realm_len);
8932 if (wpa_s->last_con_fail_realm) {
8933 wpa_s->last_con_fail_realm_len = realm_len;
8934 os_memcpy(wpa_s->last_con_fail_realm, realm, realm_len);
8935 }
8936}
8937#endif /* CONFIG_FILS */
8938
8939
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008940int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
8941{
8942 return wpa_s->conf->ap_scan == 2 ||
8943 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
8944}
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008945
Dmitry Shmidt04949592012-07-19 12:16:46 -07008946
Sunil Ravi7f769292024-07-23 22:21:32 +00008947static bool wpas_driver_rsn_override(struct wpa_supplicant *wpa_s)
8948{
8949 return !!(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_RSN_OVERRIDE_STA);
8950}
8951
8952
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00008953bool wpas_rsn_overriding(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
Sunil Ravi7f769292024-07-23 22:21:32 +00008954{
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00008955 enum wpas_rsn_overriding rsno;
8956
8957 if (ssid && ssid->rsn_overriding != RSN_OVERRIDING_NOT_SET)
8958 rsno = ssid->rsn_overriding;
8959 else
8960 rsno = wpa_s->conf->rsn_overriding;
8961
8962 if (rsno == RSN_OVERRIDING_DISABLED)
Sunil Ravi7f769292024-07-23 22:21:32 +00008963 return false;
8964
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00008965 if (rsno == RSN_OVERRIDING_ENABLED)
Sunil Ravi7f769292024-07-23 22:21:32 +00008966 return true;
8967
8968 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
8969 wpas_driver_bss_selection(wpa_s))
8970 return wpas_driver_rsn_override(wpa_s);
8971
8972 return true;
8973}
8974
8975
Gabriel Biren57ededa2021-09-03 16:08:50 +00008976#if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW) || defined (CONFIG_CTRL_IFACE_AIDL)
Dmitry Shmidt04949592012-07-19 12:16:46 -07008977int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
8978 struct wpa_ssid *ssid,
8979 const char *field,
8980 const char *value)
8981{
8982#ifdef IEEE8021X_EAPOL
Roshan Pius71a6b8a2016-08-17 13:04:08 -07008983 enum wpa_ctrl_req_type rtype;
Dmitry Shmidt04949592012-07-19 12:16:46 -07008984
8985 wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
8986 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
8987 (const u8 *) value, os_strlen(value));
8988
Roshan Pius71a6b8a2016-08-17 13:04:08 -07008989 rtype = wpa_supplicant_ctrl_req_from_string(field);
pkanwareb9203e2017-10-26 16:00:35 -07008990 return wpa_supplicant_ctrl_rsp_handle(wpa_s, ssid, rtype, value, strlen(value));
Roshan Pius71a6b8a2016-08-17 13:04:08 -07008991#else /* IEEE8021X_EAPOL */
8992 wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
8993 return -1;
8994#endif /* IEEE8021X_EAPOL */
8995}
8996
8997int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
8998 struct wpa_ssid *ssid,
8999 enum wpa_ctrl_req_type rtype,
pkanwareb9203e2017-10-26 16:00:35 -07009000 const char *value, int value_len)
Roshan Pius71a6b8a2016-08-17 13:04:08 -07009001{
9002#ifdef IEEE8021X_EAPOL
9003 struct eap_peer_config *eap = &ssid->eap;
Ecco Park00a7b212018-01-26 13:44:44 -08009004 char *identity, *imsi_identity;
Roshan Pius71a6b8a2016-08-17 13:04:08 -07009005
9006 switch (rtype) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07009007 case WPA_CTRL_REQ_EAP_IDENTITY:
9008 os_free(eap->identity);
Ecco Park00a7b212018-01-26 13:44:44 -08009009 os_free(eap->imsi_identity);
9010 if (value == NULL)
9011 return -1;
9012 identity = os_strchr(value, ':');
9013 if (identity == NULL) {
9014 /* plain identity */
9015 eap->identity = (u8 *)os_strdup(value);
9016 eap->identity_len = os_strlen(value);
9017 } else {
9018 /* have both plain identity and encrypted identity */
9019 imsi_identity = value;
9020 *identity++ = '\0';
9021 /* plain identity */
9022 eap->imsi_identity = (u8 *)dup_binstr(imsi_identity, strlen(imsi_identity));
9023 eap->imsi_identity_len = strlen(imsi_identity);
9024 /* encrypted identity */
9025 eap->identity = (u8 *)dup_binstr(identity,
9026 value_len - strlen(imsi_identity) - 1);
9027 eap->identity_len = value_len - strlen(imsi_identity) - 1;
9028 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07009029 eap->pending_req_identity = 0;
9030 if (ssid == wpa_s->current_ssid)
9031 wpa_s->reassociate = 1;
9032 break;
9033 case WPA_CTRL_REQ_EAP_PASSWORD:
Dmitry Shmidtc2817022014-07-02 10:32:10 -07009034 bin_clear_free(eap->password, eap->password_len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07009035 eap->password = (u8 *) os_strdup(value);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009036 if (!eap->password)
9037 return -1;
pkanwareb9203e2017-10-26 16:00:35 -07009038 eap->password_len = value_len;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009039 eap->pending_req_password = 0;
9040 if (ssid == wpa_s->current_ssid)
9041 wpa_s->reassociate = 1;
9042 break;
9043 case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
Dmitry Shmidtc2817022014-07-02 10:32:10 -07009044 bin_clear_free(eap->new_password, eap->new_password_len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07009045 eap->new_password = (u8 *) os_strdup(value);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009046 if (!eap->new_password)
9047 return -1;
pkanwareb9203e2017-10-26 16:00:35 -07009048 eap->new_password_len = value_len;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009049 eap->pending_req_new_password = 0;
9050 if (ssid == wpa_s->current_ssid)
9051 wpa_s->reassociate = 1;
9052 break;
9053 case WPA_CTRL_REQ_EAP_PIN:
Hai Shalomc3565922019-10-28 11:58:20 -07009054 str_clear_free(eap->cert.pin);
9055 eap->cert.pin = os_strdup(value);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009056 if (!eap->cert.pin)
9057 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009058 eap->pending_req_pin = 0;
9059 if (ssid == wpa_s->current_ssid)
9060 wpa_s->reassociate = 1;
9061 break;
9062 case WPA_CTRL_REQ_EAP_OTP:
Dmitry Shmidtc2817022014-07-02 10:32:10 -07009063 bin_clear_free(eap->otp, eap->otp_len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07009064 eap->otp = (u8 *) os_strdup(value);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009065 if (!eap->otp)
9066 return -1;
pkanwareb9203e2017-10-26 16:00:35 -07009067 eap->otp_len = value_len;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009068 os_free(eap->pending_req_otp);
9069 eap->pending_req_otp = NULL;
9070 eap->pending_req_otp_len = 0;
9071 break;
9072 case WPA_CTRL_REQ_EAP_PASSPHRASE:
Hai Shalomc3565922019-10-28 11:58:20 -07009073 str_clear_free(eap->cert.private_key_passwd);
9074 eap->cert.private_key_passwd = os_strdup(value);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009075 if (!eap->cert.private_key_passwd)
9076 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009077 eap->pending_req_passphrase = 0;
9078 if (ssid == wpa_s->current_ssid)
9079 wpa_s->reassociate = 1;
9080 break;
Dmitry Shmidt051af732013-10-22 13:52:46 -07009081 case WPA_CTRL_REQ_SIM:
Dmitry Shmidtc2817022014-07-02 10:32:10 -07009082 str_clear_free(eap->external_sim_resp);
Dmitry Shmidt051af732013-10-22 13:52:46 -07009083 eap->external_sim_resp = os_strdup(value);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009084 if (!eap->external_sim_resp)
9085 return -1;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08009086 eap->pending_req_sim = 0;
Dmitry Shmidt051af732013-10-22 13:52:46 -07009087 break;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009088 case WPA_CTRL_REQ_PSK_PASSPHRASE:
9089 if (wpa_config_set(ssid, "psk", value, 0) < 0)
9090 return -1;
9091 ssid->mem_only_psk = 1;
9092 if (ssid->passphrase)
9093 wpa_config_update_psk(ssid);
9094 if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
9095 wpa_supplicant_req_scan(wpa_s, 0, 0);
9096 break;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009097 case WPA_CTRL_REQ_EXT_CERT_CHECK:
9098 if (eap->pending_ext_cert_check != PENDING_CHECK)
9099 return -1;
9100 if (os_strcmp(value, "good") == 0)
9101 eap->pending_ext_cert_check = EXT_CERT_CHECK_GOOD;
9102 else if (os_strcmp(value, "bad") == 0)
9103 eap->pending_ext_cert_check = EXT_CERT_CHECK_BAD;
9104 else
9105 return -1;
9106 break;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009107 default:
Roshan Pius71a6b8a2016-08-17 13:04:08 -07009108 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown type %d", rtype);
Dmitry Shmidt04949592012-07-19 12:16:46 -07009109 return -1;
9110 }
9111
9112 return 0;
9113#else /* IEEE8021X_EAPOL */
9114 wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
9115 return -1;
9116#endif /* IEEE8021X_EAPOL */
9117}
Gabriel Biren57ededa2021-09-03 16:08:50 +00009118#endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW || CONFIG_CTRL_IFACE_AIDL */
Dmitry Shmidt04949592012-07-19 12:16:46 -07009119
9120
9121int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
9122{
Hai Shalomfdcde762020-04-02 11:19:20 -07009123#ifdef CONFIG_WEP
Dmitry Shmidt04949592012-07-19 12:16:46 -07009124 int i;
9125 unsigned int drv_enc;
Hai Shalomfdcde762020-04-02 11:19:20 -07009126#endif /* CONFIG_WEP */
Dmitry Shmidt04949592012-07-19 12:16:46 -07009127
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08009128 if (wpa_s->p2p_mgmt)
9129 return 1; /* no normal network profiles on p2p_mgmt interface */
9130
Dmitry Shmidt04949592012-07-19 12:16:46 -07009131 if (ssid == NULL)
9132 return 1;
9133
9134 if (ssid->disabled)
9135 return 1;
9136
Hai Shalomfdcde762020-04-02 11:19:20 -07009137#ifdef CONFIG_WEP
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08009138 if (wpa_s->drv_capa_known)
Dmitry Shmidt04949592012-07-19 12:16:46 -07009139 drv_enc = wpa_s->drv_enc;
9140 else
9141 drv_enc = (unsigned int) -1;
9142
9143 for (i = 0; i < NUM_WEP_KEYS; i++) {
9144 size_t len = ssid->wep_key_len[i];
9145 if (len == 0)
9146 continue;
9147 if (len == 5 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP40))
9148 continue;
9149 if (len == 13 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP104))
9150 continue;
9151 if (len == 16 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP128))
9152 continue;
9153 return 1; /* invalid WEP key */
9154 }
Hai Shalomfdcde762020-04-02 11:19:20 -07009155#endif /* CONFIG_WEP */
Dmitry Shmidt04949592012-07-19 12:16:46 -07009156
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009157 if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009158 (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00009159 !(wpa_key_mgmt_sae(ssid->key_mgmt) &&
Sunil Ravi876a49b2025-02-03 19:18:32 +00009160 (ssid->passphrase || ssid->sae_password || ssid->pmk_valid)) &&
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009161 !ssid->mem_only_psk)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009162 return 1;
9163
Sunil Ravi89eba102022-09-13 21:04:37 -07009164#ifdef IEEE8021X_EAPOL
Sunil8cd6f4d2022-06-28 18:40:46 +00009165#ifdef CRYPTO_RSA_OAEP_SHA256
9166 if (ssid->eap.imsi_privacy_cert) {
9167 struct crypto_rsa_key *key;
9168 bool failed = false;
9169
9170 key = crypto_rsa_key_read(ssid->eap.imsi_privacy_cert, false);
9171 if (!key)
9172 failed = true;
9173 crypto_rsa_key_free(key);
9174 if (failed) {
9175 wpa_printf(MSG_DEBUG,
9176 "Invalid imsi_privacy_cert (%s) - disable network",
9177 ssid->eap.imsi_privacy_cert);
9178 return 1;
9179 }
9180 }
9181#endif /* CRYPTO_RSA_OAEP_SHA256 */
Sunil Ravi89eba102022-09-13 21:04:37 -07009182#endif /* IEEE8021X_EAPOL */
Sunil8cd6f4d2022-06-28 18:40:46 +00009183
Dmitry Shmidt04949592012-07-19 12:16:46 -07009184 return 0;
9185}
9186
9187
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009188int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
9189{
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009190 if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
9191 if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
9192 !(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
9193 /*
9194 * Driver does not support BIP -- ignore pmf=1 default
9195 * since the connection with PMF would fail and the
9196 * configuration does not require PMF to be enabled.
9197 */
9198 return NO_MGMT_FRAME_PROTECTION;
9199 }
9200
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009201 if (ssid &&
9202 (ssid->key_mgmt &
9203 ~(WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPS |
9204 WPA_KEY_MGMT_IEEE8021X_NO_WPA)) == 0) {
9205 /*
9206 * Do not use the default PMF value for non-RSN networks
9207 * since PMF is available only with RSN and pmf=2
9208 * configuration would otherwise prevent connections to
9209 * all open networks.
9210 */
9211 return NO_MGMT_FRAME_PROTECTION;
9212 }
9213
Sunil Ravi77d572f2023-01-17 23:58:31 +00009214#ifdef CONFIG_OCV
9215 /* Enable PMF if OCV is being enabled */
9216 if (wpa_s->conf->pmf == NO_MGMT_FRAME_PROTECTION &&
9217 ssid && ssid->ocv)
9218 return MGMT_FRAME_PROTECTION_OPTIONAL;
9219#endif /* CONFIG_OCV */
9220
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009221 return wpa_s->conf->pmf;
9222 }
9223
9224 return ssid->ieee80211w;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009225}
9226
9227
Sunil Ravi77d572f2023-01-17 23:58:31 +00009228#ifdef CONFIG_SAE
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00009229
9230enum sae_pwe wpas_get_ssid_sae_pwe(struct wpa_supplicant *wpa_s,
9231 struct wpa_ssid *ssid)
9232{
9233 if (!ssid || ssid->sae_pwe == DEFAULT_SAE_PWE)
9234 return wpa_s->conf->sae_pwe;
9235 return ssid->sae_pwe;
9236}
9237
9238
Sunil Ravi77d572f2023-01-17 23:58:31 +00009239bool wpas_is_sae_avoided(struct wpa_supplicant *wpa_s,
9240 struct wpa_ssid *ssid,
9241 const struct wpa_ie_data *ie)
9242{
9243 return wpa_s->conf->sae_check_mfp &&
9244 (!(ie->capabilities &
9245 (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) ||
9246 wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION);
9247}
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00009248
Sunil Ravi77d572f2023-01-17 23:58:31 +00009249#endif /* CONFIG_SAE */
9250
9251
Hai Shalomc1a21442022-02-04 13:43:00 -08009252int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
9253{
9254 if (wpa_s->current_ssid == NULL ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009255 wpa_s->wpa_state < WPA_4WAY_HANDSHAKE)
Hai Shalomc1a21442022-02-04 13:43:00 -08009256 return 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009257 if (wpa_s->valid_links) {
9258 if (!ether_addr_equal(addr, wpa_s->ap_mld_addr) &&
9259 !wpas_ap_link_address(wpa_s, addr))
9260 return 0;
9261 } else {
9262 if (!ether_addr_equal(addr, wpa_s->bssid))
9263 return 0;
9264 }
Hai Shalomc1a21442022-02-04 13:43:00 -08009265 return wpa_sm_pmf_enabled(wpa_s->wpa);
9266}
9267
9268
Dmitry Shmidt687922c2012-03-26 14:02:32 -07009269int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009270{
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07009271 if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009272 return 1;
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07009273 if (wpa_s->global->conc_pref == WPA_CONC_PREF_STA)
Dmitry Shmidt687922c2012-03-26 14:02:32 -07009274 return 0;
Dmitry Shmidt687922c2012-03-26 14:02:32 -07009275 return -1;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009276}
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009277
9278
Sunil Ravi77d572f2023-01-17 23:58:31 +00009279void wpas_auth_failed(struct wpa_supplicant *wpa_s, const char *reason,
9280 const u8 *bssid)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009281{
9282 struct wpa_ssid *ssid = wpa_s->current_ssid;
9283 int dur;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009284 struct os_reltime now;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009285
9286 if (ssid == NULL) {
9287 wpa_printf(MSG_DEBUG, "Authentication failure but no known "
9288 "SSID block");
9289 return;
9290 }
9291
9292 if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
9293 return;
9294
9295 ssid->auth_failures++;
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -07009296
9297#ifdef CONFIG_P2P
9298 if (ssid->p2p_group &&
9299 (wpa_s->p2p_in_provisioning || wpa_s->show_group_started)) {
9300 /*
9301 * Skip the wait time since there is a short timeout on the
9302 * connection to a P2P group.
9303 */
9304 return;
9305 }
9306#endif /* CONFIG_P2P */
9307
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009308 if (ssid->auth_failures > 50)
9309 dur = 300;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009310 else if (ssid->auth_failures > 10)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08009311 dur = 120;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009312 else if (ssid->auth_failures > 5)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08009313 dur = 90;
9314 else if (ssid->auth_failures > 3)
9315 dur = 60;
9316 else if (ssid->auth_failures > 2)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009317 dur = 30;
9318 else if (ssid->auth_failures > 1)
9319 dur = 20;
9320 else
9321 dur = 10;
9322
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08009323 if (ssid->auth_failures > 1 &&
9324 wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt))
9325 dur += os_random() % (ssid->auth_failures * 10);
9326
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009327 os_get_reltime(&now);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009328 if (now.sec + dur <= ssid->disabled_until.sec)
9329 return;
9330
9331 ssid->disabled_until.sec = now.sec + dur;
9332
9333 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07009334 "id=%d ssid=\"%s\" auth_failures=%u duration=%d reason=%s",
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009335 ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07009336 ssid->auth_failures, dur, reason);
Gabriel Biren3a2ec2c2022-03-07 17:59:41 +00009337
9338 char *format_str = "id=%d ssid=\"%s\" auth_failures=%u duration=%d reason=%s";
9339 int msg_len = snprintf(NULL, 0, format_str,
9340 ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
9341 ssid->auth_failures, dur, reason) + 1;
9342 char *msg = os_malloc(msg_len);
Narasimha Rao PVSc28a5132022-12-02 18:36:38 +05309343 if (!msg)
9344 return;
Gabriel Biren3a2ec2c2022-03-07 17:59:41 +00009345 snprintf(msg, msg_len, format_str,
9346 ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
9347 ssid->auth_failures, dur, reason);
9348 wpas_notify_ssid_temp_disabled(wpa_s, msg);
9349 os_free(msg);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009350
9351 if (bssid)
9352 os_memcpy(ssid->disabled_due_to, bssid, ETH_ALEN);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009353}
9354
9355
9356void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
9357 struct wpa_ssid *ssid, int clear_failures)
9358{
9359 if (ssid == NULL)
9360 return;
9361
9362 if (ssid->disabled_until.sec) {
9363 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED
9364 "id=%d ssid=\"%s\"",
9365 ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
9366 }
9367 ssid->disabled_until.sec = 0;
9368 ssid->disabled_until.usec = 0;
Sunil Ravi77d572f2023-01-17 23:58:31 +00009369 if (clear_failures) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009370 ssid->auth_failures = 0;
Sunil Ravi77d572f2023-01-17 23:58:31 +00009371 } else if (!is_zero_ether_addr(ssid->disabled_due_to)) {
9372 wpa_printf(MSG_DEBUG, "Mark BSSID " MACSTR
9373 " ignored to allow a lower priority BSS, if any, to be tried next",
9374 MAC2STR(ssid->disabled_due_to));
9375 wpa_bssid_ignore_add(wpa_s, ssid->disabled_due_to);
9376 os_memset(ssid->disabled_due_to, 0, ETH_ALEN);
9377 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009378}
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009379
9380
9381int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid)
9382{
9383 size_t i;
9384
9385 if (wpa_s->disallow_aps_bssid == NULL)
9386 return 0;
9387
9388 for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009389 if (ether_addr_equal(wpa_s->disallow_aps_bssid + i * ETH_ALEN,
9390 bssid))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009391 return 1;
9392 }
9393
9394 return 0;
9395}
9396
9397
9398int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
9399 size_t ssid_len)
9400{
9401 size_t i;
9402
9403 if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL)
9404 return 0;
9405
9406 for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) {
9407 struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i];
9408 if (ssid_len == s->ssid_len &&
9409 os_memcmp(ssid, s->ssid, ssid_len) == 0)
9410 return 1;
9411 }
9412
9413 return 0;
9414}
9415
9416
9417/**
9418 * wpas_request_connection - Request a new connection
9419 * @wpa_s: Pointer to the network interface
9420 *
9421 * This function is used to request a new connection to be found. It will mark
9422 * the interface to allow reassociation and request a new scan to find a
9423 * suitable network to connect to.
9424 */
9425void wpas_request_connection(struct wpa_supplicant *wpa_s)
9426{
9427 wpa_s->normal_scans = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009428 wpa_s->scan_req = NORMAL_SCAN_REQ;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009429 wpa_supplicant_reinit_autoscan(wpa_s);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009430 wpa_s->disconnected = 0;
9431 wpa_s->reassociate = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009432 wpa_s->last_owe_group = 0;
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08009433
9434 if (wpa_supplicant_fast_associate(wpa_s) != 1)
9435 wpa_supplicant_req_scan(wpa_s, 0, 0);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08009436 else
9437 wpa_s->reattach = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009438}
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009439
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009440
Roshan Pius02242d72016-08-09 15:31:48 -07009441/**
9442 * wpas_request_disconnection - Request disconnection
9443 * @wpa_s: Pointer to the network interface
9444 *
9445 * This function is used to request disconnection from the currently connected
9446 * network. This will stop any ongoing scans and initiate deauthentication.
9447 */
9448void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
9449{
9450#ifdef CONFIG_SME
9451 wpa_s->sme.prev_bssid_set = 0;
9452#endif /* CONFIG_SME */
9453 wpa_s->reassociate = 0;
9454 wpa_s->disconnected = 1;
9455 wpa_supplicant_cancel_sched_scan(wpa_s);
9456 wpa_supplicant_cancel_scan(wpa_s);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00009457 wpas_abort_ongoing_scan(wpa_s);
Roshan Pius02242d72016-08-09 15:31:48 -07009458 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
9459 eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
Hai Shalom021b0b52019-04-10 11:17:58 -07009460 radio_remove_works(wpa_s, "connect", 0);
9461 radio_remove_works(wpa_s, "sme-connect", 0);
Hai Shalomc1a21442022-02-04 13:43:00 -08009462 wpa_s->roam_in_progress = false;
9463#ifdef CONFIG_WNM
9464 wpa_s->bss_trans_mgmt_in_progress = false;
9465#endif /* CONFIG_WNM */
Roshan Pius02242d72016-08-09 15:31:48 -07009466}
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009467
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07009468
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009469void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
9470 struct wpa_used_freq_data *freqs_data,
9471 unsigned int len)
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08009472{
9473 unsigned int i;
9474
9475 wpa_dbg(wpa_s, MSG_DEBUG, "Shared frequencies (len=%u): %s",
9476 len, title);
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009477 for (i = 0; i < len; i++) {
9478 struct wpa_used_freq_data *cur = &freqs_data[i];
9479 wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d, flags=0x%X",
9480 i, cur->freq, cur->flags);
9481 }
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08009482}
9483
9484
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009485/*
9486 * Find the operating frequencies of any of the virtual interfaces that
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009487 * are using the same radio as the current interface, and in addition, get
9488 * information about the interface types that are using the frequency.
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009489 */
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009490int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
9491 struct wpa_used_freq_data *freqs_data,
Sunil Ravi77d572f2023-01-17 23:58:31 +00009492 unsigned int len, bool exclude_current)
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009493{
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009494 struct wpa_supplicant *ifs;
9495 u8 bssid[ETH_ALEN];
9496 int freq;
9497 unsigned int idx = 0, i;
9498
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08009499 wpa_dbg(wpa_s, MSG_DEBUG,
9500 "Determining shared radio frequencies (max len %u)", len);
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009501 os_memset(freqs_data, 0, sizeof(struct wpa_used_freq_data) * len);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009502
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08009503 dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
9504 radio_list) {
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009505 if (idx == len)
9506 break;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009507
Sunil Ravi77d572f2023-01-17 23:58:31 +00009508 if (exclude_current && ifs == wpa_s)
9509 continue;
9510
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009511 if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
9512 continue;
9513
9514 if (ifs->current_ssid->mode == WPAS_MODE_AP ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009515 ifs->current_ssid->mode == WPAS_MODE_P2P_GO ||
9516 ifs->current_ssid->mode == WPAS_MODE_MESH)
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009517 freq = ifs->current_ssid->frequency;
9518 else if (wpa_drv_get_bssid(ifs, bssid) == 0)
9519 freq = ifs->assoc_freq;
9520 else
9521 continue;
9522
9523 /* Hold only distinct freqs */
9524 for (i = 0; i < idx; i++)
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009525 if (freqs_data[i].freq == freq)
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009526 break;
9527
9528 if (i == idx)
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009529 freqs_data[idx++].freq = freq;
9530
9531 if (ifs->current_ssid->mode == WPAS_MODE_INFRA) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009532 freqs_data[i].flags |= ifs->current_ssid->p2p_group ?
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009533 WPA_FREQ_USED_BY_P2P_CLIENT :
9534 WPA_FREQ_USED_BY_INFRA_STATION;
9535 }
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009536 }
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08009537
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009538 dump_freq_data(wpa_s, "completed iteration", freqs_data, idx);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009539 return idx;
9540}
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009541
9542
9543/*
9544 * Find the operating frequencies of any of the virtual interfaces that
9545 * are using the same radio as the current interface.
9546 */
9547int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
Sunil Ravi77d572f2023-01-17 23:58:31 +00009548 int *freq_array, unsigned int len,
9549 bool exclude_current)
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009550{
9551 struct wpa_used_freq_data *freqs_data;
9552 int num, i;
9553
9554 os_memset(freq_array, 0, sizeof(int) * len);
9555
9556 freqs_data = os_calloc(len, sizeof(struct wpa_used_freq_data));
9557 if (!freqs_data)
9558 return -1;
9559
Sunil Ravi77d572f2023-01-17 23:58:31 +00009560 num = get_shared_radio_freqs_data(wpa_s, freqs_data, len,
9561 exclude_current);
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009562 for (i = 0; i < num; i++)
9563 freq_array[i] = freqs_data[i].freq;
9564
9565 os_free(freqs_data);
9566
9567 return num;
9568}
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009569
9570
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009571struct wpa_supplicant *
9572wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
9573{
9574 switch (frame) {
9575#ifdef CONFIG_P2P
9576 case VENDOR_ELEM_PROBE_REQ_P2P:
9577 case VENDOR_ELEM_PROBE_RESP_P2P:
9578 case VENDOR_ELEM_PROBE_RESP_P2P_GO:
9579 case VENDOR_ELEM_BEACON_P2P_GO:
9580 case VENDOR_ELEM_P2P_PD_REQ:
9581 case VENDOR_ELEM_P2P_PD_RESP:
9582 case VENDOR_ELEM_P2P_GO_NEG_REQ:
9583 case VENDOR_ELEM_P2P_GO_NEG_RESP:
9584 case VENDOR_ELEM_P2P_GO_NEG_CONF:
9585 case VENDOR_ELEM_P2P_INV_REQ:
9586 case VENDOR_ELEM_P2P_INV_RESP:
9587 case VENDOR_ELEM_P2P_ASSOC_REQ:
9588 case VENDOR_ELEM_P2P_ASSOC_RESP:
Dmitry Shmidt9c175262016-03-03 10:20:07 -08009589 return wpa_s->p2pdev;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009590#endif /* CONFIG_P2P */
9591 default:
9592 return wpa_s;
9593 }
9594}
9595
9596
9597void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s)
9598{
9599 unsigned int i;
9600 char buf[30];
9601
9602 wpa_printf(MSG_DEBUG, "Update vendor elements");
9603
9604 for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
9605 if (wpa_s->vendor_elem[i]) {
9606 int res;
9607
9608 res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
9609 if (!os_snprintf_error(sizeof(buf), res)) {
9610 wpa_hexdump_buf(MSG_DEBUG, buf,
9611 wpa_s->vendor_elem[i]);
9612 }
9613 }
9614 }
9615
9616#ifdef CONFIG_P2P
Jimmy Chen48b484b2022-01-25 00:17:50 +08009617 if ((wpa_s->parent == wpa_s || (wpa_s == wpa_s->p2pdev && wpa_s->p2p_mgmt)) &&
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009618 wpa_s->global->p2p &&
9619 !wpa_s->global->p2p_disabled)
9620 p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
9621#endif /* CONFIG_P2P */
9622}
9623
9624
9625int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
9626 const u8 *elem, size_t len)
9627{
9628 u8 *ie, *end;
9629
9630 ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
9631 end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
9632
9633 for (; ie + 1 < end; ie += 2 + ie[1]) {
9634 if (ie + len > end)
9635 break;
9636 if (os_memcmp(ie, elem, len) != 0)
9637 continue;
9638
9639 if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
9640 wpabuf_free(wpa_s->vendor_elem[frame]);
9641 wpa_s->vendor_elem[frame] = NULL;
9642 } else {
9643 os_memmove(ie, ie + len, end - (ie + len));
9644 wpa_s->vendor_elem[frame]->used -= len;
9645 }
9646 wpas_vendor_elem_update(wpa_s);
9647 return 0;
9648 }
9649
9650 return -1;
9651}
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009652
9653
9654struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
Hai Shalomfdcde762020-04-02 11:19:20 -07009655 u16 num_modes, enum hostapd_hw_mode mode,
Hai Shalom60840252021-02-19 19:02:11 -08009656 bool is_6ghz)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009657{
9658 u16 i;
9659
Hai Shalomc1a21442022-02-04 13:43:00 -08009660 if (!modes)
9661 return NULL;
9662
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009663 for (i = 0; i < num_modes; i++) {
Hai Shalomfdcde762020-04-02 11:19:20 -07009664 if (modes[i].mode != mode ||
9665 !modes[i].num_channels || !modes[i].channels)
9666 continue;
Sunil Ravi99c035e2024-07-12 01:42:03 +00009667 if (is_6ghz == modes[i].is_6ghz)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009668 return &modes[i];
9669 }
9670
9671 return NULL;
9672}
9673
9674
Hai Shalomc1a21442022-02-04 13:43:00 -08009675struct hostapd_hw_modes * get_mode_with_freq(struct hostapd_hw_modes *modes,
9676 u16 num_modes, int freq)
9677{
9678 int i, j;
9679
9680 for (i = 0; i < num_modes; i++) {
9681 for (j = 0; j < modes[i].num_channels; j++) {
9682 if (freq == modes[i].channels[j].freq)
9683 return &modes[i];
9684 }
9685 }
9686
9687 return NULL;
9688}
9689
9690
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009691static struct
9692wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
9693 const u8 *bssid)
9694{
9695 struct wpa_bss_tmp_disallowed *bss;
9696
9697 dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed,
9698 struct wpa_bss_tmp_disallowed, list) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009699 if (ether_addr_equal(bssid, bss->bssid))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009700 return bss;
9701 }
9702
9703 return NULL;
9704}
9705
9706
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009707static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s)
9708{
9709 struct wpa_bss_tmp_disallowed *tmp;
9710 unsigned int num_bssid = 0;
9711 u8 *bssids;
9712 int ret;
9713
9714 bssids = os_malloc(dl_list_len(&wpa_s->bss_tmp_disallowed) * ETH_ALEN);
9715 if (!bssids)
9716 return -1;
9717 dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
9718 struct wpa_bss_tmp_disallowed, list) {
9719 os_memcpy(&bssids[num_bssid * ETH_ALEN], tmp->bssid,
9720 ETH_ALEN);
9721 num_bssid++;
9722 }
Hai Shalom899fcc72020-10-19 14:38:18 -07009723 ret = wpa_drv_set_bssid_tmp_disallow(wpa_s, num_bssid, bssids);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009724 os_free(bssids);
9725 return ret;
9726}
9727
9728
9729static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx)
9730{
9731 struct wpa_supplicant *wpa_s = eloop_ctx;
9732 struct wpa_bss_tmp_disallowed *tmp, *bss = timeout_ctx;
9733
9734 /* Make sure the bss is not already freed */
9735 dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
9736 struct wpa_bss_tmp_disallowed, list) {
9737 if (bss == tmp) {
Hai Shalomc1a21442022-02-04 13:43:00 -08009738 remove_bss_tmp_disallowed_entry(wpa_s, tmp);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009739 wpa_set_driver_tmp_disallow_list(wpa_s);
9740 break;
9741 }
9742 }
9743}
9744
9745
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009746void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
Hai Shalom74f70d42019-02-11 14:42:39 -08009747 unsigned int sec, int rssi_threshold)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009748{
9749 struct wpa_bss_tmp_disallowed *bss;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009750
9751 bss = wpas_get_disallowed_bss(wpa_s, bssid);
9752 if (bss) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009753 eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
Hai Shalom74f70d42019-02-11 14:42:39 -08009754 goto finish;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009755 }
9756
9757 bss = os_malloc(sizeof(*bss));
9758 if (!bss) {
9759 wpa_printf(MSG_DEBUG,
9760 "Failed to allocate memory for temp disallow BSS");
9761 return;
9762 }
9763
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009764 os_memcpy(bss->bssid, bssid, ETH_ALEN);
9765 dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009766 wpa_set_driver_tmp_disallow_list(wpa_s);
Hai Shalom74f70d42019-02-11 14:42:39 -08009767
9768finish:
9769 bss->rssi_threshold = rssi_threshold;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009770 eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
9771 wpa_s, bss);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009772}
9773
9774
Hai Shalom74f70d42019-02-11 14:42:39 -08009775int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
9776 struct wpa_bss *bss)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009777{
Hai Shalom74f70d42019-02-11 14:42:39 -08009778 struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009779
9780 dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
9781 struct wpa_bss_tmp_disallowed, list) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009782 if (ether_addr_equal(bss->bssid, tmp->bssid)) {
Hai Shalom74f70d42019-02-11 14:42:39 -08009783 disallowed = tmp;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009784 break;
9785 }
9786 }
Hai Shalom74f70d42019-02-11 14:42:39 -08009787 if (!disallowed)
9788 return 0;
9789
9790 if (disallowed->rssi_threshold != 0 &&
Hai Shalomc1a21442022-02-04 13:43:00 -08009791 bss->level > disallowed->rssi_threshold) {
9792 remove_bss_tmp_disallowed_entry(wpa_s, disallowed);
9793 wpa_set_driver_tmp_disallow_list(wpa_s);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009794 return 0;
Hai Shalomc1a21442022-02-04 13:43:00 -08009795 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009796
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009797 return 1;
9798}
Hai Shalom81f62d82019-07-22 12:10:00 -07009799
9800
9801int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
9802 unsigned int type, const u8 *addr,
9803 const u8 *mask)
9804{
9805 if ((addr && !mask) || (!addr && mask)) {
9806 wpa_printf(MSG_INFO,
9807 "MAC_ADDR_RAND_SCAN invalid addr/mask combination");
9808 return -1;
9809 }
9810
9811 if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
9812 wpa_printf(MSG_INFO,
9813 "MAC_ADDR_RAND_SCAN cannot allow multicast address");
9814 return -1;
9815 }
9816
9817 if (type & MAC_ADDR_RAND_SCAN) {
9818 if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
9819 addr, mask))
9820 return -1;
9821 }
9822
9823 if (type & MAC_ADDR_RAND_SCHED_SCAN) {
9824 if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
9825 addr, mask))
9826 return -1;
9827
9828 if (wpa_s->sched_scanning && !wpa_s->pno)
9829 wpas_scan_restart_sched_scan(wpa_s);
9830 }
9831
9832 if (type & MAC_ADDR_RAND_PNO) {
9833 if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
9834 addr, mask))
9835 return -1;
9836
9837 if (wpa_s->pno) {
9838 wpas_stop_pno(wpa_s);
9839 wpas_start_pno(wpa_s);
9840 }
9841 }
9842
9843 return 0;
9844}
9845
9846
9847int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
9848 unsigned int type)
9849{
9850 wpas_mac_addr_rand_scan_clear(wpa_s, type);
9851 if (wpa_s->pno) {
9852 if (type & MAC_ADDR_RAND_PNO) {
9853 wpas_stop_pno(wpa_s);
9854 wpas_start_pno(wpa_s);
9855 }
9856 } else if (wpa_s->sched_scanning && (type & MAC_ADDR_RAND_SCHED_SCAN)) {
9857 wpas_scan_restart_sched_scan(wpa_s);
9858 }
9859
9860 return 0;
9861}
Hai Shalomfdcde762020-04-02 11:19:20 -07009862
9863
9864int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
9865 struct wpa_signal_info *si)
9866{
9867 int res;
9868
9869 if (!wpa_s->driver->signal_poll)
9870 return -1;
9871
9872 res = wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
9873
9874#ifdef CONFIG_TESTING_OPTIONS
9875 if (res == 0) {
9876 struct driver_signal_override *dso;
9877
9878 dl_list_for_each(dso, &wpa_s->drv_signal_override,
9879 struct driver_signal_override, list) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009880 if (!ether_addr_equal(wpa_s->bssid, dso->bssid))
Hai Shalomfdcde762020-04-02 11:19:20 -07009881 continue;
9882 wpa_printf(MSG_DEBUG,
9883 "Override driver signal_poll information: current_signal: %d->%d avg_signal: %d->%d avg_beacon_signal: %d->%d current_noise: %d->%d",
Sunil Ravi77d572f2023-01-17 23:58:31 +00009884 si->data.signal,
Hai Shalomfdcde762020-04-02 11:19:20 -07009885 dso->si_current_signal,
Sunil Ravi77d572f2023-01-17 23:58:31 +00009886 si->data.avg_signal,
Hai Shalomfdcde762020-04-02 11:19:20 -07009887 dso->si_avg_signal,
Sunil Ravi77d572f2023-01-17 23:58:31 +00009888 si->data.avg_beacon_signal,
Hai Shalomfdcde762020-04-02 11:19:20 -07009889 dso->si_avg_beacon_signal,
9890 si->current_noise,
9891 dso->si_current_noise);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009892 si->data.signal = dso->si_current_signal;
9893 si->data.avg_signal = dso->si_avg_signal;
9894 si->data.avg_beacon_signal = dso->si_avg_beacon_signal;
Hai Shalomfdcde762020-04-02 11:19:20 -07009895 si->current_noise = dso->si_current_noise;
9896 break;
9897 }
9898 }
9899#endif /* CONFIG_TESTING_OPTIONS */
9900
9901 return res;
9902}
9903
9904
9905struct wpa_scan_results *
Sunil Ravi99c035e2024-07-12 01:42:03 +00009906wpa_drv_get_scan_results(struct wpa_supplicant *wpa_s, const u8 *bssid)
Hai Shalomfdcde762020-04-02 11:19:20 -07009907{
9908 struct wpa_scan_results *scan_res;
9909#ifdef CONFIG_TESTING_OPTIONS
9910 size_t idx;
9911#endif /* CONFIG_TESTING_OPTIONS */
9912
Sunil Ravi99c035e2024-07-12 01:42:03 +00009913 if (wpa_s->driver->get_scan_results)
9914 scan_res = wpa_s->driver->get_scan_results(wpa_s->drv_priv,
9915 bssid);
9916 else if (wpa_s->driver->get_scan_results2)
9917 scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
9918 else
Hai Shalomfdcde762020-04-02 11:19:20 -07009919 return NULL;
9920
Hai Shalomfdcde762020-04-02 11:19:20 -07009921
9922#ifdef CONFIG_TESTING_OPTIONS
9923 for (idx = 0; scan_res && idx < scan_res->num; idx++) {
9924 struct driver_signal_override *dso;
9925 struct wpa_scan_res *res = scan_res->res[idx];
9926
9927 dl_list_for_each(dso, &wpa_s->drv_signal_override,
9928 struct driver_signal_override, list) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009929 if (!ether_addr_equal(res->bssid, dso->bssid))
Hai Shalomfdcde762020-04-02 11:19:20 -07009930 continue;
9931 wpa_printf(MSG_DEBUG,
9932 "Override driver scan signal level %d->%d for "
9933 MACSTR,
9934 res->level, dso->scan_level,
9935 MAC2STR(res->bssid));
9936 res->flags |= WPA_SCAN_QUAL_INVALID;
9937 if (dso->scan_level < 0)
9938 res->flags |= WPA_SCAN_LEVEL_DBM;
9939 else
9940 res->flags &= ~WPA_SCAN_LEVEL_DBM;
9941 res->level = dso->scan_level;
9942 break;
9943 }
9944 }
9945#endif /* CONFIG_TESTING_OPTIONS */
9946
9947 return scan_res;
9948}
Sunil Ravi77d572f2023-01-17 23:58:31 +00009949
9950
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009951bool wpas_ap_link_address(struct wpa_supplicant *wpa_s, const u8 *addr)
Sunil Ravi77d572f2023-01-17 23:58:31 +00009952{
9953 int i;
9954
9955 if (!wpa_s->valid_links)
9956 return false;
9957
Sunil Ravi99c035e2024-07-12 01:42:03 +00009958 for_each_link(wpa_s->valid_links, i) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009959 if (ether_addr_equal(wpa_s->links[i].bssid, addr))
Sunil Ravi77d572f2023-01-17 23:58:31 +00009960 return true;
9961 }
9962
9963 return false;
9964}
9965
9966
9967int wpa_drv_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
9968 unsigned int wait, const u8 *dst, const u8 *src,
9969 const u8 *bssid, const u8 *data, size_t data_len,
9970 int no_cck)
9971{
9972 if (!wpa_s->driver->send_action)
9973 return -1;
9974
9975 if (data_len > 0 && data[0] != WLAN_ACTION_PUBLIC) {
9976 if (wpas_ap_link_address(wpa_s, dst))
9977 dst = wpa_s->ap_mld_addr;
9978
9979 if (wpas_ap_link_address(wpa_s, bssid))
9980 bssid = wpa_s->ap_mld_addr;
9981 }
9982
9983 return wpa_s->driver->send_action(wpa_s->drv_priv, freq, wait, dst, src,
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00009984 bssid, data, data_len, no_cck, -1);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009985}
Sunil Ravi2a14cf12023-11-21 00:54:38 +00009986
9987
9988bool wpas_is_6ghz_supported(struct wpa_supplicant *wpa_s, bool only_enabled)
9989{
9990 struct hostapd_channel_data *chnl;
9991 int i, j;
9992
9993 for (i = 0; i < wpa_s->hw.num_modes; i++) {
9994 if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211A) {
9995 chnl = wpa_s->hw.modes[i].channels;
9996 for (j = 0; j < wpa_s->hw.modes[i].num_channels; j++) {
9997 if (only_enabled &&
9998 (chnl[j].flag & HOSTAPD_CHAN_DISABLED))
9999 continue;
10000 if (is_6ghz_freq(chnl[j].freq))
10001 return true;
10002 }
10003 }
10004 }
10005
10006 return false;
10007}
Sunil Ravi7f769292024-07-23 22:21:32 +000010008
10009
10010bool wpas_ap_supports_rsn_overriding(struct wpa_supplicant *wpa_s,
10011 struct wpa_bss *bss)
10012{
10013 int i;
10014
10015 if (!bss)
10016 return false;
10017 if (wpa_bss_get_vendor_ie(bss, RSNE_OVERRIDE_IE_VENDOR_TYPE) ||
10018 wpa_bss_get_vendor_ie(bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE))
10019 return true;
10020
10021 if (!wpa_s->valid_links)
10022 return false;
10023
10024 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
10025 if (!(wpa_s->valid_links & BIT(i)))
10026 continue;
10027 if (wpa_s->links[i].bss &&
10028 (wpa_bss_get_vendor_ie(wpa_s->links[i].bss,
10029 RSNE_OVERRIDE_IE_VENDOR_TYPE) ||
10030 wpa_bss_get_vendor_ie(wpa_s->links[i].bss,
10031 RSNE_OVERRIDE_2_IE_VENDOR_TYPE)))
10032 return true;
10033 }
10034
10035 return false;
10036}
10037
10038
10039bool wpas_ap_supports_rsn_overriding_2(struct wpa_supplicant *wpa_s,
10040 struct wpa_bss *bss)
10041{
10042 int i;
10043
10044 if (!bss)
10045 return false;
10046 if (wpa_bss_get_vendor_ie(bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE))
10047 return true;
10048
10049 if (!wpa_s->valid_links)
10050 return false;
10051
10052 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
10053 if (!(wpa_s->valid_links & BIT(i)))
10054 continue;
10055 if (wpa_s->links[i].bss &&
10056 wpa_bss_get_vendor_ie(wpa_s->links[i].bss,
10057 RSNE_OVERRIDE_2_IE_VENDOR_TYPE))
10058 return true;
10059 }
10060
10061 return false;
10062}
Sunil Ravic0f5d412024-09-11 22:12:49 +000010063
10064
10065int wpas_get_owe_trans_network(const u8 *owe_ie, const u8 **bssid,
10066 const u8 **ssid, size_t *ssid_len)
10067{
10068#ifdef CONFIG_OWE
10069 const u8 *pos, *end;
10070 u8 ssid_len_tmp;
10071
10072 if (!owe_ie)
10073 return -1;
10074
10075 pos = owe_ie + 6;
10076 end = owe_ie + 2 + owe_ie[1];
10077
10078 if (end - pos < ETH_ALEN + 1)
10079 return -1;
10080 *bssid = pos;
10081 pos += ETH_ALEN;
10082 ssid_len_tmp = *pos++;
10083 if (end - pos < ssid_len_tmp || ssid_len_tmp > SSID_MAX_LEN)
10084 return -1;
10085
10086 *ssid = pos;
10087 *ssid_len = ssid_len_tmp;
10088
10089 return 0;
10090#else /* CONFIG_OWE */
10091 return -1;
10092#endif /* CONFIG_OWE */
10093}