blob: 8b8c1f09584050263f11841cae9bde472b095793 [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 Ravi72e01222024-03-09 01:25:43 +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
91u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
92{
93 u8 multi_ap_val = 0;
94
95 if (!hapd->conf->multi_ap)
96 return eid;
97 if (hapd->conf->multi_ap & BACKHAUL_BSS)
98 multi_ap_val |= MULTI_AP_BACKHAUL_BSS;
99 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
100 multi_ap_val |= MULTI_AP_FRONTHAUL_BSS;
101
102 return eid + add_multi_ap_ie(eid, 9, multi_ap_val);
103}
104
105
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700106u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
107{
108 u8 *pos = eid;
109 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700110 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700111
112 if (hapd->iface->current_rates == NULL)
113 return eid;
114
115 *pos++ = WLAN_EID_SUPP_RATES;
116 num = hapd->iface->num_rates;
117 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
118 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800119 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
120 num++;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000121#ifdef CONFIG_IEEE80211AX
122 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
123 num++;
124#endif /* CONFIG_IEEE80211AX */
125 h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
Hai Shalomfdcde762020-04-02 11:19:20 -0700126 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +0000127 hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700128 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
129 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700130 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700131 if (num > 8) {
132 /* rest of the rates are encoded in Extended supported
133 * rates element */
134 num = 8;
135 }
136
137 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700138 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
139 i++) {
140 count++;
141 *pos = hapd->iface->current_rates[i].rate / 5;
142 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
143 *pos |= 0x80;
144 pos++;
145 }
146
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800147 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
148 count++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700149 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800150 }
151
152 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
153 count++;
154 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
155 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700156
Sunil Ravi77d572f2023-01-17 23:58:31 +0000157#ifdef CONFIG_IEEE80211AX
158 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he && count < 8) {
159 count++;
160 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY;
161 }
162#endif /* CONFIG_IEEE80211AX */
163
Hai Shalomfdcde762020-04-02 11:19:20 -0700164 if (h2e_required && count < 8) {
Hai Shalomc3565922019-10-28 11:58:20 -0700165 count++;
166 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
167 }
168
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700169 return pos;
170}
171
172
173u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
174{
175 u8 *pos = eid;
176 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700177 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700178
Sunil Ravi77d572f2023-01-17 23:58:31 +0000179 hapd->conf->xrates_supported = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700180 if (hapd->iface->current_rates == NULL)
181 return eid;
182
183 num = hapd->iface->num_rates;
184 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
185 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800186 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
187 num++;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000188#ifdef CONFIG_IEEE80211AX
189 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
190 num++;
191#endif /* CONFIG_IEEE80211AX */
192 h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
Hai Shalomfdcde762020-04-02 11:19:20 -0700193 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +0000194 hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700195 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
196 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700197 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700198 if (num <= 8)
199 return eid;
200 num -= 8;
201
202 *pos++ = WLAN_EID_EXT_SUPP_RATES;
203 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700204 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
205 i++) {
206 count++;
207 if (count <= 8)
208 continue; /* already in SuppRates IE */
209 *pos = hapd->iface->current_rates[i].rate / 5;
210 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
211 *pos |= 0x80;
212 pos++;
213 }
214
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800215 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
216 count++;
217 if (count > 8)
218 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
219 }
220
221 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
222 count++;
223 if (count > 8)
224 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
225 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700226
Sunil Ravi77d572f2023-01-17 23:58:31 +0000227#ifdef CONFIG_IEEE80211AX
228 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he) {
229 count++;
230 if (count > 8)
231 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY;
232 }
233#endif /* CONFIG_IEEE80211AX */
234
Hai Shalomfdcde762020-04-02 11:19:20 -0700235 if (h2e_required) {
Hai Shalomc3565922019-10-28 11:58:20 -0700236 count++;
237 if (count > 8)
238 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
239 }
240
Sunil Ravi77d572f2023-01-17 23:58:31 +0000241 hapd->conf->xrates_supported = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700242 return pos;
243}
244
245
Hai Shalomfdcde762020-04-02 11:19:20 -0700246u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
247 size_t len)
248{
249 size_t i;
250
251 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
252 if (hapd->conf->radio_measurements[i])
253 break;
254 }
255
256 if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
257 return eid;
258
259 *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
260 *eid++ = RRM_CAPABILITIES_IE_LEN;
261 os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
262
263 return eid + RRM_CAPABILITIES_IE_LEN;
264}
265
266
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700267u16 hostapd_own_capab_info(struct hostapd_data *hapd)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700268{
269 int capab = WLAN_CAPABILITY_ESS;
Hai Shalomfdcde762020-04-02 11:19:20 -0700270 int privacy = 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800271 int dfs;
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700272 int i;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800273
274 /* Check if any of configured channels require DFS */
275 dfs = hostapd_is_dfs_required(hapd->iface);
276 if (dfs < 0) {
277 wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
278 dfs);
279 dfs = 0;
280 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700281
282 if (hapd->iface->num_sta_no_short_preamble == 0 &&
283 hapd->iconf->preamble == SHORT_PREAMBLE)
284 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
285
Hai Shalomfdcde762020-04-02 11:19:20 -0700286#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700287 privacy = hapd->conf->ssid.wep.keys_set;
288
289 if (hapd->conf->ieee802_1x &&
290 (hapd->conf->default_wep_key_len ||
291 hapd->conf->individual_wep_key_len))
292 privacy = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -0700293#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700294
295 if (hapd->conf->wpa)
296 privacy = 1;
297
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800298#ifdef CONFIG_HS20
299 if (hapd->conf->osen)
300 privacy = 1;
301#endif /* CONFIG_HS20 */
302
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700303 if (privacy)
304 capab |= WLAN_CAPABILITY_PRIVACY;
305
306 if (hapd->iface->current_mode &&
307 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
308 hapd->iface->num_sta_no_short_slot_time == 0)
309 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
310
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800311 /*
312 * Currently, Spectrum Management capability bit is set when directly
313 * requested in configuration by spectrum_mgmt_required or when AP is
314 * running on DFS channel.
315 * TODO: Also consider driver support for TPC to set Spectrum Mgmt bit
316 */
317 if (hapd->iface->current_mode &&
318 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
319 (hapd->iconf->spectrum_mgmt_required || dfs))
320 capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
321
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700322 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
323 if (hapd->conf->radio_measurements[i]) {
324 capab |= IEEE80211_CAP_RRM;
325 break;
326 }
327 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800328
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700329 return capab;
330}
331
332
Hai Shalomfdcde762020-04-02 11:19:20 -0700333#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800334#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700335static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
336 u16 auth_transaction, const u8 *challenge,
337 int iswep)
338{
339 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
340 HOSTAPD_LEVEL_DEBUG,
341 "authentication (shared key, transaction %d)",
342 auth_transaction);
343
344 if (auth_transaction == 1) {
345 if (!sta->challenge) {
346 /* Generate a pseudo-random challenge */
347 u8 key[8];
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800348
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700349 sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
350 if (sta->challenge == NULL)
351 return WLAN_STATUS_UNSPECIFIED_FAILURE;
352
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800353 if (os_get_random(key, sizeof(key)) < 0) {
354 os_free(sta->challenge);
355 sta->challenge = NULL;
356 return WLAN_STATUS_UNSPECIFIED_FAILURE;
357 }
358
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700359 rc4_skip(key, sizeof(key), 0,
360 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
361 }
362 return 0;
363 }
364
365 if (auth_transaction != 3)
366 return WLAN_STATUS_UNSPECIFIED_FAILURE;
367
368 /* Transaction 3 */
369 if (!iswep || !sta->challenge || !challenge ||
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700370 os_memcmp_const(sta->challenge, challenge,
371 WLAN_AUTH_CHALLENGE_LEN)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700372 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
373 HOSTAPD_LEVEL_INFO,
374 "shared key authentication - invalid "
375 "challenge-response");
376 return WLAN_STATUS_CHALLENGE_FAIL;
377 }
378
379 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
380 HOSTAPD_LEVEL_DEBUG,
381 "authentication OK (shared key)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700382 sta->flags |= WLAN_STA_AUTH;
383 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700384 os_free(sta->challenge);
385 sta->challenge = NULL;
386
387 return 0;
388}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800389#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700390#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700391
392
Hai Shalomfdcde762020-04-02 11:19:20 -0700393static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800394 const u8 *dst, const u8 *bssid,
395 u16 auth_alg, u16 auth_transaction, u16 resp,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700396 const u8 *ies, size_t ies_len, const char *dbg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700397{
398 struct ieee80211_mgmt *reply;
399 u8 *buf;
400 size_t rlen;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800401 int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000402 const u8 *sa = hapd->own_addr;
403 struct wpabuf *ml_resp = NULL;
404
405#ifdef CONFIG_IEEE80211BE
406 /*
407 * Once a non-AP MLD is added to the driver, the addressing should use
408 * the MLD MAC address. Thus, use the MLD address instead of translating
409 * the addresses.
410 */
Sunil Ravi72e01222024-03-09 01:25:43 +0000411 if (ap_sta_is_mld(hapd, sta)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000412 sa = hapd->mld_addr;
413
414 ml_resp = hostapd_ml_auth_resp(hapd);
415 if (!ml_resp)
416 return -1;
417 }
418#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700419
420 rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000421 if (ml_resp)
422 rlen += wpabuf_len(ml_resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700423 buf = os_zalloc(rlen);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000424 if (!buf) {
425 wpabuf_free(ml_resp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800426 return -1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000427 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700428
429 reply = (struct ieee80211_mgmt *) buf;
430 reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
431 WLAN_FC_STYPE_AUTH);
432 os_memcpy(reply->da, dst, ETH_ALEN);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000433 os_memcpy(reply->sa, sa, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700434 os_memcpy(reply->bssid, bssid, ETH_ALEN);
435
436 reply->u.auth.auth_alg = host_to_le16(auth_alg);
437 reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
438 reply->u.auth.status_code = host_to_le16(resp);
439
440 if (ies && ies_len)
441 os_memcpy(reply->u.auth.variable, ies, ies_len);
442
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000443#ifdef CONFIG_IEEE80211BE
444 if (ml_resp)
445 os_memcpy(reply->u.auth.variable + ies_len,
446 wpabuf_head(ml_resp), wpabuf_len(ml_resp));
447
448 wpabuf_free(ml_resp);
449#endif /* CONFIG_IEEE80211BE */
450
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700451 wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700452 " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700453 MAC2STR(dst), auth_alg, auth_transaction,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700454 resp, (unsigned long) ies_len, dbg);
Hai Shalomfdcde762020-04-02 11:19:20 -0700455#ifdef CONFIG_TESTING_OPTIONS
456#ifdef CONFIG_SAE
457 if (hapd->conf->sae_confirm_immediate == 2 &&
458 auth_alg == WLAN_AUTH_SAE) {
459 if (auth_transaction == 1 && sta &&
460 (resp == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -0700461 resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
462 resp == WLAN_STATUS_SAE_PK)) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700463 wpa_printf(MSG_DEBUG,
464 "TESTING: Postpone SAE Commit transmission until Confirm is ready");
465 os_free(sta->sae_postponed_commit);
466 sta->sae_postponed_commit = buf;
467 sta->sae_postponed_commit_len = rlen;
468 return WLAN_STATUS_SUCCESS;
469 }
470
471 if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
472 wpa_printf(MSG_DEBUG,
473 "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
474 if (hostapd_drv_send_mlme(hapd,
475 sta->sae_postponed_commit,
476 sta->sae_postponed_commit_len,
477 0, NULL, 0, 0) < 0)
478 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
479 os_free(sta->sae_postponed_commit);
480 sta->sae_postponed_commit = NULL;
481 sta->sae_postponed_commit_len = 0;
482 }
483 }
484#endif /* CONFIG_SAE */
485#endif /* CONFIG_TESTING_OPTIONS */
486 if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800487 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
488 else
489 reply_res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700490
491 os_free(buf);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800492
493 return reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700494}
495
496
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800497#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700498static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
499 u16 auth_transaction, u16 status,
500 const u8 *ies, size_t ies_len)
501{
502 struct hostapd_data *hapd = ctx;
503 struct sta_info *sta;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800504 int reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700505
Hai Shalomfdcde762020-04-02 11:19:20 -0700506 reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700507 auth_transaction, status, ies, ies_len,
508 "auth-ft-finish");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700509
510 sta = ap_get_sta(hapd, dst);
511 if (sta == NULL)
512 return;
513
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800514 if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
515 status != WLAN_STATUS_SUCCESS)) {
516 hostapd_drv_sta_remove(hapd, sta->addr);
517 sta->added_unassoc = 0;
518 return;
519 }
520
521 if (status != WLAN_STATUS_SUCCESS)
522 return;
523
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700524 hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
525 HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
526 sta->flags |= WLAN_STA_AUTH;
527 mlme_authenticate_indication(hapd, sta);
528}
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800529#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700530
531
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800532#ifdef CONFIG_SAE
533
Roshan Pius3a1667e2018-07-03 15:17:14 -0700534static void sae_set_state(struct sta_info *sta, enum sae_state state,
535 const char *reason)
536{
537 wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
538 sae_state_txt(sta->sae->state), sae_state_txt(state),
539 MAC2STR(sta->addr), reason);
540 sta->sae->state = state;
541}
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800542
543
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000544const char * sae_get_password(struct hostapd_data *hapd,
545 struct sta_info *sta,
546 const char *rx_id,
547 struct sae_password_entry **pw_entry,
548 struct sae_pt **s_pt,
549 const struct sae_pk **s_pk)
Hai Shalom60840252021-02-19 19:02:11 -0800550{
551 const char *password = NULL;
552 struct sae_password_entry *pw;
553 struct sae_pt *pt = NULL;
554 const struct sae_pk *pk = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -0700555 struct hostapd_sta_wpa_psk_short *psk = NULL;
Hai Shalom60840252021-02-19 19:02:11 -0800556
557 for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
558 if (!is_broadcast_ether_addr(pw->peer_addr) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000559 (!sta ||
Sunil Ravi72e01222024-03-09 01:25:43 +0000560 !ether_addr_equal(pw->peer_addr, sta->addr)))
Hai Shalom60840252021-02-19 19:02:11 -0800561 continue;
562 if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
563 continue;
564 if (rx_id && pw->identifier &&
565 os_strcmp(rx_id, pw->identifier) != 0)
566 continue;
567 password = pw->password;
568 pt = pw->pt;
569 if (!(hapd->conf->mesh & MESH_ENABLED))
570 pk = pw->pk;
571 break;
572 }
573 if (!password) {
574 password = hapd->conf->ssid.wpa_passphrase;
575 pt = hapd->conf->ssid.pt;
576 }
577
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000578 if (!password && sta) {
Sunil Ravia04bd252022-05-02 22:54:18 -0700579 for (psk = sta->psk; psk; psk = psk->next) {
580 if (psk->is_passphrase) {
581 password = psk->passphrase;
582 break;
583 }
584 }
585 }
586
Hai Shalom60840252021-02-19 19:02:11 -0800587 if (pw_entry)
588 *pw_entry = pw;
589 if (s_pt)
590 *s_pt = pt;
591 if (s_pk)
592 *s_pk = pk;
593
594 return password;
595}
596
597
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800598static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
Hai Shalomc3565922019-10-28 11:58:20 -0700599 struct sta_info *sta, int update,
600 int status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800601{
602 struct wpabuf *buf;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700603 const char *password = NULL;
604 struct sae_password_entry *pw;
605 const char *rx_id = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700606 int use_pt = 0;
607 struct sae_pt *pt = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700608 const struct sae_pk *pk = NULL;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000609 const u8 *own_addr = hapd->own_addr;
610
611#ifdef CONFIG_IEEE80211BE
Sunil Ravi72e01222024-03-09 01:25:43 +0000612 if (ap_sta_is_mld(hapd, sta))
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000613 own_addr = hapd->mld_addr;
614#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800615
Hai Shalomc3565922019-10-28 11:58:20 -0700616 if (sta->sae->tmp) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700617 rx_id = sta->sae->tmp->pw_id;
Hai Shalom899fcc72020-10-19 14:38:18 -0700618 use_pt = sta->sae->h2e;
619#ifdef CONFIG_SAE_PK
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000620 os_memcpy(sta->sae->tmp->own_addr, own_addr, ETH_ALEN);
Hai Shalom899fcc72020-10-19 14:38:18 -0700621 os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
622#endif /* CONFIG_SAE_PK */
Hai Shalomc3565922019-10-28 11:58:20 -0700623 }
624
Sunil Ravi77d572f2023-01-17 23:58:31 +0000625 if (rx_id && hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
Hai Shalomfdcde762020-04-02 11:19:20 -0700626 use_pt = 1;
627 else if (status_code == WLAN_STATUS_SUCCESS)
Hai Shalomc3565922019-10-28 11:58:20 -0700628 use_pt = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700629 else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
630 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomc3565922019-10-28 11:58:20 -0700631 use_pt = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700632
Hai Shalom60840252021-02-19 19:02:11 -0800633 password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk);
Hai Shalomc3565922019-10-28 11:58:20 -0700634 if (!password || (use_pt && !pt)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800635 wpa_printf(MSG_DEBUG, "SAE: No password available");
636 return NULL;
637 }
638
Hai Shalomc3565922019-10-28 11:58:20 -0700639 if (update && use_pt &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000640 sae_prepare_commit_pt(sta->sae, pt, own_addr, sta->addr,
Hai Shalom899fcc72020-10-19 14:38:18 -0700641 NULL, pk) < 0)
Hai Shalomc3565922019-10-28 11:58:20 -0700642 return NULL;
643
644 if (update && !use_pt &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000645 sae_prepare_commit(own_addr, sta->addr,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800646 (u8 *) password, os_strlen(password),
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800647 sta->sae) < 0) {
648 wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
649 return NULL;
650 }
651
Hai Shalom021b0b52019-04-10 11:17:58 -0700652 if (pw && pw->vlan_id) {
653 if (!sta->sae->tmp) {
654 wpa_printf(MSG_INFO,
655 "SAE: No temporary data allocated - cannot store VLAN ID");
656 return NULL;
657 }
658 sta->sae->tmp->vlan_id = pw->vlan_id;
659 }
660
Roshan Pius3a1667e2018-07-03 15:17:14 -0700661 buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
662 (rx_id ? 3 + os_strlen(rx_id) : 0));
Hai Shalomfdcde762020-04-02 11:19:20 -0700663 if (buf &&
664 sae_write_commit(sta->sae, buf, sta->sae->tmp ?
665 sta->sae->tmp->anti_clogging_token : NULL,
666 rx_id) < 0) {
667 wpabuf_free(buf);
668 buf = NULL;
669 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800670
671 return buf;
672}
673
674
675static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
676 struct sta_info *sta)
677{
678 struct wpabuf *buf;
679
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800680 buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800681 if (buf == NULL)
682 return NULL;
683
Hai Shalom899fcc72020-10-19 14:38:18 -0700684#ifdef CONFIG_SAE_PK
685#ifdef CONFIG_TESTING_OPTIONS
686 if (sta->sae->tmp)
687 sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
688#endif /* CONFIG_TESTING_OPTIONS */
689#endif /* CONFIG_SAE_PK */
690
691 if (sae_write_confirm(sta->sae, buf) < 0) {
692 wpabuf_free(buf);
693 return NULL;
694 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800695
696 return buf;
697}
698
699
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800700static int auth_sae_send_commit(struct hostapd_data *hapd,
701 struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700702 const u8 *bssid, int update, int status_code)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800703{
704 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800705 int reply_res;
Hai Shalomc3565922019-10-28 11:58:20 -0700706 u16 status;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800707
Hai Shalomc3565922019-10-28 11:58:20 -0700708 data = auth_build_sae_commit(hapd, sta, update, status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700709 if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
710 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800711 if (data == NULL)
712 return WLAN_STATUS_UNSPECIFIED_FAILURE;
713
Hai Shalom899fcc72020-10-19 14:38:18 -0700714 if (sta->sae->tmp && sta->sae->pk)
715 status = WLAN_STATUS_SAE_PK;
716 else if (sta->sae->tmp && sta->sae->h2e)
717 status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
718 else
719 status = WLAN_STATUS_SUCCESS;
720#ifdef CONFIG_TESTING_OPTIONS
721 if (hapd->conf->sae_commit_status >= 0 &&
722 hapd->conf->sae_commit_status != status) {
723 wpa_printf(MSG_INFO,
724 "TESTING: Override SAE commit status code %u --> %d",
725 status, hapd->conf->sae_commit_status);
726 status = hapd->conf->sae_commit_status;
727 }
728#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomfdcde762020-04-02 11:19:20 -0700729 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
730 WLAN_AUTH_SAE, 1,
Hai Shalomc3565922019-10-28 11:58:20 -0700731 status, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700732 wpabuf_len(data), "sae-send-commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800733
734 wpabuf_free(data);
735
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800736 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800737}
738
739
740static int auth_sae_send_confirm(struct hostapd_data *hapd,
741 struct sta_info *sta,
742 const u8 *bssid)
743{
744 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800745 int reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800746
747 data = auth_build_sae_confirm(hapd, sta);
748 if (data == NULL)
749 return WLAN_STATUS_UNSPECIFIED_FAILURE;
750
Hai Shalomfdcde762020-04-02 11:19:20 -0700751 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
752 WLAN_AUTH_SAE, 2,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800753 WLAN_STATUS_SUCCESS, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700754 wpabuf_len(data), "sae-send-confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800755
756 wpabuf_free(data);
757
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800758 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800759}
760
Hai Shaloma20dcd72022-02-04 13:43:00 -0800761#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800762
Hai Shaloma20dcd72022-02-04 13:43:00 -0800763
764#if defined(CONFIG_SAE) || defined(CONFIG_PASN)
765
766static int use_anti_clogging(struct hostapd_data *hapd)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800767{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800768 struct sta_info *sta;
769 unsigned int open = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800770
Hai Shaloma20dcd72022-02-04 13:43:00 -0800771 if (hapd->conf->anti_clogging_threshold == 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800772 return 1;
773
774 for (sta = hapd->sta_list; sta; sta = sta->next) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800775#ifdef CONFIG_SAE
776 if (sta->sae &&
777 (sta->sae->state == SAE_COMMITTED ||
778 sta->sae->state == SAE_CONFIRMED))
779 open++;
780#endif /* CONFIG_SAE */
781#ifdef CONFIG_PASN
782 if (sta->pasn && sta->pasn->ecdh)
783 open++;
784#endif /* CONFIG_PASN */
785 if (open >= hapd->conf->anti_clogging_threshold)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800786 return 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800787 }
788
Hai Shaloma20dcd72022-02-04 13:43:00 -0800789#ifdef CONFIG_SAE
Hai Shalom021b0b52019-04-10 11:17:58 -0700790 /* In addition to already existing open SAE sessions, check whether
791 * there are enough pending commit messages in the processing queue to
792 * potentially result in too many open sessions. */
793 if (open + dl_list_len(&hapd->sae_commit_queue) >=
Hai Shaloma20dcd72022-02-04 13:43:00 -0800794 hapd->conf->anti_clogging_threshold)
Hai Shalom021b0b52019-04-10 11:17:58 -0700795 return 1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800796#endif /* CONFIG_SAE */
Hai Shalom021b0b52019-04-10 11:17:58 -0700797
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800798 return 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800799}
800
Hai Shaloma20dcd72022-02-04 13:43:00 -0800801#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
802
803
804#ifdef CONFIG_SAE
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800805
Roshan Pius3a1667e2018-07-03 15:17:14 -0700806static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800807{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700808 if (sta->sae->sync > hapd->conf->sae_sync) {
809 sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800810 sta->sae->sync = 0;
811 return -1;
812 }
813 return 0;
814}
815
816
817static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
818{
819 struct hostapd_data *hapd = eloop_ctx;
820 struct sta_info *sta = eloop_data;
821 int ret;
822
Roshan Pius3a1667e2018-07-03 15:17:14 -0700823 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800824 return;
825 sta->sae->sync++;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700826 wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700827 " (sync=%d state=%s)",
828 MAC2STR(sta->addr), sta->sae->sync,
829 sae_state_txt(sta->sae->state));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800830
831 switch (sta->sae->state) {
832 case SAE_COMMITTED:
Hai Shalomc3565922019-10-28 11:58:20 -0700833 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800834 eloop_register_timeout(0,
835 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800836 auth_sae_retransmit_timer, hapd, sta);
837 break;
838 case SAE_CONFIRMED:
839 ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800840 eloop_register_timeout(0,
841 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800842 auth_sae_retransmit_timer, hapd, sta);
843 break;
844 default:
845 ret = -1;
846 break;
847 }
848
849 if (ret != WLAN_STATUS_SUCCESS)
850 wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
851}
852
853
854void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
855{
856 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
857}
858
859
860static void sae_set_retransmit_timer(struct hostapd_data *hapd,
861 struct sta_info *sta)
862{
863 if (!(hapd->conf->mesh & MESH_ENABLED))
864 return;
865
866 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800867 eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800868 auth_sae_retransmit_timer, hapd, sta);
869}
870
871
Hai Shalom5f92bc92019-04-18 11:54:11 -0700872static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
873 struct sta_info *sta, u16 status)
874{
875 struct external_auth params;
876
877 os_memset(&params, 0, sizeof(params));
878 params.status = status;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000879
880#ifdef CONFIG_IEEE80211BE
Sunil Ravi72e01222024-03-09 01:25:43 +0000881 if (ap_sta_is_mld(hapd, sta))
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000882 params.bssid =
883 sta->mld_info.links[sta->mld_assoc_link_id].peer_addr;
884#endif /* CONFIG_IEEE80211BE */
885 if (!params.bssid)
886 params.bssid = sta->addr;
887
Hai Shalom81f62d82019-07-22 12:10:00 -0700888 if (status == WLAN_STATUS_SUCCESS && sta->sae &&
889 !hapd->conf->disable_pmksa_caching)
Hai Shalom5f92bc92019-04-18 11:54:11 -0700890 params.pmkid = sta->sae->pmkid;
891
892 hostapd_drv_send_external_auth_status(hapd, &params);
893}
894
895
Dmitry Shmidte4663042016-04-04 10:07:49 -0700896void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
897{
Hai Shalom021b0b52019-04-10 11:17:58 -0700898#ifndef CONFIG_NO_VLAN
899 struct vlan_description vlan_desc;
900
901 if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
902 wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
903 " to VLAN ID %d",
904 MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
905
Sunil Ravi72e01222024-03-09 01:25:43 +0000906 if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
907 os_memset(&vlan_desc, 0, sizeof(vlan_desc));
908 vlan_desc.notempty = 1;
909 vlan_desc.untagged = sta->sae->tmp->vlan_id;
910 if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
911 wpa_printf(MSG_INFO,
912 "Invalid VLAN ID %d in sae_password",
913 sta->sae->tmp->vlan_id);
914 return;
915 }
Hai Shalom021b0b52019-04-10 11:17:58 -0700916
Sunil Ravi72e01222024-03-09 01:25:43 +0000917 if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
918 ap_sta_bind_vlan(hapd, sta) < 0) {
919 wpa_printf(MSG_INFO,
920 "Failed to assign VLAN ID %d from sae_password to "
921 MACSTR, sta->sae->tmp->vlan_id,
922 MAC2STR(sta->addr));
923 return;
924 }
925 } else {
926 sta->vlan_id = sta->sae->tmp->vlan_id;
Hai Shalom021b0b52019-04-10 11:17:58 -0700927 }
928 }
929#endif /* CONFIG_NO_VLAN */
930
Dmitry Shmidte4663042016-04-04 10:07:49 -0700931 sta->flags |= WLAN_STA_AUTH;
932 sta->auth_alg = WLAN_AUTH_SAE;
933 mlme_authenticate_indication(hapd, sta);
934 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700935 sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
Hai Shalomfdcde762020-04-02 11:19:20 -0700936 crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
937 sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
938 sta->sae->peer_commit_scalar = NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -0700939 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
Sunil Ravi89eba102022-09-13 21:04:37 -0700940 sta->sae->pmk, sta->sae->pmk_len,
941 sta->sae->pmkid, sta->sae->akmp);
Hai Shalom5f92bc92019-04-18 11:54:11 -0700942 sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
Dmitry Shmidte4663042016-04-04 10:07:49 -0700943}
944
945
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800946static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700947 const u8 *bssid, u16 auth_transaction, u16 status_code,
948 int allow_reuse, int *sta_removed)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800949{
950 int ret;
951
Hai Shalom5f92bc92019-04-18 11:54:11 -0700952 *sta_removed = 0;
953
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800954 if (auth_transaction != 1 && auth_transaction != 2)
955 return WLAN_STATUS_UNSPECIFIED_FAILURE;
956
Roshan Pius3a1667e2018-07-03 15:17:14 -0700957 wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
958 MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
959 auth_transaction);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800960 switch (sta->sae->state) {
961 case SAE_NOTHING:
962 if (auth_transaction == 1) {
Hai Shalom899fcc72020-10-19 14:38:18 -0700963 if (sta->sae->tmp) {
964 sta->sae->h2e =
965 (status_code ==
966 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
967 status_code == WLAN_STATUS_SAE_PK);
968 sta->sae->pk =
969 status_code == WLAN_STATUS_SAE_PK;
970 }
Hai Shalom021b0b52019-04-10 11:17:58 -0700971 ret = auth_sae_send_commit(hapd, sta, bssid,
Hai Shalomc3565922019-10-28 11:58:20 -0700972 !allow_reuse, status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800973 if (ret)
974 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700975 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800976
977 if (sae_process_commit(sta->sae) < 0)
978 return WLAN_STATUS_UNSPECIFIED_FAILURE;
979
980 /*
Hai Shalomc3565922019-10-28 11:58:20 -0700981 * In mesh case, both Commit and Confirm are sent
982 * immediately. In infrastructure BSS, by default, only
983 * a single Authentication frame (Commit) is expected
984 * from the AP here and the second one (Confirm) will
985 * be sent once the STA has sent its second
986 * Authentication frame (Confirm). This behavior can be
987 * overridden with explicit configuration so that the
988 * infrastructure BSS case sends both frames together.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800989 */
Hai Shalomc3565922019-10-28 11:58:20 -0700990 if ((hapd->conf->mesh & MESH_ENABLED) ||
991 hapd->conf->sae_confirm_immediate) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800992 /*
993 * Send both Commit and Confirm immediately
994 * based on SAE finite state machine
995 * Nothing -> Confirm transition.
996 */
997 ret = auth_sae_send_confirm(hapd, sta, bssid);
998 if (ret)
999 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001000 sae_set_state(sta, SAE_CONFIRMED,
1001 "Sent Confirm (mesh)");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001002 } else {
1003 /*
1004 * For infrastructure BSS, send only the Commit
1005 * message now to get alternating sequence of
1006 * Authentication frames between the AP and STA.
1007 * Confirm will be sent in
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001008 * Committed -> Confirmed/Accepted transition
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001009 * when receiving Confirm from STA.
1010 */
1011 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001012 sta->sae->sync = 0;
1013 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001014 } else {
1015 hostapd_logger(hapd, sta->addr,
1016 HOSTAPD_MODULE_IEEE80211,
1017 HOSTAPD_LEVEL_DEBUG,
1018 "SAE confirm before commit");
1019 }
1020 break;
1021 case SAE_COMMITTED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001022 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001023 if (auth_transaction == 1) {
1024 if (sae_process_commit(sta->sae) < 0)
1025 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1026
1027 ret = auth_sae_send_confirm(hapd, sta, bssid);
1028 if (ret)
1029 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001030 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001031 sta->sae->sync = 0;
1032 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001033 } else if (hapd->conf->mesh & MESH_ENABLED) {
1034 /*
1035 * In mesh case, follow SAE finite state machine and
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001036 * send Commit now, if sync count allows.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001037 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001038 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001039 return WLAN_STATUS_SUCCESS;
1040 sta->sae->sync++;
1041
Hai Shalomc3565922019-10-28 11:58:20 -07001042 ret = auth_sae_send_commit(hapd, sta, bssid, 0,
1043 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001044 if (ret)
1045 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001046
1047 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001048 } else {
1049 /*
1050 * For instructure BSS, send the postponed Confirm from
1051 * Nothing -> Confirmed transition that was reduced to
1052 * Nothing -> Committed above.
1053 */
1054 ret = auth_sae_send_confirm(hapd, sta, bssid);
1055 if (ret)
1056 return ret;
1057
Roshan Pius3a1667e2018-07-03 15:17:14 -07001058 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001059
1060 /*
1061 * Since this was triggered on Confirm RX, run another
1062 * step to get to Accepted without waiting for
1063 * additional events.
1064 */
Hai Shalom021b0b52019-04-10 11:17:58 -07001065 return sae_sm_step(hapd, sta, bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001066 WLAN_STATUS_SUCCESS, 0, sta_removed);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001067 }
1068 break;
1069 case SAE_CONFIRMED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001070 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001071 if (auth_transaction == 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001072 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001073 return WLAN_STATUS_SUCCESS;
1074 sta->sae->sync++;
1075
Hai Shalomc3565922019-10-28 11:58:20 -07001076 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1077 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001078 if (ret)
1079 return ret;
1080
1081 if (sae_process_commit(sta->sae) < 0)
1082 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1083
1084 ret = auth_sae_send_confirm(hapd, sta, bssid);
1085 if (ret)
1086 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001087
1088 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001089 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001090 sta->sae->send_confirm = 0xffff;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001091 sae_accept_sta(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001092 }
1093 break;
1094 case SAE_ACCEPTED:
Roshan Pius3a1667e2018-07-03 15:17:14 -07001095 if (auth_transaction == 1 &&
1096 (hapd->conf->mesh & MESH_ENABLED)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001097 wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
1098 ") doing reauthentication",
1099 MAC2STR(sta->addr));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001100 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
Hai Shalom5f92bc92019-04-18 11:54:11 -07001101 ap_free_sta(hapd, sta);
1102 *sta_removed = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001103 } else if (auth_transaction == 1) {
1104 wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
Hai Shalomc3565922019-10-28 11:58:20 -07001105 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1106 status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001107 if (ret)
1108 return ret;
1109 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
1110
1111 if (sae_process_commit(sta->sae) < 0)
1112 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1113 sta->sae->sync = 0;
1114 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001115 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001116 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001117 return WLAN_STATUS_SUCCESS;
1118 sta->sae->sync++;
1119
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001120 ret = auth_sae_send_confirm(hapd, sta, bssid);
1121 sae_clear_temp_data(sta->sae);
1122 if (ret)
1123 return ret;
1124 }
1125 break;
1126 default:
1127 wpa_printf(MSG_ERROR, "SAE: invalid state %d",
1128 sta->sae->state);
1129 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1130 }
1131 return WLAN_STATUS_SUCCESS;
1132}
1133
1134
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001135static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
1136{
1137 struct sae_data *sae = sta->sae;
1138 int i, *groups = hapd->conf->sae_groups;
Hai Shalom021b0b52019-04-10 11:17:58 -07001139 int default_groups[] = { 19, 0 };
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001140
1141 if (sae->state != SAE_COMMITTED)
1142 return;
1143
1144 wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
1145
Hai Shalom021b0b52019-04-10 11:17:58 -07001146 if (!groups)
1147 groups = default_groups;
1148 for (i = 0; groups[i] > 0; i++) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001149 if (sae->group == groups[i])
1150 break;
1151 }
1152
Hai Shalom021b0b52019-04-10 11:17:58 -07001153 if (groups[i] <= 0) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001154 wpa_printf(MSG_DEBUG,
1155 "SAE: Previously selected group not found from the current configuration");
1156 return;
1157 }
1158
1159 for (;;) {
1160 i++;
1161 if (groups[i] <= 0) {
1162 wpa_printf(MSG_DEBUG,
1163 "SAE: No alternative group enabled");
1164 return;
1165 }
1166
1167 if (sae_set_group(sae, groups[i]) < 0)
1168 continue;
1169
1170 break;
1171 }
1172 wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
1173}
1174
1175
Hai Shalomc3565922019-10-28 11:58:20 -07001176static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
1177{
Sunil Ravi77d572f2023-01-17 23:58:31 +00001178 enum sae_pwe sae_pwe = hapd->conf->sae_pwe;
Hai Shalomfdcde762020-04-02 11:19:20 -07001179 int id_in_use;
Hai Shalom60840252021-02-19 19:02:11 -08001180 bool sae_pk = false;
Hai Shalomfdcde762020-04-02 11:19:20 -07001181
1182 id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001183 if (id_in_use == 2 && sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
1184 sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
1185 else if (id_in_use == 1 && sae_pwe == SAE_PWE_HUNT_AND_PECK)
1186 sae_pwe = SAE_PWE_BOTH;
Hai Shalom899fcc72020-10-19 14:38:18 -07001187#ifdef CONFIG_SAE_PK
Hai Shalom60840252021-02-19 19:02:11 -08001188 sae_pk = hostapd_sae_pk_in_use(hapd->conf);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001189 if (sae_pwe == SAE_PWE_HUNT_AND_PECK && sae_pk)
1190 sae_pwe = SAE_PWE_BOTH;
Hai Shalom899fcc72020-10-19 14:38:18 -07001191#endif /* CONFIG_SAE_PK */
Sunil Ravi77d572f2023-01-17 23:58:31 +00001192 if (sae_pwe == SAE_PWE_HUNT_AND_PECK &&
Sunil Ravi89eba102022-09-13 21:04:37 -07001193 (hapd->conf->wpa_key_mgmt &
1194 (WPA_KEY_MGMT_SAE_EXT_KEY | WPA_KEY_MGMT_FT_SAE_EXT_KEY)))
Sunil Ravi77d572f2023-01-17 23:58:31 +00001195 sae_pwe = SAE_PWE_BOTH;
Hai Shalomfdcde762020-04-02 11:19:20 -07001196
Sunil Ravi77d572f2023-01-17 23:58:31 +00001197 return ((sae_pwe == SAE_PWE_HUNT_AND_PECK ||
1198 sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001199 status_code == WLAN_STATUS_SUCCESS) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001200 (sae_pwe == SAE_PWE_HASH_TO_ELEMENT &&
Hai Shalom899fcc72020-10-19 14:38:18 -07001201 (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001202 (sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001203 (sae_pwe == SAE_PWE_BOTH &&
Hai Shalomc3565922019-10-28 11:58:20 -07001204 (status_code == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -07001205 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001206 (sae_pk && status_code == WLAN_STATUS_SAE_PK)));
Hai Shalomc3565922019-10-28 11:58:20 -07001207}
1208
1209
1210static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
1211{
1212 int *groups = hapd->conf->sae_groups;
1213 int default_groups[] = { 19, 0 };
1214 int i;
1215
1216 if (!groups)
1217 groups = default_groups;
1218
1219 for (i = 0; groups[i] > 0; i++) {
1220 if (groups[i] == group)
1221 return 1;
1222 }
1223
1224 return 0;
1225}
1226
1227
1228static int check_sae_rejected_groups(struct hostapd_data *hapd,
Hai Shalom899fcc72020-10-19 14:38:18 -07001229 struct sae_data *sae)
Hai Shalomc3565922019-10-28 11:58:20 -07001230{
Hai Shalom899fcc72020-10-19 14:38:18 -07001231 const struct wpabuf *groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001232 size_t i, count;
1233 const u8 *pos;
1234
Hai Shalom899fcc72020-10-19 14:38:18 -07001235 if (!sae->tmp)
1236 return 0;
1237 groups = sae->tmp->peer_rejected_groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001238 if (!groups)
1239 return 0;
1240
1241 pos = wpabuf_head(groups);
1242 count = wpabuf_len(groups) / 2;
1243 for (i = 0; i < count; i++) {
1244 int enabled;
1245 u16 group;
1246
1247 group = WPA_GET_LE16(pos);
1248 pos += 2;
1249 enabled = sae_is_group_enabled(hapd, group);
1250 wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
1251 group, enabled ? "enabled" : "disabled");
1252 if (enabled)
1253 return 1;
1254 }
1255
1256 return 0;
1257}
1258
1259
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001260static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
1261 const struct ieee80211_mgmt *mgmt, size_t len,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001262 u16 auth_transaction, u16 status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001263{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001264 int resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001265 struct wpabuf *data = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07001266 int *groups = hapd->conf->sae_groups;
1267 int default_groups[] = { 19, 0 };
1268 const u8 *pos, *end;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001269 int sta_removed = 0;
Hai Shalom60840252021-02-19 19:02:11 -08001270 bool success_status;
Hai Shalom021b0b52019-04-10 11:17:58 -07001271
1272 if (!groups)
1273 groups = default_groups;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001274
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001275#ifdef CONFIG_TESTING_OPTIONS
1276 if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001277 wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
1278 pos = mgmt->u.auth.variable;
1279 end = ((const u8 *) mgmt) + len;
Hai Shalom899fcc72020-10-19 14:38:18 -07001280 resp = status_code;
Sunil Ravi72e01222024-03-09 01:25:43 +00001281 send_auth_reply(hapd, sta, sta->addr, mgmt->bssid,
1282 WLAN_AUTH_SAE,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001283 auth_transaction, resp, pos, end - pos,
1284 "auth-sae-reflection-attack");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001285 goto remove_sta;
1286 }
1287
1288 if (hapd->conf->sae_commit_override && auth_transaction == 1) {
1289 wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
Sunil Ravi72e01222024-03-09 01:25:43 +00001290 send_auth_reply(hapd, sta, sta->addr, mgmt->bssid,
1291 WLAN_AUTH_SAE,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001292 auth_transaction, resp,
1293 wpabuf_head(hapd->conf->sae_commit_override),
Roshan Pius3a1667e2018-07-03 15:17:14 -07001294 wpabuf_len(hapd->conf->sae_commit_override),
1295 "sae-commit-override");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001296 goto remove_sta;
1297 }
1298#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001299 if (!sta->sae) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001300 if (auth_transaction != 1 ||
Hai Shalomc3565922019-10-28 11:58:20 -07001301 !sae_status_success(hapd, status_code)) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001302 wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
1303 status_code);
1304 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1305 goto reply;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001306 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001307 sta->sae = os_zalloc(sizeof(*sta->sae));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001308 if (!sta->sae) {
1309 resp = -1;
1310 goto remove_sta;
1311 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001312 sae_set_state(sta, SAE_NOTHING, "Init");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001313 sta->sae->sync = 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001314 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001315
Dmitry Shmidte4663042016-04-04 10:07:49 -07001316 if (sta->mesh_sae_pmksa_caching) {
1317 wpa_printf(MSG_DEBUG,
1318 "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
1319 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
1320 sta->mesh_sae_pmksa_caching = 0;
1321 }
1322
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001323 if (auth_transaction == 1) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001324 const u8 *token = NULL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001325 size_t token_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07001326 int allow_reuse = 0;
1327
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001328 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1329 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001330 "start SAE authentication (RX commit, status=%u (%s))",
1331 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001332
1333 if ((hapd->conf->mesh & MESH_ENABLED) &&
1334 status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
1335 sta->sae->tmp) {
1336 pos = mgmt->u.auth.variable;
1337 end = ((const u8 *) mgmt) + len;
1338 if (pos + sizeof(le16) > end) {
1339 wpa_printf(MSG_ERROR,
1340 "SAE: Too short anti-clogging token request");
1341 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1342 goto reply;
1343 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001344 resp = sae_group_allowed(sta->sae, groups,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001345 WPA_GET_LE16(pos));
1346 if (resp != WLAN_STATUS_SUCCESS) {
1347 wpa_printf(MSG_ERROR,
1348 "SAE: Invalid group in anti-clogging token request");
1349 goto reply;
1350 }
1351 pos += sizeof(le16);
1352
1353 wpabuf_free(sta->sae->tmp->anti_clogging_token);
1354 sta->sae->tmp->anti_clogging_token =
1355 wpabuf_alloc_copy(pos, end - pos);
1356 if (sta->sae->tmp->anti_clogging_token == NULL) {
1357 wpa_printf(MSG_ERROR,
1358 "SAE: Failed to alloc for anti-clogging token");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001359 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1360 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001361 }
1362
1363 /*
1364 * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code
1365 * is 76, a new Commit Message shall be constructed
1366 * with the Anti-Clogging Token from the received
1367 * Authentication frame, and the commit-scalar and
1368 * COMMIT-ELEMENT previously sent.
1369 */
Hai Shalomc3565922019-10-28 11:58:20 -07001370 resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
1371 status_code);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001372 if (resp != WLAN_STATUS_SUCCESS) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001373 wpa_printf(MSG_ERROR,
1374 "SAE: Failed to send commit message");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001375 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001376 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001377 sae_set_state(sta, SAE_COMMITTED,
1378 "Sent Commit (anti-clogging token case in mesh)");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001379 sta->sae->sync = 0;
1380 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001381 return;
1382 }
1383
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001384 if ((hapd->conf->mesh & MESH_ENABLED) &&
1385 status_code ==
1386 WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1387 sta->sae->tmp) {
1388 wpa_printf(MSG_DEBUG,
1389 "SAE: Peer did not accept our SAE group");
1390 sae_pick_next_group(hapd, sta);
1391 goto remove_sta;
1392 }
1393
Hai Shalomc3565922019-10-28 11:58:20 -07001394 if (!sae_status_success(hapd, status_code))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001395 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001396
Roshan Pius3a1667e2018-07-03 15:17:14 -07001397 if (!(hapd->conf->mesh & MESH_ENABLED) &&
1398 sta->sae->state == SAE_COMMITTED) {
1399 /* This is needed in the infrastructure BSS case to
1400 * address a sequence where a STA entry may remain in
1401 * hostapd across two attempts to do SAE authentication
1402 * by the same STA. The second attempt may end up trying
1403 * to use a different group and that would not be
1404 * allowed if we remain in Committed state with the
1405 * previously set parameters. */
Hai Shalom021b0b52019-04-10 11:17:58 -07001406 pos = mgmt->u.auth.variable;
1407 end = ((const u8 *) mgmt) + len;
1408 if (end - pos >= (int) sizeof(le16) &&
1409 sae_group_allowed(sta->sae, groups,
1410 WPA_GET_LE16(pos)) ==
1411 WLAN_STATUS_SUCCESS) {
1412 /* Do not waste resources deriving the same PWE
1413 * again since the same group is reused. */
1414 sae_set_state(sta, SAE_NOTHING,
1415 "Allow previous PWE to be reused");
1416 allow_reuse = 1;
1417 } else {
1418 sae_set_state(sta, SAE_NOTHING,
1419 "Clear existing state to allow restart");
1420 sae_clear_data(sta->sae);
1421 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001422 }
1423
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001424 resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
1425 ((const u8 *) mgmt) + len -
1426 mgmt->u.auth.variable, &token,
Hai Shalomc3565922019-10-28 11:58:20 -07001427 &token_len, groups, status_code ==
Hai Shalom899fcc72020-10-19 14:38:18 -07001428 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001429 status_code == WLAN_STATUS_SAE_PK,
1430 NULL);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001431 if (resp == SAE_SILENTLY_DISCARD) {
1432 wpa_printf(MSG_DEBUG,
1433 "SAE: Drop commit message from " MACSTR " due to reflection attack",
1434 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001435 goto remove_sta;
Dmitry Shmidt41712582015-06-29 11:02:15 -07001436 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001437
1438 if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
1439 wpa_msg(hapd->msg_ctx, MSG_INFO,
1440 WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
1441 MACSTR, MAC2STR(sta->addr));
1442 sae_clear_retransmit_timer(hapd, sta);
1443 sae_set_state(sta, SAE_NOTHING,
1444 "Unknown Password Identifier");
1445 goto remove_sta;
1446 }
1447
Hai Shaloma20dcd72022-02-04 13:43:00 -08001448 if (token &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00001449 check_comeback_token(hapd->comeback_key,
1450 hapd->comeback_pending_idx, sta->addr,
1451 token, token_len)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001452 < 0) {
1453 wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
1454 "incorrect token from " MACSTR,
1455 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001456 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1457 goto remove_sta;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001458 }
1459
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001460 if (resp != WLAN_STATUS_SUCCESS)
1461 goto reply;
1462
Hai Shalom899fcc72020-10-19 14:38:18 -07001463 if (check_sae_rejected_groups(hapd, sta->sae)) {
Hai Shalomc3565922019-10-28 11:58:20 -07001464 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001465 goto reply;
Hai Shalomc3565922019-10-28 11:58:20 -07001466 }
1467
Hai Shaloma20dcd72022-02-04 13:43:00 -08001468 if (!token && use_anti_clogging(hapd) && !allow_reuse) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001469 int h2e = 0;
1470
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001471 wpa_printf(MSG_DEBUG,
1472 "SAE: Request anti-clogging token from "
1473 MACSTR, MAC2STR(sta->addr));
Hai Shalomfdcde762020-04-02 11:19:20 -07001474 if (sta->sae->tmp)
Hai Shalom899fcc72020-10-19 14:38:18 -07001475 h2e = sta->sae->h2e;
1476 if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1477 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomfdcde762020-04-02 11:19:20 -07001478 h2e = 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001479 data = auth_build_token_req(
1480 &hapd->last_comeback_key_update,
1481 hapd->comeback_key,
1482 hapd->comeback_idx,
1483 hapd->comeback_pending_idx,
1484 sizeof(hapd->comeback_pending_idx),
1485 sta->sae->group,
1486 sta->addr, h2e);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001487 resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
1488 if (hapd->conf->mesh & MESH_ENABLED)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001489 sae_set_state(sta, SAE_NOTHING,
1490 "Request anti-clogging token case in mesh");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001491 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001492 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001493
Hai Shalom021b0b52019-04-10 11:17:58 -07001494 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001495 status_code, allow_reuse, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001496 } else if (auth_transaction == 2) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001497 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1498 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001499 "SAE authentication (RX confirm, status=%u (%s))",
1500 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001501 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001502 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001503 if (sta->sae->state >= SAE_CONFIRMED ||
1504 !(hapd->conf->mesh & MESH_ENABLED)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001505 const u8 *var;
1506 size_t var_len;
1507 u16 peer_send_confirm;
1508
1509 var = mgmt->u.auth.variable;
1510 var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable;
1511 if (var_len < 2) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001512 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001513 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001514 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001515
1516 peer_send_confirm = WPA_GET_LE16(var);
1517
1518 if (sta->sae->state == SAE_ACCEPTED &&
1519 (peer_send_confirm <= sta->sae->rc ||
1520 peer_send_confirm == 0xffff)) {
1521 wpa_printf(MSG_DEBUG,
1522 "SAE: Silently ignore unexpected Confirm from peer "
1523 MACSTR
1524 " (peer-send-confirm=%u Rc=%u)",
1525 MAC2STR(sta->addr),
1526 peer_send_confirm, sta->sae->rc);
1527 return;
1528 }
1529
Sunil Ravi77d572f2023-01-17 23:58:31 +00001530 if (sae_check_confirm(sta->sae, var, var_len,
1531 NULL) < 0) {
1532 resp = WLAN_STATUS_CHALLENGE_FAIL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001533 goto reply;
1534 }
1535 sta->sae->rc = peer_send_confirm;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001536 }
Hai Shalomc3565922019-10-28 11:58:20 -07001537 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
1538 status_code, 0, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001539 } else {
1540 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1541 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001542 "unexpected SAE authentication transaction %u (status=%u (%s))",
1543 auth_transaction, status_code,
1544 status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001545 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001546 goto remove_sta;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001547 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1548 }
1549
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001550reply:
Hai Shalom5f92bc92019-04-18 11:54:11 -07001551 if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001552 pos = mgmt->u.auth.variable;
1553 end = ((const u8 *) mgmt) + len;
1554
1555 /* Copy the Finite Cyclic Group field from the request if we
1556 * rejected it as unsupported group. */
1557 if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1558 !data && end - pos >= 2)
1559 data = wpabuf_alloc_copy(pos, 2);
1560
Hai Shalom5f92bc92019-04-18 11:54:11 -07001561 sae_sme_send_external_auth_status(hapd, sta, resp);
Sunil Ravi72e01222024-03-09 01:25:43 +00001562 send_auth_reply(hapd, sta, sta->addr, mgmt->bssid,
1563 WLAN_AUTH_SAE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001564 auth_transaction, resp,
1565 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07001566 data ? wpabuf_len(data) : 0, "auth-sae");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001567 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001568
1569remove_sta:
Hai Shalom60840252021-02-19 19:02:11 -08001570 if (auth_transaction == 1)
1571 success_status = sae_status_success(hapd, status_code);
1572 else
1573 success_status = status_code == WLAN_STATUS_SUCCESS;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001574 if (!sta_removed && sta->added_unassoc &&
Hai Shalom60840252021-02-19 19:02:11 -08001575 (resp != WLAN_STATUS_SUCCESS || !success_status)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001576 hostapd_drv_sta_remove(hapd, sta->addr);
1577 sta->added_unassoc = 0;
1578 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001579 wpabuf_free(data);
1580}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001581
1582
1583/**
1584 * auth_sae_init_committed - Send COMMIT and start SAE in committed state
1585 * @hapd: BSS data for the device initiating the authentication
1586 * @sta: the peer to which commit authentication frame is sent
1587 *
1588 * This function implements Init event handling (IEEE Std 802.11-2012,
1589 * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
1590 * sta->sae structure should be initialized appropriately via a call to
1591 * sae_prepare_commit().
1592 */
1593int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
1594{
1595 int ret;
1596
1597 if (!sta->sae || !sta->sae->tmp)
1598 return -1;
1599
1600 if (sta->sae->state != SAE_NOTHING)
1601 return -1;
1602
Hai Shalomc3565922019-10-28 11:58:20 -07001603 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001604 if (ret)
1605 return -1;
1606
Roshan Pius3a1667e2018-07-03 15:17:14 -07001607 sae_set_state(sta, SAE_COMMITTED, "Init and sent commit");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001608 sta->sae->sync = 0;
1609 sae_set_retransmit_timer(hapd, sta);
1610
1611 return 0;
1612}
1613
Hai Shalom021b0b52019-04-10 11:17:58 -07001614
1615void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
1616{
1617 struct hostapd_data *hapd = eloop_ctx;
1618 struct hostapd_sae_commit_queue *q;
1619 unsigned int queue_len;
1620
1621 q = dl_list_first(&hapd->sae_commit_queue,
1622 struct hostapd_sae_commit_queue, list);
1623 if (!q)
1624 return;
1625 wpa_printf(MSG_DEBUG,
1626 "SAE: Process next available message from queue");
1627 dl_list_del(&q->list);
1628 handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
1629 q->rssi, 1);
1630 os_free(q);
1631
1632 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1633 return;
1634 queue_len = dl_list_len(&hapd->sae_commit_queue);
1635 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1636 hapd, NULL);
1637}
1638
1639
1640static void auth_sae_queue(struct hostapd_data *hapd,
1641 const struct ieee80211_mgmt *mgmt, size_t len,
1642 int rssi)
1643{
1644 struct hostapd_sae_commit_queue *q, *q2;
1645 unsigned int queue_len;
1646 const struct ieee80211_mgmt *mgmt2;
1647
1648 queue_len = dl_list_len(&hapd->sae_commit_queue);
1649 if (queue_len >= 15) {
1650 wpa_printf(MSG_DEBUG,
1651 "SAE: No more room in message queue - drop the new frame from "
1652 MACSTR, MAC2STR(mgmt->sa));
1653 return;
1654 }
1655
1656 wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
1657 MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
1658 queue_len);
1659 q = os_zalloc(sizeof(*q) + len);
1660 if (!q)
1661 return;
1662 q->rssi = rssi;
1663 q->len = len;
1664 os_memcpy(q->msg, mgmt, len);
1665
1666 /* Check whether there is already a queued Authentication frame from the
1667 * same station with the same transaction number and if so, replace that
1668 * queue entry with the new one. This avoids issues with a peer that
1669 * sends multiple times (e.g., due to frequent SAE retries). There is no
1670 * point in us trying to process the old attempts after a new one has
1671 * obsoleted them. */
1672 dl_list_for_each(q2, &hapd->sae_commit_queue,
1673 struct hostapd_sae_commit_queue, list) {
1674 mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
Sunil Ravi72e01222024-03-09 01:25:43 +00001675 if (ether_addr_equal(mgmt->sa, mgmt2->sa) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07001676 mgmt->u.auth.auth_transaction ==
1677 mgmt2->u.auth.auth_transaction) {
1678 wpa_printf(MSG_DEBUG,
1679 "SAE: Replace queued message from same STA with same transaction number");
1680 dl_list_add(&q2->list, &q->list);
1681 dl_list_del(&q2->list);
1682 os_free(q2);
1683 goto queued;
1684 }
1685 }
1686
1687 /* No pending identical entry, so add to the end of the queue */
1688 dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
1689
1690queued:
1691 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1692 return;
1693 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1694 hapd, NULL);
1695}
1696
1697
1698static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
1699{
1700 struct hostapd_sae_commit_queue *q;
1701 const struct ieee80211_mgmt *mgmt;
1702
1703 dl_list_for_each(q, &hapd->sae_commit_queue,
1704 struct hostapd_sae_commit_queue, list) {
1705 mgmt = (const struct ieee80211_mgmt *) q->msg;
Sunil Ravi72e01222024-03-09 01:25:43 +00001706 if (ether_addr_equal(addr, mgmt->sa))
Hai Shalom021b0b52019-04-10 11:17:58 -07001707 return 1;
1708 }
1709
1710 return 0;
1711}
1712
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001713#endif /* CONFIG_SAE */
1714
1715
Hai Shalomfdcde762020-04-02 11:19:20 -07001716static u16 wpa_res_to_status_code(enum wpa_validate_result res)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001717{
Hai Shalomfdcde762020-04-02 11:19:20 -07001718 switch (res) {
1719 case WPA_IE_OK:
1720 return WLAN_STATUS_SUCCESS;
1721 case WPA_INVALID_IE:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001722 return WLAN_STATUS_INVALID_IE;
Hai Shalomfdcde762020-04-02 11:19:20 -07001723 case WPA_INVALID_GROUP:
1724 return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
1725 case WPA_INVALID_PAIRWISE:
1726 return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
1727 case WPA_INVALID_AKMP:
1728 return WLAN_STATUS_AKMP_NOT_VALID;
1729 case WPA_NOT_ENABLED:
1730 return WLAN_STATUS_INVALID_IE;
1731 case WPA_ALLOC_FAIL:
1732 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1733 case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
1734 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
1735 case WPA_INVALID_MGMT_GROUP_CIPHER:
1736 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
1737 case WPA_INVALID_MDIE:
1738 return WLAN_STATUS_INVALID_MDIE;
1739 case WPA_INVALID_PROTO:
1740 return WLAN_STATUS_INVALID_IE;
1741 case WPA_INVALID_PMKID:
1742 return WLAN_STATUS_INVALID_PMKID;
1743 case WPA_DENIED_OTHER_REASON:
1744 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
1745 }
1746 return WLAN_STATUS_INVALID_IE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001747}
1748
1749
1750#ifdef CONFIG_FILS
1751
1752static void handle_auth_fils_finish(struct hostapd_data *hapd,
1753 struct sta_info *sta, u16 resp,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001754 struct wpabuf *data, int pub);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001755
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001756void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
1757 const u8 *pos, size_t len, u16 auth_alg,
1758 u16 auth_transaction, u16 status_code,
1759 void (*cb)(struct hostapd_data *hapd,
1760 struct sta_info *sta, u16 resp,
1761 struct wpabuf *data, int pub))
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001762{
1763 u16 resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001764 const u8 *end;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001765 struct ieee802_11_elems elems;
Hai Shalomfdcde762020-04-02 11:19:20 -07001766 enum wpa_validate_result res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001767 struct wpa_ie_data rsn;
1768 struct rsn_pmksa_cache_entry *pmksa = NULL;
1769
1770 if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
1771 return;
1772
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001773 end = pos + len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001774
1775 wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
1776 pos, end - pos);
1777
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001778 /* TODO: FILS PK */
1779#ifdef CONFIG_FILS_SK_PFS
1780 if (auth_alg == WLAN_AUTH_FILS_SK_PFS) {
1781 u16 group;
1782 struct wpabuf *pub;
1783 size_t elem_len;
1784
1785 /* Using FILS PFS */
1786
1787 /* Finite Cyclic Group */
1788 if (end - pos < 2) {
1789 wpa_printf(MSG_DEBUG,
1790 "FILS: No room for Finite Cyclic Group");
1791 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1792 goto fail;
1793 }
1794 group = WPA_GET_LE16(pos);
1795 pos += 2;
1796 if (group != hapd->conf->fils_dh_group) {
1797 wpa_printf(MSG_DEBUG,
1798 "FILS: Unsupported Finite Cyclic Group: %u (expected %u)",
1799 group, hapd->conf->fils_dh_group);
1800 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1801 goto fail;
1802 }
1803
1804 crypto_ecdh_deinit(sta->fils_ecdh);
1805 sta->fils_ecdh = crypto_ecdh_init(group);
1806 if (!sta->fils_ecdh) {
1807 wpa_printf(MSG_INFO,
1808 "FILS: Could not initialize ECDH with group %d",
1809 group);
1810 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1811 goto fail;
1812 }
1813
1814 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
1815 if (!pub) {
1816 wpa_printf(MSG_DEBUG,
1817 "FILS: Failed to derive ECDH public key");
1818 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1819 goto fail;
1820 }
1821 elem_len = wpabuf_len(pub);
1822 wpabuf_free(pub);
1823
1824 /* Element */
1825 if ((size_t) (end - pos) < elem_len) {
1826 wpa_printf(MSG_DEBUG, "FILS: No room for Element");
1827 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1828 goto fail;
1829 }
1830
1831 wpabuf_free(sta->fils_g_sta);
1832 sta->fils_g_sta = wpabuf_alloc_copy(pos, elem_len);
1833 wpabuf_clear_free(sta->fils_dh_ss);
1834 sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1,
1835 pos, elem_len);
1836 if (!sta->fils_dh_ss) {
1837 wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
1838 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1839 goto fail;
1840 }
1841 wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss);
1842 pos += elem_len;
1843 } else {
1844 crypto_ecdh_deinit(sta->fils_ecdh);
1845 sta->fils_ecdh = NULL;
1846 wpabuf_clear_free(sta->fils_dh_ss);
1847 sta->fils_dh_ss = NULL;
1848 }
1849#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001850
1851 wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
1852 if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
1853 wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
1854 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1855 goto fail;
1856 }
1857
1858 /* RSNE */
1859 wpa_hexdump(MSG_DEBUG, "FILS: RSN element",
1860 elems.rsn_ie, elems.rsn_ie_len);
1861 if (!elems.rsn_ie ||
1862 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
1863 &rsn) < 0) {
1864 wpa_printf(MSG_DEBUG, "FILS: No valid RSN element");
1865 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1866 goto fail;
1867 }
1868
1869 if (!sta->wpa_sm)
1870 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
1871 NULL);
1872 if (!sta->wpa_sm) {
1873 wpa_printf(MSG_DEBUG,
1874 "FILS: Failed to initialize RSN state machine");
1875 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1876 goto fail;
1877 }
1878
1879 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07001880 hapd->iface->freq,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001881 elems.rsn_ie - 2, elems.rsn_ie_len + 2,
Hai Shalomc3565922019-10-28 11:58:20 -07001882 elems.rsnxe ? elems.rsnxe - 2 : NULL,
1883 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001884 elems.mdie, elems.mdie_len, NULL, 0);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001885 resp = wpa_res_to_status_code(res);
1886 if (resp != WLAN_STATUS_SUCCESS)
1887 goto fail;
1888
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001889 if (!elems.fils_nonce) {
1890 wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
1891 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1892 goto fail;
1893 }
1894 wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce,
1895 FILS_NONCE_LEN);
1896 os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN);
1897
1898 /* PMKID List */
1899 if (rsn.pmkid && rsn.num_pmkid > 0) {
1900 u8 num;
1901 const u8 *pmkid;
1902
1903 wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
1904 rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
1905
1906 pmkid = rsn.pmkid;
1907 num = rsn.num_pmkid;
1908 while (num) {
1909 wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
1910 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
1911 pmkid);
1912 if (pmksa)
1913 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001914 pmksa = wpa_auth_pmksa_get_fils_cache_id(hapd->wpa_auth,
1915 sta->addr,
1916 pmkid);
1917 if (pmksa)
1918 break;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001919 pmkid += PMKID_LEN;
1920 num--;
1921 }
1922 }
1923 if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) {
1924 wpa_printf(MSG_DEBUG,
1925 "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore",
1926 wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp);
1927 pmksa = NULL;
1928 }
1929 if (pmksa)
1930 wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry");
1931
1932 /* FILS Session */
1933 if (!elems.fils_session) {
1934 wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
1935 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1936 goto fail;
1937 }
1938 wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
1939 FILS_SESSION_LEN);
1940 os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
1941
Hai Shalomfdcde762020-04-02 11:19:20 -07001942 /* Wrapped Data */
1943 if (elems.wrapped_data) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001944 wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
Hai Shalomfdcde762020-04-02 11:19:20 -07001945 elems.wrapped_data,
1946 elems.wrapped_data_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001947 if (!pmksa) {
1948#ifndef CONFIG_NO_RADIUS
1949 if (!sta->eapol_sm) {
1950 sta->eapol_sm =
1951 ieee802_1x_alloc_eapol_sm(hapd, sta);
1952 }
1953 wpa_printf(MSG_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001954 "FILS: Forward EAP-Initiate/Re-auth to authentication server");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001955 ieee802_1x_encapsulate_radius(
Hai Shalomfdcde762020-04-02 11:19:20 -07001956 hapd, sta, elems.wrapped_data,
1957 elems.wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001958 sta->fils_pending_cb = cb;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001959 wpa_printf(MSG_DEBUG,
1960 "FILS: Will send Authentication frame once the response from authentication server is available");
1961 sta->flags |= WLAN_STA_PENDING_FILS_ERP;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001962 /* Calculate pending PMKID here so that we do not need
1963 * to maintain a copy of the EAP-Initiate/Reauth
1964 * message. */
1965 if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
Hai Shalomfdcde762020-04-02 11:19:20 -07001966 elems.wrapped_data,
1967 elems.wrapped_data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001968 sta->fils_erp_pmkid) == 0)
1969 sta->fils_erp_pmkid_set = 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001970 return;
1971#else /* CONFIG_NO_RADIUS */
1972 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1973 goto fail;
1974#endif /* CONFIG_NO_RADIUS */
1975 }
1976 }
1977
1978fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001979 if (cb) {
1980 struct wpabuf *data;
1981 int pub = 0;
1982
1983 data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, NULL,
1984 NULL, 0, &pub);
1985 if (!data) {
1986 wpa_printf(MSG_DEBUG,
1987 "%s: prepare_auth_resp_fils() returned failure",
1988 __func__);
1989 }
1990
1991 cb(hapd, sta, resp, data, pub);
1992 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001993}
1994
1995
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001996static struct wpabuf *
1997prepare_auth_resp_fils(struct hostapd_data *hapd,
1998 struct sta_info *sta, u16 *resp,
1999 struct rsn_pmksa_cache_entry *pmksa,
2000 struct wpabuf *erp_resp,
2001 const u8 *msk, size_t msk_len,
2002 int *is_pub)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002003{
2004 u8 fils_nonce[FILS_NONCE_LEN];
2005 size_t ielen;
2006 struct wpabuf *data = NULL;
2007 const u8 *ie;
2008 u8 *ie_buf = NULL;
2009 const u8 *pmk = NULL;
2010 size_t pmk_len = 0;
Paul Stewart092955c2017-02-06 09:13:09 -08002011 u8 pmk_buf[PMK_LEN_MAX];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002012 struct wpabuf *pub = NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002013
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002014 if (*resp != WLAN_STATUS_SUCCESS)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002015 goto fail;
2016
2017 ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
2018 if (!ie) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002019 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002020 goto fail;
2021 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002022
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002023 if (pmksa) {
2024 /* Add PMKID of the selected PMKSA into RSNE */
2025 ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN);
2026 if (!ie_buf) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002027 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002028 goto fail;
2029 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002030
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002031 os_memcpy(ie_buf, ie, ielen);
Sunil Ravi72e01222024-03-09 01:25:43 +00002032 if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid, true) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002033 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002034 goto fail;
2035 }
2036 ie = ie_buf;
2037 }
2038
2039 if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002040 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002041 goto fail;
2042 }
2043 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
2044 fils_nonce, FILS_NONCE_LEN);
2045
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002046#ifdef CONFIG_FILS_SK_PFS
2047 if (sta->fils_dh_ss && sta->fils_ecdh) {
2048 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
2049 if (!pub) {
2050 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2051 goto fail;
2052 }
2053 }
2054#endif /* CONFIG_FILS_SK_PFS */
2055
2056 data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0));
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002057 if (!data) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002058 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002059 goto fail;
2060 }
2061
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002062 /* TODO: FILS PK */
2063#ifdef CONFIG_FILS_SK_PFS
2064 if (pub) {
2065 /* Finite Cyclic Group */
2066 wpabuf_put_le16(data, hapd->conf->fils_dh_group);
2067
2068 /* Element */
2069 wpabuf_put_buf(data, pub);
2070 }
2071#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002072
2073 /* RSNE */
2074 wpabuf_put_data(data, ie, ielen);
2075
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002076 /* MDE when using FILS+FT (already included in ie,ielen with RSNE) */
2077
2078#ifdef CONFIG_IEEE80211R_AP
2079 if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
2080 /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
2081 int res;
2082
Sunil Ravi77d572f2023-01-17 23:58:31 +00002083 res = wpa_auth_write_fte(hapd->wpa_auth, sta->wpa_sm,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002084 wpabuf_put(data, 0),
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002085 wpabuf_tailroom(data));
2086 if (res < 0) {
2087 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2088 goto fail;
2089 }
2090 wpabuf_put(data, res);
2091 }
2092#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002093
2094 /* FILS Nonce */
2095 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2096 wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */
2097 /* Element ID Extension */
2098 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE);
2099 wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN);
2100
2101 /* FILS Session */
2102 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2103 wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */
2104 /* Element ID Extension */
2105 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
2106 wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
2107
Hai Shalomfdcde762020-04-02 11:19:20 -07002108 /* Wrapped Data */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002109 if (!pmksa && erp_resp) {
2110 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2111 wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
2112 /* Element ID Extension */
Hai Shalomfdcde762020-04-02 11:19:20 -07002113 wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002114 wpabuf_put_buf(data, erp_resp);
2115
Paul Stewart092955c2017-02-06 09:13:09 -08002116 if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
2117 msk, msk_len, sta->fils_snonce, fils_nonce,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002118 sta->fils_dh_ss ?
2119 wpabuf_head(sta->fils_dh_ss) : NULL,
2120 sta->fils_dh_ss ?
2121 wpabuf_len(sta->fils_dh_ss) : 0,
2122 pmk_buf, &pmk_len)) {
Paul Stewart092955c2017-02-06 09:13:09 -08002123 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002124 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Paul Stewart092955c2017-02-06 09:13:09 -08002125 wpabuf_free(data);
2126 data = NULL;
2127 goto fail;
2128 }
2129 pmk = pmk_buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002130
2131 /* Don't use DHss in PTK derivation if PMKSA caching is not
2132 * used. */
2133 wpabuf_clear_free(sta->fils_dh_ss);
2134 sta->fils_dh_ss = NULL;
2135
2136 if (sta->fils_erp_pmkid_set) {
2137 /* TODO: get PMKLifetime from WPA parameters */
2138 unsigned int dot11RSNAConfigPMKLifetime = 43200;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002139 int session_timeout;
2140
2141 session_timeout = dot11RSNAConfigPMKLifetime;
2142 if (sta->session_timeout_set) {
2143 struct os_reltime now, diff;
2144
2145 os_get_reltime(&now);
2146 os_reltime_sub(&sta->session_timeout, &now,
2147 &diff);
2148 session_timeout = diff.sec;
2149 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002150
2151 sta->fils_erp_pmkid_set = 0;
Hai Shalom81f62d82019-07-22 12:10:00 -07002152 wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
2153 sta->fils_erp_pmkid);
Hai Shalom021b0b52019-04-10 11:17:58 -07002154 if (!hapd->conf->disable_pmksa_caching &&
2155 wpa_auth_pmksa_add2(
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002156 hapd->wpa_auth, sta->addr,
2157 pmk, pmk_len,
2158 sta->fils_erp_pmkid,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002159 session_timeout,
Sunil Ravi72e01222024-03-09 01:25:43 +00002160 wpa_auth_sta_key_mgmt(sta->wpa_sm),
2161 NULL) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002162 wpa_printf(MSG_ERROR,
2163 "FILS: Failed to add PMKSA cache entry based on ERP");
2164 }
2165 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002166 } else if (pmksa) {
2167 pmk = pmksa->pmk;
2168 pmk_len = pmksa->pmk_len;
2169 }
2170
2171 if (!pmk) {
2172 wpa_printf(MSG_DEBUG, "FILS: No PMK available");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002173 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002174 wpabuf_free(data);
2175 data = NULL;
2176 goto fail;
2177 }
2178
2179 if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002180 sta->fils_snonce, fils_nonce,
2181 sta->fils_dh_ss ?
2182 wpabuf_head(sta->fils_dh_ss) : NULL,
2183 sta->fils_dh_ss ?
2184 wpabuf_len(sta->fils_dh_ss) : 0,
2185 sta->fils_g_sta, pub) < 0) {
2186 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002187 wpabuf_free(data);
2188 data = NULL;
2189 goto fail;
2190 }
2191
2192fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002193 if (is_pub)
2194 *is_pub = pub != NULL;
2195 os_free(ie_buf);
2196 wpabuf_free(pub);
2197 wpabuf_clear_free(sta->fils_dh_ss);
2198 sta->fils_dh_ss = NULL;
2199#ifdef CONFIG_FILS_SK_PFS
2200 crypto_ecdh_deinit(sta->fils_ecdh);
2201 sta->fils_ecdh = NULL;
2202#endif /* CONFIG_FILS_SK_PFS */
2203 return data;
2204}
2205
2206
2207static void handle_auth_fils_finish(struct hostapd_data *hapd,
2208 struct sta_info *sta, u16 resp,
2209 struct wpabuf *data, int pub)
2210{
2211 u16 auth_alg;
2212
2213 auth_alg = (pub ||
2214 resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
2215 WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Hai Shalomfdcde762020-04-02 11:19:20 -07002216 send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002217 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07002218 data ? wpabuf_len(data) : 0, "auth-fils-finish");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002219 wpabuf_free(data);
2220
2221 if (resp == WLAN_STATUS_SUCCESS) {
2222 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2223 HOSTAPD_LEVEL_DEBUG,
2224 "authentication OK (FILS)");
2225 sta->flags |= WLAN_STA_AUTH;
2226 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002227 sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002228 mlme_authenticate_indication(hapd, sta);
2229 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002230}
2231
2232
2233void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
2234 struct sta_info *sta, int success,
2235 struct wpabuf *erp_resp,
2236 const u8 *msk, size_t msk_len)
2237{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002238 u16 resp;
Hai Shalom60840252021-02-19 19:02:11 -08002239 u32 flags = sta->flags;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002240
Hai Shalom60840252021-02-19 19:02:11 -08002241 sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
2242 WLAN_STA_PENDING_PASN_FILS_ERP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002243
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002244 resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
Hai Shalom60840252021-02-19 19:02:11 -08002245
2246 if (flags & WLAN_STA_PENDING_FILS_ERP) {
2247 struct wpabuf *data;
2248 int pub = 0;
2249
2250 if (!sta->fils_pending_cb)
2251 return;
2252
2253 data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
2254 msk, msk_len, &pub);
2255 if (!data) {
2256 wpa_printf(MSG_DEBUG,
2257 "%s: prepare_auth_resp_fils() failure",
2258 __func__);
2259 }
2260 sta->fils_pending_cb(hapd, sta, resp, data, pub);
2261#ifdef CONFIG_PASN
2262 } else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
2263 pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
2264 msk, msk_len);
2265#endif /* CONFIG_PASN */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002266 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002267}
2268
2269#endif /* CONFIG_FILS */
2270
2271
Hai Shalomfdcde762020-04-02 11:19:20 -07002272static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
2273 const u8 *msg, size_t len,
2274 struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002275{
2276 int res;
2277
Hai Shalomfdcde762020-04-02 11:19:20 -07002278 res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002279
2280 if (res == HOSTAPD_ACL_REJECT) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002281 wpa_printf(MSG_DEBUG, "Station " MACSTR
2282 " not allowed to authenticate",
2283 MAC2STR(addr));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002284 return HOSTAPD_ACL_REJECT;
2285 }
2286
2287 if (res == HOSTAPD_ACL_PENDING) {
2288 wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
2289 " waiting for an external authentication",
2290 MAC2STR(addr));
2291 /* Authentication code will re-send the authentication frame
2292 * after it has received (and cached) information from the
2293 * external source. */
2294 return HOSTAPD_ACL_PENDING;
2295 }
2296
2297 return res;
2298}
2299
2300
Sunil Ravia04bd252022-05-02 22:54:18 -07002301int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
2302 int res, struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002303{
Hai Shalomfdcde762020-04-02 11:19:20 -07002304 u32 session_timeout = info->session_timeout;
2305 u32 acct_interim_interval = info->acct_interim_interval;
2306 struct vlan_description *vlan_id = &info->vlan_id;
2307 struct hostapd_sta_wpa_psk_short *psk = info->psk;
2308 char *identity = info->identity;
2309 char *radius_cui = info->radius_cui;
2310
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002311 if (vlan_id->notempty &&
2312 !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
2313 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2314 HOSTAPD_LEVEL_INFO,
2315 "Invalid VLAN %d%s received from RADIUS server",
2316 vlan_id->untagged,
2317 vlan_id->tagged[0] ? "+" : "");
2318 return -1;
2319 }
2320 if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
2321 return -1;
2322 if (sta->vlan_id)
2323 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2324 HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
2325
2326 hostapd_free_psk_list(sta->psk);
Hai Shalomfdcde762020-04-02 11:19:20 -07002327 if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
2328 hostapd_copy_psk_list(&sta->psk, psk);
2329 else
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002330 sta->psk = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002331
Roshan Pius3a1667e2018-07-03 15:17:14 -07002332 os_free(sta->identity);
Hai Shalomfdcde762020-04-02 11:19:20 -07002333 if (identity)
2334 sta->identity = os_strdup(identity);
2335 else
2336 sta->identity = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002337
2338 os_free(sta->radius_cui);
Hai Shalomfdcde762020-04-02 11:19:20 -07002339 if (radius_cui)
2340 sta->radius_cui = os_strdup(radius_cui);
2341 else
2342 sta->radius_cui = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002343
2344 if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
2345 sta->acct_interim_interval = acct_interim_interval;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002346 if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
2347 sta->session_timeout_set = 1;
2348 os_get_reltime(&sta->session_timeout);
2349 sta->session_timeout.sec += session_timeout;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002350 ap_sta_session_timeout(hapd, sta, session_timeout);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002351 } else {
2352 sta->session_timeout_set = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002353 ap_sta_no_session_timeout(hapd, sta);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002354 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002355
2356 return 0;
2357}
2358
2359
Hai Shalom60840252021-02-19 19:02:11 -08002360#ifdef CONFIG_PASN
Hai Shalom60840252021-02-19 19:02:11 -08002361#ifdef CONFIG_FILS
2362
Hai Shalom60840252021-02-19 19:02:11 -08002363static void pasn_fils_auth_resp(struct hostapd_data *hapd,
2364 struct sta_info *sta, u16 status,
2365 struct wpabuf *erp_resp,
2366 const u8 *msk, size_t msk_len)
2367{
2368 struct pasn_data *pasn = sta->pasn;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002369 struct pasn_fils *fils = &pasn->fils;
Hai Shalom60840252021-02-19 19:02:11 -08002370 u8 pmk[PMK_LEN_MAX];
2371 size_t pmk_len;
2372 int ret;
2373
2374 wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
2375 status);
2376
2377 if (status != WLAN_STATUS_SUCCESS)
2378 goto fail;
2379
2380 if (!pasn->secret) {
2381 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
2382 goto fail;
2383 }
2384
2385 if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
2386 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
2387 goto fail;
2388 }
2389
2390 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
2391 fils->anonce, FILS_NONCE_LEN);
2392
2393 ret = fils_rmsk_to_pmk(pasn->akmp, msk, msk_len, fils->nonce,
2394 fils->anonce, NULL, 0, pmk, &pmk_len);
2395 if (ret) {
2396 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
2397 goto fail;
2398 }
2399
2400 ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
2401 wpabuf_head(pasn->secret),
2402 wpabuf_len(pasn->secret),
2403 &sta->pasn->ptk, sta->pasn->akmp,
Hai Shaloma20dcd72022-02-04 13:43:00 -08002404 sta->pasn->cipher, sta->pasn->kdk_len);
Hai Shalom60840252021-02-19 19:02:11 -08002405 if (ret) {
2406 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
2407 goto fail;
2408 }
2409
Sunil Ravi89eba102022-09-13 21:04:37 -07002410 if (pasn->secure_ltf) {
2411 ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp, pasn->cipher);
2412 if (ret) {
2413 wpa_printf(MSG_DEBUG,
2414 "PASN: FILS: Failed to derive LTF keyseed");
2415 goto fail;
2416 }
2417 }
2418
Hai Shalom60840252021-02-19 19:02:11 -08002419 wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
2420
2421 wpabuf_free(pasn->secret);
2422 pasn->secret = NULL;
2423
2424 fils->erp_resp = erp_resp;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002425 ret = handle_auth_pasn_resp(sta->pasn, hapd->own_addr, sta->addr, NULL,
2426 WLAN_STATUS_SUCCESS);
Hai Shalom60840252021-02-19 19:02:11 -08002427 fils->erp_resp = NULL;
2428
2429 if (ret) {
2430 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
2431 goto fail;
2432 }
2433
2434 fils->state = PASN_FILS_STATE_COMPLETE;
2435 return;
2436fail:
2437 ap_free_sta(hapd, sta);
2438}
2439
2440
2441static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
2442 struct wpabuf *wd)
2443{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002444#ifdef CONFIG_NO_RADIUS
2445 wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
2446 return -1;
2447#else /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002448 struct pasn_data *pasn = sta->pasn;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002449 struct pasn_fils *fils = &pasn->fils;
Hai Shalom60840252021-02-19 19:02:11 -08002450 struct ieee802_11_elems elems;
2451 struct wpa_ie_data rsne_data;
2452 struct wpabuf *fils_wd;
2453 const u8 *data;
2454 size_t buf_len;
2455 u16 alg, seq, status;
2456 int ret;
2457
2458 if (fils->state != PASN_FILS_STATE_NONE) {
2459 wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
2460 return -1;
2461 }
2462
2463 if (!wd) {
2464 wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
2465 return -1;
2466 }
2467
2468 data = wpabuf_head_u8(wd);
2469 buf_len = wpabuf_len(wd);
2470
2471 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002472 wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002473 buf_len);
2474 return -1;
2475 }
2476
2477 alg = WPA_GET_LE16(data);
2478 seq = WPA_GET_LE16(data + 2);
2479 status = WPA_GET_LE16(data + 4);
2480
2481 wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
2482 alg, seq, status);
2483
2484 if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
2485 status != WLAN_STATUS_SUCCESS) {
2486 wpa_printf(MSG_DEBUG,
2487 "PASN: FILS: Dropping peer authentication");
2488 return -1;
2489 }
2490
2491 data += 6;
2492 buf_len -= 6;
2493
2494 if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
2495 wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
2496 return -1;
2497 }
2498
2499 if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00002500 !elems.wrapped_data || !elems.fils_session) {
Hai Shalom60840252021-02-19 19:02:11 -08002501 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
2502 return -1;
2503 }
2504
2505 ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2506 &rsne_data);
2507 if (ret) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002508 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RSNE");
Hai Shalom60840252021-02-19 19:02:11 -08002509 return -1;
2510 }
2511
2512 ret = wpa_pasn_validate_rsne(&rsne_data);
2513 if (ret) {
2514 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
2515 return -1;
2516 }
2517
2518 if (rsne_data.num_pmkid) {
2519 wpa_printf(MSG_DEBUG,
2520 "PASN: FILS: Not expecting PMKID in RSNE");
2521 return -1;
2522 }
2523
2524 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
2525 FILS_NONCE_LEN);
2526 os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
2527
2528 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
2529 FILS_SESSION_LEN);
2530 os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
2531
Sunil Ravi72e01222024-03-09 01:25:43 +00002532 fils_wd = ieee802_11_defrag(elems.wrapped_data, elems.wrapped_data_len,
2533 true);
Hai Shalom60840252021-02-19 19:02:11 -08002534
2535 if (!fils_wd) {
2536 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
2537 return -1;
2538 }
2539
2540 if (!sta->eapol_sm)
2541 sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
2542
2543 wpa_printf(MSG_DEBUG,
2544 "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
2545
2546 ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
2547 wpabuf_len(fils_wd));
2548
2549 sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
2550
2551 fils->state = PASN_FILS_STATE_PENDING_AS;
2552
2553 /*
2554 * Calculate pending PMKID here so that we do not need to maintain a
2555 * copy of the EAP-Initiate/Reautt message.
2556 */
2557 fils_pmkid_erp(pasn->akmp, wpabuf_head(fils_wd), wpabuf_len(fils_wd),
2558 fils->erp_pmkid);
2559
2560 wpabuf_free(fils_wd);
2561 return 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002562#endif /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002563}
2564
2565#endif /* CONFIG_FILS */
2566
2567
Sunil Ravi77d572f2023-01-17 23:58:31 +00002568static int hapd_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len,
2569 int noack, unsigned int freq, unsigned int wait)
Hai Shalom60840252021-02-19 19:02:11 -08002570{
Sunil Ravi77d572f2023-01-17 23:58:31 +00002571 struct hostapd_data *hapd = ctx;
2572
2573 return hostapd_drv_send_mlme(hapd, data, data_len, 0, NULL, 0, 0);
2574}
2575
2576
2577static void hapd_initialize_pasn(struct hostapd_data *hapd,
2578 struct sta_info *sta)
2579{
2580 struct pasn_data *pasn = sta->pasn;
2581
2582 pasn->cb_ctx = hapd;
2583 pasn->send_mgmt = hapd_pasn_send_mlme;
2584 pasn->pasn_groups = hapd->conf->pasn_groups;
Sunil Ravi640215c2023-06-28 23:08:09 +00002585 pasn->noauth = hapd->conf->pasn_noauth;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002586 pasn->wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
2587 pasn->rsn_pairwise = hapd->conf->rsn_pairwise;
2588 pasn->derive_kdk = hapd->iface->drv_flags2 &
2589 WPA_DRIVER_FLAGS2_SEC_LTF_AP;
2590#ifdef CONFIG_TESTING_OPTIONS
2591 pasn->corrupt_mic = hapd->conf->pasn_corrupt_mic;
2592 if (hapd->conf->force_kdk_derivation)
2593 pasn->derive_kdk = true;
2594#endif /* CONFIG_TESTING_OPTIONS */
2595 pasn->use_anti_clogging = use_anti_clogging(hapd);
2596 pasn->password = sae_get_password(hapd, sta, NULL, NULL, &pasn->pt,
2597 NULL);
2598 pasn->rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &pasn->rsn_ie_len);
2599 pasn->rsnxe_ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
2600 pasn->disable_pmksa_caching = hapd->conf->disable_pmksa_caching;
2601 pasn->pmksa = wpa_auth_get_pmksa_cache(hapd->wpa_auth);
2602
2603 pasn->comeback_after = hapd->conf->pasn_comeback_after;
2604 pasn->comeback_idx = hapd->comeback_idx;
2605 pasn->comeback_key = hapd->comeback_key;
2606 pasn->comeback_pending_idx = hapd->comeback_pending_idx;
2607 os_memcpy(pasn->bssid, hapd->own_addr, ETH_ALEN);
Hai Shalom60840252021-02-19 19:02:11 -08002608}
2609
2610
Sunil Ravi89eba102022-09-13 21:04:37 -07002611static int pasn_set_keys_from_cache(struct hostapd_data *hapd,
2612 const u8 *own_addr, const u8 *sta_addr,
2613 int cipher, int akmp)
2614{
2615 struct ptksa_cache_entry *entry;
2616
2617 entry = ptksa_cache_get(hapd->ptksa, sta_addr, cipher);
2618 if (!entry) {
2619 wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR
2620 " not present in PTKSA cache", MAC2STR(sta_addr));
2621 return -1;
2622 }
2623
Sunil Ravi72e01222024-03-09 01:25:43 +00002624 if (!ether_addr_equal(entry->own_addr, own_addr)) {
Sunil Ravi89eba102022-09-13 21:04:37 -07002625 wpa_printf(MSG_DEBUG,
2626 "PASN: own addr " MACSTR " and PTKSA entry own addr "
2627 MACSTR " differ",
2628 MAC2STR(own_addr), MAC2STR(entry->own_addr));
2629 return -1;
2630 }
2631
2632 wpa_printf(MSG_DEBUG, "PASN: " MACSTR " present in PTKSA cache",
2633 MAC2STR(sta_addr));
2634 hostapd_drv_set_secure_ranging_ctx(hapd, own_addr, sta_addr, cipher,
2635 entry->ptk.tk_len, entry->ptk.tk,
2636 entry->ptk.ltf_keyseed_len,
2637 entry->ptk.ltf_keyseed, 0);
2638
2639 return 0;
2640}
2641
2642
Sunil Ravi77d572f2023-01-17 23:58:31 +00002643static void hapd_pasn_update_params(struct hostapd_data *hapd,
2644 struct sta_info *sta,
2645 const struct ieee80211_mgmt *mgmt,
2646 size_t len)
Hai Shalom60840252021-02-19 19:02:11 -08002647{
Sunil Ravi77d572f2023-01-17 23:58:31 +00002648 struct pasn_data *pasn = sta->pasn;
Hai Shalom60840252021-02-19 19:02:11 -08002649 struct ieee802_11_elems elems;
2650 struct wpa_ie_data rsn_data;
Sunil Ravi72e01222024-03-09 01:25:43 +00002651#ifdef CONFIG_FILS
Hai Shalom60840252021-02-19 19:02:11 -08002652 struct wpa_pasn_params_data pasn_params;
Hai Shalom60840252021-02-19 19:02:11 -08002653 struct wpabuf *wrapped_data = NULL;
Sunil Ravi72e01222024-03-09 01:25:43 +00002654#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08002655
2656 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
2657 len - offsetof(struct ieee80211_mgmt,
2658 u.auth.variable),
2659 &elems, 0) == ParseFailed) {
2660 wpa_printf(MSG_DEBUG,
2661 "PASN: Failed parsing Authentication frame");
Sunil Ravi77d572f2023-01-17 23:58:31 +00002662 return;
Hai Shalom60840252021-02-19 19:02:11 -08002663 }
2664
Sunil Ravi77d572f2023-01-17 23:58:31 +00002665 if (!elems.rsn_ie ||
2666 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2667 &rsn_data)) {
2668 wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE");
2669 return;
2670 }
2671
2672 if (!(rsn_data.key_mgmt & pasn->wpa_key_mgmt) ||
2673 !(rsn_data.pairwise_cipher & pasn->rsn_pairwise)) {
2674 wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
2675 return;
2676 }
2677
2678 pasn->akmp = rsn_data.key_mgmt;
2679 pasn->cipher = rsn_data.pairwise_cipher;
2680
2681 if (wpa_key_mgmt_ft(pasn->akmp) && rsn_data.num_pmkid) {
2682#ifdef CONFIG_IEEE80211R_AP
2683 pasn->pmk_r1_len = 0;
2684 wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
2685 rsn_data.pmkid,
2686 pasn->pmk_r1, &pasn->pmk_r1_len, NULL,
2687 NULL, NULL, NULL,
2688 NULL, NULL, NULL);
2689#endif /* CONFIG_IEEE80211R_AP */
2690 }
2691#ifdef CONFIG_FILS
2692 if (pasn->akmp != WPA_KEY_MGMT_FILS_SHA256 &&
2693 pasn->akmp != WPA_KEY_MGMT_FILS_SHA384)
2694 return;
2695 if (!elems.pasn_params ||
2696 wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
2697 elems.pasn_params_len + 3,
2698 false, &pasn_params)) {
Hai Shalom60840252021-02-19 19:02:11 -08002699 wpa_printf(MSG_DEBUG,
Sunil Ravi77d572f2023-01-17 23:58:31 +00002700 "PASN: Failed validation of PASN Parameters element");
2701 return;
Hai Shalom60840252021-02-19 19:02:11 -08002702 }
Hai Shalom60840252021-02-19 19:02:11 -08002703 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
Sunil Ravi72e01222024-03-09 01:25:43 +00002704 wrapped_data = ieee802_11_defrag(elems.wrapped_data,
2705 elems.wrapped_data_len, true);
Hai Shalom60840252021-02-19 19:02:11 -08002706 if (!wrapped_data) {
2707 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
Sunil Ravi77d572f2023-01-17 23:58:31 +00002708 return;
Hai Shalom60840252021-02-19 19:02:11 -08002709 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00002710 if (pasn_wd_handle_fils(hapd, sta, wrapped_data))
2711 wpa_printf(MSG_DEBUG,
2712 "PASN: Failed processing FILS wrapped data");
2713 else
2714 pasn->fils_wd_valid = true;
Hai Shalom60840252021-02-19 19:02:11 -08002715 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00002716 wpabuf_free(wrapped_data);
2717#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08002718}
2719
2720
2721static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
2722 const struct ieee80211_mgmt *mgmt, size_t len,
2723 u16 trans_seq, u16 status)
2724{
2725 if (hapd->conf->wpa != WPA_PROTO_RSN) {
2726 wpa_printf(MSG_INFO, "PASN: RSN is not configured");
2727 return;
2728 }
2729
2730 wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR,
2731 MAC2STR(sta->addr));
2732
2733 if (trans_seq == 1) {
2734 if (sta->pasn) {
2735 wpa_printf(MSG_DEBUG,
2736 "PASN: Not expecting transaction == 1");
2737 return;
2738 }
2739
2740 if (status != WLAN_STATUS_SUCCESS) {
2741 wpa_printf(MSG_DEBUG,
2742 "PASN: Failure status in transaction == 1");
2743 return;
2744 }
2745
2746 sta->pasn = os_zalloc(sizeof(*sta->pasn));
2747 if (!sta->pasn) {
2748 wpa_printf(MSG_DEBUG,
2749 "PASN: Failed to allocate PASN context");
2750 return;
2751 }
2752
Sunil Ravi77d572f2023-01-17 23:58:31 +00002753 hapd_initialize_pasn(hapd, sta);
2754
2755 hapd_pasn_update_params(hapd, sta, mgmt, len);
2756 if (handle_auth_pasn_1(sta->pasn, hapd->own_addr,
2757 sta->addr, mgmt, len) < 0)
2758 ap_free_sta(hapd, sta);
Hai Shalom60840252021-02-19 19:02:11 -08002759 } else if (trans_seq == 3) {
2760 if (!sta->pasn) {
2761 wpa_printf(MSG_DEBUG,
2762 "PASN: Not expecting transaction == 3");
2763 return;
2764 }
2765
2766 if (status != WLAN_STATUS_SUCCESS) {
2767 wpa_printf(MSG_DEBUG,
2768 "PASN: Failure status in transaction == 3");
2769 ap_free_sta_pasn(hapd, sta);
2770 return;
2771 }
2772
Sunil Ravi77d572f2023-01-17 23:58:31 +00002773 if (handle_auth_pasn_3(sta->pasn, hapd->own_addr,
2774 sta->addr, mgmt, len) == 0) {
2775 ptksa_cache_add(hapd->ptksa, hapd->own_addr, sta->addr,
2776 sta->pasn->cipher, 43200,
2777 &sta->pasn->ptk, NULL, NULL,
2778 sta->pasn->akmp);
2779
2780 pasn_set_keys_from_cache(hapd, hapd->own_addr,
2781 sta->addr, sta->pasn->cipher,
2782 sta->pasn->akmp);
2783 }
2784 ap_free_sta(hapd, sta);
Hai Shalom60840252021-02-19 19:02:11 -08002785 } else {
2786 wpa_printf(MSG_DEBUG,
2787 "PASN: Invalid transaction %u - ignore", trans_seq);
2788 }
2789}
2790
2791#endif /* CONFIG_PASN */
2792
2793
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002794static void handle_auth(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08002795 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom021b0b52019-04-10 11:17:58 -07002796 int rssi, int from_queue)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002797{
2798 u16 auth_alg, auth_transaction, status_code;
2799 u16 resp = WLAN_STATUS_SUCCESS;
2800 struct sta_info *sta = NULL;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002801 int res, reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002802 u16 fc;
2803 const u8 *challenge = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002804 u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
2805 size_t resp_ies_len = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002806 u16 seq_ctrl;
Hai Shalomfdcde762020-04-02 11:19:20 -07002807 struct radius_sta rad_info;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002808 const u8 *dst, *sa, *bssid;
2809 bool mld_sta = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002810
2811 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002812 wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
2813 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002814 return;
2815 }
2816
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002817#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002818 if (hapd->iconf->ignore_auth_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002819 drand48() < hapd->iconf->ignore_auth_probability) {
2820 wpa_printf(MSG_INFO,
2821 "TESTING: ignoring auth frame from " MACSTR,
2822 MAC2STR(mgmt->sa));
2823 return;
2824 }
2825#endif /* CONFIG_TESTING_OPTIONS */
2826
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002827 sa = mgmt->sa;
2828#ifdef CONFIG_IEEE80211BE
2829 /*
2830 * Handle MLO authentication before the station is added to hostapd and
2831 * the driver so that the station MLD MAC address would be used in both
2832 * hostapd and the driver.
2833 */
2834 sa = hostapd_process_ml_auth(hapd, mgmt, len);
2835 if (sa)
2836 mld_sta = true;
2837 else
2838 sa = mgmt->sa;
2839#endif /* CONFIG_IEEE80211BE */
2840
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002841 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
2842 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
2843 status_code = le_to_host16(mgmt->u.auth.status_code);
2844 fc = le_to_host16(mgmt->frame_control);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002845 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002846
2847 if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
2848 2 + WLAN_AUTH_CHALLENGE_LEN &&
2849 mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
2850 mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
2851 challenge = &mgmt->u.auth.variable[2];
2852
2853 wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002854 "auth_transaction=%d status_code=%d wep=%d%s "
Hai Shalom021b0b52019-04-10 11:17:58 -07002855 "seq_ctrl=0x%x%s%s",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002856 MAC2STR(sa), auth_alg, auth_transaction,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002857 status_code, !!(fc & WLAN_FC_ISWEP),
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002858 challenge ? " challenge" : "",
Hai Shalom021b0b52019-04-10 11:17:58 -07002859 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
2860 from_queue ? " (from queue)" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002861
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002862#ifdef CONFIG_NO_RC4
2863 if (auth_alg == WLAN_AUTH_SHARED_KEY) {
2864 wpa_printf(MSG_INFO,
2865 "Unsupported authentication algorithm (%d)",
2866 auth_alg);
2867 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
2868 goto fail;
2869 }
2870#endif /* CONFIG_NO_RC4 */
2871
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002872 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002873 wpa_printf(MSG_DEBUG,
2874 "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
2875 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002876 goto fail;
2877 }
2878
2879 if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
2880 auth_alg == WLAN_AUTH_OPEN) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002881#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002882 (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002883 auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002884#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002885#ifdef CONFIG_SAE
2886 (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
2887 auth_alg == WLAN_AUTH_SAE) ||
2888#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002889#ifdef CONFIG_FILS
2890 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
2891 auth_alg == WLAN_AUTH_FILS_SK) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002892 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
2893 hapd->conf->fils_dh_group &&
2894 auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002895#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08002896#ifdef CONFIG_PASN
2897 (hapd->conf->wpa &&
2898 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) &&
2899 auth_alg == WLAN_AUTH_PASN) ||
2900#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002901 ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
2902 auth_alg == WLAN_AUTH_SHARED_KEY))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002903 wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
2904 auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002905 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
2906 goto fail;
2907 }
2908
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002909 if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
Hai Shalom60840252021-02-19 19:02:11 -08002910#ifdef CONFIG_PASN
2911 (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) ||
2912#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002913 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002914 wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
2915 auth_transaction);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002916 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
2917 goto fail;
2918 }
2919
Sunil Ravi72e01222024-03-09 01:25:43 +00002920 if (ether_addr_equal(mgmt->sa, hapd->own_addr)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002921 wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002922 MAC2STR(sa));
2923 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2924 goto fail;
2925 }
2926
2927 if (mld_sta &&
Sunil Ravi72e01222024-03-09 01:25:43 +00002928 (ether_addr_equal(sa, hapd->own_addr) ||
2929 ether_addr_equal(sa, hapd->mld_addr))) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002930 wpa_printf(MSG_INFO,
2931 "Station " MACSTR " not allowed to authenticate",
2932 MAC2STR(sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002933 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2934 goto fail;
2935 }
2936
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002937 if (hapd->conf->no_auth_if_seen_on) {
2938 struct hostapd_data *other;
2939
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002940 other = sta_track_seen_on(hapd->iface, sa,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002941 hapd->conf->no_auth_if_seen_on);
2942 if (other) {
2943 u8 *pos;
2944 u32 info;
2945 u8 op_class, channel, phytype;
2946
2947 wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
2948 MACSTR " since STA has been seen on %s",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002949 hapd->conf->iface, MAC2STR(sa),
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002950 hapd->conf->no_auth_if_seen_on);
2951
2952 resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
2953 pos = &resp_ies[0];
2954 *pos++ = WLAN_EID_NEIGHBOR_REPORT;
2955 *pos++ = 13;
2956 os_memcpy(pos, other->own_addr, ETH_ALEN);
2957 pos += ETH_ALEN;
2958 info = 0; /* TODO: BSSID Information */
2959 WPA_PUT_LE32(pos, info);
2960 pos += 4;
2961 if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
2962 phytype = 8; /* dmg */
2963 else if (other->iconf->ieee80211ac)
2964 phytype = 9; /* vht */
2965 else if (other->iconf->ieee80211n)
2966 phytype = 7; /* ht */
2967 else if (other->iconf->hw_mode ==
2968 HOSTAPD_MODE_IEEE80211A)
2969 phytype = 4; /* ofdm */
2970 else if (other->iconf->hw_mode ==
2971 HOSTAPD_MODE_IEEE80211G)
2972 phytype = 6; /* erp */
2973 else
2974 phytype = 5; /* hrdsss */
2975 if (ieee80211_freq_to_channel_ext(
2976 hostapd_hw_get_freq(other,
2977 other->iconf->channel),
2978 other->iconf->secondary_channel,
2979 other->iconf->ieee80211ac,
2980 &op_class, &channel) == NUM_HOSTAPD_MODES) {
2981 op_class = 0;
2982 channel = other->iconf->channel;
2983 }
2984 *pos++ = op_class;
2985 *pos++ = channel;
2986 *pos++ = phytype;
2987 resp_ies_len = pos - &resp_ies[0];
2988 goto fail;
2989 }
2990 }
2991
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002992 res = ieee802_11_allowed_address(hapd, sa, (const u8 *) mgmt, len,
Hai Shalomfdcde762020-04-02 11:19:20 -07002993 &rad_info);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002994 if (res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002995 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
2996 "Ignore Authentication frame from " MACSTR
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002997 " due to ACL reject", MAC2STR(sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002998 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2999 goto fail;
3000 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003001 if (res == HOSTAPD_ACL_PENDING)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003002 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003003
Hai Shalom021b0b52019-04-10 11:17:58 -07003004#ifdef CONFIG_SAE
3005 if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
3006 (auth_transaction == 1 ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003007 (auth_transaction == 2 && auth_sae_queued_addr(hapd, sa)))) {
Hai Shalom021b0b52019-04-10 11:17:58 -07003008 /* Handle SAE Authentication commit message through a queue to
3009 * provide more control for postponing the needed heavy
3010 * processing under a possible DoS attack scenario. In addition,
3011 * queue SAE Authentication confirm message if there happens to
3012 * be a queued commit message from the same peer. This is needed
3013 * to avoid reordering Authentication frames within the same
3014 * SAE exchange. */
3015 auth_sae_queue(hapd, mgmt, len, rssi);
3016 return;
3017 }
3018#endif /* CONFIG_SAE */
3019
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003020 sta = ap_get_sta(hapd, sa);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003021 if (sta) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003022 sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
Hai Shalom74f70d42019-02-11 14:42:39 -08003023 sta->ft_over_ds = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003024 if ((fc & WLAN_FC_RETRY) &&
3025 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
3026 sta->last_seq_ctrl == seq_ctrl &&
3027 sta->last_subtype == WLAN_FC_STYPE_AUTH) {
3028 hostapd_logger(hapd, sta->addr,
3029 HOSTAPD_MODULE_IEEE80211,
3030 HOSTAPD_LEVEL_DEBUG,
3031 "Drop repeated authentication frame seq_ctrl=0x%x",
3032 seq_ctrl);
3033 return;
3034 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003035#ifdef CONFIG_MESH
3036 if ((hapd->conf->mesh & MESH_ENABLED) &&
3037 sta->plink_state == PLINK_BLOCKED) {
3038 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
3039 " is blocked - drop Authentication frame",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003040 MAC2STR(sa));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003041 return;
3042 }
3043#endif /* CONFIG_MESH */
Hai Shalom60840252021-02-19 19:02:11 -08003044#ifdef CONFIG_PASN
3045 if (auth_alg == WLAN_AUTH_PASN &&
3046 (sta->flags & WLAN_STA_ASSOC)) {
3047 wpa_printf(MSG_DEBUG,
3048 "PASN: auth: Existing station: " MACSTR,
3049 MAC2STR(sta->addr));
3050 return;
3051 }
3052#endif /* CONFIG_PASN */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003053 } else {
3054#ifdef CONFIG_MESH
3055 if (hapd->conf->mesh & MESH_ENABLED) {
3056 /* if the mesh peer is not available, we don't do auth.
3057 */
3058 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003059 " not yet known - drop Authentication frame",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003060 MAC2STR(sa));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003061 /*
3062 * Save a copy of the frame so that it can be processed
3063 * if a new peer entry is added shortly after this.
3064 */
3065 wpabuf_free(hapd->mesh_pending_auth);
3066 hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len);
3067 os_get_reltime(&hapd->mesh_pending_auth_time);
3068 return;
3069 }
3070#endif /* CONFIG_MESH */
3071
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003072 sta = ap_sta_add(hapd, sa);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003073 if (!sta) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003074 wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003075 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3076 goto fail;
3077 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003078 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003079
3080#ifdef CONFIG_IEEE80211BE
3081 if (auth_transaction == 1) {
Sunil Ravi72e01222024-03-09 01:25:43 +00003082 ap_sta_free_sta_profile(&sta->mld_info);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003083 os_memset(&sta->mld_info, 0, sizeof(sta->mld_info));
3084
3085 if (mld_sta) {
3086 u8 link_id = hapd->mld_link_id;
3087
Sunil Ravi72e01222024-03-09 01:25:43 +00003088 ap_sta_set_mld(sta, true);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003089 sta->mld_assoc_link_id = link_id;
3090
3091 /*
3092 * Set the MLD address as the station address and the
3093 * station addresses.
3094 */
3095 os_memcpy(sta->mld_info.common_info.mld_addr, sa,
3096 ETH_ALEN);
3097 os_memcpy(sta->mld_info.links[link_id].peer_addr,
3098 mgmt->sa, ETH_ALEN);
3099 os_memcpy(sta->mld_info.links[link_id].local_addr,
3100 hapd->own_addr, ETH_ALEN);
3101 }
3102 }
3103#endif /* CONFIG_IEEE80211BE */
3104
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003105 sta->last_seq_ctrl = seq_ctrl;
3106 sta->last_subtype = WLAN_FC_STYPE_AUTH;
Hai Shalom74f70d42019-02-11 14:42:39 -08003107#ifdef CONFIG_MBO
3108 sta->auth_rssi = rssi;
3109#endif /* CONFIG_MBO */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003110
Hai Shalomfdcde762020-04-02 11:19:20 -07003111 res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003112 if (res) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003113 wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003114 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3115 goto fail;
3116 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003117
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003118 sta->flags &= ~WLAN_STA_PREAUTH;
3119 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
3120
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003121 /*
3122 * If the driver supports full AP client state, add a station to the
3123 * driver before sending authentication reply to make sure the driver
3124 * has resources, and not to go through the entire authentication and
3125 * association handshake, and fail it at the end.
3126 *
3127 * If this is not the first transaction, in a multi-step authentication
3128 * algorithm, the station already exists in the driver
3129 * (sta->added_unassoc = 1) so skip it.
3130 *
3131 * In mesh mode, the station was already added to the driver when the
3132 * NEW_PEER_CANDIDATE event is received.
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003133 *
3134 * If PMF was negotiated for the existing association, skip this to
3135 * avoid dropping the STA entry and the associated keys. This is needed
3136 * to allow the original connection work until the attempt can complete
3137 * (re)association, so that unprotected Authentication frame cannot be
3138 * used to bypass PMF protection.
Hai Shalom60840252021-02-19 19:02:11 -08003139 *
3140 * PASN authentication does not require adding/removing station to the
3141 * driver so skip this flow in case of PASN authentication.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003142 */
3143 if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003144 (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003145 !(hapd->conf->mesh & MESH_ENABLED) &&
Hai Shalom60840252021-02-19 19:02:11 -08003146 !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) {
Hai Shalomb755a2a2020-04-23 21:49:02 -07003147 if (ap_sta_re_add(hapd, sta) < 0) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003148 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3149 goto fail;
3150 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003151 }
3152
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003153 switch (auth_alg) {
3154 case WLAN_AUTH_OPEN:
3155 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3156 HOSTAPD_LEVEL_DEBUG,
3157 "authentication OK (open system)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003158 sta->flags |= WLAN_STA_AUTH;
3159 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
3160 sta->auth_alg = WLAN_AUTH_OPEN;
3161 mlme_authenticate_indication(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003162 break;
Hai Shalomfdcde762020-04-02 11:19:20 -07003163#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003164#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003165 case WLAN_AUTH_SHARED_KEY:
3166 resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
3167 fc & WLAN_FC_ISWEP);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003168 if (resp != 0)
3169 wpa_printf(MSG_DEBUG,
3170 "auth_shared_key() failed: status=%d", resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003171 sta->auth_alg = WLAN_AUTH_SHARED_KEY;
3172 mlme_authenticate_indication(hapd, sta);
3173 if (sta->challenge && auth_transaction == 1) {
3174 resp_ies[0] = WLAN_EID_CHALLENGE;
3175 resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
3176 os_memcpy(resp_ies + 2, sta->challenge,
3177 WLAN_AUTH_CHALLENGE_LEN);
3178 resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
3179 }
3180 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003181#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003182#endif /* CONFIG_WEP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003183#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003184 case WLAN_AUTH_FT:
3185 sta->auth_alg = WLAN_AUTH_FT;
3186 if (sta->wpa_sm == NULL)
3187 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003188 sta->addr, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003189 if (sta->wpa_sm == NULL) {
3190 wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
3191 "state machine");
3192 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3193 goto fail;
3194 }
3195 wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
3196 auth_transaction, mgmt->u.auth.variable,
3197 len - IEEE80211_HDRLEN -
3198 sizeof(mgmt->u.auth),
3199 handle_auth_ft_finish, hapd);
3200 /* handle_auth_ft_finish() callback will complete auth. */
3201 return;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003202#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003203#ifdef CONFIG_SAE
3204 case WLAN_AUTH_SAE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003205#ifdef CONFIG_MESH
3206 if (status_code == WLAN_STATUS_SUCCESS &&
3207 hapd->conf->mesh & MESH_ENABLED) {
3208 if (sta->wpa_sm == NULL)
3209 sta->wpa_sm =
3210 wpa_auth_sta_init(hapd->wpa_auth,
3211 sta->addr, NULL);
3212 if (sta->wpa_sm == NULL) {
3213 wpa_printf(MSG_DEBUG,
3214 "SAE: Failed to initialize WPA state machine");
3215 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3216 goto fail;
3217 }
3218 }
3219#endif /* CONFIG_MESH */
3220 handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
3221 status_code);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003222 return;
3223#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003224#ifdef CONFIG_FILS
3225 case WLAN_AUTH_FILS_SK:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003226 case WLAN_AUTH_FILS_SK_PFS:
3227 handle_auth_fils(hapd, sta, mgmt->u.auth.variable,
3228 len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth),
3229 auth_alg, auth_transaction, status_code,
3230 handle_auth_fils_finish);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003231 return;
3232#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08003233#ifdef CONFIG_PASN
3234 case WLAN_AUTH_PASN:
3235 handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction,
3236 status_code);
3237 return;
3238#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003239 }
3240
3241 fail:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003242 dst = mgmt->sa;
3243 bssid = mgmt->bssid;
3244
3245#ifdef CONFIG_IEEE80211BE
3246 /*
3247 * Once a non-AP MLD is added to the driver, the addressing should use
3248 * the MLD MAC address. It is the responsibility of the driver to
3249 * handle the translations.
3250 */
Sunil Ravi72e01222024-03-09 01:25:43 +00003251 if (ap_sta_is_mld(hapd, sta)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003252 dst = sta->addr;
3253 bssid = hapd->mld_addr;
3254 }
3255#endif /* CONFIG_IEEE80211BE */
3256
3257 reply_res = send_auth_reply(hapd, sta, dst, bssid, auth_alg,
Hai Shaloma20dcd72022-02-04 13:43:00 -08003258 auth_alg == WLAN_AUTH_SAE ?
3259 auth_transaction : auth_transaction + 1,
3260 resp, resp_ies, resp_ies_len,
3261 "handle-auth");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003262
3263 if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
3264 reply_res != WLAN_STATUS_SUCCESS)) {
3265 hostapd_drv_sta_remove(hapd, sta->addr);
3266 sta->added_unassoc = 0;
3267 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003268}
3269
3270
Sunil Ravi77d572f2023-01-17 23:58:31 +00003271static u8 hostapd_max_bssid_indicator(struct hostapd_data *hapd)
3272{
3273 size_t num_bss_nontx;
3274 u8 max_bssid_ind = 0;
3275
3276 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1)
3277 return 0;
3278
3279 num_bss_nontx = hapd->iface->num_bss - 1;
3280 while (num_bss_nontx > 0) {
3281 max_bssid_ind++;
3282 num_bss_nontx >>= 1;
3283 }
3284 return max_bssid_ind;
3285}
3286
3287
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003288static u32 hostapd_get_aid_word(struct hostapd_data *hapd,
3289 struct sta_info *sta, int i)
3290{
3291#ifdef CONFIG_IEEE80211BE
3292 u32 aid_word = 0;
3293
3294 /* Do not assign an AID that is in use on any of the affiliated links
3295 * when finding an AID for a non-AP MLD. */
Sunil Ravi72e01222024-03-09 01:25:43 +00003296 if (hapd->conf->mld_ap && sta->mld_info.mld_sta) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003297 int j;
3298
3299 for (j = 0; j < MAX_NUM_MLD_LINKS; j++) {
3300 struct hostapd_data *link_bss;
3301
3302 if (!sta->mld_info.links[j].valid)
3303 continue;
3304
3305 link_bss = hostapd_mld_get_link_bss(hapd, j);
3306 if (!link_bss) {
3307 /* This shouldn't happen, just skip */
3308 wpa_printf(MSG_ERROR,
3309 "MLD: Failed to get link BSS for AID");
3310 continue;
3311 }
3312
3313 aid_word |= link_bss->sta_aid[i];
3314 }
3315
3316 return aid_word;
3317 }
3318#endif /* CONFIG_IEEE80211BE */
3319
3320 return hapd->sta_aid[i];
3321}
3322
3323
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003324int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003325{
3326 int i, j = 32, aid;
3327
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003328 /* Transmitted and non-transmitted BSSIDs share the same AID pool, so
3329 * use the shared storage in the transmitted BSS to find the next
3330 * available value. */
3331 hapd = hostapd_mbssid_get_tx_bss(hapd);
3332
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003333 /* get a unique AID */
3334 if (sta->aid > 0) {
3335 wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
3336 return 0;
3337 }
3338
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003339 if (TEST_FAIL())
3340 return -1;
3341
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003342 for (i = 0; i < AID_WORDS; i++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003343 u32 aid_word = hostapd_get_aid_word(hapd, sta, i);
3344
3345 if (aid_word == (u32) -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003346 continue;
3347 for (j = 0; j < 32; j++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003348 if (!(aid_word & BIT(j)))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003349 break;
3350 }
3351 if (j < 32)
3352 break;
3353 }
3354 if (j == 32)
3355 return -1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003356 aid = i * 32 + j + (1 << hostapd_max_bssid_indicator(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003357 if (aid > 2007)
3358 return -1;
3359
3360 sta->aid = aid;
3361 hapd->sta_aid[i] |= BIT(j);
3362 wpa_printf(MSG_DEBUG, " new AID %d", sta->aid);
3363 return 0;
3364}
3365
3366
3367static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
3368 const u8 *ssid_ie, size_t ssid_ie_len)
3369{
3370 if (ssid_ie == NULL)
3371 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3372
3373 if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
3374 os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003375 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3376 HOSTAPD_LEVEL_INFO,
3377 "Station tried to associate with unknown SSID "
Dmitry Shmidt3c479372014-02-04 10:50:36 -08003378 "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003379 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3380 }
3381
3382 return WLAN_STATUS_SUCCESS;
3383}
3384
3385
3386static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
3387 const u8 *wmm_ie, size_t wmm_ie_len)
3388{
3389 sta->flags &= ~WLAN_STA_WMM;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003390 sta->qosinfo = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003391 if (wmm_ie && hapd->conf->wmm_enabled) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003392 struct wmm_information_element *wmm;
3393
3394 if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003395 hostapd_logger(hapd, sta->addr,
3396 HOSTAPD_MODULE_WPA,
3397 HOSTAPD_LEVEL_DEBUG,
3398 "invalid WMM element in association "
3399 "request");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003400 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3401 }
3402
3403 sta->flags |= WLAN_STA_WMM;
3404 wmm = (struct wmm_information_element *) wmm_ie;
3405 sta->qosinfo = wmm->qos_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003406 }
3407 return WLAN_STATUS_SUCCESS;
3408}
3409
Hai Shalom74f70d42019-02-11 14:42:39 -08003410static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
3411 const u8 *multi_ap_ie, size_t multi_ap_len)
3412{
3413 u8 multi_ap_value = 0;
3414
3415 sta->flags &= ~WLAN_STA_MULTI_AP;
3416
3417 if (!hapd->conf->multi_ap)
3418 return WLAN_STATUS_SUCCESS;
3419
3420 if (multi_ap_ie) {
3421 const u8 *multi_ap_subelem;
3422
3423 multi_ap_subelem = get_ie(multi_ap_ie + 4,
3424 multi_ap_len - 4,
3425 MULTI_AP_SUB_ELEM_TYPE);
3426 if (multi_ap_subelem && multi_ap_subelem[1] == 1) {
3427 multi_ap_value = multi_ap_subelem[2];
3428 } else {
3429 hostapd_logger(hapd, sta->addr,
3430 HOSTAPD_MODULE_IEEE80211,
3431 HOSTAPD_LEVEL_INFO,
3432 "Multi-AP IE has missing or invalid Multi-AP subelement");
3433 return WLAN_STATUS_INVALID_IE;
3434 }
3435 }
3436
Hai Shalom021b0b52019-04-10 11:17:58 -07003437 if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA)
3438 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3439 HOSTAPD_LEVEL_INFO,
3440 "Multi-AP IE with unexpected value 0x%02x",
3441 multi_ap_value);
Hai Shalom74f70d42019-02-11 14:42:39 -08003442
Hai Shalom021b0b52019-04-10 11:17:58 -07003443 if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) {
3444 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
3445 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08003446
Hai Shalom021b0b52019-04-10 11:17:58 -07003447 hostapd_logger(hapd, sta->addr,
3448 HOSTAPD_MODULE_IEEE80211,
3449 HOSTAPD_LEVEL_INFO,
3450 "Non-Multi-AP STA tries to associate with backhaul-only BSS");
3451 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
Hai Shalom74f70d42019-02-11 14:42:39 -08003452 }
3453
Hai Shalom021b0b52019-04-10 11:17:58 -07003454 if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
3455 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3456 HOSTAPD_LEVEL_DEBUG,
3457 "Backhaul STA tries to associate with fronthaul-only BSS");
3458
3459 sta->flags |= WLAN_STA_MULTI_AP;
3460 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08003461}
3462
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003463
3464static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
3465 struct ieee802_11_elems *elems)
3466{
Dmitry Shmidt29333592017-01-09 12:27:11 -08003467 /* Supported rates not used in IEEE 802.11ad/DMG */
3468 if (hapd->iface->current_mode &&
3469 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
3470 return WLAN_STATUS_SUCCESS;
3471
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003472 if (!elems->supp_rates) {
3473 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3474 HOSTAPD_LEVEL_DEBUG,
3475 "No supported rates element in AssocReq");
3476 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3477 }
3478
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003479 if (elems->supp_rates_len + elems->ext_supp_rates_len >
3480 sizeof(sta->supported_rates)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003481 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3482 HOSTAPD_LEVEL_DEBUG,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003483 "Invalid supported rates element length %d+%d",
3484 elems->supp_rates_len,
3485 elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003486 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3487 }
3488
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003489 sta->supported_rates_len = merge_byte_arrays(
3490 sta->supported_rates, sizeof(sta->supported_rates),
3491 elems->supp_rates, elems->supp_rates_len,
3492 elems->ext_supp_rates, elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003493
3494 return WLAN_STATUS_SUCCESS;
3495}
3496
3497
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003498#ifdef CONFIG_OWE
3499
3500static int owe_group_supported(struct hostapd_data *hapd, u16 group)
3501{
3502 int i;
3503 int *groups = hapd->conf->owe_groups;
3504
3505 if (group != 19 && group != 20 && group != 21)
3506 return 0;
3507
3508 if (!groups)
3509 return 1;
3510
3511 for (i = 0; groups[i] > 0; i++) {
3512 if (groups[i] == group)
3513 return 1;
3514 }
3515
3516 return 0;
3517}
3518
3519
3520static u16 owe_process_assoc_req(struct hostapd_data *hapd,
3521 struct sta_info *sta, const u8 *owe_dh,
3522 u8 owe_dh_len)
3523{
3524 struct wpabuf *secret, *pub, *hkey;
3525 int res;
3526 u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN];
3527 const char *info = "OWE Key Generation";
3528 const u8 *addr[2];
3529 size_t len[2];
3530 u16 group;
3531 size_t hash_len, prime_len;
3532
3533 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
3534 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
3535 return WLAN_STATUS_SUCCESS;
3536 }
3537
3538 group = WPA_GET_LE16(owe_dh);
3539 if (!owe_group_supported(hapd, group)) {
3540 wpa_printf(MSG_DEBUG, "OWE: Unsupported DH group %u", group);
3541 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3542 }
3543 if (group == 19)
3544 prime_len = 32;
3545 else if (group == 20)
3546 prime_len = 48;
3547 else if (group == 21)
3548 prime_len = 66;
3549 else
3550 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3551
Sunil Ravia04bd252022-05-02 22:54:18 -07003552 if (sta->owe_group == group && sta->owe_ecdh) {
3553 /* This is a workaround for mac80211 behavior of retransmitting
3554 * the Association Request frames multiple times if the link
3555 * layer retries (i.e., seq# remains same) fail. The mac80211
3556 * initiated retransmission will use a different seq# and as
3557 * such, will go through duplicate detection. If we were to
3558 * change our DH key for that attempt, there would be two
3559 * different DH shared secrets and the STA would likely select
3560 * the wrong one. */
3561 wpa_printf(MSG_DEBUG,
3562 "OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again");
3563 } else {
3564 crypto_ecdh_deinit(sta->owe_ecdh);
3565 sta->owe_ecdh = crypto_ecdh_init(group);
3566 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003567 if (!sta->owe_ecdh)
3568 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3569 sta->owe_group = group;
3570
3571 secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2,
3572 owe_dh_len - 2);
3573 secret = wpabuf_zeropad(secret, prime_len);
3574 if (!secret) {
3575 wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
3576 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3577 }
3578 wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
3579
3580 /* prk = HKDF-extract(C | A | group, z) */
3581
3582 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
3583 if (!pub) {
3584 wpabuf_clear_free(secret);
3585 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3586 }
3587
3588 /* PMKID = Truncate-128(Hash(C | A)) */
3589 addr[0] = owe_dh + 2;
3590 len[0] = owe_dh_len - 2;
3591 addr[1] = wpabuf_head(pub);
3592 len[1] = wpabuf_len(pub);
3593 if (group == 19) {
3594 res = sha256_vector(2, addr, len, pmkid);
3595 hash_len = SHA256_MAC_LEN;
3596 } else if (group == 20) {
3597 res = sha384_vector(2, addr, len, pmkid);
3598 hash_len = SHA384_MAC_LEN;
3599 } else if (group == 21) {
3600 res = sha512_vector(2, addr, len, pmkid);
3601 hash_len = SHA512_MAC_LEN;
3602 } else {
3603 wpabuf_free(pub);
3604 wpabuf_clear_free(secret);
3605 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3606 }
3607 pub = wpabuf_zeropad(pub, prime_len);
3608 if (res < 0 || !pub) {
3609 wpabuf_free(pub);
3610 wpabuf_clear_free(secret);
3611 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3612 }
3613
3614 hkey = wpabuf_alloc(owe_dh_len - 2 + wpabuf_len(pub) + 2);
3615 if (!hkey) {
3616 wpabuf_free(pub);
3617 wpabuf_clear_free(secret);
3618 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3619 }
3620
3621 wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */
3622 wpabuf_put_buf(hkey, pub); /* A */
3623 wpabuf_free(pub);
3624 wpabuf_put_le16(hkey, group); /* group */
3625 if (group == 19)
3626 res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
3627 wpabuf_head(secret), wpabuf_len(secret), prk);
3628 else if (group == 20)
3629 res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey),
3630 wpabuf_head(secret), wpabuf_len(secret), prk);
3631 else if (group == 21)
3632 res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey),
3633 wpabuf_head(secret), wpabuf_len(secret), prk);
3634 wpabuf_clear_free(hkey);
3635 wpabuf_clear_free(secret);
3636 if (res < 0)
3637 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3638
3639 wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
3640
3641 /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
3642
3643 os_free(sta->owe_pmk);
3644 sta->owe_pmk = os_malloc(hash_len);
3645 if (!sta->owe_pmk) {
3646 os_memset(prk, 0, SHA512_MAC_LEN);
3647 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3648 }
3649
3650 if (group == 19)
3651 res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info,
3652 os_strlen(info), sta->owe_pmk, hash_len);
3653 else if (group == 20)
3654 res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info,
3655 os_strlen(info), sta->owe_pmk, hash_len);
3656 else if (group == 21)
3657 res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
3658 os_strlen(info), sta->owe_pmk, hash_len);
3659 os_memset(prk, 0, SHA512_MAC_LEN);
3660 if (res < 0) {
3661 os_free(sta->owe_pmk);
3662 sta->owe_pmk = NULL;
3663 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3664 }
3665 sta->owe_pmk_len = hash_len;
3666
3667 wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
3668 wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
3669 wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk,
Sunil Ravi72e01222024-03-09 01:25:43 +00003670 sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003671
3672 return WLAN_STATUS_SUCCESS;
3673}
3674
Hai Shalom81f62d82019-07-22 12:10:00 -07003675
3676u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
3677 const u8 *rsn_ie, size_t rsn_ie_len,
3678 const u8 *owe_dh, size_t owe_dh_len)
3679{
3680 struct wpa_ie_data data;
3681 int res;
3682
3683 if (!rsn_ie || rsn_ie_len < 2) {
3684 wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
3685 MAC2STR(peer));
3686 return WLAN_STATUS_INVALID_IE;
3687 }
3688 rsn_ie -= 2;
3689 rsn_ie_len += 2;
3690
3691 res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
3692 if (res) {
3693 wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
3694 " (res=%d)", MAC2STR(peer), res);
3695 wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
3696 return wpa_res_to_status_code(res);
3697 }
3698 if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
3699 wpa_printf(MSG_DEBUG,
3700 "OWE: Unexpected key mgmt 0x%x from " MACSTR,
3701 (unsigned int) data.key_mgmt, MAC2STR(peer));
3702 return WLAN_STATUS_AKMP_NOT_VALID;
3703 }
3704 if (!owe_dh) {
3705 wpa_printf(MSG_DEBUG,
3706 "OWE: No Diffie-Hellman Parameter element from "
3707 MACSTR, MAC2STR(peer));
3708 return WLAN_STATUS_AKMP_NOT_VALID;
3709 }
3710
3711 return WLAN_STATUS_SUCCESS;
3712}
3713
3714
3715u16 owe_process_rsn_ie(struct hostapd_data *hapd,
3716 struct sta_info *sta,
3717 const u8 *rsn_ie, size_t rsn_ie_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003718 const u8 *owe_dh, size_t owe_dh_len,
3719 const u8 *link_addr)
Hai Shalom81f62d82019-07-22 12:10:00 -07003720{
3721 u16 status;
3722 u8 *owe_buf, ie[256 * 2];
3723 size_t ie_len = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07003724 enum wpa_validate_result res;
Hai Shalom81f62d82019-07-22 12:10:00 -07003725
3726 if (!rsn_ie || rsn_ie_len < 2) {
3727 wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
3728 status = WLAN_STATUS_INVALID_IE;
3729 goto end;
3730 }
3731
3732 if (!sta->wpa_sm)
3733 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
3734 NULL);
3735 if (!sta->wpa_sm) {
3736 wpa_printf(MSG_WARNING,
3737 "OWE: Failed to initialize WPA state machine");
3738 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3739 goto end;
3740 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003741#ifdef CONFIG_IEEE80211BE
Sunil Ravi72e01222024-03-09 01:25:43 +00003742 if (ap_sta_is_mld(hapd, sta))
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003743 wpa_auth_set_ml_info(sta->wpa_sm, hapd->mld_addr,
3744 sta->mld_assoc_link_id, &sta->mld_info);
3745#endif /* CONFIG_IEEE80211BE */
Hai Shalom81f62d82019-07-22 12:10:00 -07003746 rsn_ie -= 2;
3747 rsn_ie_len += 2;
3748 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
3749 hapd->iface->freq, rsn_ie, rsn_ie_len,
Hai Shalomc3565922019-10-28 11:58:20 -07003750 NULL, 0, NULL, 0, owe_dh, owe_dh_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07003751 status = wpa_res_to_status_code(res);
3752 if (status != WLAN_STATUS_SUCCESS)
3753 goto end;
3754 status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
3755 if (status != WLAN_STATUS_SUCCESS)
3756 goto end;
3757 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
3758 NULL, 0);
3759 if (!owe_buf) {
3760 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3761 goto end;
3762 }
3763
3764 if (sta->owe_ecdh) {
3765 struct wpabuf *pub;
3766
3767 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
3768 if (!pub) {
3769 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3770 goto end;
3771 }
3772
3773 /* OWE Diffie-Hellman Parameter element */
3774 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
3775 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
3776 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
3777 */
3778 WPA_PUT_LE16(owe_buf, sta->owe_group);
3779 owe_buf += 2;
3780 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
3781 owe_buf += wpabuf_len(pub);
3782 wpabuf_free(pub);
3783 sta->external_dh_updated = 1;
3784 }
3785 ie_len = owe_buf - ie;
3786
3787end:
3788 wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
3789 MACSTR, status, (unsigned int) ie_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003790 MAC2STR(link_addr ? link_addr : sta->addr));
3791 hostapd_drv_update_dh_ie(hapd, link_addr ? link_addr : sta->addr,
3792 status,
Hai Shalom81f62d82019-07-22 12:10:00 -07003793 status == WLAN_STATUS_SUCCESS ? ie : NULL,
3794 ie_len);
3795
3796 return status;
3797}
3798
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003799#endif /* CONFIG_OWE */
3800
3801
Hai Shalom899fcc72020-10-19 14:38:18 -07003802static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
3803 int reassoc)
3804{
3805 if ((sta->flags &
3806 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
3807 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
3808 return false;
3809
3810 if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
3811 ap_check_sa_query_timeout(hapd, sta);
3812
3813 if (!sta->sa_query_timed_out &&
3814 (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
3815 /*
3816 * STA has already been associated with MFP and SA Query timeout
3817 * has not been reached. Reject the association attempt
3818 * temporarily and start SA Query, if one is not pending.
3819 */
3820 if (sta->sa_query_count == 0)
3821 ap_sta_start_sa_query(hapd, sta);
3822
3823 return true;
3824 }
3825
3826 return false;
3827}
3828
3829
Sunil Ravi036cec52023-03-29 11:35:17 -07003830static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
3831 const u8 *ies, size_t ies_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003832 struct ieee802_11_elems *elems, int reassoc,
3833 bool link)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003834{
Hai Shalomb755a2a2020-04-23 21:49:02 -07003835 int resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003836 const u8 *wpa_ie;
3837 size_t wpa_ie_len;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003838 const u8 *p2p_dev_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003839
Sunil Ravi036cec52023-03-29 11:35:17 -07003840 resp = check_ssid(hapd, sta, elems->ssid, elems->ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003841 if (resp != WLAN_STATUS_SUCCESS)
3842 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003843 resp = check_wmm(hapd, sta, elems->wmm, elems->wmm_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003844 if (resp != WLAN_STATUS_SUCCESS)
3845 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003846 resp = check_ext_capab(hapd, sta, elems->ext_capab,
3847 elems->ext_capab_len);
Dmitry Shmidt051af732013-10-22 13:52:46 -07003848 if (resp != WLAN_STATUS_SUCCESS)
3849 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003850 resp = copy_supp_rates(hapd, sta, elems);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003851 if (resp != WLAN_STATUS_SUCCESS)
3852 return resp;
Hai Shalom74f70d42019-02-11 14:42:39 -08003853
Sunil Ravi036cec52023-03-29 11:35:17 -07003854 resp = check_multi_ap(hapd, sta, elems->multi_ap, elems->multi_ap_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08003855 if (resp != WLAN_STATUS_SUCCESS)
3856 return resp;
3857
Sunil Ravi036cec52023-03-29 11:35:17 -07003858 resp = copy_sta_ht_capab(hapd, sta, elems->ht_capabilities);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003859 if (resp != WLAN_STATUS_SUCCESS)
3860 return resp;
3861 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
3862 !(sta->flags & WLAN_STA_HT)) {
3863 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3864 HOSTAPD_LEVEL_INFO, "Station does not support "
3865 "mandatory HT PHY - reject association");
3866 return WLAN_STATUS_ASSOC_DENIED_NO_HT;
3867 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003868
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003869#ifdef CONFIG_IEEE80211AC
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003870 if (hapd->iconf->ieee80211ac) {
Sunil Ravi036cec52023-03-29 11:35:17 -07003871 resp = copy_sta_vht_capab(hapd, sta, elems->vht_capabilities);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003872 if (resp != WLAN_STATUS_SUCCESS)
3873 return resp;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08003874
Sunil Ravi640215c2023-06-28 23:08:09 +00003875 resp = set_sta_vht_opmode(hapd, sta, elems->opmode_notif);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003876 if (resp != WLAN_STATUS_SUCCESS)
3877 return resp;
3878 }
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08003879
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003880 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
3881 !(sta->flags & WLAN_STA_VHT)) {
3882 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3883 HOSTAPD_LEVEL_INFO, "Station does not support "
3884 "mandatory VHT PHY - reject association");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003885 return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003886 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003887
Sunil Ravi036cec52023-03-29 11:35:17 -07003888 if (hapd->conf->vendor_vht && !elems->vht_capabilities) {
3889 resp = copy_sta_vendor_vht(hapd, sta, elems->vendor_vht,
3890 elems->vendor_vht_len);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003891 if (resp != WLAN_STATUS_SUCCESS)
3892 return resp;
3893 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003894#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07003895#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08003896 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07003897 resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
Sunil Ravi036cec52023-03-29 11:35:17 -07003898 elems->he_capabilities,
3899 elems->he_capabilities_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07003900 if (resp != WLAN_STATUS_SUCCESS)
3901 return resp;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003902
3903 if (hapd->iconf->require_he && !(sta->flags & WLAN_STA_HE)) {
3904 hostapd_logger(hapd, sta->addr,
3905 HOSTAPD_MODULE_IEEE80211,
3906 HOSTAPD_LEVEL_INFO,
3907 "Station does not support mandatory HE PHY - reject association");
3908 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
3909 }
3910
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003911 if (is_6ghz_op_class(hapd->iconf->op_class)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07003912 if (!(sta->flags & WLAN_STA_HE)) {
3913 hostapd_logger(hapd, sta->addr,
3914 HOSTAPD_MODULE_IEEE80211,
3915 HOSTAPD_LEVEL_INFO,
3916 "Station does not support mandatory HE PHY - reject association");
3917 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
3918 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003919 resp = copy_sta_he_6ghz_capab(hapd, sta,
Sunil Ravi036cec52023-03-29 11:35:17 -07003920 elems->he_6ghz_band_cap);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003921 if (resp != WLAN_STATUS_SUCCESS)
3922 return resp;
3923 }
Hai Shalom81f62d82019-07-22 12:10:00 -07003924 }
3925#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07003926#ifdef CONFIG_IEEE80211BE
3927 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
3928 resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP,
Sunil Ravi036cec52023-03-29 11:35:17 -07003929 elems->he_capabilities,
3930 elems->he_capabilities_len,
3931 elems->eht_capabilities,
3932 elems->eht_capabilities_len);
Sunil Ravia04bd252022-05-02 22:54:18 -07003933 if (resp != WLAN_STATUS_SUCCESS)
3934 return resp;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003935
3936 if (!link) {
3937 resp = hostapd_process_ml_assoc_req(hapd, elems, sta);
3938 if (resp != WLAN_STATUS_SUCCESS)
3939 return resp;
3940 }
Sunil Ravia04bd252022-05-02 22:54:18 -07003941 }
3942#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003943
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003944#ifdef CONFIG_P2P
Sunil Ravi036cec52023-03-29 11:35:17 -07003945 if (elems->p2p && ies && ies_len) {
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003946 wpabuf_free(sta->p2p_ie);
3947 sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
3948 P2P_IE_VENDOR_TYPE);
3949 if (sta->p2p_ie)
3950 p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
3951 } else {
3952 wpabuf_free(sta->p2p_ie);
3953 sta->p2p_ie = NULL;
3954 }
3955#endif /* CONFIG_P2P */
3956
Sunil Ravi036cec52023-03-29 11:35:17 -07003957 if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems->rsn_ie) {
3958 wpa_ie = elems->rsn_ie;
3959 wpa_ie_len = elems->rsn_ie_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003960 } else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07003961 elems->wpa_ie) {
3962 wpa_ie = elems->wpa_ie;
3963 wpa_ie_len = elems->wpa_ie_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003964 } else {
3965 wpa_ie = NULL;
3966 wpa_ie_len = 0;
3967 }
3968
3969#ifdef CONFIG_WPS
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003970 sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
Sunil Ravi036cec52023-03-29 11:35:17 -07003971 if (hapd->conf->wps_state && elems->wps_ie && ies && ies_len) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003972 wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
3973 "Request - assume WPS is used");
3974 sta->flags |= WLAN_STA_WPS;
3975 wpabuf_free(sta->wps_ie);
3976 sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
3977 WPS_IE_VENDOR_TYPE);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003978 if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
3979 wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
3980 sta->flags |= WLAN_STA_WPS2;
3981 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003982 wpa_ie = NULL;
3983 wpa_ie_len = 0;
3984 if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
3985 wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
3986 "(Re)Association Request - reject");
3987 return WLAN_STATUS_INVALID_IE;
3988 }
3989 } else if (hapd->conf->wps_state && wpa_ie == NULL) {
3990 wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
3991 "(Re)Association Request - possible WPS use");
3992 sta->flags |= WLAN_STA_MAYBE_WPS;
3993 } else
3994#endif /* CONFIG_WPS */
3995 if (hapd->conf->wpa && wpa_ie == NULL) {
3996 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3997 HOSTAPD_LEVEL_INFO,
3998 "No WPA/RSN IE in association request");
3999 return WLAN_STATUS_INVALID_IE;
4000 }
4001
4002 if (hapd->conf->wpa && wpa_ie) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004003 enum wpa_validate_result res;
4004
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004005 wpa_ie -= 2;
4006 wpa_ie_len += 2;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004007
4008 if (!sta->wpa_sm) {
4009#ifdef CONFIG_IEEE80211BE
4010 struct mld_info *info = &sta->mld_info;
4011#endif /* CONFIG_IEEE80211BE */
4012
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004013 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004014 sta->addr,
4015 p2p_dev_addr);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004016
4017 if (!sta->wpa_sm) {
4018 wpa_printf(MSG_WARNING,
4019 "Failed to initialize RSN state machine");
4020 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4021 }
4022
4023#ifdef CONFIG_IEEE80211BE
Sunil Ravi72e01222024-03-09 01:25:43 +00004024 if (ap_sta_is_mld(hapd, sta)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004025 wpa_printf(MSG_DEBUG,
4026 "MLD: Set ML info in RSN Authenticator");
4027 wpa_auth_set_ml_info(sta->wpa_sm,
4028 hapd->mld_addr,
4029 sta->mld_assoc_link_id,
4030 info);
4031 }
4032#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004033 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004034
Hai Shalom021b0b52019-04-10 11:17:58 -07004035 wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004036 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07004037 hapd->iface->freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004038 wpa_ie, wpa_ie_len,
Sunil Ravi036cec52023-03-29 11:35:17 -07004039 elems->rsnxe ? elems->rsnxe - 2 :
4040 NULL,
4041 elems->rsnxe ? elems->rsnxe_len + 2 :
4042 0,
4043 elems->mdie, elems->mdie_len,
4044 elems->owe_dh, elems->owe_dh_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004045 resp = wpa_res_to_status_code(res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004046 if (resp != WLAN_STATUS_SUCCESS)
4047 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004048
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004049 if (wpa_auth_uses_mfp(sta->wpa_sm))
4050 sta->flags |= WLAN_STA_MFP;
4051 else
4052 sta->flags &= ~WLAN_STA_MFP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004053
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004054#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004055 if (sta->auth_alg == WLAN_AUTH_FT) {
4056 if (!reassoc) {
4057 wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
4058 "to use association (not "
4059 "re-association) with FT auth_alg",
4060 MAC2STR(sta->addr));
4061 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4062 }
4063
4064 resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
4065 ies_len);
4066 if (resp != WLAN_STATUS_SUCCESS)
4067 return resp;
4068 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004069#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004070
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004071 if (link)
4072 goto skip_sae_owe;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004073#ifdef CONFIG_SAE
Roshan Pius3a1667e2018-07-03 15:17:14 -07004074 if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
4075 sta->sae->state == SAE_ACCEPTED)
4076 wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
4077
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004078 if (wpa_auth_uses_sae(sta->wpa_sm) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004079 sta->auth_alg == WLAN_AUTH_OPEN) {
4080 struct rsn_pmksa_cache_entry *sa;
4081 sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
Sunil Ravi89eba102022-09-13 21:04:37 -07004082 if (!sa || !wpa_key_mgmt_sae(sa->akmp)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004083 wpa_printf(MSG_DEBUG,
4084 "SAE: No PMKSA cache entry found for "
4085 MACSTR, MAC2STR(sta->addr));
4086 return WLAN_STATUS_INVALID_PMKID;
4087 }
4088 wpa_printf(MSG_DEBUG, "SAE: " MACSTR
4089 " using PMKSA caching", MAC2STR(sta->addr));
4090 } else if (wpa_auth_uses_sae(sta->wpa_sm) &&
4091 sta->auth_alg != WLAN_AUTH_SAE &&
4092 !(sta->auth_alg == WLAN_AUTH_FT &&
4093 wpa_auth_uses_ft_sae(sta->wpa_sm))) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004094 wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
4095 "SAE AKM after non-SAE auth_alg %u",
4096 MAC2STR(sta->addr), sta->auth_alg);
4097 return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
4098 }
Hai Shalomc3565922019-10-28 11:58:20 -07004099
Sunil Ravi77d572f2023-01-17 23:58:31 +00004100 if (hapd->conf->sae_pwe == SAE_PWE_BOTH &&
Hai Shalomc3565922019-10-28 11:58:20 -07004101 sta->auth_alg == WLAN_AUTH_SAE &&
Hai Shalom899fcc72020-10-19 14:38:18 -07004102 sta->sae && !sta->sae->h2e &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004103 ieee802_11_rsnx_capab_len(elems->rsnxe, elems->rsnxe_len,
Hai Shaloma20dcd72022-02-04 13:43:00 -08004104 WLAN_RSNX_CAPAB_SAE_H2E)) {
Hai Shalomc3565922019-10-28 11:58:20 -07004105 wpa_printf(MSG_INFO, "SAE: " MACSTR
4106 " indicates support for SAE H2E, but did not use it",
4107 MAC2STR(sta->addr));
4108 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4109 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004110#endif /* CONFIG_SAE */
4111
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004112#ifdef CONFIG_OWE
4113 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
4114 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004115 elems->owe_dh) {
4116 resp = owe_process_assoc_req(hapd, sta, elems->owe_dh,
4117 elems->owe_dh_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004118 if (resp != WLAN_STATUS_SUCCESS)
4119 return resp;
4120 }
4121#endif /* CONFIG_OWE */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004122 skip_sae_owe:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004123
Hai Shalom021b0b52019-04-10 11:17:58 -07004124#ifdef CONFIG_DPP2
4125 dpp_pfs_free(sta->dpp_pfs);
4126 sta->dpp_pfs = NULL;
4127
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004128 if (DPP_VERSION > 1 &&
4129 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07004130 hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
4131 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004132 elems->owe_dh) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004133 sta->dpp_pfs = dpp_pfs_init(
4134 wpabuf_head(hapd->conf->dpp_netaccesskey),
4135 wpabuf_len(hapd->conf->dpp_netaccesskey));
4136 if (!sta->dpp_pfs) {
4137 wpa_printf(MSG_DEBUG,
4138 "DPP: Could not initialize PFS");
4139 /* Try to continue without PFS */
4140 goto pfs_fail;
4141 }
4142
Sunil Ravi036cec52023-03-29 11:35:17 -07004143 if (dpp_pfs_process(sta->dpp_pfs, elems->owe_dh,
4144 elems->owe_dh_len) < 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004145 dpp_pfs_free(sta->dpp_pfs);
4146 sta->dpp_pfs = NULL;
4147 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4148 }
4149 }
4150
4151 wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
4152 sta->dpp_pfs->secret : NULL);
4153 pfs_fail:
4154#endif /* CONFIG_DPP2 */
4155
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004156 if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004157 wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
4158 hostapd_logger(hapd, sta->addr,
4159 HOSTAPD_MODULE_IEEE80211,
4160 HOSTAPD_LEVEL_INFO,
4161 "Station tried to use TKIP with HT "
4162 "association");
4163 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
4164 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004165#ifdef CONFIG_HS20
4166 } else if (hapd->conf->osen) {
Sunil Ravi036cec52023-03-29 11:35:17 -07004167 if (!elems->osen) {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004168 hostapd_logger(
4169 hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4170 HOSTAPD_LEVEL_INFO,
4171 "No HS 2.0 OSEN element in association request");
4172 return WLAN_STATUS_INVALID_IE;
4173 }
4174
4175 wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
4176 if (sta->wpa_sm == NULL)
4177 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
4178 sta->addr, NULL);
4179 if (sta->wpa_sm == NULL) {
4180 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
4181 "state machine");
4182 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4183 }
4184 if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
Sunil Ravi036cec52023-03-29 11:35:17 -07004185 elems->osen - 2, elems->osen_len + 2) < 0)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004186 return WLAN_STATUS_INVALID_IE;
4187#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004188 } else
4189 wpa_auth_sta_no_wpa(sta->wpa_sm);
4190
4191#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004192 p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
4193#endif /* CONFIG_P2P */
4194
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004195#ifdef CONFIG_HS20
4196 wpabuf_free(sta->hs20_ie);
Sunil Ravi036cec52023-03-29 11:35:17 -07004197 if (elems->hs20 && elems->hs20_len > 4) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004198 int release;
4199
Sunil Ravi036cec52023-03-29 11:35:17 -07004200 sta->hs20_ie = wpabuf_alloc_copy(elems->hs20 + 4,
4201 elems->hs20_len - 4);
4202 release = ((elems->hs20[4] >> 4) & 0x0f) + 1;
Hai Shalomc3565922019-10-28 11:58:20 -07004203 if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
4204 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004205 wpa_printf(MSG_DEBUG,
4206 "HS 2.0: PMF not negotiated by release %d station "
4207 MACSTR, release, MAC2STR(sta->addr));
4208 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
4209 }
4210 } else {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004211 sta->hs20_ie = NULL;
Hai Shalom74f70d42019-02-11 14:42:39 -08004212 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07004213
4214 wpabuf_free(sta->roaming_consortium);
Sunil Ravi036cec52023-03-29 11:35:17 -07004215 if (elems->roaming_cons_sel)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004216 sta->roaming_consortium = wpabuf_alloc_copy(
Sunil Ravi036cec52023-03-29 11:35:17 -07004217 elems->roaming_cons_sel + 4,
4218 elems->roaming_cons_sel_len - 4);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004219 else
4220 sta->roaming_consortium = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004221#endif /* CONFIG_HS20 */
4222
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004223#ifdef CONFIG_FST
4224 wpabuf_free(sta->mb_ies);
4225 if (hapd->iface->fst)
Sunil Ravi036cec52023-03-29 11:35:17 -07004226 sta->mb_ies = mb_ies_by_info(&elems->mb_ies);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004227 else
4228 sta->mb_ies = NULL;
4229#endif /* CONFIG_FST */
4230
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004231#ifdef CONFIG_MBO
Sunil Ravi036cec52023-03-29 11:35:17 -07004232 mbo_ap_check_sta_assoc(hapd, sta, elems);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004233
4234 if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004235 elems->mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004236 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
4237 wpa_printf(MSG_INFO,
4238 "MBO: Reject WPA2 association without PMF");
4239 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4240 }
4241#endif /* CONFIG_MBO */
4242
Hai Shalom74f70d42019-02-11 14:42:39 -08004243#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
4244 if (wpa_auth_uses_ocv(sta->wpa_sm) &&
4245 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4246 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4247 sta->auth_alg == WLAN_AUTH_FILS_PK)) {
4248 struct wpa_channel_info ci;
4249 int tx_chanwidth;
4250 int tx_seg1_idx;
Hai Shalom899fcc72020-10-19 14:38:18 -07004251 enum oci_verify_result res;
Hai Shalom74f70d42019-02-11 14:42:39 -08004252
4253 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
4254 wpa_printf(MSG_WARNING,
4255 "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
4256 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4257 }
4258
4259 if (get_sta_tx_parameters(sta->wpa_sm,
4260 channel_width_to_int(ci.chanwidth),
4261 ci.seg1_idx, &tx_chanwidth,
4262 &tx_seg1_idx) < 0)
4263 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4264
Sunil Ravi036cec52023-03-29 11:35:17 -07004265 res = ocv_verify_tx_params(elems->oci, elems->oci_len, &ci,
Hai Shalom899fcc72020-10-19 14:38:18 -07004266 tx_chanwidth, tx_seg1_idx);
4267 if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
4268 res == OCI_NOT_FOUND) {
4269 /* Work around misbehaving STAs */
4270 wpa_printf(MSG_INFO,
4271 "FILS: Disable OCV with a STA that does not send OCI");
4272 wpa_auth_set_ocv(sta->wpa_sm, 0);
4273 } else if (res != OCI_SUCCESS) {
4274 wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
4275 ocv_errorstr);
4276 wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
4277 MACSTR " frame=fils-reassoc-req error=%s",
4278 MAC2STR(sta->addr), ocv_errorstr);
Hai Shalom74f70d42019-02-11 14:42:39 -08004279 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4280 }
4281 }
4282#endif /* CONFIG_FILS && CONFIG_OCV */
4283
Sunil Ravi036cec52023-03-29 11:35:17 -07004284 ap_copy_sta_supp_op_classes(sta, elems->supp_op_classes,
4285 elems->supp_op_classes_len);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08004286
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004287 if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004288 elems->rrm_enabled &&
4289 elems->rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
4290 os_memcpy(sta->rrm_enabled_capa, elems->rrm_enabled,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004291 sizeof(sta->rrm_enabled_capa));
4292
Sunil Ravi036cec52023-03-29 11:35:17 -07004293 if (elems->power_capab) {
4294 sta->min_tx_power = elems->power_capab[0];
4295 sta->max_tx_power = elems->power_capab[1];
Roshan Pius3a1667e2018-07-03 15:17:14 -07004296 sta->power_capab = 1;
4297 } else {
4298 sta->power_capab = 0;
4299 }
4300
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004301 return WLAN_STATUS_SUCCESS;
4302}
4303
4304
Sunil Ravi036cec52023-03-29 11:35:17 -07004305static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
4306 const u8 *ies, size_t ies_len, int reassoc)
4307{
4308 struct ieee802_11_elems elems;
4309
4310 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
4311 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4312 HOSTAPD_LEVEL_INFO,
4313 "Station sent an invalid association request");
4314 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4315 }
4316
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004317 return __check_assoc_ies(hapd, sta, ies, ies_len, &elems, reassoc,
4318 false);
4319}
4320
4321
4322#ifdef CONFIG_IEEE80211BE
4323
Sunil Ravi72e01222024-03-09 01:25:43 +00004324static void ieee80211_ml_build_assoc_resp(struct hostapd_data *hapd,
4325 struct mld_link_info *link)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004326{
Sunil Ravi72e01222024-03-09 01:25:43 +00004327 u8 buf[EHT_ML_MAX_STA_PROF_LEN];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004328 u8 *p = buf;
Sunil Ravi72e01222024-03-09 01:25:43 +00004329 size_t buflen = sizeof(buf);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004330
4331 /* Capability Info */
4332 WPA_PUT_LE16(p, hostapd_own_capab_info(hapd));
4333 p += 2;
4334
4335 /* Status Code */
Sunil Ravi72e01222024-03-09 01:25:43 +00004336 WPA_PUT_LE16(p, link->status);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004337 p += 2;
4338
Sunil Ravi72e01222024-03-09 01:25:43 +00004339 if (link->status != WLAN_STATUS_SUCCESS)
4340 goto out;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004341
4342 /* AID is not included */
4343 p = hostapd_eid_supp_rates(hapd, p);
4344 p = hostapd_eid_ext_supp_rates(hapd, p);
4345 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
4346 p = hostapd_eid_ht_capabilities(hapd, p);
4347 p = hostapd_eid_ht_operation(hapd, p);
4348
4349 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
4350 p = hostapd_eid_vht_capabilities(hapd, p, 0);
4351 p = hostapd_eid_vht_operation(hapd, p);
4352 }
4353
4354 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
4355 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
4356 p = hostapd_eid_he_operation(hapd, p);
4357 p = hostapd_eid_spatial_reuse(hapd, p);
4358 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
4359 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
4360 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4361 p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
4362 p = hostapd_eid_eht_operation(hapd, p);
4363 }
4364 }
4365
4366 p = hostapd_eid_ext_capab(hapd, p, false);
4367 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
4368 p = hostapd_eid_wmm(hapd, p);
4369
4370 if (hapd->conf->assocresp_elements &&
4371 (size_t) (buf + buflen - p) >=
4372 wpabuf_len(hapd->conf->assocresp_elements)) {
4373 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
4374 wpabuf_len(hapd->conf->assocresp_elements));
4375 p += wpabuf_len(hapd->conf->assocresp_elements);
4376 }
4377
Sunil Ravi72e01222024-03-09 01:25:43 +00004378out:
4379 os_free(link->resp_sta_profile);
4380 link->resp_sta_profile = os_memdup(buf, p - buf);
4381 link->resp_sta_profile_len = link->resp_sta_profile ? p - buf : 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004382}
4383
4384
Sunil Ravi72e01222024-03-09 01:25:43 +00004385static int ieee80211_ml_process_link(struct hostapd_data *hapd,
4386 struct sta_info *origin_sta,
4387 struct mld_link_info *link,
4388 const u8 *ies, size_t ies_len,
4389 bool reassoc, bool offload)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004390{
4391 struct ieee802_11_elems elems;
4392 struct wpabuf *mlbuf = NULL;
4393 struct sta_info *sta = NULL;
4394 u16 status = WLAN_STATUS_SUCCESS;
Sunil Ravi72e01222024-03-09 01:25:43 +00004395 int i;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004396
4397 wpa_printf(MSG_DEBUG, "MLD: link: link_id=%u, peer=" MACSTR,
4398 hapd->mld_link_id, MAC2STR(link->peer_addr));
4399
4400 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
4401 wpa_printf(MSG_DEBUG, "MLD: link: Element parsing failed");
4402 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4403 goto out;
4404 }
4405
4406 sta = ap_get_sta(hapd, origin_sta->addr);
4407 if (sta) {
4408 wpa_printf(MSG_INFO, "MLD: link: Station already exists");
4409 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4410 sta = NULL;
4411 goto out;
4412 }
4413
4414 sta = ap_sta_add(hapd, origin_sta->addr);
4415 if (!sta) {
4416 wpa_printf(MSG_DEBUG, "MLD: link: ap_sta_add() failed");
4417 status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4418 goto out;
4419 }
4420
Sunil Ravi72e01222024-03-09 01:25:43 +00004421 mlbuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004422 if (!mlbuf)
4423 goto out;
4424
4425 if (ieee802_11_parse_link_assoc_req(ies, ies_len, &elems, mlbuf,
4426 hapd->mld_link_id, true) ==
4427 ParseFailed) {
4428 wpa_printf(MSG_DEBUG,
4429 "MLD: link: Failed to parse association request Multi-Link element");
4430 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4431 goto out;
4432 }
4433
4434 sta->flags |= origin_sta->flags | WLAN_STA_ASSOC_REQ_OK;
4435 status = __check_assoc_ies(hapd, sta, NULL, 0, &elems, reassoc, true);
4436 if (status != WLAN_STATUS_SUCCESS) {
4437 wpa_printf(MSG_DEBUG, "MLD: link: Element check failed");
4438 goto out;
4439 }
4440
Sunil Ravi72e01222024-03-09 01:25:43 +00004441 ap_sta_set_mld(sta, true);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004442 sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id;
4443
4444 os_memcpy(&sta->mld_info, &origin_sta->mld_info, sizeof(sta->mld_info));
Sunil Ravi72e01222024-03-09 01:25:43 +00004445 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
4446 struct mld_link_info *li = &sta->mld_info.links[i];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004447
Sunil Ravi72e01222024-03-09 01:25:43 +00004448 li->resp_sta_profile = NULL;
4449 li->resp_sta_profile_len = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004450 }
Sunil Ravi72e01222024-03-09 01:25:43 +00004451
4452 if (!offload) {
4453 /*
4454 * Get the AID from the station on which the association was
4455 * performed, and mark it as used.
4456 */
4457 sta->aid = origin_sta->aid;
4458 if (sta->aid == 0) {
4459 wpa_printf(MSG_DEBUG, "MLD: link: No AID assigned");
4460 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4461 goto out;
4462 }
4463 hapd->sta_aid[(sta->aid - 1) / 32] |= BIT((sta->aid - 1) % 32);
4464 sta->listen_interval = origin_sta->listen_interval;
4465 if (update_ht_state(hapd, sta) > 0)
4466 ieee802_11_update_beacons(hapd->iface);
4467 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004468
4469 /* RSN Authenticator should always be the one on the original station */
4470 wpa_auth_sta_deinit(sta->wpa_sm);
4471 sta->wpa_sm = NULL;
4472
4473 /*
4474 * Do not initialize the EAPOL state machine.
4475 * TODO: Maybe it is needed?
4476 */
4477 sta->eapol_sm = NULL;
4478
4479 wpa_printf(MSG_DEBUG, "MLD: link=%u, association OK (aid=%u)",
4480 hapd->mld_link_id, sta->aid);
4481
4482 /*
4483 * Get RSNE and RSNXE for the current BSS as they are required by the
4484 * Authenticator.
4485 */
4486 link->rsne = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
4487 link->rsnxe = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
4488
4489 sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC_REQ_OK;
4490
4491 /* TODO: What other processing is required? */
4492
Sunil Ravi72e01222024-03-09 01:25:43 +00004493 if (!offload && add_associated_sta(hapd, sta, reassoc))
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004494 status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4495out:
4496 wpabuf_free(mlbuf);
4497 link->status = status;
4498
Sunil Ravi72e01222024-03-09 01:25:43 +00004499 if (!offload)
4500 ieee80211_ml_build_assoc_resp(hapd, link);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004501
Sunil Ravi72e01222024-03-09 01:25:43 +00004502 wpa_printf(MSG_DEBUG, "MLD: link: status=%u", status);
4503 if (status != WLAN_STATUS_SUCCESS) {
4504 if (sta)
4505 ap_free_sta(hapd, sta);
4506 return -1;
4507 }
4508
4509 return 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004510}
4511
4512
4513bool hostapd_is_mld_ap(struct hostapd_data *hapd)
4514{
4515 if (!hapd->conf->mld_ap)
4516 return false;
4517
4518 if (!hapd->iface || !hapd->iface->interfaces ||
4519 hapd->iface->interfaces->count <= 1)
4520 return false;
4521
4522 return true;
4523}
4524
4525#endif /* CONFIG_IEEE80211BE */
4526
4527
Sunil Ravi72e01222024-03-09 01:25:43 +00004528int hostapd_process_assoc_ml_info(struct hostapd_data *hapd,
4529 struct sta_info *sta,
4530 const u8 *ies, size_t ies_len,
4531 bool reassoc, int tx_link_status,
4532 bool offload)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004533{
4534#ifdef CONFIG_IEEE80211BE
4535 unsigned int i, j;
4536
4537 if (!hostapd_is_mld_ap(hapd))
Sunil Ravi72e01222024-03-09 01:25:43 +00004538 return 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004539
4540 /*
4541 * This is not really needed, but make the interaction with the RSN
4542 * Authenticator more consistent
4543 */
4544 sta->mld_info.links[hapd->mld_link_id].rsne =
4545 hostapd_wpa_ie(hapd, WLAN_EID_RSN);
4546 sta->mld_info.links[hapd->mld_link_id].rsnxe =
4547 hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
4548
4549 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
4550 struct hostapd_iface *iface = NULL;
4551 struct mld_link_info *link = &sta->mld_info.links[i];
4552
4553 if (!link->valid)
4554 continue;
4555
4556 for (j = 0; j < hapd->iface->interfaces->count; j++) {
4557 iface = hapd->iface->interfaces->iface[j];
4558
4559 if (hapd->iface == iface)
4560 continue;
4561
4562 if (iface->bss[0]->conf->mld_ap &&
4563 hapd->conf->mld_id == iface->bss[0]->conf->mld_id &&
4564 i == iface->bss[0]->mld_link_id)
4565 break;
4566 }
4567
Sunil Ravi72e01222024-03-09 01:25:43 +00004568 if (!iface || j == hapd->iface->interfaces->count ||
4569 TEST_FAIL()) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004570 wpa_printf(MSG_DEBUG,
4571 "MLD: No link match for link_id=%u", i);
4572
4573 link->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
Sunil Ravi72e01222024-03-09 01:25:43 +00004574 if (!offload)
4575 ieee80211_ml_build_assoc_resp(hapd, link);
4576 } else if (tx_link_status != WLAN_STATUS_SUCCESS) {
4577 /* TX link rejected the connection */
4578 link->status = WLAN_STATUS_DENIED_TX_LINK_NOT_ACCEPTED;
4579 if (!offload)
4580 ieee80211_ml_build_assoc_resp(hapd, link);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004581 } else {
Sunil Ravi72e01222024-03-09 01:25:43 +00004582 if (ieee80211_ml_process_link(iface->bss[0], sta, link,
4583 ies, ies_len, reassoc,
4584 offload))
4585 return -1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004586 }
4587 }
4588#endif /* CONFIG_IEEE80211BE */
Sunil Ravi72e01222024-03-09 01:25:43 +00004589
4590 return 0;
Sunil Ravi036cec52023-03-29 11:35:17 -07004591}
4592
4593
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004594static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
4595 u16 reason_code)
4596{
4597 int send_len;
4598 struct ieee80211_mgmt reply;
4599
4600 os_memset(&reply, 0, sizeof(reply));
4601 reply.frame_control =
4602 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
4603 os_memcpy(reply.da, addr, ETH_ALEN);
4604 os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
4605 os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
4606
4607 send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
4608 reply.u.deauth.reason_code = host_to_le16(reason_code);
4609
Hai Shalomfdcde762020-04-02 11:19:20 -07004610 if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004611 wpa_printf(MSG_INFO, "Failed to send deauth: %s",
4612 strerror(errno));
4613}
4614
4615
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004616static int add_associated_sta(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08004617 struct sta_info *sta, int reassoc)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004618{
4619 struct ieee80211_ht_capabilities ht_cap;
4620 struct ieee80211_vht_capabilities vht_cap;
Hai Shalom81f62d82019-07-22 12:10:00 -07004621 struct ieee80211_he_capabilities he_cap;
Sunil Ravia04bd252022-05-02 22:54:18 -07004622 struct ieee80211_eht_capabilities eht_cap;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004623 int set = 1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004624 const u8 *mld_link_addr = NULL;
4625 bool mld_link_sta = false;
4626
4627#ifdef CONFIG_IEEE80211BE
Sunil Ravi72e01222024-03-09 01:25:43 +00004628 if (ap_sta_is_mld(hapd, sta)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004629 u8 mld_link_id = hapd->mld_link_id;
4630
4631 mld_link_sta = sta->mld_assoc_link_id != mld_link_id;
4632 mld_link_addr = sta->mld_info.links[mld_link_id].peer_addr;
4633
4634 if (hapd->mld_link_id != sta->mld_assoc_link_id)
4635 set = 0;
4636 }
4637#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004638
4639 /*
4640 * Remove the STA entry to ensure the STA PS state gets cleared and
4641 * configuration gets updated. This is relevant for cases, such as
4642 * FT-over-the-DS, where a station re-associates back to the same AP but
4643 * skips the authentication flow, or if working with a driver that
4644 * does not support full AP client state.
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004645 *
4646 * Skip this if the STA has already completed FT reassociation and the
4647 * TK has been configured since the TX/RX PN must not be reset to 0 for
4648 * the same key.
Hai Shalom74f70d42019-02-11 14:42:39 -08004649 *
4650 * FT-over-the-DS has a special case where the STA entry (and as such,
4651 * the TK) has not yet been configured to the driver depending on which
4652 * driver interface is used. For that case, allow add-STA operation to
4653 * be used (instead of set-STA). This is needed to allow mac80211-based
4654 * drivers to accept the STA parameter configuration. Since this is
4655 * after a new FT-over-DS exchange, a new TK has been derived, so key
4656 * reinstallation is not a concern for this case.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004657 */
Hai Shalom74f70d42019-02-11 14:42:39 -08004658 wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
4659 " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
4660 MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
4661 sta->ft_over_ds, reassoc,
4662 !!(sta->flags & WLAN_STA_AUTHORIZED),
4663 wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
4664 wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
4665
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004666 if (!mld_link_sta && !sta->added_unassoc &&
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004667 (!(sta->flags & WLAN_STA_AUTHORIZED) ||
Hai Shalom74f70d42019-02-11 14:42:39 -08004668 (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004669 (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
4670 !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004671 hostapd_drv_sta_remove(hapd, sta->addr);
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004672 wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
4673 set = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08004674
4675 /* Do not allow the FT-over-DS exception to be used more than
4676 * once per authentication exchange to guarantee a new TK is
4677 * used here */
4678 sta->ft_over_ds = 0;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004679 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004680
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004681 if (sta->flags & WLAN_STA_HT)
4682 hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004683#ifdef CONFIG_IEEE80211AC
4684 if (sta->flags & WLAN_STA_VHT)
4685 hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
4686#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07004687#ifdef CONFIG_IEEE80211AX
4688 if (sta->flags & WLAN_STA_HE) {
4689 hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
4690 sta->he_capab_len);
4691 }
4692#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07004693#ifdef CONFIG_IEEE80211BE
4694 if (sta->flags & WLAN_STA_EHT)
4695 hostapd_get_eht_capab(hapd, sta->eht_capab, &eht_cap,
4696 sta->eht_capab_len);
4697#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004698
4699 /*
4700 * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
4701 * will be set when the ACK frame for the (Re)Association Response frame
4702 * is processed (TX status driver event).
4703 */
4704 if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
4705 sta->supported_rates, sta->supported_rates_len,
4706 sta->listen_interval,
4707 sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
4708 sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
Hai Shalom81f62d82019-07-22 12:10:00 -07004709 sta->flags & WLAN_STA_HE ? &he_cap : NULL,
4710 sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
Sunil Ravia04bd252022-05-02 22:54:18 -07004711 sta->flags & WLAN_STA_EHT ? &eht_cap : NULL,
4712 sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004713 sta->he_6ghz_capab,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004714 sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004715 sta->vht_opmode, sta->p2p_ie ? 1 : 0,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004716 set, mld_link_addr, mld_link_sta)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004717 hostapd_logger(hapd, sta->addr,
4718 HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
4719 "Could not %s STA to kernel driver",
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004720 set ? "set" : "add");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004721
4722 if (sta->added_unassoc) {
4723 hostapd_drv_sta_remove(hapd, sta->addr);
4724 sta->added_unassoc = 0;
4725 }
4726
4727 return -1;
4728 }
4729
4730 sta->added_unassoc = 0;
4731
4732 return 0;
4733}
4734
4735
4736static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt29333592017-01-09 12:27:11 -08004737 const u8 *addr, u16 status_code, int reassoc,
Hai Shalomfdcde762020-04-02 11:19:20 -07004738 const u8 *ies, size_t ies_len, int rssi,
Sunil Ravi72e01222024-03-09 01:25:43 +00004739 int omit_rsnxe, bool allow_mld_addr_trans)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004740{
4741 int send_len;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004742 u8 *buf;
4743 size_t buflen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004744 struct ieee80211_mgmt *reply;
4745 u8 *p;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004746 u16 res = WLAN_STATUS_SUCCESS;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004747 const u8 *sa = hapd->own_addr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004748
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004749 buflen = sizeof(struct ieee80211_mgmt) + 1024;
4750#ifdef CONFIG_FILS
4751 if (sta && sta->fils_hlp_resp)
4752 buflen += wpabuf_len(sta->fils_hlp_resp);
Hai Shalom81f62d82019-07-22 12:10:00 -07004753 if (sta)
4754 buflen += 150;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004755#endif /* CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004756#ifdef CONFIG_OWE
4757 if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
4758 buflen += 150;
4759#endif /* CONFIG_OWE */
Hai Shalom021b0b52019-04-10 11:17:58 -07004760#ifdef CONFIG_DPP2
4761 if (sta && sta->dpp_pfs)
4762 buflen += 5 + sta->dpp_pfs->curve->prime_len;
4763#endif /* CONFIG_DPP2 */
Sunil Ravia04bd252022-05-02 22:54:18 -07004764#ifdef CONFIG_IEEE80211BE
4765 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4766 buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
4767 buflen += 3 + sizeof(struct ieee80211_eht_operation);
Sunil Ravi036cec52023-03-29 11:35:17 -07004768 if (hapd->iconf->punct_bitmap)
4769 buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
Sunil Ravia04bd252022-05-02 22:54:18 -07004770 }
4771#endif /* CONFIG_IEEE80211BE */
4772
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004773 buf = os_zalloc(buflen);
4774 if (!buf) {
4775 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4776 goto done;
4777 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004778 reply = (struct ieee80211_mgmt *) buf;
4779 reply->frame_control =
4780 IEEE80211_FC(WLAN_FC_TYPE_MGMT,
4781 (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
4782 WLAN_FC_STYPE_ASSOC_RESP));
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004783
4784#ifdef CONFIG_IEEE80211BE
4785 /*
4786 * Once a non-AP MLD is added to the driver, the addressing should use
4787 * MLD MAC address.
4788 */
Sunil Ravi72e01222024-03-09 01:25:43 +00004789 if (ap_sta_is_mld(hapd, sta) && allow_mld_addr_trans)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004790 sa = hapd->mld_addr;
4791#endif /* CONFIG_IEEE80211BE */
4792
Dmitry Shmidt29333592017-01-09 12:27:11 -08004793 os_memcpy(reply->da, addr, ETH_ALEN);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004794 os_memcpy(reply->sa, sa, ETH_ALEN);
4795 os_memcpy(reply->bssid, sa, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004796
4797 send_len = IEEE80211_HDRLEN;
4798 send_len += sizeof(reply->u.assoc_resp);
4799 reply->u.assoc_resp.capab_info =
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07004800 host_to_le16(hostapd_own_capab_info(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004801 reply->u.assoc_resp.status_code = host_to_le16(status_code);
Dmitry Shmidt29333592017-01-09 12:27:11 -08004802
4803 reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
4804 BIT(14) | BIT(15));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004805 /* Supported rates */
4806 p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
4807 /* Extended supported rates */
4808 p = hostapd_eid_ext_supp_rates(hapd, p);
4809
Hai Shalomfdcde762020-04-02 11:19:20 -07004810 /* Radio measurement capabilities */
4811 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
4812
Hai Shalom74f70d42019-02-11 14:42:39 -08004813#ifdef CONFIG_MBO
4814 if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
4815 rssi != 0) {
4816 int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
4817
4818 p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
4819 delta);
4820 }
4821#endif /* CONFIG_MBO */
4822
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004823#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt29333592017-01-09 12:27:11 -08004824 if (sta && status_code == WLAN_STATUS_SUCCESS) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004825 /* IEEE 802.11r: Mobility Domain Information, Fast BSS
4826 * Transition Information, RSN, [RIC Response] */
4827 p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004828 buf + buflen - p,
Hai Shalomfdcde762020-04-02 11:19:20 -07004829 sta->auth_alg, ies, ies_len,
4830 omit_rsnxe);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004831 if (!p) {
4832 wpa_printf(MSG_DEBUG,
4833 "FT: Failed to write AssocResp IEs");
4834 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4835 goto done;
4836 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004837 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004838#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom81f62d82019-07-22 12:10:00 -07004839#ifdef CONFIG_FILS
4840 if (sta && status_code == WLAN_STATUS_SUCCESS &&
4841 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4842 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4843 sta->auth_alg == WLAN_AUTH_FILS_PK))
4844 p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
4845 buf + buflen - p,
4846 ies, ies_len);
4847#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004848
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004849#ifdef CONFIG_OWE
Hai Shalom74f70d42019-02-11 14:42:39 -08004850 if (sta && status_code == WLAN_STATUS_SUCCESS &&
4851 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004852 p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
4853 buf + buflen - p,
4854 ies, ies_len);
4855#endif /* CONFIG_OWE */
4856
Dmitry Shmidt29333592017-01-09 12:27:11 -08004857 if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004858 p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004859
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004860 p = hostapd_eid_ht_capabilities(hapd, p);
4861 p = hostapd_eid_ht_operation(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004862
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004863#ifdef CONFIG_IEEE80211AC
Hai Shalomc3565922019-10-28 11:58:20 -07004864 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
4865 !is_6ghz_op_class(hapd->iconf->op_class)) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07004866 u32 nsts = 0, sta_nsts;
4867
Dmitry Shmidt29333592017-01-09 12:27:11 -08004868 if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07004869 struct ieee80211_vht_capabilities *capa;
4870
4871 nsts = (hapd->iface->conf->vht_capab >>
4872 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
4873 capa = sta->vht_capabilities;
4874 sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
4875 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
4876
4877 if (nsts < sta_nsts)
4878 nsts = 0;
4879 else
4880 nsts = sta_nsts;
4881 }
4882 p = hostapd_eid_vht_capabilities(hapd, p, nsts);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004883 p = hostapd_eid_vht_operation(hapd, p);
4884 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004885#endif /* CONFIG_IEEE80211AC */
4886
Hai Shalom81f62d82019-07-22 12:10:00 -07004887#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08004888 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07004889 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
4890 p = hostapd_eid_he_operation(hapd, p);
Sunil Ravia04bd252022-05-02 22:54:18 -07004891 p = hostapd_eid_cca(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07004892 p = hostapd_eid_spatial_reuse(hapd, p);
4893 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004894 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07004895 }
4896#endif /* CONFIG_IEEE80211AX */
4897
Sunil Ravi77d572f2023-01-17 23:58:31 +00004898 p = hostapd_eid_ext_capab(hapd, p, false);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004899 p = hostapd_eid_bss_max_idle_period(hapd, p);
Dmitry Shmidt29333592017-01-09 12:27:11 -08004900 if (sta && sta->qos_map_enabled)
Dmitry Shmidt051af732013-10-22 13:52:46 -07004901 p = hostapd_eid_qos_map_set(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004902
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004903#ifdef CONFIG_FST
4904 if (hapd->iface->fst_ies) {
4905 os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
4906 wpabuf_len(hapd->iface->fst_ies));
4907 p += wpabuf_len(hapd->iface->fst_ies);
4908 }
4909#endif /* CONFIG_FST */
4910
Hai Shalomfdcde762020-04-02 11:19:20 -07004911#ifdef CONFIG_TESTING_OPTIONS
4912 if (hapd->conf->rsnxe_override_ft &&
4913 buf + buflen - p >=
4914 (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
4915 sta && sta->auth_alg == WLAN_AUTH_FT) {
4916 wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
4917 os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
4918 wpabuf_len(hapd->conf->rsnxe_override_ft));
4919 p += wpabuf_len(hapd->conf->rsnxe_override_ft);
4920 goto rsnxe_done;
4921 }
4922#endif /* CONFIG_TESTING_OPTIONS */
4923 if (!omit_rsnxe)
4924 p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
4925#ifdef CONFIG_TESTING_OPTIONS
4926rsnxe_done:
4927#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomc3565922019-10-28 11:58:20 -07004928
Sunil Ravia04bd252022-05-02 22:54:18 -07004929#ifdef CONFIG_IEEE80211BE
4930 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004931 if (hapd->conf->mld_ap)
Sunil Ravi72e01222024-03-09 01:25:43 +00004932 p = hostapd_eid_eht_ml_assoc(hapd, sta, p);
Sunil Ravia04bd252022-05-02 22:54:18 -07004933 p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
4934 p = hostapd_eid_eht_operation(hapd, p);
4935 }
4936#endif /* CONFIG_IEEE80211BE */
4937
Hai Shalom021b0b52019-04-10 11:17:58 -07004938#ifdef CONFIG_OWE
4939 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
4940 sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
Hai Shalom899fcc72020-10-19 14:38:18 -07004941 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
4942 !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004943 struct wpabuf *pub;
4944
4945 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
4946 if (!pub) {
4947 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4948 goto done;
4949 }
4950 /* OWE Diffie-Hellman Parameter element */
4951 *p++ = WLAN_EID_EXTENSION; /* Element ID */
4952 *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
4953 *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
4954 WPA_PUT_LE16(p, sta->owe_group);
4955 p += 2;
4956 os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
4957 p += wpabuf_len(pub);
4958 wpabuf_free(pub);
4959 }
4960#endif /* CONFIG_OWE */
4961
4962#ifdef CONFIG_DPP2
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004963 if (DPP_VERSION > 1 && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07004964 sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
4965 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
4966 os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
4967 wpabuf_len(sta->dpp_pfs->ie));
4968 p += wpabuf_len(sta->dpp_pfs->ie);
4969 }
4970#endif /* CONFIG_DPP2 */
4971
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004972#ifdef CONFIG_IEEE80211AC
Dmitry Shmidt29333592017-01-09 12:27:11 -08004973 if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004974 p = hostapd_eid_vendor_vht(hapd, p);
4975#endif /* CONFIG_IEEE80211AC */
4976
Dmitry Shmidt29333592017-01-09 12:27:11 -08004977 if (sta && (sta->flags & WLAN_STA_WMM))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004978 p = hostapd_eid_wmm(hapd, p);
4979
4980#ifdef CONFIG_WPS
Dmitry Shmidt29333592017-01-09 12:27:11 -08004981 if (sta &&
4982 ((sta->flags & WLAN_STA_WPS) ||
4983 ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004984 struct wpabuf *wps = wps_build_assoc_resp_ie();
4985 if (wps) {
4986 os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
4987 p += wpabuf_len(wps);
4988 wpabuf_free(wps);
4989 }
4990 }
4991#endif /* CONFIG_WPS */
4992
Hai Shalom74f70d42019-02-11 14:42:39 -08004993 if (sta && (sta->flags & WLAN_STA_MULTI_AP))
4994 p = hostapd_eid_multi_ap(hapd, p);
4995
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004996#ifdef CONFIG_P2P
Dmitry Shmidt29333592017-01-09 12:27:11 -08004997 if (sta && sta->p2p_ie && hapd->p2p_group) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004998 struct wpabuf *p2p_resp_ie;
4999 enum p2p_status_code status;
5000 switch (status_code) {
5001 case WLAN_STATUS_SUCCESS:
5002 status = P2P_SC_SUCCESS;
5003 break;
5004 case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
5005 status = P2P_SC_FAIL_LIMIT_REACHED;
5006 break;
5007 default:
5008 status = P2P_SC_FAIL_INVALID_PARAMS;
5009 break;
5010 }
5011 p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
5012 if (p2p_resp_ie) {
5013 os_memcpy(p, wpabuf_head(p2p_resp_ie),
5014 wpabuf_len(p2p_resp_ie));
5015 p += wpabuf_len(p2p_resp_ie);
5016 wpabuf_free(p2p_resp_ie);
5017 }
5018 }
5019#endif /* CONFIG_P2P */
5020
5021#ifdef CONFIG_P2P_MANAGER
5022 if (hapd->conf->p2p & P2P_MANAGE)
5023 p = hostapd_eid_p2p_manage(hapd, p);
5024#endif /* CONFIG_P2P_MANAGER */
5025
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005026 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005027
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005028 if (hapd->conf->assocresp_elements &&
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005029 (size_t) (buf + buflen - p) >=
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005030 wpabuf_len(hapd->conf->assocresp_elements)) {
5031 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
5032 wpabuf_len(hapd->conf->assocresp_elements));
5033 p += wpabuf_len(hapd->conf->assocresp_elements);
5034 }
5035
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005036 send_len += p - reply->u.assoc_resp.variable;
5037
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005038#ifdef CONFIG_FILS
Dmitry Shmidt29333592017-01-09 12:27:11 -08005039 if (sta &&
5040 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005041 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5042 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
5043 status_code == WLAN_STATUS_SUCCESS) {
5044 struct ieee802_11_elems elems;
5045
5046 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005047 ParseFailed || !elems.fils_session) {
5048 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5049 goto done;
5050 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005051
5052 /* FILS Session */
5053 *p++ = WLAN_EID_EXTENSION; /* Element ID */
5054 *p++ = 1 + FILS_SESSION_LEN; /* Length */
5055 *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
5056 os_memcpy(p, elems.fils_session, FILS_SESSION_LEN);
5057 send_len += 2 + 1 + FILS_SESSION_LEN;
5058
5059 send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005060 buflen, sta->fils_hlp_resp);
5061 if (send_len < 0) {
5062 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5063 goto done;
5064 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005065 }
5066#endif /* CONFIG_FILS */
5067
Hai Shalomfdcde762020-04-02 11:19:20 -07005068 if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005069 wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
5070 strerror(errno));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005071 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005072 }
5073
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005074done:
5075 os_free(buf);
5076 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005077}
5078
5079
Roshan Pius3a1667e2018-07-03 15:17:14 -07005080#ifdef CONFIG_OWE
5081u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
5082 const u8 *owe_dh, u8 owe_dh_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07005083 u8 *owe_buf, size_t owe_buf_len, u16 *status)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005084{
5085#ifdef CONFIG_TESTING_OPTIONS
5086 if (hapd->conf->own_ie_override) {
5087 wpa_printf(MSG_DEBUG, "OWE: Using IE override");
Hai Shalomfdcde762020-04-02 11:19:20 -07005088 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005089 return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5090 owe_buf_len, NULL, 0);
5091 }
5092#endif /* CONFIG_TESTING_OPTIONS */
5093
5094 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
5095 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
5096 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5097 owe_buf_len, NULL, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -07005098 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005099 return owe_buf;
5100 }
5101
Hai Shalom81f62d82019-07-22 12:10:00 -07005102 if (sta->owe_pmk && sta->external_dh_updated) {
5103 wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
Hai Shalomfdcde762020-04-02 11:19:20 -07005104 *status = WLAN_STATUS_SUCCESS;
Hai Shalom81f62d82019-07-22 12:10:00 -07005105 return owe_buf;
5106 }
5107
Hai Shalomfdcde762020-04-02 11:19:20 -07005108 *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
5109 if (*status != WLAN_STATUS_SUCCESS)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005110 return NULL;
5111
5112 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5113 owe_buf_len, NULL, 0);
5114
5115 if (sta->owe_ecdh && owe_buf) {
5116 struct wpabuf *pub;
5117
5118 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
5119 if (!pub) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005120 *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005121 return owe_buf;
5122 }
5123
5124 /* OWE Diffie-Hellman Parameter element */
5125 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
5126 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
5127 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
5128 */
5129 WPA_PUT_LE16(owe_buf, sta->owe_group);
5130 owe_buf += 2;
5131 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
5132 owe_buf += wpabuf_len(pub);
5133 wpabuf_free(pub);
5134 }
5135
5136 return owe_buf;
5137}
5138#endif /* CONFIG_OWE */
5139
5140
Paul Stewart092955c2017-02-06 09:13:09 -08005141#ifdef CONFIG_FILS
5142
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005143void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
Paul Stewart092955c2017-02-06 09:13:09 -08005144{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005145 u16 reply_res;
Paul Stewart092955c2017-02-06 09:13:09 -08005146
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005147 wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
5148 MAC2STR(sta->addr));
5149 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5150 if (!sta->fils_pending_assoc_req)
Paul Stewart092955c2017-02-06 09:13:09 -08005151 return;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005152 reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
5153 sta->fils_pending_assoc_is_reassoc,
5154 sta->fils_pending_assoc_req,
Sunil Ravi72e01222024-03-09 01:25:43 +00005155 sta->fils_pending_assoc_req_len, 0, 0,
5156 true);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005157 os_free(sta->fils_pending_assoc_req);
5158 sta->fils_pending_assoc_req = NULL;
5159 sta->fils_pending_assoc_req_len = 0;
5160 wpabuf_free(sta->fils_hlp_resp);
5161 sta->fils_hlp_resp = NULL;
5162 wpabuf_free(sta->hlp_dhcp_discover);
5163 sta->hlp_dhcp_discover = NULL;
Paul Stewart092955c2017-02-06 09:13:09 -08005164
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005165 /*
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005166 * Remove the station in case transmission of a success response fails.
5167 * At this point the station was already added associated to the driver.
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005168 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005169 if (reply_res != WLAN_STATUS_SUCCESS)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005170 hostapd_drv_sta_remove(hapd, sta->addr);
Paul Stewart092955c2017-02-06 09:13:09 -08005171}
5172
5173
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005174void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
Paul Stewart092955c2017-02-06 09:13:09 -08005175{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005176 struct hostapd_data *hapd = eloop_ctx;
5177 struct sta_info *sta = eloop_data;
Paul Stewart092955c2017-02-06 09:13:09 -08005178
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005179 wpa_printf(MSG_DEBUG,
5180 "FILS: HLP response timeout - continue with association response for "
5181 MACSTR, MAC2STR(sta->addr));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005182 if (sta->fils_drv_assoc_finish)
5183 hostapd_notify_assoc_fils_finish(hapd, sta);
5184 else
5185 fils_hlp_finish_assoc(hapd, sta);
Paul Stewart092955c2017-02-06 09:13:09 -08005186}
5187
5188#endif /* CONFIG_FILS */
5189
5190
Sunil Ravi72e01222024-03-09 01:25:43 +00005191#ifdef CONFIG_IEEE80211BE
5192static struct sta_info * handle_mlo_translate(struct hostapd_data *hapd,
5193 const struct ieee80211_mgmt *mgmt,
5194 size_t len, bool reassoc,
5195 struct hostapd_data **assoc_hapd)
5196{
5197 struct sta_info *sta;
5198 struct ieee802_11_elems elems;
5199 u8 mld_addr[ETH_ALEN];
5200 const u8 *pos;
5201
5202 if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be)
5203 return NULL;
5204
5205 if (reassoc) {
5206 len -= IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req);
5207 pos = mgmt->u.reassoc_req.variable;
5208 } else {
5209 len -= IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req);
5210 pos = mgmt->u.assoc_req.variable;
5211 }
5212
5213 if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed)
5214 return NULL;
5215
5216 if (hostapd_process_ml_assoc_req_addr(hapd, elems.basic_mle,
5217 elems.basic_mle_len,
5218 mld_addr))
5219 return NULL;
5220
5221 sta = ap_get_sta(hapd, mld_addr);
5222 if (!sta)
5223 return NULL;
5224
5225 wpa_printf(MSG_DEBUG, "MLD: assoc: mld=" MACSTR ", link=" MACSTR,
5226 MAC2STR(mld_addr), MAC2STR(mgmt->sa));
5227
5228 return hostapd_ml_get_assoc_sta(hapd, sta, assoc_hapd);
5229}
5230#endif /* CONFIG_IEEE80211BE */
5231
5232
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005233static void handle_assoc(struct hostapd_data *hapd,
5234 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom74f70d42019-02-11 14:42:39 -08005235 int reassoc, int rssi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005236{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005237 u16 capab_info, listen_interval, seq_ctrl, fc;
Hai Shalomb755a2a2020-04-23 21:49:02 -07005238 int resp = WLAN_STATUS_SUCCESS;
Hai Shalom899fcc72020-10-19 14:38:18 -07005239 u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005240 const u8 *pos;
5241 int left, i;
5242 struct sta_info *sta;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005243 u8 *tmp = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005244#ifdef CONFIG_FILS
5245 int delay_assoc = 0;
5246#endif /* CONFIG_FILS */
Hai Shalomfdcde762020-04-02 11:19:20 -07005247 int omit_rsnxe = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005248 bool set_beacon = false;
Sunil Ravi72e01222024-03-09 01:25:43 +00005249 bool mld_addrs_not_translated = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005250
5251 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
5252 sizeof(mgmt->u.assoc_req))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005253 wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
5254 reassoc, (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005255 return;
5256 }
5257
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005258#ifdef CONFIG_TESTING_OPTIONS
5259 if (reassoc) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005260 if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005261 drand48() < hapd->iconf->ignore_reassoc_probability) {
5262 wpa_printf(MSG_INFO,
5263 "TESTING: ignoring reassoc request from "
5264 MACSTR, MAC2STR(mgmt->sa));
5265 return;
5266 }
5267 } else {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005268 if (hapd->iconf->ignore_assoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005269 drand48() < hapd->iconf->ignore_assoc_probability) {
5270 wpa_printf(MSG_INFO,
5271 "TESTING: ignoring assoc request from "
5272 MACSTR, MAC2STR(mgmt->sa));
5273 return;
5274 }
5275 }
5276#endif /* CONFIG_TESTING_OPTIONS */
5277
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005278 fc = le_to_host16(mgmt->frame_control);
5279 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
5280
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005281 if (reassoc) {
5282 capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
5283 listen_interval = le_to_host16(
5284 mgmt->u.reassoc_req.listen_interval);
5285 wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
5286 " capab_info=0x%02x listen_interval=%d current_ap="
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005287 MACSTR " seq_ctrl=0x%x%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005288 MAC2STR(mgmt->sa), capab_info, listen_interval,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005289 MAC2STR(mgmt->u.reassoc_req.current_ap),
5290 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005291 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
5292 pos = mgmt->u.reassoc_req.variable;
5293 } else {
5294 capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
5295 listen_interval = le_to_host16(
5296 mgmt->u.assoc_req.listen_interval);
5297 wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005298 " capab_info=0x%02x listen_interval=%d "
5299 "seq_ctrl=0x%x%s",
5300 MAC2STR(mgmt->sa), capab_info, listen_interval,
5301 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005302 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
5303 pos = mgmt->u.assoc_req.variable;
5304 }
5305
5306 sta = ap_get_sta(hapd, mgmt->sa);
Sunil Ravi72e01222024-03-09 01:25:43 +00005307
5308#ifdef CONFIG_IEEE80211BE
5309 /*
5310 * It is possible that the association frame is from an associated
5311 * non-AP MLD station, that tries to re-associate using different link
5312 * addresses. In such a case, try to find the station based on the AP
5313 * MLD MAC address.
5314 */
5315 if (!sta) {
5316 struct hostapd_data *assoc_hapd;
5317
5318 sta = handle_mlo_translate(hapd, mgmt, len, reassoc,
5319 &assoc_hapd);
5320 if (sta) {
5321 wpa_printf(MSG_DEBUG,
5322 "MLD: Switching to assoc hapd/station");
5323 hapd = assoc_hapd;
5324 mld_addrs_not_translated = true;
5325 }
5326 }
5327#endif /* CONFIG_IEEE80211BE */
5328
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005329#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005330 if (sta && sta->auth_alg == WLAN_AUTH_FT &&
5331 (sta->flags & WLAN_STA_AUTH) == 0) {
5332 wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
5333 "prior to authentication since it is using "
5334 "over-the-DS FT", MAC2STR(mgmt->sa));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005335
5336 /*
5337 * Mark station as authenticated, to avoid adding station
5338 * entry in the driver as associated and not authenticated
5339 */
5340 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005341 } else
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005342#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005343 if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
Dmitry Shmidt29333592017-01-09 12:27:11 -08005344 if (hapd->iface->current_mode &&
5345 hapd->iface->current_mode->mode ==
5346 HOSTAPD_MODE_IEEE80211AD) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005347 int acl_res;
Hai Shalomfdcde762020-04-02 11:19:20 -07005348 struct radius_sta info;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005349
Hai Shalomfdcde762020-04-02 11:19:20 -07005350 acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
5351 (const u8 *) mgmt,
5352 len, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005353 if (acl_res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005354 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5355 "Ignore Association Request frame from "
5356 MACSTR " due to ACL reject",
5357 MAC2STR(mgmt->sa));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005358 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5359 goto fail;
5360 }
5361 if (acl_res == HOSTAPD_ACL_PENDING)
5362 return;
5363
Dmitry Shmidt29333592017-01-09 12:27:11 -08005364 /* DMG/IEEE 802.11ad does not use authentication.
5365 * Allocate sta entry upon association. */
5366 sta = ap_sta_add(hapd, mgmt->sa);
5367 if (!sta) {
5368 hostapd_logger(hapd, mgmt->sa,
5369 HOSTAPD_MODULE_IEEE80211,
5370 HOSTAPD_LEVEL_INFO,
5371 "Failed to add STA");
5372 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5373 goto fail;
5374 }
5375
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005376 acl_res = ieee802_11_set_radius_info(
Hai Shalomfdcde762020-04-02 11:19:20 -07005377 hapd, sta, acl_res, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005378 if (acl_res) {
5379 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5380 goto fail;
5381 }
5382
Dmitry Shmidt29333592017-01-09 12:27:11 -08005383 hostapd_logger(hapd, sta->addr,
5384 HOSTAPD_MODULE_IEEE80211,
5385 HOSTAPD_LEVEL_DEBUG,
5386 "Skip authentication for DMG/IEEE 802.11ad");
5387 sta->flags |= WLAN_STA_AUTH;
5388 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
5389 sta->auth_alg = WLAN_AUTH_OPEN;
5390 } else {
5391 hostapd_logger(hapd, mgmt->sa,
5392 HOSTAPD_MODULE_IEEE80211,
5393 HOSTAPD_LEVEL_INFO,
5394 "Station tried to associate before authentication (aid=%d flags=0x%x)",
5395 sta ? sta->aid : -1,
5396 sta ? sta->flags : 0);
5397 send_deauth(hapd, mgmt->sa,
5398 WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
5399 return;
5400 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005401 }
5402
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005403 if ((fc & WLAN_FC_RETRY) &&
5404 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
5405 sta->last_seq_ctrl == seq_ctrl &&
Paul Stewart092955c2017-02-06 09:13:09 -08005406 sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5407 WLAN_FC_STYPE_ASSOC_REQ)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005408 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5409 HOSTAPD_LEVEL_DEBUG,
5410 "Drop repeated association frame seq_ctrl=0x%x",
5411 seq_ctrl);
5412 return;
5413 }
5414 sta->last_seq_ctrl = seq_ctrl;
5415 sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5416 WLAN_FC_STYPE_ASSOC_REQ;
5417
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005418 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005419 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005420 goto fail;
5421 }
5422
5423 if (listen_interval > hapd->conf->max_listen_interval) {
5424 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5425 HOSTAPD_LEVEL_DEBUG,
5426 "Too large Listen Interval (%d)",
5427 listen_interval);
5428 resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
5429 goto fail;
5430 }
5431
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005432#ifdef CONFIG_MBO
5433 if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
5434 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5435 goto fail;
5436 }
Hai Shalom74f70d42019-02-11 14:42:39 -08005437
5438 if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
5439 rssi < hapd->iconf->rssi_reject_assoc_rssi &&
5440 (sta->auth_rssi == 0 ||
5441 sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
5442 resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
5443 goto fail;
5444 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005445#endif /* CONFIG_MBO */
5446
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005447 if (hapd->conf->wpa && check_sa_query(hapd, sta, reassoc)) {
5448 resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
5449 goto fail;
5450 }
5451
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005452 /*
5453 * sta->capability is used in check_assoc_ies() for RRM enabled
5454 * capability element.
5455 */
5456 sta->capability = capab_info;
5457
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005458#ifdef CONFIG_FILS
5459 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5460 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5461 sta->auth_alg == WLAN_AUTH_FILS_PK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005462 int res;
5463
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005464 /* The end of the payload is encrypted. Need to decrypt it
5465 * before parsing. */
5466
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005467 tmp = os_memdup(pos, left);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005468 if (!tmp) {
5469 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5470 goto fail;
5471 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005472
Roshan Pius3a1667e2018-07-03 15:17:14 -07005473 res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
5474 len, tmp, left);
5475 if (res < 0) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005476 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5477 goto fail;
5478 }
5479 pos = tmp;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005480 left = res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005481 }
5482#endif /* CONFIG_FILS */
5483
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005484 /* followed by SSID and Supported rates; and HT capabilities if 802.11n
5485 * is used */
5486 resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
5487 if (resp != WLAN_STATUS_SUCCESS)
5488 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07005489 omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005490
5491 if (hostapd_get_aid(hapd, sta) < 0) {
5492 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5493 HOSTAPD_LEVEL_INFO, "No room for more AIDs");
5494 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5495 goto fail;
5496 }
5497
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005498 sta->listen_interval = listen_interval;
5499
Roshan Pius3a1667e2018-07-03 15:17:14 -07005500 if (hapd->iface->current_mode &&
5501 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005502 sta->flags |= WLAN_STA_NONERP;
5503 for (i = 0; i < sta->supported_rates_len; i++) {
5504 if ((sta->supported_rates[i] & 0x7f) > 22) {
5505 sta->flags &= ~WLAN_STA_NONERP;
5506 break;
5507 }
5508 }
5509 if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
5510 sta->nonerp_set = 1;
5511 hapd->iface->num_sta_non_erp++;
5512 if (hapd->iface->num_sta_non_erp == 1)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005513 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005514 }
5515
5516 if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
5517 !sta->no_short_slot_time_set) {
5518 sta->no_short_slot_time_set = 1;
5519 hapd->iface->num_sta_no_short_slot_time++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005520 if (hapd->iface->current_mode &&
5521 hapd->iface->current_mode->mode ==
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005522 HOSTAPD_MODE_IEEE80211G &&
5523 hapd->iface->num_sta_no_short_slot_time == 1)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005524 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005525 }
5526
5527 if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
5528 sta->flags |= WLAN_STA_SHORT_PREAMBLE;
5529 else
5530 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
5531
5532 if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
5533 !sta->no_short_preamble_set) {
5534 sta->no_short_preamble_set = 1;
5535 hapd->iface->num_sta_no_short_preamble++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005536 if (hapd->iface->current_mode &&
5537 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005538 && hapd->iface->num_sta_no_short_preamble == 1)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005539 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005540 }
5541
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005542 if (update_ht_state(hapd, sta) > 0)
5543 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005544
5545 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5546 HOSTAPD_LEVEL_DEBUG,
5547 "association OK (aid %d)", sta->aid);
5548 /* Station will be marked associated, after it acknowledges AssocResp
5549 */
5550 sta->flags |= WLAN_STA_ASSOC_REQ_OK;
5551
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005552 if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
5553 wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
5554 "SA Query procedure", reassoc ? "re" : "");
5555 /* TODO: Send a protected Disassociate frame to the STA using
5556 * the old key and Reason Code "Previous Authentication no
5557 * longer valid". Make sure this is only sent protected since
5558 * unprotected frame would be received by the STA that is now
5559 * trying to associate.
5560 */
5561 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005562
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005563 /* Make sure that the previously registered inactivity timer will not
5564 * remove the STA immediately. */
5565 sta->timeout_next = STA_NULLFUNC;
5566
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005567#ifdef CONFIG_TAXONOMY
5568 taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
5569#endif /* CONFIG_TAXONOMY */
5570
Dmitry Shmidt29333592017-01-09 12:27:11 -08005571 sta->pending_wds_enable = 0;
5572
Paul Stewart092955c2017-02-06 09:13:09 -08005573#ifdef CONFIG_FILS
5574 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5575 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005576 sta->auth_alg == WLAN_AUTH_FILS_PK) {
5577 if (fils_process_hlp(hapd, sta, pos, left) > 0)
5578 delay_assoc = 1;
5579 }
Paul Stewart092955c2017-02-06 09:13:09 -08005580#endif /* CONFIG_FILS */
5581
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005582 if (set_beacon)
5583 ieee802_11_set_beacons(hapd->iface);
5584
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005585 fail:
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005586
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005587 /*
5588 * In case of a successful response, add the station to the driver.
5589 * Otherwise, the kernel may ignore Data frames before we process the
5590 * ACK frame (TX status). In case of a failure, this station will be
5591 * removed.
5592 *
5593 * Note that this is not compliant with the IEEE 802.11 standard that
5594 * states that a non-AP station should transition into the
5595 * authenticated/associated state only after the station acknowledges
5596 * the (Re)Association Response frame. However, still do this as:
5597 *
5598 * 1. In case the station does not acknowledge the (Re)Association
5599 * Response frame, it will be removed.
5600 * 2. Data frames will be dropped in the kernel until the station is
5601 * set into authorized state, and there are no significant known
5602 * issues with processing other non-Data Class 3 frames during this
5603 * window.
5604 */
Sunil Ravi72e01222024-03-09 01:25:43 +00005605 if (sta)
5606 hostapd_process_assoc_ml_info(hapd, sta, pos, left, reassoc,
5607 resp, false);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005608
Hai Shalom74f70d42019-02-11 14:42:39 -08005609 if (resp == WLAN_STATUS_SUCCESS && sta &&
5610 add_associated_sta(hapd, sta, reassoc))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005611 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5612
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005613#ifdef CONFIG_FILS
Hai Shalom74f70d42019-02-11 14:42:39 -08005614 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
5615 eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
5616 sta->fils_pending_assoc_req) {
5617 /* Do not reschedule fils_hlp_timeout in case the station
5618 * retransmits (Re)Association Request frame while waiting for
5619 * the previously started FILS HLP wait, so that the timeout can
5620 * be determined from the first pending attempt. */
5621 wpa_printf(MSG_DEBUG,
5622 "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
5623 MACSTR, MAC2STR(sta->addr));
5624 os_free(tmp);
5625 return;
5626 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005627 if (sta) {
5628 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5629 os_free(sta->fils_pending_assoc_req);
5630 sta->fils_pending_assoc_req = NULL;
5631 sta->fils_pending_assoc_req_len = 0;
5632 wpabuf_free(sta->fils_hlp_resp);
5633 sta->fils_hlp_resp = NULL;
5634 }
5635 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
5636 sta->fils_pending_assoc_req = tmp;
5637 sta->fils_pending_assoc_req_len = left;
5638 sta->fils_pending_assoc_is_reassoc = reassoc;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005639 sta->fils_drv_assoc_finish = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005640 wpa_printf(MSG_DEBUG,
5641 "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
5642 MACSTR, MAC2STR(sta->addr));
5643 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5644 eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
5645 fils_hlp_timeout, hapd, sta);
5646 return;
5647 }
5648#endif /* CONFIG_FILS */
5649
Hai Shalomb755a2a2020-04-23 21:49:02 -07005650 if (resp >= 0)
Sunil Ravi72e01222024-03-09 01:25:43 +00005651 reply_res = send_assoc_resp(hapd,
5652 mld_addrs_not_translated ?
5653 NULL : sta,
5654 mgmt->sa, resp, reassoc,
5655 pos, left, rssi, omit_rsnxe,
5656 !mld_addrs_not_translated);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005657 os_free(tmp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005658
5659 /*
Hai Shalom899fcc72020-10-19 14:38:18 -07005660 * Remove the station in case transmission of a success response fails
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005661 * (the STA was added associated to the driver) or if the station was
5662 * previously added unassociated.
5663 */
Dmitry Shmidt29333592017-01-09 12:27:11 -08005664 if (sta && ((reply_res != WLAN_STATUS_SUCCESS &&
5665 resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005666 hostapd_drv_sta_remove(hapd, sta->addr);
5667 sta->added_unassoc = 0;
5668 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005669}
5670
5671
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005672static void hostapd_deauth_sta(struct hostapd_data *hapd,
5673 struct sta_info *sta,
5674 const struct ieee80211_mgmt *mgmt)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005675{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005676 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5677 "deauthentication: STA=" MACSTR " reason_code=%d",
5678 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005679
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005680 ap_sta_set_authorized(hapd, sta, 0);
5681 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
5682 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
5683 WLAN_STA_ASSOC_REQ_OK);
5684 hostapd_set_sta_flags(hapd, sta);
5685 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5686 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5687 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5688 mlme_deauthenticate_indication(
5689 hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
5690 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5691 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5692 ap_free_sta(hapd, sta);
5693}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005694
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005695
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005696static void hostapd_disassoc_sta(struct hostapd_data *hapd,
5697 struct sta_info *sta,
5698 const struct ieee80211_mgmt *mgmt)
5699{
5700 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5701 "disassocation: STA=" MACSTR " reason_code=%d",
5702 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005703
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005704 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005705 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005706 sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07005707 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005708 wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
5709 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5710 HOSTAPD_LEVEL_INFO, "disassociated");
5711 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5712 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5713 /* Stop Accounting and IEEE 802.1X sessions, but leave the STA
5714 * authenticated. */
5715 accounting_sta_stop(hapd, sta);
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005716 ieee802_1x_free_station(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005717 if (sta->ipaddr)
5718 hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
5719 ap_sta_ip6addr_del(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005720 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005721 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005722
5723 if (sta->timeout_next == STA_NULLFUNC ||
5724 sta->timeout_next == STA_DISASSOC) {
5725 sta->timeout_next = STA_DEAUTH;
5726 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
5727 eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
5728 hapd, sta);
5729 }
5730
5731 mlme_disassociate_indication(
5732 hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt29333592017-01-09 12:27:11 -08005733
5734 /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon
5735 * disassociation. */
5736 if (hapd->iface->current_mode &&
5737 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
5738 sta->flags &= ~WLAN_STA_AUTH;
5739 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5740 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5741 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5742 ap_free_sta(hapd, sta);
5743 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005744}
5745
5746
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005747static bool hostapd_ml_handle_disconnect(struct hostapd_data *hapd,
5748 struct sta_info *sta,
5749 const struct ieee80211_mgmt *mgmt,
5750 bool disassoc)
5751{
5752#ifdef CONFIG_IEEE80211BE
5753 struct hostapd_data *assoc_hapd, *tmp_hapd;
5754 struct sta_info *assoc_sta;
5755 unsigned int i, link_id;
5756
5757 if (!hostapd_is_mld_ap(hapd))
5758 return false;
5759
5760 /*
5761 * Get the station on which the association was performed, as it holds
5762 * the information about all the other links.
5763 */
5764 assoc_sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd);
Sunil Ravi72e01222024-03-09 01:25:43 +00005765 if (!assoc_sta)
5766 return false;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005767
5768 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
5769 for (i = 0; i < assoc_hapd->iface->interfaces->count; i++) {
5770 struct sta_info *tmp_sta;
5771
5772 if (!assoc_sta->mld_info.links[link_id].valid)
5773 continue;
5774
5775 tmp_hapd =
5776 assoc_hapd->iface->interfaces->iface[i]->bss[0];
5777
5778 if (!tmp_hapd->conf->mld_ap ||
5779 assoc_hapd->conf->mld_id != tmp_hapd->conf->mld_id)
5780 continue;
5781
5782 for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
5783 tmp_sta = tmp_sta->next) {
5784 /*
5785 * Remove the station on which the association
5786 * was done only after all other link stations
5787 * are removed. Since there is only a single
5788 * station per struct hostapd_hapd with the
5789 * same association link simply break out from
5790 * the loop.
5791 */
5792 if (tmp_sta == assoc_sta)
5793 break;
5794
5795 if (tmp_sta->mld_assoc_link_id !=
5796 assoc_sta->mld_assoc_link_id ||
5797 tmp_sta->aid != assoc_sta->aid)
5798 continue;
5799
5800 if (!disassoc)
5801 hostapd_deauth_sta(tmp_hapd, tmp_sta,
5802 mgmt);
5803 else
5804 hostapd_disassoc_sta(tmp_hapd, tmp_sta,
5805 mgmt);
5806 break;
5807 }
5808 }
5809 }
5810
5811 /* Remove the station on which the association was performed. */
5812 if (!disassoc)
5813 hostapd_deauth_sta(assoc_hapd, assoc_sta, mgmt);
5814 else
5815 hostapd_disassoc_sta(assoc_hapd, assoc_sta, mgmt);
5816
5817 return true;
5818#else /* CONFIG_IEEE80211BE */
5819 return false;
5820#endif /* CONFIG_IEEE80211BE */
5821}
5822
5823
5824static void handle_disassoc(struct hostapd_data *hapd,
5825 const struct ieee80211_mgmt *mgmt, size_t len)
5826{
5827 struct sta_info *sta;
5828
5829 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
5830 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5831 "handle_disassoc - too short payload (len=%lu)",
5832 (unsigned long) len);
5833 return;
5834 }
5835
5836 sta = ap_get_sta(hapd, mgmt->sa);
5837 if (!sta) {
5838 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
5839 " trying to disassociate, but it is not associated",
5840 MAC2STR(mgmt->sa));
5841 return;
5842 }
5843
5844 if (hostapd_ml_handle_disconnect(hapd, sta, mgmt, true))
5845 return;
5846
5847 hostapd_disassoc_sta(hapd, sta, mgmt);
5848}
5849
5850
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005851static void handle_deauth(struct hostapd_data *hapd,
5852 const struct ieee80211_mgmt *mgmt, size_t len)
5853{
5854 struct sta_info *sta;
5855
5856 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005857 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5858 "handle_deauth - too short payload (len=%lu)",
5859 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005860 return;
5861 }
5862
Hai Shaloma20dcd72022-02-04 13:43:00 -08005863 /* Clear the PTKSA cache entries for PASN */
5864 ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
5865
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005866 sta = ap_get_sta(hapd, mgmt->sa);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005867 if (!sta) {
5868 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
5869 " trying to deauthenticate, but it is not authenticated",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005870 MAC2STR(mgmt->sa));
5871 return;
5872 }
5873
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005874 if (hostapd_ml_handle_disconnect(hapd, sta, mgmt, false))
5875 return;
5876
5877 hostapd_deauth_sta(hapd, sta, mgmt);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005878}
5879
5880
5881static void handle_beacon(struct hostapd_data *hapd,
5882 const struct ieee80211_mgmt *mgmt, size_t len,
5883 struct hostapd_frame_info *fi)
5884{
5885 struct ieee802_11_elems elems;
5886
5887 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005888 wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
5889 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005890 return;
5891 }
5892
5893 (void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
5894 len - (IEEE80211_HDRLEN +
5895 sizeof(mgmt->u.beacon)), &elems,
5896 0);
5897
5898 ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
5899}
5900
5901
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005902static int robust_action_frame(u8 category)
5903{
5904 return category != WLAN_ACTION_PUBLIC &&
5905 category != WLAN_ACTION_HT;
5906}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005907
5908
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005909static int handle_action(struct hostapd_data *hapd,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005910 const struct ieee80211_mgmt *mgmt, size_t len,
5911 unsigned int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005912{
5913 struct sta_info *sta;
Hai Shalom74f70d42019-02-11 14:42:39 -08005914 u8 *action __maybe_unused;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005915
Hai Shalom74f70d42019-02-11 14:42:39 -08005916 if (len < IEEE80211_HDRLEN + 2 + 1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005917 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5918 HOSTAPD_LEVEL_DEBUG,
5919 "handle_action - too short payload (len=%lu)",
5920 (unsigned long) len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005921 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005922 }
5923
Hai Shalom74f70d42019-02-11 14:42:39 -08005924 action = (u8 *) &mgmt->u.action.u;
5925 wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
5926 " da " MACSTR " len %d freq %u",
5927 mgmt->u.action.category, *action,
5928 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
5929
5930 sta = ap_get_sta(hapd, mgmt->sa);
5931
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005932 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
5933 (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
5934 wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
5935 "frame (category=%u) from unassociated STA " MACSTR,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005936 mgmt->u.action.category, MAC2STR(mgmt->sa));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005937 return 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005938 }
5939
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005940 if (sta && (sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt18463232014-01-24 12:29:41 -08005941 !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
5942 robust_action_frame(mgmt->u.action.category)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005943 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5944 HOSTAPD_LEVEL_DEBUG,
5945 "Dropped unprotected Robust Action frame from "
5946 "an MFP STA");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005947 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005948 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005949
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005950 if (sta) {
5951 u16 fc = le_to_host16(mgmt->frame_control);
5952 u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
5953
5954 if ((fc & WLAN_FC_RETRY) &&
5955 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
5956 sta->last_seq_ctrl == seq_ctrl &&
5957 sta->last_subtype == WLAN_FC_STYPE_ACTION) {
5958 hostapd_logger(hapd, sta->addr,
5959 HOSTAPD_MODULE_IEEE80211,
5960 HOSTAPD_LEVEL_DEBUG,
5961 "Drop repeated action frame seq_ctrl=0x%x",
5962 seq_ctrl);
5963 return 1;
5964 }
5965
5966 sta->last_seq_ctrl = seq_ctrl;
5967 sta->last_subtype = WLAN_FC_STYPE_ACTION;
5968 }
5969
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005970 switch (mgmt->u.action.category) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005971#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005972 case WLAN_ACTION_FT:
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005973 if (!sta ||
5974 wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005975 len - IEEE80211_HDRLEN))
5976 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005977 return 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005978#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005979 case WLAN_ACTION_WMM:
5980 hostapd_wmm_action(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005981 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005982 case WLAN_ACTION_SA_QUERY:
Hai Shalom021b0b52019-04-10 11:17:58 -07005983 ieee802_11_sa_query_action(hapd, mgmt, len);
5984 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005985#ifdef CONFIG_WNM_AP
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005986 case WLAN_ACTION_WNM:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005987 ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
5988 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005989#endif /* CONFIG_WNM_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005990#ifdef CONFIG_FST
5991 case WLAN_ACTION_FST:
5992 if (hapd->iface->fst)
5993 fst_rx_action(hapd->iface->fst, mgmt, len);
5994 else
5995 wpa_printf(MSG_DEBUG,
5996 "FST: Ignore FST Action frame - no FST attached");
5997 return 1;
5998#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005999 case WLAN_ACTION_PUBLIC:
Dmitry Shmidt18463232014-01-24 12:29:41 -08006000 case WLAN_ACTION_PROTECTED_DUAL:
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07006001 if (len >= IEEE80211_HDRLEN + 2 &&
6002 mgmt->u.action.u.public_action.action ==
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006003 WLAN_PA_20_40_BSS_COEX) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006004 hostapd_2040_coex_action(hapd, mgmt, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006005 return 1;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006006 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006007#ifdef CONFIG_DPP
6008 if (len >= IEEE80211_HDRLEN + 6 &&
6009 mgmt->u.action.u.vs_public_action.action ==
6010 WLAN_PA_VENDOR_SPECIFIC &&
6011 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6012 OUI_WFA &&
6013 mgmt->u.action.u.vs_public_action.variable[0] ==
6014 DPP_OUI_TYPE) {
6015 const u8 *pos, *end;
6016
6017 pos = mgmt->u.action.u.vs_public_action.oui;
6018 end = ((const u8 *) mgmt) + len;
6019 hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006020 freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006021 return 1;
6022 }
6023 if (len >= IEEE80211_HDRLEN + 2 &&
6024 (mgmt->u.action.u.public_action.action ==
6025 WLAN_PA_GAS_INITIAL_RESP ||
6026 mgmt->u.action.u.public_action.action ==
6027 WLAN_PA_GAS_COMEBACK_RESP)) {
6028 const u8 *pos, *end;
6029
6030 pos = &mgmt->u.action.u.public_action.action;
6031 end = ((const u8 *) mgmt) + len;
Sunil Ravi036cec52023-03-29 11:35:17 -07006032 if (gas_query_ap_rx(hapd->gas, mgmt->sa,
6033 mgmt->u.action.category,
6034 pos, end - pos, freq) == 0)
6035 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006036 }
6037#endif /* CONFIG_DPP */
Sunil Ravi72e01222024-03-09 01:25:43 +00006038#ifdef CONFIG_NAN_USD
6039 if (mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6040 len >= IEEE80211_HDRLEN + 5 &&
6041 mgmt->u.action.u.vs_public_action.action ==
6042 WLAN_PA_VENDOR_SPECIFIC &&
6043 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6044 OUI_WFA &&
6045 mgmt->u.action.u.vs_public_action.variable[0] ==
6046 NAN_OUI_TYPE) {
6047 const u8 *pos, *end;
6048
6049 pos = mgmt->u.action.u.vs_public_action.variable;
6050 end = ((const u8 *) mgmt) + len;
6051 pos++;
6052 hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, freq,
6053 pos, end - pos);
6054 return 1;
6055 }
6056#endif /* CONFIG_NAN_USD */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006057 if (hapd->public_action_cb) {
6058 hapd->public_action_cb(hapd->public_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006059 (u8 *) mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006060 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006061 if (hapd->public_action_cb2) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -08006062 hapd->public_action_cb2(hapd->public_action_cb2_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006063 (u8 *) mgmt, len, freq);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006064 }
6065 if (hapd->public_action_cb || hapd->public_action_cb2)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006066 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006067 break;
6068 case WLAN_ACTION_VENDOR_SPECIFIC:
6069 if (hapd->vendor_action_cb) {
6070 if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006071 (u8 *) mgmt, len, freq) == 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006072 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006073 }
6074 break;
Sunil Ravi72e01222024-03-09 01:25:43 +00006075#ifndef CONFIG_NO_RRM
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006076 case WLAN_ACTION_RADIO_MEASUREMENT:
6077 hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
6078 return 1;
Sunil Ravi72e01222024-03-09 01:25:43 +00006079#endif /* CONFIG_NO_RRM */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006080 }
6081
6082 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6083 HOSTAPD_LEVEL_DEBUG,
6084 "handle_action - unknown action category %d or invalid "
6085 "frame",
6086 mgmt->u.action.category);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006087 if (!is_multicast_ether_addr(mgmt->da) &&
6088 !(mgmt->u.action.category & 0x80) &&
6089 !is_multicast_ether_addr(mgmt->sa)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006090 struct ieee80211_mgmt *resp;
6091
6092 /*
6093 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
6094 * Return the Action frame to the source without change
6095 * except that MSB of the Category set to 1.
6096 */
6097 wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
6098 "frame back to sender");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006099 resp = os_memdup(mgmt, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006100 if (resp == NULL)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006101 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006102 os_memcpy(resp->da, resp->sa, ETH_ALEN);
6103 os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
6104 os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
6105 resp->u.action.category |= 0x80;
6106
Hai Shalomfdcde762020-04-02 11:19:20 -07006107 if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006108 wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
6109 "Action frame");
6110 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006111 os_free(resp);
6112 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006113
6114 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006115}
6116
6117
6118/**
Hai Shalom60840252021-02-19 19:02:11 -08006119 * notify_mgmt_frame - Notify of Management frames on the control interface
6120 * @hapd: hostapd BSS data structure (the BSS to which the Management frame was
6121 * sent to)
6122 * @buf: Management frame data (starting from the IEEE 802.11 header)
6123 * @len: Length of frame data in octets
6124 *
6125 * Notify the control interface of any received Management frame.
6126 */
6127static void notify_mgmt_frame(struct hostapd_data *hapd, const u8 *buf,
6128 size_t len)
6129{
6130
6131 int hex_len = len * 2 + 1;
6132 char *hex = os_malloc(hex_len);
6133
6134 if (hex) {
6135 wpa_snprintf_hex(hex, hex_len, buf, len);
6136 wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO,
6137 AP_MGMT_FRAME_RECEIVED "buf=%s", hex);
6138 os_free(hex);
6139 }
6140}
6141
6142
6143/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006144 * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
6145 * @hapd: hostapd BSS data structure (the BSS to which the management frame was
6146 * sent to)
6147 * @buf: management frame data (starting from IEEE 802.11 header)
6148 * @len: length of frame data in octets
6149 * @fi: meta data about received frame (signal level, etc.)
6150 *
6151 * Process all incoming IEEE 802.11 management frames. This will be called for
6152 * each frame received from the kernel driver through wlan#ap interface. In
6153 * addition, it can be called to re-inserted pending frames (e.g., when using
6154 * external RADIUS server as an MAC ACL).
6155 */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006156int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
6157 struct hostapd_frame_info *fi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006158{
6159 struct ieee80211_mgmt *mgmt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006160 u16 fc, stype;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006161 int ret = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006162 unsigned int freq;
6163 int ssi_signal = fi ? fi->ssi_signal : 0;
Sunil Ravi72e01222024-03-09 01:25:43 +00006164#ifdef CONFIG_NAN_USD
6165 static const u8 nan_network_id[ETH_ALEN] =
6166 { 0x51, 0x6f, 0x9a, 0x01, 0x00, 0x00 };
6167#endif /* CONFIG_NAN_USD */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006168
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006169 if (len < 24)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006170 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006171
Roshan Pius3a1667e2018-07-03 15:17:14 -07006172 if (fi && fi->freq)
6173 freq = fi->freq;
6174 else
6175 freq = hapd->iface->freq;
6176
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006177 mgmt = (struct ieee80211_mgmt *) buf;
6178 fc = le_to_host16(mgmt->frame_control);
6179 stype = WLAN_FC_GET_STYPE(fc);
6180
Hai Shalomc3565922019-10-28 11:58:20 -07006181 if (is_multicast_ether_addr(mgmt->sa) ||
6182 is_zero_ether_addr(mgmt->sa) ||
Sunil Ravi72e01222024-03-09 01:25:43 +00006183 ether_addr_equal(mgmt->sa, hapd->own_addr)) {
Hai Shalomc3565922019-10-28 11:58:20 -07006184 /* Do not process any frames with unexpected/invalid SA so that
6185 * we do not add any state for unexpected STA addresses or end
6186 * up sending out frames to unexpected destination. */
6187 wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
6188 " in received frame - ignore this frame silently",
6189 MAC2STR(mgmt->sa));
6190 return 0;
6191 }
6192
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006193 if (stype == WLAN_FC_STYPE_BEACON) {
6194 handle_beacon(hapd, mgmt, len, fi);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006195 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006196 }
6197
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07006198 if (!is_broadcast_ether_addr(mgmt->bssid) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006199#ifdef CONFIG_P2P
6200 /* Invitation responses can be sent with the peer MAC as BSSID */
6201 !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
6202 stype == WLAN_FC_STYPE_ACTION) &&
6203#endif /* CONFIG_P2P */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006204#ifdef CONFIG_MESH
6205 !(hapd->conf->mesh & MESH_ENABLED) &&
6206#endif /* CONFIG_MESH */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006207#ifdef CONFIG_IEEE80211BE
6208 !(hapd->conf->mld_ap &&
Sunil Ravi72e01222024-03-09 01:25:43 +00006209 ether_addr_equal(hapd->mld_addr, mgmt->bssid)) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006210#endif /* CONFIG_IEEE80211BE */
Sunil Ravi72e01222024-03-09 01:25:43 +00006211 !ether_addr_equal(mgmt->bssid, hapd->own_addr)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006212 wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
6213 MAC2STR(mgmt->bssid));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006214 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006215 }
6216
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006217 if (hapd->iface->state != HAPD_IFACE_ENABLED) {
6218 wpa_printf(MSG_DEBUG, "MGMT: Ignore management frame while interface is not enabled (SA=" MACSTR " DA=" MACSTR " subtype=%u)",
6219 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), stype);
6220 return 1;
6221 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006222
6223 if (stype == WLAN_FC_STYPE_PROBE_REQ) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006224 handle_probe_req(hapd, mgmt, len, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006225 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006226 }
6227
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006228 if ((!is_broadcast_ether_addr(mgmt->da) ||
6229 stype != WLAN_FC_STYPE_ACTION) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006230#ifdef CONFIG_IEEE80211BE
6231 !(hapd->conf->mld_ap &&
Sunil Ravi72e01222024-03-09 01:25:43 +00006232 ether_addr_equal(hapd->mld_addr, mgmt->bssid)) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006233#endif /* CONFIG_IEEE80211BE */
Sunil Ravi72e01222024-03-09 01:25:43 +00006234#ifdef CONFIG_NAN_USD
6235 !ether_addr_equal(mgmt->da, nan_network_id) &&
6236#endif /* CONFIG_NAN_USD */
6237 !ether_addr_equal(mgmt->da, hapd->own_addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006238 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6239 HOSTAPD_LEVEL_DEBUG,
6240 "MGMT: DA=" MACSTR " not our address",
6241 MAC2STR(mgmt->da));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006242 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006243 }
6244
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006245 if (hapd->iconf->track_sta_max_num)
Roshan Pius3a1667e2018-07-03 15:17:14 -07006246 sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006247
Hai Shalom60840252021-02-19 19:02:11 -08006248 if (hapd->conf->notify_mgmt_frames)
6249 notify_mgmt_frame(hapd, buf, len);
6250
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006251 switch (stype) {
6252 case WLAN_FC_STYPE_AUTH:
6253 wpa_printf(MSG_DEBUG, "mgmt::auth");
Hai Shalom021b0b52019-04-10 11:17:58 -07006254 handle_auth(hapd, mgmt, len, ssi_signal, 0);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006255 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006256 break;
6257 case WLAN_FC_STYPE_ASSOC_REQ:
6258 wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006259 handle_assoc(hapd, mgmt, len, 0, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006260 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006261 break;
6262 case WLAN_FC_STYPE_REASSOC_REQ:
6263 wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006264 handle_assoc(hapd, mgmt, len, 1, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006265 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006266 break;
6267 case WLAN_FC_STYPE_DISASSOC:
6268 wpa_printf(MSG_DEBUG, "mgmt::disassoc");
6269 handle_disassoc(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006270 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006271 break;
6272 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006273 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006274 handle_deauth(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006275 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006276 break;
6277 case WLAN_FC_STYPE_ACTION:
6278 wpa_printf(MSG_DEBUG, "mgmt::action");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006279 ret = handle_action(hapd, mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006280 break;
6281 default:
6282 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6283 HOSTAPD_LEVEL_DEBUG,
6284 "unknown mgmt frame subtype %d", stype);
6285 break;
6286 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006287
6288 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006289}
6290
6291
6292static void handle_auth_cb(struct hostapd_data *hapd,
6293 const struct ieee80211_mgmt *mgmt,
6294 size_t len, int ok)
6295{
6296 u16 auth_alg, auth_transaction, status_code;
6297 struct sta_info *sta;
Hai Shalom60840252021-02-19 19:02:11 -08006298 bool success_status;
Hai Shalome5e28bb2019-01-28 14:51:04 -08006299
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006300 sta = ap_get_sta(hapd, mgmt->da);
6301 if (!sta) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006302 wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
6303 " not found",
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006304 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006305 return;
6306 }
6307
Hai Shalom60840252021-02-19 19:02:11 -08006308 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
6309 wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
6310 (unsigned long) len);
6311 auth_alg = 0;
6312 auth_transaction = 0;
6313 status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
6314 goto fail;
6315 }
6316
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006317 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
6318 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
6319 status_code = le_to_host16(mgmt->u.auth.status_code);
6320
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006321 if (!ok) {
6322 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6323 HOSTAPD_LEVEL_NOTICE,
6324 "did not acknowledge authentication response");
6325 goto fail;
6326 }
6327
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006328 if (status_code == WLAN_STATUS_SUCCESS &&
6329 ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
6330 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
6331 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6332 HOSTAPD_LEVEL_INFO, "authenticated");
6333 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006334 if (sta->added_unassoc)
6335 hostapd_set_sta_flags(hapd, sta);
6336 return;
6337 }
6338
6339fail:
Hai Shalom60840252021-02-19 19:02:11 -08006340 success_status = status_code == WLAN_STATUS_SUCCESS;
6341#ifdef CONFIG_SAE
6342 if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1)
6343 success_status = sae_status_success(hapd, status_code);
6344#endif /* CONFIG_SAE */
6345 if (!success_status && sta->added_unassoc) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006346 hostapd_drv_sta_remove(hapd, sta->addr);
6347 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006348 }
6349}
6350
6351
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006352static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
6353 struct sta_info *sta,
6354 char *ifname_wds)
6355{
Hai Shalomfdcde762020-04-02 11:19:20 -07006356#ifdef CONFIG_WEP
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006357 int i;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07006358 struct hostapd_ssid *ssid = &hapd->conf->ssid;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006359
6360 if (hapd->conf->ieee802_1x || hapd->conf->wpa)
6361 return;
6362
6363 for (i = 0; i < 4; i++) {
6364 if (ssid->wep.key[i] &&
6365 hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
Hai Shalomfdcde762020-04-02 11:19:20 -07006366 0, i == ssid->wep.idx, NULL, 0,
6367 ssid->wep.key[i], ssid->wep.len[i],
6368 i == ssid->wep.idx ?
6369 KEY_FLAG_GROUP_RX_TX_DEFAULT :
6370 KEY_FLAG_GROUP_RX_TX)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006371 wpa_printf(MSG_WARNING,
6372 "Could not set WEP keys for WDS interface; %s",
6373 ifname_wds);
6374 break;
6375 }
6376 }
Hai Shalomfdcde762020-04-02 11:19:20 -07006377#endif /* CONFIG_WEP */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006378}
6379
6380
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006381#ifdef CONFIG_IEEE80211BE
6382static void ieee80211_ml_link_sta_assoc_cb(struct hostapd_data *hapd,
6383 struct sta_info *sta,
6384 struct mld_link_info *link,
6385 bool ok)
6386{
Sunil Ravi72e01222024-03-09 01:25:43 +00006387 bool updated = false;
6388
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006389 if (!ok) {
6390 hostapd_logger(hapd, link->peer_addr, HOSTAPD_MODULE_IEEE80211,
6391 HOSTAPD_LEVEL_DEBUG,
6392 "did not acknowledge association response");
6393 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
6394
6395 /* The STA is added only in case of SUCCESS */
6396 if (link->status == WLAN_STATUS_SUCCESS)
6397 hostapd_drv_sta_remove(hapd, sta->addr);
6398
6399 return;
6400 }
6401
6402 if (link->status != WLAN_STATUS_SUCCESS)
6403 return;
6404
6405 sta->flags |= WLAN_STA_ASSOC;
6406 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
6407
6408 if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
Sunil Ravi72e01222024-03-09 01:25:43 +00006409 updated = ap_sta_set_authorized_flag(hapd, sta, 1);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006410
6411 hostapd_set_sta_flags(hapd, sta);
Sunil Ravi72e01222024-03-09 01:25:43 +00006412 if (updated)
6413 ap_sta_set_authorized_event(hapd, sta, 1);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006414
6415 /*
6416 * TODOs:
6417 * - IEEE 802.1X port enablement is not needed as done on the station
6418 * doing the connection.
6419 * - Not handling accounting
6420 * - Need to handle VLAN configuration
6421 */
6422}
6423#endif /* CONFIG_IEEE80211BE */
6424
6425
6426static void hostapd_ml_handle_assoc_cb(struct hostapd_data *hapd,
6427 struct sta_info *sta, bool ok)
6428{
6429#ifdef CONFIG_IEEE80211BE
6430 unsigned int i, link_id;
6431
6432 if (!hostapd_is_mld_ap(hapd))
6433 return;
6434
6435 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
6436 struct mld_link_info *link = &sta->mld_info.links[link_id];
6437
6438 if (!link->valid)
6439 continue;
6440
6441 for (i = 0; i < hapd->iface->interfaces->count; i++) {
6442 struct sta_info *tmp_sta;
6443 struct hostapd_data *tmp_hapd =
6444 hapd->iface->interfaces->iface[i]->bss[0];
6445
Sunil Ravi72e01222024-03-09 01:25:43 +00006446 if (!tmp_hapd->conf->mld_ap ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006447 hapd->conf->mld_id != tmp_hapd->conf->mld_id)
6448 continue;
6449
6450 for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
6451 tmp_sta = tmp_sta->next) {
6452 if (tmp_sta == sta ||
6453 tmp_sta->mld_assoc_link_id !=
6454 sta->mld_assoc_link_id ||
6455 tmp_sta->aid != sta->aid)
6456 continue;
6457
6458 ieee80211_ml_link_sta_assoc_cb(tmp_hapd,
6459 tmp_sta, link,
6460 ok);
6461 break;
6462 }
6463 }
6464 }
6465#endif /* CONFIG_IEEE80211BE */
6466}
6467
6468
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006469static void handle_assoc_cb(struct hostapd_data *hapd,
6470 const struct ieee80211_mgmt *mgmt,
6471 size_t len, int reassoc, int ok)
6472{
6473 u16 status;
6474 struct sta_info *sta;
6475 int new_assoc = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006476
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006477 sta = ap_get_sta(hapd, mgmt->da);
6478 if (!sta) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006479 wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
6480 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006481 return;
6482 }
6483
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006484#ifdef CONFIG_IEEE80211BE
Sunil Ravi72e01222024-03-09 01:25:43 +00006485 if (ap_sta_is_mld(hapd, sta) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006486 hapd->mld_link_id != sta->mld_assoc_link_id) {
6487 /* See ieee80211_ml_link_sta_assoc_cb() for the MLD case */
6488 wpa_printf(MSG_DEBUG,
6489 "%s: MLD: ignore on link station (%d != %d)",
6490 __func__, hapd->mld_link_id, sta->mld_assoc_link_id);
6491 return;
6492 }
6493#endif /* CONFIG_IEEE80211BE */
6494
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006495 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
6496 sizeof(mgmt->u.assoc_resp))) {
6497 wpa_printf(MSG_INFO,
6498 "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
6499 reassoc, (unsigned long) len);
6500 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006501 return;
6502 }
6503
6504 if (reassoc)
6505 status = le_to_host16(mgmt->u.reassoc_resp.status_code);
6506 else
6507 status = le_to_host16(mgmt->u.assoc_resp.status_code);
6508
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006509 if (!ok) {
6510 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6511 HOSTAPD_LEVEL_DEBUG,
6512 "did not acknowledge association response");
6513 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
6514 /* The STA is added only in case of SUCCESS */
6515 if (status == WLAN_STATUS_SUCCESS)
6516 hostapd_drv_sta_remove(hapd, sta->addr);
6517
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006518 goto handle_ml;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006519 }
6520
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006521 if (status != WLAN_STATUS_SUCCESS)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006522 goto handle_ml;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006523
6524 /* Stop previous accounting session, if one is started, and allocate
6525 * new session id for the new session. */
6526 accounting_sta_stop(hapd, sta);
6527
6528 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6529 HOSTAPD_LEVEL_INFO,
6530 "associated (aid %d)",
6531 sta->aid);
6532
6533 if (sta->flags & WLAN_STA_ASSOC)
6534 new_assoc = 0;
6535 sta->flags |= WLAN_STA_ASSOC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006536 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006537 if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
6538 !hapd->conf->osen) ||
6539 sta->auth_alg == WLAN_AUTH_FILS_SK ||
6540 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6541 sta->auth_alg == WLAN_AUTH_FILS_PK ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006542 sta->auth_alg == WLAN_AUTH_FT) {
6543 /*
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006544 * Open, static WEP, FT protocol, or FILS; no separate
6545 * authorization step.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006546 */
6547 ap_sta_set_authorized(hapd, sta, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006548 }
6549
6550 if (reassoc)
6551 mlme_reassociate_indication(hapd, sta);
6552 else
6553 mlme_associate_indication(hapd, sta);
6554
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006555 sta->sa_query_timed_out = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006556
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006557 if (sta->eapol_sm == NULL) {
6558 /*
6559 * This STA does not use RADIUS server for EAP authentication,
6560 * so bind it to the selected VLAN interface now, since the
6561 * interface selection is not going to change anymore.
6562 */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006563 if (ap_sta_bind_vlan(hapd, sta) < 0)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006564 goto handle_ml;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006565 } else if (sta->vlan_id) {
6566 /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006567 if (ap_sta_bind_vlan(hapd, sta) < 0)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006568 goto handle_ml;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006569 }
6570
6571 hostapd_set_sta_flags(hapd, sta);
6572
Dmitry Shmidt29333592017-01-09 12:27:11 -08006573 if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) {
6574 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA "
6575 MACSTR " based on pending request",
6576 MAC2STR(sta->addr));
6577 sta->pending_wds_enable = 0;
6578 sta->flags |= WLAN_STA_WDS;
6579 }
6580
Sunil Ravi640215c2023-06-28 23:08:09 +00006581 /* WPS not supported on backhaul BSS. Disable 4addr mode on fronthaul */
6582 if ((sta->flags & WLAN_STA_WDS) ||
6583 (sta->flags & WLAN_STA_MULTI_AP &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006584 (hapd->conf->multi_ap & BACKHAUL_BSS) &&
Sunil Ravi640215c2023-06-28 23:08:09 +00006585 !(sta->flags & WLAN_STA_WPS))) {
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08006586 int ret;
6587 char ifname_wds[IFNAMSIZ + 1];
6588
6589 wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA "
6590 MACSTR " (aid %u)",
6591 MAC2STR(sta->addr), sta->aid);
6592 ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
6593 sta->aid, 1);
6594 if (!ret)
6595 hostapd_set_wds_encryption(hapd, sta, ifname_wds);
6596 }
6597
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006598 if (sta->auth_alg == WLAN_AUTH_FT)
6599 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
6600 else
6601 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
6602 hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006603 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006604
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006605#ifdef CONFIG_FILS
6606 if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
6607 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6608 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
6609 fils_set_tk(sta->wpa_sm) < 0) {
6610 wpa_printf(MSG_DEBUG, "FILS: TK configuration failed");
6611 ap_sta_disconnect(hapd, sta, sta->addr,
6612 WLAN_REASON_UNSPECIFIED);
6613 return;
6614 }
6615#endif /* CONFIG_FILS */
6616
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006617 if (sta->pending_eapol_rx) {
6618 struct os_reltime now, age;
6619
6620 os_get_reltime(&now);
6621 os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
6622 if (age.sec == 0 && age.usec < 200000) {
6623 wpa_printf(MSG_DEBUG,
6624 "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
6625 MAC2STR(sta->addr));
6626 ieee802_1x_receive(
6627 hapd, mgmt->da,
6628 wpabuf_head(sta->pending_eapol_rx->buf),
Sunil8cd6f4d2022-06-28 18:40:46 +00006629 wpabuf_len(sta->pending_eapol_rx->buf),
6630 sta->pending_eapol_rx->encrypted);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006631 }
6632 wpabuf_free(sta->pending_eapol_rx->buf);
6633 os_free(sta->pending_eapol_rx);
6634 sta->pending_eapol_rx = NULL;
6635 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006636
6637handle_ml:
6638 hostapd_ml_handle_assoc_cb(hapd, sta, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006639}
6640
6641
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006642static void handle_deauth_cb(struct hostapd_data *hapd,
6643 const struct ieee80211_mgmt *mgmt,
6644 size_t len, int ok)
6645{
6646 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006647 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006648 return;
6649 sta = ap_get_sta(hapd, mgmt->da);
6650 if (!sta) {
6651 wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
6652 " not found", MAC2STR(mgmt->da));
6653 return;
6654 }
6655 if (ok)
6656 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
6657 MAC2STR(sta->addr));
6658 else
6659 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6660 "deauth", MAC2STR(sta->addr));
6661
6662 ap_sta_deauth_cb(hapd, sta);
6663}
6664
6665
6666static void handle_disassoc_cb(struct hostapd_data *hapd,
6667 const struct ieee80211_mgmt *mgmt,
6668 size_t len, int ok)
6669{
6670 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006671 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006672 return;
6673 sta = ap_get_sta(hapd, mgmt->da);
6674 if (!sta) {
6675 wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
6676 " not found", MAC2STR(mgmt->da));
6677 return;
6678 }
6679 if (ok)
6680 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
6681 MAC2STR(sta->addr));
6682 else
6683 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6684 "disassoc", MAC2STR(sta->addr));
6685
6686 ap_sta_disassoc_cb(hapd, sta);
6687}
6688
6689
Dmitry Shmidt29333592017-01-09 12:27:11 -08006690static void handle_action_cb(struct hostapd_data *hapd,
6691 const struct ieee80211_mgmt *mgmt,
6692 size_t len, int ok)
6693{
6694 struct sta_info *sta;
Sunil Ravi72e01222024-03-09 01:25:43 +00006695#ifndef CONFIG_NO_RRM
Paul Stewart092955c2017-02-06 09:13:09 -08006696 const struct rrm_measurement_report_element *report;
Sunil Ravi72e01222024-03-09 01:25:43 +00006697#endif /* CONFIG_NO_RRM */
Dmitry Shmidt29333592017-01-09 12:27:11 -08006698
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006699#ifdef CONFIG_DPP
6700 if (len >= IEEE80211_HDRLEN + 6 &&
6701 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6702 mgmt->u.action.u.vs_public_action.action ==
6703 WLAN_PA_VENDOR_SPECIFIC &&
6704 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6705 OUI_WFA &&
6706 mgmt->u.action.u.vs_public_action.variable[0] ==
6707 DPP_OUI_TYPE) {
6708 const u8 *pos, *end;
6709
6710 pos = &mgmt->u.action.u.vs_public_action.variable[1];
6711 end = ((const u8 *) mgmt) + len;
6712 hostapd_dpp_tx_status(hapd, mgmt->da, pos, end - pos, ok);
6713 return;
6714 }
6715 if (len >= IEEE80211_HDRLEN + 2 &&
6716 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6717 (mgmt->u.action.u.public_action.action ==
6718 WLAN_PA_GAS_INITIAL_REQ ||
6719 mgmt->u.action.u.public_action.action ==
6720 WLAN_PA_GAS_COMEBACK_REQ)) {
6721 const u8 *pos, *end;
6722
6723 pos = mgmt->u.action.u.public_action.variable;
6724 end = ((const u8 *) mgmt) + len;
6725 gas_query_ap_tx_status(hapd->gas, mgmt->da, pos, end - pos, ok);
6726 return;
6727 }
6728#endif /* CONFIG_DPP */
Hai Shaloma20dcd72022-02-04 13:43:00 -08006729 if (is_multicast_ether_addr(mgmt->da))
6730 return;
Dmitry Shmidt29333592017-01-09 12:27:11 -08006731 sta = ap_get_sta(hapd, mgmt->da);
6732 if (!sta) {
6733 wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR
6734 " not found", MAC2STR(mgmt->da));
6735 return;
6736 }
6737
Sunil Ravi77d572f2023-01-17 23:58:31 +00006738#ifdef CONFIG_HS20
6739 if (ok && len >= IEEE80211_HDRLEN + 2 &&
6740 mgmt->u.action.category == WLAN_ACTION_WNM &&
6741 mgmt->u.action.u.vs_public_action.action == WNM_NOTIFICATION_REQ &&
6742 sta->hs20_deauth_on_ack) {
6743 wpa_printf(MSG_DEBUG, "HS 2.0: Deauthenticate STA " MACSTR
6744 " on acknowledging the WNM-Notification",
6745 MAC2STR(sta->addr));
6746 ap_sta_session_timeout(hapd, sta, 0);
6747 return;
6748 }
6749#endif /* CONFIG_HS20 */
6750
Sunil Ravi72e01222024-03-09 01:25:43 +00006751#ifndef CONFIG_NO_RRM
Paul Stewart092955c2017-02-06 09:13:09 -08006752 if (len < 24 + 5 + sizeof(*report))
Dmitry Shmidt29333592017-01-09 12:27:11 -08006753 return;
Paul Stewart092955c2017-02-06 09:13:09 -08006754 report = (const struct rrm_measurement_report_element *)
6755 &mgmt->u.action.u.rrm.variable[2];
Dmitry Shmidt29333592017-01-09 12:27:11 -08006756 if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT &&
Paul Stewart092955c2017-02-06 09:13:09 -08006757 mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST &&
6758 report->eid == WLAN_EID_MEASURE_REQUEST &&
6759 report->len >= 3 &&
6760 report->type == MEASURE_TYPE_BEACON)
Dmitry Shmidt29333592017-01-09 12:27:11 -08006761 hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok);
Sunil Ravi72e01222024-03-09 01:25:43 +00006762#endif /* CONFIG_NO_RRM */
Dmitry Shmidt29333592017-01-09 12:27:11 -08006763}
6764
6765
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006766/**
6767 * ieee802_11_mgmt_cb - Process management frame TX status callback
6768 * @hapd: hostapd BSS data structure (the BSS from which the management frame
6769 * was sent from)
6770 * @buf: management frame data (starting from IEEE 802.11 header)
6771 * @len: length of frame data in octets
6772 * @stype: management frame subtype from frame control field
6773 * @ok: Whether the frame was ACK'ed
6774 */
6775void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
6776 u16 stype, int ok)
6777{
6778 const struct ieee80211_mgmt *mgmt;
6779 mgmt = (const struct ieee80211_mgmt *) buf;
6780
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006781#ifdef CONFIG_TESTING_OPTIONS
6782 if (hapd->ext_mgmt_frame_handling) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006783 size_t hex_len = 2 * len + 1;
6784 char *hex = os_malloc(hex_len);
6785
6786 if (hex) {
6787 wpa_snprintf_hex(hex, hex_len, buf, len);
6788 wpa_msg(hapd->msg_ctx, MSG_INFO,
6789 "MGMT-TX-STATUS stype=%u ok=%d buf=%s",
6790 stype, ok, hex);
6791 os_free(hex);
6792 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006793 return;
6794 }
6795#endif /* CONFIG_TESTING_OPTIONS */
6796
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006797 switch (stype) {
6798 case WLAN_FC_STYPE_AUTH:
6799 wpa_printf(MSG_DEBUG, "mgmt::auth cb");
6800 handle_auth_cb(hapd, mgmt, len, ok);
6801 break;
6802 case WLAN_FC_STYPE_ASSOC_RESP:
6803 wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
6804 handle_assoc_cb(hapd, mgmt, len, 0, ok);
6805 break;
6806 case WLAN_FC_STYPE_REASSOC_RESP:
6807 wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
6808 handle_assoc_cb(hapd, mgmt, len, 1, ok);
6809 break;
6810 case WLAN_FC_STYPE_PROBE_RESP:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006811 wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006812 break;
6813 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006814 wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
6815 handle_deauth_cb(hapd, mgmt, len, ok);
6816 break;
6817 case WLAN_FC_STYPE_DISASSOC:
6818 wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
6819 handle_disassoc_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006820 break;
6821 case WLAN_FC_STYPE_ACTION:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006822 wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006823 handle_action_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006824 break;
6825 default:
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006826 wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006827 break;
6828 }
6829}
6830
6831
6832int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
6833{
6834 /* TODO */
6835 return 0;
6836}
6837
6838
6839int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
6840 char *buf, size_t buflen)
6841{
6842 /* TODO */
6843 return 0;
6844}
6845
6846
6847void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
6848 const u8 *buf, size_t len, int ack)
6849{
6850 struct sta_info *sta;
6851 struct hostapd_iface *iface = hapd->iface;
6852
6853 sta = ap_get_sta(hapd, addr);
6854 if (sta == NULL && iface->num_bss > 1) {
6855 size_t j;
6856 for (j = 0; j < iface->num_bss; j++) {
6857 hapd = iface->bss[j];
6858 sta = ap_get_sta(hapd, addr);
6859 if (sta)
6860 break;
6861 }
6862 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006863 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006864 return;
6865 if (sta->flags & WLAN_STA_PENDING_POLL) {
6866 wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
6867 "activity poll", MAC2STR(sta->addr),
6868 ack ? "ACKed" : "did not ACK");
6869 if (ack)
6870 sta->flags &= ~WLAN_STA_PENDING_POLL;
6871 }
6872
6873 ieee802_1x_tx_status(hapd, sta, buf, len, ack);
6874}
6875
6876
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006877void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
6878 const u8 *data, size_t len, int ack)
6879{
6880 struct sta_info *sta;
6881 struct hostapd_iface *iface = hapd->iface;
6882
6883 sta = ap_get_sta(hapd, dst);
6884 if (sta == NULL && iface->num_bss > 1) {
6885 size_t j;
6886 for (j = 0; j < iface->num_bss; j++) {
6887 hapd = iface->bss[j];
6888 sta = ap_get_sta(hapd, dst);
6889 if (sta)
6890 break;
6891 }
6892 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006893 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
6894 wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA "
6895 MACSTR " that is not currently associated",
6896 MAC2STR(dst));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006897 return;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006898 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006899
6900 ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
6901}
6902
6903
6904void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
6905{
6906 struct sta_info *sta;
6907 struct hostapd_iface *iface = hapd->iface;
6908
6909 sta = ap_get_sta(hapd, addr);
6910 if (sta == NULL && iface->num_bss > 1) {
6911 size_t j;
6912 for (j = 0; j < iface->num_bss; j++) {
6913 hapd = iface->bss[j];
6914 sta = ap_get_sta(hapd, addr);
6915 if (sta)
6916 break;
6917 }
6918 }
6919 if (sta == NULL)
6920 return;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006921 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
6922 MAC2STR(sta->addr));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006923 if (!(sta->flags & WLAN_STA_PENDING_POLL))
6924 return;
6925
6926 wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
6927 "activity poll", MAC2STR(sta->addr));
6928 sta->flags &= ~WLAN_STA_PENDING_POLL;
6929}
6930
6931
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006932void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
6933 int wds)
6934{
6935 struct sta_info *sta;
6936
6937 sta = ap_get_sta(hapd, src);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006938 if (sta &&
6939 ((sta->flags & WLAN_STA_ASSOC) ||
6940 ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006941 if (!hapd->conf->wds_sta)
6942 return;
6943
Dmitry Shmidt29333592017-01-09 12:27:11 -08006944 if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) ==
6945 WLAN_STA_ASSOC_REQ_OK) {
6946 wpa_printf(MSG_DEBUG,
6947 "Postpone 4-address WDS mode enabling for STA "
6948 MACSTR " since TX status for AssocResp is not yet known",
6949 MAC2STR(sta->addr));
6950 sta->pending_wds_enable = 1;
6951 return;
6952 }
6953
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006954 if (wds && !(sta->flags & WLAN_STA_WDS)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006955 int ret;
6956 char ifname_wds[IFNAMSIZ + 1];
6957
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006958 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
6959 "STA " MACSTR " (aid %u)",
6960 MAC2STR(sta->addr), sta->aid);
6961 sta->flags |= WLAN_STA_WDS;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006962 ret = hostapd_set_wds_sta(hapd, ifname_wds,
6963 sta->addr, sta->aid, 1);
6964 if (!ret)
6965 hostapd_set_wds_encryption(hapd, sta,
6966 ifname_wds);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006967 }
6968 return;
6969 }
6970
6971 wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
6972 MACSTR, MAC2STR(src));
Hai Shalomc3565922019-10-28 11:58:20 -07006973 if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
Sunil Ravi72e01222024-03-09 01:25:43 +00006974 ether_addr_equal(src, hapd->own_addr)) {
Hai Shalomc3565922019-10-28 11:58:20 -07006975 /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
6976 * silently. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006977 return;
6978 }
6979
6980 if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) {
6981 wpa_printf(MSG_DEBUG, "Association Response to the STA has "
6982 "already been sent, but no TX status yet known - "
6983 "ignore Class 3 frame issue with " MACSTR,
6984 MAC2STR(src));
6985 return;
6986 }
6987
6988 if (sta && (sta->flags & WLAN_STA_AUTH))
6989 hostapd_drv_sta_disassoc(
6990 hapd, src,
6991 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
6992 else
6993 hostapd_drv_sta_deauth(
6994 hapd, src,
6995 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
6996}
6997
6998
Sunil Ravia04bd252022-05-02 22:54:18 -07006999static u8 * hostapd_add_tpe_info(u8 *eid, u8 tx_pwr_count,
7000 enum max_tx_pwr_interpretation tx_pwr_intrpn,
7001 u8 tx_pwr_cat, u8 tx_pwr)
7002{
7003 int i;
7004
7005 *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE; /* Element ID */
7006 *eid++ = 2 + tx_pwr_count; /* Length */
7007
7008 /*
7009 * Transmit Power Information field
7010 * bits 0-2 : Maximum Transmit Power Count
7011 * bits 3-5 : Maximum Transmit Power Interpretation
7012 * bits 6-7 : Maximum Transmit Power Category
7013 */
7014 *eid++ = tx_pwr_count | (tx_pwr_intrpn << 3) | (tx_pwr_cat << 6);
7015
7016 /* Maximum Transmit Power field */
7017 for (i = 0; i <= tx_pwr_count; i++)
7018 *eid++ = tx_pwr;
7019
7020 return eid;
7021}
7022
7023
7024/*
7025 * TODO: Extract power limits from channel data after 6G regulatory
7026 * support.
7027 */
7028#define REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT (-1) /* dBm/MHz */
7029#define REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT 5 /* dBm/MHz */
7030
Hai Shalom60840252021-02-19 19:02:11 -08007031u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
7032{
7033 struct hostapd_iface *iface = hapd->iface;
7034 struct hostapd_config *iconf = iface->conf;
7035 struct hostapd_hw_modes *mode = iface->current_mode;
7036 struct hostapd_channel_data *chan;
7037 int dfs, i;
7038 u8 channel, tx_pwr_count, local_pwr_constraint;
7039 int max_tx_power;
7040 u8 tx_pwr;
7041
7042 if (!mode)
7043 return eid;
7044
7045 if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
7046 return eid;
7047
7048 for (i = 0; i < mode->num_channels; i++) {
7049 if (mode->channels[i].freq == iface->freq)
7050 break;
7051 }
7052 if (i == mode->num_channels)
7053 return eid;
7054
Sunil Ravia04bd252022-05-02 22:54:18 -07007055#ifdef CONFIG_IEEE80211AX
7056 /* IEEE Std 802.11ax-2021, Annex E.2.7 (6 GHz band in the United
7057 * States): An AP that is an Indoor Access Point per regulatory rules
7058 * shall send at least two Transmit Power Envelope elements in Beacon
7059 * and Probe Response frames as follows:
7060 * - Maximum Transmit Power Category subfield = Default;
7061 * Unit interpretation = Regulatory client EIRP PSD
7062 * - Maximum Transmit Power Category subfield = Subordinate Device;
7063 * Unit interpretation = Regulatory client EIRP PSD
7064 */
7065 if (is_6ghz_op_class(iconf->op_class)) {
7066 enum max_tx_pwr_interpretation tx_pwr_intrpn;
7067
7068 /* Same Maximum Transmit Power for all 20 MHz bands */
7069 tx_pwr_count = 0;
7070 tx_pwr_intrpn = REGULATORY_CLIENT_EIRP_PSD;
7071
7072 /* Default Transmit Power Envelope for Global Operating Class */
Sunil Ravi72e01222024-03-09 01:25:43 +00007073 if (hapd->iconf->reg_def_cli_eirp_psd != -1)
7074 tx_pwr = hapd->iconf->reg_def_cli_eirp_psd;
7075 else
7076 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT * 2;
7077
Sunil Ravia04bd252022-05-02 22:54:18 -07007078 eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn,
7079 REG_DEFAULT_CLIENT, tx_pwr);
7080
7081 /* Indoor Access Point must include an additional TPE for
7082 * subordinate devices */
Sunil Ravi72e01222024-03-09 01:25:43 +00007083 if (he_reg_is_indoor(iconf->he_6ghz_reg_pwr_type)) {
Sunil Ravia04bd252022-05-02 22:54:18 -07007084 /* TODO: Extract PSD limits from channel data */
Sunil Ravi72e01222024-03-09 01:25:43 +00007085 if (hapd->iconf->reg_sub_cli_eirp_psd != -1)
7086 tx_pwr = hapd->iconf->reg_sub_cli_eirp_psd;
7087 else
7088 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT * 2;
Sunil Ravia04bd252022-05-02 22:54:18 -07007089 eid = hostapd_add_tpe_info(eid, tx_pwr_count,
7090 tx_pwr_intrpn,
7091 REG_SUBORDINATE_CLIENT,
7092 tx_pwr);
7093 }
7094
Sunil Ravi72e01222024-03-09 01:25:43 +00007095 if (iconf->reg_def_cli_eirp != -1 &&
7096 he_reg_is_sp(iconf->he_6ghz_reg_pwr_type))
7097 eid = hostapd_add_tpe_info(
7098 eid, tx_pwr_count, REGULATORY_CLIENT_EIRP,
7099 REG_DEFAULT_CLIENT,
7100 hapd->iconf->reg_def_cli_eirp);
7101
Sunil Ravia04bd252022-05-02 22:54:18 -07007102 return eid;
7103 }
7104#endif /* CONFIG_IEEE80211AX */
7105
Hai Shalom60840252021-02-19 19:02:11 -08007106 switch (hostapd_get_oper_chwidth(iconf)) {
Sunil8cd6f4d2022-06-28 18:40:46 +00007107 case CONF_OPER_CHWIDTH_USE_HT:
Hai Shalom60840252021-02-19 19:02:11 -08007108 if (iconf->secondary_channel == 0) {
7109 /* Max Transmit Power count = 0 (20 MHz) */
7110 tx_pwr_count = 0;
7111 } else {
7112 /* Max Transmit Power count = 1 (20, 40 MHz) */
7113 tx_pwr_count = 1;
7114 }
7115 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00007116 case CONF_OPER_CHWIDTH_80MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08007117 /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
7118 tx_pwr_count = 2;
7119 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00007120 case CONF_OPER_CHWIDTH_80P80MHZ:
7121 case CONF_OPER_CHWIDTH_160MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08007122 /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
7123 tx_pwr_count = 3;
7124 break;
7125 default:
7126 return eid;
7127 }
7128
7129 /*
7130 * Below local_pwr_constraint logic is referred from
7131 * hostapd_eid_pwr_constraint.
7132 *
7133 * Check if DFS is required by regulatory.
7134 */
7135 dfs = hostapd_is_dfs_required(hapd->iface);
7136 if (dfs < 0)
7137 dfs = 0;
7138
7139 /*
7140 * In order to meet regulations when TPC is not implemented using
7141 * a transmit power that is below the legal maximum (including any
7142 * mitigation factor) should help. In this case, indicate 3 dB below
7143 * maximum allowed transmit power.
7144 */
7145 if (hapd->iconf->local_pwr_constraint == -1)
7146 local_pwr_constraint = (dfs == 0) ? 0 : 3;
7147 else
7148 local_pwr_constraint = hapd->iconf->local_pwr_constraint;
7149
7150 /*
7151 * A STA that is not an AP shall use a transmit power less than or
7152 * equal to the local maximum transmit power level for the channel.
7153 * The local maximum transmit power can be calculated from the formula:
7154 * local max TX pwr = max TX pwr - local pwr constraint
7155 * Where max TX pwr is maximum transmit power level specified for
7156 * channel in Country element and local pwr constraint is specified
7157 * for channel in this Power Constraint element.
7158 */
7159 chan = &mode->channels[i];
7160 max_tx_power = chan->max_tx_power - local_pwr_constraint;
7161
7162 /*
7163 * Local Maximum Transmit power is encoded as two's complement
7164 * with a 0.5 dB step.
7165 */
7166 max_tx_power *= 2; /* in 0.5 dB steps */
7167 if (max_tx_power > 127) {
7168 /* 63.5 has special meaning of 63.5 dBm or higher */
7169 max_tx_power = 127;
7170 }
7171 if (max_tx_power < -128)
7172 max_tx_power = -128;
7173 if (max_tx_power < 0)
7174 tx_pwr = 0x80 + max_tx_power + 128;
7175 else
7176 tx_pwr = max_tx_power;
7177
Sunil Ravia04bd252022-05-02 22:54:18 -07007178 return hostapd_add_tpe_info(eid, tx_pwr_count, LOCAL_EIRP,
7179 0 /* Reserved for bands other than 6 GHz */,
7180 tx_pwr);
Hai Shalom60840252021-02-19 19:02:11 -08007181}
7182
7183
Hai Shalom899fcc72020-10-19 14:38:18 -07007184u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
7185{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007186 u8 bw, chan1 = 0, chan2 = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -07007187 int freq1;
7188
7189 if (!hapd->cs_freq_params.channel ||
7190 (!hapd->cs_freq_params.vht_enabled &&
Sunil Ravia04bd252022-05-02 22:54:18 -07007191 !hapd->cs_freq_params.he_enabled &&
7192 !hapd->cs_freq_params.eht_enabled))
Hai Shalom899fcc72020-10-19 14:38:18 -07007193 return eid;
7194
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007195 /* bandwidth: 0: 40, 1: 80, 160, 80+80, 4: 320 as per
7196 * IEEE P802.11-REVme/D4.0, 9.4.2.159 and Table 9-314. */
Hai Shalom899fcc72020-10-19 14:38:18 -07007197 switch (hapd->cs_freq_params.bandwidth) {
7198 case 40:
7199 bw = 0;
7200 break;
7201 case 80:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007202 bw = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07007203 break;
7204 case 160:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007205 bw = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07007206 break;
Sunil Ravi640215c2023-06-28 23:08:09 +00007207 case 320:
7208 bw = 4;
7209 break;
Hai Shalom899fcc72020-10-19 14:38:18 -07007210 default:
7211 /* not valid VHT bandwidth or not in CSA */
7212 return eid;
7213 }
7214
7215 freq1 = hapd->cs_freq_params.center_freq1 ?
7216 hapd->cs_freq_params.center_freq1 :
7217 hapd->cs_freq_params.freq;
7218 if (ieee80211_freq_to_chan(freq1, &chan1) !=
7219 HOSTAPD_MODE_IEEE80211A)
7220 return eid;
7221
7222 if (hapd->cs_freq_params.center_freq2 &&
7223 ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
7224 &chan2) != HOSTAPD_MODE_IEEE80211A)
7225 return eid;
7226
Sunil Ravi640215c2023-06-28 23:08:09 +00007227 *eid++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER;
Hai Shalom899fcc72020-10-19 14:38:18 -07007228 *eid++ = 5; /* Length of Channel Switch Wrapper */
Sunil Ravi640215c2023-06-28 23:08:09 +00007229 *eid++ = WLAN_EID_WIDE_BW_CHSWITCH;
Hai Shalom899fcc72020-10-19 14:38:18 -07007230 *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
7231 *eid++ = bw; /* New Channel Width */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007232 if (hapd->cs_freq_params.bandwidth == 160) {
7233 /* Update the CCFS0 and CCFS1 values in the element based on
7234 * IEEE P802.11-REVme/D4.0, Table 9-314 */
7235
7236 /* CCFS1 - The channel center frequency index of the 160 MHz
7237 * channel. */
7238 chan2 = chan1;
7239
7240 /* CCFS0 - The channel center frequency index of the 80 MHz
7241 * channel segment that contains the primary channel. */
7242 if (hapd->cs_freq_params.channel < chan1)
7243 chan1 -= 8;
7244 else
7245 chan1 += 8;
7246 }
Hai Shalom899fcc72020-10-19 14:38:18 -07007247 *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
7248 *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
7249
7250 return eid;
7251}
7252
Hai Shaloma20dcd72022-02-04 13:43:00 -08007253
7254static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd,
7255 size_t *current_len)
7256{
7257 struct hostapd_neighbor_entry *nr;
7258 size_t total_len = 0, len = *current_len;
7259
7260 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7261 list) {
7262 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7263 continue;
7264
7265 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7266 continue;
7267
7268 /* Start a new element */
7269 if (!len ||
7270 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7271 len = RNR_HEADER_LEN;
7272 total_len += RNR_HEADER_LEN;
7273 }
7274
7275 len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7276 total_len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7277 }
7278
7279 *current_len = len;
7280 return total_len;
7281}
7282
7283
Sunil Ravi640215c2023-06-28 23:08:09 +00007284struct mbssid_ie_profiles {
7285 u8 start;
7286 u8 end;
7287};
7288
7289static size_t
7290hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
7291 struct hostapd_data *reporting_hapd,
7292 size_t *current_len,
7293 struct mbssid_ie_profiles *skip_profiles)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007294{
7295 size_t total_len = 0, len = *current_len;
7296 int tbtt_count = 0;
7297 size_t i, start = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007298 bool ap_mld = false;
7299
7300#ifdef CONFIG_IEEE80211BE
7301 ap_mld = !!hapd->conf->mld_ap;
7302#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007303
7304 while (start < hapd->iface->num_bss) {
7305 if (!len ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007306 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255 ||
7307 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08007308 len = RNR_HEADER_LEN;
7309 total_len += RNR_HEADER_LEN;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007310 tbtt_count = 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007311 }
7312
7313 len += RNR_TBTT_HEADER_LEN;
7314 total_len += RNR_TBTT_HEADER_LEN;
7315
7316 for (i = start; i < hapd->iface->num_bss; i++) {
7317 struct hostapd_data *bss = hapd->iface->bss[i];
7318
7319 if (!bss || !bss->conf || !bss->started)
7320 continue;
7321
7322 if (bss == reporting_hapd ||
7323 bss->conf->ignore_broadcast_ssid)
7324 continue;
7325
Sunil Ravi640215c2023-06-28 23:08:09 +00007326 if (skip_profiles &&
7327 i >= skip_profiles->start && i < skip_profiles->end)
7328 continue;
7329
Hai Shaloma20dcd72022-02-04 13:43:00 -08007330 if (len + RNR_TBTT_INFO_LEN > 255 ||
7331 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7332 break;
7333
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007334 if (!ap_mld) {
7335 len += RNR_TBTT_INFO_LEN;
7336 total_len += RNR_TBTT_INFO_LEN;
7337 } else {
7338 len += RNR_TBTT_INFO_MLD_LEN;
7339 total_len += RNR_TBTT_INFO_MLD_LEN;
7340 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08007341 tbtt_count++;
7342 }
7343 start = i;
7344 }
7345
7346 if (!tbtt_count)
7347 total_len = 0;
7348 else
7349 *current_len = len;
7350
7351 return total_len;
7352}
7353
7354
7355enum colocation_mode {
7356 NO_COLOCATED_6GHZ,
7357 STANDALONE_6GHZ,
7358 COLOCATED_6GHZ,
7359 COLOCATED_LOWER_BAND,
7360};
7361
7362static enum colocation_mode get_colocation_mode(struct hostapd_data *hapd)
7363{
7364 u8 i;
7365 bool is_6ghz = is_6ghz_op_class(hapd->iconf->op_class);
7366
7367 if (!hapd->iface || !hapd->iface->interfaces)
7368 return NO_COLOCATED_6GHZ;
7369
7370 if (is_6ghz && hapd->iface->interfaces->count == 1)
7371 return STANDALONE_6GHZ;
7372
7373 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7374 struct hostapd_iface *iface;
7375 bool is_colocated_6ghz;
7376
7377 iface = hapd->iface->interfaces->iface[i];
7378 if (iface == hapd->iface || !iface || !iface->conf)
7379 continue;
7380
7381 is_colocated_6ghz = is_6ghz_op_class(iface->conf->op_class);
7382 if (!is_6ghz && is_colocated_6ghz)
7383 return COLOCATED_LOWER_BAND;
7384 if (is_6ghz && !is_colocated_6ghz)
7385 return COLOCATED_6GHZ;
7386 }
7387
7388 if (is_6ghz)
7389 return STANDALONE_6GHZ;
7390
7391 return NO_COLOCATED_6GHZ;
7392}
7393
7394
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007395static size_t hostapd_eid_rnr_multi_iface_len(struct hostapd_data *hapd,
7396 size_t *current_len)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007397{
7398 struct hostapd_iface *iface;
7399 size_t len = 0;
7400 size_t i;
7401
7402 if (!hapd->iface || !hapd->iface->interfaces)
7403 return 0;
7404
7405 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7406 iface = hapd->iface->interfaces->iface[i];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007407 bool ap_mld = false;
7408
7409#ifdef CONFIG_IEEE80211BE
7410 if (hapd->conf->mld_ap && iface->bss[0]->conf->mld_ap &&
7411 hapd->conf->mld_id == iface->bss[0]->conf->mld_id)
7412 ap_mld = true;
7413#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007414
7415 if (iface == hapd->iface ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007416 !(is_6ghz_op_class(iface->conf->op_class) || ap_mld))
Hai Shaloma20dcd72022-02-04 13:43:00 -08007417 continue;
7418
7419 len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007420 current_len, NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007421 }
7422
7423 return len;
7424}
7425
7426
7427size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type)
7428{
7429 size_t total_len = 0, current_len = 0;
7430 enum colocation_mode mode = get_colocation_mode(hapd);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007431 bool ap_mld = false;
7432
7433#ifdef CONFIG_IEEE80211BE
7434 ap_mld = !!hapd->conf->mld_ap;
7435#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007436
7437 switch (type) {
7438 case WLAN_FC_STYPE_BEACON:
7439 if (hapd->conf->rnr)
7440 total_len += hostapd_eid_nr_db_len(hapd, &current_len);
7441 /* fallthrough */
7442
7443 case WLAN_FC_STYPE_PROBE_RESP:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007444 if (mode == COLOCATED_LOWER_BAND || ap_mld)
7445 total_len +=
7446 hostapd_eid_rnr_multi_iface_len(hapd,
7447 &current_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007448
Sunil Ravi640215c2023-06-28 23:08:09 +00007449 if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
7450 !hapd->iconf->mbssid)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007451 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007452 &current_len,
7453 NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007454 break;
7455
7456 case WLAN_FC_STYPE_ACTION:
7457 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
7458 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007459 &current_len,
7460 NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007461 break;
7462
7463 default:
7464 break;
7465 }
7466
7467 return total_len;
7468}
7469
7470
7471static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid,
7472 size_t *current_len)
7473{
7474 struct hostapd_neighbor_entry *nr;
7475 size_t len = *current_len;
7476 u8 *size_offset = (eid - len) + 1;
7477
7478 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7479 list) {
7480 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7481 continue;
7482
7483 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7484 continue;
7485
7486 /* Start a new element */
7487 if (!len ||
7488 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7489 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7490 size_offset = eid++;
7491 len = RNR_HEADER_LEN;
7492 }
7493
7494 /* TBTT Information Header subfield (2 octets) */
7495 *eid++ = 0;
7496 /* TBTT Information Length */
7497 *eid++ = RNR_TBTT_INFO_LEN;
7498 /* Operating Class */
7499 *eid++ = wpabuf_head_u8(nr->nr)[10];
7500 /* Channel Number */
7501 *eid++ = wpabuf_head_u8(nr->nr)[11];
7502 len += RNR_TBTT_HEADER_LEN;
7503 /* TBTT Information Set */
7504 /* TBTT Information field */
7505 /* Neighbor AP TBTT Offset */
7506 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
7507 /* BSSID */
7508 os_memcpy(eid, nr->bssid, ETH_ALEN);
7509 eid += ETH_ALEN;
7510 /* Short SSID */
7511 os_memcpy(eid, &nr->short_ssid, 4);
7512 eid += 4;
7513 /* BSS parameters */
7514 *eid++ = nr->bss_parameters;
7515 /* 20 MHz PSD */
Sunil Ravi72e01222024-03-09 01:25:43 +00007516 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007517 len += RNR_TBTT_INFO_LEN;
7518 *size_offset = (eid - size_offset) - 1;
7519 }
7520
7521 *current_len = len;
7522 return eid;
7523}
7524
7525
Sunil Ravi72e01222024-03-09 01:25:43 +00007526static bool hostapd_eid_rnr_bss(struct hostapd_data *hapd,
7527 struct hostapd_data *reporting_hapd,
7528 struct mbssid_ie_profiles *skip_profiles,
7529 size_t i, u8 *tbtt_count, size_t *len,
7530 u8 **pos)
7531{
7532 struct hostapd_iface *iface = hapd->iface;
7533 struct hostapd_data *bss = iface->bss[i];
7534 u8 bss_param = 0;
7535 bool ap_mld = false;
7536 u8 *eid = *pos;
7537
7538#ifdef CONFIG_IEEE80211BE
7539 ap_mld = !!hapd->conf->mld_ap;
7540#endif /* CONFIG_IEEE80211BE */
7541
7542 if (!bss || !bss->conf || !bss->started ||
7543 bss == reporting_hapd || bss->conf->ignore_broadcast_ssid)
7544 return false;
7545
7546 if (skip_profiles
7547 && i >= skip_profiles->start && i < skip_profiles->end)
7548 return false;
7549
7550 if (*len + RNR_TBTT_INFO_LEN > 255 ||
7551 *tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7552 return true;
7553
7554 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
7555 os_memcpy(eid, bss->own_addr, ETH_ALEN);
7556 eid += ETH_ALEN;
7557 os_memcpy(eid, &bss->conf->ssid.short_ssid, 4);
7558 eid += 4;
7559 if (bss->conf->ssid.short_ssid == reporting_hapd->conf->ssid.short_ssid)
7560 bss_param |= RNR_BSS_PARAM_SAME_SSID;
7561
7562 if (iface->conf->mbssid != MBSSID_DISABLED && iface->num_bss > 1) {
7563 bss_param |= RNR_BSS_PARAM_MULTIPLE_BSSID;
7564 if (bss == hostapd_mbssid_get_tx_bss(hapd))
7565 bss_param |= RNR_BSS_PARAM_TRANSMITTED_BSSID;
7566 }
7567
7568 if (is_6ghz_op_class(hapd->iconf->op_class) &&
7569 bss->conf->unsol_bcast_probe_resp_interval)
7570 bss_param |= RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE;
7571
7572 bss_param |= RNR_BSS_PARAM_CO_LOCATED;
7573
7574 *eid++ = bss_param;
7575 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER;
7576
7577 if (!ap_mld) {
7578 *len += RNR_TBTT_INFO_LEN;
7579 } else {
7580#ifdef CONFIG_IEEE80211BE
7581 u8 param_ch = hapd->eht_mld_bss_param_change;
7582
7583 if (reporting_hapd->conf->mld_ap &&
7584 bss->conf->mld_id == reporting_hapd->conf->mld_id)
7585 *eid++ = 0;
7586 else
7587 *eid++ = hapd->conf->mld_id;
7588
7589 *eid++ = hapd->mld_link_id | ((param_ch & 0xF) << 4);
7590 *eid = (param_ch >> 4) & 0xF;
7591#ifdef CONFIG_TESTING_OPTIONS
7592 if (hapd->conf->mld_indicate_disabled)
7593 *eid |= RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED;
7594#endif /* CONFIG_TESTING_OPTIONS */
7595 eid++;
7596
7597 *len += RNR_TBTT_INFO_MLD_LEN;
7598#endif /* CONFIG_IEEE80211BE */
7599 }
7600
7601 (*tbtt_count)++;
7602 *pos = eid;
7603
7604 return false;
7605}
7606
7607
Hai Shaloma20dcd72022-02-04 13:43:00 -08007608static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
7609 struct hostapd_data *reporting_hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007610 u8 *eid, size_t *current_len,
7611 struct mbssid_ie_profiles *skip_profiles)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007612{
Hai Shaloma20dcd72022-02-04 13:43:00 -08007613 struct hostapd_iface *iface = hapd->iface;
7614 size_t i, start = 0;
7615 size_t len = *current_len;
7616 u8 *tbtt_count_pos, *eid_start = eid, *size_offset = (eid - len) + 1;
Sunil Ravi72e01222024-03-09 01:25:43 +00007617 u8 tbtt_count = 0, op_class, channel;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007618 bool ap_mld = false;
7619
7620#ifdef CONFIG_IEEE80211BE
7621 ap_mld = !!hapd->conf->mld_ap;
7622#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007623
7624 if (!(iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !iface->freq)
7625 return eid;
7626
7627 if (ieee80211_freq_to_channel_ext(iface->freq,
7628 hapd->iconf->secondary_channel,
7629 hostapd_get_oper_chwidth(hapd->iconf),
7630 &op_class, &channel) ==
7631 NUM_HOSTAPD_MODES)
7632 return eid;
7633
7634 while (start < iface->num_bss) {
7635 if (!len ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007636 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255 ||
7637 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08007638 eid_start = eid;
7639 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7640 size_offset = eid++;
7641 len = RNR_HEADER_LEN;
7642 tbtt_count = 0;
7643 }
7644
7645 tbtt_count_pos = eid++;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007646 *eid++ = ap_mld ? RNR_TBTT_INFO_MLD_LEN : RNR_TBTT_INFO_LEN;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007647 *eid++ = op_class;
7648 *eid++ = hapd->iconf->channel;
7649 len += RNR_TBTT_HEADER_LEN;
7650
7651 for (i = start; i < iface->num_bss; i++) {
Sunil Ravi72e01222024-03-09 01:25:43 +00007652 if (hostapd_eid_rnr_bss(hapd, reporting_hapd,
7653 skip_profiles, i,
7654 &tbtt_count, &len, &eid))
Hai Shaloma20dcd72022-02-04 13:43:00 -08007655 break;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007656 }
7657
7658 start = i;
7659 *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
7660 *size_offset = (eid - size_offset) - 1;
7661 }
7662
7663 if (tbtt_count == 0)
7664 return eid_start;
7665
7666 *current_len = len;
7667 return eid;
7668}
7669
7670
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007671static u8 * hostapd_eid_rnr_multi_iface(struct hostapd_data *hapd, u8 *eid,
7672 size_t *current_len)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007673{
7674 struct hostapd_iface *iface;
7675 size_t i;
7676
7677 if (!hapd->iface || !hapd->iface->interfaces)
7678 return eid;
7679
7680 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7681 iface = hapd->iface->interfaces->iface[i];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007682 bool ap_mld = false;
7683
7684#ifdef CONFIG_IEEE80211BE
7685 if (hapd->conf->mld_ap && iface->bss[0]->conf->mld_ap &&
7686 hapd->conf->mld_id == iface->bss[0]->conf->mld_id)
7687 ap_mld = true;
7688#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007689
7690 if (iface == hapd->iface ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007691 !(is_6ghz_op_class(iface->conf->op_class) || ap_mld))
Hai Shaloma20dcd72022-02-04 13:43:00 -08007692 continue;
7693
7694 eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
Sunil Ravi640215c2023-06-28 23:08:09 +00007695 current_len, NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007696 }
7697
7698 return eid;
7699}
7700
7701
7702u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
7703{
7704 u8 *eid_start = eid;
7705 size_t current_len = 0;
7706 enum colocation_mode mode = get_colocation_mode(hapd);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007707 bool ap_mld = false;
7708
7709#ifdef CONFIG_IEEE80211BE
7710 ap_mld = !!hapd->conf->mld_ap;
7711#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007712
7713 switch (type) {
7714 case WLAN_FC_STYPE_BEACON:
7715 if (hapd->conf->rnr)
7716 eid = hostapd_eid_nr_db(hapd, eid, &current_len);
7717 /* fallthrough */
7718
7719 case WLAN_FC_STYPE_PROBE_RESP:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007720 if (mode == COLOCATED_LOWER_BAND || ap_mld)
7721 eid = hostapd_eid_rnr_multi_iface(hapd, eid,
7722 &current_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007723
Sunil Ravi640215c2023-06-28 23:08:09 +00007724 if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
7725 !hapd->iconf->mbssid)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007726 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
Sunil Ravi640215c2023-06-28 23:08:09 +00007727 &current_len, NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007728 break;
7729
7730 case WLAN_FC_STYPE_ACTION:
7731 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
Sunil Ravi72e01222024-03-09 01:25:43 +00007732 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
Sunil Ravi640215c2023-06-28 23:08:09 +00007733 &current_len, NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007734 break;
7735
7736 default:
7737 return eid_start;
7738 }
7739
7740 if (eid == eid_start + 2)
7741 return eid_start;
7742
7743 return eid;
7744}
7745
Sunil Ravi77d572f2023-01-17 23:58:31 +00007746
7747static bool mbssid_known_bss(unsigned int i, const u8 *known_bss,
7748 size_t known_bss_len)
7749{
7750 if (!known_bss || known_bss_len <= i / 8)
7751 return false;
7752 known_bss = &known_bss[i / 8];
7753 return *known_bss & (u8) (BIT(i % 8));
7754}
7755
7756
7757static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd,
7758 u32 frame_type, size_t *bss_index,
7759 const u8 *known_bss,
7760 size_t known_bss_len)
7761{
7762 struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
Sunil Ravi72e01222024-03-09 01:25:43 +00007763 size_t len, i;
7764
7765 /* Element ID: 1 octet
7766 * Length: 1 octet
7767 * MaxBSSID Indicator: 1 octet
7768 * Optional Subelements: vatiable
7769 *
7770 * Total fixed length: 3 octets
7771 *
7772 * 1 octet in len for the MaxBSSID Indicator field.
7773 */
7774 len = 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00007775
7776 for (i = *bss_index; i < hapd->iface->num_bss; i++) {
7777 struct hostapd_data *bss = hapd->iface->bss[i];
7778 const u8 *auth, *rsn = NULL, *rsnx = NULL;
7779 size_t nontx_profile_len, auth_len;
7780 u8 ie_count = 0;
7781
7782 if (!bss || !bss->conf || !bss->started ||
7783 mbssid_known_bss(i, known_bss, known_bss_len))
7784 continue;
7785
7786 /*
7787 * Sublement ID: 1 octet
7788 * Length: 1 octet
7789 * Nontransmitted capabilities: 4 octets
7790 * SSID element: 2 + variable
7791 * Multiple BSSID Index Element: 3 octets (+2 octets in beacons)
7792 * Fixed length = 1 + 1 + 4 + 2 + 3 = 11
7793 */
7794 nontx_profile_len = 11 + bss->conf->ssid.ssid_len;
7795
7796 if (frame_type == WLAN_FC_STYPE_BEACON)
7797 nontx_profile_len += 2;
7798
7799 auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
7800 if (auth) {
7801 rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
7802 if (rsn)
7803 nontx_profile_len += 2 + rsn[1];
7804
7805 rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
7806 if (rsnx)
7807 nontx_profile_len += 2 + rsnx[1];
7808 }
7809 if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
7810 ie_count++;
7811 if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
7812 ie_count++;
7813 if (bss->conf->xrates_supported)
7814 nontx_profile_len += 8;
7815 else if (hapd->conf->xrates_supported)
7816 ie_count++;
7817 if (ie_count)
7818 nontx_profile_len += 4 + ie_count;
7819
7820 if (len + nontx_profile_len > 255)
7821 break;
7822
7823 len += nontx_profile_len;
7824 }
7825
7826 *bss_index = i;
Sunil Ravi72e01222024-03-09 01:25:43 +00007827
7828 /* Add 2 octets to get the full size of the element */
7829 return len + 2;
Sunil Ravi77d572f2023-01-17 23:58:31 +00007830}
7831
7832
7833size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
7834 u8 *elem_count, const u8 *known_bss,
Sunil Ravi640215c2023-06-28 23:08:09 +00007835 size_t known_bss_len, size_t *rnr_len)
Sunil Ravi77d572f2023-01-17 23:58:31 +00007836{
7837 size_t len = 0, bss_index = 1;
7838
7839 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
7840 (frame_type != WLAN_FC_STYPE_BEACON &&
7841 frame_type != WLAN_FC_STYPE_PROBE_RESP))
7842 return 0;
7843
7844 if (frame_type == WLAN_FC_STYPE_BEACON) {
7845 if (!elem_count) {
7846 wpa_printf(MSG_INFO,
7847 "MBSSID: Insufficient data for Beacon frames");
7848 return 0;
7849 }
7850 *elem_count = 0;
7851 }
7852
7853 while (bss_index < hapd->iface->num_bss) {
Sunil Ravi640215c2023-06-28 23:08:09 +00007854 size_t rnr_count = bss_index;
7855
Sunil Ravi77d572f2023-01-17 23:58:31 +00007856 len += hostapd_eid_mbssid_elem_len(hapd, frame_type,
7857 &bss_index, known_bss,
7858 known_bss_len);
7859
7860 if (frame_type == WLAN_FC_STYPE_BEACON)
7861 *elem_count += 1;
Sunil Ravi640215c2023-06-28 23:08:09 +00007862 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len) {
7863 size_t rnr_cur_len = 0;
7864 struct mbssid_ie_profiles skip_profiles = {
7865 rnr_count, bss_index
7866 };
7867
7868 *rnr_len += hostapd_eid_rnr_iface_len(
7869 hapd, hostapd_mbssid_get_tx_bss(hapd),
7870 &rnr_cur_len, &skip_profiles);
7871 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00007872 }
Sunil Ravi640215c2023-06-28 23:08:09 +00007873
7874 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len)
7875 *rnr_len += hostapd_eid_rnr_len(hapd, frame_type);
7876
Sunil Ravi77d572f2023-01-17 23:58:31 +00007877 return len;
7878}
7879
7880
7881static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end,
7882 u32 frame_type, u8 max_bssid_indicator,
7883 size_t *bss_index, u8 elem_count,
7884 const u8 *known_bss, size_t known_bss_len)
7885{
7886 struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
7887 size_t i;
7888 u8 *eid_len_offset, *max_bssid_indicator_offset;
7889
7890 *eid++ = WLAN_EID_MULTIPLE_BSSID;
7891 eid_len_offset = eid++;
7892 max_bssid_indicator_offset = eid++;
7893
7894 for (i = *bss_index; i < hapd->iface->num_bss; i++) {
7895 struct hostapd_data *bss = hapd->iface->bss[i];
7896 struct hostapd_bss_config *conf;
7897 u8 *eid_len_pos, *nontx_bss_start = eid;
7898 const u8 *auth, *rsn = NULL, *rsnx = NULL;
7899 u8 ie_count = 0, non_inherit_ie[3];
7900 size_t auth_len = 0;
7901 u16 capab_info;
7902
7903 if (!bss || !bss->conf || !bss->started ||
7904 mbssid_known_bss(i, known_bss, known_bss_len))
7905 continue;
7906 conf = bss->conf;
7907
7908 *eid++ = WLAN_MBSSID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE;
7909 eid_len_pos = eid++;
7910
7911 capab_info = hostapd_own_capab_info(bss);
7912 *eid++ = WLAN_EID_NONTRANSMITTED_BSSID_CAPA;
7913 *eid++ = sizeof(capab_info);
7914 WPA_PUT_LE16(eid, capab_info);
7915 eid += sizeof(capab_info);
7916
7917 *eid++ = WLAN_EID_SSID;
7918 *eid++ = conf->ssid.ssid_len;
7919 os_memcpy(eid, conf->ssid.ssid, conf->ssid.ssid_len);
7920 eid += conf->ssid.ssid_len;
7921
7922 *eid++ = WLAN_EID_MULTIPLE_BSSID_INDEX;
7923 if (frame_type == WLAN_FC_STYPE_BEACON) {
7924 *eid++ = 3;
7925 *eid++ = i; /* BSSID Index */
7926 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
7927 (conf->dtim_period % elem_count))
7928 conf->dtim_period = elem_count;
7929 *eid++ = conf->dtim_period;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007930 /* The driver is expected to update the DTIM Count
7931 * field for each BSS that corresponds to a
7932 * nontransmitted BSSID. The value is initialized to
7933 * 0 here so that the DTIM count would be somewhat
7934 * functional even if the driver were not to update
7935 * this. */
7936 *eid++ = 0; /* DTIM Count */
Sunil Ravi77d572f2023-01-17 23:58:31 +00007937 } else {
7938 /* Probe Request frame does not include DTIM Period and
7939 * DTIM Count fields. */
7940 *eid++ = 1;
7941 *eid++ = i; /* BSSID Index */
7942 }
7943
7944 auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
7945 if (auth) {
7946 rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
7947 if (rsn) {
7948 os_memcpy(eid, rsn, 2 + rsn[1]);
7949 eid += 2 + rsn[1];
7950 }
7951
7952 rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
7953 if (rsnx) {
7954 os_memcpy(eid, rsnx, 2 + rsnx[1]);
7955 eid += 2 + rsnx[1];
7956 }
7957 }
Sunil Ravi72e01222024-03-09 01:25:43 +00007958 /* List of Element ID values in increasing order */
Sunil Ravi77d572f2023-01-17 23:58:31 +00007959 if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
7960 non_inherit_ie[ie_count++] = WLAN_EID_RSN;
Sunil Ravi77d572f2023-01-17 23:58:31 +00007961 if (hapd->conf->xrates_supported &&
7962 !bss->conf->xrates_supported)
7963 non_inherit_ie[ie_count++] = WLAN_EID_EXT_SUPP_RATES;
Sunil Ravi72e01222024-03-09 01:25:43 +00007964 if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
7965 non_inherit_ie[ie_count++] = WLAN_EID_RSNX;
Sunil Ravi77d572f2023-01-17 23:58:31 +00007966 if (ie_count) {
7967 *eid++ = WLAN_EID_EXTENSION;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007968 *eid++ = 2 + ie_count + 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00007969 *eid++ = WLAN_EID_EXT_NON_INHERITANCE;
7970 *eid++ = ie_count;
7971 os_memcpy(eid, non_inherit_ie, ie_count);
7972 eid += ie_count;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007973 *eid++ = 0; /* No Element ID Extension List */
Sunil Ravi77d572f2023-01-17 23:58:31 +00007974 }
7975
7976 *eid_len_pos = (eid - eid_len_pos) - 1;
7977
7978 if (((eid - eid_len_offset) - 1) > 255) {
7979 eid = nontx_bss_start;
7980 break;
7981 }
7982 }
7983
7984 *bss_index = i;
7985 *max_bssid_indicator_offset = max_bssid_indicator;
7986 if (*max_bssid_indicator_offset < 1)
7987 *max_bssid_indicator_offset = 1;
7988 *eid_len_offset = (eid - eid_len_offset) - 1;
7989 return eid;
7990}
7991
7992
7993u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
7994 unsigned int frame_stype, u8 elem_count,
7995 u8 **elem_offset,
Sunil Ravi640215c2023-06-28 23:08:09 +00007996 const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid,
7997 u8 *rnr_count, u8 **rnr_offset, size_t rnr_len)
Sunil Ravi77d572f2023-01-17 23:58:31 +00007998{
Sunil Ravi640215c2023-06-28 23:08:09 +00007999 size_t bss_index = 1, cur_len = 0;
8000 u8 elem_index = 0, *rnr_start_eid = rnr_eid;
8001 bool add_rnr;
Sunil Ravi77d572f2023-01-17 23:58:31 +00008002
8003 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
8004 (frame_stype != WLAN_FC_STYPE_BEACON &&
8005 frame_stype != WLAN_FC_STYPE_PROBE_RESP))
8006 return eid;
8007
8008 if (frame_stype == WLAN_FC_STYPE_BEACON && !elem_offset) {
8009 wpa_printf(MSG_INFO,
8010 "MBSSID: Insufficient data for Beacon frames");
8011 return eid;
8012 }
8013
Sunil Ravi640215c2023-06-28 23:08:09 +00008014 add_rnr = hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
8015 frame_stype == WLAN_FC_STYPE_BEACON &&
8016 rnr_eid && rnr_count && rnr_offset && rnr_len;
8017
Sunil Ravi77d572f2023-01-17 23:58:31 +00008018 while (bss_index < hapd->iface->num_bss) {
Sunil Ravi640215c2023-06-28 23:08:09 +00008019 unsigned int rnr_start_count = bss_index;
8020
Sunil Ravi77d572f2023-01-17 23:58:31 +00008021 if (frame_stype == WLAN_FC_STYPE_BEACON) {
8022 if (elem_index == elem_count) {
8023 wpa_printf(MSG_WARNING,
8024 "MBSSID: Larger number of elements than there is room in the provided array");
8025 break;
8026 }
8027
8028 elem_offset[elem_index] = eid;
8029 elem_index = elem_index + 1;
8030 }
8031 eid = hostapd_eid_mbssid_elem(hapd, eid, end, frame_stype,
8032 hostapd_max_bssid_indicator(hapd),
8033 &bss_index, elem_count,
8034 known_bss, known_bss_len);
Sunil Ravi640215c2023-06-28 23:08:09 +00008035
8036 if (add_rnr) {
8037 struct mbssid_ie_profiles skip_profiles = {
8038 rnr_start_count, bss_index
8039 };
8040
8041 rnr_offset[*rnr_count] = rnr_eid;
8042 *rnr_count = *rnr_count + 1;
8043 cur_len = 0;
8044 rnr_eid = hostapd_eid_rnr_iface(
8045 hapd, hostapd_mbssid_get_tx_bss(hapd),
8046 rnr_eid, &cur_len, &skip_profiles);
8047 }
8048 }
8049
8050 if (add_rnr && (size_t) (rnr_eid - rnr_start_eid) < rnr_len) {
8051 rnr_offset[*rnr_count] = rnr_eid;
8052 *rnr_count = *rnr_count + 1;
8053 cur_len = 0;
8054
8055 if (hapd->conf->rnr)
8056 rnr_eid = hostapd_eid_nr_db(hapd, rnr_eid, &cur_len);
8057 if (get_colocation_mode(hapd) == COLOCATED_LOWER_BAND)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008058 rnr_eid = hostapd_eid_rnr_multi_iface(hapd, rnr_eid,
8059 &cur_len);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008060 }
8061
8062 return eid;
8063}
8064
Sunil Ravi036cec52023-03-29 11:35:17 -07008065
8066static void punct_update_legacy_bw_80(u8 bitmap, u8 pri_chan, u8 *seg0)
8067{
8068 u8 first_chan = *seg0 - 6, sec_chan;
8069
8070 switch (bitmap) {
8071 case 0x6:
8072 *seg0 = 0;
8073 return;
8074 case 0x8:
8075 case 0x4:
8076 case 0x2:
8077 case 0x1:
8078 case 0xC:
8079 case 0x3:
8080 if (pri_chan < *seg0)
8081 *seg0 -= 4;
8082 else
8083 *seg0 += 4;
8084 break;
8085 }
8086
8087 if (pri_chan < *seg0)
8088 sec_chan = pri_chan + 4;
8089 else
8090 sec_chan = pri_chan - 4;
8091
8092 if (bitmap & BIT((sec_chan - first_chan) / 4))
8093 *seg0 = 0;
8094}
8095
8096
8097static void punct_update_legacy_bw_160(u8 bitmap, u8 pri,
8098 enum oper_chan_width *width, u8 *seg0)
8099{
8100 if (pri < *seg0) {
8101 *seg0 -= 8;
8102 if (bitmap & 0x0F) {
8103 *width = 0;
8104 punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0);
8105 }
8106 } else {
8107 *seg0 += 8;
8108 if (bitmap & 0xF0) {
8109 *width = 0;
8110 punct_update_legacy_bw_80((bitmap & 0xF0) >> 4, pri,
8111 seg0);
8112 }
8113 }
8114}
8115
8116
8117void punct_update_legacy_bw(u16 bitmap, u8 pri, enum oper_chan_width *width,
8118 u8 *seg0, u8 *seg1)
8119{
8120 if (*width == CONF_OPER_CHWIDTH_80MHZ && (bitmap & 0xF)) {
8121 *width = CONF_OPER_CHWIDTH_USE_HT;
8122 punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0);
8123 }
8124
8125 if (*width == CONF_OPER_CHWIDTH_160MHZ && (bitmap & 0xFF)) {
8126 *width = CONF_OPER_CHWIDTH_80MHZ;
8127 *seg1 = 0;
8128 punct_update_legacy_bw_160(bitmap & 0xFF, pri, width, seg0);
8129 }
8130
8131 /* TODO: 320 MHz */
8132}
8133
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008134#endif /* CONFIG_NATIVE_WINDOWS */