blob: 984367939d002c8ed6a90724bfc922f374e2633f [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 Shmidt684785c2014-05-12 13:34:29 -0700802 hs20_deinit(wpa_s);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800803#endif /* CONFIG_HS20 */
Dmitry Shmidt2e67f062014-07-16 09:55:28 -0700804
805 for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
806 wpabuf_free(wpa_s->vendor_elem[i]);
807 wpa_s->vendor_elem[i] = NULL;
808 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800809
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000810#ifndef CONFIG_NO_WMM_AC
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800811 wmm_ac_notify_disassoc(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000812#endif /* CONFIG_NO_WMM_AC */
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800813
814 wpa_s->sched_scan_plans_num = 0;
815 os_free(wpa_s->sched_scan_plans);
816 wpa_s->sched_scan_plans = NULL;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800817
818#ifdef CONFIG_MBO
819 wpa_s->non_pref_chan_num = 0;
820 os_free(wpa_s->non_pref_chan);
821 wpa_s->non_pref_chan = NULL;
822#endif /* CONFIG_MBO */
823
824 free_bss_tmp_disallowed(wpa_s);
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700825
826 wpabuf_free(wpa_s->lci);
827 wpa_s->lci = NULL;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000828#ifndef CONFIG_NO_RRM
Dmitry Shmidt29333592017-01-09 12:27:11 -0800829 wpas_clear_beacon_rep_data(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000830#endif /* CONFIG_NO_RRM */
Paul Stewart092955c2017-02-06 09:13:09 -0800831
832#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
833#ifdef CONFIG_MESH
834 {
835 struct external_pmksa_cache *entry;
836
837 while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
838 struct external_pmksa_cache,
839 list)) != NULL) {
840 dl_list_del(&entry->list);
841 os_free(entry->pmksa_cache);
842 os_free(entry);
843 }
844 }
845#endif /* CONFIG_MESH */
846#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
847
848 wpas_flush_fils_hlp_req(wpa_s);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800849
850 wpabuf_free(wpa_s->ric_ies);
851 wpa_s->ric_ies = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700852
853#ifdef CONFIG_DPP
854 wpas_dpp_deinit(wpa_s);
Hai Shalom021b0b52019-04-10 11:17:58 -0700855 dpp_global_deinit(wpa_s->dpp);
856 wpa_s->dpp = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700857#endif /* CONFIG_DPP */
Hai Shalom60840252021-02-19 19:02:11 -0800858
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000859#ifdef CONFIG_NAN_USD
860 wpas_nan_usd_deinit(wpa_s);
861#endif /* CONFIG_NAN_USD */
862
Hai Shalom60840252021-02-19 19:02:11 -0800863#ifdef CONFIG_PASN
864 wpas_pasn_auth_stop(wpa_s);
865#endif /* CONFIG_PASN */
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000866#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -0800867 wpas_scs_deinit(wpa_s);
868 wpas_dscp_deinit(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000869#endif /* CONFIG_NO_ROBUST_AV */
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000870
871#ifdef CONFIG_OWE
872 os_free(wpa_s->owe_trans_scan_freq);
873 wpa_s->owe_trans_scan_freq = NULL;
874#endif /* CONFIG_OWE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700875}
876
877
878/**
879 * wpa_clear_keys - Clear keys configured for the driver
880 * @wpa_s: Pointer to wpa_supplicant data
881 * @addr: Previously used BSSID or %NULL if not available
882 *
883 * This function clears the encryption keys that has been previously configured
884 * for the driver.
885 */
886void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
887{
Hai Shalomc3565922019-10-28 11:58:20 -0700888 int i, max = 6;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700889
890 /* MLME-DELETEKEYS.request */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800891 for (i = 0; i < max; i++) {
892 if (wpa_s->keys_cleared & BIT(i))
893 continue;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000894 wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -0700895 NULL, 0, KEY_FLAG_GROUP);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800896 }
Hai Shalomfdcde762020-04-02 11:19:20 -0700897 /* Pairwise Key ID 1 for Extended Key ID is tracked in bit 15 */
898 if (~wpa_s->keys_cleared & (BIT(0) | BIT(15)) && addr &&
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800899 !is_zero_ether_addr(addr)) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700900 if (!(wpa_s->keys_cleared & BIT(0)))
Sunil Ravi77d572f2023-01-17 23:58:31 +0000901 wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, addr, 0, 0,
902 NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
Hai Shalomfdcde762020-04-02 11:19:20 -0700903 if (!(wpa_s->keys_cleared & BIT(15)))
Sunil Ravi77d572f2023-01-17 23:58:31 +0000904 wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, addr, 1, 0,
905 NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700906 /* MLME-SETPROTECTION.request(None) */
907 wpa_drv_mlme_setprotection(
908 wpa_s, addr,
909 MLME_SETPROTECTION_PROTECT_TYPE_NONE,
910 MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
911 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800912 wpa_s->keys_cleared = (u32) -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700913}
914
915
916/**
917 * wpa_supplicant_state_txt - Get the connection state name as a text string
918 * @state: State (wpa_state; WPA_*)
919 * Returns: The state name as a printable text string
920 */
921const char * wpa_supplicant_state_txt(enum wpa_states state)
922{
923 switch (state) {
924 case WPA_DISCONNECTED:
925 return "DISCONNECTED";
926 case WPA_INACTIVE:
927 return "INACTIVE";
928 case WPA_INTERFACE_DISABLED:
929 return "INTERFACE_DISABLED";
930 case WPA_SCANNING:
931 return "SCANNING";
932 case WPA_AUTHENTICATING:
933 return "AUTHENTICATING";
934 case WPA_ASSOCIATING:
935 return "ASSOCIATING";
936 case WPA_ASSOCIATED:
937 return "ASSOCIATED";
938 case WPA_4WAY_HANDSHAKE:
939 return "4WAY_HANDSHAKE";
940 case WPA_GROUP_HANDSHAKE:
941 return "GROUP_HANDSHAKE";
942 case WPA_COMPLETED:
943 return "COMPLETED";
944 default:
945 return "UNKNOWN";
946 }
947}
948
949
950#ifdef CONFIG_BGSCAN
951
Hai Shalom899fcc72020-10-19 14:38:18 -0700952static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
953{
954 if (wpa_s->bgscan_ssid) {
955 bgscan_deinit(wpa_s);
956 wpa_s->bgscan_ssid = NULL;
957 }
958}
959
960
961/**
962 * wpa_supplicant_reset_bgscan - Reset the bgscan for the current SSID.
963 * @wpa_s: Pointer to the wpa_supplicant data
964 *
965 * Stop, start, or reconfigure the scan parameters depending on the method.
966 */
967void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700968{
Dmitry Shmidtb96dad42013-11-05 10:07:29 -0800969 const char *name;
970
971 if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan)
972 name = wpa_s->current_ssid->bgscan;
973 else
974 name = wpa_s->conf->bgscan;
Hai Shalom899fcc72020-10-19 14:38:18 -0700975 if (!name || name[0] == '\0') {
976 wpa_supplicant_stop_bgscan(wpa_s);
Dmitry Shmidtb96dad42013-11-05 10:07:29 -0800977 return;
Hai Shalom899fcc72020-10-19 14:38:18 -0700978 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800979 if (wpas_driver_bss_selection(wpa_s))
980 return;
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800981#ifdef CONFIG_P2P
982 if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
983 return;
984#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700985
986 bgscan_deinit(wpa_s);
Dmitry Shmidtb96dad42013-11-05 10:07:29 -0800987 if (wpa_s->current_ssid) {
988 if (bgscan_init(wpa_s, wpa_s->current_ssid, name)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700989 wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
990 "bgscan");
991 /*
992 * Live without bgscan; it is only used as a roaming
993 * optimization, so the initial connection is not
994 * affected.
995 */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700996 } else {
997 struct wpa_scan_results *scan_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700998 wpa_s->bgscan_ssid = wpa_s->current_ssid;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700999 scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL,
Sunil Ravi99c035e2024-07-12 01:42:03 +00001000 0, NULL);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001001 if (scan_res) {
1002 bgscan_notify_scan(wpa_s, scan_res);
1003 wpa_scan_results_free(scan_res);
1004 }
1005 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001006 } else
1007 wpa_s->bgscan_ssid = NULL;
1008}
1009
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001010#endif /* CONFIG_BGSCAN */
1011
1012
Dmitry Shmidt04949592012-07-19 12:16:46 -07001013static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
1014{
1015 if (autoscan_init(wpa_s, 0))
1016 wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan");
1017}
1018
1019
1020static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)
1021{
1022 autoscan_deinit(wpa_s);
1023}
1024
1025
1026void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s)
1027{
1028 if (wpa_s->wpa_state == WPA_DISCONNECTED ||
1029 wpa_s->wpa_state == WPA_SCANNING) {
1030 autoscan_deinit(wpa_s);
1031 wpa_supplicant_start_autoscan(wpa_s);
1032 }
1033}
1034
1035
Sunil Ravi7f769292024-07-23 22:21:32 +00001036static void wpas_verify_ssid_beacon(void *eloop_ctx, void *timeout_ctx)
1037{
1038 struct wpa_supplicant *wpa_s = eloop_ctx;
1039 struct wpa_bss *bss;
1040 const u8 *ssid;
1041 size_t ssid_len;
1042
1043 if (!wpa_s->current_ssid || !wpa_s->current_bss)
1044 return;
1045
1046 ssid = wpa_s->current_bss->ssid;
1047 ssid_len = wpa_s->current_bss->ssid_len;
1048
1049 if (wpa_s->current_ssid->ssid_len &&
1050 (wpa_s->current_ssid->ssid_len != ssid_len ||
1051 os_memcmp(wpa_s->current_ssid->ssid, ssid, ssid_len) != 0))
1052 return;
1053
1054 if (wpa_s->wpa_state < WPA_4WAY_HANDSHAKE ||
1055 !wpa_s->bigtk_set || wpa_s->ssid_verified)
1056 return;
1057
1058 wpa_printf(MSG_DEBUG,
1059 "SSID not yet verified; check if the driver has received a verified Beacon frame");
1060 if (wpa_supplicant_update_scan_results(wpa_s, wpa_s->bssid) < 0)
1061 return;
1062
1063 bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->bssid);
1064 if (!bss)
1065 return;
1066 wpa_printf(MSG_DEBUG, "The current beacon time stamp: 0x%llx",
1067 (long long unsigned int) bss->tsf);
1068 if (bss->tsf > wpa_s->first_beacon_tsf) {
1069 const u8 *ie;
1070
1071 wpa_printf(MSG_DEBUG,
1072 "Verified Beacon frame has been received");
1073 wpa_s->beacons_checked++;
1074
1075 ie = wpa_bss_get_ie_beacon(bss, WLAN_EID_SSID);
1076 if (ie && ie[1] == ssid_len &&
1077 os_memcmp(&ie[2], ssid, ssid_len) == 0) {
1078 wpa_printf(MSG_DEBUG,
1079 "SSID verified based on a Beacon frame and beacon protection");
1080 wpa_s->ssid_verified = true;
1081 return;
1082 }
1083
1084 /* TODO: Multiple BSSID element */
1085 }
1086
1087 if (wpa_s->beacons_checked < 16) {
1088 eloop_register_timeout(wpa_s->next_beacon_check, 0,
1089 wpas_verify_ssid_beacon, wpa_s, NULL);
1090 wpa_s->next_beacon_check++;
1091 }
1092}
1093
1094
1095static void wpas_verify_ssid_beacon_prot(struct wpa_supplicant *wpa_s)
1096{
1097 struct wpa_bss *bss;
1098
1099 wpa_printf(MSG_DEBUG,
1100 "SSID not yet verified; try to verify using beacon protection");
1101 /* Fetch the current scan result which is likely based on not yet
1102 * verified payload since the current BIGTK was just received. Any
1103 * newer update in the future with a larger timestamp value is an
1104 * indication that a verified Beacon frame has been received. */
1105 if (wpa_supplicant_update_scan_results(wpa_s, wpa_s->bssid) < 0)
1106 return;
1107
1108 bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->bssid);
1109 if (!bss)
1110 return;
1111 wpa_printf(MSG_DEBUG, "The initial beacon time stamp: 0x%llx",
1112 (long long unsigned int) bss->tsf);
1113 wpa_s->first_beacon_tsf = bss->tsf;
1114 wpa_s->beacons_checked = 0;
1115 wpa_s->next_beacon_check = 1;
1116 eloop_cancel_timeout(wpas_verify_ssid_beacon, wpa_s, NULL);
1117 eloop_register_timeout(1, 0, wpas_verify_ssid_beacon, wpa_s, NULL);
1118}
1119
1120
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001121/**
1122 * wpa_supplicant_set_state - Set current connection state
1123 * @wpa_s: Pointer to wpa_supplicant data
1124 * @state: The new connection state
1125 *
1126 * This function is called whenever the connection state changes, e.g.,
1127 * association is completed for WPA/WPA2 4-Way Handshake is started.
1128 */
1129void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
1130 enum wpa_states state)
1131{
1132 enum wpa_states old_state = wpa_s->wpa_state;
Hai Shalomc3565922019-10-28 11:58:20 -07001133#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
Hai Shalome21d4e82020-04-29 16:34:06 -07001134 bool update_fils_connect_params = false;
Hai Shalomc3565922019-10-28 11:58:20 -07001135#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001136
1137 wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
1138 wpa_supplicant_state_txt(wpa_s->wpa_state),
1139 wpa_supplicant_state_txt(state));
1140
Hai Shalom74f70d42019-02-11 14:42:39 -08001141 if (state == WPA_COMPLETED &&
1142 os_reltime_initialized(&wpa_s->roam_start)) {
1143 os_reltime_age(&wpa_s->roam_start, &wpa_s->roam_time);
1144 wpa_s->roam_start.sec = 0;
1145 wpa_s->roam_start.usec = 0;
1146 wpas_notify_auth_changed(wpa_s);
1147 wpas_notify_roam_time(wpa_s);
1148 wpas_notify_roam_complete(wpa_s);
1149 } else if (state == WPA_DISCONNECTED &&
1150 os_reltime_initialized(&wpa_s->roam_start)) {
1151 wpa_s->roam_start.sec = 0;
1152 wpa_s->roam_start.usec = 0;
1153 wpa_s->roam_time.sec = 0;
1154 wpa_s->roam_time.usec = 0;
1155 wpas_notify_roam_complete(wpa_s);
1156 }
1157
Dmitry Shmidt9e3f8ee2014-01-17 10:52:01 -08001158 if (state == WPA_INTERFACE_DISABLED) {
1159 /* Assure normal scan when interface is restored */
1160 wpa_s->normal_scans = 0;
1161 }
1162
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07001163 if (state == WPA_COMPLETED) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001164 wpas_connect_work_done(wpa_s);
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07001165 /* Reinitialize normal_scan counter */
1166 wpa_s->normal_scans = 0;
1167 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001168
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07001169#ifdef CONFIG_P2P
1170 /*
1171 * P2PS client has to reply to Probe Request frames received on the
1172 * group operating channel. Enable Probe Request frame reporting for
1173 * P2P connected client in case p2p_cli_probe configuration property is
1174 * set to 1.
1175 */
1176 if (wpa_s->conf->p2p_cli_probe && wpa_s->current_ssid &&
1177 wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
1178 wpa_s->current_ssid->p2p_group) {
1179 if (state == WPA_COMPLETED && !wpa_s->p2p_cli_probe) {
1180 wpa_dbg(wpa_s, MSG_DEBUG,
1181 "P2P: Enable CLI Probe Request RX reporting");
1182 wpa_s->p2p_cli_probe =
1183 wpa_drv_probe_req_report(wpa_s, 1) >= 0;
1184 } else if (state != WPA_COMPLETED && wpa_s->p2p_cli_probe) {
1185 wpa_dbg(wpa_s, MSG_DEBUG,
1186 "P2P: Disable CLI Probe Request RX reporting");
1187 wpa_s->p2p_cli_probe = 0;
1188 wpa_drv_probe_req_report(wpa_s, 0);
1189 }
1190 }
1191#endif /* CONFIG_P2P */
1192
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001193 if (state != WPA_SCANNING)
1194 wpa_supplicant_notify_scanning(wpa_s, 0);
1195
1196 if (state == WPA_COMPLETED && wpa_s->new_connection) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001197 struct wpa_ssid *ssid = wpa_s->current_ssid;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001198 int fils_hlp_sent = 0;
Sunil Ravi89eba102022-09-13 21:04:37 -07001199 char mld_addr[50];
1200
1201 mld_addr[0] = '\0';
1202 if (wpa_s->valid_links)
1203 os_snprintf(mld_addr, sizeof(mld_addr),
1204 " ap_mld_addr=" MACSTR,
1205 MAC2STR(wpa_s->ap_mld_addr));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001206
1207#ifdef CONFIG_SME
1208 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
1209 wpa_auth_alg_fils(wpa_s->sme.auth_alg))
1210 fils_hlp_sent = 1;
1211#endif /* CONFIG_SME */
1212 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
1213 wpa_auth_alg_fils(wpa_s->auth_alg))
1214 fils_hlp_sent = 1;
1215
Dmitry Shmidt700a1372013-03-15 14:14:44 -07001216#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001217 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
Sunil Ravi89eba102022-09-13 21:04:37 -07001218 MACSTR " completed [id=%d id_str=%s%s]%s",
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001219 MAC2STR(wpa_s->bssid),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001220 ssid ? ssid->id : -1,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001221 ssid && ssid->id_str ? ssid->id_str : "",
Sunil Ravi89eba102022-09-13 21:04:37 -07001222 fils_hlp_sent ? " FILS_HLP_SENT" : "", mld_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001223#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001224 wpas_clear_temp_disabled(wpa_s, ssid, 1);
Hai Shalom899fcc72020-10-19 14:38:18 -07001225 wpa_s->consecutive_conn_failures = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001226 wpa_s->new_connection = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001227 wpa_drv_set_operstate(wpa_s, 1);
1228#ifndef IEEE8021X_EAPOL
1229 wpa_drv_set_supp_port(wpa_s, 1);
1230#endif /* IEEE8021X_EAPOL */
1231 wpa_s->after_wps = 0;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001232 wpa_s->known_wps_freq = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001233 wpas_p2p_completed(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001234
1235 sme_sched_obss_scan(wpa_s, 1);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001236
1237#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
1238 if (!fils_hlp_sent && ssid && ssid->eap.erp)
Hai Shalome21d4e82020-04-29 16:34:06 -07001239 update_fils_connect_params = true;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001240#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
Hai Shalomc3565922019-10-28 11:58:20 -07001241#ifdef CONFIG_OWE
1242 if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE))
1243 wpas_update_owe_connect_params(wpa_s);
1244#endif /* CONFIG_OWE */
Hai Shalom2cbbcd12021-03-08 18:33:38 -08001245#ifdef CONFIG_HS20
1246 hs20_configure_frame_filters(wpa_s);
1247#endif
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001248 if (wpa_s->conf->wfa_gen_capa == WFA_GEN_CAPA_PROTECTED &&
1249 pmf_in_use(wpa_s, wpa_s->bssid)) {
1250 eloop_cancel_timeout(wpas_wfa_capab_tx, wpa_s, NULL);
1251 eloop_register_timeout(0, 100000, wpas_wfa_capab_tx,
1252 wpa_s, NULL);
1253 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001254 } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
1255 state == WPA_ASSOCIATED) {
1256 wpa_s->new_connection = 1;
1257 wpa_drv_set_operstate(wpa_s, 0);
1258#ifndef IEEE8021X_EAPOL
1259 wpa_drv_set_supp_port(wpa_s, 0);
1260#endif /* IEEE8021X_EAPOL */
Dmitry Shmidt04949592012-07-19 12:16:46 -07001261 sme_sched_obss_scan(wpa_s, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001262 }
1263 wpa_s->wpa_state = state;
1264
1265#ifdef CONFIG_BGSCAN
Hai Shalom899fcc72020-10-19 14:38:18 -07001266 if (state == WPA_COMPLETED && wpa_s->current_ssid != wpa_s->bgscan_ssid)
1267 wpa_supplicant_reset_bgscan(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001268 else if (state < WPA_ASSOCIATED)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001269 wpa_supplicant_stop_bgscan(wpa_s);
1270#endif /* CONFIG_BGSCAN */
1271
Hai Shalom5f92bc92019-04-18 11:54:11 -07001272 if (state > WPA_SCANNING)
Dmitry Shmidt04949592012-07-19 12:16:46 -07001273 wpa_supplicant_stop_autoscan(wpa_s);
1274
1275 if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
1276 wpa_supplicant_start_autoscan(wpa_s);
1277
Sunil Ravi99c035e2024-07-12 01:42:03 +00001278 if (state == WPA_COMPLETED || state == WPA_INTERFACE_DISABLED ||
1279 state == WPA_INACTIVE)
1280 wnm_btm_reset(wpa_s);
1281
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001282#ifndef CONFIG_NO_WMM_AC
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001283 if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED)
1284 wmm_ac_notify_disassoc(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001285#endif /* CONFIG_NO_WMM_AC */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001286
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001287 if (wpa_s->wpa_state != old_state) {
1288 wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
1289
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07001290 /*
1291 * Notify the P2P Device interface about a state change in one
1292 * of the interfaces.
1293 */
1294 wpas_p2p_indicate_state_change(wpa_s);
1295
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001296 if (wpa_s->wpa_state == WPA_COMPLETED ||
1297 old_state == WPA_COMPLETED)
1298 wpas_notify_auth_changed(wpa_s);
Hai Shalomc3565922019-10-28 11:58:20 -07001299#ifdef CONFIG_DPP2
1300 if (wpa_s->wpa_state == WPA_COMPLETED)
1301 wpas_dpp_connected(wpa_s);
1302#endif /* CONFIG_DPP2 */
Sunil Ravi7f769292024-07-23 22:21:32 +00001303
1304 if (wpa_s->wpa_state == WPA_COMPLETED &&
1305 wpa_s->bigtk_set && !wpa_s->ssid_verified)
1306 wpas_verify_ssid_beacon_prot(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001307 }
Hai Shalomc3565922019-10-28 11:58:20 -07001308#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
1309 if (update_fils_connect_params)
1310 wpas_update_fils_connect_params(wpa_s);
1311#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001312}
1313
1314
1315void wpa_supplicant_terminate_proc(struct wpa_global *global)
1316{
1317 int pending = 0;
1318#ifdef CONFIG_WPS
1319 struct wpa_supplicant *wpa_s = global->ifaces;
1320 while (wpa_s) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001321 struct wpa_supplicant *next = wpa_s->next;
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07001322 if (wpas_wps_terminate_pending(wpa_s) == 1)
1323 pending = 1;
Dmitry Shmidt56052862013-10-04 10:23:25 -07001324#ifdef CONFIG_P2P
1325 if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE ||
1326 (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group))
1327 wpas_p2p_disconnect(wpa_s);
1328#endif /* CONFIG_P2P */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001329 wpa_s = next;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001330 }
1331#endif /* CONFIG_WPS */
1332 if (pending)
1333 return;
1334 eloop_terminate();
1335}
1336
1337
1338static void wpa_supplicant_terminate(int sig, void *signal_ctx)
1339{
1340 struct wpa_global *global = signal_ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001341 wpa_supplicant_terminate_proc(global);
1342}
1343
1344
1345void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
1346{
1347 enum wpa_states old_state = wpa_s->wpa_state;
Hai Shalom60840252021-02-19 19:02:11 -08001348 enum wpa_states new_state;
1349
1350 if (old_state == WPA_SCANNING)
1351 new_state = WPA_SCANNING;
1352 else
1353 new_state = WPA_DISCONNECTED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001354
1355 wpa_s->pairwise_cipher = 0;
1356 wpa_s->group_cipher = 0;
1357 wpa_s->mgmt_group_cipher = 0;
1358 wpa_s->key_mgmt = 0;
Sunil Ravi89eba102022-09-13 21:04:37 -07001359 wpa_s->allowed_key_mgmts = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001360 if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
Hai Shalom60840252021-02-19 19:02:11 -08001361 wpa_supplicant_set_state(wpa_s, new_state);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001362
1363 if (wpa_s->wpa_state != old_state)
1364 wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
1365}
1366
1367
1368/**
1369 * wpa_supplicant_reload_configuration - Reload configuration data
1370 * @wpa_s: Pointer to wpa_supplicant data
1371 * Returns: 0 on success or -1 if configuration parsing failed
1372 *
1373 * This function can be used to request that the configuration data is reloaded
1374 * (e.g., after configuration file change). This function is reloading
1375 * configuration only for one interface, so this may need to be called multiple
1376 * times if %wpa_supplicant is controlling multiple interfaces and all
1377 * interfaces need reconfiguration.
1378 */
1379int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
1380{
1381 struct wpa_config *conf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001382 int reconf_ctrl;
1383 int old_ap_scan;
1384
1385 if (wpa_s->confname == NULL)
1386 return -1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001387 conf = wpa_config_read(wpa_s->confname, NULL, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001388 if (conf == NULL) {
1389 wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
1390 "file '%s' - exiting", wpa_s->confname);
1391 return -1;
1392 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001393 if (wpa_s->confanother &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00001394 !wpa_config_read(wpa_s->confanother, conf, true)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001395 wpa_msg(wpa_s, MSG_ERROR,
1396 "Failed to parse the configuration file '%s' - exiting",
1397 wpa_s->confanother);
1398 return -1;
1399 }
Dmitry Shmidt64f47c52013-04-16 10:41:54 -07001400
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001401 conf->changed_parameters = (unsigned int) -1;
1402
1403 reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
1404 || (conf->ctrl_interface && wpa_s->conf->ctrl_interface &&
1405 os_strcmp(conf->ctrl_interface,
1406 wpa_s->conf->ctrl_interface) != 0);
1407
Jouni Malinenf3f8d3c2021-02-05 00:28:17 +02001408 if (reconf_ctrl) {
1409 wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001410 wpa_s->ctrl_iface = NULL;
1411 }
1412
1413 eapol_sm_invalidate_cached_session(wpa_s->eapol);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001414 if (wpa_s->current_ssid) {
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07001415 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
1416 wpa_s->own_disconnect_req = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001417 wpa_supplicant_deauthenticate(wpa_s,
1418 WLAN_REASON_DEAUTH_LEAVING);
1419 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001420
1421 /*
1422 * TODO: should notify EAPOL SM about changes in opensc_engine_path,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001423 * pkcs11_engine_path, pkcs11_module_path, openssl_ciphers.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001424 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001425 if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
1426 wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
1427 wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001428 /*
1429 * Clear forced success to clear EAP state for next
1430 * authentication.
1431 */
Hai Shalome21d4e82020-04-29 16:34:06 -07001432 eapol_sm_notify_eap_success(wpa_s->eapol, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001433 }
1434 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
1435 wpa_sm_set_config(wpa_s->wpa, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001436 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001437 wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
1438 rsn_preauth_deinit(wpa_s->wpa);
1439
1440 old_ap_scan = wpa_s->conf->ap_scan;
1441 wpa_config_free(wpa_s->conf);
1442 wpa_s->conf = conf;
1443 if (old_ap_scan != wpa_s->conf->ap_scan)
1444 wpas_notify_ap_scan_changed(wpa_s);
1445
1446 if (reconf_ctrl)
1447 wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
1448
1449 wpa_supplicant_update_config(wpa_s);
1450
1451 wpa_supplicant_clear_status(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001452 if (wpa_supplicant_enabled_networks(wpa_s)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001453 wpa_s->reassociate = 1;
1454 wpa_supplicant_req_scan(wpa_s, 0, 0);
1455 }
Hai Shalom60840252021-02-19 19:02:11 -08001456 wpa_bssid_ignore_clear(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001457 wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
1458 return 0;
1459}
1460
1461
1462static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
1463{
1464 struct wpa_global *global = signal_ctx;
1465 struct wpa_supplicant *wpa_s;
1466 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
1467 wpa_dbg(wpa_s, MSG_DEBUG, "Signal %d received - reconfiguring",
1468 sig);
1469 if (wpa_supplicant_reload_configuration(wpa_s) < 0) {
1470 wpa_supplicant_terminate_proc(global);
1471 }
1472 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001473
1474 if (wpa_debug_reopen_file() < 0) {
1475 /* Ignore errors since we cannot really do much to fix this */
1476 wpa_printf(MSG_DEBUG, "Could not reopen debug log file");
1477 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001478}
1479
1480
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001481static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
1482 struct wpa_ssid *ssid,
1483 struct wpa_ie_data *ie)
1484{
1485 int ret = wpa_sm_parse_own_wpa_ie(wpa_s->wpa, ie);
1486 if (ret) {
1487 if (ret == -2) {
1488 wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE "
1489 "from association info");
1490 }
1491 return -1;
1492 }
1493
1494 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set "
1495 "cipher suites");
1496 if (!(ie->group_cipher & ssid->group_cipher)) {
1497 wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group "
1498 "cipher 0x%x (mask 0x%x) - reject",
1499 ie->group_cipher, ssid->group_cipher);
1500 return -1;
1501 }
1502 if (!(ie->pairwise_cipher & ssid->pairwise_cipher)) {
1503 wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled pairwise "
1504 "cipher 0x%x (mask 0x%x) - reject",
1505 ie->pairwise_cipher, ssid->pairwise_cipher);
1506 return -1;
1507 }
1508 if (!(ie->key_mgmt & ssid->key_mgmt)) {
1509 wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled key "
1510 "management 0x%x (mask 0x%x) - reject",
1511 ie->key_mgmt, ssid->key_mgmt);
1512 return -1;
1513 }
1514
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001515 if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001516 wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001517 wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
1518 "that does not support management frame protection - "
1519 "reject");
1520 return -1;
1521 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001522
1523 return 0;
1524}
1525
1526
Hai Shalom021b0b52019-04-10 11:17:58 -07001527static int matching_ciphers(struct wpa_ssid *ssid, struct wpa_ie_data *ie,
1528 int freq)
1529{
1530 if (!ie->has_group)
1531 ie->group_cipher = wpa_default_rsn_cipher(freq);
1532 if (!ie->has_pairwise)
1533 ie->pairwise_cipher = wpa_default_rsn_cipher(freq);
1534 return (ie->group_cipher & ssid->group_cipher) &&
1535 (ie->pairwise_cipher & ssid->pairwise_cipher);
1536}
1537
1538
Hai Shalomc1a21442022-02-04 13:43:00 -08001539void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s,
1540 struct wpa_ssid *ssid, struct wpa_ie_data *ie)
1541{
1542 int sel;
1543
1544 sel = ie->mgmt_group_cipher;
1545 if (ssid->group_mgmt_cipher)
1546 sel &= ssid->group_mgmt_cipher;
1547 if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
1548 !(ie->capabilities & WPA_CAPABILITY_MFPC))
1549 sel = 0;
1550 wpa_dbg(wpa_s, MSG_DEBUG,
1551 "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x",
1552 ie->mgmt_group_cipher, ssid->group_mgmt_cipher, sel);
1553 if (sel & WPA_CIPHER_AES_128_CMAC) {
1554 wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
1555 wpa_dbg(wpa_s, MSG_DEBUG,
1556 "WPA: using MGMT group cipher AES-128-CMAC");
1557 } else if (sel & WPA_CIPHER_BIP_GMAC_128) {
1558 wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128;
1559 wpa_dbg(wpa_s, MSG_DEBUG,
1560 "WPA: using MGMT group cipher BIP-GMAC-128");
1561 } else if (sel & WPA_CIPHER_BIP_GMAC_256) {
1562 wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256;
1563 wpa_dbg(wpa_s, MSG_DEBUG,
1564 "WPA: using MGMT group cipher BIP-GMAC-256");
1565 } else if (sel & WPA_CIPHER_BIP_CMAC_256) {
1566 wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256;
1567 wpa_dbg(wpa_s, MSG_DEBUG,
1568 "WPA: using MGMT group cipher BIP-CMAC-256");
1569 } else {
1570 wpa_s->mgmt_group_cipher = 0;
1571 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
1572 }
1573 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
1574 wpa_s->mgmt_group_cipher);
1575 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
1576 wpas_get_ssid_pmf(wpa_s, ssid));
1577}
1578
Sunil Ravi77d572f2023-01-17 23:58:31 +00001579/**
1580 * wpa_supplicant_get_psk - Get PSK from config or external database
1581 * @wpa_s: Pointer to wpa_supplicant data
1582 * @bss: Scan results for the selected BSS, or %NULL if not available
1583 * @ssid: Configuration data for the selected network
1584 * @psk: Buffer for the PSK
1585 * Returns: 0 on success or -1 if configuration parsing failed
1586 *
1587 * This function obtains the PSK for a network, either included inline in the
1588 * config or retrieved from an external database.
1589 */
1590static int wpa_supplicant_get_psk(struct wpa_supplicant *wpa_s,
1591 struct wpa_bss *bss, struct wpa_ssid *ssid,
1592 u8 *psk)
1593{
1594 if (ssid->psk_set) {
1595 wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)",
1596 ssid->psk, PMK_LEN);
1597 os_memcpy(psk, ssid->psk, PMK_LEN);
1598 return 0;
1599 }
1600
1601#ifndef CONFIG_NO_PBKDF2
1602 if (bss && ssid->bssid_set && ssid->ssid_len == 0 && ssid->passphrase) {
1603 if (pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
1604 4096, psk, PMK_LEN) != 0) {
1605 wpa_msg(wpa_s, MSG_WARNING, "Error in pbkdf2_sha1()");
1606 return -1;
1607 }
1608 wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
1609 psk, PMK_LEN);
1610 return 0;
1611 }
1612#endif /* CONFIG_NO_PBKDF2 */
1613
1614#ifdef CONFIG_EXT_PASSWORD
1615 if (ssid->ext_psk) {
1616 struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
1617 ssid->ext_psk);
1618 char pw_str[64 + 1];
1619
1620 if (!pw) {
1621 wpa_msg(wpa_s, MSG_INFO,
1622 "EXT PW: No PSK found from external storage");
1623 return -1;
1624 }
1625
1626 if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
1627 wpa_msg(wpa_s, MSG_INFO,
1628 "EXT PW: Unexpected PSK length %d in external storage",
1629 (int) wpabuf_len(pw));
1630 ext_password_free(pw);
1631 return -1;
1632 }
1633
1634 os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
1635 pw_str[wpabuf_len(pw)] = '\0';
1636
1637#ifndef CONFIG_NO_PBKDF2
1638 if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
1639 {
1640 if (pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
1641 4096, psk, PMK_LEN) != 0) {
1642 wpa_msg(wpa_s, MSG_WARNING,
1643 "Error in pbkdf2_sha1()");
1644 forced_memzero(pw_str, sizeof(pw_str));
1645 ext_password_free(pw);
1646 return -1;
1647 }
1648 wpa_hexdump_key(MSG_MSGDUMP,
1649 "PSK (from external passphrase)",
1650 psk, PMK_LEN);
1651 } else
1652#endif /* CONFIG_NO_PBKDF2 */
1653 if (wpabuf_len(pw) == 2 * PMK_LEN) {
1654 if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
1655 wpa_msg(wpa_s, MSG_INFO,
1656 "EXT PW: Invalid PSK hex string");
1657 forced_memzero(pw_str, sizeof(pw_str));
1658 ext_password_free(pw);
1659 return -1;
1660 }
1661 wpa_hexdump_key(MSG_MSGDUMP, "PSK (from external PSK)",
1662 psk, PMK_LEN);
1663 } else {
1664 wpa_msg(wpa_s, MSG_INFO,
1665 "EXT PW: No suitable PSK available");
1666 forced_memzero(pw_str, sizeof(pw_str));
1667 ext_password_free(pw);
1668 return -1;
1669 }
1670
1671 forced_memzero(pw_str, sizeof(pw_str));
1672 ext_password_free(pw);
1673
1674 return 0;
1675 }
1676#endif /* CONFIG_EXT_PASSWORD */
1677
1678 return -1;
1679}
1680
Hai Shalomc1a21442022-02-04 13:43:00 -08001681
Sunil Ravi89eba102022-09-13 21:04:37 -07001682static void wpas_update_allowed_key_mgmt(struct wpa_supplicant *wpa_s,
1683 struct wpa_ssid *ssid)
1684{
1685 int akm_count = wpa_s->max_num_akms;
1686 u8 capab = 0;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001687#ifdef CONFIG_SAE
1688 enum sae_pwe sae_pwe;
1689#endif /* CONFIG_SAE */
Sunil Ravi89eba102022-09-13 21:04:37 -07001690
1691 if (akm_count < 2)
1692 return;
1693
1694 akm_count--;
1695 wpa_s->allowed_key_mgmts = 0;
1696 switch (wpa_s->key_mgmt) {
1697 case WPA_KEY_MGMT_PSK:
1698 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
1699 akm_count--;
1700 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
1701 }
1702 if (!akm_count)
1703 break;
1704 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
1705 akm_count--;
1706 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
1707 }
1708 if (!akm_count)
1709 break;
1710 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
1711 wpa_s->allowed_key_mgmts |=
1712 WPA_KEY_MGMT_PSK_SHA256;
1713 break;
1714 case WPA_KEY_MGMT_PSK_SHA256:
1715 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
1716 akm_count--;
1717 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
1718 }
1719 if (!akm_count)
1720 break;
1721 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
1722 akm_count--;
1723 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
1724 }
1725 if (!akm_count)
1726 break;
1727 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
1728 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
1729 break;
1730 case WPA_KEY_MGMT_SAE:
1731 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
1732 akm_count--;
1733 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
1734 }
1735 if (!akm_count)
1736 break;
1737 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
1738 akm_count--;
1739 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
1740 }
1741 if (!akm_count)
1742 break;
1743 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
1744 wpa_s->allowed_key_mgmts |=
1745 WPA_KEY_MGMT_PSK_SHA256;
1746 break;
1747 case WPA_KEY_MGMT_SAE_EXT_KEY:
1748 if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
1749 akm_count--;
1750 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
1751 }
1752 if (!akm_count)
1753 break;
1754 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
1755 akm_count--;
1756 wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
1757 }
1758 if (!akm_count)
1759 break;
1760 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
1761 wpa_s->allowed_key_mgmts |=
1762 WPA_KEY_MGMT_PSK_SHA256;
1763 break;
1764 default:
1765 return;
1766 }
1767
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001768#ifdef CONFIG_SAE
1769 sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
1770 if (sae_pwe != SAE_PWE_HUNT_AND_PECK &&
1771 sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
Sunil Ravi89eba102022-09-13 21:04:37 -07001772 capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
1773#ifdef CONFIG_SAE_PK
1774 if (ssid->sae_pk)
1775 capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
1776#endif /* CONFIG_SAE_PK */
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001777#endif /* CONFIG_SAE */
Sunil Ravi89eba102022-09-13 21:04:37 -07001778
1779 if (!((wpa_s->allowed_key_mgmts &
1780 (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY)) && capab))
1781 return;
1782
1783 if (!wpa_s->rsnxe_len) {
1784 wpa_s->rsnxe_len = 3;
1785 wpa_s->rsnxe[0] = WLAN_EID_RSNX;
1786 wpa_s->rsnxe[1] = 1;
1787 wpa_s->rsnxe[2] = 0;
1788 }
1789
1790 wpa_s->rsnxe[2] |= capab;
1791}
1792
1793
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001794/**
1795 * wpa_supplicant_set_suites - Set authentication and encryption parameters
1796 * @wpa_s: Pointer to wpa_supplicant data
1797 * @bss: Scan results for the selected BSS, or %NULL if not available
1798 * @ssid: Configuration data for the selected network
1799 * @wpa_ie: Buffer for the WPA/RSN IE
1800 * @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the
1801 * used buffer length in case the functions returns success.
Sunil Ravi77d572f2023-01-17 23:58:31 +00001802 * @skip_default_rsne: Whether to skip setting of the default RSNE/RSNXE
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001803 * Returns: 0 on success or -1 on failure
1804 *
1805 * This function is used to configure authentication and encryption parameters
1806 * based on the network configuration and scan result for the selected BSS (if
1807 * available).
1808 */
1809int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
1810 struct wpa_bss *bss, struct wpa_ssid *ssid,
Sunil Ravi77d572f2023-01-17 23:58:31 +00001811 u8 *wpa_ie, size_t *wpa_ie_len,
1812 bool skip_default_rsne)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001813{
1814 struct wpa_ie_data ie;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001815 int sel, proto;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001816#ifdef CONFIG_SAE
Sunil Ravi77d572f2023-01-17 23:58:31 +00001817 enum sae_pwe sae_pwe;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001818#endif /* CONFIG_SAE */
Hai Shalomc3565922019-10-28 11:58:20 -07001819 const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
Sunil Ravi640215c2023-06-28 23:08:09 +00001820 bool wmm;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001821
1822 if (bss) {
1823 bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
Sunil Ravi7f769292024-07-23 22:21:32 +00001824 bss_rsn = wpa_bss_get_rsne(wpa_s, bss, ssid, false);
1825 bss_rsnx = wpa_bss_get_rsnxe(wpa_s, bss, ssid, false);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001826 bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
Hai Shalomc3565922019-10-28 11:58:20 -07001827 } else {
1828 bss_wpa = bss_rsn = bss_rsnx = bss_osen = NULL;
1829 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001830
1831 if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
1832 wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
Hai Shalom021b0b52019-04-10 11:17:58 -07001833 matching_ciphers(ssid, &ie, bss->freq) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001834 (ie.key_mgmt & ssid->key_mgmt)) {
1835 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
1836 proto = WPA_PROTO_RSN;
1837 } else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001838 wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie) == 0 &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001839 (ie.group_cipher & ssid->group_cipher) &&
1840 (ie.pairwise_cipher & ssid->pairwise_cipher) &&
1841 (ie.key_mgmt & ssid->key_mgmt)) {
1842 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
1843 proto = WPA_PROTO_WPA;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001844#ifdef CONFIG_HS20
Hai Shalom74f70d42019-02-11 14:42:39 -08001845 } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN) &&
1846 wpa_parse_wpa_ie(bss_osen, 2 + bss_osen[1], &ie) == 0 &&
1847 (ie.group_cipher & ssid->group_cipher) &&
1848 (ie.pairwise_cipher & ssid->pairwise_cipher) &&
1849 (ie.key_mgmt & ssid->key_mgmt)) {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001850 wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using OSEN");
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001851 proto = WPA_PROTO_OSEN;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001852 } else if (bss_rsn && (ssid->proto & WPA_PROTO_OSEN) &&
1853 wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
1854 (ie.group_cipher & ssid->group_cipher) &&
1855 (ie.pairwise_cipher & ssid->pairwise_cipher) &&
1856 (ie.key_mgmt & ssid->key_mgmt)) {
1857 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using OSEN (within RSN)");
1858 proto = WPA_PROTO_RSN;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001859#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001860 } else if (bss) {
1861 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001862 wpa_dbg(wpa_s, MSG_DEBUG,
1863 "WPA: ssid proto=0x%x pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
1864 ssid->proto, ssid->pairwise_cipher, ssid->group_cipher,
1865 ssid->key_mgmt);
1866 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: BSS " MACSTR " ssid='%s'%s%s%s",
1867 MAC2STR(bss->bssid),
1868 wpa_ssid_txt(bss->ssid, bss->ssid_len),
1869 bss_wpa ? " WPA" : "",
1870 bss_rsn ? " RSN" : "",
1871 bss_osen ? " OSEN" : "");
1872 if (bss_rsn) {
1873 wpa_hexdump(MSG_DEBUG, "RSN", bss_rsn, 2 + bss_rsn[1]);
1874 if (wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie)) {
1875 wpa_dbg(wpa_s, MSG_DEBUG,
1876 "Could not parse RSN element");
1877 } else {
1878 wpa_dbg(wpa_s, MSG_DEBUG,
1879 "RSN: 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 }
1884 if (bss_wpa) {
1885 wpa_hexdump(MSG_DEBUG, "WPA", bss_wpa, 2 + bss_wpa[1]);
1886 if (wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie)) {
1887 wpa_dbg(wpa_s, MSG_DEBUG,
1888 "Could not parse WPA element");
1889 } else {
1890 wpa_dbg(wpa_s, MSG_DEBUG,
1891 "WPA: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
1892 ie.pairwise_cipher, ie.group_cipher,
1893 ie.key_mgmt);
1894 }
1895 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001896 return -1;
1897 } else {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001898 if (ssid->proto & WPA_PROTO_OSEN)
1899 proto = WPA_PROTO_OSEN;
1900 else if (ssid->proto & WPA_PROTO_RSN)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001901 proto = WPA_PROTO_RSN;
1902 else
1903 proto = WPA_PROTO_WPA;
1904 if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) {
1905 os_memset(&ie, 0, sizeof(ie));
1906 ie.group_cipher = ssid->group_cipher;
1907 ie.pairwise_cipher = ssid->pairwise_cipher;
1908 ie.key_mgmt = ssid->key_mgmt;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001909 ie.mgmt_group_cipher = 0;
1910 if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
1911 if (ssid->group_mgmt_cipher &
1912 WPA_CIPHER_BIP_GMAC_256)
1913 ie.mgmt_group_cipher =
1914 WPA_CIPHER_BIP_GMAC_256;
1915 else if (ssid->group_mgmt_cipher &
1916 WPA_CIPHER_BIP_CMAC_256)
1917 ie.mgmt_group_cipher =
1918 WPA_CIPHER_BIP_CMAC_256;
1919 else if (ssid->group_mgmt_cipher &
1920 WPA_CIPHER_BIP_GMAC_128)
1921 ie.mgmt_group_cipher =
1922 WPA_CIPHER_BIP_GMAC_128;
1923 else
1924 ie.mgmt_group_cipher =
1925 WPA_CIPHER_AES_128_CMAC;
1926 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001927#ifdef CONFIG_OWE
1928 if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
1929 !ssid->owe_only &&
1930 !bss_wpa && !bss_rsn && !bss_osen) {
1931 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
1932 wpa_s->wpa_proto = 0;
1933 *wpa_ie_len = 0;
1934 return 0;
1935 }
1936#endif /* CONFIG_OWE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001937 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
1938 "based on configuration");
1939 } else
1940 proto = ie.proto;
1941 }
1942
1943 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
1944 "pairwise %d key_mgmt %d proto %d",
1945 ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001946 if (ssid->ieee80211w) {
1947 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
1948 ie.mgmt_group_cipher);
1949 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001950
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001951 wpa_s->wpa_proto = proto;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001952 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
1953 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001954 !!(ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001955
1956 if (bss || !wpa_s->ap_ies_from_associnfo) {
Sunil Ravic0f5d412024-09-11 22:12:49 +00001957 const u8 *rsnoe = NULL, *rsno2e = NULL, *rsnxoe = NULL;
1958
1959 if (bss) {
1960 bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
1961 bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
1962 rsnoe = wpa_bss_get_vendor_ie(
1963 bss, RSNE_OVERRIDE_IE_VENDOR_TYPE);
1964 rsno2e = wpa_bss_get_vendor_ie(
1965 bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
1966 rsnxoe = wpa_bss_get_vendor_ie(
1967 bss, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
1968 }
1969
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001970 if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
1971 bss_wpa ? 2 + bss_wpa[1] : 0) ||
1972 wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
Hai Shalomc3565922019-10-28 11:58:20 -07001973 bss_rsn ? 2 + bss_rsn[1] : 0) ||
1974 wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001975 bss_rsnx ? 2 + bss_rsnx[1] : 0) ||
1976 wpa_sm_set_ap_rsne_override(wpa_s->wpa, rsnoe,
1977 rsnoe ? 2 + rsnoe[1] : 0) ||
1978 wpa_sm_set_ap_rsne_override_2(wpa_s->wpa, rsno2e,
1979 rsno2e ? 2 + rsno2e[1] : 0) ||
1980 wpa_sm_set_ap_rsnxe_override(wpa_s->wpa, rsnxoe,
1981 rsnxoe ? 2 + rsnxoe[1] : 0))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001982 return -1;
1983 }
1984
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001985#ifdef CONFIG_NO_WPA
1986 wpa_s->group_cipher = WPA_CIPHER_NONE;
1987 wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
1988#else /* CONFIG_NO_WPA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001989 sel = ie.group_cipher & ssid->group_cipher;
Hai Shalom021b0b52019-04-10 11:17:58 -07001990 wpa_dbg(wpa_s, MSG_DEBUG,
1991 "WPA: AP group 0x%x network profile group 0x%x; available group 0x%x",
1992 ie.group_cipher, ssid->group_cipher, sel);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001993 wpa_s->group_cipher = wpa_pick_group_cipher(sel);
1994 if (wpa_s->group_cipher < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001995 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
1996 "cipher");
1997 return -1;
1998 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001999 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK %s",
2000 wpa_cipher_txt(wpa_s->group_cipher));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002001
2002 sel = ie.pairwise_cipher & ssid->pairwise_cipher;
Hai Shalom021b0b52019-04-10 11:17:58 -07002003 wpa_dbg(wpa_s, MSG_DEBUG,
2004 "WPA: AP pairwise 0x%x network profile pairwise 0x%x; available pairwise 0x%x",
2005 ie.pairwise_cipher, ssid->pairwise_cipher, sel);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002006 wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
2007 if (wpa_s->pairwise_cipher < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002008 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
2009 "cipher");
2010 return -1;
2011 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002012 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s",
2013 wpa_cipher_txt(wpa_s->pairwise_cipher));
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002014#endif /* CONFIG_NO_WPA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002015
2016 sel = ie.key_mgmt & ssid->key_mgmt;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002017#ifdef CONFIG_SAE
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002018 if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) &&
2019 !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA)) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00002020 wpas_is_sae_avoided(wpa_s, ssid, &ie))
Sunil Ravi89eba102022-09-13 21:04:37 -07002021 sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY |
2022 WPA_KEY_MGMT_FT_SAE | WPA_KEY_MGMT_FT_SAE_EXT_KEY);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002023#endif /* CONFIG_SAE */
Hai Shalomfdcde762020-04-02 11:19:20 -07002024#ifdef CONFIG_IEEE80211R
2025 if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME |
2026 WPA_DRIVER_FLAGS_UPDATE_FT_IES)))
2027 sel &= ~WPA_KEY_MGMT_FT;
2028#endif /* CONFIG_IEEE80211R */
2029 wpa_dbg(wpa_s, MSG_DEBUG,
2030 "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
2031 ie.key_mgmt, ssid->key_mgmt, sel);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002032 if (0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07002033#ifdef CONFIG_IEEE80211R
2034#ifdef CONFIG_SHA384
Hai Shalomc3565922019-10-28 11:58:20 -07002035 } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
2036 os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07002037 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
2038 wpa_dbg(wpa_s, MSG_DEBUG,
2039 "WPA: using KEY_MGMT FT/802.1X-SHA384");
Hai Shalom81f62d82019-07-22 12:10:00 -07002040 if (!ssid->ft_eap_pmksa_caching &&
2041 pmksa_cache_get_current(wpa_s->wpa)) {
2042 /* PMKSA caching with FT may have interoperability
2043 * issues, so disable that case by default for now. */
Hai Shalom021b0b52019-04-10 11:17:58 -07002044 wpa_dbg(wpa_s, MSG_DEBUG,
2045 "WPA: Disable PMKSA caching for FT/802.1X connection");
2046 pmksa_cache_clear_current(wpa_s->wpa);
2047 }
2048#endif /* CONFIG_SHA384 */
2049#endif /* CONFIG_IEEE80211R */
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002050#ifdef CONFIG_SUITEB192
2051 } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
2052 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
2053 wpa_dbg(wpa_s, MSG_DEBUG,
2054 "WPA: using KEY_MGMT 802.1X with Suite B (192-bit)");
2055#endif /* CONFIG_SUITEB192 */
2056#ifdef CONFIG_SUITEB
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002057 } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
2058 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
2059 wpa_dbg(wpa_s, MSG_DEBUG,
2060 "WPA: using KEY_MGMT 802.1X with Suite B");
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002061#endif /* CONFIG_SUITEB */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002062#ifdef CONFIG_SHA384
2063 } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA384) {
2064 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA384;
2065 wpa_dbg(wpa_s, MSG_DEBUG,
2066 "WPA: using KEY_MGMT 802.1X with SHA384");
2067#endif /* CONFIG_SHA384 */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002068#ifdef CONFIG_FILS
2069#ifdef CONFIG_IEEE80211R
2070 } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA384) {
2071 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
2072 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA384");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002073#endif /* CONFIG_IEEE80211R */
2074 } else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
2075 wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
2076 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA384");
Sunil Ravi89eba102022-09-13 21:04:37 -07002077#ifdef CONFIG_IEEE80211R
2078 } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) {
2079 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
2080 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256");
2081#endif /* CONFIG_IEEE80211R */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002082 } else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
2083 wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
2084 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
2085#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002086#ifdef CONFIG_IEEE80211R
Hai Shalomc3565922019-10-28 11:58:20 -07002087 } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) &&
2088 os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002089 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
2090 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
Hai Shalom81f62d82019-07-22 12:10:00 -07002091 if (!ssid->ft_eap_pmksa_caching &&
2092 pmksa_cache_get_current(wpa_s->wpa)) {
2093 /* PMKSA caching with FT may have interoperability
2094 * issues, so disable that case by default for now. */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002095 wpa_dbg(wpa_s, MSG_DEBUG,
2096 "WPA: Disable PMKSA caching for FT/802.1X connection");
2097 pmksa_cache_clear_current(wpa_s->wpa);
2098 }
Hai Shalom021b0b52019-04-10 11:17:58 -07002099#endif /* CONFIG_IEEE80211R */
2100#ifdef CONFIG_DPP
2101 } else if (sel & WPA_KEY_MGMT_DPP) {
2102 wpa_s->key_mgmt = WPA_KEY_MGMT_DPP;
2103 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP");
2104#endif /* CONFIG_DPP */
2105#ifdef CONFIG_SAE
Sunil Ravi89eba102022-09-13 21:04:37 -07002106 } else if (sel & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
2107 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE_EXT_KEY;
2108 wpa_dbg(wpa_s, MSG_DEBUG,
2109 "RSN: using KEY_MGMT FT/SAE (ext key)");
2110 } else if (sel & WPA_KEY_MGMT_SAE_EXT_KEY) {
2111 wpa_s->key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
2112 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE (ext key)");
Hai Shalom021b0b52019-04-10 11:17:58 -07002113 } else if (sel & WPA_KEY_MGMT_FT_SAE) {
2114 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
2115 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
2116 } else if (sel & WPA_KEY_MGMT_SAE) {
2117 wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
2118 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
2119#endif /* CONFIG_SAE */
2120#ifdef CONFIG_IEEE80211R
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002121 } else if (sel & WPA_KEY_MGMT_FT_PSK) {
2122 wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
2123 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
2124#endif /* CONFIG_IEEE80211R */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002125 } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
2126 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
2127 wpa_dbg(wpa_s, MSG_DEBUG,
2128 "WPA: using KEY_MGMT 802.1X with SHA256");
2129 } else if (sel & WPA_KEY_MGMT_PSK_SHA256) {
2130 wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
2131 wpa_dbg(wpa_s, MSG_DEBUG,
2132 "WPA: using KEY_MGMT PSK with SHA256");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002133 } else if (sel & WPA_KEY_MGMT_IEEE8021X) {
2134 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
2135 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
2136 } else if (sel & WPA_KEY_MGMT_PSK) {
2137 wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
2138 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK");
2139 } else if (sel & WPA_KEY_MGMT_WPA_NONE) {
2140 wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
2141 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002142#ifdef CONFIG_HS20
2143 } else if (sel & WPA_KEY_MGMT_OSEN) {
2144 wpa_s->key_mgmt = WPA_KEY_MGMT_OSEN;
2145 wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using KEY_MGMT OSEN");
2146#endif /* CONFIG_HS20 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002147#ifdef CONFIG_OWE
2148 } else if (sel & WPA_KEY_MGMT_OWE) {
2149 wpa_s->key_mgmt = WPA_KEY_MGMT_OWE;
2150 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT OWE");
2151#endif /* CONFIG_OWE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002152 } else {
2153 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
2154 "authenticated key management type");
2155 return -1;
2156 }
2157
2158 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
2159 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
2160 wpa_s->pairwise_cipher);
2161 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
2162
Hai Shalomc3565922019-10-28 11:58:20 -07002163 if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00002164 (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED ||
2165 (bss && is_6ghz_freq(bss->freq)))) {
Hai Shalomc3565922019-10-28 11:58:20 -07002166 wpa_msg(wpa_s, MSG_INFO,
2167 "RSN: Management frame protection required but the selected AP does not enable it");
2168 return -1;
2169 }
2170
Hai Shalomc1a21442022-02-04 13:43:00 -08002171 wpas_set_mgmt_group_cipher(wpa_s, ssid, &ie);
Hai Shalom74f70d42019-02-11 14:42:39 -08002172#ifdef CONFIG_OCV
Hai Shalom60840252021-02-19 19:02:11 -08002173 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
2174 (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OCV))
2175 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
Hai Shalom74f70d42019-02-11 14:42:39 -08002176#endif /* CONFIG_OCV */
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002177#ifdef CONFIG_SAE
2178 sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
Sunil Ravi89eba102022-09-13 21:04:37 -07002179 if ((ssid->sae_password_id ||
2180 wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt)) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00002181 sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
2182 sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
2183 if (bss && is_6ghz_freq(bss->freq) &&
2184 sae_pwe == SAE_PWE_HUNT_AND_PECK) {
2185 wpa_dbg(wpa_s, MSG_DEBUG,
2186 "RSN: Enable SAE hash-to-element mode for 6 GHz BSS");
2187 sae_pwe = SAE_PWE_BOTH;
Jimmy Chenaace8cd2021-04-13 14:55:52 +08002188 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002189 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe);
Hai Shalom899fcc72020-10-19 14:38:18 -07002190#ifdef CONFIG_SAE_PK
2191 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PK,
2192 wpa_key_mgmt_sae(ssid->key_mgmt) &&
2193 ssid->sae_pk != SAE_PK_MODE_DISABLED &&
2194 ((ssid->sae_password &&
2195 sae_pk_valid_password(ssid->sae_password)) ||
2196 (!ssid->sae_password && ssid->passphrase &&
2197 sae_pk_valid_password(ssid->passphrase))));
2198#endif /* CONFIG_SAE_PK */
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002199#endif /* CONFIG_SAE */
Sunil Ravi77d572f2023-01-17 23:58:31 +00002200 if (bss && is_6ghz_freq(bss->freq) &&
2201 wpas_get_ssid_pmf(wpa_s, ssid) != MGMT_FRAME_PROTECTION_REQUIRED) {
2202 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Force MFPR=1 on 6 GHz");
2203 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
2204 MGMT_FRAME_PROTECTION_REQUIRED);
2205 }
Hai Shalomb755a2a2020-04-23 21:49:02 -07002206#ifdef CONFIG_TESTING_OPTIONS
2207 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_RSNXE_USED,
2208 wpa_s->ft_rsnxe_used);
Hai Shalom899fcc72020-10-19 14:38:18 -07002209 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL,
2210 wpa_s->oci_freq_override_eapol);
2211 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
2212 wpa_s->oci_freq_override_eapol_g2);
2213 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
2214 wpa_s->oci_freq_override_ft_assoc);
2215 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FILS_ASSOC,
2216 wpa_s->oci_freq_override_fils_assoc);
Sunil Ravia04bd252022-05-02 22:54:18 -07002217 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DISABLE_EAPOL_G2_TX,
2218 wpa_s->disable_eapol_g2_tx);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002219 wpa_sm_set_param(wpa_s->wpa,
2220 WPA_PARAM_EAPOL_2_KEY_INFO_SET_MASK,
2221 wpa_s->eapol_2_key_info_set_mask);
Hai Shalomb755a2a2020-04-23 21:49:02 -07002222#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomfdcde762020-04-02 11:19:20 -07002223
2224 /* Extended Key ID is only supported in infrastructure BSS so far */
2225 if (ssid->mode == WPAS_MODE_INFRA && wpa_s->conf->extended_key_id &&
2226 (ssid->proto & WPA_PROTO_RSN) &&
2227 ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
2228 WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256) &&
2229 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)) {
2230 int use_ext_key_id = 0;
2231
2232 wpa_msg(wpa_s, MSG_DEBUG,
2233 "WPA: Enable Extended Key ID support");
2234 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID,
2235 wpa_s->conf->extended_key_id);
2236 if (bss_rsn &&
2237 wpa_s->conf->extended_key_id &&
2238 wpa_s->pairwise_cipher != WPA_CIPHER_TKIP &&
2239 (ie.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST))
2240 use_ext_key_id = 1;
2241 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID,
2242 use_ext_key_id);
2243 } else {
2244 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID, 0);
2245 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0);
2246 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002247
Sunil Ravi640215c2023-06-28 23:08:09 +00002248 /* Mark WMM enabled for any HT/VHT/HE/EHT association to get more
2249 * appropriate advertisement of the supported number of PTKSA receive
2250 * counters. In theory, this could be based on a driver capability, but
2251 * in practice all cases using WMM support at least eight replay
2252 * counters, so use a hardcoded value for now since there is no explicit
2253 * driver capability indication for this.
2254 *
2255 * In addition, claim WMM to be enabled if the AP supports it since it
2256 * is far more likely for any current device to support WMM. */
2257 wmm = wpa_s->connection_set &&
2258 (wpa_s->connection_ht || wpa_s->connection_vht ||
2259 wpa_s->connection_he || wpa_s->connection_eht);
2260 if (!wmm && bss)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002261 wmm = !!wpa_bss_get_vendor_ie(bss, WMM_IE_VENDOR_TYPE);
Sunil Ravi640215c2023-06-28 23:08:09 +00002262 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_WMM_ENABLED, wmm);
2263
Sunil Ravi7f769292024-07-23 22:21:32 +00002264 if (ssid->ssid_protection && proto == WPA_PROTO_RSN) {
2265 bool ssid_prot;
2266
2267 /* Enable SSID protection based on the AP advertising support
2268 * for it to avoid potential interoperability issues with
2269 * incorrect AP behavior if we were to send an "unexpected"
2270 * RSNXE with multiple octets of payload. */
2271 ssid_prot = ieee802_11_rsnx_capab(
2272 bss_rsnx, WLAN_RSNX_CAPAB_SSID_PROTECTION);
2273 if (!skip_default_rsne)
2274 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION,
2275 proto == WPA_PROTO_RSN && ssid_prot);
2276 } else {
2277 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION, false);
2278 }
2279
Sunil Ravi77d572f2023-01-17 23:58:31 +00002280 if (!skip_default_rsne) {
2281 if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie,
2282 wpa_ie_len)) {
2283 wpa_msg(wpa_s, MSG_WARNING,
2284 "RSN: Failed to generate RSNE/WPA IE");
2285 return -1;
2286 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002287
Matthew Wang9ed1c792024-12-02 14:05:18 +00002288#ifndef CONFIG_NO_WPA
Sunil Ravi77d572f2023-01-17 23:58:31 +00002289 wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
2290 if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
2291 &wpa_s->rsnxe_len)) {
2292 wpa_msg(wpa_s, MSG_WARNING,
2293 "RSN: Failed to generate RSNXE");
2294 return -1;
2295 }
Matthew Wang9ed1c792024-12-02 14:05:18 +00002296#endif /* CONFIG_NO_WPA */
Hai Shalomc3565922019-10-28 11:58:20 -07002297 }
2298
Hai Shalom021b0b52019-04-10 11:17:58 -07002299 if (0) {
2300#ifdef CONFIG_DPP
2301 } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
2302 /* Use PMK from DPP network introduction (PMKSA entry) */
2303 wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002304#ifdef CONFIG_DPP2
2305 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DPP_PFS, ssid->dpp_pfs);
2306#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07002307#endif /* CONFIG_DPP */
2308 } else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002309 int psk_set = 0;
2310
Sunil Ravi77d572f2023-01-17 23:58:31 +00002311 if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt)) {
2312 u8 psk[PMK_LEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -07002313
Sunil Ravi77d572f2023-01-17 23:58:31 +00002314 if (wpa_supplicant_get_psk(wpa_s, bss, ssid,
2315 psk) == 0) {
2316 wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
2317 NULL);
2318 psk_set = 1;
2319 }
2320 forced_memzero(psk, sizeof(psk));
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002321 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002322
Roshan Pius3a1667e2018-07-03 15:17:14 -07002323 if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00002324 (ssid->sae_password || ssid->passphrase || ssid->ext_psk))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002325 psk_set = 1;
2326
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002327 if (!psk_set && !ssid->pmk_valid) {
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002328 wpa_msg(wpa_s, MSG_INFO,
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002329 "No PSK/PMK available for association");
Sunil Ravi77d572f2023-01-17 23:58:31 +00002330 wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE", NULL);
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002331 return -1;
2332 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002333#ifdef CONFIG_OWE
2334 } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) {
2335 /* OWE Diffie-Hellman exchange in (Re)Association
2336 * Request/Response frames set the PMK, so do not override it
2337 * here. */
2338#endif /* CONFIG_OWE */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002339 } else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002340 wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
2341
Hai Shalomfdcde762020-04-02 11:19:20 -07002342 if (ssid->mode != WPAS_MODE_IBSS &&
2343 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
2344 (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
2345 (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
2346 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
2347 wpa_msg(wpa_s, MSG_INFO,
2348 "Disable PTK0 rekey support - replaced with reconnect");
2349 wpa_s->deny_ptk0_rekey = 1;
2350 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 1);
2351 } else {
2352 wpa_s->deny_ptk0_rekey = 0;
2353 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0);
2354 }
2355
Isaac Chiou6ce580d2024-04-24 17:07:24 +08002356#if (defined(CONFIG_DRIVER_NL80211_BRCM) && !defined(WIFI_BRCM_OPEN_SOURCE_MULTI_AKM)) || \
2357 defined(CONFIG_DRIVER_NL80211_SYNA)
Vinayak Yadawad14709082022-03-17 14:25:11 +05302358 if ((wpa_s->key_mgmt & WPA_KEY_MGMT_CROSS_AKM_ROAM) &&
Dennis Jeon2a960552022-07-05 13:56:50 +09002359 IS_CROSS_AKM_ROAM_KEY_MGMT(ssid->key_mgmt) &&
2360 (wpa_s->group_cipher == WPA_CIPHER_CCMP) &&
Dennis Jeona3930812022-10-24 15:31:04 +09002361 (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP) &&
2362 (wpa_s->wpa_proto == WPA_PROTO_RSN)) {
Vinayak Yadawad14709082022-03-17 14:25:11 +05302363 wpa_s->key_mgmt = WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_PSK;
2364 wpa_dbg(wpa_s, MSG_INFO,
2365 "WPA: Updating to KEY_MGMT SAE+PSK for seamless roaming");
2366 }
Sunil Ravif42be322022-11-04 03:31:21 +00002367#else
2368 if (wpa_key_mgmt_cross_akm(wpa_s->key_mgmt) &&
2369 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
2370 wpas_update_allowed_key_mgmt(wpa_s, ssid);
Isaac Chiou6ce580d2024-04-24 17:07:24 +08002371#endif /* (CONFIG_DRIVER_NL80211_BRCM && !WIFI_BRCM_OPEN_SOURCE_MULTI_AKM) ||
2372 * CONFIG_DRIVER_NL80211_SYNA */
Vinayak Yadawad14709082022-03-17 14:25:11 +05302373
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002374 return 0;
2375}
2376
2377
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002378static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx,
2379 struct wpa_bss *bss)
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002380{
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002381#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08002382 bool scs = true, mscs = true;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002383#endif /* CONFIG_NO_ROBUST_AV */
Hai Shalomc1a21442022-02-04 13:43:00 -08002384
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002385 *pos = 0x00;
2386
2387 switch (idx) {
2388 case 0: /* Bits 0-7 */
2389 break;
2390 case 1: /* Bits 8-15 */
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002391 if (wpa_s->conf->coloc_intf_reporting) {
2392 /* Bit 13 - Collocated Interference Reporting */
2393 *pos |= 0x20;
2394 }
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002395 break;
2396 case 2: /* Bits 16-23 */
2397#ifdef CONFIG_WNM
2398 *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002399 if ((wpas_driver_bss_selection(wpa_s) ||
2400 !wpa_s->disable_mbo_oce) &&
2401 !wpa_s->conf->disable_btm)
Hai Shalom81f62d82019-07-22 12:10:00 -07002402 *pos |= 0x08; /* Bit 19 - BSS Transition */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002403#endif /* CONFIG_WNM */
2404 break;
2405 case 3: /* Bits 24-31 */
2406#ifdef CONFIG_WNM
2407 *pos |= 0x02; /* Bit 25 - SSID List */
2408#endif /* CONFIG_WNM */
2409#ifdef CONFIG_INTERWORKING
2410 if (wpa_s->conf->interworking)
2411 *pos |= 0x80; /* Bit 31 - Interworking */
2412#endif /* CONFIG_INTERWORKING */
2413 break;
2414 case 4: /* Bits 32-39 */
Dmitry Shmidt051af732013-10-22 13:52:46 -07002415#ifdef CONFIG_INTERWORKING
Hai Shalomce48b4a2018-09-05 11:41:35 -07002416 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002417 *pos |= 0x01; /* Bit 32 - QoS Map */
Dmitry Shmidt051af732013-10-22 13:52:46 -07002418#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002419 break;
2420 case 5: /* Bits 40-47 */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002421#ifdef CONFIG_HS20
2422 if (wpa_s->conf->hs20)
2423 *pos |= 0x40; /* Bit 46 - WNM-Notification */
2424#endif /* CONFIG_HS20 */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002425#ifdef CONFIG_MBO
2426 *pos |= 0x40; /* Bit 46 - WNM-Notification */
2427#endif /* CONFIG_MBO */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002428 break;
2429 case 6: /* Bits 48-55 */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002430#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08002431#ifdef CONFIG_TESTING_OPTIONS
2432 if (wpa_s->disable_scs_support)
2433 scs = false;
2434#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002435 if (bss && !wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_SCS)) {
2436 /* Drop own SCS capability indication since the AP does
2437 * not support it. This is needed to avoid
2438 * interoperability issues with APs that get confused
2439 * with Extended Capabilities element. */
2440 scs = false;
2441 }
Hai Shalomc1a21442022-02-04 13:43:00 -08002442 if (scs)
2443 *pos |= 0x40; /* Bit 54 - SCS */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002444#endif /* CONFIG_NO_ROBUST_AV */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002445 break;
Dmitry Shmidt7d175302016-09-06 13:11:34 -07002446 case 7: /* Bits 56-63 */
2447 break;
2448 case 8: /* Bits 64-71 */
2449 if (wpa_s->conf->ftm_responder)
2450 *pos |= 0x40; /* Bit 70 - FTM responder */
2451 if (wpa_s->conf->ftm_initiator)
2452 *pos |= 0x80; /* Bit 71 - FTM initiator */
2453 break;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002454 case 9: /* Bits 72-79 */
2455#ifdef CONFIG_FILS
Roshan Pius3a1667e2018-07-03 15:17:14 -07002456 if (!wpa_s->disable_fils)
2457 *pos |= 0x01;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002458#endif /* CONFIG_FILS */
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002459 if (wpa_s->conf->twt_requester)
2460 *pos |= 0x20; /* Bit 77 - TWT Requester Support */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002461 break;
Hai Shalom899fcc72020-10-19 14:38:18 -07002462 case 10: /* Bits 80-87 */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002463#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08002464#ifdef CONFIG_TESTING_OPTIONS
2465 if (wpa_s->disable_mscs_support)
2466 mscs = false;
2467#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002468 if (bss && !wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS)) {
2469 /* Drop own MSCS capability indication since the AP does
2470 * not support it. This is needed to avoid
2471 * interoperability issues with APs that get confused
2472 * with Extended Capabilities element. */
2473 mscs = false;
2474 }
Hai Shalomc1a21442022-02-04 13:43:00 -08002475 if (mscs)
2476 *pos |= 0x20; /* Bit 85 - Mirrored SCS */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002477#endif /* CONFIG_NO_ROBUST_AV */
Hai Shalom899fcc72020-10-19 14:38:18 -07002478 break;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002479 }
2480}
2481
2482
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002483int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf,
2484 size_t buflen, struct wpa_bss *bss)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002485{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002486 u8 *pos = buf;
Hai Shalom899fcc72020-10-19 14:38:18 -07002487 u8 len = 11, i;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002488
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002489 if (len < wpa_s->extended_capa_len)
2490 len = wpa_s->extended_capa_len;
Dmitry Shmidt09f57ba2014-06-10 16:07:13 -07002491 if (buflen < (size_t) len + 2) {
2492 wpa_printf(MSG_INFO,
2493 "Not enough room for building extended capabilities element");
2494 return -1;
2495 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002496
2497 *pos++ = WLAN_EID_EXT_CAPAB;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002498 *pos++ = len;
2499 for (i = 0; i < len; i++, pos++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002500 wpas_ext_capab_byte(wpa_s, pos, i, bss);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002501
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002502 if (i < wpa_s->extended_capa_len) {
2503 *pos &= ~wpa_s->extended_capa_mask[i];
2504 *pos |= wpa_s->extended_capa[i];
2505 }
2506 }
2507
2508 while (len > 0 && buf[1 + len] == 0) {
2509 len--;
2510 buf[1] = len;
2511 }
2512 if (len == 0)
2513 return 0;
2514
2515 return 2 + len;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002516}
2517
2518
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002519static int wpas_valid_bss(struct wpa_supplicant *wpa_s,
2520 struct wpa_bss *test_bss)
2521{
2522 struct wpa_bss *bss;
2523
2524 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
2525 if (bss == test_bss)
2526 return 1;
2527 }
2528
2529 return 0;
2530}
2531
2532
2533static int wpas_valid_ssid(struct wpa_supplicant *wpa_s,
2534 struct wpa_ssid *test_ssid)
2535{
2536 struct wpa_ssid *ssid;
2537
2538 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
2539 if (ssid == test_ssid)
2540 return 1;
2541 }
2542
2543 return 0;
2544}
2545
2546
2547int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss,
2548 struct wpa_ssid *test_ssid)
2549{
2550 if (test_bss && !wpas_valid_bss(wpa_s, test_bss))
2551 return 0;
2552
2553 return test_ssid == NULL || wpas_valid_ssid(wpa_s, test_ssid);
2554}
2555
2556
2557void wpas_connect_work_free(struct wpa_connect_work *cwork)
2558{
2559 if (cwork == NULL)
2560 return;
2561 os_free(cwork);
2562}
2563
2564
2565void wpas_connect_work_done(struct wpa_supplicant *wpa_s)
2566{
2567 struct wpa_connect_work *cwork;
2568 struct wpa_radio_work *work = wpa_s->connect_work;
2569
2570 if (!work)
2571 return;
2572
2573 wpa_s->connect_work = NULL;
2574 cwork = work->ctx;
2575 work->ctx = NULL;
2576 wpas_connect_work_free(cwork);
2577 radio_work_done(work);
2578}
2579
2580
Sunil Ravi77d572f2023-01-17 23:58:31 +00002581int wpas_update_random_addr(struct wpa_supplicant *wpa_s,
2582 enum wpas_mac_addr_style style,
2583 struct wpa_ssid *ssid)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002584{
2585 struct os_reltime now;
2586 u8 addr[ETH_ALEN];
2587
2588 os_get_reltime(&now);
Sunil Ravi77d572f2023-01-17 23:58:31 +00002589 /* Random addresses are valid within a given ESS so check
2590 * expiration/value only when continuing to use the same ESS. */
2591 if (wpa_s->last_mac_addr_style == style && wpa_s->reassoc_same_ess) {
2592 if (style == WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS) {
2593 /* Pregenerated addresses do not expire but their value
2594 * might have changed, so let's check that. */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002595 if (ether_addr_equal(wpa_s->own_addr, ssid->mac_value))
Sunil Ravi77d572f2023-01-17 23:58:31 +00002596 return 0;
2597 } else if ((wpa_s->last_mac_addr_change.sec != 0 ||
2598 wpa_s->last_mac_addr_change.usec != 0) &&
2599 !os_reltime_expired(
2600 &now,
2601 &wpa_s->last_mac_addr_change,
2602 wpa_s->conf->rand_addr_lifetime)) {
2603 wpa_msg(wpa_s, MSG_DEBUG,
2604 "Previously selected random MAC address has not yet expired");
2605 return 0;
2606 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002607 }
2608
2609 switch (style) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002610 case WPAS_MAC_ADDR_STYLE_RANDOM:
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002611 if (random_mac_addr(addr) < 0)
2612 return -1;
2613 break;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002614 case WPAS_MAC_ADDR_STYLE_RANDOM_SAME_OUI:
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002615 os_memcpy(addr, wpa_s->perm_addr, ETH_ALEN);
2616 if (random_mac_addr_keep_oui(addr) < 0)
2617 return -1;
2618 break;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002619 case WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS:
2620 if (!ssid) {
2621 wpa_msg(wpa_s, MSG_INFO,
2622 "Invalid 'ssid' for address policy 3");
2623 return -1;
2624 }
2625 os_memcpy(addr, ssid->mac_value, ETH_ALEN);
2626 break;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002627 default:
2628 return -1;
2629 }
2630
2631 if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
2632 wpa_msg(wpa_s, MSG_INFO,
2633 "Failed to set random MAC address");
2634 return -1;
2635 }
2636
2637 os_get_reltime(&wpa_s->last_mac_addr_change);
2638 wpa_s->mac_addr_changed = 1;
2639 wpa_s->last_mac_addr_style = style;
2640
2641 if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
2642 wpa_msg(wpa_s, MSG_INFO,
2643 "Could not update MAC address information");
2644 return -1;
2645 }
2646
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002647 wpas_p2p_update_dev_addr(wpa_s);
2648
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002649 wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
2650 MAC2STR(addr));
2651
Sunil Ravi77d572f2023-01-17 23:58:31 +00002652 return 1;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002653}
2654
2655
2656int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
2657{
2658 if (wpa_s->wpa_state >= WPA_AUTHENTICATING ||
2659 !wpa_s->conf->preassoc_mac_addr)
2660 return 0;
2661
Sunil Ravi77d572f2023-01-17 23:58:31 +00002662 return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr,
2663 NULL);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002664}
2665
2666
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002667void wpa_s_setup_sae_pt(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
Sunil Ravi036cec52023-03-29 11:35:17 -07002668 bool force)
Hai Shalomc3565922019-10-28 11:58:20 -07002669{
2670#ifdef CONFIG_SAE
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002671 struct wpa_config *conf = wpa_s->conf;
Hai Shalomc3565922019-10-28 11:58:20 -07002672 int *groups = conf->sae_groups;
2673 int default_groups[] = { 19, 20, 21, 0 };
2674 const char *password;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002675 enum sae_pwe sae_pwe;
Hai Shalomc3565922019-10-28 11:58:20 -07002676
2677 if (!groups || groups[0] <= 0)
2678 groups = default_groups;
2679
2680 password = ssid->sae_password;
2681 if (!password)
2682 password = ssid->passphrase;
2683
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002684 sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
2685
Hai Shalom899fcc72020-10-19 14:38:18 -07002686 if (!password ||
Sunil Ravi7f769292024-07-23 22:21:32 +00002687 !wpa_key_mgmt_sae(ssid->key_mgmt) ||
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002688 (sae_pwe == SAE_PWE_HUNT_AND_PECK && !ssid->sae_password_id &&
Sunil Ravi89eba102022-09-13 21:04:37 -07002689 !wpa_key_mgmt_sae_ext_key(ssid->key_mgmt) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07002690 !force &&
Hai Shalom899fcc72020-10-19 14:38:18 -07002691 !sae_pk_valid_password(password)) ||
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002692 sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) {
Hai Shalomc3565922019-10-28 11:58:20 -07002693 /* PT derivation not needed */
2694 sae_deinit_pt(ssid->pt);
2695 ssid->pt = NULL;
2696 return;
2697 }
2698
2699 if (ssid->pt)
2700 return; /* PT already derived */
2701 ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
2702 (const u8 *) password, os_strlen(password),
2703 ssid->sae_password_id);
2704#endif /* CONFIG_SAE */
2705}
2706
2707
Sunil Ravi7f769292024-07-23 22:21:32 +00002708void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s)
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002709{
2710#if defined(CONFIG_SAE) && defined(CONFIG_SME)
2711 os_free(wpa_s->sme.sae_rejected_groups);
2712 wpa_s->sme.sae_rejected_groups = NULL;
2713#ifdef CONFIG_TESTING_OPTIONS
2714 if (wpa_s->extra_sae_rejected_groups) {
2715 int i, *groups = wpa_s->extra_sae_rejected_groups;
2716
2717 for (i = 0; groups[i]; i++) {
2718 wpa_printf(MSG_DEBUG,
2719 "TESTING: Indicate rejection of an extra SAE group %d",
2720 groups[i]);
2721 int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
2722 groups[i]);
2723 }
2724 }
2725#endif /* CONFIG_TESTING_OPTIONS */
2726#endif /* CONFIG_SAE && CONFIG_SME */
2727}
2728
2729
Hai Shalom60840252021-02-19 19:02:11 -08002730int wpas_restore_permanent_mac_addr(struct wpa_supplicant *wpa_s)
2731{
2732 if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
2733 wpa_msg(wpa_s, MSG_INFO,
2734 "Could not restore permanent MAC address");
2735 return -1;
2736 }
2737 wpa_s->mac_addr_changed = 0;
2738 if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
2739 wpa_msg(wpa_s, MSG_INFO,
2740 "Could not update MAC address information");
2741 return -1;
2742 }
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002743
2744 wpas_p2p_update_dev_addr(wpa_s);
2745
Hai Shalom60840252021-02-19 19:02:11 -08002746 wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
2747 return 0;
2748}
2749
2750
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002751static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
2752
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002753/**
2754 * wpa_supplicant_associate - Request association
2755 * @wpa_s: Pointer to wpa_supplicant data
2756 * @bss: Scan results for the selected BSS, or %NULL if not available
2757 * @ssid: Configuration data for the selected network
2758 *
2759 * This function is used to request %wpa_supplicant to associate with a BSS.
2760 */
2761void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
2762 struct wpa_bss *bss, struct wpa_ssid *ssid)
2763{
Sunil Ravi7f769292024-07-23 22:21:32 +00002764 bool clear_rejected = true;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002765 struct wpa_connect_work *cwork;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002766 enum wpas_mac_addr_style rand_style;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002767
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002768 wpa_s->own_disconnect_req = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07002769 wpa_s->own_reconnect_req = 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002770
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002771 /*
2772 * If we are starting a new connection, any previously pending EAPOL
2773 * RX cannot be valid anymore.
2774 */
2775 wpabuf_free(wpa_s->pending_eapol_rx);
2776 wpa_s->pending_eapol_rx = NULL;
2777
Sunil Ravi77d572f2023-01-17 23:58:31 +00002778 if (ssid->mac_addr == WPAS_MAC_ADDR_STYLE_NOT_SET)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002779 rand_style = wpa_s->conf->mac_addr;
2780 else
2781 rand_style = ssid->mac_addr;
2782
Sunil Ravia04bd252022-05-02 22:54:18 -07002783 wpa_s->eapol_failed = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07002784 wpa_s->multi_ap_ie = 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002785#ifndef CONFIG_NO_WMM_AC
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002786 wmm_ac_clear_saved_tspecs(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002787#endif /* CONFIG_NO_WMM_AC */
2788#ifdef CONFIG_WNM
2789 wpa_s->wnm_mode = 0;
Sunil Ravi99c035e2024-07-12 01:42:03 +00002790 wpa_s->wnm_target_bss = NULL;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002791#endif /* CONFIG_WNM */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002792 wpa_s->reassoc_same_bss = 0;
Dmitry Shmidte4663042016-04-04 10:07:49 -07002793 wpa_s->reassoc_same_ess = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002794#ifdef CONFIG_TESTING_OPTIONS
2795 wpa_s->testing_resend_assoc = 0;
2796#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002797
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002798 if (wpa_s->last_ssid == ssid) {
2799 wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
Dmitry Shmidte4663042016-04-04 10:07:49 -07002800 wpa_s->reassoc_same_ess = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002801 if (wpa_s->current_bss && wpa_s->current_bss == bss) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002802#ifndef CONFIG_NO_WMM_AC
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002803 wmm_ac_save_tspecs(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002804#endif /* CONFIG_NO_WMM_AC */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002805 wpa_s->reassoc_same_bss = 1;
Sunil Ravi7f769292024-07-23 22:21:32 +00002806 clear_rejected = false;
Hai Shalom74f70d42019-02-11 14:42:39 -08002807 } else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
2808 os_get_reltime(&wpa_s->roam_start);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002809 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002810 }
Sunil Ravi7f769292024-07-23 22:21:32 +00002811
2812 if (clear_rejected)
2813 wpa_s_clear_sae_rejected(wpa_s);
2814
Hai Shalomc1a21442022-02-04 13:43:00 -08002815#ifdef CONFIG_SAE
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002816 wpa_s_setup_sae_pt(wpa_s, ssid, false);
Hai Shalomc1a21442022-02-04 13:43:00 -08002817#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002818
Sunil Ravi77d572f2023-01-17 23:58:31 +00002819 if (rand_style > WPAS_MAC_ADDR_STYLE_PERMANENT) {
2820 int status = wpas_update_random_addr(wpa_s, rand_style, ssid);
2821
2822 if (status < 0)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002823 return;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002824 if (rand_style != WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS &&
2825 status > 0) /* MAC changed */
2826 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
2827 } else if (rand_style == WPAS_MAC_ADDR_STYLE_PERMANENT &&
2828 wpa_s->mac_addr_changed) {
Hai Shalom60840252021-02-19 19:02:11 -08002829 if (wpas_restore_permanent_mac_addr(wpa_s) < 0)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002830 return;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002831 }
2832 wpa_s->last_ssid = ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002833
2834#ifdef CONFIG_IBSS_RSN
2835 ibss_rsn_deinit(wpa_s->ibss_rsn);
2836 wpa_s->ibss_rsn = NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002837#else /* CONFIG_IBSS_RSN */
2838 if (ssid->mode == WPAS_MODE_IBSS &&
2839 !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
2840 wpa_msg(wpa_s, MSG_INFO,
2841 "IBSS RSN not supported in the build");
2842 return;
2843 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002844#endif /* CONFIG_IBSS_RSN */
2845
2846 if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
2847 ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
2848#ifdef CONFIG_AP
2849 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
2850 wpa_msg(wpa_s, MSG_INFO, "Driver does not support AP "
2851 "mode");
2852 return;
2853 }
Dmitry Shmidtaa532512012-09-24 10:35:31 -07002854 if (wpa_supplicant_create_ap(wpa_s, ssid) < 0) {
2855 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
Ajay Davanageri10b3c662024-05-02 19:19:24 +05302856 if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
2857 ssid->mode == WPAS_MODE_P2P_GO) {
2858 wpa_msg(wpa_s, MSG_ERROR, "create ap failed. clean up the states");
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07002859 wpas_p2p_ap_setup_failed(wpa_s);
Ajay Davanageri10b3c662024-05-02 19:19:24 +05302860 }
Dmitry Shmidtaa532512012-09-24 10:35:31 -07002861 return;
2862 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002863 wpa_s->current_bss = bss;
2864#else /* CONFIG_AP */
2865 wpa_msg(wpa_s, MSG_ERROR, "AP mode support not included in "
2866 "the build");
2867#endif /* CONFIG_AP */
2868 return;
2869 }
2870
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002871 if (ssid->mode == WPAS_MODE_MESH) {
2872#ifdef CONFIG_MESH
2873 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MESH)) {
2874 wpa_msg(wpa_s, MSG_INFO,
2875 "Driver does not support mesh mode");
2876 return;
2877 }
2878 if (bss)
2879 ssid->frequency = bss->freq;
2880 if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) {
Sunil Ravi036cec52023-03-29 11:35:17 -07002881 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002882 wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh");
2883 return;
2884 }
2885 wpa_s->current_bss = bss;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002886#else /* CONFIG_MESH */
2887 wpa_msg(wpa_s, MSG_ERROR,
2888 "mesh mode support not included in the build");
2889#endif /* CONFIG_MESH */
2890 return;
2891 }
2892
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002893 /*
2894 * Set WPA state machine configuration to match the selected network now
2895 * so that the information is available before wpas_start_assoc_cb()
2896 * gets called. This is needed at least for RSN pre-authentication where
2897 * candidate APs are added to a list based on scan result processing
2898 * before completion of the first association.
2899 */
2900 wpa_supplicant_rsn_supp_set_config(wpa_s, ssid);
2901
2902#ifdef CONFIG_DPP
2903 if (wpas_dpp_check_connect(wpa_s, ssid, bss) != 0)
2904 return;
2905#endif /* CONFIG_DPP */
2906
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002907#ifdef CONFIG_TDLS
2908 if (bss)
Hai Shalom60840252021-02-19 19:02:11 -08002909 wpa_tdls_ap_ies(wpa_s->wpa, wpa_bss_ie_ptr(bss), bss->ie_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002910#endif /* CONFIG_TDLS */
2911
Hai Shalomc3565922019-10-28 11:58:20 -07002912#ifdef CONFIG_MBO
2913 wpas_mbo_check_pmf(wpa_s, bss, ssid);
2914#endif /* CONFIG_MBO */
2915
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002916 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
Hai Shalom81f62d82019-07-22 12:10:00 -07002917 ssid->mode == WPAS_MODE_INFRA) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002918 sme_authenticate(wpa_s, bss, ssid);
2919 return;
2920 }
2921
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002922 if (wpa_s->connect_work) {
2923 wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist");
2924 return;
2925 }
2926
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002927 if (radio_work_pending(wpa_s, "connect")) {
2928 wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since pending work exist");
2929 return;
2930 }
2931
Dmitry Shmidt29333592017-01-09 12:27:11 -08002932#ifdef CONFIG_SME
2933 if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) {
2934 /* Clear possibly set auth_alg, if any, from last attempt. */
2935 wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN;
2936 }
2937#endif /* CONFIG_SME */
2938
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002939 wpas_abort_ongoing_scan(wpa_s);
2940
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002941 cwork = os_zalloc(sizeof(*cwork));
2942 if (cwork == NULL)
2943 return;
2944
2945 cwork->bss = bss;
2946 cwork->ssid = ssid;
2947
2948 if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1,
2949 wpas_start_assoc_cb, cwork) < 0) {
2950 os_free(cwork);
2951 }
2952}
2953
2954
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002955static int bss_is_ibss(struct wpa_bss *bss)
2956{
2957 return (bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) ==
2958 IEEE80211_CAP_IBSS;
2959}
2960
2961
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002962static int drv_supports_vht(struct wpa_supplicant *wpa_s,
2963 const struct wpa_ssid *ssid)
2964{
2965 enum hostapd_hw_mode hw_mode;
2966 struct hostapd_hw_modes *mode = NULL;
2967 u8 channel;
2968 int i;
2969
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002970 hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
2971 if (hw_mode == NUM_HOSTAPD_MODES)
2972 return 0;
2973 for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
2974 if (wpa_s->hw.modes[i].mode == hw_mode) {
2975 mode = &wpa_s->hw.modes[i];
2976 break;
2977 }
2978 }
2979
2980 if (!mode)
2981 return 0;
2982
2983 return mode->vht_capab != 0;
2984}
2985
2986
Hai Shalomc1a21442022-02-04 13:43:00 -08002987static bool ibss_mesh_is_80mhz_avail(int channel, struct hostapd_hw_modes *mode)
2988{
2989 int i;
2990
2991 for (i = channel; i < channel + 16; i += 4) {
2992 struct hostapd_channel_data *chan;
2993
2994 chan = hw_get_channel_chan(mode, i, NULL);
2995 if (!chan ||
2996 chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
2997 return false;
2998 }
2999
3000 return true;
3001}
3002
3003
Sunil Ravi036cec52023-03-29 11:35:17 -07003004static struct wpa_bss * ibss_find_existing_bss(struct wpa_supplicant *wpa_s,
3005 const struct wpa_ssid *ssid)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003006{
Sunil Ravi036cec52023-03-29 11:35:17 -07003007 unsigned int j;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003008
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003009 for (j = 0; j < wpa_s->last_scan_res_used; j++) {
3010 struct wpa_bss *bss = wpa_s->last_scan_res[j];
3011
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003012 if (!bss_is_ibss(bss))
3013 continue;
3014
3015 if (ssid->ssid_len == bss->ssid_len &&
Sunil Ravi036cec52023-03-29 11:35:17 -07003016 os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) == 0)
3017 return bss;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003018 }
Sunil Ravi036cec52023-03-29 11:35:17 -07003019 return NULL;
3020}
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003021
Sunil Ravi036cec52023-03-29 11:35:17 -07003022
3023static bool ibss_mesh_can_use_ht(struct wpa_supplicant *wpa_s,
3024 const struct wpa_ssid *ssid,
3025 struct hostapd_hw_modes *mode)
3026{
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003027 /* For IBSS check HT_IBSS flag */
3028 if (ssid->mode == WPAS_MODE_IBSS &&
3029 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_HT_IBSS))
Sunil Ravi036cec52023-03-29 11:35:17 -07003030 return false;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003031
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003032 if (wpa_s->group_cipher == WPA_CIPHER_WEP40 ||
3033 wpa_s->group_cipher == WPA_CIPHER_WEP104 ||
3034 wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) {
3035 wpa_printf(MSG_DEBUG,
3036 "IBSS: WEP/TKIP detected, do not try to enable HT");
Sunil Ravi036cec52023-03-29 11:35:17 -07003037 return false;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003038 }
3039
Sunil Ravi036cec52023-03-29 11:35:17 -07003040 if (!ht_supported(mode))
3041 return false;
Hai Shalomc1a21442022-02-04 13:43:00 -08003042
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003043#ifdef CONFIG_HT_OVERRIDES
Sunil Ravi036cec52023-03-29 11:35:17 -07003044 if (ssid->disable_ht)
3045 return false;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003046#endif /* CONFIG_HT_OVERRIDES */
3047
Sunil Ravi036cec52023-03-29 11:35:17 -07003048 return true;
3049}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003050
Sunil Ravi036cec52023-03-29 11:35:17 -07003051
3052static bool ibss_mesh_can_use_vht(struct wpa_supplicant *wpa_s,
3053 const struct wpa_ssid *ssid,
3054 struct hostapd_hw_modes *mode)
3055{
3056 if (mode->mode != HOSTAPD_MODE_IEEE80211A)
3057 return false;
3058
3059 if (!drv_supports_vht(wpa_s, ssid))
3060 return false;
3061
3062 /* For IBSS check VHT_IBSS flag */
3063 if (ssid->mode == WPAS_MODE_IBSS &&
3064 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
3065 return false;
3066
3067 if (!vht_supported(mode))
3068 return false;
3069
3070#ifdef CONFIG_VHT_OVERRIDES
3071 if (ssid->disable_vht)
3072 return false;
3073#endif /* CONFIG_VHT_OVERRIDES */
3074
3075 return true;
3076}
3077
3078
3079static bool ibss_mesh_can_use_he(struct wpa_supplicant *wpa_s,
3080 const struct wpa_ssid *ssid,
3081 const struct hostapd_hw_modes *mode,
3082 int ieee80211_mode)
3083{
Hai Shalomfdcde762020-04-02 11:19:20 -07003084#ifdef CONFIG_HE_OVERRIDES
Sunil Ravi036cec52023-03-29 11:35:17 -07003085 if (ssid->disable_he)
3086 return false;
Hai Shalomfdcde762020-04-02 11:19:20 -07003087#endif /* CONFIG_HE_OVERRIDES */
Hai Shalomc3565922019-10-28 11:58:20 -07003088
Sunil Ravi036cec52023-03-29 11:35:17 -07003089 switch (mode->mode) {
3090 case HOSTAPD_MODE_IEEE80211G:
3091 case HOSTAPD_MODE_IEEE80211B:
3092 case HOSTAPD_MODE_IEEE80211A:
3093 return mode->he_capab[ieee80211_mode].he_supported;
3094 default:
3095 return false;
3096 }
3097}
3098
3099
3100static bool ibss_mesh_can_use_eht(struct wpa_supplicant *wpa_s,
3101 const struct wpa_ssid *ssid,
3102 const struct hostapd_hw_modes *mode,
3103 int ieee80211_mode)
3104{
3105 if (ssid->disable_eht)
3106 return false;
3107
3108 switch(mode->mode) {
3109 case HOSTAPD_MODE_IEEE80211G:
3110 case HOSTAPD_MODE_IEEE80211B:
3111 case HOSTAPD_MODE_IEEE80211A:
3112 return mode->eht_capab[ieee80211_mode].eht_supported;
3113 default:
3114 return false;
3115 }
3116}
3117
3118
3119static void ibss_mesh_select_40mhz(struct wpa_supplicant *wpa_s,
3120 const struct wpa_ssid *ssid,
3121 struct hostapd_hw_modes *mode,
3122 struct hostapd_freq_params *freq,
3123 int obss_scan) {
3124 int chan_idx;
3125 struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
3126 int i, res;
3127 unsigned int j;
3128 static const int ht40plus[] = {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003129 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
3130 149, 157, 165, 173, 184, 192
Sunil Ravi036cec52023-03-29 11:35:17 -07003131 };
3132 int ht40 = -1;
3133
3134 if (!freq->ht_enabled)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003135 return;
3136
3137 for (chan_idx = 0; chan_idx < mode->num_channels; chan_idx++) {
3138 pri_chan = &mode->channels[chan_idx];
Sunil Ravi036cec52023-03-29 11:35:17 -07003139 if (pri_chan->chan == freq->channel)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003140 break;
3141 pri_chan = NULL;
3142 }
3143 if (!pri_chan)
3144 return;
3145
3146 /* Check primary channel flags */
3147 if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
3148 return;
3149
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003150#ifdef CONFIG_HT_OVERRIDES
Sunil Ravi036cec52023-03-29 11:35:17 -07003151 if (ssid->disable_ht40)
3152 return;
3153#endif
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003154
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003155 /* Check/setup HT40+/HT40- */
3156 for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
Sunil Ravi036cec52023-03-29 11:35:17 -07003157 if (ht40plus[j] == freq->channel) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003158 ht40 = 1;
3159 break;
3160 }
3161 }
3162
3163 /* Find secondary channel */
3164 for (i = 0; i < mode->num_channels; i++) {
3165 sec_chan = &mode->channels[i];
Sunil Ravi036cec52023-03-29 11:35:17 -07003166 if (sec_chan->chan == freq->channel + ht40 * 4)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003167 break;
3168 sec_chan = NULL;
3169 }
3170 if (!sec_chan)
3171 return;
3172
3173 /* Check secondary channel flags */
3174 if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
3175 return;
3176
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003177 if (ht40 == -1) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003178 if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
3179 return;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003180 } else {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003181 if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
3182 return;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003183 }
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003184 freq->sec_channel_offset = ht40;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003185
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003186 if (obss_scan) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003187 struct wpa_scan_results *scan_res;
3188
Sunil Ravi99c035e2024-07-12 01:42:03 +00003189 scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0,
3190 NULL);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003191 if (scan_res == NULL) {
3192 /* Back to HT20 */
3193 freq->sec_channel_offset = 0;
3194 return;
3195 }
3196
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003197 res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003198 switch (res) {
3199 case 0:
3200 /* Back to HT20 */
3201 freq->sec_channel_offset = 0;
3202 break;
3203 case 1:
3204 /* Configuration allowed */
3205 break;
3206 case 2:
3207 /* Switch pri/sec channels */
3208 freq->freq = hw_get_freq(mode, sec_chan->chan);
3209 freq->sec_channel_offset = -freq->sec_channel_offset;
3210 freq->channel = sec_chan->chan;
3211 break;
3212 default:
3213 freq->sec_channel_offset = 0;
3214 break;
3215 }
3216
3217 wpa_scan_results_free(scan_res);
3218 }
3219
3220 wpa_printf(MSG_DEBUG,
3221 "IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
3222 freq->channel, freq->sec_channel_offset);
Sunil Ravi036cec52023-03-29 11:35:17 -07003223}
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003224
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003225
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003226static int ibss_get_center_320mhz(int channel)
3227{
3228 int seg0;
3229
3230 if (channel >= 1 && channel <= 45)
3231 seg0 = 31;
3232 else if (channel >= 49 && channel <= 77)
3233 seg0 = 63;
3234 else if (channel >= 81 && channel <= 109)
3235 seg0 = 95;
3236 else if (channel >= 113 && channel <= 141)
3237 seg0 = 127;
3238 else if (channel >= 145 && channel <= 173)
3239 seg0 = 159;
3240 else
3241 seg0 = 191;
3242
3243 return seg0;
3244}
3245
3246
Sunil Ravi036cec52023-03-29 11:35:17 -07003247static bool ibss_mesh_select_80_160mhz(struct wpa_supplicant *wpa_s,
3248 const struct wpa_ssid *ssid,
3249 struct hostapd_hw_modes *mode,
3250 struct hostapd_freq_params *freq,
3251 int ieee80211_mode, bool is_6ghz) {
3252 static const int bw80[] = {
3253 5180, 5260, 5500, 5580, 5660, 5745, 5825,
3254 5955, 6035, 6115, 6195, 6275, 6355, 6435,
3255 6515, 6595, 6675, 6755, 6835, 6915, 6995
3256 };
3257 static const int bw160[] = {
3258 5955, 6115, 6275, 6435, 6595, 6755, 6915
3259 };
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003260 static const int bw320[]= {
3261 5955, 6255, 6115, 6415, 6275, 6575, 6435,
3262 6735, 6595, 6895, 6755, 7055
3263 };
3264
Sunil Ravi036cec52023-03-29 11:35:17 -07003265 struct hostapd_freq_params vht_freq;
3266 int i;
3267 unsigned int j, k;
3268 int chwidth, seg0, seg1;
3269 u32 vht_caps = 0;
3270 u8 channel = freq->channel;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003271
Sunil Ravi036cec52023-03-29 11:35:17 -07003272 if (!freq->vht_enabled && !freq->he_enabled)
3273 return true;
Paul Stewart092955c2017-02-06 09:13:09 -08003274
Hai Shalomc1a21442022-02-04 13:43:00 -08003275 vht_freq = *freq;
3276
Sunil Ravi036cec52023-03-29 11:35:17 -07003277 chwidth = CONF_OPER_CHWIDTH_USE_HT;
3278 seg0 = freq->channel + 2 * freq->sec_channel_offset;
3279 seg1 = 0;
3280 if (freq->sec_channel_offset == 0) {
3281 seg0 = 0;
3282 /* Don't try 80 MHz if 40 MHz failed, except in 6 GHz */
3283 if (freq->ht_enabled && !is_6ghz)
3284 goto skip_80mhz;
3285 }
3286 if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
3287 goto skip_80mhz;
Hai Shalomc3565922019-10-28 11:58:20 -07003288
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003289 /* setup center_freq1, bandwidth */
Hai Shalomc1a21442022-02-04 13:43:00 -08003290 for (j = 0; j < ARRAY_SIZE(bw80); j++) {
3291 if (freq->freq >= bw80[j] &&
3292 freq->freq < bw80[j] + 80)
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003293 break;
3294 }
3295
Hai Shalomc1a21442022-02-04 13:43:00 -08003296 if (j == ARRAY_SIZE(bw80) ||
3297 ieee80211_freq_to_chan(bw80[j], &channel) == NUM_HOSTAPD_MODES)
Sunil Ravi036cec52023-03-29 11:35:17 -07003298 goto skip_80mhz;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003299
Sunil Ravi036cec52023-03-29 11:35:17 -07003300 /* Use 40 MHz if channel not usable */
Hai Shalomc1a21442022-02-04 13:43:00 -08003301 if (!ibss_mesh_is_80mhz_avail(channel, mode))
Sunil Ravi036cec52023-03-29 11:35:17 -07003302 goto skip_80mhz;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003303
Sunil8cd6f4d2022-06-28 18:40:46 +00003304 chwidth = CONF_OPER_CHWIDTH_80MHZ;
Hai Shalomc1a21442022-02-04 13:43:00 -08003305 seg0 = channel + 6;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003306 seg1 = 0;
3307
Sunil Ravi036cec52023-03-29 11:35:17 -07003308 /* In 160 MHz, the initial four 20 MHz channels were validated
3309 * above. If 160 MHz is supported, check the remaining four 20 MHz
3310 * channels for the total of 160 MHz bandwidth for 6 GHz.
3311 */
Hai Shalomc1a21442022-02-04 13:43:00 -08003312 if ((mode->he_capab[ieee80211_mode].phy_cap[
3313 HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
Sunil Ravi036cec52023-03-29 11:35:17 -07003314 HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G) && is_6ghz &&
3315 ibss_mesh_is_80mhz_avail(channel + 16, mode)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08003316 for (j = 0; j < ARRAY_SIZE(bw160); j++) {
3317 if (freq->freq == bw160[j]) {
Sunil8cd6f4d2022-06-28 18:40:46 +00003318 chwidth = CONF_OPER_CHWIDTH_160MHZ;
Hai Shalomc1a21442022-02-04 13:43:00 -08003319 seg0 = channel + 14;
3320 break;
3321 }
3322 }
3323 }
3324
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003325 /* In 320 MHz, the initial four 20 MHz channels were validated
3326 * above. If 320 MHz is supported, check the remaining 12 20 MHz
3327 * channels for the total of 320 MHz bandwidth for 6 GHz.
3328 */
3329 if ((mode->eht_capab[ieee80211_mode].phy_cap[
3330 EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
3331 EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK) && is_6ghz &&
3332 ibss_mesh_is_80mhz_avail(channel + 16, mode) &&
3333 ibss_mesh_is_80mhz_avail(channel + 32, mode) &&
3334 ibss_mesh_is_80mhz_avail(channel + 48, mode)) {
3335 for (j = 0; j < ARRAY_SIZE(bw320); j += 2) {
3336 if (freq->freq >= bw320[j] &&
3337 freq->freq <= bw320[j + 1]) {
3338 chwidth = CONF_OPER_CHWIDTH_320MHZ;
3339 seg0 = ibss_get_center_320mhz(freq->channel);
3340 break;
3341 }
3342 }
3343 }
3344
Sunil8cd6f4d2022-06-28 18:40:46 +00003345 if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003346 /* setup center_freq2, bandwidth */
Hai Shalomc1a21442022-02-04 13:43:00 -08003347 for (k = 0; k < ARRAY_SIZE(bw80); k++) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003348 /* Only accept 80 MHz segments separated by a gap */
Hai Shalomc1a21442022-02-04 13:43:00 -08003349 if (j == k || abs(bw80[j] - bw80[k]) == 80)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003350 continue;
Hai Shalomc1a21442022-02-04 13:43:00 -08003351
3352 if (ieee80211_freq_to_chan(bw80[k], &channel) ==
3353 NUM_HOSTAPD_MODES)
Sunil Ravi036cec52023-03-29 11:35:17 -07003354 break;
Hai Shalomc1a21442022-02-04 13:43:00 -08003355
3356 for (i = channel; i < channel + 16; i += 4) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003357 struct hostapd_channel_data *chan;
3358
3359 chan = hw_get_channel_chan(mode, i, NULL);
3360 if (!chan)
3361 continue;
3362
3363 if (chan->flag & (HOSTAPD_CHAN_DISABLED |
3364 HOSTAPD_CHAN_NO_IR |
3365 HOSTAPD_CHAN_RADAR))
3366 continue;
3367
3368 /* Found a suitable second segment for 80+80 */
Sunil8cd6f4d2022-06-28 18:40:46 +00003369 chwidth = CONF_OPER_CHWIDTH_80P80MHZ;
Hai Shalomc1a21442022-02-04 13:43:00 -08003370 if (!is_6ghz)
3371 vht_caps |=
3372 VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
3373 seg1 = channel + 6;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003374 }
3375
Sunil8cd6f4d2022-06-28 18:40:46 +00003376 if (chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003377 break;
3378 }
Sunil8cd6f4d2022-06-28 18:40:46 +00003379 } else if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003380 if (freq->freq == 5180) {
Sunil8cd6f4d2022-06-28 18:40:46 +00003381 chwidth = CONF_OPER_CHWIDTH_160MHZ;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003382 vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
3383 seg0 = 50;
3384 } else if (freq->freq == 5520) {
Sunil8cd6f4d2022-06-28 18:40:46 +00003385 chwidth = CONF_OPER_CHWIDTH_160MHZ;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003386 vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
3387 seg0 = 114;
3388 }
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003389 }
3390
Sunil Ravi036cec52023-03-29 11:35:17 -07003391skip_80mhz:
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003392 if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
Hai Shalomc3565922019-10-28 11:58:20 -07003393 freq->channel, ssid->enable_edmg,
3394 ssid->edmg_channel, freq->ht_enabled,
Sunil Ravi036cec52023-03-29 11:35:17 -07003395 freq->vht_enabled, freq->he_enabled,
3396 freq->eht_enabled,
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003397 freq->sec_channel_offset,
Hai Shalom81f62d82019-07-22 12:10:00 -07003398 chwidth, seg0, seg1, vht_caps,
Sunil Ravia04bd252022-05-02 22:54:18 -07003399 &mode->he_capab[ieee80211_mode],
Sunil Ravi99c035e2024-07-12 01:42:03 +00003400 &mode->eht_capab[ieee80211_mode], 0) != 0)
Sunil Ravi036cec52023-03-29 11:35:17 -07003401 return false;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003402
3403 *freq = vht_freq;
3404
3405 wpa_printf(MSG_DEBUG, "IBSS: VHT setup freq cf1 %d, cf2 %d, bw %d",
3406 freq->center_freq1, freq->center_freq2, freq->bandwidth);
Sunil Ravi036cec52023-03-29 11:35:17 -07003407 return true;
3408}
3409
3410
3411void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
3412 const struct wpa_ssid *ssid,
3413 struct hostapd_freq_params *freq)
3414{
3415 int ieee80211_mode = wpas_mode_to_ieee80211_mode(ssid->mode);
3416 enum hostapd_hw_mode hw_mode;
3417 struct hostapd_hw_modes *mode = NULL;
Sunil Ravi7f769292024-07-23 22:21:32 +00003418 int obss_scan = 1;
Sunil Ravi036cec52023-03-29 11:35:17 -07003419 u8 channel;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003420 bool is_6ghz, is_24ghz;
Sunil Ravi036cec52023-03-29 11:35:17 -07003421
3422 freq->freq = ssid->frequency;
3423
3424 if (ssid->mode == WPAS_MODE_IBSS && !ssid->fixed_freq) {
3425 struct wpa_bss *bss = ibss_find_existing_bss(wpa_s, ssid);
3426
3427 if (bss) {
3428 wpa_printf(MSG_DEBUG,
3429 "IBSS already found in scan results, adjust control freq: %d",
3430 bss->freq);
3431 freq->freq = bss->freq;
3432 obss_scan = 0;
3433 }
3434 }
3435
3436 hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
Sunil Ravi7f769292024-07-23 22:21:32 +00003437 mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
3438 hw_mode, is_6ghz_freq(ssid->frequency));
Sunil Ravi036cec52023-03-29 11:35:17 -07003439
3440 if (!mode)
3441 return;
3442
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003443 is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
3444 hw_mode == HOSTAPD_MODE_IEEE80211B;
3445
Sunil Ravi036cec52023-03-29 11:35:17 -07003446 is_6ghz = is_6ghz_freq(freq->freq);
3447
3448 freq->ht_enabled = 0;
3449 freq->vht_enabled = 0;
3450 freq->he_enabled = 0;
3451 freq->eht_enabled = 0;
3452
3453 if (!is_6ghz)
3454 freq->ht_enabled = ibss_mesh_can_use_ht(wpa_s, ssid, mode);
3455 if (freq->ht_enabled)
3456 freq->vht_enabled = ibss_mesh_can_use_vht(wpa_s, ssid, mode);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003457 if (freq->vht_enabled || (freq->ht_enabled && is_24ghz) || is_6ghz)
Sunil Ravi036cec52023-03-29 11:35:17 -07003458 freq->he_enabled = ibss_mesh_can_use_he(wpa_s, ssid, mode,
3459 ieee80211_mode);
3460 freq->channel = channel;
3461 /* Setup higher BW only for 5 GHz */
3462 if (mode->mode == HOSTAPD_MODE_IEEE80211A) {
3463 ibss_mesh_select_40mhz(wpa_s, ssid, mode, freq, obss_scan);
3464 if (!ibss_mesh_select_80_160mhz(wpa_s, ssid, mode, freq,
3465 ieee80211_mode, is_6ghz))
3466 freq->he_enabled = freq->vht_enabled = false;
3467 }
3468
3469 if (freq->he_enabled)
3470 freq->eht_enabled = ibss_mesh_can_use_eht(wpa_s, ssid, mode,
3471 ieee80211_mode);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003472}
3473
3474
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003475#ifdef CONFIG_FILS
3476static size_t wpas_add_fils_hlp_req(struct wpa_supplicant *wpa_s, u8 *ie_buf,
3477 size_t ie_buf_len)
3478{
3479 struct fils_hlp_req *req;
3480 size_t rem_len, hdr_len, hlp_len, len, ie_len = 0;
3481 const u8 *pos;
3482 u8 *buf = ie_buf;
3483
3484 dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
3485 list) {
3486 rem_len = ie_buf_len - ie_len;
3487 pos = wpabuf_head(req->pkt);
3488 hdr_len = 1 + 2 * ETH_ALEN + 6;
3489 hlp_len = wpabuf_len(req->pkt);
3490
3491 if (rem_len < 2 + hdr_len + hlp_len) {
3492 wpa_printf(MSG_ERROR,
3493 "FILS: Cannot fit HLP - rem_len=%lu to_fill=%lu",
3494 (unsigned long) rem_len,
3495 (unsigned long) (2 + hdr_len + hlp_len));
3496 break;
3497 }
3498
3499 len = (hdr_len + hlp_len) > 255 ? 255 : hdr_len + hlp_len;
3500 /* Element ID */
3501 *buf++ = WLAN_EID_EXTENSION;
3502 /* Length */
3503 *buf++ = len;
3504 /* Element ID Extension */
3505 *buf++ = WLAN_EID_EXT_FILS_HLP_CONTAINER;
3506 /* Destination MAC address */
3507 os_memcpy(buf, req->dst, ETH_ALEN);
3508 buf += ETH_ALEN;
3509 /* Source MAC address */
3510 os_memcpy(buf, wpa_s->own_addr, ETH_ALEN);
3511 buf += ETH_ALEN;
3512 /* LLC/SNAP Header */
3513 os_memcpy(buf, "\xaa\xaa\x03\x00\x00\x00", 6);
3514 buf += 6;
3515 /* HLP Packet */
3516 os_memcpy(buf, pos, len - hdr_len);
3517 buf += len - hdr_len;
3518 pos += len - hdr_len;
3519
3520 hlp_len -= len - hdr_len;
3521 ie_len += 2 + len;
3522 rem_len -= 2 + len;
3523
3524 while (hlp_len) {
3525 len = (hlp_len > 255) ? 255 : hlp_len;
3526 if (rem_len < 2 + len)
3527 break;
3528 *buf++ = WLAN_EID_FRAGMENT;
3529 *buf++ = len;
3530 os_memcpy(buf, pos, len);
3531 buf += len;
3532 pos += len;
3533
3534 hlp_len -= len;
3535 ie_len += 2 + len;
3536 rem_len -= 2 + len;
3537 }
3538 }
3539
3540 return ie_len;
3541}
Roshan Pius3a1667e2018-07-03 15:17:14 -07003542
3543
3544int wpa_is_fils_supported(struct wpa_supplicant *wpa_s)
3545{
3546 return (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
3547 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) ||
3548 (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
3549 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)));
3550}
3551
3552
3553int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s)
3554{
3555#ifdef CONFIG_FILS_SK_PFS
3556 return (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
3557 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS);
3558#else /* CONFIG_FILS_SK_PFS */
3559 return 0;
3560#endif /* CONFIG_FILS_SK_PFS */
3561}
3562
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003563#endif /* CONFIG_FILS */
3564
3565
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003566bool wpa_is_non_eht_scs_traffic_desc_supported(struct wpa_bss *bss)
3567{
3568 const u8 *wfa_capa;
3569
3570 if (!bss)
3571 return false;
3572
3573 /* Get WFA capability from Beacon or Probe Response frame elements */
3574 wfa_capa = wpa_bss_get_vendor_ie(bss, WFA_CAPA_IE_VENDOR_TYPE);
3575 if (!wfa_capa)
3576 wfa_capa = wpa_bss_get_vendor_ie_beacon(
3577 bss, WFA_CAPA_IE_VENDOR_TYPE);
3578
3579 if (!wfa_capa || wfa_capa[1] < 6 || wfa_capa[6] < 1 ||
3580 !(wfa_capa[7] & WFA_CAPA_QM_NON_EHT_SCS_TRAFFIC_DESC)) {
3581 /* AP does not enable QM non EHT traffic description policy */
3582 return false;
3583 }
3584
3585 return true;
3586}
3587
3588
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003589int wpas_populate_wfa_capa(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
3590 u8 *wpa_ie, size_t wpa_ie_len, size_t max_wpa_ie_len)
Hai Shalomc1a21442022-02-04 13:43:00 -08003591{
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003592 struct wpabuf *wfa_ie = NULL, *attr = NULL;
Hai Shalomc1a21442022-02-04 13:43:00 -08003593 u8 wfa_capa[1];
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003594 u8 capab_len = 0;
Hai Shalomc1a21442022-02-04 13:43:00 -08003595 size_t wfa_ie_len, buf_len;
3596
3597 os_memset(wfa_capa, 0, sizeof(wfa_capa));
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003598#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08003599 if (wpa_s->enable_dscp_policy_capa)
3600 wfa_capa[0] |= WFA_CAPA_QM_DSCP_POLICY;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003601#endif /* CONFIG_NO_ROBUST_AV */
Hai Shalomc1a21442022-02-04 13:43:00 -08003602
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003603 if (wpa_is_non_eht_scs_traffic_desc_supported(bss))
3604 wfa_capa[0] |= WFA_CAPA_QM_NON_EHT_SCS_TRAFFIC_DESC;
3605
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003606 if (wfa_capa[0])
3607 capab_len = 1;
3608
3609 if (wpa_s->conf->wfa_gen_capa == WFA_GEN_CAPA_UNPROTECTED)
3610 attr = wpas_wfa_gen_capab_attr(wpa_s);
3611
3612 if (capab_len == 0 && !attr)
Hai Shalomc1a21442022-02-04 13:43:00 -08003613 return wpa_ie_len;
3614
3615 /* Wi-Fi Alliance element */
3616 buf_len = 1 + /* Element ID */
3617 1 + /* Length */
3618 3 + /* OUI */
3619 1 + /* OUI Type */
3620 1 + /* Capabilities Length */
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003621 capab_len + /* Capabilities */
3622 (attr ? wpabuf_len(attr) : 0) /* Attributes */;
Hai Shalomc1a21442022-02-04 13:43:00 -08003623 wfa_ie = wpabuf_alloc(buf_len);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003624 if (!wfa_ie) {
3625 wpabuf_free(attr);
Hai Shalomc1a21442022-02-04 13:43:00 -08003626 return wpa_ie_len;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003627 }
Hai Shalomc1a21442022-02-04 13:43:00 -08003628
3629 wpabuf_put_u8(wfa_ie, WLAN_EID_VENDOR_SPECIFIC);
3630 wpabuf_put_u8(wfa_ie, buf_len - 2);
3631 wpabuf_put_be24(wfa_ie, OUI_WFA);
3632 wpabuf_put_u8(wfa_ie, WFA_CAPA_OUI_TYPE);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003633 wpabuf_put_u8(wfa_ie, capab_len);
3634 wpabuf_put_data(wfa_ie, wfa_capa, capab_len);
3635 if (attr)
3636 wpabuf_put_buf(wfa_ie, attr);
3637 wpabuf_free(attr);
Hai Shalomc1a21442022-02-04 13:43:00 -08003638
3639 wfa_ie_len = wpabuf_len(wfa_ie);
3640 if (wpa_ie_len + wfa_ie_len <= max_wpa_ie_len) {
3641 wpa_hexdump_buf(MSG_MSGDUMP, "WFA Capabilities element",
3642 wfa_ie);
3643 os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(wfa_ie),
3644 wfa_ie_len);
3645 wpa_ie_len += wfa_ie_len;
3646 }
3647
3648 wpabuf_free(wfa_ie);
3649 return wpa_ie_len;
3650}
3651
3652
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003653static u8 * wpas_populate_assoc_ies(
3654 struct wpa_supplicant *wpa_s,
3655 struct wpa_bss *bss, struct wpa_ssid *ssid,
3656 struct wpa_driver_associate_params *params,
3657 enum wpa_drv_update_connect_params_mask *mask)
3658{
3659 u8 *wpa_ie;
3660 size_t max_wpa_ie_len = 500;
3661 size_t wpa_ie_len;
3662 int algs = WPA_AUTH_ALG_OPEN;
Hai Shalomce48b4a2018-09-05 11:41:35 -07003663#ifdef CONFIG_MBO
3664 const u8 *mbo_ie;
3665#endif
Vinita S. Maloofb3a4442020-05-19 17:43:22 +05303666#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
3667 int pmksa_cached = 0;
3668#endif /* CONFIG_SAE || CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003669#ifdef CONFIG_FILS
3670 const u8 *realm, *username, *rrk;
3671 size_t realm_len, username_len, rrk_len;
3672 u16 next_seq_num;
3673 struct fils_hlp_req *req;
3674
3675 dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
3676 list) {
3677 max_wpa_ie_len += 3 + 2 * ETH_ALEN + 6 + wpabuf_len(req->pkt) +
3678 2 + 2 * wpabuf_len(req->pkt) / 255;
3679 }
3680#endif /* CONFIG_FILS */
3681
3682 wpa_ie = os_malloc(max_wpa_ie_len);
3683 if (!wpa_ie) {
3684 wpa_printf(MSG_ERROR,
3685 "Failed to allocate connect IE buffer for %lu bytes",
3686 (unsigned long) max_wpa_ie_len);
3687 return NULL;
3688 }
3689
3690 if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
Sunil Ravi7f769292024-07-23 22:21:32 +00003691 wpa_bss_get_rsne(wpa_s, bss, ssid, false)) &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003692 wpa_key_mgmt_wpa(ssid->key_mgmt)) {
3693 int try_opportunistic;
3694 const u8 *cache_id = NULL;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003695 const u8 *addr = bss->bssid;
3696
Sunil Ravi036cec52023-03-29 11:35:17 -07003697 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
3698 (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) &&
3699 !is_zero_ether_addr(bss->mld_addr))
3700 addr = bss->mld_addr;
3701
3702 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
3703 wpa_s->valid_links)
Sunil Ravi77d572f2023-01-17 23:58:31 +00003704 addr = wpa_s->ap_mld_addr;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003705
3706 try_opportunistic = (ssid->proactive_key_caching < 0 ?
3707 wpa_s->conf->okc :
3708 ssid->proactive_key_caching) &&
3709 (ssid->proto & WPA_PROTO_RSN);
3710#ifdef CONFIG_FILS
3711 if (wpa_key_mgmt_fils(ssid->key_mgmt))
3712 cache_id = wpa_bss_get_fils_cache_id(bss);
3713#endif /* CONFIG_FILS */
Sunil Ravi77d572f2023-01-17 23:58:31 +00003714 if (pmksa_cache_set_current(wpa_s->wpa, NULL, addr,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003715 ssid, try_opportunistic,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003716 cache_id, 0, false) == 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003717 eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
Vinita S. Maloofb3a4442020-05-19 17:43:22 +05303718#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
3719 pmksa_cached = 1;
3720#endif /* CONFIG_SAE || CONFIG_FILS */
Hai Shalom5f92bc92019-04-18 11:54:11 -07003721 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003722 wpa_ie_len = max_wpa_ie_len;
3723 if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
Sunil Ravi77d572f2023-01-17 23:58:31 +00003724 wpa_ie, &wpa_ie_len, false)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003725 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
3726 "key management and encryption suites");
3727 os_free(wpa_ie);
3728 return NULL;
3729 }
Hai Shalom74f70d42019-02-11 14:42:39 -08003730#ifdef CONFIG_HS20
3731 } else if (bss && wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) &&
3732 (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) {
3733 /* No PMKSA caching, but otherwise similar to RSN/WPA */
3734 wpa_ie_len = max_wpa_ie_len;
3735 if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
Sunil Ravi77d572f2023-01-17 23:58:31 +00003736 wpa_ie, &wpa_ie_len, false)) {
Hai Shalom74f70d42019-02-11 14:42:39 -08003737 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
3738 "key management and encryption suites");
3739 os_free(wpa_ie);
3740 return NULL;
3741 }
3742#endif /* CONFIG_HS20 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003743 } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
3744 wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
3745 /*
3746 * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
3747 * use non-WPA since the scan results did not indicate that the
3748 * AP is using WPA or WPA2.
3749 */
3750 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
3751 wpa_ie_len = 0;
3752 wpa_s->wpa_proto = 0;
3753 } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
3754 wpa_ie_len = max_wpa_ie_len;
3755 if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
Sunil Ravi77d572f2023-01-17 23:58:31 +00003756 wpa_ie, &wpa_ie_len, false)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003757 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
3758 "key management and encryption suites (no "
3759 "scan results)");
3760 os_free(wpa_ie);
3761 return NULL;
3762 }
3763#ifdef CONFIG_WPS
3764 } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
3765 struct wpabuf *wps_ie;
3766 wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
3767 if (wps_ie && wpabuf_len(wps_ie) <= max_wpa_ie_len) {
3768 wpa_ie_len = wpabuf_len(wps_ie);
3769 os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
3770 } else
3771 wpa_ie_len = 0;
3772 wpabuf_free(wps_ie);
3773 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
3774 if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY))
3775 params->wps = WPS_MODE_PRIVACY;
3776 else
3777 params->wps = WPS_MODE_OPEN;
3778 wpa_s->wpa_proto = 0;
3779#endif /* CONFIG_WPS */
3780 } else {
3781 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
3782 wpa_ie_len = 0;
3783 wpa_s->wpa_proto = 0;
3784 }
3785
3786#ifdef IEEE8021X_EAPOL
3787 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
3788 if (ssid->leap) {
3789 if (ssid->non_leap == 0)
3790 algs = WPA_AUTH_ALG_LEAP;
3791 else
3792 algs |= WPA_AUTH_ALG_LEAP;
3793 }
3794 }
3795
3796#ifdef CONFIG_FILS
3797 /* Clear FILS association */
3798 wpa_sm_set_reset_fils_completed(wpa_s->wpa, 0);
3799
3800 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
3801 ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
3802 eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, &username,
3803 &username_len, &realm, &realm_len,
Hai Shalomce48b4a2018-09-05 11:41:35 -07003804 &next_seq_num, &rrk, &rrk_len) == 0 &&
3805 (!wpa_s->last_con_fail_realm ||
3806 wpa_s->last_con_fail_realm_len != realm_len ||
3807 os_memcmp(wpa_s->last_con_fail_realm, realm, realm_len) != 0)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003808 algs = WPA_AUTH_ALG_FILS;
3809 params->fils_erp_username = username;
3810 params->fils_erp_username_len = username_len;
3811 params->fils_erp_realm = realm;
3812 params->fils_erp_realm_len = realm_len;
3813 params->fils_erp_next_seq_num = next_seq_num;
3814 params->fils_erp_rrk = rrk;
3815 params->fils_erp_rrk_len = rrk_len;
3816
3817 if (mask)
3818 *mask |= WPA_DRV_UPDATE_FILS_ERP_INFO;
Vinita S. Maloofb3a4442020-05-19 17:43:22 +05303819 } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
3820 ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
3821 pmksa_cached) {
3822 algs = WPA_AUTH_ALG_FILS;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003823 }
3824#endif /* CONFIG_FILS */
3825#endif /* IEEE8021X_EAPOL */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003826#ifdef CONFIG_SAE
Sunil Ravi89eba102022-09-13 21:04:37 -07003827 if (wpa_key_mgmt_sae(wpa_s->key_mgmt))
Roshan Pius3a1667e2018-07-03 15:17:14 -07003828 algs = WPA_AUTH_ALG_SAE;
3829#endif /* CONFIG_SAE */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003830
3831 wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
3832 if (ssid->auth_alg) {
3833 algs = ssid->auth_alg;
3834 wpa_dbg(wpa_s, MSG_DEBUG,
3835 "Overriding auth_alg selection: 0x%x", algs);
3836 }
3837
Hai Shalom5f92bc92019-04-18 11:54:11 -07003838#ifdef CONFIG_SAE
Vinita S. Maloofb3a4442020-05-19 17:43:22 +05303839 if (pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
Hai Shalom5f92bc92019-04-18 11:54:11 -07003840 wpa_dbg(wpa_s, MSG_DEBUG,
3841 "SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt");
3842 algs = WPA_AUTH_ALG_OPEN;
3843 }
3844#endif /* CONFIG_SAE */
3845
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003846#ifdef CONFIG_P2P
3847 if (wpa_s->global->p2p) {
3848 u8 *pos;
3849 size_t len;
3850 int res;
3851 pos = wpa_ie + wpa_ie_len;
3852 len = max_wpa_ie_len - wpa_ie_len;
3853 res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
3854 ssid->p2p_group);
3855 if (res >= 0)
3856 wpa_ie_len += res;
3857 }
3858
3859 wpa_s->cross_connect_disallowed = 0;
3860 if (bss) {
3861 struct wpabuf *p2p;
3862 p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
3863 if (p2p) {
3864 wpa_s->cross_connect_disallowed =
3865 p2p_get_cross_connect_disallowed(p2p);
3866 wpabuf_free(p2p);
3867 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: WLAN AP %s cross "
3868 "connection",
3869 wpa_s->cross_connect_disallowed ?
3870 "disallows" : "allows");
3871 }
3872 }
3873
3874 os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
3875#endif /* CONFIG_P2P */
3876
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003877#ifndef CONFIG_NO_RRM
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003878 if (bss) {
Hai Shalomfdcde762020-04-02 11:19:20 -07003879 wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003880 wpa_ie + wpa_ie_len,
3881 max_wpa_ie_len -
3882 wpa_ie_len);
3883 }
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003884#endif /* CONFIG_NO_RRM */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003885
3886 /*
3887 * Workaround: Add Extended Capabilities element only if the AP
3888 * included this element in Beacon/Probe Response frames. Some older
3889 * APs seem to have interoperability issues if this element is
3890 * included, so while the standard may require us to include the
3891 * element in all cases, it is justifiable to skip it to avoid
3892 * interoperability issues.
3893 */
3894 if (ssid->p2p_group)
3895 wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
3896 else
3897 wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
3898
3899 if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
3900 u8 ext_capab[18];
3901 int ext_capab_len;
3902 ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003903 sizeof(ext_capab), bss);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003904 if (ext_capab_len > 0 &&
3905 wpa_ie_len + ext_capab_len <= max_wpa_ie_len) {
3906 u8 *pos = wpa_ie;
3907 if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
3908 pos += 2 + pos[1];
3909 os_memmove(pos + ext_capab_len, pos,
3910 wpa_ie_len - (pos - wpa_ie));
3911 wpa_ie_len += ext_capab_len;
3912 os_memcpy(pos, ext_capab, ext_capab_len);
3913 }
3914 }
3915
Sunil Ravi7f769292024-07-23 22:21:32 +00003916 if (ssid->max_idle && wpa_ie_len + 5 <= max_wpa_ie_len) {
3917 u8 *pos = wpa_ie;
3918
3919 *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
3920 *pos++ = 3;
3921 WPA_PUT_LE16(pos, ssid->max_idle);
3922 pos += 2;
3923 *pos = 0; /* Idle Options */
3924 wpa_ie_len += 5;
3925 }
3926
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003927#ifdef CONFIG_HS20
Hai Shalomcded4e22022-01-28 15:29:52 -08003928 if (is_hs20_network(wpa_s, ssid, bss)
3929#ifndef ANDROID /* Android does not use the native HS 2.0 config */
3930 && is_hs20_config(wpa_s)
3931#endif /* ANDROID */
3932 ) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003933 struct wpabuf *hs20;
3934
Roshan Pius3a1667e2018-07-03 15:17:14 -07003935 hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003936 if (hs20) {
3937 int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
3938 size_t len;
3939
Hai Shalom74f70d42019-02-11 14:42:39 -08003940 wpas_hs20_add_indication(hs20, pps_mo_id,
3941 get_hs20_version(bss));
Roshan Pius3a1667e2018-07-03 15:17:14 -07003942 wpas_hs20_add_roam_cons_sel(hs20, ssid);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003943 len = max_wpa_ie_len - wpa_ie_len;
3944 if (wpabuf_len(hs20) <= len) {
3945 os_memcpy(wpa_ie + wpa_ie_len,
3946 wpabuf_head(hs20), wpabuf_len(hs20));
3947 wpa_ie_len += wpabuf_len(hs20);
3948 }
3949 wpabuf_free(hs20);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003950 }
3951 }
Hai Shalom2cbbcd12021-03-08 18:33:38 -08003952 hs20_configure_frame_filters(wpa_s);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003953#endif /* CONFIG_HS20 */
3954
3955 if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
3956 struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
3957 size_t len;
3958
3959 len = max_wpa_ie_len - wpa_ie_len;
3960 if (wpabuf_len(buf) <= len) {
3961 os_memcpy(wpa_ie + wpa_ie_len,
3962 wpabuf_head(buf), wpabuf_len(buf));
3963 wpa_ie_len += wpabuf_len(buf);
3964 }
3965 }
3966
3967#ifdef CONFIG_FST
3968 if (wpa_s->fst_ies) {
3969 int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
3970
3971 if (wpa_ie_len + fst_ies_len <= max_wpa_ie_len) {
3972 os_memcpy(wpa_ie + wpa_ie_len,
3973 wpabuf_head(wpa_s->fst_ies), fst_ies_len);
3974 wpa_ie_len += fst_ies_len;
3975 }
3976 }
3977#endif /* CONFIG_FST */
3978
3979#ifdef CONFIG_MBO
Hai Shalomce48b4a2018-09-05 11:41:35 -07003980 mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
Hai Shalomc3565922019-10-28 11:58:20 -07003981 if (!wpa_s->disable_mbo_oce && mbo_ie) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003982 int len;
3983
3984 len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
Hai Shalomce48b4a2018-09-05 11:41:35 -07003985 max_wpa_ie_len - wpa_ie_len,
3986 !!mbo_attr_from_mbo_ie(mbo_ie,
3987 OCE_ATTR_ID_CAPA_IND));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003988 if (len >= 0)
3989 wpa_ie_len += len;
3990 }
3991#endif /* CONFIG_MBO */
3992
3993#ifdef CONFIG_FILS
3994 if (algs == WPA_AUTH_ALG_FILS) {
3995 size_t len;
3996
3997 len = wpas_add_fils_hlp_req(wpa_s, wpa_ie + wpa_ie_len,
3998 max_wpa_ie_len - wpa_ie_len);
3999 wpa_ie_len += len;
4000 }
4001#endif /* CONFIG_FILS */
4002
4003#ifdef CONFIG_OWE
Roshan Pius3a1667e2018-07-03 15:17:14 -07004004#ifdef CONFIG_TESTING_OPTIONS
4005 if (get_ie_ext(wpa_ie, wpa_ie_len, WLAN_EID_EXT_OWE_DH_PARAM)) {
4006 wpa_printf(MSG_INFO, "TESTING: Override OWE DH element");
4007 } else
4008#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004009 if (algs == WPA_AUTH_ALG_OPEN &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004010 ssid->key_mgmt == WPA_KEY_MGMT_OWE &&
4011 !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OWE_OFFLOAD_STA)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004012 struct wpabuf *owe_ie;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004013 u16 group;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004014
Roshan Pius3a1667e2018-07-03 15:17:14 -07004015 if (ssid->owe_group) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004016 group = ssid->owe_group;
Hai Shalom74f70d42019-02-11 14:42:39 -08004017 } else if (wpa_s->assoc_status_code ==
4018 WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004019 if (wpa_s->last_owe_group == 19)
4020 group = 20;
4021 else if (wpa_s->last_owe_group == 20)
4022 group = 21;
4023 else
4024 group = OWE_DH_GROUP;
Hai Shalom74f70d42019-02-11 14:42:39 -08004025 } else {
4026 group = OWE_DH_GROUP;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004027 }
Hai Shalom74f70d42019-02-11 14:42:39 -08004028
Roshan Pius3a1667e2018-07-03 15:17:14 -07004029 wpa_s->last_owe_group = group;
4030 wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004031 owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
4032 if (owe_ie &&
4033 wpabuf_len(owe_ie) <= max_wpa_ie_len - wpa_ie_len) {
4034 os_memcpy(wpa_ie + wpa_ie_len,
4035 wpabuf_head(owe_ie), wpabuf_len(owe_ie));
4036 wpa_ie_len += wpabuf_len(owe_ie);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004037 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004038 wpabuf_free(owe_ie);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004039 }
4040#endif /* CONFIG_OWE */
4041
Hai Shalom021b0b52019-04-10 11:17:58 -07004042#ifdef CONFIG_DPP2
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004043 if (DPP_VERSION > 1 &&
4044 wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
Hai Shalomfdcde762020-04-02 11:19:20 -07004045 ssid->dpp_netaccesskey &&
4046 ssid->dpp_pfs != 2 && !ssid->dpp_pfs_fallback) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004047 struct rsn_pmksa_cache_entry *pmksa;
4048
4049 pmksa = pmksa_cache_get_current(wpa_s->wpa);
4050 if (!pmksa || !pmksa->dpp_pfs)
4051 goto pfs_fail;
4052
Hai Shalom021b0b52019-04-10 11:17:58 -07004053 dpp_pfs_free(wpa_s->dpp_pfs);
4054 wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
4055 ssid->dpp_netaccesskey_len);
4056 if (!wpa_s->dpp_pfs) {
4057 wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS");
4058 /* Try to continue without PFS */
4059 goto pfs_fail;
4060 }
4061 if (wpabuf_len(wpa_s->dpp_pfs->ie) <=
4062 max_wpa_ie_len - wpa_ie_len) {
4063 os_memcpy(wpa_ie + wpa_ie_len,
4064 wpabuf_head(wpa_s->dpp_pfs->ie),
4065 wpabuf_len(wpa_s->dpp_pfs->ie));
4066 wpa_ie_len += wpabuf_len(wpa_s->dpp_pfs->ie);
4067 }
4068 }
4069pfs_fail:
4070#endif /* CONFIG_DPP2 */
4071
Roshan Pius3a1667e2018-07-03 15:17:14 -07004072#ifdef CONFIG_IEEE80211R
4073 /*
4074 * Add MDIE under these conditions: the network profile allows FT,
4075 * the AP supports FT, and the mobility domain ID matches.
4076 */
4077 if (bss && wpa_key_mgmt_ft(wpa_sm_get_key_mgmt(wpa_s->wpa))) {
4078 const u8 *mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
4079
4080 if (mdie && mdie[1] >= MOBILITY_DOMAIN_ID_LEN) {
4081 size_t len = 0;
4082 const u8 *md = mdie + 2;
4083 const u8 *wpa_md = wpa_sm_get_ft_md(wpa_s->wpa);
4084
4085 if (os_memcmp(md, wpa_md,
4086 MOBILITY_DOMAIN_ID_LEN) == 0) {
4087 /* Add mobility domain IE */
4088 len = wpa_ft_add_mdie(
4089 wpa_s->wpa, wpa_ie + wpa_ie_len,
4090 max_wpa_ie_len - wpa_ie_len, mdie);
4091 wpa_ie_len += len;
4092 }
4093#ifdef CONFIG_SME
4094 if (len > 0 && wpa_s->sme.ft_used &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00004095 wpa_sm_has_ft_keys(wpa_s->wpa, md)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004096 wpa_dbg(wpa_s, MSG_DEBUG,
4097 "SME: Trying to use FT over-the-air");
4098 algs |= WPA_AUTH_ALG_FT;
4099 }
4100#endif /* CONFIG_SME */
4101 }
4102 }
4103#endif /* CONFIG_IEEE80211R */
4104
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004105#ifdef CONFIG_TESTING_OPTIONS
4106 if (wpa_s->rsnxe_override_assoc &&
4107 wpabuf_len(wpa_s->rsnxe_override_assoc) <=
4108 max_wpa_ie_len - wpa_ie_len) {
4109 wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
4110 os_memcpy(wpa_ie + wpa_ie_len,
4111 wpabuf_head(wpa_s->rsnxe_override_assoc),
4112 wpabuf_len(wpa_s->rsnxe_override_assoc));
4113 wpa_ie_len += wpabuf_len(wpa_s->rsnxe_override_assoc);
4114 } else
4115#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomc3565922019-10-28 11:58:20 -07004116 if (wpa_s->rsnxe_len > 0 &&
4117 wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
4118 os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
4119 wpa_ie_len += wpa_s->rsnxe_len;
4120 }
4121
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004122#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08004123#ifdef CONFIG_TESTING_OPTIONS
4124 if (wpa_s->disable_mscs_support)
4125 goto mscs_end;
4126#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalom60840252021-02-19 19:02:11 -08004127 if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS) &&
4128 wpa_s->robust_av.valid_config) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004129 struct wpabuf *mscs_ie;
4130 size_t mscs_ie_len, buf_len;
4131
Hai Shalom899fcc72020-10-19 14:38:18 -07004132 buf_len = 3 + /* MSCS descriptor IE header */
4133 1 + /* Request type */
4134 2 + /* User priority control */
4135 4 + /* Stream timeout */
4136 3 + /* TCLAS Mask IE header */
4137 wpa_s->robust_av.frame_classifier_len;
4138 mscs_ie = wpabuf_alloc(buf_len);
4139 if (!mscs_ie) {
4140 wpa_printf(MSG_INFO,
4141 "MSCS: Failed to allocate MSCS IE");
Hai Shalomc1a21442022-02-04 13:43:00 -08004142 goto mscs_end;
Hai Shalom899fcc72020-10-19 14:38:18 -07004143 }
4144
4145 wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
4146 if ((wpa_ie_len + wpabuf_len(mscs_ie)) <= max_wpa_ie_len) {
4147 wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE", mscs_ie);
4148 mscs_ie_len = wpabuf_len(mscs_ie);
4149 os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(mscs_ie),
4150 mscs_ie_len);
4151 wpa_ie_len += mscs_ie_len;
4152 }
4153
4154 wpabuf_free(mscs_ie);
4155 }
Hai Shalomc1a21442022-02-04 13:43:00 -08004156mscs_end:
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004157#endif /* CONFIG_NO_ROBUST_AV */
Hai Shalomc1a21442022-02-04 13:43:00 -08004158
4159 wpa_ie_len = wpas_populate_wfa_capa(wpa_s, bss, wpa_ie, wpa_ie_len,
4160 max_wpa_ie_len);
Hai Shalom899fcc72020-10-19 14:38:18 -07004161
Hai Shalom74f70d42019-02-11 14:42:39 -08004162 if (ssid->multi_ap_backhaul_sta) {
4163 size_t multi_ap_ie_len;
Sunil Ravi99c035e2024-07-12 01:42:03 +00004164 struct multi_ap_params multi_ap = { 0 };
4165
4166 multi_ap.capability = MULTI_AP_BACKHAUL_STA;
4167 multi_ap.profile = ssid->multi_ap_profile;
Hai Shalom74f70d42019-02-11 14:42:39 -08004168
4169 multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len,
4170 max_wpa_ie_len - wpa_ie_len,
Sunil Ravi99c035e2024-07-12 01:42:03 +00004171 &multi_ap);
Hai Shalom74f70d42019-02-11 14:42:39 -08004172 if (multi_ap_ie_len == 0) {
4173 wpa_printf(MSG_ERROR,
4174 "Multi-AP: Failed to build Multi-AP IE");
4175 os_free(wpa_ie);
4176 return NULL;
4177 }
4178 wpa_ie_len += multi_ap_ie_len;
4179 }
4180
Sunil Ravic0f5d412024-09-11 22:12:49 +00004181 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE_SUPPORT,
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00004182 wpas_rsn_overriding(wpa_s, ssid));
Sunil Ravic0f5d412024-09-11 22:12:49 +00004183 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
4184 RSN_OVERRIDE_NOT_USED);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00004185 if (wpas_rsn_overriding(wpa_s, ssid) &&
Sunil Ravi7f769292024-07-23 22:21:32 +00004186 wpas_ap_supports_rsn_overriding(wpa_s, bss) &&
Sunil Ravic0f5d412024-09-11 22:12:49 +00004187 wpa_ie_len + 2 + 4 + 1 <= max_wpa_ie_len) {
4188 u8 *pos = wpa_ie + wpa_ie_len, *start = pos;
Sunil Ravi7f769292024-07-23 22:21:32 +00004189 const u8 *ie;
Sunil Ravic0f5d412024-09-11 22:12:49 +00004190 enum rsn_selection_variant variant = RSN_SELECTION_RSNE;
Sunil Ravi7f769292024-07-23 22:21:32 +00004191
Sunil Ravic0f5d412024-09-11 22:12:49 +00004192 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
4193 RSN_OVERRIDE_RSNE);
Sunil Ravi7f769292024-07-23 22:21:32 +00004194 ie = wpa_bss_get_rsne(wpa_s, bss, ssid, wpa_s->valid_links);
Sunil Ravic0f5d412024-09-11 22:12:49 +00004195 if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4) {
4196 u32 type;
4197
Sunil Ravi7f769292024-07-23 22:21:32 +00004198 type = WPA_GET_BE32(&ie[2]);
Sunil Ravic0f5d412024-09-11 22:12:49 +00004199 if (type == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
4200 variant = RSN_SELECTION_RSNE_OVERRIDE;
4201 wpa_sm_set_param(wpa_s->wpa,
4202 WPA_PARAM_RSN_OVERRIDE,
4203 RSN_OVERRIDE_RSNE_OVERRIDE);
4204 } else if (type == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
4205 variant = RSN_SELECTION_RSNE_OVERRIDE_2;
4206 wpa_sm_set_param(wpa_s->wpa,
4207 WPA_PARAM_RSN_OVERRIDE,
4208 RSN_OVERRIDE_RSNE_OVERRIDE_2);
4209 }
Sunil Ravi7f769292024-07-23 22:21:32 +00004210 }
Sunil Ravic0f5d412024-09-11 22:12:49 +00004211
4212 /* Indicate which RSNE variant was used */
4213 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
4214 *pos++ = 4 + 1;
4215 WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
4216 pos += 4;
4217 *pos++ = variant;
4218 wpa_hexdump(MSG_MSGDUMP, "RSN Selection", start, pos - start);
4219 wpa_ie_len += pos - start;
Sunil Ravi7f769292024-07-23 22:21:32 +00004220 }
4221
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00004222 params->rsn_overriding = wpas_rsn_overriding(wpa_s, ssid);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004223 params->wpa_ie = wpa_ie;
4224 params->wpa_ie_len = wpa_ie_len;
4225 params->auth_alg = algs;
4226 if (mask)
4227 *mask |= WPA_DRV_UPDATE_ASSOC_IES | WPA_DRV_UPDATE_AUTH_TYPE;
4228
4229 return wpa_ie;
4230}
4231
4232
Hai Shalomc3565922019-10-28 11:58:20 -07004233#ifdef CONFIG_OWE
4234static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s)
4235{
4236 struct wpa_driver_associate_params params;
4237 u8 *wpa_ie;
4238
4239 os_memset(&params, 0, sizeof(params));
4240 wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
4241 wpa_s->current_ssid, &params, NULL);
4242 if (!wpa_ie)
4243 return;
4244
4245 wpa_drv_update_connect_params(wpa_s, &params, WPA_DRV_UPDATE_ASSOC_IES);
4246 os_free(wpa_ie);
4247}
4248#endif /* CONFIG_OWE */
4249
4250
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004251#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
4252static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
4253{
4254 struct wpa_driver_associate_params params;
4255 enum wpa_drv_update_connect_params_mask mask = 0;
4256 u8 *wpa_ie;
4257
4258 if (wpa_s->auth_alg != WPA_AUTH_ALG_OPEN)
4259 return; /* nothing to do */
4260
4261 os_memset(&params, 0, sizeof(params));
4262 wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
4263 wpa_s->current_ssid, &params, &mask);
4264 if (!wpa_ie)
4265 return;
4266
Hai Shalomc1a21442022-02-04 13:43:00 -08004267 if (params.auth_alg == WPA_AUTH_ALG_FILS) {
4268 wpa_s->auth_alg = params.auth_alg;
4269 wpa_drv_update_connect_params(wpa_s, &params, mask);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004270 }
4271
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004272 os_free(wpa_ie);
4273}
4274#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
4275
4276
Hai Shalomc3565922019-10-28 11:58:20 -07004277static u8 wpa_ie_get_edmg_oper_chans(const u8 *edmg_ie)
4278{
4279 if (!edmg_ie || edmg_ie[1] < 6)
4280 return 0;
4281 return edmg_ie[EDMG_BSS_OPERATING_CHANNELS_OFFSET];
4282}
4283
4284
4285static u8 wpa_ie_get_edmg_oper_chan_width(const u8 *edmg_ie)
4286{
4287 if (!edmg_ie || edmg_ie[1] < 6)
4288 return 0;
4289 return edmg_ie[EDMG_OPERATING_CHANNEL_WIDTH_OFFSET];
4290}
4291
4292
4293/* Returns the intersection of two EDMG configurations.
4294 * Note: The current implementation is limited to CB2 only (CB1 included),
4295 * i.e., the implementation supports up to 2 contiguous channels.
4296 * For supporting non-contiguous (aggregated) channels and for supporting
4297 * CB3 and above, this function will need to be extended.
4298 */
4299static struct ieee80211_edmg_config
4300get_edmg_intersection(struct ieee80211_edmg_config a,
4301 struct ieee80211_edmg_config b,
4302 u8 primary_channel)
4303{
4304 struct ieee80211_edmg_config result;
4305 int i, contiguous = 0;
4306 int max_contiguous = 0;
4307
4308 result.channels = b.channels & a.channels;
4309 if (!result.channels) {
4310 wpa_printf(MSG_DEBUG,
4311 "EDMG not possible: cannot intersect channels 0x%x and 0x%x",
4312 a.channels, b.channels);
4313 goto fail;
4314 }
4315
4316 if (!(result.channels & BIT(primary_channel - 1))) {
4317 wpa_printf(MSG_DEBUG,
4318 "EDMG not possible: the primary channel %d is not one of the intersected channels 0x%x",
4319 primary_channel, result.channels);
4320 goto fail;
4321 }
4322
4323 /* Find max contiguous channels */
4324 for (i = 0; i < 6; i++) {
4325 if (result.channels & BIT(i))
4326 contiguous++;
4327 else
4328 contiguous = 0;
4329
4330 if (contiguous > max_contiguous)
4331 max_contiguous = contiguous;
4332 }
4333
4334 /* Assuming AP and STA supports ONLY contiguous channels,
4335 * bw configuration can have value between 4-7.
4336 */
4337 if ((b.bw_config < a.bw_config))
4338 result.bw_config = b.bw_config;
4339 else
4340 result.bw_config = a.bw_config;
4341
4342 if ((max_contiguous >= 2 && result.bw_config < EDMG_BW_CONFIG_5) ||
4343 (max_contiguous >= 1 && result.bw_config < EDMG_BW_CONFIG_4)) {
4344 wpa_printf(MSG_DEBUG,
4345 "EDMG not possible: not enough contiguous channels %d for supporting CB1 or CB2",
4346 max_contiguous);
4347 goto fail;
4348 }
4349
4350 return result;
4351
4352fail:
4353 result.channels = 0;
4354 result.bw_config = 0;
4355 return result;
4356}
4357
4358
4359static struct ieee80211_edmg_config
4360get_supported_edmg(struct wpa_supplicant *wpa_s,
4361 struct hostapd_freq_params *freq,
4362 struct ieee80211_edmg_config request_edmg)
4363{
4364 enum hostapd_hw_mode hw_mode;
4365 struct hostapd_hw_modes *mode = NULL;
4366 u8 primary_channel;
4367
4368 if (!wpa_s->hw.modes)
4369 goto fail;
4370
4371 hw_mode = ieee80211_freq_to_chan(freq->freq, &primary_channel);
4372 if (hw_mode == NUM_HOSTAPD_MODES)
4373 goto fail;
4374
Hai Shalom60840252021-02-19 19:02:11 -08004375 mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, false);
Hai Shalomc3565922019-10-28 11:58:20 -07004376 if (!mode)
4377 goto fail;
4378
4379 return get_edmg_intersection(mode->edmg, request_edmg, primary_channel);
4380
4381fail:
4382 request_edmg.channels = 0;
4383 request_edmg.bw_config = 0;
4384 return request_edmg;
4385}
4386
4387
Hai Shalom021b0b52019-04-10 11:17:58 -07004388#ifdef CONFIG_MBO
4389void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
4390{
4391 struct wpa_driver_associate_params params;
4392 u8 *wpa_ie;
4393
4394 /*
4395 * Update MBO connect params only in case of change of MBO attributes
4396 * when connected, if the AP support MBO.
4397 */
4398
4399 if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid ||
4400 !wpa_s->current_bss ||
4401 !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
4402 return;
4403
4404 os_memset(&params, 0, sizeof(params));
4405 wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
4406 wpa_s->current_ssid, &params, NULL);
4407 if (!wpa_ie)
4408 return;
4409
4410 wpa_drv_update_connect_params(wpa_s, &params, WPA_DRV_UPDATE_ASSOC_IES);
4411 os_free(wpa_ie);
4412}
4413#endif /* CONFIG_MBO */
4414
4415
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004416static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
4417{
4418 struct wpa_connect_work *cwork = work->ctx;
4419 struct wpa_bss *bss = cwork->bss;
4420 struct wpa_ssid *ssid = cwork->ssid;
4421 struct wpa_supplicant *wpa_s = work->wpa_s;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004422 u8 *wpa_ie;
Hai Shalomc3565922019-10-28 11:58:20 -07004423 const u8 *edmg_ie_oper;
Hai Shalomfdcde762020-04-02 11:19:20 -07004424 int use_crypt, ret, bssid_changed;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004425 unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004426 struct wpa_driver_associate_params params;
Sunil Ravi77d572f2023-01-17 23:58:31 +00004427 u8 psk[PMK_LEN];
Hai Shalomfdcde762020-04-02 11:19:20 -07004428#if defined(CONFIG_WEP) || defined(IEEE8021X_EAPOL)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004429 int wep_keys_set = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07004430#endif /* CONFIG_WEP || IEEE8021X_EAPOL */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004431 int assoc_failed = 0;
4432 struct wpa_ssid *old_ssid;
Dmitry Shmidte4663042016-04-04 10:07:49 -07004433 u8 prev_bssid[ETH_ALEN];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004434#ifdef CONFIG_HT_OVERRIDES
4435 struct ieee80211_ht_capabilities htcaps;
4436 struct ieee80211_ht_capabilities htcaps_mask;
4437#endif /* CONFIG_HT_OVERRIDES */
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07004438#ifdef CONFIG_VHT_OVERRIDES
4439 struct ieee80211_vht_capabilities vhtcaps;
4440 struct ieee80211_vht_capabilities vhtcaps_mask;
4441#endif /* CONFIG_VHT_OVERRIDES */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004442
Hai Shalomc1a21442022-02-04 13:43:00 -08004443 wpa_s->roam_in_progress = false;
4444#ifdef CONFIG_WNM
4445 wpa_s->bss_trans_mgmt_in_progress = false;
4446#endif /* CONFIG_WNM */
Sunil Ravi7f769292024-07-23 22:21:32 +00004447 wpa_s->no_suitable_network = 0;
Hai Shalomc1a21442022-02-04 13:43:00 -08004448
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004449 if (deinit) {
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08004450 if (work->started) {
4451 wpa_s->connect_work = NULL;
4452
4453 /* cancel possible auth. timeout */
4454 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s,
4455 NULL);
4456 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004457 wpas_connect_work_free(cwork);
4458 return;
4459 }
4460
4461 wpa_s->connect_work = work;
4462
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004463 if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid) ||
4464 wpas_network_disabled(wpa_s, ssid)) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004465 wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
4466 wpas_connect_work_done(wpa_s);
4467 return;
4468 }
4469
Sunil Ravi640215c2023-06-28 23:08:09 +00004470 /*
4471 * Set the current AP's BSSID (for non-MLO connection) or MLD address
4472 * (for MLO connection) as the previous BSSID for reassociation requests
4473 * handled by SME-in-driver. If wpa_supplicant is in disconnected state,
4474 * prev_bssid will be zero as both wpa_s->valid_links and wpa_s->bssid
4475 * will be zero.
4476 */
4477 os_memcpy(prev_bssid,
4478 wpa_s->valid_links ? wpa_s->ap_mld_addr : wpa_s->bssid,
4479 ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004480 os_memset(&params, 0, sizeof(params));
4481 wpa_s->reassociate = 0;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08004482 wpa_s->eap_expected_failure = 0;
Hai Shalom60840252021-02-19 19:02:11 -08004483
4484 /* Starting new association, so clear the possibly used WPA IE from the
4485 * previous association. */
4486 wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
Matthew Wang9ed1c792024-12-02 14:05:18 +00004487#ifndef CONFIG_NO_WPA
Hai Shalom60840252021-02-19 19:02:11 -08004488 wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
Matthew Wang9ed1c792024-12-02 14:05:18 +00004489#endif /* CONFIG_NO_WPA */
Hai Shalom60840252021-02-19 19:02:11 -08004490 wpa_s->rsnxe_len = 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004491#ifndef CONFIG_NO_ROBUST_AV
Hai Shalom60840252021-02-19 19:02:11 -08004492 wpa_s->mscs_setup_done = false;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004493#endif /* CONFIG_NO_ROBUST_AV */
Hai Shalom60840252021-02-19 19:02:11 -08004494
4495 wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
4496 if (!wpa_ie) {
4497 wpas_connect_work_done(wpa_s);
4498 return;
4499 }
4500
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004501 if (bss &&
4502 (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004503#ifdef CONFIG_IEEE80211R
4504 const u8 *ie, *md = NULL;
4505#endif /* CONFIG_IEEE80211R */
4506 wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
4507 " (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
4508 wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
4509 bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
4510 os_memset(wpa_s->bssid, 0, ETH_ALEN);
4511 os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
4512 if (bssid_changed)
4513 wpas_notify_bssid_changed(wpa_s);
4514#ifdef CONFIG_IEEE80211R
4515 ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
4516 if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
4517 md = ie + 2;
4518 wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
4519 if (md) {
4520 /* Prepare for the next transition */
4521 wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
4522 }
4523#endif /* CONFIG_IEEE80211R */
4524#ifdef CONFIG_WPS
4525 } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
4526 wpa_s->conf->ap_scan == 2 &&
4527 (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
4528 /* Use ap_scan==1 style network selection to find the network
4529 */
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08004530 wpas_connect_work_done(wpa_s);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004531 wpa_s->scan_req = MANUAL_SCAN_REQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004532 wpa_s->reassociate = 1;
4533 wpa_supplicant_req_scan(wpa_s, 0, 0);
Hai Shalomc1a21442022-02-04 13:43:00 -08004534 os_free(wpa_ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004535 return;
4536#endif /* CONFIG_WPS */
4537 } else {
4538 wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
4539 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07004540 if (bss)
4541 os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
4542 else
4543 os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004544 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004545 if (!wpa_s->pno)
4546 wpa_supplicant_cancel_sched_scan(wpa_s);
4547
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004548 wpa_supplicant_cancel_scan(wpa_s);
4549
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004550 wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
4551 use_crypt = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004552 cipher_pairwise = wpa_s->pairwise_cipher;
4553 cipher_group = wpa_s->group_cipher;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004554 cipher_group_mgmt = wpa_s->mgmt_group_cipher;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004555 if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
4556 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
4557 if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
4558 use_crypt = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07004559#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004560 if (wpa_set_wep_keys(wpa_s, ssid)) {
4561 use_crypt = 1;
4562 wep_keys_set = 1;
4563 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004564#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004565 }
4566 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
4567 use_crypt = 0;
4568
4569#ifdef IEEE8021X_EAPOL
4570 if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
4571 if ((ssid->eapol_flags &
4572 (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
4573 EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) == 0 &&
4574 !wep_keys_set) {
4575 use_crypt = 0;
4576 } else {
4577 /* Assume that dynamic WEP-104 keys will be used and
4578 * set cipher suites in order for drivers to expect
4579 * encryption. */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004580 cipher_pairwise = cipher_group = WPA_CIPHER_WEP104;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004581 }
4582 }
4583#endif /* IEEE8021X_EAPOL */
4584
4585 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
4586 /* Set the key before (and later after) association */
4587 wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
4588 }
4589
Sunil8cd6f4d2022-06-28 18:40:46 +00004590 /* Set current_ssid before changing state to ASSOCIATING, so that the
4591 * selected SSID is available to wpas_notify_state_changed(). */
4592 old_ssid = wpa_s->current_ssid;
4593 wpa_s->current_ssid = ssid;
4594
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004595 wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
4596 if (bss) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004597 params.ssid = bss->ssid;
4598 params.ssid_len = bss->ssid_len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004599 if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set ||
4600 wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07004601 wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
4602 MACSTR " freq=%u MHz based on scan results "
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004603 "(bssid_set=%d wps=%d)",
Dmitry Shmidt04949592012-07-19 12:16:46 -07004604 MAC2STR(bss->bssid), bss->freq,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004605 ssid->bssid_set,
4606 wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004607 params.bssid = bss->bssid;
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07004608 params.freq.freq = bss->freq;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004609 }
Dmitry Shmidt96be6222014-02-13 10:16:51 -08004610 params.bssid_hint = bss->bssid;
4611 params.freq_hint = bss->freq;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004612 params.pbss = bss_is_pbss(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004613 } else {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004614 if (ssid->bssid_hint_set)
4615 params.bssid_hint = ssid->bssid_hint;
4616
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004617 params.ssid = ssid->ssid;
4618 params.ssid_len = ssid->ssid_len;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004619 params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004620 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004621
4622 if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
4623 wpa_s->conf->ap_scan == 2) {
4624 params.bssid = ssid->bssid;
4625 params.fixed_bssid = 1;
4626 }
4627
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004628 /* Initial frequency for IBSS/mesh */
4629 if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004630 ssid->frequency > 0 && params.freq.freq == 0)
4631 ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
Dmitry Shmidt2ac5f602014-03-07 10:08:21 -08004632
4633 if (ssid->mode == WPAS_MODE_IBSS) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004634 params.fixed_freq = ssid->fixed_freq;
Dmitry Shmidt2ac5f602014-03-07 10:08:21 -08004635 if (ssid->beacon_int)
4636 params.beacon_int = ssid->beacon_int;
4637 else
4638 params.beacon_int = wpa_s->conf->beacon_int;
4639 }
4640
Hai Shalomc3565922019-10-28 11:58:20 -07004641 if (bss && ssid->enable_edmg)
Hai Shalom60840252021-02-19 19:02:11 -08004642 edmg_ie_oper = wpa_bss_get_ie_ext(bss,
4643 WLAN_EID_EXT_EDMG_OPERATION);
Hai Shalomc3565922019-10-28 11:58:20 -07004644 else
4645 edmg_ie_oper = NULL;
4646
4647 if (edmg_ie_oper) {
4648 params.freq.edmg.channels =
4649 wpa_ie_get_edmg_oper_chans(edmg_ie_oper);
4650 params.freq.edmg.bw_config =
4651 wpa_ie_get_edmg_oper_chan_width(edmg_ie_oper);
4652 wpa_printf(MSG_DEBUG,
4653 "AP supports EDMG channels 0x%x, bw_config %d",
4654 params.freq.edmg.channels,
4655 params.freq.edmg.bw_config);
4656
4657 /* User may ask for specific EDMG channel for EDMG connection
4658 * (must be supported by AP)
4659 */
4660 if (ssid->edmg_channel) {
4661 struct ieee80211_edmg_config configured_edmg;
4662 enum hostapd_hw_mode hw_mode;
4663 u8 primary_channel;
4664
4665 hw_mode = ieee80211_freq_to_chan(bss->freq,
4666 &primary_channel);
4667 if (hw_mode == NUM_HOSTAPD_MODES)
4668 goto edmg_fail;
4669
4670 hostapd_encode_edmg_chan(ssid->enable_edmg,
4671 ssid->edmg_channel,
4672 primary_channel,
4673 &configured_edmg);
4674
4675 if (ieee802_edmg_is_allowed(params.freq.edmg,
4676 configured_edmg)) {
4677 params.freq.edmg = configured_edmg;
4678 wpa_printf(MSG_DEBUG,
4679 "Use EDMG channel %d for connection",
4680 ssid->edmg_channel);
4681 } else {
4682 edmg_fail:
4683 params.freq.edmg.channels = 0;
4684 params.freq.edmg.bw_config = 0;
4685 wpa_printf(MSG_WARNING,
4686 "EDMG channel %d not supported by AP, fallback to DMG",
4687 ssid->edmg_channel);
4688 }
4689 }
4690
4691 if (params.freq.edmg.channels) {
4692 wpa_printf(MSG_DEBUG,
4693 "EDMG before: channels 0x%x, bw_config %d",
4694 params.freq.edmg.channels,
4695 params.freq.edmg.bw_config);
4696 params.freq.edmg = get_supported_edmg(wpa_s,
4697 &params.freq,
4698 params.freq.edmg);
4699 wpa_printf(MSG_DEBUG,
4700 "EDMG after: channels 0x%x, bw_config %d",
4701 params.freq.edmg.channels,
4702 params.freq.edmg.bw_config);
4703 }
4704 }
4705
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004706 params.pairwise_suite = cipher_pairwise;
4707 params.group_suite = cipher_group;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004708 params.mgmt_group_suite = cipher_group_mgmt;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004709 params.key_mgmt_suite = wpa_s->key_mgmt;
Sunil Ravi89eba102022-09-13 21:04:37 -07004710 params.allowed_key_mgmts = wpa_s->allowed_key_mgmts;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004711 params.wpa_proto = wpa_s->wpa_proto;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004712 wpa_s->auth_alg = params.auth_alg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004713 params.mode = ssid->mode;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004714 params.bg_scan_period = ssid->bg_scan_period;
Hai Shalomfdcde762020-04-02 11:19:20 -07004715#ifdef CONFIG_WEP
4716 {
4717 int i;
4718
4719 for (i = 0; i < NUM_WEP_KEYS; i++) {
4720 if (ssid->wep_key_len[i])
4721 params.wep_key[i] = ssid->wep_key[i];
4722 params.wep_key_len[i] = ssid->wep_key_len[i];
4723 }
4724 params.wep_tx_keyidx = ssid->wep_tx_keyidx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004725 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004726#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004727
Hai Shalom74f70d42019-02-11 14:42:39 -08004728 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
Isaac Chiou6ce580d2024-04-24 17:07:24 +08004729#if (defined(CONFIG_DRIVER_NL80211_BRCM) && !defined(WIFI_BRCM_OPEN_SOURCE_MULTI_AKM)) || \
4730 defined(CONFIG_DRIVER_NL80211_SYNA)
Sunil Ravi89eba102022-09-13 21:04:37 -07004731 ((params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
4732 (params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK))) {
Isaac Chiou6ce580d2024-04-24 17:07:24 +08004733#elif (defined(CONFIG_DRIVER_NL80211_BRCM) && defined(WIFI_BRCM_OPEN_SOURCE_MULTI_AKM)) || \
4734 defined(CONFIG_DRIVER_NL80211_SYNA)
4735 (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
4736 params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
4737 params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
4738 wpa_key_mgmt_wpa_psk_no_sae(params.allowed_key_mgmts))) {
Vinayak Yadawad14709082022-03-17 14:25:11 +05304739#else
Sunil Ravi89eba102022-09-13 21:04:37 -07004740 (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
4741 params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
4742 (params.allowed_key_mgmts &
4743 (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK)))) {
Isaac Chiou6ce580d2024-04-24 17:07:24 +08004744#endif /* (CONFIG_DRIVER_NL80211_BRCM && !WIFI_BRCM_OPEN_SOURCE_MULTI_AKM) ||
4745 * CONFIG_DRIVER_NL80211_SYNA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004746 params.passphrase = ssid->passphrase;
Sunil Ravi77d572f2023-01-17 23:58:31 +00004747 if (wpa_supplicant_get_psk(wpa_s, bss, ssid, psk) == 0)
4748 params.psk = psk;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004749 }
4750
Hai Shalom74f70d42019-02-11 14:42:39 -08004751 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
4752 (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
4753 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
4754 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004755 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
4756 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA384))
Hai Shalomc3565922019-10-28 11:58:20 -07004757 params.req_handshake_offload = 1;
Hai Shalom74f70d42019-02-11 14:42:39 -08004758
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004759 if (wpa_s->conf->key_mgmt_offload) {
4760 if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
4761 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
Dmitry Shmidt807291d2015-01-27 13:40:23 -08004762 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004763 params.key_mgmt_suite ==
4764 WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
4765 params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA384)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004766 params.req_key_mgmt_offload =
4767 ssid->proactive_key_caching < 0 ?
4768 wpa_s->conf->okc : ssid->proactive_key_caching;
4769 else
4770 params.req_key_mgmt_offload = 1;
4771
Isaac Chiou6ce580d2024-04-24 17:07:24 +08004772#if (defined(CONFIG_DRIVER_NL80211_BRCM) && !defined(WIFI_BRCM_OPEN_SOURCE_MULTI_AKM)) || \
4773 defined(CONFIG_DRIVER_NL80211_SYNA)
Sunil Ravi89eba102022-09-13 21:04:37 -07004774 if (((params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004775 params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
4776 params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
Sunil Ravi89eba102022-09-13 21:04:37 -07004777#else
4778 if ((wpa_key_mgmt_wpa_psk_no_sae(params.key_mgmt_suite) ||
4779 wpa_key_mgmt_wpa_psk_no_sae(params.allowed_key_mgmts)) &&
Isaac Chiou6ce580d2024-04-24 17:07:24 +08004780#endif /* (CONFIG_DRIVER_NL80211_BRCM && !WIFI_BRCM_OPEN_SOURCE_MULTI_AKM) ||
4781 * CONFIG_DRIVER_NL80211_SYNA */
Sunil Ravi77d572f2023-01-17 23:58:31 +00004782 wpa_supplicant_get_psk(wpa_s, bss, ssid, psk) == 0)
4783 params.psk = psk;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004784 }
4785
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004786 if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA) &&
4787 wpa_key_mgmt_sae(params.key_mgmt_suite)) {
4788 params.auth_alg = WPA_AUTH_ALG_SAE;
4789 if (ssid->sae_password) {
4790 params.sae_password = ssid->sae_password;
4791 params.sae_password_id = ssid->sae_password_id;
4792 } else if (ssid->passphrase) {
4793 params.passphrase = ssid->passphrase;
4794 }
4795 }
4796
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004797 params.drop_unencrypted = use_crypt;
4798
Dmitry Shmidt807291d2015-01-27 13:40:23 -08004799 params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004800 if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
Sunil Ravi7f769292024-07-23 22:21:32 +00004801 const u8 *rsn = wpa_bss_get_rsne(wpa_s, bss, ssid, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004802 struct wpa_ie_data ie;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004803 if (!wpas_driver_bss_selection(wpa_s) && rsn &&
4804 wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004805 ie.capabilities &
4806 (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
4807 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected AP supports "
4808 "MFP: require MFP");
4809 params.mgmt_frame_protection =
4810 MGMT_FRAME_PROTECTION_REQUIRED;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08004811#ifdef CONFIG_OWE
4812 } else if (!rsn && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
4813 !ssid->owe_only) {
4814 params.mgmt_frame_protection = NO_MGMT_FRAME_PROTECTION;
4815#endif /* CONFIG_OWE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004816 }
4817 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004818
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004819 params.p2p = ssid->p2p_group;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004820
Dmitry Shmidt9c175262016-03-03 10:20:07 -08004821 if (wpa_s->p2pdev->set_sta_uapsd)
4822 params.uapsd = wpa_s->p2pdev->sta_uapsd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004823 else
4824 params.uapsd = -1;
4825
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004826#ifdef CONFIG_HT_OVERRIDES
4827 os_memset(&htcaps, 0, sizeof(htcaps));
4828 os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
4829 params.htcaps = (u8 *) &htcaps;
4830 params.htcaps_mask = (u8 *) &htcaps_mask;
4831 wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
4832#endif /* CONFIG_HT_OVERRIDES */
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07004833#ifdef CONFIG_VHT_OVERRIDES
4834 os_memset(&vhtcaps, 0, sizeof(vhtcaps));
4835 os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
4836 params.vhtcaps = &vhtcaps;
4837 params.vhtcaps_mask = &vhtcaps_mask;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004838 wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07004839#endif /* CONFIG_VHT_OVERRIDES */
Hai Shalomfdcde762020-04-02 11:19:20 -07004840#ifdef CONFIG_HE_OVERRIDES
4841 wpa_supplicant_apply_he_overrides(wpa_s, ssid, &params);
4842#endif /* CONFIG_HE_OVERRIDES */
Sunil Ravi77d572f2023-01-17 23:58:31 +00004843 wpa_supplicant_apply_eht_overrides(wpa_s, ssid, &params);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004844
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08004845#ifdef CONFIG_P2P
4846 /*
4847 * If multi-channel concurrency is not supported, check for any
4848 * frequency conflict. In case of any frequency conflict, remove the
4849 * least prioritized connection.
4850 */
4851 if (wpa_s->num_multichan_concurrent < 2) {
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07004852 int freq, num;
Sunil Ravi77d572f2023-01-17 23:58:31 +00004853 num = get_shared_radio_freqs(wpa_s, &freq, 1, false);
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07004854 if (num > 0 && freq > 0 && freq != params.freq.freq) {
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07004855 wpa_printf(MSG_DEBUG,
4856 "Assoc conflicting freq found (%d != %d)",
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07004857 freq, params.freq.freq);
4858 if (wpas_p2p_handle_frequency_conflicts(
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08004859 wpa_s, params.freq.freq, ssid) < 0) {
4860 wpas_connect_work_done(wpa_s);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004861 os_free(wpa_ie);
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08004862 return;
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08004863 }
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08004864 }
4865 }
4866#endif /* CONFIG_P2P */
4867
Dmitry Shmidte4663042016-04-04 10:07:49 -07004868 if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
Sunil8cd6f4d2022-06-28 18:40:46 +00004869 old_ssid)
Dmitry Shmidte4663042016-04-04 10:07:49 -07004870 params.prev_bssid = prev_bssid;
4871
Hai Shalom60840252021-02-19 19:02:11 -08004872#ifdef CONFIG_SAE
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00004873 params.sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
Hai Shalom60840252021-02-19 19:02:11 -08004874#endif /* CONFIG_SAE */
4875
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004876 ret = wpa_drv_associate(wpa_s, &params);
Sunil Ravi77d572f2023-01-17 23:58:31 +00004877 forced_memzero(psk, sizeof(psk));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004878 os_free(wpa_ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004879 if (ret < 0) {
4880 wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
4881 "failed");
Hai Shalomc1a21442022-02-04 13:43:00 -08004882 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_VALID_ERROR_CODES) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004883 /*
4884 * The driver is known to mean what is saying, so we
4885 * can stop right here; the association will not
4886 * succeed.
4887 */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004888 wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
4889 NULL);
Roger Wang4c09cc92020-11-05 18:57:12 +08004890 wpa_s->assoc_status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
Sunil Ravie06118e2021-01-03 08:39:46 -08004891 wpas_notify_assoc_status_code(wpa_s, wpa_s->pending_bssid, 0, NULL, 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004892 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004893 os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
4894 return;
4895 }
4896 /* try to continue anyway; new association will be tried again
4897 * after timeout */
4898 assoc_failed = 1;
4899 }
4900
4901 if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
4902 /* Set the key after the association just in case association
4903 * cleared the previously configured key. */
4904 wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
4905 /* No need to timeout authentication since there is no key
4906 * management. */
4907 wpa_supplicant_cancel_auth_timeout(wpa_s);
4908 wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
4909#ifdef CONFIG_IBSS_RSN
4910 } else if (ssid->mode == WPAS_MODE_IBSS &&
4911 wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
4912 wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
4913 /*
4914 * RSN IBSS authentication is per-STA and we can disable the
4915 * per-BSSID authentication.
4916 */
4917 wpa_supplicant_cancel_auth_timeout(wpa_s);
4918#endif /* CONFIG_IBSS_RSN */
4919 } else {
4920 /* Timeout for IEEE 802.11 authentication and association */
4921 int timeout = 60;
4922
4923 if (assoc_failed) {
4924 /* give IBSS a bit more time */
4925 timeout = ssid->mode == WPAS_MODE_IBSS ? 10 : 5;
4926 } else if (wpa_s->conf->ap_scan == 1) {
4927 /* give IBSS a bit more time */
4928 timeout = ssid->mode == WPAS_MODE_IBSS ? 20 : 10;
4929 }
4930 wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
4931 }
4932
Hai Shalomfdcde762020-04-02 11:19:20 -07004933#ifdef CONFIG_WEP
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07004934 if (wep_keys_set &&
4935 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004936 /* Set static WEP keys again */
4937 wpa_set_wep_keys(wpa_s, ssid);
4938 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004939#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004940
Sunil8cd6f4d2022-06-28 18:40:46 +00004941 if (old_ssid && old_ssid != ssid) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004942 /*
4943 * Do not allow EAP session resumption between different
4944 * network configurations.
4945 */
4946 eapol_sm_invalidate_cached_session(wpa_s->eapol);
4947 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004948
mtk30479d7f89782024-01-24 11:51:43 +08004949 if (!wpas_driver_bss_selection(wpa_s) ||
4950#ifdef CONFIG_P2P
4951 wpa_s->p2p_in_invitation ||
4952#endif /* CONFIG_P2P */
4953 ssid->bssid_set) {
Dmitry Shmidtb1e52102015-05-29 12:36:29 -07004954 wpa_s->current_bss = bss;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004955#ifdef CONFIG_HS20
4956 hs20_configure_frame_filters(wpa_s);
4957#endif /* CONFIG_HS20 */
4958 }
4959
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004960 wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
Matthew Wang9ed1c792024-12-02 14:05:18 +00004961#ifndef CONFIG_NO_WPA
Sunil Ravi7f769292024-07-23 22:21:32 +00004962 if (bss)
4963 wpa_sm_set_ssid(wpa_s->wpa, bss->ssid, bss->ssid_len);
Matthew Wang9ed1c792024-12-02 14:05:18 +00004964#endif /* CONFIG_NO_WPA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004965 wpa_supplicant_initiate_eapol(wpa_s);
4966 if (old_ssid != wpa_s->current_ssid)
4967 wpas_notify_network_changed(wpa_s);
Sunil Ravi77d572f2023-01-17 23:58:31 +00004968 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
4969 wpas_notify_auth_changed(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004970}
4971
4972
4973static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
4974 const u8 *addr)
4975{
4976 struct wpa_ssid *old_ssid;
4977
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004978 wpa_s->ml_connect_probe_ssid = NULL;
4979 wpa_s->ml_connect_probe_bss = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004980 wpas_connect_work_done(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004981 wpa_clear_keys(wpa_s, addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004982 old_ssid = wpa_s->current_ssid;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004983 wpa_supplicant_mark_disassoc(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004984 wpa_sm_set_config(wpa_s->wpa, NULL);
4985 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
4986 if (old_ssid != wpa_s->current_ssid)
4987 wpas_notify_network_changed(wpa_s);
Hai Shalomc1a21442022-02-04 13:43:00 -08004988
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004989#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08004990 wpas_scs_deinit(wpa_s);
4991 wpas_dscp_deinit(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004992#endif /* CONFIG_NO_ROBUST_AV */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004993 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
4994}
4995
4996
4997/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004998 * wpa_supplicant_deauthenticate - Deauthenticate the current connection
4999 * @wpa_s: Pointer to wpa_supplicant data
5000 * @reason_code: IEEE 802.11 reason code for the deauthenticate frame
5001 *
5002 * This function is used to request %wpa_supplicant to deauthenticate from the
5003 * current AP.
5004 */
5005void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
Hai Shalom81f62d82019-07-22 12:10:00 -07005006 u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005007{
5008 u8 *addr = NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005009 union wpa_event_data event;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005010 int zero_addr = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005011
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005012 wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
Sunil Ravi7f769292024-07-23 22:21:32 +00005013 " pending_bssid=" MACSTR
5014 " reason=%d (%s) state=%s valid_links=0x%x ap_mld_addr=" MACSTR,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005015 MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
Hai Shalom81f62d82019-07-22 12:10:00 -07005016 reason_code, reason2str(reason_code),
Sunil Ravi7f769292024-07-23 22:21:32 +00005017 wpa_supplicant_state_txt(wpa_s->wpa_state), wpa_s->valid_links,
5018 MAC2STR(wpa_s->ap_mld_addr));
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005019
Sunil Ravi7f769292024-07-23 22:21:32 +00005020 if (wpa_s->valid_links && !is_zero_ether_addr(wpa_s->ap_mld_addr))
5021 addr = wpa_s->ap_mld_addr;
5022 else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
5023 (wpa_s->wpa_state == WPA_AUTHENTICATING ||
5024 wpa_s->wpa_state == WPA_ASSOCIATING))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005025 addr = wpa_s->pending_bssid;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005026 else if (!is_zero_ether_addr(wpa_s->bssid))
5027 addr = wpa_s->bssid;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005028 else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
5029 /*
5030 * When using driver-based BSS selection, we may not know the
5031 * BSSID with which we are currently trying to associate. We
5032 * need to notify the driver of this disconnection even in such
5033 * a case, so use the all zeros address here.
5034 */
5035 addr = wpa_s->bssid;
5036 zero_addr = 1;
5037 }
5038
Hai Shalom74f70d42019-02-11 14:42:39 -08005039 if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
5040 wpa_s->enabled_4addr_mode = 0;
5041
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005042#ifdef CONFIG_TDLS
5043 wpa_tdls_teardown_peers(wpa_s->wpa);
5044#endif /* CONFIG_TDLS */
5045
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005046#ifdef CONFIG_MESH
5047 if (wpa_s->ifmsh) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005048 struct mesh_conf *mconf;
5049
5050 mconf = wpa_s->ifmsh->mconf;
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005051 wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
5052 wpa_s->ifname);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005053 wpas_notify_mesh_group_removed(wpa_s, mconf->meshid,
5054 mconf->meshid_len, reason_code);
Hai Shalom60840252021-02-19 19:02:11 -08005055 wpa_supplicant_leave_mesh(wpa_s, true);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005056 }
5057#endif /* CONFIG_MESH */
5058
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005059 if (addr) {
5060 wpa_drv_deauthenticate(wpa_s, addr, reason_code);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005061 os_memset(&event, 0, sizeof(event));
Hai Shalom81f62d82019-07-22 12:10:00 -07005062 event.deauth_info.reason_code = reason_code;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005063 event.deauth_info.locally_generated = 1;
5064 wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005065 if (zero_addr)
5066 addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005067 }
5068
5069 wpa_supplicant_clear_connection(wpa_s, addr);
5070}
5071
Hai Shalomfdcde762020-04-02 11:19:20 -07005072
5073void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s)
5074{
5075 wpa_s->own_reconnect_req = 1;
5076 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
5077
5078}
5079
5080
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005081static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
5082 struct wpa_ssid *ssid)
5083{
5084 if (!ssid || !ssid->disabled || ssid->disabled == 2)
5085 return;
5086
5087 ssid->disabled = 0;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08005088 ssid->owe_transition_bss_select_count = 0;
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005089 wpas_clear_temp_disabled(wpa_s, ssid, 1);
5090 wpas_notify_network_enabled_changed(wpa_s, ssid);
5091
5092 /*
5093 * Try to reassociate since there is no current configuration and a new
5094 * network was made available.
5095 */
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07005096 if (!wpa_s->current_ssid && !wpa_s->disconnected)
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005097 wpa_s->reassociate = 1;
5098}
5099
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005100
Roshan Pius950bec92016-07-19 09:49:24 -07005101/**
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005102 * wpa_supplicant_add_network - Add a new network
Roshan Pius950bec92016-07-19 09:49:24 -07005103 * @wpa_s: wpa_supplicant structure for a network interface
5104 * Returns: The new network configuration or %NULL if operation failed
5105 *
5106 * This function performs the following operations:
5107 * 1. Adds a new network.
5108 * 2. Send network addition notification.
5109 * 3. Marks the network disabled.
5110 * 4. Set network default parameters.
5111 */
5112struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
5113{
5114 struct wpa_ssid *ssid;
5115
5116 ssid = wpa_config_add_network(wpa_s->conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005117 if (!ssid)
Roshan Pius950bec92016-07-19 09:49:24 -07005118 return NULL;
Roshan Pius950bec92016-07-19 09:49:24 -07005119 wpas_notify_network_added(wpa_s, ssid);
5120 ssid->disabled = 1;
5121 wpa_config_set_network_defaults(ssid);
5122
5123 return ssid;
5124}
5125
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005126
Roshan Pius950bec92016-07-19 09:49:24 -07005127/**
5128 * wpa_supplicant_remove_network - Remove a configured network based on id
5129 * @wpa_s: wpa_supplicant structure for a network interface
5130 * @id: Unique network id to search for
5131 * Returns: 0 on success, or -1 if the network was not found, -2 if the network
5132 * could not be removed
5133 *
5134 * This function performs the following operations:
5135 * 1. Removes the network.
5136 * 2. Send network removal notification.
5137 * 3. Update internal state machines.
5138 * 4. Stop any running sched scans.
5139 */
5140int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
5141{
Sunil Ravia04bd252022-05-02 22:54:18 -07005142 struct wpa_ssid *ssid, *prev = wpa_s->current_ssid;
Roshan Pius950bec92016-07-19 09:49:24 -07005143 int was_disabled;
5144
5145 ssid = wpa_config_get_network(wpa_s->conf, id);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005146 if (!ssid)
Roshan Pius950bec92016-07-19 09:49:24 -07005147 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005148 wpas_notify_network_removed(wpa_s, ssid);
Roshan Pius950bec92016-07-19 09:49:24 -07005149
Sunil Ravia04bd252022-05-02 22:54:18 -07005150 if (ssid == prev || !prev) {
Roshan Pius950bec92016-07-19 09:49:24 -07005151#ifdef CONFIG_SME
5152 wpa_s->sme.prev_bssid_set = 0;
5153#endif /* CONFIG_SME */
5154 /*
5155 * Invalidate the EAP session cache if the current or
5156 * previously used network is removed.
5157 */
5158 eapol_sm_invalidate_cached_session(wpa_s->eapol);
5159 }
5160
Sunil Ravia04bd252022-05-02 22:54:18 -07005161 if (ssid == prev) {
Roshan Pius950bec92016-07-19 09:49:24 -07005162 wpa_sm_set_config(wpa_s->wpa, NULL);
5163 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
5164
5165 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
5166 wpa_s->own_disconnect_req = 1;
5167 wpa_supplicant_deauthenticate(wpa_s,
5168 WLAN_REASON_DEAUTH_LEAVING);
5169 }
5170
5171 was_disabled = ssid->disabled;
5172
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005173 if (wpa_config_remove_network(wpa_s->conf, id) < 0)
Roshan Pius950bec92016-07-19 09:49:24 -07005174 return -2;
Roshan Pius950bec92016-07-19 09:49:24 -07005175
5176 if (!was_disabled && wpa_s->sched_scanning) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005177 wpa_printf(MSG_DEBUG,
5178 "Stop ongoing sched_scan to remove network from filters");
Roshan Pius950bec92016-07-19 09:49:24 -07005179 wpa_supplicant_cancel_sched_scan(wpa_s);
5180 wpa_supplicant_req_scan(wpa_s, 0, 0);
5181 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005182
Roshan Pius950bec92016-07-19 09:49:24 -07005183 return 0;
5184}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005185
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005186
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005187/**
Hai Shalom899fcc72020-10-19 14:38:18 -07005188 * wpa_supplicant_remove_all_networks - Remove all configured networks
5189 * @wpa_s: wpa_supplicant structure for a network interface
5190 * Returns: 0 on success (errors are currently ignored)
5191 *
5192 * This function performs the following operations:
5193 * 1. Remove all networks.
5194 * 2. Send network removal notifications.
5195 * 3. Update internal state machines.
5196 * 4. Stop any running sched scans.
5197 */
5198int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s)
5199{
5200 struct wpa_ssid *ssid;
5201
Vinayak Yadawad4222acc2023-12-15 17:39:27 +05305202 if (wpa_s->drv_flags2 &
5203 (WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA |
5204 WPA_DRIVER_FLAGS2_OWE_OFFLOAD_STA))
5205 wpa_drv_flush_pmkid(wpa_s);
5206
Hai Shalom899fcc72020-10-19 14:38:18 -07005207 if (wpa_s->sched_scanning)
5208 wpa_supplicant_cancel_sched_scan(wpa_s);
5209
5210 eapol_sm_invalidate_cached_session(wpa_s->eapol);
5211 if (wpa_s->current_ssid) {
5212#ifdef CONFIG_SME
5213 wpa_s->sme.prev_bssid_set = 0;
5214#endif /* CONFIG_SME */
5215 wpa_sm_set_config(wpa_s->wpa, NULL);
5216 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
5217 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
5218 wpa_s->own_disconnect_req = 1;
5219 wpa_supplicant_deauthenticate(
5220 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
5221 }
5222 ssid = wpa_s->conf->ssid;
5223 while (ssid) {
5224 struct wpa_ssid *remove_ssid = ssid;
5225 int id;
5226
5227 id = ssid->id;
5228 ssid = ssid->next;
Hai Shalom899fcc72020-10-19 14:38:18 -07005229 wpas_notify_network_removed(wpa_s, remove_ssid);
5230 wpa_config_remove_network(wpa_s->conf, id);
5231 }
5232 return 0;
5233}
5234
5235
5236/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005237 * wpa_supplicant_enable_network - Mark a configured network as enabled
5238 * @wpa_s: wpa_supplicant structure for a network interface
5239 * @ssid: wpa_ssid structure for a configured network or %NULL
5240 *
5241 * Enables the specified network or all networks if no network specified.
5242 */
5243void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
5244 struct wpa_ssid *ssid)
5245{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005246 if (ssid == NULL) {
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005247 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
5248 wpa_supplicant_enable_one_network(wpa_s, ssid);
5249 } else
5250 wpa_supplicant_enable_one_network(wpa_s, ssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005251
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005252 if (wpa_s->reassociate && !wpa_s->disconnected &&
5253 (!wpa_s->current_ssid ||
5254 wpa_s->wpa_state == WPA_DISCONNECTED ||
5255 wpa_s->wpa_state == WPA_SCANNING)) {
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005256 if (wpa_s->sched_scanning) {
5257 wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to add "
5258 "new network to scan filters");
5259 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005260 }
5261
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005262 if (wpa_supplicant_fast_associate(wpa_s) != 1) {
5263 wpa_s->scan_req = NORMAL_SCAN_REQ;
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07005264 wpa_supplicant_req_scan(wpa_s, 0, 0);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005265 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005266 }
5267}
5268
5269
5270/**
5271 * wpa_supplicant_disable_network - Mark a configured network as disabled
5272 * @wpa_s: wpa_supplicant structure for a network interface
5273 * @ssid: wpa_ssid structure for a configured network or %NULL
5274 *
5275 * Disables the specified network or all networks if no network specified.
5276 */
5277void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
5278 struct wpa_ssid *ssid)
5279{
5280 struct wpa_ssid *other_ssid;
5281 int was_disabled;
5282
5283 if (ssid == NULL) {
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005284 if (wpa_s->sched_scanning)
5285 wpa_supplicant_cancel_sched_scan(wpa_s);
5286
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005287 for (other_ssid = wpa_s->conf->ssid; other_ssid;
5288 other_ssid = other_ssid->next) {
5289 was_disabled = other_ssid->disabled;
5290 if (was_disabled == 2)
5291 continue; /* do not change persistent P2P group
5292 * data */
5293
5294 other_ssid->disabled = 1;
5295
5296 if (was_disabled != other_ssid->disabled)
5297 wpas_notify_network_enabled_changed(
5298 wpa_s, other_ssid);
5299 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005300 if (wpa_s->current_ssid) {
5301 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
5302 wpa_s->own_disconnect_req = 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005303 wpa_supplicant_deauthenticate(
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005304 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005305 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005306 } else if (ssid->disabled != 2) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005307 if (ssid == wpa_s->current_ssid) {
5308 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
5309 wpa_s->own_disconnect_req = 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005310 wpa_supplicant_deauthenticate(
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005311 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005312 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005313
5314 was_disabled = ssid->disabled;
5315
5316 ssid->disabled = 1;
5317
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005318 if (was_disabled != ssid->disabled) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005319 wpas_notify_network_enabled_changed(wpa_s, ssid);
Dmitry Shmidt2f023192013-03-12 12:44:17 -07005320 if (wpa_s->sched_scanning) {
5321 wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan "
5322 "to remove network from filters");
5323 wpa_supplicant_cancel_sched_scan(wpa_s);
5324 wpa_supplicant_req_scan(wpa_s, 0, 0);
5325 }
5326 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005327 }
5328}
5329
5330
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00005331static bool ssid_in_last_scan(struct wpa_supplicant *wpa_s,
5332 struct wpa_ssid *ssid)
5333{
5334 size_t i;
5335
5336 /* Check if the previous scan included the selected network */
5337 if (wpa_s->last_scan_num_ssids <= 1 ||
5338 !ssid->ssid || ssid->ssid_len == 0)
5339 return false;
5340
5341 /* Iterate through the previous scan SSIDs */
5342 for (i = 0; i < wpa_s->last_scan_num_ssids; i++) {
5343 if (os_memcmp(wpa_s->last_scan_ssids[i].ssid, ssid->ssid,
5344 ssid->ssid_len) == 0)
5345 return true;
5346 }
5347
5348 return false;
5349}
5350
5351
5352/**
5353 * Checks whether an SSID was discovered in the last scan.
5354 * @wpa_s: wpa_supplicant structure for a network interface.
5355 * @ssid: wpa_ssid structure for a configured network.
5356 * Returns: true if ssid found, false otherwise.
5357 */
5358static bool ssid_in_last_scan_res(struct wpa_supplicant *wpa_s,
5359 struct wpa_ssid *ssid)
5360{
5361 size_t i;
5362
5363 if (!wpa_s->last_scan_res || !ssid->ssid || ssid->ssid_len == 0)
5364 return false;
5365
5366 for (i = 0; i < wpa_s->last_scan_res_used; i++) {
5367 if (os_memcmp(wpa_s->last_scan_res[i]->ssid,
5368 ssid->ssid, ssid->ssid_len) == 0)
5369 return true;
5370 }
5371
5372 return false;
5373}
5374
5375
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005376/**
5377 * wpa_supplicant_select_network - Attempt association with a network
5378 * @wpa_s: wpa_supplicant structure for a network interface
5379 * @ssid: wpa_ssid structure for a configured network or %NULL for any network
5380 */
5381void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
5382 struct wpa_ssid *ssid)
5383{
5384
5385 struct wpa_ssid *other_ssid;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005386 int disconnected = 0;
Sunil Ravi7f769292024-07-23 22:21:32 +00005387 bool request_new_scan = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005388
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005389 if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07005390 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
5391 wpa_s->own_disconnect_req = 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005392 wpa_supplicant_deauthenticate(
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005393 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005394 disconnected = 1;
5395 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005396
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005397 if (ssid)
5398 wpas_clear_temp_disabled(wpa_s, ssid, 1);
5399
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005400 /*
5401 * Mark all other networks disabled or mark all networks enabled if no
5402 * network specified.
5403 */
5404 for (other_ssid = wpa_s->conf->ssid; other_ssid;
5405 other_ssid = other_ssid->next) {
5406 int was_disabled = other_ssid->disabled;
5407 if (was_disabled == 2)
5408 continue; /* do not change persistent P2P group data */
5409
5410 other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005411 if (was_disabled && !other_ssid->disabled)
5412 wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005413
5414 if (was_disabled != other_ssid->disabled)
5415 wpas_notify_network_enabled_changed(wpa_s, other_ssid);
5416 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005417
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005418 if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid &&
5419 wpa_s->wpa_state >= WPA_AUTHENTICATING) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005420 /* We are already associated with the selected network */
5421 wpa_printf(MSG_DEBUG, "Already associated with the "
5422 "selected network - do nothing");
5423 return;
5424 }
5425
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07005426 if (ssid) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005427 wpa_s->current_ssid = ssid;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07005428 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005429 wpa_s->connect_without_scan =
Sunil Ravi640215c2023-06-28 23:08:09 +00005430 (ssid->mode == WPAS_MODE_MESH ||
5431 ssid->mode == WPAS_MODE_AP) ? ssid : NULL;
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07005432
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00005433 if (ssid->scan_ssid) {
5434 if (ssid_in_last_scan(wpa_s, ssid)) {
5435 wpa_printf(MSG_DEBUG,
5436 "Hidden network was scanned for in last scan");
5437 } else if (ssid_in_last_scan_res(wpa_s, ssid)) {
5438 wpa_printf(MSG_DEBUG,
5439 "Hidden network was found in last scan results");
5440 } else {
5441 request_new_scan = true;
5442 wpa_printf(MSG_DEBUG,
5443 "Request a new scan for hidden network");
5444 }
5445 }
5446
5447 if (!request_new_scan && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
5448 !ssid->owe_only) {
Sunil Ravi7f769292024-07-23 22:21:32 +00005449 wpa_printf(MSG_DEBUG,
5450 "Request a new scan for OWE transition SSID");
5451 request_new_scan = true;
5452 }
5453
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07005454 /*
5455 * Don't optimize next scan freqs since a new ESS has been
5456 * selected.
5457 */
5458 os_free(wpa_s->next_scan_freqs);
5459 wpa_s->next_scan_freqs = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005460 } else {
5461 wpa_s->connect_without_scan = NULL;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07005462 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005463
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005464 wpa_s->disconnected = 0;
5465 wpa_s->reassociate = 1;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005466 wpa_s_clear_sae_rejected(wpa_s);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005467 wpa_s->last_owe_group = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07005468 if (ssid) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08005469 ssid->owe_transition_bss_select_count = 0;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00005470 wpa_s_setup_sae_pt(wpa_s, ssid, false);
Hai Shalomc3565922019-10-28 11:58:20 -07005471 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08005472
Sunil Ravi7f769292024-07-23 22:21:32 +00005473 if (wpa_s->connect_without_scan || request_new_scan ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005474 wpa_supplicant_fast_associate(wpa_s) != 1) {
5475 wpa_s->scan_req = NORMAL_SCAN_REQ;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005476 wpas_scan_reset_sched_scan(wpa_s);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08005477 wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005478 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005479
5480 if (ssid)
5481 wpas_notify_network_selected(wpa_s, ssid);
5482}
5483
5484
5485/**
Hai Shalomc1a21442022-02-04 13:43:00 -08005486 * wpas_remove_cred - Remove the specified credential and all the network
5487 * entries created based on the removed credential
5488 * @wpa_s: wpa_supplicant structure for a network interface
5489 * @cred: The credential to remove
5490 * Returns: 0 on success, -1 on failure
5491 */
5492int wpas_remove_cred(struct wpa_supplicant *wpa_s, struct wpa_cred *cred)
5493{
5494 struct wpa_ssid *ssid, *next;
5495 int id;
5496
5497 if (!cred) {
5498 wpa_printf(MSG_DEBUG, "Could not find cred");
5499 return -1;
5500 }
5501
5502 id = cred->id;
5503 if (wpa_config_remove_cred(wpa_s->conf, id) < 0) {
5504 wpa_printf(MSG_DEBUG, "Could not find cred %d", id);
5505 return -1;
5506 }
5507
5508 wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id);
5509
5510 /* Remove any network entry created based on the removed credential */
5511 ssid = wpa_s->conf->ssid;
5512 while (ssid) {
5513 next = ssid->next;
5514
5515 if (ssid->parent_cred == cred) {
5516 wpa_printf(MSG_DEBUG,
5517 "Remove network id %d since it used the removed credential",
5518 ssid->id);
5519 if (wpa_supplicant_remove_network(wpa_s, ssid->id) ==
5520 -1) {
5521 wpa_printf(MSG_DEBUG,
5522 "Could not find network id=%d",
5523 ssid->id);
5524 }
5525 }
5526
5527 ssid = next;
5528 }
5529
5530 return 0;
5531}
5532
5533
5534/**
5535 * wpas_remove_cred - Remove all the Interworking credentials
5536 * @wpa_s: wpa_supplicant structure for a network interface
5537 * Returns: 0 on success, -1 on failure
5538 */
5539int wpas_remove_all_creds(struct wpa_supplicant *wpa_s)
5540{
5541 int res, ret = 0;
5542 struct wpa_cred *cred, *prev;
5543
5544 cred = wpa_s->conf->cred;
5545 while (cred) {
5546 prev = cred;
5547 cred = cred->next;
5548 res = wpas_remove_cred(wpa_s, prev);
5549 if (res < 0) {
5550 wpa_printf(MSG_DEBUG,
5551 "Removal of all credentials failed - failed to remove credential id=%d",
5552 prev->id);
5553 ret = -1;
5554 }
5555 }
5556
5557 return ret;
5558}
5559
5560
5561/**
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08005562 * wpas_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
5563 * @wpa_s: wpa_supplicant structure for a network interface
5564 * @pkcs11_engine_path: PKCS #11 engine path or NULL
5565 * @pkcs11_module_path: PKCS #11 module path or NULL
5566 * Returns: 0 on success; -1 on failure
5567 *
5568 * Sets the PKCS #11 engine and module path. Both have to be NULL or a valid
5569 * path. If resetting the EAPOL state machine with the new PKCS #11 engine and
5570 * module path fails the paths will be reset to the default value (NULL).
5571 */
5572int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s,
5573 const char *pkcs11_engine_path,
5574 const char *pkcs11_module_path)
5575{
5576 char *pkcs11_engine_path_copy = NULL;
5577 char *pkcs11_module_path_copy = NULL;
5578
5579 if (pkcs11_engine_path != NULL) {
5580 pkcs11_engine_path_copy = os_strdup(pkcs11_engine_path);
5581 if (pkcs11_engine_path_copy == NULL)
5582 return -1;
5583 }
5584 if (pkcs11_module_path != NULL) {
5585 pkcs11_module_path_copy = os_strdup(pkcs11_module_path);
Dmitry Shmidt97672262014-02-03 13:02:54 -08005586 if (pkcs11_module_path_copy == NULL) {
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08005587 os_free(pkcs11_engine_path_copy);
5588 return -1;
5589 }
5590 }
5591
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005592#ifndef CONFIG_PKCS11_ENGINE_PATH
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08005593 os_free(wpa_s->conf->pkcs11_engine_path);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08005594 wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path_copy;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005595#endif /* CONFIG_PKCS11_ENGINE_PATH */
5596#ifndef CONFIG_PKCS11_MODULE_PATH
5597 os_free(wpa_s->conf->pkcs11_module_path);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08005598 wpa_s->conf->pkcs11_module_path = pkcs11_module_path_copy;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005599#endif /* CONFIG_PKCS11_MODULE_PATH */
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08005600
5601 wpa_sm_set_eapol(wpa_s->wpa, NULL);
5602 eapol_sm_deinit(wpa_s->eapol);
5603 wpa_s->eapol = NULL;
5604 if (wpa_supplicant_init_eapol(wpa_s)) {
5605 /* Error -> Reset paths to the default value (NULL) once. */
5606 if (pkcs11_engine_path != NULL && pkcs11_module_path != NULL)
5607 wpas_set_pkcs11_engine_and_module_path(wpa_s, NULL,
5608 NULL);
5609
5610 return -1;
5611 }
5612 wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
5613
5614 return 0;
5615}
5616
5617
5618/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005619 * wpa_supplicant_set_ap_scan - Set AP scan mode for interface
5620 * @wpa_s: wpa_supplicant structure for a network interface
5621 * @ap_scan: AP scan mode
5622 * Returns: 0 if succeed or -1 if ap_scan has an invalid value
5623 *
5624 */
5625int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
5626{
5627
5628 int old_ap_scan;
5629
5630 if (ap_scan < 0 || ap_scan > 2)
5631 return -1;
5632
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005633 if (ap_scan == 2 && os_strcmp(wpa_s->driver->name, "nl80211") == 0) {
5634 wpa_printf(MSG_INFO,
5635 "Note: nl80211 driver interface is not designed to be used with ap_scan=2; this can result in connection failures");
5636 }
5637
Dmitry Shmidt114c3862011-08-16 11:52:06 -07005638#ifdef ANDROID
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005639 if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan &&
5640 wpa_s->wpa_state >= WPA_ASSOCIATING &&
5641 wpa_s->wpa_state < WPA_COMPLETED) {
5642 wpa_printf(MSG_ERROR, "ap_scan = %d (%d) rejected while "
5643 "associating", wpa_s->conf->ap_scan, ap_scan);
Dmitry Shmidt114c3862011-08-16 11:52:06 -07005644 return 0;
5645 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005646#endif /* ANDROID */
Dmitry Shmidt114c3862011-08-16 11:52:06 -07005647
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005648 old_ap_scan = wpa_s->conf->ap_scan;
5649 wpa_s->conf->ap_scan = ap_scan;
5650
5651 if (old_ap_scan != wpa_s->conf->ap_scan)
5652 wpas_notify_ap_scan_changed(wpa_s);
5653
5654 return 0;
5655}
5656
5657
5658/**
5659 * wpa_supplicant_set_bss_expiration_age - Set BSS entry expiration age
5660 * @wpa_s: wpa_supplicant structure for a network interface
5661 * @expire_age: Expiration age in seconds
5662 * Returns: 0 if succeed or -1 if expire_age has an invalid value
5663 *
5664 */
5665int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
5666 unsigned int bss_expire_age)
5667{
5668 if (bss_expire_age < 10) {
5669 wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration age %u",
5670 bss_expire_age);
5671 return -1;
5672 }
5673 wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration age: %d sec",
5674 bss_expire_age);
5675 wpa_s->conf->bss_expiration_age = bss_expire_age;
5676
5677 return 0;
5678}
5679
5680
5681/**
5682 * wpa_supplicant_set_bss_expiration_count - Set BSS entry expiration scan count
5683 * @wpa_s: wpa_supplicant structure for a network interface
5684 * @expire_count: number of scans after which an unseen BSS is reclaimed
5685 * Returns: 0 if succeed or -1 if expire_count has an invalid value
5686 *
5687 */
5688int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
5689 unsigned int bss_expire_count)
5690{
5691 if (bss_expire_count < 1) {
5692 wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration count %u",
5693 bss_expire_count);
5694 return -1;
5695 }
5696 wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration scan count: %u",
5697 bss_expire_count);
5698 wpa_s->conf->bss_expiration_scan_count = bss_expire_count;
5699
5700 return 0;
5701}
5702
5703
5704/**
Dmitry Shmidt04949592012-07-19 12:16:46 -07005705 * wpa_supplicant_set_scan_interval - Set scan interval
5706 * @wpa_s: wpa_supplicant structure for a network interface
5707 * @scan_interval: scan interval in seconds
5708 * Returns: 0 if succeed or -1 if scan_interval has an invalid value
5709 *
5710 */
5711int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
5712 int scan_interval)
5713{
5714 if (scan_interval < 0) {
5715 wpa_msg(wpa_s, MSG_ERROR, "Invalid scan interval %d",
5716 scan_interval);
5717 return -1;
5718 }
5719 wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
5720 scan_interval);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08005721 wpa_supplicant_update_scan_int(wpa_s, scan_interval);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005722
5723 return 0;
5724}
5725
5726
5727/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005728 * wpa_supplicant_set_debug_params - Set global debug params
5729 * @global: wpa_global structure
5730 * @debug_level: debug level
5731 * @debug_timestamp: determines if show timestamp in debug data
5732 * @debug_show_keys: determines if show keys in debug data
5733 * Returns: 0 if succeed or -1 if debug_level has wrong value
5734 */
5735int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
5736 int debug_timestamp, int debug_show_keys)
5737{
5738
5739 int old_level, old_timestamp, old_show_keys;
5740
5741 /* check for allowed debuglevels */
5742 if (debug_level != MSG_EXCESSIVE &&
5743 debug_level != MSG_MSGDUMP &&
5744 debug_level != MSG_DEBUG &&
5745 debug_level != MSG_INFO &&
5746 debug_level != MSG_WARNING &&
5747 debug_level != MSG_ERROR)
5748 return -1;
5749
5750 old_level = wpa_debug_level;
5751 old_timestamp = wpa_debug_timestamp;
5752 old_show_keys = wpa_debug_show_keys;
5753
5754 wpa_debug_level = debug_level;
5755 wpa_debug_timestamp = debug_timestamp ? 1 : 0;
5756 wpa_debug_show_keys = debug_show_keys ? 1 : 0;
5757
5758 if (wpa_debug_level != old_level)
5759 wpas_notify_debug_level_changed(global);
5760 if (wpa_debug_timestamp != old_timestamp)
5761 wpas_notify_debug_timestamp_changed(global);
5762 if (wpa_debug_show_keys != old_show_keys)
5763 wpas_notify_debug_show_keys_changed(global);
5764
5765 return 0;
5766}
5767
5768
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005769#ifdef CONFIG_OWE
5770static int owe_trans_ssid_match(struct wpa_supplicant *wpa_s, const u8 *bssid,
5771 const u8 *entry_ssid, size_t entry_ssid_len)
5772{
Sunil Ravic0f5d412024-09-11 22:12:49 +00005773 const u8 *owe, *owe_bssid, *owe_ssid;
5774 size_t owe_ssid_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005775 struct wpa_bss *bss;
5776
5777 /* Check network profile SSID aganst the SSID in the
5778 * OWE Transition Mode element. */
5779
5780 bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
5781 if (!bss)
5782 return 0;
5783
5784 owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
5785 if (!owe)
5786 return 0;
5787
Sunil Ravic0f5d412024-09-11 22:12:49 +00005788 if (wpas_get_owe_trans_network(owe, &owe_bssid, &owe_ssid,
5789 &owe_ssid_len))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005790 return 0;
5791
Sunil Ravic0f5d412024-09-11 22:12:49 +00005792 return entry_ssid_len == owe_ssid_len &&
5793 os_memcmp(owe_ssid, entry_ssid, owe_ssid_len) == 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005794}
5795#endif /* CONFIG_OWE */
5796
5797
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005798/**
5799 * wpa_supplicant_get_ssid - Get a pointer to the current network structure
5800 * @wpa_s: Pointer to wpa_supplicant data
5801 * Returns: A pointer to the current network structure or %NULL on failure
5802 */
5803struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
5804{
5805 struct wpa_ssid *entry;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07005806 u8 ssid[SSID_MAX_LEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005807 int res;
5808 size_t ssid_len;
5809 u8 bssid[ETH_ALEN];
5810 int wired;
5811
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005812 res = wpa_drv_get_ssid(wpa_s, ssid);
5813 if (res < 0) {
5814 wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
5815 "driver");
5816 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005817 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005818 ssid_len = res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005819
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005820 if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005821 wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from "
5822 "driver");
5823 return NULL;
5824 }
5825
5826 wired = wpa_s->conf->ap_scan == 0 &&
5827 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED);
5828
5829 entry = wpa_s->conf->ssid;
5830 while (entry) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07005831 if (!wpas_network_disabled(wpa_s, entry) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005832 ((ssid_len == entry->ssid_len &&
Hai Shalom021b0b52019-04-10 11:17:58 -07005833 (!entry->ssid ||
5834 os_memcmp(ssid, entry->ssid, ssid_len) == 0)) ||
5835 wired) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005836 (!entry->bssid_set ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005837 ether_addr_equal(bssid, entry->bssid)))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005838 return entry;
5839#ifdef CONFIG_WPS
Dmitry Shmidt04949592012-07-19 12:16:46 -07005840 if (!wpas_network_disabled(wpa_s, entry) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005841 (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
5842 (entry->ssid == NULL || entry->ssid_len == 0) &&
5843 (!entry->bssid_set ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005844 ether_addr_equal(bssid, entry->bssid)))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005845 return entry;
5846#endif /* CONFIG_WPS */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005847
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005848#ifdef CONFIG_OWE
5849 if (!wpas_network_disabled(wpa_s, entry) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005850 (entry->ssid &&
5851 owe_trans_ssid_match(wpa_s, bssid, entry->ssid,
5852 entry->ssid_len)) &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005853 (!entry->bssid_set ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005854 ether_addr_equal(bssid, entry->bssid)))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005855 return entry;
5856#endif /* CONFIG_OWE */
5857
Dmitry Shmidt04949592012-07-19 12:16:46 -07005858 if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005859 entry->ssid_len == 0 &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005860 ether_addr_equal(bssid, entry->bssid))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005861 return entry;
5862
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005863 entry = entry->next;
5864 }
5865
5866 return NULL;
5867}
5868
5869
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005870static int select_driver(struct wpa_supplicant *wpa_s, int i)
5871{
5872 struct wpa_global *global = wpa_s->global;
5873
5874 if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
Dmitry Shmidte4663042016-04-04 10:07:49 -07005875 global->drv_priv[i] = wpa_drivers[i]->global_init(global);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005876 if (global->drv_priv[i] == NULL) {
5877 wpa_printf(MSG_ERROR, "Failed to initialize driver "
5878 "'%s'", wpa_drivers[i]->name);
5879 return -1;
5880 }
5881 }
5882
5883 wpa_s->driver = wpa_drivers[i];
5884 wpa_s->global_drv_priv = global->drv_priv[i];
5885
5886 return 0;
5887}
5888
5889
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005890static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
5891 const char *name)
5892{
5893 int i;
5894 size_t len;
5895 const char *pos, *driver = name;
5896
5897 if (wpa_s == NULL)
5898 return -1;
5899
5900 if (wpa_drivers[0] == NULL) {
5901 wpa_msg(wpa_s, MSG_ERROR, "No driver interfaces build into "
5902 "wpa_supplicant");
5903 return -1;
5904 }
5905
5906 if (name == NULL) {
Hai Shalomc1a21442022-02-04 13:43:00 -08005907 /* Default to first successful driver in the list */
5908 for (i = 0; wpa_drivers[i]; i++) {
5909 if (select_driver(wpa_s, i) == 0)
5910 return 0;
5911 }
5912 /* Drivers have each reported failure, so no wpa_msg() here. */
5913 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005914 }
5915
5916 do {
5917 pos = os_strchr(driver, ',');
5918 if (pos)
5919 len = pos - driver;
5920 else
5921 len = os_strlen(driver);
5922
5923 for (i = 0; wpa_drivers[i]; i++) {
5924 if (os_strlen(wpa_drivers[i]->name) == len &&
5925 os_strncmp(driver, wpa_drivers[i]->name, len) ==
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005926 0) {
5927 /* First driver that succeeds wins */
5928 if (select_driver(wpa_s, i) == 0)
5929 return 0;
5930 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005931 }
5932
5933 driver = pos + 1;
5934 } while (pos);
5935
5936 wpa_msg(wpa_s, MSG_ERROR, "Unsupported driver '%s'", name);
5937 return -1;
5938}
5939
5940
5941/**
5942 * wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant
5943 * @ctx: Context pointer (wpa_s); this is the ctx variable registered
5944 * with struct wpa_driver_ops::init()
5945 * @src_addr: Source address of the EAPOL frame
5946 * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
5947 * @len: Length of the EAPOL data
Sunil8cd6f4d2022-06-28 18:40:46 +00005948 * @encrypted: Whether the frame was encrypted
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005949 *
5950 * This function is called for each received EAPOL frame. Most driver
5951 * interfaces rely on more generic OS mechanism for receiving frames through
5952 * l2_packet, but if such a mechanism is not available, the driver wrapper may
5953 * take care of received EAPOL frames and deliver them to the core supplicant
5954 * code by calling this function.
5955 */
5956void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
Sunil8cd6f4d2022-06-28 18:40:46 +00005957 const u8 *buf, size_t len,
5958 enum frame_encryption encrypted)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005959{
5960 struct wpa_supplicant *wpa_s = ctx;
Sunil Ravi77d572f2023-01-17 23:58:31 +00005961 const u8 *connected_addr = wpa_s->valid_links ?
5962 wpa_s->ap_mld_addr : wpa_s->bssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005963
Sunil8cd6f4d2022-06-28 18:40:46 +00005964 wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " (encrypted=%d)",
5965 MAC2STR(src_addr), encrypted);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005966 wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
5967
Hai Shalomc1a21442022-02-04 13:43:00 -08005968 if (wpa_s->own_disconnect_req) {
5969 wpa_printf(MSG_DEBUG,
5970 "Drop received EAPOL frame as we are disconnecting");
5971 return;
5972 }
5973
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005974#ifdef CONFIG_TESTING_OPTIONS
Hai Shalomc1a21442022-02-04 13:43:00 -08005975 wpa_msg_ctrl(wpa_s, MSG_INFO, "EAPOL-RX " MACSTR " %zu",
5976 MAC2STR(src_addr), len);
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005977 if (wpa_s->ignore_auth_resp) {
5978 wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
5979 return;
5980 }
5981#endif /* CONFIG_TESTING_OPTIONS */
5982
Jouni Malinena05074c2012-12-21 21:35:35 +02005983 if (wpa_s->wpa_state < WPA_ASSOCIATED ||
5984 (wpa_s->last_eapol_matches_bssid &&
5985#ifdef CONFIG_AP
5986 !wpa_s->ap_iface &&
5987#endif /* CONFIG_AP */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005988 !ether_addr_equal(src_addr, connected_addr))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005989 /*
5990 * There is possible race condition between receiving the
5991 * association event and the EAPOL frame since they are coming
5992 * through different paths from the driver. In order to avoid
5993 * issues in trying to process the EAPOL frame before receiving
5994 * association information, lets queue it for processing until
Jouni Malinena05074c2012-12-21 21:35:35 +02005995 * the association event is received. This may also be needed in
5996 * driver-based roaming case, so also use src_addr != BSSID as a
5997 * trigger if we have previously confirmed that the
5998 * Authenticator uses BSSID as the src_addr (which is not the
5999 * case with wired IEEE 802.1X).
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006000 */
Sunil Ravi77d572f2023-01-17 23:58:31 +00006001 wpa_dbg(wpa_s, MSG_DEBUG,
6002 "Not associated - Delay processing of received EAPOL frame (state=%s connected_addr="
6003 MACSTR ")",
Jouni Malinena05074c2012-12-21 21:35:35 +02006004 wpa_supplicant_state_txt(wpa_s->wpa_state),
Sunil Ravi77d572f2023-01-17 23:58:31 +00006005 MAC2STR(connected_addr));
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00006006 delay_processing:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006007 wpabuf_free(wpa_s->pending_eapol_rx);
6008 wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
6009 if (wpa_s->pending_eapol_rx) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006010 os_get_reltime(&wpa_s->pending_eapol_rx_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006011 os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
6012 ETH_ALEN);
Sunil8cd6f4d2022-06-28 18:40:46 +00006013 wpa_s->pending_eapol_encrypted = encrypted;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006014 }
6015 return;
6016 }
6017
Jouni Malinena05074c2012-12-21 21:35:35 +02006018 wpa_s->last_eapol_matches_bssid =
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006019 ether_addr_equal(src_addr, connected_addr);
Jouni Malinena05074c2012-12-21 21:35:35 +02006020
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006021#ifdef CONFIG_AP
6022 if (wpa_s->ap_iface) {
Sunil8cd6f4d2022-06-28 18:40:46 +00006023 wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len,
6024 encrypted);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006025 return;
6026 }
6027#endif /* CONFIG_AP */
6028
6029 if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
6030 wpa_dbg(wpa_s, MSG_DEBUG, "Ignored received EAPOL frame since "
6031 "no key management is configured");
6032 return;
6033 }
6034
6035 if (wpa_s->eapol_received == 0 &&
Hai Shalom74f70d42019-02-11 14:42:39 -08006036 (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006037 !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
6038 wpa_s->wpa_state != WPA_COMPLETED) &&
6039 (wpa_s->current_ssid == NULL ||
Hai Shalom81f62d82019-07-22 12:10:00 -07006040 wpa_s->current_ssid->mode != WPAS_MODE_IBSS)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006041 /* Timeout for completing IEEE 802.1X and WPA authentication */
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07006042 int timeout = 10;
6043
6044 if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
6045 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
6046 wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
6047 /* Use longer timeout for IEEE 802.1X/EAP */
6048 timeout = 70;
6049 }
6050
Dmitry Shmidt8bd70b72015-05-26 16:02:19 -07006051#ifdef CONFIG_WPS
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07006052 if (wpa_s->current_ssid && wpa_s->current_bss &&
6053 (wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
6054 eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
6055 /*
6056 * Use shorter timeout if going through WPS AP iteration
6057 * for PIN config method with an AP that does not
6058 * advertise Selected Registrar.
6059 */
6060 struct wpabuf *wps_ie;
6061
6062 wps_ie = wpa_bss_get_vendor_ie_multi(
6063 wpa_s->current_bss, WPS_IE_VENDOR_TYPE);
6064 if (wps_ie &&
6065 !wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1))
6066 timeout = 10;
6067 wpabuf_free(wps_ie);
6068 }
Dmitry Shmidt8bd70b72015-05-26 16:02:19 -07006069#endif /* CONFIG_WPS */
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07006070
6071 wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006072 }
6073 wpa_s->eapol_received++;
6074
6075 if (wpa_s->countermeasures) {
6076 wpa_msg(wpa_s, MSG_INFO, "WPA: Countermeasures - dropped "
6077 "EAPOL packet");
6078 return;
6079 }
6080
6081#ifdef CONFIG_IBSS_RSN
6082 if (wpa_s->current_ssid &&
6083 wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
Sunil8cd6f4d2022-06-28 18:40:46 +00006084 ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len,
6085 encrypted);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006086 return;
6087 }
6088#endif /* CONFIG_IBSS_RSN */
6089
6090 /* Source address of the incoming EAPOL frame could be compared to the
6091 * current BSSID. However, it is possible that a centralized
6092 * Authenticator could be using another MAC address than the BSSID of
6093 * an AP, so just allow any address to be used for now. The replies are
6094 * still sent to the current BSSID (if available), though. */
6095
6096 os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
6097 if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006098 wpa_s->key_mgmt != WPA_KEY_MGMT_OWE &&
6099 wpa_s->key_mgmt != WPA_KEY_MGMT_DPP &&
Sunil8cd6f4d2022-06-28 18:40:46 +00006100 eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len,
6101 encrypted) > 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006102 return;
6103 wpa_drv_poll(wpa_s);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00006104 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
6105 if (wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len,
6106 encrypted) == -2 &&
6107#ifdef CONFIG_AP
6108 !wpa_s->ap_iface &&
6109#endif /* CONFIG_AP */
6110 wpa_s->last_eapol_matches_bssid) {
6111 /* Handle the case where reassociation occurs to the
6112 * current connected AP */
6113 wpa_dbg(wpa_s, MSG_DEBUG,
6114 "Delay processing of received EAPOL frame for reassociation to the current connected AP (state=%s connected_addr="
6115 MACSTR ")",
6116 wpa_supplicant_state_txt(wpa_s->wpa_state),
6117 MAC2STR(connected_addr));
6118 goto delay_processing;
6119 }
6120 } else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006121 /*
Hai Shalome21d4e82020-04-29 16:34:06 -07006122 * Set portValid = true here since we are going to skip 4-way
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006123 * handshake processing which would normally set portValid. We
6124 * need this to allow the EAPOL state machines to be completed
6125 * without going through EAPOL-Key handshake.
6126 */
Hai Shalome21d4e82020-04-29 16:34:06 -07006127 eapol_sm_notify_portValid(wpa_s->eapol, true);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006128 }
6129}
6130
6131
Sunil8cd6f4d2022-06-28 18:40:46 +00006132static void wpa_supplicant_rx_eapol_cb(void *ctx, const u8 *src_addr,
6133 const u8 *buf, size_t len)
6134{
6135 wpa_supplicant_rx_eapol(ctx, src_addr, buf, len,
6136 FRAME_ENCRYPTION_UNKNOWN);
6137}
6138
6139
Hai Shalomb755a2a2020-04-23 21:49:02 -07006140static int wpas_eapol_needs_l2_packet(struct wpa_supplicant *wpa_s)
6141{
6142 return !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) ||
6143 !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX);
6144}
6145
6146
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006147int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006148{
Sunil Ravi77d572f2023-01-17 23:58:31 +00006149 u8 prev_mac_addr[ETH_ALEN];
6150
6151 os_memcpy(prev_mac_addr, wpa_s->own_addr, ETH_ALEN);
6152
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006153 if ((!wpa_s->p2p_mgmt ||
6154 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
6155 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006156 l2_packet_deinit(wpa_s->l2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006157 wpa_s->l2 = l2_packet_init(wpa_s->ifname,
6158 wpa_drv_get_mac_addr(wpa_s),
6159 ETH_P_EAPOL,
Hai Shalomb755a2a2020-04-23 21:49:02 -07006160 wpas_eapol_needs_l2_packet(wpa_s) ?
Sunil8cd6f4d2022-06-28 18:40:46 +00006161 wpa_supplicant_rx_eapol_cb : NULL,
Hai Shalomb755a2a2020-04-23 21:49:02 -07006162 wpa_s, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006163 if (wpa_s->l2 == NULL)
6164 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006165
6166 if (l2_packet_set_packet_filter(wpa_s->l2,
6167 L2_PACKET_FILTER_PKTTYPE))
6168 wpa_dbg(wpa_s, MSG_DEBUG,
6169 "Failed to attach pkt_type filter");
Hai Shalomb755a2a2020-04-23 21:49:02 -07006170
6171 if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
6172 wpa_msg(wpa_s, MSG_ERROR,
6173 "Failed to get own L2 address");
6174 return -1;
6175 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006176 } else {
6177 const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
6178 if (addr)
6179 os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
6180 }
6181
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006182 wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
Mikael Kanstrupcc779b82019-08-16 08:50:54 +02006183 wpas_wps_update_mac_addr(wpa_s);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006184
Hai Shalomc3565922019-10-28 11:58:20 -07006185#ifdef CONFIG_FST
6186 if (wpa_s->fst)
6187 fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
6188#endif /* CONFIG_FST */
6189
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006190 if (!ether_addr_equal(prev_mac_addr, wpa_s->own_addr))
Sunil Ravi77d572f2023-01-17 23:58:31 +00006191 wpas_notify_mac_address_changed(wpa_s);
6192
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006193 return 0;
6194}
6195
6196
Dmitry Shmidt04949592012-07-19 12:16:46 -07006197static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
6198 const u8 *buf, size_t len)
6199{
6200 struct wpa_supplicant *wpa_s = ctx;
6201 const struct l2_ethhdr *eth;
6202
6203 if (len < sizeof(*eth))
6204 return;
6205 eth = (const struct l2_ethhdr *) buf;
6206
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006207 if (!ether_addr_equal(eth->h_dest, wpa_s->own_addr) &&
Dmitry Shmidt04949592012-07-19 12:16:46 -07006208 !(eth->h_dest[0] & 0x01)) {
6209 wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
6210 " (bridge - not for this interface - ignore)",
6211 MAC2STR(src_addr), MAC2STR(eth->h_dest));
6212 return;
6213 }
6214
6215 wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
6216 " (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
6217 wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
Sunil8cd6f4d2022-06-28 18:40:46 +00006218 len - sizeof(*eth), FRAME_ENCRYPTION_UNKNOWN);
Dmitry Shmidt04949592012-07-19 12:16:46 -07006219}
6220
6221
Hai Shalom899fcc72020-10-19 14:38:18 -07006222int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s,
6223 const char *bridge_ifname)
6224{
6225 if (wpa_s->wpa_state > WPA_SCANNING)
6226 return -EBUSY;
6227
6228 if (bridge_ifname &&
6229 os_strlen(bridge_ifname) >= sizeof(wpa_s->bridge_ifname))
6230 return -EINVAL;
6231
6232 if (!bridge_ifname)
6233 bridge_ifname = "";
6234
6235 if (os_strcmp(wpa_s->bridge_ifname, bridge_ifname) == 0)
6236 return 0;
6237
6238 if (wpa_s->l2_br) {
6239 l2_packet_deinit(wpa_s->l2_br);
6240 wpa_s->l2_br = NULL;
6241 }
6242
6243 os_strlcpy(wpa_s->bridge_ifname, bridge_ifname,
6244 sizeof(wpa_s->bridge_ifname));
6245
6246 if (wpa_s->bridge_ifname[0]) {
6247 wpa_dbg(wpa_s, MSG_DEBUG,
6248 "Receiving packets from bridge interface '%s'",
6249 wpa_s->bridge_ifname);
6250 wpa_s->l2_br = l2_packet_init_bridge(
6251 wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
6252 ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
6253 if (!wpa_s->l2_br) {
6254 wpa_msg(wpa_s, MSG_ERROR,
6255 "Failed to open l2_packet connection for the bridge interface '%s'",
6256 wpa_s->bridge_ifname);
6257 goto fail;
6258 }
6259 }
6260
6261#ifdef CONFIG_TDLS
6262 if (!wpa_s->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
6263 goto fail;
6264#endif /* CONFIG_TDLS */
6265
6266 return 0;
6267fail:
6268 wpa_s->bridge_ifname[0] = 0;
6269 if (wpa_s->l2_br) {
6270 l2_packet_deinit(wpa_s->l2_br);
6271 wpa_s->l2_br = NULL;
6272 }
6273#ifdef CONFIG_TDLS
6274 if (!wpa_s->p2p_mgmt)
6275 wpa_tdls_init(wpa_s->wpa);
6276#endif /* CONFIG_TDLS */
6277 return -EIO;
6278}
6279
6280
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006281/**
6282 * wpa_supplicant_driver_init - Initialize driver interface parameters
6283 * @wpa_s: Pointer to wpa_supplicant data
6284 * Returns: 0 on success, -1 on failure
6285 *
6286 * This function is called to initialize driver interface parameters.
6287 * wpa_drv_init() must have been called before this function to initialize the
6288 * driver interface.
6289 */
6290int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
6291{
6292 static int interface_count = 0;
6293
6294 if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
6295 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006296
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006297 wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
6298 MAC2STR(wpa_s->own_addr));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006299 os_memcpy(wpa_s->perm_addr, wpa_s->own_addr, ETH_ALEN);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006300 wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
6301
Hai Shalomb755a2a2020-04-23 21:49:02 -07006302 if (wpa_s->bridge_ifname[0] && wpas_eapol_needs_l2_packet(wpa_s)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006303 wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
6304 "interface '%s'", wpa_s->bridge_ifname);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08006305 wpa_s->l2_br = l2_packet_init_bridge(
6306 wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
6307 ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006308 if (wpa_s->l2_br == NULL) {
6309 wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
6310 "connection for the bridge interface '%s'",
6311 wpa_s->bridge_ifname);
6312 return -1;
6313 }
6314 }
6315
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006316 if (wpa_s->conf->ap_scan == 2 &&
6317 os_strcmp(wpa_s->driver->name, "nl80211") == 0) {
6318 wpa_printf(MSG_INFO,
6319 "Note: nl80211 driver interface is not designed to be used with ap_scan=2; this can result in connection failures");
6320 }
6321
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006322 wpa_clear_keys(wpa_s, NULL);
6323
6324 /* Make sure that TKIP countermeasures are not left enabled (could
6325 * happen if wpa_supplicant is killed during countermeasures. */
6326 wpa_drv_set_countermeasures(wpa_s, 0);
6327
6328 wpa_dbg(wpa_s, MSG_DEBUG, "RSN: flushing PMKID list in the driver");
6329 wpa_drv_flush_pmkid(wpa_s);
6330
6331 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006332 wpa_s->prev_scan_wildcard = 0;
6333
Dmitry Shmidt04949592012-07-19 12:16:46 -07006334 if (wpa_supplicant_enabled_networks(wpa_s)) {
Dmitry Shmidt9e3f8ee2014-01-17 10:52:01 -08006335 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
6336 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
6337 interface_count = 0;
6338 }
Keith Mok4389c282022-11-23 21:36:48 +00006339#ifndef CONFIG_CTRL_IFACE_AIDL
Dmitry Shmidta38abf92014-03-06 13:38:44 -08006340 if (!wpa_s->p2p_mgmt &&
Dmitry Shmidt98660862014-03-11 17:26:21 -07006341 wpa_supplicant_delayed_sched_scan(wpa_s,
6342 interface_count % 3,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006343 100000))
Dmitry Shmidt98660862014-03-11 17:26:21 -07006344 wpa_supplicant_req_scan(wpa_s, interface_count % 3,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006345 100000);
Keith Mok4389c282022-11-23 21:36:48 +00006346#endif /* CONFIG_CTRL_IFACE_AIDL */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006347 interface_count++;
6348 } else
6349 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
6350
6351 return 0;
6352}
6353
6354
6355static int wpa_supplicant_daemon(const char *pid_file)
6356{
6357 wpa_printf(MSG_DEBUG, "Daemonize..");
6358 return os_daemonize(pid_file);
6359}
6360
6361
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08006362static struct wpa_supplicant *
6363wpa_supplicant_alloc(struct wpa_supplicant *parent)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006364{
6365 struct wpa_supplicant *wpa_s;
6366
6367 wpa_s = os_zalloc(sizeof(*wpa_s));
6368 if (wpa_s == NULL)
6369 return NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006370 wpa_s->scan_req = INITIAL_SCAN_REQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006371 wpa_s->scan_interval = 5;
6372 wpa_s->new_connection = 1;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08006373 wpa_s->parent = parent ? parent : wpa_s;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08006374 wpa_s->p2pdev = wpa_s->parent;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00006375#ifdef CONFIG_P2P
6376 if (parent)
6377 wpa_s->p2p_mode = parent->p2p_mode;
6378#endif /* CONFIG_P2P */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006379 wpa_s->sched_scanning = 0;
Hai Shalom60840252021-02-19 19:02:11 -08006380 wpa_s->setband_mask = WPA_SETBAND_AUTO;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006381
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006382 dl_list_init(&wpa_s->bss_tmp_disallowed);
Paul Stewart092955c2017-02-06 09:13:09 -08006383 dl_list_init(&wpa_s->fils_hlp_req);
Hai Shalomfdcde762020-04-02 11:19:20 -07006384#ifdef CONFIG_TESTING_OPTIONS
6385 dl_list_init(&wpa_s->drv_signal_override);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006386 wpa_s->test_assoc_comeback_type = -1;
Hai Shalomfdcde762020-04-02 11:19:20 -07006387#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006388#ifndef CONFIG_NO_ROBUST_AV
Hai Shalomc1a21442022-02-04 13:43:00 -08006389 dl_list_init(&wpa_s->active_scs_ids);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006390#endif /* CONFIG_NO_ROBUST_AV */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006391 wpa_s->ml_probe_mld_id = -1;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006392
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006393 return wpa_s;
6394}
6395
6396
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006397#ifdef CONFIG_HT_OVERRIDES
6398
6399static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
6400 struct ieee80211_ht_capabilities *htcaps,
6401 struct ieee80211_ht_capabilities *htcaps_mask,
6402 const char *ht_mcs)
6403{
6404 /* parse ht_mcs into hex array */
6405 int i;
6406 const char *tmp = ht_mcs;
6407 char *end = NULL;
6408
6409 /* If ht_mcs is null, do not set anything */
6410 if (!ht_mcs)
6411 return 0;
6412
6413 /* This is what we are setting in the kernel */
6414 os_memset(&htcaps->supported_mcs_set, 0, IEEE80211_HT_MCS_MASK_LEN);
6415
6416 wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
6417
6418 for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
Paul Stewart092955c2017-02-06 09:13:09 -08006419 long v;
6420
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006421 errno = 0;
Paul Stewart092955c2017-02-06 09:13:09 -08006422 v = strtol(tmp, &end, 16);
6423
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006424 if (errno == 0) {
6425 wpa_msg(wpa_s, MSG_DEBUG,
6426 "htcap value[%i]: %ld end: %p tmp: %p",
6427 i, v, end, tmp);
6428 if (end == tmp)
6429 break;
6430
6431 htcaps->supported_mcs_set[i] = v;
6432 tmp = end;
6433 } else {
6434 wpa_msg(wpa_s, MSG_ERROR,
6435 "Failed to parse ht-mcs: %s, error: %s\n",
6436 ht_mcs, strerror(errno));
6437 return -1;
6438 }
6439 }
6440
6441 /*
6442 * If we were able to parse any values, then set mask for the MCS set.
6443 */
6444 if (i) {
6445 os_memset(&htcaps_mask->supported_mcs_set, 0xff,
6446 IEEE80211_HT_MCS_MASK_LEN - 1);
6447 /* skip the 3 reserved bits */
6448 htcaps_mask->supported_mcs_set[IEEE80211_HT_MCS_MASK_LEN - 1] =
6449 0x1f;
6450 }
6451
6452 return 0;
6453}
6454
6455
6456static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
6457 struct ieee80211_ht_capabilities *htcaps,
6458 struct ieee80211_ht_capabilities *htcaps_mask,
6459 int disabled)
6460{
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006461 le16 msk;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006462
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006463 if (disabled == -1)
6464 return 0;
6465
Hai Shalom74f70d42019-02-11 14:42:39 -08006466 wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
6467
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006468 msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
6469 htcaps_mask->ht_capabilities_info |= msk;
6470 if (disabled)
6471 htcaps->ht_capabilities_info &= msk;
6472 else
6473 htcaps->ht_capabilities_info |= msk;
6474
6475 return 0;
6476}
6477
6478
6479static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
6480 struct ieee80211_ht_capabilities *htcaps,
6481 struct ieee80211_ht_capabilities *htcaps_mask,
6482 int factor)
6483{
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006484 if (factor == -1)
6485 return 0;
6486
Hai Shalom74f70d42019-02-11 14:42:39 -08006487 wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
6488
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006489 if (factor < 0 || factor > 3) {
6490 wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
6491 "Must be 0-3 or -1", factor);
6492 return -EINVAL;
6493 }
6494
6495 htcaps_mask->a_mpdu_params |= 0x3; /* 2 bits for factor */
6496 htcaps->a_mpdu_params &= ~0x3;
6497 htcaps->a_mpdu_params |= factor & 0x3;
6498
6499 return 0;
6500}
6501
6502
6503static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
6504 struct ieee80211_ht_capabilities *htcaps,
6505 struct ieee80211_ht_capabilities *htcaps_mask,
6506 int density)
6507{
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006508 if (density == -1)
6509 return 0;
6510
Hai Shalom74f70d42019-02-11 14:42:39 -08006511 wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
6512
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006513 if (density < 0 || density > 7) {
6514 wpa_msg(wpa_s, MSG_ERROR,
6515 "ampdu_density: %d out of range. Must be 0-7 or -1.",
6516 density);
6517 return -EINVAL;
6518 }
6519
6520 htcaps_mask->a_mpdu_params |= 0x1C;
6521 htcaps->a_mpdu_params &= ~(0x1C);
6522 htcaps->a_mpdu_params |= (density << 2) & 0x1C;
6523
6524 return 0;
6525}
6526
6527
6528static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
6529 struct ieee80211_ht_capabilities *htcaps,
6530 struct ieee80211_ht_capabilities *htcaps_mask,
6531 int disabled)
6532{
Hai Shalom74f70d42019-02-11 14:42:39 -08006533 if (disabled)
6534 wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006535
Paul Stewart092955c2017-02-06 09:13:09 -08006536 set_disable_ht40(htcaps, disabled);
6537 set_disable_ht40(htcaps_mask, 0);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006538
6539 return 0;
6540}
6541
6542
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006543static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
6544 struct ieee80211_ht_capabilities *htcaps,
6545 struct ieee80211_ht_capabilities *htcaps_mask,
6546 int disabled)
6547{
6548 /* Masking these out disables SGI */
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006549 le16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
6550 HT_CAP_INFO_SHORT_GI40MHZ);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006551
Hai Shalom74f70d42019-02-11 14:42:39 -08006552 if (disabled)
6553 wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006554
6555 if (disabled)
6556 htcaps->ht_capabilities_info &= ~msk;
6557 else
6558 htcaps->ht_capabilities_info |= msk;
6559
6560 htcaps_mask->ht_capabilities_info |= msk;
6561
6562 return 0;
6563}
6564
6565
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006566static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s,
6567 struct ieee80211_ht_capabilities *htcaps,
6568 struct ieee80211_ht_capabilities *htcaps_mask,
6569 int disabled)
6570{
6571 /* Masking these out disables LDPC */
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006572 le16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006573
Hai Shalom74f70d42019-02-11 14:42:39 -08006574 if (disabled)
6575 wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006576
6577 if (disabled)
6578 htcaps->ht_capabilities_info &= ~msk;
6579 else
6580 htcaps->ht_capabilities_info |= msk;
6581
6582 htcaps_mask->ht_capabilities_info |= msk;
6583
6584 return 0;
6585}
6586
6587
Hai Shalom74f70d42019-02-11 14:42:39 -08006588static int wpa_set_tx_stbc(struct wpa_supplicant *wpa_s,
6589 struct ieee80211_ht_capabilities *htcaps,
6590 struct ieee80211_ht_capabilities *htcaps_mask,
6591 int tx_stbc)
6592{
6593 le16 msk = host_to_le16(HT_CAP_INFO_TX_STBC);
6594
6595 if (tx_stbc == -1)
6596 return 0;
6597
6598 wpa_msg(wpa_s, MSG_DEBUG, "set_tx_stbc: %d", tx_stbc);
6599
6600 if (tx_stbc < 0 || tx_stbc > 1) {
6601 wpa_msg(wpa_s, MSG_ERROR,
6602 "tx_stbc: %d out of range. Must be 0-1 or -1", tx_stbc);
6603 return -EINVAL;
6604 }
6605
6606 htcaps_mask->ht_capabilities_info |= msk;
6607 htcaps->ht_capabilities_info &= ~msk;
6608 htcaps->ht_capabilities_info |= (tx_stbc << 7) & msk;
6609
6610 return 0;
6611}
6612
6613
6614static int wpa_set_rx_stbc(struct wpa_supplicant *wpa_s,
6615 struct ieee80211_ht_capabilities *htcaps,
6616 struct ieee80211_ht_capabilities *htcaps_mask,
6617 int rx_stbc)
6618{
6619 le16 msk = host_to_le16(HT_CAP_INFO_RX_STBC_MASK);
6620
6621 if (rx_stbc == -1)
6622 return 0;
6623
6624 wpa_msg(wpa_s, MSG_DEBUG, "set_rx_stbc: %d", rx_stbc);
6625
6626 if (rx_stbc < 0 || rx_stbc > 3) {
6627 wpa_msg(wpa_s, MSG_ERROR,
6628 "rx_stbc: %d out of range. Must be 0-3 or -1", rx_stbc);
6629 return -EINVAL;
6630 }
6631
6632 htcaps_mask->ht_capabilities_info |= msk;
6633 htcaps->ht_capabilities_info &= ~msk;
6634 htcaps->ht_capabilities_info |= (rx_stbc << 8) & msk;
6635
6636 return 0;
6637}
6638
6639
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006640void wpa_supplicant_apply_ht_overrides(
6641 struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
6642 struct wpa_driver_associate_params *params)
6643{
6644 struct ieee80211_ht_capabilities *htcaps;
6645 struct ieee80211_ht_capabilities *htcaps_mask;
6646
6647 if (!ssid)
6648 return;
6649
6650 params->disable_ht = ssid->disable_ht;
6651 if (!params->htcaps || !params->htcaps_mask)
6652 return;
6653
6654 htcaps = (struct ieee80211_ht_capabilities *) params->htcaps;
6655 htcaps_mask = (struct ieee80211_ht_capabilities *) params->htcaps_mask;
6656 wpa_set_htcap_mcs(wpa_s, htcaps, htcaps_mask, ssid->ht_mcs);
6657 wpa_disable_max_amsdu(wpa_s, htcaps, htcaps_mask,
6658 ssid->disable_max_amsdu);
6659 wpa_set_ampdu_factor(wpa_s, htcaps, htcaps_mask, ssid->ampdu_factor);
6660 wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
6661 wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006662 wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006663 wpa_set_disable_ldpc(wpa_s, htcaps, htcaps_mask, ssid->disable_ldpc);
Hai Shalom74f70d42019-02-11 14:42:39 -08006664 wpa_set_rx_stbc(wpa_s, htcaps, htcaps_mask, ssid->rx_stbc);
6665 wpa_set_tx_stbc(wpa_s, htcaps, htcaps_mask, ssid->tx_stbc);
Dmitry Shmidt61593f02014-04-21 16:27:35 -07006666
6667 if (ssid->ht40_intolerant) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006668 le16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT);
Dmitry Shmidt61593f02014-04-21 16:27:35 -07006669 htcaps->ht_capabilities_info |= bit;
6670 htcaps_mask->ht_capabilities_info |= bit;
6671 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006672}
6673
6674#endif /* CONFIG_HT_OVERRIDES */
6675
6676
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006677#ifdef CONFIG_VHT_OVERRIDES
6678void wpa_supplicant_apply_vht_overrides(
6679 struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
6680 struct wpa_driver_associate_params *params)
6681{
6682 struct ieee80211_vht_capabilities *vhtcaps;
6683 struct ieee80211_vht_capabilities *vhtcaps_mask;
6684
6685 if (!ssid)
6686 return;
6687
6688 params->disable_vht = ssid->disable_vht;
6689
6690 vhtcaps = (void *) params->vhtcaps;
6691 vhtcaps_mask = (void *) params->vhtcaps_mask;
6692
6693 if (!vhtcaps || !vhtcaps_mask)
6694 return;
6695
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006696 vhtcaps->vht_capabilities_info = host_to_le32(ssid->vht_capa);
6697 vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask);
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006698
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006699#ifdef CONFIG_HT_OVERRIDES
Hai Shalom74f70d42019-02-11 14:42:39 -08006700 if (ssid->disable_sgi) {
6701 vhtcaps_mask->vht_capabilities_info |= (VHT_CAP_SHORT_GI_80 |
6702 VHT_CAP_SHORT_GI_160);
6703 vhtcaps->vht_capabilities_info &= ~(VHT_CAP_SHORT_GI_80 |
6704 VHT_CAP_SHORT_GI_160);
6705 wpa_msg(wpa_s, MSG_DEBUG,
6706 "disable-sgi override specified, vht-caps: 0x%x",
6707 vhtcaps->vht_capabilities_info);
6708 }
6709
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006710 /* if max ampdu is <= 3, we have to make the HT cap the same */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006711 if (ssid->vht_capa_mask & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) {
6712 int max_ampdu;
6713
6714 max_ampdu = (ssid->vht_capa &
6715 VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) >>
6716 VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006717
6718 max_ampdu = max_ampdu < 3 ? max_ampdu : 3;
6719 wpa_set_ampdu_factor(wpa_s,
6720 (void *) params->htcaps,
6721 (void *) params->htcaps_mask,
6722 max_ampdu);
6723 }
6724#endif /* CONFIG_HT_OVERRIDES */
6725
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006726#define OVERRIDE_MCS(i) \
6727 if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \
6728 vhtcaps_mask->vht_supported_mcs_set.tx_map |= \
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006729 host_to_le16(3 << 2 * (i - 1)); \
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006730 vhtcaps->vht_supported_mcs_set.tx_map |= \
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006731 host_to_le16(ssid->vht_tx_mcs_nss_ ##i << \
6732 2 * (i - 1)); \
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006733 } \
6734 if (ssid->vht_rx_mcs_nss_ ##i >= 0) { \
6735 vhtcaps_mask->vht_supported_mcs_set.rx_map |= \
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006736 host_to_le16(3 << 2 * (i - 1)); \
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006737 vhtcaps->vht_supported_mcs_set.rx_map |= \
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006738 host_to_le16(ssid->vht_rx_mcs_nss_ ##i << \
6739 2 * (i - 1)); \
Dmitry Shmidt2f023192013-03-12 12:44:17 -07006740 }
6741
6742 OVERRIDE_MCS(1);
6743 OVERRIDE_MCS(2);
6744 OVERRIDE_MCS(3);
6745 OVERRIDE_MCS(4);
6746 OVERRIDE_MCS(5);
6747 OVERRIDE_MCS(6);
6748 OVERRIDE_MCS(7);
6749 OVERRIDE_MCS(8);
6750}
6751#endif /* CONFIG_VHT_OVERRIDES */
6752
6753
Hai Shalomfdcde762020-04-02 11:19:20 -07006754#ifdef CONFIG_HE_OVERRIDES
6755void wpa_supplicant_apply_he_overrides(
6756 struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
6757 struct wpa_driver_associate_params *params)
6758{
6759 if (!ssid)
6760 return;
6761
6762 params->disable_he = ssid->disable_he;
6763}
6764#endif /* CONFIG_HE_OVERRIDES */
6765
6766
Sunil Ravi77d572f2023-01-17 23:58:31 +00006767void wpa_supplicant_apply_eht_overrides(
6768 struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
6769 struct wpa_driver_associate_params *params)
6770{
6771 if (!ssid)
6772 return;
6773
6774 params->disable_eht = ssid->disable_eht;
6775}
6776
6777
Dmitry Shmidt04949592012-07-19 12:16:46 -07006778static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
6779{
6780#ifdef PCSC_FUNCS
6781 size_t len;
6782
6783 if (!wpa_s->conf->pcsc_reader)
6784 return 0;
6785
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08006786 wpa_s->scard = scard_init(wpa_s->conf->pcsc_reader);
Dmitry Shmidt04949592012-07-19 12:16:46 -07006787 if (!wpa_s->scard)
6788 return 1;
6789
6790 if (wpa_s->conf->pcsc_pin &&
6791 scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) {
6792 scard_deinit(wpa_s->scard);
6793 wpa_s->scard = NULL;
6794 wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed");
6795 return -1;
6796 }
6797
6798 len = sizeof(wpa_s->imsi) - 1;
6799 if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
6800 scard_deinit(wpa_s->scard);
6801 wpa_s->scard = NULL;
6802 wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
6803 return -1;
6804 }
6805 wpa_s->imsi[len] = '\0';
6806
6807 wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
6808
6809 wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
6810 wpa_s->imsi, wpa_s->mnc_len);
6811
6812 wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
6813 eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
6814#endif /* PCSC_FUNCS */
6815
6816 return 0;
6817}
6818
6819
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006820int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
6821{
6822 char *val, *pos;
6823
6824 ext_password_deinit(wpa_s->ext_pw);
6825 wpa_s->ext_pw = NULL;
6826 eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL);
6827
6828 if (!wpa_s->conf->ext_password_backend)
6829 return 0;
6830
6831 val = os_strdup(wpa_s->conf->ext_password_backend);
6832 if (val == NULL)
6833 return -1;
6834 pos = os_strchr(val, ':');
6835 if (pos)
6836 *pos++ = '\0';
6837
6838 wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val);
6839
6840 wpa_s->ext_pw = ext_password_init(val, pos);
6841 os_free(val);
6842 if (wpa_s->ext_pw == NULL) {
6843 wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend");
6844 return -1;
6845 }
6846 eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw);
6847
6848 return 0;
6849}
6850
6851
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006852#ifdef CONFIG_FST
6853
6854static const u8 * wpas_fst_get_bssid_cb(void *ctx)
6855{
6856 struct wpa_supplicant *wpa_s = ctx;
6857
6858 return (is_zero_ether_addr(wpa_s->bssid) ||
6859 wpa_s->wpa_state != WPA_COMPLETED) ? NULL : wpa_s->bssid;
6860}
6861
6862
6863static void wpas_fst_get_channel_info_cb(void *ctx,
6864 enum hostapd_hw_mode *hw_mode,
6865 u8 *channel)
6866{
6867 struct wpa_supplicant *wpa_s = ctx;
6868
6869 if (wpa_s->current_bss) {
6870 *hw_mode = ieee80211_freq_to_chan(wpa_s->current_bss->freq,
6871 channel);
6872 } else if (wpa_s->hw.num_modes) {
6873 *hw_mode = wpa_s->hw.modes[0].mode;
6874 } else {
6875 WPA_ASSERT(0);
6876 *hw_mode = 0;
6877 }
6878}
6879
6880
6881static int wpas_fst_get_hw_modes(void *ctx, struct hostapd_hw_modes **modes)
6882{
6883 struct wpa_supplicant *wpa_s = ctx;
6884
6885 *modes = wpa_s->hw.modes;
6886 return wpa_s->hw.num_modes;
6887}
6888
6889
6890static void wpas_fst_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
6891{
6892 struct wpa_supplicant *wpa_s = ctx;
6893
6894 wpa_hexdump_buf(MSG_DEBUG, "FST: Set IEs", fst_ies);
6895 wpa_s->fst_ies = fst_ies;
6896}
6897
6898
6899static int wpas_fst_send_action_cb(void *ctx, const u8 *da, struct wpabuf *data)
6900{
6901 struct wpa_supplicant *wpa_s = ctx;
6902
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006903 if (!ether_addr_equal(wpa_s->bssid, da)) {
Paul Stewart092955c2017-02-06 09:13:09 -08006904 wpa_printf(MSG_INFO, "FST:%s:bssid=" MACSTR " != da=" MACSTR,
6905 __func__, MAC2STR(wpa_s->bssid), MAC2STR(da));
6906 return -1;
6907 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006908 return wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
Paul Stewart092955c2017-02-06 09:13:09 -08006909 wpa_s->own_addr, wpa_s->bssid,
6910 wpabuf_head(data), wpabuf_len(data),
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006911 0);
6912}
6913
6914
6915static const struct wpabuf * wpas_fst_get_mb_ie_cb(void *ctx, const u8 *addr)
6916{
6917 struct wpa_supplicant *wpa_s = ctx;
6918
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006919 WPA_ASSERT(ether_addr_equal(wpa_s->bssid, addr));
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006920 return wpa_s->received_mb_ies;
6921}
6922
6923
6924static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
6925 const u8 *buf, size_t size)
6926{
6927 struct wpa_supplicant *wpa_s = ctx;
6928 struct mb_ies_info info;
6929
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006930 WPA_ASSERT(ether_addr_equal(wpa_s->bssid, addr));
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006931
6932 if (!mb_ies_info_by_ies(&info, buf, size)) {
6933 wpabuf_free(wpa_s->received_mb_ies);
6934 wpa_s->received_mb_ies = mb_ies_by_info(&info);
6935 }
6936}
6937
6938
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006939static const u8 * wpas_fst_get_peer_first(void *ctx,
6940 struct fst_get_peer_ctx **get_ctx,
Hai Shalome21d4e82020-04-29 16:34:06 -07006941 bool mb_only)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006942{
6943 struct wpa_supplicant *wpa_s = ctx;
6944
6945 *get_ctx = NULL;
6946 if (!is_zero_ether_addr(wpa_s->bssid))
6947 return (wpa_s->received_mb_ies || !mb_only) ?
6948 wpa_s->bssid : NULL;
6949 return NULL;
6950}
6951
6952
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07006953static const u8 * wpas_fst_get_peer_next(void *ctx,
6954 struct fst_get_peer_ctx **get_ctx,
Hai Shalome21d4e82020-04-29 16:34:06 -07006955 bool mb_only)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006956{
6957 return NULL;
6958}
6959
6960void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
6961 struct fst_wpa_obj *iface_obj)
6962{
Sunil8cd6f4d2022-06-28 18:40:46 +00006963 os_memset(iface_obj, 0, sizeof(*iface_obj));
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006964 iface_obj->ctx = wpa_s;
6965 iface_obj->get_bssid = wpas_fst_get_bssid_cb;
6966 iface_obj->get_channel_info = wpas_fst_get_channel_info_cb;
6967 iface_obj->get_hw_modes = wpas_fst_get_hw_modes;
6968 iface_obj->set_ies = wpas_fst_set_ies_cb;
6969 iface_obj->send_action = wpas_fst_send_action_cb;
6970 iface_obj->get_mb_ie = wpas_fst_get_mb_ie_cb;
6971 iface_obj->update_mb_ie = wpas_fst_update_mb_ie_cb;
6972 iface_obj->get_peer_first = wpas_fst_get_peer_first;
6973 iface_obj->get_peer_next = wpas_fst_get_peer_next;
6974}
6975#endif /* CONFIG_FST */
6976
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006977static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006978 const struct wpa_driver_capa *capa)
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07006979{
Dmitry Shmidt0207e232014-09-03 14:58:37 -07006980 struct wowlan_triggers *triggers;
6981 int ret = 0;
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07006982
6983 if (!wpa_s->conf->wowlan_triggers)
6984 return 0;
6985
Dmitry Shmidt0207e232014-09-03 14:58:37 -07006986 triggers = wpa_get_wowlan_triggers(wpa_s->conf->wowlan_triggers, capa);
6987 if (triggers) {
6988 ret = wpa_drv_wowlan(wpa_s, triggers);
6989 os_free(triggers);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07006990 }
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07006991 return ret;
6992}
6993
6994
Dmitry Shmidt9c175262016-03-03 10:20:07 -08006995enum wpa_radio_work_band wpas_freq_to_band(int freq)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006996{
6997 if (freq < 3000)
6998 return BAND_2_4_GHZ;
6999 if (freq > 50000)
7000 return BAND_60_GHZ;
7001 return BAND_5_GHZ;
7002}
7003
7004
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007005unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007006{
7007 int i;
7008 unsigned int band = 0;
7009
7010 if (freqs) {
7011 /* freqs are specified for the radio work */
7012 for (i = 0; freqs[i]; i++)
7013 band |= wpas_freq_to_band(freqs[i]);
7014 } else {
7015 /*
7016 * freqs are not specified, implies all
7017 * the supported freqs by HW
7018 */
7019 for (i = 0; i < wpa_s->hw.num_modes; i++) {
7020 if (wpa_s->hw.modes[i].num_channels != 0) {
7021 if (wpa_s->hw.modes[i].mode ==
7022 HOSTAPD_MODE_IEEE80211B ||
7023 wpa_s->hw.modes[i].mode ==
7024 HOSTAPD_MODE_IEEE80211G)
7025 band |= BAND_2_4_GHZ;
7026 else if (wpa_s->hw.modes[i].mode ==
7027 HOSTAPD_MODE_IEEE80211A)
7028 band |= BAND_5_GHZ;
7029 else if (wpa_s->hw.modes[i].mode ==
7030 HOSTAPD_MODE_IEEE80211AD)
7031 band |= BAND_60_GHZ;
7032 else if (wpa_s->hw.modes[i].mode ==
7033 HOSTAPD_MODE_IEEE80211ANY)
7034 band = BAND_2_4_GHZ | BAND_5_GHZ |
7035 BAND_60_GHZ;
7036 }
7037 }
7038 }
7039
7040 return band;
7041}
7042
7043
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007044static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
7045 const char *rn)
7046{
7047 struct wpa_supplicant *iface = wpa_s->global->ifaces;
7048 struct wpa_radio *radio;
7049
7050 while (rn && iface) {
7051 radio = iface->radio;
7052 if (radio && os_strcmp(rn, radio->name) == 0) {
7053 wpa_printf(MSG_DEBUG, "Add interface %s to existing radio %s",
7054 wpa_s->ifname, rn);
7055 dl_list_add(&radio->ifaces, &wpa_s->radio_list);
7056 return radio;
7057 }
Dmitry Shmidt3cf6f792013-12-18 13:12:19 -08007058
7059 iface = iface->next;
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007060 }
7061
7062 wpa_printf(MSG_DEBUG, "Add interface %s to a new radio %s",
7063 wpa_s->ifname, rn ? rn : "N/A");
7064 radio = os_zalloc(sizeof(*radio));
7065 if (radio == NULL)
7066 return NULL;
7067
7068 if (rn)
7069 os_strlcpy(radio->name, rn, sizeof(radio->name));
7070 dl_list_init(&radio->ifaces);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007071 dl_list_init(&radio->work);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007072 dl_list_add(&radio->ifaces, &wpa_s->radio_list);
7073
7074 return radio;
7075}
7076
7077
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007078static void radio_work_free(struct wpa_radio_work *work)
7079{
7080 if (work->wpa_s->scan_work == work) {
7081 /* This should not really happen. */
7082 wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as scan_work",
7083 work->type, work, work->started);
7084 work->wpa_s->scan_work = NULL;
7085 }
7086
7087#ifdef CONFIG_P2P
7088 if (work->wpa_s->p2p_scan_work == work) {
7089 /* This should not really happen. */
7090 wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as p2p_scan_work",
7091 work->type, work, work->started);
7092 work->wpa_s->p2p_scan_work = NULL;
7093 }
7094#endif /* CONFIG_P2P */
7095
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007096 if (work->started) {
7097 work->wpa_s->radio->num_active_works--;
7098 wpa_dbg(work->wpa_s, MSG_DEBUG,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007099 "radio_work_free('%s'@%p): num_active_works --> %u",
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007100 work->type, work,
7101 work->wpa_s->radio->num_active_works);
7102 }
7103
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007104 dl_list_del(&work->list);
7105 os_free(work);
7106}
7107
7108
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08007109static int radio_work_is_connect(struct wpa_radio_work *work)
7110{
7111 return os_strcmp(work->type, "sme-connect") == 0 ||
7112 os_strcmp(work->type, "connect") == 0;
7113}
7114
7115
7116static int radio_work_is_scan(struct wpa_radio_work *work)
7117{
7118 return os_strcmp(work->type, "scan") == 0 ||
7119 os_strcmp(work->type, "p2p-scan") == 0;
7120}
7121
7122
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007123static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
7124{
7125 struct wpa_radio_work *active_work = NULL;
7126 struct wpa_radio_work *tmp;
7127
7128 /* Get the active work to know the type and band. */
7129 dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
7130 if (tmp->started) {
7131 active_work = tmp;
7132 break;
7133 }
7134 }
7135
7136 if (!active_work) {
7137 /* No active work, start one */
7138 radio->num_active_works = 0;
7139 dl_list_for_each(tmp, &radio->work, struct wpa_radio_work,
7140 list) {
7141 if (os_strcmp(tmp->type, "scan") == 0 &&
Hai Shalom60840252021-02-19 19:02:11 -08007142 external_scan_running(radio) &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007143 (((struct wpa_driver_scan_params *)
7144 tmp->ctx)->only_new_results ||
7145 tmp->wpa_s->clear_driver_scan_cache))
7146 continue;
7147 return tmp;
7148 }
7149 return NULL;
7150 }
7151
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08007152 if (radio_work_is_connect(active_work)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007153 /*
7154 * If the active work is either connect or sme-connect,
7155 * do not parallelize them with other radio works.
7156 */
7157 wpa_dbg(active_work->wpa_s, MSG_DEBUG,
7158 "Do not parallelize radio work with %s",
7159 active_work->type);
7160 return NULL;
7161 }
7162
7163 dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
7164 if (tmp->started)
7165 continue;
7166
7167 /*
7168 * If connect or sme-connect are enqueued, parallelize only
7169 * those operations ahead of them in the queue.
7170 */
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08007171 if (radio_work_is_connect(tmp))
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007172 break;
7173
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08007174 /* Serialize parallel scan and p2p_scan operations on the same
7175 * interface since the driver_nl80211 mechanism for tracking
7176 * scan cookies does not yet have support for this. */
7177 if (active_work->wpa_s == tmp->wpa_s &&
7178 radio_work_is_scan(active_work) &&
7179 radio_work_is_scan(tmp)) {
7180 wpa_dbg(active_work->wpa_s, MSG_DEBUG,
7181 "Do not start work '%s' when another work '%s' is already scheduled",
7182 tmp->type, active_work->type);
7183 continue;
7184 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007185 /*
7186 * Check that the radio works are distinct and
7187 * on different bands.
7188 */
7189 if (os_strcmp(active_work->type, tmp->type) != 0 &&
7190 (active_work->bands != tmp->bands)) {
7191 /*
7192 * If a scan has to be scheduled through nl80211 scan
7193 * interface and if an external scan is already running,
7194 * do not schedule the scan since it is likely to get
7195 * rejected by kernel.
7196 */
7197 if (os_strcmp(tmp->type, "scan") == 0 &&
Hai Shalom60840252021-02-19 19:02:11 -08007198 external_scan_running(radio) &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007199 (((struct wpa_driver_scan_params *)
7200 tmp->ctx)->only_new_results ||
7201 tmp->wpa_s->clear_driver_scan_cache))
7202 continue;
7203
7204 wpa_dbg(active_work->wpa_s, MSG_DEBUG,
7205 "active_work:%s new_work:%s",
7206 active_work->type, tmp->type);
7207 return tmp;
7208 }
7209 }
7210
7211 /* Did not find a radio work to schedule in parallel. */
7212 return NULL;
7213}
7214
7215
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007216static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
7217{
7218 struct wpa_radio *radio = eloop_ctx;
7219 struct wpa_radio_work *work;
7220 struct os_reltime now, diff;
7221 struct wpa_supplicant *wpa_s;
7222
7223 work = dl_list_first(&radio->work, struct wpa_radio_work, list);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007224 if (work == NULL) {
7225 radio->num_active_works = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007226 return;
7227 }
7228
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007229 wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant,
7230 radio_list);
7231
7232 if (!(wpa_s &&
7233 wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)) {
7234 if (work->started)
7235 return; /* already started and still in progress */
7236
Hai Shalom60840252021-02-19 19:02:11 -08007237 if (wpa_s && external_scan_running(wpa_s->radio)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007238 wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
7239 return;
7240 }
7241 } else {
7242 work = NULL;
7243 if (radio->num_active_works < MAX_ACTIVE_WORKS) {
7244 /* get the work to schedule next */
7245 work = radio_work_get_next_work(radio);
7246 }
7247 if (!work)
7248 return;
7249 }
7250
7251 wpa_s = work->wpa_s;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007252 os_get_reltime(&now);
7253 os_reltime_sub(&now, &work->time, &diff);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007254 wpa_dbg(wpa_s, MSG_DEBUG,
7255 "Starting radio work '%s'@%p after %ld.%06ld second wait",
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007256 work->type, work, diff.sec, diff.usec);
7257 work->started = 1;
7258 work->time = now;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007259 radio->num_active_works++;
7260
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007261 work->cb(work, 0);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007262
7263 if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS) &&
7264 radio->num_active_works < MAX_ACTIVE_WORKS)
7265 radio_work_check_next(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007266}
7267
7268
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007269/*
7270 * This function removes both started and pending radio works running on
7271 * the provided interface's radio.
7272 * Prior to the removal of the radio work, its callback (cb) is called with
7273 * deinit set to be 1. Each work's callback is responsible for clearing its
7274 * internal data and restoring to a correct state.
7275 * @wpa_s: wpa_supplicant data
7276 * @type: type of works to be removed
7277 * @remove_all: 1 to remove all the works on this radio, 0 to remove only
7278 * this interface's works.
7279 */
7280void radio_remove_works(struct wpa_supplicant *wpa_s,
7281 const char *type, int remove_all)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007282{
7283 struct wpa_radio_work *work, *tmp;
7284 struct wpa_radio *radio = wpa_s->radio;
7285
7286 dl_list_for_each_safe(work, tmp, &radio->work, struct wpa_radio_work,
7287 list) {
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007288 if (type && os_strcmp(type, work->type) != 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007289 continue;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007290
7291 /* skip other ifaces' works */
7292 if (!remove_all && work->wpa_s != wpa_s)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007293 continue;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007294
7295 wpa_dbg(wpa_s, MSG_DEBUG, "Remove radio work '%s'@%p%s",
7296 work->type, work, work->started ? " (started)" : "");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007297 work->cb(work, 1);
7298 radio_work_free(work);
7299 }
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007300
7301 /* in case we removed the started work */
7302 radio_work_check_next(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007303}
7304
7305
Roshan Pius3a1667e2018-07-03 15:17:14 -07007306void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx)
7307{
7308 struct wpa_radio_work *work;
7309 struct wpa_radio *radio = wpa_s->radio;
7310
7311 dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
7312 if (work->ctx != ctx)
7313 continue;
7314 wpa_dbg(wpa_s, MSG_DEBUG, "Free pending radio work '%s'@%p%s",
7315 work->type, work, work->started ? " (started)" : "");
7316 radio_work_free(work);
7317 break;
7318 }
7319}
7320
7321
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007322static void radio_remove_interface(struct wpa_supplicant *wpa_s)
7323{
7324 struct wpa_radio *radio = wpa_s->radio;
7325
7326 if (!radio)
7327 return;
7328
7329 wpa_printf(MSG_DEBUG, "Remove interface %s from radio %s",
7330 wpa_s->ifname, radio->name);
7331 dl_list_del(&wpa_s->radio_list);
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07007332 radio_remove_works(wpa_s, NULL, 0);
Hai Shalom60840252021-02-19 19:02:11 -08007333 /* If the interface that triggered the external scan was removed, the
7334 * external scan is no longer running. */
7335 if (wpa_s == radio->external_scan_req_interface)
7336 radio->external_scan_req_interface = NULL;
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07007337 wpa_s->radio = NULL;
7338 if (!dl_list_empty(&radio->ifaces))
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007339 return; /* Interfaces remain for this radio */
7340
7341 wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007342 eloop_cancel_timeout(radio_start_next_work, radio, NULL);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007343 os_free(radio);
7344}
7345
7346
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007347void radio_work_check_next(struct wpa_supplicant *wpa_s)
7348{
7349 struct wpa_radio *radio = wpa_s->radio;
7350
7351 if (dl_list_empty(&radio->work))
7352 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007353 if (wpa_s->ext_work_in_progress) {
7354 wpa_printf(MSG_DEBUG,
7355 "External radio work in progress - delay start of pending item");
7356 return;
7357 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007358 eloop_cancel_timeout(radio_start_next_work, radio, NULL);
7359 eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL);
7360}
7361
7362
7363/**
7364 * radio_add_work - Add a radio work item
7365 * @wpa_s: Pointer to wpa_supplicant data
7366 * @freq: Frequency of the offchannel operation in MHz or 0
7367 * @type: Unique identifier for each type of work
7368 * @next: Force as the next work to be executed
7369 * @cb: Callback function for indicating when radio is available
7370 * @ctx: Context pointer for the work (work->ctx in cb())
7371 * Returns: 0 on success, -1 on failure
7372 *
7373 * This function is used to request time for an operation that requires
7374 * exclusive radio control. Once the radio is available, the registered callback
7375 * function will be called. radio_work_done() must be called once the exclusive
7376 * radio operation has been completed, so that the radio is freed for other
7377 * operations. The special case of deinit=1 is used to free the context data
7378 * during interface removal. That does not allow the callback function to start
7379 * the radio operation, i.e., it must free any resources allocated for the radio
7380 * work and return.
7381 *
7382 * The @freq parameter can be used to indicate a single channel on which the
7383 * offchannel operation will occur. This may allow multiple radio work
7384 * operations to be performed in parallel if they apply for the same channel.
7385 * Setting this to 0 indicates that the work item may use multiple channels or
7386 * requires exclusive control of the radio.
7387 */
7388int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
7389 const char *type, int next,
7390 void (*cb)(struct wpa_radio_work *work, int deinit),
7391 void *ctx)
7392{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007393 struct wpa_radio *radio = wpa_s->radio;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007394 struct wpa_radio_work *work;
7395 int was_empty;
7396
7397 work = os_zalloc(sizeof(*work));
7398 if (work == NULL)
7399 return -1;
7400 wpa_dbg(wpa_s, MSG_DEBUG, "Add radio work '%s'@%p", type, work);
7401 os_get_reltime(&work->time);
7402 work->freq = freq;
7403 work->type = type;
7404 work->wpa_s = wpa_s;
7405 work->cb = cb;
7406 work->ctx = ctx;
7407
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007408 if (freq)
7409 work->bands = wpas_freq_to_band(freq);
7410 else if (os_strcmp(type, "scan") == 0 ||
7411 os_strcmp(type, "p2p-scan") == 0)
7412 work->bands = wpas_get_bands(wpa_s,
7413 ((struct wpa_driver_scan_params *)
7414 ctx)->freqs);
7415 else
7416 work->bands = wpas_get_bands(wpa_s, NULL);
7417
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007418 was_empty = dl_list_empty(&wpa_s->radio->work);
7419 if (next)
7420 dl_list_add(&wpa_s->radio->work, &work->list);
7421 else
7422 dl_list_add_tail(&wpa_s->radio->work, &work->list);
7423 if (was_empty) {
7424 wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately");
7425 radio_work_check_next(wpa_s);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007426 } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)
7427 && radio->num_active_works < MAX_ACTIVE_WORKS) {
7428 wpa_dbg(wpa_s, MSG_DEBUG,
7429 "Try to schedule a radio work (num_active_works=%u)",
7430 radio->num_active_works);
7431 radio_work_check_next(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007432 }
7433
7434 return 0;
7435}
7436
7437
7438/**
7439 * radio_work_done - Indicate that a radio work item has been completed
7440 * @work: Completed work
7441 *
7442 * This function is called once the callback function registered with
7443 * radio_add_work() has completed its work.
7444 */
7445void radio_work_done(struct wpa_radio_work *work)
7446{
7447 struct wpa_supplicant *wpa_s = work->wpa_s;
7448 struct os_reltime now, diff;
7449 unsigned int started = work->started;
7450
7451 os_get_reltime(&now);
7452 os_reltime_sub(&now, &work->time, &diff);
7453 wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %ld.%06ld seconds",
7454 work->type, work, started ? "done" : "canceled",
7455 diff.sec, diff.usec);
7456 radio_work_free(work);
7457 if (started)
7458 radio_work_check_next(wpa_s);
7459}
7460
7461
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08007462struct wpa_radio_work *
7463radio_work_pending(struct wpa_supplicant *wpa_s, const char *type)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007464{
7465 struct wpa_radio_work *work;
7466 struct wpa_radio *radio = wpa_s->radio;
7467
7468 dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
7469 if (work->wpa_s == wpa_s && os_strcmp(work->type, type) == 0)
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08007470 return work;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007471 }
7472
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08007473 return NULL;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007474}
7475
7476
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007477static int wpas_init_driver(struct wpa_supplicant *wpa_s,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007478 const struct wpa_interface *iface)
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007479{
7480 const char *ifname, *driver, *rn;
7481
7482 driver = iface->driver;
7483next_driver:
7484 if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
7485 return -1;
7486
7487 wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
7488 if (wpa_s->drv_priv == NULL) {
7489 const char *pos;
Hai Shalom899fcc72020-10-19 14:38:18 -07007490 int level = MSG_ERROR;
7491
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007492 pos = driver ? os_strchr(driver, ',') : NULL;
7493 if (pos) {
7494 wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
7495 "driver interface - try next driver wrapper");
7496 driver = pos + 1;
7497 goto next_driver;
7498 }
Hai Shalom899fcc72020-10-19 14:38:18 -07007499
7500#ifdef CONFIG_MATCH_IFACE
7501 if (wpa_s->matched == WPA_IFACE_MATCHED_NULL)
7502 level = MSG_DEBUG;
7503#endif /* CONFIG_MATCH_IFACE */
7504 wpa_msg(wpa_s, level, "Failed to initialize driver interface");
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007505 return -1;
7506 }
7507 if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
7508 wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
7509 "driver_param '%s'", wpa_s->conf->driver_param);
7510 return -1;
7511 }
7512
7513 ifname = wpa_drv_get_ifname(wpa_s);
7514 if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
7515 wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
7516 "interface name with '%s'", ifname);
7517 os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
7518 }
7519
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07007520 rn = wpa_driver_get_radio_name(wpa_s);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007521 if (rn && rn[0] == '\0')
7522 rn = NULL;
7523
7524 wpa_s->radio = radio_add_interface(wpa_s, rn);
7525 if (wpa_s->radio == NULL)
7526 return -1;
7527
7528 return 0;
7529}
7530
7531
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007532#ifdef CONFIG_GAS_SERVER
7533
7534static void wpas_gas_server_tx_status(struct wpa_supplicant *wpa_s,
7535 unsigned int freq, const u8 *dst,
7536 const u8 *src, const u8 *bssid,
7537 const u8 *data, size_t data_len,
7538 enum offchannel_send_action_result result)
7539{
7540 wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
7541 " result=%s",
7542 freq, MAC2STR(dst),
7543 result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
7544 (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
7545 "FAILED"));
7546 gas_server_tx_status(wpa_s->gas_server, dst, data, data_len,
7547 result == OFFCHANNEL_SEND_ACTION_SUCCESS);
7548}
7549
7550
7551static void wpas_gas_server_tx(void *ctx, int freq, const u8 *da,
7552 struct wpabuf *buf, unsigned int wait_time)
7553{
7554 struct wpa_supplicant *wpa_s = ctx;
7555 const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
7556
7557 if (wait_time > wpa_s->max_remain_on_chan)
7558 wait_time = wpa_s->max_remain_on_chan;
7559
7560 offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, broadcast,
7561 wpabuf_head(buf), wpabuf_len(buf),
7562 wait_time, wpas_gas_server_tx_status, 0);
7563}
7564
7565#endif /* CONFIG_GAS_SERVER */
7566
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007567static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007568 const struct wpa_interface *iface)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007569{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007570 struct wpa_driver_capa capa;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007571 int capa_res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007572 u8 dfs_domain;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007573
7574 wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
7575 "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
7576 iface->confname ? iface->confname : "N/A",
7577 iface->driver ? iface->driver : "default",
7578 iface->ctrl_interface ? iface->ctrl_interface : "N/A",
7579 iface->bridge_ifname ? iface->bridge_ifname : "N/A");
7580
7581 if (iface->confname) {
7582#ifdef CONFIG_BACKEND_FILE
7583 wpa_s->confname = os_rel2abs_path(iface->confname);
7584 if (wpa_s->confname == NULL) {
7585 wpa_printf(MSG_ERROR, "Failed to get absolute path "
7586 "for configuration file '%s'.",
7587 iface->confname);
7588 return -1;
7589 }
7590 wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
7591 iface->confname, wpa_s->confname);
7592#else /* CONFIG_BACKEND_FILE */
7593 wpa_s->confname = os_strdup(iface->confname);
7594#endif /* CONFIG_BACKEND_FILE */
Sunil Ravi77d572f2023-01-17 23:58:31 +00007595 wpa_s->conf = wpa_config_read(wpa_s->confname, NULL, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007596 if (wpa_s->conf == NULL) {
7597 wpa_printf(MSG_ERROR, "Failed to read or parse "
7598 "configuration '%s'.", wpa_s->confname);
7599 return -1;
7600 }
Dmitry Shmidt64f47c52013-04-16 10:41:54 -07007601 wpa_s->confanother = os_rel2abs_path(iface->confanother);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007602 if (wpa_s->confanother &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00007603 !wpa_config_read(wpa_s->confanother, wpa_s->conf, true)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007604 wpa_printf(MSG_ERROR,
7605 "Failed to read or parse configuration '%s'.",
7606 wpa_s->confanother);
7607 return -1;
7608 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007609
7610 /*
7611 * Override ctrl_interface and driver_param if set on command
7612 * line.
7613 */
7614 if (iface->ctrl_interface) {
7615 os_free(wpa_s->conf->ctrl_interface);
7616 wpa_s->conf->ctrl_interface =
7617 os_strdup(iface->ctrl_interface);
Sunil Ravi77d572f2023-01-17 23:58:31 +00007618 if (!wpa_s->conf->ctrl_interface) {
7619 wpa_printf(MSG_ERROR,
7620 "Failed to duplicate control interface '%s'.",
7621 iface->ctrl_interface);
7622 return -1;
7623 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007624 }
7625
7626 if (iface->driver_param) {
7627 os_free(wpa_s->conf->driver_param);
7628 wpa_s->conf->driver_param =
7629 os_strdup(iface->driver_param);
Sunil Ravi77d572f2023-01-17 23:58:31 +00007630 if (!wpa_s->conf->driver_param) {
7631 wpa_printf(MSG_ERROR,
7632 "Failed to duplicate driver param '%s'.",
7633 iface->driver_param);
7634 return -1;
7635 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007636 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007637
7638 if (iface->p2p_mgmt && !iface->ctrl_interface) {
7639 os_free(wpa_s->conf->ctrl_interface);
7640 wpa_s->conf->ctrl_interface = NULL;
7641 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007642 } else
7643 wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
7644 iface->driver_param);
7645
7646 if (wpa_s->conf == NULL) {
7647 wpa_printf(MSG_ERROR, "\nNo configuration found.");
7648 return -1;
7649 }
7650
7651 if (iface->ifname == NULL) {
7652 wpa_printf(MSG_ERROR, "\nInterface name is required.");
7653 return -1;
7654 }
7655 if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
7656 wpa_printf(MSG_ERROR, "\nToo long interface name '%s'.",
7657 iface->ifname);
7658 return -1;
7659 }
7660 os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
Hai Shalom899fcc72020-10-19 14:38:18 -07007661#ifdef CONFIG_MATCH_IFACE
7662 wpa_s->matched = iface->matched;
7663#endif /* CONFIG_MATCH_IFACE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007664
7665 if (iface->bridge_ifname) {
7666 if (os_strlen(iface->bridge_ifname) >=
7667 sizeof(wpa_s->bridge_ifname)) {
7668 wpa_printf(MSG_ERROR, "\nToo long bridge interface "
7669 "name '%s'.", iface->bridge_ifname);
7670 return -1;
7671 }
7672 os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname,
7673 sizeof(wpa_s->bridge_ifname));
7674 }
7675
7676 /* RSNA Supplicant Key Management - INITIALIZE */
Hai Shalome21d4e82020-04-29 16:34:06 -07007677 eapol_sm_notify_portEnabled(wpa_s->eapol, false);
7678 eapol_sm_notify_portValid(wpa_s->eapol, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007679
7680 /* Initialize driver interface and register driver event handler before
7681 * L2 receive handler so that association events are processed before
7682 * EAPOL-Key packets if both become available for the same select()
7683 * call. */
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007684 if (wpas_init_driver(wpa_s, iface) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007685 return -1;
7686
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007687 if (wpa_supplicant_init_wpa(wpa_s) < 0)
7688 return -1;
7689
7690 wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,
7691 wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname :
7692 NULL);
7693 wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
7694
7695 if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
7696 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
7697 wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
7698 wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
7699 "dot11RSNAConfigPMKLifetime");
7700 return -1;
7701 }
7702
7703 if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
7704 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
7705 wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
7706 wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
7707 "dot11RSNAConfigPMKReauthThreshold");
7708 return -1;
7709 }
7710
7711 if (wpa_s->conf->dot11RSNAConfigSATimeout &&
7712 wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
7713 wpa_s->conf->dot11RSNAConfigSATimeout)) {
7714 wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
7715 "dot11RSNAConfigSATimeout");
7716 return -1;
7717 }
7718
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007719 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_PREPEND_PMKID,
7720 wpa_s->conf->ft_prepend_pmkid);
7721
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007722 wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
7723 &wpa_s->hw.num_modes,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007724 &wpa_s->hw.flags,
7725 &dfs_domain);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08007726 if (wpa_s->hw.modes) {
7727 u16 i;
7728
7729 for (i = 0; i < wpa_s->hw.num_modes; i++) {
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00007730 if (wpa_s->hw.modes[i].eht_capab[IEEE80211_MODE_INFRA].
7731 eht_supported)
7732 wpa_s->hw_capab |= BIT(CAPAB_EHT);
7733 if (wpa_s->hw.modes[i].he_capab[IEEE80211_MODE_INFRA].
7734 he_supported)
7735 wpa_s->hw_capab |= BIT(CAPAB_HE);
7736 if (wpa_s->hw.modes[i].vht_capab)
7737 wpa_s->hw_capab |= BIT(CAPAB_VHT);
7738 if (wpa_s->hw.modes[i].ht_capab)
7739 wpa_s->hw_capab |= BIT(CAPAB_HT);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08007740 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007741 wpa_s->support_6ghz = wpas_is_6ghz_supported(wpa_s, false);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08007742 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007743
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007744 capa_res = wpa_drv_get_capa(wpa_s, &capa);
7745 if (capa_res == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007746 wpa_s->drv_capa_known = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007747 wpa_s->drv_flags = capa.flags;
Hai Shalomb755a2a2020-04-23 21:49:02 -07007748 wpa_s->drv_flags2 = capa.flags2;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007749 wpa_s->drv_enc = capa.enc;
Sunil Ravi7f769292024-07-23 22:21:32 +00007750 wpa_s->drv_key_mgmt = capa.key_mgmt;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007751 wpa_s->drv_rrm_flags = capa.rrm_flags;
Sunil Ravia04bd252022-05-02 22:54:18 -07007752 wpa_s->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007753 wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007754 wpa_s->max_scan_ssids = capa.max_scan_ssids;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007755 wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007756 wpa_s->max_sched_scan_plans = capa.max_sched_scan_plans;
7757 wpa_s->max_sched_scan_plan_interval =
7758 capa.max_sched_scan_plan_interval;
7759 wpa_s->max_sched_scan_plan_iterations =
7760 capa.max_sched_scan_plan_iterations;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007761 wpa_s->sched_scan_supported = capa.sched_scan_supported;
7762 wpa_s->max_match_sets = capa.max_match_sets;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007763 wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
7764 wpa_s->max_stations = capa.max_stations;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007765 wpa_s->extended_capa = capa.extended_capa;
7766 wpa_s->extended_capa_mask = capa.extended_capa_mask;
7767 wpa_s->extended_capa_len = capa.extended_capa_len;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07007768 wpa_s->num_multichan_concurrent =
7769 capa.num_multichan_concurrent;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007770#ifndef CONFIG_NO_WMM_AC
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007771 wpa_s->wmm_ac_supported = capa.wmm_ac_supported;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007772#endif /* CONFIG_NO_WMM_AC */
Sunil Ravi89eba102022-09-13 21:04:37 -07007773 wpa_s->max_num_akms = capa.max_num_akms;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007774
7775 if (capa.mac_addr_rand_scan_supported)
7776 wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;
7777 if (wpa_s->sched_scan_supported &&
7778 capa.mac_addr_rand_sched_scan_supported)
7779 wpa_s->mac_addr_rand_supported |=
7780 (MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00007781 wpa_s->drv_max_probe_req_ie_len = capa.max_probe_req_ie_len;
Hai Shalom74f70d42019-02-11 14:42:39 -08007782
7783 wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
7784 if (wpa_s->extended_capa &&
7785 wpa_s->extended_capa_len >= 3 &&
7786 wpa_s->extended_capa[2] & 0x40)
7787 wpa_s->multi_bss_support = 1;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00007788 } else {
7789 wpa_s->drv_max_probe_req_ie_len = 1500;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007790 }
Sunil Ravi89eba102022-09-13 21:04:37 -07007791#ifdef CONFIG_PASN
7792 wpa_pasn_sm_set_caps(wpa_s->wpa, wpa_s->drv_flags2);
7793#endif /* CONFIG_PASN */
Matthew Wang9ed1c792024-12-02 14:05:18 +00007794#ifndef CONFIG_NO_WPA
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007795 wpa_sm_set_driver_bss_selection(wpa_s->wpa,
7796 !!(wpa_s->drv_flags &
7797 WPA_DRIVER_FLAGS_BSS_SELECTION));
Matthew Wang9ed1c792024-12-02 14:05:18 +00007798#endif /* CONFIG_NO_WPA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007799 if (wpa_s->max_remain_on_chan == 0)
7800 wpa_s->max_remain_on_chan = 1000;
7801
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007802 /*
7803 * Only take p2p_mgmt parameters when P2P Device is supported.
7804 * Doing it here as it determines whether l2_packet_init() will be done
7805 * during wpa_supplicant_driver_init().
7806 */
7807 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
7808 wpa_s->p2p_mgmt = iface->p2p_mgmt;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007809
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07007810 if (wpa_s->num_multichan_concurrent == 0)
7811 wpa_s->num_multichan_concurrent = 1;
7812
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007813 if (wpa_supplicant_driver_init(wpa_s) < 0)
7814 return -1;
7815
7816#ifdef CONFIG_TDLS
Roshan Pius3a1667e2018-07-03 15:17:14 -07007817 if (!iface->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007818 return -1;
7819#endif /* CONFIG_TDLS */
7820
7821 if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
7822 wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
7823 wpa_dbg(wpa_s, MSG_DEBUG, "Failed to set country");
7824 return -1;
7825 }
7826
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007827#ifdef CONFIG_FST
7828 if (wpa_s->conf->fst_group_id) {
7829 struct fst_iface_cfg cfg;
7830 struct fst_wpa_obj iface_obj;
7831
7832 fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj);
7833 os_strlcpy(cfg.group_id, wpa_s->conf->fst_group_id,
7834 sizeof(cfg.group_id));
7835 cfg.priority = wpa_s->conf->fst_priority;
7836 cfg.llt = wpa_s->conf->fst_llt;
7837
7838 wpa_s->fst = fst_attach(wpa_s->ifname, wpa_s->own_addr,
7839 &iface_obj, &cfg);
7840 if (!wpa_s->fst) {
7841 wpa_msg(wpa_s, MSG_ERROR,
7842 "FST: Cannot attach iface %s to group %s",
7843 wpa_s->ifname, cfg.group_id);
7844 return -1;
7845 }
7846 }
7847#endif /* CONFIG_FST */
7848
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007849 if (wpas_wps_init(wpa_s))
7850 return -1;
7851
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007852#ifdef CONFIG_GAS_SERVER
7853 wpa_s->gas_server = gas_server_init(wpa_s, wpas_gas_server_tx);
7854 if (!wpa_s->gas_server) {
7855 wpa_printf(MSG_ERROR, "Failed to initialize GAS server");
7856 return -1;
7857 }
7858#endif /* CONFIG_GAS_SERVER */
7859
7860#ifdef CONFIG_DPP
7861 if (wpas_dpp_init(wpa_s) < 0)
7862 return -1;
7863#endif /* CONFIG_DPP */
7864
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007865#ifdef CONFIG_NAN_USD
7866 if (wpas_nan_usd_init(wpa_s) < 0)
7867 return -1;
7868#endif /* CONFIG_NAN_USD */
7869
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007870 if (wpa_supplicant_init_eapol(wpa_s) < 0)
7871 return -1;
7872 wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
7873
7874 wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
7875 if (wpa_s->ctrl_iface == NULL) {
7876 wpa_printf(MSG_ERROR,
7877 "Failed to initialize control interface '%s'.\n"
7878 "You may have another wpa_supplicant process "
7879 "already running or the file was\n"
7880 "left by an unclean termination of wpa_supplicant "
7881 "in which case you will need\n"
7882 "to manually remove this file before starting "
7883 "wpa_supplicant again.\n",
7884 wpa_s->conf->ctrl_interface);
7885 return -1;
7886 }
7887
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007888 wpa_s->gas = gas_query_init(wpa_s);
7889 if (wpa_s->gas == NULL) {
7890 wpa_printf(MSG_ERROR, "Failed to initialize GAS query");
7891 return -1;
7892 }
7893
Roshan Pius3a1667e2018-07-03 15:17:14 -07007894 if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) ||
7895 wpa_s->p2p_mgmt) &&
7896 wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007897 wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
7898 return -1;
7899 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007900
7901 if (wpa_bss_init(wpa_s) < 0)
7902 return -1;
7903
Paul Stewart092955c2017-02-06 09:13:09 -08007904#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
7905#ifdef CONFIG_MESH
7906 dl_list_init(&wpa_s->mesh_external_pmksa_cache);
7907#endif /* CONFIG_MESH */
7908#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
7909
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07007910 /*
7911 * Set Wake-on-WLAN triggers, if configured.
7912 * Note: We don't restore/remove the triggers on shutdown (it doesn't
7913 * have effect anyway when the interface is down).
7914 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007915 if (capa_res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07007916 return -1;
7917
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007918#ifdef CONFIG_EAP_PROXY
7919{
7920 size_t len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007921 wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1,
7922 wpa_s->imsi, &len);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007923 if (wpa_s->mnc_len > 0) {
7924 wpa_s->imsi[len] = '\0';
7925 wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
7926 wpa_s->imsi, wpa_s->mnc_len);
7927 } else {
7928 wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
7929 }
7930}
7931#endif /* CONFIG_EAP_PROXY */
7932
Dmitry Shmidt04949592012-07-19 12:16:46 -07007933 if (pcsc_reader_init(wpa_s) < 0)
7934 return -1;
7935
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007936 if (wpas_init_ext_pw(wpa_s) < 0)
7937 return -1;
7938
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007939#ifndef CONFIG_NO_RRM
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007940 wpas_rrm_reset(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007941#endif /* CONFIG_NO_RRM */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007942
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007943 wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
7944
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08007945#ifdef CONFIG_HS20
7946 hs20_init(wpa_s);
7947#endif /* CONFIG_HS20 */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007948#ifdef CONFIG_MBO
Hai Shalomc3565922019-10-28 11:58:20 -07007949 if (!wpa_s->disable_mbo_oce && wpa_s->conf->oce) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007950 if ((wpa_s->conf->oce & OCE_STA) &&
7951 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
7952 wpa_s->enable_oce = OCE_STA;
7953 if ((wpa_s->conf->oce & OCE_STA_CFON) &&
7954 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON)) {
7955 /* TODO: Need to add STA-CFON support */
7956 wpa_printf(MSG_ERROR,
7957 "OCE STA-CFON feature is not yet supported");
7958 }
7959 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007960 wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan);
7961#endif /* CONFIG_MBO */
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08007962
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07007963 wpa_supplicant_set_default_scan_ies(wpa_s);
7964
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007965 return 0;
7966}
7967
7968
7969static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07007970 int notify, int terminate)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007971{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007972 struct wpa_global *global = wpa_s->global;
7973 struct wpa_supplicant *iface, *prev;
7974
Jimmy Chen0e73c002021-08-18 13:21:30 +08007975 if (wpa_s == wpa_s->parent || (wpa_s == wpa_s->p2pdev && wpa_s->p2p_mgmt))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007976 wpas_p2p_group_remove(wpa_s, "*");
7977
7978 iface = global->ifaces;
7979 while (iface) {
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007980 if (iface->p2pdev == wpa_s)
7981 iface->p2pdev = iface->parent;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007982 if (iface == wpa_s || iface->parent != wpa_s) {
7983 iface = iface->next;
7984 continue;
7985 }
7986 wpa_printf(MSG_DEBUG,
7987 "Remove remaining child interface %s from parent %s",
7988 iface->ifname, wpa_s->ifname);
7989 prev = iface;
7990 iface = iface->next;
7991 wpa_supplicant_remove_iface(global, prev, terminate);
7992 }
7993
Dmitry Shmidtea69e842013-05-13 14:52:28 -07007994 wpa_s->disconnected = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007995 if (wpa_s->drv_priv) {
Hai Shalom60840252021-02-19 19:02:11 -08007996 /*
7997 * Don't deauthenticate if WoWLAN is enable and not explicitly
7998 * been configured to disconnect.
7999 */
8000 if (!wpa_drv_get_wowlan(wpa_s) ||
8001 wpa_s->conf->wowlan_disconnect_on_deinit) {
Hai Shalomfdcde762020-04-02 11:19:20 -07008002 wpa_supplicant_deauthenticate(
8003 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008004
Hai Shalomfdcde762020-04-02 11:19:20 -07008005 wpa_drv_set_countermeasures(wpa_s, 0);
8006 wpa_clear_keys(wpa_s, NULL);
8007 } else {
8008 wpa_msg(wpa_s, MSG_INFO,
8009 "Do not deauthenticate as part of interface deinit since WoWLAN is enabled");
8010 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008011 }
8012
8013 wpa_supplicant_cleanup(wpa_s);
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07008014 wpas_p2p_deinit_iface(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07008015
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008016 wpas_ctrl_radio_work_flush(wpa_s);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08008017 radio_remove_interface(wpa_s);
8018
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008019#ifdef CONFIG_FST
8020 if (wpa_s->fst) {
8021 fst_detach(wpa_s->fst);
8022 wpa_s->fst = NULL;
8023 }
8024 if (wpa_s->received_mb_ies) {
8025 wpabuf_free(wpa_s->received_mb_ies);
8026 wpa_s->received_mb_ies = NULL;
8027 }
8028#endif /* CONFIG_FST */
8029
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008030 if (wpa_s->drv_priv)
8031 wpa_drv_deinit(wpa_s);
Irfan Sheriff622b66d2011-08-03 09:11:49 -07008032
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008033 if (notify)
8034 wpas_notify_iface_removed(wpa_s);
8035
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008036 if (terminate)
8037 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
Irfan Sheriff622b66d2011-08-03 09:11:49 -07008038
Jouni Malinenf3f8d3c2021-02-05 00:28:17 +02008039 wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
8040 wpa_s->ctrl_iface = NULL;
Irfan Sheriff622b66d2011-08-03 09:11:49 -07008041
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008042#ifdef CONFIG_MESH
8043 if (wpa_s->ifmsh) {
Hai Shalom60840252021-02-19 19:02:11 -08008044 wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh, true);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008045 wpa_s->ifmsh = NULL;
8046 }
8047#endif /* CONFIG_MESH */
8048
Irfan Sheriff622b66d2011-08-03 09:11:49 -07008049 if (wpa_s->conf != NULL) {
Irfan Sheriff622b66d2011-08-03 09:11:49 -07008050 wpa_config_free(wpa_s->conf);
8051 wpa_s->conf = NULL;
8052 }
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008053
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07008054 os_free(wpa_s->ssids_from_scan_req);
Hai Shalomc3565922019-10-28 11:58:20 -07008055 os_free(wpa_s->last_scan_freqs);
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07008056
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008057 os_free(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008058}
8059
8060
Dmitry Shmidte4663042016-04-04 10:07:49 -07008061#ifdef CONFIG_MATCH_IFACE
8062
8063/**
8064 * wpa_supplicant_match_iface - Match an interface description to a name
8065 * @global: Pointer to global data from wpa_supplicant_init()
8066 * @ifname: Name of the interface to match
8067 * Returns: Pointer to the created interface description or %NULL on failure
8068 */
8069struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
8070 const char *ifname)
8071{
8072 int i;
8073 struct wpa_interface *iface, *miface;
8074
8075 for (i = 0; i < global->params.match_iface_count; i++) {
8076 miface = &global->params.match_ifaces[i];
8077 if (!miface->ifname ||
8078 fnmatch(miface->ifname, ifname, 0) == 0) {
8079 iface = os_zalloc(sizeof(*iface));
8080 if (!iface)
8081 return NULL;
8082 *iface = *miface;
Hai Shalom899fcc72020-10-19 14:38:18 -07008083 if (!miface->ifname)
8084 iface->matched = WPA_IFACE_MATCHED_NULL;
8085 else
8086 iface->matched = WPA_IFACE_MATCHED;
Dmitry Shmidte4663042016-04-04 10:07:49 -07008087 iface->ifname = ifname;
8088 return iface;
8089 }
8090 }
8091
8092 return NULL;
8093}
8094
8095
8096/**
8097 * wpa_supplicant_match_existing - Match existing interfaces
8098 * @global: Pointer to global data from wpa_supplicant_init()
8099 * Returns: 0 on success, -1 on failure
8100 */
8101static int wpa_supplicant_match_existing(struct wpa_global *global)
8102{
8103 struct if_nameindex *ifi, *ifp;
8104 struct wpa_supplicant *wpa_s;
8105 struct wpa_interface *iface;
8106
8107 ifp = if_nameindex();
8108 if (!ifp) {
8109 wpa_printf(MSG_ERROR, "if_nameindex: %s", strerror(errno));
8110 return -1;
8111 }
8112
8113 for (ifi = ifp; ifi->if_name; ifi++) {
8114 wpa_s = wpa_supplicant_get_iface(global, ifi->if_name);
8115 if (wpa_s)
8116 continue;
8117 iface = wpa_supplicant_match_iface(global, ifi->if_name);
8118 if (iface) {
Hai Shalom60840252021-02-19 19:02:11 -08008119 wpa_supplicant_add_iface(global, iface, NULL);
Dmitry Shmidte4663042016-04-04 10:07:49 -07008120 os_free(iface);
Dmitry Shmidte4663042016-04-04 10:07:49 -07008121 }
8122 }
8123
8124 if_freenameindex(ifp);
8125 return 0;
8126}
8127
8128#endif /* CONFIG_MATCH_IFACE */
8129
8130
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008131/**
8132 * wpa_supplicant_add_iface - Add a new network interface
8133 * @global: Pointer to global data from wpa_supplicant_init()
8134 * @iface: Interface configuration options
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08008135 * @parent: Parent interface or %NULL to assign new interface as parent
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008136 * Returns: Pointer to the created interface or %NULL on failure
8137 *
8138 * This function is used to add new network interfaces for %wpa_supplicant.
8139 * This can be called before wpa_supplicant_run() to add interfaces before the
8140 * main event loop has been started. In addition, new interfaces can be added
8141 * dynamically while %wpa_supplicant is already running. This could happen,
8142 * e.g., when a hotplug network adapter is inserted.
8143 */
8144struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08008145 struct wpa_interface *iface,
8146 struct wpa_supplicant *parent)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008147{
8148 struct wpa_supplicant *wpa_s;
8149 struct wpa_interface t_iface;
8150 struct wpa_ssid *ssid;
8151
8152 if (global == NULL || iface == NULL)
8153 return NULL;
8154
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08008155 wpa_s = wpa_supplicant_alloc(parent);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008156 if (wpa_s == NULL)
8157 return NULL;
8158
8159 wpa_s->global = global;
8160
8161 t_iface = *iface;
8162 if (global->params.override_driver) {
8163 wpa_printf(MSG_DEBUG, "Override interface parameter: driver "
8164 "('%s' -> '%s')",
8165 iface->driver, global->params.override_driver);
8166 t_iface.driver = global->params.override_driver;
8167 }
8168 if (global->params.override_ctrl_interface) {
8169 wpa_printf(MSG_DEBUG, "Override interface parameter: "
8170 "ctrl_interface ('%s' -> '%s')",
8171 iface->ctrl_interface,
8172 global->params.override_ctrl_interface);
8173 t_iface.ctrl_interface =
8174 global->params.override_ctrl_interface;
8175 }
8176 if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
8177 wpa_printf(MSG_DEBUG, "Failed to add interface %s",
8178 iface->ifname);
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008179 wpa_supplicant_deinit_iface(wpa_s, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008180 return NULL;
8181 }
8182
Roshan Piusd6d8b8d2016-11-08 14:45:26 -08008183 /* Notify the control interfaces about new iface */
8184 if (wpas_notify_iface_added(wpa_s)) {
8185 wpa_supplicant_deinit_iface(wpa_s, 1, 0);
8186 return NULL;
8187 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008188
Jimmy Chene2206be2022-07-10 10:25:21 +08008189 /* Notify the control interfaces about new networks */
8190 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
8191 if (iface->p2p_mgmt == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008192 wpas_notify_network_added(wpa_s, ssid);
Jimmy Chene2206be2022-07-10 10:25:21 +08008193 } else if (ssid->ssid_len > P2P_WILDCARD_SSID_LEN
8194 && os_strncmp((const char *) ssid->ssid,
8195 P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0) {
8196 wpas_notify_persistent_group_added(wpa_s, ssid);
8197 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008198 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008199
8200 wpa_s->next = global->ifaces;
8201 global->ifaces = wpa_s;
8202
8203 wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
Dmitry Shmidt04949592012-07-19 12:16:46 -07008204 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008205
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008206#ifdef CONFIG_P2P
8207 if (wpa_s->global->p2p == NULL &&
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07008208 !wpa_s->global->p2p_disabled && !wpa_s->conf->p2p_disabled &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008209 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07008210 wpas_p2p_add_p2pdev_interface(
8211 wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008212 wpa_printf(MSG_INFO,
8213 "P2P: Failed to enable P2P Device interface");
8214 /* Try to continue without. P2P will be disabled. */
8215 }
8216#endif /* CONFIG_P2P */
8217
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008218 return wpa_s;
8219}
8220
8221
8222/**
8223 * wpa_supplicant_remove_iface - Remove a network interface
8224 * @global: Pointer to global data from wpa_supplicant_init()
8225 * @wpa_s: Pointer to the network interface to be removed
8226 * Returns: 0 if interface was removed, -1 if interface was not found
8227 *
8228 * This function can be used to dynamically remove network interfaces from
8229 * %wpa_supplicant, e.g., when a hotplug network adapter is ejected. In
8230 * addition, this function is used to remove all remaining interfaces when
8231 * %wpa_supplicant is terminated.
8232 */
8233int wpa_supplicant_remove_iface(struct wpa_global *global,
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008234 struct wpa_supplicant *wpa_s,
8235 int terminate)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008236{
8237 struct wpa_supplicant *prev;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008238#ifdef CONFIG_MESH
8239 unsigned int mesh_if_created = wpa_s->mesh_if_created;
8240 char *ifname = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008241 struct wpa_supplicant *parent = wpa_s->parent;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008242#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008243
8244 /* Remove interface from the global list of interfaces */
8245 prev = global->ifaces;
8246 if (prev == wpa_s) {
8247 global->ifaces = wpa_s->next;
8248 } else {
8249 while (prev && prev->next != wpa_s)
8250 prev = prev->next;
8251 if (prev == NULL)
8252 return -1;
8253 prev->next = wpa_s->next;
8254 }
8255
8256 wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
8257
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008258#ifdef CONFIG_MESH
8259 if (mesh_if_created) {
8260 ifname = os_strdup(wpa_s->ifname);
8261 if (ifname == NULL) {
8262 wpa_dbg(wpa_s, MSG_ERROR,
8263 "mesh: Failed to malloc ifname");
8264 return -1;
8265 }
8266 }
8267#endif /* CONFIG_MESH */
8268
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008269 if (global->p2p_group_formation == wpa_s)
8270 global->p2p_group_formation = NULL;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07008271 if (global->p2p_invite_group == wpa_s)
8272 global->p2p_invite_group = NULL;
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008273 wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008274
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008275#ifdef CONFIG_MESH
8276 if (mesh_if_created) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008277 wpa_drv_if_remove(parent, WPA_IF_MESH, ifname);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008278 os_free(ifname);
8279 }
8280#endif /* CONFIG_MESH */
8281
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008282 return 0;
8283}
8284
8285
8286/**
8287 * wpa_supplicant_get_eap_mode - Get the current EAP mode
8288 * @wpa_s: Pointer to the network interface
8289 * Returns: Pointer to the eap mode or the string "UNKNOWN" if not found
8290 */
8291const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s)
8292{
8293 const char *eapol_method;
8294
8295 if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) == 0 &&
8296 wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
8297 return "NO-EAP";
8298 }
8299
8300 eapol_method = eapol_sm_get_method_name(wpa_s->eapol);
8301 if (eapol_method == NULL)
8302 return "UNKNOWN-EAP";
8303
8304 return eapol_method;
8305}
8306
8307
8308/**
8309 * wpa_supplicant_get_iface - Get a new network interface
8310 * @global: Pointer to global data from wpa_supplicant_init()
8311 * @ifname: Interface name
8312 * Returns: Pointer to the interface or %NULL if not found
8313 */
8314struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
8315 const char *ifname)
8316{
8317 struct wpa_supplicant *wpa_s;
8318
8319 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
8320 if (os_strcmp(wpa_s->ifname, ifname) == 0)
8321 return wpa_s;
8322 }
8323 return NULL;
8324}
8325
8326
8327#ifndef CONFIG_NO_WPA_MSG
8328static const char * wpa_supplicant_msg_ifname_cb(void *ctx)
8329{
8330 struct wpa_supplicant *wpa_s = ctx;
8331 if (wpa_s == NULL)
8332 return NULL;
8333 return wpa_s->ifname;
8334}
8335#endif /* CONFIG_NO_WPA_MSG */
8336
8337
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008338#ifndef WPA_SUPPLICANT_CLEANUP_INTERVAL
8339#define WPA_SUPPLICANT_CLEANUP_INTERVAL 10
8340#endif /* WPA_SUPPLICANT_CLEANUP_INTERVAL */
8341
8342/* Periodic cleanup tasks */
8343static void wpas_periodic(void *eloop_ctx, void *timeout_ctx)
8344{
8345 struct wpa_global *global = eloop_ctx;
8346 struct wpa_supplicant *wpa_s;
8347
8348 eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
8349 wpas_periodic, global, NULL);
8350
8351#ifdef CONFIG_P2P
8352 if (global->p2p)
8353 p2p_expire_peers(global->p2p);
8354#endif /* CONFIG_P2P */
8355
8356 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
8357 wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
8358#ifdef CONFIG_AP
8359 ap_periodic(wpa_s);
8360#endif /* CONFIG_AP */
8361 }
8362}
8363
8364
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008365/**
8366 * wpa_supplicant_init - Initialize %wpa_supplicant
8367 * @params: Parameters for %wpa_supplicant
8368 * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
8369 *
8370 * This function is used to initialize %wpa_supplicant. After successful
8371 * initialization, the returned data pointer can be used to add and remove
8372 * network interfaces, and eventually, to deinitialize %wpa_supplicant.
8373 */
8374struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
8375{
8376 struct wpa_global *global;
8377 int ret, i;
8378
8379 if (params == NULL)
8380 return NULL;
8381
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008382#ifdef CONFIG_DRIVER_NDIS
8383 {
8384 void driver_ndis_init_ops(void);
8385 driver_ndis_init_ops();
8386 }
8387#endif /* CONFIG_DRIVER_NDIS */
8388
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008389#ifndef CONFIG_NO_WPA_MSG
8390 wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
8391#endif /* CONFIG_NO_WPA_MSG */
8392
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008393 if (params->wpa_debug_file_path)
8394 wpa_debug_open_file(params->wpa_debug_file_path);
Hai Shalomfdcde762020-04-02 11:19:20 -07008395 if (!params->wpa_debug_file_path && !params->wpa_debug_syslog)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008396 wpa_debug_setup_stdout();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008397 if (params->wpa_debug_syslog)
8398 wpa_debug_open_syslog();
Dmitry Shmidt04949592012-07-19 12:16:46 -07008399 if (params->wpa_debug_tracing) {
8400 ret = wpa_debug_open_linux_tracing();
8401 if (ret) {
8402 wpa_printf(MSG_ERROR,
8403 "Failed to enable trace logging");
8404 return NULL;
8405 }
8406 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008407
8408 ret = eap_register_methods();
8409 if (ret) {
8410 wpa_printf(MSG_ERROR, "Failed to register EAP methods");
8411 if (ret == -2)
8412 wpa_printf(MSG_ERROR, "Two or more EAP methods used "
8413 "the same EAP type.");
8414 return NULL;
8415 }
8416
8417 global = os_zalloc(sizeof(*global));
8418 if (global == NULL)
8419 return NULL;
8420 dl_list_init(&global->p2p_srv_bonjour);
8421 dl_list_init(&global->p2p_srv_upnp);
8422 global->params.daemonize = params->daemonize;
8423 global->params.wait_for_monitor = params->wait_for_monitor;
8424 global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
Sunil Ravi77d572f2023-01-17 23:58:31 +00008425
8426 if (params->pid_file) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008427 global->params.pid_file = os_strdup(params->pid_file);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008428 if (!global->params.pid_file) {
8429 wpa_supplicant_deinit(global);
8430 return NULL;
8431 }
8432 }
8433
8434 if (params->ctrl_interface) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008435 global->params.ctrl_interface =
8436 os_strdup(params->ctrl_interface);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008437 if (!global->params.ctrl_interface) {
8438 wpa_supplicant_deinit(global);
8439 return NULL;
8440 }
8441 }
8442
8443 if (params->ctrl_interface_group) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07008444 global->params.ctrl_interface_group =
8445 os_strdup(params->ctrl_interface_group);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008446 if (!global->params.ctrl_interface_group) {
8447 wpa_supplicant_deinit(global);
8448 return NULL;
8449 }
8450 }
8451
8452 if (params->override_driver) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008453 global->params.override_driver =
8454 os_strdup(params->override_driver);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008455 if (!global->params.override_driver) {
8456 wpa_supplicant_deinit(global);
8457 return NULL;
8458 }
8459 }
8460
8461 if (params->override_ctrl_interface) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008462 global->params.override_ctrl_interface =
8463 os_strdup(params->override_ctrl_interface);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008464 if (!global->params.override_ctrl_interface) {
8465 wpa_supplicant_deinit(global);
8466 return NULL;
8467 }
8468 }
8469
Dmitry Shmidte4663042016-04-04 10:07:49 -07008470#ifdef CONFIG_MATCH_IFACE
8471 global->params.match_iface_count = params->match_iface_count;
8472 if (params->match_iface_count) {
8473 global->params.match_ifaces =
8474 os_calloc(params->match_iface_count,
8475 sizeof(struct wpa_interface));
Sunil Ravi77d572f2023-01-17 23:58:31 +00008476 if (!global->params.match_ifaces) {
8477 wpa_printf(MSG_ERROR,
8478 "Failed to allocate match interfaces");
8479 wpa_supplicant_deinit(global);
8480 return NULL;
8481 }
Dmitry Shmidte4663042016-04-04 10:07:49 -07008482 os_memcpy(global->params.match_ifaces,
8483 params->match_ifaces,
8484 params->match_iface_count *
8485 sizeof(struct wpa_interface));
8486 }
8487#endif /* CONFIG_MATCH_IFACE */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008488#ifdef CONFIG_P2P
Sunil Ravi77d572f2023-01-17 23:58:31 +00008489 if (params->conf_p2p_dev) {
Sasha Levitskiydaa60e52015-08-05 13:02:59 -07008490 global->params.conf_p2p_dev =
8491 os_strdup(params->conf_p2p_dev);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008492 if (!global->params.conf_p2p_dev) {
8493 wpa_printf(MSG_ERROR, "Failed to allocate conf p2p");
8494 wpa_supplicant_deinit(global);
8495 return NULL;
8496 }
8497 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008498#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008499 wpa_debug_level = global->params.wpa_debug_level =
8500 params->wpa_debug_level;
8501 wpa_debug_show_keys = global->params.wpa_debug_show_keys =
8502 params->wpa_debug_show_keys;
8503 wpa_debug_timestamp = global->params.wpa_debug_timestamp =
8504 params->wpa_debug_timestamp;
8505
Hai Shalomfdcde762020-04-02 11:19:20 -07008506 wpa_printf(MSG_DEBUG, "wpa_supplicant v%s", VERSION_STR);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008507
8508 if (eloop_init()) {
8509 wpa_printf(MSG_ERROR, "Failed to initialize event loop");
8510 wpa_supplicant_deinit(global);
8511 return NULL;
8512 }
8513
Jouni Malinen75ecf522011-06-27 15:19:46 -07008514 random_init(params->entropy_file);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008515
8516 global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
8517 if (global->ctrl_iface == NULL) {
8518 wpa_supplicant_deinit(global);
8519 return NULL;
8520 }
8521
8522 if (wpas_notify_supplicant_initialized(global)) {
8523 wpa_supplicant_deinit(global);
8524 return NULL;
8525 }
8526
8527 for (i = 0; wpa_drivers[i]; i++)
8528 global->drv_count++;
8529 if (global->drv_count == 0) {
8530 wpa_printf(MSG_ERROR, "No drivers enabled");
8531 wpa_supplicant_deinit(global);
8532 return NULL;
8533 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008534 global->drv_priv = os_calloc(global->drv_count, sizeof(void *));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008535 if (global->drv_priv == NULL) {
8536 wpa_supplicant_deinit(global);
8537 return NULL;
8538 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008539
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008540#ifdef CONFIG_WIFI_DISPLAY
8541 if (wifi_display_init(global) < 0) {
8542 wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");
8543 wpa_supplicant_deinit(global);
8544 return NULL;
8545 }
8546#endif /* CONFIG_WIFI_DISPLAY */
8547
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008548 eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
8549 wpas_periodic, global, NULL);
8550
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008551 return global;
8552}
8553
8554
8555/**
8556 * wpa_supplicant_run - Run the %wpa_supplicant main event loop
8557 * @global: Pointer to global data from wpa_supplicant_init()
8558 * Returns: 0 after successful event loop run, -1 on failure
8559 *
8560 * This function starts the main event loop and continues running as long as
8561 * there are any remaining events. In most cases, this function is running as
8562 * long as the %wpa_supplicant process in still in use.
8563 */
8564int wpa_supplicant_run(struct wpa_global *global)
8565{
8566 struct wpa_supplicant *wpa_s;
8567
8568 if (global->params.daemonize &&
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08008569 (wpa_supplicant_daemon(global->params.pid_file) ||
8570 eloop_sock_requeue()))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008571 return -1;
8572
Dmitry Shmidte4663042016-04-04 10:07:49 -07008573#ifdef CONFIG_MATCH_IFACE
8574 if (wpa_supplicant_match_existing(global))
8575 return -1;
8576#endif
8577
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008578 if (global->params.wait_for_monitor) {
8579 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08008580 if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008581 wpa_supplicant_ctrl_iface_wait(
8582 wpa_s->ctrl_iface);
8583 }
8584
Kiran Kumar Lokerea9f98eb2023-03-17 13:01:12 -07008585#ifdef CONFIG_AIDL
Gabriel Biren7a30e7f2023-06-02 20:11:28 +00008586 // If daemonize is enabled, initialize AIDL here.
8587 if (global->params.daemonize) {
8588 global->aidl = wpas_aidl_init(global);
8589 if (!global->aidl)
8590 return -1;
8591 }
Kiran Kumar Lokerea9f98eb2023-03-17 13:01:12 -07008592#endif /* CONFIG_AIDL */
8593
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008594 eloop_register_signal_terminate(wpa_supplicant_terminate, global);
8595 eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
8596
8597 eloop_run();
8598
8599 return 0;
8600}
8601
8602
8603/**
8604 * wpa_supplicant_deinit - Deinitialize %wpa_supplicant
8605 * @global: Pointer to global data from wpa_supplicant_init()
8606 *
8607 * This function is called to deinitialize %wpa_supplicant and to free all
8608 * allocated resources. Remaining network interfaces will also be removed.
8609 */
8610void wpa_supplicant_deinit(struct wpa_global *global)
8611{
8612 int i;
8613
8614 if (global == NULL)
8615 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008616
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008617 eloop_cancel_timeout(wpas_periodic, global, NULL);
8618
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008619#ifdef CONFIG_WIFI_DISPLAY
8620 wifi_display_deinit(global);
8621#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008622
8623 while (global->ifaces)
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008624 wpa_supplicant_remove_iface(global, global->ifaces, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008625
8626 if (global->ctrl_iface)
8627 wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
8628
8629 wpas_notify_supplicant_deinitialized(global);
8630
8631 eap_peer_unregister_methods();
8632#ifdef CONFIG_AP
8633 eap_server_unregister_methods();
8634#endif /* CONFIG_AP */
8635
8636 for (i = 0; wpa_drivers[i] && global->drv_priv; i++) {
8637 if (!global->drv_priv[i])
8638 continue;
8639 wpa_drivers[i]->global_deinit(global->drv_priv[i]);
8640 }
8641 os_free(global->drv_priv);
8642
8643 random_deinit();
8644
8645 eloop_destroy();
8646
8647 if (global->params.pid_file) {
8648 os_daemonize_terminate(global->params.pid_file);
8649 os_free(global->params.pid_file);
8650 }
8651 os_free(global->params.ctrl_interface);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07008652 os_free(global->params.ctrl_interface_group);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008653 os_free(global->params.override_driver);
8654 os_free(global->params.override_ctrl_interface);
Dmitry Shmidte4663042016-04-04 10:07:49 -07008655#ifdef CONFIG_MATCH_IFACE
8656 os_free(global->params.match_ifaces);
8657#endif /* CONFIG_MATCH_IFACE */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008658#ifdef CONFIG_P2P
Sasha Levitskiydaa60e52015-08-05 13:02:59 -07008659 os_free(global->params.conf_p2p_dev);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008660#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008661
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07008662 os_free(global->p2p_disallow_freq.range);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08008663 os_free(global->p2p_go_avoid_freq.range);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07008664 os_free(global->add_psk);
Dmitry Shmidt04949592012-07-19 12:16:46 -07008665
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008666 os_free(global);
8667 wpa_debug_close_syslog();
8668 wpa_debug_close_file();
Dmitry Shmidt04949592012-07-19 12:16:46 -07008669 wpa_debug_close_linux_tracing();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008670}
8671
8672
8673void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
8674{
8675 if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
8676 wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
8677 char country[3];
8678 country[0] = wpa_s->conf->country[0];
8679 country[1] = wpa_s->conf->country[1];
8680 country[2] = '\0';
8681 if (wpa_drv_set_country(wpa_s, country) < 0) {
8682 wpa_printf(MSG_ERROR, "Failed to set country code "
8683 "'%s'", country);
8684 }
8685 }
8686
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008687 if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
8688 wpas_init_ext_pw(wpa_s);
8689
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008690 if (wpa_s->conf->changed_parameters & CFG_CHANGED_SCHED_SCAN_PLANS)
8691 wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
8692
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008693 if (wpa_s->conf->changed_parameters & CFG_CHANGED_WOWLAN_TRIGGERS) {
8694 struct wpa_driver_capa capa;
8695 int res = wpa_drv_get_capa(wpa_s, &capa);
8696
8697 if (res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
8698 wpa_printf(MSG_ERROR,
8699 "Failed to update wowlan_triggers to '%s'",
8700 wpa_s->conf->wowlan_triggers);
8701 }
8702
Hai Shalom81f62d82019-07-22 12:10:00 -07008703 if (wpa_s->conf->changed_parameters & CFG_CHANGED_DISABLE_BTM)
8704 wpa_supplicant_set_default_scan_ies(wpa_s);
8705
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008706 if (wpa_s->conf->changed_parameters & CFG_CHANGED_FT_PREPEND_PMKID)
8707 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_PREPEND_PMKID,
8708 wpa_s->conf->ft_prepend_pmkid);
8709
Hai Shalom899fcc72020-10-19 14:38:18 -07008710#ifdef CONFIG_BGSCAN
8711 /*
8712 * We default to global bgscan parameters only when per-network bgscan
8713 * parameters aren't set. Only bother resetting bgscan parameters if
8714 * this is the case.
8715 */
8716 if ((wpa_s->conf->changed_parameters & CFG_CHANGED_BGSCAN) &&
8717 wpa_s->current_ssid && !wpa_s->current_ssid->bgscan &&
8718 wpa_s->wpa_state == WPA_COMPLETED)
8719 wpa_supplicant_reset_bgscan(wpa_s);
8720#endif /* CONFIG_BGSCAN */
8721
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008722#ifdef CONFIG_WPS
8723 wpas_wps_update_config(wpa_s);
8724#endif /* CONFIG_WPS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008725 wpas_p2p_update_config(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008726 wpa_s->conf->changed_parameters = 0;
8727}
8728
8729
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008730void add_freq(int *freqs, int *num_freqs, int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008731{
8732 int i;
8733
8734 for (i = 0; i < *num_freqs; i++) {
8735 if (freqs[i] == freq)
8736 return;
8737 }
8738
8739 freqs[*num_freqs] = freq;
8740 (*num_freqs)++;
8741}
8742
8743
8744static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
8745{
8746 struct wpa_bss *bss, *cbss;
8747 const int max_freqs = 10;
8748 int *freqs;
8749 int num_freqs = 0;
8750
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008751 freqs = os_calloc(max_freqs + 1, sizeof(int));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008752 if (freqs == NULL)
8753 return NULL;
8754
8755 cbss = wpa_s->current_bss;
8756
8757 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
8758 if (bss == cbss)
8759 continue;
8760 if (bss->ssid_len == cbss->ssid_len &&
8761 os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
Hai Shalom60840252021-02-19 19:02:11 -08008762 !wpa_bssid_ignore_is_listed(wpa_s, bss->bssid)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008763 add_freq(freqs, &num_freqs, bss->freq);
8764 if (num_freqs == max_freqs)
8765 break;
8766 }
8767 }
8768
8769 if (num_freqs == 0) {
8770 os_free(freqs);
8771 freqs = NULL;
8772 }
8773
8774 return freqs;
8775}
8776
8777
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008778void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid,
8779 const u8 **link_bssids)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008780{
8781 int timeout;
8782 int count;
8783 int *freqs = NULL;
8784
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008785 wpas_connect_work_done(wpa_s);
8786
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008787 /*
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008788 * Remove possible authentication timeout since the connection failed.
8789 */
8790 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
8791
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08008792 /*
Hai Shalom60840252021-02-19 19:02:11 -08008793 * There is no point in ignoring the AP temporarily if this event is
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08008794 * generated based on local request to disconnect.
8795 */
Hai Shalomfdcde762020-04-02 11:19:20 -07008796 if (wpa_s->own_disconnect_req || wpa_s->own_reconnect_req) {
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08008797 wpa_s->own_disconnect_req = 0;
8798 wpa_dbg(wpa_s, MSG_DEBUG,
8799 "Ignore connection failure due to local request to disconnect");
8800 return;
8801 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008802 if (wpa_s->disconnected) {
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008803 wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
8804 "indication since interface has been put into "
8805 "disconnected state");
8806 return;
8807 }
Roshan Piusb1ae0fe2019-02-15 08:05:38 -08008808 if (wpa_s->auto_reconnect_disabled) {
8809 wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
8810 "indication since auto connect is disabled");
8811 return;
8812 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008813
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008814 /* Also mark links as failed */
8815 while (link_bssids && *link_bssids) {
8816 wpa_bssid_ignore_add(wpa_s, *link_bssids);
8817 link_bssids++;
8818 }
8819
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008820 /*
Hai Shalom60840252021-02-19 19:02:11 -08008821 * Add the failed BSSID into the ignore list and speed up next scan
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008822 * attempt if there could be other APs that could accept association.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008823 */
Hai Shalom60840252021-02-19 19:02:11 -08008824 count = wpa_bssid_ignore_add(wpa_s, bssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008825 if (count == 1 && wpa_s->current_bss) {
8826 /*
Hai Shalom60840252021-02-19 19:02:11 -08008827 * This BSS was not in the ignore list before. If there is
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008828 * another BSS available for the same ESS, we should try that
8829 * next. Otherwise, we may as well try this one once more
8830 * before allowing other, likely worse, ESSes to be considered.
8831 */
8832 freqs = get_bss_freqs_in_ess(wpa_s);
8833 if (freqs) {
8834 wpa_dbg(wpa_s, MSG_DEBUG, "Another BSS in this ESS "
8835 "has been seen; try it next");
Hai Shalom60840252021-02-19 19:02:11 -08008836 wpa_bssid_ignore_add(wpa_s, bssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008837 /*
8838 * On the next scan, go through only the known channels
8839 * used in this ESS based on previous scans to speed up
8840 * common load balancing use case.
8841 */
8842 os_free(wpa_s->next_scan_freqs);
8843 wpa_s->next_scan_freqs = freqs;
8844 }
8845 }
8846
Hai Shalom899fcc72020-10-19 14:38:18 -07008847 wpa_s->consecutive_conn_failures++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08008848
Hai Shalom899fcc72020-10-19 14:38:18 -07008849 if (wpa_s->consecutive_conn_failures > 3 && wpa_s->current_ssid) {
Dmitry Shmidt4b060592013-04-29 16:42:49 -07008850 wpa_printf(MSG_DEBUG, "Continuous association failures - "
8851 "consider temporary network disabling");
Sunil Ravi77d572f2023-01-17 23:58:31 +00008852 wpas_auth_failed(wpa_s, "CONN_FAILED", bssid);
Dmitry Shmidt4b060592013-04-29 16:42:49 -07008853 }
Hai Shalom899fcc72020-10-19 14:38:18 -07008854 /*
8855 * Multiple consecutive connection failures mean that other APs are
8856 * either not available or have already been tried, so we can start
8857 * increasing the delay here to avoid constant scanning.
8858 */
8859 switch (wpa_s->consecutive_conn_failures) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008860 case 1:
8861 timeout = 100;
8862 break;
8863 case 2:
8864 timeout = 500;
8865 break;
8866 case 3:
8867 timeout = 1000;
8868 break;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08008869 case 4:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008870 timeout = 5000;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08008871 break;
8872 default:
8873 timeout = 10000;
8874 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008875 }
8876
Hai Shalom899fcc72020-10-19 14:38:18 -07008877 wpa_dbg(wpa_s, MSG_DEBUG,
8878 "Consecutive connection failures: %d --> request scan in %d ms",
8879 wpa_s->consecutive_conn_failures, timeout);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08008880
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008881 /*
8882 * TODO: if more than one possible AP is available in scan results,
8883 * could try the other ones before requesting a new scan.
8884 */
Hai Shalom021b0b52019-04-10 11:17:58 -07008885
8886 /* speed up the connection attempt with normal scan */
8887 wpa_s->normal_scans = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008888 wpa_supplicant_req_scan(wpa_s, timeout / 1000,
8889 1000 * (timeout % 1000));
8890}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008891
8892
Hai Shalomce48b4a2018-09-05 11:41:35 -07008893#ifdef CONFIG_FILS
Hai Shalomc1a21442022-02-04 13:43:00 -08008894
8895void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s)
8896{
8897 struct wpa_ssid *ssid = wpa_s->current_ssid;
8898 const u8 *realm, *username, *rrk;
8899 size_t realm_len, username_len, rrk_len;
8900 u16 next_seq_num;
8901
8902 /* Clear the PMKSA cache entry if FILS authentication was rejected.
8903 * Check for ERP keys existing to limit when this can be done since
8904 * the rejection response is not protected and such triggers should
8905 * really not allow internal state to be modified unless required to
8906 * avoid significant issues in functionality. In addition, drop
8907 * externally configure PMKSA entries even without ERP keys since it
8908 * is possible for an external component to add PMKSA entries for FILS
8909 * authentication without restoring previously generated ERP keys.
8910 *
8911 * In this case, this is needed to allow recovery from cases where the
8912 * AP or authentication server has dropped PMKSAs and ERP keys. */
8913 if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt))
8914 return;
8915
8916 if (eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
8917 &username, &username_len,
8918 &realm, &realm_len, &next_seq_num,
8919 &rrk, &rrk_len) != 0 ||
8920 !realm) {
8921 wpa_dbg(wpa_s, MSG_DEBUG,
8922 "FILS: Drop external PMKSA cache entry");
8923 wpa_sm_aborted_external_cached(wpa_s->wpa);
8924 wpa_sm_external_pmksa_cache_flush(wpa_s->wpa, ssid);
8925 return;
8926 }
8927
8928 wpa_dbg(wpa_s, MSG_DEBUG, "FILS: Drop PMKSA cache entry");
8929 wpa_sm_aborted_cached(wpa_s->wpa);
8930 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
8931}
8932
8933
Hai Shalomce48b4a2018-09-05 11:41:35 -07008934void fils_connection_failure(struct wpa_supplicant *wpa_s)
8935{
8936 struct wpa_ssid *ssid = wpa_s->current_ssid;
8937 const u8 *realm, *username, *rrk;
8938 size_t realm_len, username_len, rrk_len;
8939 u16 next_seq_num;
8940
8941 if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt) ||
8942 eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
8943 &username, &username_len,
8944 &realm, &realm_len, &next_seq_num,
8945 &rrk, &rrk_len) != 0 ||
8946 !realm)
8947 return;
8948
8949 wpa_hexdump_ascii(MSG_DEBUG,
8950 "FILS: Store last connection failure realm",
8951 realm, realm_len);
8952 os_free(wpa_s->last_con_fail_realm);
8953 wpa_s->last_con_fail_realm = os_malloc(realm_len);
8954 if (wpa_s->last_con_fail_realm) {
8955 wpa_s->last_con_fail_realm_len = realm_len;
8956 os_memcpy(wpa_s->last_con_fail_realm, realm, realm_len);
8957 }
8958}
8959#endif /* CONFIG_FILS */
8960
8961
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008962int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
8963{
8964 return wpa_s->conf->ap_scan == 2 ||
8965 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
8966}
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008967
Dmitry Shmidt04949592012-07-19 12:16:46 -07008968
Sunil Ravi7f769292024-07-23 22:21:32 +00008969static bool wpas_driver_rsn_override(struct wpa_supplicant *wpa_s)
8970{
8971 return !!(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_RSN_OVERRIDE_STA);
8972}
8973
8974
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00008975bool wpas_rsn_overriding(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
Sunil Ravi7f769292024-07-23 22:21:32 +00008976{
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00008977 enum wpas_rsn_overriding rsno;
8978
8979 if (ssid && ssid->rsn_overriding != RSN_OVERRIDING_NOT_SET)
8980 rsno = ssid->rsn_overriding;
8981 else
8982 rsno = wpa_s->conf->rsn_overriding;
8983
8984 if (rsno == RSN_OVERRIDING_DISABLED)
Sunil Ravi7f769292024-07-23 22:21:32 +00008985 return false;
8986
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00008987 if (rsno == RSN_OVERRIDING_ENABLED)
Sunil Ravi7f769292024-07-23 22:21:32 +00008988 return true;
8989
8990 if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
8991 wpas_driver_bss_selection(wpa_s))
8992 return wpas_driver_rsn_override(wpa_s);
8993
8994 return true;
8995}
8996
8997
Gabriel Biren57ededa2021-09-03 16:08:50 +00008998#if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW) || defined (CONFIG_CTRL_IFACE_AIDL)
Dmitry Shmidt04949592012-07-19 12:16:46 -07008999int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
9000 struct wpa_ssid *ssid,
9001 const char *field,
9002 const char *value)
9003{
9004#ifdef IEEE8021X_EAPOL
Roshan Pius71a6b8a2016-08-17 13:04:08 -07009005 enum wpa_ctrl_req_type rtype;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009006
9007 wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
9008 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
9009 (const u8 *) value, os_strlen(value));
9010
Roshan Pius71a6b8a2016-08-17 13:04:08 -07009011 rtype = wpa_supplicant_ctrl_req_from_string(field);
pkanwareb9203e2017-10-26 16:00:35 -07009012 return wpa_supplicant_ctrl_rsp_handle(wpa_s, ssid, rtype, value, strlen(value));
Roshan Pius71a6b8a2016-08-17 13:04:08 -07009013#else /* IEEE8021X_EAPOL */
9014 wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
9015 return -1;
9016#endif /* IEEE8021X_EAPOL */
9017}
9018
9019int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
9020 struct wpa_ssid *ssid,
9021 enum wpa_ctrl_req_type rtype,
pkanwareb9203e2017-10-26 16:00:35 -07009022 const char *value, int value_len)
Roshan Pius71a6b8a2016-08-17 13:04:08 -07009023{
9024#ifdef IEEE8021X_EAPOL
9025 struct eap_peer_config *eap = &ssid->eap;
Ecco Park00a7b212018-01-26 13:44:44 -08009026 char *identity, *imsi_identity;
Roshan Pius71a6b8a2016-08-17 13:04:08 -07009027
9028 switch (rtype) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07009029 case WPA_CTRL_REQ_EAP_IDENTITY:
9030 os_free(eap->identity);
Ecco Park00a7b212018-01-26 13:44:44 -08009031 os_free(eap->imsi_identity);
9032 if (value == NULL)
9033 return -1;
9034 identity = os_strchr(value, ':');
9035 if (identity == NULL) {
9036 /* plain identity */
9037 eap->identity = (u8 *)os_strdup(value);
9038 eap->identity_len = os_strlen(value);
9039 } else {
9040 /* have both plain identity and encrypted identity */
9041 imsi_identity = value;
9042 *identity++ = '\0';
9043 /* plain identity */
9044 eap->imsi_identity = (u8 *)dup_binstr(imsi_identity, strlen(imsi_identity));
9045 eap->imsi_identity_len = strlen(imsi_identity);
9046 /* encrypted identity */
9047 eap->identity = (u8 *)dup_binstr(identity,
9048 value_len - strlen(imsi_identity) - 1);
9049 eap->identity_len = value_len - strlen(imsi_identity) - 1;
9050 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07009051 eap->pending_req_identity = 0;
9052 if (ssid == wpa_s->current_ssid)
9053 wpa_s->reassociate = 1;
9054 break;
9055 case WPA_CTRL_REQ_EAP_PASSWORD:
Dmitry Shmidtc2817022014-07-02 10:32:10 -07009056 bin_clear_free(eap->password, eap->password_len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07009057 eap->password = (u8 *) os_strdup(value);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009058 if (!eap->password)
9059 return -1;
pkanwareb9203e2017-10-26 16:00:35 -07009060 eap->password_len = value_len;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009061 eap->pending_req_password = 0;
9062 if (ssid == wpa_s->current_ssid)
9063 wpa_s->reassociate = 1;
9064 break;
9065 case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
Dmitry Shmidtc2817022014-07-02 10:32:10 -07009066 bin_clear_free(eap->new_password, eap->new_password_len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07009067 eap->new_password = (u8 *) os_strdup(value);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009068 if (!eap->new_password)
9069 return -1;
pkanwareb9203e2017-10-26 16:00:35 -07009070 eap->new_password_len = value_len;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009071 eap->pending_req_new_password = 0;
9072 if (ssid == wpa_s->current_ssid)
9073 wpa_s->reassociate = 1;
9074 break;
9075 case WPA_CTRL_REQ_EAP_PIN:
Hai Shalomc3565922019-10-28 11:58:20 -07009076 str_clear_free(eap->cert.pin);
9077 eap->cert.pin = os_strdup(value);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009078 if (!eap->cert.pin)
9079 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009080 eap->pending_req_pin = 0;
9081 if (ssid == wpa_s->current_ssid)
9082 wpa_s->reassociate = 1;
9083 break;
9084 case WPA_CTRL_REQ_EAP_OTP:
Dmitry Shmidtc2817022014-07-02 10:32:10 -07009085 bin_clear_free(eap->otp, eap->otp_len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07009086 eap->otp = (u8 *) os_strdup(value);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009087 if (!eap->otp)
9088 return -1;
pkanwareb9203e2017-10-26 16:00:35 -07009089 eap->otp_len = value_len;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009090 os_free(eap->pending_req_otp);
9091 eap->pending_req_otp = NULL;
9092 eap->pending_req_otp_len = 0;
9093 break;
9094 case WPA_CTRL_REQ_EAP_PASSPHRASE:
Hai Shalomc3565922019-10-28 11:58:20 -07009095 str_clear_free(eap->cert.private_key_passwd);
9096 eap->cert.private_key_passwd = os_strdup(value);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009097 if (!eap->cert.private_key_passwd)
9098 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009099 eap->pending_req_passphrase = 0;
9100 if (ssid == wpa_s->current_ssid)
9101 wpa_s->reassociate = 1;
9102 break;
Dmitry Shmidt051af732013-10-22 13:52:46 -07009103 case WPA_CTRL_REQ_SIM:
Dmitry Shmidtc2817022014-07-02 10:32:10 -07009104 str_clear_free(eap->external_sim_resp);
Dmitry Shmidt051af732013-10-22 13:52:46 -07009105 eap->external_sim_resp = os_strdup(value);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009106 if (!eap->external_sim_resp)
9107 return -1;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08009108 eap->pending_req_sim = 0;
Dmitry Shmidt051af732013-10-22 13:52:46 -07009109 break;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009110 case WPA_CTRL_REQ_PSK_PASSPHRASE:
9111 if (wpa_config_set(ssid, "psk", value, 0) < 0)
9112 return -1;
9113 ssid->mem_only_psk = 1;
9114 if (ssid->passphrase)
9115 wpa_config_update_psk(ssid);
9116 if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
9117 wpa_supplicant_req_scan(wpa_s, 0, 0);
9118 break;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009119 case WPA_CTRL_REQ_EXT_CERT_CHECK:
9120 if (eap->pending_ext_cert_check != PENDING_CHECK)
9121 return -1;
9122 if (os_strcmp(value, "good") == 0)
9123 eap->pending_ext_cert_check = EXT_CERT_CHECK_GOOD;
9124 else if (os_strcmp(value, "bad") == 0)
9125 eap->pending_ext_cert_check = EXT_CERT_CHECK_BAD;
9126 else
9127 return -1;
9128 break;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009129 default:
Roshan Pius71a6b8a2016-08-17 13:04:08 -07009130 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown type %d", rtype);
Dmitry Shmidt04949592012-07-19 12:16:46 -07009131 return -1;
9132 }
9133
9134 return 0;
9135#else /* IEEE8021X_EAPOL */
9136 wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
9137 return -1;
9138#endif /* IEEE8021X_EAPOL */
9139}
Gabriel Biren57ededa2021-09-03 16:08:50 +00009140#endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW || CONFIG_CTRL_IFACE_AIDL */
Dmitry Shmidt04949592012-07-19 12:16:46 -07009141
9142
9143int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
9144{
Hai Shalomfdcde762020-04-02 11:19:20 -07009145#ifdef CONFIG_WEP
Dmitry Shmidt04949592012-07-19 12:16:46 -07009146 int i;
9147 unsigned int drv_enc;
Hai Shalomfdcde762020-04-02 11:19:20 -07009148#endif /* CONFIG_WEP */
Dmitry Shmidt04949592012-07-19 12:16:46 -07009149
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08009150 if (wpa_s->p2p_mgmt)
9151 return 1; /* no normal network profiles on p2p_mgmt interface */
9152
Dmitry Shmidt04949592012-07-19 12:16:46 -07009153 if (ssid == NULL)
9154 return 1;
9155
9156 if (ssid->disabled)
9157 return 1;
9158
Hai Shalomfdcde762020-04-02 11:19:20 -07009159#ifdef CONFIG_WEP
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08009160 if (wpa_s->drv_capa_known)
Dmitry Shmidt04949592012-07-19 12:16:46 -07009161 drv_enc = wpa_s->drv_enc;
9162 else
9163 drv_enc = (unsigned int) -1;
9164
9165 for (i = 0; i < NUM_WEP_KEYS; i++) {
9166 size_t len = ssid->wep_key_len[i];
9167 if (len == 0)
9168 continue;
9169 if (len == 5 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP40))
9170 continue;
9171 if (len == 13 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP104))
9172 continue;
9173 if (len == 16 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP128))
9174 continue;
9175 return 1; /* invalid WEP key */
9176 }
Hai Shalomfdcde762020-04-02 11:19:20 -07009177#endif /* CONFIG_WEP */
Dmitry Shmidt04949592012-07-19 12:16:46 -07009178
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009179 if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009180 (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00009181 !(wpa_key_mgmt_sae(ssid->key_mgmt) &&
9182 (ssid->sae_password || ssid->pmk_valid)) &&
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009183 !ssid->mem_only_psk)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009184 return 1;
9185
Sunil Ravi89eba102022-09-13 21:04:37 -07009186#ifdef IEEE8021X_EAPOL
Sunil8cd6f4d2022-06-28 18:40:46 +00009187#ifdef CRYPTO_RSA_OAEP_SHA256
9188 if (ssid->eap.imsi_privacy_cert) {
9189 struct crypto_rsa_key *key;
9190 bool failed = false;
9191
9192 key = crypto_rsa_key_read(ssid->eap.imsi_privacy_cert, false);
9193 if (!key)
9194 failed = true;
9195 crypto_rsa_key_free(key);
9196 if (failed) {
9197 wpa_printf(MSG_DEBUG,
9198 "Invalid imsi_privacy_cert (%s) - disable network",
9199 ssid->eap.imsi_privacy_cert);
9200 return 1;
9201 }
9202 }
9203#endif /* CRYPTO_RSA_OAEP_SHA256 */
Sunil Ravi89eba102022-09-13 21:04:37 -07009204#endif /* IEEE8021X_EAPOL */
Sunil8cd6f4d2022-06-28 18:40:46 +00009205
Dmitry Shmidt04949592012-07-19 12:16:46 -07009206 return 0;
9207}
9208
9209
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009210int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
9211{
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009212 if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
9213 if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
9214 !(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
9215 /*
9216 * Driver does not support BIP -- ignore pmf=1 default
9217 * since the connection with PMF would fail and the
9218 * configuration does not require PMF to be enabled.
9219 */
9220 return NO_MGMT_FRAME_PROTECTION;
9221 }
9222
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009223 if (ssid &&
9224 (ssid->key_mgmt &
9225 ~(WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPS |
9226 WPA_KEY_MGMT_IEEE8021X_NO_WPA)) == 0) {
9227 /*
9228 * Do not use the default PMF value for non-RSN networks
9229 * since PMF is available only with RSN and pmf=2
9230 * configuration would otherwise prevent connections to
9231 * all open networks.
9232 */
9233 return NO_MGMT_FRAME_PROTECTION;
9234 }
9235
Sunil Ravi77d572f2023-01-17 23:58:31 +00009236#ifdef CONFIG_OCV
9237 /* Enable PMF if OCV is being enabled */
9238 if (wpa_s->conf->pmf == NO_MGMT_FRAME_PROTECTION &&
9239 ssid && ssid->ocv)
9240 return MGMT_FRAME_PROTECTION_OPTIONAL;
9241#endif /* CONFIG_OCV */
9242
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009243 return wpa_s->conf->pmf;
9244 }
9245
9246 return ssid->ieee80211w;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009247}
9248
9249
Sunil Ravi77d572f2023-01-17 23:58:31 +00009250#ifdef CONFIG_SAE
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00009251
9252enum sae_pwe wpas_get_ssid_sae_pwe(struct wpa_supplicant *wpa_s,
9253 struct wpa_ssid *ssid)
9254{
9255 if (!ssid || ssid->sae_pwe == DEFAULT_SAE_PWE)
9256 return wpa_s->conf->sae_pwe;
9257 return ssid->sae_pwe;
9258}
9259
9260
Sunil Ravi77d572f2023-01-17 23:58:31 +00009261bool wpas_is_sae_avoided(struct wpa_supplicant *wpa_s,
9262 struct wpa_ssid *ssid,
9263 const struct wpa_ie_data *ie)
9264{
9265 return wpa_s->conf->sae_check_mfp &&
9266 (!(ie->capabilities &
9267 (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) ||
9268 wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION);
9269}
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00009270
Sunil Ravi77d572f2023-01-17 23:58:31 +00009271#endif /* CONFIG_SAE */
9272
9273
Hai Shalomc1a21442022-02-04 13:43:00 -08009274int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
9275{
9276 if (wpa_s->current_ssid == NULL ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009277 wpa_s->wpa_state < WPA_4WAY_HANDSHAKE)
Hai Shalomc1a21442022-02-04 13:43:00 -08009278 return 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009279 if (wpa_s->valid_links) {
9280 if (!ether_addr_equal(addr, wpa_s->ap_mld_addr) &&
9281 !wpas_ap_link_address(wpa_s, addr))
9282 return 0;
9283 } else {
9284 if (!ether_addr_equal(addr, wpa_s->bssid))
9285 return 0;
9286 }
Hai Shalomc1a21442022-02-04 13:43:00 -08009287 return wpa_sm_pmf_enabled(wpa_s->wpa);
9288}
9289
9290
Dmitry Shmidt687922c2012-03-26 14:02:32 -07009291int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009292{
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07009293 if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009294 return 1;
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07009295 if (wpa_s->global->conc_pref == WPA_CONC_PREF_STA)
Dmitry Shmidt687922c2012-03-26 14:02:32 -07009296 return 0;
Dmitry Shmidt687922c2012-03-26 14:02:32 -07009297 return -1;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009298}
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009299
9300
Sunil Ravi77d572f2023-01-17 23:58:31 +00009301void wpas_auth_failed(struct wpa_supplicant *wpa_s, const char *reason,
9302 const u8 *bssid)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009303{
9304 struct wpa_ssid *ssid = wpa_s->current_ssid;
9305 int dur;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009306 struct os_reltime now;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009307
9308 if (ssid == NULL) {
9309 wpa_printf(MSG_DEBUG, "Authentication failure but no known "
9310 "SSID block");
9311 return;
9312 }
9313
9314 if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
9315 return;
9316
9317 ssid->auth_failures++;
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -07009318
9319#ifdef CONFIG_P2P
9320 if (ssid->p2p_group &&
9321 (wpa_s->p2p_in_provisioning || wpa_s->show_group_started)) {
9322 /*
9323 * Skip the wait time since there is a short timeout on the
9324 * connection to a P2P group.
9325 */
9326 return;
9327 }
9328#endif /* CONFIG_P2P */
9329
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009330 if (ssid->auth_failures > 50)
9331 dur = 300;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009332 else if (ssid->auth_failures > 10)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08009333 dur = 120;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009334 else if (ssid->auth_failures > 5)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08009335 dur = 90;
9336 else if (ssid->auth_failures > 3)
9337 dur = 60;
9338 else if (ssid->auth_failures > 2)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009339 dur = 30;
9340 else if (ssid->auth_failures > 1)
9341 dur = 20;
9342 else
9343 dur = 10;
9344
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08009345 if (ssid->auth_failures > 1 &&
9346 wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt))
9347 dur += os_random() % (ssid->auth_failures * 10);
9348
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009349 os_get_reltime(&now);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009350 if (now.sec + dur <= ssid->disabled_until.sec)
9351 return;
9352
9353 ssid->disabled_until.sec = now.sec + dur;
9354
9355 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07009356 "id=%d ssid=\"%s\" auth_failures=%u duration=%d reason=%s",
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009357 ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07009358 ssid->auth_failures, dur, reason);
Gabriel Biren3a2ec2c2022-03-07 17:59:41 +00009359
9360 char *format_str = "id=%d ssid=\"%s\" auth_failures=%u duration=%d reason=%s";
9361 int msg_len = snprintf(NULL, 0, format_str,
9362 ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
9363 ssid->auth_failures, dur, reason) + 1;
9364 char *msg = os_malloc(msg_len);
Narasimha Rao PVSc28a5132022-12-02 18:36:38 +05309365 if (!msg)
9366 return;
Gabriel Biren3a2ec2c2022-03-07 17:59:41 +00009367 snprintf(msg, msg_len, format_str,
9368 ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
9369 ssid->auth_failures, dur, reason);
9370 wpas_notify_ssid_temp_disabled(wpa_s, msg);
9371 os_free(msg);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009372
9373 if (bssid)
9374 os_memcpy(ssid->disabled_due_to, bssid, ETH_ALEN);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009375}
9376
9377
9378void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
9379 struct wpa_ssid *ssid, int clear_failures)
9380{
9381 if (ssid == NULL)
9382 return;
9383
9384 if (ssid->disabled_until.sec) {
9385 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED
9386 "id=%d ssid=\"%s\"",
9387 ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
9388 }
9389 ssid->disabled_until.sec = 0;
9390 ssid->disabled_until.usec = 0;
Sunil Ravi77d572f2023-01-17 23:58:31 +00009391 if (clear_failures) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009392 ssid->auth_failures = 0;
Sunil Ravi77d572f2023-01-17 23:58:31 +00009393 } else if (!is_zero_ether_addr(ssid->disabled_due_to)) {
9394 wpa_printf(MSG_DEBUG, "Mark BSSID " MACSTR
9395 " ignored to allow a lower priority BSS, if any, to be tried next",
9396 MAC2STR(ssid->disabled_due_to));
9397 wpa_bssid_ignore_add(wpa_s, ssid->disabled_due_to);
9398 os_memset(ssid->disabled_due_to, 0, ETH_ALEN);
9399 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009400}
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009401
9402
9403int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid)
9404{
9405 size_t i;
9406
9407 if (wpa_s->disallow_aps_bssid == NULL)
9408 return 0;
9409
9410 for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009411 if (ether_addr_equal(wpa_s->disallow_aps_bssid + i * ETH_ALEN,
9412 bssid))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009413 return 1;
9414 }
9415
9416 return 0;
9417}
9418
9419
9420int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
9421 size_t ssid_len)
9422{
9423 size_t i;
9424
9425 if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL)
9426 return 0;
9427
9428 for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) {
9429 struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i];
9430 if (ssid_len == s->ssid_len &&
9431 os_memcmp(ssid, s->ssid, ssid_len) == 0)
9432 return 1;
9433 }
9434
9435 return 0;
9436}
9437
9438
9439/**
9440 * wpas_request_connection - Request a new connection
9441 * @wpa_s: Pointer to the network interface
9442 *
9443 * This function is used to request a new connection to be found. It will mark
9444 * the interface to allow reassociation and request a new scan to find a
9445 * suitable network to connect to.
9446 */
9447void wpas_request_connection(struct wpa_supplicant *wpa_s)
9448{
9449 wpa_s->normal_scans = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009450 wpa_s->scan_req = NORMAL_SCAN_REQ;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009451 wpa_supplicant_reinit_autoscan(wpa_s);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009452 wpa_s->disconnected = 0;
9453 wpa_s->reassociate = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009454 wpa_s->last_owe_group = 0;
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08009455
9456 if (wpa_supplicant_fast_associate(wpa_s) != 1)
9457 wpa_supplicant_req_scan(wpa_s, 0, 0);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08009458 else
9459 wpa_s->reattach = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009460}
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009461
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009462
Roshan Pius02242d72016-08-09 15:31:48 -07009463/**
9464 * wpas_request_disconnection - Request disconnection
9465 * @wpa_s: Pointer to the network interface
9466 *
9467 * This function is used to request disconnection from the currently connected
9468 * network. This will stop any ongoing scans and initiate deauthentication.
9469 */
9470void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
9471{
9472#ifdef CONFIG_SME
9473 wpa_s->sme.prev_bssid_set = 0;
9474#endif /* CONFIG_SME */
9475 wpa_s->reassociate = 0;
9476 wpa_s->disconnected = 1;
9477 wpa_supplicant_cancel_sched_scan(wpa_s);
9478 wpa_supplicant_cancel_scan(wpa_s);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00009479 wpas_abort_ongoing_scan(wpa_s);
Roshan Pius02242d72016-08-09 15:31:48 -07009480 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
9481 eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
Hai Shalom021b0b52019-04-10 11:17:58 -07009482 radio_remove_works(wpa_s, "connect", 0);
9483 radio_remove_works(wpa_s, "sme-connect", 0);
Hai Shalomc1a21442022-02-04 13:43:00 -08009484 wpa_s->roam_in_progress = false;
9485#ifdef CONFIG_WNM
9486 wpa_s->bss_trans_mgmt_in_progress = false;
9487#endif /* CONFIG_WNM */
Roshan Pius02242d72016-08-09 15:31:48 -07009488}
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009489
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07009490
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009491void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
9492 struct wpa_used_freq_data *freqs_data,
9493 unsigned int len)
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08009494{
9495 unsigned int i;
9496
9497 wpa_dbg(wpa_s, MSG_DEBUG, "Shared frequencies (len=%u): %s",
9498 len, title);
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009499 for (i = 0; i < len; i++) {
9500 struct wpa_used_freq_data *cur = &freqs_data[i];
9501 wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d, flags=0x%X",
9502 i, cur->freq, cur->flags);
9503 }
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08009504}
9505
9506
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009507/*
9508 * Find the operating frequencies of any of the virtual interfaces that
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009509 * are using the same radio as the current interface, and in addition, get
9510 * information about the interface types that are using the frequency.
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009511 */
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009512int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
9513 struct wpa_used_freq_data *freqs_data,
Sunil Ravi77d572f2023-01-17 23:58:31 +00009514 unsigned int len, bool exclude_current)
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009515{
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009516 struct wpa_supplicant *ifs;
9517 u8 bssid[ETH_ALEN];
9518 int freq;
9519 unsigned int idx = 0, i;
9520
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08009521 wpa_dbg(wpa_s, MSG_DEBUG,
9522 "Determining shared radio frequencies (max len %u)", len);
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009523 os_memset(freqs_data, 0, sizeof(struct wpa_used_freq_data) * len);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009524
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08009525 dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
9526 radio_list) {
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009527 if (idx == len)
9528 break;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009529
Sunil Ravi77d572f2023-01-17 23:58:31 +00009530 if (exclude_current && ifs == wpa_s)
9531 continue;
9532
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009533 if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
9534 continue;
9535
9536 if (ifs->current_ssid->mode == WPAS_MODE_AP ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009537 ifs->current_ssid->mode == WPAS_MODE_P2P_GO ||
9538 ifs->current_ssid->mode == WPAS_MODE_MESH)
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009539 freq = ifs->current_ssid->frequency;
9540 else if (wpa_drv_get_bssid(ifs, bssid) == 0)
9541 freq = ifs->assoc_freq;
9542 else
9543 continue;
9544
9545 /* Hold only distinct freqs */
9546 for (i = 0; i < idx; i++)
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009547 if (freqs_data[i].freq == freq)
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009548 break;
9549
9550 if (i == idx)
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009551 freqs_data[idx++].freq = freq;
9552
9553 if (ifs->current_ssid->mode == WPAS_MODE_INFRA) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009554 freqs_data[i].flags |= ifs->current_ssid->p2p_group ?
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009555 WPA_FREQ_USED_BY_P2P_CLIENT :
9556 WPA_FREQ_USED_BY_INFRA_STATION;
9557 }
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009558 }
Dmitry Shmidtb96dad42013-11-05 10:07:29 -08009559
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009560 dump_freq_data(wpa_s, "completed iteration", freqs_data, idx);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009561 return idx;
9562}
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009563
9564
9565/*
9566 * Find the operating frequencies of any of the virtual interfaces that
9567 * are using the same radio as the current interface.
9568 */
9569int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
Sunil Ravi77d572f2023-01-17 23:58:31 +00009570 int *freq_array, unsigned int len,
9571 bool exclude_current)
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009572{
9573 struct wpa_used_freq_data *freqs_data;
9574 int num, i;
9575
9576 os_memset(freq_array, 0, sizeof(int) * len);
9577
9578 freqs_data = os_calloc(len, sizeof(struct wpa_used_freq_data));
9579 if (!freqs_data)
9580 return -1;
9581
Sunil Ravi77d572f2023-01-17 23:58:31 +00009582 num = get_shared_radio_freqs_data(wpa_s, freqs_data, len,
9583 exclude_current);
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009584 for (i = 0; i < num; i++)
9585 freq_array[i] = freqs_data[i].freq;
9586
9587 os_free(freqs_data);
9588
9589 return num;
9590}
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009591
9592
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009593struct wpa_supplicant *
9594wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
9595{
9596 switch (frame) {
9597#ifdef CONFIG_P2P
9598 case VENDOR_ELEM_PROBE_REQ_P2P:
9599 case VENDOR_ELEM_PROBE_RESP_P2P:
9600 case VENDOR_ELEM_PROBE_RESP_P2P_GO:
9601 case VENDOR_ELEM_BEACON_P2P_GO:
9602 case VENDOR_ELEM_P2P_PD_REQ:
9603 case VENDOR_ELEM_P2P_PD_RESP:
9604 case VENDOR_ELEM_P2P_GO_NEG_REQ:
9605 case VENDOR_ELEM_P2P_GO_NEG_RESP:
9606 case VENDOR_ELEM_P2P_GO_NEG_CONF:
9607 case VENDOR_ELEM_P2P_INV_REQ:
9608 case VENDOR_ELEM_P2P_INV_RESP:
9609 case VENDOR_ELEM_P2P_ASSOC_REQ:
9610 case VENDOR_ELEM_P2P_ASSOC_RESP:
Dmitry Shmidt9c175262016-03-03 10:20:07 -08009611 return wpa_s->p2pdev;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009612#endif /* CONFIG_P2P */
9613 default:
9614 return wpa_s;
9615 }
9616}
9617
9618
9619void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s)
9620{
9621 unsigned int i;
9622 char buf[30];
9623
9624 wpa_printf(MSG_DEBUG, "Update vendor elements");
9625
9626 for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
9627 if (wpa_s->vendor_elem[i]) {
9628 int res;
9629
9630 res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
9631 if (!os_snprintf_error(sizeof(buf), res)) {
9632 wpa_hexdump_buf(MSG_DEBUG, buf,
9633 wpa_s->vendor_elem[i]);
9634 }
9635 }
9636 }
9637
9638#ifdef CONFIG_P2P
Jimmy Chen48b484b2022-01-25 00:17:50 +08009639 if ((wpa_s->parent == wpa_s || (wpa_s == wpa_s->p2pdev && wpa_s->p2p_mgmt)) &&
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009640 wpa_s->global->p2p &&
9641 !wpa_s->global->p2p_disabled)
9642 p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
9643#endif /* CONFIG_P2P */
9644}
9645
9646
9647int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
9648 const u8 *elem, size_t len)
9649{
9650 u8 *ie, *end;
9651
9652 ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
9653 end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
9654
9655 for (; ie + 1 < end; ie += 2 + ie[1]) {
9656 if (ie + len > end)
9657 break;
9658 if (os_memcmp(ie, elem, len) != 0)
9659 continue;
9660
9661 if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
9662 wpabuf_free(wpa_s->vendor_elem[frame]);
9663 wpa_s->vendor_elem[frame] = NULL;
9664 } else {
9665 os_memmove(ie, ie + len, end - (ie + len));
9666 wpa_s->vendor_elem[frame]->used -= len;
9667 }
9668 wpas_vendor_elem_update(wpa_s);
9669 return 0;
9670 }
9671
9672 return -1;
9673}
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009674
9675
9676struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
Hai Shalomfdcde762020-04-02 11:19:20 -07009677 u16 num_modes, enum hostapd_hw_mode mode,
Hai Shalom60840252021-02-19 19:02:11 -08009678 bool is_6ghz)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009679{
9680 u16 i;
9681
Hai Shalomc1a21442022-02-04 13:43:00 -08009682 if (!modes)
9683 return NULL;
9684
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009685 for (i = 0; i < num_modes; i++) {
Hai Shalomfdcde762020-04-02 11:19:20 -07009686 if (modes[i].mode != mode ||
9687 !modes[i].num_channels || !modes[i].channels)
9688 continue;
Sunil Ravi99c035e2024-07-12 01:42:03 +00009689 if (is_6ghz == modes[i].is_6ghz)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009690 return &modes[i];
9691 }
9692
9693 return NULL;
9694}
9695
9696
Hai Shalomc1a21442022-02-04 13:43:00 -08009697struct hostapd_hw_modes * get_mode_with_freq(struct hostapd_hw_modes *modes,
9698 u16 num_modes, int freq)
9699{
9700 int i, j;
9701
9702 for (i = 0; i < num_modes; i++) {
9703 for (j = 0; j < modes[i].num_channels; j++) {
9704 if (freq == modes[i].channels[j].freq)
9705 return &modes[i];
9706 }
9707 }
9708
9709 return NULL;
9710}
9711
9712
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009713static struct
9714wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
9715 const u8 *bssid)
9716{
9717 struct wpa_bss_tmp_disallowed *bss;
9718
9719 dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed,
9720 struct wpa_bss_tmp_disallowed, list) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009721 if (ether_addr_equal(bssid, bss->bssid))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009722 return bss;
9723 }
9724
9725 return NULL;
9726}
9727
9728
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009729static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s)
9730{
9731 struct wpa_bss_tmp_disallowed *tmp;
9732 unsigned int num_bssid = 0;
9733 u8 *bssids;
9734 int ret;
9735
9736 bssids = os_malloc(dl_list_len(&wpa_s->bss_tmp_disallowed) * ETH_ALEN);
9737 if (!bssids)
9738 return -1;
9739 dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
9740 struct wpa_bss_tmp_disallowed, list) {
9741 os_memcpy(&bssids[num_bssid * ETH_ALEN], tmp->bssid,
9742 ETH_ALEN);
9743 num_bssid++;
9744 }
Hai Shalom899fcc72020-10-19 14:38:18 -07009745 ret = wpa_drv_set_bssid_tmp_disallow(wpa_s, num_bssid, bssids);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009746 os_free(bssids);
9747 return ret;
9748}
9749
9750
9751static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx)
9752{
9753 struct wpa_supplicant *wpa_s = eloop_ctx;
9754 struct wpa_bss_tmp_disallowed *tmp, *bss = timeout_ctx;
9755
9756 /* Make sure the bss is not already freed */
9757 dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
9758 struct wpa_bss_tmp_disallowed, list) {
9759 if (bss == tmp) {
Hai Shalomc1a21442022-02-04 13:43:00 -08009760 remove_bss_tmp_disallowed_entry(wpa_s, tmp);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009761 wpa_set_driver_tmp_disallow_list(wpa_s);
9762 break;
9763 }
9764 }
9765}
9766
9767
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009768void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
Hai Shalom74f70d42019-02-11 14:42:39 -08009769 unsigned int sec, int rssi_threshold)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009770{
9771 struct wpa_bss_tmp_disallowed *bss;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009772
9773 bss = wpas_get_disallowed_bss(wpa_s, bssid);
9774 if (bss) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009775 eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
Hai Shalom74f70d42019-02-11 14:42:39 -08009776 goto finish;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009777 }
9778
9779 bss = os_malloc(sizeof(*bss));
9780 if (!bss) {
9781 wpa_printf(MSG_DEBUG,
9782 "Failed to allocate memory for temp disallow BSS");
9783 return;
9784 }
9785
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009786 os_memcpy(bss->bssid, bssid, ETH_ALEN);
9787 dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009788 wpa_set_driver_tmp_disallow_list(wpa_s);
Hai Shalom74f70d42019-02-11 14:42:39 -08009789
9790finish:
9791 bss->rssi_threshold = rssi_threshold;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009792 eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
9793 wpa_s, bss);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009794}
9795
9796
Hai Shalom74f70d42019-02-11 14:42:39 -08009797int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
9798 struct wpa_bss *bss)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009799{
Hai Shalom74f70d42019-02-11 14:42:39 -08009800 struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009801
9802 dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
9803 struct wpa_bss_tmp_disallowed, list) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009804 if (ether_addr_equal(bss->bssid, tmp->bssid)) {
Hai Shalom74f70d42019-02-11 14:42:39 -08009805 disallowed = tmp;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009806 break;
9807 }
9808 }
Hai Shalom74f70d42019-02-11 14:42:39 -08009809 if (!disallowed)
9810 return 0;
9811
9812 if (disallowed->rssi_threshold != 0 &&
Hai Shalomc1a21442022-02-04 13:43:00 -08009813 bss->level > disallowed->rssi_threshold) {
9814 remove_bss_tmp_disallowed_entry(wpa_s, disallowed);
9815 wpa_set_driver_tmp_disallow_list(wpa_s);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009816 return 0;
Hai Shalomc1a21442022-02-04 13:43:00 -08009817 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009818
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009819 return 1;
9820}
Hai Shalom81f62d82019-07-22 12:10:00 -07009821
9822
9823int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
9824 unsigned int type, const u8 *addr,
9825 const u8 *mask)
9826{
9827 if ((addr && !mask) || (!addr && mask)) {
9828 wpa_printf(MSG_INFO,
9829 "MAC_ADDR_RAND_SCAN invalid addr/mask combination");
9830 return -1;
9831 }
9832
9833 if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
9834 wpa_printf(MSG_INFO,
9835 "MAC_ADDR_RAND_SCAN cannot allow multicast address");
9836 return -1;
9837 }
9838
9839 if (type & MAC_ADDR_RAND_SCAN) {
9840 if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
9841 addr, mask))
9842 return -1;
9843 }
9844
9845 if (type & MAC_ADDR_RAND_SCHED_SCAN) {
9846 if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
9847 addr, mask))
9848 return -1;
9849
9850 if (wpa_s->sched_scanning && !wpa_s->pno)
9851 wpas_scan_restart_sched_scan(wpa_s);
9852 }
9853
9854 if (type & MAC_ADDR_RAND_PNO) {
9855 if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
9856 addr, mask))
9857 return -1;
9858
9859 if (wpa_s->pno) {
9860 wpas_stop_pno(wpa_s);
9861 wpas_start_pno(wpa_s);
9862 }
9863 }
9864
9865 return 0;
9866}
9867
9868
9869int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
9870 unsigned int type)
9871{
9872 wpas_mac_addr_rand_scan_clear(wpa_s, type);
9873 if (wpa_s->pno) {
9874 if (type & MAC_ADDR_RAND_PNO) {
9875 wpas_stop_pno(wpa_s);
9876 wpas_start_pno(wpa_s);
9877 }
9878 } else if (wpa_s->sched_scanning && (type & MAC_ADDR_RAND_SCHED_SCAN)) {
9879 wpas_scan_restart_sched_scan(wpa_s);
9880 }
9881
9882 return 0;
9883}
Hai Shalomfdcde762020-04-02 11:19:20 -07009884
9885
9886int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
9887 struct wpa_signal_info *si)
9888{
9889 int res;
9890
9891 if (!wpa_s->driver->signal_poll)
9892 return -1;
9893
9894 res = wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
9895
9896#ifdef CONFIG_TESTING_OPTIONS
9897 if (res == 0) {
9898 struct driver_signal_override *dso;
9899
9900 dl_list_for_each(dso, &wpa_s->drv_signal_override,
9901 struct driver_signal_override, list) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009902 if (!ether_addr_equal(wpa_s->bssid, dso->bssid))
Hai Shalomfdcde762020-04-02 11:19:20 -07009903 continue;
9904 wpa_printf(MSG_DEBUG,
9905 "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 +00009906 si->data.signal,
Hai Shalomfdcde762020-04-02 11:19:20 -07009907 dso->si_current_signal,
Sunil Ravi77d572f2023-01-17 23:58:31 +00009908 si->data.avg_signal,
Hai Shalomfdcde762020-04-02 11:19:20 -07009909 dso->si_avg_signal,
Sunil Ravi77d572f2023-01-17 23:58:31 +00009910 si->data.avg_beacon_signal,
Hai Shalomfdcde762020-04-02 11:19:20 -07009911 dso->si_avg_beacon_signal,
9912 si->current_noise,
9913 dso->si_current_noise);
Sunil Ravi77d572f2023-01-17 23:58:31 +00009914 si->data.signal = dso->si_current_signal;
9915 si->data.avg_signal = dso->si_avg_signal;
9916 si->data.avg_beacon_signal = dso->si_avg_beacon_signal;
Hai Shalomfdcde762020-04-02 11:19:20 -07009917 si->current_noise = dso->si_current_noise;
9918 break;
9919 }
9920 }
9921#endif /* CONFIG_TESTING_OPTIONS */
9922
9923 return res;
9924}
9925
9926
9927struct wpa_scan_results *
Sunil Ravi99c035e2024-07-12 01:42:03 +00009928wpa_drv_get_scan_results(struct wpa_supplicant *wpa_s, const u8 *bssid)
Hai Shalomfdcde762020-04-02 11:19:20 -07009929{
9930 struct wpa_scan_results *scan_res;
9931#ifdef CONFIG_TESTING_OPTIONS
9932 size_t idx;
9933#endif /* CONFIG_TESTING_OPTIONS */
9934
Sunil Ravi99c035e2024-07-12 01:42:03 +00009935 if (wpa_s->driver->get_scan_results)
9936 scan_res = wpa_s->driver->get_scan_results(wpa_s->drv_priv,
9937 bssid);
9938 else if (wpa_s->driver->get_scan_results2)
9939 scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
9940 else
Hai Shalomfdcde762020-04-02 11:19:20 -07009941 return NULL;
9942
Hai Shalomfdcde762020-04-02 11:19:20 -07009943
9944#ifdef CONFIG_TESTING_OPTIONS
9945 for (idx = 0; scan_res && idx < scan_res->num; idx++) {
9946 struct driver_signal_override *dso;
9947 struct wpa_scan_res *res = scan_res->res[idx];
9948
9949 dl_list_for_each(dso, &wpa_s->drv_signal_override,
9950 struct driver_signal_override, list) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009951 if (!ether_addr_equal(res->bssid, dso->bssid))
Hai Shalomfdcde762020-04-02 11:19:20 -07009952 continue;
9953 wpa_printf(MSG_DEBUG,
9954 "Override driver scan signal level %d->%d for "
9955 MACSTR,
9956 res->level, dso->scan_level,
9957 MAC2STR(res->bssid));
9958 res->flags |= WPA_SCAN_QUAL_INVALID;
9959 if (dso->scan_level < 0)
9960 res->flags |= WPA_SCAN_LEVEL_DBM;
9961 else
9962 res->flags &= ~WPA_SCAN_LEVEL_DBM;
9963 res->level = dso->scan_level;
9964 break;
9965 }
9966 }
9967#endif /* CONFIG_TESTING_OPTIONS */
9968
9969 return scan_res;
9970}
Sunil Ravi77d572f2023-01-17 23:58:31 +00009971
9972
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009973bool wpas_ap_link_address(struct wpa_supplicant *wpa_s, const u8 *addr)
Sunil Ravi77d572f2023-01-17 23:58:31 +00009974{
9975 int i;
9976
9977 if (!wpa_s->valid_links)
9978 return false;
9979
Sunil Ravi99c035e2024-07-12 01:42:03 +00009980 for_each_link(wpa_s->valid_links, i) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009981 if (ether_addr_equal(wpa_s->links[i].bssid, addr))
Sunil Ravi77d572f2023-01-17 23:58:31 +00009982 return true;
9983 }
9984
9985 return false;
9986}
9987
9988
9989int wpa_drv_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
9990 unsigned int wait, const u8 *dst, const u8 *src,
9991 const u8 *bssid, const u8 *data, size_t data_len,
9992 int no_cck)
9993{
9994 if (!wpa_s->driver->send_action)
9995 return -1;
9996
9997 if (data_len > 0 && data[0] != WLAN_ACTION_PUBLIC) {
9998 if (wpas_ap_link_address(wpa_s, dst))
9999 dst = wpa_s->ap_mld_addr;
10000
10001 if (wpas_ap_link_address(wpa_s, bssid))
10002 bssid = wpa_s->ap_mld_addr;
10003 }
10004
10005 return wpa_s->driver->send_action(wpa_s->drv_priv, freq, wait, dst, src,
Sunil Ravi79e6c4f2025-01-04 00:47:06 +000010006 bssid, data, data_len, no_cck, -1);
Sunil Ravi77d572f2023-01-17 23:58:31 +000010007}
Sunil Ravi2a14cf12023-11-21 00:54:38 +000010008
10009
10010bool wpas_is_6ghz_supported(struct wpa_supplicant *wpa_s, bool only_enabled)
10011{
10012 struct hostapd_channel_data *chnl;
10013 int i, j;
10014
10015 for (i = 0; i < wpa_s->hw.num_modes; i++) {
10016 if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211A) {
10017 chnl = wpa_s->hw.modes[i].channels;
10018 for (j = 0; j < wpa_s->hw.modes[i].num_channels; j++) {
10019 if (only_enabled &&
10020 (chnl[j].flag & HOSTAPD_CHAN_DISABLED))
10021 continue;
10022 if (is_6ghz_freq(chnl[j].freq))
10023 return true;
10024 }
10025 }
10026 }
10027
10028 return false;
10029}
Sunil Ravi7f769292024-07-23 22:21:32 +000010030
10031
10032bool wpas_ap_supports_rsn_overriding(struct wpa_supplicant *wpa_s,
10033 struct wpa_bss *bss)
10034{
10035 int i;
10036
10037 if (!bss)
10038 return false;
10039 if (wpa_bss_get_vendor_ie(bss, RSNE_OVERRIDE_IE_VENDOR_TYPE) ||
10040 wpa_bss_get_vendor_ie(bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE))
10041 return true;
10042
10043 if (!wpa_s->valid_links)
10044 return false;
10045
10046 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
10047 if (!(wpa_s->valid_links & BIT(i)))
10048 continue;
10049 if (wpa_s->links[i].bss &&
10050 (wpa_bss_get_vendor_ie(wpa_s->links[i].bss,
10051 RSNE_OVERRIDE_IE_VENDOR_TYPE) ||
10052 wpa_bss_get_vendor_ie(wpa_s->links[i].bss,
10053 RSNE_OVERRIDE_2_IE_VENDOR_TYPE)))
10054 return true;
10055 }
10056
10057 return false;
10058}
10059
10060
10061bool wpas_ap_supports_rsn_overriding_2(struct wpa_supplicant *wpa_s,
10062 struct wpa_bss *bss)
10063{
10064 int i;
10065
10066 if (!bss)
10067 return false;
10068 if (wpa_bss_get_vendor_ie(bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE))
10069 return true;
10070
10071 if (!wpa_s->valid_links)
10072 return false;
10073
10074 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
10075 if (!(wpa_s->valid_links & BIT(i)))
10076 continue;
10077 if (wpa_s->links[i].bss &&
10078 wpa_bss_get_vendor_ie(wpa_s->links[i].bss,
10079 RSNE_OVERRIDE_2_IE_VENDOR_TYPE))
10080 return true;
10081 }
10082
10083 return false;
10084}
Sunil Ravic0f5d412024-09-11 22:12:49 +000010085
10086
10087int wpas_get_owe_trans_network(const u8 *owe_ie, const u8 **bssid,
10088 const u8 **ssid, size_t *ssid_len)
10089{
10090#ifdef CONFIG_OWE
10091 const u8 *pos, *end;
10092 u8 ssid_len_tmp;
10093
10094 if (!owe_ie)
10095 return -1;
10096
10097 pos = owe_ie + 6;
10098 end = owe_ie + 2 + owe_ie[1];
10099
10100 if (end - pos < ETH_ALEN + 1)
10101 return -1;
10102 *bssid = pos;
10103 pos += ETH_ALEN;
10104 ssid_len_tmp = *pos++;
10105 if (end - pos < ssid_len_tmp || ssid_len_tmp > SSID_MAX_LEN)
10106 return -1;
10107
10108 *ssid = pos;
10109 *ssid_len = ssid_len_tmp;
10110
10111 return 0;
10112#else /* CONFIG_OWE */
10113 return -1;
10114#endif /* CONFIG_OWE */
10115}