blob: 0a0a50f3a63d8a5647ad80a406425a59cdb77ee3 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * wpa_supplicant - SME
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003 * Copyright (c) 2009-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
9#include "includes.h"
10
11#include "common.h"
12#include "utils/eloop.h"
Sunil Ravi77d572f2023-01-17 23:58:31 +000013#include "utils/ext_password.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014#include "common/ieee802_11_defs.h"
15#include "common/ieee802_11_common.h"
Hai Shalom74f70d42019-02-11 14:42:39 -080016#include "common/ocv.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070017#include "eapol_supp/eapol_supp_sm.h"
18#include "common/wpa_common.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080019#include "common/sae.h"
Hai Shalom021b0b52019-04-10 11:17:58 -070020#include "common/dpp.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021#include "rsn_supp/wpa.h"
22#include "rsn_supp/pmksa_cache.h"
23#include "config.h"
24#include "wpa_supplicant_i.h"
25#include "driver_i.h"
26#include "wpas_glue.h"
27#include "wps_supplicant.h"
28#include "p2p_supplicant.h"
29#include "notify.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070030#include "bss.h"
Sunil Ravib0ac25f2024-07-12 01:42:03 +000031#include "bssid_ignore.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070032#include "scan.h"
33#include "sme.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070034#include "hs20_supplicant.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070035
36#define SME_AUTH_TIMEOUT 5
37#define SME_ASSOC_TIMEOUT 5
38
39static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx);
40static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx);
Dmitry Shmidt04949592012-07-19 12:16:46 -070041static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070042static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070043
44
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080045#ifdef CONFIG_SAE
46
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080047static int index_within_array(const int *array, int idx)
48{
49 int i;
50 for (i = 0; i < idx; i++) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -080051 if (array[i] <= 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080052 return 0;
53 }
54 return 1;
55}
56
57
Sunil Ravi77d572f2023-01-17 23:58:31 +000058static int sme_set_sae_group(struct wpa_supplicant *wpa_s, bool external)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080059{
60 int *groups = wpa_s->conf->sae_groups;
Hai Shalom021b0b52019-04-10 11:17:58 -070061 int default_groups[] = { 19, 20, 21, 0 };
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080062
Dmitry Shmidtcce06662013-11-04 18:44:24 -080063 if (!groups || groups[0] <= 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080064 groups = default_groups;
65
66 /* Configuration may have changed, so validate current index */
67 if (!index_within_array(groups, wpa_s->sme.sae_group_index))
68 return -1;
69
70 for (;;) {
71 int group = groups[wpa_s->sme.sae_group_index];
Dmitry Shmidt41712582015-06-29 11:02:15 -070072 if (group <= 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080073 break;
Sunil Ravi7f769292024-07-23 22:21:32 +000074 if (!int_array_includes(wpa_s->sme.sae_rejected_groups,
75 group) &&
76 sae_set_group(&wpa_s->sme.sae, group) == 0) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080077 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
78 wpa_s->sme.sae.group);
Sunil Ravi77d572f2023-01-17 23:58:31 +000079 wpa_s->sme.sae.akmp = external ?
80 wpa_s->sme.ext_auth_key_mgmt : wpa_s->key_mgmt;
Hai Shalom74f70d42019-02-11 14:42:39 -080081 return 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080082 }
83 wpa_s->sme.sae_group_index++;
84 }
85
86 return -1;
87}
88
89
90static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
91 struct wpa_ssid *ssid,
Sunil Ravi77d572f2023-01-17 23:58:31 +000092 const u8 *bssid,
93 const u8 *mld_addr,
94 int external,
Hai Shalom899fcc72020-10-19 14:38:18 -070095 int reuse, int *ret_use_pt,
96 bool *ret_use_pk)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080097{
98 struct wpabuf *buf;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080099 size_t len;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000100 char *password = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700101 struct wpa_bss *bss;
102 int use_pt = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700103 bool use_pk = false;
104 u8 rsnxe_capa = 0;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000105 int key_mgmt = external ? wpa_s->sme.ext_auth_key_mgmt :
106 wpa_s->key_mgmt;
107 const u8 *addr = mld_addr ? mld_addr : bssid;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000108 enum sae_pwe sae_pwe;
Hai Shalomc3565922019-10-28 11:58:20 -0700109
110 if (ret_use_pt)
111 *ret_use_pt = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700112 if (ret_use_pk)
113 *ret_use_pk = false;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800114
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700115#ifdef CONFIG_TESTING_OPTIONS
116 if (wpa_s->sae_commit_override) {
117 wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
118 buf = wpabuf_alloc(4 + wpabuf_len(wpa_s->sae_commit_override));
119 if (!buf)
Sunil Ravi77d572f2023-01-17 23:58:31 +0000120 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -0700121 if (!external) {
122 wpabuf_put_le16(buf, 1); /* Transaction seq# */
123 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
124 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700125 wpabuf_put_buf(buf, wpa_s->sae_commit_override);
126 return buf;
127 }
128#endif /* CONFIG_TESTING_OPTIONS */
129
Sunil Ravi77d572f2023-01-17 23:58:31 +0000130 if (ssid->sae_password) {
131 password = os_strdup(ssid->sae_password);
132 if (!password) {
133 wpa_dbg(wpa_s, MSG_INFO,
134 "SAE: Failed to allocate password");
135 goto fail;
136 }
137 }
138 if (!password && ssid->passphrase) {
139 password = os_strdup(ssid->passphrase);
140 if (!password) {
141 wpa_dbg(wpa_s, MSG_INFO,
142 "SAE: Failed to allocate password");
143 goto fail;
144 }
145 }
146 if (!password && ssid->ext_psk) {
147 struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
148 ssid->ext_psk);
149
150 if (!pw) {
151 wpa_msg(wpa_s, MSG_INFO,
152 "SAE: No password found from external storage");
153 goto fail;
154 }
155
156 password = os_malloc(wpabuf_len(pw) + 1);
157 if (!password) {
158 wpa_dbg(wpa_s, MSG_INFO,
159 "SAE: Failed to allocate password");
160 goto fail;
161 }
162 os_memcpy(password, wpabuf_head(pw), wpabuf_len(pw));
163 password[wpabuf_len(pw)] = '\0';
164 ext_password_free(pw);
165 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700166 if (!password) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800167 wpa_printf(MSG_DEBUG, "SAE: No password available");
Sunil Ravi77d572f2023-01-17 23:58:31 +0000168 goto fail;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800169 }
170
Hai Shalom021b0b52019-04-10 11:17:58 -0700171 if (reuse && wpa_s->sme.sae.tmp &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000172 ether_addr_equal(addr, wpa_s->sme.sae.tmp->bssid)) {
Hai Shalom021b0b52019-04-10 11:17:58 -0700173 wpa_printf(MSG_DEBUG,
174 "SAE: Reuse previously generated PWE on a retry with the same AP");
Hai Shalom899fcc72020-10-19 14:38:18 -0700175 use_pt = wpa_s->sme.sae.h2e;
176 use_pk = wpa_s->sme.sae.pk;
Hai Shalom021b0b52019-04-10 11:17:58 -0700177 goto reuse_data;
178 }
Sunil Ravi77d572f2023-01-17 23:58:31 +0000179 if (sme_set_sae_group(wpa_s, external) < 0) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800180 wpa_printf(MSG_DEBUG, "SAE: Failed to select group");
Sunil Ravi77d572f2023-01-17 23:58:31 +0000181 goto fail;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800182 }
183
Hai Shalom899fcc72020-10-19 14:38:18 -0700184 bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800185 if (!bss) {
186 wpa_printf(MSG_DEBUG,
187 "SAE: BSS not available, update scan result to get BSS");
Sunil Ravi99c035e2024-07-12 01:42:03 +0000188 wpa_supplicant_update_scan_results(wpa_s, bssid);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800189 bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
190 }
Hai Shalom899fcc72020-10-19 14:38:18 -0700191 if (bss) {
192 const u8 *rsnxe;
193
Sunil Ravi7f769292024-07-23 22:21:32 +0000194 rsnxe = wpa_bss_get_rsnxe(wpa_s, bss, ssid, false);
195 if (rsnxe && rsnxe[0] == WLAN_EID_VENDOR_SPECIFIC &&
196 rsnxe[1] >= 1 + 4)
197 rsnxe_capa = rsnxe[2 + 4];
198 else if (rsnxe && rsnxe[1] >= 1)
Hai Shalom899fcc72020-10-19 14:38:18 -0700199 rsnxe_capa = rsnxe[2];
200 }
201
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000202 sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
203
Sunil Ravi77d572f2023-01-17 23:58:31 +0000204 if (ssid->sae_password_id &&
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000205 sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
Hai Shalomfdcde762020-04-02 11:19:20 -0700206 use_pt = 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000207 if (wpa_key_mgmt_sae_ext_key(key_mgmt) &&
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000208 sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
Sunil Ravi89eba102022-09-13 21:04:37 -0700209 use_pt = 1;
Sunil Ravi036cec52023-03-29 11:35:17 -0700210 if (bss && is_6ghz_freq(bss->freq) &&
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000211 sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
Sunil Ravi036cec52023-03-29 11:35:17 -0700212 use_pt = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -0700213#ifdef CONFIG_SAE_PK
214 if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
215 ssid->sae_pk != SAE_PK_MODE_DISABLED &&
216 ((ssid->sae_password &&
217 sae_pk_valid_password(ssid->sae_password)) ||
218 (!ssid->sae_password && ssid->passphrase &&
219 sae_pk_valid_password(ssid->passphrase)))) {
220 use_pt = 1;
221 use_pk = true;
222 }
223
224 if (ssid->sae_pk == SAE_PK_MODE_ONLY && !use_pk) {
225 wpa_printf(MSG_DEBUG,
226 "SAE: Cannot use PK with the selected AP");
Sunil Ravi77d572f2023-01-17 23:58:31 +0000227 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -0700228 }
229#endif /* CONFIG_SAE_PK */
Hai Shalomfdcde762020-04-02 11:19:20 -0700230
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000231 if (use_pt || sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
232 sae_pwe == SAE_PWE_BOTH) {
Hai Shalom899fcc72020-10-19 14:38:18 -0700233 use_pt = !!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E));
Hai Shalomc3565922019-10-28 11:58:20 -0700234
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000235 if ((sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
Sunil Ravi77d572f2023-01-17 23:58:31 +0000236 ssid->sae_password_id ||
237 wpa_key_mgmt_sae_ext_key(key_mgmt)) &&
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000238 sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700239 !use_pt) {
Hai Shalomc3565922019-10-28 11:58:20 -0700240 wpa_printf(MSG_DEBUG,
241 "SAE: Cannot use H2E with the selected AP");
Sunil Ravi77d572f2023-01-17 23:58:31 +0000242 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -0700243 }
244 }
245
Sunil Ravi036cec52023-03-29 11:35:17 -0700246 if (use_pt && !ssid->pt)
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000247 wpa_s_setup_sae_pt(wpa_s, ssid, true);
Hai Shalomc3565922019-10-28 11:58:20 -0700248 if (use_pt &&
249 sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
Sunil Ravi77d572f2023-01-17 23:58:31 +0000250 wpa_s->own_addr, addr,
Hai Shalom899fcc72020-10-19 14:38:18 -0700251 wpa_s->sme.sae_rejected_groups, NULL) < 0)
Sunil Ravi77d572f2023-01-17 23:58:31 +0000252 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -0700253 if (!use_pt &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000254 sae_prepare_commit(wpa_s->own_addr, addr,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700255 (u8 *) password, os_strlen(password),
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800256 &wpa_s->sme.sae) < 0) {
257 wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
Sunil Ravi77d572f2023-01-17 23:58:31 +0000258 goto fail;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800259 }
Hai Shalom899fcc72020-10-19 14:38:18 -0700260 if (wpa_s->sme.sae.tmp) {
Sunil Ravi77d572f2023-01-17 23:58:31 +0000261 os_memcpy(wpa_s->sme.sae.tmp->bssid, addr, ETH_ALEN);
Hai Shalom899fcc72020-10-19 14:38:18 -0700262 if (use_pt && use_pk)
263 wpa_s->sme.sae.pk = 1;
264#ifdef CONFIG_SAE_PK
265 os_memcpy(wpa_s->sme.sae.tmp->own_addr, wpa_s->own_addr,
266 ETH_ALEN);
Sunil Ravi77d572f2023-01-17 23:58:31 +0000267 os_memcpy(wpa_s->sme.sae.tmp->peer_addr, addr, ETH_ALEN);
Hai Shalom899fcc72020-10-19 14:38:18 -0700268 sae_pk_set_password(&wpa_s->sme.sae, password);
269#endif /* CONFIG_SAE_PK */
270 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800271
Hai Shalom021b0b52019-04-10 11:17:58 -0700272reuse_data:
Hai Shalomfdcde762020-04-02 11:19:20 -0700273 len = wpa_s->sme.sae_token ? 3 + wpabuf_len(wpa_s->sme.sae_token) : 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700274 if (ssid->sae_password_id)
275 len += 4 + os_strlen(ssid->sae_password_id);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800276 buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800277 if (buf == NULL)
Sunil Ravi77d572f2023-01-17 23:58:31 +0000278 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700279 if (!external) {
280 wpabuf_put_le16(buf, 1); /* Transaction seq# */
Hai Shalom899fcc72020-10-19 14:38:18 -0700281 if (use_pk)
282 wpabuf_put_le16(buf, WLAN_STATUS_SAE_PK);
283 else if (use_pt)
284 wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
285 else
286 wpabuf_put_le16(buf,WLAN_STATUS_SUCCESS);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700287 }
Hai Shalomfdcde762020-04-02 11:19:20 -0700288 if (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
289 ssid->sae_password_id) < 0) {
290 wpabuf_free(buf);
Sunil Ravi77d572f2023-01-17 23:58:31 +0000291 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -0700292 }
Hai Shalomc3565922019-10-28 11:58:20 -0700293 if (ret_use_pt)
294 *ret_use_pt = use_pt;
Hai Shalom899fcc72020-10-19 14:38:18 -0700295 if (ret_use_pk)
296 *ret_use_pk = use_pk;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800297
Sunil Ravi77d572f2023-01-17 23:58:31 +0000298 str_clear_free(password);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800299 return buf;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000300
301fail:
302 str_clear_free(password);
303 return NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800304}
305
306
Roshan Pius3a1667e2018-07-03 15:17:14 -0700307static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s,
308 int external)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800309{
310 struct wpabuf *buf;
311
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800312 buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800313 if (buf == NULL)
314 return NULL;
315
Roshan Pius3a1667e2018-07-03 15:17:14 -0700316 if (!external) {
317 wpabuf_put_le16(buf, 2); /* Transaction seq# */
318 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
319 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800320 sae_write_confirm(&wpa_s->sme.sae, buf);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800321
322 return buf;
323}
324
325#endif /* CONFIG_SAE */
326
327
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800328/**
329 * sme_auth_handle_rrm - Handle RRM aspects of current authentication attempt
330 * @wpa_s: Pointer to wpa_supplicant data
331 * @bss: Pointer to the bss which is the target of authentication attempt
332 */
333static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
334 struct wpa_bss *bss)
335{
336 const u8 rrm_ie_len = 5;
337 u8 *pos;
338 const u8 *rrm_ie;
339
340 wpa_s->rrm.rrm_used = 0;
341
342 wpa_printf(MSG_DEBUG,
343 "RRM: Determining whether RRM can be used - device support: 0x%x",
344 wpa_s->drv_rrm_flags);
345
346 rrm_ie = wpa_bss_get_ie(bss, WLAN_EID_RRM_ENABLED_CAPABILITIES);
347 if (!rrm_ie || !(bss->caps & IEEE80211_CAP_RRM)) {
348 wpa_printf(MSG_DEBUG, "RRM: No RRM in network");
349 return;
350 }
351
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700352 if (!((wpa_s->drv_rrm_flags &
353 WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
354 (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
355 !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800356 wpa_printf(MSG_DEBUG,
357 "RRM: Insufficient RRM support in driver - do not use RRM");
358 return;
359 }
360
361 if (sizeof(wpa_s->sme.assoc_req_ie) <
362 wpa_s->sme.assoc_req_ie_len + rrm_ie_len + 2) {
363 wpa_printf(MSG_INFO,
364 "RRM: Unable to use RRM, no room for RRM IE");
365 return;
366 }
367
368 wpa_printf(MSG_DEBUG, "RRM: Adding RRM IE to Association Request");
369 pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
370 os_memset(pos, 0, 2 + rrm_ie_len);
371 *pos++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
372 *pos++ = rrm_ie_len;
373
Hai Shalom60840252021-02-19 19:02:11 -0800374 /* Set supported capabilities flags */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800375 if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
376 *pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
377
Dmitry Shmidt29333592017-01-09 12:27:11 -0800378 *pos |= WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
379 WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
380 WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
381
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700382 if (wpa_s->lci)
383 pos[1] |= WLAN_RRM_CAPS_LCI_MEASUREMENT;
384
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800385 wpa_s->sme.assoc_req_ie_len += rrm_ie_len + 2;
386 wpa_s->rrm.rrm_used = 1;
387}
388
389
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000390static void wpas_ml_handle_removed_links(struct wpa_supplicant *wpa_s,
391 struct wpa_bss *bss)
392{
393 u16 removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, bss);
394
395 wpa_s->valid_links &= ~removed_links;
396}
397
398
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000399#ifdef CONFIG_TESTING_OPTIONS
400static struct wpa_bss * wpas_ml_connect_pref(struct wpa_supplicant *wpa_s,
Sunil Ravi7f769292024-07-23 22:21:32 +0000401 struct wpa_bss *bss,
402 struct wpa_ssid *ssid)
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000403{
404 unsigned int low, high, i;
405
406 wpa_printf(MSG_DEBUG,
407 "MLD: valid_links=%d, band_pref=%u, bssid_pref=" MACSTR,
408 wpa_s->valid_links,
409 wpa_s->conf->mld_connect_band_pref,
410 MAC2STR(wpa_s->conf->mld_connect_bssid_pref));
411
412 /* Check if there are more than one link */
413 if (!(wpa_s->valid_links & (wpa_s->valid_links - 1)))
414 return bss;
415
416 if (!is_zero_ether_addr(wpa_s->conf->mld_connect_bssid_pref)) {
Sunil Ravi99c035e2024-07-12 01:42:03 +0000417 for_each_link(wpa_s->valid_links, i) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000418 if (wpa_s->mlo_assoc_link_id == i)
419 continue;
420
421 if (ether_addr_equal(
422 wpa_s->links[i].bssid,
423 wpa_s->conf->mld_connect_bssid_pref))
424 goto found;
425 }
426 }
427
428 if (wpa_s->conf->mld_connect_band_pref == MLD_CONNECT_BAND_PREF_AUTO)
429 return bss;
430
431 switch (wpa_s->conf->mld_connect_band_pref) {
432 case MLD_CONNECT_BAND_PREF_2GHZ:
433 low = 2412;
434 high = 2472;
435 break;
436 case MLD_CONNECT_BAND_PREF_5GHZ:
437 low = 5180;
438 high = 5985;
439 break;
440 case MLD_CONNECT_BAND_PREF_6GHZ:
441 low = 5955;
442 high = 7125;
443 break;
444 default:
445 return bss;
446 }
447
Sunil Ravi99c035e2024-07-12 01:42:03 +0000448 for_each_link(wpa_s->valid_links, i) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000449 if (wpa_s->mlo_assoc_link_id == i)
450 continue;
451
452 if (wpa_s->links[i].freq >= low && wpa_s->links[i].freq <= high)
453 goto found;
454 }
455
456found:
457 if (i == MAX_NUM_MLD_LINKS) {
458 wpa_printf(MSG_DEBUG, "MLD: No match for connect/band pref");
459 return bss;
460 }
461
462 wpa_printf(MSG_DEBUG,
463 "MLD: Change BSS for connect: " MACSTR " -> " MACSTR,
464 MAC2STR(wpa_s->links[wpa_s->mlo_assoc_link_id].bssid),
465 MAC2STR(wpa_s->links[i].bssid));
466
467 /* Get the BSS entry and do the switch */
Sunil Ravi7f769292024-07-23 22:21:32 +0000468 if (ssid && ssid->ssid_len)
469 bss = wpa_bss_get(wpa_s, wpa_s->links[i].bssid, ssid->ssid,
470 ssid->ssid_len);
471 else
472 bss = wpa_bss_get_bssid(wpa_s, wpa_s->links[i].bssid);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000473 wpa_s->mlo_assoc_link_id = i;
474
475 return bss;
476}
477#endif /* CONFIG_TESTING_OPTIONS */
478
479
480static int wpas_sme_ml_auth(struct wpa_supplicant *wpa_s,
481 union wpa_event_data *data,
482 int ie_offset)
Sunil Ravi77d572f2023-01-17 23:58:31 +0000483{
484 struct ieee802_11_elems elems;
485 const u8 *mld_addr;
Sunil Ravi640215c2023-06-28 23:08:09 +0000486 u16 status_code = data->auth.status_code;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000487
488 if (!wpa_s->valid_links)
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000489 return 0;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000490
491 if (ieee802_11_parse_elems(data->auth.ies + ie_offset,
492 data->auth.ies_len - ie_offset,
Sunil Ravi640215c2023-06-28 23:08:09 +0000493 &elems, 0) == ParseFailed) {
Sunil Ravi77d572f2023-01-17 23:58:31 +0000494 wpa_printf(MSG_DEBUG, "MLD: Failed parsing elements");
Sunil Ravi7f769292024-07-23 22:21:32 +0000495 return -1;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000496 }
497
498 if (!elems.basic_mle || !elems.basic_mle_len) {
499 wpa_printf(MSG_DEBUG, "MLD: No ML element in authentication");
Sunil Ravi640215c2023-06-28 23:08:09 +0000500 if (status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ ||
501 status_code == WLAN_STATUS_SUCCESS ||
502 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
503 status_code == WLAN_STATUS_SAE_PK)
Sunil Ravi7f769292024-07-23 22:21:32 +0000504 return -1;
Sunil Ravi640215c2023-06-28 23:08:09 +0000505 /* Accept missing Multi-Link element in failed authentication
506 * cases. */
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000507 return 0;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000508 }
509
510 mld_addr = get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len);
511 if (!mld_addr)
Sunil Ravi7f769292024-07-23 22:21:32 +0000512 return -1;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000513
514 wpa_printf(MSG_DEBUG, "MLD: mld_address=" MACSTR, MAC2STR(mld_addr));
515
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000516 if (!ether_addr_equal(wpa_s->ap_mld_addr, mld_addr)) {
Sunil Ravi77d572f2023-01-17 23:58:31 +0000517 wpa_printf(MSG_DEBUG, "MLD: Unexpected MLD address (expected "
518 MACSTR ")", MAC2STR(wpa_s->ap_mld_addr));
Sunil Ravi7f769292024-07-23 22:21:32 +0000519 return -1;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000520 }
521
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000522 return 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000523}
524
525
526static void wpas_sme_set_mlo_links(struct wpa_supplicant *wpa_s,
Sunil Ravi7f769292024-07-23 22:21:32 +0000527 struct wpa_bss *bss, struct wpa_ssid *ssid)
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000528{
Sunil Ravi99c035e2024-07-12 01:42:03 +0000529 u8 i;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000530
531 wpa_s->valid_links = 0;
Sunil Ravi99c035e2024-07-12 01:42:03 +0000532 wpa_s->mlo_assoc_link_id = bss->mld_link_id;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000533
Sunil Ravi99c035e2024-07-12 01:42:03 +0000534 for_each_link(bss->valid_links, i) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000535 const u8 *bssid = bss->mld_links[i].bssid;
536
Sunil Ravi99c035e2024-07-12 01:42:03 +0000537 wpa_s->valid_links |= BIT(i);
538 os_memcpy(wpa_s->links[i].bssid, bssid, ETH_ALEN);
539 wpa_s->links[i].freq = bss->mld_links[i].freq;
540 wpa_s->links[i].disabled = bss->mld_links[i].disabled;
541
542 if (bss->mld_link_id == i)
543 wpa_s->links[i].bss = bss;
Sunil Ravi7f769292024-07-23 22:21:32 +0000544 else if (ssid && ssid->ssid_len)
545 wpa_s->links[i].bss = wpa_bss_get(wpa_s, bssid,
546 ssid->ssid,
547 ssid->ssid_len);
Sunil Ravi99c035e2024-07-12 01:42:03 +0000548 else
549 wpa_s->links[i].bss = wpa_bss_get_bssid(wpa_s, bssid);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000550 }
Sunil Ravi77d572f2023-01-17 23:58:31 +0000551}
552
553
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800554static void sme_send_authentication(struct wpa_supplicant *wpa_s,
555 struct wpa_bss *bss, struct wpa_ssid *ssid,
556 int start)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700557{
558 struct wpa_driver_auth_params params;
559 struct wpa_ssid *old_ssid;
560#ifdef CONFIG_IEEE80211R
561 const u8 *ie;
562#endif /* CONFIG_IEEE80211R */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700563#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700564 const u8 *md = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700565#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
Hai Shalomfdcde762020-04-02 11:19:20 -0700566 int bssid_changed;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800567 struct wpabuf *resp = NULL;
Dmitry Shmidt09f57ba2014-06-10 16:07:13 -0700568 u8 ext_capab[18];
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800569 int ext_capab_len;
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800570 int skip_auth;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800571 u8 *wpa_ie;
572 size_t wpa_ie_len;
Hai Shalomce48b4a2018-09-05 11:41:35 -0700573#ifdef CONFIG_MBO
574 const u8 *mbo_ie;
575#endif /* CONFIG_MBO */
Hai Shalomfdcde762020-04-02 11:19:20 -0700576 int omit_rsnxe = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700577
578 if (bss == NULL) {
579 wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
580 "the network");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800581 wpas_connect_work_done(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700582 return;
583 }
584
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000585 os_memset(&params, 0, sizeof(params));
586
587 if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) &&
588 !wpa_bss_parse_basic_ml_element(wpa_s, bss, wpa_s->ap_mld_addr,
589 NULL, ssid, NULL) &&
Sunil Ravi99c035e2024-07-12 01:42:03 +0000590 bss->valid_links) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000591 wpa_printf(MSG_DEBUG, "MLD: In authentication");
Sunil Ravi7f769292024-07-23 22:21:32 +0000592 wpas_sme_set_mlo_links(wpa_s, bss, ssid);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000593
594#ifdef CONFIG_TESTING_OPTIONS
Sunil Ravi7f769292024-07-23 22:21:32 +0000595 bss = wpas_ml_connect_pref(wpa_s, bss, ssid);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000596
597 if (wpa_s->conf->mld_force_single_link) {
598 wpa_printf(MSG_DEBUG, "MLD: Force single link");
599 wpa_s->valid_links = BIT(wpa_s->mlo_assoc_link_id);
600 }
601#endif /* CONFIG_TESTING_OPTIONS */
602 params.mld = true;
603 params.mld_link_id = wpa_s->mlo_assoc_link_id;
604 params.ap_mld_addr = wpa_s->ap_mld_addr;
605 wpas_ml_handle_removed_links(wpa_s, bss);
606 }
607
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800608 skip_auth = wpa_s->conf->reassoc_same_bss_optim &&
609 wpa_s->reassoc_same_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700610 wpa_s->current_bss = bss;
611
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700612 wpa_s->reassociate = 0;
613
614 params.freq = bss->freq;
615 params.bssid = bss->bssid;
616 params.ssid = bss->ssid;
617 params.ssid_len = bss->ssid_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800618 params.p2p = ssid->p2p_group;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700619
620 if (wpa_s->sme.ssid_len != params.ssid_len ||
621 os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0)
622 wpa_s->sme.prev_bssid_set = 0;
623
624 wpa_s->sme.freq = params.freq;
625 os_memcpy(wpa_s->sme.ssid, params.ssid, params.ssid_len);
626 wpa_s->sme.ssid_len = params.ssid_len;
627
628 params.auth_alg = WPA_AUTH_ALG_OPEN;
629#ifdef IEEE8021X_EAPOL
630 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
631 if (ssid->leap) {
632 if (ssid->non_leap == 0)
633 params.auth_alg = WPA_AUTH_ALG_LEAP;
634 else
635 params.auth_alg |= WPA_AUTH_ALG_LEAP;
636 }
637 }
638#endif /* IEEE8021X_EAPOL */
639 wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x",
640 params.auth_alg);
641 if (ssid->auth_alg) {
642 params.auth_alg = ssid->auth_alg;
643 wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
644 "0x%x", params.auth_alg);
645 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800646#ifdef CONFIG_SAE
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800647 wpa_s->sme.sae_pmksa_caching = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800648 if (wpa_key_mgmt_sae(ssid->key_mgmt)) {
649 const u8 *rsn;
650 struct wpa_ie_data ied;
651
Sunil Ravi7f769292024-07-23 22:21:32 +0000652 rsn = wpa_bss_get_rsne(wpa_s, bss, ssid, false);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800653 if (!rsn) {
654 wpa_dbg(wpa_s, MSG_DEBUG,
655 "SAE enabled, but target BSS does not advertise RSN");
Hai Shalom021b0b52019-04-10 11:17:58 -0700656#ifdef CONFIG_DPP
657 } else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
658 (ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
659 (ied.key_mgmt & WPA_KEY_MGMT_DPP)) {
660 wpa_dbg(wpa_s, MSG_DEBUG, "Prefer DPP over SAE when both are enabled");
661#endif /* CONFIG_DPP */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800662 } else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
663 wpa_key_mgmt_sae(ied.key_mgmt)) {
Sunil Ravi77d572f2023-01-17 23:58:31 +0000664 if (wpas_is_sae_avoided(wpa_s, ssid, &ied)) {
665 wpa_dbg(wpa_s, MSG_DEBUG,
666 "SAE enabled, but disallowing SAE auth_alg without PMF");
667 } else {
668 wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
669 params.auth_alg = WPA_AUTH_ALG_SAE;
670 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800671 } else {
672 wpa_dbg(wpa_s, MSG_DEBUG,
673 "SAE enabled, but target BSS does not advertise SAE AKM for RSN");
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800674 }
675 }
676#endif /* CONFIG_SAE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700677
Hai Shalomfdcde762020-04-02 11:19:20 -0700678#ifdef CONFIG_WEP
679 {
680 int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700681
Hai Shalomfdcde762020-04-02 11:19:20 -0700682 for (i = 0; i < NUM_WEP_KEYS; i++) {
683 if (ssid->wep_key_len[i])
684 params.wep_key[i] = ssid->wep_key[i];
685 params.wep_key_len[i] = ssid->wep_key_len[i];
686 }
687 params.wep_tx_keyidx = ssid->wep_tx_keyidx;
688 }
689#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700690
691 if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
Sunil Ravi7f769292024-07-23 22:21:32 +0000692 wpa_bss_get_rsne(wpa_s, bss, ssid, false)) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800693 wpa_key_mgmt_wpa(ssid->key_mgmt)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700694 int try_opportunistic;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700695 const u8 *cache_id = NULL;
696
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800697 try_opportunistic = (ssid->proactive_key_caching < 0 ?
698 wpa_s->conf->okc :
699 ssid->proactive_key_caching) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700700 (ssid->proto & WPA_PROTO_RSN);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700701#ifdef CONFIG_FILS
702 if (wpa_key_mgmt_fils(ssid->key_mgmt))
703 cache_id = wpa_bss_get_fils_cache_id(bss);
704#endif /* CONFIG_FILS */
Sunil Ravi77d572f2023-01-17 23:58:31 +0000705 if (pmksa_cache_set_current(wpa_s->wpa, NULL,
706 params.mld ? params.ap_mld_addr :
707 bss->bssid,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700708 wpa_s->current_ssid,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700709 try_opportunistic, cache_id,
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000710 0, false) == 0)
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800711 eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700712 wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
713 if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
714 wpa_s->sme.assoc_req_ie,
Sunil Ravi77d572f2023-01-17 23:58:31 +0000715 &wpa_s->sme.assoc_req_ie_len,
716 false)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700717 wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
718 "key management and encryption suites");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800719 wpas_connect_work_done(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700720 return;
721 }
Hai Shalom74f70d42019-02-11 14:42:39 -0800722#ifdef CONFIG_HS20
723 } else if (wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) &&
724 (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) {
725 /* No PMKSA caching, but otherwise similar to RSN/WPA */
726 wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
727 if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
728 wpa_s->sme.assoc_req_ie,
Sunil Ravi77d572f2023-01-17 23:58:31 +0000729 &wpa_s->sme.assoc_req_ie_len,
730 false)) {
Hai Shalom74f70d42019-02-11 14:42:39 -0800731 wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
732 "key management and encryption suites");
733 wpas_connect_work_done(wpa_s);
734 return;
735 }
736#endif /* CONFIG_HS20 */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700737 } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
738 wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
739 /*
740 * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
741 * use non-WPA since the scan results did not indicate that the
742 * AP is using WPA or WPA2.
743 */
744 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
745 wpa_s->sme.assoc_req_ie_len = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800746 } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700747 wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
748 if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
749 wpa_s->sme.assoc_req_ie,
Sunil Ravi77d572f2023-01-17 23:58:31 +0000750 &wpa_s->sme.assoc_req_ie_len,
751 false)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700752 wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
753 "key management and encryption suites (no "
754 "scan results)");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800755 wpas_connect_work_done(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700756 return;
757 }
758#ifdef CONFIG_WPS
759 } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
760 struct wpabuf *wps_ie;
761 wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
762 if (wps_ie && wpabuf_len(wps_ie) <=
763 sizeof(wpa_s->sme.assoc_req_ie)) {
764 wpa_s->sme.assoc_req_ie_len = wpabuf_len(wps_ie);
765 os_memcpy(wpa_s->sme.assoc_req_ie, wpabuf_head(wps_ie),
766 wpa_s->sme.assoc_req_ie_len);
767 } else
768 wpa_s->sme.assoc_req_ie_len = 0;
769 wpabuf_free(wps_ie);
770 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
771#endif /* CONFIG_WPS */
772 } else {
773 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
774 wpa_s->sme.assoc_req_ie_len = 0;
775 }
776
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800777 /* In case the WPA vendor IE is used, it should be placed after all the
778 * non-vendor IEs, as the lower layer expects the IEs to be ordered as
779 * defined in the standard. Store the WPA IE so it can later be
780 * inserted at the correct location.
781 */
782 wpa_ie = NULL;
783 wpa_ie_len = 0;
784 if (wpa_s->wpa_proto == WPA_PROTO_WPA) {
785 wpa_ie = os_memdup(wpa_s->sme.assoc_req_ie,
786 wpa_s->sme.assoc_req_ie_len);
787 if (wpa_ie) {
788 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Storing WPA IE");
789
790 wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
791 wpa_s->sme.assoc_req_ie_len = 0;
792 } else {
793 wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed copy WPA IE");
794 wpas_connect_work_done(wpa_s);
795 return;
796 }
797 }
798
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700799#ifdef CONFIG_IEEE80211R
800 ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
801 if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
802 md = ie + 2;
803 wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
Hai Shalom021b0b52019-04-10 11:17:58 -0700804 if (md && (!wpa_key_mgmt_ft(ssid->key_mgmt) ||
805 !wpa_key_mgmt_ft(wpa_s->key_mgmt)))
806 md = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700807 if (md) {
808 /* Prepare for the next transition */
809 wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
810 }
811
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700812 if (md) {
813 wpa_dbg(wpa_s, MSG_DEBUG, "SME: FT mobility domain %02x%02x",
814 md[0], md[1]);
815
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700816 if (wpa_s->sme.assoc_req_ie_len + 5 <
817 sizeof(wpa_s->sme.assoc_req_ie)) {
818 struct rsn_mdie *mdie;
819 u8 *pos = wpa_s->sme.assoc_req_ie +
820 wpa_s->sme.assoc_req_ie_len;
821 *pos++ = WLAN_EID_MOBILITY_DOMAIN;
822 *pos++ = sizeof(*mdie);
823 mdie = (struct rsn_mdie *) pos;
824 os_memcpy(mdie->mobility_domain, md,
825 MOBILITY_DOMAIN_ID_LEN);
826 mdie->ft_capab = md[MOBILITY_DOMAIN_ID_LEN];
827 wpa_s->sme.assoc_req_ie_len += 5;
828 }
829
Hai Shalom74f70d42019-02-11 14:42:39 -0800830 if (wpa_s->sme.prev_bssid_set && wpa_s->sme.ft_used &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700831 os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 &&
Sunil Ravi77d572f2023-01-17 23:58:31 +0000832 wpa_sm_has_ft_keys(wpa_s->wpa, md)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700833 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT "
834 "over-the-air");
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000835 omit_rsnxe = !wpa_bss_get_rsnxe(wpa_s, bss, ssid,
836 false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700837 params.auth_alg = WPA_AUTH_ALG_FT;
838 params.ie = wpa_s->sme.ft_ies;
839 params.ie_len = wpa_s->sme.ft_ies_len;
840 }
841 }
842#endif /* CONFIG_IEEE80211R */
843
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800844 wpa_s->sme.mfp = wpas_get_ssid_pmf(wpa_s, ssid);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800845 if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
Sunil Ravi7f769292024-07-23 22:21:32 +0000846 const u8 *rsn = wpa_bss_get_rsne(wpa_s, bss, ssid, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700847 struct wpa_ie_data _ie;
848 if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 &&
849 _ie.capabilities &
850 (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
851 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected AP supports "
852 "MFP: require MFP");
853 wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
854 }
855 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700856
857#ifdef CONFIG_P2P
858 if (wpa_s->global->p2p) {
859 u8 *pos;
860 size_t len;
861 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700862 pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
863 len = sizeof(wpa_s->sme.assoc_req_ie) -
864 wpa_s->sme.assoc_req_ie_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800865 res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
866 ssid->p2p_group);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700867 if (res >= 0)
868 wpa_s->sme.assoc_req_ie_len += res;
869 }
870#endif /* CONFIG_P2P */
871
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800872#ifdef CONFIG_FST
873 if (wpa_s->fst_ies) {
874 int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
875
876 if (wpa_s->sme.assoc_req_ie_len + fst_ies_len <=
877 sizeof(wpa_s->sme.assoc_req_ie)) {
878 os_memcpy(wpa_s->sme.assoc_req_ie +
879 wpa_s->sme.assoc_req_ie_len,
880 wpabuf_head(wpa_s->fst_ies),
881 fst_ies_len);
882 wpa_s->sme.assoc_req_ie_len += fst_ies_len;
883 }
884 }
885#endif /* CONFIG_FST */
886
887 sme_auth_handle_rrm(wpa_s, bss);
888
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000889#ifndef CONFIG_NO_RRM
Dmitry Shmidt29333592017-01-09 12:27:11 -0800890 wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie(
Hai Shalomfdcde762020-04-02 11:19:20 -0700891 wpa_s, ssid, bss,
Dmitry Shmidt29333592017-01-09 12:27:11 -0800892 wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
893 sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000894#endif /* CONFIG_NO_RRM */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800895
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700896 if (params.p2p)
897 wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
898 else
899 wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
900
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800901 ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000902 sizeof(ext_capab), bss);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800903 if (ext_capab_len > 0) {
904 u8 *pos = wpa_s->sme.assoc_req_ie;
905 if (wpa_s->sme.assoc_req_ie_len > 0 && pos[0] == WLAN_EID_RSN)
906 pos += 2 + pos[1];
907 os_memmove(pos + ext_capab_len, pos,
908 wpa_s->sme.assoc_req_ie_len -
909 (pos - wpa_s->sme.assoc_req_ie));
910 wpa_s->sme.assoc_req_ie_len += ext_capab_len;
911 os_memcpy(pos, ext_capab, ext_capab_len);
912 }
913
Sunil Ravi7f769292024-07-23 22:21:32 +0000914 if (ssid->max_idle && wpa_s->sme.assoc_req_ie_len + 5 <=
915 sizeof(wpa_s->sme.assoc_req_ie)) {
916 u8 *pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
917
918 *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
919 *pos++ = 3;
920 WPA_PUT_LE16(pos, ssid->max_idle);
921 pos += 2;
922 *pos = 0; /* Idle Options */
923 wpa_s->sme.assoc_req_ie_len += 5;
924 }
925
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800926#ifdef CONFIG_TESTING_OPTIONS
927 if (wpa_s->rsnxe_override_assoc &&
928 wpabuf_len(wpa_s->rsnxe_override_assoc) <=
929 sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
930 wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
931 os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
932 wpabuf_head(wpa_s->rsnxe_override_assoc),
933 wpabuf_len(wpa_s->rsnxe_override_assoc));
934 wpa_s->sme.assoc_req_ie_len +=
935 wpabuf_len(wpa_s->rsnxe_override_assoc);
936 } else
937#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomc3565922019-10-28 11:58:20 -0700938 if (wpa_s->rsnxe_len > 0 &&
939 wpa_s->rsnxe_len <=
Hai Shalomfdcde762020-04-02 11:19:20 -0700940 sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len &&
941 !omit_rsnxe) {
Hai Shalomc3565922019-10-28 11:58:20 -0700942 os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
943 wpa_s->rsnxe, wpa_s->rsnxe_len);
944 wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len;
945 }
946
Dmitry Shmidt04949592012-07-19 12:16:46 -0700947#ifdef CONFIG_HS20
Hai Shalomcded4e22022-01-28 15:29:52 -0800948 if (is_hs20_network(wpa_s, ssid, bss)
949#ifndef ANDROID /* Android does not use the native HS 2.0 config */
950 && is_hs20_config(wpa_s)
951#endif /* ANDROID */
952 ) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700953 struct wpabuf *hs20;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800954
Roshan Pius3a1667e2018-07-03 15:17:14 -0700955 hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700956 if (hs20) {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800957 int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700958 size_t len;
959
Hai Shalom74f70d42019-02-11 14:42:39 -0800960 wpas_hs20_add_indication(hs20, pps_mo_id,
961 get_hs20_version(bss));
Roshan Pius3a1667e2018-07-03 15:17:14 -0700962 wpas_hs20_add_roam_cons_sel(hs20, ssid);
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700963 len = sizeof(wpa_s->sme.assoc_req_ie) -
964 wpa_s->sme.assoc_req_ie_len;
965 if (wpabuf_len(hs20) <= len) {
966 os_memcpy(wpa_s->sme.assoc_req_ie +
967 wpa_s->sme.assoc_req_ie_len,
968 wpabuf_head(hs20), wpabuf_len(hs20));
969 wpa_s->sme.assoc_req_ie_len += wpabuf_len(hs20);
970 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700971 wpabuf_free(hs20);
972 }
973 }
974#endif /* CONFIG_HS20 */
975
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800976 if (wpa_ie) {
977 size_t len;
978
979 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Reinsert WPA IE");
980
981 len = sizeof(wpa_s->sme.assoc_req_ie) -
982 wpa_s->sme.assoc_req_ie_len;
983
984 if (len > wpa_ie_len) {
985 os_memcpy(wpa_s->sme.assoc_req_ie +
986 wpa_s->sme.assoc_req_ie_len,
987 wpa_ie, wpa_ie_len);
988 wpa_s->sme.assoc_req_ie_len += wpa_ie_len;
989 } else {
990 wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Failed to add WPA IE");
991 }
992
993 os_free(wpa_ie);
994 }
995
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800996 if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
997 struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
998 size_t len;
999
1000 len = sizeof(wpa_s->sme.assoc_req_ie) -
1001 wpa_s->sme.assoc_req_ie_len;
1002 if (wpabuf_len(buf) <= len) {
1003 os_memcpy(wpa_s->sme.assoc_req_ie +
1004 wpa_s->sme.assoc_req_ie_len,
1005 wpabuf_head(buf), wpabuf_len(buf));
1006 wpa_s->sme.assoc_req_ie_len += wpabuf_len(buf);
1007 }
1008 }
1009
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001010#ifdef CONFIG_MBO
Hai Shalomce48b4a2018-09-05 11:41:35 -07001011 mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
Hai Shalomc3565922019-10-28 11:58:20 -07001012 if (!wpa_s->disable_mbo_oce && mbo_ie) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001013 int len;
1014
1015 len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
1016 wpa_s->sme.assoc_req_ie_len,
1017 sizeof(wpa_s->sme.assoc_req_ie) -
Hai Shalomce48b4a2018-09-05 11:41:35 -07001018 wpa_s->sme.assoc_req_ie_len,
1019 !!mbo_attr_from_mbo_ie(mbo_ie,
1020 OCE_ATTR_ID_CAPA_IND));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001021 if (len >= 0)
1022 wpa_s->sme.assoc_req_ie_len += len;
1023 }
1024#endif /* CONFIG_MBO */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001025
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001026#ifdef CONFIG_SAE
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001027 if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00001028 pmksa_cache_set_current(wpa_s->wpa, NULL,
1029 params.mld ? params.ap_mld_addr :
1030 bss->bssid,
1031 ssid, 0,
Hai Shalom021b0b52019-04-10 11:17:58 -07001032 NULL,
Sunil Ravi89eba102022-09-13 21:04:37 -07001033 wpa_key_mgmt_sae(wpa_s->key_mgmt) ?
1034 wpa_s->key_mgmt :
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001035 (int) WPA_KEY_MGMT_SAE, false) == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001036 wpa_dbg(wpa_s, MSG_DEBUG,
1037 "PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001038 wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001039 params.auth_alg = WPA_AUTH_ALG_OPEN;
1040 wpa_s->sme.sae_pmksa_caching = 1;
1041 }
1042
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001043 if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001044 if (start)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001045 resp = sme_auth_build_sae_commit(wpa_s, ssid,
Sunil Ravi77d572f2023-01-17 23:58:31 +00001046 bss->bssid,
1047 params.mld ?
1048 params.ap_mld_addr :
1049 NULL, 0,
Hai Shalom899fcc72020-10-19 14:38:18 -07001050 start == 2, NULL,
1051 NULL);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001052 else
Roshan Pius3a1667e2018-07-03 15:17:14 -07001053 resp = sme_auth_build_sae_confirm(wpa_s, 0);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001054 if (resp == NULL) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001055 wpas_connection_failed(wpa_s, bss->bssid, NULL);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001056 return;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001057 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001058 params.auth_data = wpabuf_head(resp);
1059 params.auth_data_len = wpabuf_len(resp);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001060 wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001061 }
1062#endif /* CONFIG_SAE */
1063
Hai Shalomfdcde762020-04-02 11:19:20 -07001064 bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
1065 os_memset(wpa_s->bssid, 0, ETH_ALEN);
1066 os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
1067 if (bssid_changed)
1068 wpas_notify_bssid_changed(wpa_s);
1069
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001070 old_ssid = wpa_s->current_ssid;
1071 wpa_s->current_ssid = ssid;
1072 wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
Sunil Ravi7f769292024-07-23 22:21:32 +00001073 wpa_sm_set_ssid(wpa_s->wpa, bss->ssid, bss->ssid_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001074 wpa_supplicant_initiate_eapol(wpa_s);
1075
1076#ifdef CONFIG_FILS
1077 /* TODO: FILS operations can in some cases be done between different
1078 * network_ctx (i.e., same credentials can be used with multiple
1079 * networks). */
1080 if (params.auth_alg == WPA_AUTH_ALG_OPEN &&
1081 wpa_key_mgmt_fils(ssid->key_mgmt)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001082 const u8 *indic;
1083 u16 fils_info;
Hai Shalomce48b4a2018-09-05 11:41:35 -07001084 const u8 *realm, *username, *rrk;
1085 size_t realm_len, username_len, rrk_len;
1086 u16 next_seq_num;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001087
1088 /*
1089 * Check FILS Indication element (FILS Information field) bits
1090 * indicating supported authentication algorithms against local
1091 * configuration (ssid->fils_dh_group). Try to use FILS
1092 * authentication only if the AP supports the combination in the
1093 * network profile. */
1094 indic = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
1095 if (!indic || indic[1] < 2) {
1096 wpa_printf(MSG_DEBUG, "SME: " MACSTR
1097 " does not include FILS Indication element - cannot use FILS authentication with it",
1098 MAC2STR(bss->bssid));
1099 goto no_fils;
1100 }
1101
1102 fils_info = WPA_GET_LE16(indic + 2);
1103 if (ssid->fils_dh_group == 0 && !(fils_info & BIT(9))) {
1104 wpa_printf(MSG_DEBUG, "SME: " MACSTR
1105 " does not support FILS SK without PFS - cannot use FILS authentication with it",
1106 MAC2STR(bss->bssid));
1107 goto no_fils;
1108 }
1109 if (ssid->fils_dh_group != 0 && !(fils_info & BIT(10))) {
1110 wpa_printf(MSG_DEBUG, "SME: " MACSTR
1111 " does not support FILS SK with PFS - cannot use FILS authentication with it",
1112 MAC2STR(bss->bssid));
1113 goto no_fils;
1114 }
1115
Hai Shalomce48b4a2018-09-05 11:41:35 -07001116 if (wpa_s->last_con_fail_realm &&
1117 eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
1118 &username, &username_len,
1119 &realm, &realm_len, &next_seq_num,
1120 &rrk, &rrk_len) == 0 &&
1121 realm && realm_len == wpa_s->last_con_fail_realm_len &&
1122 os_memcmp(realm, wpa_s->last_con_fail_realm,
1123 realm_len) == 0) {
1124 wpa_printf(MSG_DEBUG,
1125 "SME: FILS authentication for this realm failed last time - try to regenerate ERP key hierarchy");
1126 goto no_fils;
1127 }
1128
Sunil Ravi77d572f2023-01-17 23:58:31 +00001129 if (pmksa_cache_set_current(wpa_s->wpa, NULL,
1130 params.mld ? params.ap_mld_addr :
1131 bss->bssid,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001132 ssid, 0,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001133 wpa_bss_get_fils_cache_id(bss),
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001134 0, false) == 0)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001135 wpa_printf(MSG_DEBUG,
1136 "SME: Try to use FILS with PMKSA caching");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001137 resp = fils_build_auth(wpa_s->wpa, ssid->fils_dh_group, md);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001138 if (resp) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001139 int auth_alg;
1140
1141 if (ssid->fils_dh_group)
1142 wpa_printf(MSG_DEBUG,
1143 "SME: Try to use FILS SK authentication with PFS (DH Group %u)",
1144 ssid->fils_dh_group);
1145 else
1146 wpa_printf(MSG_DEBUG,
1147 "SME: Try to use FILS SK authentication without PFS");
1148 auth_alg = ssid->fils_dh_group ?
1149 WPA_AUTH_ALG_FILS_SK_PFS : WPA_AUTH_ALG_FILS;
1150 params.auth_alg = auth_alg;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001151 params.auth_data = wpabuf_head(resp);
1152 params.auth_data_len = wpabuf_len(resp);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001153 wpa_s->sme.auth_alg = auth_alg;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001154 }
1155 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001156no_fils:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001157#endif /* CONFIG_FILS */
1158
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001159 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001160 wpa_supplicant_cancel_scan(wpa_s);
1161
1162 wpa_msg(wpa_s, MSG_INFO, "SME: Trying to authenticate with " MACSTR
1163 " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
1164 wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
1165
Hai Shalome21d4e82020-04-29 16:34:06 -07001166 eapol_sm_notify_portValid(wpa_s->eapol, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001167 wpa_clear_keys(wpa_s, bss->bssid);
1168 wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001169 if (old_ssid != wpa_s->current_ssid)
1170 wpas_notify_network_changed(wpa_s);
1171
Dmitry Shmidt849734c2016-05-27 09:59:01 -07001172#ifdef CONFIG_HS20
1173 hs20_configure_frame_filters(wpa_s);
1174#endif /* CONFIG_HS20 */
1175
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07001176#ifdef CONFIG_P2P
1177 /*
1178 * If multi-channel concurrency is not supported, check for any
1179 * frequency conflict. In case of any frequency conflict, remove the
1180 * least prioritized connection.
1181 */
1182 if (wpa_s->num_multichan_concurrent < 2) {
1183 int freq, num;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001184 num = get_shared_radio_freqs(wpa_s, &freq, 1, false);
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07001185 if (num > 0 && freq > 0 && freq != params.freq) {
1186 wpa_printf(MSG_DEBUG,
1187 "Conflicting frequency found (%d != %d)",
1188 freq, params.freq);
1189 if (wpas_p2p_handle_frequency_conflicts(wpa_s,
1190 params.freq,
1191 ssid) < 0) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001192 wpas_connection_failed(wpa_s, bss->bssid, NULL);
Dmitry Shmidtf9bdef92014-04-25 10:46:36 -07001193 wpa_supplicant_mark_disassoc(wpa_s);
1194 wpabuf_free(resp);
1195 wpas_connect_work_done(wpa_s);
1196 return;
1197 }
1198 }
1199 }
1200#endif /* CONFIG_P2P */
1201
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001202 if (skip_auth) {
1203 wpa_msg(wpa_s, MSG_DEBUG,
1204 "SME: Skip authentication step on reassoc-to-same-BSS");
1205 wpabuf_free(resp);
1206 sme_associate(wpa_s, ssid->mode, bss->bssid, WLAN_AUTH_OPEN);
1207 return;
1208 }
1209
1210
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001211 wpa_s->sme.auth_alg = params.auth_alg;
1212 if (wpa_drv_authenticate(wpa_s, &params) < 0) {
1213 wpa_msg(wpa_s, MSG_INFO, "SME: Authentication request to the "
1214 "driver failed");
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001215 wpas_connection_failed(wpa_s, bss->bssid, NULL);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001216 wpa_supplicant_mark_disassoc(wpa_s);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001217 wpabuf_free(resp);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001218 wpas_connect_work_done(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001219 return;
1220 }
1221
1222 eloop_register_timeout(SME_AUTH_TIMEOUT, 0, sme_auth_timer, wpa_s,
1223 NULL);
1224
1225 /*
1226 * Association will be started based on the authentication event from
1227 * the driver.
1228 */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001229
1230 wpabuf_free(resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001231}
1232
1233
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001234static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
1235{
1236 struct wpa_connect_work *cwork = work->ctx;
1237 struct wpa_supplicant *wpa_s = work->wpa_s;
1238
Hai Shaloma20dcd72022-02-04 13:43:00 -08001239 wpa_s->roam_in_progress = false;
1240#ifdef CONFIG_WNM
1241 wpa_s->bss_trans_mgmt_in_progress = false;
1242#endif /* CONFIG_WNM */
1243
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001244 if (deinit) {
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08001245 if (work->started)
1246 wpa_s->connect_work = NULL;
1247
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001248 wpas_connect_work_free(cwork);
1249 return;
1250 }
1251
1252 wpa_s->connect_work = work;
1253
Dmitry Shmidt2e425d62014-11-10 11:18:27 -08001254 if (cwork->bss_removed ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001255 !wpas_valid_bss_ssid(wpa_s, cwork->bss, cwork->ssid) ||
1256 wpas_network_disabled(wpa_s, cwork->ssid)) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001257 wpa_dbg(wpa_s, MSG_DEBUG, "SME: BSS/SSID entry for authentication not valid anymore - drop connection attempt");
1258 wpas_connect_work_done(wpa_s);
1259 return;
1260 }
1261
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001262 /* Starting new connection, so clear the possibly used WPA IE from the
1263 * previous association. */
1264 wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
Hai Shalomc3565922019-10-28 11:58:20 -07001265 wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
1266 wpa_s->rsnxe_len = 0;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001267
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001268 sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001269 wpas_notify_auth_changed(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001270}
1271
1272
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001273void sme_authenticate(struct wpa_supplicant *wpa_s,
1274 struct wpa_bss *bss, struct wpa_ssid *ssid)
1275{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001276 struct wpa_connect_work *cwork;
1277
1278 if (bss == NULL || ssid == NULL)
1279 return;
1280 if (wpa_s->connect_work) {
1281 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Reject sme_authenticate() call since connect_work exist");
1282 return;
1283 }
1284
Hai Shaloma20dcd72022-02-04 13:43:00 -08001285 if (wpa_s->roam_in_progress) {
1286 wpa_dbg(wpa_s, MSG_DEBUG,
1287 "SME: Reject sme_authenticate() in favor of explicit roam request");
1288 return;
1289 }
1290#ifdef CONFIG_WNM
1291 if (wpa_s->bss_trans_mgmt_in_progress) {
1292 wpa_dbg(wpa_s, MSG_DEBUG,
1293 "SME: Reject sme_authenticate() in favor of BSS transition management request");
1294 return;
1295 }
1296#endif /* CONFIG_WNM */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001297 if (radio_work_pending(wpa_s, "sme-connect")) {
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001298 /*
1299 * The previous sme-connect work might no longer be valid due to
1300 * the fact that the BSS list was updated. In addition, it makes
1301 * sense to adhere to the 'newer' decision.
1302 */
1303 wpa_dbg(wpa_s, MSG_DEBUG,
1304 "SME: Remove previous pending sme-connect");
1305 radio_remove_works(wpa_s, "sme-connect", 0);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001306 }
1307
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001308 wpas_abort_ongoing_scan(wpa_s);
1309
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001310 cwork = os_zalloc(sizeof(*cwork));
1311 if (cwork == NULL)
1312 return;
1313 cwork->bss = bss;
1314 cwork->ssid = ssid;
1315 cwork->sme = 1;
1316
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001317#ifdef CONFIG_SAE
1318 wpa_s->sme.sae.state = SAE_NOTHING;
1319 wpa_s->sme.sae.send_confirm = 0;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001320 wpa_s->sme.sae_group_index = 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001321#endif /* CONFIG_SAE */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001322
1323 if (radio_add_work(wpa_s, bss->freq, "sme-connect", 1,
1324 sme_auth_start_cb, cwork) < 0)
1325 wpas_connect_work_free(cwork);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001326}
1327
1328
1329#ifdef CONFIG_SAE
1330
Sunil Ravi036cec52023-03-29 11:35:17 -07001331#define WPA_AUTH_FRAME_ML_IE_LEN (6 + ETH_ALEN)
1332
1333static void wpa_auth_ml_ie(struct wpabuf *buf, const u8 *mld_addr)
1334{
1335
1336 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
1337 wpabuf_put_u8(buf, 4 + ETH_ALEN);
1338 wpabuf_put_u8(buf, WLAN_EID_EXT_MULTI_LINK);
1339
1340 /* Basic Multi-Link element Control field */
1341 wpabuf_put_u8(buf, 0x0);
1342 wpabuf_put_u8(buf, 0x0);
1343
1344 /* Common Info */
1345 wpabuf_put_u8(buf, 0x7); /* length = Length field + MLD MAC address */
1346 wpabuf_put_data(buf, mld_addr, ETH_ALEN);
1347}
1348
1349
Roshan Pius3a1667e2018-07-03 15:17:14 -07001350static int sme_external_auth_build_buf(struct wpabuf *buf,
1351 struct wpabuf *params,
1352 const u8 *sa, const u8 *da,
Hai Shalomc3565922019-10-28 11:58:20 -07001353 u16 auth_transaction, u16 seq_num,
Sunil Ravi036cec52023-03-29 11:35:17 -07001354 u16 status_code, const u8 *mld_addr)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001355{
1356 struct ieee80211_mgmt *resp;
1357
1358 resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
1359 u.auth.variable));
1360
1361 resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
1362 (WLAN_FC_STYPE_AUTH << 4));
1363 os_memcpy(resp->da, da, ETH_ALEN);
1364 os_memcpy(resp->sa, sa, ETH_ALEN);
1365 os_memcpy(resp->bssid, da, ETH_ALEN);
Hai Shalom74f70d42019-02-11 14:42:39 -08001366 resp->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE);
1367 resp->seq_ctrl = host_to_le16(seq_num << 4);
1368 resp->u.auth.auth_transaction = host_to_le16(auth_transaction);
Hai Shalomc3565922019-10-28 11:58:20 -07001369 resp->u.auth.status_code = host_to_le16(status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001370 if (params)
1371 wpabuf_put_buf(buf, params);
1372
Sunil Ravi036cec52023-03-29 11:35:17 -07001373 if (mld_addr)
1374 wpa_auth_ml_ie(buf, mld_addr);
1375
Roshan Pius3a1667e2018-07-03 15:17:14 -07001376 return 0;
1377}
1378
1379
Hai Shalom81f62d82019-07-22 12:10:00 -07001380static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
1381 const u8 *bssid,
1382 struct wpa_ssid *ssid)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001383{
1384 struct wpabuf *resp, *buf;
Hai Shalomc3565922019-10-28 11:58:20 -07001385 int use_pt;
Hai Shalom899fcc72020-10-19 14:38:18 -07001386 bool use_pk;
1387 u16 status;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001388
Sunil Ravi036cec52023-03-29 11:35:17 -07001389 resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid,
1390 wpa_s->sme.ext_ml_auth ?
1391 wpa_s->sme.ext_auth_ap_mld_addr : NULL,
Sunil Ravi77d572f2023-01-17 23:58:31 +00001392 1, 0, &use_pt, &use_pk);
Hai Shalom81f62d82019-07-22 12:10:00 -07001393 if (!resp) {
1394 wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit");
1395 return -1;
1396 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001397
1398 wpa_s->sme.sae.state = SAE_COMMITTED;
Sunil Ravi036cec52023-03-29 11:35:17 -07001399 buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp) +
1400 (wpa_s->sme.ext_ml_auth ? WPA_AUTH_FRAME_ML_IE_LEN :
1401 0));
Roshan Pius3a1667e2018-07-03 15:17:14 -07001402 if (!buf) {
1403 wpabuf_free(resp);
Hai Shalom81f62d82019-07-22 12:10:00 -07001404 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001405 }
1406
1407 wpa_s->sme.seq_num++;
Hai Shalom899fcc72020-10-19 14:38:18 -07001408 if (use_pk)
1409 status = WLAN_STATUS_SAE_PK;
1410 else if (use_pt)
1411 status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
1412 else
1413 status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001414 sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
Sunil Ravi036cec52023-03-29 11:35:17 -07001415 wpa_s->sme.ext_ml_auth ?
1416 wpa_s->sme.ext_auth_ap_mld_addr : bssid, 1,
1417 wpa_s->sme.seq_num, status,
1418 wpa_s->sme.ext_ml_auth ?
1419 wpa_s->own_addr : NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07001420 wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001421 wpabuf_free(resp);
1422 wpabuf_free(buf);
Hai Shalom81f62d82019-07-22 12:10:00 -07001423
1424 return 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001425}
1426
1427
1428static void sme_send_external_auth_status(struct wpa_supplicant *wpa_s,
1429 u16 status)
1430{
1431 struct external_auth params;
1432
Sunil Ravi89eba102022-09-13 21:04:37 -07001433 wpa_s->sme.ext_auth_wpa_ssid = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001434 os_memset(&params, 0, sizeof(params));
1435 params.status = status;
Hai Shalom66904732019-05-29 11:54:04 -07001436 params.ssid = wpa_s->sme.ext_auth_ssid;
1437 params.ssid_len = wpa_s->sme.ext_auth_ssid_len;
1438 params.bssid = wpa_s->sme.ext_auth_bssid;
Hai Shalomc3565922019-10-28 11:58:20 -07001439 if (wpa_s->conf->sae_pmkid_in_assoc && status == WLAN_STATUS_SUCCESS)
1440 params.pmkid = wpa_s->sme.sae.pmkid;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001441 wpa_drv_send_external_auth_status(wpa_s, &params);
1442}
1443
1444
Hai Shalom81f62d82019-07-22 12:10:00 -07001445static int sme_handle_external_auth_start(struct wpa_supplicant *wpa_s,
1446 union wpa_event_data *data)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001447{
1448 struct wpa_ssid *ssid;
1449 size_t ssid_str_len = data->external_auth.ssid_len;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001450 const u8 *ssid_str = data->external_auth.ssid;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001451
Sunil Ravi89eba102022-09-13 21:04:37 -07001452 wpa_s->sme.ext_auth_wpa_ssid = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001453 /* Get the SSID conf from the ssid string obtained */
1454 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1455 if (!wpas_network_disabled(wpa_s, ssid) &&
1456 ssid_str_len == ssid->ssid_len &&
Hai Shalom74f70d42019-02-11 14:42:39 -08001457 os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0 &&
Sunil Ravi89eba102022-09-13 21:04:37 -07001458 wpa_key_mgmt_sae(ssid->key_mgmt)) {
1459 /* Make sure PT is derived */
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001460 wpa_s_setup_sae_pt(wpa_s, ssid, false);
Sunil Ravi89eba102022-09-13 21:04:37 -07001461 wpa_s->sme.ext_auth_wpa_ssid = ssid;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001462 break;
Sunil Ravi89eba102022-09-13 21:04:37 -07001463 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001464 }
Hai Shalom81f62d82019-07-22 12:10:00 -07001465 if (!ssid ||
1466 sme_external_auth_send_sae_commit(wpa_s, data->external_auth.bssid,
1467 ssid) < 0)
1468 return -1;
1469
1470 return 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001471}
1472
1473
1474static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s,
1475 const u8 *da)
1476{
1477 struct wpabuf *resp, *buf;
1478
1479 resp = sme_auth_build_sae_confirm(wpa_s, 1);
1480 if (!resp) {
1481 wpa_printf(MSG_DEBUG, "SAE: Confirm message buf alloc failure");
1482 return;
1483 }
1484
1485 wpa_s->sme.sae.state = SAE_CONFIRMED;
Sunil Ravi036cec52023-03-29 11:35:17 -07001486 buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN + wpabuf_len(resp) +
1487 (wpa_s->sme.ext_ml_auth ? WPA_AUTH_FRAME_ML_IE_LEN :
1488 0));
Roshan Pius3a1667e2018-07-03 15:17:14 -07001489 if (!buf) {
1490 wpa_printf(MSG_DEBUG, "SAE: Auth Confirm buf alloc failure");
1491 wpabuf_free(resp);
1492 return;
1493 }
1494 wpa_s->sme.seq_num++;
1495 sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
Hai Shalomc3565922019-10-28 11:58:20 -07001496 da, 2, wpa_s->sme.seq_num,
Sunil Ravi036cec52023-03-29 11:35:17 -07001497 WLAN_STATUS_SUCCESS,
1498 wpa_s->sme.ext_ml_auth ?
1499 wpa_s->own_addr : NULL);
1500
Hai Shalomfdcde762020-04-02 11:19:20 -07001501 wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001502 wpabuf_free(resp);
1503 wpabuf_free(buf);
1504}
1505
1506
Sunil Ravi77d572f2023-01-17 23:58:31 +00001507static bool is_sae_key_mgmt_suite(struct wpa_supplicant *wpa_s, u32 suite)
1508{
1509 /* suite is supposed to be the selector value in host byte order with
1510 * the OUI in three most significant octets. However, the initial
1511 * implementation swapped that byte order and did not work with drivers
1512 * that followed the expected byte order. Keep a workaround here to
1513 * match that initial implementation so that already deployed use cases
1514 * remain functional. */
1515 if (RSN_SELECTOR_GET(&suite) == RSN_AUTH_KEY_MGMT_SAE) {
1516 /* Old drivers which follow initial implementation send SAE AKM
1517 * for both SAE and FT-SAE connections. In that case, determine
1518 * the actual AKM from wpa_s->key_mgmt. */
1519 wpa_s->sme.ext_auth_key_mgmt = wpa_s->key_mgmt;
1520 return true;
1521 }
1522
1523 if (suite == RSN_AUTH_KEY_MGMT_SAE)
1524 wpa_s->sme.ext_auth_key_mgmt = WPA_KEY_MGMT_SAE;
1525 else if (suite == RSN_AUTH_KEY_MGMT_FT_SAE)
1526 wpa_s->sme.ext_auth_key_mgmt = WPA_KEY_MGMT_FT_SAE;
1527 else if (suite == RSN_AUTH_KEY_MGMT_SAE_EXT_KEY)
1528 wpa_s->sme.ext_auth_key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
1529 else if (suite == RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY)
1530 wpa_s->sme.ext_auth_key_mgmt = WPA_KEY_MGMT_FT_SAE_EXT_KEY;
1531 else
1532 return false;
1533
1534 return true;
1535}
1536
1537
Roshan Pius3a1667e2018-07-03 15:17:14 -07001538void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
1539 union wpa_event_data *data)
1540{
Sunil Ravi77d572f2023-01-17 23:58:31 +00001541 if (!is_sae_key_mgmt_suite(wpa_s, data->external_auth.key_mgmt_suite))
Roshan Pius3a1667e2018-07-03 15:17:14 -07001542 return;
1543
1544 if (data->external_auth.action == EXT_AUTH_START) {
Hai Shalom66904732019-05-29 11:54:04 -07001545 if (!data->external_auth.bssid || !data->external_auth.ssid)
1546 return;
1547 os_memcpy(wpa_s->sme.ext_auth_bssid, data->external_auth.bssid,
1548 ETH_ALEN);
1549 os_memcpy(wpa_s->sme.ext_auth_ssid, data->external_auth.ssid,
1550 data->external_auth.ssid_len);
1551 wpa_s->sme.ext_auth_ssid_len = data->external_auth.ssid_len;
Sunil Ravi036cec52023-03-29 11:35:17 -07001552 if (data->external_auth.mld_addr) {
1553 wpa_s->sme.ext_ml_auth = true;
1554 os_memcpy(wpa_s->sme.ext_auth_ap_mld_addr,
1555 data->external_auth.mld_addr, ETH_ALEN);
1556 } else {
1557 wpa_s->sme.ext_ml_auth = false;
1558 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001559 wpa_s->sme.seq_num = 0;
1560 wpa_s->sme.sae.state = SAE_NOTHING;
1561 wpa_s->sme.sae.send_confirm = 0;
1562 wpa_s->sme.sae_group_index = 0;
Hai Shalom81f62d82019-07-22 12:10:00 -07001563 if (sme_handle_external_auth_start(wpa_s, data) < 0)
1564 sme_send_external_auth_status(wpa_s,
1565 WLAN_STATUS_UNSPECIFIED_FAILURE);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001566 } else if (data->external_auth.action == EXT_AUTH_ABORT) {
1567 /* Report failure to driver for the wrong trigger */
1568 sme_send_external_auth_status(wpa_s,
1569 WLAN_STATUS_UNSPECIFIED_FAILURE);
1570 }
1571}
1572
1573
Hai Shalomc3565922019-10-28 11:58:20 -07001574static int sme_sae_is_group_enabled(struct wpa_supplicant *wpa_s, int group)
1575{
1576 int *groups = wpa_s->conf->sae_groups;
1577 int default_groups[] = { 19, 20, 21, 0 };
1578 int i;
1579
1580 if (!groups)
1581 groups = default_groups;
1582
1583 for (i = 0; groups[i] > 0; i++) {
1584 if (groups[i] == group)
1585 return 1;
1586 }
1587
1588 return 0;
1589}
1590
1591
1592static int sme_check_sae_rejected_groups(struct wpa_supplicant *wpa_s,
1593 const struct wpabuf *groups)
1594{
Sunil Ravi7f769292024-07-23 22:21:32 +00001595 size_t i, count, len;
Hai Shalomc3565922019-10-28 11:58:20 -07001596 const u8 *pos;
1597
1598 if (!groups)
1599 return 0;
1600
1601 pos = wpabuf_head(groups);
Sunil Ravi7f769292024-07-23 22:21:32 +00001602 len = wpabuf_len(groups);
1603 if (len & 1) {
1604 wpa_printf(MSG_DEBUG,
1605 "SAE: Invalid length of the Rejected Groups element payload: %zu",
1606 len);
1607 return 1;
1608 }
1609 count = len / 2;
Hai Shalomc3565922019-10-28 11:58:20 -07001610 for (i = 0; i < count; i++) {
1611 int enabled;
1612 u16 group;
1613
1614 group = WPA_GET_LE16(pos);
1615 pos += 2;
1616 enabled = sme_sae_is_group_enabled(wpa_s, group);
1617 wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
1618 group, enabled ? "enabled" : "disabled");
1619 if (enabled)
1620 return 1;
1621 }
1622
1623 return 0;
1624}
1625
1626
Sunil Ravi036cec52023-03-29 11:35:17 -07001627static int sme_external_ml_auth(struct wpa_supplicant *wpa_s,
Sunil Ravi640215c2023-06-28 23:08:09 +00001628 const u8 *data, size_t len, int ie_offset,
1629 u16 status_code)
Sunil Ravi036cec52023-03-29 11:35:17 -07001630{
1631 struct ieee802_11_elems elems;
1632 const u8 *mld_addr;
1633
1634 if (ieee802_11_parse_elems(data + ie_offset, len - ie_offset,
Sunil Ravi640215c2023-06-28 23:08:09 +00001635 &elems, 0) == ParseFailed) {
Sunil Ravi036cec52023-03-29 11:35:17 -07001636 wpa_printf(MSG_DEBUG, "MLD: Failed parsing elements");
1637 return -1;
1638 }
1639
1640 if (!elems.basic_mle || !elems.basic_mle_len) {
1641 wpa_printf(MSG_DEBUG, "MLD: No ML element in authentication");
Sunil Ravi640215c2023-06-28 23:08:09 +00001642 if (status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ ||
1643 status_code == WLAN_STATUS_SUCCESS ||
1644 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1645 status_code == WLAN_STATUS_SAE_PK)
1646 return -1;
1647 /* Accept missing Multi-Link element in failed authentication
1648 * cases. */
1649 return 0;
Sunil Ravi036cec52023-03-29 11:35:17 -07001650 }
1651
1652 mld_addr = get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len);
1653 if (!mld_addr) {
1654 wpa_printf(MSG_DEBUG, "MLD: No MLD address in ML element");
1655 return -1;
1656 }
1657
1658 wpa_printf(MSG_DEBUG, "MLD: mld_address=" MACSTR, MAC2STR(mld_addr));
1659
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001660 if (!ether_addr_equal(wpa_s->sme.ext_auth_ap_mld_addr, mld_addr)) {
Sunil Ravi036cec52023-03-29 11:35:17 -07001661 wpa_printf(MSG_DEBUG, "MLD: Unexpected MLD address (expected "
Sunil Ravi640215c2023-06-28 23:08:09 +00001662 MACSTR ")",
1663 MAC2STR(wpa_s->sme.ext_auth_ap_mld_addr));
Sunil Ravi036cec52023-03-29 11:35:17 -07001664 return -1;
1665 }
1666
1667 return 0;
1668}
1669
1670
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001671static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001672 u16 status_code, const u8 *data, size_t len,
Sunil Ravi77d572f2023-01-17 23:58:31 +00001673 int external, const u8 *sa, int *ie_offset)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001674{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001675 int *groups;
1676
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001677 wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE authentication transaction %u "
1678 "status code %u", auth_transaction, status_code);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001679
1680 if (auth_transaction == 1 &&
1681 status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
1682 wpa_s->sme.sae.state == SAE_COMMITTED &&
Sunil Ravi89eba102022-09-13 21:04:37 -07001683 ((external && wpa_s->sme.ext_auth_wpa_ssid) ||
1684 (!external && wpa_s->current_bss && wpa_s->current_ssid))) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001685 int default_groups[] = { 19, 20, 21, 0 };
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001686 u16 group;
Hai Shalomfdcde762020-04-02 11:19:20 -07001687 const u8 *token_pos;
1688 size_t token_len;
1689 int h2e = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001690
1691 groups = wpa_s->conf->sae_groups;
1692 if (!groups || groups[0] <= 0)
1693 groups = default_groups;
1694
Hai Shalomfdcde762020-04-02 11:19:20 -07001695 wpa_hexdump(MSG_DEBUG, "SME: SAE anti-clogging token request",
1696 data, len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001697 if (len < sizeof(le16)) {
1698 wpa_dbg(wpa_s, MSG_DEBUG,
1699 "SME: Too short SAE anti-clogging token request");
1700 return -1;
1701 }
1702 group = WPA_GET_LE16(data);
1703 wpa_dbg(wpa_s, MSG_DEBUG,
1704 "SME: SAE anti-clogging token requested (group %u)",
1705 group);
1706 if (sae_group_allowed(&wpa_s->sme.sae, groups, group) !=
1707 WLAN_STATUS_SUCCESS) {
1708 wpa_dbg(wpa_s, MSG_ERROR,
1709 "SME: SAE group %u of anti-clogging request is invalid",
1710 group);
1711 return -1;
1712 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001713 wpabuf_free(wpa_s->sme.sae_token);
Hai Shalomfdcde762020-04-02 11:19:20 -07001714 token_pos = data + sizeof(le16);
1715 token_len = len - sizeof(le16);
Hai Shalom899fcc72020-10-19 14:38:18 -07001716 h2e = wpa_s->sme.sae.h2e;
Hai Shalomfdcde762020-04-02 11:19:20 -07001717 if (h2e) {
Sunil8cd6f4d2022-06-28 18:40:46 +00001718 u8 id, elen, extid;
1719
Hai Shalomfdcde762020-04-02 11:19:20 -07001720 if (token_len < 3) {
1721 wpa_dbg(wpa_s, MSG_DEBUG,
1722 "SME: Too short SAE anti-clogging token container");
1723 return -1;
1724 }
Sunil8cd6f4d2022-06-28 18:40:46 +00001725 id = *token_pos++;
1726 elen = *token_pos++;
1727 extid = *token_pos++;
1728 if (id != WLAN_EID_EXTENSION ||
1729 elen == 0 || elen > token_len - 2 ||
1730 extid != WLAN_EID_EXT_ANTI_CLOGGING_TOKEN) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001731 wpa_dbg(wpa_s, MSG_DEBUG,
1732 "SME: Invalid SAE anti-clogging token container header");
1733 return -1;
1734 }
Sunil8cd6f4d2022-06-28 18:40:46 +00001735 token_len = elen - 1;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001736#ifdef CONFIG_IEEE80211BE
1737 } else if ((wpa_s->valid_links ||
1738 (external && wpa_s->sme.ext_ml_auth)) &&
1739 token_len > 12 &&
1740 token_pos[token_len - 12] == WLAN_EID_EXTENSION &&
1741 token_pos[token_len - 11] == 10 &&
1742 token_pos[token_len - 10] ==
1743 WLAN_EID_EXT_MULTI_LINK) {
1744 /* IEEE P802.11be requires H2E to be used whenever SAE
1745 * is used for ML association. However, some early
1746 * Wi-Fi 7 APs enable MLO without H2E. Recognize this
1747 * special case based on the fixed length Basic
1748 * Multi-Link element being at the end of the data that
1749 * would contain the unknown variable length
1750 * Anti-Clogging Token field. The Basic Multi-Link
1751 * element in Authentication frames include the MLD MAC
1752 * addreess in the Common Info field and all subfields
1753 * of the Presence Bitmap subfield of the Multi-Link
1754 * Control field of the element zero and consequently,
1755 * has a fixed length of 12 octets. */
1756 wpa_printf(MSG_DEBUG,
1757 "SME: Detected Basic Multi-Link element at the end of Anti-Clogging Token field");
1758 token_len -= 12;
1759#endif /* CONFIG_IEEE80211BE */
Hai Shalomfdcde762020-04-02 11:19:20 -07001760 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00001761
Sunil Ravi036cec52023-03-29 11:35:17 -07001762 *ie_offset = token_pos + token_len - data;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001763
Hai Shalomfdcde762020-04-02 11:19:20 -07001764 wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001765 if (!wpa_s->sme.sae_token) {
1766 wpa_dbg(wpa_s, MSG_ERROR,
1767 "SME: Failed to allocate SAE token");
1768 return -1;
1769 }
1770
Hai Shalomfdcde762020-04-02 11:19:20 -07001771 wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token",
1772 wpa_s->sme.sae_token);
Sunil Ravi036cec52023-03-29 11:35:17 -07001773 if (!external) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001774 sme_send_authentication(wpa_s, wpa_s->current_bss,
Hai Shalom021b0b52019-04-10 11:17:58 -07001775 wpa_s->current_ssid, 2);
Sunil Ravi036cec52023-03-29 11:35:17 -07001776 } else {
1777 if (wpa_s->sme.ext_ml_auth &&
Sunil Ravi640215c2023-06-28 23:08:09 +00001778 sme_external_ml_auth(wpa_s, data, len, *ie_offset,
1779 status_code))
Sunil Ravi036cec52023-03-29 11:35:17 -07001780 return -1;
1781
Roshan Pius3a1667e2018-07-03 15:17:14 -07001782 sme_external_auth_send_sae_commit(
Hai Shalom66904732019-05-29 11:54:04 -07001783 wpa_s, wpa_s->sme.ext_auth_bssid,
Sunil Ravi89eba102022-09-13 21:04:37 -07001784 wpa_s->sme.ext_auth_wpa_ssid);
Sunil Ravi036cec52023-03-29 11:35:17 -07001785 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001786 return 0;
1787 }
1788
1789 if (auth_transaction == 1 &&
1790 status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1791 wpa_s->sme.sae.state == SAE_COMMITTED &&
Sunil Ravi89eba102022-09-13 21:04:37 -07001792 ((external && wpa_s->sme.ext_auth_wpa_ssid) ||
1793 (!external && wpa_s->current_bss && wpa_s->current_ssid))) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001794 wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
Hai Shalomc3565922019-10-28 11:58:20 -07001795 int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
1796 wpa_s->sme.sae.group);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001797 wpa_s->sme.sae_group_index++;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001798 if (sme_set_sae_group(wpa_s, external) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001799 return -1; /* no other groups enabled */
1800 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group");
Sunil Ravi036cec52023-03-29 11:35:17 -07001801 if (!external) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001802 sme_send_authentication(wpa_s, wpa_s->current_bss,
1803 wpa_s->current_ssid, 1);
Sunil Ravi036cec52023-03-29 11:35:17 -07001804 } else {
1805 if (wpa_s->sme.ext_ml_auth &&
Sunil Ravi640215c2023-06-28 23:08:09 +00001806 sme_external_ml_auth(wpa_s, data, len, *ie_offset,
1807 status_code))
Sunil Ravi036cec52023-03-29 11:35:17 -07001808 return -1;
1809
Roshan Pius3a1667e2018-07-03 15:17:14 -07001810 sme_external_auth_send_sae_commit(
Hai Shalom66904732019-05-29 11:54:04 -07001811 wpa_s, wpa_s->sme.ext_auth_bssid,
Sunil Ravi89eba102022-09-13 21:04:37 -07001812 wpa_s->sme.ext_auth_wpa_ssid);
Sunil Ravi036cec52023-03-29 11:35:17 -07001813 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001814 return 0;
1815 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001816
Roshan Pius3a1667e2018-07-03 15:17:14 -07001817 if (auth_transaction == 1 &&
1818 status_code == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
1819 const u8 *bssid = sa ? sa : wpa_s->pending_bssid;
1820
1821 wpa_msg(wpa_s, MSG_INFO,
1822 WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER MACSTR,
1823 MAC2STR(bssid));
1824 return -1;
1825 }
1826
Hai Shalomc3565922019-10-28 11:58:20 -07001827 if (status_code != WLAN_STATUS_SUCCESS &&
Hai Shalom899fcc72020-10-19 14:38:18 -07001828 status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT &&
Hai Shaloma20dcd72022-02-04 13:43:00 -08001829 status_code != WLAN_STATUS_SAE_PK) {
1830 const u8 *bssid = sa ? sa : wpa_s->pending_bssid;
1831
1832 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AUTH_REJECT MACSTR
1833 " auth_type=%u auth_transaction=%u status_code=%u",
1834 MAC2STR(bssid), WLAN_AUTH_SAE,
1835 auth_transaction, status_code);
Sunil Ravia04bd252022-05-02 22:54:18 -07001836 return -2;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001837 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001838
1839 if (auth_transaction == 1) {
Dmitry Shmidt41712582015-06-29 11:02:15 -07001840 u16 res;
1841
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001842 groups = wpa_s->conf->sae_groups;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001843
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001844 wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
Sunil Ravi89eba102022-09-13 21:04:37 -07001845 if ((external && !wpa_s->sme.ext_auth_wpa_ssid) ||
1846 (!external &&
1847 (!wpa_s->current_bss || !wpa_s->current_ssid)))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001848 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07001849 if (wpa_s->sme.sae.state != SAE_COMMITTED) {
1850 wpa_printf(MSG_DEBUG,
1851 "SAE: Ignore commit message while waiting for confirm");
1852 return 0;
1853 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001854 if (wpa_s->sme.sae.h2e && status_code == WLAN_STATUS_SUCCESS) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001855 wpa_printf(MSG_DEBUG,
1856 "SAE: Unexpected use of status code 0 in SAE commit when H2E was expected");
1857 return -1;
1858 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001859 if ((!wpa_s->sme.sae.h2e || wpa_s->sme.sae.pk) &&
Hai Shalomfdcde762020-04-02 11:19:20 -07001860 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
1861 wpa_printf(MSG_DEBUG,
1862 "SAE: Unexpected use of status code for H2E in SAE commit when H2E was not expected");
1863 return -1;
1864 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001865 if (!wpa_s->sme.sae.pk &&
1866 status_code == WLAN_STATUS_SAE_PK) {
1867 wpa_printf(MSG_DEBUG,
1868 "SAE: Unexpected use of status code for PK in SAE commit when PK was not expected");
1869 return -1;
1870 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001871
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001872 if (groups && groups[0] <= 0)
1873 groups = NULL;
Dmitry Shmidt41712582015-06-29 11:02:15 -07001874 res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
Hai Shalomc3565922019-10-28 11:58:20 -07001875 groups, status_code ==
Hai Shalom899fcc72020-10-19 14:38:18 -07001876 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001877 status_code == WLAN_STATUS_SAE_PK,
1878 ie_offset);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001879 if (res == SAE_SILENTLY_DISCARD) {
1880 wpa_printf(MSG_DEBUG,
1881 "SAE: Drop commit message due to reflection attack");
1882 return 0;
1883 }
1884 if (res != WLAN_STATUS_SUCCESS)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001885 return -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001886
Hai Shalomc3565922019-10-28 11:58:20 -07001887 if (wpa_s->sme.sae.tmp &&
1888 sme_check_sae_rejected_groups(
1889 wpa_s,
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001890 wpa_s->sme.sae.tmp->peer_rejected_groups))
Hai Shalomc3565922019-10-28 11:58:20 -07001891 return -1;
1892
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001893 if (sae_process_commit(&wpa_s->sme.sae) < 0) {
1894 wpa_printf(MSG_DEBUG, "SAE: Failed to process peer "
1895 "commit");
1896 return -1;
1897 }
1898
1899 wpabuf_free(wpa_s->sme.sae_token);
1900 wpa_s->sme.sae_token = NULL;
Sunil Ravi036cec52023-03-29 11:35:17 -07001901 if (!external) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001902 sme_send_authentication(wpa_s, wpa_s->current_bss,
1903 wpa_s->current_ssid, 0);
Sunil Ravi036cec52023-03-29 11:35:17 -07001904 } else {
1905 if (wpa_s->sme.ext_ml_auth &&
Sunil Ravi640215c2023-06-28 23:08:09 +00001906 sme_external_ml_auth(wpa_s, data, len, *ie_offset,
1907 status_code))
Sunil Ravi036cec52023-03-29 11:35:17 -07001908 return -1;
1909
Roshan Pius3a1667e2018-07-03 15:17:14 -07001910 sme_external_auth_send_sae_confirm(wpa_s, sa);
Sunil Ravi036cec52023-03-29 11:35:17 -07001911 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001912 return 0;
1913 } else if (auth_transaction == 2) {
Hai Shalomc3565922019-10-28 11:58:20 -07001914 if (status_code != WLAN_STATUS_SUCCESS)
1915 return -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001916 wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001917 if (wpa_s->sme.sae.state != SAE_CONFIRMED)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001918 return -1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001919 if (sae_check_confirm(&wpa_s->sme.sae, data, len,
1920 ie_offset) < 0)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001921 return -1;
Sunil Ravi036cec52023-03-29 11:35:17 -07001922 if (external && wpa_s->sme.ext_ml_auth &&
Sunil Ravi640215c2023-06-28 23:08:09 +00001923 sme_external_ml_auth(wpa_s, data, len, *ie_offset,
1924 status_code))
Sunil Ravi036cec52023-03-29 11:35:17 -07001925 return -1;
1926
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001927 wpa_s->sme.sae.state = SAE_ACCEPTED;
1928 sae_clear_temp_data(&wpa_s->sme.sae);
Sunil Ravi7f769292024-07-23 22:21:32 +00001929 wpa_s_clear_sae_rejected(wpa_s);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001930
1931 if (external) {
1932 /* Report success to driver */
1933 sme_send_external_auth_status(wpa_s,
1934 WLAN_STATUS_SUCCESS);
1935 }
1936
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001937 return 1;
1938 }
1939
1940 return -1;
1941}
Roshan Pius3a1667e2018-07-03 15:17:14 -07001942
1943
Hai Shalomc3565922019-10-28 11:58:20 -07001944static int sme_sae_set_pmk(struct wpa_supplicant *wpa_s, const u8 *bssid)
1945{
1946 wpa_printf(MSG_DEBUG,
1947 "SME: SAE completed - setting PMK for 4-way handshake");
Sunil Ravi89eba102022-09-13 21:04:37 -07001948 wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, wpa_s->sme.sae.pmk_len,
Hai Shalomc3565922019-10-28 11:58:20 -07001949 wpa_s->sme.sae.pmkid, bssid);
1950 if (wpa_s->conf->sae_pmkid_in_assoc) {
1951 /* Update the own RSNE contents now that we have set the PMK
1952 * and added a PMKSA cache entry based on the successfully
1953 * completed SAE exchange. In practice, this will add the PMKID
1954 * into RSNE. */
1955 if (wpa_s->sme.assoc_req_ie_len + 2 + PMKID_LEN >
1956 sizeof(wpa_s->sme.assoc_req_ie)) {
1957 wpa_msg(wpa_s, MSG_WARNING,
1958 "RSN: Not enough room for inserting own PMKID into RSNE");
1959 return -1;
1960 }
1961 if (wpa_insert_pmkid(wpa_s->sme.assoc_req_ie,
1962 &wpa_s->sme.assoc_req_ie_len,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001963 wpa_s->sme.sae.pmkid, true) < 0)
Hai Shalomc3565922019-10-28 11:58:20 -07001964 return -1;
1965 wpa_hexdump(MSG_DEBUG,
1966 "SME: Updated Association Request IEs",
1967 wpa_s->sme.assoc_req_ie,
1968 wpa_s->sme.assoc_req_ie_len);
1969 }
1970
1971 return 0;
1972}
1973
1974
Roshan Pius3a1667e2018-07-03 15:17:14 -07001975void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
1976 const u8 *auth_frame, size_t len)
1977{
1978 const struct ieee80211_mgmt *header;
1979 size_t auth_length;
1980
1981 header = (const struct ieee80211_mgmt *) auth_frame;
1982 auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth);
1983
1984 if (len < auth_length) {
1985 /* Notify failure to the driver */
1986 sme_send_external_auth_status(wpa_s,
1987 WLAN_STATUS_UNSPECIFIED_FAILURE);
1988 return;
1989 }
1990
Hai Shalom74f70d42019-02-11 14:42:39 -08001991 if (le_to_host16(header->u.auth.auth_alg) == WLAN_AUTH_SAE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001992 int res;
Sunil Ravi036cec52023-03-29 11:35:17 -07001993 int ie_offset = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001994
Hai Shalom74f70d42019-02-11 14:42:39 -08001995 res = sme_sae_auth(
1996 wpa_s, le_to_host16(header->u.auth.auth_transaction),
1997 le_to_host16(header->u.auth.status_code),
1998 header->u.auth.variable,
Sunil Ravi036cec52023-03-29 11:35:17 -07001999 len - auth_length, 1, header->sa, &ie_offset);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002000 if (res < 0) {
2001 /* Notify failure to the driver */
2002 sme_send_external_auth_status(
Sunil Ravia04bd252022-05-02 22:54:18 -07002003 wpa_s,
2004 res == -2 ?
2005 le_to_host16(header->u.auth.status_code) :
2006 WLAN_STATUS_UNSPECIFIED_FAILURE);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002007 return;
2008 }
2009 if (res != 1)
2010 return;
2011
Sunil Ravi036cec52023-03-29 11:35:17 -07002012 if (sme_sae_set_pmk(wpa_s,
2013 wpa_s->sme.ext_ml_auth ?
2014 wpa_s->sme.ext_auth_ap_mld_addr :
2015 wpa_s->sme.ext_auth_bssid) < 0)
Hai Shalomc3565922019-10-28 11:58:20 -07002016 return;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002017 }
2018}
2019
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002020#endif /* CONFIG_SAE */
2021
2022
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002023void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
2024{
2025 struct wpa_ssid *ssid = wpa_s->current_ssid;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002026 int ie_offset = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002027
2028 if (ssid == NULL) {
2029 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication event "
2030 "when network is not selected");
2031 return;
2032 }
2033
2034 if (wpa_s->wpa_state != WPA_AUTHENTICATING) {
2035 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication event "
2036 "when not in authenticating state");
2037 return;
2038 }
2039
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002040 if (!ether_addr_equal(wpa_s->pending_bssid, data->auth.peer) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00002041 !(wpa_s->valid_links &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002042 ether_addr_equal(wpa_s->ap_mld_addr, data->auth.peer))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002043 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication with "
2044 "unexpected peer " MACSTR,
2045 MAC2STR(data->auth.peer));
2046 return;
2047 }
2048
2049 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002050 " auth_type=%d auth_transaction=%d status_code=%d",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002051 MAC2STR(data->auth.peer), data->auth.auth_type,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002052 data->auth.auth_transaction, data->auth.status_code);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002053 wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs",
2054 data->auth.ies, data->auth.ies_len);
2055
2056 eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
2057
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002058#ifdef CONFIG_SAE
2059 if (data->auth.auth_type == WLAN_AUTH_SAE) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002060 const u8 *addr = wpa_s->pending_bssid;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002061 int res;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002062
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002063 res = sme_sae_auth(wpa_s, data->auth.auth_transaction,
2064 data->auth.status_code, data->auth.ies,
Sunil Ravi77d572f2023-01-17 23:58:31 +00002065 data->auth.ies_len, 0, data->auth.peer,
2066 &ie_offset);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002067 if (res < 0) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002068 wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
2069 NULL);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002070 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
2071
Sunil Ravi7f769292024-07-23 22:21:32 +00002072 if (wpa_s->sme.sae_rejected_groups &&
2073 ssid->disabled_until.sec) {
2074 wpa_printf(MSG_DEBUG,
2075 "SME: Clear SAE state with rejected groups due to continuous failures");
2076 wpa_s_clear_sae_rejected(wpa_s);
2077 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002078 }
2079 if (res != 1)
2080 return;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002081
Sunil Ravi77d572f2023-01-17 23:58:31 +00002082 if (wpa_s->valid_links)
2083 addr = wpa_s->ap_mld_addr;
2084
2085 if (sme_sae_set_pmk(wpa_s, addr) < 0)
Hai Shalomc3565922019-10-28 11:58:20 -07002086 return;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002087 }
2088#endif /* CONFIG_SAE */
2089
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002090 if (data->auth.status_code != WLAN_STATUS_SUCCESS) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002091 char *ie_txt = NULL;
2092
2093 if (data->auth.ies && data->auth.ies_len) {
2094 size_t buflen = 2 * data->auth.ies_len + 1;
2095 ie_txt = os_malloc(buflen);
2096 if (ie_txt) {
2097 wpa_snprintf_hex(ie_txt, buflen, data->auth.ies,
2098 data->auth.ies_len);
2099 }
2100 }
2101 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AUTH_REJECT MACSTR
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002102 " auth_type=%u auth_transaction=%u status_code=%u%s%s",
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002103 MAC2STR(data->auth.peer), data->auth.auth_type,
2104 data->auth.auth_transaction, data->auth.status_code,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002105 ie_txt ? " ie=" : "",
2106 ie_txt ? ie_txt : "");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002107 os_free(ie_txt);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002108
Hai Shalomce48b4a2018-09-05 11:41:35 -07002109#ifdef CONFIG_FILS
2110 if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS ||
2111 wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS_SK_PFS)
2112 fils_connection_failure(wpa_s);
2113#endif /* CONFIG_FILS */
2114
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002115 if (data->auth.status_code !=
2116 WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG ||
2117 wpa_s->sme.auth_alg == data->auth.auth_type ||
2118 wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002119 wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
2120 NULL);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002121 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002122 return;
2123 }
2124
Dmitry Shmidt97672262014-02-03 13:02:54 -08002125 wpas_connect_work_done(wpa_s);
2126
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002127 switch (data->auth.auth_type) {
2128 case WLAN_AUTH_OPEN:
2129 wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_SHARED;
2130
2131 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying SHARED auth");
2132 wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
2133 wpa_s->current_ssid);
2134 return;
2135
2136 case WLAN_AUTH_SHARED_KEY:
2137 wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_LEAP;
2138
2139 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying LEAP auth");
2140 wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
2141 wpa_s->current_ssid);
2142 return;
2143
2144 default:
2145 return;
2146 }
2147 }
2148
2149#ifdef CONFIG_IEEE80211R
2150 if (data->auth.auth_type == WLAN_AUTH_FT) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002151 const u8 *ric_ies = NULL;
2152 size_t ric_ies_len = 0;
2153
2154 if (wpa_s->ric_ies) {
2155 ric_ies = wpabuf_head(wpa_s->ric_ies);
2156 ric_ies_len = wpabuf_len(wpa_s->ric_ies);
2157 }
Dmitry Shmidt41712582015-06-29 11:02:15 -07002158 if (wpa_ft_process_response(wpa_s->wpa, data->auth.ies,
2159 data->auth.ies_len, 0,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002160 data->auth.peer,
2161 ric_ies, ric_ies_len) < 0) {
Dmitry Shmidt41712582015-06-29 11:02:15 -07002162 wpa_dbg(wpa_s, MSG_DEBUG,
2163 "SME: FT Authentication response processing failed");
2164 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid="
2165 MACSTR
2166 " reason=%d locally_generated=1",
2167 MAC2STR(wpa_s->pending_bssid),
2168 WLAN_REASON_DEAUTH_LEAVING);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002169 wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
2170 NULL);
Dmitry Shmidt41712582015-06-29 11:02:15 -07002171 wpa_supplicant_mark_disassoc(wpa_s);
2172 return;
2173 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002174 }
2175#endif /* CONFIG_IEEE80211R */
2176
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002177#ifdef CONFIG_FILS
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002178 if (data->auth.auth_type == WLAN_AUTH_FILS_SK ||
2179 data->auth.auth_type == WLAN_AUTH_FILS_SK_PFS) {
2180 u16 expect_auth_type;
2181
2182 expect_auth_type = wpa_s->sme.auth_alg ==
2183 WPA_AUTH_ALG_FILS_SK_PFS ? WLAN_AUTH_FILS_SK_PFS :
2184 WLAN_AUTH_FILS_SK;
2185 if (data->auth.auth_type != expect_auth_type) {
2186 wpa_dbg(wpa_s, MSG_DEBUG,
2187 "SME: FILS Authentication response used different auth alg (%u; expected %u)",
2188 data->auth.auth_type, expect_auth_type);
2189 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid="
2190 MACSTR
2191 " reason=%d locally_generated=1",
2192 MAC2STR(wpa_s->pending_bssid),
2193 WLAN_REASON_DEAUTH_LEAVING);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002194 wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
2195 NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002196 wpa_supplicant_mark_disassoc(wpa_s);
2197 return;
2198 }
2199
2200 if (fils_process_auth(wpa_s->wpa, wpa_s->pending_bssid,
2201 data->auth.ies, data->auth.ies_len) < 0) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002202 wpa_dbg(wpa_s, MSG_DEBUG,
2203 "SME: FILS Authentication response processing failed");
2204 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid="
2205 MACSTR
2206 " reason=%d locally_generated=1",
2207 MAC2STR(wpa_s->pending_bssid),
2208 WLAN_REASON_DEAUTH_LEAVING);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002209 wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
2210 NULL);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002211 wpa_supplicant_mark_disassoc(wpa_s);
2212 return;
2213 }
2214 }
2215#endif /* CONFIG_FILS */
2216
Sunil Ravi77d572f2023-01-17 23:58:31 +00002217 /* TODO: Support additional auth_type values as well */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002218 if ((data->auth.auth_type == WLAN_AUTH_OPEN ||
2219 data->auth.auth_type == WLAN_AUTH_SAE) &&
2220 wpas_sme_ml_auth(wpa_s, data, ie_offset) < 0) {
2221 wpa_dbg(wpa_s, MSG_DEBUG,
2222 "MLD: Failed to parse ML Authentication frame");
2223 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
2224 " reason=%d locally_generated=1",
2225 MAC2STR(wpa_s->pending_bssid),
2226 WLAN_REASON_DEAUTH_LEAVING);
2227 wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL);
Sunil Ravi7f769292024-07-23 22:21:32 +00002228 wpa_supplicant_deauthenticate(wpa_s,
2229 WLAN_REASON_DEAUTH_LEAVING);
2230 wpa_printf(MSG_DEBUG,
2231 "MLD: Authentication - clearing MLD state");
2232 wpas_reset_mlo_info(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002233 return;
2234 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00002235
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002236 sme_associate(wpa_s, ssid->mode, data->auth.peer,
2237 data->auth.auth_type);
2238}
2239
2240
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002241#ifdef CONFIG_IEEE80211R
2242static void remove_ie(u8 *buf, size_t *len, u8 eid)
2243{
2244 u8 *pos, *next, *end;
2245
2246 pos = (u8 *) get_ie(buf, *len, eid);
2247 if (pos) {
2248 next = pos + 2 + pos[1];
2249 end = buf + *len;
2250 *len -= 2 + pos[1];
2251 os_memmove(pos, next, end - next);
2252 }
2253}
2254#endif /* CONFIG_IEEE80211R */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002255
2256
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002257void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
2258 const u8 *bssid, u16 auth_type)
2259{
2260 struct wpa_driver_associate_params params;
2261 struct ieee802_11_elems elems;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002262 struct wpa_ssid *ssid = wpa_s->current_ssid;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002263#ifdef CONFIG_FILS
2264 u8 nonces[2 * FILS_NONCE_LEN];
2265#endif /* CONFIG_FILS */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002266#ifdef CONFIG_HT_OVERRIDES
2267 struct ieee80211_ht_capabilities htcaps;
2268 struct ieee80211_ht_capabilities htcaps_mask;
2269#endif /* CONFIG_HT_OVERRIDES */
Dmitry Shmidt2f023192013-03-12 12:44:17 -07002270#ifdef CONFIG_VHT_OVERRIDES
2271 struct ieee80211_vht_capabilities vhtcaps;
2272 struct ieee80211_vht_capabilities vhtcaps_mask;
2273#endif /* CONFIG_VHT_OVERRIDES */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002274
2275 os_memset(&params, 0, sizeof(params));
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002276
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002277 /* Save auth type, in case we need to retry after comeback timer. */
2278 wpa_s->sme.assoc_auth_type = auth_type;
2279
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002280#ifdef CONFIG_FILS
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002281 if (auth_type == WLAN_AUTH_FILS_SK ||
2282 auth_type == WLAN_AUTH_FILS_SK_PFS) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002283 struct wpabuf *buf;
2284 const u8 *snonce, *anonce;
Paul Stewart092955c2017-02-06 09:13:09 -08002285 const unsigned int max_hlp = 20;
2286 struct wpabuf *hlp[max_hlp];
2287 unsigned int i, num_hlp = 0;
2288 struct fils_hlp_req *req;
2289
2290 dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
2291 list) {
2292 hlp[num_hlp] = wpabuf_alloc(2 * ETH_ALEN + 6 +
2293 wpabuf_len(req->pkt));
2294 if (!hlp[num_hlp])
2295 break;
2296 wpabuf_put_data(hlp[num_hlp], req->dst, ETH_ALEN);
2297 wpabuf_put_data(hlp[num_hlp], wpa_s->own_addr,
2298 ETH_ALEN);
2299 wpabuf_put_data(hlp[num_hlp],
2300 "\xaa\xaa\x03\x00\x00\x00", 6);
2301 wpabuf_put_buf(hlp[num_hlp], req->pkt);
2302 num_hlp++;
2303 if (num_hlp >= max_hlp)
2304 break;
2305 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002306
2307 buf = fils_build_assoc_req(wpa_s->wpa, &params.fils_kek,
2308 &params.fils_kek_len, &snonce,
Paul Stewart092955c2017-02-06 09:13:09 -08002309 &anonce,
2310 (const struct wpabuf **) hlp,
2311 num_hlp);
2312 for (i = 0; i < num_hlp; i++)
2313 wpabuf_free(hlp[i]);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002314 if (!buf)
2315 return;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002316 wpa_hexdump(MSG_DEBUG, "FILS: assoc_req before FILS elements",
2317 wpa_s->sme.assoc_req_ie,
2318 wpa_s->sme.assoc_req_ie_len);
2319#ifdef CONFIG_IEEE80211R
2320 if (wpa_key_mgmt_ft(wpa_s->key_mgmt)) {
2321 /* Remove RSNE and MDE to allow them to be overridden
2322 * with FILS+FT specific values from
2323 * fils_build_assoc_req(). */
2324 remove_ie(wpa_s->sme.assoc_req_ie,
2325 &wpa_s->sme.assoc_req_ie_len,
2326 WLAN_EID_RSN);
2327 wpa_hexdump(MSG_DEBUG,
2328 "FILS: assoc_req after RSNE removal",
2329 wpa_s->sme.assoc_req_ie,
2330 wpa_s->sme.assoc_req_ie_len);
2331 remove_ie(wpa_s->sme.assoc_req_ie,
2332 &wpa_s->sme.assoc_req_ie_len,
2333 WLAN_EID_MOBILITY_DOMAIN);
2334 wpa_hexdump(MSG_DEBUG,
2335 "FILS: assoc_req after MDE removal",
2336 wpa_s->sme.assoc_req_ie,
2337 wpa_s->sme.assoc_req_ie_len);
2338 }
2339#endif /* CONFIG_IEEE80211R */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002340 /* TODO: Make wpa_s->sme.assoc_req_ie use dynamic allocation */
2341 if (wpa_s->sme.assoc_req_ie_len + wpabuf_len(buf) >
2342 sizeof(wpa_s->sme.assoc_req_ie)) {
2343 wpa_printf(MSG_ERROR,
2344 "FILS: Not enough buffer room for own AssocReq elements");
2345 wpabuf_free(buf);
2346 return;
2347 }
2348 os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
2349 wpabuf_head(buf), wpabuf_len(buf));
2350 wpa_s->sme.assoc_req_ie_len += wpabuf_len(buf);
2351 wpabuf_free(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002352 wpa_hexdump(MSG_DEBUG, "FILS: assoc_req after FILS elements",
2353 wpa_s->sme.assoc_req_ie,
2354 wpa_s->sme.assoc_req_ie_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002355
2356 os_memcpy(nonces, snonce, FILS_NONCE_LEN);
2357 os_memcpy(nonces + FILS_NONCE_LEN, anonce, FILS_NONCE_LEN);
2358 params.fils_nonces = nonces;
2359 params.fils_nonces_len = sizeof(nonces);
2360 }
2361#endif /* CONFIG_FILS */
2362
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002363#ifdef CONFIG_OWE
2364#ifdef CONFIG_TESTING_OPTIONS
2365 if (get_ie_ext(wpa_s->sme.assoc_req_ie, wpa_s->sme.assoc_req_ie_len,
2366 WLAN_EID_EXT_OWE_DH_PARAM)) {
2367 wpa_printf(MSG_INFO, "TESTING: Override OWE DH element");
2368 } else
2369#endif /* CONFIG_TESTING_OPTIONS */
2370 if (auth_type == WLAN_AUTH_OPEN &&
2371 wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) {
2372 struct wpabuf *owe_ie;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002373 u16 group;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002374
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002375 if (ssid && ssid->owe_group) {
2376 group = ssid->owe_group;
Hai Shalom74f70d42019-02-11 14:42:39 -08002377 } else if (wpa_s->assoc_status_code ==
2378 WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002379 if (wpa_s->last_owe_group == 19)
2380 group = 20;
2381 else if (wpa_s->last_owe_group == 20)
2382 group = 21;
2383 else
2384 group = OWE_DH_GROUP;
Hai Shalom74f70d42019-02-11 14:42:39 -08002385 } else {
2386 group = OWE_DH_GROUP;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002387 }
Hai Shalom74f70d42019-02-11 14:42:39 -08002388
Roshan Pius3a1667e2018-07-03 15:17:14 -07002389 wpa_s->last_owe_group = group;
2390 wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002391 owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
2392 if (!owe_ie) {
2393 wpa_printf(MSG_ERROR,
2394 "OWE: Failed to build IE for Association Request frame");
2395 return;
2396 }
2397 if (wpa_s->sme.assoc_req_ie_len + wpabuf_len(owe_ie) >
2398 sizeof(wpa_s->sme.assoc_req_ie)) {
2399 wpa_printf(MSG_ERROR,
2400 "OWE: Not enough buffer room for own Association Request frame elements");
2401 wpabuf_free(owe_ie);
2402 return;
2403 }
2404 os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
2405 wpabuf_head(owe_ie), wpabuf_len(owe_ie));
2406 wpa_s->sme.assoc_req_ie_len += wpabuf_len(owe_ie);
2407 wpabuf_free(owe_ie);
2408 }
2409#endif /* CONFIG_OWE */
2410
Hai Shalom021b0b52019-04-10 11:17:58 -07002411#ifdef CONFIG_DPP2
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002412 if (DPP_VERSION > 1 && wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && ssid &&
2413 ssid->dpp_netaccesskey && ssid->dpp_pfs != 2 &&
2414 !ssid->dpp_pfs_fallback) {
2415 struct rsn_pmksa_cache_entry *pmksa;
2416
2417 pmksa = pmksa_cache_get_current(wpa_s->wpa);
2418 if (!pmksa || !pmksa->dpp_pfs)
2419 goto pfs_fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07002420
2421 dpp_pfs_free(wpa_s->dpp_pfs);
2422 wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
2423 ssid->dpp_netaccesskey_len);
2424 if (!wpa_s->dpp_pfs) {
2425 wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS");
2426 /* Try to continue without PFS */
2427 goto pfs_fail;
2428 }
2429 if (wpa_s->sme.assoc_req_ie_len +
2430 wpabuf_len(wpa_s->dpp_pfs->ie) >
2431 sizeof(wpa_s->sme.assoc_req_ie)) {
2432 wpa_printf(MSG_ERROR,
2433 "DPP: Not enough buffer room for own Association Request frame elements");
2434 dpp_pfs_free(wpa_s->dpp_pfs);
2435 wpa_s->dpp_pfs = NULL;
2436 goto pfs_fail;
2437 }
2438 os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
2439 wpabuf_head(wpa_s->dpp_pfs->ie),
2440 wpabuf_len(wpa_s->dpp_pfs->ie));
2441 wpa_s->sme.assoc_req_ie_len += wpabuf_len(wpa_s->dpp_pfs->ie);
2442 }
2443pfs_fail:
2444#endif /* CONFIG_DPP2 */
2445
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002446#ifndef CONFIG_NO_ROBUST_AV
Hai Shalom899fcc72020-10-19 14:38:18 -07002447 wpa_s->mscs_setup_done = false;
Hai Shalom60840252021-02-19 19:02:11 -08002448 if (wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_MSCS) &&
2449 wpa_s->robust_av.valid_config) {
Hai Shalom899fcc72020-10-19 14:38:18 -07002450 struct wpabuf *mscs_ie;
2451 size_t mscs_ie_len, buf_len, *wpa_ie_len, max_ie_len;
2452
Hai Shalom899fcc72020-10-19 14:38:18 -07002453 buf_len = 3 + /* MSCS descriptor IE header */
2454 1 + /* Request type */
2455 2 + /* User priority control */
2456 4 + /* Stream timeout */
2457 3 + /* TCLAS Mask IE header */
2458 wpa_s->robust_av.frame_classifier_len;
2459 mscs_ie = wpabuf_alloc(buf_len);
2460 if (!mscs_ie) {
2461 wpa_printf(MSG_INFO,
2462 "MSCS: Failed to allocate MSCS IE");
2463 goto mscs_fail;
2464 }
2465
2466 wpa_ie_len = &wpa_s->sme.assoc_req_ie_len;
2467 max_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
2468 wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
2469 if ((*wpa_ie_len + wpabuf_len(mscs_ie)) <= max_ie_len) {
2470 wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE", mscs_ie);
2471 mscs_ie_len = wpabuf_len(mscs_ie);
2472 os_memcpy(wpa_s->sme.assoc_req_ie + *wpa_ie_len,
2473 wpabuf_head(mscs_ie), mscs_ie_len);
2474 *wpa_ie_len += mscs_ie_len;
2475 }
2476
2477 wpabuf_free(mscs_ie);
2478 }
2479mscs_fail:
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002480#endif /* CONFIG_NO_ROBUST_AV */
Hai Shalom899fcc72020-10-19 14:38:18 -07002481
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002482 wpa_s->sme.assoc_req_ie_len =
2483 wpas_populate_wfa_capa(wpa_s, wpa_s->current_bss,
2484 wpa_s->sme.assoc_req_ie,
2485 wpa_s->sme.assoc_req_ie_len,
2486 sizeof(wpa_s->sme.assoc_req_ie));
2487
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002488 if (ssid && ssid->multi_ap_backhaul_sta) {
Hai Shalom74f70d42019-02-11 14:42:39 -08002489 size_t multi_ap_ie_len;
Sunil Ravi99c035e2024-07-12 01:42:03 +00002490 struct multi_ap_params multi_ap = { 0 };
2491
2492 multi_ap.capability = MULTI_AP_BACKHAUL_STA;
2493 multi_ap.profile = ssid->multi_ap_profile;
Hai Shalom74f70d42019-02-11 14:42:39 -08002494
2495 multi_ap_ie_len = add_multi_ap_ie(
2496 wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
2497 sizeof(wpa_s->sme.assoc_req_ie) -
2498 wpa_s->sme.assoc_req_ie_len,
Sunil Ravi99c035e2024-07-12 01:42:03 +00002499 &multi_ap);
Hai Shalom74f70d42019-02-11 14:42:39 -08002500 if (multi_ap_ie_len == 0) {
2501 wpa_printf(MSG_ERROR,
2502 "Multi-AP: Failed to build Multi-AP IE");
2503 return;
2504 }
2505 wpa_s->sme.assoc_req_ie_len += multi_ap_ie_len;
2506 }
2507
Sunil Ravic0f5d412024-09-11 22:12:49 +00002508 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE_SUPPORT,
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002509 wpas_rsn_overriding(wpa_s, ssid));
Sunil Ravic0f5d412024-09-11 22:12:49 +00002510 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
2511 RSN_OVERRIDE_NOT_USED);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002512 if (wpas_rsn_overriding(wpa_s, ssid) &&
Sunil Ravi7f769292024-07-23 22:21:32 +00002513 wpas_ap_supports_rsn_overriding(wpa_s, wpa_s->current_bss) &&
2514 wpa_s->sme.assoc_req_ie_len + 2 + 4 <=
2515 sizeof(wpa_s->sme.assoc_req_ie)) {
2516 u8 *pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
Sunil Ravi7f769292024-07-23 22:21:32 +00002517 const u8 *ie;
Sunil Ravic0f5d412024-09-11 22:12:49 +00002518 enum rsn_selection_variant variant = RSN_SELECTION_RSNE;
Sunil Ravi7f769292024-07-23 22:21:32 +00002519
Sunil Ravic0f5d412024-09-11 22:12:49 +00002520 wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
2521 RSN_OVERRIDE_RSNE);
Sunil Ravi7f769292024-07-23 22:21:32 +00002522 ie = wpa_bss_get_rsne(wpa_s, wpa_s->current_bss, ssid,
2523 wpa_s->valid_links);
Sunil Ravic0f5d412024-09-11 22:12:49 +00002524 if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4) {
2525 u32 type;
Sunil Ravi7f769292024-07-23 22:21:32 +00002526
Sunil Ravic0f5d412024-09-11 22:12:49 +00002527 type = WPA_GET_BE32(&ie[2]);
2528 if (type == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
2529 variant = RSN_SELECTION_RSNE_OVERRIDE;
2530 wpa_sm_set_param(wpa_s->wpa,
2531 WPA_PARAM_RSN_OVERRIDE,
2532 RSN_OVERRIDE_RSNE_OVERRIDE);
2533 } else if (type == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
2534 variant = RSN_SELECTION_RSNE_OVERRIDE_2;
2535 wpa_sm_set_param(wpa_s->wpa,
2536 WPA_PARAM_RSN_OVERRIDE,
2537 RSN_OVERRIDE_RSNE_OVERRIDE_2);
2538 }
Sunil Ravi7f769292024-07-23 22:21:32 +00002539 }
Sunil Ravic0f5d412024-09-11 22:12:49 +00002540
2541 /* Indicate which RSNE variant was used */
2542 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
2543 *pos++ = 4 + 1;
2544 WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
2545 pos += 4;
2546 *pos = variant;
2547 wpa_s->sme.assoc_req_ie_len += 2 + 4 + 1;
Sunil Ravi7f769292024-07-23 22:21:32 +00002548 }
2549
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002550 params.bssid = bssid;
2551 params.ssid = wpa_s->sme.ssid;
2552 params.ssid_len = wpa_s->sme.ssid_len;
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07002553 params.freq.freq = wpa_s->sme.freq;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002554 params.bg_scan_period = ssid ? ssid->bg_scan_period : -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002555 params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
2556 wpa_s->sme.assoc_req_ie : NULL;
2557 params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
Hai Shalom74f70d42019-02-11 14:42:39 -08002558 wpa_hexdump(MSG_DEBUG, "SME: Association Request IEs",
2559 params.wpa_ie, params.wpa_ie_len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002560 params.pairwise_suite = wpa_s->pairwise_cipher;
2561 params.group_suite = wpa_s->group_cipher;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002562 params.mgmt_group_suite = wpa_s->mgmt_group_cipher;
Dmitry Shmidt15907092014-03-25 10:42:57 -07002563 params.key_mgmt_suite = wpa_s->key_mgmt;
2564 params.wpa_proto = wpa_s->wpa_proto;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002565#ifdef CONFIG_HT_OVERRIDES
2566 os_memset(&htcaps, 0, sizeof(htcaps));
2567 os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
2568 params.htcaps = (u8 *) &htcaps;
2569 params.htcaps_mask = (u8 *) &htcaps_mask;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002570 wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002571#endif /* CONFIG_HT_OVERRIDES */
Dmitry Shmidt2f023192013-03-12 12:44:17 -07002572#ifdef CONFIG_VHT_OVERRIDES
2573 os_memset(&vhtcaps, 0, sizeof(vhtcaps));
2574 os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
2575 params.vhtcaps = &vhtcaps;
2576 params.vhtcaps_mask = &vhtcaps_mask;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002577 wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
Dmitry Shmidt2f023192013-03-12 12:44:17 -07002578#endif /* CONFIG_VHT_OVERRIDES */
Hai Shalomfdcde762020-04-02 11:19:20 -07002579#ifdef CONFIG_HE_OVERRIDES
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002580 wpa_supplicant_apply_he_overrides(wpa_s, ssid, &params);
Hai Shalomfdcde762020-04-02 11:19:20 -07002581#endif /* CONFIG_HE_OVERRIDES */
Sunil Ravi77d572f2023-01-17 23:58:31 +00002582 wpa_supplicant_apply_eht_overrides(wpa_s, ssid, &params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002583#ifdef CONFIG_IEEE80211R
Hai Shalom74f70d42019-02-11 14:42:39 -08002584 if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies &&
2585 get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len,
2586 WLAN_EID_RIC_DATA)) {
2587 /* There seems to be a pretty inconvenient bug in the Linux
2588 * kernel IE splitting functionality when RIC is used. For now,
2589 * skip correct behavior in IE construction here (i.e., drop the
2590 * additional non-FT-specific IEs) to avoid kernel issues. This
2591 * is fine since RIC is used only for testing purposes in the
2592 * current implementation. */
2593 wpa_printf(MSG_INFO,
2594 "SME: Linux kernel workaround - do not try to include additional IEs with RIC");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002595 params.wpa_ie = wpa_s->sme.ft_ies;
2596 params.wpa_ie_len = wpa_s->sme.ft_ies_len;
Hai Shalom74f70d42019-02-11 14:42:39 -08002597 } else if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
2598 const u8 *rm_en, *pos, *end;
2599 size_t rm_en_len = 0;
2600 u8 *rm_en_dup = NULL, *wpos;
2601
2602 /* Remove RSNE, MDE, FTE to allow them to be overridden with
2603 * FT specific values */
2604 remove_ie(wpa_s->sme.assoc_req_ie,
2605 &wpa_s->sme.assoc_req_ie_len,
2606 WLAN_EID_RSN);
2607 remove_ie(wpa_s->sme.assoc_req_ie,
2608 &wpa_s->sme.assoc_req_ie_len,
2609 WLAN_EID_MOBILITY_DOMAIN);
2610 remove_ie(wpa_s->sme.assoc_req_ie,
2611 &wpa_s->sme.assoc_req_ie_len,
2612 WLAN_EID_FAST_BSS_TRANSITION);
2613 rm_en = get_ie(wpa_s->sme.assoc_req_ie,
2614 wpa_s->sme.assoc_req_ie_len,
2615 WLAN_EID_RRM_ENABLED_CAPABILITIES);
2616 if (rm_en) {
2617 /* Need to remove RM Enabled Capabilities element as
2618 * well temporarily, so that it can be placed between
2619 * RSNE and MDE. */
2620 rm_en_len = 2 + rm_en[1];
2621 rm_en_dup = os_memdup(rm_en, rm_en_len);
2622 remove_ie(wpa_s->sme.assoc_req_ie,
2623 &wpa_s->sme.assoc_req_ie_len,
2624 WLAN_EID_RRM_ENABLED_CAPABILITIES);
2625 }
2626 wpa_hexdump(MSG_DEBUG,
2627 "SME: Association Request IEs after FT IE removal",
2628 wpa_s->sme.assoc_req_ie,
2629 wpa_s->sme.assoc_req_ie_len);
2630 if (wpa_s->sme.assoc_req_ie_len + wpa_s->sme.ft_ies_len +
2631 rm_en_len > sizeof(wpa_s->sme.assoc_req_ie)) {
2632 wpa_printf(MSG_ERROR,
2633 "SME: Not enough buffer room for FT IEs in Association Request frame");
2634 os_free(rm_en_dup);
2635 return;
2636 }
2637
2638 os_memmove(wpa_s->sme.assoc_req_ie + wpa_s->sme.ft_ies_len +
2639 rm_en_len,
2640 wpa_s->sme.assoc_req_ie,
2641 wpa_s->sme.assoc_req_ie_len);
2642 pos = wpa_s->sme.ft_ies;
2643 end = pos + wpa_s->sme.ft_ies_len;
2644 wpos = wpa_s->sme.assoc_req_ie;
2645 if (*pos == WLAN_EID_RSN) {
2646 os_memcpy(wpos, pos, 2 + pos[1]);
2647 wpos += 2 + pos[1];
2648 pos += 2 + pos[1];
2649 }
2650 if (rm_en_dup) {
2651 os_memcpy(wpos, rm_en_dup, rm_en_len);
2652 wpos += rm_en_len;
2653 os_free(rm_en_dup);
2654 }
2655 os_memcpy(wpos, pos, end - pos);
2656 wpa_s->sme.assoc_req_ie_len += wpa_s->sme.ft_ies_len +
2657 rm_en_len;
2658 params.wpa_ie = wpa_s->sme.assoc_req_ie;
2659 params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
2660 wpa_hexdump(MSG_DEBUG,
2661 "SME: Association Request IEs after FT override",
2662 params.wpa_ie, params.wpa_ie_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002663 }
2664#endif /* CONFIG_IEEE80211R */
2665 params.mode = mode;
2666 params.mgmt_frame_protection = wpa_s->sme.mfp;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002667 params.rrm_used = wpa_s->rrm.rrm_used;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002668 if (wpa_s->sme.prev_bssid_set)
2669 params.prev_bssid = wpa_s->sme.prev_bssid;
2670
2671 wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
2672 " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
2673 params.ssid ? wpa_ssid_txt(params.ssid, params.ssid_len) : "",
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07002674 params.freq.freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002675
2676 wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
2677
2678 if (params.wpa_ie == NULL ||
2679 ieee802_11_parse_elems(params.wpa_ie, params.wpa_ie_len, &elems, 0)
2680 < 0) {
2681 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Could not parse own IEs?!");
2682 os_memset(&elems, 0, sizeof(elems));
2683 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002684 if (elems.rsn_ie) {
2685 params.wpa_proto = WPA_PROTO_RSN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002686 wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.rsn_ie - 2,
2687 elems.rsn_ie_len + 2);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002688 } else if (elems.wpa_ie) {
2689 params.wpa_proto = WPA_PROTO_WPA;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002690 wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2,
2691 elems.wpa_ie_len + 2);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002692 } else if (elems.osen) {
2693 params.wpa_proto = WPA_PROTO_OSEN;
2694 wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.osen - 2,
2695 elems.osen_len + 2);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002696 } else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002697 wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
Hai Shalomc3565922019-10-28 11:58:20 -07002698 if (elems.rsnxe)
2699 wpa_sm_set_assoc_rsnxe(wpa_s->wpa, elems.rsnxe - 2,
2700 elems.rsnxe_len + 2);
2701 else
2702 wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002703 if (ssid && ssid->p2p_group)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002704 params.p2p = 1;
2705
Dmitry Shmidt9c175262016-03-03 10:20:07 -08002706 if (wpa_s->p2pdev->set_sta_uapsd)
2707 params.uapsd = wpa_s->p2pdev->sta_uapsd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002708 else
2709 params.uapsd = -1;
2710
Sunil Ravi77d572f2023-01-17 23:58:31 +00002711 if (wpa_s->valid_links) {
2712 unsigned int i;
2713
2714 wpa_printf(MSG_DEBUG,
2715 "MLD: In association. assoc_link_id=%u, valid_links=0x%x",
2716 wpa_s->mlo_assoc_link_id, wpa_s->valid_links);
2717
2718 params.mld_params.mld_addr = wpa_s->ap_mld_addr;
2719 params.mld_params.valid_links = wpa_s->valid_links;
2720 params.mld_params.assoc_link_id = wpa_s->mlo_assoc_link_id;
Sunil Ravi99c035e2024-07-12 01:42:03 +00002721 for_each_link(wpa_s->valid_links, i) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002722 params.mld_params.mld_links[i].bssid =
2723 wpa_s->links[i].bssid;
2724 params.mld_params.mld_links[i].freq =
2725 wpa_s->links[i].freq;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002726 params.mld_params.mld_links[i].disabled =
2727 wpa_s->links[i].disabled;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002728
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002729 wpa_printf(MSG_DEBUG,
2730 "MLD: id=%u, freq=%d, disabled=%u, " MACSTR,
Sunil Ravi77d572f2023-01-17 23:58:31 +00002731 i, wpa_s->links[i].freq,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002732 wpa_s->links[i].disabled,
Sunil Ravi77d572f2023-01-17 23:58:31 +00002733 MAC2STR(wpa_s->links[i].bssid));
2734 }
2735 }
2736
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002737 if (wpa_drv_associate(wpa_s, &params) < 0) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002738 unsigned int n_failed_links = 0;
2739 int i;
2740
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002741 wpa_msg(wpa_s, MSG_INFO, "SME: Association request to the "
2742 "driver failed");
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002743
2744 /* Prepare list of failed links for error report */
2745 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
2746 if (!(wpa_s->valid_links & BIT(i)) ||
2747 wpa_s->mlo_assoc_link_id == i ||
2748 !params.mld_params.mld_links[i].error)
2749 continue;
2750
2751 wpa_bssid_ignore_add(wpa_s, wpa_s->links[i].bssid);
2752 n_failed_links++;
2753 }
2754
2755 if (n_failed_links) {
2756 /* Deauth and connect (possibly to the same AP MLD) */
2757 wpa_drv_deauthenticate(wpa_s, wpa_s->ap_mld_addr,
2758 WLAN_REASON_DEAUTH_LEAVING);
2759 wpas_connect_work_done(wpa_s);
2760 wpa_supplicant_mark_disassoc(wpa_s);
2761 wpas_request_connection(wpa_s);
2762 } else {
2763 wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
2764 NULL);
2765 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
2766 os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
2767 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002768 return;
2769 }
2770
2771 eloop_register_timeout(SME_ASSOC_TIMEOUT, 0, sme_assoc_timer, wpa_s,
2772 NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002773
2774#ifdef CONFIG_TESTING_OPTIONS
2775 wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
2776 wpa_s->last_assoc_req_wpa_ie = NULL;
2777 if (params.wpa_ie)
2778 wpa_s->last_assoc_req_wpa_ie =
2779 wpabuf_alloc_copy(params.wpa_ie, params.wpa_ie_len);
2780#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002781}
2782
2783
2784int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
2785 const u8 *ies, size_t ies_len)
2786{
2787 if (md == NULL || ies == NULL) {
2788 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Remove mobility domain");
2789 os_free(wpa_s->sme.ft_ies);
2790 wpa_s->sme.ft_ies = NULL;
2791 wpa_s->sme.ft_ies_len = 0;
2792 wpa_s->sme.ft_used = 0;
2793 return 0;
2794 }
2795
2796 os_memcpy(wpa_s->sme.mobility_domain, md, MOBILITY_DOMAIN_ID_LEN);
2797 wpa_hexdump(MSG_DEBUG, "SME: FT IEs", ies, ies_len);
2798 os_free(wpa_s->sme.ft_ies);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002799 wpa_s->sme.ft_ies = os_memdup(ies, ies_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002800 if (wpa_s->sme.ft_ies == NULL)
2801 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002802 wpa_s->sme.ft_ies_len = ies_len;
2803 return 0;
2804}
2805
2806
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002807static void sme_deauth(struct wpa_supplicant *wpa_s, const u8 **link_bssids)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002808{
2809 int bssid_changed;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002810 const u8 *bssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002811
2812 bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
2813
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002814 if (wpa_s->valid_links)
2815 bssid = wpa_s->ap_mld_addr;
2816 else
2817 bssid = wpa_s->pending_bssid;
2818
2819 if (wpa_drv_deauthenticate(wpa_s, bssid,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002820 WLAN_REASON_DEAUTH_LEAVING) < 0) {
2821 wpa_msg(wpa_s, MSG_INFO, "SME: Deauth request to the driver "
2822 "failed");
2823 }
2824 wpa_s->sme.prev_bssid_set = 0;
2825
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002826 wpas_connection_failed(wpa_s, wpa_s->pending_bssid, link_bssids);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002827 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
2828 os_memset(wpa_s->bssid, 0, ETH_ALEN);
2829 os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
2830 if (bssid_changed)
2831 wpas_notify_bssid_changed(wpa_s);
2832}
2833
2834
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002835static void sme_assoc_comeback_timer(void *eloop_ctx, void *timeout_ctx)
Sunil Ravi72e01222024-03-09 01:25:43 +00002836{
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002837 struct wpa_supplicant *wpa_s = eloop_ctx;
2838
2839 if (!wpa_s->current_bss || !wpa_s->current_ssid) {
2840 wpa_msg(wpa_s, MSG_DEBUG,
2841 "SME: Comeback timeout expired; SSID/BSSID cleared; ignoring");
2842 return;
2843 }
2844
2845 wpa_msg(wpa_s, MSG_DEBUG,
2846 "SME: Comeback timeout expired; retry associating with "
2847 MACSTR "; mode=%d auth_type=%u",
2848 MAC2STR(wpa_s->current_bss->bssid),
2849 wpa_s->current_ssid->mode,
2850 wpa_s->sme.assoc_auth_type);
2851
2852 /* Authentication state was completed already; just try association
2853 * again. */
2854 sme_associate(wpa_s, wpa_s->current_ssid->mode,
2855 wpa_s->current_bss->bssid,
2856 wpa_s->sme.assoc_auth_type);
2857}
2858
2859
2860static bool sme_try_assoc_comeback(struct wpa_supplicant *wpa_s,
2861 union wpa_event_data *data)
2862{
2863 struct ieee802_11_elems elems;
2864 u32 timeout_interval;
2865 unsigned long comeback_usec;
2866 u8 type = WLAN_TIMEOUT_ASSOC_COMEBACK;
2867
2868#ifdef CONFIG_TESTING_OPTIONS
2869 if (wpa_s->test_assoc_comeback_type != -1)
2870 type = wpa_s->test_assoc_comeback_type;
2871#endif /* CONFIG_TESTING_OPTIONS */
2872
2873 if (ieee802_11_parse_elems(data->assoc_reject.resp_ies,
2874 data->assoc_reject.resp_ies_len,
2875 &elems, 0) == ParseFailed) {
2876 wpa_msg(wpa_s, MSG_INFO,
2877 "SME: Temporary assoc reject: failed to parse (Re)Association Response frame elements");
2878 return false;
2879 }
2880
2881 if (!elems.timeout_int) {
2882 wpa_msg(wpa_s, MSG_INFO,
2883 "SME: Temporary assoc reject: missing timeout interval IE");
2884 return false;
2885 }
2886
2887 if (elems.timeout_int[0] != type) {
2888 wpa_msg(wpa_s, MSG_INFO,
2889 "SME: Temporary assoc reject: missing association comeback time");
2890 return false;
2891 }
2892
2893 timeout_interval = WPA_GET_LE32(&elems.timeout_int[1]);
2894 if (timeout_interval > 60000) {
2895 /* This is unprotected information and there is no point in
2896 * getting stuck waiting for very long duration based on it */
2897 wpa_msg(wpa_s, MSG_DEBUG,
2898 "SME: Ignore overly long association comeback interval: %u TUs",
2899 timeout_interval);
2900 return false;
2901 }
2902 wpa_msg(wpa_s, MSG_DEBUG, "SME: Association comeback interval: %u TUs",
2903 timeout_interval);
2904
2905 comeback_usec = timeout_interval * 1024;
2906 eloop_register_timeout(comeback_usec / 1000000, comeback_usec % 1000000,
2907 sme_assoc_comeback_timer, wpa_s, NULL);
2908 return true;
2909}
2910
2911
2912void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
2913 union wpa_event_data *data,
2914 const u8 **link_bssids)
2915{
2916 const u8 *bssid;
2917
2918 if (wpa_s->valid_links)
2919 bssid = wpa_s->ap_mld_addr;
2920 else
2921 bssid = wpa_s->pending_bssid;
2922
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002923 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association with " MACSTR " failed: "
2924 "status code %d", MAC2STR(wpa_s->pending_bssid),
2925 data->assoc_reject.status_code);
2926
2927 eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002928 eloop_cancel_timeout(sme_assoc_comeback_timer, wpa_s, NULL);
2929
2930 /* Authentication phase has been completed at this point. Check whether
2931 * the AP rejected association temporarily due to still holding a
2932 * security associationis with us (MFP). If so, we must wait for the
2933 * AP's association comeback timeout period before associating again. */
2934 if (data->assoc_reject.status_code ==
2935 WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
2936 wpa_msg(wpa_s, MSG_DEBUG,
2937 "SME: Temporary association reject from BSS " MACSTR,
2938 MAC2STR(bssid));
2939 if (sme_try_assoc_comeback(wpa_s, data)) {
2940 /* Break out early; comeback error is not a failure. */
2941 return;
2942 }
2943 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002944
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002945#ifdef CONFIG_SAE
2946 if (wpa_s->sme.sae_pmksa_caching && wpa_s->current_ssid &&
2947 wpa_key_mgmt_sae(wpa_s->current_ssid->key_mgmt)) {
2948 wpa_dbg(wpa_s, MSG_DEBUG,
2949 "PMKSA caching attempt rejected - drop PMKSA cache entry and fall back to SAE authentication");
2950 wpa_sm_aborted_cached(wpa_s->wpa);
2951 wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
2952 if (wpa_s->current_bss) {
2953 struct wpa_bss *bss = wpa_s->current_bss;
2954 struct wpa_ssid *ssid = wpa_s->current_ssid;
2955
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002956 wpa_drv_deauthenticate(wpa_s, bssid,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002957 WLAN_REASON_DEAUTH_LEAVING);
2958 wpas_connect_work_done(wpa_s);
2959 wpa_supplicant_mark_disassoc(wpa_s);
2960 wpa_supplicant_connect(wpa_s, bss, ssid);
2961 return;
2962 }
2963 }
2964#endif /* CONFIG_SAE */
2965
Sunil Ravi77d572f2023-01-17 23:58:31 +00002966#ifdef CONFIG_DPP
2967 if (wpa_s->current_ssid &&
2968 wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
2969 !data->assoc_reject.timed_out &&
2970 data->assoc_reject.status_code == WLAN_STATUS_INVALID_PMKID) {
2971 struct rsn_pmksa_cache_entry *pmksa;
2972
2973 pmksa = pmksa_cache_get_current(wpa_s->wpa);
2974 if (pmksa) {
2975 wpa_dbg(wpa_s, MSG_DEBUG,
2976 "DPP: Drop PMKSA cache entry for the BSS due to invalid PMKID report");
2977 wpa_sm_pmksa_cache_remove(wpa_s->wpa, pmksa);
2978 }
2979 wpa_sm_aborted_cached(wpa_s->wpa);
2980 if (wpa_s->current_bss) {
2981 struct wpa_bss *bss = wpa_s->current_bss;
2982 struct wpa_ssid *ssid = wpa_s->current_ssid;
2983
2984 wpa_dbg(wpa_s, MSG_DEBUG,
2985 "DPP: Try network introduction again");
2986 wpas_connect_work_done(wpa_s);
2987 wpa_supplicant_mark_disassoc(wpa_s);
2988 wpa_supplicant_connect(wpa_s, bss, ssid);
2989 return;
2990 }
2991 }
2992#endif /* CONFIG_DPP */
2993
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002994 /*
2995 * For now, unconditionally terminate the previous authentication. In
2996 * theory, this should not be needed, but mac80211 gets quite confused
2997 * if the authentication is left pending.. Some roaming cases might
2998 * benefit from using the previous authentication, so this could be
2999 * optimized in the future.
3000 */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003001 sme_deauth(wpa_s, link_bssids);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003002}
3003
3004
3005void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
3006 union wpa_event_data *data)
3007{
3008 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication timed out");
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003009 wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003010 wpa_supplicant_mark_disassoc(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003011}
3012
3013
3014void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
3015 union wpa_event_data *data)
3016{
3017 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association timed out");
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003018 wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003019 wpa_supplicant_mark_disassoc(wpa_s);
3020}
3021
3022
3023void sme_event_disassoc(struct wpa_supplicant *wpa_s,
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003024 struct disassoc_info *info)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003025{
3026 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Disassociation event received");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003027 if (wpa_s->sme.prev_bssid_set) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003028 /*
3029 * cfg80211/mac80211 can get into somewhat confused state if
3030 * the AP only disassociates us and leaves us in authenticated
3031 * state. For now, force the state to be cleared to avoid
3032 * confusing errors if we try to associate with the AP again.
3033 */
3034 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Deauthenticate to clear "
3035 "driver state");
3036 wpa_drv_deauthenticate(wpa_s, wpa_s->sme.prev_bssid,
3037 WLAN_REASON_DEAUTH_LEAVING);
3038 }
3039}
3040
3041
3042static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx)
3043{
3044 struct wpa_supplicant *wpa_s = eloop_ctx;
3045 if (wpa_s->wpa_state == WPA_AUTHENTICATING) {
3046 wpa_msg(wpa_s, MSG_DEBUG, "SME: Authentication timeout");
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003047 sme_deauth(wpa_s, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003048 }
3049}
3050
3051
3052static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx)
3053{
3054 struct wpa_supplicant *wpa_s = eloop_ctx;
3055 if (wpa_s->wpa_state == WPA_ASSOCIATING) {
3056 wpa_msg(wpa_s, MSG_DEBUG, "SME: Association timeout");
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003057 sme_deauth(wpa_s, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003058 }
3059}
3060
3061
3062void sme_state_changed(struct wpa_supplicant *wpa_s)
3063{
3064 /* Make sure timers are cleaned up appropriately. */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003065 if (wpa_s->wpa_state != WPA_ASSOCIATING) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003066 eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003067 eloop_cancel_timeout(sme_assoc_comeback_timer, wpa_s, NULL);
3068 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003069 if (wpa_s->wpa_state != WPA_AUTHENTICATING)
3070 eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
3071}
3072
3073
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003074void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s)
3075{
3076 wpa_s->sme.prev_bssid_set = 0;
3077#ifdef CONFIG_SAE
3078 wpabuf_free(wpa_s->sme.sae_token);
3079 wpa_s->sme.sae_token = NULL;
3080 sae_clear_data(&wpa_s->sme.sae);
3081#endif /* CONFIG_SAE */
3082#ifdef CONFIG_IEEE80211R
Roshan Pius3a1667e2018-07-03 15:17:14 -07003083 if (wpa_s->sme.ft_ies || wpa_s->sme.ft_used)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003084 sme_update_ft_ies(wpa_s, NULL, NULL, 0);
3085#endif /* CONFIG_IEEE80211R */
Hai Shalom5f92bc92019-04-18 11:54:11 -07003086 sme_stop_sa_query(wpa_s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003087}
3088
3089
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003090void sme_deinit(struct wpa_supplicant *wpa_s)
3091{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003092 sme_clear_on_disassoc(wpa_s);
Hai Shalomc3565922019-10-28 11:58:20 -07003093#ifdef CONFIG_SAE
3094 os_free(wpa_s->sme.sae_rejected_groups);
3095 wpa_s->sme.sae_rejected_groups = NULL;
3096#endif /* CONFIG_SAE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003097
3098 eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
3099 eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003100 eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003101 eloop_cancel_timeout(sme_assoc_comeback_timer, wpa_s, NULL);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003102}
3103
3104
3105static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
3106 const u8 *chan_list, u8 num_channels,
3107 u8 num_intol)
3108{
3109 struct ieee80211_2040_bss_coex_ie *bc_ie;
3110 struct ieee80211_2040_intol_chan_report *ic_report;
3111 struct wpabuf *buf;
3112
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07003113 wpa_printf(MSG_DEBUG, "SME: Send 20/40 BSS Coexistence to " MACSTR
3114 " (num_channels=%u num_intol=%u)",
3115 MAC2STR(wpa_s->bssid), num_channels, num_intol);
3116 wpa_hexdump(MSG_DEBUG, "SME: 20/40 BSS Intolerant Channels",
3117 chan_list, num_channels);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003118
3119 buf = wpabuf_alloc(2 + /* action.category + action_code */
3120 sizeof(struct ieee80211_2040_bss_coex_ie) +
3121 sizeof(struct ieee80211_2040_intol_chan_report) +
3122 num_channels);
3123 if (buf == NULL)
3124 return;
3125
3126 wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
3127 wpabuf_put_u8(buf, WLAN_PA_20_40_BSS_COEX);
3128
3129 bc_ie = wpabuf_put(buf, sizeof(*bc_ie));
3130 bc_ie->element_id = WLAN_EID_20_40_BSS_COEXISTENCE;
3131 bc_ie->length = 1;
3132 if (num_intol)
3133 bc_ie->coex_param |= WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ;
3134
3135 if (num_channels > 0) {
3136 ic_report = wpabuf_put(buf, sizeof(*ic_report));
3137 ic_report->element_id = WLAN_EID_20_40_BSS_INTOLERANT;
3138 ic_report->length = num_channels + 1;
3139 ic_report->op_class = 0;
3140 os_memcpy(wpabuf_put(buf, num_channels), chan_list,
3141 num_channels);
3142 }
3143
3144 if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
3145 wpa_s->own_addr, wpa_s->bssid,
3146 wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
3147 wpa_msg(wpa_s, MSG_INFO,
3148 "SME: Failed to send 20/40 BSS Coexistence frame");
3149 }
3150
3151 wpabuf_free(buf);
3152}
3153
3154
Hai Shaloma20dcd72022-02-04 13:43:00 -08003155int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
Dmitry Shmidt04949592012-07-19 12:16:46 -07003156{
Hai Shaloma20dcd72022-02-04 13:43:00 -08003157 struct wpa_bss *bss;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003158 const u8 *ie;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003159 u16 ht_cap;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003160 u8 chan_list[P2P_MAX_CHANNELS], channel;
3161 u8 num_channels = 0, num_intol = 0, i;
3162
3163 if (!wpa_s->sme.sched_obss_scan)
3164 return 0;
3165
3166 wpa_s->sme.sched_obss_scan = 0;
3167 if (!wpa_s->current_bss || wpa_s->wpa_state != WPA_COMPLETED)
3168 return 1;
3169
3170 /*
3171 * Check whether AP uses regulatory triplet or channel triplet in
3172 * country info. Right now the operating class of the BSS channel
3173 * width trigger event is "unknown" (IEEE Std 802.11-2012 10.15.12),
3174 * based on the assumption that operating class triplet is not used in
3175 * beacon frame. If the First Channel Number/Operating Extension
3176 * Identifier octet has a positive integer value of 201 or greater,
3177 * then its operating class triplet.
3178 *
3179 * TODO: If Supported Operating Classes element is present in beacon
3180 * frame, have to lookup operating class in Annex E and fill them in
3181 * 2040 coex frame.
3182 */
3183 ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY);
3184 if (ie && (ie[1] >= 6) && (ie[5] >= 201))
3185 return 1;
3186
3187 os_memset(chan_list, 0, sizeof(chan_list));
3188
Hai Shaloma20dcd72022-02-04 13:43:00 -08003189 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003190 /* Skip other band bss */
Hai Shaloma20dcd72022-02-04 13:43:00 -08003191 enum hostapd_hw_mode mode;
Dmitry Shmidt4b060592013-04-29 16:42:49 -07003192 mode = ieee80211_freq_to_chan(bss->freq, &channel);
3193 if (mode != HOSTAPD_MODE_IEEE80211G &&
3194 mode != HOSTAPD_MODE_IEEE80211B)
Dmitry Shmidt04949592012-07-19 12:16:46 -07003195 continue;
3196
Hai Shaloma20dcd72022-02-04 13:43:00 -08003197 ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
3198 ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
3199 wpa_printf(MSG_DEBUG, "SME OBSS scan BSS " MACSTR
3200 " freq=%u chan=%u ht_cap=0x%x",
3201 MAC2STR(bss->bssid), bss->freq, channel, ht_cap);
3202
3203 if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
3204 if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07003205 num_intol++;
3206
Dmitry Shmidt04949592012-07-19 12:16:46 -07003207 /* Check whether the channel is already considered */
3208 for (i = 0; i < num_channels; i++) {
3209 if (channel == chan_list[i])
3210 break;
3211 }
3212 if (i != num_channels)
3213 continue;
3214
Dmitry Shmidt04949592012-07-19 12:16:46 -07003215 chan_list[num_channels++] = channel;
3216 }
3217 }
3218
3219 sme_send_2040_bss_coex(wpa_s, chan_list, num_channels, num_intol);
3220 return 1;
3221}
3222
3223
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003224static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s,
3225 struct wpa_driver_scan_params *params)
Dmitry Shmidt04949592012-07-19 12:16:46 -07003226{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003227 /* Include only affected channels */
Dmitry Shmidt04949592012-07-19 12:16:46 -07003228 struct hostapd_hw_modes *mode;
3229 int count, i;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003230 int start, end;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003231
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003232 mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
Hai Shalom60840252021-02-19 19:02:11 -08003233 HOSTAPD_MODE_IEEE80211G, false);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003234 if (mode == NULL) {
3235 /* No channels supported in this band - use empty list */
3236 params->freqs = os_zalloc(sizeof(int));
3237 return;
3238 }
3239
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003240 if (wpa_s->sme.ht_sec_chan == HT_SEC_CHAN_UNKNOWN &&
3241 wpa_s->current_bss) {
3242 const u8 *ie;
3243
3244 ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_OPERATION);
3245 if (ie && ie[1] >= 2) {
3246 u8 o;
3247
3248 o = ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
3249 if (o == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
3250 wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_ABOVE;
3251 else if (o == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
3252 wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_BELOW;
3253 }
3254 }
3255
3256 start = wpa_s->assoc_freq - 10;
3257 end = wpa_s->assoc_freq + 10;
3258 switch (wpa_s->sme.ht_sec_chan) {
3259 case HT_SEC_CHAN_UNKNOWN:
3260 /* HT40+ possible on channels 1..9 */
3261 if (wpa_s->assoc_freq <= 2452)
3262 start -= 20;
3263 /* HT40- possible on channels 5-13 */
3264 if (wpa_s->assoc_freq >= 2432)
3265 end += 20;
3266 break;
3267 case HT_SEC_CHAN_ABOVE:
3268 end += 20;
3269 break;
3270 case HT_SEC_CHAN_BELOW:
3271 start -= 20;
3272 break;
3273 }
3274 wpa_printf(MSG_DEBUG,
3275 "OBSS: assoc_freq %d possible affected range %d-%d",
3276 wpa_s->assoc_freq, start, end);
3277
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003278 params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
Dmitry Shmidt04949592012-07-19 12:16:46 -07003279 if (params->freqs == NULL)
3280 return;
3281 for (count = 0, i = 0; i < mode->num_channels; i++) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003282 int freq;
3283
Dmitry Shmidt04949592012-07-19 12:16:46 -07003284 if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
3285 continue;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003286 freq = mode->channels[i].freq;
3287 if (freq - 10 >= end || freq + 10 <= start)
3288 continue; /* not affected */
3289 params->freqs[count++] = freq;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003290 }
3291}
3292
3293
3294static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx)
3295{
3296 struct wpa_supplicant *wpa_s = eloop_ctx;
3297 struct wpa_driver_scan_params params;
3298
3299 if (!wpa_s->current_bss) {
3300 wpa_printf(MSG_DEBUG, "SME OBSS: Ignore scan request");
3301 return;
3302 }
3303
3304 os_memset(&params, 0, sizeof(params));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003305 wpa_obss_scan_freqs_list(wpa_s, &params);
Dmitry Shmidt2271d3f2014-06-23 12:16:31 -07003306 params.low_priority = 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003307 wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan");
3308
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003309 if (wpa_supplicant_trigger_scan(wpa_s, &params, true, false))
Dmitry Shmidt04949592012-07-19 12:16:46 -07003310 wpa_printf(MSG_DEBUG, "SME OBSS: Failed to trigger scan");
3311 else
3312 wpa_s->sme.sched_obss_scan = 1;
3313 os_free(params.freqs);
3314
3315 eloop_register_timeout(wpa_s->sme.obss_scan_int, 0,
3316 sme_obss_scan_timeout, wpa_s, NULL);
3317}
3318
3319
3320void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable)
3321{
3322 const u8 *ie;
3323 struct wpa_bss *bss = wpa_s->current_bss;
3324 struct wpa_ssid *ssid = wpa_s->current_ssid;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003325 struct hostapd_hw_modes *hw_mode = NULL;
3326 int i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003327
3328 eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
3329 wpa_s->sme.sched_obss_scan = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003330 wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_UNKNOWN;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003331 if (!enable)
3332 return;
3333
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003334 /*
3335 * Schedule OBSS scan if driver is using station SME in wpa_supplicant
3336 * or it expects OBSS scan to be performed by wpa_supplicant.
3337 */
3338 if (!((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
3339 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OBSS_SCAN)) ||
Hai Shalom81f62d82019-07-22 12:10:00 -07003340 ssid == NULL || ssid->mode != WPAS_MODE_INFRA)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003341 return;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003342
Hai Shaloma20dcd72022-02-04 13:43:00 -08003343#ifdef CONFIG_HT_OVERRIDES
3344 /* No need for OBSS scan if HT40 is explicitly disabled */
3345 if (ssid->disable_ht40)
3346 return;
3347#endif /* CONFIG_HT_OVERRIDES */
3348
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003349 if (!wpa_s->hw.modes)
3350 return;
3351
3352 /* only HT caps in 11g mode are relevant */
3353 for (i = 0; i < wpa_s->hw.num_modes; i++) {
3354 hw_mode = &wpa_s->hw.modes[i];
3355 if (hw_mode->mode == HOSTAPD_MODE_IEEE80211G)
3356 break;
3357 }
3358
3359 /* Driver does not support HT40 for 11g or doesn't have 11g. */
3360 if (i == wpa_s->hw.num_modes || !hw_mode ||
3361 !(hw_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
3362 return;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003363
3364 if (bss == NULL || bss->freq < 2400 || bss->freq > 2500)
3365 return; /* Not associated on 2.4 GHz band */
3366
3367 /* Check whether AP supports HT40 */
3368 ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_CAP);
3369 if (!ie || ie[1] < 2 ||
3370 !(WPA_GET_LE16(ie + 2) & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
3371 return; /* AP does not support HT40 */
3372
3373 ie = wpa_bss_get_ie(wpa_s->current_bss,
3374 WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS);
3375 if (!ie || ie[1] < 14)
3376 return; /* AP does not request OBSS scans */
3377
3378 wpa_s->sme.obss_scan_int = WPA_GET_LE16(ie + 6);
3379 if (wpa_s->sme.obss_scan_int < 10) {
3380 wpa_printf(MSG_DEBUG, "SME: Invalid OBSS Scan Interval %u "
3381 "replaced with the minimum 10 sec",
3382 wpa_s->sme.obss_scan_int);
3383 wpa_s->sme.obss_scan_int = 10;
3384 }
3385 wpa_printf(MSG_DEBUG, "SME: OBSS Scan Interval %u sec",
3386 wpa_s->sme.obss_scan_int);
3387 eloop_register_timeout(wpa_s->sme.obss_scan_int, 0,
3388 sme_obss_scan_timeout, wpa_s, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003389}
3390
3391
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003392static const unsigned int sa_query_max_timeout = 1000;
3393static const unsigned int sa_query_retry_timeout = 201;
Hai Shalom74f70d42019-02-11 14:42:39 -08003394static const unsigned int sa_query_ch_switch_max_delay = 5000; /* in usec */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003395
3396static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s)
3397{
3398 u32 tu;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003399 struct os_reltime now, passed;
3400 os_get_reltime(&now);
3401 os_reltime_sub(&now, &wpa_s->sme.sa_query_start, &passed);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003402 tu = (passed.sec * 1000000 + passed.usec) / 1024;
3403 if (sa_query_max_timeout < tu) {
3404 wpa_dbg(wpa_s, MSG_DEBUG, "SME: SA Query timed out");
3405 sme_stop_sa_query(wpa_s);
3406 wpa_supplicant_deauthenticate(
3407 wpa_s, WLAN_REASON_PREV_AUTH_NOT_VALID);
3408 return 1;
3409 }
3410
3411 return 0;
3412}
3413
3414
3415static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s,
3416 const u8 *trans_id)
3417{
Hai Shalom74f70d42019-02-11 14:42:39 -08003418 u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN + OCV_OCI_EXTENDED_LEN];
3419 u8 req_len = 2 + WLAN_SA_QUERY_TR_ID_LEN;
3420
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003421 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Request to "
3422 MACSTR, MAC2STR(wpa_s->bssid));
3423 wpa_hexdump(MSG_DEBUG, "SME: SA Query Transaction ID",
3424 trans_id, WLAN_SA_QUERY_TR_ID_LEN);
3425 req[0] = WLAN_ACTION_SA_QUERY;
3426 req[1] = WLAN_SA_QUERY_REQUEST;
3427 os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN);
Hai Shalom74f70d42019-02-11 14:42:39 -08003428
3429#ifdef CONFIG_OCV
3430 if (wpa_sm_ocv_enabled(wpa_s->wpa)) {
3431 struct wpa_channel_info ci;
3432
3433 if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
3434 wpa_printf(MSG_WARNING,
3435 "Failed to get channel info for OCI element in SA Query Request frame");
3436 return;
3437 }
3438
Hai Shalom899fcc72020-10-19 14:38:18 -07003439#ifdef CONFIG_TESTING_OPTIONS
3440 if (wpa_s->oci_freq_override_saquery_req) {
3441 wpa_printf(MSG_INFO,
3442 "TEST: Override SA Query Request OCI frequency %d -> %d MHz",
3443 ci.frequency,
3444 wpa_s->oci_freq_override_saquery_req);
3445 ci.frequency = wpa_s->oci_freq_override_saquery_req;
3446 }
3447#endif /* CONFIG_TESTING_OPTIONS */
3448
Hai Shalom74f70d42019-02-11 14:42:39 -08003449 if (ocv_insert_extended_oci(&ci, req + req_len) < 0)
3450 return;
3451
3452 req_len += OCV_OCI_EXTENDED_LEN;
3453 }
3454#endif /* CONFIG_OCV */
3455
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003456 if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
3457 wpa_s->own_addr, wpa_s->bssid,
Hai Shalom74f70d42019-02-11 14:42:39 -08003458 req, req_len, 0) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003459 wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send SA Query "
3460 "Request");
3461}
3462
3463
3464static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
3465{
3466 struct wpa_supplicant *wpa_s = eloop_ctx;
3467 unsigned int timeout, sec, usec;
3468 u8 *trans_id, *nbuf;
3469
3470 if (wpa_s->sme.sa_query_count > 0 &&
3471 sme_check_sa_query_timeout(wpa_s))
3472 return;
3473
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003474 nbuf = os_realloc_array(wpa_s->sme.sa_query_trans_id,
3475 wpa_s->sme.sa_query_count + 1,
3476 WLAN_SA_QUERY_TR_ID_LEN);
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003477 if (nbuf == NULL) {
3478 sme_stop_sa_query(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003479 return;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003480 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003481 if (wpa_s->sme.sa_query_count == 0) {
3482 /* Starting a new SA Query procedure */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003483 os_get_reltime(&wpa_s->sme.sa_query_start);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003484 }
3485 trans_id = nbuf + wpa_s->sme.sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
3486 wpa_s->sme.sa_query_trans_id = nbuf;
3487 wpa_s->sme.sa_query_count++;
3488
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003489 if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
3490 wpa_printf(MSG_DEBUG, "Could not generate SA Query ID");
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003491 sme_stop_sa_query(wpa_s);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003492 return;
3493 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003494
3495 timeout = sa_query_retry_timeout;
3496 sec = ((timeout / 1000) * 1024) / 1000;
3497 usec = (timeout % 1000) * 1024;
3498 eloop_register_timeout(sec, usec, sme_sa_query_timer, wpa_s, NULL);
3499
3500 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association SA Query attempt %d",
3501 wpa_s->sme.sa_query_count);
3502
3503 sme_send_sa_query_req(wpa_s, trans_id);
3504}
3505
3506
3507static void sme_start_sa_query(struct wpa_supplicant *wpa_s)
3508{
3509 sme_sa_query_timer(wpa_s, NULL);
3510}
3511
3512
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003513static void sme_stop_sa_query(struct wpa_supplicant *wpa_s)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003514{
Hai Shalom5f92bc92019-04-18 11:54:11 -07003515 if (wpa_s->sme.sa_query_trans_id)
3516 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Stop SA Query");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003517 eloop_cancel_timeout(sme_sa_query_timer, wpa_s, NULL);
3518 os_free(wpa_s->sme.sa_query_trans_id);
3519 wpa_s->sme.sa_query_trans_id = NULL;
3520 wpa_s->sme.sa_query_count = 0;
3521}
3522
3523
3524void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
3525 const u8 *da, u16 reason_code)
3526{
3527 struct wpa_ssid *ssid;
Dmitry Shmidt0c08fdc2014-06-20 10:16:40 -07003528 struct os_reltime now;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003529
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003530 if (wpa_s->wpa_state != WPA_COMPLETED)
3531 return;
3532 ssid = wpa_s->current_ssid;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003533 if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003534 return;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003535 if (!ether_addr_equal(sa, wpa_s->bssid))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003536 return;
3537 if (reason_code != WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA &&
3538 reason_code != WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA)
3539 return;
3540 if (wpa_s->sme.sa_query_count > 0)
3541 return;
Hai Shalomfdcde762020-04-02 11:19:20 -07003542#ifdef CONFIG_TESTING_OPTIONS
3543 if (wpa_s->disable_sa_query)
3544 return;
3545#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003546
Dmitry Shmidt0c08fdc2014-06-20 10:16:40 -07003547 os_get_reltime(&now);
3548 if (wpa_s->sme.last_unprot_disconnect.sec &&
3549 !os_reltime_expired(&now, &wpa_s->sme.last_unprot_disconnect, 10))
3550 return; /* limit SA Query procedure frequency */
3551 wpa_s->sme.last_unprot_disconnect = now;
3552
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003553 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Unprotected disconnect dropped - "
3554 "possible AP/STA state mismatch - trigger SA Query");
3555 sme_start_sa_query(wpa_s);
3556}
3557
3558
Hai Shalom74f70d42019-02-11 14:42:39 -08003559void sme_event_ch_switch(struct wpa_supplicant *wpa_s)
3560{
3561 unsigned int usec;
3562 u32 _rand;
3563
3564 if (wpa_s->wpa_state != WPA_COMPLETED ||
3565 !wpa_sm_ocv_enabled(wpa_s->wpa))
3566 return;
3567
3568 wpa_dbg(wpa_s, MSG_DEBUG,
3569 "SME: Channel switch completed - trigger new SA Query to verify new operating channel");
3570 sme_stop_sa_query(wpa_s);
3571
3572 if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
3573 _rand = os_random();
3574 usec = _rand % (sa_query_ch_switch_max_delay + 1);
3575 eloop_register_timeout(0, usec, sme_sa_query_timer, wpa_s, NULL);
3576}
3577
3578
3579static void sme_process_sa_query_request(struct wpa_supplicant *wpa_s,
3580 const u8 *sa, const u8 *data,
3581 size_t len)
3582{
3583 u8 resp[2 + WLAN_SA_QUERY_TR_ID_LEN + OCV_OCI_EXTENDED_LEN];
3584 u8 resp_len = 2 + WLAN_SA_QUERY_TR_ID_LEN;
3585
3586 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Response to "
3587 MACSTR, MAC2STR(wpa_s->bssid));
3588
3589 resp[0] = WLAN_ACTION_SA_QUERY;
3590 resp[1] = WLAN_SA_QUERY_RESPONSE;
3591 os_memcpy(resp + 2, data + 1, WLAN_SA_QUERY_TR_ID_LEN);
3592
3593#ifdef CONFIG_OCV
3594 if (wpa_sm_ocv_enabled(wpa_s->wpa)) {
3595 struct wpa_channel_info ci;
3596
3597 if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
3598 wpa_printf(MSG_WARNING,
3599 "Failed to get channel info for OCI element in SA Query Response frame");
3600 return;
3601 }
3602
Hai Shalom899fcc72020-10-19 14:38:18 -07003603#ifdef CONFIG_TESTING_OPTIONS
3604 if (wpa_s->oci_freq_override_saquery_resp) {
3605 wpa_printf(MSG_INFO,
3606 "TEST: Override SA Query Response OCI frequency %d -> %d MHz",
3607 ci.frequency,
3608 wpa_s->oci_freq_override_saquery_resp);
3609 ci.frequency = wpa_s->oci_freq_override_saquery_resp;
3610 }
3611#endif /* CONFIG_TESTING_OPTIONS */
3612
Hai Shalom74f70d42019-02-11 14:42:39 -08003613 if (ocv_insert_extended_oci(&ci, resp + resp_len) < 0)
3614 return;
3615
3616 resp_len += OCV_OCI_EXTENDED_LEN;
3617 }
3618#endif /* CONFIG_OCV */
3619
3620 if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
3621 wpa_s->own_addr, wpa_s->bssid,
3622 resp, resp_len, 0) < 0)
3623 wpa_msg(wpa_s, MSG_INFO,
3624 "SME: Failed to send SA Query Response");
3625}
3626
3627
3628static void sme_process_sa_query_response(struct wpa_supplicant *wpa_s,
3629 const u8 *sa, const u8 *data,
3630 size_t len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003631{
3632 int i;
3633
Hai Shalom74f70d42019-02-11 14:42:39 -08003634 if (!wpa_s->sme.sa_query_trans_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003635 return;
Hai Shalom74f70d42019-02-11 14:42:39 -08003636
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003637 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query response from "
3638 MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]);
3639
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003640 if (!ether_addr_equal(sa, wpa_s->bssid))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003641 return;
3642
3643 for (i = 0; i < wpa_s->sme.sa_query_count; i++) {
3644 if (os_memcmp(wpa_s->sme.sa_query_trans_id +
3645 i * WLAN_SA_QUERY_TR_ID_LEN,
3646 data + 1, WLAN_SA_QUERY_TR_ID_LEN) == 0)
3647 break;
3648 }
3649
3650 if (i >= wpa_s->sme.sa_query_count) {
3651 wpa_dbg(wpa_s, MSG_DEBUG, "SME: No matching SA Query "
3652 "transaction identifier found");
3653 return;
3654 }
3655
3656 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Reply to pending SA Query received "
3657 "from " MACSTR, MAC2STR(sa));
3658 sme_stop_sa_query(wpa_s);
3659}
3660
Hai Shalom74f70d42019-02-11 14:42:39 -08003661
Hai Shaloma20dcd72022-02-04 13:43:00 -08003662void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *da, const u8 *sa,
Hai Shalom74f70d42019-02-11 14:42:39 -08003663 const u8 *data, size_t len)
3664{
3665 if (len < 1 + WLAN_SA_QUERY_TR_ID_LEN)
3666 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003667 if (is_multicast_ether_addr(da)) {
3668 wpa_printf(MSG_DEBUG,
3669 "IEEE 802.11: Ignore group-addressed SA Query frame (A1=" MACSTR " A2=" MACSTR ")",
3670 MAC2STR(da), MAC2STR(sa));
3671 return;
3672 }
Hai Shalom74f70d42019-02-11 14:42:39 -08003673
3674 wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query frame from "
3675 MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]);
3676
3677#ifdef CONFIG_OCV
3678 if (wpa_sm_ocv_enabled(wpa_s->wpa)) {
3679 struct ieee802_11_elems elems;
3680 struct wpa_channel_info ci;
3681
3682 if (ieee802_11_parse_elems(data + 1 + WLAN_SA_QUERY_TR_ID_LEN,
3683 len - 1 - WLAN_SA_QUERY_TR_ID_LEN,
3684 &elems, 1) == ParseFailed) {
3685 wpa_printf(MSG_DEBUG,
3686 "SA Query: Failed to parse elements");
3687 return;
3688 }
3689
3690 if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
3691 wpa_printf(MSG_WARNING,
3692 "Failed to get channel info to validate received OCI in SA Query Action frame");
3693 return;
3694 }
3695
3696 if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
3697 channel_width_to_int(ci.chanwidth),
Hai Shalom899fcc72020-10-19 14:38:18 -07003698 ci.seg1_idx) != OCI_SUCCESS) {
3699 wpa_msg(wpa_s, MSG_INFO, OCV_FAILURE "addr=" MACSTR
3700 " frame=saquery%s error=%s",
3701 MAC2STR(sa), data[0] == WLAN_SA_QUERY_REQUEST ?
3702 "req" : "resp", ocv_errorstr);
Hai Shalom74f70d42019-02-11 14:42:39 -08003703 return;
3704 }
3705 }
3706#endif /* CONFIG_OCV */
3707
3708 if (data[0] == WLAN_SA_QUERY_REQUEST)
3709 sme_process_sa_query_request(wpa_s, sa, data, len);
3710 else if (data[0] == WLAN_SA_QUERY_RESPONSE)
3711 sme_process_sa_query_response(wpa_s, sa, data, len);
3712}