blob: 1f39107d8e0ef31842648ba89f7bddb5882c6584 [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"
59#include "pasn/pasn_common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070060
61
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070062#ifdef CONFIG_FILS
63static struct wpabuf *
64prepare_auth_resp_fils(struct hostapd_data *hapd,
65 struct sta_info *sta, u16 *resp,
66 struct rsn_pmksa_cache_entry *pmksa,
67 struct wpabuf *erp_resp,
68 const u8 *msk, size_t msk_len,
69 int *is_pub);
70#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -080071
72#ifdef CONFIG_PASN
Hai Shalom60840252021-02-19 19:02:11 -080073#ifdef CONFIG_FILS
74
75static void pasn_fils_auth_resp(struct hostapd_data *hapd,
76 struct sta_info *sta, u16 status,
77 struct wpabuf *erp_resp,
78 const u8 *msk, size_t msk_len);
79
80#endif /* CONFIG_FILS */
81#endif /* CONFIG_PASN */
82
Hai Shalom021b0b52019-04-10 11:17:58 -070083static void handle_auth(struct hostapd_data *hapd,
84 const struct ieee80211_mgmt *mgmt, size_t len,
85 int rssi, int from_queue);
Sunil Ravi2a14cf12023-11-21 00:54:38 +000086static int add_associated_sta(struct hostapd_data *hapd,
87 struct sta_info *sta, int reassoc);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070088
Hai Shalom74f70d42019-02-11 14:42:39 -080089
90u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
91{
92 u8 multi_ap_val = 0;
93
94 if (!hapd->conf->multi_ap)
95 return eid;
96 if (hapd->conf->multi_ap & BACKHAUL_BSS)
97 multi_ap_val |= MULTI_AP_BACKHAUL_BSS;
98 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
99 multi_ap_val |= MULTI_AP_FRONTHAUL_BSS;
100
101 return eid + add_multi_ap_ie(eid, 9, multi_ap_val);
102}
103
104
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700105u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
106{
107 u8 *pos = eid;
108 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700109 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700110
111 if (hapd->iface->current_rates == NULL)
112 return eid;
113
114 *pos++ = WLAN_EID_SUPP_RATES;
115 num = hapd->iface->num_rates;
116 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
117 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800118 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
119 num++;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000120#ifdef CONFIG_IEEE80211AX
121 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
122 num++;
123#endif /* CONFIG_IEEE80211AX */
124 h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
Hai Shalomfdcde762020-04-02 11:19:20 -0700125 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +0000126 hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700127 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
128 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700129 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700130 if (num > 8) {
131 /* rest of the rates are encoded in Extended supported
132 * rates element */
133 num = 8;
134 }
135
136 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700137 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
138 i++) {
139 count++;
140 *pos = hapd->iface->current_rates[i].rate / 5;
141 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
142 *pos |= 0x80;
143 pos++;
144 }
145
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800146 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
147 count++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700148 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800149 }
150
151 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
152 count++;
153 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
154 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700155
Sunil Ravi77d572f2023-01-17 23:58:31 +0000156#ifdef CONFIG_IEEE80211AX
157 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he && count < 8) {
158 count++;
159 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY;
160 }
161#endif /* CONFIG_IEEE80211AX */
162
Hai Shalomfdcde762020-04-02 11:19:20 -0700163 if (h2e_required && count < 8) {
Hai Shalomc3565922019-10-28 11:58:20 -0700164 count++;
165 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
166 }
167
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700168 return pos;
169}
170
171
172u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
173{
174 u8 *pos = eid;
175 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700176 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700177
Sunil Ravi77d572f2023-01-17 23:58:31 +0000178 hapd->conf->xrates_supported = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700179 if (hapd->iface->current_rates == NULL)
180 return eid;
181
182 num = hapd->iface->num_rates;
183 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
184 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800185 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
186 num++;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000187#ifdef CONFIG_IEEE80211AX
188 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
189 num++;
190#endif /* CONFIG_IEEE80211AX */
191 h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
Hai Shalomfdcde762020-04-02 11:19:20 -0700192 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +0000193 hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700194 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
195 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700196 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700197 if (num <= 8)
198 return eid;
199 num -= 8;
200
201 *pos++ = WLAN_EID_EXT_SUPP_RATES;
202 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700203 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
204 i++) {
205 count++;
206 if (count <= 8)
207 continue; /* already in SuppRates IE */
208 *pos = hapd->iface->current_rates[i].rate / 5;
209 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
210 *pos |= 0x80;
211 pos++;
212 }
213
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800214 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
215 count++;
216 if (count > 8)
217 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
218 }
219
220 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
221 count++;
222 if (count > 8)
223 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
224 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700225
Sunil Ravi77d572f2023-01-17 23:58:31 +0000226#ifdef CONFIG_IEEE80211AX
227 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he) {
228 count++;
229 if (count > 8)
230 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY;
231 }
232#endif /* CONFIG_IEEE80211AX */
233
Hai Shalomfdcde762020-04-02 11:19:20 -0700234 if (h2e_required) {
Hai Shalomc3565922019-10-28 11:58:20 -0700235 count++;
236 if (count > 8)
237 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
238 }
239
Sunil Ravi77d572f2023-01-17 23:58:31 +0000240 hapd->conf->xrates_supported = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700241 return pos;
242}
243
244
Hai Shalomfdcde762020-04-02 11:19:20 -0700245u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
246 size_t len)
247{
248 size_t i;
249
250 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
251 if (hapd->conf->radio_measurements[i])
252 break;
253 }
254
255 if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
256 return eid;
257
258 *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
259 *eid++ = RRM_CAPABILITIES_IE_LEN;
260 os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
261
262 return eid + RRM_CAPABILITIES_IE_LEN;
263}
264
265
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700266u16 hostapd_own_capab_info(struct hostapd_data *hapd)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700267{
268 int capab = WLAN_CAPABILITY_ESS;
Hai Shalomfdcde762020-04-02 11:19:20 -0700269 int privacy = 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800270 int dfs;
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700271 int i;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800272
273 /* Check if any of configured channels require DFS */
274 dfs = hostapd_is_dfs_required(hapd->iface);
275 if (dfs < 0) {
276 wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
277 dfs);
278 dfs = 0;
279 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700280
281 if (hapd->iface->num_sta_no_short_preamble == 0 &&
282 hapd->iconf->preamble == SHORT_PREAMBLE)
283 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
284
Hai Shalomfdcde762020-04-02 11:19:20 -0700285#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700286 privacy = hapd->conf->ssid.wep.keys_set;
287
288 if (hapd->conf->ieee802_1x &&
289 (hapd->conf->default_wep_key_len ||
290 hapd->conf->individual_wep_key_len))
291 privacy = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -0700292#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700293
294 if (hapd->conf->wpa)
295 privacy = 1;
296
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800297#ifdef CONFIG_HS20
298 if (hapd->conf->osen)
299 privacy = 1;
300#endif /* CONFIG_HS20 */
301
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700302 if (privacy)
303 capab |= WLAN_CAPABILITY_PRIVACY;
304
305 if (hapd->iface->current_mode &&
306 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
307 hapd->iface->num_sta_no_short_slot_time == 0)
308 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
309
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800310 /*
311 * Currently, Spectrum Management capability bit is set when directly
312 * requested in configuration by spectrum_mgmt_required or when AP is
313 * running on DFS channel.
314 * TODO: Also consider driver support for TPC to set Spectrum Mgmt bit
315 */
316 if (hapd->iface->current_mode &&
317 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
318 (hapd->iconf->spectrum_mgmt_required || dfs))
319 capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
320
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700321 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
322 if (hapd->conf->radio_measurements[i]) {
323 capab |= IEEE80211_CAP_RRM;
324 break;
325 }
326 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800327
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700328 return capab;
329}
330
331
Hai Shalomfdcde762020-04-02 11:19:20 -0700332#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800333#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700334static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
335 u16 auth_transaction, const u8 *challenge,
336 int iswep)
337{
338 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
339 HOSTAPD_LEVEL_DEBUG,
340 "authentication (shared key, transaction %d)",
341 auth_transaction);
342
343 if (auth_transaction == 1) {
344 if (!sta->challenge) {
345 /* Generate a pseudo-random challenge */
346 u8 key[8];
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800347
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700348 sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
349 if (sta->challenge == NULL)
350 return WLAN_STATUS_UNSPECIFIED_FAILURE;
351
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800352 if (os_get_random(key, sizeof(key)) < 0) {
353 os_free(sta->challenge);
354 sta->challenge = NULL;
355 return WLAN_STATUS_UNSPECIFIED_FAILURE;
356 }
357
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700358 rc4_skip(key, sizeof(key), 0,
359 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
360 }
361 return 0;
362 }
363
364 if (auth_transaction != 3)
365 return WLAN_STATUS_UNSPECIFIED_FAILURE;
366
367 /* Transaction 3 */
368 if (!iswep || !sta->challenge || !challenge ||
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700369 os_memcmp_const(sta->challenge, challenge,
370 WLAN_AUTH_CHALLENGE_LEN)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700371 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
372 HOSTAPD_LEVEL_INFO,
373 "shared key authentication - invalid "
374 "challenge-response");
375 return WLAN_STATUS_CHALLENGE_FAIL;
376 }
377
378 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
379 HOSTAPD_LEVEL_DEBUG,
380 "authentication OK (shared key)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700381 sta->flags |= WLAN_STA_AUTH;
382 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700383 os_free(sta->challenge);
384 sta->challenge = NULL;
385
386 return 0;
387}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800388#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700389#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700390
391
Hai Shalomfdcde762020-04-02 11:19:20 -0700392static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800393 const u8 *dst, const u8 *bssid,
394 u16 auth_alg, u16 auth_transaction, u16 resp,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700395 const u8 *ies, size_t ies_len, const char *dbg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700396{
397 struct ieee80211_mgmt *reply;
398 u8 *buf;
399 size_t rlen;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800400 int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000401 const u8 *sa = hapd->own_addr;
402 struct wpabuf *ml_resp = NULL;
403
404#ifdef CONFIG_IEEE80211BE
405 /*
406 * Once a non-AP MLD is added to the driver, the addressing should use
407 * the MLD MAC address. Thus, use the MLD address instead of translating
408 * the addresses.
409 */
410 if (hapd->conf->mld_ap && sta && sta->mld_info.mld_sta) {
411 sa = hapd->mld_addr;
412
413 ml_resp = hostapd_ml_auth_resp(hapd);
414 if (!ml_resp)
415 return -1;
416 }
417#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700418
419 rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000420 if (ml_resp)
421 rlen += wpabuf_len(ml_resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700422 buf = os_zalloc(rlen);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000423 if (!buf) {
424 wpabuf_free(ml_resp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800425 return -1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000426 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700427
428 reply = (struct ieee80211_mgmt *) buf;
429 reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
430 WLAN_FC_STYPE_AUTH);
431 os_memcpy(reply->da, dst, ETH_ALEN);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000432 os_memcpy(reply->sa, sa, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700433 os_memcpy(reply->bssid, bssid, ETH_ALEN);
434
435 reply->u.auth.auth_alg = host_to_le16(auth_alg);
436 reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
437 reply->u.auth.status_code = host_to_le16(resp);
438
439 if (ies && ies_len)
440 os_memcpy(reply->u.auth.variable, ies, ies_len);
441
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000442#ifdef CONFIG_IEEE80211BE
443 if (ml_resp)
444 os_memcpy(reply->u.auth.variable + ies_len,
445 wpabuf_head(ml_resp), wpabuf_len(ml_resp));
446
447 wpabuf_free(ml_resp);
448#endif /* CONFIG_IEEE80211BE */
449
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700450 wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700451 " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700452 MAC2STR(dst), auth_alg, auth_transaction,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700453 resp, (unsigned long) ies_len, dbg);
Hai Shalomfdcde762020-04-02 11:19:20 -0700454#ifdef CONFIG_TESTING_OPTIONS
455#ifdef CONFIG_SAE
456 if (hapd->conf->sae_confirm_immediate == 2 &&
457 auth_alg == WLAN_AUTH_SAE) {
458 if (auth_transaction == 1 && sta &&
459 (resp == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -0700460 resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
461 resp == WLAN_STATUS_SAE_PK)) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700462 wpa_printf(MSG_DEBUG,
463 "TESTING: Postpone SAE Commit transmission until Confirm is ready");
464 os_free(sta->sae_postponed_commit);
465 sta->sae_postponed_commit = buf;
466 sta->sae_postponed_commit_len = rlen;
467 return WLAN_STATUS_SUCCESS;
468 }
469
470 if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
471 wpa_printf(MSG_DEBUG,
472 "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
473 if (hostapd_drv_send_mlme(hapd,
474 sta->sae_postponed_commit,
475 sta->sae_postponed_commit_len,
476 0, NULL, 0, 0) < 0)
477 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
478 os_free(sta->sae_postponed_commit);
479 sta->sae_postponed_commit = NULL;
480 sta->sae_postponed_commit_len = 0;
481 }
482 }
483#endif /* CONFIG_SAE */
484#endif /* CONFIG_TESTING_OPTIONS */
485 if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800486 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
487 else
488 reply_res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700489
490 os_free(buf);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800491
492 return reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700493}
494
495
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800496#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700497static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
498 u16 auth_transaction, u16 status,
499 const u8 *ies, size_t ies_len)
500{
501 struct hostapd_data *hapd = ctx;
502 struct sta_info *sta;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800503 int reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700504
Hai Shalomfdcde762020-04-02 11:19:20 -0700505 reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700506 auth_transaction, status, ies, ies_len,
507 "auth-ft-finish");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700508
509 sta = ap_get_sta(hapd, dst);
510 if (sta == NULL)
511 return;
512
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800513 if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
514 status != WLAN_STATUS_SUCCESS)) {
515 hostapd_drv_sta_remove(hapd, sta->addr);
516 sta->added_unassoc = 0;
517 return;
518 }
519
520 if (status != WLAN_STATUS_SUCCESS)
521 return;
522
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700523 hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
524 HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
525 sta->flags |= WLAN_STA_AUTH;
526 mlme_authenticate_indication(hapd, sta);
527}
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800528#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700529
530
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800531#ifdef CONFIG_SAE
532
Roshan Pius3a1667e2018-07-03 15:17:14 -0700533static void sae_set_state(struct sta_info *sta, enum sae_state state,
534 const char *reason)
535{
536 wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
537 sae_state_txt(sta->sae->state), sae_state_txt(state),
538 MAC2STR(sta->addr), reason);
539 sta->sae->state = state;
540}
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800541
542
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000543const char * sae_get_password(struct hostapd_data *hapd,
544 struct sta_info *sta,
545 const char *rx_id,
546 struct sae_password_entry **pw_entry,
547 struct sae_pt **s_pt,
548 const struct sae_pk **s_pk)
Hai Shalom60840252021-02-19 19:02:11 -0800549{
550 const char *password = NULL;
551 struct sae_password_entry *pw;
552 struct sae_pt *pt = NULL;
553 const struct sae_pk *pk = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -0700554 struct hostapd_sta_wpa_psk_short *psk = NULL;
Hai Shalom60840252021-02-19 19:02:11 -0800555
556 for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
557 if (!is_broadcast_ether_addr(pw->peer_addr) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000558 (!sta ||
559 os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0))
Hai Shalom60840252021-02-19 19:02:11 -0800560 continue;
561 if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
562 continue;
563 if (rx_id && pw->identifier &&
564 os_strcmp(rx_id, pw->identifier) != 0)
565 continue;
566 password = pw->password;
567 pt = pw->pt;
568 if (!(hapd->conf->mesh & MESH_ENABLED))
569 pk = pw->pk;
570 break;
571 }
572 if (!password) {
573 password = hapd->conf->ssid.wpa_passphrase;
574 pt = hapd->conf->ssid.pt;
575 }
576
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000577 if (!password && sta) {
Sunil Ravia04bd252022-05-02 22:54:18 -0700578 for (psk = sta->psk; psk; psk = psk->next) {
579 if (psk->is_passphrase) {
580 password = psk->passphrase;
581 break;
582 }
583 }
584 }
585
Hai Shalom60840252021-02-19 19:02:11 -0800586 if (pw_entry)
587 *pw_entry = pw;
588 if (s_pt)
589 *s_pt = pt;
590 if (s_pk)
591 *s_pk = pk;
592
593 return password;
594}
595
596
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800597static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
Hai Shalomc3565922019-10-28 11:58:20 -0700598 struct sta_info *sta, int update,
599 int status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800600{
601 struct wpabuf *buf;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700602 const char *password = NULL;
603 struct sae_password_entry *pw;
604 const char *rx_id = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700605 int use_pt = 0;
606 struct sae_pt *pt = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700607 const struct sae_pk *pk = NULL;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000608 const u8 *own_addr = hapd->own_addr;
609
610#ifdef CONFIG_IEEE80211BE
611 if (hapd->conf->mld_ap && sta->mld_info.mld_sta)
612 own_addr = hapd->mld_addr;
613#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800614
Hai Shalomc3565922019-10-28 11:58:20 -0700615 if (sta->sae->tmp) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700616 rx_id = sta->sae->tmp->pw_id;
Hai Shalom899fcc72020-10-19 14:38:18 -0700617 use_pt = sta->sae->h2e;
618#ifdef CONFIG_SAE_PK
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000619 os_memcpy(sta->sae->tmp->own_addr, own_addr, ETH_ALEN);
Hai Shalom899fcc72020-10-19 14:38:18 -0700620 os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
621#endif /* CONFIG_SAE_PK */
Hai Shalomc3565922019-10-28 11:58:20 -0700622 }
623
Sunil Ravi77d572f2023-01-17 23:58:31 +0000624 if (rx_id && hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
Hai Shalomfdcde762020-04-02 11:19:20 -0700625 use_pt = 1;
626 else if (status_code == WLAN_STATUS_SUCCESS)
Hai Shalomc3565922019-10-28 11:58:20 -0700627 use_pt = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700628 else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
629 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomc3565922019-10-28 11:58:20 -0700630 use_pt = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700631
Hai Shalom60840252021-02-19 19:02:11 -0800632 password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk);
Hai Shalomc3565922019-10-28 11:58:20 -0700633 if (!password || (use_pt && !pt)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800634 wpa_printf(MSG_DEBUG, "SAE: No password available");
635 return NULL;
636 }
637
Hai Shalomc3565922019-10-28 11:58:20 -0700638 if (update && use_pt &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000639 sae_prepare_commit_pt(sta->sae, pt, own_addr, sta->addr,
Hai Shalom899fcc72020-10-19 14:38:18 -0700640 NULL, pk) < 0)
Hai Shalomc3565922019-10-28 11:58:20 -0700641 return NULL;
642
643 if (update && !use_pt &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000644 sae_prepare_commit(own_addr, sta->addr,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800645 (u8 *) password, os_strlen(password),
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800646 sta->sae) < 0) {
647 wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
648 return NULL;
649 }
650
Hai Shalom021b0b52019-04-10 11:17:58 -0700651 if (pw && pw->vlan_id) {
652 if (!sta->sae->tmp) {
653 wpa_printf(MSG_INFO,
654 "SAE: No temporary data allocated - cannot store VLAN ID");
655 return NULL;
656 }
657 sta->sae->tmp->vlan_id = pw->vlan_id;
658 }
659
Roshan Pius3a1667e2018-07-03 15:17:14 -0700660 buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
661 (rx_id ? 3 + os_strlen(rx_id) : 0));
Hai Shalomfdcde762020-04-02 11:19:20 -0700662 if (buf &&
663 sae_write_commit(sta->sae, buf, sta->sae->tmp ?
664 sta->sae->tmp->anti_clogging_token : NULL,
665 rx_id) < 0) {
666 wpabuf_free(buf);
667 buf = NULL;
668 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800669
670 return buf;
671}
672
673
674static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
675 struct sta_info *sta)
676{
677 struct wpabuf *buf;
678
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800679 buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800680 if (buf == NULL)
681 return NULL;
682
Hai Shalom899fcc72020-10-19 14:38:18 -0700683#ifdef CONFIG_SAE_PK
684#ifdef CONFIG_TESTING_OPTIONS
685 if (sta->sae->tmp)
686 sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
687#endif /* CONFIG_TESTING_OPTIONS */
688#endif /* CONFIG_SAE_PK */
689
690 if (sae_write_confirm(sta->sae, buf) < 0) {
691 wpabuf_free(buf);
692 return NULL;
693 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800694
695 return buf;
696}
697
698
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800699static int auth_sae_send_commit(struct hostapd_data *hapd,
700 struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700701 const u8 *bssid, int update, int status_code)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800702{
703 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800704 int reply_res;
Hai Shalomc3565922019-10-28 11:58:20 -0700705 u16 status;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800706
Hai Shalomc3565922019-10-28 11:58:20 -0700707 data = auth_build_sae_commit(hapd, sta, update, status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700708 if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
709 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800710 if (data == NULL)
711 return WLAN_STATUS_UNSPECIFIED_FAILURE;
712
Hai Shalom899fcc72020-10-19 14:38:18 -0700713 if (sta->sae->tmp && sta->sae->pk)
714 status = WLAN_STATUS_SAE_PK;
715 else if (sta->sae->tmp && sta->sae->h2e)
716 status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
717 else
718 status = WLAN_STATUS_SUCCESS;
719#ifdef CONFIG_TESTING_OPTIONS
720 if (hapd->conf->sae_commit_status >= 0 &&
721 hapd->conf->sae_commit_status != status) {
722 wpa_printf(MSG_INFO,
723 "TESTING: Override SAE commit status code %u --> %d",
724 status, hapd->conf->sae_commit_status);
725 status = hapd->conf->sae_commit_status;
726 }
727#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomfdcde762020-04-02 11:19:20 -0700728 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
729 WLAN_AUTH_SAE, 1,
Hai Shalomc3565922019-10-28 11:58:20 -0700730 status, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700731 wpabuf_len(data), "sae-send-commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800732
733 wpabuf_free(data);
734
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800735 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800736}
737
738
739static int auth_sae_send_confirm(struct hostapd_data *hapd,
740 struct sta_info *sta,
741 const u8 *bssid)
742{
743 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800744 int reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800745
746 data = auth_build_sae_confirm(hapd, sta);
747 if (data == NULL)
748 return WLAN_STATUS_UNSPECIFIED_FAILURE;
749
Hai Shalomfdcde762020-04-02 11:19:20 -0700750 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
751 WLAN_AUTH_SAE, 2,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800752 WLAN_STATUS_SUCCESS, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700753 wpabuf_len(data), "sae-send-confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800754
755 wpabuf_free(data);
756
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800757 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800758}
759
Hai Shaloma20dcd72022-02-04 13:43:00 -0800760#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800761
Hai Shaloma20dcd72022-02-04 13:43:00 -0800762
763#if defined(CONFIG_SAE) || defined(CONFIG_PASN)
764
765static int use_anti_clogging(struct hostapd_data *hapd)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800766{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800767 struct sta_info *sta;
768 unsigned int open = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800769
Hai Shaloma20dcd72022-02-04 13:43:00 -0800770 if (hapd->conf->anti_clogging_threshold == 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800771 return 1;
772
773 for (sta = hapd->sta_list; sta; sta = sta->next) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800774#ifdef CONFIG_SAE
775 if (sta->sae &&
776 (sta->sae->state == SAE_COMMITTED ||
777 sta->sae->state == SAE_CONFIRMED))
778 open++;
779#endif /* CONFIG_SAE */
780#ifdef CONFIG_PASN
781 if (sta->pasn && sta->pasn->ecdh)
782 open++;
783#endif /* CONFIG_PASN */
784 if (open >= hapd->conf->anti_clogging_threshold)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800785 return 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800786 }
787
Hai Shaloma20dcd72022-02-04 13:43:00 -0800788#ifdef CONFIG_SAE
Hai Shalom021b0b52019-04-10 11:17:58 -0700789 /* In addition to already existing open SAE sessions, check whether
790 * there are enough pending commit messages in the processing queue to
791 * potentially result in too many open sessions. */
792 if (open + dl_list_len(&hapd->sae_commit_queue) >=
Hai Shaloma20dcd72022-02-04 13:43:00 -0800793 hapd->conf->anti_clogging_threshold)
Hai Shalom021b0b52019-04-10 11:17:58 -0700794 return 1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800795#endif /* CONFIG_SAE */
Hai Shalom021b0b52019-04-10 11:17:58 -0700796
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800797 return 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800798}
799
Hai Shaloma20dcd72022-02-04 13:43:00 -0800800#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
801
802
803#ifdef CONFIG_SAE
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800804
Roshan Pius3a1667e2018-07-03 15:17:14 -0700805static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800806{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700807 if (sta->sae->sync > hapd->conf->sae_sync) {
808 sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800809 sta->sae->sync = 0;
810 return -1;
811 }
812 return 0;
813}
814
815
816static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
817{
818 struct hostapd_data *hapd = eloop_ctx;
819 struct sta_info *sta = eloop_data;
820 int ret;
821
Roshan Pius3a1667e2018-07-03 15:17:14 -0700822 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800823 return;
824 sta->sae->sync++;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700825 wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700826 " (sync=%d state=%s)",
827 MAC2STR(sta->addr), sta->sae->sync,
828 sae_state_txt(sta->sae->state));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800829
830 switch (sta->sae->state) {
831 case SAE_COMMITTED:
Hai Shalomc3565922019-10-28 11:58:20 -0700832 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800833 eloop_register_timeout(0,
834 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800835 auth_sae_retransmit_timer, hapd, sta);
836 break;
837 case SAE_CONFIRMED:
838 ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800839 eloop_register_timeout(0,
840 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800841 auth_sae_retransmit_timer, hapd, sta);
842 break;
843 default:
844 ret = -1;
845 break;
846 }
847
848 if (ret != WLAN_STATUS_SUCCESS)
849 wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
850}
851
852
853void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
854{
855 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
856}
857
858
859static void sae_set_retransmit_timer(struct hostapd_data *hapd,
860 struct sta_info *sta)
861{
862 if (!(hapd->conf->mesh & MESH_ENABLED))
863 return;
864
865 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800866 eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800867 auth_sae_retransmit_timer, hapd, sta);
868}
869
870
Hai Shalom5f92bc92019-04-18 11:54:11 -0700871static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
872 struct sta_info *sta, u16 status)
873{
874 struct external_auth params;
875
876 os_memset(&params, 0, sizeof(params));
877 params.status = status;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000878
879#ifdef CONFIG_IEEE80211BE
880 if (sta->mld_info.mld_sta)
881 params.bssid =
882 sta->mld_info.links[sta->mld_assoc_link_id].peer_addr;
883#endif /* CONFIG_IEEE80211BE */
884 if (!params.bssid)
885 params.bssid = sta->addr;
886
Hai Shalom81f62d82019-07-22 12:10:00 -0700887 if (status == WLAN_STATUS_SUCCESS && sta->sae &&
888 !hapd->conf->disable_pmksa_caching)
Hai Shalom5f92bc92019-04-18 11:54:11 -0700889 params.pmkid = sta->sae->pmkid;
890
891 hostapd_drv_send_external_auth_status(hapd, &params);
892}
893
894
Dmitry Shmidte4663042016-04-04 10:07:49 -0700895void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
896{
Hai Shalom021b0b52019-04-10 11:17:58 -0700897#ifndef CONFIG_NO_VLAN
898 struct vlan_description vlan_desc;
899
900 if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
901 wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
902 " to VLAN ID %d",
903 MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
904
905 os_memset(&vlan_desc, 0, sizeof(vlan_desc));
906 vlan_desc.notempty = 1;
907 vlan_desc.untagged = sta->sae->tmp->vlan_id;
908 if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
909 wpa_printf(MSG_INFO,
910 "Invalid VLAN ID %d in sae_password",
911 sta->sae->tmp->vlan_id);
912 return;
913 }
914
915 if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
916 ap_sta_bind_vlan(hapd, sta) < 0) {
917 wpa_printf(MSG_INFO,
918 "Failed to assign VLAN ID %d from sae_password to "
919 MACSTR, sta->sae->tmp->vlan_id,
920 MAC2STR(sta->addr));
921 return;
922 }
923 }
924#endif /* CONFIG_NO_VLAN */
925
Dmitry Shmidte4663042016-04-04 10:07:49 -0700926 sta->flags |= WLAN_STA_AUTH;
927 sta->auth_alg = WLAN_AUTH_SAE;
928 mlme_authenticate_indication(hapd, sta);
929 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700930 sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
Hai Shalomfdcde762020-04-02 11:19:20 -0700931 crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
932 sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
933 sta->sae->peer_commit_scalar = NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -0700934 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
Sunil Ravi89eba102022-09-13 21:04:37 -0700935 sta->sae->pmk, sta->sae->pmk_len,
936 sta->sae->pmkid, sta->sae->akmp);
Hai Shalom5f92bc92019-04-18 11:54:11 -0700937 sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
Dmitry Shmidte4663042016-04-04 10:07:49 -0700938}
939
940
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800941static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700942 const u8 *bssid, u16 auth_transaction, u16 status_code,
943 int allow_reuse, int *sta_removed)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800944{
945 int ret;
946
Hai Shalom5f92bc92019-04-18 11:54:11 -0700947 *sta_removed = 0;
948
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800949 if (auth_transaction != 1 && auth_transaction != 2)
950 return WLAN_STATUS_UNSPECIFIED_FAILURE;
951
Roshan Pius3a1667e2018-07-03 15:17:14 -0700952 wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
953 MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
954 auth_transaction);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800955 switch (sta->sae->state) {
956 case SAE_NOTHING:
957 if (auth_transaction == 1) {
Hai Shalom899fcc72020-10-19 14:38:18 -0700958 if (sta->sae->tmp) {
959 sta->sae->h2e =
960 (status_code ==
961 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
962 status_code == WLAN_STATUS_SAE_PK);
963 sta->sae->pk =
964 status_code == WLAN_STATUS_SAE_PK;
965 }
Hai Shalom021b0b52019-04-10 11:17:58 -0700966 ret = auth_sae_send_commit(hapd, sta, bssid,
Hai Shalomc3565922019-10-28 11:58:20 -0700967 !allow_reuse, status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800968 if (ret)
969 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700970 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800971
972 if (sae_process_commit(sta->sae) < 0)
973 return WLAN_STATUS_UNSPECIFIED_FAILURE;
974
975 /*
Hai Shalomc3565922019-10-28 11:58:20 -0700976 * In mesh case, both Commit and Confirm are sent
977 * immediately. In infrastructure BSS, by default, only
978 * a single Authentication frame (Commit) is expected
979 * from the AP here and the second one (Confirm) will
980 * be sent once the STA has sent its second
981 * Authentication frame (Confirm). This behavior can be
982 * overridden with explicit configuration so that the
983 * infrastructure BSS case sends both frames together.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800984 */
Hai Shalomc3565922019-10-28 11:58:20 -0700985 if ((hapd->conf->mesh & MESH_ENABLED) ||
986 hapd->conf->sae_confirm_immediate) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800987 /*
988 * Send both Commit and Confirm immediately
989 * based on SAE finite state machine
990 * Nothing -> Confirm transition.
991 */
992 ret = auth_sae_send_confirm(hapd, sta, bssid);
993 if (ret)
994 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700995 sae_set_state(sta, SAE_CONFIRMED,
996 "Sent Confirm (mesh)");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800997 } else {
998 /*
999 * For infrastructure BSS, send only the Commit
1000 * message now to get alternating sequence of
1001 * Authentication frames between the AP and STA.
1002 * Confirm will be sent in
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001003 * Committed -> Confirmed/Accepted transition
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001004 * when receiving Confirm from STA.
1005 */
1006 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001007 sta->sae->sync = 0;
1008 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001009 } else {
1010 hostapd_logger(hapd, sta->addr,
1011 HOSTAPD_MODULE_IEEE80211,
1012 HOSTAPD_LEVEL_DEBUG,
1013 "SAE confirm before commit");
1014 }
1015 break;
1016 case SAE_COMMITTED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001017 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001018 if (auth_transaction == 1) {
1019 if (sae_process_commit(sta->sae) < 0)
1020 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1021
1022 ret = auth_sae_send_confirm(hapd, sta, bssid);
1023 if (ret)
1024 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001025 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001026 sta->sae->sync = 0;
1027 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001028 } else if (hapd->conf->mesh & MESH_ENABLED) {
1029 /*
1030 * In mesh case, follow SAE finite state machine and
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001031 * send Commit now, if sync count allows.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001032 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001033 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001034 return WLAN_STATUS_SUCCESS;
1035 sta->sae->sync++;
1036
Hai Shalomc3565922019-10-28 11:58:20 -07001037 ret = auth_sae_send_commit(hapd, sta, bssid, 0,
1038 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001039 if (ret)
1040 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001041
1042 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001043 } else {
1044 /*
1045 * For instructure BSS, send the postponed Confirm from
1046 * Nothing -> Confirmed transition that was reduced to
1047 * Nothing -> Committed above.
1048 */
1049 ret = auth_sae_send_confirm(hapd, sta, bssid);
1050 if (ret)
1051 return ret;
1052
Roshan Pius3a1667e2018-07-03 15:17:14 -07001053 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001054
1055 /*
1056 * Since this was triggered on Confirm RX, run another
1057 * step to get to Accepted without waiting for
1058 * additional events.
1059 */
Hai Shalom021b0b52019-04-10 11:17:58 -07001060 return sae_sm_step(hapd, sta, bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001061 WLAN_STATUS_SUCCESS, 0, sta_removed);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001062 }
1063 break;
1064 case SAE_CONFIRMED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001065 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001066 if (auth_transaction == 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001067 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001068 return WLAN_STATUS_SUCCESS;
1069 sta->sae->sync++;
1070
Hai Shalomc3565922019-10-28 11:58:20 -07001071 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1072 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001073 if (ret)
1074 return ret;
1075
1076 if (sae_process_commit(sta->sae) < 0)
1077 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1078
1079 ret = auth_sae_send_confirm(hapd, sta, bssid);
1080 if (ret)
1081 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001082
1083 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001084 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001085 sta->sae->send_confirm = 0xffff;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001086 sae_accept_sta(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001087 }
1088 break;
1089 case SAE_ACCEPTED:
Roshan Pius3a1667e2018-07-03 15:17:14 -07001090 if (auth_transaction == 1 &&
1091 (hapd->conf->mesh & MESH_ENABLED)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001092 wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
1093 ") doing reauthentication",
1094 MAC2STR(sta->addr));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001095 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
Hai Shalom5f92bc92019-04-18 11:54:11 -07001096 ap_free_sta(hapd, sta);
1097 *sta_removed = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001098 } else if (auth_transaction == 1) {
1099 wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
Hai Shalomc3565922019-10-28 11:58:20 -07001100 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1101 status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001102 if (ret)
1103 return ret;
1104 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
1105
1106 if (sae_process_commit(sta->sae) < 0)
1107 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1108 sta->sae->sync = 0;
1109 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001110 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001111 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001112 return WLAN_STATUS_SUCCESS;
1113 sta->sae->sync++;
1114
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001115 ret = auth_sae_send_confirm(hapd, sta, bssid);
1116 sae_clear_temp_data(sta->sae);
1117 if (ret)
1118 return ret;
1119 }
1120 break;
1121 default:
1122 wpa_printf(MSG_ERROR, "SAE: invalid state %d",
1123 sta->sae->state);
1124 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1125 }
1126 return WLAN_STATUS_SUCCESS;
1127}
1128
1129
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001130static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
1131{
1132 struct sae_data *sae = sta->sae;
1133 int i, *groups = hapd->conf->sae_groups;
Hai Shalom021b0b52019-04-10 11:17:58 -07001134 int default_groups[] = { 19, 0 };
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001135
1136 if (sae->state != SAE_COMMITTED)
1137 return;
1138
1139 wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
1140
Hai Shalom021b0b52019-04-10 11:17:58 -07001141 if (!groups)
1142 groups = default_groups;
1143 for (i = 0; groups[i] > 0; i++) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001144 if (sae->group == groups[i])
1145 break;
1146 }
1147
Hai Shalom021b0b52019-04-10 11:17:58 -07001148 if (groups[i] <= 0) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001149 wpa_printf(MSG_DEBUG,
1150 "SAE: Previously selected group not found from the current configuration");
1151 return;
1152 }
1153
1154 for (;;) {
1155 i++;
1156 if (groups[i] <= 0) {
1157 wpa_printf(MSG_DEBUG,
1158 "SAE: No alternative group enabled");
1159 return;
1160 }
1161
1162 if (sae_set_group(sae, groups[i]) < 0)
1163 continue;
1164
1165 break;
1166 }
1167 wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
1168}
1169
1170
Hai Shalomc3565922019-10-28 11:58:20 -07001171static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
1172{
Sunil Ravi77d572f2023-01-17 23:58:31 +00001173 enum sae_pwe sae_pwe = hapd->conf->sae_pwe;
Hai Shalomfdcde762020-04-02 11:19:20 -07001174 int id_in_use;
Hai Shalom60840252021-02-19 19:02:11 -08001175 bool sae_pk = false;
Hai Shalomfdcde762020-04-02 11:19:20 -07001176
1177 id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001178 if (id_in_use == 2 && sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
1179 sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
1180 else if (id_in_use == 1 && sae_pwe == SAE_PWE_HUNT_AND_PECK)
1181 sae_pwe = SAE_PWE_BOTH;
Hai Shalom899fcc72020-10-19 14:38:18 -07001182#ifdef CONFIG_SAE_PK
Hai Shalom60840252021-02-19 19:02:11 -08001183 sae_pk = hostapd_sae_pk_in_use(hapd->conf);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001184 if (sae_pwe == SAE_PWE_HUNT_AND_PECK && sae_pk)
1185 sae_pwe = SAE_PWE_BOTH;
Hai Shalom899fcc72020-10-19 14:38:18 -07001186#endif /* CONFIG_SAE_PK */
Sunil Ravi77d572f2023-01-17 23:58:31 +00001187 if (sae_pwe == SAE_PWE_HUNT_AND_PECK &&
Sunil Ravi89eba102022-09-13 21:04:37 -07001188 (hapd->conf->wpa_key_mgmt &
1189 (WPA_KEY_MGMT_SAE_EXT_KEY | WPA_KEY_MGMT_FT_SAE_EXT_KEY)))
Sunil Ravi77d572f2023-01-17 23:58:31 +00001190 sae_pwe = SAE_PWE_BOTH;
Hai Shalomfdcde762020-04-02 11:19:20 -07001191
Sunil Ravi77d572f2023-01-17 23:58:31 +00001192 return ((sae_pwe == SAE_PWE_HUNT_AND_PECK ||
1193 sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001194 status_code == WLAN_STATUS_SUCCESS) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001195 (sae_pwe == SAE_PWE_HASH_TO_ELEMENT &&
Hai Shalom899fcc72020-10-19 14:38:18 -07001196 (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001197 (sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001198 (sae_pwe == SAE_PWE_BOTH &&
Hai Shalomc3565922019-10-28 11:58:20 -07001199 (status_code == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -07001200 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001201 (sae_pk && status_code == WLAN_STATUS_SAE_PK)));
Hai Shalomc3565922019-10-28 11:58:20 -07001202}
1203
1204
1205static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
1206{
1207 int *groups = hapd->conf->sae_groups;
1208 int default_groups[] = { 19, 0 };
1209 int i;
1210
1211 if (!groups)
1212 groups = default_groups;
1213
1214 for (i = 0; groups[i] > 0; i++) {
1215 if (groups[i] == group)
1216 return 1;
1217 }
1218
1219 return 0;
1220}
1221
1222
1223static int check_sae_rejected_groups(struct hostapd_data *hapd,
Hai Shalom899fcc72020-10-19 14:38:18 -07001224 struct sae_data *sae)
Hai Shalomc3565922019-10-28 11:58:20 -07001225{
Hai Shalom899fcc72020-10-19 14:38:18 -07001226 const struct wpabuf *groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001227 size_t i, count;
1228 const u8 *pos;
1229
Hai Shalom899fcc72020-10-19 14:38:18 -07001230 if (!sae->tmp)
1231 return 0;
1232 groups = sae->tmp->peer_rejected_groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001233 if (!groups)
1234 return 0;
1235
1236 pos = wpabuf_head(groups);
1237 count = wpabuf_len(groups) / 2;
1238 for (i = 0; i < count; i++) {
1239 int enabled;
1240 u16 group;
1241
1242 group = WPA_GET_LE16(pos);
1243 pos += 2;
1244 enabled = sae_is_group_enabled(hapd, group);
1245 wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
1246 group, enabled ? "enabled" : "disabled");
1247 if (enabled)
1248 return 1;
1249 }
1250
1251 return 0;
1252}
1253
1254
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001255static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
1256 const struct ieee80211_mgmt *mgmt, size_t len,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001257 u16 auth_transaction, u16 status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001258{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001259 int resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001260 struct wpabuf *data = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07001261 int *groups = hapd->conf->sae_groups;
1262 int default_groups[] = { 19, 0 };
1263 const u8 *pos, *end;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001264 int sta_removed = 0;
Hai Shalom60840252021-02-19 19:02:11 -08001265 bool success_status;
Hai Shalom021b0b52019-04-10 11:17:58 -07001266
1267 if (!groups)
1268 groups = default_groups;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001269
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001270#ifdef CONFIG_TESTING_OPTIONS
1271 if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001272 wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
1273 pos = mgmt->u.auth.variable;
1274 end = ((const u8 *) mgmt) + len;
Hai Shalom899fcc72020-10-19 14:38:18 -07001275 resp = status_code;
Hai Shalomfdcde762020-04-02 11:19:20 -07001276 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001277 auth_transaction, resp, pos, end - pos,
1278 "auth-sae-reflection-attack");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001279 goto remove_sta;
1280 }
1281
1282 if (hapd->conf->sae_commit_override && auth_transaction == 1) {
1283 wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
Hai Shalomfdcde762020-04-02 11:19:20 -07001284 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001285 auth_transaction, resp,
1286 wpabuf_head(hapd->conf->sae_commit_override),
Roshan Pius3a1667e2018-07-03 15:17:14 -07001287 wpabuf_len(hapd->conf->sae_commit_override),
1288 "sae-commit-override");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001289 goto remove_sta;
1290 }
1291#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001292 if (!sta->sae) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001293 if (auth_transaction != 1 ||
Hai Shalomc3565922019-10-28 11:58:20 -07001294 !sae_status_success(hapd, status_code)) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001295 wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
1296 status_code);
1297 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1298 goto reply;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001299 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001300 sta->sae = os_zalloc(sizeof(*sta->sae));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001301 if (!sta->sae) {
1302 resp = -1;
1303 goto remove_sta;
1304 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001305 sae_set_state(sta, SAE_NOTHING, "Init");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001306 sta->sae->sync = 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001307 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001308
Dmitry Shmidte4663042016-04-04 10:07:49 -07001309 if (sta->mesh_sae_pmksa_caching) {
1310 wpa_printf(MSG_DEBUG,
1311 "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
1312 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
1313 sta->mesh_sae_pmksa_caching = 0;
1314 }
1315
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001316 if (auth_transaction == 1) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001317 const u8 *token = NULL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001318 size_t token_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07001319 int allow_reuse = 0;
1320
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001321 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1322 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001323 "start SAE authentication (RX commit, status=%u (%s))",
1324 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001325
1326 if ((hapd->conf->mesh & MESH_ENABLED) &&
1327 status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
1328 sta->sae->tmp) {
1329 pos = mgmt->u.auth.variable;
1330 end = ((const u8 *) mgmt) + len;
1331 if (pos + sizeof(le16) > end) {
1332 wpa_printf(MSG_ERROR,
1333 "SAE: Too short anti-clogging token request");
1334 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1335 goto reply;
1336 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001337 resp = sae_group_allowed(sta->sae, groups,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001338 WPA_GET_LE16(pos));
1339 if (resp != WLAN_STATUS_SUCCESS) {
1340 wpa_printf(MSG_ERROR,
1341 "SAE: Invalid group in anti-clogging token request");
1342 goto reply;
1343 }
1344 pos += sizeof(le16);
1345
1346 wpabuf_free(sta->sae->tmp->anti_clogging_token);
1347 sta->sae->tmp->anti_clogging_token =
1348 wpabuf_alloc_copy(pos, end - pos);
1349 if (sta->sae->tmp->anti_clogging_token == NULL) {
1350 wpa_printf(MSG_ERROR,
1351 "SAE: Failed to alloc for anti-clogging token");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001352 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1353 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001354 }
1355
1356 /*
1357 * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code
1358 * is 76, a new Commit Message shall be constructed
1359 * with the Anti-Clogging Token from the received
1360 * Authentication frame, and the commit-scalar and
1361 * COMMIT-ELEMENT previously sent.
1362 */
Hai Shalomc3565922019-10-28 11:58:20 -07001363 resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
1364 status_code);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001365 if (resp != WLAN_STATUS_SUCCESS) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001366 wpa_printf(MSG_ERROR,
1367 "SAE: Failed to send commit message");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001368 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001369 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001370 sae_set_state(sta, SAE_COMMITTED,
1371 "Sent Commit (anti-clogging token case in mesh)");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001372 sta->sae->sync = 0;
1373 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001374 return;
1375 }
1376
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001377 if ((hapd->conf->mesh & MESH_ENABLED) &&
1378 status_code ==
1379 WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1380 sta->sae->tmp) {
1381 wpa_printf(MSG_DEBUG,
1382 "SAE: Peer did not accept our SAE group");
1383 sae_pick_next_group(hapd, sta);
1384 goto remove_sta;
1385 }
1386
Hai Shalomc3565922019-10-28 11:58:20 -07001387 if (!sae_status_success(hapd, status_code))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001388 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001389
Roshan Pius3a1667e2018-07-03 15:17:14 -07001390 if (!(hapd->conf->mesh & MESH_ENABLED) &&
1391 sta->sae->state == SAE_COMMITTED) {
1392 /* This is needed in the infrastructure BSS case to
1393 * address a sequence where a STA entry may remain in
1394 * hostapd across two attempts to do SAE authentication
1395 * by the same STA. The second attempt may end up trying
1396 * to use a different group and that would not be
1397 * allowed if we remain in Committed state with the
1398 * previously set parameters. */
Hai Shalom021b0b52019-04-10 11:17:58 -07001399 pos = mgmt->u.auth.variable;
1400 end = ((const u8 *) mgmt) + len;
1401 if (end - pos >= (int) sizeof(le16) &&
1402 sae_group_allowed(sta->sae, groups,
1403 WPA_GET_LE16(pos)) ==
1404 WLAN_STATUS_SUCCESS) {
1405 /* Do not waste resources deriving the same PWE
1406 * again since the same group is reused. */
1407 sae_set_state(sta, SAE_NOTHING,
1408 "Allow previous PWE to be reused");
1409 allow_reuse = 1;
1410 } else {
1411 sae_set_state(sta, SAE_NOTHING,
1412 "Clear existing state to allow restart");
1413 sae_clear_data(sta->sae);
1414 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001415 }
1416
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001417 resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
1418 ((const u8 *) mgmt) + len -
1419 mgmt->u.auth.variable, &token,
Hai Shalomc3565922019-10-28 11:58:20 -07001420 &token_len, groups, status_code ==
Hai Shalom899fcc72020-10-19 14:38:18 -07001421 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001422 status_code == WLAN_STATUS_SAE_PK,
1423 NULL);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001424 if (resp == SAE_SILENTLY_DISCARD) {
1425 wpa_printf(MSG_DEBUG,
1426 "SAE: Drop commit message from " MACSTR " due to reflection attack",
1427 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001428 goto remove_sta;
Dmitry Shmidt41712582015-06-29 11:02:15 -07001429 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001430
1431 if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
1432 wpa_msg(hapd->msg_ctx, MSG_INFO,
1433 WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
1434 MACSTR, MAC2STR(sta->addr));
1435 sae_clear_retransmit_timer(hapd, sta);
1436 sae_set_state(sta, SAE_NOTHING,
1437 "Unknown Password Identifier");
1438 goto remove_sta;
1439 }
1440
Hai Shaloma20dcd72022-02-04 13:43:00 -08001441 if (token &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00001442 check_comeback_token(hapd->comeback_key,
1443 hapd->comeback_pending_idx, sta->addr,
1444 token, token_len)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001445 < 0) {
1446 wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
1447 "incorrect token from " MACSTR,
1448 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001449 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1450 goto remove_sta;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001451 }
1452
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001453 if (resp != WLAN_STATUS_SUCCESS)
1454 goto reply;
1455
Hai Shalom899fcc72020-10-19 14:38:18 -07001456 if (check_sae_rejected_groups(hapd, sta->sae)) {
Hai Shalomc3565922019-10-28 11:58:20 -07001457 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001458 goto reply;
Hai Shalomc3565922019-10-28 11:58:20 -07001459 }
1460
Hai Shaloma20dcd72022-02-04 13:43:00 -08001461 if (!token && use_anti_clogging(hapd) && !allow_reuse) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001462 int h2e = 0;
1463
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001464 wpa_printf(MSG_DEBUG,
1465 "SAE: Request anti-clogging token from "
1466 MACSTR, MAC2STR(sta->addr));
Hai Shalomfdcde762020-04-02 11:19:20 -07001467 if (sta->sae->tmp)
Hai Shalom899fcc72020-10-19 14:38:18 -07001468 h2e = sta->sae->h2e;
1469 if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1470 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomfdcde762020-04-02 11:19:20 -07001471 h2e = 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001472 data = auth_build_token_req(
1473 &hapd->last_comeback_key_update,
1474 hapd->comeback_key,
1475 hapd->comeback_idx,
1476 hapd->comeback_pending_idx,
1477 sizeof(hapd->comeback_pending_idx),
1478 sta->sae->group,
1479 sta->addr, h2e);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001480 resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
1481 if (hapd->conf->mesh & MESH_ENABLED)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001482 sae_set_state(sta, SAE_NOTHING,
1483 "Request anti-clogging token case in mesh");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001484 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001485 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001486
Hai Shalom021b0b52019-04-10 11:17:58 -07001487 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001488 status_code, allow_reuse, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001489 } else if (auth_transaction == 2) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001490 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1491 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001492 "SAE authentication (RX confirm, status=%u (%s))",
1493 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001494 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001495 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001496 if (sta->sae->state >= SAE_CONFIRMED ||
1497 !(hapd->conf->mesh & MESH_ENABLED)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001498 const u8 *var;
1499 size_t var_len;
1500 u16 peer_send_confirm;
1501
1502 var = mgmt->u.auth.variable;
1503 var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable;
1504 if (var_len < 2) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001505 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001506 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001507 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001508
1509 peer_send_confirm = WPA_GET_LE16(var);
1510
1511 if (sta->sae->state == SAE_ACCEPTED &&
1512 (peer_send_confirm <= sta->sae->rc ||
1513 peer_send_confirm == 0xffff)) {
1514 wpa_printf(MSG_DEBUG,
1515 "SAE: Silently ignore unexpected Confirm from peer "
1516 MACSTR
1517 " (peer-send-confirm=%u Rc=%u)",
1518 MAC2STR(sta->addr),
1519 peer_send_confirm, sta->sae->rc);
1520 return;
1521 }
1522
Sunil Ravi77d572f2023-01-17 23:58:31 +00001523 if (sae_check_confirm(sta->sae, var, var_len,
1524 NULL) < 0) {
1525 resp = WLAN_STATUS_CHALLENGE_FAIL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001526 goto reply;
1527 }
1528 sta->sae->rc = peer_send_confirm;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001529 }
Hai Shalomc3565922019-10-28 11:58:20 -07001530 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
1531 status_code, 0, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001532 } else {
1533 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1534 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001535 "unexpected SAE authentication transaction %u (status=%u (%s))",
1536 auth_transaction, status_code,
1537 status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001538 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001539 goto remove_sta;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001540 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1541 }
1542
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001543reply:
Hai Shalom5f92bc92019-04-18 11:54:11 -07001544 if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001545 pos = mgmt->u.auth.variable;
1546 end = ((const u8 *) mgmt) + len;
1547
1548 /* Copy the Finite Cyclic Group field from the request if we
1549 * rejected it as unsupported group. */
1550 if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1551 !data && end - pos >= 2)
1552 data = wpabuf_alloc_copy(pos, 2);
1553
Hai Shalom5f92bc92019-04-18 11:54:11 -07001554 sae_sme_send_external_auth_status(hapd, sta, resp);
Hai Shalomfdcde762020-04-02 11:19:20 -07001555 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001556 auth_transaction, resp,
1557 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07001558 data ? wpabuf_len(data) : 0, "auth-sae");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001559 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001560
1561remove_sta:
Hai Shalom60840252021-02-19 19:02:11 -08001562 if (auth_transaction == 1)
1563 success_status = sae_status_success(hapd, status_code);
1564 else
1565 success_status = status_code == WLAN_STATUS_SUCCESS;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001566 if (!sta_removed && sta->added_unassoc &&
Hai Shalom60840252021-02-19 19:02:11 -08001567 (resp != WLAN_STATUS_SUCCESS || !success_status)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001568 hostapd_drv_sta_remove(hapd, sta->addr);
1569 sta->added_unassoc = 0;
1570 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001571 wpabuf_free(data);
1572}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001573
1574
1575/**
1576 * auth_sae_init_committed - Send COMMIT and start SAE in committed state
1577 * @hapd: BSS data for the device initiating the authentication
1578 * @sta: the peer to which commit authentication frame is sent
1579 *
1580 * This function implements Init event handling (IEEE Std 802.11-2012,
1581 * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
1582 * sta->sae structure should be initialized appropriately via a call to
1583 * sae_prepare_commit().
1584 */
1585int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
1586{
1587 int ret;
1588
1589 if (!sta->sae || !sta->sae->tmp)
1590 return -1;
1591
1592 if (sta->sae->state != SAE_NOTHING)
1593 return -1;
1594
Hai Shalomc3565922019-10-28 11:58:20 -07001595 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001596 if (ret)
1597 return -1;
1598
Roshan Pius3a1667e2018-07-03 15:17:14 -07001599 sae_set_state(sta, SAE_COMMITTED, "Init and sent commit");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001600 sta->sae->sync = 0;
1601 sae_set_retransmit_timer(hapd, sta);
1602
1603 return 0;
1604}
1605
Hai Shalom021b0b52019-04-10 11:17:58 -07001606
1607void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
1608{
1609 struct hostapd_data *hapd = eloop_ctx;
1610 struct hostapd_sae_commit_queue *q;
1611 unsigned int queue_len;
1612
1613 q = dl_list_first(&hapd->sae_commit_queue,
1614 struct hostapd_sae_commit_queue, list);
1615 if (!q)
1616 return;
1617 wpa_printf(MSG_DEBUG,
1618 "SAE: Process next available message from queue");
1619 dl_list_del(&q->list);
1620 handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
1621 q->rssi, 1);
1622 os_free(q);
1623
1624 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1625 return;
1626 queue_len = dl_list_len(&hapd->sae_commit_queue);
1627 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1628 hapd, NULL);
1629}
1630
1631
1632static void auth_sae_queue(struct hostapd_data *hapd,
1633 const struct ieee80211_mgmt *mgmt, size_t len,
1634 int rssi)
1635{
1636 struct hostapd_sae_commit_queue *q, *q2;
1637 unsigned int queue_len;
1638 const struct ieee80211_mgmt *mgmt2;
1639
1640 queue_len = dl_list_len(&hapd->sae_commit_queue);
1641 if (queue_len >= 15) {
1642 wpa_printf(MSG_DEBUG,
1643 "SAE: No more room in message queue - drop the new frame from "
1644 MACSTR, MAC2STR(mgmt->sa));
1645 return;
1646 }
1647
1648 wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
1649 MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
1650 queue_len);
1651 q = os_zalloc(sizeof(*q) + len);
1652 if (!q)
1653 return;
1654 q->rssi = rssi;
1655 q->len = len;
1656 os_memcpy(q->msg, mgmt, len);
1657
1658 /* Check whether there is already a queued Authentication frame from the
1659 * same station with the same transaction number and if so, replace that
1660 * queue entry with the new one. This avoids issues with a peer that
1661 * sends multiple times (e.g., due to frequent SAE retries). There is no
1662 * point in us trying to process the old attempts after a new one has
1663 * obsoleted them. */
1664 dl_list_for_each(q2, &hapd->sae_commit_queue,
1665 struct hostapd_sae_commit_queue, list) {
1666 mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
1667 if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 &&
1668 mgmt->u.auth.auth_transaction ==
1669 mgmt2->u.auth.auth_transaction) {
1670 wpa_printf(MSG_DEBUG,
1671 "SAE: Replace queued message from same STA with same transaction number");
1672 dl_list_add(&q2->list, &q->list);
1673 dl_list_del(&q2->list);
1674 os_free(q2);
1675 goto queued;
1676 }
1677 }
1678
1679 /* No pending identical entry, so add to the end of the queue */
1680 dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
1681
1682queued:
1683 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1684 return;
1685 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1686 hapd, NULL);
1687}
1688
1689
1690static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
1691{
1692 struct hostapd_sae_commit_queue *q;
1693 const struct ieee80211_mgmt *mgmt;
1694
1695 dl_list_for_each(q, &hapd->sae_commit_queue,
1696 struct hostapd_sae_commit_queue, list) {
1697 mgmt = (const struct ieee80211_mgmt *) q->msg;
1698 if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0)
1699 return 1;
1700 }
1701
1702 return 0;
1703}
1704
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001705#endif /* CONFIG_SAE */
1706
1707
Hai Shalomfdcde762020-04-02 11:19:20 -07001708static u16 wpa_res_to_status_code(enum wpa_validate_result res)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001709{
Hai Shalomfdcde762020-04-02 11:19:20 -07001710 switch (res) {
1711 case WPA_IE_OK:
1712 return WLAN_STATUS_SUCCESS;
1713 case WPA_INVALID_IE:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001714 return WLAN_STATUS_INVALID_IE;
Hai Shalomfdcde762020-04-02 11:19:20 -07001715 case WPA_INVALID_GROUP:
1716 return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
1717 case WPA_INVALID_PAIRWISE:
1718 return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
1719 case WPA_INVALID_AKMP:
1720 return WLAN_STATUS_AKMP_NOT_VALID;
1721 case WPA_NOT_ENABLED:
1722 return WLAN_STATUS_INVALID_IE;
1723 case WPA_ALLOC_FAIL:
1724 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1725 case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
1726 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
1727 case WPA_INVALID_MGMT_GROUP_CIPHER:
1728 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
1729 case WPA_INVALID_MDIE:
1730 return WLAN_STATUS_INVALID_MDIE;
1731 case WPA_INVALID_PROTO:
1732 return WLAN_STATUS_INVALID_IE;
1733 case WPA_INVALID_PMKID:
1734 return WLAN_STATUS_INVALID_PMKID;
1735 case WPA_DENIED_OTHER_REASON:
1736 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
1737 }
1738 return WLAN_STATUS_INVALID_IE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001739}
1740
1741
1742#ifdef CONFIG_FILS
1743
1744static void handle_auth_fils_finish(struct hostapd_data *hapd,
1745 struct sta_info *sta, u16 resp,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001746 struct wpabuf *data, int pub);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001747
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001748void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
1749 const u8 *pos, size_t len, u16 auth_alg,
1750 u16 auth_transaction, u16 status_code,
1751 void (*cb)(struct hostapd_data *hapd,
1752 struct sta_info *sta, u16 resp,
1753 struct wpabuf *data, int pub))
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001754{
1755 u16 resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001756 const u8 *end;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001757 struct ieee802_11_elems elems;
Hai Shalomfdcde762020-04-02 11:19:20 -07001758 enum wpa_validate_result res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001759 struct wpa_ie_data rsn;
1760 struct rsn_pmksa_cache_entry *pmksa = NULL;
1761
1762 if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
1763 return;
1764
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001765 end = pos + len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001766
1767 wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
1768 pos, end - pos);
1769
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001770 /* TODO: FILS PK */
1771#ifdef CONFIG_FILS_SK_PFS
1772 if (auth_alg == WLAN_AUTH_FILS_SK_PFS) {
1773 u16 group;
1774 struct wpabuf *pub;
1775 size_t elem_len;
1776
1777 /* Using FILS PFS */
1778
1779 /* Finite Cyclic Group */
1780 if (end - pos < 2) {
1781 wpa_printf(MSG_DEBUG,
1782 "FILS: No room for Finite Cyclic Group");
1783 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1784 goto fail;
1785 }
1786 group = WPA_GET_LE16(pos);
1787 pos += 2;
1788 if (group != hapd->conf->fils_dh_group) {
1789 wpa_printf(MSG_DEBUG,
1790 "FILS: Unsupported Finite Cyclic Group: %u (expected %u)",
1791 group, hapd->conf->fils_dh_group);
1792 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1793 goto fail;
1794 }
1795
1796 crypto_ecdh_deinit(sta->fils_ecdh);
1797 sta->fils_ecdh = crypto_ecdh_init(group);
1798 if (!sta->fils_ecdh) {
1799 wpa_printf(MSG_INFO,
1800 "FILS: Could not initialize ECDH with group %d",
1801 group);
1802 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1803 goto fail;
1804 }
1805
1806 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
1807 if (!pub) {
1808 wpa_printf(MSG_DEBUG,
1809 "FILS: Failed to derive ECDH public key");
1810 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1811 goto fail;
1812 }
1813 elem_len = wpabuf_len(pub);
1814 wpabuf_free(pub);
1815
1816 /* Element */
1817 if ((size_t) (end - pos) < elem_len) {
1818 wpa_printf(MSG_DEBUG, "FILS: No room for Element");
1819 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1820 goto fail;
1821 }
1822
1823 wpabuf_free(sta->fils_g_sta);
1824 sta->fils_g_sta = wpabuf_alloc_copy(pos, elem_len);
1825 wpabuf_clear_free(sta->fils_dh_ss);
1826 sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1,
1827 pos, elem_len);
1828 if (!sta->fils_dh_ss) {
1829 wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
1830 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1831 goto fail;
1832 }
1833 wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss);
1834 pos += elem_len;
1835 } else {
1836 crypto_ecdh_deinit(sta->fils_ecdh);
1837 sta->fils_ecdh = NULL;
1838 wpabuf_clear_free(sta->fils_dh_ss);
1839 sta->fils_dh_ss = NULL;
1840 }
1841#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001842
1843 wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
1844 if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
1845 wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
1846 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1847 goto fail;
1848 }
1849
1850 /* RSNE */
1851 wpa_hexdump(MSG_DEBUG, "FILS: RSN element",
1852 elems.rsn_ie, elems.rsn_ie_len);
1853 if (!elems.rsn_ie ||
1854 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
1855 &rsn) < 0) {
1856 wpa_printf(MSG_DEBUG, "FILS: No valid RSN element");
1857 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1858 goto fail;
1859 }
1860
1861 if (!sta->wpa_sm)
1862 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
1863 NULL);
1864 if (!sta->wpa_sm) {
1865 wpa_printf(MSG_DEBUG,
1866 "FILS: Failed to initialize RSN state machine");
1867 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1868 goto fail;
1869 }
1870
1871 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07001872 hapd->iface->freq,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001873 elems.rsn_ie - 2, elems.rsn_ie_len + 2,
Hai Shalomc3565922019-10-28 11:58:20 -07001874 elems.rsnxe ? elems.rsnxe - 2 : NULL,
1875 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001876 elems.mdie, elems.mdie_len, NULL, 0);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001877 resp = wpa_res_to_status_code(res);
1878 if (resp != WLAN_STATUS_SUCCESS)
1879 goto fail;
1880
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001881 if (!elems.fils_nonce) {
1882 wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
1883 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1884 goto fail;
1885 }
1886 wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce,
1887 FILS_NONCE_LEN);
1888 os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN);
1889
1890 /* PMKID List */
1891 if (rsn.pmkid && rsn.num_pmkid > 0) {
1892 u8 num;
1893 const u8 *pmkid;
1894
1895 wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
1896 rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
1897
1898 pmkid = rsn.pmkid;
1899 num = rsn.num_pmkid;
1900 while (num) {
1901 wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
1902 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
1903 pmkid);
1904 if (pmksa)
1905 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001906 pmksa = wpa_auth_pmksa_get_fils_cache_id(hapd->wpa_auth,
1907 sta->addr,
1908 pmkid);
1909 if (pmksa)
1910 break;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001911 pmkid += PMKID_LEN;
1912 num--;
1913 }
1914 }
1915 if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) {
1916 wpa_printf(MSG_DEBUG,
1917 "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore",
1918 wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp);
1919 pmksa = NULL;
1920 }
1921 if (pmksa)
1922 wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry");
1923
1924 /* FILS Session */
1925 if (!elems.fils_session) {
1926 wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
1927 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1928 goto fail;
1929 }
1930 wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
1931 FILS_SESSION_LEN);
1932 os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
1933
Hai Shalomfdcde762020-04-02 11:19:20 -07001934 /* Wrapped Data */
1935 if (elems.wrapped_data) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001936 wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
Hai Shalomfdcde762020-04-02 11:19:20 -07001937 elems.wrapped_data,
1938 elems.wrapped_data_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001939 if (!pmksa) {
1940#ifndef CONFIG_NO_RADIUS
1941 if (!sta->eapol_sm) {
1942 sta->eapol_sm =
1943 ieee802_1x_alloc_eapol_sm(hapd, sta);
1944 }
1945 wpa_printf(MSG_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001946 "FILS: Forward EAP-Initiate/Re-auth to authentication server");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001947 ieee802_1x_encapsulate_radius(
Hai Shalomfdcde762020-04-02 11:19:20 -07001948 hapd, sta, elems.wrapped_data,
1949 elems.wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001950 sta->fils_pending_cb = cb;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001951 wpa_printf(MSG_DEBUG,
1952 "FILS: Will send Authentication frame once the response from authentication server is available");
1953 sta->flags |= WLAN_STA_PENDING_FILS_ERP;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001954 /* Calculate pending PMKID here so that we do not need
1955 * to maintain a copy of the EAP-Initiate/Reauth
1956 * message. */
1957 if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
Hai Shalomfdcde762020-04-02 11:19:20 -07001958 elems.wrapped_data,
1959 elems.wrapped_data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001960 sta->fils_erp_pmkid) == 0)
1961 sta->fils_erp_pmkid_set = 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001962 return;
1963#else /* CONFIG_NO_RADIUS */
1964 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1965 goto fail;
1966#endif /* CONFIG_NO_RADIUS */
1967 }
1968 }
1969
1970fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001971 if (cb) {
1972 struct wpabuf *data;
1973 int pub = 0;
1974
1975 data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, NULL,
1976 NULL, 0, &pub);
1977 if (!data) {
1978 wpa_printf(MSG_DEBUG,
1979 "%s: prepare_auth_resp_fils() returned failure",
1980 __func__);
1981 }
1982
1983 cb(hapd, sta, resp, data, pub);
1984 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001985}
1986
1987
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001988static struct wpabuf *
1989prepare_auth_resp_fils(struct hostapd_data *hapd,
1990 struct sta_info *sta, u16 *resp,
1991 struct rsn_pmksa_cache_entry *pmksa,
1992 struct wpabuf *erp_resp,
1993 const u8 *msk, size_t msk_len,
1994 int *is_pub)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001995{
1996 u8 fils_nonce[FILS_NONCE_LEN];
1997 size_t ielen;
1998 struct wpabuf *data = NULL;
1999 const u8 *ie;
2000 u8 *ie_buf = NULL;
2001 const u8 *pmk = NULL;
2002 size_t pmk_len = 0;
Paul Stewart092955c2017-02-06 09:13:09 -08002003 u8 pmk_buf[PMK_LEN_MAX];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002004 struct wpabuf *pub = NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002005
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002006 if (*resp != WLAN_STATUS_SUCCESS)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002007 goto fail;
2008
2009 ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
2010 if (!ie) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002011 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002012 goto fail;
2013 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002014
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002015 if (pmksa) {
2016 /* Add PMKID of the selected PMKSA into RSNE */
2017 ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN);
2018 if (!ie_buf) {
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 os_memcpy(ie_buf, ie, ielen);
2024 if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002025 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002026 goto fail;
2027 }
2028 ie = ie_buf;
2029 }
2030
2031 if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002032 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002033 goto fail;
2034 }
2035 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
2036 fils_nonce, FILS_NONCE_LEN);
2037
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002038#ifdef CONFIG_FILS_SK_PFS
2039 if (sta->fils_dh_ss && sta->fils_ecdh) {
2040 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
2041 if (!pub) {
2042 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2043 goto fail;
2044 }
2045 }
2046#endif /* CONFIG_FILS_SK_PFS */
2047
2048 data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0));
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002049 if (!data) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002050 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002051 goto fail;
2052 }
2053
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002054 /* TODO: FILS PK */
2055#ifdef CONFIG_FILS_SK_PFS
2056 if (pub) {
2057 /* Finite Cyclic Group */
2058 wpabuf_put_le16(data, hapd->conf->fils_dh_group);
2059
2060 /* Element */
2061 wpabuf_put_buf(data, pub);
2062 }
2063#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002064
2065 /* RSNE */
2066 wpabuf_put_data(data, ie, ielen);
2067
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002068 /* MDE when using FILS+FT (already included in ie,ielen with RSNE) */
2069
2070#ifdef CONFIG_IEEE80211R_AP
2071 if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
2072 /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
2073 int res;
2074
Sunil Ravi77d572f2023-01-17 23:58:31 +00002075 res = wpa_auth_write_fte(hapd->wpa_auth, sta->wpa_sm,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002076 wpabuf_put(data, 0),
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002077 wpabuf_tailroom(data));
2078 if (res < 0) {
2079 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2080 goto fail;
2081 }
2082 wpabuf_put(data, res);
2083 }
2084#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002085
2086 /* FILS Nonce */
2087 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2088 wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */
2089 /* Element ID Extension */
2090 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE);
2091 wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN);
2092
2093 /* FILS Session */
2094 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2095 wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */
2096 /* Element ID Extension */
2097 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
2098 wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
2099
Hai Shalomfdcde762020-04-02 11:19:20 -07002100 /* Wrapped Data */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002101 if (!pmksa && erp_resp) {
2102 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2103 wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
2104 /* Element ID Extension */
Hai Shalomfdcde762020-04-02 11:19:20 -07002105 wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002106 wpabuf_put_buf(data, erp_resp);
2107
Paul Stewart092955c2017-02-06 09:13:09 -08002108 if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
2109 msk, msk_len, sta->fils_snonce, fils_nonce,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002110 sta->fils_dh_ss ?
2111 wpabuf_head(sta->fils_dh_ss) : NULL,
2112 sta->fils_dh_ss ?
2113 wpabuf_len(sta->fils_dh_ss) : 0,
2114 pmk_buf, &pmk_len)) {
Paul Stewart092955c2017-02-06 09:13:09 -08002115 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002116 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Paul Stewart092955c2017-02-06 09:13:09 -08002117 wpabuf_free(data);
2118 data = NULL;
2119 goto fail;
2120 }
2121 pmk = pmk_buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002122
2123 /* Don't use DHss in PTK derivation if PMKSA caching is not
2124 * used. */
2125 wpabuf_clear_free(sta->fils_dh_ss);
2126 sta->fils_dh_ss = NULL;
2127
2128 if (sta->fils_erp_pmkid_set) {
2129 /* TODO: get PMKLifetime from WPA parameters */
2130 unsigned int dot11RSNAConfigPMKLifetime = 43200;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002131 int session_timeout;
2132
2133 session_timeout = dot11RSNAConfigPMKLifetime;
2134 if (sta->session_timeout_set) {
2135 struct os_reltime now, diff;
2136
2137 os_get_reltime(&now);
2138 os_reltime_sub(&sta->session_timeout, &now,
2139 &diff);
2140 session_timeout = diff.sec;
2141 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002142
2143 sta->fils_erp_pmkid_set = 0;
Hai Shalom81f62d82019-07-22 12:10:00 -07002144 wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
2145 sta->fils_erp_pmkid);
Hai Shalom021b0b52019-04-10 11:17:58 -07002146 if (!hapd->conf->disable_pmksa_caching &&
2147 wpa_auth_pmksa_add2(
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002148 hapd->wpa_auth, sta->addr,
2149 pmk, pmk_len,
2150 sta->fils_erp_pmkid,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002151 session_timeout,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002152 wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) {
2153 wpa_printf(MSG_ERROR,
2154 "FILS: Failed to add PMKSA cache entry based on ERP");
2155 }
2156 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002157 } else if (pmksa) {
2158 pmk = pmksa->pmk;
2159 pmk_len = pmksa->pmk_len;
2160 }
2161
2162 if (!pmk) {
2163 wpa_printf(MSG_DEBUG, "FILS: No PMK available");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002164 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002165 wpabuf_free(data);
2166 data = NULL;
2167 goto fail;
2168 }
2169
2170 if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002171 sta->fils_snonce, fils_nonce,
2172 sta->fils_dh_ss ?
2173 wpabuf_head(sta->fils_dh_ss) : NULL,
2174 sta->fils_dh_ss ?
2175 wpabuf_len(sta->fils_dh_ss) : 0,
2176 sta->fils_g_sta, pub) < 0) {
2177 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002178 wpabuf_free(data);
2179 data = NULL;
2180 goto fail;
2181 }
2182
2183fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002184 if (is_pub)
2185 *is_pub = pub != NULL;
2186 os_free(ie_buf);
2187 wpabuf_free(pub);
2188 wpabuf_clear_free(sta->fils_dh_ss);
2189 sta->fils_dh_ss = NULL;
2190#ifdef CONFIG_FILS_SK_PFS
2191 crypto_ecdh_deinit(sta->fils_ecdh);
2192 sta->fils_ecdh = NULL;
2193#endif /* CONFIG_FILS_SK_PFS */
2194 return data;
2195}
2196
2197
2198static void handle_auth_fils_finish(struct hostapd_data *hapd,
2199 struct sta_info *sta, u16 resp,
2200 struct wpabuf *data, int pub)
2201{
2202 u16 auth_alg;
2203
2204 auth_alg = (pub ||
2205 resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
2206 WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Hai Shalomfdcde762020-04-02 11:19:20 -07002207 send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002208 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07002209 data ? wpabuf_len(data) : 0, "auth-fils-finish");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002210 wpabuf_free(data);
2211
2212 if (resp == WLAN_STATUS_SUCCESS) {
2213 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2214 HOSTAPD_LEVEL_DEBUG,
2215 "authentication OK (FILS)");
2216 sta->flags |= WLAN_STA_AUTH;
2217 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002218 sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002219 mlme_authenticate_indication(hapd, sta);
2220 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002221}
2222
2223
2224void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
2225 struct sta_info *sta, int success,
2226 struct wpabuf *erp_resp,
2227 const u8 *msk, size_t msk_len)
2228{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002229 u16 resp;
Hai Shalom60840252021-02-19 19:02:11 -08002230 u32 flags = sta->flags;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002231
Hai Shalom60840252021-02-19 19:02:11 -08002232 sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
2233 WLAN_STA_PENDING_PASN_FILS_ERP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002234
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002235 resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
Hai Shalom60840252021-02-19 19:02:11 -08002236
2237 if (flags & WLAN_STA_PENDING_FILS_ERP) {
2238 struct wpabuf *data;
2239 int pub = 0;
2240
2241 if (!sta->fils_pending_cb)
2242 return;
2243
2244 data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
2245 msk, msk_len, &pub);
2246 if (!data) {
2247 wpa_printf(MSG_DEBUG,
2248 "%s: prepare_auth_resp_fils() failure",
2249 __func__);
2250 }
2251 sta->fils_pending_cb(hapd, sta, resp, data, pub);
2252#ifdef CONFIG_PASN
2253 } else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
2254 pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
2255 msk, msk_len);
2256#endif /* CONFIG_PASN */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002257 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002258}
2259
2260#endif /* CONFIG_FILS */
2261
2262
Hai Shalomfdcde762020-04-02 11:19:20 -07002263static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
2264 const u8 *msg, size_t len,
2265 struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002266{
2267 int res;
2268
Hai Shalomfdcde762020-04-02 11:19:20 -07002269 res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002270
2271 if (res == HOSTAPD_ACL_REJECT) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002272 wpa_printf(MSG_DEBUG, "Station " MACSTR
2273 " not allowed to authenticate",
2274 MAC2STR(addr));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002275 return HOSTAPD_ACL_REJECT;
2276 }
2277
2278 if (res == HOSTAPD_ACL_PENDING) {
2279 wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
2280 " waiting for an external authentication",
2281 MAC2STR(addr));
2282 /* Authentication code will re-send the authentication frame
2283 * after it has received (and cached) information from the
2284 * external source. */
2285 return HOSTAPD_ACL_PENDING;
2286 }
2287
2288 return res;
2289}
2290
2291
Sunil Ravia04bd252022-05-02 22:54:18 -07002292int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
2293 int res, struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002294{
Hai Shalomfdcde762020-04-02 11:19:20 -07002295 u32 session_timeout = info->session_timeout;
2296 u32 acct_interim_interval = info->acct_interim_interval;
2297 struct vlan_description *vlan_id = &info->vlan_id;
2298 struct hostapd_sta_wpa_psk_short *psk = info->psk;
2299 char *identity = info->identity;
2300 char *radius_cui = info->radius_cui;
2301
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002302 if (vlan_id->notempty &&
2303 !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
2304 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2305 HOSTAPD_LEVEL_INFO,
2306 "Invalid VLAN %d%s received from RADIUS server",
2307 vlan_id->untagged,
2308 vlan_id->tagged[0] ? "+" : "");
2309 return -1;
2310 }
2311 if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
2312 return -1;
2313 if (sta->vlan_id)
2314 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2315 HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
2316
2317 hostapd_free_psk_list(sta->psk);
Hai Shalomfdcde762020-04-02 11:19:20 -07002318 if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
2319 hostapd_copy_psk_list(&sta->psk, psk);
2320 else
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002321 sta->psk = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002322
Roshan Pius3a1667e2018-07-03 15:17:14 -07002323 os_free(sta->identity);
Hai Shalomfdcde762020-04-02 11:19:20 -07002324 if (identity)
2325 sta->identity = os_strdup(identity);
2326 else
2327 sta->identity = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002328
2329 os_free(sta->radius_cui);
Hai Shalomfdcde762020-04-02 11:19:20 -07002330 if (radius_cui)
2331 sta->radius_cui = os_strdup(radius_cui);
2332 else
2333 sta->radius_cui = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002334
2335 if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
2336 sta->acct_interim_interval = acct_interim_interval;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002337 if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
2338 sta->session_timeout_set = 1;
2339 os_get_reltime(&sta->session_timeout);
2340 sta->session_timeout.sec += session_timeout;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002341 ap_sta_session_timeout(hapd, sta, session_timeout);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002342 } else {
2343 sta->session_timeout_set = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002344 ap_sta_no_session_timeout(hapd, sta);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002345 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002346
2347 return 0;
2348}
2349
2350
Hai Shalom60840252021-02-19 19:02:11 -08002351#ifdef CONFIG_PASN
Hai Shalom60840252021-02-19 19:02:11 -08002352#ifdef CONFIG_FILS
2353
Hai Shalom60840252021-02-19 19:02:11 -08002354static void pasn_fils_auth_resp(struct hostapd_data *hapd,
2355 struct sta_info *sta, u16 status,
2356 struct wpabuf *erp_resp,
2357 const u8 *msk, size_t msk_len)
2358{
2359 struct pasn_data *pasn = sta->pasn;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002360 struct pasn_fils *fils = &pasn->fils;
Hai Shalom60840252021-02-19 19:02:11 -08002361 u8 pmk[PMK_LEN_MAX];
2362 size_t pmk_len;
2363 int ret;
2364
2365 wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
2366 status);
2367
2368 if (status != WLAN_STATUS_SUCCESS)
2369 goto fail;
2370
2371 if (!pasn->secret) {
2372 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
2373 goto fail;
2374 }
2375
2376 if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
2377 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
2378 goto fail;
2379 }
2380
2381 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
2382 fils->anonce, FILS_NONCE_LEN);
2383
2384 ret = fils_rmsk_to_pmk(pasn->akmp, msk, msk_len, fils->nonce,
2385 fils->anonce, NULL, 0, pmk, &pmk_len);
2386 if (ret) {
2387 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
2388 goto fail;
2389 }
2390
2391 ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
2392 wpabuf_head(pasn->secret),
2393 wpabuf_len(pasn->secret),
2394 &sta->pasn->ptk, sta->pasn->akmp,
Hai Shaloma20dcd72022-02-04 13:43:00 -08002395 sta->pasn->cipher, sta->pasn->kdk_len);
Hai Shalom60840252021-02-19 19:02:11 -08002396 if (ret) {
2397 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
2398 goto fail;
2399 }
2400
Sunil Ravi89eba102022-09-13 21:04:37 -07002401 if (pasn->secure_ltf) {
2402 ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp, pasn->cipher);
2403 if (ret) {
2404 wpa_printf(MSG_DEBUG,
2405 "PASN: FILS: Failed to derive LTF keyseed");
2406 goto fail;
2407 }
2408 }
2409
Hai Shalom60840252021-02-19 19:02:11 -08002410 wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
2411
2412 wpabuf_free(pasn->secret);
2413 pasn->secret = NULL;
2414
2415 fils->erp_resp = erp_resp;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002416 ret = handle_auth_pasn_resp(sta->pasn, hapd->own_addr, sta->addr, NULL,
2417 WLAN_STATUS_SUCCESS);
Hai Shalom60840252021-02-19 19:02:11 -08002418 fils->erp_resp = NULL;
2419
2420 if (ret) {
2421 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
2422 goto fail;
2423 }
2424
2425 fils->state = PASN_FILS_STATE_COMPLETE;
2426 return;
2427fail:
2428 ap_free_sta(hapd, sta);
2429}
2430
2431
2432static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
2433 struct wpabuf *wd)
2434{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002435#ifdef CONFIG_NO_RADIUS
2436 wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
2437 return -1;
2438#else /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002439 struct pasn_data *pasn = sta->pasn;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002440 struct pasn_fils *fils = &pasn->fils;
Hai Shalom60840252021-02-19 19:02:11 -08002441 struct ieee802_11_elems elems;
2442 struct wpa_ie_data rsne_data;
2443 struct wpabuf *fils_wd;
2444 const u8 *data;
2445 size_t buf_len;
2446 u16 alg, seq, status;
2447 int ret;
2448
2449 if (fils->state != PASN_FILS_STATE_NONE) {
2450 wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
2451 return -1;
2452 }
2453
2454 if (!wd) {
2455 wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
2456 return -1;
2457 }
2458
2459 data = wpabuf_head_u8(wd);
2460 buf_len = wpabuf_len(wd);
2461
2462 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002463 wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002464 buf_len);
2465 return -1;
2466 }
2467
2468 alg = WPA_GET_LE16(data);
2469 seq = WPA_GET_LE16(data + 2);
2470 status = WPA_GET_LE16(data + 4);
2471
2472 wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
2473 alg, seq, status);
2474
2475 if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
2476 status != WLAN_STATUS_SUCCESS) {
2477 wpa_printf(MSG_DEBUG,
2478 "PASN: FILS: Dropping peer authentication");
2479 return -1;
2480 }
2481
2482 data += 6;
2483 buf_len -= 6;
2484
2485 if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
2486 wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
2487 return -1;
2488 }
2489
2490 if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00002491 !elems.wrapped_data || !elems.fils_session) {
Hai Shalom60840252021-02-19 19:02:11 -08002492 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
2493 return -1;
2494 }
2495
2496 ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2497 &rsne_data);
2498 if (ret) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002499 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RSNE");
Hai Shalom60840252021-02-19 19:02:11 -08002500 return -1;
2501 }
2502
2503 ret = wpa_pasn_validate_rsne(&rsne_data);
2504 if (ret) {
2505 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
2506 return -1;
2507 }
2508
2509 if (rsne_data.num_pmkid) {
2510 wpa_printf(MSG_DEBUG,
2511 "PASN: FILS: Not expecting PMKID in RSNE");
2512 return -1;
2513 }
2514
2515 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
2516 FILS_NONCE_LEN);
2517 os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
2518
2519 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
2520 FILS_SESSION_LEN);
2521 os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
2522
Hai Shalom60840252021-02-19 19:02:11 -08002523 fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
2524 WLAN_EID_EXT_WRAPPED_DATA);
2525
2526 if (!fils_wd) {
2527 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
2528 return -1;
2529 }
2530
2531 if (!sta->eapol_sm)
2532 sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
2533
2534 wpa_printf(MSG_DEBUG,
2535 "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
2536
2537 ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
2538 wpabuf_len(fils_wd));
2539
2540 sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
2541
2542 fils->state = PASN_FILS_STATE_PENDING_AS;
2543
2544 /*
2545 * Calculate pending PMKID here so that we do not need to maintain a
2546 * copy of the EAP-Initiate/Reautt message.
2547 */
2548 fils_pmkid_erp(pasn->akmp, wpabuf_head(fils_wd), wpabuf_len(fils_wd),
2549 fils->erp_pmkid);
2550
2551 wpabuf_free(fils_wd);
2552 return 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002553#endif /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002554}
2555
2556#endif /* CONFIG_FILS */
2557
2558
Sunil Ravi77d572f2023-01-17 23:58:31 +00002559static int hapd_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len,
2560 int noack, unsigned int freq, unsigned int wait)
Hai Shalom60840252021-02-19 19:02:11 -08002561{
Sunil Ravi77d572f2023-01-17 23:58:31 +00002562 struct hostapd_data *hapd = ctx;
2563
2564 return hostapd_drv_send_mlme(hapd, data, data_len, 0, NULL, 0, 0);
2565}
2566
2567
2568static void hapd_initialize_pasn(struct hostapd_data *hapd,
2569 struct sta_info *sta)
2570{
2571 struct pasn_data *pasn = sta->pasn;
2572
2573 pasn->cb_ctx = hapd;
2574 pasn->send_mgmt = hapd_pasn_send_mlme;
2575 pasn->pasn_groups = hapd->conf->pasn_groups;
Sunil Ravi640215c2023-06-28 23:08:09 +00002576 pasn->noauth = hapd->conf->pasn_noauth;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002577 pasn->wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
2578 pasn->rsn_pairwise = hapd->conf->rsn_pairwise;
2579 pasn->derive_kdk = hapd->iface->drv_flags2 &
2580 WPA_DRIVER_FLAGS2_SEC_LTF_AP;
2581#ifdef CONFIG_TESTING_OPTIONS
2582 pasn->corrupt_mic = hapd->conf->pasn_corrupt_mic;
2583 if (hapd->conf->force_kdk_derivation)
2584 pasn->derive_kdk = true;
2585#endif /* CONFIG_TESTING_OPTIONS */
2586 pasn->use_anti_clogging = use_anti_clogging(hapd);
2587 pasn->password = sae_get_password(hapd, sta, NULL, NULL, &pasn->pt,
2588 NULL);
2589 pasn->rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &pasn->rsn_ie_len);
2590 pasn->rsnxe_ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
2591 pasn->disable_pmksa_caching = hapd->conf->disable_pmksa_caching;
2592 pasn->pmksa = wpa_auth_get_pmksa_cache(hapd->wpa_auth);
2593
2594 pasn->comeback_after = hapd->conf->pasn_comeback_after;
2595 pasn->comeback_idx = hapd->comeback_idx;
2596 pasn->comeback_key = hapd->comeback_key;
2597 pasn->comeback_pending_idx = hapd->comeback_pending_idx;
2598 os_memcpy(pasn->bssid, hapd->own_addr, ETH_ALEN);
Hai Shalom60840252021-02-19 19:02:11 -08002599}
2600
2601
Sunil Ravi89eba102022-09-13 21:04:37 -07002602static int pasn_set_keys_from_cache(struct hostapd_data *hapd,
2603 const u8 *own_addr, const u8 *sta_addr,
2604 int cipher, int akmp)
2605{
2606 struct ptksa_cache_entry *entry;
2607
2608 entry = ptksa_cache_get(hapd->ptksa, sta_addr, cipher);
2609 if (!entry) {
2610 wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR
2611 " not present in PTKSA cache", MAC2STR(sta_addr));
2612 return -1;
2613 }
2614
2615 if (os_memcmp(entry->own_addr, own_addr, ETH_ALEN) != 0) {
2616 wpa_printf(MSG_DEBUG,
2617 "PASN: own addr " MACSTR " and PTKSA entry own addr "
2618 MACSTR " differ",
2619 MAC2STR(own_addr), MAC2STR(entry->own_addr));
2620 return -1;
2621 }
2622
2623 wpa_printf(MSG_DEBUG, "PASN: " MACSTR " present in PTKSA cache",
2624 MAC2STR(sta_addr));
2625 hostapd_drv_set_secure_ranging_ctx(hapd, own_addr, sta_addr, cipher,
2626 entry->ptk.tk_len, entry->ptk.tk,
2627 entry->ptk.ltf_keyseed_len,
2628 entry->ptk.ltf_keyseed, 0);
2629
2630 return 0;
2631}
2632
2633
Sunil Ravi77d572f2023-01-17 23:58:31 +00002634static void hapd_pasn_update_params(struct hostapd_data *hapd,
2635 struct sta_info *sta,
2636 const struct ieee80211_mgmt *mgmt,
2637 size_t len)
Hai Shalom60840252021-02-19 19:02:11 -08002638{
Sunil Ravi77d572f2023-01-17 23:58:31 +00002639 struct pasn_data *pasn = sta->pasn;
Hai Shalom60840252021-02-19 19:02:11 -08002640 struct ieee802_11_elems elems;
2641 struct wpa_ie_data rsn_data;
2642 struct wpa_pasn_params_data pasn_params;
Hai Shalom60840252021-02-19 19:02:11 -08002643 struct wpabuf *wrapped_data = NULL;
Hai Shalom60840252021-02-19 19:02:11 -08002644
2645 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
2646 len - offsetof(struct ieee80211_mgmt,
2647 u.auth.variable),
2648 &elems, 0) == ParseFailed) {
2649 wpa_printf(MSG_DEBUG,
2650 "PASN: Failed parsing Authentication frame");
Sunil Ravi77d572f2023-01-17 23:58:31 +00002651 return;
Hai Shalom60840252021-02-19 19:02:11 -08002652 }
2653
Sunil Ravi77d572f2023-01-17 23:58:31 +00002654 if (!elems.rsn_ie ||
2655 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2656 &rsn_data)) {
2657 wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE");
2658 return;
2659 }
2660
2661 if (!(rsn_data.key_mgmt & pasn->wpa_key_mgmt) ||
2662 !(rsn_data.pairwise_cipher & pasn->rsn_pairwise)) {
2663 wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
2664 return;
2665 }
2666
2667 pasn->akmp = rsn_data.key_mgmt;
2668 pasn->cipher = rsn_data.pairwise_cipher;
2669
2670 if (wpa_key_mgmt_ft(pasn->akmp) && rsn_data.num_pmkid) {
2671#ifdef CONFIG_IEEE80211R_AP
2672 pasn->pmk_r1_len = 0;
2673 wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
2674 rsn_data.pmkid,
2675 pasn->pmk_r1, &pasn->pmk_r1_len, NULL,
2676 NULL, NULL, NULL,
2677 NULL, NULL, NULL);
2678#endif /* CONFIG_IEEE80211R_AP */
2679 }
2680#ifdef CONFIG_FILS
2681 if (pasn->akmp != WPA_KEY_MGMT_FILS_SHA256 &&
2682 pasn->akmp != WPA_KEY_MGMT_FILS_SHA384)
2683 return;
2684 if (!elems.pasn_params ||
2685 wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
2686 elems.pasn_params_len + 3,
2687 false, &pasn_params)) {
Hai Shalom60840252021-02-19 19:02:11 -08002688 wpa_printf(MSG_DEBUG,
Sunil Ravi77d572f2023-01-17 23:58:31 +00002689 "PASN: Failed validation of PASN Parameters element");
2690 return;
Hai Shalom60840252021-02-19 19:02:11 -08002691 }
Hai Shalom60840252021-02-19 19:02:11 -08002692 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002693 wrapped_data = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
Hai Shalom60840252021-02-19 19:02:11 -08002694 WLAN_EID_EXT_WRAPPED_DATA);
Hai Shalom60840252021-02-19 19:02:11 -08002695 if (!wrapped_data) {
2696 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
Sunil Ravi77d572f2023-01-17 23:58:31 +00002697 return;
Hai Shalom60840252021-02-19 19:02:11 -08002698 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00002699 if (pasn_wd_handle_fils(hapd, sta, wrapped_data))
2700 wpa_printf(MSG_DEBUG,
2701 "PASN: Failed processing FILS wrapped data");
2702 else
2703 pasn->fils_wd_valid = true;
Hai Shalom60840252021-02-19 19:02:11 -08002704 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00002705 wpabuf_free(wrapped_data);
2706#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08002707}
2708
2709
2710static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
2711 const struct ieee80211_mgmt *mgmt, size_t len,
2712 u16 trans_seq, u16 status)
2713{
2714 if (hapd->conf->wpa != WPA_PROTO_RSN) {
2715 wpa_printf(MSG_INFO, "PASN: RSN is not configured");
2716 return;
2717 }
2718
2719 wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR,
2720 MAC2STR(sta->addr));
2721
2722 if (trans_seq == 1) {
2723 if (sta->pasn) {
2724 wpa_printf(MSG_DEBUG,
2725 "PASN: Not expecting transaction == 1");
2726 return;
2727 }
2728
2729 if (status != WLAN_STATUS_SUCCESS) {
2730 wpa_printf(MSG_DEBUG,
2731 "PASN: Failure status in transaction == 1");
2732 return;
2733 }
2734
2735 sta->pasn = os_zalloc(sizeof(*sta->pasn));
2736 if (!sta->pasn) {
2737 wpa_printf(MSG_DEBUG,
2738 "PASN: Failed to allocate PASN context");
2739 return;
2740 }
2741
Sunil Ravi77d572f2023-01-17 23:58:31 +00002742 hapd_initialize_pasn(hapd, sta);
2743
2744 hapd_pasn_update_params(hapd, sta, mgmt, len);
2745 if (handle_auth_pasn_1(sta->pasn, hapd->own_addr,
2746 sta->addr, mgmt, len) < 0)
2747 ap_free_sta(hapd, sta);
Hai Shalom60840252021-02-19 19:02:11 -08002748 } else if (trans_seq == 3) {
2749 if (!sta->pasn) {
2750 wpa_printf(MSG_DEBUG,
2751 "PASN: Not expecting transaction == 3");
2752 return;
2753 }
2754
2755 if (status != WLAN_STATUS_SUCCESS) {
2756 wpa_printf(MSG_DEBUG,
2757 "PASN: Failure status in transaction == 3");
2758 ap_free_sta_pasn(hapd, sta);
2759 return;
2760 }
2761
Sunil Ravi77d572f2023-01-17 23:58:31 +00002762 if (handle_auth_pasn_3(sta->pasn, hapd->own_addr,
2763 sta->addr, mgmt, len) == 0) {
2764 ptksa_cache_add(hapd->ptksa, hapd->own_addr, sta->addr,
2765 sta->pasn->cipher, 43200,
2766 &sta->pasn->ptk, NULL, NULL,
2767 sta->pasn->akmp);
2768
2769 pasn_set_keys_from_cache(hapd, hapd->own_addr,
2770 sta->addr, sta->pasn->cipher,
2771 sta->pasn->akmp);
2772 }
2773 ap_free_sta(hapd, sta);
Hai Shalom60840252021-02-19 19:02:11 -08002774 } else {
2775 wpa_printf(MSG_DEBUG,
2776 "PASN: Invalid transaction %u - ignore", trans_seq);
2777 }
2778}
2779
2780#endif /* CONFIG_PASN */
2781
2782
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002783static void handle_auth(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08002784 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom021b0b52019-04-10 11:17:58 -07002785 int rssi, int from_queue)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002786{
2787 u16 auth_alg, auth_transaction, status_code;
2788 u16 resp = WLAN_STATUS_SUCCESS;
2789 struct sta_info *sta = NULL;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002790 int res, reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002791 u16 fc;
2792 const u8 *challenge = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002793 u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
2794 size_t resp_ies_len = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002795 u16 seq_ctrl;
Hai Shalomfdcde762020-04-02 11:19:20 -07002796 struct radius_sta rad_info;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002797 const u8 *dst, *sa, *bssid;
2798 bool mld_sta = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002799
2800 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002801 wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
2802 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002803 return;
2804 }
2805
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002806#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002807 if (hapd->iconf->ignore_auth_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002808 drand48() < hapd->iconf->ignore_auth_probability) {
2809 wpa_printf(MSG_INFO,
2810 "TESTING: ignoring auth frame from " MACSTR,
2811 MAC2STR(mgmt->sa));
2812 return;
2813 }
2814#endif /* CONFIG_TESTING_OPTIONS */
2815
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002816 sa = mgmt->sa;
2817#ifdef CONFIG_IEEE80211BE
2818 /*
2819 * Handle MLO authentication before the station is added to hostapd and
2820 * the driver so that the station MLD MAC address would be used in both
2821 * hostapd and the driver.
2822 */
2823 sa = hostapd_process_ml_auth(hapd, mgmt, len);
2824 if (sa)
2825 mld_sta = true;
2826 else
2827 sa = mgmt->sa;
2828#endif /* CONFIG_IEEE80211BE */
2829
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002830 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
2831 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
2832 status_code = le_to_host16(mgmt->u.auth.status_code);
2833 fc = le_to_host16(mgmt->frame_control);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002834 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002835
2836 if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
2837 2 + WLAN_AUTH_CHALLENGE_LEN &&
2838 mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
2839 mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
2840 challenge = &mgmt->u.auth.variable[2];
2841
2842 wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002843 "auth_transaction=%d status_code=%d wep=%d%s "
Hai Shalom021b0b52019-04-10 11:17:58 -07002844 "seq_ctrl=0x%x%s%s",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002845 MAC2STR(sa), auth_alg, auth_transaction,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002846 status_code, !!(fc & WLAN_FC_ISWEP),
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002847 challenge ? " challenge" : "",
Hai Shalom021b0b52019-04-10 11:17:58 -07002848 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
2849 from_queue ? " (from queue)" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002850
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002851#ifdef CONFIG_NO_RC4
2852 if (auth_alg == WLAN_AUTH_SHARED_KEY) {
2853 wpa_printf(MSG_INFO,
2854 "Unsupported authentication algorithm (%d)",
2855 auth_alg);
2856 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
2857 goto fail;
2858 }
2859#endif /* CONFIG_NO_RC4 */
2860
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002861 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002862 wpa_printf(MSG_DEBUG,
2863 "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
2864 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002865 goto fail;
2866 }
2867
2868 if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
2869 auth_alg == WLAN_AUTH_OPEN) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002870#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002871 (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002872 auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002873#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002874#ifdef CONFIG_SAE
2875 (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
2876 auth_alg == WLAN_AUTH_SAE) ||
2877#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002878#ifdef CONFIG_FILS
2879 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
2880 auth_alg == WLAN_AUTH_FILS_SK) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002881 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
2882 hapd->conf->fils_dh_group &&
2883 auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002884#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08002885#ifdef CONFIG_PASN
2886 (hapd->conf->wpa &&
2887 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) &&
2888 auth_alg == WLAN_AUTH_PASN) ||
2889#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002890 ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
2891 auth_alg == WLAN_AUTH_SHARED_KEY))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002892 wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
2893 auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002894 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
2895 goto fail;
2896 }
2897
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002898 if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
Hai Shalom60840252021-02-19 19:02:11 -08002899#ifdef CONFIG_PASN
2900 (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) ||
2901#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002902 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002903 wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
2904 auth_transaction);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002905 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
2906 goto fail;
2907 }
2908
2909 if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002910 wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002911 MAC2STR(sa));
2912 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2913 goto fail;
2914 }
2915
2916 if (mld_sta &&
2917 (os_memcmp(sa, hapd->own_addr, ETH_ALEN) == 0 ||
2918 os_memcmp(sa, hapd->mld_addr, ETH_ALEN) == 0)) {
2919 wpa_printf(MSG_INFO,
2920 "Station " MACSTR " not allowed to authenticate",
2921 MAC2STR(sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002922 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2923 goto fail;
2924 }
2925
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002926 if (hapd->conf->no_auth_if_seen_on) {
2927 struct hostapd_data *other;
2928
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002929 other = sta_track_seen_on(hapd->iface, sa,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002930 hapd->conf->no_auth_if_seen_on);
2931 if (other) {
2932 u8 *pos;
2933 u32 info;
2934 u8 op_class, channel, phytype;
2935
2936 wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
2937 MACSTR " since STA has been seen on %s",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002938 hapd->conf->iface, MAC2STR(sa),
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002939 hapd->conf->no_auth_if_seen_on);
2940
2941 resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
2942 pos = &resp_ies[0];
2943 *pos++ = WLAN_EID_NEIGHBOR_REPORT;
2944 *pos++ = 13;
2945 os_memcpy(pos, other->own_addr, ETH_ALEN);
2946 pos += ETH_ALEN;
2947 info = 0; /* TODO: BSSID Information */
2948 WPA_PUT_LE32(pos, info);
2949 pos += 4;
2950 if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
2951 phytype = 8; /* dmg */
2952 else if (other->iconf->ieee80211ac)
2953 phytype = 9; /* vht */
2954 else if (other->iconf->ieee80211n)
2955 phytype = 7; /* ht */
2956 else if (other->iconf->hw_mode ==
2957 HOSTAPD_MODE_IEEE80211A)
2958 phytype = 4; /* ofdm */
2959 else if (other->iconf->hw_mode ==
2960 HOSTAPD_MODE_IEEE80211G)
2961 phytype = 6; /* erp */
2962 else
2963 phytype = 5; /* hrdsss */
2964 if (ieee80211_freq_to_channel_ext(
2965 hostapd_hw_get_freq(other,
2966 other->iconf->channel),
2967 other->iconf->secondary_channel,
2968 other->iconf->ieee80211ac,
2969 &op_class, &channel) == NUM_HOSTAPD_MODES) {
2970 op_class = 0;
2971 channel = other->iconf->channel;
2972 }
2973 *pos++ = op_class;
2974 *pos++ = channel;
2975 *pos++ = phytype;
2976 resp_ies_len = pos - &resp_ies[0];
2977 goto fail;
2978 }
2979 }
2980
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002981 res = ieee802_11_allowed_address(hapd, sa, (const u8 *) mgmt, len,
Hai Shalomfdcde762020-04-02 11:19:20 -07002982 &rad_info);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002983 if (res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002984 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
2985 "Ignore Authentication frame from " MACSTR
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002986 " due to ACL reject", MAC2STR(sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002987 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2988 goto fail;
2989 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002990 if (res == HOSTAPD_ACL_PENDING)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002991 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002992
Hai Shalom021b0b52019-04-10 11:17:58 -07002993#ifdef CONFIG_SAE
2994 if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
2995 (auth_transaction == 1 ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002996 (auth_transaction == 2 && auth_sae_queued_addr(hapd, sa)))) {
Hai Shalom021b0b52019-04-10 11:17:58 -07002997 /* Handle SAE Authentication commit message through a queue to
2998 * provide more control for postponing the needed heavy
2999 * processing under a possible DoS attack scenario. In addition,
3000 * queue SAE Authentication confirm message if there happens to
3001 * be a queued commit message from the same peer. This is needed
3002 * to avoid reordering Authentication frames within the same
3003 * SAE exchange. */
3004 auth_sae_queue(hapd, mgmt, len, rssi);
3005 return;
3006 }
3007#endif /* CONFIG_SAE */
3008
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003009 sta = ap_get_sta(hapd, sa);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003010 if (sta) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003011 sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
Hai Shalom74f70d42019-02-11 14:42:39 -08003012 sta->ft_over_ds = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003013 if ((fc & WLAN_FC_RETRY) &&
3014 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
3015 sta->last_seq_ctrl == seq_ctrl &&
3016 sta->last_subtype == WLAN_FC_STYPE_AUTH) {
3017 hostapd_logger(hapd, sta->addr,
3018 HOSTAPD_MODULE_IEEE80211,
3019 HOSTAPD_LEVEL_DEBUG,
3020 "Drop repeated authentication frame seq_ctrl=0x%x",
3021 seq_ctrl);
3022 return;
3023 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003024#ifdef CONFIG_MESH
3025 if ((hapd->conf->mesh & MESH_ENABLED) &&
3026 sta->plink_state == PLINK_BLOCKED) {
3027 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
3028 " is blocked - drop Authentication frame",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003029 MAC2STR(sa));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003030 return;
3031 }
3032#endif /* CONFIG_MESH */
Hai Shalom60840252021-02-19 19:02:11 -08003033#ifdef CONFIG_PASN
3034 if (auth_alg == WLAN_AUTH_PASN &&
3035 (sta->flags & WLAN_STA_ASSOC)) {
3036 wpa_printf(MSG_DEBUG,
3037 "PASN: auth: Existing station: " MACSTR,
3038 MAC2STR(sta->addr));
3039 return;
3040 }
3041#endif /* CONFIG_PASN */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003042 } else {
3043#ifdef CONFIG_MESH
3044 if (hapd->conf->mesh & MESH_ENABLED) {
3045 /* if the mesh peer is not available, we don't do auth.
3046 */
3047 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003048 " not yet known - drop Authentication frame",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003049 MAC2STR(sa));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003050 /*
3051 * Save a copy of the frame so that it can be processed
3052 * if a new peer entry is added shortly after this.
3053 */
3054 wpabuf_free(hapd->mesh_pending_auth);
3055 hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len);
3056 os_get_reltime(&hapd->mesh_pending_auth_time);
3057 return;
3058 }
3059#endif /* CONFIG_MESH */
3060
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003061 sta = ap_sta_add(hapd, sa);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003062 if (!sta) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003063 wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003064 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3065 goto fail;
3066 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003067 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003068
3069#ifdef CONFIG_IEEE80211BE
3070 if (auth_transaction == 1) {
3071 os_memset(&sta->mld_info, 0, sizeof(sta->mld_info));
3072
3073 if (mld_sta) {
3074 u8 link_id = hapd->mld_link_id;
3075
3076 sta->mld_info.mld_sta = true;
3077 sta->mld_assoc_link_id = link_id;
3078
3079 /*
3080 * Set the MLD address as the station address and the
3081 * station addresses.
3082 */
3083 os_memcpy(sta->mld_info.common_info.mld_addr, sa,
3084 ETH_ALEN);
3085 os_memcpy(sta->mld_info.links[link_id].peer_addr,
3086 mgmt->sa, ETH_ALEN);
3087 os_memcpy(sta->mld_info.links[link_id].local_addr,
3088 hapd->own_addr, ETH_ALEN);
3089 }
3090 }
3091#endif /* CONFIG_IEEE80211BE */
3092
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003093 sta->last_seq_ctrl = seq_ctrl;
3094 sta->last_subtype = WLAN_FC_STYPE_AUTH;
Hai Shalom74f70d42019-02-11 14:42:39 -08003095#ifdef CONFIG_MBO
3096 sta->auth_rssi = rssi;
3097#endif /* CONFIG_MBO */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003098
Hai Shalomfdcde762020-04-02 11:19:20 -07003099 res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003100 if (res) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003101 wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003102 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3103 goto fail;
3104 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003105
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003106 sta->flags &= ~WLAN_STA_PREAUTH;
3107 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
3108
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003109 /*
3110 * If the driver supports full AP client state, add a station to the
3111 * driver before sending authentication reply to make sure the driver
3112 * has resources, and not to go through the entire authentication and
3113 * association handshake, and fail it at the end.
3114 *
3115 * If this is not the first transaction, in a multi-step authentication
3116 * algorithm, the station already exists in the driver
3117 * (sta->added_unassoc = 1) so skip it.
3118 *
3119 * In mesh mode, the station was already added to the driver when the
3120 * NEW_PEER_CANDIDATE event is received.
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003121 *
3122 * If PMF was negotiated for the existing association, skip this to
3123 * avoid dropping the STA entry and the associated keys. This is needed
3124 * to allow the original connection work until the attempt can complete
3125 * (re)association, so that unprotected Authentication frame cannot be
3126 * used to bypass PMF protection.
Hai Shalom60840252021-02-19 19:02:11 -08003127 *
3128 * PASN authentication does not require adding/removing station to the
3129 * driver so skip this flow in case of PASN authentication.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003130 */
3131 if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003132 (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003133 !(hapd->conf->mesh & MESH_ENABLED) &&
Hai Shalom60840252021-02-19 19:02:11 -08003134 !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) {
Hai Shalomb755a2a2020-04-23 21:49:02 -07003135 if (ap_sta_re_add(hapd, sta) < 0) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003136 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3137 goto fail;
3138 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003139 }
3140
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003141 switch (auth_alg) {
3142 case WLAN_AUTH_OPEN:
3143 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3144 HOSTAPD_LEVEL_DEBUG,
3145 "authentication OK (open system)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003146 sta->flags |= WLAN_STA_AUTH;
3147 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
3148 sta->auth_alg = WLAN_AUTH_OPEN;
3149 mlme_authenticate_indication(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003150 break;
Hai Shalomfdcde762020-04-02 11:19:20 -07003151#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003152#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003153 case WLAN_AUTH_SHARED_KEY:
3154 resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
3155 fc & WLAN_FC_ISWEP);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003156 if (resp != 0)
3157 wpa_printf(MSG_DEBUG,
3158 "auth_shared_key() failed: status=%d", resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003159 sta->auth_alg = WLAN_AUTH_SHARED_KEY;
3160 mlme_authenticate_indication(hapd, sta);
3161 if (sta->challenge && auth_transaction == 1) {
3162 resp_ies[0] = WLAN_EID_CHALLENGE;
3163 resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
3164 os_memcpy(resp_ies + 2, sta->challenge,
3165 WLAN_AUTH_CHALLENGE_LEN);
3166 resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
3167 }
3168 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003169#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003170#endif /* CONFIG_WEP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003171#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003172 case WLAN_AUTH_FT:
3173 sta->auth_alg = WLAN_AUTH_FT;
3174 if (sta->wpa_sm == NULL)
3175 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003176 sta->addr, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003177 if (sta->wpa_sm == NULL) {
3178 wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
3179 "state machine");
3180 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3181 goto fail;
3182 }
3183 wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
3184 auth_transaction, mgmt->u.auth.variable,
3185 len - IEEE80211_HDRLEN -
3186 sizeof(mgmt->u.auth),
3187 handle_auth_ft_finish, hapd);
3188 /* handle_auth_ft_finish() callback will complete auth. */
3189 return;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003190#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003191#ifdef CONFIG_SAE
3192 case WLAN_AUTH_SAE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003193#ifdef CONFIG_MESH
3194 if (status_code == WLAN_STATUS_SUCCESS &&
3195 hapd->conf->mesh & MESH_ENABLED) {
3196 if (sta->wpa_sm == NULL)
3197 sta->wpa_sm =
3198 wpa_auth_sta_init(hapd->wpa_auth,
3199 sta->addr, NULL);
3200 if (sta->wpa_sm == NULL) {
3201 wpa_printf(MSG_DEBUG,
3202 "SAE: Failed to initialize WPA state machine");
3203 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3204 goto fail;
3205 }
3206 }
3207#endif /* CONFIG_MESH */
3208 handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
3209 status_code);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003210 return;
3211#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003212#ifdef CONFIG_FILS
3213 case WLAN_AUTH_FILS_SK:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003214 case WLAN_AUTH_FILS_SK_PFS:
3215 handle_auth_fils(hapd, sta, mgmt->u.auth.variable,
3216 len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth),
3217 auth_alg, auth_transaction, status_code,
3218 handle_auth_fils_finish);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003219 return;
3220#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08003221#ifdef CONFIG_PASN
3222 case WLAN_AUTH_PASN:
3223 handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction,
3224 status_code);
3225 return;
3226#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003227 }
3228
3229 fail:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003230 dst = mgmt->sa;
3231 bssid = mgmt->bssid;
3232
3233#ifdef CONFIG_IEEE80211BE
3234 /*
3235 * Once a non-AP MLD is added to the driver, the addressing should use
3236 * the MLD MAC address. It is the responsibility of the driver to
3237 * handle the translations.
3238 */
3239 if (hapd->conf->mld_ap && sta && sta->mld_info.mld_sta) {
3240 dst = sta->addr;
3241 bssid = hapd->mld_addr;
3242 }
3243#endif /* CONFIG_IEEE80211BE */
3244
3245 reply_res = send_auth_reply(hapd, sta, dst, bssid, auth_alg,
Hai Shaloma20dcd72022-02-04 13:43:00 -08003246 auth_alg == WLAN_AUTH_SAE ?
3247 auth_transaction : auth_transaction + 1,
3248 resp, resp_ies, resp_ies_len,
3249 "handle-auth");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003250
3251 if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
3252 reply_res != WLAN_STATUS_SUCCESS)) {
3253 hostapd_drv_sta_remove(hapd, sta->addr);
3254 sta->added_unassoc = 0;
3255 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003256}
3257
3258
Sunil Ravi77d572f2023-01-17 23:58:31 +00003259static u8 hostapd_max_bssid_indicator(struct hostapd_data *hapd)
3260{
3261 size_t num_bss_nontx;
3262 u8 max_bssid_ind = 0;
3263
3264 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1)
3265 return 0;
3266
3267 num_bss_nontx = hapd->iface->num_bss - 1;
3268 while (num_bss_nontx > 0) {
3269 max_bssid_ind++;
3270 num_bss_nontx >>= 1;
3271 }
3272 return max_bssid_ind;
3273}
3274
3275
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003276static u32 hostapd_get_aid_word(struct hostapd_data *hapd,
3277 struct sta_info *sta, int i)
3278{
3279#ifdef CONFIG_IEEE80211BE
3280 u32 aid_word = 0;
3281
3282 /* Do not assign an AID that is in use on any of the affiliated links
3283 * when finding an AID for a non-AP MLD. */
3284 if (hapd->conf->mld_ap) {
3285 int j;
3286
3287 for (j = 0; j < MAX_NUM_MLD_LINKS; j++) {
3288 struct hostapd_data *link_bss;
3289
3290 if (!sta->mld_info.links[j].valid)
3291 continue;
3292
3293 link_bss = hostapd_mld_get_link_bss(hapd, j);
3294 if (!link_bss) {
3295 /* This shouldn't happen, just skip */
3296 wpa_printf(MSG_ERROR,
3297 "MLD: Failed to get link BSS for AID");
3298 continue;
3299 }
3300
3301 aid_word |= link_bss->sta_aid[i];
3302 }
3303
3304 return aid_word;
3305 }
3306#endif /* CONFIG_IEEE80211BE */
3307
3308 return hapd->sta_aid[i];
3309}
3310
3311
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003312int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003313{
3314 int i, j = 32, aid;
3315
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003316 /* Transmitted and non-transmitted BSSIDs share the same AID pool, so
3317 * use the shared storage in the transmitted BSS to find the next
3318 * available value. */
3319 hapd = hostapd_mbssid_get_tx_bss(hapd);
3320
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003321 /* get a unique AID */
3322 if (sta->aid > 0) {
3323 wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
3324 return 0;
3325 }
3326
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003327 if (TEST_FAIL())
3328 return -1;
3329
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003330 for (i = 0; i < AID_WORDS; i++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003331 u32 aid_word = hostapd_get_aid_word(hapd, sta, i);
3332
3333 if (aid_word == (u32) -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003334 continue;
3335 for (j = 0; j < 32; j++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003336 if (!(aid_word & BIT(j)))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003337 break;
3338 }
3339 if (j < 32)
3340 break;
3341 }
3342 if (j == 32)
3343 return -1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003344 aid = i * 32 + j + (1 << hostapd_max_bssid_indicator(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003345 if (aid > 2007)
3346 return -1;
3347
3348 sta->aid = aid;
3349 hapd->sta_aid[i] |= BIT(j);
3350 wpa_printf(MSG_DEBUG, " new AID %d", sta->aid);
3351 return 0;
3352}
3353
3354
3355static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
3356 const u8 *ssid_ie, size_t ssid_ie_len)
3357{
3358 if (ssid_ie == NULL)
3359 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3360
3361 if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
3362 os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003363 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3364 HOSTAPD_LEVEL_INFO,
3365 "Station tried to associate with unknown SSID "
Dmitry Shmidt3c479372014-02-04 10:50:36 -08003366 "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003367 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3368 }
3369
3370 return WLAN_STATUS_SUCCESS;
3371}
3372
3373
3374static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
3375 const u8 *wmm_ie, size_t wmm_ie_len)
3376{
3377 sta->flags &= ~WLAN_STA_WMM;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003378 sta->qosinfo = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003379 if (wmm_ie && hapd->conf->wmm_enabled) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003380 struct wmm_information_element *wmm;
3381
3382 if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003383 hostapd_logger(hapd, sta->addr,
3384 HOSTAPD_MODULE_WPA,
3385 HOSTAPD_LEVEL_DEBUG,
3386 "invalid WMM element in association "
3387 "request");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003388 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3389 }
3390
3391 sta->flags |= WLAN_STA_WMM;
3392 wmm = (struct wmm_information_element *) wmm_ie;
3393 sta->qosinfo = wmm->qos_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003394 }
3395 return WLAN_STATUS_SUCCESS;
3396}
3397
Hai Shalom74f70d42019-02-11 14:42:39 -08003398static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
3399 const u8 *multi_ap_ie, size_t multi_ap_len)
3400{
3401 u8 multi_ap_value = 0;
3402
3403 sta->flags &= ~WLAN_STA_MULTI_AP;
3404
3405 if (!hapd->conf->multi_ap)
3406 return WLAN_STATUS_SUCCESS;
3407
3408 if (multi_ap_ie) {
3409 const u8 *multi_ap_subelem;
3410
3411 multi_ap_subelem = get_ie(multi_ap_ie + 4,
3412 multi_ap_len - 4,
3413 MULTI_AP_SUB_ELEM_TYPE);
3414 if (multi_ap_subelem && multi_ap_subelem[1] == 1) {
3415 multi_ap_value = multi_ap_subelem[2];
3416 } else {
3417 hostapd_logger(hapd, sta->addr,
3418 HOSTAPD_MODULE_IEEE80211,
3419 HOSTAPD_LEVEL_INFO,
3420 "Multi-AP IE has missing or invalid Multi-AP subelement");
3421 return WLAN_STATUS_INVALID_IE;
3422 }
3423 }
3424
Hai Shalom021b0b52019-04-10 11:17:58 -07003425 if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA)
3426 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3427 HOSTAPD_LEVEL_INFO,
3428 "Multi-AP IE with unexpected value 0x%02x",
3429 multi_ap_value);
Hai Shalom74f70d42019-02-11 14:42:39 -08003430
Hai Shalom021b0b52019-04-10 11:17:58 -07003431 if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) {
3432 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
3433 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08003434
Hai Shalom021b0b52019-04-10 11:17:58 -07003435 hostapd_logger(hapd, sta->addr,
3436 HOSTAPD_MODULE_IEEE80211,
3437 HOSTAPD_LEVEL_INFO,
3438 "Non-Multi-AP STA tries to associate with backhaul-only BSS");
3439 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
Hai Shalom74f70d42019-02-11 14:42:39 -08003440 }
3441
Hai Shalom021b0b52019-04-10 11:17:58 -07003442 if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
3443 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3444 HOSTAPD_LEVEL_DEBUG,
3445 "Backhaul STA tries to associate with fronthaul-only BSS");
3446
3447 sta->flags |= WLAN_STA_MULTI_AP;
3448 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08003449}
3450
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003451
3452static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
3453 struct ieee802_11_elems *elems)
3454{
Dmitry Shmidt29333592017-01-09 12:27:11 -08003455 /* Supported rates not used in IEEE 802.11ad/DMG */
3456 if (hapd->iface->current_mode &&
3457 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
3458 return WLAN_STATUS_SUCCESS;
3459
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003460 if (!elems->supp_rates) {
3461 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3462 HOSTAPD_LEVEL_DEBUG,
3463 "No supported rates element in AssocReq");
3464 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3465 }
3466
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003467 if (elems->supp_rates_len + elems->ext_supp_rates_len >
3468 sizeof(sta->supported_rates)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003469 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3470 HOSTAPD_LEVEL_DEBUG,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003471 "Invalid supported rates element length %d+%d",
3472 elems->supp_rates_len,
3473 elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003474 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3475 }
3476
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003477 sta->supported_rates_len = merge_byte_arrays(
3478 sta->supported_rates, sizeof(sta->supported_rates),
3479 elems->supp_rates, elems->supp_rates_len,
3480 elems->ext_supp_rates, elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003481
3482 return WLAN_STATUS_SUCCESS;
3483}
3484
3485
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003486#ifdef CONFIG_OWE
3487
3488static int owe_group_supported(struct hostapd_data *hapd, u16 group)
3489{
3490 int i;
3491 int *groups = hapd->conf->owe_groups;
3492
3493 if (group != 19 && group != 20 && group != 21)
3494 return 0;
3495
3496 if (!groups)
3497 return 1;
3498
3499 for (i = 0; groups[i] > 0; i++) {
3500 if (groups[i] == group)
3501 return 1;
3502 }
3503
3504 return 0;
3505}
3506
3507
3508static u16 owe_process_assoc_req(struct hostapd_data *hapd,
3509 struct sta_info *sta, const u8 *owe_dh,
3510 u8 owe_dh_len)
3511{
3512 struct wpabuf *secret, *pub, *hkey;
3513 int res;
3514 u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN];
3515 const char *info = "OWE Key Generation";
3516 const u8 *addr[2];
3517 size_t len[2];
3518 u16 group;
3519 size_t hash_len, prime_len;
3520
3521 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
3522 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
3523 return WLAN_STATUS_SUCCESS;
3524 }
3525
3526 group = WPA_GET_LE16(owe_dh);
3527 if (!owe_group_supported(hapd, group)) {
3528 wpa_printf(MSG_DEBUG, "OWE: Unsupported DH group %u", group);
3529 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3530 }
3531 if (group == 19)
3532 prime_len = 32;
3533 else if (group == 20)
3534 prime_len = 48;
3535 else if (group == 21)
3536 prime_len = 66;
3537 else
3538 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3539
Sunil Ravia04bd252022-05-02 22:54:18 -07003540 if (sta->owe_group == group && sta->owe_ecdh) {
3541 /* This is a workaround for mac80211 behavior of retransmitting
3542 * the Association Request frames multiple times if the link
3543 * layer retries (i.e., seq# remains same) fail. The mac80211
3544 * initiated retransmission will use a different seq# and as
3545 * such, will go through duplicate detection. If we were to
3546 * change our DH key for that attempt, there would be two
3547 * different DH shared secrets and the STA would likely select
3548 * the wrong one. */
3549 wpa_printf(MSG_DEBUG,
3550 "OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again");
3551 } else {
3552 crypto_ecdh_deinit(sta->owe_ecdh);
3553 sta->owe_ecdh = crypto_ecdh_init(group);
3554 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003555 if (!sta->owe_ecdh)
3556 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3557 sta->owe_group = group;
3558
3559 secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2,
3560 owe_dh_len - 2);
3561 secret = wpabuf_zeropad(secret, prime_len);
3562 if (!secret) {
3563 wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
3564 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3565 }
3566 wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
3567
3568 /* prk = HKDF-extract(C | A | group, z) */
3569
3570 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
3571 if (!pub) {
3572 wpabuf_clear_free(secret);
3573 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3574 }
3575
3576 /* PMKID = Truncate-128(Hash(C | A)) */
3577 addr[0] = owe_dh + 2;
3578 len[0] = owe_dh_len - 2;
3579 addr[1] = wpabuf_head(pub);
3580 len[1] = wpabuf_len(pub);
3581 if (group == 19) {
3582 res = sha256_vector(2, addr, len, pmkid);
3583 hash_len = SHA256_MAC_LEN;
3584 } else if (group == 20) {
3585 res = sha384_vector(2, addr, len, pmkid);
3586 hash_len = SHA384_MAC_LEN;
3587 } else if (group == 21) {
3588 res = sha512_vector(2, addr, len, pmkid);
3589 hash_len = SHA512_MAC_LEN;
3590 } else {
3591 wpabuf_free(pub);
3592 wpabuf_clear_free(secret);
3593 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3594 }
3595 pub = wpabuf_zeropad(pub, prime_len);
3596 if (res < 0 || !pub) {
3597 wpabuf_free(pub);
3598 wpabuf_clear_free(secret);
3599 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3600 }
3601
3602 hkey = wpabuf_alloc(owe_dh_len - 2 + wpabuf_len(pub) + 2);
3603 if (!hkey) {
3604 wpabuf_free(pub);
3605 wpabuf_clear_free(secret);
3606 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3607 }
3608
3609 wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */
3610 wpabuf_put_buf(hkey, pub); /* A */
3611 wpabuf_free(pub);
3612 wpabuf_put_le16(hkey, group); /* group */
3613 if (group == 19)
3614 res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
3615 wpabuf_head(secret), wpabuf_len(secret), prk);
3616 else if (group == 20)
3617 res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey),
3618 wpabuf_head(secret), wpabuf_len(secret), prk);
3619 else if (group == 21)
3620 res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey),
3621 wpabuf_head(secret), wpabuf_len(secret), prk);
3622 wpabuf_clear_free(hkey);
3623 wpabuf_clear_free(secret);
3624 if (res < 0)
3625 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3626
3627 wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
3628
3629 /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
3630
3631 os_free(sta->owe_pmk);
3632 sta->owe_pmk = os_malloc(hash_len);
3633 if (!sta->owe_pmk) {
3634 os_memset(prk, 0, SHA512_MAC_LEN);
3635 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3636 }
3637
3638 if (group == 19)
3639 res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info,
3640 os_strlen(info), sta->owe_pmk, hash_len);
3641 else if (group == 20)
3642 res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info,
3643 os_strlen(info), sta->owe_pmk, hash_len);
3644 else if (group == 21)
3645 res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
3646 os_strlen(info), sta->owe_pmk, hash_len);
3647 os_memset(prk, 0, SHA512_MAC_LEN);
3648 if (res < 0) {
3649 os_free(sta->owe_pmk);
3650 sta->owe_pmk = NULL;
3651 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3652 }
3653 sta->owe_pmk_len = hash_len;
3654
3655 wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
3656 wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
3657 wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk,
3658 sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE);
3659
3660 return WLAN_STATUS_SUCCESS;
3661}
3662
Hai Shalom81f62d82019-07-22 12:10:00 -07003663
3664u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
3665 const u8 *rsn_ie, size_t rsn_ie_len,
3666 const u8 *owe_dh, size_t owe_dh_len)
3667{
3668 struct wpa_ie_data data;
3669 int res;
3670
3671 if (!rsn_ie || rsn_ie_len < 2) {
3672 wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
3673 MAC2STR(peer));
3674 return WLAN_STATUS_INVALID_IE;
3675 }
3676 rsn_ie -= 2;
3677 rsn_ie_len += 2;
3678
3679 res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
3680 if (res) {
3681 wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
3682 " (res=%d)", MAC2STR(peer), res);
3683 wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
3684 return wpa_res_to_status_code(res);
3685 }
3686 if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
3687 wpa_printf(MSG_DEBUG,
3688 "OWE: Unexpected key mgmt 0x%x from " MACSTR,
3689 (unsigned int) data.key_mgmt, MAC2STR(peer));
3690 return WLAN_STATUS_AKMP_NOT_VALID;
3691 }
3692 if (!owe_dh) {
3693 wpa_printf(MSG_DEBUG,
3694 "OWE: No Diffie-Hellman Parameter element from "
3695 MACSTR, MAC2STR(peer));
3696 return WLAN_STATUS_AKMP_NOT_VALID;
3697 }
3698
3699 return WLAN_STATUS_SUCCESS;
3700}
3701
3702
3703u16 owe_process_rsn_ie(struct hostapd_data *hapd,
3704 struct sta_info *sta,
3705 const u8 *rsn_ie, size_t rsn_ie_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003706 const u8 *owe_dh, size_t owe_dh_len,
3707 const u8 *link_addr)
Hai Shalom81f62d82019-07-22 12:10:00 -07003708{
3709 u16 status;
3710 u8 *owe_buf, ie[256 * 2];
3711 size_t ie_len = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07003712 enum wpa_validate_result res;
Hai Shalom81f62d82019-07-22 12:10:00 -07003713
3714 if (!rsn_ie || rsn_ie_len < 2) {
3715 wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
3716 status = WLAN_STATUS_INVALID_IE;
3717 goto end;
3718 }
3719
3720 if (!sta->wpa_sm)
3721 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
3722 NULL);
3723 if (!sta->wpa_sm) {
3724 wpa_printf(MSG_WARNING,
3725 "OWE: Failed to initialize WPA state machine");
3726 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3727 goto end;
3728 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003729#ifdef CONFIG_IEEE80211BE
3730 if (sta->mld_info.mld_sta)
3731 wpa_auth_set_ml_info(sta->wpa_sm, hapd->mld_addr,
3732 sta->mld_assoc_link_id, &sta->mld_info);
3733#endif /* CONFIG_IEEE80211BE */
Hai Shalom81f62d82019-07-22 12:10:00 -07003734 rsn_ie -= 2;
3735 rsn_ie_len += 2;
3736 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
3737 hapd->iface->freq, rsn_ie, rsn_ie_len,
Hai Shalomc3565922019-10-28 11:58:20 -07003738 NULL, 0, NULL, 0, owe_dh, owe_dh_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07003739 status = wpa_res_to_status_code(res);
3740 if (status != WLAN_STATUS_SUCCESS)
3741 goto end;
3742 status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
3743 if (status != WLAN_STATUS_SUCCESS)
3744 goto end;
3745 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
3746 NULL, 0);
3747 if (!owe_buf) {
3748 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3749 goto end;
3750 }
3751
3752 if (sta->owe_ecdh) {
3753 struct wpabuf *pub;
3754
3755 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
3756 if (!pub) {
3757 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3758 goto end;
3759 }
3760
3761 /* OWE Diffie-Hellman Parameter element */
3762 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
3763 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
3764 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
3765 */
3766 WPA_PUT_LE16(owe_buf, sta->owe_group);
3767 owe_buf += 2;
3768 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
3769 owe_buf += wpabuf_len(pub);
3770 wpabuf_free(pub);
3771 sta->external_dh_updated = 1;
3772 }
3773 ie_len = owe_buf - ie;
3774
3775end:
3776 wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
3777 MACSTR, status, (unsigned int) ie_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003778 MAC2STR(link_addr ? link_addr : sta->addr));
3779 hostapd_drv_update_dh_ie(hapd, link_addr ? link_addr : sta->addr,
3780 status,
Hai Shalom81f62d82019-07-22 12:10:00 -07003781 status == WLAN_STATUS_SUCCESS ? ie : NULL,
3782 ie_len);
3783
3784 return status;
3785}
3786
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003787#endif /* CONFIG_OWE */
3788
3789
Hai Shalom899fcc72020-10-19 14:38:18 -07003790static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
3791 int reassoc)
3792{
3793 if ((sta->flags &
3794 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
3795 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
3796 return false;
3797
3798 if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
3799 ap_check_sa_query_timeout(hapd, sta);
3800
3801 if (!sta->sa_query_timed_out &&
3802 (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
3803 /*
3804 * STA has already been associated with MFP and SA Query timeout
3805 * has not been reached. Reject the association attempt
3806 * temporarily and start SA Query, if one is not pending.
3807 */
3808 if (sta->sa_query_count == 0)
3809 ap_sta_start_sa_query(hapd, sta);
3810
3811 return true;
3812 }
3813
3814 return false;
3815}
3816
3817
Sunil Ravi036cec52023-03-29 11:35:17 -07003818static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
3819 const u8 *ies, size_t ies_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003820 struct ieee802_11_elems *elems, int reassoc,
3821 bool link)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003822{
Hai Shalomb755a2a2020-04-23 21:49:02 -07003823 int resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003824 const u8 *wpa_ie;
3825 size_t wpa_ie_len;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003826 const u8 *p2p_dev_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003827
Sunil Ravi036cec52023-03-29 11:35:17 -07003828 resp = check_ssid(hapd, sta, elems->ssid, elems->ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003829 if (resp != WLAN_STATUS_SUCCESS)
3830 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003831 resp = check_wmm(hapd, sta, elems->wmm, elems->wmm_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003832 if (resp != WLAN_STATUS_SUCCESS)
3833 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003834 resp = check_ext_capab(hapd, sta, elems->ext_capab,
3835 elems->ext_capab_len);
Dmitry Shmidt051af732013-10-22 13:52:46 -07003836 if (resp != WLAN_STATUS_SUCCESS)
3837 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003838 resp = copy_supp_rates(hapd, sta, elems);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003839 if (resp != WLAN_STATUS_SUCCESS)
3840 return resp;
Hai Shalom74f70d42019-02-11 14:42:39 -08003841
Sunil Ravi036cec52023-03-29 11:35:17 -07003842 resp = check_multi_ap(hapd, sta, elems->multi_ap, elems->multi_ap_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08003843 if (resp != WLAN_STATUS_SUCCESS)
3844 return resp;
3845
Sunil Ravi036cec52023-03-29 11:35:17 -07003846 resp = copy_sta_ht_capab(hapd, sta, elems->ht_capabilities);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003847 if (resp != WLAN_STATUS_SUCCESS)
3848 return resp;
3849 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
3850 !(sta->flags & WLAN_STA_HT)) {
3851 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3852 HOSTAPD_LEVEL_INFO, "Station does not support "
3853 "mandatory HT PHY - reject association");
3854 return WLAN_STATUS_ASSOC_DENIED_NO_HT;
3855 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003856
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003857#ifdef CONFIG_IEEE80211AC
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003858 if (hapd->iconf->ieee80211ac) {
Sunil Ravi036cec52023-03-29 11:35:17 -07003859 resp = copy_sta_vht_capab(hapd, sta, elems->vht_capabilities);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003860 if (resp != WLAN_STATUS_SUCCESS)
3861 return resp;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08003862
Sunil Ravi640215c2023-06-28 23:08:09 +00003863 resp = set_sta_vht_opmode(hapd, sta, elems->opmode_notif);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003864 if (resp != WLAN_STATUS_SUCCESS)
3865 return resp;
3866 }
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08003867
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003868 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
3869 !(sta->flags & WLAN_STA_VHT)) {
3870 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3871 HOSTAPD_LEVEL_INFO, "Station does not support "
3872 "mandatory VHT PHY - reject association");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003873 return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003874 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003875
Sunil Ravi036cec52023-03-29 11:35:17 -07003876 if (hapd->conf->vendor_vht && !elems->vht_capabilities) {
3877 resp = copy_sta_vendor_vht(hapd, sta, elems->vendor_vht,
3878 elems->vendor_vht_len);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003879 if (resp != WLAN_STATUS_SUCCESS)
3880 return resp;
3881 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003882#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07003883#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08003884 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07003885 resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
Sunil Ravi036cec52023-03-29 11:35:17 -07003886 elems->he_capabilities,
3887 elems->he_capabilities_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07003888 if (resp != WLAN_STATUS_SUCCESS)
3889 return resp;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003890
3891 if (hapd->iconf->require_he && !(sta->flags & WLAN_STA_HE)) {
3892 hostapd_logger(hapd, sta->addr,
3893 HOSTAPD_MODULE_IEEE80211,
3894 HOSTAPD_LEVEL_INFO,
3895 "Station does not support mandatory HE PHY - reject association");
3896 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
3897 }
3898
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003899 if (is_6ghz_op_class(hapd->iconf->op_class)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07003900 if (!(sta->flags & WLAN_STA_HE)) {
3901 hostapd_logger(hapd, sta->addr,
3902 HOSTAPD_MODULE_IEEE80211,
3903 HOSTAPD_LEVEL_INFO,
3904 "Station does not support mandatory HE PHY - reject association");
3905 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
3906 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003907 resp = copy_sta_he_6ghz_capab(hapd, sta,
Sunil Ravi036cec52023-03-29 11:35:17 -07003908 elems->he_6ghz_band_cap);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003909 if (resp != WLAN_STATUS_SUCCESS)
3910 return resp;
3911 }
Hai Shalom81f62d82019-07-22 12:10:00 -07003912 }
3913#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07003914#ifdef CONFIG_IEEE80211BE
3915 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
3916 resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP,
Sunil Ravi036cec52023-03-29 11:35:17 -07003917 elems->he_capabilities,
3918 elems->he_capabilities_len,
3919 elems->eht_capabilities,
3920 elems->eht_capabilities_len);
Sunil Ravia04bd252022-05-02 22:54:18 -07003921 if (resp != WLAN_STATUS_SUCCESS)
3922 return resp;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003923
3924 if (!link) {
3925 resp = hostapd_process_ml_assoc_req(hapd, elems, sta);
3926 if (resp != WLAN_STATUS_SUCCESS)
3927 return resp;
3928 }
Sunil Ravia04bd252022-05-02 22:54:18 -07003929 }
3930#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003931
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003932#ifdef CONFIG_P2P
Sunil Ravi036cec52023-03-29 11:35:17 -07003933 if (elems->p2p && ies && ies_len) {
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003934 wpabuf_free(sta->p2p_ie);
3935 sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
3936 P2P_IE_VENDOR_TYPE);
3937 if (sta->p2p_ie)
3938 p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
3939 } else {
3940 wpabuf_free(sta->p2p_ie);
3941 sta->p2p_ie = NULL;
3942 }
3943#endif /* CONFIG_P2P */
3944
Sunil Ravi036cec52023-03-29 11:35:17 -07003945 if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems->rsn_ie) {
3946 wpa_ie = elems->rsn_ie;
3947 wpa_ie_len = elems->rsn_ie_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003948 } else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07003949 elems->wpa_ie) {
3950 wpa_ie = elems->wpa_ie;
3951 wpa_ie_len = elems->wpa_ie_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003952 } else {
3953 wpa_ie = NULL;
3954 wpa_ie_len = 0;
3955 }
3956
3957#ifdef CONFIG_WPS
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003958 sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
Sunil Ravi036cec52023-03-29 11:35:17 -07003959 if (hapd->conf->wps_state && elems->wps_ie && ies && ies_len) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003960 wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
3961 "Request - assume WPS is used");
3962 sta->flags |= WLAN_STA_WPS;
3963 wpabuf_free(sta->wps_ie);
3964 sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
3965 WPS_IE_VENDOR_TYPE);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003966 if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
3967 wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
3968 sta->flags |= WLAN_STA_WPS2;
3969 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003970 wpa_ie = NULL;
3971 wpa_ie_len = 0;
3972 if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
3973 wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
3974 "(Re)Association Request - reject");
3975 return WLAN_STATUS_INVALID_IE;
3976 }
3977 } else if (hapd->conf->wps_state && wpa_ie == NULL) {
3978 wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
3979 "(Re)Association Request - possible WPS use");
3980 sta->flags |= WLAN_STA_MAYBE_WPS;
3981 } else
3982#endif /* CONFIG_WPS */
3983 if (hapd->conf->wpa && wpa_ie == NULL) {
3984 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3985 HOSTAPD_LEVEL_INFO,
3986 "No WPA/RSN IE in association request");
3987 return WLAN_STATUS_INVALID_IE;
3988 }
3989
3990 if (hapd->conf->wpa && wpa_ie) {
Hai Shalomfdcde762020-04-02 11:19:20 -07003991 enum wpa_validate_result res;
3992
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003993 wpa_ie -= 2;
3994 wpa_ie_len += 2;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003995
3996 if (!sta->wpa_sm) {
3997#ifdef CONFIG_IEEE80211BE
3998 struct mld_info *info = &sta->mld_info;
3999#endif /* CONFIG_IEEE80211BE */
4000
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004001 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004002 sta->addr,
4003 p2p_dev_addr);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004004
4005 if (!sta->wpa_sm) {
4006 wpa_printf(MSG_WARNING,
4007 "Failed to initialize RSN state machine");
4008 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4009 }
4010
4011#ifdef CONFIG_IEEE80211BE
4012 if (info->mld_sta) {
4013 wpa_printf(MSG_DEBUG,
4014 "MLD: Set ML info in RSN Authenticator");
4015 wpa_auth_set_ml_info(sta->wpa_sm,
4016 hapd->mld_addr,
4017 sta->mld_assoc_link_id,
4018 info);
4019 }
4020#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004021 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004022
Hai Shalom021b0b52019-04-10 11:17:58 -07004023 wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004024 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07004025 hapd->iface->freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004026 wpa_ie, wpa_ie_len,
Sunil Ravi036cec52023-03-29 11:35:17 -07004027 elems->rsnxe ? elems->rsnxe - 2 :
4028 NULL,
4029 elems->rsnxe ? elems->rsnxe_len + 2 :
4030 0,
4031 elems->mdie, elems->mdie_len,
4032 elems->owe_dh, elems->owe_dh_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004033 resp = wpa_res_to_status_code(res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004034 if (resp != WLAN_STATUS_SUCCESS)
4035 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004036
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004037 if (wpa_auth_uses_mfp(sta->wpa_sm))
4038 sta->flags |= WLAN_STA_MFP;
4039 else
4040 sta->flags &= ~WLAN_STA_MFP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004041
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004042#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004043 if (sta->auth_alg == WLAN_AUTH_FT) {
4044 if (!reassoc) {
4045 wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
4046 "to use association (not "
4047 "re-association) with FT auth_alg",
4048 MAC2STR(sta->addr));
4049 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4050 }
4051
4052 resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
4053 ies_len);
4054 if (resp != WLAN_STATUS_SUCCESS)
4055 return resp;
4056 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004057#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004058
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004059 if (link)
4060 goto skip_sae_owe;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004061#ifdef CONFIG_SAE
Roshan Pius3a1667e2018-07-03 15:17:14 -07004062 if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
4063 sta->sae->state == SAE_ACCEPTED)
4064 wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
4065
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004066 if (wpa_auth_uses_sae(sta->wpa_sm) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004067 sta->auth_alg == WLAN_AUTH_OPEN) {
4068 struct rsn_pmksa_cache_entry *sa;
4069 sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
Sunil Ravi89eba102022-09-13 21:04:37 -07004070 if (!sa || !wpa_key_mgmt_sae(sa->akmp)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004071 wpa_printf(MSG_DEBUG,
4072 "SAE: No PMKSA cache entry found for "
4073 MACSTR, MAC2STR(sta->addr));
4074 return WLAN_STATUS_INVALID_PMKID;
4075 }
4076 wpa_printf(MSG_DEBUG, "SAE: " MACSTR
4077 " using PMKSA caching", MAC2STR(sta->addr));
4078 } else if (wpa_auth_uses_sae(sta->wpa_sm) &&
4079 sta->auth_alg != WLAN_AUTH_SAE &&
4080 !(sta->auth_alg == WLAN_AUTH_FT &&
4081 wpa_auth_uses_ft_sae(sta->wpa_sm))) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004082 wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
4083 "SAE AKM after non-SAE auth_alg %u",
4084 MAC2STR(sta->addr), sta->auth_alg);
4085 return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
4086 }
Hai Shalomc3565922019-10-28 11:58:20 -07004087
Sunil Ravi77d572f2023-01-17 23:58:31 +00004088 if (hapd->conf->sae_pwe == SAE_PWE_BOTH &&
Hai Shalomc3565922019-10-28 11:58:20 -07004089 sta->auth_alg == WLAN_AUTH_SAE &&
Hai Shalom899fcc72020-10-19 14:38:18 -07004090 sta->sae && !sta->sae->h2e &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004091 ieee802_11_rsnx_capab_len(elems->rsnxe, elems->rsnxe_len,
Hai Shaloma20dcd72022-02-04 13:43:00 -08004092 WLAN_RSNX_CAPAB_SAE_H2E)) {
Hai Shalomc3565922019-10-28 11:58:20 -07004093 wpa_printf(MSG_INFO, "SAE: " MACSTR
4094 " indicates support for SAE H2E, but did not use it",
4095 MAC2STR(sta->addr));
4096 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4097 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004098#endif /* CONFIG_SAE */
4099
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004100#ifdef CONFIG_OWE
4101 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
4102 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004103 elems->owe_dh) {
4104 resp = owe_process_assoc_req(hapd, sta, elems->owe_dh,
4105 elems->owe_dh_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004106 if (resp != WLAN_STATUS_SUCCESS)
4107 return resp;
4108 }
4109#endif /* CONFIG_OWE */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004110 skip_sae_owe:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004111
Hai Shalom021b0b52019-04-10 11:17:58 -07004112#ifdef CONFIG_DPP2
4113 dpp_pfs_free(sta->dpp_pfs);
4114 sta->dpp_pfs = NULL;
4115
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004116 if (DPP_VERSION > 1 &&
4117 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07004118 hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
4119 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004120 elems->owe_dh) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004121 sta->dpp_pfs = dpp_pfs_init(
4122 wpabuf_head(hapd->conf->dpp_netaccesskey),
4123 wpabuf_len(hapd->conf->dpp_netaccesskey));
4124 if (!sta->dpp_pfs) {
4125 wpa_printf(MSG_DEBUG,
4126 "DPP: Could not initialize PFS");
4127 /* Try to continue without PFS */
4128 goto pfs_fail;
4129 }
4130
Sunil Ravi036cec52023-03-29 11:35:17 -07004131 if (dpp_pfs_process(sta->dpp_pfs, elems->owe_dh,
4132 elems->owe_dh_len) < 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004133 dpp_pfs_free(sta->dpp_pfs);
4134 sta->dpp_pfs = NULL;
4135 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4136 }
4137 }
4138
4139 wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
4140 sta->dpp_pfs->secret : NULL);
4141 pfs_fail:
4142#endif /* CONFIG_DPP2 */
4143
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004144 if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004145 wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
4146 hostapd_logger(hapd, sta->addr,
4147 HOSTAPD_MODULE_IEEE80211,
4148 HOSTAPD_LEVEL_INFO,
4149 "Station tried to use TKIP with HT "
4150 "association");
4151 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
4152 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004153#ifdef CONFIG_HS20
4154 } else if (hapd->conf->osen) {
Sunil Ravi036cec52023-03-29 11:35:17 -07004155 if (!elems->osen) {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004156 hostapd_logger(
4157 hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4158 HOSTAPD_LEVEL_INFO,
4159 "No HS 2.0 OSEN element in association request");
4160 return WLAN_STATUS_INVALID_IE;
4161 }
4162
4163 wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
4164 if (sta->wpa_sm == NULL)
4165 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
4166 sta->addr, NULL);
4167 if (sta->wpa_sm == NULL) {
4168 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
4169 "state machine");
4170 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4171 }
4172 if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
Sunil Ravi036cec52023-03-29 11:35:17 -07004173 elems->osen - 2, elems->osen_len + 2) < 0)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004174 return WLAN_STATUS_INVALID_IE;
4175#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004176 } else
4177 wpa_auth_sta_no_wpa(sta->wpa_sm);
4178
4179#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004180 p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
4181#endif /* CONFIG_P2P */
4182
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004183#ifdef CONFIG_HS20
4184 wpabuf_free(sta->hs20_ie);
Sunil Ravi036cec52023-03-29 11:35:17 -07004185 if (elems->hs20 && elems->hs20_len > 4) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004186 int release;
4187
Sunil Ravi036cec52023-03-29 11:35:17 -07004188 sta->hs20_ie = wpabuf_alloc_copy(elems->hs20 + 4,
4189 elems->hs20_len - 4);
4190 release = ((elems->hs20[4] >> 4) & 0x0f) + 1;
Hai Shalomc3565922019-10-28 11:58:20 -07004191 if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
4192 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004193 wpa_printf(MSG_DEBUG,
4194 "HS 2.0: PMF not negotiated by release %d station "
4195 MACSTR, release, MAC2STR(sta->addr));
4196 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
4197 }
4198 } else {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004199 sta->hs20_ie = NULL;
Hai Shalom74f70d42019-02-11 14:42:39 -08004200 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07004201
4202 wpabuf_free(sta->roaming_consortium);
Sunil Ravi036cec52023-03-29 11:35:17 -07004203 if (elems->roaming_cons_sel)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004204 sta->roaming_consortium = wpabuf_alloc_copy(
Sunil Ravi036cec52023-03-29 11:35:17 -07004205 elems->roaming_cons_sel + 4,
4206 elems->roaming_cons_sel_len - 4);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004207 else
4208 sta->roaming_consortium = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004209#endif /* CONFIG_HS20 */
4210
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004211#ifdef CONFIG_FST
4212 wpabuf_free(sta->mb_ies);
4213 if (hapd->iface->fst)
Sunil Ravi036cec52023-03-29 11:35:17 -07004214 sta->mb_ies = mb_ies_by_info(&elems->mb_ies);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004215 else
4216 sta->mb_ies = NULL;
4217#endif /* CONFIG_FST */
4218
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004219#ifdef CONFIG_MBO
Sunil Ravi036cec52023-03-29 11:35:17 -07004220 mbo_ap_check_sta_assoc(hapd, sta, elems);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004221
4222 if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004223 elems->mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004224 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
4225 wpa_printf(MSG_INFO,
4226 "MBO: Reject WPA2 association without PMF");
4227 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4228 }
4229#endif /* CONFIG_MBO */
4230
Hai Shalom74f70d42019-02-11 14:42:39 -08004231#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
4232 if (wpa_auth_uses_ocv(sta->wpa_sm) &&
4233 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4234 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4235 sta->auth_alg == WLAN_AUTH_FILS_PK)) {
4236 struct wpa_channel_info ci;
4237 int tx_chanwidth;
4238 int tx_seg1_idx;
Hai Shalom899fcc72020-10-19 14:38:18 -07004239 enum oci_verify_result res;
Hai Shalom74f70d42019-02-11 14:42:39 -08004240
4241 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
4242 wpa_printf(MSG_WARNING,
4243 "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
4244 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4245 }
4246
4247 if (get_sta_tx_parameters(sta->wpa_sm,
4248 channel_width_to_int(ci.chanwidth),
4249 ci.seg1_idx, &tx_chanwidth,
4250 &tx_seg1_idx) < 0)
4251 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4252
Sunil Ravi036cec52023-03-29 11:35:17 -07004253 res = ocv_verify_tx_params(elems->oci, elems->oci_len, &ci,
Hai Shalom899fcc72020-10-19 14:38:18 -07004254 tx_chanwidth, tx_seg1_idx);
4255 if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
4256 res == OCI_NOT_FOUND) {
4257 /* Work around misbehaving STAs */
4258 wpa_printf(MSG_INFO,
4259 "FILS: Disable OCV with a STA that does not send OCI");
4260 wpa_auth_set_ocv(sta->wpa_sm, 0);
4261 } else if (res != OCI_SUCCESS) {
4262 wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
4263 ocv_errorstr);
4264 wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
4265 MACSTR " frame=fils-reassoc-req error=%s",
4266 MAC2STR(sta->addr), ocv_errorstr);
Hai Shalom74f70d42019-02-11 14:42:39 -08004267 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4268 }
4269 }
4270#endif /* CONFIG_FILS && CONFIG_OCV */
4271
Sunil Ravi036cec52023-03-29 11:35:17 -07004272 ap_copy_sta_supp_op_classes(sta, elems->supp_op_classes,
4273 elems->supp_op_classes_len);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08004274
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004275 if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004276 elems->rrm_enabled &&
4277 elems->rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
4278 os_memcpy(sta->rrm_enabled_capa, elems->rrm_enabled,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004279 sizeof(sta->rrm_enabled_capa));
4280
Sunil Ravi036cec52023-03-29 11:35:17 -07004281 if (elems->power_capab) {
4282 sta->min_tx_power = elems->power_capab[0];
4283 sta->max_tx_power = elems->power_capab[1];
Roshan Pius3a1667e2018-07-03 15:17:14 -07004284 sta->power_capab = 1;
4285 } else {
4286 sta->power_capab = 0;
4287 }
4288
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004289 return WLAN_STATUS_SUCCESS;
4290}
4291
4292
Sunil Ravi036cec52023-03-29 11:35:17 -07004293static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
4294 const u8 *ies, size_t ies_len, int reassoc)
4295{
4296 struct ieee802_11_elems elems;
4297
4298 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
4299 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4300 HOSTAPD_LEVEL_INFO,
4301 "Station sent an invalid association request");
4302 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4303 }
4304
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004305 return __check_assoc_ies(hapd, sta, ies, ies_len, &elems, reassoc,
4306 false);
4307}
4308
4309
4310#ifdef CONFIG_IEEE80211BE
4311
4312static size_t ieee80211_ml_build_assoc_resp(struct hostapd_data *hapd,
4313 u16 status_code,
4314 u8 *buf, size_t buflen)
4315{
4316 u8 *p = buf;
4317
4318 /* Capability Info */
4319 WPA_PUT_LE16(p, hostapd_own_capab_info(hapd));
4320 p += 2;
4321
4322 /* Status Code */
4323 WPA_PUT_LE16(p, status_code);
4324 p += 2;
4325
4326 if (status_code != WLAN_STATUS_SUCCESS)
4327 return p - buf;
4328
4329 /* AID is not included */
4330 p = hostapd_eid_supp_rates(hapd, p);
4331 p = hostapd_eid_ext_supp_rates(hapd, p);
4332 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
4333 p = hostapd_eid_ht_capabilities(hapd, p);
4334 p = hostapd_eid_ht_operation(hapd, p);
4335
4336 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
4337 p = hostapd_eid_vht_capabilities(hapd, p, 0);
4338 p = hostapd_eid_vht_operation(hapd, p);
4339 }
4340
4341 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
4342 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
4343 p = hostapd_eid_he_operation(hapd, p);
4344 p = hostapd_eid_spatial_reuse(hapd, p);
4345 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
4346 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
4347 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4348 p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
4349 p = hostapd_eid_eht_operation(hapd, p);
4350 }
4351 }
4352
4353 p = hostapd_eid_ext_capab(hapd, p, false);
4354 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
4355 p = hostapd_eid_wmm(hapd, p);
4356
4357 if (hapd->conf->assocresp_elements &&
4358 (size_t) (buf + buflen - p) >=
4359 wpabuf_len(hapd->conf->assocresp_elements)) {
4360 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
4361 wpabuf_len(hapd->conf->assocresp_elements));
4362 p += wpabuf_len(hapd->conf->assocresp_elements);
4363 }
4364
4365 return p - buf;
4366}
4367
4368
4369static void ieee80211_ml_process_link(struct hostapd_data *hapd,
4370 struct sta_info *origin_sta,
4371 struct mld_link_info *link,
4372 const u8 *ies, size_t ies_len,
4373 bool reassoc)
4374{
4375 struct ieee802_11_elems elems;
4376 struct wpabuf *mlbuf = NULL;
4377 struct sta_info *sta = NULL;
4378 u16 status = WLAN_STATUS_SUCCESS;
4379
4380 wpa_printf(MSG_DEBUG, "MLD: link: link_id=%u, peer=" MACSTR,
4381 hapd->mld_link_id, MAC2STR(link->peer_addr));
4382
4383 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
4384 wpa_printf(MSG_DEBUG, "MLD: link: Element parsing failed");
4385 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4386 goto out;
4387 }
4388
4389 sta = ap_get_sta(hapd, origin_sta->addr);
4390 if (sta) {
4391 wpa_printf(MSG_INFO, "MLD: link: Station already exists");
4392 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4393 sta = NULL;
4394 goto out;
4395 }
4396
4397 sta = ap_sta_add(hapd, origin_sta->addr);
4398 if (!sta) {
4399 wpa_printf(MSG_DEBUG, "MLD: link: ap_sta_add() failed");
4400 status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4401 goto out;
4402 }
4403
4404 mlbuf = ieee802_11_defrag_mle(&elems, MULTI_LINK_CONTROL_TYPE_BASIC);
4405 if (!mlbuf)
4406 goto out;
4407
4408 if (ieee802_11_parse_link_assoc_req(ies, ies_len, &elems, mlbuf,
4409 hapd->mld_link_id, true) ==
4410 ParseFailed) {
4411 wpa_printf(MSG_DEBUG,
4412 "MLD: link: Failed to parse association request Multi-Link element");
4413 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4414 goto out;
4415 }
4416
4417 sta->flags |= origin_sta->flags | WLAN_STA_ASSOC_REQ_OK;
4418 status = __check_assoc_ies(hapd, sta, NULL, 0, &elems, reassoc, true);
4419 if (status != WLAN_STATUS_SUCCESS) {
4420 wpa_printf(MSG_DEBUG, "MLD: link: Element check failed");
4421 goto out;
4422 }
4423
4424 sta->mld_info.mld_sta = true;
4425 sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id;
4426
4427 os_memcpy(&sta->mld_info, &origin_sta->mld_info, sizeof(sta->mld_info));
4428
4429 /*
4430 * Get the AID from the station on which the association was performed,
4431 * and mark it as used.
4432 */
4433 sta->aid = origin_sta->aid;
4434 if (sta->aid == 0) {
4435 wpa_printf(MSG_DEBUG, "MLD: link: No AID assigned");
4436 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4437 goto out;
4438 }
4439 hapd->sta_aid[(sta->aid - 1) / 32] |= BIT((sta->aid - 1) % 32);
4440 sta->listen_interval = origin_sta->listen_interval;
4441 if (update_ht_state(hapd, sta) > 0)
4442 ieee802_11_update_beacons(hapd->iface);
4443
4444 /* RSN Authenticator should always be the one on the original station */
4445 wpa_auth_sta_deinit(sta->wpa_sm);
4446 sta->wpa_sm = NULL;
4447
4448 /*
4449 * Do not initialize the EAPOL state machine.
4450 * TODO: Maybe it is needed?
4451 */
4452 sta->eapol_sm = NULL;
4453
4454 wpa_printf(MSG_DEBUG, "MLD: link=%u, association OK (aid=%u)",
4455 hapd->mld_link_id, sta->aid);
4456
4457 /*
4458 * Get RSNE and RSNXE for the current BSS as they are required by the
4459 * Authenticator.
4460 */
4461 link->rsne = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
4462 link->rsnxe = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
4463
4464 sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC_REQ_OK;
4465
4466 /* TODO: What other processing is required? */
4467
4468 if (add_associated_sta(hapd, sta, reassoc))
4469 status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4470out:
4471 wpabuf_free(mlbuf);
4472 link->status = status;
4473
4474 wpa_printf(MSG_DEBUG, "MLD: link: status=%u", status);
4475 if (sta && status != WLAN_STATUS_SUCCESS)
4476 ap_free_sta(hapd, sta);
4477
4478 link->resp_sta_profile_len =
4479 ieee80211_ml_build_assoc_resp(hapd, link->status,
4480 link->resp_sta_profile,
4481 sizeof(link->resp_sta_profile));
4482}
4483
4484
4485bool hostapd_is_mld_ap(struct hostapd_data *hapd)
4486{
4487 if (!hapd->conf->mld_ap)
4488 return false;
4489
4490 if (!hapd->iface || !hapd->iface->interfaces ||
4491 hapd->iface->interfaces->count <= 1)
4492 return false;
4493
4494 return true;
4495}
4496
4497#endif /* CONFIG_IEEE80211BE */
4498
4499
4500static void hostapd_process_assoc_ml_info(struct hostapd_data *hapd,
4501 struct sta_info *sta,
4502 const u8 *ies, size_t ies_len,
4503 bool reassoc)
4504{
4505#ifdef CONFIG_IEEE80211BE
4506 unsigned int i, j;
4507
4508 if (!hostapd_is_mld_ap(hapd))
4509 return;
4510
4511 /*
4512 * This is not really needed, but make the interaction with the RSN
4513 * Authenticator more consistent
4514 */
4515 sta->mld_info.links[hapd->mld_link_id].rsne =
4516 hostapd_wpa_ie(hapd, WLAN_EID_RSN);
4517 sta->mld_info.links[hapd->mld_link_id].rsnxe =
4518 hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
4519
4520 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
4521 struct hostapd_iface *iface = NULL;
4522 struct mld_link_info *link = &sta->mld_info.links[i];
4523
4524 if (!link->valid)
4525 continue;
4526
4527 for (j = 0; j < hapd->iface->interfaces->count; j++) {
4528 iface = hapd->iface->interfaces->iface[j];
4529
4530 if (hapd->iface == iface)
4531 continue;
4532
4533 if (iface->bss[0]->conf->mld_ap &&
4534 hapd->conf->mld_id == iface->bss[0]->conf->mld_id &&
4535 i == iface->bss[0]->mld_link_id)
4536 break;
4537 }
4538
4539 if (!iface || j == hapd->iface->interfaces->count) {
4540 wpa_printf(MSG_DEBUG,
4541 "MLD: No link match for link_id=%u", i);
4542
4543 link->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4544 link->resp_sta_profile_len =
4545 ieee80211_ml_build_assoc_resp(
4546 hapd, link->status,
4547 link->resp_sta_profile,
4548 sizeof(link->resp_sta_profile));
4549 } else {
4550 ieee80211_ml_process_link(iface->bss[0], sta, link,
4551 ies, ies_len, reassoc);
4552 }
4553 }
4554#endif /* CONFIG_IEEE80211BE */
Sunil Ravi036cec52023-03-29 11:35:17 -07004555}
4556
4557
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004558static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
4559 u16 reason_code)
4560{
4561 int send_len;
4562 struct ieee80211_mgmt reply;
4563
4564 os_memset(&reply, 0, sizeof(reply));
4565 reply.frame_control =
4566 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
4567 os_memcpy(reply.da, addr, ETH_ALEN);
4568 os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
4569 os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
4570
4571 send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
4572 reply.u.deauth.reason_code = host_to_le16(reason_code);
4573
Hai Shalomfdcde762020-04-02 11:19:20 -07004574 if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004575 wpa_printf(MSG_INFO, "Failed to send deauth: %s",
4576 strerror(errno));
4577}
4578
4579
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004580static int add_associated_sta(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08004581 struct sta_info *sta, int reassoc)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004582{
4583 struct ieee80211_ht_capabilities ht_cap;
4584 struct ieee80211_vht_capabilities vht_cap;
Hai Shalom81f62d82019-07-22 12:10:00 -07004585 struct ieee80211_he_capabilities he_cap;
Sunil Ravia04bd252022-05-02 22:54:18 -07004586 struct ieee80211_eht_capabilities eht_cap;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004587 int set = 1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004588 const u8 *mld_link_addr = NULL;
4589 bool mld_link_sta = false;
4590
4591#ifdef CONFIG_IEEE80211BE
4592 if (hapd->conf->mld_ap && sta->mld_info.mld_sta) {
4593 u8 mld_link_id = hapd->mld_link_id;
4594
4595 mld_link_sta = sta->mld_assoc_link_id != mld_link_id;
4596 mld_link_addr = sta->mld_info.links[mld_link_id].peer_addr;
4597
4598 if (hapd->mld_link_id != sta->mld_assoc_link_id)
4599 set = 0;
4600 }
4601#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004602
4603 /*
4604 * Remove the STA entry to ensure the STA PS state gets cleared and
4605 * configuration gets updated. This is relevant for cases, such as
4606 * FT-over-the-DS, where a station re-associates back to the same AP but
4607 * skips the authentication flow, or if working with a driver that
4608 * does not support full AP client state.
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004609 *
4610 * Skip this if the STA has already completed FT reassociation and the
4611 * TK has been configured since the TX/RX PN must not be reset to 0 for
4612 * the same key.
Hai Shalom74f70d42019-02-11 14:42:39 -08004613 *
4614 * FT-over-the-DS has a special case where the STA entry (and as such,
4615 * the TK) has not yet been configured to the driver depending on which
4616 * driver interface is used. For that case, allow add-STA operation to
4617 * be used (instead of set-STA). This is needed to allow mac80211-based
4618 * drivers to accept the STA parameter configuration. Since this is
4619 * after a new FT-over-DS exchange, a new TK has been derived, so key
4620 * reinstallation is not a concern for this case.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004621 */
Hai Shalom74f70d42019-02-11 14:42:39 -08004622 wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
4623 " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
4624 MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
4625 sta->ft_over_ds, reassoc,
4626 !!(sta->flags & WLAN_STA_AUTHORIZED),
4627 wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
4628 wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
4629
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004630 if (!mld_link_sta && !sta->added_unassoc &&
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004631 (!(sta->flags & WLAN_STA_AUTHORIZED) ||
Hai Shalom74f70d42019-02-11 14:42:39 -08004632 (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004633 (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
4634 !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004635 hostapd_drv_sta_remove(hapd, sta->addr);
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004636 wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
4637 set = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08004638
4639 /* Do not allow the FT-over-DS exception to be used more than
4640 * once per authentication exchange to guarantee a new TK is
4641 * used here */
4642 sta->ft_over_ds = 0;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004643 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004644
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004645 if (sta->flags & WLAN_STA_HT)
4646 hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004647#ifdef CONFIG_IEEE80211AC
4648 if (sta->flags & WLAN_STA_VHT)
4649 hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
4650#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07004651#ifdef CONFIG_IEEE80211AX
4652 if (sta->flags & WLAN_STA_HE) {
4653 hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
4654 sta->he_capab_len);
4655 }
4656#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07004657#ifdef CONFIG_IEEE80211BE
4658 if (sta->flags & WLAN_STA_EHT)
4659 hostapd_get_eht_capab(hapd, sta->eht_capab, &eht_cap,
4660 sta->eht_capab_len);
4661#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004662
4663 /*
4664 * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
4665 * will be set when the ACK frame for the (Re)Association Response frame
4666 * is processed (TX status driver event).
4667 */
4668 if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
4669 sta->supported_rates, sta->supported_rates_len,
4670 sta->listen_interval,
4671 sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
4672 sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
Hai Shalom81f62d82019-07-22 12:10:00 -07004673 sta->flags & WLAN_STA_HE ? &he_cap : NULL,
4674 sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
Sunil Ravia04bd252022-05-02 22:54:18 -07004675 sta->flags & WLAN_STA_EHT ? &eht_cap : NULL,
4676 sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004677 sta->he_6ghz_capab,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004678 sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004679 sta->vht_opmode, sta->p2p_ie ? 1 : 0,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004680 set, mld_link_addr, mld_link_sta)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004681 hostapd_logger(hapd, sta->addr,
4682 HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
4683 "Could not %s STA to kernel driver",
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004684 set ? "set" : "add");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004685
4686 if (sta->added_unassoc) {
4687 hostapd_drv_sta_remove(hapd, sta->addr);
4688 sta->added_unassoc = 0;
4689 }
4690
4691 return -1;
4692 }
4693
4694 sta->added_unassoc = 0;
4695
4696 return 0;
4697}
4698
4699
4700static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt29333592017-01-09 12:27:11 -08004701 const u8 *addr, u16 status_code, int reassoc,
Hai Shalomfdcde762020-04-02 11:19:20 -07004702 const u8 *ies, size_t ies_len, int rssi,
4703 int omit_rsnxe)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004704{
4705 int send_len;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004706 u8 *buf;
4707 size_t buflen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004708 struct ieee80211_mgmt *reply;
4709 u8 *p;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004710 u16 res = WLAN_STATUS_SUCCESS;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004711 const u8 *sa = hapd->own_addr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004712
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004713 buflen = sizeof(struct ieee80211_mgmt) + 1024;
4714#ifdef CONFIG_FILS
4715 if (sta && sta->fils_hlp_resp)
4716 buflen += wpabuf_len(sta->fils_hlp_resp);
Hai Shalom81f62d82019-07-22 12:10:00 -07004717 if (sta)
4718 buflen += 150;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004719#endif /* CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004720#ifdef CONFIG_OWE
4721 if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
4722 buflen += 150;
4723#endif /* CONFIG_OWE */
Hai Shalom021b0b52019-04-10 11:17:58 -07004724#ifdef CONFIG_DPP2
4725 if (sta && sta->dpp_pfs)
4726 buflen += 5 + sta->dpp_pfs->curve->prime_len;
4727#endif /* CONFIG_DPP2 */
Sunil Ravia04bd252022-05-02 22:54:18 -07004728#ifdef CONFIG_IEEE80211BE
4729 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4730 buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
4731 buflen += 3 + sizeof(struct ieee80211_eht_operation);
Sunil Ravi036cec52023-03-29 11:35:17 -07004732 if (hapd->iconf->punct_bitmap)
4733 buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
Sunil Ravia04bd252022-05-02 22:54:18 -07004734 }
4735#endif /* CONFIG_IEEE80211BE */
4736
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004737 buf = os_zalloc(buflen);
4738 if (!buf) {
4739 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4740 goto done;
4741 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004742 reply = (struct ieee80211_mgmt *) buf;
4743 reply->frame_control =
4744 IEEE80211_FC(WLAN_FC_TYPE_MGMT,
4745 (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
4746 WLAN_FC_STYPE_ASSOC_RESP));
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004747
4748#ifdef CONFIG_IEEE80211BE
4749 /*
4750 * Once a non-AP MLD is added to the driver, the addressing should use
4751 * MLD MAC address.
4752 */
4753 if (hapd->conf->mld_ap && sta && sta->mld_info.mld_sta)
4754 sa = hapd->mld_addr;
4755#endif /* CONFIG_IEEE80211BE */
4756
Dmitry Shmidt29333592017-01-09 12:27:11 -08004757 os_memcpy(reply->da, addr, ETH_ALEN);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004758 os_memcpy(reply->sa, sa, ETH_ALEN);
4759 os_memcpy(reply->bssid, sa, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004760
4761 send_len = IEEE80211_HDRLEN;
4762 send_len += sizeof(reply->u.assoc_resp);
4763 reply->u.assoc_resp.capab_info =
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07004764 host_to_le16(hostapd_own_capab_info(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004765 reply->u.assoc_resp.status_code = host_to_le16(status_code);
Dmitry Shmidt29333592017-01-09 12:27:11 -08004766
4767 reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
4768 BIT(14) | BIT(15));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004769 /* Supported rates */
4770 p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
4771 /* Extended supported rates */
4772 p = hostapd_eid_ext_supp_rates(hapd, p);
4773
Hai Shalomfdcde762020-04-02 11:19:20 -07004774 /* Radio measurement capabilities */
4775 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
4776
Hai Shalom74f70d42019-02-11 14:42:39 -08004777#ifdef CONFIG_MBO
4778 if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
4779 rssi != 0) {
4780 int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
4781
4782 p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
4783 delta);
4784 }
4785#endif /* CONFIG_MBO */
4786
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004787#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt29333592017-01-09 12:27:11 -08004788 if (sta && status_code == WLAN_STATUS_SUCCESS) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004789 /* IEEE 802.11r: Mobility Domain Information, Fast BSS
4790 * Transition Information, RSN, [RIC Response] */
4791 p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004792 buf + buflen - p,
Hai Shalomfdcde762020-04-02 11:19:20 -07004793 sta->auth_alg, ies, ies_len,
4794 omit_rsnxe);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004795 if (!p) {
4796 wpa_printf(MSG_DEBUG,
4797 "FT: Failed to write AssocResp IEs");
4798 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4799 goto done;
4800 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004801 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004802#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom81f62d82019-07-22 12:10:00 -07004803#ifdef CONFIG_FILS
4804 if (sta && status_code == WLAN_STATUS_SUCCESS &&
4805 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4806 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4807 sta->auth_alg == WLAN_AUTH_FILS_PK))
4808 p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
4809 buf + buflen - p,
4810 ies, ies_len);
4811#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004812
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004813#ifdef CONFIG_OWE
Hai Shalom74f70d42019-02-11 14:42:39 -08004814 if (sta && status_code == WLAN_STATUS_SUCCESS &&
4815 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004816 p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
4817 buf + buflen - p,
4818 ies, ies_len);
4819#endif /* CONFIG_OWE */
4820
Dmitry Shmidt29333592017-01-09 12:27:11 -08004821 if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004822 p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004823
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004824 p = hostapd_eid_ht_capabilities(hapd, p);
4825 p = hostapd_eid_ht_operation(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004826
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004827#ifdef CONFIG_IEEE80211AC
Hai Shalomc3565922019-10-28 11:58:20 -07004828 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
4829 !is_6ghz_op_class(hapd->iconf->op_class)) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07004830 u32 nsts = 0, sta_nsts;
4831
Dmitry Shmidt29333592017-01-09 12:27:11 -08004832 if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07004833 struct ieee80211_vht_capabilities *capa;
4834
4835 nsts = (hapd->iface->conf->vht_capab >>
4836 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
4837 capa = sta->vht_capabilities;
4838 sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
4839 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
4840
4841 if (nsts < sta_nsts)
4842 nsts = 0;
4843 else
4844 nsts = sta_nsts;
4845 }
4846 p = hostapd_eid_vht_capabilities(hapd, p, nsts);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004847 p = hostapd_eid_vht_operation(hapd, p);
4848 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004849#endif /* CONFIG_IEEE80211AC */
4850
Hai Shalom81f62d82019-07-22 12:10:00 -07004851#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08004852 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07004853 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
4854 p = hostapd_eid_he_operation(hapd, p);
Sunil Ravia04bd252022-05-02 22:54:18 -07004855 p = hostapd_eid_cca(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07004856 p = hostapd_eid_spatial_reuse(hapd, p);
4857 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004858 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07004859 }
4860#endif /* CONFIG_IEEE80211AX */
4861
Sunil Ravi77d572f2023-01-17 23:58:31 +00004862 p = hostapd_eid_ext_capab(hapd, p, false);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004863 p = hostapd_eid_bss_max_idle_period(hapd, p);
Dmitry Shmidt29333592017-01-09 12:27:11 -08004864 if (sta && sta->qos_map_enabled)
Dmitry Shmidt051af732013-10-22 13:52:46 -07004865 p = hostapd_eid_qos_map_set(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004866
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004867#ifdef CONFIG_FST
4868 if (hapd->iface->fst_ies) {
4869 os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
4870 wpabuf_len(hapd->iface->fst_ies));
4871 p += wpabuf_len(hapd->iface->fst_ies);
4872 }
4873#endif /* CONFIG_FST */
4874
Hai Shalomfdcde762020-04-02 11:19:20 -07004875#ifdef CONFIG_TESTING_OPTIONS
4876 if (hapd->conf->rsnxe_override_ft &&
4877 buf + buflen - p >=
4878 (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
4879 sta && sta->auth_alg == WLAN_AUTH_FT) {
4880 wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
4881 os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
4882 wpabuf_len(hapd->conf->rsnxe_override_ft));
4883 p += wpabuf_len(hapd->conf->rsnxe_override_ft);
4884 goto rsnxe_done;
4885 }
4886#endif /* CONFIG_TESTING_OPTIONS */
4887 if (!omit_rsnxe)
4888 p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
4889#ifdef CONFIG_TESTING_OPTIONS
4890rsnxe_done:
4891#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomc3565922019-10-28 11:58:20 -07004892
Sunil Ravia04bd252022-05-02 22:54:18 -07004893#ifdef CONFIG_IEEE80211BE
4894 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004895 if (hapd->conf->mld_ap)
4896 p = hostapd_eid_eht_basic_ml(hapd, p, sta, false);
Sunil Ravia04bd252022-05-02 22:54:18 -07004897 p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
4898 p = hostapd_eid_eht_operation(hapd, p);
4899 }
4900#endif /* CONFIG_IEEE80211BE */
4901
Hai Shalom021b0b52019-04-10 11:17:58 -07004902#ifdef CONFIG_OWE
4903 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
4904 sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
Hai Shalom899fcc72020-10-19 14:38:18 -07004905 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
4906 !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004907 struct wpabuf *pub;
4908
4909 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
4910 if (!pub) {
4911 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4912 goto done;
4913 }
4914 /* OWE Diffie-Hellman Parameter element */
4915 *p++ = WLAN_EID_EXTENSION; /* Element ID */
4916 *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
4917 *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
4918 WPA_PUT_LE16(p, sta->owe_group);
4919 p += 2;
4920 os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
4921 p += wpabuf_len(pub);
4922 wpabuf_free(pub);
4923 }
4924#endif /* CONFIG_OWE */
4925
4926#ifdef CONFIG_DPP2
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004927 if (DPP_VERSION > 1 && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07004928 sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
4929 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
4930 os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
4931 wpabuf_len(sta->dpp_pfs->ie));
4932 p += wpabuf_len(sta->dpp_pfs->ie);
4933 }
4934#endif /* CONFIG_DPP2 */
4935
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004936#ifdef CONFIG_IEEE80211AC
Dmitry Shmidt29333592017-01-09 12:27:11 -08004937 if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004938 p = hostapd_eid_vendor_vht(hapd, p);
4939#endif /* CONFIG_IEEE80211AC */
4940
Dmitry Shmidt29333592017-01-09 12:27:11 -08004941 if (sta && (sta->flags & WLAN_STA_WMM))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004942 p = hostapd_eid_wmm(hapd, p);
4943
4944#ifdef CONFIG_WPS
Dmitry Shmidt29333592017-01-09 12:27:11 -08004945 if (sta &&
4946 ((sta->flags & WLAN_STA_WPS) ||
4947 ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004948 struct wpabuf *wps = wps_build_assoc_resp_ie();
4949 if (wps) {
4950 os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
4951 p += wpabuf_len(wps);
4952 wpabuf_free(wps);
4953 }
4954 }
4955#endif /* CONFIG_WPS */
4956
Hai Shalom74f70d42019-02-11 14:42:39 -08004957 if (sta && (sta->flags & WLAN_STA_MULTI_AP))
4958 p = hostapd_eid_multi_ap(hapd, p);
4959
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004960#ifdef CONFIG_P2P
Dmitry Shmidt29333592017-01-09 12:27:11 -08004961 if (sta && sta->p2p_ie && hapd->p2p_group) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004962 struct wpabuf *p2p_resp_ie;
4963 enum p2p_status_code status;
4964 switch (status_code) {
4965 case WLAN_STATUS_SUCCESS:
4966 status = P2P_SC_SUCCESS;
4967 break;
4968 case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
4969 status = P2P_SC_FAIL_LIMIT_REACHED;
4970 break;
4971 default:
4972 status = P2P_SC_FAIL_INVALID_PARAMS;
4973 break;
4974 }
4975 p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
4976 if (p2p_resp_ie) {
4977 os_memcpy(p, wpabuf_head(p2p_resp_ie),
4978 wpabuf_len(p2p_resp_ie));
4979 p += wpabuf_len(p2p_resp_ie);
4980 wpabuf_free(p2p_resp_ie);
4981 }
4982 }
4983#endif /* CONFIG_P2P */
4984
4985#ifdef CONFIG_P2P_MANAGER
4986 if (hapd->conf->p2p & P2P_MANAGE)
4987 p = hostapd_eid_p2p_manage(hapd, p);
4988#endif /* CONFIG_P2P_MANAGER */
4989
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004990 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004991
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004992 if (hapd->conf->assocresp_elements &&
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004993 (size_t) (buf + buflen - p) >=
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004994 wpabuf_len(hapd->conf->assocresp_elements)) {
4995 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
4996 wpabuf_len(hapd->conf->assocresp_elements));
4997 p += wpabuf_len(hapd->conf->assocresp_elements);
4998 }
4999
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005000 send_len += p - reply->u.assoc_resp.variable;
5001
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005002#ifdef CONFIG_FILS
Dmitry Shmidt29333592017-01-09 12:27:11 -08005003 if (sta &&
5004 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005005 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5006 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
5007 status_code == WLAN_STATUS_SUCCESS) {
5008 struct ieee802_11_elems elems;
5009
5010 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005011 ParseFailed || !elems.fils_session) {
5012 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5013 goto done;
5014 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005015
5016 /* FILS Session */
5017 *p++ = WLAN_EID_EXTENSION; /* Element ID */
5018 *p++ = 1 + FILS_SESSION_LEN; /* Length */
5019 *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
5020 os_memcpy(p, elems.fils_session, FILS_SESSION_LEN);
5021 send_len += 2 + 1 + FILS_SESSION_LEN;
5022
5023 send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005024 buflen, sta->fils_hlp_resp);
5025 if (send_len < 0) {
5026 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5027 goto done;
5028 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005029 }
5030#endif /* CONFIG_FILS */
5031
Hai Shalomfdcde762020-04-02 11:19:20 -07005032 if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005033 wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
5034 strerror(errno));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005035 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005036 }
5037
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005038done:
5039 os_free(buf);
5040 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005041}
5042
5043
Roshan Pius3a1667e2018-07-03 15:17:14 -07005044#ifdef CONFIG_OWE
5045u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
5046 const u8 *owe_dh, u8 owe_dh_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07005047 u8 *owe_buf, size_t owe_buf_len, u16 *status)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005048{
5049#ifdef CONFIG_TESTING_OPTIONS
5050 if (hapd->conf->own_ie_override) {
5051 wpa_printf(MSG_DEBUG, "OWE: Using IE override");
Hai Shalomfdcde762020-04-02 11:19:20 -07005052 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005053 return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5054 owe_buf_len, NULL, 0);
5055 }
5056#endif /* CONFIG_TESTING_OPTIONS */
5057
5058 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
5059 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
5060 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5061 owe_buf_len, NULL, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -07005062 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005063 return owe_buf;
5064 }
5065
Hai Shalom81f62d82019-07-22 12:10:00 -07005066 if (sta->owe_pmk && sta->external_dh_updated) {
5067 wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
Hai Shalomfdcde762020-04-02 11:19:20 -07005068 *status = WLAN_STATUS_SUCCESS;
Hai Shalom81f62d82019-07-22 12:10:00 -07005069 return owe_buf;
5070 }
5071
Hai Shalomfdcde762020-04-02 11:19:20 -07005072 *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
5073 if (*status != WLAN_STATUS_SUCCESS)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005074 return NULL;
5075
5076 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5077 owe_buf_len, NULL, 0);
5078
5079 if (sta->owe_ecdh && owe_buf) {
5080 struct wpabuf *pub;
5081
5082 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
5083 if (!pub) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005084 *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005085 return owe_buf;
5086 }
5087
5088 /* OWE Diffie-Hellman Parameter element */
5089 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
5090 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
5091 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
5092 */
5093 WPA_PUT_LE16(owe_buf, sta->owe_group);
5094 owe_buf += 2;
5095 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
5096 owe_buf += wpabuf_len(pub);
5097 wpabuf_free(pub);
5098 }
5099
5100 return owe_buf;
5101}
5102#endif /* CONFIG_OWE */
5103
5104
Paul Stewart092955c2017-02-06 09:13:09 -08005105#ifdef CONFIG_FILS
5106
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005107void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
Paul Stewart092955c2017-02-06 09:13:09 -08005108{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005109 u16 reply_res;
Paul Stewart092955c2017-02-06 09:13:09 -08005110
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005111 wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
5112 MAC2STR(sta->addr));
5113 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5114 if (!sta->fils_pending_assoc_req)
Paul Stewart092955c2017-02-06 09:13:09 -08005115 return;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005116 reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
5117 sta->fils_pending_assoc_is_reassoc,
5118 sta->fils_pending_assoc_req,
Hai Shalomfdcde762020-04-02 11:19:20 -07005119 sta->fils_pending_assoc_req_len, 0, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005120 os_free(sta->fils_pending_assoc_req);
5121 sta->fils_pending_assoc_req = NULL;
5122 sta->fils_pending_assoc_req_len = 0;
5123 wpabuf_free(sta->fils_hlp_resp);
5124 sta->fils_hlp_resp = NULL;
5125 wpabuf_free(sta->hlp_dhcp_discover);
5126 sta->hlp_dhcp_discover = NULL;
Paul Stewart092955c2017-02-06 09:13:09 -08005127
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005128 /*
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005129 * Remove the station in case transmission of a success response fails.
5130 * At this point the station was already added associated to the driver.
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005131 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005132 if (reply_res != WLAN_STATUS_SUCCESS)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005133 hostapd_drv_sta_remove(hapd, sta->addr);
Paul Stewart092955c2017-02-06 09:13:09 -08005134}
5135
5136
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005137void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
Paul Stewart092955c2017-02-06 09:13:09 -08005138{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005139 struct hostapd_data *hapd = eloop_ctx;
5140 struct sta_info *sta = eloop_data;
Paul Stewart092955c2017-02-06 09:13:09 -08005141
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005142 wpa_printf(MSG_DEBUG,
5143 "FILS: HLP response timeout - continue with association response for "
5144 MACSTR, MAC2STR(sta->addr));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005145 if (sta->fils_drv_assoc_finish)
5146 hostapd_notify_assoc_fils_finish(hapd, sta);
5147 else
5148 fils_hlp_finish_assoc(hapd, sta);
Paul Stewart092955c2017-02-06 09:13:09 -08005149}
5150
5151#endif /* CONFIG_FILS */
5152
5153
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005154static void handle_assoc(struct hostapd_data *hapd,
5155 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom74f70d42019-02-11 14:42:39 -08005156 int reassoc, int rssi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005157{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005158 u16 capab_info, listen_interval, seq_ctrl, fc;
Hai Shalomb755a2a2020-04-23 21:49:02 -07005159 int resp = WLAN_STATUS_SUCCESS;
Hai Shalom899fcc72020-10-19 14:38:18 -07005160 u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005161 const u8 *pos;
5162 int left, i;
5163 struct sta_info *sta;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005164 u8 *tmp = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005165#ifdef CONFIG_FILS
5166 int delay_assoc = 0;
5167#endif /* CONFIG_FILS */
Hai Shalomfdcde762020-04-02 11:19:20 -07005168 int omit_rsnxe = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005169 bool set_beacon = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005170
5171 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
5172 sizeof(mgmt->u.assoc_req))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005173 wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
5174 reassoc, (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005175 return;
5176 }
5177
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005178#ifdef CONFIG_TESTING_OPTIONS
5179 if (reassoc) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005180 if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005181 drand48() < hapd->iconf->ignore_reassoc_probability) {
5182 wpa_printf(MSG_INFO,
5183 "TESTING: ignoring reassoc request from "
5184 MACSTR, MAC2STR(mgmt->sa));
5185 return;
5186 }
5187 } else {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005188 if (hapd->iconf->ignore_assoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005189 drand48() < hapd->iconf->ignore_assoc_probability) {
5190 wpa_printf(MSG_INFO,
5191 "TESTING: ignoring assoc request from "
5192 MACSTR, MAC2STR(mgmt->sa));
5193 return;
5194 }
5195 }
5196#endif /* CONFIG_TESTING_OPTIONS */
5197
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005198 fc = le_to_host16(mgmt->frame_control);
5199 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
5200
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005201 if (reassoc) {
5202 capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
5203 listen_interval = le_to_host16(
5204 mgmt->u.reassoc_req.listen_interval);
5205 wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
5206 " capab_info=0x%02x listen_interval=%d current_ap="
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005207 MACSTR " seq_ctrl=0x%x%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005208 MAC2STR(mgmt->sa), capab_info, listen_interval,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005209 MAC2STR(mgmt->u.reassoc_req.current_ap),
5210 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005211 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
5212 pos = mgmt->u.reassoc_req.variable;
5213 } else {
5214 capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
5215 listen_interval = le_to_host16(
5216 mgmt->u.assoc_req.listen_interval);
5217 wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005218 " capab_info=0x%02x listen_interval=%d "
5219 "seq_ctrl=0x%x%s",
5220 MAC2STR(mgmt->sa), capab_info, listen_interval,
5221 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005222 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
5223 pos = mgmt->u.assoc_req.variable;
5224 }
5225
5226 sta = ap_get_sta(hapd, mgmt->sa);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005227#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005228 if (sta && sta->auth_alg == WLAN_AUTH_FT &&
5229 (sta->flags & WLAN_STA_AUTH) == 0) {
5230 wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
5231 "prior to authentication since it is using "
5232 "over-the-DS FT", MAC2STR(mgmt->sa));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005233
5234 /*
5235 * Mark station as authenticated, to avoid adding station
5236 * entry in the driver as associated and not authenticated
5237 */
5238 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005239 } else
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005240#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005241 if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
Dmitry Shmidt29333592017-01-09 12:27:11 -08005242 if (hapd->iface->current_mode &&
5243 hapd->iface->current_mode->mode ==
5244 HOSTAPD_MODE_IEEE80211AD) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005245 int acl_res;
Hai Shalomfdcde762020-04-02 11:19:20 -07005246 struct radius_sta info;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005247
Hai Shalomfdcde762020-04-02 11:19:20 -07005248 acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
5249 (const u8 *) mgmt,
5250 len, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005251 if (acl_res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005252 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5253 "Ignore Association Request frame from "
5254 MACSTR " due to ACL reject",
5255 MAC2STR(mgmt->sa));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005256 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5257 goto fail;
5258 }
5259 if (acl_res == HOSTAPD_ACL_PENDING)
5260 return;
5261
Dmitry Shmidt29333592017-01-09 12:27:11 -08005262 /* DMG/IEEE 802.11ad does not use authentication.
5263 * Allocate sta entry upon association. */
5264 sta = ap_sta_add(hapd, mgmt->sa);
5265 if (!sta) {
5266 hostapd_logger(hapd, mgmt->sa,
5267 HOSTAPD_MODULE_IEEE80211,
5268 HOSTAPD_LEVEL_INFO,
5269 "Failed to add STA");
5270 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5271 goto fail;
5272 }
5273
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005274 acl_res = ieee802_11_set_radius_info(
Hai Shalomfdcde762020-04-02 11:19:20 -07005275 hapd, sta, acl_res, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005276 if (acl_res) {
5277 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5278 goto fail;
5279 }
5280
Dmitry Shmidt29333592017-01-09 12:27:11 -08005281 hostapd_logger(hapd, sta->addr,
5282 HOSTAPD_MODULE_IEEE80211,
5283 HOSTAPD_LEVEL_DEBUG,
5284 "Skip authentication for DMG/IEEE 802.11ad");
5285 sta->flags |= WLAN_STA_AUTH;
5286 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
5287 sta->auth_alg = WLAN_AUTH_OPEN;
5288 } else {
5289 hostapd_logger(hapd, mgmt->sa,
5290 HOSTAPD_MODULE_IEEE80211,
5291 HOSTAPD_LEVEL_INFO,
5292 "Station tried to associate before authentication (aid=%d flags=0x%x)",
5293 sta ? sta->aid : -1,
5294 sta ? sta->flags : 0);
5295 send_deauth(hapd, mgmt->sa,
5296 WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
5297 return;
5298 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005299 }
5300
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005301 if ((fc & WLAN_FC_RETRY) &&
5302 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
5303 sta->last_seq_ctrl == seq_ctrl &&
Paul Stewart092955c2017-02-06 09:13:09 -08005304 sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5305 WLAN_FC_STYPE_ASSOC_REQ)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005306 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5307 HOSTAPD_LEVEL_DEBUG,
5308 "Drop repeated association frame seq_ctrl=0x%x",
5309 seq_ctrl);
5310 return;
5311 }
5312 sta->last_seq_ctrl = seq_ctrl;
5313 sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5314 WLAN_FC_STYPE_ASSOC_REQ;
5315
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005316 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005317 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005318 goto fail;
5319 }
5320
5321 if (listen_interval > hapd->conf->max_listen_interval) {
5322 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5323 HOSTAPD_LEVEL_DEBUG,
5324 "Too large Listen Interval (%d)",
5325 listen_interval);
5326 resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
5327 goto fail;
5328 }
5329
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005330#ifdef CONFIG_MBO
5331 if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
5332 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5333 goto fail;
5334 }
Hai Shalom74f70d42019-02-11 14:42:39 -08005335
5336 if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
5337 rssi < hapd->iconf->rssi_reject_assoc_rssi &&
5338 (sta->auth_rssi == 0 ||
5339 sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
5340 resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
5341 goto fail;
5342 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005343#endif /* CONFIG_MBO */
5344
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005345 if (hapd->conf->wpa && check_sa_query(hapd, sta, reassoc)) {
5346 resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
5347 goto fail;
5348 }
5349
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005350 /*
5351 * sta->capability is used in check_assoc_ies() for RRM enabled
5352 * capability element.
5353 */
5354 sta->capability = capab_info;
5355
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005356#ifdef CONFIG_FILS
5357 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5358 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5359 sta->auth_alg == WLAN_AUTH_FILS_PK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005360 int res;
5361
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005362 /* The end of the payload is encrypted. Need to decrypt it
5363 * before parsing. */
5364
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005365 tmp = os_memdup(pos, left);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005366 if (!tmp) {
5367 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5368 goto fail;
5369 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005370
Roshan Pius3a1667e2018-07-03 15:17:14 -07005371 res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
5372 len, tmp, left);
5373 if (res < 0) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005374 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5375 goto fail;
5376 }
5377 pos = tmp;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005378 left = res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005379 }
5380#endif /* CONFIG_FILS */
5381
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005382 /* followed by SSID and Supported rates; and HT capabilities if 802.11n
5383 * is used */
5384 resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
5385 if (resp != WLAN_STATUS_SUCCESS)
5386 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07005387 omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005388
5389 if (hostapd_get_aid(hapd, sta) < 0) {
5390 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5391 HOSTAPD_LEVEL_INFO, "No room for more AIDs");
5392 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5393 goto fail;
5394 }
5395
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005396 sta->listen_interval = listen_interval;
5397
Roshan Pius3a1667e2018-07-03 15:17:14 -07005398 if (hapd->iface->current_mode &&
5399 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005400 sta->flags |= WLAN_STA_NONERP;
5401 for (i = 0; i < sta->supported_rates_len; i++) {
5402 if ((sta->supported_rates[i] & 0x7f) > 22) {
5403 sta->flags &= ~WLAN_STA_NONERP;
5404 break;
5405 }
5406 }
5407 if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
5408 sta->nonerp_set = 1;
5409 hapd->iface->num_sta_non_erp++;
5410 if (hapd->iface->num_sta_non_erp == 1)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005411 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005412 }
5413
5414 if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
5415 !sta->no_short_slot_time_set) {
5416 sta->no_short_slot_time_set = 1;
5417 hapd->iface->num_sta_no_short_slot_time++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005418 if (hapd->iface->current_mode &&
5419 hapd->iface->current_mode->mode ==
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005420 HOSTAPD_MODE_IEEE80211G &&
5421 hapd->iface->num_sta_no_short_slot_time == 1)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005422 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005423 }
5424
5425 if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
5426 sta->flags |= WLAN_STA_SHORT_PREAMBLE;
5427 else
5428 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
5429
5430 if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
5431 !sta->no_short_preamble_set) {
5432 sta->no_short_preamble_set = 1;
5433 hapd->iface->num_sta_no_short_preamble++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005434 if (hapd->iface->current_mode &&
5435 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005436 && hapd->iface->num_sta_no_short_preamble == 1)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005437 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005438 }
5439
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005440 if (update_ht_state(hapd, sta) > 0)
5441 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005442
5443 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5444 HOSTAPD_LEVEL_DEBUG,
5445 "association OK (aid %d)", sta->aid);
5446 /* Station will be marked associated, after it acknowledges AssocResp
5447 */
5448 sta->flags |= WLAN_STA_ASSOC_REQ_OK;
5449
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005450 if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
5451 wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
5452 "SA Query procedure", reassoc ? "re" : "");
5453 /* TODO: Send a protected Disassociate frame to the STA using
5454 * the old key and Reason Code "Previous Authentication no
5455 * longer valid". Make sure this is only sent protected since
5456 * unprotected frame would be received by the STA that is now
5457 * trying to associate.
5458 */
5459 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005460
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005461 /* Make sure that the previously registered inactivity timer will not
5462 * remove the STA immediately. */
5463 sta->timeout_next = STA_NULLFUNC;
5464
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005465#ifdef CONFIG_TAXONOMY
5466 taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
5467#endif /* CONFIG_TAXONOMY */
5468
Dmitry Shmidt29333592017-01-09 12:27:11 -08005469 sta->pending_wds_enable = 0;
5470
Paul Stewart092955c2017-02-06 09:13:09 -08005471#ifdef CONFIG_FILS
5472 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5473 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005474 sta->auth_alg == WLAN_AUTH_FILS_PK) {
5475 if (fils_process_hlp(hapd, sta, pos, left) > 0)
5476 delay_assoc = 1;
5477 }
Paul Stewart092955c2017-02-06 09:13:09 -08005478#endif /* CONFIG_FILS */
5479
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005480 if (set_beacon)
5481 ieee802_11_set_beacons(hapd->iface);
5482
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005483 fail:
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005484
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005485 /*
5486 * In case of a successful response, add the station to the driver.
5487 * Otherwise, the kernel may ignore Data frames before we process the
5488 * ACK frame (TX status). In case of a failure, this station will be
5489 * removed.
5490 *
5491 * Note that this is not compliant with the IEEE 802.11 standard that
5492 * states that a non-AP station should transition into the
5493 * authenticated/associated state only after the station acknowledges
5494 * the (Re)Association Response frame. However, still do this as:
5495 *
5496 * 1. In case the station does not acknowledge the (Re)Association
5497 * Response frame, it will be removed.
5498 * 2. Data frames will be dropped in the kernel until the station is
5499 * set into authorized state, and there are no significant known
5500 * issues with processing other non-Data Class 3 frames during this
5501 * window.
5502 */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005503 if (resp == WLAN_STATUS_SUCCESS)
5504 hostapd_process_assoc_ml_info(hapd, sta, pos, left, reassoc);
5505
Hai Shalom74f70d42019-02-11 14:42:39 -08005506 if (resp == WLAN_STATUS_SUCCESS && sta &&
5507 add_associated_sta(hapd, sta, reassoc))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005508 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5509
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005510#ifdef CONFIG_FILS
Hai Shalom74f70d42019-02-11 14:42:39 -08005511 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
5512 eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
5513 sta->fils_pending_assoc_req) {
5514 /* Do not reschedule fils_hlp_timeout in case the station
5515 * retransmits (Re)Association Request frame while waiting for
5516 * the previously started FILS HLP wait, so that the timeout can
5517 * be determined from the first pending attempt. */
5518 wpa_printf(MSG_DEBUG,
5519 "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
5520 MACSTR, MAC2STR(sta->addr));
5521 os_free(tmp);
5522 return;
5523 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005524 if (sta) {
5525 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5526 os_free(sta->fils_pending_assoc_req);
5527 sta->fils_pending_assoc_req = NULL;
5528 sta->fils_pending_assoc_req_len = 0;
5529 wpabuf_free(sta->fils_hlp_resp);
5530 sta->fils_hlp_resp = NULL;
5531 }
5532 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
5533 sta->fils_pending_assoc_req = tmp;
5534 sta->fils_pending_assoc_req_len = left;
5535 sta->fils_pending_assoc_is_reassoc = reassoc;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005536 sta->fils_drv_assoc_finish = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005537 wpa_printf(MSG_DEBUG,
5538 "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
5539 MACSTR, MAC2STR(sta->addr));
5540 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5541 eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
5542 fils_hlp_timeout, hapd, sta);
5543 return;
5544 }
5545#endif /* CONFIG_FILS */
5546
Hai Shalomb755a2a2020-04-23 21:49:02 -07005547 if (resp >= 0)
5548 reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc,
5549 pos, left, rssi, omit_rsnxe);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005550 os_free(tmp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005551
5552 /*
Hai Shalom899fcc72020-10-19 14:38:18 -07005553 * Remove the station in case transmission of a success response fails
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005554 * (the STA was added associated to the driver) or if the station was
5555 * previously added unassociated.
5556 */
Dmitry Shmidt29333592017-01-09 12:27:11 -08005557 if (sta && ((reply_res != WLAN_STATUS_SUCCESS &&
5558 resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005559 hostapd_drv_sta_remove(hapd, sta->addr);
5560 sta->added_unassoc = 0;
5561 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005562}
5563
5564
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005565static void hostapd_deauth_sta(struct hostapd_data *hapd,
5566 struct sta_info *sta,
5567 const struct ieee80211_mgmt *mgmt)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005568{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005569 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5570 "deauthentication: STA=" MACSTR " reason_code=%d",
5571 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005572
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005573 ap_sta_set_authorized(hapd, sta, 0);
5574 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
5575 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
5576 WLAN_STA_ASSOC_REQ_OK);
5577 hostapd_set_sta_flags(hapd, sta);
5578 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5579 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5580 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5581 mlme_deauthenticate_indication(
5582 hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
5583 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5584 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5585 ap_free_sta(hapd, sta);
5586}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005587
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005588
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005589static void hostapd_disassoc_sta(struct hostapd_data *hapd,
5590 struct sta_info *sta,
5591 const struct ieee80211_mgmt *mgmt)
5592{
5593 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5594 "disassocation: STA=" MACSTR " reason_code=%d",
5595 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005596
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005597 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005598 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005599 sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07005600 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005601 wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
5602 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5603 HOSTAPD_LEVEL_INFO, "disassociated");
5604 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5605 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5606 /* Stop Accounting and IEEE 802.1X sessions, but leave the STA
5607 * authenticated. */
5608 accounting_sta_stop(hapd, sta);
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005609 ieee802_1x_free_station(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005610 if (sta->ipaddr)
5611 hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
5612 ap_sta_ip6addr_del(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005613 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005614 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005615
5616 if (sta->timeout_next == STA_NULLFUNC ||
5617 sta->timeout_next == STA_DISASSOC) {
5618 sta->timeout_next = STA_DEAUTH;
5619 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
5620 eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
5621 hapd, sta);
5622 }
5623
5624 mlme_disassociate_indication(
5625 hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt29333592017-01-09 12:27:11 -08005626
5627 /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon
5628 * disassociation. */
5629 if (hapd->iface->current_mode &&
5630 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
5631 sta->flags &= ~WLAN_STA_AUTH;
5632 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5633 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5634 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5635 ap_free_sta(hapd, sta);
5636 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005637}
5638
5639
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005640#ifdef CONFIG_IEEE80211BE
5641static struct sta_info *
5642hostapd_ml_get_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
5643 struct hostapd_data **assoc_hapd)
5644{
5645 struct hostapd_data *other_hapd = NULL;
5646 struct sta_info *tmp_sta;
5647
5648 *assoc_hapd = hapd;
5649
5650 /* The station is the one on which the association was performed */
5651 if (sta->mld_assoc_link_id == hapd->mld_link_id)
5652 return sta;
5653
5654 other_hapd = hostapd_mld_get_link_bss(hapd, sta->mld_assoc_link_id);
5655 if (!other_hapd) {
5656 wpa_printf(MSG_DEBUG, "MLD: No link match for link_id=%u",
5657 sta->mld_assoc_link_id);
5658 return sta;
5659 }
5660
5661 /*
5662 * Iterate over the stations and find the one with the matching link ID
5663 * and association ID.
5664 */
5665 for (tmp_sta = other_hapd->sta_list; tmp_sta; tmp_sta = tmp_sta->next) {
5666 if (tmp_sta->mld_assoc_link_id == sta->mld_assoc_link_id &&
5667 tmp_sta->aid == sta->aid) {
5668 *assoc_hapd = other_hapd;
5669 return tmp_sta;
5670 }
5671 }
5672
5673 return sta;
5674}
5675#endif /* CONFIG_IEEE80211BE */
5676
5677
5678static bool hostapd_ml_handle_disconnect(struct hostapd_data *hapd,
5679 struct sta_info *sta,
5680 const struct ieee80211_mgmt *mgmt,
5681 bool disassoc)
5682{
5683#ifdef CONFIG_IEEE80211BE
5684 struct hostapd_data *assoc_hapd, *tmp_hapd;
5685 struct sta_info *assoc_sta;
5686 unsigned int i, link_id;
5687
5688 if (!hostapd_is_mld_ap(hapd))
5689 return false;
5690
5691 /*
5692 * Get the station on which the association was performed, as it holds
5693 * the information about all the other links.
5694 */
5695 assoc_sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd);
5696
5697 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
5698 for (i = 0; i < assoc_hapd->iface->interfaces->count; i++) {
5699 struct sta_info *tmp_sta;
5700
5701 if (!assoc_sta->mld_info.links[link_id].valid)
5702 continue;
5703
5704 tmp_hapd =
5705 assoc_hapd->iface->interfaces->iface[i]->bss[0];
5706
5707 if (!tmp_hapd->conf->mld_ap ||
5708 assoc_hapd->conf->mld_id != tmp_hapd->conf->mld_id)
5709 continue;
5710
5711 for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
5712 tmp_sta = tmp_sta->next) {
5713 /*
5714 * Remove the station on which the association
5715 * was done only after all other link stations
5716 * are removed. Since there is only a single
5717 * station per struct hostapd_hapd with the
5718 * same association link simply break out from
5719 * the loop.
5720 */
5721 if (tmp_sta == assoc_sta)
5722 break;
5723
5724 if (tmp_sta->mld_assoc_link_id !=
5725 assoc_sta->mld_assoc_link_id ||
5726 tmp_sta->aid != assoc_sta->aid)
5727 continue;
5728
5729 if (!disassoc)
5730 hostapd_deauth_sta(tmp_hapd, tmp_sta,
5731 mgmt);
5732 else
5733 hostapd_disassoc_sta(tmp_hapd, tmp_sta,
5734 mgmt);
5735 break;
5736 }
5737 }
5738 }
5739
5740 /* Remove the station on which the association was performed. */
5741 if (!disassoc)
5742 hostapd_deauth_sta(assoc_hapd, assoc_sta, mgmt);
5743 else
5744 hostapd_disassoc_sta(assoc_hapd, assoc_sta, mgmt);
5745
5746 return true;
5747#else /* CONFIG_IEEE80211BE */
5748 return false;
5749#endif /* CONFIG_IEEE80211BE */
5750}
5751
5752
5753static void handle_disassoc(struct hostapd_data *hapd,
5754 const struct ieee80211_mgmt *mgmt, size_t len)
5755{
5756 struct sta_info *sta;
5757
5758 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
5759 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5760 "handle_disassoc - too short payload (len=%lu)",
5761 (unsigned long) len);
5762 return;
5763 }
5764
5765 sta = ap_get_sta(hapd, mgmt->sa);
5766 if (!sta) {
5767 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
5768 " trying to disassociate, but it is not associated",
5769 MAC2STR(mgmt->sa));
5770 return;
5771 }
5772
5773 if (hostapd_ml_handle_disconnect(hapd, sta, mgmt, true))
5774 return;
5775
5776 hostapd_disassoc_sta(hapd, sta, mgmt);
5777}
5778
5779
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005780static void handle_deauth(struct hostapd_data *hapd,
5781 const struct ieee80211_mgmt *mgmt, size_t len)
5782{
5783 struct sta_info *sta;
5784
5785 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005786 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5787 "handle_deauth - too short payload (len=%lu)",
5788 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005789 return;
5790 }
5791
Hai Shaloma20dcd72022-02-04 13:43:00 -08005792 /* Clear the PTKSA cache entries for PASN */
5793 ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
5794
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005795 sta = ap_get_sta(hapd, mgmt->sa);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005796 if (!sta) {
5797 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
5798 " trying to deauthenticate, but it is not authenticated",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005799 MAC2STR(mgmt->sa));
5800 return;
5801 }
5802
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005803 if (hostapd_ml_handle_disconnect(hapd, sta, mgmt, false))
5804 return;
5805
5806 hostapd_deauth_sta(hapd, sta, mgmt);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005807}
5808
5809
5810static void handle_beacon(struct hostapd_data *hapd,
5811 const struct ieee80211_mgmt *mgmt, size_t len,
5812 struct hostapd_frame_info *fi)
5813{
5814 struct ieee802_11_elems elems;
5815
5816 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005817 wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
5818 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005819 return;
5820 }
5821
5822 (void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
5823 len - (IEEE80211_HDRLEN +
5824 sizeof(mgmt->u.beacon)), &elems,
5825 0);
5826
5827 ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
5828}
5829
5830
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005831static int robust_action_frame(u8 category)
5832{
5833 return category != WLAN_ACTION_PUBLIC &&
5834 category != WLAN_ACTION_HT;
5835}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005836
5837
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005838static int handle_action(struct hostapd_data *hapd,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005839 const struct ieee80211_mgmt *mgmt, size_t len,
5840 unsigned int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005841{
5842 struct sta_info *sta;
Hai Shalom74f70d42019-02-11 14:42:39 -08005843 u8 *action __maybe_unused;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005844
Hai Shalom74f70d42019-02-11 14:42:39 -08005845 if (len < IEEE80211_HDRLEN + 2 + 1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005846 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5847 HOSTAPD_LEVEL_DEBUG,
5848 "handle_action - too short payload (len=%lu)",
5849 (unsigned long) len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005850 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005851 }
5852
Hai Shalom74f70d42019-02-11 14:42:39 -08005853 action = (u8 *) &mgmt->u.action.u;
5854 wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
5855 " da " MACSTR " len %d freq %u",
5856 mgmt->u.action.category, *action,
5857 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
5858
5859 sta = ap_get_sta(hapd, mgmt->sa);
5860
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005861 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
5862 (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
5863 wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
5864 "frame (category=%u) from unassociated STA " MACSTR,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005865 mgmt->u.action.category, MAC2STR(mgmt->sa));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005866 return 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005867 }
5868
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005869 if (sta && (sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt18463232014-01-24 12:29:41 -08005870 !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
5871 robust_action_frame(mgmt->u.action.category)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005872 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5873 HOSTAPD_LEVEL_DEBUG,
5874 "Dropped unprotected Robust Action frame from "
5875 "an MFP STA");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005876 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005877 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005878
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005879 if (sta) {
5880 u16 fc = le_to_host16(mgmt->frame_control);
5881 u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
5882
5883 if ((fc & WLAN_FC_RETRY) &&
5884 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
5885 sta->last_seq_ctrl == seq_ctrl &&
5886 sta->last_subtype == WLAN_FC_STYPE_ACTION) {
5887 hostapd_logger(hapd, sta->addr,
5888 HOSTAPD_MODULE_IEEE80211,
5889 HOSTAPD_LEVEL_DEBUG,
5890 "Drop repeated action frame seq_ctrl=0x%x",
5891 seq_ctrl);
5892 return 1;
5893 }
5894
5895 sta->last_seq_ctrl = seq_ctrl;
5896 sta->last_subtype = WLAN_FC_STYPE_ACTION;
5897 }
5898
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005899 switch (mgmt->u.action.category) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005900#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005901 case WLAN_ACTION_FT:
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005902 if (!sta ||
5903 wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005904 len - IEEE80211_HDRLEN))
5905 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005906 return 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005907#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005908 case WLAN_ACTION_WMM:
5909 hostapd_wmm_action(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005910 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005911 case WLAN_ACTION_SA_QUERY:
Hai Shalom021b0b52019-04-10 11:17:58 -07005912 ieee802_11_sa_query_action(hapd, mgmt, len);
5913 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005914#ifdef CONFIG_WNM_AP
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005915 case WLAN_ACTION_WNM:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005916 ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
5917 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005918#endif /* CONFIG_WNM_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005919#ifdef CONFIG_FST
5920 case WLAN_ACTION_FST:
5921 if (hapd->iface->fst)
5922 fst_rx_action(hapd->iface->fst, mgmt, len);
5923 else
5924 wpa_printf(MSG_DEBUG,
5925 "FST: Ignore FST Action frame - no FST attached");
5926 return 1;
5927#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005928 case WLAN_ACTION_PUBLIC:
Dmitry Shmidt18463232014-01-24 12:29:41 -08005929 case WLAN_ACTION_PROTECTED_DUAL:
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07005930 if (len >= IEEE80211_HDRLEN + 2 &&
5931 mgmt->u.action.u.public_action.action ==
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005932 WLAN_PA_20_40_BSS_COEX) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005933 hostapd_2040_coex_action(hapd, mgmt, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005934 return 1;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005935 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005936#ifdef CONFIG_DPP
5937 if (len >= IEEE80211_HDRLEN + 6 &&
5938 mgmt->u.action.u.vs_public_action.action ==
5939 WLAN_PA_VENDOR_SPECIFIC &&
5940 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
5941 OUI_WFA &&
5942 mgmt->u.action.u.vs_public_action.variable[0] ==
5943 DPP_OUI_TYPE) {
5944 const u8 *pos, *end;
5945
5946 pos = mgmt->u.action.u.vs_public_action.oui;
5947 end = ((const u8 *) mgmt) + len;
5948 hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005949 freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005950 return 1;
5951 }
5952 if (len >= IEEE80211_HDRLEN + 2 &&
5953 (mgmt->u.action.u.public_action.action ==
5954 WLAN_PA_GAS_INITIAL_RESP ||
5955 mgmt->u.action.u.public_action.action ==
5956 WLAN_PA_GAS_COMEBACK_RESP)) {
5957 const u8 *pos, *end;
5958
5959 pos = &mgmt->u.action.u.public_action.action;
5960 end = ((const u8 *) mgmt) + len;
Sunil Ravi036cec52023-03-29 11:35:17 -07005961 if (gas_query_ap_rx(hapd->gas, mgmt->sa,
5962 mgmt->u.action.category,
5963 pos, end - pos, freq) == 0)
5964 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005965 }
5966#endif /* CONFIG_DPP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005967 if (hapd->public_action_cb) {
5968 hapd->public_action_cb(hapd->public_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08005969 (u8 *) mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005970 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08005971 if (hapd->public_action_cb2) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005972 hapd->public_action_cb2(hapd->public_action_cb2_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08005973 (u8 *) mgmt, len, freq);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08005974 }
5975 if (hapd->public_action_cb || hapd->public_action_cb2)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005976 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005977 break;
5978 case WLAN_ACTION_VENDOR_SPECIFIC:
5979 if (hapd->vendor_action_cb) {
5980 if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08005981 (u8 *) mgmt, len, freq) == 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005982 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005983 }
5984 break;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005985 case WLAN_ACTION_RADIO_MEASUREMENT:
5986 hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
5987 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005988 }
5989
5990 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5991 HOSTAPD_LEVEL_DEBUG,
5992 "handle_action - unknown action category %d or invalid "
5993 "frame",
5994 mgmt->u.action.category);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07005995 if (!is_multicast_ether_addr(mgmt->da) &&
5996 !(mgmt->u.action.category & 0x80) &&
5997 !is_multicast_ether_addr(mgmt->sa)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005998 struct ieee80211_mgmt *resp;
5999
6000 /*
6001 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
6002 * Return the Action frame to the source without change
6003 * except that MSB of the Category set to 1.
6004 */
6005 wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
6006 "frame back to sender");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006007 resp = os_memdup(mgmt, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006008 if (resp == NULL)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006009 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006010 os_memcpy(resp->da, resp->sa, ETH_ALEN);
6011 os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
6012 os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
6013 resp->u.action.category |= 0x80;
6014
Hai Shalomfdcde762020-04-02 11:19:20 -07006015 if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006016 wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
6017 "Action frame");
6018 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006019 os_free(resp);
6020 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006021
6022 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006023}
6024
6025
6026/**
Hai Shalom60840252021-02-19 19:02:11 -08006027 * notify_mgmt_frame - Notify of Management frames on the control interface
6028 * @hapd: hostapd BSS data structure (the BSS to which the Management frame was
6029 * sent to)
6030 * @buf: Management frame data (starting from the IEEE 802.11 header)
6031 * @len: Length of frame data in octets
6032 *
6033 * Notify the control interface of any received Management frame.
6034 */
6035static void notify_mgmt_frame(struct hostapd_data *hapd, const u8 *buf,
6036 size_t len)
6037{
6038
6039 int hex_len = len * 2 + 1;
6040 char *hex = os_malloc(hex_len);
6041
6042 if (hex) {
6043 wpa_snprintf_hex(hex, hex_len, buf, len);
6044 wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO,
6045 AP_MGMT_FRAME_RECEIVED "buf=%s", hex);
6046 os_free(hex);
6047 }
6048}
6049
6050
6051/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006052 * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
6053 * @hapd: hostapd BSS data structure (the BSS to which the management frame was
6054 * sent to)
6055 * @buf: management frame data (starting from IEEE 802.11 header)
6056 * @len: length of frame data in octets
6057 * @fi: meta data about received frame (signal level, etc.)
6058 *
6059 * Process all incoming IEEE 802.11 management frames. This will be called for
6060 * each frame received from the kernel driver through wlan#ap interface. In
6061 * addition, it can be called to re-inserted pending frames (e.g., when using
6062 * external RADIUS server as an MAC ACL).
6063 */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006064int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
6065 struct hostapd_frame_info *fi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006066{
6067 struct ieee80211_mgmt *mgmt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006068 u16 fc, stype;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006069 int ret = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006070 unsigned int freq;
6071 int ssi_signal = fi ? fi->ssi_signal : 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006072
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006073 if (len < 24)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006074 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006075
Roshan Pius3a1667e2018-07-03 15:17:14 -07006076 if (fi && fi->freq)
6077 freq = fi->freq;
6078 else
6079 freq = hapd->iface->freq;
6080
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006081 mgmt = (struct ieee80211_mgmt *) buf;
6082 fc = le_to_host16(mgmt->frame_control);
6083 stype = WLAN_FC_GET_STYPE(fc);
6084
Hai Shalomc3565922019-10-28 11:58:20 -07006085 if (is_multicast_ether_addr(mgmt->sa) ||
6086 is_zero_ether_addr(mgmt->sa) ||
6087 os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
6088 /* Do not process any frames with unexpected/invalid SA so that
6089 * we do not add any state for unexpected STA addresses or end
6090 * up sending out frames to unexpected destination. */
6091 wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
6092 " in received frame - ignore this frame silently",
6093 MAC2STR(mgmt->sa));
6094 return 0;
6095 }
6096
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006097 if (stype == WLAN_FC_STYPE_BEACON) {
6098 handle_beacon(hapd, mgmt, len, fi);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006099 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006100 }
6101
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07006102 if (!is_broadcast_ether_addr(mgmt->bssid) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006103#ifdef CONFIG_P2P
6104 /* Invitation responses can be sent with the peer MAC as BSSID */
6105 !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
6106 stype == WLAN_FC_STYPE_ACTION) &&
6107#endif /* CONFIG_P2P */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006108#ifdef CONFIG_MESH
6109 !(hapd->conf->mesh & MESH_ENABLED) &&
6110#endif /* CONFIG_MESH */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006111#ifdef CONFIG_IEEE80211BE
6112 !(hapd->conf->mld_ap &&
6113 os_memcmp(hapd->mld_addr, mgmt->bssid, ETH_ALEN) == 0) &&
6114#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006115 os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006116 wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
6117 MAC2STR(mgmt->bssid));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006118 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006119 }
6120
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006121 if (hapd->iface->state != HAPD_IFACE_ENABLED) {
6122 wpa_printf(MSG_DEBUG, "MGMT: Ignore management frame while interface is not enabled (SA=" MACSTR " DA=" MACSTR " subtype=%u)",
6123 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), stype);
6124 return 1;
6125 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006126
6127 if (stype == WLAN_FC_STYPE_PROBE_REQ) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006128 handle_probe_req(hapd, mgmt, len, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006129 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006130 }
6131
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006132 if ((!is_broadcast_ether_addr(mgmt->da) ||
6133 stype != WLAN_FC_STYPE_ACTION) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006134#ifdef CONFIG_IEEE80211BE
6135 !(hapd->conf->mld_ap &&
6136 os_memcmp(hapd->mld_addr, mgmt->bssid, ETH_ALEN) == 0) &&
6137#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006138 os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006139 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6140 HOSTAPD_LEVEL_DEBUG,
6141 "MGMT: DA=" MACSTR " not our address",
6142 MAC2STR(mgmt->da));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006143 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006144 }
6145
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006146 if (hapd->iconf->track_sta_max_num)
Roshan Pius3a1667e2018-07-03 15:17:14 -07006147 sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006148
Hai Shalom60840252021-02-19 19:02:11 -08006149 if (hapd->conf->notify_mgmt_frames)
6150 notify_mgmt_frame(hapd, buf, len);
6151
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006152 switch (stype) {
6153 case WLAN_FC_STYPE_AUTH:
6154 wpa_printf(MSG_DEBUG, "mgmt::auth");
Hai Shalom021b0b52019-04-10 11:17:58 -07006155 handle_auth(hapd, mgmt, len, ssi_signal, 0);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006156 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006157 break;
6158 case WLAN_FC_STYPE_ASSOC_REQ:
6159 wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006160 handle_assoc(hapd, mgmt, len, 0, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006161 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006162 break;
6163 case WLAN_FC_STYPE_REASSOC_REQ:
6164 wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006165 handle_assoc(hapd, mgmt, len, 1, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006166 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006167 break;
6168 case WLAN_FC_STYPE_DISASSOC:
6169 wpa_printf(MSG_DEBUG, "mgmt::disassoc");
6170 handle_disassoc(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006171 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006172 break;
6173 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006174 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006175 handle_deauth(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006176 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006177 break;
6178 case WLAN_FC_STYPE_ACTION:
6179 wpa_printf(MSG_DEBUG, "mgmt::action");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006180 ret = handle_action(hapd, mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006181 break;
6182 default:
6183 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6184 HOSTAPD_LEVEL_DEBUG,
6185 "unknown mgmt frame subtype %d", stype);
6186 break;
6187 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006188
6189 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006190}
6191
6192
6193static void handle_auth_cb(struct hostapd_data *hapd,
6194 const struct ieee80211_mgmt *mgmt,
6195 size_t len, int ok)
6196{
6197 u16 auth_alg, auth_transaction, status_code;
6198 struct sta_info *sta;
Hai Shalom60840252021-02-19 19:02:11 -08006199 bool success_status;
Hai Shalome5e28bb2019-01-28 14:51:04 -08006200
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006201 sta = ap_get_sta(hapd, mgmt->da);
6202 if (!sta) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006203 wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
6204 " not found",
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006205 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006206 return;
6207 }
6208
Hai Shalom60840252021-02-19 19:02:11 -08006209 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
6210 wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
6211 (unsigned long) len);
6212 auth_alg = 0;
6213 auth_transaction = 0;
6214 status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
6215 goto fail;
6216 }
6217
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006218 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
6219 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
6220 status_code = le_to_host16(mgmt->u.auth.status_code);
6221
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006222 if (!ok) {
6223 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6224 HOSTAPD_LEVEL_NOTICE,
6225 "did not acknowledge authentication response");
6226 goto fail;
6227 }
6228
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006229 if (status_code == WLAN_STATUS_SUCCESS &&
6230 ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
6231 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
6232 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6233 HOSTAPD_LEVEL_INFO, "authenticated");
6234 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006235 if (sta->added_unassoc)
6236 hostapd_set_sta_flags(hapd, sta);
6237 return;
6238 }
6239
6240fail:
Hai Shalom60840252021-02-19 19:02:11 -08006241 success_status = status_code == WLAN_STATUS_SUCCESS;
6242#ifdef CONFIG_SAE
6243 if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1)
6244 success_status = sae_status_success(hapd, status_code);
6245#endif /* CONFIG_SAE */
6246 if (!success_status && sta->added_unassoc) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006247 hostapd_drv_sta_remove(hapd, sta->addr);
6248 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006249 }
6250}
6251
6252
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006253static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
6254 struct sta_info *sta,
6255 char *ifname_wds)
6256{
Hai Shalomfdcde762020-04-02 11:19:20 -07006257#ifdef CONFIG_WEP
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006258 int i;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07006259 struct hostapd_ssid *ssid = &hapd->conf->ssid;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006260
6261 if (hapd->conf->ieee802_1x || hapd->conf->wpa)
6262 return;
6263
6264 for (i = 0; i < 4; i++) {
6265 if (ssid->wep.key[i] &&
6266 hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
Hai Shalomfdcde762020-04-02 11:19:20 -07006267 0, i == ssid->wep.idx, NULL, 0,
6268 ssid->wep.key[i], ssid->wep.len[i],
6269 i == ssid->wep.idx ?
6270 KEY_FLAG_GROUP_RX_TX_DEFAULT :
6271 KEY_FLAG_GROUP_RX_TX)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006272 wpa_printf(MSG_WARNING,
6273 "Could not set WEP keys for WDS interface; %s",
6274 ifname_wds);
6275 break;
6276 }
6277 }
Hai Shalomfdcde762020-04-02 11:19:20 -07006278#endif /* CONFIG_WEP */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006279}
6280
6281
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006282#ifdef CONFIG_IEEE80211BE
6283static void ieee80211_ml_link_sta_assoc_cb(struct hostapd_data *hapd,
6284 struct sta_info *sta,
6285 struct mld_link_info *link,
6286 bool ok)
6287{
6288 if (!ok) {
6289 hostapd_logger(hapd, link->peer_addr, HOSTAPD_MODULE_IEEE80211,
6290 HOSTAPD_LEVEL_DEBUG,
6291 "did not acknowledge association response");
6292 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
6293
6294 /* The STA is added only in case of SUCCESS */
6295 if (link->status == WLAN_STATUS_SUCCESS)
6296 hostapd_drv_sta_remove(hapd, sta->addr);
6297
6298 return;
6299 }
6300
6301 if (link->status != WLAN_STATUS_SUCCESS)
6302 return;
6303
6304 sta->flags |= WLAN_STA_ASSOC;
6305 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
6306
6307 if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
6308 ap_sta_set_authorized(hapd, sta, 1);
6309
6310 hostapd_set_sta_flags(hapd, sta);
6311
6312 /*
6313 * TODOs:
6314 * - IEEE 802.1X port enablement is not needed as done on the station
6315 * doing the connection.
6316 * - Not handling accounting
6317 * - Need to handle VLAN configuration
6318 */
6319}
6320#endif /* CONFIG_IEEE80211BE */
6321
6322
6323static void hostapd_ml_handle_assoc_cb(struct hostapd_data *hapd,
6324 struct sta_info *sta, bool ok)
6325{
6326#ifdef CONFIG_IEEE80211BE
6327 unsigned int i, link_id;
6328
6329 if (!hostapd_is_mld_ap(hapd))
6330 return;
6331
6332 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
6333 struct mld_link_info *link = &sta->mld_info.links[link_id];
6334
6335 if (!link->valid)
6336 continue;
6337
6338 for (i = 0; i < hapd->iface->interfaces->count; i++) {
6339 struct sta_info *tmp_sta;
6340 struct hostapd_data *tmp_hapd =
6341 hapd->iface->interfaces->iface[i]->bss[0];
6342
6343 if (tmp_hapd->conf->mld_ap ||
6344 hapd->conf->mld_id != tmp_hapd->conf->mld_id)
6345 continue;
6346
6347 for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
6348 tmp_sta = tmp_sta->next) {
6349 if (tmp_sta == sta ||
6350 tmp_sta->mld_assoc_link_id !=
6351 sta->mld_assoc_link_id ||
6352 tmp_sta->aid != sta->aid)
6353 continue;
6354
6355 ieee80211_ml_link_sta_assoc_cb(tmp_hapd,
6356 tmp_sta, link,
6357 ok);
6358 break;
6359 }
6360 }
6361 }
6362#endif /* CONFIG_IEEE80211BE */
6363}
6364
6365
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006366static void handle_assoc_cb(struct hostapd_data *hapd,
6367 const struct ieee80211_mgmt *mgmt,
6368 size_t len, int reassoc, int ok)
6369{
6370 u16 status;
6371 struct sta_info *sta;
6372 int new_assoc = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006373
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006374 sta = ap_get_sta(hapd, mgmt->da);
6375 if (!sta) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006376 wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
6377 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006378 return;
6379 }
6380
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006381#ifdef CONFIG_IEEE80211BE
6382 if (hapd->conf->mld_ap && sta->mld_info.mld_sta &&
6383 hapd->mld_link_id != sta->mld_assoc_link_id) {
6384 /* See ieee80211_ml_link_sta_assoc_cb() for the MLD case */
6385 wpa_printf(MSG_DEBUG,
6386 "%s: MLD: ignore on link station (%d != %d)",
6387 __func__, hapd->mld_link_id, sta->mld_assoc_link_id);
6388 return;
6389 }
6390#endif /* CONFIG_IEEE80211BE */
6391
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006392 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
6393 sizeof(mgmt->u.assoc_resp))) {
6394 wpa_printf(MSG_INFO,
6395 "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
6396 reassoc, (unsigned long) len);
6397 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006398 return;
6399 }
6400
6401 if (reassoc)
6402 status = le_to_host16(mgmt->u.reassoc_resp.status_code);
6403 else
6404 status = le_to_host16(mgmt->u.assoc_resp.status_code);
6405
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006406 if (!ok) {
6407 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6408 HOSTAPD_LEVEL_DEBUG,
6409 "did not acknowledge association response");
6410 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
6411 /* The STA is added only in case of SUCCESS */
6412 if (status == WLAN_STATUS_SUCCESS)
6413 hostapd_drv_sta_remove(hapd, sta->addr);
6414
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006415 goto handle_ml;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006416 }
6417
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006418 if (status != WLAN_STATUS_SUCCESS)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006419 goto handle_ml;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006420
6421 /* Stop previous accounting session, if one is started, and allocate
6422 * new session id for the new session. */
6423 accounting_sta_stop(hapd, sta);
6424
6425 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6426 HOSTAPD_LEVEL_INFO,
6427 "associated (aid %d)",
6428 sta->aid);
6429
6430 if (sta->flags & WLAN_STA_ASSOC)
6431 new_assoc = 0;
6432 sta->flags |= WLAN_STA_ASSOC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006433 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006434 if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
6435 !hapd->conf->osen) ||
6436 sta->auth_alg == WLAN_AUTH_FILS_SK ||
6437 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6438 sta->auth_alg == WLAN_AUTH_FILS_PK ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006439 sta->auth_alg == WLAN_AUTH_FT) {
6440 /*
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006441 * Open, static WEP, FT protocol, or FILS; no separate
6442 * authorization step.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006443 */
6444 ap_sta_set_authorized(hapd, sta, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006445 }
6446
6447 if (reassoc)
6448 mlme_reassociate_indication(hapd, sta);
6449 else
6450 mlme_associate_indication(hapd, sta);
6451
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006452 sta->sa_query_timed_out = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006453
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006454 if (sta->eapol_sm == NULL) {
6455 /*
6456 * This STA does not use RADIUS server for EAP authentication,
6457 * so bind it to the selected VLAN interface now, since the
6458 * interface selection is not going to change anymore.
6459 */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006460 if (ap_sta_bind_vlan(hapd, sta) < 0)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006461 goto handle_ml;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006462 } else if (sta->vlan_id) {
6463 /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006464 if (ap_sta_bind_vlan(hapd, sta) < 0)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006465 goto handle_ml;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006466 }
6467
6468 hostapd_set_sta_flags(hapd, sta);
6469
Dmitry Shmidt29333592017-01-09 12:27:11 -08006470 if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) {
6471 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA "
6472 MACSTR " based on pending request",
6473 MAC2STR(sta->addr));
6474 sta->pending_wds_enable = 0;
6475 sta->flags |= WLAN_STA_WDS;
6476 }
6477
Sunil Ravi640215c2023-06-28 23:08:09 +00006478 /* WPS not supported on backhaul BSS. Disable 4addr mode on fronthaul */
6479 if ((sta->flags & WLAN_STA_WDS) ||
6480 (sta->flags & WLAN_STA_MULTI_AP &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006481 (hapd->conf->multi_ap & BACKHAUL_BSS) &&
Sunil Ravi640215c2023-06-28 23:08:09 +00006482 !(sta->flags & WLAN_STA_WPS))) {
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08006483 int ret;
6484 char ifname_wds[IFNAMSIZ + 1];
6485
6486 wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA "
6487 MACSTR " (aid %u)",
6488 MAC2STR(sta->addr), sta->aid);
6489 ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
6490 sta->aid, 1);
6491 if (!ret)
6492 hostapd_set_wds_encryption(hapd, sta, ifname_wds);
6493 }
6494
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006495 if (sta->auth_alg == WLAN_AUTH_FT)
6496 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
6497 else
6498 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
6499 hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006500 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006501
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006502#ifdef CONFIG_FILS
6503 if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
6504 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6505 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
6506 fils_set_tk(sta->wpa_sm) < 0) {
6507 wpa_printf(MSG_DEBUG, "FILS: TK configuration failed");
6508 ap_sta_disconnect(hapd, sta, sta->addr,
6509 WLAN_REASON_UNSPECIFIED);
6510 return;
6511 }
6512#endif /* CONFIG_FILS */
6513
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006514 if (sta->pending_eapol_rx) {
6515 struct os_reltime now, age;
6516
6517 os_get_reltime(&now);
6518 os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
6519 if (age.sec == 0 && age.usec < 200000) {
6520 wpa_printf(MSG_DEBUG,
6521 "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
6522 MAC2STR(sta->addr));
6523 ieee802_1x_receive(
6524 hapd, mgmt->da,
6525 wpabuf_head(sta->pending_eapol_rx->buf),
Sunil8cd6f4d2022-06-28 18:40:46 +00006526 wpabuf_len(sta->pending_eapol_rx->buf),
6527 sta->pending_eapol_rx->encrypted);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006528 }
6529 wpabuf_free(sta->pending_eapol_rx->buf);
6530 os_free(sta->pending_eapol_rx);
6531 sta->pending_eapol_rx = NULL;
6532 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006533
6534handle_ml:
6535 hostapd_ml_handle_assoc_cb(hapd, sta, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006536}
6537
6538
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006539static void handle_deauth_cb(struct hostapd_data *hapd,
6540 const struct ieee80211_mgmt *mgmt,
6541 size_t len, int ok)
6542{
6543 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006544 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006545 return;
6546 sta = ap_get_sta(hapd, mgmt->da);
6547 if (!sta) {
6548 wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
6549 " not found", MAC2STR(mgmt->da));
6550 return;
6551 }
6552 if (ok)
6553 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
6554 MAC2STR(sta->addr));
6555 else
6556 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6557 "deauth", MAC2STR(sta->addr));
6558
6559 ap_sta_deauth_cb(hapd, sta);
6560}
6561
6562
6563static void handle_disassoc_cb(struct hostapd_data *hapd,
6564 const struct ieee80211_mgmt *mgmt,
6565 size_t len, int ok)
6566{
6567 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006568 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006569 return;
6570 sta = ap_get_sta(hapd, mgmt->da);
6571 if (!sta) {
6572 wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
6573 " not found", MAC2STR(mgmt->da));
6574 return;
6575 }
6576 if (ok)
6577 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
6578 MAC2STR(sta->addr));
6579 else
6580 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6581 "disassoc", MAC2STR(sta->addr));
6582
6583 ap_sta_disassoc_cb(hapd, sta);
6584}
6585
6586
Dmitry Shmidt29333592017-01-09 12:27:11 -08006587static void handle_action_cb(struct hostapd_data *hapd,
6588 const struct ieee80211_mgmt *mgmt,
6589 size_t len, int ok)
6590{
6591 struct sta_info *sta;
Paul Stewart092955c2017-02-06 09:13:09 -08006592 const struct rrm_measurement_report_element *report;
Dmitry Shmidt29333592017-01-09 12:27:11 -08006593
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006594#ifdef CONFIG_DPP
6595 if (len >= IEEE80211_HDRLEN + 6 &&
6596 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6597 mgmt->u.action.u.vs_public_action.action ==
6598 WLAN_PA_VENDOR_SPECIFIC &&
6599 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6600 OUI_WFA &&
6601 mgmt->u.action.u.vs_public_action.variable[0] ==
6602 DPP_OUI_TYPE) {
6603 const u8 *pos, *end;
6604
6605 pos = &mgmt->u.action.u.vs_public_action.variable[1];
6606 end = ((const u8 *) mgmt) + len;
6607 hostapd_dpp_tx_status(hapd, mgmt->da, pos, end - pos, ok);
6608 return;
6609 }
6610 if (len >= IEEE80211_HDRLEN + 2 &&
6611 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6612 (mgmt->u.action.u.public_action.action ==
6613 WLAN_PA_GAS_INITIAL_REQ ||
6614 mgmt->u.action.u.public_action.action ==
6615 WLAN_PA_GAS_COMEBACK_REQ)) {
6616 const u8 *pos, *end;
6617
6618 pos = mgmt->u.action.u.public_action.variable;
6619 end = ((const u8 *) mgmt) + len;
6620 gas_query_ap_tx_status(hapd->gas, mgmt->da, pos, end - pos, ok);
6621 return;
6622 }
6623#endif /* CONFIG_DPP */
Hai Shaloma20dcd72022-02-04 13:43:00 -08006624 if (is_multicast_ether_addr(mgmt->da))
6625 return;
Dmitry Shmidt29333592017-01-09 12:27:11 -08006626 sta = ap_get_sta(hapd, mgmt->da);
6627 if (!sta) {
6628 wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR
6629 " not found", MAC2STR(mgmt->da));
6630 return;
6631 }
6632
Sunil Ravi77d572f2023-01-17 23:58:31 +00006633#ifdef CONFIG_HS20
6634 if (ok && len >= IEEE80211_HDRLEN + 2 &&
6635 mgmt->u.action.category == WLAN_ACTION_WNM &&
6636 mgmt->u.action.u.vs_public_action.action == WNM_NOTIFICATION_REQ &&
6637 sta->hs20_deauth_on_ack) {
6638 wpa_printf(MSG_DEBUG, "HS 2.0: Deauthenticate STA " MACSTR
6639 " on acknowledging the WNM-Notification",
6640 MAC2STR(sta->addr));
6641 ap_sta_session_timeout(hapd, sta, 0);
6642 return;
6643 }
6644#endif /* CONFIG_HS20 */
6645
Paul Stewart092955c2017-02-06 09:13:09 -08006646 if (len < 24 + 5 + sizeof(*report))
Dmitry Shmidt29333592017-01-09 12:27:11 -08006647 return;
Paul Stewart092955c2017-02-06 09:13:09 -08006648 report = (const struct rrm_measurement_report_element *)
6649 &mgmt->u.action.u.rrm.variable[2];
Dmitry Shmidt29333592017-01-09 12:27:11 -08006650 if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT &&
Paul Stewart092955c2017-02-06 09:13:09 -08006651 mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST &&
6652 report->eid == WLAN_EID_MEASURE_REQUEST &&
6653 report->len >= 3 &&
6654 report->type == MEASURE_TYPE_BEACON)
Dmitry Shmidt29333592017-01-09 12:27:11 -08006655 hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok);
6656}
6657
6658
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006659/**
6660 * ieee802_11_mgmt_cb - Process management frame TX status callback
6661 * @hapd: hostapd BSS data structure (the BSS from which the management frame
6662 * was sent from)
6663 * @buf: management frame data (starting from IEEE 802.11 header)
6664 * @len: length of frame data in octets
6665 * @stype: management frame subtype from frame control field
6666 * @ok: Whether the frame was ACK'ed
6667 */
6668void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
6669 u16 stype, int ok)
6670{
6671 const struct ieee80211_mgmt *mgmt;
6672 mgmt = (const struct ieee80211_mgmt *) buf;
6673
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006674#ifdef CONFIG_TESTING_OPTIONS
6675 if (hapd->ext_mgmt_frame_handling) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006676 size_t hex_len = 2 * len + 1;
6677 char *hex = os_malloc(hex_len);
6678
6679 if (hex) {
6680 wpa_snprintf_hex(hex, hex_len, buf, len);
6681 wpa_msg(hapd->msg_ctx, MSG_INFO,
6682 "MGMT-TX-STATUS stype=%u ok=%d buf=%s",
6683 stype, ok, hex);
6684 os_free(hex);
6685 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006686 return;
6687 }
6688#endif /* CONFIG_TESTING_OPTIONS */
6689
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006690 switch (stype) {
6691 case WLAN_FC_STYPE_AUTH:
6692 wpa_printf(MSG_DEBUG, "mgmt::auth cb");
6693 handle_auth_cb(hapd, mgmt, len, ok);
6694 break;
6695 case WLAN_FC_STYPE_ASSOC_RESP:
6696 wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
6697 handle_assoc_cb(hapd, mgmt, len, 0, ok);
6698 break;
6699 case WLAN_FC_STYPE_REASSOC_RESP:
6700 wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
6701 handle_assoc_cb(hapd, mgmt, len, 1, ok);
6702 break;
6703 case WLAN_FC_STYPE_PROBE_RESP:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006704 wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006705 break;
6706 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006707 wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
6708 handle_deauth_cb(hapd, mgmt, len, ok);
6709 break;
6710 case WLAN_FC_STYPE_DISASSOC:
6711 wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
6712 handle_disassoc_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006713 break;
6714 case WLAN_FC_STYPE_ACTION:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006715 wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006716 handle_action_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006717 break;
6718 default:
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006719 wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006720 break;
6721 }
6722}
6723
6724
6725int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
6726{
6727 /* TODO */
6728 return 0;
6729}
6730
6731
6732int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
6733 char *buf, size_t buflen)
6734{
6735 /* TODO */
6736 return 0;
6737}
6738
6739
6740void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
6741 const u8 *buf, size_t len, int ack)
6742{
6743 struct sta_info *sta;
6744 struct hostapd_iface *iface = hapd->iface;
6745
6746 sta = ap_get_sta(hapd, addr);
6747 if (sta == NULL && iface->num_bss > 1) {
6748 size_t j;
6749 for (j = 0; j < iface->num_bss; j++) {
6750 hapd = iface->bss[j];
6751 sta = ap_get_sta(hapd, addr);
6752 if (sta)
6753 break;
6754 }
6755 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006756 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006757 return;
6758 if (sta->flags & WLAN_STA_PENDING_POLL) {
6759 wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
6760 "activity poll", MAC2STR(sta->addr),
6761 ack ? "ACKed" : "did not ACK");
6762 if (ack)
6763 sta->flags &= ~WLAN_STA_PENDING_POLL;
6764 }
6765
6766 ieee802_1x_tx_status(hapd, sta, buf, len, ack);
6767}
6768
6769
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006770void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
6771 const u8 *data, size_t len, int ack)
6772{
6773 struct sta_info *sta;
6774 struct hostapd_iface *iface = hapd->iface;
6775
6776 sta = ap_get_sta(hapd, dst);
6777 if (sta == NULL && iface->num_bss > 1) {
6778 size_t j;
6779 for (j = 0; j < iface->num_bss; j++) {
6780 hapd = iface->bss[j];
6781 sta = ap_get_sta(hapd, dst);
6782 if (sta)
6783 break;
6784 }
6785 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006786 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
6787 wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA "
6788 MACSTR " that is not currently associated",
6789 MAC2STR(dst));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006790 return;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006791 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006792
6793 ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
6794}
6795
6796
6797void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
6798{
6799 struct sta_info *sta;
6800 struct hostapd_iface *iface = hapd->iface;
6801
6802 sta = ap_get_sta(hapd, addr);
6803 if (sta == NULL && iface->num_bss > 1) {
6804 size_t j;
6805 for (j = 0; j < iface->num_bss; j++) {
6806 hapd = iface->bss[j];
6807 sta = ap_get_sta(hapd, addr);
6808 if (sta)
6809 break;
6810 }
6811 }
6812 if (sta == NULL)
6813 return;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006814 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
6815 MAC2STR(sta->addr));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006816 if (!(sta->flags & WLAN_STA_PENDING_POLL))
6817 return;
6818
6819 wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
6820 "activity poll", MAC2STR(sta->addr));
6821 sta->flags &= ~WLAN_STA_PENDING_POLL;
6822}
6823
6824
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006825void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
6826 int wds)
6827{
6828 struct sta_info *sta;
6829
6830 sta = ap_get_sta(hapd, src);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006831 if (sta &&
6832 ((sta->flags & WLAN_STA_ASSOC) ||
6833 ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006834 if (!hapd->conf->wds_sta)
6835 return;
6836
Dmitry Shmidt29333592017-01-09 12:27:11 -08006837 if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) ==
6838 WLAN_STA_ASSOC_REQ_OK) {
6839 wpa_printf(MSG_DEBUG,
6840 "Postpone 4-address WDS mode enabling for STA "
6841 MACSTR " since TX status for AssocResp is not yet known",
6842 MAC2STR(sta->addr));
6843 sta->pending_wds_enable = 1;
6844 return;
6845 }
6846
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006847 if (wds && !(sta->flags & WLAN_STA_WDS)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006848 int ret;
6849 char ifname_wds[IFNAMSIZ + 1];
6850
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006851 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
6852 "STA " MACSTR " (aid %u)",
6853 MAC2STR(sta->addr), sta->aid);
6854 sta->flags |= WLAN_STA_WDS;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006855 ret = hostapd_set_wds_sta(hapd, ifname_wds,
6856 sta->addr, sta->aid, 1);
6857 if (!ret)
6858 hostapd_set_wds_encryption(hapd, sta,
6859 ifname_wds);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006860 }
6861 return;
6862 }
6863
6864 wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
6865 MACSTR, MAC2STR(src));
Hai Shalomc3565922019-10-28 11:58:20 -07006866 if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
6867 os_memcmp(src, hapd->own_addr, ETH_ALEN) == 0) {
6868 /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
6869 * silently. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006870 return;
6871 }
6872
6873 if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) {
6874 wpa_printf(MSG_DEBUG, "Association Response to the STA has "
6875 "already been sent, but no TX status yet known - "
6876 "ignore Class 3 frame issue with " MACSTR,
6877 MAC2STR(src));
6878 return;
6879 }
6880
6881 if (sta && (sta->flags & WLAN_STA_AUTH))
6882 hostapd_drv_sta_disassoc(
6883 hapd, src,
6884 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
6885 else
6886 hostapd_drv_sta_deauth(
6887 hapd, src,
6888 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
6889}
6890
6891
Sunil Ravia04bd252022-05-02 22:54:18 -07006892static u8 * hostapd_add_tpe_info(u8 *eid, u8 tx_pwr_count,
6893 enum max_tx_pwr_interpretation tx_pwr_intrpn,
6894 u8 tx_pwr_cat, u8 tx_pwr)
6895{
6896 int i;
6897
6898 *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE; /* Element ID */
6899 *eid++ = 2 + tx_pwr_count; /* Length */
6900
6901 /*
6902 * Transmit Power Information field
6903 * bits 0-2 : Maximum Transmit Power Count
6904 * bits 3-5 : Maximum Transmit Power Interpretation
6905 * bits 6-7 : Maximum Transmit Power Category
6906 */
6907 *eid++ = tx_pwr_count | (tx_pwr_intrpn << 3) | (tx_pwr_cat << 6);
6908
6909 /* Maximum Transmit Power field */
6910 for (i = 0; i <= tx_pwr_count; i++)
6911 *eid++ = tx_pwr;
6912
6913 return eid;
6914}
6915
6916
6917/*
6918 * TODO: Extract power limits from channel data after 6G regulatory
6919 * support.
6920 */
6921#define REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT (-1) /* dBm/MHz */
6922#define REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT 5 /* dBm/MHz */
6923
Hai Shalom60840252021-02-19 19:02:11 -08006924u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
6925{
6926 struct hostapd_iface *iface = hapd->iface;
6927 struct hostapd_config *iconf = iface->conf;
6928 struct hostapd_hw_modes *mode = iface->current_mode;
6929 struct hostapd_channel_data *chan;
6930 int dfs, i;
6931 u8 channel, tx_pwr_count, local_pwr_constraint;
6932 int max_tx_power;
6933 u8 tx_pwr;
6934
6935 if (!mode)
6936 return eid;
6937
6938 if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
6939 return eid;
6940
6941 for (i = 0; i < mode->num_channels; i++) {
6942 if (mode->channels[i].freq == iface->freq)
6943 break;
6944 }
6945 if (i == mode->num_channels)
6946 return eid;
6947
Sunil Ravia04bd252022-05-02 22:54:18 -07006948#ifdef CONFIG_IEEE80211AX
6949 /* IEEE Std 802.11ax-2021, Annex E.2.7 (6 GHz band in the United
6950 * States): An AP that is an Indoor Access Point per regulatory rules
6951 * shall send at least two Transmit Power Envelope elements in Beacon
6952 * and Probe Response frames as follows:
6953 * - Maximum Transmit Power Category subfield = Default;
6954 * Unit interpretation = Regulatory client EIRP PSD
6955 * - Maximum Transmit Power Category subfield = Subordinate Device;
6956 * Unit interpretation = Regulatory client EIRP PSD
6957 */
6958 if (is_6ghz_op_class(iconf->op_class)) {
6959 enum max_tx_pwr_interpretation tx_pwr_intrpn;
6960
6961 /* Same Maximum Transmit Power for all 20 MHz bands */
6962 tx_pwr_count = 0;
6963 tx_pwr_intrpn = REGULATORY_CLIENT_EIRP_PSD;
6964
6965 /* Default Transmit Power Envelope for Global Operating Class */
6966 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT * 2;
6967 eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn,
6968 REG_DEFAULT_CLIENT, tx_pwr);
6969
6970 /* Indoor Access Point must include an additional TPE for
6971 * subordinate devices */
6972 if (iconf->he_6ghz_reg_pwr_type == HE_6GHZ_INDOOR_AP) {
6973 /* TODO: Extract PSD limits from channel data */
6974 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT * 2;
6975 eid = hostapd_add_tpe_info(eid, tx_pwr_count,
6976 tx_pwr_intrpn,
6977 REG_SUBORDINATE_CLIENT,
6978 tx_pwr);
6979 }
6980
6981 return eid;
6982 }
6983#endif /* CONFIG_IEEE80211AX */
6984
Hai Shalom60840252021-02-19 19:02:11 -08006985 switch (hostapd_get_oper_chwidth(iconf)) {
Sunil8cd6f4d2022-06-28 18:40:46 +00006986 case CONF_OPER_CHWIDTH_USE_HT:
Hai Shalom60840252021-02-19 19:02:11 -08006987 if (iconf->secondary_channel == 0) {
6988 /* Max Transmit Power count = 0 (20 MHz) */
6989 tx_pwr_count = 0;
6990 } else {
6991 /* Max Transmit Power count = 1 (20, 40 MHz) */
6992 tx_pwr_count = 1;
6993 }
6994 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00006995 case CONF_OPER_CHWIDTH_80MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08006996 /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
6997 tx_pwr_count = 2;
6998 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00006999 case CONF_OPER_CHWIDTH_80P80MHZ:
7000 case CONF_OPER_CHWIDTH_160MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08007001 /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
7002 tx_pwr_count = 3;
7003 break;
7004 default:
7005 return eid;
7006 }
7007
7008 /*
7009 * Below local_pwr_constraint logic is referred from
7010 * hostapd_eid_pwr_constraint.
7011 *
7012 * Check if DFS is required by regulatory.
7013 */
7014 dfs = hostapd_is_dfs_required(hapd->iface);
7015 if (dfs < 0)
7016 dfs = 0;
7017
7018 /*
7019 * In order to meet regulations when TPC is not implemented using
7020 * a transmit power that is below the legal maximum (including any
7021 * mitigation factor) should help. In this case, indicate 3 dB below
7022 * maximum allowed transmit power.
7023 */
7024 if (hapd->iconf->local_pwr_constraint == -1)
7025 local_pwr_constraint = (dfs == 0) ? 0 : 3;
7026 else
7027 local_pwr_constraint = hapd->iconf->local_pwr_constraint;
7028
7029 /*
7030 * A STA that is not an AP shall use a transmit power less than or
7031 * equal to the local maximum transmit power level for the channel.
7032 * The local maximum transmit power can be calculated from the formula:
7033 * local max TX pwr = max TX pwr - local pwr constraint
7034 * Where max TX pwr is maximum transmit power level specified for
7035 * channel in Country element and local pwr constraint is specified
7036 * for channel in this Power Constraint element.
7037 */
7038 chan = &mode->channels[i];
7039 max_tx_power = chan->max_tx_power - local_pwr_constraint;
7040
7041 /*
7042 * Local Maximum Transmit power is encoded as two's complement
7043 * with a 0.5 dB step.
7044 */
7045 max_tx_power *= 2; /* in 0.5 dB steps */
7046 if (max_tx_power > 127) {
7047 /* 63.5 has special meaning of 63.5 dBm or higher */
7048 max_tx_power = 127;
7049 }
7050 if (max_tx_power < -128)
7051 max_tx_power = -128;
7052 if (max_tx_power < 0)
7053 tx_pwr = 0x80 + max_tx_power + 128;
7054 else
7055 tx_pwr = max_tx_power;
7056
Sunil Ravia04bd252022-05-02 22:54:18 -07007057 return hostapd_add_tpe_info(eid, tx_pwr_count, LOCAL_EIRP,
7058 0 /* Reserved for bands other than 6 GHz */,
7059 tx_pwr);
Hai Shalom60840252021-02-19 19:02:11 -08007060}
7061
7062
Hai Shalom899fcc72020-10-19 14:38:18 -07007063u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
7064{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007065 u8 bw, chan1 = 0, chan2 = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -07007066 int freq1;
7067
7068 if (!hapd->cs_freq_params.channel ||
7069 (!hapd->cs_freq_params.vht_enabled &&
Sunil Ravia04bd252022-05-02 22:54:18 -07007070 !hapd->cs_freq_params.he_enabled &&
7071 !hapd->cs_freq_params.eht_enabled))
Hai Shalom899fcc72020-10-19 14:38:18 -07007072 return eid;
7073
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007074 /* bandwidth: 0: 40, 1: 80, 160, 80+80, 4: 320 as per
7075 * IEEE P802.11-REVme/D4.0, 9.4.2.159 and Table 9-314. */
Hai Shalom899fcc72020-10-19 14:38:18 -07007076 switch (hapd->cs_freq_params.bandwidth) {
7077 case 40:
7078 bw = 0;
7079 break;
7080 case 80:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007081 bw = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07007082 break;
7083 case 160:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007084 bw = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07007085 break;
Sunil Ravi640215c2023-06-28 23:08:09 +00007086 case 320:
7087 bw = 4;
7088 break;
Hai Shalom899fcc72020-10-19 14:38:18 -07007089 default:
7090 /* not valid VHT bandwidth or not in CSA */
7091 return eid;
7092 }
7093
7094 freq1 = hapd->cs_freq_params.center_freq1 ?
7095 hapd->cs_freq_params.center_freq1 :
7096 hapd->cs_freq_params.freq;
7097 if (ieee80211_freq_to_chan(freq1, &chan1) !=
7098 HOSTAPD_MODE_IEEE80211A)
7099 return eid;
7100
7101 if (hapd->cs_freq_params.center_freq2 &&
7102 ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
7103 &chan2) != HOSTAPD_MODE_IEEE80211A)
7104 return eid;
7105
Sunil Ravi640215c2023-06-28 23:08:09 +00007106 *eid++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER;
Hai Shalom899fcc72020-10-19 14:38:18 -07007107 *eid++ = 5; /* Length of Channel Switch Wrapper */
Sunil Ravi640215c2023-06-28 23:08:09 +00007108 *eid++ = WLAN_EID_WIDE_BW_CHSWITCH;
Hai Shalom899fcc72020-10-19 14:38:18 -07007109 *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
7110 *eid++ = bw; /* New Channel Width */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007111 if (hapd->cs_freq_params.bandwidth == 160) {
7112 /* Update the CCFS0 and CCFS1 values in the element based on
7113 * IEEE P802.11-REVme/D4.0, Table 9-314 */
7114
7115 /* CCFS1 - The channel center frequency index of the 160 MHz
7116 * channel. */
7117 chan2 = chan1;
7118
7119 /* CCFS0 - The channel center frequency index of the 80 MHz
7120 * channel segment that contains the primary channel. */
7121 if (hapd->cs_freq_params.channel < chan1)
7122 chan1 -= 8;
7123 else
7124 chan1 += 8;
7125 }
Hai Shalom899fcc72020-10-19 14:38:18 -07007126 *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
7127 *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
7128
7129 return eid;
7130}
7131
Hai Shaloma20dcd72022-02-04 13:43:00 -08007132
7133static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd,
7134 size_t *current_len)
7135{
7136 struct hostapd_neighbor_entry *nr;
7137 size_t total_len = 0, len = *current_len;
7138
7139 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7140 list) {
7141 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7142 continue;
7143
7144 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7145 continue;
7146
7147 /* Start a new element */
7148 if (!len ||
7149 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7150 len = RNR_HEADER_LEN;
7151 total_len += RNR_HEADER_LEN;
7152 }
7153
7154 len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7155 total_len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7156 }
7157
7158 *current_len = len;
7159 return total_len;
7160}
7161
7162
Sunil Ravi640215c2023-06-28 23:08:09 +00007163struct mbssid_ie_profiles {
7164 u8 start;
7165 u8 end;
7166};
7167
7168static size_t
7169hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
7170 struct hostapd_data *reporting_hapd,
7171 size_t *current_len,
7172 struct mbssid_ie_profiles *skip_profiles)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007173{
7174 size_t total_len = 0, len = *current_len;
7175 int tbtt_count = 0;
7176 size_t i, start = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007177 bool ap_mld = false;
7178
7179#ifdef CONFIG_IEEE80211BE
7180 ap_mld = !!hapd->conf->mld_ap;
7181#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007182
7183 while (start < hapd->iface->num_bss) {
7184 if (!len ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007185 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255 ||
7186 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08007187 len = RNR_HEADER_LEN;
7188 total_len += RNR_HEADER_LEN;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007189 tbtt_count = 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007190 }
7191
7192 len += RNR_TBTT_HEADER_LEN;
7193 total_len += RNR_TBTT_HEADER_LEN;
7194
7195 for (i = start; i < hapd->iface->num_bss; i++) {
7196 struct hostapd_data *bss = hapd->iface->bss[i];
7197
7198 if (!bss || !bss->conf || !bss->started)
7199 continue;
7200
7201 if (bss == reporting_hapd ||
7202 bss->conf->ignore_broadcast_ssid)
7203 continue;
7204
Sunil Ravi640215c2023-06-28 23:08:09 +00007205 if (skip_profiles &&
7206 i >= skip_profiles->start && i < skip_profiles->end)
7207 continue;
7208
Hai Shaloma20dcd72022-02-04 13:43:00 -08007209 if (len + RNR_TBTT_INFO_LEN > 255 ||
7210 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7211 break;
7212
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007213 if (!ap_mld) {
7214 len += RNR_TBTT_INFO_LEN;
7215 total_len += RNR_TBTT_INFO_LEN;
7216 } else {
7217 len += RNR_TBTT_INFO_MLD_LEN;
7218 total_len += RNR_TBTT_INFO_MLD_LEN;
7219 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08007220 tbtt_count++;
7221 }
7222 start = i;
7223 }
7224
7225 if (!tbtt_count)
7226 total_len = 0;
7227 else
7228 *current_len = len;
7229
7230 return total_len;
7231}
7232
7233
7234enum colocation_mode {
7235 NO_COLOCATED_6GHZ,
7236 STANDALONE_6GHZ,
7237 COLOCATED_6GHZ,
7238 COLOCATED_LOWER_BAND,
7239};
7240
7241static enum colocation_mode get_colocation_mode(struct hostapd_data *hapd)
7242{
7243 u8 i;
7244 bool is_6ghz = is_6ghz_op_class(hapd->iconf->op_class);
7245
7246 if (!hapd->iface || !hapd->iface->interfaces)
7247 return NO_COLOCATED_6GHZ;
7248
7249 if (is_6ghz && hapd->iface->interfaces->count == 1)
7250 return STANDALONE_6GHZ;
7251
7252 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7253 struct hostapd_iface *iface;
7254 bool is_colocated_6ghz;
7255
7256 iface = hapd->iface->interfaces->iface[i];
7257 if (iface == hapd->iface || !iface || !iface->conf)
7258 continue;
7259
7260 is_colocated_6ghz = is_6ghz_op_class(iface->conf->op_class);
7261 if (!is_6ghz && is_colocated_6ghz)
7262 return COLOCATED_LOWER_BAND;
7263 if (is_6ghz && !is_colocated_6ghz)
7264 return COLOCATED_6GHZ;
7265 }
7266
7267 if (is_6ghz)
7268 return STANDALONE_6GHZ;
7269
7270 return NO_COLOCATED_6GHZ;
7271}
7272
7273
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007274static size_t hostapd_eid_rnr_multi_iface_len(struct hostapd_data *hapd,
7275 size_t *current_len)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007276{
7277 struct hostapd_iface *iface;
7278 size_t len = 0;
7279 size_t i;
7280
7281 if (!hapd->iface || !hapd->iface->interfaces)
7282 return 0;
7283
7284 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7285 iface = hapd->iface->interfaces->iface[i];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007286 bool ap_mld = false;
7287
7288#ifdef CONFIG_IEEE80211BE
7289 if (hapd->conf->mld_ap && iface->bss[0]->conf->mld_ap &&
7290 hapd->conf->mld_id == iface->bss[0]->conf->mld_id)
7291 ap_mld = true;
7292#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007293
7294 if (iface == hapd->iface ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007295 !(is_6ghz_op_class(iface->conf->op_class) || ap_mld))
Hai Shaloma20dcd72022-02-04 13:43:00 -08007296 continue;
7297
7298 len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007299 current_len, NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007300 }
7301
7302 return len;
7303}
7304
7305
7306size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type)
7307{
7308 size_t total_len = 0, current_len = 0;
7309 enum colocation_mode mode = get_colocation_mode(hapd);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007310 bool ap_mld = false;
7311
7312#ifdef CONFIG_IEEE80211BE
7313 ap_mld = !!hapd->conf->mld_ap;
7314#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007315
7316 switch (type) {
7317 case WLAN_FC_STYPE_BEACON:
7318 if (hapd->conf->rnr)
7319 total_len += hostapd_eid_nr_db_len(hapd, &current_len);
7320 /* fallthrough */
7321
7322 case WLAN_FC_STYPE_PROBE_RESP:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007323 if (mode == COLOCATED_LOWER_BAND || ap_mld)
7324 total_len +=
7325 hostapd_eid_rnr_multi_iface_len(hapd,
7326 &current_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007327
Sunil Ravi640215c2023-06-28 23:08:09 +00007328 if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
7329 !hapd->iconf->mbssid)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007330 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007331 &current_len,
7332 NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007333 break;
7334
7335 case WLAN_FC_STYPE_ACTION:
7336 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
7337 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007338 &current_len,
7339 NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007340 break;
7341
7342 default:
7343 break;
7344 }
7345
7346 return total_len;
7347}
7348
7349
7350static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid,
7351 size_t *current_len)
7352{
7353 struct hostapd_neighbor_entry *nr;
7354 size_t len = *current_len;
7355 u8 *size_offset = (eid - len) + 1;
7356
7357 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7358 list) {
7359 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7360 continue;
7361
7362 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7363 continue;
7364
7365 /* Start a new element */
7366 if (!len ||
7367 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7368 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7369 size_offset = eid++;
7370 len = RNR_HEADER_LEN;
7371 }
7372
7373 /* TBTT Information Header subfield (2 octets) */
7374 *eid++ = 0;
7375 /* TBTT Information Length */
7376 *eid++ = RNR_TBTT_INFO_LEN;
7377 /* Operating Class */
7378 *eid++ = wpabuf_head_u8(nr->nr)[10];
7379 /* Channel Number */
7380 *eid++ = wpabuf_head_u8(nr->nr)[11];
7381 len += RNR_TBTT_HEADER_LEN;
7382 /* TBTT Information Set */
7383 /* TBTT Information field */
7384 /* Neighbor AP TBTT Offset */
7385 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
7386 /* BSSID */
7387 os_memcpy(eid, nr->bssid, ETH_ALEN);
7388 eid += ETH_ALEN;
7389 /* Short SSID */
7390 os_memcpy(eid, &nr->short_ssid, 4);
7391 eid += 4;
7392 /* BSS parameters */
7393 *eid++ = nr->bss_parameters;
7394 /* 20 MHz PSD */
7395 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1;
7396 len += RNR_TBTT_INFO_LEN;
7397 *size_offset = (eid - size_offset) - 1;
7398 }
7399
7400 *current_len = len;
7401 return eid;
7402}
7403
7404
7405static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
7406 struct hostapd_data *reporting_hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007407 u8 *eid, size_t *current_len,
7408 struct mbssid_ie_profiles *skip_profiles)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007409{
7410 struct hostapd_data *bss;
7411 struct hostapd_iface *iface = hapd->iface;
7412 size_t i, start = 0;
7413 size_t len = *current_len;
7414 u8 *tbtt_count_pos, *eid_start = eid, *size_offset = (eid - len) + 1;
7415 u8 tbtt_count = 0, op_class, channel, bss_param;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007416 bool ap_mld = false;
7417
7418#ifdef CONFIG_IEEE80211BE
7419 ap_mld = !!hapd->conf->mld_ap;
7420#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007421
7422 if (!(iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !iface->freq)
7423 return eid;
7424
7425 if (ieee80211_freq_to_channel_ext(iface->freq,
7426 hapd->iconf->secondary_channel,
7427 hostapd_get_oper_chwidth(hapd->iconf),
7428 &op_class, &channel) ==
7429 NUM_HOSTAPD_MODES)
7430 return eid;
7431
7432 while (start < iface->num_bss) {
7433 if (!len ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007434 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255 ||
7435 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08007436 eid_start = eid;
7437 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7438 size_offset = eid++;
7439 len = RNR_HEADER_LEN;
7440 tbtt_count = 0;
7441 }
7442
7443 tbtt_count_pos = eid++;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007444 *eid++ = ap_mld ? RNR_TBTT_INFO_MLD_LEN : RNR_TBTT_INFO_LEN;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007445 *eid++ = op_class;
7446 *eid++ = hapd->iconf->channel;
7447 len += RNR_TBTT_HEADER_LEN;
7448
7449 for (i = start; i < iface->num_bss; i++) {
7450 bss_param = 0;
7451 bss = iface->bss[i];
7452 if (!bss || !bss->conf || !bss->started)
7453 continue;
7454
7455 if (bss == reporting_hapd ||
7456 bss->conf->ignore_broadcast_ssid)
7457 continue;
7458
Sunil Ravi640215c2023-06-28 23:08:09 +00007459 if (skip_profiles &&
7460 i >= skip_profiles->start && i < skip_profiles->end)
7461 continue;
7462
Hai Shaloma20dcd72022-02-04 13:43:00 -08007463 if (len + RNR_TBTT_INFO_LEN > 255 ||
7464 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7465 break;
7466
7467 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
Sunil Ravi89eba102022-09-13 21:04:37 -07007468 os_memcpy(eid, bss->own_addr, ETH_ALEN);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007469 eid += ETH_ALEN;
7470 os_memcpy(eid, &bss->conf->ssid.short_ssid, 4);
7471 eid += 4;
7472 if (bss->conf->ssid.short_ssid ==
7473 reporting_hapd->conf->ssid.short_ssid)
7474 bss_param |= RNR_BSS_PARAM_SAME_SSID;
7475
Sunil Ravi77d572f2023-01-17 23:58:31 +00007476 if (iface->conf->mbssid != MBSSID_DISABLED &&
7477 iface->num_bss > 1) {
7478 bss_param |= RNR_BSS_PARAM_MULTIPLE_BSSID;
Sunil Ravi640215c2023-06-28 23:08:09 +00007479 if (bss == hostapd_mbssid_get_tx_bss(hapd))
Sunil Ravi77d572f2023-01-17 23:58:31 +00007480 bss_param |=
7481 RNR_BSS_PARAM_TRANSMITTED_BSSID;
7482 }
7483
Hai Shaloma20dcd72022-02-04 13:43:00 -08007484 if (is_6ghz_op_class(hapd->iconf->op_class) &&
7485 bss->conf->unsol_bcast_probe_resp_interval)
7486 bss_param |=
7487 RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE;
7488
7489 bss_param |= RNR_BSS_PARAM_CO_LOCATED;
7490
7491 *eid++ = bss_param;
7492 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007493
7494 if (!ap_mld) {
7495 len += RNR_TBTT_INFO_LEN;
7496 } else {
7497#ifdef CONFIG_IEEE80211BE
7498 *eid++ = hapd->conf->mld_id;
7499 *eid++ = hapd->mld_link_id | (1 << 4);
7500 *eid++ = 0;
7501 len += RNR_TBTT_INFO_MLD_LEN;
7502#endif /* CONFIG_IEEE80211BE */
7503 }
7504
Hai Shaloma20dcd72022-02-04 13:43:00 -08007505 tbtt_count += 1;
7506 }
7507
7508 start = i;
7509 *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
7510 *size_offset = (eid - size_offset) - 1;
7511 }
7512
7513 if (tbtt_count == 0)
7514 return eid_start;
7515
7516 *current_len = len;
7517 return eid;
7518}
7519
7520
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007521static u8 * hostapd_eid_rnr_multi_iface(struct hostapd_data *hapd, u8 *eid,
7522 size_t *current_len)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007523{
7524 struct hostapd_iface *iface;
7525 size_t i;
7526
7527 if (!hapd->iface || !hapd->iface->interfaces)
7528 return eid;
7529
7530 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7531 iface = hapd->iface->interfaces->iface[i];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007532 bool ap_mld = false;
7533
7534#ifdef CONFIG_IEEE80211BE
7535 if (hapd->conf->mld_ap && iface->bss[0]->conf->mld_ap &&
7536 hapd->conf->mld_id == iface->bss[0]->conf->mld_id)
7537 ap_mld = true;
7538#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007539
7540 if (iface == hapd->iface ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007541 !(is_6ghz_op_class(iface->conf->op_class) || ap_mld))
Hai Shaloma20dcd72022-02-04 13:43:00 -08007542 continue;
7543
7544 eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
Sunil Ravi640215c2023-06-28 23:08:09 +00007545 current_len, NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007546 }
7547
7548 return eid;
7549}
7550
7551
7552u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
7553{
7554 u8 *eid_start = eid;
7555 size_t current_len = 0;
7556 enum colocation_mode mode = get_colocation_mode(hapd);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007557 bool ap_mld = false;
7558
7559#ifdef CONFIG_IEEE80211BE
7560 ap_mld = !!hapd->conf->mld_ap;
7561#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007562
7563 switch (type) {
7564 case WLAN_FC_STYPE_BEACON:
7565 if (hapd->conf->rnr)
7566 eid = hostapd_eid_nr_db(hapd, eid, &current_len);
7567 /* fallthrough */
7568
7569 case WLAN_FC_STYPE_PROBE_RESP:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007570 if (mode == COLOCATED_LOWER_BAND || ap_mld)
7571 eid = hostapd_eid_rnr_multi_iface(hapd, eid,
7572 &current_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007573
Sunil Ravi640215c2023-06-28 23:08:09 +00007574 if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
7575 !hapd->iconf->mbssid)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007576 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
Sunil Ravi640215c2023-06-28 23:08:09 +00007577 &current_len, NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007578 break;
7579
7580 case WLAN_FC_STYPE_ACTION:
7581 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
7582 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
Sunil Ravi640215c2023-06-28 23:08:09 +00007583 &current_len, NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007584 break;
7585
7586 default:
7587 return eid_start;
7588 }
7589
7590 if (eid == eid_start + 2)
7591 return eid_start;
7592
7593 return eid;
7594}
7595
Sunil Ravi77d572f2023-01-17 23:58:31 +00007596
7597static bool mbssid_known_bss(unsigned int i, const u8 *known_bss,
7598 size_t known_bss_len)
7599{
7600 if (!known_bss || known_bss_len <= i / 8)
7601 return false;
7602 known_bss = &known_bss[i / 8];
7603 return *known_bss & (u8) (BIT(i % 8));
7604}
7605
7606
7607static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd,
7608 u32 frame_type, size_t *bss_index,
7609 const u8 *known_bss,
7610 size_t known_bss_len)
7611{
7612 struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
7613 size_t len = 3, i;
7614
7615 for (i = *bss_index; i < hapd->iface->num_bss; i++) {
7616 struct hostapd_data *bss = hapd->iface->bss[i];
7617 const u8 *auth, *rsn = NULL, *rsnx = NULL;
7618 size_t nontx_profile_len, auth_len;
7619 u8 ie_count = 0;
7620
7621 if (!bss || !bss->conf || !bss->started ||
7622 mbssid_known_bss(i, known_bss, known_bss_len))
7623 continue;
7624
7625 /*
7626 * Sublement ID: 1 octet
7627 * Length: 1 octet
7628 * Nontransmitted capabilities: 4 octets
7629 * SSID element: 2 + variable
7630 * Multiple BSSID Index Element: 3 octets (+2 octets in beacons)
7631 * Fixed length = 1 + 1 + 4 + 2 + 3 = 11
7632 */
7633 nontx_profile_len = 11 + bss->conf->ssid.ssid_len;
7634
7635 if (frame_type == WLAN_FC_STYPE_BEACON)
7636 nontx_profile_len += 2;
7637
7638 auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
7639 if (auth) {
7640 rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
7641 if (rsn)
7642 nontx_profile_len += 2 + rsn[1];
7643
7644 rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
7645 if (rsnx)
7646 nontx_profile_len += 2 + rsnx[1];
7647 }
7648 if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
7649 ie_count++;
7650 if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
7651 ie_count++;
7652 if (bss->conf->xrates_supported)
7653 nontx_profile_len += 8;
7654 else if (hapd->conf->xrates_supported)
7655 ie_count++;
7656 if (ie_count)
7657 nontx_profile_len += 4 + ie_count;
7658
7659 if (len + nontx_profile_len > 255)
7660 break;
7661
7662 len += nontx_profile_len;
7663 }
7664
7665 *bss_index = i;
7666 return len;
7667}
7668
7669
7670size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
7671 u8 *elem_count, const u8 *known_bss,
Sunil Ravi640215c2023-06-28 23:08:09 +00007672 size_t known_bss_len, size_t *rnr_len)
Sunil Ravi77d572f2023-01-17 23:58:31 +00007673{
7674 size_t len = 0, bss_index = 1;
7675
7676 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
7677 (frame_type != WLAN_FC_STYPE_BEACON &&
7678 frame_type != WLAN_FC_STYPE_PROBE_RESP))
7679 return 0;
7680
7681 if (frame_type == WLAN_FC_STYPE_BEACON) {
7682 if (!elem_count) {
7683 wpa_printf(MSG_INFO,
7684 "MBSSID: Insufficient data for Beacon frames");
7685 return 0;
7686 }
7687 *elem_count = 0;
7688 }
7689
7690 while (bss_index < hapd->iface->num_bss) {
Sunil Ravi640215c2023-06-28 23:08:09 +00007691 size_t rnr_count = bss_index;
7692
Sunil Ravi77d572f2023-01-17 23:58:31 +00007693 len += hostapd_eid_mbssid_elem_len(hapd, frame_type,
7694 &bss_index, known_bss,
7695 known_bss_len);
7696
7697 if (frame_type == WLAN_FC_STYPE_BEACON)
7698 *elem_count += 1;
Sunil Ravi640215c2023-06-28 23:08:09 +00007699 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len) {
7700 size_t rnr_cur_len = 0;
7701 struct mbssid_ie_profiles skip_profiles = {
7702 rnr_count, bss_index
7703 };
7704
7705 *rnr_len += hostapd_eid_rnr_iface_len(
7706 hapd, hostapd_mbssid_get_tx_bss(hapd),
7707 &rnr_cur_len, &skip_profiles);
7708 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00007709 }
Sunil Ravi640215c2023-06-28 23:08:09 +00007710
7711 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len)
7712 *rnr_len += hostapd_eid_rnr_len(hapd, frame_type);
7713
Sunil Ravi77d572f2023-01-17 23:58:31 +00007714 return len;
7715}
7716
7717
7718static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end,
7719 u32 frame_type, u8 max_bssid_indicator,
7720 size_t *bss_index, u8 elem_count,
7721 const u8 *known_bss, size_t known_bss_len)
7722{
7723 struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
7724 size_t i;
7725 u8 *eid_len_offset, *max_bssid_indicator_offset;
7726
7727 *eid++ = WLAN_EID_MULTIPLE_BSSID;
7728 eid_len_offset = eid++;
7729 max_bssid_indicator_offset = eid++;
7730
7731 for (i = *bss_index; i < hapd->iface->num_bss; i++) {
7732 struct hostapd_data *bss = hapd->iface->bss[i];
7733 struct hostapd_bss_config *conf;
7734 u8 *eid_len_pos, *nontx_bss_start = eid;
7735 const u8 *auth, *rsn = NULL, *rsnx = NULL;
7736 u8 ie_count = 0, non_inherit_ie[3];
7737 size_t auth_len = 0;
7738 u16 capab_info;
7739
7740 if (!bss || !bss->conf || !bss->started ||
7741 mbssid_known_bss(i, known_bss, known_bss_len))
7742 continue;
7743 conf = bss->conf;
7744
7745 *eid++ = WLAN_MBSSID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE;
7746 eid_len_pos = eid++;
7747
7748 capab_info = hostapd_own_capab_info(bss);
7749 *eid++ = WLAN_EID_NONTRANSMITTED_BSSID_CAPA;
7750 *eid++ = sizeof(capab_info);
7751 WPA_PUT_LE16(eid, capab_info);
7752 eid += sizeof(capab_info);
7753
7754 *eid++ = WLAN_EID_SSID;
7755 *eid++ = conf->ssid.ssid_len;
7756 os_memcpy(eid, conf->ssid.ssid, conf->ssid.ssid_len);
7757 eid += conf->ssid.ssid_len;
7758
7759 *eid++ = WLAN_EID_MULTIPLE_BSSID_INDEX;
7760 if (frame_type == WLAN_FC_STYPE_BEACON) {
7761 *eid++ = 3;
7762 *eid++ = i; /* BSSID Index */
7763 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
7764 (conf->dtim_period % elem_count))
7765 conf->dtim_period = elem_count;
7766 *eid++ = conf->dtim_period;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007767 /* The driver is expected to update the DTIM Count
7768 * field for each BSS that corresponds to a
7769 * nontransmitted BSSID. The value is initialized to
7770 * 0 here so that the DTIM count would be somewhat
7771 * functional even if the driver were not to update
7772 * this. */
7773 *eid++ = 0; /* DTIM Count */
Sunil Ravi77d572f2023-01-17 23:58:31 +00007774 } else {
7775 /* Probe Request frame does not include DTIM Period and
7776 * DTIM Count fields. */
7777 *eid++ = 1;
7778 *eid++ = i; /* BSSID Index */
7779 }
7780
7781 auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
7782 if (auth) {
7783 rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
7784 if (rsn) {
7785 os_memcpy(eid, rsn, 2 + rsn[1]);
7786 eid += 2 + rsn[1];
7787 }
7788
7789 rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
7790 if (rsnx) {
7791 os_memcpy(eid, rsnx, 2 + rsnx[1]);
7792 eid += 2 + rsnx[1];
7793 }
7794 }
7795 if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
7796 non_inherit_ie[ie_count++] = WLAN_EID_RSN;
7797 if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
7798 non_inherit_ie[ie_count++] = WLAN_EID_RSNX;
7799 if (hapd->conf->xrates_supported &&
7800 !bss->conf->xrates_supported)
7801 non_inherit_ie[ie_count++] = WLAN_EID_EXT_SUPP_RATES;
7802 if (ie_count) {
7803 *eid++ = WLAN_EID_EXTENSION;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007804 *eid++ = 2 + ie_count + 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00007805 *eid++ = WLAN_EID_EXT_NON_INHERITANCE;
7806 *eid++ = ie_count;
7807 os_memcpy(eid, non_inherit_ie, ie_count);
7808 eid += ie_count;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007809 *eid++ = 0; /* No Element ID Extension List */
Sunil Ravi77d572f2023-01-17 23:58:31 +00007810 }
7811
7812 *eid_len_pos = (eid - eid_len_pos) - 1;
7813
7814 if (((eid - eid_len_offset) - 1) > 255) {
7815 eid = nontx_bss_start;
7816 break;
7817 }
7818 }
7819
7820 *bss_index = i;
7821 *max_bssid_indicator_offset = max_bssid_indicator;
7822 if (*max_bssid_indicator_offset < 1)
7823 *max_bssid_indicator_offset = 1;
7824 *eid_len_offset = (eid - eid_len_offset) - 1;
7825 return eid;
7826}
7827
7828
7829u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
7830 unsigned int frame_stype, u8 elem_count,
7831 u8 **elem_offset,
Sunil Ravi640215c2023-06-28 23:08:09 +00007832 const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid,
7833 u8 *rnr_count, u8 **rnr_offset, size_t rnr_len)
Sunil Ravi77d572f2023-01-17 23:58:31 +00007834{
Sunil Ravi640215c2023-06-28 23:08:09 +00007835 size_t bss_index = 1, cur_len = 0;
7836 u8 elem_index = 0, *rnr_start_eid = rnr_eid;
7837 bool add_rnr;
Sunil Ravi77d572f2023-01-17 23:58:31 +00007838
7839 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
7840 (frame_stype != WLAN_FC_STYPE_BEACON &&
7841 frame_stype != WLAN_FC_STYPE_PROBE_RESP))
7842 return eid;
7843
7844 if (frame_stype == WLAN_FC_STYPE_BEACON && !elem_offset) {
7845 wpa_printf(MSG_INFO,
7846 "MBSSID: Insufficient data for Beacon frames");
7847 return eid;
7848 }
7849
Sunil Ravi640215c2023-06-28 23:08:09 +00007850 add_rnr = hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
7851 frame_stype == WLAN_FC_STYPE_BEACON &&
7852 rnr_eid && rnr_count && rnr_offset && rnr_len;
7853
Sunil Ravi77d572f2023-01-17 23:58:31 +00007854 while (bss_index < hapd->iface->num_bss) {
Sunil Ravi640215c2023-06-28 23:08:09 +00007855 unsigned int rnr_start_count = bss_index;
7856
Sunil Ravi77d572f2023-01-17 23:58:31 +00007857 if (frame_stype == WLAN_FC_STYPE_BEACON) {
7858 if (elem_index == elem_count) {
7859 wpa_printf(MSG_WARNING,
7860 "MBSSID: Larger number of elements than there is room in the provided array");
7861 break;
7862 }
7863
7864 elem_offset[elem_index] = eid;
7865 elem_index = elem_index + 1;
7866 }
7867 eid = hostapd_eid_mbssid_elem(hapd, eid, end, frame_stype,
7868 hostapd_max_bssid_indicator(hapd),
7869 &bss_index, elem_count,
7870 known_bss, known_bss_len);
Sunil Ravi640215c2023-06-28 23:08:09 +00007871
7872 if (add_rnr) {
7873 struct mbssid_ie_profiles skip_profiles = {
7874 rnr_start_count, bss_index
7875 };
7876
7877 rnr_offset[*rnr_count] = rnr_eid;
7878 *rnr_count = *rnr_count + 1;
7879 cur_len = 0;
7880 rnr_eid = hostapd_eid_rnr_iface(
7881 hapd, hostapd_mbssid_get_tx_bss(hapd),
7882 rnr_eid, &cur_len, &skip_profiles);
7883 }
7884 }
7885
7886 if (add_rnr && (size_t) (rnr_eid - rnr_start_eid) < rnr_len) {
7887 rnr_offset[*rnr_count] = rnr_eid;
7888 *rnr_count = *rnr_count + 1;
7889 cur_len = 0;
7890
7891 if (hapd->conf->rnr)
7892 rnr_eid = hostapd_eid_nr_db(hapd, rnr_eid, &cur_len);
7893 if (get_colocation_mode(hapd) == COLOCATED_LOWER_BAND)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007894 rnr_eid = hostapd_eid_rnr_multi_iface(hapd, rnr_eid,
7895 &cur_len);
Sunil Ravi77d572f2023-01-17 23:58:31 +00007896 }
7897
7898 return eid;
7899}
7900
Sunil Ravi036cec52023-03-29 11:35:17 -07007901
7902static void punct_update_legacy_bw_80(u8 bitmap, u8 pri_chan, u8 *seg0)
7903{
7904 u8 first_chan = *seg0 - 6, sec_chan;
7905
7906 switch (bitmap) {
7907 case 0x6:
7908 *seg0 = 0;
7909 return;
7910 case 0x8:
7911 case 0x4:
7912 case 0x2:
7913 case 0x1:
7914 case 0xC:
7915 case 0x3:
7916 if (pri_chan < *seg0)
7917 *seg0 -= 4;
7918 else
7919 *seg0 += 4;
7920 break;
7921 }
7922
7923 if (pri_chan < *seg0)
7924 sec_chan = pri_chan + 4;
7925 else
7926 sec_chan = pri_chan - 4;
7927
7928 if (bitmap & BIT((sec_chan - first_chan) / 4))
7929 *seg0 = 0;
7930}
7931
7932
7933static void punct_update_legacy_bw_160(u8 bitmap, u8 pri,
7934 enum oper_chan_width *width, u8 *seg0)
7935{
7936 if (pri < *seg0) {
7937 *seg0 -= 8;
7938 if (bitmap & 0x0F) {
7939 *width = 0;
7940 punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0);
7941 }
7942 } else {
7943 *seg0 += 8;
7944 if (bitmap & 0xF0) {
7945 *width = 0;
7946 punct_update_legacy_bw_80((bitmap & 0xF0) >> 4, pri,
7947 seg0);
7948 }
7949 }
7950}
7951
7952
7953void punct_update_legacy_bw(u16 bitmap, u8 pri, enum oper_chan_width *width,
7954 u8 *seg0, u8 *seg1)
7955{
7956 if (*width == CONF_OPER_CHWIDTH_80MHZ && (bitmap & 0xF)) {
7957 *width = CONF_OPER_CHWIDTH_USE_HT;
7958 punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0);
7959 }
7960
7961 if (*width == CONF_OPER_CHWIDTH_160MHZ && (bitmap & 0xFF)) {
7962 *width = CONF_OPER_CHWIDTH_80MHZ;
7963 *seg1 = 0;
7964 punct_update_legacy_bw_160(bitmap & 0xFF, pri, width, seg0);
7965 }
7966
7967 /* TODO: 320 MHz */
7968}
7969
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007970#endif /* CONFIG_NATIVE_WINDOWS */