blob: 1cd76ca785831df853a5ad7787a0e0e6cf01ab84 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / IEEE 802.11 Management
Dmitry Shmidt29333592017-01-09 12:27:11 -08003 * Copyright (c) 2002-2017, 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 "utils/includes.h"
10
11#ifndef CONFIG_NATIVE_WINDOWS
12
13#include "utils/common.h"
14#include "utils/eloop.h"
15#include "crypto/crypto.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080016#include "crypto/sha256.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070017#include "crypto/sha384.h"
18#include "crypto/sha512.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080019#include "crypto/random.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070020#include "common/ieee802_11_defs.h"
21#include "common/ieee802_11_common.h"
22#include "common/wpa_ctrl.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080023#include "common/sae.h"
Hai Shalom021b0b52019-04-10 11:17:58 -070024#include "common/dpp.h"
Hai Shalom74f70d42019-02-11 14:42:39 -080025#include "common/ocv.h"
Hai Shalom81f62d82019-07-22 12:10:00 -070026#include "common/wpa_common.h"
Hai Shalom899fcc72020-10-19 14:38:18 -070027#include "common/wpa_ctrl.h"
Hai Shalom60840252021-02-19 19:02:11 -080028#include "common/ptksa_cache.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070029#include "radius/radius.h"
30#include "radius/radius_client.h"
31#include "p2p/p2p.h"
32#include "wps/wps.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080033#include "fst/fst.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070034#include "hostapd.h"
35#include "beacon.h"
36#include "ieee802_11_auth.h"
37#include "sta_info.h"
38#include "ieee802_1x.h"
39#include "wpa_auth.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080040#include "pmksa_cache_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070041#include "wmm.h"
42#include "ap_list.h"
43#include "accounting.h"
44#include "ap_config.h"
45#include "ap_mlme.h"
46#include "p2p_hostapd.h"
47#include "ap_drv_ops.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080048#include "wnm_ap.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080049#include "hw_features.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070050#include "ieee802_11.h"
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080051#include "dfs.h"
Dmitry Shmidt57c2d392016-02-23 13:40:19 -080052#include "mbo_ap.h"
Dmitry Shmidt849734c2016-05-27 09:59:01 -070053#include "rrm.h"
Dmitry Shmidtaca489e2016-09-28 15:44:14 -070054#include "taxonomy.h"
Dmitry Shmidtebd93af2017-02-21 13:40:44 -080055#include "fils_hlp.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070056#include "dpp_hostapd.h"
57#include "gas_query_ap.h"
Sunil Ravi77d572f2023-01-17 23:58:31 +000058#include "comeback_token.h"
Sunil Ravib0ac25f2024-07-12 01:42:03 +000059#include "nan_usd_ap.h"
Sunil Ravi77d572f2023-01-17 23:58:31 +000060#include "pasn/pasn_common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070061
62
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070063#ifdef CONFIG_FILS
64static struct wpabuf *
65prepare_auth_resp_fils(struct hostapd_data *hapd,
66 struct sta_info *sta, u16 *resp,
67 struct rsn_pmksa_cache_entry *pmksa,
68 struct wpabuf *erp_resp,
69 const u8 *msk, size_t msk_len,
70 int *is_pub);
71#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -080072
73#ifdef CONFIG_PASN
Hai Shalom60840252021-02-19 19:02:11 -080074#ifdef CONFIG_FILS
75
76static void pasn_fils_auth_resp(struct hostapd_data *hapd,
77 struct sta_info *sta, u16 status,
78 struct wpabuf *erp_resp,
79 const u8 *msk, size_t msk_len);
80
81#endif /* CONFIG_FILS */
82#endif /* CONFIG_PASN */
83
Hai Shalom021b0b52019-04-10 11:17:58 -070084static void handle_auth(struct hostapd_data *hapd,
85 const struct ieee80211_mgmt *mgmt, size_t len,
86 int rssi, int from_queue);
Sunil Ravi2a14cf12023-11-21 00:54:38 +000087static int add_associated_sta(struct hostapd_data *hapd,
88 struct sta_info *sta, int reassoc);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070089
Hai Shalom74f70d42019-02-11 14:42:39 -080090
Sunil Ravi99c035e2024-07-12 01:42:03 +000091static u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid, size_t len)
Hai Shalom74f70d42019-02-11 14:42:39 -080092{
Sunil Ravi99c035e2024-07-12 01:42:03 +000093 struct multi_ap_params multi_ap = { 0 };
Hai Shalom74f70d42019-02-11 14:42:39 -080094
95 if (!hapd->conf->multi_ap)
96 return eid;
Sunil Raviaf399a82024-05-05 20:56:55 +000097
Sunil Ravi99c035e2024-07-12 01:42:03 +000098 if (hapd->conf->multi_ap & BACKHAUL_BSS)
99 multi_ap.capability |= MULTI_AP_BACKHAUL_BSS;
100 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
101 multi_ap.capability |= MULTI_AP_FRONTHAUL_BSS;
102
103 if (hapd->conf->multi_ap_client_disallow &
104 PROFILE1_CLIENT_ASSOC_DISALLOW)
105 multi_ap.capability |=
106 MULTI_AP_PROFILE1_BACKHAUL_STA_DISALLOWED;
107 if (hapd->conf->multi_ap_client_disallow &
108 PROFILE2_CLIENT_ASSOC_DISALLOW)
109 multi_ap.capability |=
110 MULTI_AP_PROFILE2_BACKHAUL_STA_DISALLOWED;
111
112 multi_ap.profile = hapd->conf->multi_ap_profile;
113 multi_ap.vlanid = hapd->conf->multi_ap_vlanid;
114
115 return eid + add_multi_ap_ie(eid, len, &multi_ap);
Hai Shalom74f70d42019-02-11 14:42:39 -0800116}
117
118
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700119u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
120{
121 u8 *pos = eid;
122 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700123 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700124
125 if (hapd->iface->current_rates == NULL)
126 return eid;
127
128 *pos++ = WLAN_EID_SUPP_RATES;
129 num = hapd->iface->num_rates;
130 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
131 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800132 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
133 num++;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000134#ifdef CONFIG_IEEE80211AX
135 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
136 num++;
137#endif /* CONFIG_IEEE80211AX */
138 h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
Hai Shalomfdcde762020-04-02 11:19:20 -0700139 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +0000140 hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700141 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
142 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700143 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700144 if (num > 8) {
145 /* rest of the rates are encoded in Extended supported
146 * rates element */
147 num = 8;
148 }
149
150 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700151 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
152 i++) {
153 count++;
154 *pos = hapd->iface->current_rates[i].rate / 5;
155 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
156 *pos |= 0x80;
157 pos++;
158 }
159
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800160 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
161 count++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700162 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800163 }
164
165 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
166 count++;
167 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
168 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700169
Sunil Ravi77d572f2023-01-17 23:58:31 +0000170#ifdef CONFIG_IEEE80211AX
171 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he && count < 8) {
172 count++;
173 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY;
174 }
175#endif /* CONFIG_IEEE80211AX */
176
Hai Shalomfdcde762020-04-02 11:19:20 -0700177 if (h2e_required && count < 8) {
Hai Shalomc3565922019-10-28 11:58:20 -0700178 count++;
179 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
180 }
181
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700182 return pos;
183}
184
185
186u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
187{
188 u8 *pos = eid;
189 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700190 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700191
Sunil Ravi77d572f2023-01-17 23:58:31 +0000192 hapd->conf->xrates_supported = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700193 if (hapd->iface->current_rates == NULL)
194 return eid;
195
196 num = hapd->iface->num_rates;
197 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
198 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800199 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
200 num++;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000201#ifdef CONFIG_IEEE80211AX
202 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
203 num++;
204#endif /* CONFIG_IEEE80211AX */
205 h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
Hai Shalomfdcde762020-04-02 11:19:20 -0700206 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +0000207 hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700208 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
209 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700210 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700211 if (num <= 8)
212 return eid;
213 num -= 8;
214
215 *pos++ = WLAN_EID_EXT_SUPP_RATES;
216 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700217 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
218 i++) {
219 count++;
220 if (count <= 8)
221 continue; /* already in SuppRates IE */
222 *pos = hapd->iface->current_rates[i].rate / 5;
223 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
224 *pos |= 0x80;
225 pos++;
226 }
227
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800228 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
229 count++;
230 if (count > 8)
231 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
232 }
233
234 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
235 count++;
236 if (count > 8)
237 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
238 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700239
Sunil Ravi77d572f2023-01-17 23:58:31 +0000240#ifdef CONFIG_IEEE80211AX
241 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he) {
242 count++;
243 if (count > 8)
244 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY;
245 }
246#endif /* CONFIG_IEEE80211AX */
247
Hai Shalomfdcde762020-04-02 11:19:20 -0700248 if (h2e_required) {
Hai Shalomc3565922019-10-28 11:58:20 -0700249 count++;
250 if (count > 8)
251 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
252 }
253
Sunil Ravi77d572f2023-01-17 23:58:31 +0000254 hapd->conf->xrates_supported = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700255 return pos;
256}
257
258
Hai Shalomfdcde762020-04-02 11:19:20 -0700259u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
260 size_t len)
261{
262 size_t i;
263
264 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
265 if (hapd->conf->radio_measurements[i])
266 break;
267 }
268
269 if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
270 return eid;
271
272 *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
273 *eid++ = RRM_CAPABILITIES_IE_LEN;
274 os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
275
276 return eid + RRM_CAPABILITIES_IE_LEN;
277}
278
279
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700280u16 hostapd_own_capab_info(struct hostapd_data *hapd)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700281{
282 int capab = WLAN_CAPABILITY_ESS;
Hai Shalomfdcde762020-04-02 11:19:20 -0700283 int privacy = 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800284 int dfs;
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700285 int i;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800286
287 /* Check if any of configured channels require DFS */
288 dfs = hostapd_is_dfs_required(hapd->iface);
289 if (dfs < 0) {
290 wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
291 dfs);
292 dfs = 0;
293 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700294
295 if (hapd->iface->num_sta_no_short_preamble == 0 &&
296 hapd->iconf->preamble == SHORT_PREAMBLE)
297 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
298
Hai Shalomfdcde762020-04-02 11:19:20 -0700299#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700300 privacy = hapd->conf->ssid.wep.keys_set;
301
302 if (hapd->conf->ieee802_1x &&
303 (hapd->conf->default_wep_key_len ||
304 hapd->conf->individual_wep_key_len))
305 privacy = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -0700306#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700307
308 if (hapd->conf->wpa)
309 privacy = 1;
310
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800311#ifdef CONFIG_HS20
312 if (hapd->conf->osen)
313 privacy = 1;
314#endif /* CONFIG_HS20 */
315
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700316 if (privacy)
317 capab |= WLAN_CAPABILITY_PRIVACY;
318
319 if (hapd->iface->current_mode &&
320 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
321 hapd->iface->num_sta_no_short_slot_time == 0)
322 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
323
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800324 /*
325 * Currently, Spectrum Management capability bit is set when directly
326 * requested in configuration by spectrum_mgmt_required or when AP is
327 * running on DFS channel.
328 * TODO: Also consider driver support for TPC to set Spectrum Mgmt bit
329 */
330 if (hapd->iface->current_mode &&
331 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
332 (hapd->iconf->spectrum_mgmt_required || dfs))
333 capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
334
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700335 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
336 if (hapd->conf->radio_measurements[i]) {
337 capab |= IEEE80211_CAP_RRM;
338 break;
339 }
340 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800341
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700342 return capab;
343}
344
345
Hai Shalomfdcde762020-04-02 11:19:20 -0700346#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800347#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700348static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
349 u16 auth_transaction, const u8 *challenge,
350 int iswep)
351{
352 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
353 HOSTAPD_LEVEL_DEBUG,
354 "authentication (shared key, transaction %d)",
355 auth_transaction);
356
357 if (auth_transaction == 1) {
358 if (!sta->challenge) {
359 /* Generate a pseudo-random challenge */
360 u8 key[8];
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800361
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700362 sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
363 if (sta->challenge == NULL)
364 return WLAN_STATUS_UNSPECIFIED_FAILURE;
365
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800366 if (os_get_random(key, sizeof(key)) < 0) {
367 os_free(sta->challenge);
368 sta->challenge = NULL;
369 return WLAN_STATUS_UNSPECIFIED_FAILURE;
370 }
371
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700372 rc4_skip(key, sizeof(key), 0,
373 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
374 }
375 return 0;
376 }
377
378 if (auth_transaction != 3)
379 return WLAN_STATUS_UNSPECIFIED_FAILURE;
380
381 /* Transaction 3 */
382 if (!iswep || !sta->challenge || !challenge ||
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700383 os_memcmp_const(sta->challenge, challenge,
384 WLAN_AUTH_CHALLENGE_LEN)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700385 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
386 HOSTAPD_LEVEL_INFO,
387 "shared key authentication - invalid "
388 "challenge-response");
389 return WLAN_STATUS_CHALLENGE_FAIL;
390 }
391
392 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
393 HOSTAPD_LEVEL_DEBUG,
394 "authentication OK (shared key)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700395 sta->flags |= WLAN_STA_AUTH;
396 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700397 os_free(sta->challenge);
398 sta->challenge = NULL;
399
400 return 0;
401}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800402#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700403#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700404
405
Hai Shalomfdcde762020-04-02 11:19:20 -0700406static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
Sunil Ravi7f769292024-07-23 22:21:32 +0000407 const u8 *dst,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800408 u16 auth_alg, u16 auth_transaction, u16 resp,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700409 const u8 *ies, size_t ies_len, const char *dbg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700410{
411 struct ieee80211_mgmt *reply;
412 u8 *buf;
413 size_t rlen;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800414 int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000415 const u8 *sa = hapd->own_addr;
416 struct wpabuf *ml_resp = NULL;
417
418#ifdef CONFIG_IEEE80211BE
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000419 if (ap_sta_is_mld(hapd, sta)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000420 ml_resp = hostapd_ml_auth_resp(hapd);
421 if (!ml_resp)
422 return -1;
423 }
424#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700425
426 rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000427 if (ml_resp)
428 rlen += wpabuf_len(ml_resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700429 buf = os_zalloc(rlen);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000430 if (!buf) {
431 wpabuf_free(ml_resp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800432 return -1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000433 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700434
435 reply = (struct ieee80211_mgmt *) buf;
436 reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
437 WLAN_FC_STYPE_AUTH);
438 os_memcpy(reply->da, dst, ETH_ALEN);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000439 os_memcpy(reply->sa, sa, ETH_ALEN);
Sunil Ravi7f769292024-07-23 22:21:32 +0000440 os_memcpy(reply->bssid, sa, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700441
442 reply->u.auth.auth_alg = host_to_le16(auth_alg);
443 reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
444 reply->u.auth.status_code = host_to_le16(resp);
445
446 if (ies && ies_len)
447 os_memcpy(reply->u.auth.variable, ies, ies_len);
448
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000449#ifdef CONFIG_IEEE80211BE
450 if (ml_resp)
451 os_memcpy(reply->u.auth.variable + ies_len,
452 wpabuf_head(ml_resp), wpabuf_len(ml_resp));
453
454 wpabuf_free(ml_resp);
455#endif /* CONFIG_IEEE80211BE */
456
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700457 wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700458 " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700459 MAC2STR(dst), auth_alg, auth_transaction,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700460 resp, (unsigned long) ies_len, dbg);
Hai Shalomfdcde762020-04-02 11:19:20 -0700461#ifdef CONFIG_TESTING_OPTIONS
462#ifdef CONFIG_SAE
463 if (hapd->conf->sae_confirm_immediate == 2 &&
464 auth_alg == WLAN_AUTH_SAE) {
465 if (auth_transaction == 1 && sta &&
466 (resp == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -0700467 resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
468 resp == WLAN_STATUS_SAE_PK)) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700469 wpa_printf(MSG_DEBUG,
470 "TESTING: Postpone SAE Commit transmission until Confirm is ready");
471 os_free(sta->sae_postponed_commit);
472 sta->sae_postponed_commit = buf;
473 sta->sae_postponed_commit_len = rlen;
474 return WLAN_STATUS_SUCCESS;
475 }
476
477 if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
478 wpa_printf(MSG_DEBUG,
479 "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
480 if (hostapd_drv_send_mlme(hapd,
481 sta->sae_postponed_commit,
482 sta->sae_postponed_commit_len,
483 0, NULL, 0, 0) < 0)
484 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
485 os_free(sta->sae_postponed_commit);
486 sta->sae_postponed_commit = NULL;
487 sta->sae_postponed_commit_len = 0;
488 }
489 }
490#endif /* CONFIG_SAE */
491#endif /* CONFIG_TESTING_OPTIONS */
492 if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800493 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
494 else
495 reply_res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700496
497 os_free(buf);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800498
499 return reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700500}
501
502
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800503#ifdef CONFIG_IEEE80211R_AP
Sunil Ravi7f769292024-07-23 22:21:32 +0000504static void handle_auth_ft_finish(void *ctx, const u8 *dst,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700505 u16 auth_transaction, u16 status,
506 const u8 *ies, size_t ies_len)
507{
508 struct hostapd_data *hapd = ctx;
509 struct sta_info *sta;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800510 int reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700511
Sunil Ravi7f769292024-07-23 22:21:32 +0000512 reply_res = send_auth_reply(hapd, NULL, dst, WLAN_AUTH_FT,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700513 auth_transaction, status, ies, ies_len,
514 "auth-ft-finish");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700515
516 sta = ap_get_sta(hapd, dst);
517 if (sta == NULL)
518 return;
519
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800520 if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
521 status != WLAN_STATUS_SUCCESS)) {
522 hostapd_drv_sta_remove(hapd, sta->addr);
523 sta->added_unassoc = 0;
524 return;
525 }
526
527 if (status != WLAN_STATUS_SUCCESS)
528 return;
529
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700530 hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
531 HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
532 sta->flags |= WLAN_STA_AUTH;
533 mlme_authenticate_indication(hapd, sta);
534}
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800535#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700536
537
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800538#ifdef CONFIG_SAE
539
Roshan Pius3a1667e2018-07-03 15:17:14 -0700540static void sae_set_state(struct sta_info *sta, enum sae_state state,
541 const char *reason)
542{
543 wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
544 sae_state_txt(sta->sae->state), sae_state_txt(state),
545 MAC2STR(sta->addr), reason);
546 sta->sae->state = state;
547}
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800548
549
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000550const char * sae_get_password(struct hostapd_data *hapd,
551 struct sta_info *sta,
552 const char *rx_id,
553 struct sae_password_entry **pw_entry,
554 struct sae_pt **s_pt,
555 const struct sae_pk **s_pk)
Hai Shalom60840252021-02-19 19:02:11 -0800556{
557 const char *password = NULL;
558 struct sae_password_entry *pw;
559 struct sae_pt *pt = NULL;
560 const struct sae_pk *pk = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -0700561 struct hostapd_sta_wpa_psk_short *psk = NULL;
Hai Shalom60840252021-02-19 19:02:11 -0800562
563 for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
564 if (!is_broadcast_ether_addr(pw->peer_addr) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000565 (!sta ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000566 !ether_addr_equal(pw->peer_addr, sta->addr)))
Hai Shalom60840252021-02-19 19:02:11 -0800567 continue;
568 if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
569 continue;
570 if (rx_id && pw->identifier &&
571 os_strcmp(rx_id, pw->identifier) != 0)
572 continue;
573 password = pw->password;
574 pt = pw->pt;
575 if (!(hapd->conf->mesh & MESH_ENABLED))
576 pk = pw->pk;
577 break;
578 }
579 if (!password) {
580 password = hapd->conf->ssid.wpa_passphrase;
581 pt = hapd->conf->ssid.pt;
582 }
583
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000584 if (!password && sta) {
Sunil Ravia04bd252022-05-02 22:54:18 -0700585 for (psk = sta->psk; psk; psk = psk->next) {
586 if (psk->is_passphrase) {
587 password = psk->passphrase;
588 break;
589 }
590 }
591 }
592
Hai Shalom60840252021-02-19 19:02:11 -0800593 if (pw_entry)
594 *pw_entry = pw;
595 if (s_pt)
596 *s_pt = pt;
597 if (s_pk)
598 *s_pk = pk;
599
600 return password;
601}
602
603
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800604static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
Hai Shalomc3565922019-10-28 11:58:20 -0700605 struct sta_info *sta, int update,
606 int status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800607{
608 struct wpabuf *buf;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700609 const char *password = NULL;
610 struct sae_password_entry *pw;
611 const char *rx_id = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700612 int use_pt = 0;
613 struct sae_pt *pt = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700614 const struct sae_pk *pk = NULL;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000615 const u8 *own_addr = hapd->own_addr;
616
617#ifdef CONFIG_IEEE80211BE
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000618 if (ap_sta_is_mld(hapd, sta))
Sunil Ravi99c035e2024-07-12 01:42:03 +0000619 own_addr = hapd->mld->mld_addr;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000620#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800621
Hai Shalomc3565922019-10-28 11:58:20 -0700622 if (sta->sae->tmp) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700623 rx_id = sta->sae->tmp->pw_id;
Hai Shalom899fcc72020-10-19 14:38:18 -0700624 use_pt = sta->sae->h2e;
625#ifdef CONFIG_SAE_PK
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000626 os_memcpy(sta->sae->tmp->own_addr, own_addr, ETH_ALEN);
Hai Shalom899fcc72020-10-19 14:38:18 -0700627 os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
628#endif /* CONFIG_SAE_PK */
Hai Shalomc3565922019-10-28 11:58:20 -0700629 }
630
Sunil Ravi77d572f2023-01-17 23:58:31 +0000631 if (rx_id && hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
Hai Shalomfdcde762020-04-02 11:19:20 -0700632 use_pt = 1;
633 else if (status_code == WLAN_STATUS_SUCCESS)
Hai Shalomc3565922019-10-28 11:58:20 -0700634 use_pt = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700635 else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
636 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomc3565922019-10-28 11:58:20 -0700637 use_pt = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700638
Hai Shalom60840252021-02-19 19:02:11 -0800639 password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk);
Hai Shalomc3565922019-10-28 11:58:20 -0700640 if (!password || (use_pt && !pt)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800641 wpa_printf(MSG_DEBUG, "SAE: No password available");
642 return NULL;
643 }
644
Hai Shalomc3565922019-10-28 11:58:20 -0700645 if (update && use_pt &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000646 sae_prepare_commit_pt(sta->sae, pt, own_addr, sta->addr,
Hai Shalom899fcc72020-10-19 14:38:18 -0700647 NULL, pk) < 0)
Hai Shalomc3565922019-10-28 11:58:20 -0700648 return NULL;
649
650 if (update && !use_pt &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000651 sae_prepare_commit(own_addr, sta->addr,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800652 (u8 *) password, os_strlen(password),
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800653 sta->sae) < 0) {
654 wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
655 return NULL;
656 }
657
Hai Shalom021b0b52019-04-10 11:17:58 -0700658 if (pw && pw->vlan_id) {
659 if (!sta->sae->tmp) {
660 wpa_printf(MSG_INFO,
661 "SAE: No temporary data allocated - cannot store VLAN ID");
662 return NULL;
663 }
664 sta->sae->tmp->vlan_id = pw->vlan_id;
665 }
666
Roshan Pius3a1667e2018-07-03 15:17:14 -0700667 buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
668 (rx_id ? 3 + os_strlen(rx_id) : 0));
Hai Shalomfdcde762020-04-02 11:19:20 -0700669 if (buf &&
670 sae_write_commit(sta->sae, buf, sta->sae->tmp ?
671 sta->sae->tmp->anti_clogging_token : NULL,
672 rx_id) < 0) {
673 wpabuf_free(buf);
674 buf = NULL;
675 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800676
677 return buf;
678}
679
680
681static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
682 struct sta_info *sta)
683{
684 struct wpabuf *buf;
685
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800686 buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800687 if (buf == NULL)
688 return NULL;
689
Hai Shalom899fcc72020-10-19 14:38:18 -0700690#ifdef CONFIG_SAE_PK
691#ifdef CONFIG_TESTING_OPTIONS
692 if (sta->sae->tmp)
693 sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
694#endif /* CONFIG_TESTING_OPTIONS */
695#endif /* CONFIG_SAE_PK */
696
697 if (sae_write_confirm(sta->sae, buf) < 0) {
698 wpabuf_free(buf);
699 return NULL;
700 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800701
702 return buf;
703}
704
705
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800706static int auth_sae_send_commit(struct hostapd_data *hapd,
707 struct sta_info *sta,
Sunil Ravi7f769292024-07-23 22:21:32 +0000708 int update, int status_code)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800709{
710 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800711 int reply_res;
Hai Shalomc3565922019-10-28 11:58:20 -0700712 u16 status;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800713
Hai Shalomc3565922019-10-28 11:58:20 -0700714 data = auth_build_sae_commit(hapd, sta, update, status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700715 if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
716 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800717 if (data == NULL)
718 return WLAN_STATUS_UNSPECIFIED_FAILURE;
719
Hai Shalom899fcc72020-10-19 14:38:18 -0700720 if (sta->sae->tmp && sta->sae->pk)
721 status = WLAN_STATUS_SAE_PK;
722 else if (sta->sae->tmp && sta->sae->h2e)
723 status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
724 else
725 status = WLAN_STATUS_SUCCESS;
726#ifdef CONFIG_TESTING_OPTIONS
727 if (hapd->conf->sae_commit_status >= 0 &&
728 hapd->conf->sae_commit_status != status) {
729 wpa_printf(MSG_INFO,
730 "TESTING: Override SAE commit status code %u --> %d",
731 status, hapd->conf->sae_commit_status);
732 status = hapd->conf->sae_commit_status;
733 }
734#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravi7f769292024-07-23 22:21:32 +0000735 reply_res = send_auth_reply(hapd, sta, sta->addr,
Hai Shalomfdcde762020-04-02 11:19:20 -0700736 WLAN_AUTH_SAE, 1,
Hai Shalomc3565922019-10-28 11:58:20 -0700737 status, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700738 wpabuf_len(data), "sae-send-commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800739
740 wpabuf_free(data);
741
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800742 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800743}
744
745
746static int auth_sae_send_confirm(struct hostapd_data *hapd,
Sunil Ravi7f769292024-07-23 22:21:32 +0000747 struct sta_info *sta)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800748{
749 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800750 int reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800751
752 data = auth_build_sae_confirm(hapd, sta);
753 if (data == NULL)
754 return WLAN_STATUS_UNSPECIFIED_FAILURE;
755
Sunil Ravi7f769292024-07-23 22:21:32 +0000756 reply_res = send_auth_reply(hapd, sta, sta->addr,
Hai Shalomfdcde762020-04-02 11:19:20 -0700757 WLAN_AUTH_SAE, 2,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800758 WLAN_STATUS_SUCCESS, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700759 wpabuf_len(data), "sae-send-confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800760
761 wpabuf_free(data);
762
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800763 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800764}
765
Hai Shaloma20dcd72022-02-04 13:43:00 -0800766#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800767
Hai Shaloma20dcd72022-02-04 13:43:00 -0800768
769#if defined(CONFIG_SAE) || defined(CONFIG_PASN)
770
771static int use_anti_clogging(struct hostapd_data *hapd)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800772{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800773 struct sta_info *sta;
774 unsigned int open = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800775
Hai Shaloma20dcd72022-02-04 13:43:00 -0800776 if (hapd->conf->anti_clogging_threshold == 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800777 return 1;
778
779 for (sta = hapd->sta_list; sta; sta = sta->next) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800780#ifdef CONFIG_SAE
781 if (sta->sae &&
782 (sta->sae->state == SAE_COMMITTED ||
783 sta->sae->state == SAE_CONFIRMED))
784 open++;
785#endif /* CONFIG_SAE */
786#ifdef CONFIG_PASN
787 if (sta->pasn && sta->pasn->ecdh)
788 open++;
789#endif /* CONFIG_PASN */
790 if (open >= hapd->conf->anti_clogging_threshold)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800791 return 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800792 }
793
Hai Shaloma20dcd72022-02-04 13:43:00 -0800794#ifdef CONFIG_SAE
Hai Shalom021b0b52019-04-10 11:17:58 -0700795 /* In addition to already existing open SAE sessions, check whether
796 * there are enough pending commit messages in the processing queue to
797 * potentially result in too many open sessions. */
798 if (open + dl_list_len(&hapd->sae_commit_queue) >=
Hai Shaloma20dcd72022-02-04 13:43:00 -0800799 hapd->conf->anti_clogging_threshold)
Hai Shalom021b0b52019-04-10 11:17:58 -0700800 return 1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800801#endif /* CONFIG_SAE */
Hai Shalom021b0b52019-04-10 11:17:58 -0700802
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800803 return 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800804}
805
Hai Shaloma20dcd72022-02-04 13:43:00 -0800806#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
807
808
809#ifdef CONFIG_SAE
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800810
Roshan Pius3a1667e2018-07-03 15:17:14 -0700811static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800812{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700813 if (sta->sae->sync > hapd->conf->sae_sync) {
814 sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800815 sta->sae->sync = 0;
Sunil Ravi7f769292024-07-23 22:21:32 +0000816 if (sta->sae->tmp) {
817 /* Disable this SAE instance for 10 seconds to avoid
818 * unnecessary flood of multiple SAE commits in
819 * unexpected mesh cases. */
820 if (os_get_reltime(&sta->sae->tmp->disabled_until) == 0)
821 sta->sae->tmp->disabled_until.sec += 10;
822 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800823 return -1;
824 }
825 return 0;
826}
827
828
Sunil Ravi7f769292024-07-23 22:21:32 +0000829static bool sae_proto_instance_disabled(struct sta_info *sta)
830{
831 struct sae_temporary_data *tmp;
832
833 if (!sta->sae)
834 return false;
835 tmp = sta->sae->tmp;
836 if (!tmp)
837 return false;
838
839 if (os_reltime_initialized(&tmp->disabled_until)) {
840 struct os_reltime now;
841
842 os_get_reltime(&now);
843 if (os_reltime_before(&now, &tmp->disabled_until))
844 return true;
845 }
846
847 return false;
848}
849
850
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800851static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
852{
853 struct hostapd_data *hapd = eloop_ctx;
854 struct sta_info *sta = eloop_data;
855 int ret;
856
Roshan Pius3a1667e2018-07-03 15:17:14 -0700857 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800858 return;
859 sta->sae->sync++;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700860 wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700861 " (sync=%d state=%s)",
862 MAC2STR(sta->addr), sta->sae->sync,
863 sae_state_txt(sta->sae->state));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800864
865 switch (sta->sae->state) {
866 case SAE_COMMITTED:
Sunil Ravi7f769292024-07-23 22:21:32 +0000867 ret = auth_sae_send_commit(hapd, sta, 0, -1);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800868 eloop_register_timeout(0,
869 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800870 auth_sae_retransmit_timer, hapd, sta);
871 break;
872 case SAE_CONFIRMED:
Sunil Ravi7f769292024-07-23 22:21:32 +0000873 ret = auth_sae_send_confirm(hapd, sta);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800874 eloop_register_timeout(0,
875 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800876 auth_sae_retransmit_timer, hapd, sta);
877 break;
878 default:
879 ret = -1;
880 break;
881 }
882
883 if (ret != WLAN_STATUS_SUCCESS)
884 wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
885}
886
887
888void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
889{
890 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
891}
892
893
894static void sae_set_retransmit_timer(struct hostapd_data *hapd,
895 struct sta_info *sta)
896{
897 if (!(hapd->conf->mesh & MESH_ENABLED))
898 return;
899
900 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800901 eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800902 auth_sae_retransmit_timer, hapd, sta);
903}
904
905
Hai Shalom5f92bc92019-04-18 11:54:11 -0700906static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
907 struct sta_info *sta, u16 status)
908{
909 struct external_auth params;
910
911 os_memset(&params, 0, sizeof(params));
912 params.status = status;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000913
914#ifdef CONFIG_IEEE80211BE
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000915 if (ap_sta_is_mld(hapd, sta))
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000916 params.bssid =
917 sta->mld_info.links[sta->mld_assoc_link_id].peer_addr;
918#endif /* CONFIG_IEEE80211BE */
919 if (!params.bssid)
920 params.bssid = sta->addr;
921
Hai Shalom81f62d82019-07-22 12:10:00 -0700922 if (status == WLAN_STATUS_SUCCESS && sta->sae &&
923 !hapd->conf->disable_pmksa_caching)
Hai Shalom5f92bc92019-04-18 11:54:11 -0700924 params.pmkid = sta->sae->pmkid;
925
926 hostapd_drv_send_external_auth_status(hapd, &params);
927}
928
929
Dmitry Shmidte4663042016-04-04 10:07:49 -0700930void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
931{
Hai Shalom021b0b52019-04-10 11:17:58 -0700932#ifndef CONFIG_NO_VLAN
933 struct vlan_description vlan_desc;
934
935 if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
936 wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
937 " to VLAN ID %d",
938 MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
939
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000940 if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
941 os_memset(&vlan_desc, 0, sizeof(vlan_desc));
942 vlan_desc.notempty = 1;
943 vlan_desc.untagged = sta->sae->tmp->vlan_id;
944 if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
945 wpa_printf(MSG_INFO,
946 "Invalid VLAN ID %d in sae_password",
947 sta->sae->tmp->vlan_id);
948 return;
949 }
Hai Shalom021b0b52019-04-10 11:17:58 -0700950
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000951 if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
952 ap_sta_bind_vlan(hapd, sta) < 0) {
953 wpa_printf(MSG_INFO,
954 "Failed to assign VLAN ID %d from sae_password to "
955 MACSTR, sta->sae->tmp->vlan_id,
956 MAC2STR(sta->addr));
957 return;
958 }
959 } else {
960 sta->vlan_id = sta->sae->tmp->vlan_id;
Hai Shalom021b0b52019-04-10 11:17:58 -0700961 }
962 }
963#endif /* CONFIG_NO_VLAN */
964
Dmitry Shmidte4663042016-04-04 10:07:49 -0700965 sta->flags |= WLAN_STA_AUTH;
966 sta->auth_alg = WLAN_AUTH_SAE;
967 mlme_authenticate_indication(hapd, sta);
968 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700969 sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
Hai Shalomfdcde762020-04-02 11:19:20 -0700970 crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
971 sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
972 sta->sae->peer_commit_scalar = NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -0700973 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
Sunil Ravi89eba102022-09-13 21:04:37 -0700974 sta->sae->pmk, sta->sae->pmk_len,
975 sta->sae->pmkid, sta->sae->akmp);
Hai Shalom5f92bc92019-04-18 11:54:11 -0700976 sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
Dmitry Shmidte4663042016-04-04 10:07:49 -0700977}
978
979
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800980static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
Sunil Ravi7f769292024-07-23 22:21:32 +0000981 u16 auth_transaction, u16 status_code,
Hai Shalomc3565922019-10-28 11:58:20 -0700982 int allow_reuse, int *sta_removed)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800983{
984 int ret;
985
Hai Shalom5f92bc92019-04-18 11:54:11 -0700986 *sta_removed = 0;
987
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800988 if (auth_transaction != 1 && auth_transaction != 2)
989 return WLAN_STATUS_UNSPECIFIED_FAILURE;
990
Roshan Pius3a1667e2018-07-03 15:17:14 -0700991 wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
992 MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
993 auth_transaction);
Sunil Ravi7f769292024-07-23 22:21:32 +0000994
995 if (auth_transaction == 1 && sae_proto_instance_disabled(sta)) {
996 wpa_printf(MSG_DEBUG,
997 "SAE: Protocol instance temporarily disabled - discard received SAE commit");
998 return WLAN_STATUS_SUCCESS;
999 }
1000
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001001 switch (sta->sae->state) {
1002 case SAE_NOTHING:
1003 if (auth_transaction == 1) {
Hai Shalom899fcc72020-10-19 14:38:18 -07001004 if (sta->sae->tmp) {
1005 sta->sae->h2e =
1006 (status_code ==
1007 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1008 status_code == WLAN_STATUS_SAE_PK);
1009 sta->sae->pk =
1010 status_code == WLAN_STATUS_SAE_PK;
1011 }
Sunil Ravi7f769292024-07-23 22:21:32 +00001012 ret = auth_sae_send_commit(hapd, sta,
Hai Shalomc3565922019-10-28 11:58:20 -07001013 !allow_reuse, status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001014 if (ret)
1015 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001016 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001017
1018 if (sae_process_commit(sta->sae) < 0)
1019 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1020
1021 /*
Hai Shalomc3565922019-10-28 11:58:20 -07001022 * In mesh case, both Commit and Confirm are sent
1023 * immediately. In infrastructure BSS, by default, only
1024 * a single Authentication frame (Commit) is expected
1025 * from the AP here and the second one (Confirm) will
1026 * be sent once the STA has sent its second
1027 * Authentication frame (Confirm). This behavior can be
1028 * overridden with explicit configuration so that the
1029 * infrastructure BSS case sends both frames together.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001030 */
Hai Shalomc3565922019-10-28 11:58:20 -07001031 if ((hapd->conf->mesh & MESH_ENABLED) ||
1032 hapd->conf->sae_confirm_immediate) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001033 /*
1034 * Send both Commit and Confirm immediately
1035 * based on SAE finite state machine
1036 * Nothing -> Confirm transition.
1037 */
Sunil Ravi7f769292024-07-23 22:21:32 +00001038 ret = auth_sae_send_confirm(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001039 if (ret)
1040 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001041 sae_set_state(sta, SAE_CONFIRMED,
1042 "Sent Confirm (mesh)");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001043 } else {
1044 /*
1045 * For infrastructure BSS, send only the Commit
1046 * message now to get alternating sequence of
1047 * Authentication frames between the AP and STA.
1048 * Confirm will be sent in
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001049 * Committed -> Confirmed/Accepted transition
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001050 * when receiving Confirm from STA.
1051 */
1052 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001053 sta->sae->sync = 0;
1054 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001055 } else {
1056 hostapd_logger(hapd, sta->addr,
1057 HOSTAPD_MODULE_IEEE80211,
1058 HOSTAPD_LEVEL_DEBUG,
1059 "SAE confirm before commit");
1060 }
1061 break;
1062 case SAE_COMMITTED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001063 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001064 if (auth_transaction == 1) {
1065 if (sae_process_commit(sta->sae) < 0)
1066 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1067
Sunil Ravi7f769292024-07-23 22:21:32 +00001068 ret = auth_sae_send_confirm(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001069 if (ret)
1070 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001071 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001072 sta->sae->sync = 0;
1073 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001074 } else if (hapd->conf->mesh & MESH_ENABLED) {
1075 /*
1076 * In mesh case, follow SAE finite state machine and
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001077 * send Commit now, if sync count allows.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001078 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001079 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001080 return WLAN_STATUS_SUCCESS;
1081 sta->sae->sync++;
1082
Sunil Ravi7f769292024-07-23 22:21:32 +00001083 ret = auth_sae_send_commit(hapd, sta, 0, status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001084 if (ret)
1085 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001086
1087 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001088 } else {
1089 /*
1090 * For instructure BSS, send the postponed Confirm from
1091 * Nothing -> Confirmed transition that was reduced to
1092 * Nothing -> Committed above.
1093 */
Sunil Ravi7f769292024-07-23 22:21:32 +00001094 ret = auth_sae_send_confirm(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001095 if (ret)
1096 return ret;
1097
Roshan Pius3a1667e2018-07-03 15:17:14 -07001098 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001099
1100 /*
1101 * Since this was triggered on Confirm RX, run another
1102 * step to get to Accepted without waiting for
1103 * additional events.
1104 */
Sunil Ravi7f769292024-07-23 22:21:32 +00001105 return sae_sm_step(hapd, sta, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001106 WLAN_STATUS_SUCCESS, 0, sta_removed);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001107 }
1108 break;
1109 case SAE_CONFIRMED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001110 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001111 if (auth_transaction == 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001112 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001113 return WLAN_STATUS_SUCCESS;
1114 sta->sae->sync++;
1115
Sunil Ravi7f769292024-07-23 22:21:32 +00001116 ret = auth_sae_send_commit(hapd, sta, 1, status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001117 if (ret)
1118 return ret;
1119
1120 if (sae_process_commit(sta->sae) < 0)
1121 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1122
Sunil Ravi7f769292024-07-23 22:21:32 +00001123 ret = auth_sae_send_confirm(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001124 if (ret)
1125 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001126
1127 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001128 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001129 sta->sae->send_confirm = 0xffff;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001130 sae_accept_sta(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001131 }
1132 break;
1133 case SAE_ACCEPTED:
Roshan Pius3a1667e2018-07-03 15:17:14 -07001134 if (auth_transaction == 1 &&
1135 (hapd->conf->mesh & MESH_ENABLED)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001136 wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
1137 ") doing reauthentication",
1138 MAC2STR(sta->addr));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001139 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
Hai Shalom5f92bc92019-04-18 11:54:11 -07001140 ap_free_sta(hapd, sta);
1141 *sta_removed = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001142 } else if (auth_transaction == 1) {
1143 wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
Sunil Ravi7f769292024-07-23 22:21:32 +00001144 ret = auth_sae_send_commit(hapd, sta, 1, status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001145 if (ret)
1146 return ret;
1147 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
1148
1149 if (sae_process_commit(sta->sae) < 0)
1150 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1151 sta->sae->sync = 0;
1152 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001153 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001154 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001155 return WLAN_STATUS_SUCCESS;
1156 sta->sae->sync++;
1157
Sunil Ravi7f769292024-07-23 22:21:32 +00001158 ret = auth_sae_send_confirm(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001159 sae_clear_temp_data(sta->sae);
1160 if (ret)
1161 return ret;
1162 }
1163 break;
1164 default:
1165 wpa_printf(MSG_ERROR, "SAE: invalid state %d",
1166 sta->sae->state);
1167 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1168 }
1169 return WLAN_STATUS_SUCCESS;
1170}
1171
1172
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001173static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
1174{
1175 struct sae_data *sae = sta->sae;
1176 int i, *groups = hapd->conf->sae_groups;
Hai Shalom021b0b52019-04-10 11:17:58 -07001177 int default_groups[] = { 19, 0 };
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001178
1179 if (sae->state != SAE_COMMITTED)
1180 return;
1181
1182 wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
1183
Hai Shalom021b0b52019-04-10 11:17:58 -07001184 if (!groups)
1185 groups = default_groups;
1186 for (i = 0; groups[i] > 0; i++) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001187 if (sae->group == groups[i])
1188 break;
1189 }
1190
Hai Shalom021b0b52019-04-10 11:17:58 -07001191 if (groups[i] <= 0) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001192 wpa_printf(MSG_DEBUG,
1193 "SAE: Previously selected group not found from the current configuration");
1194 return;
1195 }
1196
1197 for (;;) {
1198 i++;
1199 if (groups[i] <= 0) {
1200 wpa_printf(MSG_DEBUG,
1201 "SAE: No alternative group enabled");
1202 return;
1203 }
1204
1205 if (sae_set_group(sae, groups[i]) < 0)
1206 continue;
1207
1208 break;
1209 }
1210 wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
1211}
1212
1213
Hai Shalomc3565922019-10-28 11:58:20 -07001214static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
1215{
Sunil Ravi77d572f2023-01-17 23:58:31 +00001216 enum sae_pwe sae_pwe = hapd->conf->sae_pwe;
Hai Shalomfdcde762020-04-02 11:19:20 -07001217 int id_in_use;
Hai Shalom60840252021-02-19 19:02:11 -08001218 bool sae_pk = false;
Hai Shalomfdcde762020-04-02 11:19:20 -07001219
1220 id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001221 if (id_in_use == 2 && sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
1222 sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
1223 else if (id_in_use == 1 && sae_pwe == SAE_PWE_HUNT_AND_PECK)
1224 sae_pwe = SAE_PWE_BOTH;
Hai Shalom899fcc72020-10-19 14:38:18 -07001225#ifdef CONFIG_SAE_PK
Hai Shalom60840252021-02-19 19:02:11 -08001226 sae_pk = hostapd_sae_pk_in_use(hapd->conf);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001227 if (sae_pwe == SAE_PWE_HUNT_AND_PECK && sae_pk)
1228 sae_pwe = SAE_PWE_BOTH;
Hai Shalom899fcc72020-10-19 14:38:18 -07001229#endif /* CONFIG_SAE_PK */
Sunil Ravi77d572f2023-01-17 23:58:31 +00001230 if (sae_pwe == SAE_PWE_HUNT_AND_PECK &&
Sunil Ravi89eba102022-09-13 21:04:37 -07001231 (hapd->conf->wpa_key_mgmt &
1232 (WPA_KEY_MGMT_SAE_EXT_KEY | WPA_KEY_MGMT_FT_SAE_EXT_KEY)))
Sunil Ravi77d572f2023-01-17 23:58:31 +00001233 sae_pwe = SAE_PWE_BOTH;
Hai Shalomfdcde762020-04-02 11:19:20 -07001234
Sunil Ravi77d572f2023-01-17 23:58:31 +00001235 return ((sae_pwe == SAE_PWE_HUNT_AND_PECK ||
1236 sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001237 status_code == WLAN_STATUS_SUCCESS) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001238 (sae_pwe == SAE_PWE_HASH_TO_ELEMENT &&
Hai Shalom899fcc72020-10-19 14:38:18 -07001239 (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001240 (sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001241 (sae_pwe == SAE_PWE_BOTH &&
Hai Shalomc3565922019-10-28 11:58:20 -07001242 (status_code == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -07001243 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001244 (sae_pk && status_code == WLAN_STATUS_SAE_PK)));
Hai Shalomc3565922019-10-28 11:58:20 -07001245}
1246
1247
1248static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
1249{
1250 int *groups = hapd->conf->sae_groups;
1251 int default_groups[] = { 19, 0 };
1252 int i;
1253
1254 if (!groups)
1255 groups = default_groups;
1256
1257 for (i = 0; groups[i] > 0; i++) {
1258 if (groups[i] == group)
1259 return 1;
1260 }
1261
1262 return 0;
1263}
1264
1265
1266static int check_sae_rejected_groups(struct hostapd_data *hapd,
Hai Shalom899fcc72020-10-19 14:38:18 -07001267 struct sae_data *sae)
Hai Shalomc3565922019-10-28 11:58:20 -07001268{
Hai Shalom899fcc72020-10-19 14:38:18 -07001269 const struct wpabuf *groups;
Sunil Ravi7f769292024-07-23 22:21:32 +00001270 size_t i, count, len;
Hai Shalomc3565922019-10-28 11:58:20 -07001271 const u8 *pos;
1272
Hai Shalom899fcc72020-10-19 14:38:18 -07001273 if (!sae->tmp)
1274 return 0;
1275 groups = sae->tmp->peer_rejected_groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001276 if (!groups)
1277 return 0;
1278
1279 pos = wpabuf_head(groups);
Sunil Ravi7f769292024-07-23 22:21:32 +00001280 len = wpabuf_len(groups);
1281 if (len & 1) {
1282 wpa_printf(MSG_DEBUG,
1283 "SAE: Invalid length of the Rejected Groups element payload: %zu",
1284 len);
1285 return 1;
1286 }
1287
1288 count = len / 2;
Hai Shalomc3565922019-10-28 11:58:20 -07001289 for (i = 0; i < count; i++) {
1290 int enabled;
1291 u16 group;
1292
1293 group = WPA_GET_LE16(pos);
1294 pos += 2;
1295 enabled = sae_is_group_enabled(hapd, group);
1296 wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
1297 group, enabled ? "enabled" : "disabled");
1298 if (enabled)
1299 return 1;
1300 }
1301
1302 return 0;
1303}
1304
1305
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001306static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
1307 const struct ieee80211_mgmt *mgmt, size_t len,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001308 u16 auth_transaction, u16 status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001309{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001310 int resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001311 struct wpabuf *data = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07001312 int *groups = hapd->conf->sae_groups;
1313 int default_groups[] = { 19, 0 };
1314 const u8 *pos, *end;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001315 int sta_removed = 0;
Hai Shalom60840252021-02-19 19:02:11 -08001316 bool success_status;
Hai Shalom021b0b52019-04-10 11:17:58 -07001317
1318 if (!groups)
1319 groups = default_groups;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001320
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001321#ifdef CONFIG_TESTING_OPTIONS
1322 if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001323 wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
1324 pos = mgmt->u.auth.variable;
1325 end = ((const u8 *) mgmt) + len;
Hai Shalom899fcc72020-10-19 14:38:18 -07001326 resp = status_code;
Sunil Ravi7f769292024-07-23 22:21:32 +00001327 send_auth_reply(hapd, sta, sta->addr,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001328 WLAN_AUTH_SAE,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001329 auth_transaction, resp, pos, end - pos,
1330 "auth-sae-reflection-attack");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001331 goto remove_sta;
1332 }
1333
1334 if (hapd->conf->sae_commit_override && auth_transaction == 1) {
1335 wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
Sunil Ravi7f769292024-07-23 22:21:32 +00001336 send_auth_reply(hapd, sta, sta->addr,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001337 WLAN_AUTH_SAE,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001338 auth_transaction, resp,
1339 wpabuf_head(hapd->conf->sae_commit_override),
Roshan Pius3a1667e2018-07-03 15:17:14 -07001340 wpabuf_len(hapd->conf->sae_commit_override),
1341 "sae-commit-override");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001342 goto remove_sta;
1343 }
1344#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001345 if (!sta->sae) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001346 if (auth_transaction != 1 ||
Hai Shalomc3565922019-10-28 11:58:20 -07001347 !sae_status_success(hapd, status_code)) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001348 wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
1349 status_code);
1350 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1351 goto reply;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001352 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001353 sta->sae = os_zalloc(sizeof(*sta->sae));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001354 if (!sta->sae) {
1355 resp = -1;
1356 goto remove_sta;
1357 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001358 sae_set_state(sta, SAE_NOTHING, "Init");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001359 sta->sae->sync = 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001360 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001361
Dmitry Shmidte4663042016-04-04 10:07:49 -07001362 if (sta->mesh_sae_pmksa_caching) {
1363 wpa_printf(MSG_DEBUG,
1364 "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
1365 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
1366 sta->mesh_sae_pmksa_caching = 0;
1367 }
1368
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001369 if (auth_transaction == 1) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001370 const u8 *token = NULL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001371 size_t token_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07001372 int allow_reuse = 0;
1373
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001374 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1375 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001376 "start SAE authentication (RX commit, status=%u (%s))",
1377 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001378
1379 if ((hapd->conf->mesh & MESH_ENABLED) &&
1380 status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
1381 sta->sae->tmp) {
1382 pos = mgmt->u.auth.variable;
1383 end = ((const u8 *) mgmt) + len;
1384 if (pos + sizeof(le16) > end) {
1385 wpa_printf(MSG_ERROR,
1386 "SAE: Too short anti-clogging token request");
1387 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1388 goto reply;
1389 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001390 resp = sae_group_allowed(sta->sae, groups,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001391 WPA_GET_LE16(pos));
1392 if (resp != WLAN_STATUS_SUCCESS) {
1393 wpa_printf(MSG_ERROR,
1394 "SAE: Invalid group in anti-clogging token request");
1395 goto reply;
1396 }
1397 pos += sizeof(le16);
1398
1399 wpabuf_free(sta->sae->tmp->anti_clogging_token);
1400 sta->sae->tmp->anti_clogging_token =
1401 wpabuf_alloc_copy(pos, end - pos);
1402 if (sta->sae->tmp->anti_clogging_token == NULL) {
1403 wpa_printf(MSG_ERROR,
1404 "SAE: Failed to alloc for anti-clogging token");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001405 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1406 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001407 }
1408
1409 /*
1410 * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code
1411 * is 76, a new Commit Message shall be constructed
1412 * with the Anti-Clogging Token from the received
1413 * Authentication frame, and the commit-scalar and
1414 * COMMIT-ELEMENT previously sent.
1415 */
Sunil Ravi7f769292024-07-23 22:21:32 +00001416 resp = auth_sae_send_commit(hapd, sta, 0, status_code);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001417 if (resp != WLAN_STATUS_SUCCESS) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001418 wpa_printf(MSG_ERROR,
1419 "SAE: Failed to send commit message");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001420 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001421 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001422 sae_set_state(sta, SAE_COMMITTED,
1423 "Sent Commit (anti-clogging token case in mesh)");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001424 sta->sae->sync = 0;
1425 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001426 return;
1427 }
1428
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001429 if ((hapd->conf->mesh & MESH_ENABLED) &&
1430 status_code ==
1431 WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1432 sta->sae->tmp) {
1433 wpa_printf(MSG_DEBUG,
1434 "SAE: Peer did not accept our SAE group");
1435 sae_pick_next_group(hapd, sta);
1436 goto remove_sta;
1437 }
1438
Hai Shalomc3565922019-10-28 11:58:20 -07001439 if (!sae_status_success(hapd, status_code))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001440 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001441
Sunil Ravi7f769292024-07-23 22:21:32 +00001442 if (sae_proto_instance_disabled(sta)) {
1443 wpa_printf(MSG_DEBUG,
1444 "SAE: Protocol instance temporarily disabled - discard received SAE commit");
1445 return;
1446 }
1447
Roshan Pius3a1667e2018-07-03 15:17:14 -07001448 if (!(hapd->conf->mesh & MESH_ENABLED) &&
1449 sta->sae->state == SAE_COMMITTED) {
1450 /* This is needed in the infrastructure BSS case to
1451 * address a sequence where a STA entry may remain in
1452 * hostapd across two attempts to do SAE authentication
1453 * by the same STA. The second attempt may end up trying
1454 * to use a different group and that would not be
1455 * allowed if we remain in Committed state with the
1456 * previously set parameters. */
Hai Shalom021b0b52019-04-10 11:17:58 -07001457 pos = mgmt->u.auth.variable;
1458 end = ((const u8 *) mgmt) + len;
1459 if (end - pos >= (int) sizeof(le16) &&
1460 sae_group_allowed(sta->sae, groups,
1461 WPA_GET_LE16(pos)) ==
1462 WLAN_STATUS_SUCCESS) {
1463 /* Do not waste resources deriving the same PWE
1464 * again since the same group is reused. */
1465 sae_set_state(sta, SAE_NOTHING,
1466 "Allow previous PWE to be reused");
1467 allow_reuse = 1;
1468 } else {
1469 sae_set_state(sta, SAE_NOTHING,
1470 "Clear existing state to allow restart");
1471 sae_clear_data(sta->sae);
1472 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001473 }
1474
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001475 resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
1476 ((const u8 *) mgmt) + len -
1477 mgmt->u.auth.variable, &token,
Hai Shalomc3565922019-10-28 11:58:20 -07001478 &token_len, groups, status_code ==
Hai Shalom899fcc72020-10-19 14:38:18 -07001479 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001480 status_code == WLAN_STATUS_SAE_PK,
1481 NULL);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001482 if (resp == SAE_SILENTLY_DISCARD) {
1483 wpa_printf(MSG_DEBUG,
1484 "SAE: Drop commit message from " MACSTR " due to reflection attack",
1485 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001486 goto remove_sta;
Dmitry Shmidt41712582015-06-29 11:02:15 -07001487 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001488
1489 if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
1490 wpa_msg(hapd->msg_ctx, MSG_INFO,
1491 WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
1492 MACSTR, MAC2STR(sta->addr));
1493 sae_clear_retransmit_timer(hapd, sta);
1494 sae_set_state(sta, SAE_NOTHING,
1495 "Unknown Password Identifier");
1496 goto remove_sta;
1497 }
1498
Hai Shaloma20dcd72022-02-04 13:43:00 -08001499 if (token &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00001500 check_comeback_token(hapd->comeback_key,
1501 hapd->comeback_pending_idx, sta->addr,
1502 token, token_len)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001503 < 0) {
1504 wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
1505 "incorrect token from " MACSTR,
1506 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001507 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1508 goto remove_sta;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001509 }
1510
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001511 if (resp != WLAN_STATUS_SUCCESS)
1512 goto reply;
1513
Hai Shalom899fcc72020-10-19 14:38:18 -07001514 if (check_sae_rejected_groups(hapd, sta->sae)) {
Hai Shalomc3565922019-10-28 11:58:20 -07001515 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001516 goto reply;
Hai Shalomc3565922019-10-28 11:58:20 -07001517 }
1518
Hai Shaloma20dcd72022-02-04 13:43:00 -08001519 if (!token && use_anti_clogging(hapd) && !allow_reuse) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001520 int h2e = 0;
1521
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001522 wpa_printf(MSG_DEBUG,
1523 "SAE: Request anti-clogging token from "
1524 MACSTR, MAC2STR(sta->addr));
Hai Shalomfdcde762020-04-02 11:19:20 -07001525 if (sta->sae->tmp)
Hai Shalom899fcc72020-10-19 14:38:18 -07001526 h2e = sta->sae->h2e;
1527 if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1528 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomfdcde762020-04-02 11:19:20 -07001529 h2e = 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001530 data = auth_build_token_req(
1531 &hapd->last_comeback_key_update,
1532 hapd->comeback_key,
1533 hapd->comeback_idx,
1534 hapd->comeback_pending_idx,
1535 sizeof(hapd->comeback_pending_idx),
1536 sta->sae->group,
1537 sta->addr, h2e);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001538 resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
1539 if (hapd->conf->mesh & MESH_ENABLED)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001540 sae_set_state(sta, SAE_NOTHING,
1541 "Request anti-clogging token case in mesh");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001542 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001543 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001544
Sunil Ravi7f769292024-07-23 22:21:32 +00001545 resp = sae_sm_step(hapd, sta, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001546 status_code, allow_reuse, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001547 } else if (auth_transaction == 2) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001548 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1549 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001550 "SAE authentication (RX confirm, status=%u (%s))",
1551 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001552 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001553 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001554 if (sta->sae->state >= SAE_CONFIRMED ||
1555 !(hapd->conf->mesh & MESH_ENABLED)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001556 const u8 *var;
1557 size_t var_len;
1558 u16 peer_send_confirm;
1559
1560 var = mgmt->u.auth.variable;
1561 var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable;
1562 if (var_len < 2) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001563 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001564 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001565 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001566
1567 peer_send_confirm = WPA_GET_LE16(var);
1568
1569 if (sta->sae->state == SAE_ACCEPTED &&
1570 (peer_send_confirm <= sta->sae->rc ||
1571 peer_send_confirm == 0xffff)) {
1572 wpa_printf(MSG_DEBUG,
1573 "SAE: Silently ignore unexpected Confirm from peer "
1574 MACSTR
1575 " (peer-send-confirm=%u Rc=%u)",
1576 MAC2STR(sta->addr),
1577 peer_send_confirm, sta->sae->rc);
1578 return;
1579 }
1580
Sunil Ravi77d572f2023-01-17 23:58:31 +00001581 if (sae_check_confirm(sta->sae, var, var_len,
1582 NULL) < 0) {
1583 resp = WLAN_STATUS_CHALLENGE_FAIL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001584 goto reply;
1585 }
1586 sta->sae->rc = peer_send_confirm;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001587 }
Sunil Ravi7f769292024-07-23 22:21:32 +00001588 resp = sae_sm_step(hapd, sta, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001589 status_code, 0, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001590 } else {
1591 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1592 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001593 "unexpected SAE authentication transaction %u (status=%u (%s))",
1594 auth_transaction, status_code,
1595 status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001596 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001597 goto remove_sta;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001598 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1599 }
1600
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001601reply:
Hai Shalom5f92bc92019-04-18 11:54:11 -07001602 if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001603 pos = mgmt->u.auth.variable;
1604 end = ((const u8 *) mgmt) + len;
1605
1606 /* Copy the Finite Cyclic Group field from the request if we
1607 * rejected it as unsupported group. */
1608 if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1609 !data && end - pos >= 2)
1610 data = wpabuf_alloc_copy(pos, 2);
1611
Hai Shalom5f92bc92019-04-18 11:54:11 -07001612 sae_sme_send_external_auth_status(hapd, sta, resp);
Sunil Ravi7f769292024-07-23 22:21:32 +00001613 send_auth_reply(hapd, sta, sta->addr,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001614 WLAN_AUTH_SAE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001615 auth_transaction, resp,
1616 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07001617 data ? wpabuf_len(data) : 0, "auth-sae");
Sunil Ravi7f769292024-07-23 22:21:32 +00001618 if (sta->sae && sta->sae->tmp && sta->sae->tmp->pw_id &&
1619 resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER &&
1620 auth_transaction == 1) {
1621 wpa_printf(MSG_DEBUG,
1622 "SAE: Clear stored password identifier since this SAE commit was not accepted");
1623 os_free(sta->sae->tmp->pw_id);
1624 sta->sae->tmp->pw_id = NULL;
1625 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001626 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001627
1628remove_sta:
Hai Shalom60840252021-02-19 19:02:11 -08001629 if (auth_transaction == 1)
1630 success_status = sae_status_success(hapd, status_code);
1631 else
1632 success_status = status_code == WLAN_STATUS_SUCCESS;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001633 if (!sta_removed && sta->added_unassoc &&
Hai Shalom60840252021-02-19 19:02:11 -08001634 (resp != WLAN_STATUS_SUCCESS || !success_status)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001635 hostapd_drv_sta_remove(hapd, sta->addr);
1636 sta->added_unassoc = 0;
1637 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001638 wpabuf_free(data);
1639}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001640
1641
1642/**
1643 * auth_sae_init_committed - Send COMMIT and start SAE in committed state
1644 * @hapd: BSS data for the device initiating the authentication
1645 * @sta: the peer to which commit authentication frame is sent
1646 *
1647 * This function implements Init event handling (IEEE Std 802.11-2012,
1648 * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
1649 * sta->sae structure should be initialized appropriately via a call to
1650 * sae_prepare_commit().
1651 */
1652int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
1653{
1654 int ret;
1655
1656 if (!sta->sae || !sta->sae->tmp)
1657 return -1;
1658
1659 if (sta->sae->state != SAE_NOTHING)
1660 return -1;
1661
Sunil Ravi7f769292024-07-23 22:21:32 +00001662 ret = auth_sae_send_commit(hapd, sta, 0, -1);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001663 if (ret)
1664 return -1;
1665
Roshan Pius3a1667e2018-07-03 15:17:14 -07001666 sae_set_state(sta, SAE_COMMITTED, "Init and sent commit");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001667 sta->sae->sync = 0;
1668 sae_set_retransmit_timer(hapd, sta);
1669
1670 return 0;
1671}
1672
Hai Shalom021b0b52019-04-10 11:17:58 -07001673
1674void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
1675{
1676 struct hostapd_data *hapd = eloop_ctx;
1677 struct hostapd_sae_commit_queue *q;
1678 unsigned int queue_len;
1679
1680 q = dl_list_first(&hapd->sae_commit_queue,
1681 struct hostapd_sae_commit_queue, list);
1682 if (!q)
1683 return;
1684 wpa_printf(MSG_DEBUG,
1685 "SAE: Process next available message from queue");
1686 dl_list_del(&q->list);
1687 handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
1688 q->rssi, 1);
1689 os_free(q);
1690
1691 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1692 return;
1693 queue_len = dl_list_len(&hapd->sae_commit_queue);
1694 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1695 hapd, NULL);
1696}
1697
1698
1699static void auth_sae_queue(struct hostapd_data *hapd,
1700 const struct ieee80211_mgmt *mgmt, size_t len,
1701 int rssi)
1702{
1703 struct hostapd_sae_commit_queue *q, *q2;
1704 unsigned int queue_len;
1705 const struct ieee80211_mgmt *mgmt2;
1706
1707 queue_len = dl_list_len(&hapd->sae_commit_queue);
1708 if (queue_len >= 15) {
1709 wpa_printf(MSG_DEBUG,
1710 "SAE: No more room in message queue - drop the new frame from "
1711 MACSTR, MAC2STR(mgmt->sa));
1712 return;
1713 }
1714
1715 wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
1716 MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
1717 queue_len);
1718 q = os_zalloc(sizeof(*q) + len);
1719 if (!q)
1720 return;
1721 q->rssi = rssi;
1722 q->len = len;
1723 os_memcpy(q->msg, mgmt, len);
1724
1725 /* Check whether there is already a queued Authentication frame from the
1726 * same station with the same transaction number and if so, replace that
1727 * queue entry with the new one. This avoids issues with a peer that
1728 * sends multiple times (e.g., due to frequent SAE retries). There is no
1729 * point in us trying to process the old attempts after a new one has
1730 * obsoleted them. */
1731 dl_list_for_each(q2, &hapd->sae_commit_queue,
1732 struct hostapd_sae_commit_queue, list) {
1733 mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001734 if (ether_addr_equal(mgmt->sa, mgmt2->sa) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07001735 mgmt->u.auth.auth_transaction ==
1736 mgmt2->u.auth.auth_transaction) {
1737 wpa_printf(MSG_DEBUG,
1738 "SAE: Replace queued message from same STA with same transaction number");
1739 dl_list_add(&q2->list, &q->list);
1740 dl_list_del(&q2->list);
1741 os_free(q2);
1742 goto queued;
1743 }
1744 }
1745
1746 /* No pending identical entry, so add to the end of the queue */
1747 dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
1748
1749queued:
1750 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1751 return;
1752 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1753 hapd, NULL);
1754}
1755
1756
1757static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
1758{
1759 struct hostapd_sae_commit_queue *q;
1760 const struct ieee80211_mgmt *mgmt;
1761
1762 dl_list_for_each(q, &hapd->sae_commit_queue,
1763 struct hostapd_sae_commit_queue, list) {
1764 mgmt = (const struct ieee80211_mgmt *) q->msg;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001765 if (ether_addr_equal(addr, mgmt->sa))
Hai Shalom021b0b52019-04-10 11:17:58 -07001766 return 1;
1767 }
1768
1769 return 0;
1770}
1771
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001772#endif /* CONFIG_SAE */
1773
1774
Hai Shalomfdcde762020-04-02 11:19:20 -07001775static u16 wpa_res_to_status_code(enum wpa_validate_result res)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001776{
Hai Shalomfdcde762020-04-02 11:19:20 -07001777 switch (res) {
1778 case WPA_IE_OK:
1779 return WLAN_STATUS_SUCCESS;
1780 case WPA_INVALID_IE:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001781 return WLAN_STATUS_INVALID_IE;
Hai Shalomfdcde762020-04-02 11:19:20 -07001782 case WPA_INVALID_GROUP:
1783 return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
1784 case WPA_INVALID_PAIRWISE:
1785 return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
1786 case WPA_INVALID_AKMP:
1787 return WLAN_STATUS_AKMP_NOT_VALID;
1788 case WPA_NOT_ENABLED:
1789 return WLAN_STATUS_INVALID_IE;
1790 case WPA_ALLOC_FAIL:
1791 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1792 case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
1793 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
1794 case WPA_INVALID_MGMT_GROUP_CIPHER:
1795 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
1796 case WPA_INVALID_MDIE:
1797 return WLAN_STATUS_INVALID_MDIE;
1798 case WPA_INVALID_PROTO:
1799 return WLAN_STATUS_INVALID_IE;
1800 case WPA_INVALID_PMKID:
1801 return WLAN_STATUS_INVALID_PMKID;
1802 case WPA_DENIED_OTHER_REASON:
1803 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
1804 }
1805 return WLAN_STATUS_INVALID_IE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001806}
1807
1808
1809#ifdef CONFIG_FILS
1810
1811static void handle_auth_fils_finish(struct hostapd_data *hapd,
1812 struct sta_info *sta, u16 resp,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001813 struct wpabuf *data, int pub);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001814
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001815void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
1816 const u8 *pos, size_t len, u16 auth_alg,
1817 u16 auth_transaction, u16 status_code,
1818 void (*cb)(struct hostapd_data *hapd,
1819 struct sta_info *sta, u16 resp,
1820 struct wpabuf *data, int pub))
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001821{
1822 u16 resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001823 const u8 *end;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001824 struct ieee802_11_elems elems;
Hai Shalomfdcde762020-04-02 11:19:20 -07001825 enum wpa_validate_result res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001826 struct wpa_ie_data rsn;
1827 struct rsn_pmksa_cache_entry *pmksa = NULL;
1828
1829 if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
1830 return;
1831
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001832 end = pos + len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001833
1834 wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
1835 pos, end - pos);
1836
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001837 /* TODO: FILS PK */
1838#ifdef CONFIG_FILS_SK_PFS
1839 if (auth_alg == WLAN_AUTH_FILS_SK_PFS) {
1840 u16 group;
1841 struct wpabuf *pub;
1842 size_t elem_len;
1843
1844 /* Using FILS PFS */
1845
1846 /* Finite Cyclic Group */
1847 if (end - pos < 2) {
1848 wpa_printf(MSG_DEBUG,
1849 "FILS: No room for Finite Cyclic Group");
1850 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1851 goto fail;
1852 }
1853 group = WPA_GET_LE16(pos);
1854 pos += 2;
1855 if (group != hapd->conf->fils_dh_group) {
1856 wpa_printf(MSG_DEBUG,
1857 "FILS: Unsupported Finite Cyclic Group: %u (expected %u)",
1858 group, hapd->conf->fils_dh_group);
1859 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1860 goto fail;
1861 }
1862
1863 crypto_ecdh_deinit(sta->fils_ecdh);
1864 sta->fils_ecdh = crypto_ecdh_init(group);
1865 if (!sta->fils_ecdh) {
1866 wpa_printf(MSG_INFO,
1867 "FILS: Could not initialize ECDH with group %d",
1868 group);
1869 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1870 goto fail;
1871 }
1872
1873 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
1874 if (!pub) {
1875 wpa_printf(MSG_DEBUG,
1876 "FILS: Failed to derive ECDH public key");
1877 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1878 goto fail;
1879 }
1880 elem_len = wpabuf_len(pub);
1881 wpabuf_free(pub);
1882
1883 /* Element */
1884 if ((size_t) (end - pos) < elem_len) {
1885 wpa_printf(MSG_DEBUG, "FILS: No room for Element");
1886 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1887 goto fail;
1888 }
1889
1890 wpabuf_free(sta->fils_g_sta);
1891 sta->fils_g_sta = wpabuf_alloc_copy(pos, elem_len);
1892 wpabuf_clear_free(sta->fils_dh_ss);
1893 sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1,
1894 pos, elem_len);
1895 if (!sta->fils_dh_ss) {
1896 wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
1897 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1898 goto fail;
1899 }
1900 wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss);
1901 pos += elem_len;
1902 } else {
1903 crypto_ecdh_deinit(sta->fils_ecdh);
1904 sta->fils_ecdh = NULL;
1905 wpabuf_clear_free(sta->fils_dh_ss);
1906 sta->fils_dh_ss = NULL;
1907 }
1908#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001909
1910 wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
1911 if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
1912 wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
1913 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1914 goto fail;
1915 }
1916
1917 /* RSNE */
1918 wpa_hexdump(MSG_DEBUG, "FILS: RSN element",
1919 elems.rsn_ie, elems.rsn_ie_len);
1920 if (!elems.rsn_ie ||
1921 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
1922 &rsn) < 0) {
1923 wpa_printf(MSG_DEBUG, "FILS: No valid RSN element");
1924 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1925 goto fail;
1926 }
1927
1928 if (!sta->wpa_sm)
1929 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
1930 NULL);
1931 if (!sta->wpa_sm) {
1932 wpa_printf(MSG_DEBUG,
1933 "FILS: Failed to initialize RSN state machine");
1934 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1935 goto fail;
1936 }
1937
1938 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07001939 hapd->iface->freq,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001940 elems.rsn_ie - 2, elems.rsn_ie_len + 2,
Hai Shalomc3565922019-10-28 11:58:20 -07001941 elems.rsnxe ? elems.rsnxe - 2 : NULL,
1942 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Sunil Ravi7f769292024-07-23 22:21:32 +00001943 elems.mdie, elems.mdie_len, NULL, 0, NULL);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001944 resp = wpa_res_to_status_code(res);
1945 if (resp != WLAN_STATUS_SUCCESS)
1946 goto fail;
1947
Sunil Ravi7f769292024-07-23 22:21:32 +00001948 wpa_auth_set_rsn_override(sta->wpa_sm, elems.rsne_override != NULL);
1949 wpa_auth_set_rsn_override_2(sta->wpa_sm, elems.rsne_override_2 != NULL);
1950
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001951 if (!elems.fils_nonce) {
1952 wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
1953 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1954 goto fail;
1955 }
1956 wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce,
1957 FILS_NONCE_LEN);
1958 os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN);
1959
1960 /* PMKID List */
1961 if (rsn.pmkid && rsn.num_pmkid > 0) {
1962 u8 num;
1963 const u8 *pmkid;
1964
1965 wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
1966 rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
1967
1968 pmkid = rsn.pmkid;
1969 num = rsn.num_pmkid;
1970 while (num) {
1971 wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
1972 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
1973 pmkid);
1974 if (pmksa)
1975 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001976 pmksa = wpa_auth_pmksa_get_fils_cache_id(hapd->wpa_auth,
1977 sta->addr,
1978 pmkid);
1979 if (pmksa)
1980 break;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001981 pmkid += PMKID_LEN;
1982 num--;
1983 }
1984 }
1985 if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) {
1986 wpa_printf(MSG_DEBUG,
1987 "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore",
1988 wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp);
1989 pmksa = NULL;
1990 }
1991 if (pmksa)
1992 wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry");
1993
1994 /* FILS Session */
1995 if (!elems.fils_session) {
1996 wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
1997 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1998 goto fail;
1999 }
2000 wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
2001 FILS_SESSION_LEN);
2002 os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
2003
Hai Shalomfdcde762020-04-02 11:19:20 -07002004 /* Wrapped Data */
2005 if (elems.wrapped_data) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002006 wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
Hai Shalomfdcde762020-04-02 11:19:20 -07002007 elems.wrapped_data,
2008 elems.wrapped_data_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002009 if (!pmksa) {
2010#ifndef CONFIG_NO_RADIUS
2011 if (!sta->eapol_sm) {
2012 sta->eapol_sm =
2013 ieee802_1x_alloc_eapol_sm(hapd, sta);
2014 }
2015 wpa_printf(MSG_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002016 "FILS: Forward EAP-Initiate/Re-auth to authentication server");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002017 ieee802_1x_encapsulate_radius(
Hai Shalomfdcde762020-04-02 11:19:20 -07002018 hapd, sta, elems.wrapped_data,
2019 elems.wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002020 sta->fils_pending_cb = cb;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002021 wpa_printf(MSG_DEBUG,
2022 "FILS: Will send Authentication frame once the response from authentication server is available");
2023 sta->flags |= WLAN_STA_PENDING_FILS_ERP;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002024 /* Calculate pending PMKID here so that we do not need
2025 * to maintain a copy of the EAP-Initiate/Reauth
2026 * message. */
2027 if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
Hai Shalomfdcde762020-04-02 11:19:20 -07002028 elems.wrapped_data,
2029 elems.wrapped_data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002030 sta->fils_erp_pmkid) == 0)
2031 sta->fils_erp_pmkid_set = 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002032 return;
2033#else /* CONFIG_NO_RADIUS */
2034 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2035 goto fail;
2036#endif /* CONFIG_NO_RADIUS */
2037 }
2038 }
2039
2040fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002041 if (cb) {
2042 struct wpabuf *data;
2043 int pub = 0;
2044
2045 data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, NULL,
2046 NULL, 0, &pub);
2047 if (!data) {
2048 wpa_printf(MSG_DEBUG,
2049 "%s: prepare_auth_resp_fils() returned failure",
2050 __func__);
2051 }
2052
2053 cb(hapd, sta, resp, data, pub);
2054 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002055}
2056
2057
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002058static struct wpabuf *
2059prepare_auth_resp_fils(struct hostapd_data *hapd,
2060 struct sta_info *sta, u16 *resp,
2061 struct rsn_pmksa_cache_entry *pmksa,
2062 struct wpabuf *erp_resp,
2063 const u8 *msk, size_t msk_len,
2064 int *is_pub)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002065{
2066 u8 fils_nonce[FILS_NONCE_LEN];
2067 size_t ielen;
2068 struct wpabuf *data = NULL;
2069 const u8 *ie;
2070 u8 *ie_buf = NULL;
2071 const u8 *pmk = NULL;
2072 size_t pmk_len = 0;
Paul Stewart092955c2017-02-06 09:13:09 -08002073 u8 pmk_buf[PMK_LEN_MAX];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002074 struct wpabuf *pub = NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002075
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002076 if (*resp != WLAN_STATUS_SUCCESS)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002077 goto fail;
2078
2079 ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
2080 if (!ie) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002081 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002082 goto fail;
2083 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002084
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002085 if (pmksa) {
2086 /* Add PMKID of the selected PMKSA into RSNE */
2087 ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN);
2088 if (!ie_buf) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002089 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002090 goto fail;
2091 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002092
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002093 os_memcpy(ie_buf, ie, ielen);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002094 if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid, true) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002095 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002096 goto fail;
2097 }
2098 ie = ie_buf;
2099 }
2100
2101 if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002102 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002103 goto fail;
2104 }
2105 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
2106 fils_nonce, FILS_NONCE_LEN);
2107
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002108#ifdef CONFIG_FILS_SK_PFS
2109 if (sta->fils_dh_ss && sta->fils_ecdh) {
2110 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
2111 if (!pub) {
2112 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2113 goto fail;
2114 }
2115 }
2116#endif /* CONFIG_FILS_SK_PFS */
2117
2118 data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0));
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002119 if (!data) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002120 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002121 goto fail;
2122 }
2123
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002124 /* TODO: FILS PK */
2125#ifdef CONFIG_FILS_SK_PFS
2126 if (pub) {
2127 /* Finite Cyclic Group */
2128 wpabuf_put_le16(data, hapd->conf->fils_dh_group);
2129
2130 /* Element */
2131 wpabuf_put_buf(data, pub);
2132 }
2133#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002134
2135 /* RSNE */
2136 wpabuf_put_data(data, ie, ielen);
2137
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002138 /* MDE when using FILS+FT (already included in ie,ielen with RSNE) */
2139
2140#ifdef CONFIG_IEEE80211R_AP
2141 if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
2142 /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
2143 int res;
2144
Sunil Ravi77d572f2023-01-17 23:58:31 +00002145 res = wpa_auth_write_fte(hapd->wpa_auth, sta->wpa_sm,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002146 wpabuf_put(data, 0),
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002147 wpabuf_tailroom(data));
2148 if (res < 0) {
2149 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2150 goto fail;
2151 }
2152 wpabuf_put(data, res);
2153 }
2154#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002155
2156 /* FILS Nonce */
2157 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2158 wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */
2159 /* Element ID Extension */
2160 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE);
2161 wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN);
2162
2163 /* FILS Session */
2164 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2165 wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */
2166 /* Element ID Extension */
2167 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
2168 wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
2169
Hai Shalomfdcde762020-04-02 11:19:20 -07002170 /* Wrapped Data */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002171 if (!pmksa && erp_resp) {
2172 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2173 wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
2174 /* Element ID Extension */
Hai Shalomfdcde762020-04-02 11:19:20 -07002175 wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002176 wpabuf_put_buf(data, erp_resp);
2177
Paul Stewart092955c2017-02-06 09:13:09 -08002178 if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
2179 msk, msk_len, sta->fils_snonce, fils_nonce,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002180 sta->fils_dh_ss ?
2181 wpabuf_head(sta->fils_dh_ss) : NULL,
2182 sta->fils_dh_ss ?
2183 wpabuf_len(sta->fils_dh_ss) : 0,
2184 pmk_buf, &pmk_len)) {
Paul Stewart092955c2017-02-06 09:13:09 -08002185 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002186 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Paul Stewart092955c2017-02-06 09:13:09 -08002187 wpabuf_free(data);
2188 data = NULL;
2189 goto fail;
2190 }
2191 pmk = pmk_buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002192
2193 /* Don't use DHss in PTK derivation if PMKSA caching is not
2194 * used. */
2195 wpabuf_clear_free(sta->fils_dh_ss);
2196 sta->fils_dh_ss = NULL;
2197
2198 if (sta->fils_erp_pmkid_set) {
2199 /* TODO: get PMKLifetime from WPA parameters */
2200 unsigned int dot11RSNAConfigPMKLifetime = 43200;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002201 int session_timeout;
2202
2203 session_timeout = dot11RSNAConfigPMKLifetime;
2204 if (sta->session_timeout_set) {
2205 struct os_reltime now, diff;
2206
2207 os_get_reltime(&now);
2208 os_reltime_sub(&sta->session_timeout, &now,
2209 &diff);
2210 session_timeout = diff.sec;
2211 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002212
2213 sta->fils_erp_pmkid_set = 0;
Hai Shalom81f62d82019-07-22 12:10:00 -07002214 wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
2215 sta->fils_erp_pmkid);
Hai Shalom021b0b52019-04-10 11:17:58 -07002216 if (!hapd->conf->disable_pmksa_caching &&
2217 wpa_auth_pmksa_add2(
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002218 hapd->wpa_auth, sta->addr,
2219 pmk, pmk_len,
2220 sta->fils_erp_pmkid,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002221 session_timeout,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002222 wpa_auth_sta_key_mgmt(sta->wpa_sm),
2223 NULL) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002224 wpa_printf(MSG_ERROR,
2225 "FILS: Failed to add PMKSA cache entry based on ERP");
2226 }
2227 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002228 } else if (pmksa) {
2229 pmk = pmksa->pmk;
2230 pmk_len = pmksa->pmk_len;
2231 }
2232
2233 if (!pmk) {
2234 wpa_printf(MSG_DEBUG, "FILS: No PMK available");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002235 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002236 wpabuf_free(data);
2237 data = NULL;
2238 goto fail;
2239 }
2240
2241 if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002242 sta->fils_snonce, fils_nonce,
2243 sta->fils_dh_ss ?
2244 wpabuf_head(sta->fils_dh_ss) : NULL,
2245 sta->fils_dh_ss ?
2246 wpabuf_len(sta->fils_dh_ss) : 0,
2247 sta->fils_g_sta, pub) < 0) {
2248 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002249 wpabuf_free(data);
2250 data = NULL;
2251 goto fail;
2252 }
2253
2254fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002255 if (is_pub)
2256 *is_pub = pub != NULL;
2257 os_free(ie_buf);
2258 wpabuf_free(pub);
2259 wpabuf_clear_free(sta->fils_dh_ss);
2260 sta->fils_dh_ss = NULL;
2261#ifdef CONFIG_FILS_SK_PFS
2262 crypto_ecdh_deinit(sta->fils_ecdh);
2263 sta->fils_ecdh = NULL;
2264#endif /* CONFIG_FILS_SK_PFS */
2265 return data;
2266}
2267
2268
2269static void handle_auth_fils_finish(struct hostapd_data *hapd,
2270 struct sta_info *sta, u16 resp,
2271 struct wpabuf *data, int pub)
2272{
2273 u16 auth_alg;
2274
2275 auth_alg = (pub ||
2276 resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
2277 WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Sunil Ravi7f769292024-07-23 22:21:32 +00002278 send_auth_reply(hapd, sta, sta->addr, auth_alg, 2, resp,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002279 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07002280 data ? wpabuf_len(data) : 0, "auth-fils-finish");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002281 wpabuf_free(data);
2282
2283 if (resp == WLAN_STATUS_SUCCESS) {
2284 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2285 HOSTAPD_LEVEL_DEBUG,
2286 "authentication OK (FILS)");
2287 sta->flags |= WLAN_STA_AUTH;
2288 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002289 sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002290 mlme_authenticate_indication(hapd, sta);
2291 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002292}
2293
2294
2295void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
2296 struct sta_info *sta, int success,
2297 struct wpabuf *erp_resp,
2298 const u8 *msk, size_t msk_len)
2299{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002300 u16 resp;
Hai Shalom60840252021-02-19 19:02:11 -08002301 u32 flags = sta->flags;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002302
Hai Shalom60840252021-02-19 19:02:11 -08002303 sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
2304 WLAN_STA_PENDING_PASN_FILS_ERP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002305
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002306 resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
Hai Shalom60840252021-02-19 19:02:11 -08002307
2308 if (flags & WLAN_STA_PENDING_FILS_ERP) {
2309 struct wpabuf *data;
2310 int pub = 0;
2311
2312 if (!sta->fils_pending_cb)
2313 return;
2314
2315 data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
2316 msk, msk_len, &pub);
2317 if (!data) {
2318 wpa_printf(MSG_DEBUG,
2319 "%s: prepare_auth_resp_fils() failure",
2320 __func__);
2321 }
2322 sta->fils_pending_cb(hapd, sta, resp, data, pub);
2323#ifdef CONFIG_PASN
2324 } else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
2325 pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
2326 msk, msk_len);
2327#endif /* CONFIG_PASN */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002328 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002329}
2330
2331#endif /* CONFIG_FILS */
2332
2333
Hai Shalomfdcde762020-04-02 11:19:20 -07002334static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
2335 const u8 *msg, size_t len,
2336 struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002337{
2338 int res;
2339
Hai Shalomfdcde762020-04-02 11:19:20 -07002340 res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002341
2342 if (res == HOSTAPD_ACL_REJECT) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002343 wpa_printf(MSG_DEBUG, "Station " MACSTR
2344 " not allowed to authenticate",
2345 MAC2STR(addr));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002346 return HOSTAPD_ACL_REJECT;
2347 }
2348
2349 if (res == HOSTAPD_ACL_PENDING) {
2350 wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
2351 " waiting for an external authentication",
2352 MAC2STR(addr));
2353 /* Authentication code will re-send the authentication frame
2354 * after it has received (and cached) information from the
2355 * external source. */
2356 return HOSTAPD_ACL_PENDING;
2357 }
2358
2359 return res;
2360}
2361
2362
Sunil Ravia04bd252022-05-02 22:54:18 -07002363int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
2364 int res, struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002365{
Hai Shalomfdcde762020-04-02 11:19:20 -07002366 u32 session_timeout = info->session_timeout;
2367 u32 acct_interim_interval = info->acct_interim_interval;
2368 struct vlan_description *vlan_id = &info->vlan_id;
2369 struct hostapd_sta_wpa_psk_short *psk = info->psk;
2370 char *identity = info->identity;
2371 char *radius_cui = info->radius_cui;
2372
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002373 if (vlan_id->notempty &&
2374 !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
2375 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2376 HOSTAPD_LEVEL_INFO,
2377 "Invalid VLAN %d%s received from RADIUS server",
2378 vlan_id->untagged,
2379 vlan_id->tagged[0] ? "+" : "");
2380 return -1;
2381 }
2382 if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
2383 return -1;
2384 if (sta->vlan_id)
2385 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2386 HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
2387
2388 hostapd_free_psk_list(sta->psk);
Hai Shalomfdcde762020-04-02 11:19:20 -07002389 if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
2390 hostapd_copy_psk_list(&sta->psk, psk);
2391 else
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002392 sta->psk = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002393
Roshan Pius3a1667e2018-07-03 15:17:14 -07002394 os_free(sta->identity);
Hai Shalomfdcde762020-04-02 11:19:20 -07002395 if (identity)
2396 sta->identity = os_strdup(identity);
2397 else
2398 sta->identity = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002399
2400 os_free(sta->radius_cui);
Hai Shalomfdcde762020-04-02 11:19:20 -07002401 if (radius_cui)
2402 sta->radius_cui = os_strdup(radius_cui);
2403 else
2404 sta->radius_cui = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002405
2406 if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
2407 sta->acct_interim_interval = acct_interim_interval;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002408 if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
2409 sta->session_timeout_set = 1;
2410 os_get_reltime(&sta->session_timeout);
2411 sta->session_timeout.sec += session_timeout;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002412 ap_sta_session_timeout(hapd, sta, session_timeout);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002413 } else {
2414 sta->session_timeout_set = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002415 ap_sta_no_session_timeout(hapd, sta);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002416 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002417
2418 return 0;
2419}
2420
2421
Hai Shalom60840252021-02-19 19:02:11 -08002422#ifdef CONFIG_PASN
Hai Shalom60840252021-02-19 19:02:11 -08002423#ifdef CONFIG_FILS
2424
Hai Shalom60840252021-02-19 19:02:11 -08002425static void pasn_fils_auth_resp(struct hostapd_data *hapd,
2426 struct sta_info *sta, u16 status,
2427 struct wpabuf *erp_resp,
2428 const u8 *msk, size_t msk_len)
2429{
2430 struct pasn_data *pasn = sta->pasn;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002431 struct pasn_fils *fils = &pasn->fils;
Hai Shalom60840252021-02-19 19:02:11 -08002432 u8 pmk[PMK_LEN_MAX];
2433 size_t pmk_len;
2434 int ret;
2435
2436 wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
2437 status);
2438
2439 if (status != WLAN_STATUS_SUCCESS)
2440 goto fail;
2441
2442 if (!pasn->secret) {
2443 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
2444 goto fail;
2445 }
2446
2447 if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
2448 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
2449 goto fail;
2450 }
2451
2452 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
2453 fils->anonce, FILS_NONCE_LEN);
2454
Sunil Ravi99c035e2024-07-12 01:42:03 +00002455 ret = fils_rmsk_to_pmk(pasn_get_akmp(pasn), msk, msk_len, fils->nonce,
Hai Shalom60840252021-02-19 19:02:11 -08002456 fils->anonce, NULL, 0, pmk, &pmk_len);
2457 if (ret) {
2458 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
2459 goto fail;
2460 }
2461
2462 ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
2463 wpabuf_head(pasn->secret),
2464 wpabuf_len(pasn->secret),
Sunil Ravi99c035e2024-07-12 01:42:03 +00002465 pasn_get_ptk(sta->pasn), pasn_get_akmp(sta->pasn),
2466 pasn_get_cipher(sta->pasn), sta->pasn->kdk_len);
Hai Shalom60840252021-02-19 19:02:11 -08002467 if (ret) {
2468 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
2469 goto fail;
2470 }
2471
Sunil Ravi89eba102022-09-13 21:04:37 -07002472 if (pasn->secure_ltf) {
Sunil Ravi99c035e2024-07-12 01:42:03 +00002473 ret = wpa_ltf_keyseed(pasn_get_ptk(pasn), pasn_get_akmp(pasn),
2474 pasn_get_cipher(pasn));
Sunil Ravi89eba102022-09-13 21:04:37 -07002475 if (ret) {
2476 wpa_printf(MSG_DEBUG,
2477 "PASN: FILS: Failed to derive LTF keyseed");
2478 goto fail;
2479 }
2480 }
2481
Hai Shalom60840252021-02-19 19:02:11 -08002482 wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
2483
2484 wpabuf_free(pasn->secret);
2485 pasn->secret = NULL;
2486
2487 fils->erp_resp = erp_resp;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002488 ret = handle_auth_pasn_resp(sta->pasn, hapd->own_addr, sta->addr, NULL,
2489 WLAN_STATUS_SUCCESS);
Hai Shalom60840252021-02-19 19:02:11 -08002490 fils->erp_resp = NULL;
2491
2492 if (ret) {
2493 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
2494 goto fail;
2495 }
2496
2497 fils->state = PASN_FILS_STATE_COMPLETE;
2498 return;
2499fail:
2500 ap_free_sta(hapd, sta);
2501}
2502
2503
2504static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
2505 struct wpabuf *wd)
2506{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002507#ifdef CONFIG_NO_RADIUS
2508 wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
2509 return -1;
2510#else /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002511 struct pasn_data *pasn = sta->pasn;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002512 struct pasn_fils *fils = &pasn->fils;
Hai Shalom60840252021-02-19 19:02:11 -08002513 struct ieee802_11_elems elems;
2514 struct wpa_ie_data rsne_data;
2515 struct wpabuf *fils_wd;
2516 const u8 *data;
2517 size_t buf_len;
2518 u16 alg, seq, status;
2519 int ret;
2520
2521 if (fils->state != PASN_FILS_STATE_NONE) {
2522 wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
2523 return -1;
2524 }
2525
2526 if (!wd) {
2527 wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
2528 return -1;
2529 }
2530
2531 data = wpabuf_head_u8(wd);
2532 buf_len = wpabuf_len(wd);
2533
2534 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002535 wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002536 buf_len);
2537 return -1;
2538 }
2539
2540 alg = WPA_GET_LE16(data);
2541 seq = WPA_GET_LE16(data + 2);
2542 status = WPA_GET_LE16(data + 4);
2543
2544 wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
2545 alg, seq, status);
2546
2547 if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
2548 status != WLAN_STATUS_SUCCESS) {
2549 wpa_printf(MSG_DEBUG,
2550 "PASN: FILS: Dropping peer authentication");
2551 return -1;
2552 }
2553
2554 data += 6;
2555 buf_len -= 6;
2556
2557 if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
2558 wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
2559 return -1;
2560 }
2561
2562 if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00002563 !elems.wrapped_data || !elems.fils_session) {
Hai Shalom60840252021-02-19 19:02:11 -08002564 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
2565 return -1;
2566 }
2567
2568 ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2569 &rsne_data);
2570 if (ret) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002571 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RSNE");
Hai Shalom60840252021-02-19 19:02:11 -08002572 return -1;
2573 }
2574
2575 ret = wpa_pasn_validate_rsne(&rsne_data);
2576 if (ret) {
2577 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
2578 return -1;
2579 }
2580
2581 if (rsne_data.num_pmkid) {
2582 wpa_printf(MSG_DEBUG,
2583 "PASN: FILS: Not expecting PMKID in RSNE");
2584 return -1;
2585 }
2586
2587 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
2588 FILS_NONCE_LEN);
2589 os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
2590
2591 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
2592 FILS_SESSION_LEN);
2593 os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
2594
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002595 fils_wd = ieee802_11_defrag(elems.wrapped_data, elems.wrapped_data_len,
2596 true);
Hai Shalom60840252021-02-19 19:02:11 -08002597
2598 if (!fils_wd) {
2599 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
2600 return -1;
2601 }
2602
2603 if (!sta->eapol_sm)
2604 sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
2605
2606 wpa_printf(MSG_DEBUG,
2607 "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
2608
2609 ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
2610 wpabuf_len(fils_wd));
2611
2612 sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
2613
2614 fils->state = PASN_FILS_STATE_PENDING_AS;
2615
2616 /*
2617 * Calculate pending PMKID here so that we do not need to maintain a
2618 * copy of the EAP-Initiate/Reautt message.
2619 */
Sunil Ravi99c035e2024-07-12 01:42:03 +00002620 fils_pmkid_erp(pasn_get_akmp(pasn),
2621 wpabuf_head(fils_wd), wpabuf_len(fils_wd),
Hai Shalom60840252021-02-19 19:02:11 -08002622 fils->erp_pmkid);
2623
2624 wpabuf_free(fils_wd);
2625 return 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002626#endif /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002627}
2628
2629#endif /* CONFIG_FILS */
2630
2631
Sunil Ravi77d572f2023-01-17 23:58:31 +00002632static int hapd_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len,
2633 int noack, unsigned int freq, unsigned int wait)
Hai Shalom60840252021-02-19 19:02:11 -08002634{
Sunil Ravi77d572f2023-01-17 23:58:31 +00002635 struct hostapd_data *hapd = ctx;
2636
2637 return hostapd_drv_send_mlme(hapd, data, data_len, 0, NULL, 0, 0);
2638}
2639
2640
2641static void hapd_initialize_pasn(struct hostapd_data *hapd,
2642 struct sta_info *sta)
2643{
2644 struct pasn_data *pasn = sta->pasn;
2645
Sunil Ravi99c035e2024-07-12 01:42:03 +00002646 pasn_register_callbacks(pasn, hapd, hapd_pasn_send_mlme, NULL);
2647 pasn_set_bssid(pasn, hapd->own_addr);
2648 pasn_set_own_addr(pasn, hapd->own_addr);
2649 pasn_set_peer_addr(pasn, sta->addr);
2650 pasn_set_wpa_key_mgmt(pasn, hapd->conf->wpa_key_mgmt);
2651 pasn_set_rsn_pairwise(pasn, hapd->conf->rsn_pairwise);
Sunil Ravi77d572f2023-01-17 23:58:31 +00002652 pasn->pasn_groups = hapd->conf->pasn_groups;
Sunil Ravi640215c2023-06-28 23:08:09 +00002653 pasn->noauth = hapd->conf->pasn_noauth;
Sunil Ravi99c035e2024-07-12 01:42:03 +00002654 if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP)
2655 pasn_enable_kdk_derivation(pasn);
2656
Sunil Ravi77d572f2023-01-17 23:58:31 +00002657#ifdef CONFIG_TESTING_OPTIONS
2658 pasn->corrupt_mic = hapd->conf->pasn_corrupt_mic;
2659 if (hapd->conf->force_kdk_derivation)
Sunil Ravi99c035e2024-07-12 01:42:03 +00002660 pasn_enable_kdk_derivation(pasn);
Sunil Ravi77d572f2023-01-17 23:58:31 +00002661#endif /* CONFIG_TESTING_OPTIONS */
2662 pasn->use_anti_clogging = use_anti_clogging(hapd);
Sunil Ravi99c035e2024-07-12 01:42:03 +00002663 pasn_set_password(pasn, sae_get_password(hapd, sta, NULL, NULL,
2664 &pasn->pt, NULL));
Sunil Ravi77d572f2023-01-17 23:58:31 +00002665 pasn->rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &pasn->rsn_ie_len);
Sunil Ravi99c035e2024-07-12 01:42:03 +00002666 pasn_set_rsnxe_ie(pasn, hostapd_wpa_ie(hapd, WLAN_EID_RSNX));
Sunil Ravi77d572f2023-01-17 23:58:31 +00002667 pasn->disable_pmksa_caching = hapd->conf->disable_pmksa_caching;
Sunil Ravi99c035e2024-07-12 01:42:03 +00002668 pasn_set_responder_pmksa(pasn,
2669 wpa_auth_get_pmksa_cache(hapd->wpa_auth));
Sunil Ravi77d572f2023-01-17 23:58:31 +00002670
2671 pasn->comeback_after = hapd->conf->pasn_comeback_after;
2672 pasn->comeback_idx = hapd->comeback_idx;
2673 pasn->comeback_key = hapd->comeback_key;
2674 pasn->comeback_pending_idx = hapd->comeback_pending_idx;
Hai Shalom60840252021-02-19 19:02:11 -08002675}
2676
2677
Sunil Ravi89eba102022-09-13 21:04:37 -07002678static int pasn_set_keys_from_cache(struct hostapd_data *hapd,
2679 const u8 *own_addr, const u8 *sta_addr,
2680 int cipher, int akmp)
2681{
2682 struct ptksa_cache_entry *entry;
2683
2684 entry = ptksa_cache_get(hapd->ptksa, sta_addr, cipher);
2685 if (!entry) {
2686 wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR
2687 " not present in PTKSA cache", MAC2STR(sta_addr));
2688 return -1;
2689 }
2690
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002691 if (!ether_addr_equal(entry->own_addr, own_addr)) {
Sunil Ravi89eba102022-09-13 21:04:37 -07002692 wpa_printf(MSG_DEBUG,
2693 "PASN: own addr " MACSTR " and PTKSA entry own addr "
2694 MACSTR " differ",
2695 MAC2STR(own_addr), MAC2STR(entry->own_addr));
2696 return -1;
2697 }
2698
2699 wpa_printf(MSG_DEBUG, "PASN: " MACSTR " present in PTKSA cache",
2700 MAC2STR(sta_addr));
2701 hostapd_drv_set_secure_ranging_ctx(hapd, own_addr, sta_addr, cipher,
2702 entry->ptk.tk_len, entry->ptk.tk,
2703 entry->ptk.ltf_keyseed_len,
2704 entry->ptk.ltf_keyseed, 0);
2705
2706 return 0;
2707}
2708
2709
Sunil Ravi77d572f2023-01-17 23:58:31 +00002710static void hapd_pasn_update_params(struct hostapd_data *hapd,
2711 struct sta_info *sta,
2712 const struct ieee80211_mgmt *mgmt,
2713 size_t len)
Hai Shalom60840252021-02-19 19:02:11 -08002714{
Sunil Ravi77d572f2023-01-17 23:58:31 +00002715 struct pasn_data *pasn = sta->pasn;
Hai Shalom60840252021-02-19 19:02:11 -08002716 struct ieee802_11_elems elems;
2717 struct wpa_ie_data rsn_data;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002718#ifdef CONFIG_FILS
Hai Shalom60840252021-02-19 19:02:11 -08002719 struct wpa_pasn_params_data pasn_params;
Hai Shalom60840252021-02-19 19:02:11 -08002720 struct wpabuf *wrapped_data = NULL;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002721#endif /* CONFIG_FILS */
Sunil Ravi99c035e2024-07-12 01:42:03 +00002722 int akmp;
Hai Shalom60840252021-02-19 19:02:11 -08002723
2724 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
2725 len - offsetof(struct ieee80211_mgmt,
2726 u.auth.variable),
2727 &elems, 0) == ParseFailed) {
2728 wpa_printf(MSG_DEBUG,
2729 "PASN: Failed parsing Authentication frame");
Sunil Ravi77d572f2023-01-17 23:58:31 +00002730 return;
Hai Shalom60840252021-02-19 19:02:11 -08002731 }
2732
Sunil Ravi77d572f2023-01-17 23:58:31 +00002733 if (!elems.rsn_ie ||
2734 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2735 &rsn_data)) {
2736 wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE");
2737 return;
2738 }
2739
2740 if (!(rsn_data.key_mgmt & pasn->wpa_key_mgmt) ||
2741 !(rsn_data.pairwise_cipher & pasn->rsn_pairwise)) {
2742 wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
2743 return;
2744 }
2745
Sunil Ravi99c035e2024-07-12 01:42:03 +00002746 pasn_set_akmp(pasn, rsn_data.key_mgmt);
2747 pasn_set_cipher(pasn, rsn_data.pairwise_cipher);
Sunil Ravi77d572f2023-01-17 23:58:31 +00002748
Sunil Ravi7f769292024-07-23 22:21:32 +00002749 if (pasn->derive_kdk &&
2750 !ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
2751 WLAN_RSNX_CAPAB_SECURE_LTF))
2752 pasn_disable_kdk_derivation(pasn);
2753#ifdef CONFIG_TESTING_OPTIONS
2754 if (hapd->conf->force_kdk_derivation)
2755 pasn_enable_kdk_derivation(pasn);
2756#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravi99c035e2024-07-12 01:42:03 +00002757 akmp = pasn_get_akmp(pasn);
2758
2759 if (wpa_key_mgmt_ft(akmp) && rsn_data.num_pmkid) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002760#ifdef CONFIG_IEEE80211R_AP
2761 pasn->pmk_r1_len = 0;
2762 wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
2763 rsn_data.pmkid,
2764 pasn->pmk_r1, &pasn->pmk_r1_len, NULL,
2765 NULL, NULL, NULL,
2766 NULL, NULL, NULL);
2767#endif /* CONFIG_IEEE80211R_AP */
2768 }
2769#ifdef CONFIG_FILS
Sunil Ravi99c035e2024-07-12 01:42:03 +00002770 if (akmp != WPA_KEY_MGMT_FILS_SHA256 &&
2771 akmp != WPA_KEY_MGMT_FILS_SHA384)
Sunil Ravi77d572f2023-01-17 23:58:31 +00002772 return;
2773 if (!elems.pasn_params ||
2774 wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
2775 elems.pasn_params_len + 3,
2776 false, &pasn_params)) {
Hai Shalom60840252021-02-19 19:02:11 -08002777 wpa_printf(MSG_DEBUG,
Sunil Ravi77d572f2023-01-17 23:58:31 +00002778 "PASN: Failed validation of PASN Parameters element");
2779 return;
Hai Shalom60840252021-02-19 19:02:11 -08002780 }
Hai Shalom60840252021-02-19 19:02:11 -08002781 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002782 wrapped_data = ieee802_11_defrag(elems.wrapped_data,
2783 elems.wrapped_data_len, true);
Hai Shalom60840252021-02-19 19:02:11 -08002784 if (!wrapped_data) {
2785 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
Sunil Ravi77d572f2023-01-17 23:58:31 +00002786 return;
Hai Shalom60840252021-02-19 19:02:11 -08002787 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00002788 if (pasn_wd_handle_fils(hapd, sta, wrapped_data))
2789 wpa_printf(MSG_DEBUG,
2790 "PASN: Failed processing FILS wrapped data");
2791 else
2792 pasn->fils_wd_valid = true;
Hai Shalom60840252021-02-19 19:02:11 -08002793 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00002794 wpabuf_free(wrapped_data);
2795#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08002796}
2797
2798
2799static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
2800 const struct ieee80211_mgmt *mgmt, size_t len,
2801 u16 trans_seq, u16 status)
2802{
2803 if (hapd->conf->wpa != WPA_PROTO_RSN) {
2804 wpa_printf(MSG_INFO, "PASN: RSN is not configured");
2805 return;
2806 }
2807
2808 wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR,
2809 MAC2STR(sta->addr));
2810
2811 if (trans_seq == 1) {
2812 if (sta->pasn) {
2813 wpa_printf(MSG_DEBUG,
2814 "PASN: Not expecting transaction == 1");
2815 return;
2816 }
2817
2818 if (status != WLAN_STATUS_SUCCESS) {
2819 wpa_printf(MSG_DEBUG,
2820 "PASN: Failure status in transaction == 1");
2821 return;
2822 }
2823
Sunil Ravi99c035e2024-07-12 01:42:03 +00002824 sta->pasn = pasn_data_init();
Hai Shalom60840252021-02-19 19:02:11 -08002825 if (!sta->pasn) {
2826 wpa_printf(MSG_DEBUG,
2827 "PASN: Failed to allocate PASN context");
2828 return;
2829 }
2830
Sunil Ravi77d572f2023-01-17 23:58:31 +00002831 hapd_initialize_pasn(hapd, sta);
2832
2833 hapd_pasn_update_params(hapd, sta, mgmt, len);
2834 if (handle_auth_pasn_1(sta->pasn, hapd->own_addr,
2835 sta->addr, mgmt, len) < 0)
2836 ap_free_sta(hapd, sta);
Hai Shalom60840252021-02-19 19:02:11 -08002837 } else if (trans_seq == 3) {
2838 if (!sta->pasn) {
2839 wpa_printf(MSG_DEBUG,
2840 "PASN: Not expecting transaction == 3");
2841 return;
2842 }
2843
2844 if (status != WLAN_STATUS_SUCCESS) {
2845 wpa_printf(MSG_DEBUG,
2846 "PASN: Failure status in transaction == 3");
2847 ap_free_sta_pasn(hapd, sta);
2848 return;
2849 }
2850
Sunil Ravi77d572f2023-01-17 23:58:31 +00002851 if (handle_auth_pasn_3(sta->pasn, hapd->own_addr,
2852 sta->addr, mgmt, len) == 0) {
2853 ptksa_cache_add(hapd->ptksa, hapd->own_addr, sta->addr,
Sunil Ravi99c035e2024-07-12 01:42:03 +00002854 pasn_get_cipher(sta->pasn), 43200,
2855 pasn_get_ptk(sta->pasn), NULL, NULL,
2856 pasn_get_akmp(sta->pasn));
Sunil Ravi77d572f2023-01-17 23:58:31 +00002857
2858 pasn_set_keys_from_cache(hapd, hapd->own_addr,
Sunil Ravi99c035e2024-07-12 01:42:03 +00002859 sta->addr,
2860 pasn_get_cipher(sta->pasn),
2861 pasn_get_akmp(sta->pasn));
Sunil Ravi77d572f2023-01-17 23:58:31 +00002862 }
2863 ap_free_sta(hapd, sta);
Hai Shalom60840252021-02-19 19:02:11 -08002864 } else {
2865 wpa_printf(MSG_DEBUG,
2866 "PASN: Invalid transaction %u - ignore", trans_seq);
2867 }
2868}
2869
2870#endif /* CONFIG_PASN */
2871
2872
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002873static void handle_auth(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08002874 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom021b0b52019-04-10 11:17:58 -07002875 int rssi, int from_queue)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002876{
2877 u16 auth_alg, auth_transaction, status_code;
2878 u16 resp = WLAN_STATUS_SUCCESS;
2879 struct sta_info *sta = NULL;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002880 int res, reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002881 u16 fc;
2882 const u8 *challenge = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002883 u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
2884 size_t resp_ies_len = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002885 u16 seq_ctrl;
Hai Shalomfdcde762020-04-02 11:19:20 -07002886 struct radius_sta rad_info;
Sunil Ravi7f769292024-07-23 22:21:32 +00002887 const u8 *dst, *sa;
Sunil Ravi99c035e2024-07-12 01:42:03 +00002888#ifdef CONFIG_IEEE80211BE
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002889 bool mld_sta = false;
Sunil Ravi99c035e2024-07-12 01:42:03 +00002890#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002891
2892 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002893 wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
2894 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002895 return;
2896 }
2897
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002898#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002899 if (hapd->iconf->ignore_auth_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002900 drand48() < hapd->iconf->ignore_auth_probability) {
2901 wpa_printf(MSG_INFO,
2902 "TESTING: ignoring auth frame from " MACSTR,
2903 MAC2STR(mgmt->sa));
2904 return;
2905 }
2906#endif /* CONFIG_TESTING_OPTIONS */
2907
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002908 sa = mgmt->sa;
2909#ifdef CONFIG_IEEE80211BE
2910 /*
2911 * Handle MLO authentication before the station is added to hostapd and
2912 * the driver so that the station MLD MAC address would be used in both
2913 * hostapd and the driver.
2914 */
2915 sa = hostapd_process_ml_auth(hapd, mgmt, len);
2916 if (sa)
2917 mld_sta = true;
2918 else
2919 sa = mgmt->sa;
2920#endif /* CONFIG_IEEE80211BE */
2921
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002922 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
2923 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
2924 status_code = le_to_host16(mgmt->u.auth.status_code);
2925 fc = le_to_host16(mgmt->frame_control);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002926 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002927
2928 if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
2929 2 + WLAN_AUTH_CHALLENGE_LEN &&
2930 mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
2931 mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
2932 challenge = &mgmt->u.auth.variable[2];
2933
2934 wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002935 "auth_transaction=%d status_code=%d wep=%d%s "
Hai Shalom021b0b52019-04-10 11:17:58 -07002936 "seq_ctrl=0x%x%s%s",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002937 MAC2STR(sa), auth_alg, auth_transaction,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002938 status_code, !!(fc & WLAN_FC_ISWEP),
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002939 challenge ? " challenge" : "",
Hai Shalom021b0b52019-04-10 11:17:58 -07002940 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
2941 from_queue ? " (from queue)" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002942
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002943#ifdef CONFIG_NO_RC4
2944 if (auth_alg == WLAN_AUTH_SHARED_KEY) {
2945 wpa_printf(MSG_INFO,
2946 "Unsupported authentication algorithm (%d)",
2947 auth_alg);
2948 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
2949 goto fail;
2950 }
2951#endif /* CONFIG_NO_RC4 */
2952
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002953 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002954 wpa_printf(MSG_DEBUG,
2955 "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
2956 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002957 goto fail;
2958 }
2959
2960 if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
2961 auth_alg == WLAN_AUTH_OPEN) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002962#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002963 (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002964 auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002965#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002966#ifdef CONFIG_SAE
Sunil Ravi7f769292024-07-23 22:21:32 +00002967 (hapd->conf->wpa &&
2968 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt |
2969 hapd->conf->rsn_override_key_mgmt |
2970 hapd->conf->rsn_override_key_mgmt_2) &&
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002971 auth_alg == WLAN_AUTH_SAE) ||
2972#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002973#ifdef CONFIG_FILS
2974 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
2975 auth_alg == WLAN_AUTH_FILS_SK) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002976 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
2977 hapd->conf->fils_dh_group &&
2978 auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002979#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08002980#ifdef CONFIG_PASN
2981 (hapd->conf->wpa &&
2982 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) &&
2983 auth_alg == WLAN_AUTH_PASN) ||
2984#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002985 ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
2986 auth_alg == WLAN_AUTH_SHARED_KEY))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002987 wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
2988 auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002989 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
2990 goto fail;
2991 }
2992
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002993 if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
Hai Shalom60840252021-02-19 19:02:11 -08002994#ifdef CONFIG_PASN
2995 (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) ||
2996#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002997 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002998 wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
2999 auth_transaction);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003000 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
3001 goto fail;
3002 }
3003
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003004 if (ether_addr_equal(mgmt->sa, hapd->own_addr)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003005 wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003006 MAC2STR(sa));
3007 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3008 goto fail;
3009 }
3010
Sunil Ravi99c035e2024-07-12 01:42:03 +00003011#ifdef CONFIG_IEEE80211BE
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003012 if (mld_sta &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003013 (ether_addr_equal(sa, hapd->own_addr) ||
Sunil Ravi99c035e2024-07-12 01:42:03 +00003014 ether_addr_equal(sa, hapd->mld->mld_addr))) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003015 wpa_printf(MSG_INFO,
3016 "Station " MACSTR " not allowed to authenticate",
3017 MAC2STR(sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003018 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3019 goto fail;
3020 }
Sunil Ravi99c035e2024-07-12 01:42:03 +00003021#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003022
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003023 if (hapd->conf->no_auth_if_seen_on) {
3024 struct hostapd_data *other;
3025
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003026 other = sta_track_seen_on(hapd->iface, sa,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003027 hapd->conf->no_auth_if_seen_on);
3028 if (other) {
3029 u8 *pos;
3030 u32 info;
3031 u8 op_class, channel, phytype;
3032
3033 wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
3034 MACSTR " since STA has been seen on %s",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003035 hapd->conf->iface, MAC2STR(sa),
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003036 hapd->conf->no_auth_if_seen_on);
3037
3038 resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
3039 pos = &resp_ies[0];
3040 *pos++ = WLAN_EID_NEIGHBOR_REPORT;
3041 *pos++ = 13;
3042 os_memcpy(pos, other->own_addr, ETH_ALEN);
3043 pos += ETH_ALEN;
3044 info = 0; /* TODO: BSSID Information */
3045 WPA_PUT_LE32(pos, info);
3046 pos += 4;
3047 if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
3048 phytype = 8; /* dmg */
3049 else if (other->iconf->ieee80211ac)
3050 phytype = 9; /* vht */
3051 else if (other->iconf->ieee80211n)
3052 phytype = 7; /* ht */
3053 else if (other->iconf->hw_mode ==
3054 HOSTAPD_MODE_IEEE80211A)
3055 phytype = 4; /* ofdm */
3056 else if (other->iconf->hw_mode ==
3057 HOSTAPD_MODE_IEEE80211G)
3058 phytype = 6; /* erp */
3059 else
3060 phytype = 5; /* hrdsss */
3061 if (ieee80211_freq_to_channel_ext(
3062 hostapd_hw_get_freq(other,
3063 other->iconf->channel),
3064 other->iconf->secondary_channel,
3065 other->iconf->ieee80211ac,
3066 &op_class, &channel) == NUM_HOSTAPD_MODES) {
3067 op_class = 0;
3068 channel = other->iconf->channel;
3069 }
3070 *pos++ = op_class;
3071 *pos++ = channel;
3072 *pos++ = phytype;
3073 resp_ies_len = pos - &resp_ies[0];
3074 goto fail;
3075 }
3076 }
3077
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003078 res = ieee802_11_allowed_address(hapd, sa, (const u8 *) mgmt, len,
Hai Shalomfdcde762020-04-02 11:19:20 -07003079 &rad_info);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003080 if (res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003081 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
3082 "Ignore Authentication frame from " MACSTR
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003083 " due to ACL reject", MAC2STR(sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003084 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3085 goto fail;
3086 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003087 if (res == HOSTAPD_ACL_PENDING)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003088 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003089
Hai Shalom021b0b52019-04-10 11:17:58 -07003090#ifdef CONFIG_SAE
3091 if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
3092 (auth_transaction == 1 ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003093 (auth_transaction == 2 && auth_sae_queued_addr(hapd, sa)))) {
Hai Shalom021b0b52019-04-10 11:17:58 -07003094 /* Handle SAE Authentication commit message through a queue to
3095 * provide more control for postponing the needed heavy
3096 * processing under a possible DoS attack scenario. In addition,
3097 * queue SAE Authentication confirm message if there happens to
3098 * be a queued commit message from the same peer. This is needed
3099 * to avoid reordering Authentication frames within the same
3100 * SAE exchange. */
3101 auth_sae_queue(hapd, mgmt, len, rssi);
3102 return;
3103 }
3104#endif /* CONFIG_SAE */
3105
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003106 sta = ap_get_sta(hapd, sa);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003107 if (sta) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003108 sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
Hai Shalom74f70d42019-02-11 14:42:39 -08003109 sta->ft_over_ds = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003110 if ((fc & WLAN_FC_RETRY) &&
3111 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
3112 sta->last_seq_ctrl == seq_ctrl &&
3113 sta->last_subtype == WLAN_FC_STYPE_AUTH) {
3114 hostapd_logger(hapd, sta->addr,
3115 HOSTAPD_MODULE_IEEE80211,
3116 HOSTAPD_LEVEL_DEBUG,
3117 "Drop repeated authentication frame seq_ctrl=0x%x",
3118 seq_ctrl);
3119 return;
3120 }
Hai Shalom60840252021-02-19 19:02:11 -08003121#ifdef CONFIG_PASN
3122 if (auth_alg == WLAN_AUTH_PASN &&
3123 (sta->flags & WLAN_STA_ASSOC)) {
3124 wpa_printf(MSG_DEBUG,
3125 "PASN: auth: Existing station: " MACSTR,
3126 MAC2STR(sta->addr));
3127 return;
3128 }
3129#endif /* CONFIG_PASN */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003130 } else {
3131#ifdef CONFIG_MESH
3132 if (hapd->conf->mesh & MESH_ENABLED) {
3133 /* if the mesh peer is not available, we don't do auth.
3134 */
3135 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003136 " not yet known - drop Authentication frame",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003137 MAC2STR(sa));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003138 /*
3139 * Save a copy of the frame so that it can be processed
3140 * if a new peer entry is added shortly after this.
3141 */
3142 wpabuf_free(hapd->mesh_pending_auth);
3143 hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len);
3144 os_get_reltime(&hapd->mesh_pending_auth_time);
3145 return;
3146 }
3147#endif /* CONFIG_MESH */
3148
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003149 sta = ap_sta_add(hapd, sa);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003150 if (!sta) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003151 wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003152 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3153 goto fail;
3154 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003155 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003156
3157#ifdef CONFIG_IEEE80211BE
Sunil Ravi99c035e2024-07-12 01:42:03 +00003158 /* Set the non-AP MLD information based on the initial Authentication
3159 * frame. Once the STA entry has been added to the driver, the driver
3160 * will translate addresses in the frame and we need to avoid overriding
3161 * peer_addr based on mgmt->sa which would have been translated to the
3162 * MLD MAC address. */
3163 if (!sta->added_unassoc && auth_transaction == 1) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003164 ap_sta_free_sta_profile(&sta->mld_info);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003165 os_memset(&sta->mld_info, 0, sizeof(sta->mld_info));
3166
3167 if (mld_sta) {
3168 u8 link_id = hapd->mld_link_id;
3169
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003170 ap_sta_set_mld(sta, true);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003171 sta->mld_assoc_link_id = link_id;
3172
3173 /*
3174 * Set the MLD address as the station address and the
3175 * station addresses.
3176 */
3177 os_memcpy(sta->mld_info.common_info.mld_addr, sa,
3178 ETH_ALEN);
3179 os_memcpy(sta->mld_info.links[link_id].peer_addr,
3180 mgmt->sa, ETH_ALEN);
3181 os_memcpy(sta->mld_info.links[link_id].local_addr,
3182 hapd->own_addr, ETH_ALEN);
3183 }
3184 }
3185#endif /* CONFIG_IEEE80211BE */
3186
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003187 sta->last_seq_ctrl = seq_ctrl;
3188 sta->last_subtype = WLAN_FC_STYPE_AUTH;
Hai Shalom74f70d42019-02-11 14:42:39 -08003189#ifdef CONFIG_MBO
3190 sta->auth_rssi = rssi;
3191#endif /* CONFIG_MBO */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003192
Hai Shalomfdcde762020-04-02 11:19:20 -07003193 res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003194 if (res) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003195 wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003196 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3197 goto fail;
3198 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003199
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003200 sta->flags &= ~WLAN_STA_PREAUTH;
3201 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
3202
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003203 /*
3204 * If the driver supports full AP client state, add a station to the
3205 * driver before sending authentication reply to make sure the driver
3206 * has resources, and not to go through the entire authentication and
3207 * association handshake, and fail it at the end.
3208 *
3209 * If this is not the first transaction, in a multi-step authentication
3210 * algorithm, the station already exists in the driver
3211 * (sta->added_unassoc = 1) so skip it.
3212 *
3213 * In mesh mode, the station was already added to the driver when the
3214 * NEW_PEER_CANDIDATE event is received.
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003215 *
3216 * If PMF was negotiated for the existing association, skip this to
3217 * avoid dropping the STA entry and the associated keys. This is needed
3218 * to allow the original connection work until the attempt can complete
3219 * (re)association, so that unprotected Authentication frame cannot be
3220 * used to bypass PMF protection.
Hai Shalom60840252021-02-19 19:02:11 -08003221 *
3222 * PASN authentication does not require adding/removing station to the
3223 * driver so skip this flow in case of PASN authentication.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003224 */
3225 if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003226 (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003227 !(hapd->conf->mesh & MESH_ENABLED) &&
Hai Shalom60840252021-02-19 19:02:11 -08003228 !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) {
Hai Shalomb755a2a2020-04-23 21:49:02 -07003229 if (ap_sta_re_add(hapd, sta) < 0) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003230 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3231 goto fail;
3232 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003233 }
3234
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003235 switch (auth_alg) {
3236 case WLAN_AUTH_OPEN:
3237 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3238 HOSTAPD_LEVEL_DEBUG,
3239 "authentication OK (open system)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003240 sta->flags |= WLAN_STA_AUTH;
3241 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
3242 sta->auth_alg = WLAN_AUTH_OPEN;
3243 mlme_authenticate_indication(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003244 break;
Hai Shalomfdcde762020-04-02 11:19:20 -07003245#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003246#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003247 case WLAN_AUTH_SHARED_KEY:
3248 resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
3249 fc & WLAN_FC_ISWEP);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003250 if (resp != 0)
3251 wpa_printf(MSG_DEBUG,
3252 "auth_shared_key() failed: status=%d", resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003253 sta->auth_alg = WLAN_AUTH_SHARED_KEY;
3254 mlme_authenticate_indication(hapd, sta);
3255 if (sta->challenge && auth_transaction == 1) {
3256 resp_ies[0] = WLAN_EID_CHALLENGE;
3257 resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
3258 os_memcpy(resp_ies + 2, sta->challenge,
3259 WLAN_AUTH_CHALLENGE_LEN);
3260 resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
3261 }
3262 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003263#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003264#endif /* CONFIG_WEP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003265#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003266 case WLAN_AUTH_FT:
3267 sta->auth_alg = WLAN_AUTH_FT;
3268 if (sta->wpa_sm == NULL)
3269 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003270 sta->addr, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003271 if (sta->wpa_sm == NULL) {
3272 wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
3273 "state machine");
3274 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3275 goto fail;
3276 }
Sunil Ravi7f769292024-07-23 22:21:32 +00003277 wpa_ft_process_auth(sta->wpa_sm,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003278 auth_transaction, mgmt->u.auth.variable,
3279 len - IEEE80211_HDRLEN -
3280 sizeof(mgmt->u.auth),
3281 handle_auth_ft_finish, hapd);
3282 /* handle_auth_ft_finish() callback will complete auth. */
3283 return;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003284#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003285#ifdef CONFIG_SAE
3286 case WLAN_AUTH_SAE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003287#ifdef CONFIG_MESH
3288 if (status_code == WLAN_STATUS_SUCCESS &&
3289 hapd->conf->mesh & MESH_ENABLED) {
3290 if (sta->wpa_sm == NULL)
3291 sta->wpa_sm =
3292 wpa_auth_sta_init(hapd->wpa_auth,
3293 sta->addr, NULL);
3294 if (sta->wpa_sm == NULL) {
3295 wpa_printf(MSG_DEBUG,
3296 "SAE: Failed to initialize WPA state machine");
3297 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3298 goto fail;
3299 }
3300 }
3301#endif /* CONFIG_MESH */
3302 handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
3303 status_code);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003304 return;
3305#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003306#ifdef CONFIG_FILS
3307 case WLAN_AUTH_FILS_SK:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003308 case WLAN_AUTH_FILS_SK_PFS:
3309 handle_auth_fils(hapd, sta, mgmt->u.auth.variable,
3310 len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth),
3311 auth_alg, auth_transaction, status_code,
3312 handle_auth_fils_finish);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003313 return;
3314#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08003315#ifdef CONFIG_PASN
3316 case WLAN_AUTH_PASN:
3317 handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction,
3318 status_code);
3319 return;
3320#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003321 }
3322
3323 fail:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003324 dst = mgmt->sa;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003325
3326#ifdef CONFIG_IEEE80211BE
Sunil Ravi7f769292024-07-23 22:21:32 +00003327 if (ap_sta_is_mld(hapd, sta))
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003328 dst = sta->addr;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003329#endif /* CONFIG_IEEE80211BE */
3330
Sunil Ravi7f769292024-07-23 22:21:32 +00003331 reply_res = send_auth_reply(hapd, sta, dst, auth_alg,
Hai Shaloma20dcd72022-02-04 13:43:00 -08003332 auth_alg == WLAN_AUTH_SAE ?
3333 auth_transaction : auth_transaction + 1,
3334 resp, resp_ies, resp_ies_len,
3335 "handle-auth");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003336
3337 if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
3338 reply_res != WLAN_STATUS_SUCCESS)) {
3339 hostapd_drv_sta_remove(hapd, sta->addr);
3340 sta->added_unassoc = 0;
3341 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003342}
3343
3344
Sunil Ravi77d572f2023-01-17 23:58:31 +00003345static u8 hostapd_max_bssid_indicator(struct hostapd_data *hapd)
3346{
3347 size_t num_bss_nontx;
3348 u8 max_bssid_ind = 0;
3349
3350 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1)
3351 return 0;
3352
3353 num_bss_nontx = hapd->iface->num_bss - 1;
3354 while (num_bss_nontx > 0) {
3355 max_bssid_ind++;
3356 num_bss_nontx >>= 1;
3357 }
3358 return max_bssid_ind;
3359}
3360
3361
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003362static u32 hostapd_get_aid_word(struct hostapd_data *hapd,
3363 struct sta_info *sta, int i)
3364{
3365#ifdef CONFIG_IEEE80211BE
3366 u32 aid_word = 0;
3367
3368 /* Do not assign an AID that is in use on any of the affiliated links
3369 * when finding an AID for a non-AP MLD. */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003370 if (hapd->conf->mld_ap && sta->mld_info.mld_sta) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003371 int j;
3372
3373 for (j = 0; j < MAX_NUM_MLD_LINKS; j++) {
3374 struct hostapd_data *link_bss;
3375
3376 if (!sta->mld_info.links[j].valid)
3377 continue;
3378
3379 link_bss = hostapd_mld_get_link_bss(hapd, j);
3380 if (!link_bss) {
3381 /* This shouldn't happen, just skip */
3382 wpa_printf(MSG_ERROR,
3383 "MLD: Failed to get link BSS for AID");
3384 continue;
3385 }
3386
3387 aid_word |= link_bss->sta_aid[i];
3388 }
3389
3390 return aid_word;
3391 }
3392#endif /* CONFIG_IEEE80211BE */
3393
3394 return hapd->sta_aid[i];
3395}
3396
3397
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003398int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003399{
3400 int i, j = 32, aid;
3401
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003402 /* Transmitted and non-transmitted BSSIDs share the same AID pool, so
3403 * use the shared storage in the transmitted BSS to find the next
3404 * available value. */
3405 hapd = hostapd_mbssid_get_tx_bss(hapd);
3406
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003407 /* get a unique AID */
3408 if (sta->aid > 0) {
3409 wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
3410 return 0;
3411 }
3412
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003413 if (TEST_FAIL())
3414 return -1;
3415
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003416 for (i = 0; i < AID_WORDS; i++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003417 u32 aid_word = hostapd_get_aid_word(hapd, sta, i);
3418
3419 if (aid_word == (u32) -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003420 continue;
3421 for (j = 0; j < 32; j++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003422 if (!(aid_word & BIT(j)))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003423 break;
3424 }
3425 if (j < 32)
3426 break;
3427 }
3428 if (j == 32)
3429 return -1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003430 aid = i * 32 + j + (1 << hostapd_max_bssid_indicator(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003431 if (aid > 2007)
3432 return -1;
3433
3434 sta->aid = aid;
3435 hapd->sta_aid[i] |= BIT(j);
3436 wpa_printf(MSG_DEBUG, " new AID %d", sta->aid);
3437 return 0;
3438}
3439
3440
3441static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
3442 const u8 *ssid_ie, size_t ssid_ie_len)
3443{
3444 if (ssid_ie == NULL)
3445 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3446
3447 if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
3448 os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003449 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3450 HOSTAPD_LEVEL_INFO,
3451 "Station tried to associate with unknown SSID "
Dmitry Shmidt3c479372014-02-04 10:50:36 -08003452 "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003453 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3454 }
3455
3456 return WLAN_STATUS_SUCCESS;
3457}
3458
3459
3460static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
3461 const u8 *wmm_ie, size_t wmm_ie_len)
3462{
3463 sta->flags &= ~WLAN_STA_WMM;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003464 sta->qosinfo = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003465 if (wmm_ie && hapd->conf->wmm_enabled) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003466 struct wmm_information_element *wmm;
3467
3468 if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003469 hostapd_logger(hapd, sta->addr,
3470 HOSTAPD_MODULE_WPA,
3471 HOSTAPD_LEVEL_DEBUG,
3472 "invalid WMM element in association "
3473 "request");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003474 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3475 }
3476
3477 sta->flags |= WLAN_STA_WMM;
3478 wmm = (struct wmm_information_element *) wmm_ie;
3479 sta->qosinfo = wmm->qos_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003480 }
3481 return WLAN_STATUS_SUCCESS;
3482}
3483
Hai Shalom74f70d42019-02-11 14:42:39 -08003484static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
3485 const u8 *multi_ap_ie, size_t multi_ap_len)
3486{
Sunil Ravi99c035e2024-07-12 01:42:03 +00003487 struct multi_ap_params multi_ap;
3488 u16 status;
Hai Shalom74f70d42019-02-11 14:42:39 -08003489
3490 sta->flags &= ~WLAN_STA_MULTI_AP;
3491
3492 if (!hapd->conf->multi_ap)
3493 return WLAN_STATUS_SUCCESS;
3494
Sunil Ravi99c035e2024-07-12 01:42:03 +00003495 if (!multi_ap_ie) {
3496 if (!(hapd->conf->multi_ap & FRONTHAUL_BSS)) {
Hai Shalom74f70d42019-02-11 14:42:39 -08003497 hostapd_logger(hapd, sta->addr,
3498 HOSTAPD_MODULE_IEEE80211,
3499 HOSTAPD_LEVEL_INFO,
Sunil Ravi99c035e2024-07-12 01:42:03 +00003500 "Non-Multi-AP STA tries to associate with backhaul-only BSS");
3501 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
Hai Shalom74f70d42019-02-11 14:42:39 -08003502 }
Sunil Ravi99c035e2024-07-12 01:42:03 +00003503
3504 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08003505 }
3506
Sunil Ravi99c035e2024-07-12 01:42:03 +00003507 status = check_multi_ap_ie(multi_ap_ie + 4, multi_ap_len - 4,
3508 &multi_ap);
3509 if (status != WLAN_STATUS_SUCCESS)
3510 return status;
3511
3512 if (multi_ap.capability && multi_ap.capability != MULTI_AP_BACKHAUL_STA)
Hai Shalom021b0b52019-04-10 11:17:58 -07003513 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3514 HOSTAPD_LEVEL_INFO,
3515 "Multi-AP IE with unexpected value 0x%02x",
Sunil Ravi99c035e2024-07-12 01:42:03 +00003516 multi_ap.capability);
Hai Shalom74f70d42019-02-11 14:42:39 -08003517
Sunil Ravi99c035e2024-07-12 01:42:03 +00003518 if (multi_ap.profile == MULTI_AP_PROFILE_1 &&
3519 (hapd->conf->multi_ap_client_disallow &
3520 PROFILE1_CLIENT_ASSOC_DISALLOW)) {
3521 hostapd_logger(hapd, sta->addr,
3522 HOSTAPD_MODULE_IEEE80211,
3523 HOSTAPD_LEVEL_INFO,
3524 "Multi-AP Profile-1 clients not allowed");
3525 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
3526 }
3527
3528 if (multi_ap.profile >= MULTI_AP_PROFILE_2 &&
3529 (hapd->conf->multi_ap_client_disallow &
3530 PROFILE2_CLIENT_ASSOC_DISALLOW)) {
3531 hostapd_logger(hapd, sta->addr,
3532 HOSTAPD_MODULE_IEEE80211,
3533 HOSTAPD_LEVEL_INFO,
3534 "Multi-AP Profile-2 clients not allowed");
3535 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
3536 }
3537
3538 if (!(multi_ap.capability & MULTI_AP_BACKHAUL_STA)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07003539 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
3540 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08003541
Hai Shalom021b0b52019-04-10 11:17:58 -07003542 hostapd_logger(hapd, sta->addr,
3543 HOSTAPD_MODULE_IEEE80211,
3544 HOSTAPD_LEVEL_INFO,
3545 "Non-Multi-AP STA tries to associate with backhaul-only BSS");
3546 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
Hai Shalom74f70d42019-02-11 14:42:39 -08003547 }
3548
Hai Shalom021b0b52019-04-10 11:17:58 -07003549 if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
3550 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3551 HOSTAPD_LEVEL_DEBUG,
3552 "Backhaul STA tries to associate with fronthaul-only BSS");
3553
3554 sta->flags |= WLAN_STA_MULTI_AP;
3555 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08003556}
3557
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003558
3559static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
3560 struct ieee802_11_elems *elems)
3561{
Dmitry Shmidt29333592017-01-09 12:27:11 -08003562 /* Supported rates not used in IEEE 802.11ad/DMG */
3563 if (hapd->iface->current_mode &&
3564 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
3565 return WLAN_STATUS_SUCCESS;
3566
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003567 if (!elems->supp_rates) {
3568 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3569 HOSTAPD_LEVEL_DEBUG,
3570 "No supported rates element in AssocReq");
3571 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3572 }
3573
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003574 if (elems->supp_rates_len + elems->ext_supp_rates_len >
3575 sizeof(sta->supported_rates)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003576 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3577 HOSTAPD_LEVEL_DEBUG,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003578 "Invalid supported rates element length %d+%d",
3579 elems->supp_rates_len,
3580 elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003581 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3582 }
3583
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003584 sta->supported_rates_len = merge_byte_arrays(
3585 sta->supported_rates, sizeof(sta->supported_rates),
3586 elems->supp_rates, elems->supp_rates_len,
3587 elems->ext_supp_rates, elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003588
3589 return WLAN_STATUS_SUCCESS;
3590}
3591
3592
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003593#ifdef CONFIG_OWE
3594
3595static int owe_group_supported(struct hostapd_data *hapd, u16 group)
3596{
3597 int i;
3598 int *groups = hapd->conf->owe_groups;
3599
3600 if (group != 19 && group != 20 && group != 21)
3601 return 0;
3602
3603 if (!groups)
3604 return 1;
3605
3606 for (i = 0; groups[i] > 0; i++) {
3607 if (groups[i] == group)
3608 return 1;
3609 }
3610
3611 return 0;
3612}
3613
3614
3615static u16 owe_process_assoc_req(struct hostapd_data *hapd,
3616 struct sta_info *sta, const u8 *owe_dh,
3617 u8 owe_dh_len)
3618{
3619 struct wpabuf *secret, *pub, *hkey;
3620 int res;
3621 u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN];
3622 const char *info = "OWE Key Generation";
3623 const u8 *addr[2];
3624 size_t len[2];
3625 u16 group;
3626 size_t hash_len, prime_len;
3627
3628 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
3629 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
3630 return WLAN_STATUS_SUCCESS;
3631 }
3632
3633 group = WPA_GET_LE16(owe_dh);
3634 if (!owe_group_supported(hapd, group)) {
3635 wpa_printf(MSG_DEBUG, "OWE: Unsupported DH group %u", group);
3636 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3637 }
3638 if (group == 19)
3639 prime_len = 32;
3640 else if (group == 20)
3641 prime_len = 48;
3642 else if (group == 21)
3643 prime_len = 66;
3644 else
3645 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3646
Sunil Ravia04bd252022-05-02 22:54:18 -07003647 if (sta->owe_group == group && sta->owe_ecdh) {
3648 /* This is a workaround for mac80211 behavior of retransmitting
3649 * the Association Request frames multiple times if the link
3650 * layer retries (i.e., seq# remains same) fail. The mac80211
3651 * initiated retransmission will use a different seq# and as
3652 * such, will go through duplicate detection. If we were to
3653 * change our DH key for that attempt, there would be two
3654 * different DH shared secrets and the STA would likely select
3655 * the wrong one. */
3656 wpa_printf(MSG_DEBUG,
3657 "OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again");
3658 } else {
3659 crypto_ecdh_deinit(sta->owe_ecdh);
3660 sta->owe_ecdh = crypto_ecdh_init(group);
3661 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003662 if (!sta->owe_ecdh)
3663 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3664 sta->owe_group = group;
3665
3666 secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2,
3667 owe_dh_len - 2);
3668 secret = wpabuf_zeropad(secret, prime_len);
3669 if (!secret) {
3670 wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
3671 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3672 }
3673 wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
3674
3675 /* prk = HKDF-extract(C | A | group, z) */
3676
3677 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
3678 if (!pub) {
3679 wpabuf_clear_free(secret);
3680 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3681 }
3682
3683 /* PMKID = Truncate-128(Hash(C | A)) */
3684 addr[0] = owe_dh + 2;
3685 len[0] = owe_dh_len - 2;
3686 addr[1] = wpabuf_head(pub);
3687 len[1] = wpabuf_len(pub);
3688 if (group == 19) {
3689 res = sha256_vector(2, addr, len, pmkid);
3690 hash_len = SHA256_MAC_LEN;
3691 } else if (group == 20) {
3692 res = sha384_vector(2, addr, len, pmkid);
3693 hash_len = SHA384_MAC_LEN;
3694 } else if (group == 21) {
3695 res = sha512_vector(2, addr, len, pmkid);
3696 hash_len = SHA512_MAC_LEN;
3697 } else {
3698 wpabuf_free(pub);
3699 wpabuf_clear_free(secret);
3700 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3701 }
3702 pub = wpabuf_zeropad(pub, prime_len);
3703 if (res < 0 || !pub) {
3704 wpabuf_free(pub);
3705 wpabuf_clear_free(secret);
3706 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3707 }
3708
3709 hkey = wpabuf_alloc(owe_dh_len - 2 + wpabuf_len(pub) + 2);
3710 if (!hkey) {
3711 wpabuf_free(pub);
3712 wpabuf_clear_free(secret);
3713 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3714 }
3715
3716 wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */
3717 wpabuf_put_buf(hkey, pub); /* A */
3718 wpabuf_free(pub);
3719 wpabuf_put_le16(hkey, group); /* group */
3720 if (group == 19)
3721 res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
3722 wpabuf_head(secret), wpabuf_len(secret), prk);
3723 else if (group == 20)
3724 res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey),
3725 wpabuf_head(secret), wpabuf_len(secret), prk);
3726 else if (group == 21)
3727 res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey),
3728 wpabuf_head(secret), wpabuf_len(secret), prk);
3729 wpabuf_clear_free(hkey);
3730 wpabuf_clear_free(secret);
3731 if (res < 0)
3732 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3733
3734 wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
3735
3736 /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
3737
3738 os_free(sta->owe_pmk);
3739 sta->owe_pmk = os_malloc(hash_len);
3740 if (!sta->owe_pmk) {
3741 os_memset(prk, 0, SHA512_MAC_LEN);
3742 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3743 }
3744
3745 if (group == 19)
3746 res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info,
3747 os_strlen(info), sta->owe_pmk, hash_len);
3748 else if (group == 20)
3749 res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info,
3750 os_strlen(info), sta->owe_pmk, hash_len);
3751 else if (group == 21)
3752 res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
3753 os_strlen(info), sta->owe_pmk, hash_len);
3754 os_memset(prk, 0, SHA512_MAC_LEN);
3755 if (res < 0) {
3756 os_free(sta->owe_pmk);
3757 sta->owe_pmk = NULL;
3758 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3759 }
3760 sta->owe_pmk_len = hash_len;
3761
3762 wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
3763 wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
3764 wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003765 sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003766
3767 return WLAN_STATUS_SUCCESS;
3768}
3769
Hai Shalom81f62d82019-07-22 12:10:00 -07003770
3771u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
3772 const u8 *rsn_ie, size_t rsn_ie_len,
3773 const u8 *owe_dh, size_t owe_dh_len)
3774{
3775 struct wpa_ie_data data;
3776 int res;
3777
3778 if (!rsn_ie || rsn_ie_len < 2) {
3779 wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
3780 MAC2STR(peer));
3781 return WLAN_STATUS_INVALID_IE;
3782 }
3783 rsn_ie -= 2;
3784 rsn_ie_len += 2;
3785
3786 res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
3787 if (res) {
3788 wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
3789 " (res=%d)", MAC2STR(peer), res);
3790 wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
3791 return wpa_res_to_status_code(res);
3792 }
3793 if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
3794 wpa_printf(MSG_DEBUG,
3795 "OWE: Unexpected key mgmt 0x%x from " MACSTR,
3796 (unsigned int) data.key_mgmt, MAC2STR(peer));
3797 return WLAN_STATUS_AKMP_NOT_VALID;
3798 }
3799 if (!owe_dh) {
3800 wpa_printf(MSG_DEBUG,
3801 "OWE: No Diffie-Hellman Parameter element from "
3802 MACSTR, MAC2STR(peer));
3803 return WLAN_STATUS_AKMP_NOT_VALID;
3804 }
3805
3806 return WLAN_STATUS_SUCCESS;
3807}
3808
3809
3810u16 owe_process_rsn_ie(struct hostapd_data *hapd,
3811 struct sta_info *sta,
3812 const u8 *rsn_ie, size_t rsn_ie_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003813 const u8 *owe_dh, size_t owe_dh_len,
3814 const u8 *link_addr)
Hai Shalom81f62d82019-07-22 12:10:00 -07003815{
3816 u16 status;
3817 u8 *owe_buf, ie[256 * 2];
3818 size_t ie_len = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07003819 enum wpa_validate_result res;
Hai Shalom81f62d82019-07-22 12:10:00 -07003820
3821 if (!rsn_ie || rsn_ie_len < 2) {
3822 wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
3823 status = WLAN_STATUS_INVALID_IE;
3824 goto end;
3825 }
3826
3827 if (!sta->wpa_sm)
3828 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
3829 NULL);
3830 if (!sta->wpa_sm) {
3831 wpa_printf(MSG_WARNING,
3832 "OWE: Failed to initialize WPA state machine");
3833 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3834 goto end;
3835 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003836#ifdef CONFIG_IEEE80211BE
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003837 if (ap_sta_is_mld(hapd, sta))
Sunil Ravi7f769292024-07-23 22:21:32 +00003838 wpa_auth_set_ml_info(sta->wpa_sm,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003839 sta->mld_assoc_link_id, &sta->mld_info);
3840#endif /* CONFIG_IEEE80211BE */
Hai Shalom81f62d82019-07-22 12:10:00 -07003841 rsn_ie -= 2;
3842 rsn_ie_len += 2;
3843 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
3844 hapd->iface->freq, rsn_ie, rsn_ie_len,
Sunil Ravi7f769292024-07-23 22:21:32 +00003845 NULL, 0, NULL, 0, owe_dh, owe_dh_len, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -07003846 status = wpa_res_to_status_code(res);
3847 if (status != WLAN_STATUS_SUCCESS)
3848 goto end;
3849 status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
3850 if (status != WLAN_STATUS_SUCCESS)
3851 goto end;
3852 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
3853 NULL, 0);
3854 if (!owe_buf) {
3855 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3856 goto end;
3857 }
3858
3859 if (sta->owe_ecdh) {
3860 struct wpabuf *pub;
3861
3862 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
3863 if (!pub) {
3864 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3865 goto end;
3866 }
3867
3868 /* OWE Diffie-Hellman Parameter element */
3869 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
3870 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
3871 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
3872 */
3873 WPA_PUT_LE16(owe_buf, sta->owe_group);
3874 owe_buf += 2;
3875 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
3876 owe_buf += wpabuf_len(pub);
3877 wpabuf_free(pub);
3878 sta->external_dh_updated = 1;
3879 }
3880 ie_len = owe_buf - ie;
3881
3882end:
3883 wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
3884 MACSTR, status, (unsigned int) ie_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003885 MAC2STR(link_addr ? link_addr : sta->addr));
3886 hostapd_drv_update_dh_ie(hapd, link_addr ? link_addr : sta->addr,
3887 status,
Hai Shalom81f62d82019-07-22 12:10:00 -07003888 status == WLAN_STATUS_SUCCESS ? ie : NULL,
3889 ie_len);
3890
3891 return status;
3892}
3893
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003894#endif /* CONFIG_OWE */
3895
3896
Hai Shalom899fcc72020-10-19 14:38:18 -07003897static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
3898 int reassoc)
3899{
3900 if ((sta->flags &
3901 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
3902 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
3903 return false;
3904
3905 if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
3906 ap_check_sa_query_timeout(hapd, sta);
3907
3908 if (!sta->sa_query_timed_out &&
3909 (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
3910 /*
3911 * STA has already been associated with MFP and SA Query timeout
3912 * has not been reached. Reject the association attempt
3913 * temporarily and start SA Query, if one is not pending.
3914 */
3915 if (sta->sa_query_count == 0)
3916 ap_sta_start_sa_query(hapd, sta);
3917
3918 return true;
3919 }
3920
3921 return false;
3922}
3923
3924
Sunil Ravi036cec52023-03-29 11:35:17 -07003925static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
3926 const u8 *ies, size_t ies_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003927 struct ieee802_11_elems *elems, int reassoc,
3928 bool link)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003929{
Hai Shalomb755a2a2020-04-23 21:49:02 -07003930 int resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003931 const u8 *wpa_ie;
3932 size_t wpa_ie_len;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003933 const u8 *p2p_dev_addr = NULL;
Sunil Ravi7f769292024-07-23 22:21:32 +00003934 struct hostapd_data *assoc_hapd;
3935 struct sta_info *assoc_sta = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003936
Sunil Ravi036cec52023-03-29 11:35:17 -07003937 resp = check_ssid(hapd, sta, elems->ssid, elems->ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003938 if (resp != WLAN_STATUS_SUCCESS)
3939 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003940 resp = check_wmm(hapd, sta, elems->wmm, elems->wmm_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003941 if (resp != WLAN_STATUS_SUCCESS)
3942 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003943 resp = check_ext_capab(hapd, sta, elems->ext_capab,
3944 elems->ext_capab_len);
Dmitry Shmidt051af732013-10-22 13:52:46 -07003945 if (resp != WLAN_STATUS_SUCCESS)
3946 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003947 resp = copy_supp_rates(hapd, sta, elems);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003948 if (resp != WLAN_STATUS_SUCCESS)
3949 return resp;
Hai Shalom74f70d42019-02-11 14:42:39 -08003950
Sunil Ravi036cec52023-03-29 11:35:17 -07003951 resp = check_multi_ap(hapd, sta, elems->multi_ap, elems->multi_ap_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08003952 if (resp != WLAN_STATUS_SUCCESS)
3953 return resp;
3954
Sunil Ravi036cec52023-03-29 11:35:17 -07003955 resp = copy_sta_ht_capab(hapd, sta, elems->ht_capabilities);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003956 if (resp != WLAN_STATUS_SUCCESS)
3957 return resp;
3958 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
3959 !(sta->flags & WLAN_STA_HT)) {
3960 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3961 HOSTAPD_LEVEL_INFO, "Station does not support "
3962 "mandatory HT PHY - reject association");
3963 return WLAN_STATUS_ASSOC_DENIED_NO_HT;
3964 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003965
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003966#ifdef CONFIG_IEEE80211AC
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003967 if (hapd->iconf->ieee80211ac) {
Sunil Ravi036cec52023-03-29 11:35:17 -07003968 resp = copy_sta_vht_capab(hapd, sta, elems->vht_capabilities);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003969 if (resp != WLAN_STATUS_SUCCESS)
3970 return resp;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08003971
Sunil Ravi640215c2023-06-28 23:08:09 +00003972 resp = set_sta_vht_opmode(hapd, sta, elems->opmode_notif);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003973 if (resp != WLAN_STATUS_SUCCESS)
3974 return resp;
3975 }
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08003976
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003977 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
3978 !(sta->flags & WLAN_STA_VHT)) {
3979 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3980 HOSTAPD_LEVEL_INFO, "Station does not support "
3981 "mandatory VHT PHY - reject association");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003982 return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003983 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003984
Sunil Ravi036cec52023-03-29 11:35:17 -07003985 if (hapd->conf->vendor_vht && !elems->vht_capabilities) {
3986 resp = copy_sta_vendor_vht(hapd, sta, elems->vendor_vht,
3987 elems->vendor_vht_len);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003988 if (resp != WLAN_STATUS_SUCCESS)
3989 return resp;
3990 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003991#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07003992#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08003993 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07003994 resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
Sunil Ravi036cec52023-03-29 11:35:17 -07003995 elems->he_capabilities,
3996 elems->he_capabilities_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07003997 if (resp != WLAN_STATUS_SUCCESS)
3998 return resp;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003999
4000 if (hapd->iconf->require_he && !(sta->flags & WLAN_STA_HE)) {
4001 hostapd_logger(hapd, sta->addr,
4002 HOSTAPD_MODULE_IEEE80211,
4003 HOSTAPD_LEVEL_INFO,
4004 "Station does not support mandatory HE PHY - reject association");
4005 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
4006 }
4007
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004008 if (is_6ghz_op_class(hapd->iconf->op_class)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004009 if (!(sta->flags & WLAN_STA_HE)) {
4010 hostapd_logger(hapd, sta->addr,
4011 HOSTAPD_MODULE_IEEE80211,
4012 HOSTAPD_LEVEL_INFO,
4013 "Station does not support mandatory HE PHY - reject association");
4014 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
4015 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004016 resp = copy_sta_he_6ghz_capab(hapd, sta,
Sunil Ravi036cec52023-03-29 11:35:17 -07004017 elems->he_6ghz_band_cap);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004018 if (resp != WLAN_STATUS_SUCCESS)
4019 return resp;
4020 }
Hai Shalom81f62d82019-07-22 12:10:00 -07004021 }
4022#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07004023#ifdef CONFIG_IEEE80211BE
4024 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4025 resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP,
Sunil Ravi036cec52023-03-29 11:35:17 -07004026 elems->he_capabilities,
4027 elems->he_capabilities_len,
4028 elems->eht_capabilities,
4029 elems->eht_capabilities_len);
Sunil Ravia04bd252022-05-02 22:54:18 -07004030 if (resp != WLAN_STATUS_SUCCESS)
4031 return resp;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004032
4033 if (!link) {
4034 resp = hostapd_process_ml_assoc_req(hapd, elems, sta);
4035 if (resp != WLAN_STATUS_SUCCESS)
4036 return resp;
4037 }
Sunil Ravia04bd252022-05-02 22:54:18 -07004038 }
4039#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004040
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004041#ifdef CONFIG_P2P
Sunil Ravi036cec52023-03-29 11:35:17 -07004042 if (elems->p2p && ies && ies_len) {
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004043 wpabuf_free(sta->p2p_ie);
4044 sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
4045 P2P_IE_VENDOR_TYPE);
4046 if (sta->p2p_ie)
4047 p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
4048 } else {
4049 wpabuf_free(sta->p2p_ie);
4050 sta->p2p_ie = NULL;
4051 }
4052#endif /* CONFIG_P2P */
4053
Sunil Ravi036cec52023-03-29 11:35:17 -07004054 if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems->rsn_ie) {
4055 wpa_ie = elems->rsn_ie;
4056 wpa_ie_len = elems->rsn_ie_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004057 } else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004058 elems->wpa_ie) {
4059 wpa_ie = elems->wpa_ie;
4060 wpa_ie_len = elems->wpa_ie_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004061 } else {
4062 wpa_ie = NULL;
4063 wpa_ie_len = 0;
4064 }
4065
4066#ifdef CONFIG_WPS
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004067 sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
Sunil Ravi036cec52023-03-29 11:35:17 -07004068 if (hapd->conf->wps_state && elems->wps_ie && ies && ies_len) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004069 wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
4070 "Request - assume WPS is used");
4071 sta->flags |= WLAN_STA_WPS;
4072 wpabuf_free(sta->wps_ie);
4073 sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
4074 WPS_IE_VENDOR_TYPE);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004075 if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
4076 wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
4077 sta->flags |= WLAN_STA_WPS2;
4078 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004079 wpa_ie = NULL;
4080 wpa_ie_len = 0;
4081 if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
4082 wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
4083 "(Re)Association Request - reject");
4084 return WLAN_STATUS_INVALID_IE;
4085 }
4086 } else if (hapd->conf->wps_state && wpa_ie == NULL) {
4087 wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
4088 "(Re)Association Request - possible WPS use");
4089 sta->flags |= WLAN_STA_MAYBE_WPS;
4090 } else
4091#endif /* CONFIG_WPS */
4092 if (hapd->conf->wpa && wpa_ie == NULL) {
4093 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4094 HOSTAPD_LEVEL_INFO,
4095 "No WPA/RSN IE in association request");
4096 return WLAN_STATUS_INVALID_IE;
4097 }
4098
4099 if (hapd->conf->wpa && wpa_ie) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004100 enum wpa_validate_result res;
Sunil Ravi7f769292024-07-23 22:21:32 +00004101#ifdef CONFIG_IEEE80211BE
4102 struct mld_info *info = &sta->mld_info;
4103 bool init = !sta->wpa_sm;
4104#endif /* CONFIG_IEEE80211BE */
Hai Shalomfdcde762020-04-02 11:19:20 -07004105
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004106 wpa_ie -= 2;
4107 wpa_ie_len += 2;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004108
4109 if (!sta->wpa_sm) {
Sunil Ravi7f769292024-07-23 22:21:32 +00004110 if (!link)
4111 assoc_sta = hostapd_ml_get_assoc_sta(
4112 hapd, sta, &assoc_hapd);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004113
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004114 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004115 sta->addr,
4116 p2p_dev_addr);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004117
4118 if (!sta->wpa_sm) {
4119 wpa_printf(MSG_WARNING,
4120 "Failed to initialize RSN state machine");
4121 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4122 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004123 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004124
Sunil Ravi7f769292024-07-23 22:21:32 +00004125#ifdef CONFIG_IEEE80211BE
4126 if (ap_sta_is_mld(hapd, sta)) {
4127 wpa_printf(MSG_DEBUG,
4128 "MLD: %s ML info in RSN Authenticator",
4129 init ? "Set" : "Reset");
4130 wpa_auth_set_ml_info(sta->wpa_sm,
4131 sta->mld_assoc_link_id,
4132 info);
4133 }
4134#endif /* CONFIG_IEEE80211BE */
4135
Hai Shalom021b0b52019-04-10 11:17:58 -07004136 wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
Sunil Ravi7f769292024-07-23 22:21:32 +00004137 wpa_auth_set_rsn_override(sta->wpa_sm,
4138 elems->rsne_override != NULL);
4139 wpa_auth_set_rsn_override_2(sta->wpa_sm,
4140 elems->rsne_override_2 != NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004141 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07004142 hapd->iface->freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004143 wpa_ie, wpa_ie_len,
Sunil Ravi036cec52023-03-29 11:35:17 -07004144 elems->rsnxe ? elems->rsnxe - 2 :
4145 NULL,
4146 elems->rsnxe ? elems->rsnxe_len + 2 :
4147 0,
4148 elems->mdie, elems->mdie_len,
Sunil Ravi7f769292024-07-23 22:21:32 +00004149 elems->owe_dh, elems->owe_dh_len,
4150 assoc_sta ? assoc_sta->wpa_sm : NULL);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004151 resp = wpa_res_to_status_code(res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004152 if (resp != WLAN_STATUS_SUCCESS)
4153 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004154
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004155 if (wpa_auth_uses_mfp(sta->wpa_sm))
4156 sta->flags |= WLAN_STA_MFP;
4157 else
4158 sta->flags &= ~WLAN_STA_MFP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004159
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004160#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004161 if (sta->auth_alg == WLAN_AUTH_FT) {
4162 if (!reassoc) {
4163 wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
4164 "to use association (not "
4165 "re-association) with FT auth_alg",
4166 MAC2STR(sta->addr));
4167 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4168 }
4169
4170 resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
4171 ies_len);
4172 if (resp != WLAN_STATUS_SUCCESS)
4173 return resp;
4174 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004175#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004176
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004177 if (link)
4178 goto skip_sae_owe;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004179#ifdef CONFIG_SAE
Roshan Pius3a1667e2018-07-03 15:17:14 -07004180 if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
4181 sta->sae->state == SAE_ACCEPTED)
4182 wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
4183
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004184 if (wpa_auth_uses_sae(sta->wpa_sm) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004185 sta->auth_alg == WLAN_AUTH_OPEN) {
4186 struct rsn_pmksa_cache_entry *sa;
4187 sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
Sunil Ravi89eba102022-09-13 21:04:37 -07004188 if (!sa || !wpa_key_mgmt_sae(sa->akmp)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004189 wpa_printf(MSG_DEBUG,
4190 "SAE: No PMKSA cache entry found for "
4191 MACSTR, MAC2STR(sta->addr));
4192 return WLAN_STATUS_INVALID_PMKID;
4193 }
4194 wpa_printf(MSG_DEBUG, "SAE: " MACSTR
4195 " using PMKSA caching", MAC2STR(sta->addr));
4196 } else if (wpa_auth_uses_sae(sta->wpa_sm) &&
4197 sta->auth_alg != WLAN_AUTH_SAE &&
4198 !(sta->auth_alg == WLAN_AUTH_FT &&
4199 wpa_auth_uses_ft_sae(sta->wpa_sm))) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004200 wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
4201 "SAE AKM after non-SAE auth_alg %u",
4202 MAC2STR(sta->addr), sta->auth_alg);
4203 return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
4204 }
Hai Shalomc3565922019-10-28 11:58:20 -07004205
Sunil Ravi77d572f2023-01-17 23:58:31 +00004206 if (hapd->conf->sae_pwe == SAE_PWE_BOTH &&
Hai Shalomc3565922019-10-28 11:58:20 -07004207 sta->auth_alg == WLAN_AUTH_SAE &&
Hai Shalom899fcc72020-10-19 14:38:18 -07004208 sta->sae && !sta->sae->h2e &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004209 ieee802_11_rsnx_capab_len(elems->rsnxe, elems->rsnxe_len,
Hai Shaloma20dcd72022-02-04 13:43:00 -08004210 WLAN_RSNX_CAPAB_SAE_H2E)) {
Hai Shalomc3565922019-10-28 11:58:20 -07004211 wpa_printf(MSG_INFO, "SAE: " MACSTR
4212 " indicates support for SAE H2E, but did not use it",
4213 MAC2STR(sta->addr));
4214 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4215 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004216#endif /* CONFIG_SAE */
4217
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004218#ifdef CONFIG_OWE
4219 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
4220 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004221 elems->owe_dh) {
4222 resp = owe_process_assoc_req(hapd, sta, elems->owe_dh,
4223 elems->owe_dh_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004224 if (resp != WLAN_STATUS_SUCCESS)
4225 return resp;
4226 }
4227#endif /* CONFIG_OWE */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004228 skip_sae_owe:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004229
Hai Shalom021b0b52019-04-10 11:17:58 -07004230#ifdef CONFIG_DPP2
4231 dpp_pfs_free(sta->dpp_pfs);
4232 sta->dpp_pfs = NULL;
4233
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004234 if (DPP_VERSION > 1 &&
4235 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07004236 hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
4237 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004238 elems->owe_dh) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004239 sta->dpp_pfs = dpp_pfs_init(
4240 wpabuf_head(hapd->conf->dpp_netaccesskey),
4241 wpabuf_len(hapd->conf->dpp_netaccesskey));
4242 if (!sta->dpp_pfs) {
4243 wpa_printf(MSG_DEBUG,
4244 "DPP: Could not initialize PFS");
4245 /* Try to continue without PFS */
4246 goto pfs_fail;
4247 }
4248
Sunil Ravi036cec52023-03-29 11:35:17 -07004249 if (dpp_pfs_process(sta->dpp_pfs, elems->owe_dh,
4250 elems->owe_dh_len) < 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004251 dpp_pfs_free(sta->dpp_pfs);
4252 sta->dpp_pfs = NULL;
4253 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4254 }
4255 }
4256
4257 wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
4258 sta->dpp_pfs->secret : NULL);
4259 pfs_fail:
4260#endif /* CONFIG_DPP2 */
4261
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004262 if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004263 wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
4264 hostapd_logger(hapd, sta->addr,
4265 HOSTAPD_MODULE_IEEE80211,
4266 HOSTAPD_LEVEL_INFO,
4267 "Station tried to use TKIP with HT "
4268 "association");
4269 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
4270 }
Sunil Ravi7f769292024-07-23 22:21:32 +00004271
4272 wpa_auth_set_ssid_protection(
4273 sta->wpa_sm,
4274 hapd->conf->ssid_protection &&
4275 ieee802_11_rsnx_capab_len(
4276 elems->rsnxe, elems->rsnxe_len,
4277 WLAN_RSNX_CAPAB_SSID_PROTECTION));
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004278#ifdef CONFIG_HS20
4279 } else if (hapd->conf->osen) {
Sunil Ravi036cec52023-03-29 11:35:17 -07004280 if (!elems->osen) {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004281 hostapd_logger(
4282 hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4283 HOSTAPD_LEVEL_INFO,
4284 "No HS 2.0 OSEN element in association request");
4285 return WLAN_STATUS_INVALID_IE;
4286 }
4287
4288 wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
4289 if (sta->wpa_sm == NULL)
4290 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
4291 sta->addr, NULL);
4292 if (sta->wpa_sm == NULL) {
4293 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
4294 "state machine");
4295 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4296 }
4297 if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
Sunil Ravi036cec52023-03-29 11:35:17 -07004298 elems->osen - 2, elems->osen_len + 2) < 0)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004299 return WLAN_STATUS_INVALID_IE;
4300#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004301 } else
4302 wpa_auth_sta_no_wpa(sta->wpa_sm);
4303
4304#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004305 p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
4306#endif /* CONFIG_P2P */
4307
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004308#ifdef CONFIG_HS20
4309 wpabuf_free(sta->hs20_ie);
Sunil Ravi036cec52023-03-29 11:35:17 -07004310 if (elems->hs20 && elems->hs20_len > 4) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004311 int release;
4312
Sunil Ravi036cec52023-03-29 11:35:17 -07004313 sta->hs20_ie = wpabuf_alloc_copy(elems->hs20 + 4,
4314 elems->hs20_len - 4);
4315 release = ((elems->hs20[4] >> 4) & 0x0f) + 1;
Hai Shalomc3565922019-10-28 11:58:20 -07004316 if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
4317 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004318 wpa_printf(MSG_DEBUG,
4319 "HS 2.0: PMF not negotiated by release %d station "
4320 MACSTR, release, MAC2STR(sta->addr));
4321 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
4322 }
4323 } else {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004324 sta->hs20_ie = NULL;
Hai Shalom74f70d42019-02-11 14:42:39 -08004325 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07004326
4327 wpabuf_free(sta->roaming_consortium);
Sunil Ravi036cec52023-03-29 11:35:17 -07004328 if (elems->roaming_cons_sel)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004329 sta->roaming_consortium = wpabuf_alloc_copy(
Sunil Ravi036cec52023-03-29 11:35:17 -07004330 elems->roaming_cons_sel + 4,
4331 elems->roaming_cons_sel_len - 4);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004332 else
4333 sta->roaming_consortium = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004334#endif /* CONFIG_HS20 */
4335
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004336#ifdef CONFIG_FST
4337 wpabuf_free(sta->mb_ies);
4338 if (hapd->iface->fst)
Sunil Ravi036cec52023-03-29 11:35:17 -07004339 sta->mb_ies = mb_ies_by_info(&elems->mb_ies);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004340 else
4341 sta->mb_ies = NULL;
4342#endif /* CONFIG_FST */
4343
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004344#ifdef CONFIG_MBO
Sunil Ravi036cec52023-03-29 11:35:17 -07004345 mbo_ap_check_sta_assoc(hapd, sta, elems);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004346
4347 if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004348 elems->mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004349 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
4350 wpa_printf(MSG_INFO,
4351 "MBO: Reject WPA2 association without PMF");
4352 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4353 }
4354#endif /* CONFIG_MBO */
4355
Hai Shalom74f70d42019-02-11 14:42:39 -08004356#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
4357 if (wpa_auth_uses_ocv(sta->wpa_sm) &&
4358 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4359 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4360 sta->auth_alg == WLAN_AUTH_FILS_PK)) {
4361 struct wpa_channel_info ci;
4362 int tx_chanwidth;
4363 int tx_seg1_idx;
Hai Shalom899fcc72020-10-19 14:38:18 -07004364 enum oci_verify_result res;
Hai Shalom74f70d42019-02-11 14:42:39 -08004365
4366 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
4367 wpa_printf(MSG_WARNING,
4368 "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
4369 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4370 }
4371
4372 if (get_sta_tx_parameters(sta->wpa_sm,
4373 channel_width_to_int(ci.chanwidth),
4374 ci.seg1_idx, &tx_chanwidth,
4375 &tx_seg1_idx) < 0)
4376 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4377
Sunil Ravi036cec52023-03-29 11:35:17 -07004378 res = ocv_verify_tx_params(elems->oci, elems->oci_len, &ci,
Hai Shalom899fcc72020-10-19 14:38:18 -07004379 tx_chanwidth, tx_seg1_idx);
4380 if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
4381 res == OCI_NOT_FOUND) {
4382 /* Work around misbehaving STAs */
4383 wpa_printf(MSG_INFO,
4384 "FILS: Disable OCV with a STA that does not send OCI");
4385 wpa_auth_set_ocv(sta->wpa_sm, 0);
4386 } else if (res != OCI_SUCCESS) {
4387 wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
4388 ocv_errorstr);
4389 wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
4390 MACSTR " frame=fils-reassoc-req error=%s",
4391 MAC2STR(sta->addr), ocv_errorstr);
Hai Shalom74f70d42019-02-11 14:42:39 -08004392 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4393 }
4394 }
4395#endif /* CONFIG_FILS && CONFIG_OCV */
4396
Sunil Ravi036cec52023-03-29 11:35:17 -07004397 ap_copy_sta_supp_op_classes(sta, elems->supp_op_classes,
4398 elems->supp_op_classes_len);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08004399
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004400 if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004401 elems->rrm_enabled &&
4402 elems->rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
4403 os_memcpy(sta->rrm_enabled_capa, elems->rrm_enabled,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004404 sizeof(sta->rrm_enabled_capa));
4405
Sunil Ravi036cec52023-03-29 11:35:17 -07004406 if (elems->power_capab) {
4407 sta->min_tx_power = elems->power_capab[0];
4408 sta->max_tx_power = elems->power_capab[1];
Roshan Pius3a1667e2018-07-03 15:17:14 -07004409 sta->power_capab = 1;
4410 } else {
4411 sta->power_capab = 0;
4412 }
4413
Sunil Ravi7f769292024-07-23 22:21:32 +00004414 if (elems->bss_max_idle_period &&
4415 hapd->conf->max_acceptable_idle_period) {
4416 u16 req;
4417
4418 req = WPA_GET_LE16(elems->bss_max_idle_period);
4419 if (req <= hapd->conf->max_acceptable_idle_period)
4420 sta->max_idle_period = req;
4421 else if (hapd->conf->max_acceptable_idle_period >
4422 hapd->conf->ap_max_inactivity)
4423 sta->max_idle_period =
4424 hapd->conf->max_acceptable_idle_period;
4425 }
4426
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004427 return WLAN_STATUS_SUCCESS;
4428}
4429
4430
Sunil Ravi036cec52023-03-29 11:35:17 -07004431static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
4432 const u8 *ies, size_t ies_len, int reassoc)
4433{
4434 struct ieee802_11_elems elems;
4435
4436 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
4437 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4438 HOSTAPD_LEVEL_INFO,
4439 "Station sent an invalid association request");
4440 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4441 }
4442
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004443 return __check_assoc_ies(hapd, sta, ies, ies_len, &elems, reassoc,
4444 false);
4445}
4446
4447
4448#ifdef CONFIG_IEEE80211BE
4449
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004450static void ieee80211_ml_build_assoc_resp(struct hostapd_data *hapd,
4451 struct mld_link_info *link)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004452{
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004453 u8 buf[EHT_ML_MAX_STA_PROF_LEN];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004454 u8 *p = buf;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004455 size_t buflen = sizeof(buf);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004456
4457 /* Capability Info */
4458 WPA_PUT_LE16(p, hostapd_own_capab_info(hapd));
4459 p += 2;
4460
4461 /* Status Code */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004462 WPA_PUT_LE16(p, link->status);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004463 p += 2;
4464
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004465 if (link->status != WLAN_STATUS_SUCCESS)
4466 goto out;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004467
4468 /* AID is not included */
4469 p = hostapd_eid_supp_rates(hapd, p);
4470 p = hostapd_eid_ext_supp_rates(hapd, p);
4471 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
4472 p = hostapd_eid_ht_capabilities(hapd, p);
4473 p = hostapd_eid_ht_operation(hapd, p);
4474
4475 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
4476 p = hostapd_eid_vht_capabilities(hapd, p, 0);
4477 p = hostapd_eid_vht_operation(hapd, p);
4478 }
4479
4480 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
4481 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
4482 p = hostapd_eid_he_operation(hapd, p);
4483 p = hostapd_eid_spatial_reuse(hapd, p);
4484 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
4485 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
4486 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4487 p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
4488 p = hostapd_eid_eht_operation(hapd, p);
4489 }
4490 }
4491
4492 p = hostapd_eid_ext_capab(hapd, p, false);
4493 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
4494 p = hostapd_eid_wmm(hapd, p);
4495
4496 if (hapd->conf->assocresp_elements &&
4497 (size_t) (buf + buflen - p) >=
4498 wpabuf_len(hapd->conf->assocresp_elements)) {
4499 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
4500 wpabuf_len(hapd->conf->assocresp_elements));
4501 p += wpabuf_len(hapd->conf->assocresp_elements);
4502 }
4503
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004504out:
4505 os_free(link->resp_sta_profile);
4506 link->resp_sta_profile = os_memdup(buf, p - buf);
4507 link->resp_sta_profile_len = link->resp_sta_profile ? p - buf : 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004508}
4509
4510
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004511static int ieee80211_ml_process_link(struct hostapd_data *hapd,
4512 struct sta_info *origin_sta,
4513 struct mld_link_info *link,
4514 const u8 *ies, size_t ies_len,
4515 bool reassoc, bool offload)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004516{
4517 struct ieee802_11_elems elems;
4518 struct wpabuf *mlbuf = NULL;
4519 struct sta_info *sta = NULL;
4520 u16 status = WLAN_STATUS_SUCCESS;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004521 int i;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004522
4523 wpa_printf(MSG_DEBUG, "MLD: link: link_id=%u, peer=" MACSTR,
4524 hapd->mld_link_id, MAC2STR(link->peer_addr));
4525
4526 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
4527 wpa_printf(MSG_DEBUG, "MLD: link: Element parsing failed");
4528 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4529 goto out;
4530 }
4531
4532 sta = ap_get_sta(hapd, origin_sta->addr);
4533 if (sta) {
4534 wpa_printf(MSG_INFO, "MLD: link: Station already exists");
4535 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4536 sta = NULL;
4537 goto out;
4538 }
4539
4540 sta = ap_sta_add(hapd, origin_sta->addr);
4541 if (!sta) {
4542 wpa_printf(MSG_DEBUG, "MLD: link: ap_sta_add() failed");
4543 status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4544 goto out;
4545 }
4546
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004547 mlbuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004548 if (!mlbuf)
4549 goto out;
4550
4551 if (ieee802_11_parse_link_assoc_req(ies, ies_len, &elems, mlbuf,
4552 hapd->mld_link_id, true) ==
4553 ParseFailed) {
4554 wpa_printf(MSG_DEBUG,
4555 "MLD: link: Failed to parse association request Multi-Link element");
4556 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4557 goto out;
4558 }
4559
4560 sta->flags |= origin_sta->flags | WLAN_STA_ASSOC_REQ_OK;
Sunil Ravi7f769292024-07-23 22:21:32 +00004561 sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id;
4562
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004563 status = __check_assoc_ies(hapd, sta, NULL, 0, &elems, reassoc, true);
4564 if (status != WLAN_STATUS_SUCCESS) {
4565 wpa_printf(MSG_DEBUG, "MLD: link: Element check failed");
4566 goto out;
4567 }
4568
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004569 ap_sta_set_mld(sta, true);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004570
4571 os_memcpy(&sta->mld_info, &origin_sta->mld_info, sizeof(sta->mld_info));
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004572 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
4573 struct mld_link_info *li = &sta->mld_info.links[i];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004574
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004575 li->resp_sta_profile = NULL;
4576 li->resp_sta_profile_len = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004577 }
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004578
4579 if (!offload) {
4580 /*
4581 * Get the AID from the station on which the association was
4582 * performed, and mark it as used.
4583 */
4584 sta->aid = origin_sta->aid;
4585 if (sta->aid == 0) {
4586 wpa_printf(MSG_DEBUG, "MLD: link: No AID assigned");
4587 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4588 goto out;
4589 }
4590 hapd->sta_aid[(sta->aid - 1) / 32] |= BIT((sta->aid - 1) % 32);
4591 sta->listen_interval = origin_sta->listen_interval;
4592 if (update_ht_state(hapd, sta) > 0)
4593 ieee802_11_update_beacons(hapd->iface);
4594 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004595
Sunil Ravi7f769292024-07-23 22:21:32 +00004596 /* Maintain state machine reference on all link STAs, this is needed
4597 * during group rekey handling.
4598 */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004599 wpa_auth_sta_deinit(sta->wpa_sm);
Sunil Ravi7f769292024-07-23 22:21:32 +00004600 sta->wpa_sm = origin_sta->wpa_sm;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004601
4602 /*
4603 * Do not initialize the EAPOL state machine.
4604 * TODO: Maybe it is needed?
4605 */
4606 sta->eapol_sm = NULL;
4607
4608 wpa_printf(MSG_DEBUG, "MLD: link=%u, association OK (aid=%u)",
4609 hapd->mld_link_id, sta->aid);
4610
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004611 sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC_REQ_OK;
4612
4613 /* TODO: What other processing is required? */
4614
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004615 if (!offload && add_associated_sta(hapd, sta, reassoc))
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004616 status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4617out:
4618 wpabuf_free(mlbuf);
4619 link->status = status;
4620
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004621 if (!offload)
4622 ieee80211_ml_build_assoc_resp(hapd, link);
Sunil Ravi72e01222024-03-09 01:25:43 +00004623
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004624 wpa_printf(MSG_DEBUG, "MLD: link: status=%u", status);
4625 if (status != WLAN_STATUS_SUCCESS) {
4626 if (sta)
4627 ap_free_sta(hapd, sta);
4628 return -1;
4629 }
4630
4631 return 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004632}
4633
4634
4635bool hostapd_is_mld_ap(struct hostapd_data *hapd)
4636{
4637 if (!hapd->conf->mld_ap)
4638 return false;
4639
4640 if (!hapd->iface || !hapd->iface->interfaces ||
4641 hapd->iface->interfaces->count <= 1)
4642 return false;
4643
4644 return true;
4645}
4646
4647#endif /* CONFIG_IEEE80211BE */
4648
4649
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004650int hostapd_process_assoc_ml_info(struct hostapd_data *hapd,
4651 struct sta_info *sta,
4652 const u8 *ies, size_t ies_len,
4653 bool reassoc, int tx_link_status,
4654 bool offload)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004655{
4656#ifdef CONFIG_IEEE80211BE
Sunil Ravi7f769292024-07-23 22:21:32 +00004657 unsigned int i;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004658
4659 if (!hostapd_is_mld_ap(hapd))
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004660 return 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004661
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004662 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
Sunil Ravi7f769292024-07-23 22:21:32 +00004663 struct hostapd_data *bss = NULL;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004664 struct mld_link_info *link = &sta->mld_info.links[i];
Sunil Ravi7f769292024-07-23 22:21:32 +00004665 bool link_bss_found = false;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004666
Sunil Ravi7f769292024-07-23 22:21:32 +00004667 if (!link->valid || i == sta->mld_assoc_link_id)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004668 continue;
4669
Sunil Ravi7f769292024-07-23 22:21:32 +00004670 for_each_mld_link(bss, hapd) {
4671 if (bss == hapd)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004672 continue;
4673
Sunil Ravi7f769292024-07-23 22:21:32 +00004674 if (bss->mld_link_id != i)
4675 continue;
4676
4677 link_bss_found = true;
4678 break;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004679 }
4680
Sunil Ravi7f769292024-07-23 22:21:32 +00004681 if (!link_bss_found || TEST_FAIL()) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004682 wpa_printf(MSG_DEBUG,
4683 "MLD: No link match for link_id=%u", i);
4684
4685 link->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004686 if (!offload)
4687 ieee80211_ml_build_assoc_resp(hapd, link);
4688 } else if (tx_link_status != WLAN_STATUS_SUCCESS) {
4689 /* TX link rejected the connection */
4690 link->status = WLAN_STATUS_DENIED_TX_LINK_NOT_ACCEPTED;
4691 if (!offload)
4692 ieee80211_ml_build_assoc_resp(hapd, link);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004693 } else {
Sunil Ravi7f769292024-07-23 22:21:32 +00004694 if (ieee80211_ml_process_link(bss, sta, link,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004695 ies, ies_len, reassoc,
4696 offload))
4697 return -1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004698 }
4699 }
4700#endif /* CONFIG_IEEE80211BE */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004701
4702 return 0;
Sunil Ravi036cec52023-03-29 11:35:17 -07004703}
4704
4705
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004706static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
4707 u16 reason_code)
4708{
4709 int send_len;
4710 struct ieee80211_mgmt reply;
4711
4712 os_memset(&reply, 0, sizeof(reply));
4713 reply.frame_control =
4714 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
4715 os_memcpy(reply.da, addr, ETH_ALEN);
4716 os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
4717 os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
4718
4719 send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
4720 reply.u.deauth.reason_code = host_to_le16(reason_code);
4721
Hai Shalomfdcde762020-04-02 11:19:20 -07004722 if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004723 wpa_printf(MSG_INFO, "Failed to send deauth: %s",
4724 strerror(errno));
4725}
4726
4727
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004728static int add_associated_sta(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08004729 struct sta_info *sta, int reassoc)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004730{
4731 struct ieee80211_ht_capabilities ht_cap;
4732 struct ieee80211_vht_capabilities vht_cap;
Hai Shalom81f62d82019-07-22 12:10:00 -07004733 struct ieee80211_he_capabilities he_cap;
Sunil Ravia04bd252022-05-02 22:54:18 -07004734 struct ieee80211_eht_capabilities eht_cap;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004735 int set = 1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004736 const u8 *mld_link_addr = NULL;
4737 bool mld_link_sta = false;
4738
4739#ifdef CONFIG_IEEE80211BE
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004740 if (ap_sta_is_mld(hapd, sta)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004741 u8 mld_link_id = hapd->mld_link_id;
4742
4743 mld_link_sta = sta->mld_assoc_link_id != mld_link_id;
4744 mld_link_addr = sta->mld_info.links[mld_link_id].peer_addr;
4745
4746 if (hapd->mld_link_id != sta->mld_assoc_link_id)
4747 set = 0;
4748 }
4749#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004750
4751 /*
4752 * Remove the STA entry to ensure the STA PS state gets cleared and
4753 * configuration gets updated. This is relevant for cases, such as
4754 * FT-over-the-DS, where a station re-associates back to the same AP but
4755 * skips the authentication flow, or if working with a driver that
4756 * does not support full AP client state.
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004757 *
4758 * Skip this if the STA has already completed FT reassociation and the
4759 * TK has been configured since the TX/RX PN must not be reset to 0 for
4760 * the same key.
Hai Shalom74f70d42019-02-11 14:42:39 -08004761 *
4762 * FT-over-the-DS has a special case where the STA entry (and as such,
4763 * the TK) has not yet been configured to the driver depending on which
4764 * driver interface is used. For that case, allow add-STA operation to
4765 * be used (instead of set-STA). This is needed to allow mac80211-based
4766 * drivers to accept the STA parameter configuration. Since this is
4767 * after a new FT-over-DS exchange, a new TK has been derived, so key
4768 * reinstallation is not a concern for this case.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004769 */
Hai Shalom74f70d42019-02-11 14:42:39 -08004770 wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
4771 " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
4772 MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
4773 sta->ft_over_ds, reassoc,
4774 !!(sta->flags & WLAN_STA_AUTHORIZED),
4775 wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
4776 wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
4777
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004778 if (!mld_link_sta && !sta->added_unassoc &&
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004779 (!(sta->flags & WLAN_STA_AUTHORIZED) ||
Hai Shalom74f70d42019-02-11 14:42:39 -08004780 (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004781 (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
4782 !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004783 hostapd_drv_sta_remove(hapd, sta->addr);
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004784 wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
4785 set = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08004786
4787 /* Do not allow the FT-over-DS exception to be used more than
4788 * once per authentication exchange to guarantee a new TK is
4789 * used here */
4790 sta->ft_over_ds = 0;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004791 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004792
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004793 if (sta->flags & WLAN_STA_HT)
4794 hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004795#ifdef CONFIG_IEEE80211AC
4796 if (sta->flags & WLAN_STA_VHT)
4797 hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
4798#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07004799#ifdef CONFIG_IEEE80211AX
4800 if (sta->flags & WLAN_STA_HE) {
4801 hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
4802 sta->he_capab_len);
4803 }
4804#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07004805#ifdef CONFIG_IEEE80211BE
4806 if (sta->flags & WLAN_STA_EHT)
4807 hostapd_get_eht_capab(hapd, sta->eht_capab, &eht_cap,
4808 sta->eht_capab_len);
4809#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004810
4811 /*
4812 * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
4813 * will be set when the ACK frame for the (Re)Association Response frame
4814 * is processed (TX status driver event).
4815 */
4816 if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
4817 sta->supported_rates, sta->supported_rates_len,
4818 sta->listen_interval,
4819 sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
4820 sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
Hai Shalom81f62d82019-07-22 12:10:00 -07004821 sta->flags & WLAN_STA_HE ? &he_cap : NULL,
4822 sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
Sunil Ravia04bd252022-05-02 22:54:18 -07004823 sta->flags & WLAN_STA_EHT ? &eht_cap : NULL,
4824 sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004825 sta->he_6ghz_capab,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004826 sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004827 sta->vht_opmode, sta->p2p_ie ? 1 : 0,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004828 set, mld_link_addr, mld_link_sta)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004829 hostapd_logger(hapd, sta->addr,
4830 HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
4831 "Could not %s STA to kernel driver",
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004832 set ? "set" : "add");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004833
4834 if (sta->added_unassoc) {
4835 hostapd_drv_sta_remove(hapd, sta->addr);
4836 sta->added_unassoc = 0;
4837 }
4838
4839 return -1;
4840 }
4841
4842 sta->added_unassoc = 0;
4843
4844 return 0;
4845}
4846
4847
4848static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt29333592017-01-09 12:27:11 -08004849 const u8 *addr, u16 status_code, int reassoc,
Hai Shalomfdcde762020-04-02 11:19:20 -07004850 const u8 *ies, size_t ies_len, int rssi,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004851 int omit_rsnxe, bool allow_mld_addr_trans)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004852{
4853 int send_len;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004854 u8 *buf;
4855 size_t buflen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004856 struct ieee80211_mgmt *reply;
4857 u8 *p;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004858 u16 res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004859
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004860 buflen = sizeof(struct ieee80211_mgmt) + 1024;
4861#ifdef CONFIG_FILS
4862 if (sta && sta->fils_hlp_resp)
4863 buflen += wpabuf_len(sta->fils_hlp_resp);
Hai Shalom81f62d82019-07-22 12:10:00 -07004864 if (sta)
4865 buflen += 150;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004866#endif /* CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004867#ifdef CONFIG_OWE
4868 if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
4869 buflen += 150;
4870#endif /* CONFIG_OWE */
Hai Shalom021b0b52019-04-10 11:17:58 -07004871#ifdef CONFIG_DPP2
4872 if (sta && sta->dpp_pfs)
4873 buflen += 5 + sta->dpp_pfs->curve->prime_len;
4874#endif /* CONFIG_DPP2 */
Sunil Ravia04bd252022-05-02 22:54:18 -07004875#ifdef CONFIG_IEEE80211BE
4876 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4877 buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
4878 buflen += 3 + sizeof(struct ieee80211_eht_operation);
Sunil Ravi036cec52023-03-29 11:35:17 -07004879 if (hapd->iconf->punct_bitmap)
4880 buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
Sunil Ravia04bd252022-05-02 22:54:18 -07004881 }
4882#endif /* CONFIG_IEEE80211BE */
4883
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004884 buf = os_zalloc(buflen);
4885 if (!buf) {
4886 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4887 goto done;
4888 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004889 reply = (struct ieee80211_mgmt *) buf;
4890 reply->frame_control =
4891 IEEE80211_FC(WLAN_FC_TYPE_MGMT,
4892 (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
4893 WLAN_FC_STYPE_ASSOC_RESP));
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004894
Dmitry Shmidt29333592017-01-09 12:27:11 -08004895 os_memcpy(reply->da, addr, ETH_ALEN);
Sunil Ravi7f769292024-07-23 22:21:32 +00004896 os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
4897 os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004898
4899 send_len = IEEE80211_HDRLEN;
4900 send_len += sizeof(reply->u.assoc_resp);
4901 reply->u.assoc_resp.capab_info =
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07004902 host_to_le16(hostapd_own_capab_info(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004903 reply->u.assoc_resp.status_code = host_to_le16(status_code);
Dmitry Shmidt29333592017-01-09 12:27:11 -08004904
4905 reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
4906 BIT(14) | BIT(15));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004907 /* Supported rates */
4908 p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
4909 /* Extended supported rates */
4910 p = hostapd_eid_ext_supp_rates(hapd, p);
4911
Hai Shalomfdcde762020-04-02 11:19:20 -07004912 /* Radio measurement capabilities */
4913 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
4914
Hai Shalom74f70d42019-02-11 14:42:39 -08004915#ifdef CONFIG_MBO
4916 if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
4917 rssi != 0) {
4918 int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
4919
4920 p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
4921 delta);
4922 }
4923#endif /* CONFIG_MBO */
4924
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004925#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt29333592017-01-09 12:27:11 -08004926 if (sta && status_code == WLAN_STATUS_SUCCESS) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004927 /* IEEE 802.11r: Mobility Domain Information, Fast BSS
4928 * Transition Information, RSN, [RIC Response] */
4929 p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004930 buf + buflen - p,
Hai Shalomfdcde762020-04-02 11:19:20 -07004931 sta->auth_alg, ies, ies_len,
4932 omit_rsnxe);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004933 if (!p) {
4934 wpa_printf(MSG_DEBUG,
4935 "FT: Failed to write AssocResp IEs");
4936 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4937 goto done;
4938 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004939 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004940#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom81f62d82019-07-22 12:10:00 -07004941#ifdef CONFIG_FILS
4942 if (sta && status_code == WLAN_STATUS_SUCCESS &&
4943 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4944 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4945 sta->auth_alg == WLAN_AUTH_FILS_PK))
4946 p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
4947 buf + buflen - p,
4948 ies, ies_len);
4949#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004950
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004951#ifdef CONFIG_OWE
Hai Shalom74f70d42019-02-11 14:42:39 -08004952 if (sta && status_code == WLAN_STATUS_SUCCESS &&
4953 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004954 p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
4955 buf + buflen - p,
4956 ies, ies_len);
4957#endif /* CONFIG_OWE */
4958
Dmitry Shmidt29333592017-01-09 12:27:11 -08004959 if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004960 p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004961
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004962 p = hostapd_eid_ht_capabilities(hapd, p);
4963 p = hostapd_eid_ht_operation(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004964
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004965#ifdef CONFIG_IEEE80211AC
Hai Shalomc3565922019-10-28 11:58:20 -07004966 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
4967 !is_6ghz_op_class(hapd->iconf->op_class)) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07004968 u32 nsts = 0, sta_nsts;
4969
Dmitry Shmidt29333592017-01-09 12:27:11 -08004970 if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07004971 struct ieee80211_vht_capabilities *capa;
4972
4973 nsts = (hapd->iface->conf->vht_capab >>
4974 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
4975 capa = sta->vht_capabilities;
4976 sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
4977 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
4978
4979 if (nsts < sta_nsts)
4980 nsts = 0;
4981 else
4982 nsts = sta_nsts;
4983 }
4984 p = hostapd_eid_vht_capabilities(hapd, p, nsts);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004985 p = hostapd_eid_vht_operation(hapd, p);
4986 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004987#endif /* CONFIG_IEEE80211AC */
4988
Hai Shalom81f62d82019-07-22 12:10:00 -07004989#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08004990 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07004991 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
4992 p = hostapd_eid_he_operation(hapd, p);
Sunil Ravia04bd252022-05-02 22:54:18 -07004993 p = hostapd_eid_cca(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07004994 p = hostapd_eid_spatial_reuse(hapd, p);
4995 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004996 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07004997 }
4998#endif /* CONFIG_IEEE80211AX */
4999
Sunil Ravi77d572f2023-01-17 23:58:31 +00005000 p = hostapd_eid_ext_capab(hapd, p, false);
Sunil Ravi7f769292024-07-23 22:21:32 +00005001 p = hostapd_eid_bss_max_idle_period(hapd, p, sta->max_idle_period);
Dmitry Shmidt29333592017-01-09 12:27:11 -08005002 if (sta && sta->qos_map_enabled)
Dmitry Shmidt051af732013-10-22 13:52:46 -07005003 p = hostapd_eid_qos_map_set(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005004
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005005#ifdef CONFIG_FST
5006 if (hapd->iface->fst_ies) {
5007 os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
5008 wpabuf_len(hapd->iface->fst_ies));
5009 p += wpabuf_len(hapd->iface->fst_ies);
5010 }
5011#endif /* CONFIG_FST */
5012
Hai Shalomfdcde762020-04-02 11:19:20 -07005013#ifdef CONFIG_TESTING_OPTIONS
5014 if (hapd->conf->rsnxe_override_ft &&
5015 buf + buflen - p >=
5016 (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
5017 sta && sta->auth_alg == WLAN_AUTH_FT) {
5018 wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
5019 os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
5020 wpabuf_len(hapd->conf->rsnxe_override_ft));
5021 p += wpabuf_len(hapd->conf->rsnxe_override_ft);
5022 goto rsnxe_done;
5023 }
5024#endif /* CONFIG_TESTING_OPTIONS */
5025 if (!omit_rsnxe)
5026 p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
5027#ifdef CONFIG_TESTING_OPTIONS
5028rsnxe_done:
5029#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomc3565922019-10-28 11:58:20 -07005030
Sunil Ravia04bd252022-05-02 22:54:18 -07005031#ifdef CONFIG_IEEE80211BE
5032 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005033 if (hapd->conf->mld_ap)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005034 p = hostapd_eid_eht_ml_assoc(hapd, sta, p);
Sunil Ravia04bd252022-05-02 22:54:18 -07005035 p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
5036 p = hostapd_eid_eht_operation(hapd, p);
5037 }
5038#endif /* CONFIG_IEEE80211BE */
5039
Hai Shalom021b0b52019-04-10 11:17:58 -07005040#ifdef CONFIG_OWE
5041 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
5042 sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
Hai Shalom899fcc72020-10-19 14:38:18 -07005043 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
5044 !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07005045 struct wpabuf *pub;
5046
5047 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
5048 if (!pub) {
5049 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5050 goto done;
5051 }
5052 /* OWE Diffie-Hellman Parameter element */
5053 *p++ = WLAN_EID_EXTENSION; /* Element ID */
5054 *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
5055 *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
5056 WPA_PUT_LE16(p, sta->owe_group);
5057 p += 2;
5058 os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
5059 p += wpabuf_len(pub);
5060 wpabuf_free(pub);
5061 }
5062#endif /* CONFIG_OWE */
5063
5064#ifdef CONFIG_DPP2
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005065 if (DPP_VERSION > 1 && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07005066 sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
5067 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
5068 os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
5069 wpabuf_len(sta->dpp_pfs->ie));
5070 p += wpabuf_len(sta->dpp_pfs->ie);
5071 }
5072#endif /* CONFIG_DPP2 */
5073
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005074#ifdef CONFIG_IEEE80211AC
Dmitry Shmidt29333592017-01-09 12:27:11 -08005075 if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005076 p = hostapd_eid_vendor_vht(hapd, p);
5077#endif /* CONFIG_IEEE80211AC */
5078
Dmitry Shmidt29333592017-01-09 12:27:11 -08005079 if (sta && (sta->flags & WLAN_STA_WMM))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005080 p = hostapd_eid_wmm(hapd, p);
5081
5082#ifdef CONFIG_WPS
Dmitry Shmidt29333592017-01-09 12:27:11 -08005083 if (sta &&
5084 ((sta->flags & WLAN_STA_WPS) ||
5085 ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005086 struct wpabuf *wps = wps_build_assoc_resp_ie();
5087 if (wps) {
5088 os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
5089 p += wpabuf_len(wps);
5090 wpabuf_free(wps);
5091 }
5092 }
5093#endif /* CONFIG_WPS */
5094
Hai Shalom74f70d42019-02-11 14:42:39 -08005095 if (sta && (sta->flags & WLAN_STA_MULTI_AP))
Sunil Ravi99c035e2024-07-12 01:42:03 +00005096 p = hostapd_eid_multi_ap(hapd, p, buf + buflen - p);
Hai Shalom74f70d42019-02-11 14:42:39 -08005097
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005098#ifdef CONFIG_P2P
Dmitry Shmidt29333592017-01-09 12:27:11 -08005099 if (sta && sta->p2p_ie && hapd->p2p_group) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005100 struct wpabuf *p2p_resp_ie;
5101 enum p2p_status_code status;
5102 switch (status_code) {
5103 case WLAN_STATUS_SUCCESS:
5104 status = P2P_SC_SUCCESS;
5105 break;
5106 case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
5107 status = P2P_SC_FAIL_LIMIT_REACHED;
5108 break;
5109 default:
5110 status = P2P_SC_FAIL_INVALID_PARAMS;
5111 break;
5112 }
5113 p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
5114 if (p2p_resp_ie) {
5115 os_memcpy(p, wpabuf_head(p2p_resp_ie),
5116 wpabuf_len(p2p_resp_ie));
5117 p += wpabuf_len(p2p_resp_ie);
5118 wpabuf_free(p2p_resp_ie);
5119 }
5120 }
5121#endif /* CONFIG_P2P */
5122
5123#ifdef CONFIG_P2P_MANAGER
5124 if (hapd->conf->p2p & P2P_MANAGE)
5125 p = hostapd_eid_p2p_manage(hapd, p);
5126#endif /* CONFIG_P2P_MANAGER */
5127
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005128 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005129
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005130 if (hapd->conf->assocresp_elements &&
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005131 (size_t) (buf + buflen - p) >=
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005132 wpabuf_len(hapd->conf->assocresp_elements)) {
5133 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
5134 wpabuf_len(hapd->conf->assocresp_elements));
5135 p += wpabuf_len(hapd->conf->assocresp_elements);
5136 }
5137
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005138 send_len += p - reply->u.assoc_resp.variable;
5139
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005140#ifdef CONFIG_FILS
Dmitry Shmidt29333592017-01-09 12:27:11 -08005141 if (sta &&
5142 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005143 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5144 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
5145 status_code == WLAN_STATUS_SUCCESS) {
5146 struct ieee802_11_elems elems;
5147
5148 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005149 ParseFailed || !elems.fils_session) {
5150 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5151 goto done;
5152 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005153
5154 /* FILS Session */
5155 *p++ = WLAN_EID_EXTENSION; /* Element ID */
5156 *p++ = 1 + FILS_SESSION_LEN; /* Length */
5157 *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
5158 os_memcpy(p, elems.fils_session, FILS_SESSION_LEN);
5159 send_len += 2 + 1 + FILS_SESSION_LEN;
5160
5161 send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005162 buflen, sta->fils_hlp_resp);
5163 if (send_len < 0) {
5164 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5165 goto done;
5166 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005167 }
5168#endif /* CONFIG_FILS */
5169
Hai Shalomfdcde762020-04-02 11:19:20 -07005170 if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005171 wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
5172 strerror(errno));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005173 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005174 }
5175
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005176done:
5177 os_free(buf);
5178 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005179}
5180
5181
Roshan Pius3a1667e2018-07-03 15:17:14 -07005182#ifdef CONFIG_OWE
5183u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
5184 const u8 *owe_dh, u8 owe_dh_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07005185 u8 *owe_buf, size_t owe_buf_len, u16 *status)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005186{
5187#ifdef CONFIG_TESTING_OPTIONS
5188 if (hapd->conf->own_ie_override) {
5189 wpa_printf(MSG_DEBUG, "OWE: Using IE override");
Hai Shalomfdcde762020-04-02 11:19:20 -07005190 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005191 return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5192 owe_buf_len, NULL, 0);
5193 }
5194#endif /* CONFIG_TESTING_OPTIONS */
5195
5196 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
5197 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
5198 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5199 owe_buf_len, NULL, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -07005200 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005201 return owe_buf;
5202 }
5203
Hai Shalom81f62d82019-07-22 12:10:00 -07005204 if (sta->owe_pmk && sta->external_dh_updated) {
5205 wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
Hai Shalomfdcde762020-04-02 11:19:20 -07005206 *status = WLAN_STATUS_SUCCESS;
Hai Shalom81f62d82019-07-22 12:10:00 -07005207 return owe_buf;
5208 }
5209
Hai Shalomfdcde762020-04-02 11:19:20 -07005210 *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
5211 if (*status != WLAN_STATUS_SUCCESS)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005212 return NULL;
5213
5214 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5215 owe_buf_len, NULL, 0);
5216
5217 if (sta->owe_ecdh && owe_buf) {
5218 struct wpabuf *pub;
5219
5220 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
5221 if (!pub) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005222 *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005223 return owe_buf;
5224 }
5225
5226 /* OWE Diffie-Hellman Parameter element */
5227 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
5228 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
5229 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
5230 */
5231 WPA_PUT_LE16(owe_buf, sta->owe_group);
5232 owe_buf += 2;
5233 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
5234 owe_buf += wpabuf_len(pub);
5235 wpabuf_free(pub);
5236 }
5237
5238 return owe_buf;
5239}
5240#endif /* CONFIG_OWE */
5241
5242
Paul Stewart092955c2017-02-06 09:13:09 -08005243#ifdef CONFIG_FILS
5244
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005245void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
Paul Stewart092955c2017-02-06 09:13:09 -08005246{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005247 u16 reply_res;
Paul Stewart092955c2017-02-06 09:13:09 -08005248
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005249 wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
5250 MAC2STR(sta->addr));
5251 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5252 if (!sta->fils_pending_assoc_req)
Paul Stewart092955c2017-02-06 09:13:09 -08005253 return;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005254 reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
5255 sta->fils_pending_assoc_is_reassoc,
5256 sta->fils_pending_assoc_req,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005257 sta->fils_pending_assoc_req_len, 0, 0,
5258 true);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005259 os_free(sta->fils_pending_assoc_req);
5260 sta->fils_pending_assoc_req = NULL;
5261 sta->fils_pending_assoc_req_len = 0;
5262 wpabuf_free(sta->fils_hlp_resp);
5263 sta->fils_hlp_resp = NULL;
5264 wpabuf_free(sta->hlp_dhcp_discover);
5265 sta->hlp_dhcp_discover = NULL;
Paul Stewart092955c2017-02-06 09:13:09 -08005266
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005267 /*
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005268 * Remove the station in case transmission of a success response fails.
5269 * At this point the station was already added associated to the driver.
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005270 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005271 if (reply_res != WLAN_STATUS_SUCCESS)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005272 hostapd_drv_sta_remove(hapd, sta->addr);
Paul Stewart092955c2017-02-06 09:13:09 -08005273}
5274
5275
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005276void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
Paul Stewart092955c2017-02-06 09:13:09 -08005277{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005278 struct hostapd_data *hapd = eloop_ctx;
5279 struct sta_info *sta = eloop_data;
Paul Stewart092955c2017-02-06 09:13:09 -08005280
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005281 wpa_printf(MSG_DEBUG,
5282 "FILS: HLP response timeout - continue with association response for "
5283 MACSTR, MAC2STR(sta->addr));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005284 if (sta->fils_drv_assoc_finish)
5285 hostapd_notify_assoc_fils_finish(hapd, sta);
5286 else
5287 fils_hlp_finish_assoc(hapd, sta);
Paul Stewart092955c2017-02-06 09:13:09 -08005288}
5289
5290#endif /* CONFIG_FILS */
5291
5292
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005293#ifdef CONFIG_IEEE80211BE
5294static struct sta_info * handle_mlo_translate(struct hostapd_data *hapd,
5295 const struct ieee80211_mgmt *mgmt,
5296 size_t len, bool reassoc,
5297 struct hostapd_data **assoc_hapd)
5298{
5299 struct sta_info *sta;
5300 struct ieee802_11_elems elems;
5301 u8 mld_addr[ETH_ALEN];
5302 const u8 *pos;
5303
5304 if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be)
5305 return NULL;
5306
5307 if (reassoc) {
5308 len -= IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req);
5309 pos = mgmt->u.reassoc_req.variable;
5310 } else {
5311 len -= IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req);
5312 pos = mgmt->u.assoc_req.variable;
5313 }
5314
5315 if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed)
5316 return NULL;
5317
5318 if (hostapd_process_ml_assoc_req_addr(hapd, elems.basic_mle,
5319 elems.basic_mle_len,
5320 mld_addr))
5321 return NULL;
5322
5323 sta = ap_get_sta(hapd, mld_addr);
5324 if (!sta)
5325 return NULL;
5326
5327 wpa_printf(MSG_DEBUG, "MLD: assoc: mld=" MACSTR ", link=" MACSTR,
5328 MAC2STR(mld_addr), MAC2STR(mgmt->sa));
5329
5330 return hostapd_ml_get_assoc_sta(hapd, sta, assoc_hapd);
5331}
5332#endif /* CONFIG_IEEE80211BE */
5333
5334
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005335static void handle_assoc(struct hostapd_data *hapd,
5336 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom74f70d42019-02-11 14:42:39 -08005337 int reassoc, int rssi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005338{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005339 u16 capab_info, listen_interval, seq_ctrl, fc;
Hai Shalomb755a2a2020-04-23 21:49:02 -07005340 int resp = WLAN_STATUS_SUCCESS;
Hai Shalom899fcc72020-10-19 14:38:18 -07005341 u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005342 const u8 *pos;
5343 int left, i;
5344 struct sta_info *sta;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005345 u8 *tmp = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005346#ifdef CONFIG_FILS
5347 int delay_assoc = 0;
5348#endif /* CONFIG_FILS */
Hai Shalomfdcde762020-04-02 11:19:20 -07005349 int omit_rsnxe = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005350 bool set_beacon = false;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005351 bool mld_addrs_not_translated = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005352
5353 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
5354 sizeof(mgmt->u.assoc_req))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005355 wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
5356 reassoc, (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005357 return;
5358 }
5359
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005360#ifdef CONFIG_TESTING_OPTIONS
5361 if (reassoc) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005362 if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005363 drand48() < hapd->iconf->ignore_reassoc_probability) {
5364 wpa_printf(MSG_INFO,
5365 "TESTING: ignoring reassoc request from "
5366 MACSTR, MAC2STR(mgmt->sa));
5367 return;
5368 }
5369 } else {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005370 if (hapd->iconf->ignore_assoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005371 drand48() < hapd->iconf->ignore_assoc_probability) {
5372 wpa_printf(MSG_INFO,
5373 "TESTING: ignoring assoc request from "
5374 MACSTR, MAC2STR(mgmt->sa));
5375 return;
5376 }
5377 }
5378#endif /* CONFIG_TESTING_OPTIONS */
5379
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005380 fc = le_to_host16(mgmt->frame_control);
5381 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
5382
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005383 if (reassoc) {
5384 capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
5385 listen_interval = le_to_host16(
5386 mgmt->u.reassoc_req.listen_interval);
5387 wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
5388 " capab_info=0x%02x listen_interval=%d current_ap="
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005389 MACSTR " seq_ctrl=0x%x%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005390 MAC2STR(mgmt->sa), capab_info, listen_interval,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005391 MAC2STR(mgmt->u.reassoc_req.current_ap),
5392 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005393 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
5394 pos = mgmt->u.reassoc_req.variable;
5395 } else {
5396 capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
5397 listen_interval = le_to_host16(
5398 mgmt->u.assoc_req.listen_interval);
5399 wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005400 " capab_info=0x%02x listen_interval=%d "
5401 "seq_ctrl=0x%x%s",
5402 MAC2STR(mgmt->sa), capab_info, listen_interval,
5403 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005404 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
5405 pos = mgmt->u.assoc_req.variable;
5406 }
5407
5408 sta = ap_get_sta(hapd, mgmt->sa);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005409
5410#ifdef CONFIG_IEEE80211BE
5411 /*
5412 * It is possible that the association frame is from an associated
5413 * non-AP MLD station, that tries to re-associate using different link
5414 * addresses. In such a case, try to find the station based on the AP
5415 * MLD MAC address.
5416 */
5417 if (!sta) {
5418 struct hostapd_data *assoc_hapd;
5419
5420 sta = handle_mlo_translate(hapd, mgmt, len, reassoc,
5421 &assoc_hapd);
5422 if (sta) {
5423 wpa_printf(MSG_DEBUG,
5424 "MLD: Switching to assoc hapd/station");
5425 hapd = assoc_hapd;
5426 mld_addrs_not_translated = true;
5427 }
5428 }
5429#endif /* CONFIG_IEEE80211BE */
5430
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005431#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005432 if (sta && sta->auth_alg == WLAN_AUTH_FT &&
5433 (sta->flags & WLAN_STA_AUTH) == 0) {
5434 wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
5435 "prior to authentication since it is using "
5436 "over-the-DS FT", MAC2STR(mgmt->sa));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005437
5438 /*
5439 * Mark station as authenticated, to avoid adding station
5440 * entry in the driver as associated and not authenticated
5441 */
5442 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005443 } else
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005444#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005445 if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
Dmitry Shmidt29333592017-01-09 12:27:11 -08005446 if (hapd->iface->current_mode &&
5447 hapd->iface->current_mode->mode ==
5448 HOSTAPD_MODE_IEEE80211AD) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005449 int acl_res;
Hai Shalomfdcde762020-04-02 11:19:20 -07005450 struct radius_sta info;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005451
Hai Shalomfdcde762020-04-02 11:19:20 -07005452 acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
5453 (const u8 *) mgmt,
5454 len, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005455 if (acl_res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005456 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5457 "Ignore Association Request frame from "
5458 MACSTR " due to ACL reject",
5459 MAC2STR(mgmt->sa));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005460 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5461 goto fail;
5462 }
5463 if (acl_res == HOSTAPD_ACL_PENDING)
5464 return;
5465
Dmitry Shmidt29333592017-01-09 12:27:11 -08005466 /* DMG/IEEE 802.11ad does not use authentication.
5467 * Allocate sta entry upon association. */
5468 sta = ap_sta_add(hapd, mgmt->sa);
5469 if (!sta) {
5470 hostapd_logger(hapd, mgmt->sa,
5471 HOSTAPD_MODULE_IEEE80211,
5472 HOSTAPD_LEVEL_INFO,
5473 "Failed to add STA");
5474 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5475 goto fail;
5476 }
5477
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005478 acl_res = ieee802_11_set_radius_info(
Hai Shalomfdcde762020-04-02 11:19:20 -07005479 hapd, sta, acl_res, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005480 if (acl_res) {
5481 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5482 goto fail;
5483 }
5484
Dmitry Shmidt29333592017-01-09 12:27:11 -08005485 hostapd_logger(hapd, sta->addr,
5486 HOSTAPD_MODULE_IEEE80211,
5487 HOSTAPD_LEVEL_DEBUG,
5488 "Skip authentication for DMG/IEEE 802.11ad");
5489 sta->flags |= WLAN_STA_AUTH;
5490 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
5491 sta->auth_alg = WLAN_AUTH_OPEN;
5492 } else {
5493 hostapd_logger(hapd, mgmt->sa,
5494 HOSTAPD_MODULE_IEEE80211,
5495 HOSTAPD_LEVEL_INFO,
5496 "Station tried to associate before authentication (aid=%d flags=0x%x)",
5497 sta ? sta->aid : -1,
5498 sta ? sta->flags : 0);
5499 send_deauth(hapd, mgmt->sa,
5500 WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
5501 return;
5502 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005503 }
5504
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005505 if ((fc & WLAN_FC_RETRY) &&
5506 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
5507 sta->last_seq_ctrl == seq_ctrl &&
Paul Stewart092955c2017-02-06 09:13:09 -08005508 sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5509 WLAN_FC_STYPE_ASSOC_REQ)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005510 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5511 HOSTAPD_LEVEL_DEBUG,
5512 "Drop repeated association frame seq_ctrl=0x%x",
5513 seq_ctrl);
5514 return;
5515 }
5516 sta->last_seq_ctrl = seq_ctrl;
5517 sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5518 WLAN_FC_STYPE_ASSOC_REQ;
5519
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005520 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005521 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005522 goto fail;
5523 }
5524
5525 if (listen_interval > hapd->conf->max_listen_interval) {
5526 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5527 HOSTAPD_LEVEL_DEBUG,
5528 "Too large Listen Interval (%d)",
5529 listen_interval);
5530 resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
5531 goto fail;
5532 }
5533
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005534#ifdef CONFIG_MBO
5535 if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
5536 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5537 goto fail;
5538 }
Hai Shalom74f70d42019-02-11 14:42:39 -08005539
5540 if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
5541 rssi < hapd->iconf->rssi_reject_assoc_rssi &&
5542 (sta->auth_rssi == 0 ||
5543 sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
5544 resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
5545 goto fail;
5546 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005547#endif /* CONFIG_MBO */
5548
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005549 if (hapd->conf->wpa && check_sa_query(hapd, sta, reassoc)) {
5550 resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
5551 goto fail;
5552 }
5553
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005554 /*
5555 * sta->capability is used in check_assoc_ies() for RRM enabled
5556 * capability element.
5557 */
5558 sta->capability = capab_info;
5559
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005560#ifdef CONFIG_FILS
5561 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5562 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5563 sta->auth_alg == WLAN_AUTH_FILS_PK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005564 int res;
5565
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005566 /* The end of the payload is encrypted. Need to decrypt it
5567 * before parsing. */
5568
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005569 tmp = os_memdup(pos, left);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005570 if (!tmp) {
5571 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5572 goto fail;
5573 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005574
Roshan Pius3a1667e2018-07-03 15:17:14 -07005575 res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
5576 len, tmp, left);
5577 if (res < 0) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005578 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5579 goto fail;
5580 }
5581 pos = tmp;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005582 left = res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005583 }
5584#endif /* CONFIG_FILS */
5585
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005586 /* followed by SSID and Supported rates; and HT capabilities if 802.11n
5587 * is used */
5588 resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
5589 if (resp != WLAN_STATUS_SUCCESS)
5590 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07005591 omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005592
5593 if (hostapd_get_aid(hapd, sta) < 0) {
5594 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5595 HOSTAPD_LEVEL_INFO, "No room for more AIDs");
5596 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5597 goto fail;
5598 }
5599
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005600 sta->listen_interval = listen_interval;
5601
Roshan Pius3a1667e2018-07-03 15:17:14 -07005602 if (hapd->iface->current_mode &&
5603 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005604 sta->flags |= WLAN_STA_NONERP;
5605 for (i = 0; i < sta->supported_rates_len; i++) {
5606 if ((sta->supported_rates[i] & 0x7f) > 22) {
5607 sta->flags &= ~WLAN_STA_NONERP;
5608 break;
5609 }
5610 }
5611 if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
5612 sta->nonerp_set = 1;
5613 hapd->iface->num_sta_non_erp++;
5614 if (hapd->iface->num_sta_non_erp == 1)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005615 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005616 }
5617
5618 if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
5619 !sta->no_short_slot_time_set) {
5620 sta->no_short_slot_time_set = 1;
5621 hapd->iface->num_sta_no_short_slot_time++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005622 if (hapd->iface->current_mode &&
5623 hapd->iface->current_mode->mode ==
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005624 HOSTAPD_MODE_IEEE80211G &&
5625 hapd->iface->num_sta_no_short_slot_time == 1)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005626 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005627 }
5628
5629 if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
5630 sta->flags |= WLAN_STA_SHORT_PREAMBLE;
5631 else
5632 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
5633
5634 if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
5635 !sta->no_short_preamble_set) {
5636 sta->no_short_preamble_set = 1;
5637 hapd->iface->num_sta_no_short_preamble++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005638 if (hapd->iface->current_mode &&
5639 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005640 && hapd->iface->num_sta_no_short_preamble == 1)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005641 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005642 }
5643
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005644 if (update_ht_state(hapd, sta) > 0)
5645 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005646
5647 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5648 HOSTAPD_LEVEL_DEBUG,
5649 "association OK (aid %d)", sta->aid);
5650 /* Station will be marked associated, after it acknowledges AssocResp
5651 */
5652 sta->flags |= WLAN_STA_ASSOC_REQ_OK;
5653
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005654 if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
5655 wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
5656 "SA Query procedure", reassoc ? "re" : "");
5657 /* TODO: Send a protected Disassociate frame to the STA using
5658 * the old key and Reason Code "Previous Authentication no
5659 * longer valid". Make sure this is only sent protected since
5660 * unprotected frame would be received by the STA that is now
5661 * trying to associate.
5662 */
5663 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005664
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005665 /* Make sure that the previously registered inactivity timer will not
5666 * remove the STA immediately. */
5667 sta->timeout_next = STA_NULLFUNC;
5668
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005669#ifdef CONFIG_TAXONOMY
5670 taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
5671#endif /* CONFIG_TAXONOMY */
5672
Dmitry Shmidt29333592017-01-09 12:27:11 -08005673 sta->pending_wds_enable = 0;
5674
Paul Stewart092955c2017-02-06 09:13:09 -08005675#ifdef CONFIG_FILS
5676 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5677 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005678 sta->auth_alg == WLAN_AUTH_FILS_PK) {
5679 if (fils_process_hlp(hapd, sta, pos, left) > 0)
5680 delay_assoc = 1;
5681 }
Paul Stewart092955c2017-02-06 09:13:09 -08005682#endif /* CONFIG_FILS */
5683
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005684 if (set_beacon)
Sunil Ravi7f769292024-07-23 22:21:32 +00005685 ieee802_11_update_beacons(hapd->iface);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005686
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005687 fail:
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005688
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005689 /*
5690 * In case of a successful response, add the station to the driver.
5691 * Otherwise, the kernel may ignore Data frames before we process the
5692 * ACK frame (TX status). In case of a failure, this station will be
5693 * removed.
5694 *
5695 * Note that this is not compliant with the IEEE 802.11 standard that
5696 * states that a non-AP station should transition into the
5697 * authenticated/associated state only after the station acknowledges
5698 * the (Re)Association Response frame. However, still do this as:
5699 *
5700 * 1. In case the station does not acknowledge the (Re)Association
5701 * Response frame, it will be removed.
5702 * 2. Data frames will be dropped in the kernel until the station is
5703 * set into authorized state, and there are no significant known
5704 * issues with processing other non-Data Class 3 frames during this
5705 * window.
5706 */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005707 if (sta)
5708 hostapd_process_assoc_ml_info(hapd, sta, pos, left, reassoc,
5709 resp, false);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005710
Hai Shalom74f70d42019-02-11 14:42:39 -08005711 if (resp == WLAN_STATUS_SUCCESS && sta &&
5712 add_associated_sta(hapd, sta, reassoc))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005713 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5714
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005715#ifdef CONFIG_FILS
Hai Shalom74f70d42019-02-11 14:42:39 -08005716 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
5717 eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
5718 sta->fils_pending_assoc_req) {
5719 /* Do not reschedule fils_hlp_timeout in case the station
5720 * retransmits (Re)Association Request frame while waiting for
5721 * the previously started FILS HLP wait, so that the timeout can
5722 * be determined from the first pending attempt. */
5723 wpa_printf(MSG_DEBUG,
5724 "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
5725 MACSTR, MAC2STR(sta->addr));
5726 os_free(tmp);
5727 return;
5728 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005729 if (sta) {
5730 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5731 os_free(sta->fils_pending_assoc_req);
5732 sta->fils_pending_assoc_req = NULL;
5733 sta->fils_pending_assoc_req_len = 0;
5734 wpabuf_free(sta->fils_hlp_resp);
5735 sta->fils_hlp_resp = NULL;
5736 }
5737 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
5738 sta->fils_pending_assoc_req = tmp;
5739 sta->fils_pending_assoc_req_len = left;
5740 sta->fils_pending_assoc_is_reassoc = reassoc;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005741 sta->fils_drv_assoc_finish = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005742 wpa_printf(MSG_DEBUG,
5743 "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
5744 MACSTR, MAC2STR(sta->addr));
5745 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5746 eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
5747 fils_hlp_timeout, hapd, sta);
5748 return;
5749 }
5750#endif /* CONFIG_FILS */
5751
Hai Shalomb755a2a2020-04-23 21:49:02 -07005752 if (resp >= 0)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005753 reply_res = send_assoc_resp(hapd,
5754 mld_addrs_not_translated ?
5755 NULL : sta,
5756 mgmt->sa, resp, reassoc,
5757 pos, left, rssi, omit_rsnxe,
5758 !mld_addrs_not_translated);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005759 os_free(tmp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005760
5761 /*
Hai Shalom899fcc72020-10-19 14:38:18 -07005762 * Remove the station in case transmission of a success response fails
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005763 * (the STA was added associated to the driver) or if the station was
5764 * previously added unassociated.
5765 */
Dmitry Shmidt29333592017-01-09 12:27:11 -08005766 if (sta && ((reply_res != WLAN_STATUS_SUCCESS &&
5767 resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005768 hostapd_drv_sta_remove(hapd, sta->addr);
5769 sta->added_unassoc = 0;
5770 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005771}
5772
5773
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005774static void hostapd_deauth_sta(struct hostapd_data *hapd,
5775 struct sta_info *sta,
5776 const struct ieee80211_mgmt *mgmt)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005777{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005778 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5779 "deauthentication: STA=" MACSTR " reason_code=%d",
5780 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005781
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005782 ap_sta_set_authorized(hapd, sta, 0);
5783 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
5784 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
5785 WLAN_STA_ASSOC_REQ_OK);
5786 hostapd_set_sta_flags(hapd, sta);
5787 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5788 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5789 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5790 mlme_deauthenticate_indication(
5791 hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
5792 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5793 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5794 ap_free_sta(hapd, sta);
5795}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005796
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005797
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005798static void hostapd_disassoc_sta(struct hostapd_data *hapd,
5799 struct sta_info *sta,
5800 const struct ieee80211_mgmt *mgmt)
5801{
5802 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5803 "disassocation: STA=" MACSTR " reason_code=%d",
5804 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005805
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005806 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005807 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005808 sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07005809 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005810 wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
5811 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5812 HOSTAPD_LEVEL_INFO, "disassociated");
5813 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5814 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5815 /* Stop Accounting and IEEE 802.1X sessions, but leave the STA
5816 * authenticated. */
5817 accounting_sta_stop(hapd, sta);
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005818 ieee802_1x_free_station(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005819 if (sta->ipaddr)
5820 hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
5821 ap_sta_ip6addr_del(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005822 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005823 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005824
5825 if (sta->timeout_next == STA_NULLFUNC ||
5826 sta->timeout_next == STA_DISASSOC) {
5827 sta->timeout_next = STA_DEAUTH;
5828 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
5829 eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
5830 hapd, sta);
5831 }
5832
5833 mlme_disassociate_indication(
5834 hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt29333592017-01-09 12:27:11 -08005835
5836 /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon
5837 * disassociation. */
5838 if (hapd->iface->current_mode &&
5839 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
5840 sta->flags &= ~WLAN_STA_AUTH;
5841 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5842 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5843 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5844 ap_free_sta(hapd, sta);
5845 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005846}
5847
5848
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005849static bool hostapd_ml_handle_disconnect(struct hostapd_data *hapd,
5850 struct sta_info *sta,
5851 const struct ieee80211_mgmt *mgmt,
5852 bool disassoc)
5853{
5854#ifdef CONFIG_IEEE80211BE
5855 struct hostapd_data *assoc_hapd, *tmp_hapd;
5856 struct sta_info *assoc_sta;
Sunil Ravi7f769292024-07-23 22:21:32 +00005857 struct sta_info *tmp_sta;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005858
5859 if (!hostapd_is_mld_ap(hapd))
5860 return false;
5861
5862 /*
5863 * Get the station on which the association was performed, as it holds
5864 * the information about all the other links.
5865 */
5866 assoc_sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005867 if (!assoc_sta)
5868 return false;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005869
Sunil Ravi7f769292024-07-23 22:21:32 +00005870 for_each_mld_link(tmp_hapd, assoc_hapd) {
5871 if (tmp_hapd == assoc_hapd)
5872 continue;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005873
Sunil Ravi7f769292024-07-23 22:21:32 +00005874 if (!assoc_sta->mld_info.links[tmp_hapd->mld_link_id].valid)
5875 continue;
5876
5877 for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
5878 tmp_sta = tmp_sta->next) {
5879 if (tmp_sta->mld_assoc_link_id !=
5880 assoc_sta->mld_assoc_link_id ||
5881 tmp_sta->aid != assoc_sta->aid)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005882 continue;
5883
Sunil Ravi7f769292024-07-23 22:21:32 +00005884 if (!disassoc)
5885 hostapd_deauth_sta(tmp_hapd, tmp_sta, mgmt);
5886 else
5887 hostapd_disassoc_sta(tmp_hapd, tmp_sta, mgmt);
5888 break;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005889 }
5890 }
5891
5892 /* Remove the station on which the association was performed. */
5893 if (!disassoc)
5894 hostapd_deauth_sta(assoc_hapd, assoc_sta, mgmt);
5895 else
5896 hostapd_disassoc_sta(assoc_hapd, assoc_sta, mgmt);
5897
5898 return true;
5899#else /* CONFIG_IEEE80211BE */
5900 return false;
5901#endif /* CONFIG_IEEE80211BE */
5902}
5903
5904
5905static void handle_disassoc(struct hostapd_data *hapd,
5906 const struct ieee80211_mgmt *mgmt, size_t len)
5907{
5908 struct sta_info *sta;
5909
5910 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
5911 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5912 "handle_disassoc - too short payload (len=%lu)",
5913 (unsigned long) len);
5914 return;
5915 }
5916
5917 sta = ap_get_sta(hapd, mgmt->sa);
5918 if (!sta) {
5919 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
5920 " trying to disassociate, but it is not associated",
5921 MAC2STR(mgmt->sa));
5922 return;
5923 }
5924
5925 if (hostapd_ml_handle_disconnect(hapd, sta, mgmt, true))
5926 return;
5927
5928 hostapd_disassoc_sta(hapd, sta, mgmt);
5929}
5930
5931
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005932static void handle_deauth(struct hostapd_data *hapd,
5933 const struct ieee80211_mgmt *mgmt, size_t len)
5934{
5935 struct sta_info *sta;
5936
5937 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005938 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5939 "handle_deauth - too short payload (len=%lu)",
5940 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005941 return;
5942 }
5943
Hai Shaloma20dcd72022-02-04 13:43:00 -08005944 /* Clear the PTKSA cache entries for PASN */
5945 ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
5946
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005947 sta = ap_get_sta(hapd, mgmt->sa);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005948 if (!sta) {
5949 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
5950 " trying to deauthenticate, but it is not authenticated",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005951 MAC2STR(mgmt->sa));
5952 return;
5953 }
5954
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005955 if (hostapd_ml_handle_disconnect(hapd, sta, mgmt, false))
5956 return;
5957
5958 hostapd_deauth_sta(hapd, sta, mgmt);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005959}
5960
5961
5962static void handle_beacon(struct hostapd_data *hapd,
5963 const struct ieee80211_mgmt *mgmt, size_t len,
5964 struct hostapd_frame_info *fi)
5965{
5966 struct ieee802_11_elems elems;
5967
5968 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005969 wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
5970 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005971 return;
5972 }
5973
5974 (void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
5975 len - (IEEE80211_HDRLEN +
5976 sizeof(mgmt->u.beacon)), &elems,
5977 0);
5978
5979 ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
5980}
5981
5982
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005983static int robust_action_frame(u8 category)
5984{
5985 return category != WLAN_ACTION_PUBLIC &&
5986 category != WLAN_ACTION_HT;
5987}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005988
5989
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005990static int handle_action(struct hostapd_data *hapd,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005991 const struct ieee80211_mgmt *mgmt, size_t len,
5992 unsigned int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005993{
5994 struct sta_info *sta;
Hai Shalom74f70d42019-02-11 14:42:39 -08005995 u8 *action __maybe_unused;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005996
Hai Shalom74f70d42019-02-11 14:42:39 -08005997 if (len < IEEE80211_HDRLEN + 2 + 1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005998 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5999 HOSTAPD_LEVEL_DEBUG,
6000 "handle_action - too short payload (len=%lu)",
6001 (unsigned long) len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006002 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006003 }
6004
Hai Shalom74f70d42019-02-11 14:42:39 -08006005 action = (u8 *) &mgmt->u.action.u;
6006 wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
6007 " da " MACSTR " len %d freq %u",
6008 mgmt->u.action.category, *action,
6009 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
6010
6011 sta = ap_get_sta(hapd, mgmt->sa);
6012
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006013 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
6014 (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
6015 wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
6016 "frame (category=%u) from unassociated STA " MACSTR,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08006017 mgmt->u.action.category, MAC2STR(mgmt->sa));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006018 return 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006019 }
6020
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006021 if (sta && (sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt18463232014-01-24 12:29:41 -08006022 !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
6023 robust_action_frame(mgmt->u.action.category)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006024 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6025 HOSTAPD_LEVEL_DEBUG,
6026 "Dropped unprotected Robust Action frame from "
6027 "an MFP STA");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006028 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006029 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006030
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006031 if (sta) {
6032 u16 fc = le_to_host16(mgmt->frame_control);
6033 u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
6034
6035 if ((fc & WLAN_FC_RETRY) &&
6036 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
6037 sta->last_seq_ctrl == seq_ctrl &&
6038 sta->last_subtype == WLAN_FC_STYPE_ACTION) {
6039 hostapd_logger(hapd, sta->addr,
6040 HOSTAPD_MODULE_IEEE80211,
6041 HOSTAPD_LEVEL_DEBUG,
6042 "Drop repeated action frame seq_ctrl=0x%x",
6043 seq_ctrl);
6044 return 1;
6045 }
6046
6047 sta->last_seq_ctrl = seq_ctrl;
6048 sta->last_subtype = WLAN_FC_STYPE_ACTION;
6049 }
6050
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006051 switch (mgmt->u.action.category) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006052#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006053 case WLAN_ACTION_FT:
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006054 if (!sta ||
6055 wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006056 len - IEEE80211_HDRLEN))
6057 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006058 return 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006059#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006060 case WLAN_ACTION_WMM:
6061 hostapd_wmm_action(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006062 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006063 case WLAN_ACTION_SA_QUERY:
Hai Shalom021b0b52019-04-10 11:17:58 -07006064 ieee802_11_sa_query_action(hapd, mgmt, len);
6065 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006066#ifdef CONFIG_WNM_AP
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006067 case WLAN_ACTION_WNM:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006068 ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
6069 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006070#endif /* CONFIG_WNM_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006071#ifdef CONFIG_FST
6072 case WLAN_ACTION_FST:
6073 if (hapd->iface->fst)
6074 fst_rx_action(hapd->iface->fst, mgmt, len);
6075 else
6076 wpa_printf(MSG_DEBUG,
6077 "FST: Ignore FST Action frame - no FST attached");
6078 return 1;
6079#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006080 case WLAN_ACTION_PUBLIC:
Dmitry Shmidt18463232014-01-24 12:29:41 -08006081 case WLAN_ACTION_PROTECTED_DUAL:
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07006082 if (len >= IEEE80211_HDRLEN + 2 &&
6083 mgmt->u.action.u.public_action.action ==
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006084 WLAN_PA_20_40_BSS_COEX) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006085 hostapd_2040_coex_action(hapd, mgmt, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006086 return 1;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006087 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006088#ifdef CONFIG_DPP
6089 if (len >= IEEE80211_HDRLEN + 6 &&
6090 mgmt->u.action.u.vs_public_action.action ==
6091 WLAN_PA_VENDOR_SPECIFIC &&
6092 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6093 OUI_WFA &&
6094 mgmt->u.action.u.vs_public_action.variable[0] ==
6095 DPP_OUI_TYPE) {
6096 const u8 *pos, *end;
6097
6098 pos = mgmt->u.action.u.vs_public_action.oui;
6099 end = ((const u8 *) mgmt) + len;
6100 hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006101 freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006102 return 1;
6103 }
6104 if (len >= IEEE80211_HDRLEN + 2 &&
6105 (mgmt->u.action.u.public_action.action ==
6106 WLAN_PA_GAS_INITIAL_RESP ||
6107 mgmt->u.action.u.public_action.action ==
6108 WLAN_PA_GAS_COMEBACK_RESP)) {
6109 const u8 *pos, *end;
6110
6111 pos = &mgmt->u.action.u.public_action.action;
6112 end = ((const u8 *) mgmt) + len;
Sunil Ravi036cec52023-03-29 11:35:17 -07006113 if (gas_query_ap_rx(hapd->gas, mgmt->sa,
6114 mgmt->u.action.category,
6115 pos, end - pos, freq) == 0)
6116 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006117 }
6118#endif /* CONFIG_DPP */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006119#ifdef CONFIG_NAN_USD
6120 if (mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6121 len >= IEEE80211_HDRLEN + 5 &&
6122 mgmt->u.action.u.vs_public_action.action ==
6123 WLAN_PA_VENDOR_SPECIFIC &&
6124 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6125 OUI_WFA &&
6126 mgmt->u.action.u.vs_public_action.variable[0] ==
6127 NAN_OUI_TYPE) {
6128 const u8 *pos, *end;
6129
6130 pos = mgmt->u.action.u.vs_public_action.variable;
6131 end = ((const u8 *) mgmt) + len;
6132 pos++;
6133 hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, freq,
6134 pos, end - pos);
6135 return 1;
6136 }
6137#endif /* CONFIG_NAN_USD */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006138 if (hapd->public_action_cb) {
6139 hapd->public_action_cb(hapd->public_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006140 (u8 *) mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006141 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006142 if (hapd->public_action_cb2) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -08006143 hapd->public_action_cb2(hapd->public_action_cb2_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006144 (u8 *) mgmt, len, freq);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006145 }
6146 if (hapd->public_action_cb || hapd->public_action_cb2)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006147 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006148 break;
6149 case WLAN_ACTION_VENDOR_SPECIFIC:
6150 if (hapd->vendor_action_cb) {
6151 if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006152 (u8 *) mgmt, len, freq) == 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006153 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006154 }
6155 break;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006156#ifndef CONFIG_NO_RRM
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006157 case WLAN_ACTION_RADIO_MEASUREMENT:
6158 hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
6159 return 1;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006160#endif /* CONFIG_NO_RRM */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006161 }
6162
6163 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6164 HOSTAPD_LEVEL_DEBUG,
6165 "handle_action - unknown action category %d or invalid "
6166 "frame",
6167 mgmt->u.action.category);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006168 if (!is_multicast_ether_addr(mgmt->da) &&
6169 !(mgmt->u.action.category & 0x80) &&
6170 !is_multicast_ether_addr(mgmt->sa)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006171 struct ieee80211_mgmt *resp;
6172
6173 /*
6174 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
6175 * Return the Action frame to the source without change
6176 * except that MSB of the Category set to 1.
6177 */
6178 wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
6179 "frame back to sender");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006180 resp = os_memdup(mgmt, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006181 if (resp == NULL)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006182 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006183 os_memcpy(resp->da, resp->sa, ETH_ALEN);
6184 os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
6185 os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
6186 resp->u.action.category |= 0x80;
6187
Hai Shalomfdcde762020-04-02 11:19:20 -07006188 if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006189 wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
6190 "Action frame");
6191 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006192 os_free(resp);
6193 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006194
6195 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006196}
6197
6198
6199/**
Hai Shalom60840252021-02-19 19:02:11 -08006200 * notify_mgmt_frame - Notify of Management frames on the control interface
6201 * @hapd: hostapd BSS data structure (the BSS to which the Management frame was
6202 * sent to)
6203 * @buf: Management frame data (starting from the IEEE 802.11 header)
6204 * @len: Length of frame data in octets
6205 *
6206 * Notify the control interface of any received Management frame.
6207 */
6208static void notify_mgmt_frame(struct hostapd_data *hapd, const u8 *buf,
6209 size_t len)
6210{
6211
6212 int hex_len = len * 2 + 1;
6213 char *hex = os_malloc(hex_len);
6214
6215 if (hex) {
6216 wpa_snprintf_hex(hex, hex_len, buf, len);
6217 wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO,
6218 AP_MGMT_FRAME_RECEIVED "buf=%s", hex);
6219 os_free(hex);
6220 }
6221}
6222
6223
6224/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006225 * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
6226 * @hapd: hostapd BSS data structure (the BSS to which the management frame was
6227 * sent to)
6228 * @buf: management frame data (starting from IEEE 802.11 header)
6229 * @len: length of frame data in octets
6230 * @fi: meta data about received frame (signal level, etc.)
6231 *
6232 * Process all incoming IEEE 802.11 management frames. This will be called for
6233 * each frame received from the kernel driver through wlan#ap interface. In
6234 * addition, it can be called to re-inserted pending frames (e.g., when using
6235 * external RADIUS server as an MAC ACL).
6236 */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006237int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
6238 struct hostapd_frame_info *fi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006239{
6240 struct ieee80211_mgmt *mgmt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006241 u16 fc, stype;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006242 int ret = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006243 unsigned int freq;
6244 int ssi_signal = fi ? fi->ssi_signal : 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006245#ifdef CONFIG_NAN_USD
6246 static const u8 nan_network_id[ETH_ALEN] =
6247 { 0x51, 0x6f, 0x9a, 0x01, 0x00, 0x00 };
6248#endif /* CONFIG_NAN_USD */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006249
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006250 if (len < 24)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006251 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006252
Roshan Pius3a1667e2018-07-03 15:17:14 -07006253 if (fi && fi->freq)
6254 freq = fi->freq;
6255 else
6256 freq = hapd->iface->freq;
6257
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006258 mgmt = (struct ieee80211_mgmt *) buf;
6259 fc = le_to_host16(mgmt->frame_control);
6260 stype = WLAN_FC_GET_STYPE(fc);
6261
Hai Shalomc3565922019-10-28 11:58:20 -07006262 if (is_multicast_ether_addr(mgmt->sa) ||
6263 is_zero_ether_addr(mgmt->sa) ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006264 ether_addr_equal(mgmt->sa, hapd->own_addr)) {
Hai Shalomc3565922019-10-28 11:58:20 -07006265 /* Do not process any frames with unexpected/invalid SA so that
6266 * we do not add any state for unexpected STA addresses or end
6267 * up sending out frames to unexpected destination. */
6268 wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
6269 " in received frame - ignore this frame silently",
6270 MAC2STR(mgmt->sa));
6271 return 0;
6272 }
6273
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006274 if (stype == WLAN_FC_STYPE_BEACON) {
6275 handle_beacon(hapd, mgmt, len, fi);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006276 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006277 }
6278
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07006279 if (!is_broadcast_ether_addr(mgmt->bssid) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006280#ifdef CONFIG_P2P
6281 /* Invitation responses can be sent with the peer MAC as BSSID */
6282 !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
6283 stype == WLAN_FC_STYPE_ACTION) &&
6284#endif /* CONFIG_P2P */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006285#ifdef CONFIG_MESH
6286 !(hapd->conf->mesh & MESH_ENABLED) &&
6287#endif /* CONFIG_MESH */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006288#ifdef CONFIG_IEEE80211BE
6289 !(hapd->conf->mld_ap &&
Sunil Ravi99c035e2024-07-12 01:42:03 +00006290 ether_addr_equal(hapd->mld->mld_addr, mgmt->bssid)) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006291#endif /* CONFIG_IEEE80211BE */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006292 !ether_addr_equal(mgmt->bssid, hapd->own_addr)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006293 wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
6294 MAC2STR(mgmt->bssid));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006295 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006296 }
6297
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006298 if (hapd->iface->state != HAPD_IFACE_ENABLED) {
6299 wpa_printf(MSG_DEBUG, "MGMT: Ignore management frame while interface is not enabled (SA=" MACSTR " DA=" MACSTR " subtype=%u)",
6300 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), stype);
6301 return 1;
6302 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006303
6304 if (stype == WLAN_FC_STYPE_PROBE_REQ) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006305 handle_probe_req(hapd, mgmt, len, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006306 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006307 }
6308
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006309 if ((!is_broadcast_ether_addr(mgmt->da) ||
6310 stype != WLAN_FC_STYPE_ACTION) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006311#ifdef CONFIG_IEEE80211BE
6312 !(hapd->conf->mld_ap &&
Sunil Ravi99c035e2024-07-12 01:42:03 +00006313 ether_addr_equal(hapd->mld->mld_addr, mgmt->bssid)) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006314#endif /* CONFIG_IEEE80211BE */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006315#ifdef CONFIG_NAN_USD
6316 !ether_addr_equal(mgmt->da, nan_network_id) &&
6317#endif /* CONFIG_NAN_USD */
6318 !ether_addr_equal(mgmt->da, hapd->own_addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006319 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6320 HOSTAPD_LEVEL_DEBUG,
6321 "MGMT: DA=" MACSTR " not our address",
6322 MAC2STR(mgmt->da));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006323 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006324 }
6325
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006326 if (hapd->iconf->track_sta_max_num)
Roshan Pius3a1667e2018-07-03 15:17:14 -07006327 sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006328
Hai Shalom60840252021-02-19 19:02:11 -08006329 if (hapd->conf->notify_mgmt_frames)
6330 notify_mgmt_frame(hapd, buf, len);
6331
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006332 switch (stype) {
6333 case WLAN_FC_STYPE_AUTH:
6334 wpa_printf(MSG_DEBUG, "mgmt::auth");
Hai Shalom021b0b52019-04-10 11:17:58 -07006335 handle_auth(hapd, mgmt, len, ssi_signal, 0);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006336 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006337 break;
6338 case WLAN_FC_STYPE_ASSOC_REQ:
6339 wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006340 handle_assoc(hapd, mgmt, len, 0, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006341 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006342 break;
6343 case WLAN_FC_STYPE_REASSOC_REQ:
6344 wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006345 handle_assoc(hapd, mgmt, len, 1, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006346 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006347 break;
6348 case WLAN_FC_STYPE_DISASSOC:
6349 wpa_printf(MSG_DEBUG, "mgmt::disassoc");
6350 handle_disassoc(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006351 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006352 break;
6353 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006354 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006355 handle_deauth(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006356 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006357 break;
6358 case WLAN_FC_STYPE_ACTION:
6359 wpa_printf(MSG_DEBUG, "mgmt::action");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006360 ret = handle_action(hapd, mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006361 break;
6362 default:
6363 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6364 HOSTAPD_LEVEL_DEBUG,
6365 "unknown mgmt frame subtype %d", stype);
6366 break;
6367 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006368
6369 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006370}
6371
6372
6373static void handle_auth_cb(struct hostapd_data *hapd,
6374 const struct ieee80211_mgmt *mgmt,
6375 size_t len, int ok)
6376{
6377 u16 auth_alg, auth_transaction, status_code;
6378 struct sta_info *sta;
Hai Shalom60840252021-02-19 19:02:11 -08006379 bool success_status;
Hai Shalome5e28bb2019-01-28 14:51:04 -08006380
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006381 sta = ap_get_sta(hapd, mgmt->da);
6382 if (!sta) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006383 wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
6384 " not found",
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006385 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006386 return;
6387 }
6388
Hai Shalom60840252021-02-19 19:02:11 -08006389 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
6390 wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
6391 (unsigned long) len);
6392 auth_alg = 0;
6393 auth_transaction = 0;
6394 status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
6395 goto fail;
6396 }
6397
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006398 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
6399 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
6400 status_code = le_to_host16(mgmt->u.auth.status_code);
6401
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006402 if (!ok) {
6403 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6404 HOSTAPD_LEVEL_NOTICE,
6405 "did not acknowledge authentication response");
6406 goto fail;
6407 }
6408
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006409 if (status_code == WLAN_STATUS_SUCCESS &&
6410 ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
6411 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
6412 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6413 HOSTAPD_LEVEL_INFO, "authenticated");
6414 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006415 if (sta->added_unassoc)
6416 hostapd_set_sta_flags(hapd, sta);
6417 return;
6418 }
6419
6420fail:
Hai Shalom60840252021-02-19 19:02:11 -08006421 success_status = status_code == WLAN_STATUS_SUCCESS;
6422#ifdef CONFIG_SAE
6423 if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1)
6424 success_status = sae_status_success(hapd, status_code);
6425#endif /* CONFIG_SAE */
6426 if (!success_status && sta->added_unassoc) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006427 hostapd_drv_sta_remove(hapd, sta->addr);
6428 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006429 }
6430}
6431
6432
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006433static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
6434 struct sta_info *sta,
6435 char *ifname_wds)
6436{
Hai Shalomfdcde762020-04-02 11:19:20 -07006437#ifdef CONFIG_WEP
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006438 int i;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07006439 struct hostapd_ssid *ssid = &hapd->conf->ssid;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006440
6441 if (hapd->conf->ieee802_1x || hapd->conf->wpa)
6442 return;
6443
6444 for (i = 0; i < 4; i++) {
6445 if (ssid->wep.key[i] &&
6446 hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
Hai Shalomfdcde762020-04-02 11:19:20 -07006447 0, i == ssid->wep.idx, NULL, 0,
6448 ssid->wep.key[i], ssid->wep.len[i],
6449 i == ssid->wep.idx ?
6450 KEY_FLAG_GROUP_RX_TX_DEFAULT :
6451 KEY_FLAG_GROUP_RX_TX)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006452 wpa_printf(MSG_WARNING,
6453 "Could not set WEP keys for WDS interface; %s",
6454 ifname_wds);
6455 break;
6456 }
6457 }
Hai Shalomfdcde762020-04-02 11:19:20 -07006458#endif /* CONFIG_WEP */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006459}
6460
6461
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006462#ifdef CONFIG_IEEE80211BE
6463static void ieee80211_ml_link_sta_assoc_cb(struct hostapd_data *hapd,
6464 struct sta_info *sta,
6465 struct mld_link_info *link,
6466 bool ok)
6467{
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006468 bool updated = false;
6469
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006470 if (!ok) {
6471 hostapd_logger(hapd, link->peer_addr, HOSTAPD_MODULE_IEEE80211,
6472 HOSTAPD_LEVEL_DEBUG,
6473 "did not acknowledge association response");
6474 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
6475
6476 /* The STA is added only in case of SUCCESS */
6477 if (link->status == WLAN_STATUS_SUCCESS)
6478 hostapd_drv_sta_remove(hapd, sta->addr);
6479
6480 return;
6481 }
6482
6483 if (link->status != WLAN_STATUS_SUCCESS)
6484 return;
6485
6486 sta->flags |= WLAN_STA_ASSOC;
6487 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
6488
6489 if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006490 updated = ap_sta_set_authorized_flag(hapd, sta, 1);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006491
6492 hostapd_set_sta_flags(hapd, sta);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006493 if (updated)
6494 ap_sta_set_authorized_event(hapd, sta, 1);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006495
6496 /*
6497 * TODOs:
6498 * - IEEE 802.1X port enablement is not needed as done on the station
6499 * doing the connection.
6500 * - Not handling accounting
6501 * - Need to handle VLAN configuration
6502 */
6503}
6504#endif /* CONFIG_IEEE80211BE */
6505
6506
6507static void hostapd_ml_handle_assoc_cb(struct hostapd_data *hapd,
6508 struct sta_info *sta, bool ok)
6509{
6510#ifdef CONFIG_IEEE80211BE
Sunil Ravi7f769292024-07-23 22:21:32 +00006511 struct hostapd_data *tmp_hapd;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006512
6513 if (!hostapd_is_mld_ap(hapd))
6514 return;
6515
Sunil Ravi7f769292024-07-23 22:21:32 +00006516 for_each_mld_link(tmp_hapd, hapd) {
6517 struct mld_link_info *link;
6518 struct sta_info *tmp_sta;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006519
Sunil Ravi7f769292024-07-23 22:21:32 +00006520 if (tmp_hapd == hapd)
6521 continue;
6522
6523 link = &sta->mld_info.links[tmp_hapd->mld_link_id];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006524 if (!link->valid)
6525 continue;
6526
Sunil Ravi7f769292024-07-23 22:21:32 +00006527 for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
6528 tmp_sta = tmp_sta->next) {
6529 if (tmp_sta == sta ||
6530 tmp_sta->mld_assoc_link_id !=
6531 sta->mld_assoc_link_id ||
6532 tmp_sta->aid != sta->aid)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006533 continue;
6534
Sunil Ravi7f769292024-07-23 22:21:32 +00006535 ieee80211_ml_link_sta_assoc_cb(tmp_hapd, tmp_sta, link,
6536 ok);
6537 break;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006538 }
6539 }
6540#endif /* CONFIG_IEEE80211BE */
6541}
6542
6543
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006544static void handle_assoc_cb(struct hostapd_data *hapd,
6545 const struct ieee80211_mgmt *mgmt,
6546 size_t len, int reassoc, int ok)
6547{
6548 u16 status;
6549 struct sta_info *sta;
6550 int new_assoc = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006551
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006552 sta = ap_get_sta(hapd, mgmt->da);
6553 if (!sta) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006554 wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
6555 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006556 return;
6557 }
6558
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006559#ifdef CONFIG_IEEE80211BE
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006560 if (ap_sta_is_mld(hapd, sta) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006561 hapd->mld_link_id != sta->mld_assoc_link_id) {
6562 /* See ieee80211_ml_link_sta_assoc_cb() for the MLD case */
6563 wpa_printf(MSG_DEBUG,
6564 "%s: MLD: ignore on link station (%d != %d)",
6565 __func__, hapd->mld_link_id, sta->mld_assoc_link_id);
6566 return;
6567 }
6568#endif /* CONFIG_IEEE80211BE */
6569
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006570 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
6571 sizeof(mgmt->u.assoc_resp))) {
6572 wpa_printf(MSG_INFO,
6573 "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
6574 reassoc, (unsigned long) len);
6575 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006576 return;
6577 }
6578
6579 if (reassoc)
6580 status = le_to_host16(mgmt->u.reassoc_resp.status_code);
6581 else
6582 status = le_to_host16(mgmt->u.assoc_resp.status_code);
6583
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006584 if (!ok) {
6585 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6586 HOSTAPD_LEVEL_DEBUG,
6587 "did not acknowledge association response");
6588 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
6589 /* The STA is added only in case of SUCCESS */
6590 if (status == WLAN_STATUS_SUCCESS)
6591 hostapd_drv_sta_remove(hapd, sta->addr);
6592
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006593 goto handle_ml;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006594 }
6595
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006596 if (status != WLAN_STATUS_SUCCESS)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006597 goto handle_ml;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006598
6599 /* Stop previous accounting session, if one is started, and allocate
6600 * new session id for the new session. */
6601 accounting_sta_stop(hapd, sta);
6602
6603 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6604 HOSTAPD_LEVEL_INFO,
6605 "associated (aid %d)",
6606 sta->aid);
6607
6608 if (sta->flags & WLAN_STA_ASSOC)
6609 new_assoc = 0;
6610 sta->flags |= WLAN_STA_ASSOC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006611 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006612 if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
6613 !hapd->conf->osen) ||
6614 sta->auth_alg == WLAN_AUTH_FILS_SK ||
6615 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6616 sta->auth_alg == WLAN_AUTH_FILS_PK ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006617 sta->auth_alg == WLAN_AUTH_FT) {
6618 /*
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006619 * Open, static WEP, FT protocol, or FILS; no separate
6620 * authorization step.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006621 */
6622 ap_sta_set_authorized(hapd, sta, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006623 }
6624
6625 if (reassoc)
6626 mlme_reassociate_indication(hapd, sta);
6627 else
6628 mlme_associate_indication(hapd, sta);
6629
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006630 sta->sa_query_timed_out = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006631
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006632 if (sta->eapol_sm == NULL) {
6633 /*
6634 * This STA does not use RADIUS server for EAP authentication,
6635 * so bind it to the selected VLAN interface now, since the
6636 * interface selection is not going to change anymore.
6637 */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006638 if (ap_sta_bind_vlan(hapd, sta) < 0)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006639 goto handle_ml;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006640 } else if (sta->vlan_id) {
6641 /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006642 if (ap_sta_bind_vlan(hapd, sta) < 0)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006643 goto handle_ml;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006644 }
6645
6646 hostapd_set_sta_flags(hapd, sta);
6647
Dmitry Shmidt29333592017-01-09 12:27:11 -08006648 if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) {
6649 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA "
6650 MACSTR " based on pending request",
6651 MAC2STR(sta->addr));
6652 sta->pending_wds_enable = 0;
6653 sta->flags |= WLAN_STA_WDS;
6654 }
6655
Sunil Ravi640215c2023-06-28 23:08:09 +00006656 /* WPS not supported on backhaul BSS. Disable 4addr mode on fronthaul */
6657 if ((sta->flags & WLAN_STA_WDS) ||
6658 (sta->flags & WLAN_STA_MULTI_AP &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006659 (hapd->conf->multi_ap & BACKHAUL_BSS) &&
Sunil Ravi7f769292024-07-23 22:21:32 +00006660 hapd->conf->wds_sta &&
Sunil Ravi640215c2023-06-28 23:08:09 +00006661 !(sta->flags & WLAN_STA_WPS))) {
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08006662 int ret;
6663 char ifname_wds[IFNAMSIZ + 1];
6664
6665 wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA "
6666 MACSTR " (aid %u)",
6667 MAC2STR(sta->addr), sta->aid);
6668 ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
6669 sta->aid, 1);
6670 if (!ret)
6671 hostapd_set_wds_encryption(hapd, sta, ifname_wds);
6672 }
6673
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006674 if (sta->auth_alg == WLAN_AUTH_FT)
6675 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
6676 else
6677 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
6678 hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006679 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006680
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006681#ifdef CONFIG_FILS
6682 if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
6683 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6684 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
6685 fils_set_tk(sta->wpa_sm) < 0) {
6686 wpa_printf(MSG_DEBUG, "FILS: TK configuration failed");
6687 ap_sta_disconnect(hapd, sta, sta->addr,
6688 WLAN_REASON_UNSPECIFIED);
6689 return;
6690 }
6691#endif /* CONFIG_FILS */
6692
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006693 if (sta->pending_eapol_rx) {
6694 struct os_reltime now, age;
6695
6696 os_get_reltime(&now);
6697 os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
6698 if (age.sec == 0 && age.usec < 200000) {
6699 wpa_printf(MSG_DEBUG,
6700 "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
6701 MAC2STR(sta->addr));
6702 ieee802_1x_receive(
6703 hapd, mgmt->da,
6704 wpabuf_head(sta->pending_eapol_rx->buf),
Sunil8cd6f4d2022-06-28 18:40:46 +00006705 wpabuf_len(sta->pending_eapol_rx->buf),
6706 sta->pending_eapol_rx->encrypted);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006707 }
6708 wpabuf_free(sta->pending_eapol_rx->buf);
6709 os_free(sta->pending_eapol_rx);
6710 sta->pending_eapol_rx = NULL;
6711 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006712
6713handle_ml:
6714 hostapd_ml_handle_assoc_cb(hapd, sta, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006715}
6716
6717
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006718static void handle_deauth_cb(struct hostapd_data *hapd,
6719 const struct ieee80211_mgmt *mgmt,
6720 size_t len, int ok)
6721{
6722 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006723 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006724 return;
6725 sta = ap_get_sta(hapd, mgmt->da);
6726 if (!sta) {
6727 wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
6728 " not found", MAC2STR(mgmt->da));
6729 return;
6730 }
6731 if (ok)
6732 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
6733 MAC2STR(sta->addr));
6734 else
6735 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6736 "deauth", MAC2STR(sta->addr));
6737
6738 ap_sta_deauth_cb(hapd, sta);
6739}
6740
6741
6742static void handle_disassoc_cb(struct hostapd_data *hapd,
6743 const struct ieee80211_mgmt *mgmt,
6744 size_t len, int ok)
6745{
6746 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006747 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006748 return;
6749 sta = ap_get_sta(hapd, mgmt->da);
6750 if (!sta) {
6751 wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
6752 " not found", MAC2STR(mgmt->da));
6753 return;
6754 }
6755 if (ok)
6756 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
6757 MAC2STR(sta->addr));
6758 else
6759 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6760 "disassoc", MAC2STR(sta->addr));
6761
6762 ap_sta_disassoc_cb(hapd, sta);
6763}
6764
6765
Dmitry Shmidt29333592017-01-09 12:27:11 -08006766static void handle_action_cb(struct hostapd_data *hapd,
6767 const struct ieee80211_mgmt *mgmt,
6768 size_t len, int ok)
6769{
6770 struct sta_info *sta;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006771#ifndef CONFIG_NO_RRM
Paul Stewart092955c2017-02-06 09:13:09 -08006772 const struct rrm_measurement_report_element *report;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006773#endif /* CONFIG_NO_RRM */
Dmitry Shmidt29333592017-01-09 12:27:11 -08006774
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006775#ifdef CONFIG_DPP
6776 if (len >= IEEE80211_HDRLEN + 6 &&
6777 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6778 mgmt->u.action.u.vs_public_action.action ==
6779 WLAN_PA_VENDOR_SPECIFIC &&
6780 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6781 OUI_WFA &&
6782 mgmt->u.action.u.vs_public_action.variable[0] ==
6783 DPP_OUI_TYPE) {
6784 const u8 *pos, *end;
6785
6786 pos = &mgmt->u.action.u.vs_public_action.variable[1];
6787 end = ((const u8 *) mgmt) + len;
6788 hostapd_dpp_tx_status(hapd, mgmt->da, pos, end - pos, ok);
6789 return;
6790 }
6791 if (len >= IEEE80211_HDRLEN + 2 &&
6792 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6793 (mgmt->u.action.u.public_action.action ==
6794 WLAN_PA_GAS_INITIAL_REQ ||
6795 mgmt->u.action.u.public_action.action ==
6796 WLAN_PA_GAS_COMEBACK_REQ)) {
6797 const u8 *pos, *end;
6798
6799 pos = mgmt->u.action.u.public_action.variable;
6800 end = ((const u8 *) mgmt) + len;
6801 gas_query_ap_tx_status(hapd->gas, mgmt->da, pos, end - pos, ok);
6802 return;
6803 }
6804#endif /* CONFIG_DPP */
Hai Shaloma20dcd72022-02-04 13:43:00 -08006805 if (is_multicast_ether_addr(mgmt->da))
6806 return;
Dmitry Shmidt29333592017-01-09 12:27:11 -08006807 sta = ap_get_sta(hapd, mgmt->da);
6808 if (!sta) {
6809 wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR
6810 " not found", MAC2STR(mgmt->da));
6811 return;
6812 }
6813
Sunil Ravi77d572f2023-01-17 23:58:31 +00006814#ifdef CONFIG_HS20
6815 if (ok && len >= IEEE80211_HDRLEN + 2 &&
6816 mgmt->u.action.category == WLAN_ACTION_WNM &&
6817 mgmt->u.action.u.vs_public_action.action == WNM_NOTIFICATION_REQ &&
6818 sta->hs20_deauth_on_ack) {
6819 wpa_printf(MSG_DEBUG, "HS 2.0: Deauthenticate STA " MACSTR
6820 " on acknowledging the WNM-Notification",
6821 MAC2STR(sta->addr));
6822 ap_sta_session_timeout(hapd, sta, 0);
6823 return;
6824 }
6825#endif /* CONFIG_HS20 */
6826
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006827#ifndef CONFIG_NO_RRM
Paul Stewart092955c2017-02-06 09:13:09 -08006828 if (len < 24 + 5 + sizeof(*report))
Dmitry Shmidt29333592017-01-09 12:27:11 -08006829 return;
Paul Stewart092955c2017-02-06 09:13:09 -08006830 report = (const struct rrm_measurement_report_element *)
6831 &mgmt->u.action.u.rrm.variable[2];
Dmitry Shmidt29333592017-01-09 12:27:11 -08006832 if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT &&
Paul Stewart092955c2017-02-06 09:13:09 -08006833 mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST &&
6834 report->eid == WLAN_EID_MEASURE_REQUEST &&
6835 report->len >= 3 &&
6836 report->type == MEASURE_TYPE_BEACON)
Dmitry Shmidt29333592017-01-09 12:27:11 -08006837 hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006838#endif /* CONFIG_NO_RRM */
Dmitry Shmidt29333592017-01-09 12:27:11 -08006839}
6840
6841
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006842/**
6843 * ieee802_11_mgmt_cb - Process management frame TX status callback
6844 * @hapd: hostapd BSS data structure (the BSS from which the management frame
6845 * was sent from)
6846 * @buf: management frame data (starting from IEEE 802.11 header)
6847 * @len: length of frame data in octets
6848 * @stype: management frame subtype from frame control field
6849 * @ok: Whether the frame was ACK'ed
6850 */
6851void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
6852 u16 stype, int ok)
6853{
6854 const struct ieee80211_mgmt *mgmt;
6855 mgmt = (const struct ieee80211_mgmt *) buf;
6856
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006857#ifdef CONFIG_TESTING_OPTIONS
6858 if (hapd->ext_mgmt_frame_handling) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006859 size_t hex_len = 2 * len + 1;
6860 char *hex = os_malloc(hex_len);
6861
6862 if (hex) {
6863 wpa_snprintf_hex(hex, hex_len, buf, len);
6864 wpa_msg(hapd->msg_ctx, MSG_INFO,
6865 "MGMT-TX-STATUS stype=%u ok=%d buf=%s",
6866 stype, ok, hex);
6867 os_free(hex);
6868 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006869 return;
6870 }
6871#endif /* CONFIG_TESTING_OPTIONS */
6872
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006873 switch (stype) {
6874 case WLAN_FC_STYPE_AUTH:
6875 wpa_printf(MSG_DEBUG, "mgmt::auth cb");
6876 handle_auth_cb(hapd, mgmt, len, ok);
6877 break;
6878 case WLAN_FC_STYPE_ASSOC_RESP:
6879 wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
6880 handle_assoc_cb(hapd, mgmt, len, 0, ok);
6881 break;
6882 case WLAN_FC_STYPE_REASSOC_RESP:
6883 wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
6884 handle_assoc_cb(hapd, mgmt, len, 1, ok);
6885 break;
6886 case WLAN_FC_STYPE_PROBE_RESP:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006887 wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006888 break;
6889 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006890 wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
6891 handle_deauth_cb(hapd, mgmt, len, ok);
6892 break;
6893 case WLAN_FC_STYPE_DISASSOC:
6894 wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
6895 handle_disassoc_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006896 break;
6897 case WLAN_FC_STYPE_ACTION:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006898 wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006899 handle_action_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006900 break;
6901 default:
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006902 wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006903 break;
6904 }
6905}
6906
6907
6908int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
6909{
6910 /* TODO */
6911 return 0;
6912}
6913
6914
6915int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
6916 char *buf, size_t buflen)
6917{
6918 /* TODO */
6919 return 0;
6920}
6921
6922
6923void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
6924 const u8 *buf, size_t len, int ack)
6925{
6926 struct sta_info *sta;
6927 struct hostapd_iface *iface = hapd->iface;
6928
6929 sta = ap_get_sta(hapd, addr);
6930 if (sta == NULL && iface->num_bss > 1) {
6931 size_t j;
6932 for (j = 0; j < iface->num_bss; j++) {
6933 hapd = iface->bss[j];
6934 sta = ap_get_sta(hapd, addr);
6935 if (sta)
6936 break;
6937 }
6938 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006939 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006940 return;
6941 if (sta->flags & WLAN_STA_PENDING_POLL) {
6942 wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
6943 "activity poll", MAC2STR(sta->addr),
6944 ack ? "ACKed" : "did not ACK");
6945 if (ack)
6946 sta->flags &= ~WLAN_STA_PENDING_POLL;
6947 }
6948
6949 ieee802_1x_tx_status(hapd, sta, buf, len, ack);
6950}
6951
6952
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006953void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
6954{
6955 struct sta_info *sta;
6956 struct hostapd_iface *iface = hapd->iface;
6957
6958 sta = ap_get_sta(hapd, addr);
6959 if (sta == NULL && iface->num_bss > 1) {
6960 size_t j;
6961 for (j = 0; j < iface->num_bss; j++) {
6962 hapd = iface->bss[j];
6963 sta = ap_get_sta(hapd, addr);
6964 if (sta)
6965 break;
6966 }
6967 }
6968 if (sta == NULL)
6969 return;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006970 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
6971 MAC2STR(sta->addr));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006972 if (!(sta->flags & WLAN_STA_PENDING_POLL))
6973 return;
6974
6975 wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
6976 "activity poll", MAC2STR(sta->addr));
6977 sta->flags &= ~WLAN_STA_PENDING_POLL;
6978}
6979
6980
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006981void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
6982 int wds)
6983{
6984 struct sta_info *sta;
6985
6986 sta = ap_get_sta(hapd, src);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006987 if (sta &&
6988 ((sta->flags & WLAN_STA_ASSOC) ||
6989 ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006990 if (!hapd->conf->wds_sta)
6991 return;
6992
Dmitry Shmidt29333592017-01-09 12:27:11 -08006993 if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) ==
6994 WLAN_STA_ASSOC_REQ_OK) {
6995 wpa_printf(MSG_DEBUG,
6996 "Postpone 4-address WDS mode enabling for STA "
6997 MACSTR " since TX status for AssocResp is not yet known",
6998 MAC2STR(sta->addr));
6999 sta->pending_wds_enable = 1;
7000 return;
7001 }
7002
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007003 if (wds && !(sta->flags & WLAN_STA_WDS)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07007004 int ret;
7005 char ifname_wds[IFNAMSIZ + 1];
7006
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007007 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
7008 "STA " MACSTR " (aid %u)",
7009 MAC2STR(sta->addr), sta->aid);
7010 sta->flags |= WLAN_STA_WDS;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07007011 ret = hostapd_set_wds_sta(hapd, ifname_wds,
7012 sta->addr, sta->aid, 1);
7013 if (!ret)
7014 hostapd_set_wds_encryption(hapd, sta,
7015 ifname_wds);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007016 }
7017 return;
7018 }
7019
7020 wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
7021 MACSTR, MAC2STR(src));
Hai Shalomc3565922019-10-28 11:58:20 -07007022 if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007023 ether_addr_equal(src, hapd->own_addr)) {
Hai Shalomc3565922019-10-28 11:58:20 -07007024 /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
7025 * silently. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007026 return;
7027 }
7028
7029 if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) {
7030 wpa_printf(MSG_DEBUG, "Association Response to the STA has "
7031 "already been sent, but no TX status yet known - "
7032 "ignore Class 3 frame issue with " MACSTR,
7033 MAC2STR(src));
7034 return;
7035 }
7036
7037 if (sta && (sta->flags & WLAN_STA_AUTH))
7038 hostapd_drv_sta_disassoc(
7039 hapd, src,
7040 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
7041 else
7042 hostapd_drv_sta_deauth(
7043 hapd, src,
7044 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
7045}
7046
7047
Sunil Ravia04bd252022-05-02 22:54:18 -07007048static u8 * hostapd_add_tpe_info(u8 *eid, u8 tx_pwr_count,
7049 enum max_tx_pwr_interpretation tx_pwr_intrpn,
7050 u8 tx_pwr_cat, u8 tx_pwr)
7051{
7052 int i;
7053
7054 *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE; /* Element ID */
7055 *eid++ = 2 + tx_pwr_count; /* Length */
7056
7057 /*
7058 * Transmit Power Information field
7059 * bits 0-2 : Maximum Transmit Power Count
7060 * bits 3-5 : Maximum Transmit Power Interpretation
7061 * bits 6-7 : Maximum Transmit Power Category
7062 */
7063 *eid++ = tx_pwr_count | (tx_pwr_intrpn << 3) | (tx_pwr_cat << 6);
7064
7065 /* Maximum Transmit Power field */
7066 for (i = 0; i <= tx_pwr_count; i++)
7067 *eid++ = tx_pwr;
7068
7069 return eid;
7070}
7071
7072
7073/*
7074 * TODO: Extract power limits from channel data after 6G regulatory
7075 * support.
7076 */
7077#define REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT (-1) /* dBm/MHz */
7078#define REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT 5 /* dBm/MHz */
7079
Hai Shalom60840252021-02-19 19:02:11 -08007080u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
7081{
7082 struct hostapd_iface *iface = hapd->iface;
7083 struct hostapd_config *iconf = iface->conf;
7084 struct hostapd_hw_modes *mode = iface->current_mode;
7085 struct hostapd_channel_data *chan;
7086 int dfs, i;
7087 u8 channel, tx_pwr_count, local_pwr_constraint;
7088 int max_tx_power;
7089 u8 tx_pwr;
7090
7091 if (!mode)
7092 return eid;
7093
7094 if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
7095 return eid;
7096
7097 for (i = 0; i < mode->num_channels; i++) {
7098 if (mode->channels[i].freq == iface->freq)
7099 break;
7100 }
7101 if (i == mode->num_channels)
7102 return eid;
7103
Sunil Ravia04bd252022-05-02 22:54:18 -07007104#ifdef CONFIG_IEEE80211AX
7105 /* IEEE Std 802.11ax-2021, Annex E.2.7 (6 GHz band in the United
7106 * States): An AP that is an Indoor Access Point per regulatory rules
7107 * shall send at least two Transmit Power Envelope elements in Beacon
7108 * and Probe Response frames as follows:
7109 * - Maximum Transmit Power Category subfield = Default;
7110 * Unit interpretation = Regulatory client EIRP PSD
7111 * - Maximum Transmit Power Category subfield = Subordinate Device;
7112 * Unit interpretation = Regulatory client EIRP PSD
7113 */
7114 if (is_6ghz_op_class(iconf->op_class)) {
7115 enum max_tx_pwr_interpretation tx_pwr_intrpn;
7116
7117 /* Same Maximum Transmit Power for all 20 MHz bands */
7118 tx_pwr_count = 0;
7119 tx_pwr_intrpn = REGULATORY_CLIENT_EIRP_PSD;
7120
7121 /* Default Transmit Power Envelope for Global Operating Class */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007122 if (hapd->iconf->reg_def_cli_eirp_psd != -1)
7123 tx_pwr = hapd->iconf->reg_def_cli_eirp_psd;
7124 else
7125 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT * 2;
7126
Sunil Ravia04bd252022-05-02 22:54:18 -07007127 eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn,
7128 REG_DEFAULT_CLIENT, tx_pwr);
7129
7130 /* Indoor Access Point must include an additional TPE for
7131 * subordinate devices */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007132 if (he_reg_is_indoor(iconf->he_6ghz_reg_pwr_type)) {
Sunil Ravia04bd252022-05-02 22:54:18 -07007133 /* TODO: Extract PSD limits from channel data */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007134 if (hapd->iconf->reg_sub_cli_eirp_psd != -1)
7135 tx_pwr = hapd->iconf->reg_sub_cli_eirp_psd;
7136 else
7137 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT * 2;
Sunil Ravia04bd252022-05-02 22:54:18 -07007138 eid = hostapd_add_tpe_info(eid, tx_pwr_count,
7139 tx_pwr_intrpn,
7140 REG_SUBORDINATE_CLIENT,
7141 tx_pwr);
7142 }
7143
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007144 if (iconf->reg_def_cli_eirp != -1 &&
7145 he_reg_is_sp(iconf->he_6ghz_reg_pwr_type))
7146 eid = hostapd_add_tpe_info(
7147 eid, tx_pwr_count, REGULATORY_CLIENT_EIRP,
7148 REG_DEFAULT_CLIENT,
7149 hapd->iconf->reg_def_cli_eirp);
7150
Sunil Ravia04bd252022-05-02 22:54:18 -07007151 return eid;
7152 }
7153#endif /* CONFIG_IEEE80211AX */
7154
Hai Shalom60840252021-02-19 19:02:11 -08007155 switch (hostapd_get_oper_chwidth(iconf)) {
Sunil8cd6f4d2022-06-28 18:40:46 +00007156 case CONF_OPER_CHWIDTH_USE_HT:
Hai Shalom60840252021-02-19 19:02:11 -08007157 if (iconf->secondary_channel == 0) {
7158 /* Max Transmit Power count = 0 (20 MHz) */
7159 tx_pwr_count = 0;
7160 } else {
7161 /* Max Transmit Power count = 1 (20, 40 MHz) */
7162 tx_pwr_count = 1;
7163 }
7164 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00007165 case CONF_OPER_CHWIDTH_80MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08007166 /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
7167 tx_pwr_count = 2;
7168 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00007169 case CONF_OPER_CHWIDTH_80P80MHZ:
7170 case CONF_OPER_CHWIDTH_160MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08007171 /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
7172 tx_pwr_count = 3;
7173 break;
7174 default:
7175 return eid;
7176 }
7177
7178 /*
7179 * Below local_pwr_constraint logic is referred from
7180 * hostapd_eid_pwr_constraint.
7181 *
7182 * Check if DFS is required by regulatory.
7183 */
7184 dfs = hostapd_is_dfs_required(hapd->iface);
7185 if (dfs < 0)
7186 dfs = 0;
7187
7188 /*
7189 * In order to meet regulations when TPC is not implemented using
7190 * a transmit power that is below the legal maximum (including any
7191 * mitigation factor) should help. In this case, indicate 3 dB below
7192 * maximum allowed transmit power.
7193 */
7194 if (hapd->iconf->local_pwr_constraint == -1)
7195 local_pwr_constraint = (dfs == 0) ? 0 : 3;
7196 else
7197 local_pwr_constraint = hapd->iconf->local_pwr_constraint;
7198
7199 /*
7200 * A STA that is not an AP shall use a transmit power less than or
7201 * equal to the local maximum transmit power level for the channel.
7202 * The local maximum transmit power can be calculated from the formula:
7203 * local max TX pwr = max TX pwr - local pwr constraint
7204 * Where max TX pwr is maximum transmit power level specified for
7205 * channel in Country element and local pwr constraint is specified
7206 * for channel in this Power Constraint element.
7207 */
7208 chan = &mode->channels[i];
7209 max_tx_power = chan->max_tx_power - local_pwr_constraint;
7210
7211 /*
7212 * Local Maximum Transmit power is encoded as two's complement
7213 * with a 0.5 dB step.
7214 */
7215 max_tx_power *= 2; /* in 0.5 dB steps */
7216 if (max_tx_power > 127) {
7217 /* 63.5 has special meaning of 63.5 dBm or higher */
7218 max_tx_power = 127;
7219 }
7220 if (max_tx_power < -128)
7221 max_tx_power = -128;
7222 if (max_tx_power < 0)
7223 tx_pwr = 0x80 + max_tx_power + 128;
7224 else
7225 tx_pwr = max_tx_power;
7226
Sunil Ravia04bd252022-05-02 22:54:18 -07007227 return hostapd_add_tpe_info(eid, tx_pwr_count, LOCAL_EIRP,
7228 0 /* Reserved for bands other than 6 GHz */,
7229 tx_pwr);
Hai Shalom60840252021-02-19 19:02:11 -08007230}
7231
7232
Hai Shalom899fcc72020-10-19 14:38:18 -07007233u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
7234{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007235 u8 bw, chan1 = 0, chan2 = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -07007236 int freq1;
7237
7238 if (!hapd->cs_freq_params.channel ||
7239 (!hapd->cs_freq_params.vht_enabled &&
Sunil Ravia04bd252022-05-02 22:54:18 -07007240 !hapd->cs_freq_params.he_enabled &&
7241 !hapd->cs_freq_params.eht_enabled))
Hai Shalom899fcc72020-10-19 14:38:18 -07007242 return eid;
7243
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007244 /* bandwidth: 0: 40, 1: 80, 160, 80+80, 4: 320 as per
7245 * IEEE P802.11-REVme/D4.0, 9.4.2.159 and Table 9-314. */
Hai Shalom899fcc72020-10-19 14:38:18 -07007246 switch (hapd->cs_freq_params.bandwidth) {
7247 case 40:
7248 bw = 0;
7249 break;
7250 case 80:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007251 bw = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07007252 break;
7253 case 160:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007254 bw = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07007255 break;
Sunil Ravi640215c2023-06-28 23:08:09 +00007256 case 320:
7257 bw = 4;
7258 break;
Hai Shalom899fcc72020-10-19 14:38:18 -07007259 default:
7260 /* not valid VHT bandwidth or not in CSA */
7261 return eid;
7262 }
7263
7264 freq1 = hapd->cs_freq_params.center_freq1 ?
7265 hapd->cs_freq_params.center_freq1 :
7266 hapd->cs_freq_params.freq;
7267 if (ieee80211_freq_to_chan(freq1, &chan1) !=
7268 HOSTAPD_MODE_IEEE80211A)
7269 return eid;
7270
7271 if (hapd->cs_freq_params.center_freq2 &&
7272 ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
7273 &chan2) != HOSTAPD_MODE_IEEE80211A)
7274 return eid;
7275
Sunil Ravi640215c2023-06-28 23:08:09 +00007276 *eid++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER;
Hai Shalom899fcc72020-10-19 14:38:18 -07007277 *eid++ = 5; /* Length of Channel Switch Wrapper */
Sunil Ravi640215c2023-06-28 23:08:09 +00007278 *eid++ = WLAN_EID_WIDE_BW_CHSWITCH;
Hai Shalom899fcc72020-10-19 14:38:18 -07007279 *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
7280 *eid++ = bw; /* New Channel Width */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007281 if (hapd->cs_freq_params.bandwidth == 160) {
7282 /* Update the CCFS0 and CCFS1 values in the element based on
7283 * IEEE P802.11-REVme/D4.0, Table 9-314 */
7284
7285 /* CCFS1 - The channel center frequency index of the 160 MHz
7286 * channel. */
7287 chan2 = chan1;
7288
7289 /* CCFS0 - The channel center frequency index of the 80 MHz
7290 * channel segment that contains the primary channel. */
7291 if (hapd->cs_freq_params.channel < chan1)
7292 chan1 -= 8;
7293 else
7294 chan1 += 8;
7295 }
Hai Shalom899fcc72020-10-19 14:38:18 -07007296 *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
7297 *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
7298
7299 return eid;
7300}
7301
Hai Shaloma20dcd72022-02-04 13:43:00 -08007302
7303static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd,
7304 size_t *current_len)
7305{
7306 struct hostapd_neighbor_entry *nr;
7307 size_t total_len = 0, len = *current_len;
7308
7309 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7310 list) {
7311 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7312 continue;
7313
7314 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7315 continue;
7316
7317 /* Start a new element */
7318 if (!len ||
7319 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7320 len = RNR_HEADER_LEN;
7321 total_len += RNR_HEADER_LEN;
7322 }
7323
7324 len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7325 total_len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7326 }
7327
7328 *current_len = len;
7329 return total_len;
7330}
7331
7332
Sunil Ravi640215c2023-06-28 23:08:09 +00007333struct mbssid_ie_profiles {
7334 u8 start;
7335 u8 end;
7336};
7337
Sunil Ravi7f769292024-07-23 22:21:32 +00007338static bool hostapd_skip_rnr(size_t i, struct mbssid_ie_profiles *skip_profiles,
7339 bool ap_mld, u8 tbtt_info_len, bool mld_update,
7340 struct hostapd_data *reporting_hapd,
7341 struct hostapd_data *bss)
7342{
7343 if (skip_profiles &&
7344 i >= skip_profiles->start && i < skip_profiles->end)
7345 return true;
7346
7347 /* No need to report if length is for normal TBTT and the BSS is
7348 * affiliated with an AP MLD. MLD TBTT will include this. */
7349 if (tbtt_info_len == RNR_TBTT_INFO_LEN && ap_mld)
7350 return true;
7351
7352 /* No need to report if length is for MLD TBTT and the BSS is not
7353 * affiliated with an aP MLD. Normal TBTT will include this. */
7354 if (tbtt_info_len == RNR_TBTT_INFO_MLD_LEN && !ap_mld)
7355 return true;
7356
7357#ifdef CONFIG_IEEE80211BE
7358 /* If building for co-location and they are ML partners, no need to
7359 * include since the ML RNR will carry this. */
7360 if (!mld_update && hostapd_is_ml_partner(reporting_hapd, bss))
7361 return true;
7362
7363 /* If building for ML RNR and they are not ML partners, don't include.
7364 */
7365 if (mld_update && !hostapd_is_ml_partner(reporting_hapd, bss))
7366 return true;
7367#endif /* CONFIG_IEEE80211BE */
7368
7369 return false;
7370}
7371
7372
Sunil Ravi640215c2023-06-28 23:08:09 +00007373static size_t
7374hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
7375 struct hostapd_data *reporting_hapd,
7376 size_t *current_len,
Sunil Ravi7f769292024-07-23 22:21:32 +00007377 struct mbssid_ie_profiles *skip_profiles,
7378 bool mld_update)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007379{
7380 size_t total_len = 0, len = *current_len;
Sunil Ravi7f769292024-07-23 22:21:32 +00007381 int tbtt_count, total_tbtt_count = 0;
7382 size_t i, start;
7383 u8 tbtt_info_len = mld_update ? RNR_TBTT_INFO_MLD_LEN :
7384 RNR_TBTT_INFO_LEN;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007385
Sunil Ravi7f769292024-07-23 22:21:32 +00007386repeat_rnr_len:
7387 start = 0;
7388 tbtt_count = 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007389
7390 while (start < hapd->iface->num_bss) {
7391 if (!len ||
Sunil Ravi7f769292024-07-23 22:21:32 +00007392 len + RNR_TBTT_HEADER_LEN + tbtt_info_len > 255 ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007393 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08007394 len = RNR_HEADER_LEN;
7395 total_len += RNR_HEADER_LEN;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007396 tbtt_count = 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007397 }
7398
7399 len += RNR_TBTT_HEADER_LEN;
7400 total_len += RNR_TBTT_HEADER_LEN;
7401
7402 for (i = start; i < hapd->iface->num_bss; i++) {
7403 struct hostapd_data *bss = hapd->iface->bss[i];
Sunil Ravi7f769292024-07-23 22:21:32 +00007404 bool ap_mld = false;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007405
7406 if (!bss || !bss->conf || !bss->started)
7407 continue;
7408
Sunil Ravi7f769292024-07-23 22:21:32 +00007409#ifdef CONFIG_IEEE80211BE
7410 ap_mld = bss->conf->mld_ap;
7411#endif /* CONFIG_IEEE80211BE */
7412
Hai Shaloma20dcd72022-02-04 13:43:00 -08007413 if (bss == reporting_hapd ||
7414 bss->conf->ignore_broadcast_ssid)
7415 continue;
7416
Sunil Ravi7f769292024-07-23 22:21:32 +00007417 if (hostapd_skip_rnr(i, skip_profiles, ap_mld,
7418 tbtt_info_len, mld_update,
7419 reporting_hapd, bss))
Sunil Ravi640215c2023-06-28 23:08:09 +00007420 continue;
7421
Sunil Ravi7f769292024-07-23 22:21:32 +00007422 if (len + tbtt_info_len > 255 ||
Hai Shaloma20dcd72022-02-04 13:43:00 -08007423 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7424 break;
7425
Sunil Ravi7f769292024-07-23 22:21:32 +00007426 len += tbtt_info_len;
7427 total_len += tbtt_info_len;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007428 tbtt_count++;
7429 }
7430 start = i;
7431 }
7432
Sunil Ravi7f769292024-07-23 22:21:32 +00007433 total_tbtt_count += tbtt_count;
7434
7435 /* If building for co-location, re-build again but this time include
7436 * ML TBTTs.
7437 */
7438 if (!mld_update && tbtt_info_len == RNR_TBTT_INFO_LEN) {
7439 tbtt_info_len = RNR_TBTT_INFO_MLD_LEN;
7440
7441 /* If no TBTT was found, adjust the len and total_len since it
7442 * would have incremented before we checked all BSSs. */
7443 if (!tbtt_count) {
7444 len -= RNR_TBTT_HEADER_LEN;
7445 total_len -= RNR_TBTT_HEADER_LEN;
7446 }
7447
7448 goto repeat_rnr_len;
7449 }
7450
7451 /* This is possible when in the re-built case and no suitable TBTT was
7452 * found. Adjust the length accordingly. */
7453 if (!tbtt_count && total_tbtt_count) {
7454 len -= RNR_TBTT_HEADER_LEN;
7455 total_len -= RNR_TBTT_HEADER_LEN;
7456 }
7457
7458 if (!total_tbtt_count)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007459 total_len = 0;
7460 else
7461 *current_len = len;
7462
7463 return total_len;
7464}
7465
7466
7467enum colocation_mode {
7468 NO_COLOCATED_6GHZ,
7469 STANDALONE_6GHZ,
7470 COLOCATED_6GHZ,
7471 COLOCATED_LOWER_BAND,
7472};
7473
7474static enum colocation_mode get_colocation_mode(struct hostapd_data *hapd)
7475{
7476 u8 i;
7477 bool is_6ghz = is_6ghz_op_class(hapd->iconf->op_class);
7478
7479 if (!hapd->iface || !hapd->iface->interfaces)
7480 return NO_COLOCATED_6GHZ;
7481
7482 if (is_6ghz && hapd->iface->interfaces->count == 1)
7483 return STANDALONE_6GHZ;
7484
7485 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7486 struct hostapd_iface *iface;
7487 bool is_colocated_6ghz;
7488
7489 iface = hapd->iface->interfaces->iface[i];
7490 if (iface == hapd->iface || !iface || !iface->conf)
7491 continue;
7492
7493 is_colocated_6ghz = is_6ghz_op_class(iface->conf->op_class);
7494 if (!is_6ghz && is_colocated_6ghz)
7495 return COLOCATED_LOWER_BAND;
7496 if (is_6ghz && !is_colocated_6ghz)
7497 return COLOCATED_6GHZ;
7498 }
7499
7500 if (is_6ghz)
7501 return STANDALONE_6GHZ;
7502
7503 return NO_COLOCATED_6GHZ;
7504}
7505
7506
Sunil Ravi7f769292024-07-23 22:21:32 +00007507static size_t hostapd_eid_rnr_colocation_len(struct hostapd_data *hapd,
7508 size_t *current_len)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007509{
7510 struct hostapd_iface *iface;
7511 size_t len = 0;
7512 size_t i;
7513
7514 if (!hapd->iface || !hapd->iface->interfaces)
7515 return 0;
7516
7517 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7518 iface = hapd->iface->interfaces->iface[i];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007519
Sunil Ravi7f769292024-07-23 22:21:32 +00007520 if (!iface || iface == hapd->iface ||
Sunil Ravi99c035e2024-07-12 01:42:03 +00007521 iface->state != HAPD_IFACE_ENABLED ||
Sunil Ravi7f769292024-07-23 22:21:32 +00007522 !is_6ghz_op_class(iface->conf->op_class))
Hai Shaloma20dcd72022-02-04 13:43:00 -08007523 continue;
7524
7525 len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
Sunil Ravi7f769292024-07-23 22:21:32 +00007526 current_len, NULL, false);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007527 }
7528
7529 return len;
7530}
7531
7532
Sunil Ravi7f769292024-07-23 22:21:32 +00007533static size_t hostapd_eid_rnr_mlo_len(struct hostapd_data *hapd, u32 type,
7534 size_t *current_len)
7535{
7536 size_t len = 0;
7537#ifdef CONFIG_IEEE80211BE
7538 struct hostapd_iface *iface;
7539 size_t i;
7540
7541 if (!hapd->iface || !hapd->iface->interfaces || !hapd->conf->mld_ap)
7542 return 0;
7543
7544 /* TODO: Allow for FILS/Action as well */
7545 if (type != WLAN_FC_STYPE_BEACON && type != WLAN_FC_STYPE_PROBE_RESP)
7546 return 0;
7547
7548 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7549 iface = hapd->iface->interfaces->iface[i];
7550
7551 if (!iface || iface == hapd->iface ||
7552 hapd->iface->freq == iface->freq)
7553 continue;
7554
7555 len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
7556 current_len, NULL, true);
7557 }
7558#endif /* CONFIG_IEEE80211BE */
7559
7560 return len;
7561}
7562
7563
7564size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type,
7565 bool include_mld_params)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007566{
7567 size_t total_len = 0, current_len = 0;
7568 enum colocation_mode mode = get_colocation_mode(hapd);
7569
7570 switch (type) {
7571 case WLAN_FC_STYPE_BEACON:
7572 if (hapd->conf->rnr)
7573 total_len += hostapd_eid_nr_db_len(hapd, &current_len);
7574 /* fallthrough */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007575 case WLAN_FC_STYPE_PROBE_RESP:
Sunil Ravi7f769292024-07-23 22:21:32 +00007576 if (mode == COLOCATED_LOWER_BAND)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007577 total_len +=
Sunil Ravi7f769292024-07-23 22:21:32 +00007578 hostapd_eid_rnr_colocation_len(hapd,
7579 &current_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007580
Sunil Ravi640215c2023-06-28 23:08:09 +00007581 if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
7582 !hapd->iconf->mbssid)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007583 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007584 &current_len,
Sunil Ravi7f769292024-07-23 22:21:32 +00007585 NULL, false);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007586 break;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007587 case WLAN_FC_STYPE_ACTION:
7588 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
7589 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007590 &current_len,
Sunil Ravi7f769292024-07-23 22:21:32 +00007591 NULL, false);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007592 break;
7593 }
7594
Sunil Ravi7f769292024-07-23 22:21:32 +00007595 /* For EMA Beacons, MLD neighbor repoting is added as part of
7596 * MBSSID RNR. */
7597 if (include_mld_params &&
7598 (type != WLAN_FC_STYPE_BEACON ||
7599 hapd->iconf->mbssid != ENHANCED_MBSSID_ENABLED))
7600 total_len += hostapd_eid_rnr_mlo_len(hapd, type, &current_len);
7601
Hai Shaloma20dcd72022-02-04 13:43:00 -08007602 return total_len;
7603}
7604
7605
7606static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid,
7607 size_t *current_len)
7608{
7609 struct hostapd_neighbor_entry *nr;
7610 size_t len = *current_len;
7611 u8 *size_offset = (eid - len) + 1;
7612
7613 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7614 list) {
7615 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7616 continue;
7617
7618 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7619 continue;
7620
7621 /* Start a new element */
7622 if (!len ||
7623 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7624 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7625 size_offset = eid++;
7626 len = RNR_HEADER_LEN;
7627 }
7628
7629 /* TBTT Information Header subfield (2 octets) */
7630 *eid++ = 0;
7631 /* TBTT Information Length */
7632 *eid++ = RNR_TBTT_INFO_LEN;
7633 /* Operating Class */
7634 *eid++ = wpabuf_head_u8(nr->nr)[10];
7635 /* Channel Number */
7636 *eid++ = wpabuf_head_u8(nr->nr)[11];
7637 len += RNR_TBTT_HEADER_LEN;
7638 /* TBTT Information Set */
7639 /* TBTT Information field */
7640 /* Neighbor AP TBTT Offset */
7641 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
7642 /* BSSID */
7643 os_memcpy(eid, nr->bssid, ETH_ALEN);
7644 eid += ETH_ALEN;
7645 /* Short SSID */
7646 os_memcpy(eid, &nr->short_ssid, 4);
7647 eid += 4;
7648 /* BSS parameters */
7649 *eid++ = nr->bss_parameters;
7650 /* 20 MHz PSD */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007651 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007652 len += RNR_TBTT_INFO_LEN;
7653 *size_offset = (eid - size_offset) - 1;
7654 }
7655
7656 *current_len = len;
7657 return eid;
7658}
7659
7660
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007661static bool hostapd_eid_rnr_bss(struct hostapd_data *hapd,
7662 struct hostapd_data *reporting_hapd,
7663 struct mbssid_ie_profiles *skip_profiles,
7664 size_t i, u8 *tbtt_count, size_t *len,
Sunil Ravi7f769292024-07-23 22:21:32 +00007665 u8 **pos, u8 **tbtt_count_pos, u8 tbtt_info_len,
7666 u8 op_class, bool mld_update)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007667{
7668 struct hostapd_iface *iface = hapd->iface;
7669 struct hostapd_data *bss = iface->bss[i];
7670 u8 bss_param = 0;
7671 bool ap_mld = false;
7672 u8 *eid = *pos;
7673
7674#ifdef CONFIG_IEEE80211BE
7675 ap_mld = !!hapd->conf->mld_ap;
7676#endif /* CONFIG_IEEE80211BE */
7677
7678 if (!bss || !bss->conf || !bss->started ||
7679 bss == reporting_hapd || bss->conf->ignore_broadcast_ssid)
7680 return false;
7681
Sunil Ravi7f769292024-07-23 22:21:32 +00007682 if (hostapd_skip_rnr(i, skip_profiles, ap_mld, tbtt_info_len,
7683 mld_update, reporting_hapd, bss))
7684 return false;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007685
7686 if (*len + RNR_TBTT_INFO_LEN > 255 ||
7687 *tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7688 return true;
7689
Sunil Ravi7f769292024-07-23 22:21:32 +00007690 if (!(*tbtt_count)) {
7691 /* Add neighbor report header info only if there is at least
7692 * one TBTT info available. */
7693 *tbtt_count_pos = eid++;
7694 *eid++ = tbtt_info_len;
7695 *eid++ = op_class;
7696 *eid++ = bss->iconf->channel;
7697 *len += RNR_TBTT_HEADER_LEN;
7698 }
7699
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007700 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
7701 os_memcpy(eid, bss->own_addr, ETH_ALEN);
7702 eid += ETH_ALEN;
7703 os_memcpy(eid, &bss->conf->ssid.short_ssid, 4);
7704 eid += 4;
7705 if (bss->conf->ssid.short_ssid == reporting_hapd->conf->ssid.short_ssid)
7706 bss_param |= RNR_BSS_PARAM_SAME_SSID;
7707
7708 if (iface->conf->mbssid != MBSSID_DISABLED && iface->num_bss > 1) {
7709 bss_param |= RNR_BSS_PARAM_MULTIPLE_BSSID;
7710 if (bss == hostapd_mbssid_get_tx_bss(hapd))
7711 bss_param |= RNR_BSS_PARAM_TRANSMITTED_BSSID;
7712 }
7713
7714 if (is_6ghz_op_class(hapd->iconf->op_class) &&
7715 bss->conf->unsol_bcast_probe_resp_interval)
7716 bss_param |= RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE;
7717
7718 bss_param |= RNR_BSS_PARAM_CO_LOCATED;
7719
7720 *eid++ = bss_param;
7721 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER;
7722
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007723#ifdef CONFIG_IEEE80211BE
Sunil Ravi7f769292024-07-23 22:21:32 +00007724 if (ap_mld) {
7725 u8 param_ch = bss->eht_mld_bss_param_change;
7726 bool is_partner;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007727
Sunil Ravi7f769292024-07-23 22:21:32 +00007728 /* If BSS is not a partner of the reporting_hapd
7729 * a) MLD ID advertised shall be 255.
7730 * b) Link ID advertised shall be 15.
7731 * c) BPCC advertised shall be 255 */
7732 is_partner = hostapd_is_ml_partner(bss, reporting_hapd);
7733 /* MLD ID */
7734 *eid++ = is_partner ? hostapd_get_mld_id(bss) : 0xFF;
7735 /* Link ID (Bit 3 to Bit 0)
7736 * BPCC (Bit 4 to Bit 7) */
7737 *eid++ = is_partner ?
7738 bss->mld_link_id | ((param_ch & 0xF) << 4) :
7739 (MAX_NUM_MLD_LINKS | 0xF0);
7740 /* BPCC (Bit 3 to Bit 0) */
7741 *eid = is_partner ? ((param_ch & 0xF0) >> 4) : 0x0F;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007742#ifdef CONFIG_TESTING_OPTIONS
Sunil Ravi7f769292024-07-23 22:21:32 +00007743 if (bss->conf->mld_indicate_disabled)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007744 *eid |= RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED;
7745#endif /* CONFIG_TESTING_OPTIONS */
7746 eid++;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007747 }
Sunil Ravi7f769292024-07-23 22:21:32 +00007748#endif /* CONFIG_IEEE80211BE */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007749
Sunil Ravi7f769292024-07-23 22:21:32 +00007750 *len += tbtt_info_len;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007751 (*tbtt_count)++;
7752 *pos = eid;
7753
7754 return false;
7755}
7756
7757
Hai Shaloma20dcd72022-02-04 13:43:00 -08007758static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
7759 struct hostapd_data *reporting_hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007760 u8 *eid, size_t *current_len,
Sunil Ravi7f769292024-07-23 22:21:32 +00007761 struct mbssid_ie_profiles *skip_profiles,
7762 bool mld_update)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007763{
Hai Shaloma20dcd72022-02-04 13:43:00 -08007764 struct hostapd_iface *iface = hapd->iface;
Sunil Ravi7f769292024-07-23 22:21:32 +00007765 size_t i, start;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007766 size_t len = *current_len;
Sunil Ravi7f769292024-07-23 22:21:32 +00007767 u8 *eid_start = eid, *size_offset = (eid - len) + 1;
7768 u8 *tbtt_count_pos = size_offset + 1;
7769 u8 tbtt_count, total_tbtt_count = 0, op_class, channel;
7770 u8 tbtt_info_len = mld_update ? RNR_TBTT_INFO_MLD_LEN :
7771 RNR_TBTT_INFO_LEN;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007772
7773 if (!(iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !iface->freq)
7774 return eid;
7775
7776 if (ieee80211_freq_to_channel_ext(iface->freq,
7777 hapd->iconf->secondary_channel,
7778 hostapd_get_oper_chwidth(hapd->iconf),
7779 &op_class, &channel) ==
7780 NUM_HOSTAPD_MODES)
7781 return eid;
7782
Sunil Ravi7f769292024-07-23 22:21:32 +00007783repeat_rnr:
7784 start = 0;
7785 tbtt_count = 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007786 while (start < iface->num_bss) {
7787 if (!len ||
Sunil Ravi7f769292024-07-23 22:21:32 +00007788 len + RNR_TBTT_HEADER_LEN + tbtt_info_len > 255 ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007789 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08007790 eid_start = eid;
7791 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7792 size_offset = eid++;
7793 len = RNR_HEADER_LEN;
7794 tbtt_count = 0;
7795 }
7796
Hai Shaloma20dcd72022-02-04 13:43:00 -08007797 for (i = start; i < iface->num_bss; i++) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007798 if (hostapd_eid_rnr_bss(hapd, reporting_hapd,
7799 skip_profiles, i,
Sunil Ravi7f769292024-07-23 22:21:32 +00007800 &tbtt_count, &len, &eid,
7801 &tbtt_count_pos, tbtt_info_len,
7802 op_class, mld_update))
Hai Shaloma20dcd72022-02-04 13:43:00 -08007803 break;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007804 }
7805
7806 start = i;
Sunil Ravi7f769292024-07-23 22:21:32 +00007807
7808 if (tbtt_count) {
7809 *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
7810 *size_offset = (eid - size_offset) - 1;
7811 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08007812 }
7813
Sunil Ravi7f769292024-07-23 22:21:32 +00007814 total_tbtt_count += tbtt_count;
7815
7816 /* If building for co-location, re-build again but this time include
7817 * ML TBTTs.
7818 */
7819 if (!mld_update && tbtt_info_len == RNR_TBTT_INFO_LEN) {
7820 tbtt_info_len = RNR_TBTT_INFO_MLD_LEN;
7821 goto repeat_rnr;
7822 }
7823
7824 if (!total_tbtt_count)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007825 return eid_start;
7826
7827 *current_len = len;
7828 return eid;
7829}
7830
7831
Sunil Ravi7f769292024-07-23 22:21:32 +00007832u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid,
7833 size_t *current_len)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007834{
7835 struct hostapd_iface *iface;
7836 size_t i;
7837
7838 if (!hapd->iface || !hapd->iface->interfaces)
7839 return eid;
7840
7841 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7842 iface = hapd->iface->interfaces->iface[i];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007843
Sunil Ravi7f769292024-07-23 22:21:32 +00007844 if (!iface || iface == hapd->iface ||
Sunil Ravi99c035e2024-07-12 01:42:03 +00007845 iface->state != HAPD_IFACE_ENABLED ||
Sunil Ravi7f769292024-07-23 22:21:32 +00007846 !is_6ghz_op_class(iface->conf->op_class))
Hai Shaloma20dcd72022-02-04 13:43:00 -08007847 continue;
7848
7849 eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
Sunil Ravi7f769292024-07-23 22:21:32 +00007850 current_len, NULL, false);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007851 }
7852
7853 return eid;
7854}
7855
7856
Sunil Ravi7f769292024-07-23 22:21:32 +00007857u8 * hostapd_eid_rnr_mlo(struct hostapd_data *hapd, u32 type,
7858 u8 *eid, size_t *current_len)
7859{
7860#ifdef CONFIG_IEEE80211BE
7861 struct hostapd_iface *iface;
7862 size_t i;
7863
7864 if (!hapd->iface || !hapd->iface->interfaces || !hapd->conf->mld_ap)
7865 return eid;
7866
7867 /* TODO: Allow for FILS/Action as well */
7868 if (type != WLAN_FC_STYPE_BEACON && type != WLAN_FC_STYPE_PROBE_RESP)
7869 return eid;
7870
7871 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7872 iface = hapd->iface->interfaces->iface[i];
7873
7874 if (!iface || iface == hapd->iface ||
7875 hapd->iface->freq == iface->freq)
7876 continue;
7877
7878 eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
7879 current_len, NULL, true);
7880 }
7881#endif /* CONFIG_IEEE80211BE */
7882
7883 return eid;
7884}
7885
7886
7887u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type,
7888 bool include_mld_params)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007889{
7890 u8 *eid_start = eid;
7891 size_t current_len = 0;
7892 enum colocation_mode mode = get_colocation_mode(hapd);
7893
7894 switch (type) {
7895 case WLAN_FC_STYPE_BEACON:
7896 if (hapd->conf->rnr)
7897 eid = hostapd_eid_nr_db(hapd, eid, &current_len);
7898 /* fallthrough */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007899 case WLAN_FC_STYPE_PROBE_RESP:
Sunil Ravi7f769292024-07-23 22:21:32 +00007900 if (mode == COLOCATED_LOWER_BAND)
7901 eid = hostapd_eid_rnr_colocation(hapd, eid,
7902 &current_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007903
Sunil Ravi640215c2023-06-28 23:08:09 +00007904 if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
7905 !hapd->iconf->mbssid)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007906 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
Sunil Ravi7f769292024-07-23 22:21:32 +00007907 &current_len, NULL, false);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007908 break;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007909 case WLAN_FC_STYPE_ACTION:
7910 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007911 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
Sunil Ravi7f769292024-07-23 22:21:32 +00007912 &current_len, NULL, false);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007913 break;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007914 default:
7915 return eid_start;
7916 }
7917
Sunil Ravi7f769292024-07-23 22:21:32 +00007918 /* For EMA Beacons, MLD neighbor repoting is added as part of
7919 * MBSSID RNR. */
7920 if (include_mld_params &&
7921 (type != WLAN_FC_STYPE_BEACON ||
7922 hapd->iconf->mbssid != ENHANCED_MBSSID_ENABLED))
7923 eid = hostapd_eid_rnr_mlo(hapd, type, eid, &current_len);
7924
Hai Shaloma20dcd72022-02-04 13:43:00 -08007925 if (eid == eid_start + 2)
7926 return eid_start;
7927
7928 return eid;
7929}
7930
Sunil Ravi77d572f2023-01-17 23:58:31 +00007931
7932static bool mbssid_known_bss(unsigned int i, const u8 *known_bss,
7933 size_t known_bss_len)
7934{
7935 if (!known_bss || known_bss_len <= i / 8)
7936 return false;
7937 known_bss = &known_bss[i / 8];
7938 return *known_bss & (u8) (BIT(i % 8));
7939}
7940
7941
Sunil Ravi99c035e2024-07-12 01:42:03 +00007942static size_t hostapd_mbssid_ext_capa(struct hostapd_data *bss,
7943 struct hostapd_data *tx_bss, u8 *buf)
7944{
7945 u8 ext_capa_tx[20], *ext_capa_tx_end, ext_capa[20], *ext_capa_end;
7946 size_t ext_capa_len, ext_capa_tx_len;
7947
7948 ext_capa_tx_end = hostapd_eid_ext_capab(tx_bss, ext_capa_tx,
7949 true);
7950 ext_capa_tx_len = ext_capa_tx_end - ext_capa_tx;
7951 ext_capa_end = hostapd_eid_ext_capab(bss, ext_capa, true);
7952 ext_capa_len = ext_capa_end - ext_capa;
7953 if (ext_capa_tx_len != ext_capa_len ||
7954 os_memcmp(ext_capa_tx, ext_capa, ext_capa_len) != 0) {
7955 os_memcpy(buf, ext_capa, ext_capa_len);
7956 return ext_capa_len;
7957 }
7958
7959 return 0;
7960}
7961
7962
Sunil Ravi77d572f2023-01-17 23:58:31 +00007963static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd,
7964 u32 frame_type, size_t *bss_index,
7965 const u8 *known_bss,
7966 size_t known_bss_len)
7967{
7968 struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007969 size_t len, i;
Sunil Ravi99c035e2024-07-12 01:42:03 +00007970 u8 ext_capa[20];
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007971
7972 /* Element ID: 1 octet
7973 * Length: 1 octet
7974 * MaxBSSID Indicator: 1 octet
7975 * Optional Subelements: vatiable
7976 *
7977 * Total fixed length: 3 octets
7978 *
7979 * 1 octet in len for the MaxBSSID Indicator field.
7980 */
7981 len = 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00007982
7983 for (i = *bss_index; i < hapd->iface->num_bss; i++) {
7984 struct hostapd_data *bss = hapd->iface->bss[i];
7985 const u8 *auth, *rsn = NULL, *rsnx = NULL;
7986 size_t nontx_profile_len, auth_len;
7987 u8 ie_count = 0;
7988
7989 if (!bss || !bss->conf || !bss->started ||
7990 mbssid_known_bss(i, known_bss, known_bss_len))
7991 continue;
7992
7993 /*
7994 * Sublement ID: 1 octet
7995 * Length: 1 octet
7996 * Nontransmitted capabilities: 4 octets
7997 * SSID element: 2 + variable
7998 * Multiple BSSID Index Element: 3 octets (+2 octets in beacons)
7999 * Fixed length = 1 + 1 + 4 + 2 + 3 = 11
8000 */
8001 nontx_profile_len = 11 + bss->conf->ssid.ssid_len;
8002
8003 if (frame_type == WLAN_FC_STYPE_BEACON)
8004 nontx_profile_len += 2;
8005
8006 auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
8007 if (auth) {
8008 rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
8009 if (rsn)
8010 nontx_profile_len += 2 + rsn[1];
8011
8012 rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
8013 if (rsnx)
8014 nontx_profile_len += 2 + rsnx[1];
8015 }
Sunil Ravi99c035e2024-07-12 01:42:03 +00008016
8017 nontx_profile_len += hostapd_mbssid_ext_capa(bss, tx_bss,
8018 ext_capa);
8019
Sunil Ravi77d572f2023-01-17 23:58:31 +00008020 if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
8021 ie_count++;
8022 if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
8023 ie_count++;
8024 if (bss->conf->xrates_supported)
8025 nontx_profile_len += 8;
8026 else if (hapd->conf->xrates_supported)
8027 ie_count++;
8028 if (ie_count)
8029 nontx_profile_len += 4 + ie_count;
8030
8031 if (len + nontx_profile_len > 255)
8032 break;
8033
8034 len += nontx_profile_len;
8035 }
8036
8037 *bss_index = i;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008038
8039 /* Add 2 octets to get the full size of the element */
8040 return len + 2;
Sunil Ravi77d572f2023-01-17 23:58:31 +00008041}
8042
8043
8044size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
8045 u8 *elem_count, const u8 *known_bss,
Sunil Ravi640215c2023-06-28 23:08:09 +00008046 size_t known_bss_len, size_t *rnr_len)
Sunil Ravi77d572f2023-01-17 23:58:31 +00008047{
8048 size_t len = 0, bss_index = 1;
Sunil Ravi7f769292024-07-23 22:21:32 +00008049 bool ap_mld = false;
8050
8051#ifdef CONFIG_IEEE80211BE
8052 ap_mld = hapd->conf->mld_ap;
8053#endif /* CONFIG_IEEE80211BE */
Sunil Ravi77d572f2023-01-17 23:58:31 +00008054
8055 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
8056 (frame_type != WLAN_FC_STYPE_BEACON &&
8057 frame_type != WLAN_FC_STYPE_PROBE_RESP))
8058 return 0;
8059
8060 if (frame_type == WLAN_FC_STYPE_BEACON) {
8061 if (!elem_count) {
8062 wpa_printf(MSG_INFO,
8063 "MBSSID: Insufficient data for Beacon frames");
8064 return 0;
8065 }
8066 *elem_count = 0;
8067 }
8068
8069 while (bss_index < hapd->iface->num_bss) {
Sunil Ravi640215c2023-06-28 23:08:09 +00008070 size_t rnr_count = bss_index;
8071
Sunil Ravi77d572f2023-01-17 23:58:31 +00008072 len += hostapd_eid_mbssid_elem_len(hapd, frame_type,
8073 &bss_index, known_bss,
8074 known_bss_len);
8075
8076 if (frame_type == WLAN_FC_STYPE_BEACON)
8077 *elem_count += 1;
Sunil Ravi640215c2023-06-28 23:08:09 +00008078 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len) {
8079 size_t rnr_cur_len = 0;
8080 struct mbssid_ie_profiles skip_profiles = {
8081 rnr_count, bss_index
8082 };
8083
8084 *rnr_len += hostapd_eid_rnr_iface_len(
8085 hapd, hostapd_mbssid_get_tx_bss(hapd),
Sunil Ravi7f769292024-07-23 22:21:32 +00008086 &rnr_cur_len, &skip_profiles, ap_mld);
Sunil Ravi640215c2023-06-28 23:08:09 +00008087 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00008088 }
Sunil Ravi640215c2023-06-28 23:08:09 +00008089
8090 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len)
Sunil Ravi7f769292024-07-23 22:21:32 +00008091 *rnr_len += hostapd_eid_rnr_len(hapd, frame_type, false);
Sunil Ravi640215c2023-06-28 23:08:09 +00008092
Sunil Ravi77d572f2023-01-17 23:58:31 +00008093 return len;
8094}
8095
8096
8097static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end,
8098 u32 frame_type, u8 max_bssid_indicator,
8099 size_t *bss_index, u8 elem_count,
8100 const u8 *known_bss, size_t known_bss_len)
8101{
8102 struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
8103 size_t i;
8104 u8 *eid_len_offset, *max_bssid_indicator_offset;
8105
8106 *eid++ = WLAN_EID_MULTIPLE_BSSID;
8107 eid_len_offset = eid++;
8108 max_bssid_indicator_offset = eid++;
8109
8110 for (i = *bss_index; i < hapd->iface->num_bss; i++) {
8111 struct hostapd_data *bss = hapd->iface->bss[i];
8112 struct hostapd_bss_config *conf;
8113 u8 *eid_len_pos, *nontx_bss_start = eid;
8114 const u8 *auth, *rsn = NULL, *rsnx = NULL;
8115 u8 ie_count = 0, non_inherit_ie[3];
8116 size_t auth_len = 0;
8117 u16 capab_info;
8118
8119 if (!bss || !bss->conf || !bss->started ||
8120 mbssid_known_bss(i, known_bss, known_bss_len))
8121 continue;
8122 conf = bss->conf;
8123
8124 *eid++ = WLAN_MBSSID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE;
8125 eid_len_pos = eid++;
8126
8127 capab_info = hostapd_own_capab_info(bss);
8128 *eid++ = WLAN_EID_NONTRANSMITTED_BSSID_CAPA;
8129 *eid++ = sizeof(capab_info);
8130 WPA_PUT_LE16(eid, capab_info);
8131 eid += sizeof(capab_info);
8132
8133 *eid++ = WLAN_EID_SSID;
8134 *eid++ = conf->ssid.ssid_len;
8135 os_memcpy(eid, conf->ssid.ssid, conf->ssid.ssid_len);
8136 eid += conf->ssid.ssid_len;
8137
8138 *eid++ = WLAN_EID_MULTIPLE_BSSID_INDEX;
8139 if (frame_type == WLAN_FC_STYPE_BEACON) {
8140 *eid++ = 3;
8141 *eid++ = i; /* BSSID Index */
8142 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
8143 (conf->dtim_period % elem_count))
8144 conf->dtim_period = elem_count;
8145 *eid++ = conf->dtim_period;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008146 /* The driver is expected to update the DTIM Count
8147 * field for each BSS that corresponds to a
8148 * nontransmitted BSSID. The value is initialized to
8149 * 0 here so that the DTIM count would be somewhat
8150 * functional even if the driver were not to update
8151 * this. */
8152 *eid++ = 0; /* DTIM Count */
Sunil Ravi77d572f2023-01-17 23:58:31 +00008153 } else {
8154 /* Probe Request frame does not include DTIM Period and
8155 * DTIM Count fields. */
8156 *eid++ = 1;
8157 *eid++ = i; /* BSSID Index */
8158 }
8159
8160 auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
8161 if (auth) {
8162 rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
8163 if (rsn) {
8164 os_memcpy(eid, rsn, 2 + rsn[1]);
8165 eid += 2 + rsn[1];
8166 }
8167
8168 rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
8169 if (rsnx) {
8170 os_memcpy(eid, rsnx, 2 + rsnx[1]);
8171 eid += 2 + rsnx[1];
8172 }
8173 }
Sunil Ravi99c035e2024-07-12 01:42:03 +00008174
8175 eid += hostapd_mbssid_ext_capa(bss, tx_bss, eid);
8176
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008177 /* List of Element ID values in increasing order */
Sunil Ravi77d572f2023-01-17 23:58:31 +00008178 if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
8179 non_inherit_ie[ie_count++] = WLAN_EID_RSN;
Sunil Ravi77d572f2023-01-17 23:58:31 +00008180 if (hapd->conf->xrates_supported &&
8181 !bss->conf->xrates_supported)
8182 non_inherit_ie[ie_count++] = WLAN_EID_EXT_SUPP_RATES;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008183 if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
8184 non_inherit_ie[ie_count++] = WLAN_EID_RSNX;
Sunil Ravi77d572f2023-01-17 23:58:31 +00008185 if (ie_count) {
8186 *eid++ = WLAN_EID_EXTENSION;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008187 *eid++ = 2 + ie_count + 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00008188 *eid++ = WLAN_EID_EXT_NON_INHERITANCE;
8189 *eid++ = ie_count;
8190 os_memcpy(eid, non_inherit_ie, ie_count);
8191 eid += ie_count;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008192 *eid++ = 0; /* No Element ID Extension List */
Sunil Ravi77d572f2023-01-17 23:58:31 +00008193 }
8194
8195 *eid_len_pos = (eid - eid_len_pos) - 1;
8196
8197 if (((eid - eid_len_offset) - 1) > 255) {
8198 eid = nontx_bss_start;
8199 break;
8200 }
8201 }
8202
8203 *bss_index = i;
8204 *max_bssid_indicator_offset = max_bssid_indicator;
8205 if (*max_bssid_indicator_offset < 1)
8206 *max_bssid_indicator_offset = 1;
8207 *eid_len_offset = (eid - eid_len_offset) - 1;
8208 return eid;
8209}
8210
8211
8212u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
8213 unsigned int frame_stype, u8 elem_count,
8214 u8 **elem_offset,
Sunil Ravi640215c2023-06-28 23:08:09 +00008215 const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid,
8216 u8 *rnr_count, u8 **rnr_offset, size_t rnr_len)
Sunil Ravi77d572f2023-01-17 23:58:31 +00008217{
Sunil Ravi640215c2023-06-28 23:08:09 +00008218 size_t bss_index = 1, cur_len = 0;
8219 u8 elem_index = 0, *rnr_start_eid = rnr_eid;
Sunil Ravi7f769292024-07-23 22:21:32 +00008220 bool add_rnr, ap_mld = false;
8221
8222#ifdef CONFIG_IEEE80211BE
8223 ap_mld = hapd->conf->mld_ap;
8224#endif /* CONFIG_IEEE80211BE */
Sunil Ravi77d572f2023-01-17 23:58:31 +00008225
8226 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
8227 (frame_stype != WLAN_FC_STYPE_BEACON &&
8228 frame_stype != WLAN_FC_STYPE_PROBE_RESP))
8229 return eid;
8230
8231 if (frame_stype == WLAN_FC_STYPE_BEACON && !elem_offset) {
8232 wpa_printf(MSG_INFO,
8233 "MBSSID: Insufficient data for Beacon frames");
8234 return eid;
8235 }
8236
Sunil Ravi640215c2023-06-28 23:08:09 +00008237 add_rnr = hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
8238 frame_stype == WLAN_FC_STYPE_BEACON &&
8239 rnr_eid && rnr_count && rnr_offset && rnr_len;
8240
Sunil Ravi77d572f2023-01-17 23:58:31 +00008241 while (bss_index < hapd->iface->num_bss) {
Sunil Ravi640215c2023-06-28 23:08:09 +00008242 unsigned int rnr_start_count = bss_index;
8243
Sunil Ravi77d572f2023-01-17 23:58:31 +00008244 if (frame_stype == WLAN_FC_STYPE_BEACON) {
8245 if (elem_index == elem_count) {
8246 wpa_printf(MSG_WARNING,
8247 "MBSSID: Larger number of elements than there is room in the provided array");
8248 break;
8249 }
8250
8251 elem_offset[elem_index] = eid;
8252 elem_index = elem_index + 1;
8253 }
8254 eid = hostapd_eid_mbssid_elem(hapd, eid, end, frame_stype,
8255 hostapd_max_bssid_indicator(hapd),
8256 &bss_index, elem_count,
8257 known_bss, known_bss_len);
Sunil Ravi640215c2023-06-28 23:08:09 +00008258
8259 if (add_rnr) {
8260 struct mbssid_ie_profiles skip_profiles = {
8261 rnr_start_count, bss_index
8262 };
8263
8264 rnr_offset[*rnr_count] = rnr_eid;
8265 *rnr_count = *rnr_count + 1;
8266 cur_len = 0;
8267 rnr_eid = hostapd_eid_rnr_iface(
8268 hapd, hostapd_mbssid_get_tx_bss(hapd),
Sunil Ravi7f769292024-07-23 22:21:32 +00008269 rnr_eid, &cur_len, &skip_profiles, ap_mld);
Sunil Ravi640215c2023-06-28 23:08:09 +00008270 }
8271 }
8272
8273 if (add_rnr && (size_t) (rnr_eid - rnr_start_eid) < rnr_len) {
8274 rnr_offset[*rnr_count] = rnr_eid;
8275 *rnr_count = *rnr_count + 1;
8276 cur_len = 0;
8277
8278 if (hapd->conf->rnr)
8279 rnr_eid = hostapd_eid_nr_db(hapd, rnr_eid, &cur_len);
8280 if (get_colocation_mode(hapd) == COLOCATED_LOWER_BAND)
Sunil Ravi7f769292024-07-23 22:21:32 +00008281 rnr_eid = hostapd_eid_rnr_colocation(hapd, rnr_eid,
8282 &cur_len);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008283 }
8284
8285 return eid;
8286}
8287
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008288#endif /* CONFIG_NATIVE_WINDOWS */