blob: 85a39d5ffb0e7f1bf1d75ce1fc4e3d5c886f9387 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / IEEE 802.11 Management
Dmitry Shmidt29333592017-01-09 12:27:11 -08003 * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "utils/includes.h"
10
11#ifndef CONFIG_NATIVE_WINDOWS
12
13#include "utils/common.h"
14#include "utils/eloop.h"
15#include "crypto/crypto.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080016#include "crypto/sha256.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070017#include "crypto/sha384.h"
18#include "crypto/sha512.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080019#include "crypto/random.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070020#include "common/ieee802_11_defs.h"
21#include "common/ieee802_11_common.h"
22#include "common/wpa_ctrl.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080023#include "common/sae.h"
Hai Shalom021b0b52019-04-10 11:17:58 -070024#include "common/dpp.h"
Hai Shalom74f70d42019-02-11 14:42:39 -080025#include "common/ocv.h"
Hai Shalom81f62d82019-07-22 12:10:00 -070026#include "common/wpa_common.h"
Hai Shalom899fcc72020-10-19 14:38:18 -070027#include "common/wpa_ctrl.h"
Hai Shalom60840252021-02-19 19:02:11 -080028#include "common/ptksa_cache.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070029#include "radius/radius.h"
30#include "radius/radius_client.h"
31#include "p2p/p2p.h"
32#include "wps/wps.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080033#include "fst/fst.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070034#include "hostapd.h"
35#include "beacon.h"
36#include "ieee802_11_auth.h"
37#include "sta_info.h"
38#include "ieee802_1x.h"
39#include "wpa_auth.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080040#include "pmksa_cache_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070041#include "wmm.h"
42#include "ap_list.h"
43#include "accounting.h"
44#include "ap_config.h"
45#include "ap_mlme.h"
46#include "p2p_hostapd.h"
47#include "ap_drv_ops.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080048#include "wnm_ap.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080049#include "hw_features.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070050#include "ieee802_11.h"
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080051#include "dfs.h"
Dmitry Shmidt57c2d392016-02-23 13:40:19 -080052#include "mbo_ap.h"
Dmitry Shmidt849734c2016-05-27 09:59:01 -070053#include "rrm.h"
Dmitry Shmidtaca489e2016-09-28 15:44:14 -070054#include "taxonomy.h"
Dmitry Shmidtebd93af2017-02-21 13:40:44 -080055#include "fils_hlp.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070056#include "dpp_hostapd.h"
57#include "gas_query_ap.h"
Sunil Ravi77d572f2023-01-17 23:58:31 +000058#include "comeback_token.h"
Sunil Ravi72e01222024-03-09 01:25:43 +000059#include "nan_usd_ap.h"
Sunil Ravi77d572f2023-01-17 23:58:31 +000060#include "pasn/pasn_common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070061
62
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070063#ifdef CONFIG_FILS
64static struct wpabuf *
65prepare_auth_resp_fils(struct hostapd_data *hapd,
66 struct sta_info *sta, u16 *resp,
67 struct rsn_pmksa_cache_entry *pmksa,
68 struct wpabuf *erp_resp,
69 const u8 *msk, size_t msk_len,
70 int *is_pub);
71#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -080072
73#ifdef CONFIG_PASN
Hai Shalom60840252021-02-19 19:02:11 -080074#ifdef CONFIG_FILS
75
76static void pasn_fils_auth_resp(struct hostapd_data *hapd,
77 struct sta_info *sta, u16 status,
78 struct wpabuf *erp_resp,
79 const u8 *msk, size_t msk_len);
80
81#endif /* CONFIG_FILS */
82#endif /* CONFIG_PASN */
83
Hai Shalom021b0b52019-04-10 11:17:58 -070084static void handle_auth(struct hostapd_data *hapd,
85 const struct ieee80211_mgmt *mgmt, size_t len,
86 int rssi, int from_queue);
Sunil Ravi2a14cf12023-11-21 00:54:38 +000087static int add_associated_sta(struct hostapd_data *hapd,
88 struct sta_info *sta, int reassoc);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070089
Hai Shalom74f70d42019-02-11 14:42:39 -080090
Sunil Raviaf399a82024-05-05 20:56:55 +000091static u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid, size_t len)
Hai Shalom74f70d42019-02-11 14:42:39 -080092{
Sunil Raviaf399a82024-05-05 20:56:55 +000093 struct multi_ap_params multi_ap = { 0 };
Hai Shalom74f70d42019-02-11 14:42:39 -080094
95 if (!hapd->conf->multi_ap)
96 return eid;
Hai Shalom74f70d42019-02-11 14:42:39 -080097
Sunil Raviaf399a82024-05-05 20:56:55 +000098 if (hapd->conf->multi_ap & BACKHAUL_BSS)
99 multi_ap.capability |= MULTI_AP_BACKHAUL_BSS;
100 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
101 multi_ap.capability |= MULTI_AP_FRONTHAUL_BSS;
102
103 if (hapd->conf->multi_ap_client_disallow &
104 PROFILE1_CLIENT_ASSOC_DISALLOW)
105 multi_ap.capability |=
106 MULTI_AP_PROFILE1_BACKHAUL_STA_DISALLOWED;
107 if (hapd->conf->multi_ap_client_disallow &
108 PROFILE2_CLIENT_ASSOC_DISALLOW)
109 multi_ap.capability |=
110 MULTI_AP_PROFILE2_BACKHAUL_STA_DISALLOWED;
111
112 multi_ap.profile = hapd->conf->multi_ap_profile;
113 multi_ap.vlanid = hapd->conf->multi_ap_vlanid;
114
115 return eid + add_multi_ap_ie(eid, len, &multi_ap);
Hai Shalom74f70d42019-02-11 14:42:39 -0800116}
117
118
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700119u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
120{
121 u8 *pos = eid;
122 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700123 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700124
125 if (hapd->iface->current_rates == NULL)
126 return eid;
127
128 *pos++ = WLAN_EID_SUPP_RATES;
129 num = hapd->iface->num_rates;
130 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
131 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800132 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
133 num++;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000134#ifdef CONFIG_IEEE80211AX
135 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
136 num++;
137#endif /* CONFIG_IEEE80211AX */
138 h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
Hai Shalomfdcde762020-04-02 11:19:20 -0700139 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +0000140 hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700141 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
142 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700143 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700144 if (num > 8) {
145 /* rest of the rates are encoded in Extended supported
146 * rates element */
147 num = 8;
148 }
149
150 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700151 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
152 i++) {
153 count++;
154 *pos = hapd->iface->current_rates[i].rate / 5;
155 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
156 *pos |= 0x80;
157 pos++;
158 }
159
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800160 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
161 count++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700162 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800163 }
164
165 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
166 count++;
167 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
168 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700169
Sunil Ravi77d572f2023-01-17 23:58:31 +0000170#ifdef CONFIG_IEEE80211AX
171 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he && count < 8) {
172 count++;
173 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY;
174 }
175#endif /* CONFIG_IEEE80211AX */
176
Hai Shalomfdcde762020-04-02 11:19:20 -0700177 if (h2e_required && count < 8) {
Hai Shalomc3565922019-10-28 11:58:20 -0700178 count++;
179 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
180 }
181
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700182 return pos;
183}
184
185
186u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
187{
188 u8 *pos = eid;
189 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700190 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700191
Sunil Ravi77d572f2023-01-17 23:58:31 +0000192 hapd->conf->xrates_supported = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700193 if (hapd->iface->current_rates == NULL)
194 return eid;
195
196 num = hapd->iface->num_rates;
197 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
198 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800199 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
200 num++;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000201#ifdef CONFIG_IEEE80211AX
202 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
203 num++;
204#endif /* CONFIG_IEEE80211AX */
205 h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
Hai Shalomfdcde762020-04-02 11:19:20 -0700206 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +0000207 hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700208 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
209 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700210 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700211 if (num <= 8)
212 return eid;
213 num -= 8;
214
215 *pos++ = WLAN_EID_EXT_SUPP_RATES;
216 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700217 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
218 i++) {
219 count++;
220 if (count <= 8)
221 continue; /* already in SuppRates IE */
222 *pos = hapd->iface->current_rates[i].rate / 5;
223 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
224 *pos |= 0x80;
225 pos++;
226 }
227
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800228 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
229 count++;
230 if (count > 8)
231 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
232 }
233
234 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
235 count++;
236 if (count > 8)
237 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
238 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700239
Sunil Ravi77d572f2023-01-17 23:58:31 +0000240#ifdef CONFIG_IEEE80211AX
241 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he) {
242 count++;
243 if (count > 8)
244 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY;
245 }
246#endif /* CONFIG_IEEE80211AX */
247
Hai Shalomfdcde762020-04-02 11:19:20 -0700248 if (h2e_required) {
Hai Shalomc3565922019-10-28 11:58:20 -0700249 count++;
250 if (count > 8)
251 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
252 }
253
Sunil Ravi77d572f2023-01-17 23:58:31 +0000254 hapd->conf->xrates_supported = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700255 return pos;
256}
257
258
Hai Shalomfdcde762020-04-02 11:19:20 -0700259u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
260 size_t len)
261{
262 size_t i;
263
264 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
265 if (hapd->conf->radio_measurements[i])
266 break;
267 }
268
269 if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
270 return eid;
271
272 *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
273 *eid++ = RRM_CAPABILITIES_IE_LEN;
274 os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
275
276 return eid + RRM_CAPABILITIES_IE_LEN;
277}
278
279
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700280u16 hostapd_own_capab_info(struct hostapd_data *hapd)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700281{
282 int capab = WLAN_CAPABILITY_ESS;
Hai Shalomfdcde762020-04-02 11:19:20 -0700283 int privacy = 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800284 int dfs;
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700285 int i;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800286
287 /* Check if any of configured channels require DFS */
288 dfs = hostapd_is_dfs_required(hapd->iface);
289 if (dfs < 0) {
290 wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
291 dfs);
292 dfs = 0;
293 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700294
295 if (hapd->iface->num_sta_no_short_preamble == 0 &&
296 hapd->iconf->preamble == SHORT_PREAMBLE)
297 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
298
Hai Shalomfdcde762020-04-02 11:19:20 -0700299#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700300 privacy = hapd->conf->ssid.wep.keys_set;
301
302 if (hapd->conf->ieee802_1x &&
303 (hapd->conf->default_wep_key_len ||
304 hapd->conf->individual_wep_key_len))
305 privacy = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -0700306#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700307
308 if (hapd->conf->wpa)
309 privacy = 1;
310
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800311#ifdef CONFIG_HS20
312 if (hapd->conf->osen)
313 privacy = 1;
314#endif /* CONFIG_HS20 */
315
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700316 if (privacy)
317 capab |= WLAN_CAPABILITY_PRIVACY;
318
319 if (hapd->iface->current_mode &&
320 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
321 hapd->iface->num_sta_no_short_slot_time == 0)
322 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
323
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800324 /*
325 * Currently, Spectrum Management capability bit is set when directly
326 * requested in configuration by spectrum_mgmt_required or when AP is
327 * running on DFS channel.
328 * TODO: Also consider driver support for TPC to set Spectrum Mgmt bit
329 */
330 if (hapd->iface->current_mode &&
331 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
332 (hapd->iconf->spectrum_mgmt_required || dfs))
333 capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
334
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700335 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
336 if (hapd->conf->radio_measurements[i]) {
337 capab |= IEEE80211_CAP_RRM;
338 break;
339 }
340 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800341
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700342 return capab;
343}
344
345
Hai Shalomfdcde762020-04-02 11:19:20 -0700346#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800347#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700348static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
349 u16 auth_transaction, const u8 *challenge,
350 int iswep)
351{
352 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
353 HOSTAPD_LEVEL_DEBUG,
354 "authentication (shared key, transaction %d)",
355 auth_transaction);
356
357 if (auth_transaction == 1) {
358 if (!sta->challenge) {
359 /* Generate a pseudo-random challenge */
360 u8 key[8];
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800361
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700362 sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
363 if (sta->challenge == NULL)
364 return WLAN_STATUS_UNSPECIFIED_FAILURE;
365
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800366 if (os_get_random(key, sizeof(key)) < 0) {
367 os_free(sta->challenge);
368 sta->challenge = NULL;
369 return WLAN_STATUS_UNSPECIFIED_FAILURE;
370 }
371
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700372 rc4_skip(key, sizeof(key), 0,
373 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
374 }
375 return 0;
376 }
377
378 if (auth_transaction != 3)
379 return WLAN_STATUS_UNSPECIFIED_FAILURE;
380
381 /* Transaction 3 */
382 if (!iswep || !sta->challenge || !challenge ||
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700383 os_memcmp_const(sta->challenge, challenge,
384 WLAN_AUTH_CHALLENGE_LEN)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700385 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
386 HOSTAPD_LEVEL_INFO,
387 "shared key authentication - invalid "
388 "challenge-response");
389 return WLAN_STATUS_CHALLENGE_FAIL;
390 }
391
392 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
393 HOSTAPD_LEVEL_DEBUG,
394 "authentication OK (shared key)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700395 sta->flags |= WLAN_STA_AUTH;
396 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700397 os_free(sta->challenge);
398 sta->challenge = NULL;
399
400 return 0;
401}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800402#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700403#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700404
405
Hai Shalomfdcde762020-04-02 11:19:20 -0700406static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800407 const u8 *dst, const u8 *bssid,
408 u16 auth_alg, u16 auth_transaction, u16 resp,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700409 const u8 *ies, size_t ies_len, const char *dbg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700410{
411 struct ieee80211_mgmt *reply;
412 u8 *buf;
413 size_t rlen;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800414 int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000415 const u8 *sa = hapd->own_addr;
416 struct wpabuf *ml_resp = NULL;
417
418#ifdef CONFIG_IEEE80211BE
419 /*
420 * Once a non-AP MLD is added to the driver, the addressing should use
421 * the MLD MAC address. Thus, use the MLD address instead of translating
422 * the addresses.
423 */
Sunil Ravi72e01222024-03-09 01:25:43 +0000424 if (ap_sta_is_mld(hapd, sta)) {
Sunil Raviaf399a82024-05-05 20:56:55 +0000425 sa = hapd->mld->mld_addr;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000426
427 ml_resp = hostapd_ml_auth_resp(hapd);
428 if (!ml_resp)
429 return -1;
430 }
431#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700432
433 rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000434 if (ml_resp)
435 rlen += wpabuf_len(ml_resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700436 buf = os_zalloc(rlen);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000437 if (!buf) {
438 wpabuf_free(ml_resp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800439 return -1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000440 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700441
442 reply = (struct ieee80211_mgmt *) buf;
443 reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
444 WLAN_FC_STYPE_AUTH);
445 os_memcpy(reply->da, dst, ETH_ALEN);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000446 os_memcpy(reply->sa, sa, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700447 os_memcpy(reply->bssid, bssid, ETH_ALEN);
448
449 reply->u.auth.auth_alg = host_to_le16(auth_alg);
450 reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
451 reply->u.auth.status_code = host_to_le16(resp);
452
453 if (ies && ies_len)
454 os_memcpy(reply->u.auth.variable, ies, ies_len);
455
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000456#ifdef CONFIG_IEEE80211BE
457 if (ml_resp)
458 os_memcpy(reply->u.auth.variable + ies_len,
459 wpabuf_head(ml_resp), wpabuf_len(ml_resp));
460
461 wpabuf_free(ml_resp);
462#endif /* CONFIG_IEEE80211BE */
463
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700464 wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700465 " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700466 MAC2STR(dst), auth_alg, auth_transaction,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700467 resp, (unsigned long) ies_len, dbg);
Hai Shalomfdcde762020-04-02 11:19:20 -0700468#ifdef CONFIG_TESTING_OPTIONS
469#ifdef CONFIG_SAE
470 if (hapd->conf->sae_confirm_immediate == 2 &&
471 auth_alg == WLAN_AUTH_SAE) {
472 if (auth_transaction == 1 && sta &&
473 (resp == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -0700474 resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
475 resp == WLAN_STATUS_SAE_PK)) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700476 wpa_printf(MSG_DEBUG,
477 "TESTING: Postpone SAE Commit transmission until Confirm is ready");
478 os_free(sta->sae_postponed_commit);
479 sta->sae_postponed_commit = buf;
480 sta->sae_postponed_commit_len = rlen;
481 return WLAN_STATUS_SUCCESS;
482 }
483
484 if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
485 wpa_printf(MSG_DEBUG,
486 "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
487 if (hostapd_drv_send_mlme(hapd,
488 sta->sae_postponed_commit,
489 sta->sae_postponed_commit_len,
490 0, NULL, 0, 0) < 0)
491 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
492 os_free(sta->sae_postponed_commit);
493 sta->sae_postponed_commit = NULL;
494 sta->sae_postponed_commit_len = 0;
495 }
496 }
497#endif /* CONFIG_SAE */
498#endif /* CONFIG_TESTING_OPTIONS */
499 if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800500 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
501 else
502 reply_res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700503
504 os_free(buf);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800505
506 return reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700507}
508
509
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800510#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700511static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
512 u16 auth_transaction, u16 status,
513 const u8 *ies, size_t ies_len)
514{
515 struct hostapd_data *hapd = ctx;
516 struct sta_info *sta;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800517 int reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700518
Hai Shalomfdcde762020-04-02 11:19:20 -0700519 reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700520 auth_transaction, status, ies, ies_len,
521 "auth-ft-finish");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700522
523 sta = ap_get_sta(hapd, dst);
524 if (sta == NULL)
525 return;
526
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800527 if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
528 status != WLAN_STATUS_SUCCESS)) {
529 hostapd_drv_sta_remove(hapd, sta->addr);
530 sta->added_unassoc = 0;
531 return;
532 }
533
534 if (status != WLAN_STATUS_SUCCESS)
535 return;
536
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700537 hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
538 HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
539 sta->flags |= WLAN_STA_AUTH;
540 mlme_authenticate_indication(hapd, sta);
541}
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800542#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700543
544
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800545#ifdef CONFIG_SAE
546
Roshan Pius3a1667e2018-07-03 15:17:14 -0700547static void sae_set_state(struct sta_info *sta, enum sae_state state,
548 const char *reason)
549{
550 wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
551 sae_state_txt(sta->sae->state), sae_state_txt(state),
552 MAC2STR(sta->addr), reason);
553 sta->sae->state = state;
554}
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800555
556
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000557const char * sae_get_password(struct hostapd_data *hapd,
558 struct sta_info *sta,
559 const char *rx_id,
560 struct sae_password_entry **pw_entry,
561 struct sae_pt **s_pt,
562 const struct sae_pk **s_pk)
Hai Shalom60840252021-02-19 19:02:11 -0800563{
564 const char *password = NULL;
565 struct sae_password_entry *pw;
566 struct sae_pt *pt = NULL;
567 const struct sae_pk *pk = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -0700568 struct hostapd_sta_wpa_psk_short *psk = NULL;
Hai Shalom60840252021-02-19 19:02:11 -0800569
570 for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
571 if (!is_broadcast_ether_addr(pw->peer_addr) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000572 (!sta ||
Sunil Ravi72e01222024-03-09 01:25:43 +0000573 !ether_addr_equal(pw->peer_addr, sta->addr)))
Hai Shalom60840252021-02-19 19:02:11 -0800574 continue;
575 if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
576 continue;
577 if (rx_id && pw->identifier &&
578 os_strcmp(rx_id, pw->identifier) != 0)
579 continue;
580 password = pw->password;
581 pt = pw->pt;
582 if (!(hapd->conf->mesh & MESH_ENABLED))
583 pk = pw->pk;
584 break;
585 }
586 if (!password) {
587 password = hapd->conf->ssid.wpa_passphrase;
588 pt = hapd->conf->ssid.pt;
589 }
590
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000591 if (!password && sta) {
Sunil Ravia04bd252022-05-02 22:54:18 -0700592 for (psk = sta->psk; psk; psk = psk->next) {
593 if (psk->is_passphrase) {
594 password = psk->passphrase;
595 break;
596 }
597 }
598 }
599
Hai Shalom60840252021-02-19 19:02:11 -0800600 if (pw_entry)
601 *pw_entry = pw;
602 if (s_pt)
603 *s_pt = pt;
604 if (s_pk)
605 *s_pk = pk;
606
607 return password;
608}
609
610
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800611static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
Hai Shalomc3565922019-10-28 11:58:20 -0700612 struct sta_info *sta, int update,
613 int status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800614{
615 struct wpabuf *buf;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700616 const char *password = NULL;
617 struct sae_password_entry *pw;
618 const char *rx_id = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700619 int use_pt = 0;
620 struct sae_pt *pt = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700621 const struct sae_pk *pk = NULL;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000622 const u8 *own_addr = hapd->own_addr;
623
624#ifdef CONFIG_IEEE80211BE
Sunil Ravi72e01222024-03-09 01:25:43 +0000625 if (ap_sta_is_mld(hapd, sta))
Sunil Raviaf399a82024-05-05 20:56:55 +0000626 own_addr = hapd->mld->mld_addr;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000627#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800628
Hai Shalomc3565922019-10-28 11:58:20 -0700629 if (sta->sae->tmp) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700630 rx_id = sta->sae->tmp->pw_id;
Hai Shalom899fcc72020-10-19 14:38:18 -0700631 use_pt = sta->sae->h2e;
632#ifdef CONFIG_SAE_PK
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000633 os_memcpy(sta->sae->tmp->own_addr, own_addr, ETH_ALEN);
Hai Shalom899fcc72020-10-19 14:38:18 -0700634 os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
635#endif /* CONFIG_SAE_PK */
Hai Shalomc3565922019-10-28 11:58:20 -0700636 }
637
Sunil Ravi77d572f2023-01-17 23:58:31 +0000638 if (rx_id && hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
Hai Shalomfdcde762020-04-02 11:19:20 -0700639 use_pt = 1;
640 else if (status_code == WLAN_STATUS_SUCCESS)
Hai Shalomc3565922019-10-28 11:58:20 -0700641 use_pt = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700642 else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
643 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomc3565922019-10-28 11:58:20 -0700644 use_pt = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700645
Hai Shalom60840252021-02-19 19:02:11 -0800646 password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk);
Hai Shalomc3565922019-10-28 11:58:20 -0700647 if (!password || (use_pt && !pt)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800648 wpa_printf(MSG_DEBUG, "SAE: No password available");
649 return NULL;
650 }
651
Hai Shalomc3565922019-10-28 11:58:20 -0700652 if (update && use_pt &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000653 sae_prepare_commit_pt(sta->sae, pt, own_addr, sta->addr,
Hai Shalom899fcc72020-10-19 14:38:18 -0700654 NULL, pk) < 0)
Hai Shalomc3565922019-10-28 11:58:20 -0700655 return NULL;
656
657 if (update && !use_pt &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000658 sae_prepare_commit(own_addr, sta->addr,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800659 (u8 *) password, os_strlen(password),
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800660 sta->sae) < 0) {
661 wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
662 return NULL;
663 }
664
Hai Shalom021b0b52019-04-10 11:17:58 -0700665 if (pw && pw->vlan_id) {
666 if (!sta->sae->tmp) {
667 wpa_printf(MSG_INFO,
668 "SAE: No temporary data allocated - cannot store VLAN ID");
669 return NULL;
670 }
671 sta->sae->tmp->vlan_id = pw->vlan_id;
672 }
673
Roshan Pius3a1667e2018-07-03 15:17:14 -0700674 buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
675 (rx_id ? 3 + os_strlen(rx_id) : 0));
Hai Shalomfdcde762020-04-02 11:19:20 -0700676 if (buf &&
677 sae_write_commit(sta->sae, buf, sta->sae->tmp ?
678 sta->sae->tmp->anti_clogging_token : NULL,
679 rx_id) < 0) {
680 wpabuf_free(buf);
681 buf = NULL;
682 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800683
684 return buf;
685}
686
687
688static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
689 struct sta_info *sta)
690{
691 struct wpabuf *buf;
692
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800693 buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800694 if (buf == NULL)
695 return NULL;
696
Hai Shalom899fcc72020-10-19 14:38:18 -0700697#ifdef CONFIG_SAE_PK
698#ifdef CONFIG_TESTING_OPTIONS
699 if (sta->sae->tmp)
700 sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
701#endif /* CONFIG_TESTING_OPTIONS */
702#endif /* CONFIG_SAE_PK */
703
704 if (sae_write_confirm(sta->sae, buf) < 0) {
705 wpabuf_free(buf);
706 return NULL;
707 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800708
709 return buf;
710}
711
712
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800713static int auth_sae_send_commit(struct hostapd_data *hapd,
714 struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700715 const u8 *bssid, int update, int status_code)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800716{
717 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800718 int reply_res;
Hai Shalomc3565922019-10-28 11:58:20 -0700719 u16 status;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800720
Hai Shalomc3565922019-10-28 11:58:20 -0700721 data = auth_build_sae_commit(hapd, sta, update, status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700722 if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
723 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800724 if (data == NULL)
725 return WLAN_STATUS_UNSPECIFIED_FAILURE;
726
Hai Shalom899fcc72020-10-19 14:38:18 -0700727 if (sta->sae->tmp && sta->sae->pk)
728 status = WLAN_STATUS_SAE_PK;
729 else if (sta->sae->tmp && sta->sae->h2e)
730 status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
731 else
732 status = WLAN_STATUS_SUCCESS;
733#ifdef CONFIG_TESTING_OPTIONS
734 if (hapd->conf->sae_commit_status >= 0 &&
735 hapd->conf->sae_commit_status != status) {
736 wpa_printf(MSG_INFO,
737 "TESTING: Override SAE commit status code %u --> %d",
738 status, hapd->conf->sae_commit_status);
739 status = hapd->conf->sae_commit_status;
740 }
741#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomfdcde762020-04-02 11:19:20 -0700742 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
743 WLAN_AUTH_SAE, 1,
Hai Shalomc3565922019-10-28 11:58:20 -0700744 status, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700745 wpabuf_len(data), "sae-send-commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800746
747 wpabuf_free(data);
748
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800749 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800750}
751
752
753static int auth_sae_send_confirm(struct hostapd_data *hapd,
754 struct sta_info *sta,
755 const u8 *bssid)
756{
757 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800758 int reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800759
760 data = auth_build_sae_confirm(hapd, sta);
761 if (data == NULL)
762 return WLAN_STATUS_UNSPECIFIED_FAILURE;
763
Hai Shalomfdcde762020-04-02 11:19:20 -0700764 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
765 WLAN_AUTH_SAE, 2,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800766 WLAN_STATUS_SUCCESS, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700767 wpabuf_len(data), "sae-send-confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800768
769 wpabuf_free(data);
770
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800771 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800772}
773
Hai Shaloma20dcd72022-02-04 13:43:00 -0800774#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800775
Hai Shaloma20dcd72022-02-04 13:43:00 -0800776
777#if defined(CONFIG_SAE) || defined(CONFIG_PASN)
778
779static int use_anti_clogging(struct hostapd_data *hapd)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800780{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800781 struct sta_info *sta;
782 unsigned int open = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800783
Hai Shaloma20dcd72022-02-04 13:43:00 -0800784 if (hapd->conf->anti_clogging_threshold == 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800785 return 1;
786
787 for (sta = hapd->sta_list; sta; sta = sta->next) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800788#ifdef CONFIG_SAE
789 if (sta->sae &&
790 (sta->sae->state == SAE_COMMITTED ||
791 sta->sae->state == SAE_CONFIRMED))
792 open++;
793#endif /* CONFIG_SAE */
794#ifdef CONFIG_PASN
795 if (sta->pasn && sta->pasn->ecdh)
796 open++;
797#endif /* CONFIG_PASN */
798 if (open >= hapd->conf->anti_clogging_threshold)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800799 return 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800800 }
801
Hai Shaloma20dcd72022-02-04 13:43:00 -0800802#ifdef CONFIG_SAE
Hai Shalom021b0b52019-04-10 11:17:58 -0700803 /* In addition to already existing open SAE sessions, check whether
804 * there are enough pending commit messages in the processing queue to
805 * potentially result in too many open sessions. */
806 if (open + dl_list_len(&hapd->sae_commit_queue) >=
Hai Shaloma20dcd72022-02-04 13:43:00 -0800807 hapd->conf->anti_clogging_threshold)
Hai Shalom021b0b52019-04-10 11:17:58 -0700808 return 1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800809#endif /* CONFIG_SAE */
Hai Shalom021b0b52019-04-10 11:17:58 -0700810
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800811 return 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800812}
813
Hai Shaloma20dcd72022-02-04 13:43:00 -0800814#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
815
816
817#ifdef CONFIG_SAE
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800818
Roshan Pius3a1667e2018-07-03 15:17:14 -0700819static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800820{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700821 if (sta->sae->sync > hapd->conf->sae_sync) {
822 sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800823 sta->sae->sync = 0;
824 return -1;
825 }
826 return 0;
827}
828
829
830static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
831{
832 struct hostapd_data *hapd = eloop_ctx;
833 struct sta_info *sta = eloop_data;
834 int ret;
835
Roshan Pius3a1667e2018-07-03 15:17:14 -0700836 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800837 return;
838 sta->sae->sync++;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700839 wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700840 " (sync=%d state=%s)",
841 MAC2STR(sta->addr), sta->sae->sync,
842 sae_state_txt(sta->sae->state));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800843
844 switch (sta->sae->state) {
845 case SAE_COMMITTED:
Hai Shalomc3565922019-10-28 11:58:20 -0700846 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800847 eloop_register_timeout(0,
848 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800849 auth_sae_retransmit_timer, hapd, sta);
850 break;
851 case SAE_CONFIRMED:
852 ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800853 eloop_register_timeout(0,
854 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800855 auth_sae_retransmit_timer, hapd, sta);
856 break;
857 default:
858 ret = -1;
859 break;
860 }
861
862 if (ret != WLAN_STATUS_SUCCESS)
863 wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
864}
865
866
867void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
868{
869 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
870}
871
872
873static void sae_set_retransmit_timer(struct hostapd_data *hapd,
874 struct sta_info *sta)
875{
876 if (!(hapd->conf->mesh & MESH_ENABLED))
877 return;
878
879 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800880 eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800881 auth_sae_retransmit_timer, hapd, sta);
882}
883
884
Hai Shalom5f92bc92019-04-18 11:54:11 -0700885static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
886 struct sta_info *sta, u16 status)
887{
888 struct external_auth params;
889
890 os_memset(&params, 0, sizeof(params));
891 params.status = status;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000892
893#ifdef CONFIG_IEEE80211BE
Sunil Ravi72e01222024-03-09 01:25:43 +0000894 if (ap_sta_is_mld(hapd, sta))
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000895 params.bssid =
896 sta->mld_info.links[sta->mld_assoc_link_id].peer_addr;
897#endif /* CONFIG_IEEE80211BE */
898 if (!params.bssid)
899 params.bssid = sta->addr;
900
Hai Shalom81f62d82019-07-22 12:10:00 -0700901 if (status == WLAN_STATUS_SUCCESS && sta->sae &&
902 !hapd->conf->disable_pmksa_caching)
Hai Shalom5f92bc92019-04-18 11:54:11 -0700903 params.pmkid = sta->sae->pmkid;
904
905 hostapd_drv_send_external_auth_status(hapd, &params);
906}
907
908
Dmitry Shmidte4663042016-04-04 10:07:49 -0700909void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
910{
Hai Shalom021b0b52019-04-10 11:17:58 -0700911#ifndef CONFIG_NO_VLAN
912 struct vlan_description vlan_desc;
913
914 if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
915 wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
916 " to VLAN ID %d",
917 MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
918
Sunil Ravi72e01222024-03-09 01:25:43 +0000919 if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
920 os_memset(&vlan_desc, 0, sizeof(vlan_desc));
921 vlan_desc.notempty = 1;
922 vlan_desc.untagged = sta->sae->tmp->vlan_id;
923 if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
924 wpa_printf(MSG_INFO,
925 "Invalid VLAN ID %d in sae_password",
926 sta->sae->tmp->vlan_id);
927 return;
928 }
Hai Shalom021b0b52019-04-10 11:17:58 -0700929
Sunil Ravi72e01222024-03-09 01:25:43 +0000930 if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
931 ap_sta_bind_vlan(hapd, sta) < 0) {
932 wpa_printf(MSG_INFO,
933 "Failed to assign VLAN ID %d from sae_password to "
934 MACSTR, sta->sae->tmp->vlan_id,
935 MAC2STR(sta->addr));
936 return;
937 }
938 } else {
939 sta->vlan_id = sta->sae->tmp->vlan_id;
Hai Shalom021b0b52019-04-10 11:17:58 -0700940 }
941 }
942#endif /* CONFIG_NO_VLAN */
943
Dmitry Shmidte4663042016-04-04 10:07:49 -0700944 sta->flags |= WLAN_STA_AUTH;
945 sta->auth_alg = WLAN_AUTH_SAE;
946 mlme_authenticate_indication(hapd, sta);
947 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700948 sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
Hai Shalomfdcde762020-04-02 11:19:20 -0700949 crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
950 sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
951 sta->sae->peer_commit_scalar = NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -0700952 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
Sunil Ravi89eba102022-09-13 21:04:37 -0700953 sta->sae->pmk, sta->sae->pmk_len,
954 sta->sae->pmkid, sta->sae->akmp);
Hai Shalom5f92bc92019-04-18 11:54:11 -0700955 sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
Dmitry Shmidte4663042016-04-04 10:07:49 -0700956}
957
958
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800959static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700960 const u8 *bssid, u16 auth_transaction, u16 status_code,
961 int allow_reuse, int *sta_removed)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800962{
963 int ret;
964
Hai Shalom5f92bc92019-04-18 11:54:11 -0700965 *sta_removed = 0;
966
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800967 if (auth_transaction != 1 && auth_transaction != 2)
968 return WLAN_STATUS_UNSPECIFIED_FAILURE;
969
Roshan Pius3a1667e2018-07-03 15:17:14 -0700970 wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
971 MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
972 auth_transaction);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800973 switch (sta->sae->state) {
974 case SAE_NOTHING:
975 if (auth_transaction == 1) {
Hai Shalom899fcc72020-10-19 14:38:18 -0700976 if (sta->sae->tmp) {
977 sta->sae->h2e =
978 (status_code ==
979 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
980 status_code == WLAN_STATUS_SAE_PK);
981 sta->sae->pk =
982 status_code == WLAN_STATUS_SAE_PK;
983 }
Hai Shalom021b0b52019-04-10 11:17:58 -0700984 ret = auth_sae_send_commit(hapd, sta, bssid,
Hai Shalomc3565922019-10-28 11:58:20 -0700985 !allow_reuse, status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800986 if (ret)
987 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700988 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800989
990 if (sae_process_commit(sta->sae) < 0)
991 return WLAN_STATUS_UNSPECIFIED_FAILURE;
992
993 /*
Hai Shalomc3565922019-10-28 11:58:20 -0700994 * In mesh case, both Commit and Confirm are sent
995 * immediately. In infrastructure BSS, by default, only
996 * a single Authentication frame (Commit) is expected
997 * from the AP here and the second one (Confirm) will
998 * be sent once the STA has sent its second
999 * Authentication frame (Confirm). This behavior can be
1000 * overridden with explicit configuration so that the
1001 * infrastructure BSS case sends both frames together.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001002 */
Hai Shalomc3565922019-10-28 11:58:20 -07001003 if ((hapd->conf->mesh & MESH_ENABLED) ||
1004 hapd->conf->sae_confirm_immediate) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001005 /*
1006 * Send both Commit and Confirm immediately
1007 * based on SAE finite state machine
1008 * Nothing -> Confirm transition.
1009 */
1010 ret = auth_sae_send_confirm(hapd, sta, bssid);
1011 if (ret)
1012 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001013 sae_set_state(sta, SAE_CONFIRMED,
1014 "Sent Confirm (mesh)");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001015 } else {
1016 /*
1017 * For infrastructure BSS, send only the Commit
1018 * message now to get alternating sequence of
1019 * Authentication frames between the AP and STA.
1020 * Confirm will be sent in
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001021 * Committed -> Confirmed/Accepted transition
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001022 * when receiving Confirm from STA.
1023 */
1024 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001025 sta->sae->sync = 0;
1026 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001027 } else {
1028 hostapd_logger(hapd, sta->addr,
1029 HOSTAPD_MODULE_IEEE80211,
1030 HOSTAPD_LEVEL_DEBUG,
1031 "SAE confirm before commit");
1032 }
1033 break;
1034 case SAE_COMMITTED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001035 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001036 if (auth_transaction == 1) {
1037 if (sae_process_commit(sta->sae) < 0)
1038 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1039
1040 ret = auth_sae_send_confirm(hapd, sta, bssid);
1041 if (ret)
1042 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001043 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001044 sta->sae->sync = 0;
1045 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001046 } else if (hapd->conf->mesh & MESH_ENABLED) {
1047 /*
1048 * In mesh case, follow SAE finite state machine and
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001049 * send Commit now, if sync count allows.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001050 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001051 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001052 return WLAN_STATUS_SUCCESS;
1053 sta->sae->sync++;
1054
Hai Shalomc3565922019-10-28 11:58:20 -07001055 ret = auth_sae_send_commit(hapd, sta, bssid, 0,
1056 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001057 if (ret)
1058 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001059
1060 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001061 } else {
1062 /*
1063 * For instructure BSS, send the postponed Confirm from
1064 * Nothing -> Confirmed transition that was reduced to
1065 * Nothing -> Committed above.
1066 */
1067 ret = auth_sae_send_confirm(hapd, sta, bssid);
1068 if (ret)
1069 return ret;
1070
Roshan Pius3a1667e2018-07-03 15:17:14 -07001071 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001072
1073 /*
1074 * Since this was triggered on Confirm RX, run another
1075 * step to get to Accepted without waiting for
1076 * additional events.
1077 */
Hai Shalom021b0b52019-04-10 11:17:58 -07001078 return sae_sm_step(hapd, sta, bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001079 WLAN_STATUS_SUCCESS, 0, sta_removed);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001080 }
1081 break;
1082 case SAE_CONFIRMED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001083 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001084 if (auth_transaction == 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001085 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001086 return WLAN_STATUS_SUCCESS;
1087 sta->sae->sync++;
1088
Hai Shalomc3565922019-10-28 11:58:20 -07001089 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1090 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001091 if (ret)
1092 return ret;
1093
1094 if (sae_process_commit(sta->sae) < 0)
1095 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1096
1097 ret = auth_sae_send_confirm(hapd, sta, bssid);
1098 if (ret)
1099 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001100
1101 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001102 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001103 sta->sae->send_confirm = 0xffff;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001104 sae_accept_sta(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001105 }
1106 break;
1107 case SAE_ACCEPTED:
Roshan Pius3a1667e2018-07-03 15:17:14 -07001108 if (auth_transaction == 1 &&
1109 (hapd->conf->mesh & MESH_ENABLED)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001110 wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
1111 ") doing reauthentication",
1112 MAC2STR(sta->addr));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001113 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
Hai Shalom5f92bc92019-04-18 11:54:11 -07001114 ap_free_sta(hapd, sta);
1115 *sta_removed = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001116 } else if (auth_transaction == 1) {
1117 wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
Hai Shalomc3565922019-10-28 11:58:20 -07001118 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1119 status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001120 if (ret)
1121 return ret;
1122 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
1123
1124 if (sae_process_commit(sta->sae) < 0)
1125 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1126 sta->sae->sync = 0;
1127 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001128 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001129 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001130 return WLAN_STATUS_SUCCESS;
1131 sta->sae->sync++;
1132
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001133 ret = auth_sae_send_confirm(hapd, sta, bssid);
1134 sae_clear_temp_data(sta->sae);
1135 if (ret)
1136 return ret;
1137 }
1138 break;
1139 default:
1140 wpa_printf(MSG_ERROR, "SAE: invalid state %d",
1141 sta->sae->state);
1142 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1143 }
1144 return WLAN_STATUS_SUCCESS;
1145}
1146
1147
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001148static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
1149{
1150 struct sae_data *sae = sta->sae;
1151 int i, *groups = hapd->conf->sae_groups;
Hai Shalom021b0b52019-04-10 11:17:58 -07001152 int default_groups[] = { 19, 0 };
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001153
1154 if (sae->state != SAE_COMMITTED)
1155 return;
1156
1157 wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
1158
Hai Shalom021b0b52019-04-10 11:17:58 -07001159 if (!groups)
1160 groups = default_groups;
1161 for (i = 0; groups[i] > 0; i++) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001162 if (sae->group == groups[i])
1163 break;
1164 }
1165
Hai Shalom021b0b52019-04-10 11:17:58 -07001166 if (groups[i] <= 0) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001167 wpa_printf(MSG_DEBUG,
1168 "SAE: Previously selected group not found from the current configuration");
1169 return;
1170 }
1171
1172 for (;;) {
1173 i++;
1174 if (groups[i] <= 0) {
1175 wpa_printf(MSG_DEBUG,
1176 "SAE: No alternative group enabled");
1177 return;
1178 }
1179
1180 if (sae_set_group(sae, groups[i]) < 0)
1181 continue;
1182
1183 break;
1184 }
1185 wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
1186}
1187
1188
Hai Shalomc3565922019-10-28 11:58:20 -07001189static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
1190{
Sunil Ravi77d572f2023-01-17 23:58:31 +00001191 enum sae_pwe sae_pwe = hapd->conf->sae_pwe;
Hai Shalomfdcde762020-04-02 11:19:20 -07001192 int id_in_use;
Hai Shalom60840252021-02-19 19:02:11 -08001193 bool sae_pk = false;
Hai Shalomfdcde762020-04-02 11:19:20 -07001194
1195 id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001196 if (id_in_use == 2 && sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
1197 sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
1198 else if (id_in_use == 1 && sae_pwe == SAE_PWE_HUNT_AND_PECK)
1199 sae_pwe = SAE_PWE_BOTH;
Hai Shalom899fcc72020-10-19 14:38:18 -07001200#ifdef CONFIG_SAE_PK
Hai Shalom60840252021-02-19 19:02:11 -08001201 sae_pk = hostapd_sae_pk_in_use(hapd->conf);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001202 if (sae_pwe == SAE_PWE_HUNT_AND_PECK && sae_pk)
1203 sae_pwe = SAE_PWE_BOTH;
Hai Shalom899fcc72020-10-19 14:38:18 -07001204#endif /* CONFIG_SAE_PK */
Sunil Ravi77d572f2023-01-17 23:58:31 +00001205 if (sae_pwe == SAE_PWE_HUNT_AND_PECK &&
Sunil Ravi89eba102022-09-13 21:04:37 -07001206 (hapd->conf->wpa_key_mgmt &
1207 (WPA_KEY_MGMT_SAE_EXT_KEY | WPA_KEY_MGMT_FT_SAE_EXT_KEY)))
Sunil Ravi77d572f2023-01-17 23:58:31 +00001208 sae_pwe = SAE_PWE_BOTH;
Hai Shalomfdcde762020-04-02 11:19:20 -07001209
Sunil Ravi77d572f2023-01-17 23:58:31 +00001210 return ((sae_pwe == SAE_PWE_HUNT_AND_PECK ||
1211 sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001212 status_code == WLAN_STATUS_SUCCESS) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001213 (sae_pwe == SAE_PWE_HASH_TO_ELEMENT &&
Hai Shalom899fcc72020-10-19 14:38:18 -07001214 (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001215 (sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001216 (sae_pwe == SAE_PWE_BOTH &&
Hai Shalomc3565922019-10-28 11:58:20 -07001217 (status_code == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -07001218 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001219 (sae_pk && status_code == WLAN_STATUS_SAE_PK)));
Hai Shalomc3565922019-10-28 11:58:20 -07001220}
1221
1222
1223static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
1224{
1225 int *groups = hapd->conf->sae_groups;
1226 int default_groups[] = { 19, 0 };
1227 int i;
1228
1229 if (!groups)
1230 groups = default_groups;
1231
1232 for (i = 0; groups[i] > 0; i++) {
1233 if (groups[i] == group)
1234 return 1;
1235 }
1236
1237 return 0;
1238}
1239
1240
1241static int check_sae_rejected_groups(struct hostapd_data *hapd,
Hai Shalom899fcc72020-10-19 14:38:18 -07001242 struct sae_data *sae)
Hai Shalomc3565922019-10-28 11:58:20 -07001243{
Hai Shalom899fcc72020-10-19 14:38:18 -07001244 const struct wpabuf *groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001245 size_t i, count;
1246 const u8 *pos;
1247
Hai Shalom899fcc72020-10-19 14:38:18 -07001248 if (!sae->tmp)
1249 return 0;
1250 groups = sae->tmp->peer_rejected_groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001251 if (!groups)
1252 return 0;
1253
1254 pos = wpabuf_head(groups);
1255 count = wpabuf_len(groups) / 2;
1256 for (i = 0; i < count; i++) {
1257 int enabled;
1258 u16 group;
1259
1260 group = WPA_GET_LE16(pos);
1261 pos += 2;
1262 enabled = sae_is_group_enabled(hapd, group);
1263 wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
1264 group, enabled ? "enabled" : "disabled");
1265 if (enabled)
1266 return 1;
1267 }
1268
1269 return 0;
1270}
1271
1272
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001273static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
1274 const struct ieee80211_mgmt *mgmt, size_t len,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001275 u16 auth_transaction, u16 status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001276{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001277 int resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001278 struct wpabuf *data = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07001279 int *groups = hapd->conf->sae_groups;
1280 int default_groups[] = { 19, 0 };
1281 const u8 *pos, *end;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001282 int sta_removed = 0;
Hai Shalom60840252021-02-19 19:02:11 -08001283 bool success_status;
Hai Shalom021b0b52019-04-10 11:17:58 -07001284
1285 if (!groups)
1286 groups = default_groups;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001287
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001288#ifdef CONFIG_TESTING_OPTIONS
1289 if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001290 wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
1291 pos = mgmt->u.auth.variable;
1292 end = ((const u8 *) mgmt) + len;
Hai Shalom899fcc72020-10-19 14:38:18 -07001293 resp = status_code;
Sunil Ravi72e01222024-03-09 01:25:43 +00001294 send_auth_reply(hapd, sta, sta->addr, mgmt->bssid,
1295 WLAN_AUTH_SAE,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001296 auth_transaction, resp, pos, end - pos,
1297 "auth-sae-reflection-attack");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001298 goto remove_sta;
1299 }
1300
1301 if (hapd->conf->sae_commit_override && auth_transaction == 1) {
1302 wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
Sunil Ravi72e01222024-03-09 01:25:43 +00001303 send_auth_reply(hapd, sta, sta->addr, mgmt->bssid,
1304 WLAN_AUTH_SAE,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001305 auth_transaction, resp,
1306 wpabuf_head(hapd->conf->sae_commit_override),
Roshan Pius3a1667e2018-07-03 15:17:14 -07001307 wpabuf_len(hapd->conf->sae_commit_override),
1308 "sae-commit-override");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001309 goto remove_sta;
1310 }
1311#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001312 if (!sta->sae) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001313 if (auth_transaction != 1 ||
Hai Shalomc3565922019-10-28 11:58:20 -07001314 !sae_status_success(hapd, status_code)) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001315 wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
1316 status_code);
1317 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1318 goto reply;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001319 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001320 sta->sae = os_zalloc(sizeof(*sta->sae));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001321 if (!sta->sae) {
1322 resp = -1;
1323 goto remove_sta;
1324 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001325 sae_set_state(sta, SAE_NOTHING, "Init");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001326 sta->sae->sync = 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001327 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001328
Dmitry Shmidte4663042016-04-04 10:07:49 -07001329 if (sta->mesh_sae_pmksa_caching) {
1330 wpa_printf(MSG_DEBUG,
1331 "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
1332 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
1333 sta->mesh_sae_pmksa_caching = 0;
1334 }
1335
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001336 if (auth_transaction == 1) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001337 const u8 *token = NULL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001338 size_t token_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07001339 int allow_reuse = 0;
1340
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001341 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1342 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001343 "start SAE authentication (RX commit, status=%u (%s))",
1344 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001345
1346 if ((hapd->conf->mesh & MESH_ENABLED) &&
1347 status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
1348 sta->sae->tmp) {
1349 pos = mgmt->u.auth.variable;
1350 end = ((const u8 *) mgmt) + len;
1351 if (pos + sizeof(le16) > end) {
1352 wpa_printf(MSG_ERROR,
1353 "SAE: Too short anti-clogging token request");
1354 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1355 goto reply;
1356 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001357 resp = sae_group_allowed(sta->sae, groups,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001358 WPA_GET_LE16(pos));
1359 if (resp != WLAN_STATUS_SUCCESS) {
1360 wpa_printf(MSG_ERROR,
1361 "SAE: Invalid group in anti-clogging token request");
1362 goto reply;
1363 }
1364 pos += sizeof(le16);
1365
1366 wpabuf_free(sta->sae->tmp->anti_clogging_token);
1367 sta->sae->tmp->anti_clogging_token =
1368 wpabuf_alloc_copy(pos, end - pos);
1369 if (sta->sae->tmp->anti_clogging_token == NULL) {
1370 wpa_printf(MSG_ERROR,
1371 "SAE: Failed to alloc for anti-clogging token");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001372 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1373 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001374 }
1375
1376 /*
1377 * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code
1378 * is 76, a new Commit Message shall be constructed
1379 * with the Anti-Clogging Token from the received
1380 * Authentication frame, and the commit-scalar and
1381 * COMMIT-ELEMENT previously sent.
1382 */
Hai Shalomc3565922019-10-28 11:58:20 -07001383 resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
1384 status_code);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001385 if (resp != WLAN_STATUS_SUCCESS) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001386 wpa_printf(MSG_ERROR,
1387 "SAE: Failed to send commit message");
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 sae_set_state(sta, SAE_COMMITTED,
1391 "Sent Commit (anti-clogging token case in mesh)");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001392 sta->sae->sync = 0;
1393 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001394 return;
1395 }
1396
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001397 if ((hapd->conf->mesh & MESH_ENABLED) &&
1398 status_code ==
1399 WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1400 sta->sae->tmp) {
1401 wpa_printf(MSG_DEBUG,
1402 "SAE: Peer did not accept our SAE group");
1403 sae_pick_next_group(hapd, sta);
1404 goto remove_sta;
1405 }
1406
Hai Shalomc3565922019-10-28 11:58:20 -07001407 if (!sae_status_success(hapd, status_code))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001408 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001409
Roshan Pius3a1667e2018-07-03 15:17:14 -07001410 if (!(hapd->conf->mesh & MESH_ENABLED) &&
1411 sta->sae->state == SAE_COMMITTED) {
1412 /* This is needed in the infrastructure BSS case to
1413 * address a sequence where a STA entry may remain in
1414 * hostapd across two attempts to do SAE authentication
1415 * by the same STA. The second attempt may end up trying
1416 * to use a different group and that would not be
1417 * allowed if we remain in Committed state with the
1418 * previously set parameters. */
Hai Shalom021b0b52019-04-10 11:17:58 -07001419 pos = mgmt->u.auth.variable;
1420 end = ((const u8 *) mgmt) + len;
1421 if (end - pos >= (int) sizeof(le16) &&
1422 sae_group_allowed(sta->sae, groups,
1423 WPA_GET_LE16(pos)) ==
1424 WLAN_STATUS_SUCCESS) {
1425 /* Do not waste resources deriving the same PWE
1426 * again since the same group is reused. */
1427 sae_set_state(sta, SAE_NOTHING,
1428 "Allow previous PWE to be reused");
1429 allow_reuse = 1;
1430 } else {
1431 sae_set_state(sta, SAE_NOTHING,
1432 "Clear existing state to allow restart");
1433 sae_clear_data(sta->sae);
1434 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001435 }
1436
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001437 resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
1438 ((const u8 *) mgmt) + len -
1439 mgmt->u.auth.variable, &token,
Hai Shalomc3565922019-10-28 11:58:20 -07001440 &token_len, groups, status_code ==
Hai Shalom899fcc72020-10-19 14:38:18 -07001441 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001442 status_code == WLAN_STATUS_SAE_PK,
1443 NULL);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001444 if (resp == SAE_SILENTLY_DISCARD) {
1445 wpa_printf(MSG_DEBUG,
1446 "SAE: Drop commit message from " MACSTR " due to reflection attack",
1447 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001448 goto remove_sta;
Dmitry Shmidt41712582015-06-29 11:02:15 -07001449 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001450
1451 if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
1452 wpa_msg(hapd->msg_ctx, MSG_INFO,
1453 WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
1454 MACSTR, MAC2STR(sta->addr));
1455 sae_clear_retransmit_timer(hapd, sta);
1456 sae_set_state(sta, SAE_NOTHING,
1457 "Unknown Password Identifier");
1458 goto remove_sta;
1459 }
1460
Hai Shaloma20dcd72022-02-04 13:43:00 -08001461 if (token &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00001462 check_comeback_token(hapd->comeback_key,
1463 hapd->comeback_pending_idx, sta->addr,
1464 token, token_len)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001465 < 0) {
1466 wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
1467 "incorrect token from " MACSTR,
1468 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001469 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1470 goto remove_sta;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001471 }
1472
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001473 if (resp != WLAN_STATUS_SUCCESS)
1474 goto reply;
1475
Hai Shalom899fcc72020-10-19 14:38:18 -07001476 if (check_sae_rejected_groups(hapd, sta->sae)) {
Hai Shalomc3565922019-10-28 11:58:20 -07001477 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001478 goto reply;
Hai Shalomc3565922019-10-28 11:58:20 -07001479 }
1480
Hai Shaloma20dcd72022-02-04 13:43:00 -08001481 if (!token && use_anti_clogging(hapd) && !allow_reuse) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001482 int h2e = 0;
1483
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001484 wpa_printf(MSG_DEBUG,
1485 "SAE: Request anti-clogging token from "
1486 MACSTR, MAC2STR(sta->addr));
Hai Shalomfdcde762020-04-02 11:19:20 -07001487 if (sta->sae->tmp)
Hai Shalom899fcc72020-10-19 14:38:18 -07001488 h2e = sta->sae->h2e;
1489 if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1490 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomfdcde762020-04-02 11:19:20 -07001491 h2e = 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001492 data = auth_build_token_req(
1493 &hapd->last_comeback_key_update,
1494 hapd->comeback_key,
1495 hapd->comeback_idx,
1496 hapd->comeback_pending_idx,
1497 sizeof(hapd->comeback_pending_idx),
1498 sta->sae->group,
1499 sta->addr, h2e);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001500 resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
1501 if (hapd->conf->mesh & MESH_ENABLED)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001502 sae_set_state(sta, SAE_NOTHING,
1503 "Request anti-clogging token case in mesh");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001504 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001505 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001506
Hai Shalom021b0b52019-04-10 11:17:58 -07001507 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001508 status_code, allow_reuse, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001509 } else if (auth_transaction == 2) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001510 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1511 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001512 "SAE authentication (RX confirm, status=%u (%s))",
1513 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001514 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001515 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001516 if (sta->sae->state >= SAE_CONFIRMED ||
1517 !(hapd->conf->mesh & MESH_ENABLED)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001518 const u8 *var;
1519 size_t var_len;
1520 u16 peer_send_confirm;
1521
1522 var = mgmt->u.auth.variable;
1523 var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable;
1524 if (var_len < 2) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001525 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001526 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001527 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001528
1529 peer_send_confirm = WPA_GET_LE16(var);
1530
1531 if (sta->sae->state == SAE_ACCEPTED &&
1532 (peer_send_confirm <= sta->sae->rc ||
1533 peer_send_confirm == 0xffff)) {
1534 wpa_printf(MSG_DEBUG,
1535 "SAE: Silently ignore unexpected Confirm from peer "
1536 MACSTR
1537 " (peer-send-confirm=%u Rc=%u)",
1538 MAC2STR(sta->addr),
1539 peer_send_confirm, sta->sae->rc);
1540 return;
1541 }
1542
Sunil Ravi77d572f2023-01-17 23:58:31 +00001543 if (sae_check_confirm(sta->sae, var, var_len,
1544 NULL) < 0) {
1545 resp = WLAN_STATUS_CHALLENGE_FAIL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001546 goto reply;
1547 }
1548 sta->sae->rc = peer_send_confirm;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001549 }
Hai Shalomc3565922019-10-28 11:58:20 -07001550 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
1551 status_code, 0, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001552 } else {
1553 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1554 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001555 "unexpected SAE authentication transaction %u (status=%u (%s))",
1556 auth_transaction, status_code,
1557 status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001558 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001559 goto remove_sta;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001560 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1561 }
1562
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001563reply:
Hai Shalom5f92bc92019-04-18 11:54:11 -07001564 if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001565 pos = mgmt->u.auth.variable;
1566 end = ((const u8 *) mgmt) + len;
1567
1568 /* Copy the Finite Cyclic Group field from the request if we
1569 * rejected it as unsupported group. */
1570 if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1571 !data && end - pos >= 2)
1572 data = wpabuf_alloc_copy(pos, 2);
1573
Hai Shalom5f92bc92019-04-18 11:54:11 -07001574 sae_sme_send_external_auth_status(hapd, sta, resp);
Sunil Ravi72e01222024-03-09 01:25:43 +00001575 send_auth_reply(hapd, sta, sta->addr, mgmt->bssid,
1576 WLAN_AUTH_SAE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001577 auth_transaction, resp,
1578 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07001579 data ? wpabuf_len(data) : 0, "auth-sae");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001580 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001581
1582remove_sta:
Hai Shalom60840252021-02-19 19:02:11 -08001583 if (auth_transaction == 1)
1584 success_status = sae_status_success(hapd, status_code);
1585 else
1586 success_status = status_code == WLAN_STATUS_SUCCESS;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001587 if (!sta_removed && sta->added_unassoc &&
Hai Shalom60840252021-02-19 19:02:11 -08001588 (resp != WLAN_STATUS_SUCCESS || !success_status)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001589 hostapd_drv_sta_remove(hapd, sta->addr);
1590 sta->added_unassoc = 0;
1591 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001592 wpabuf_free(data);
1593}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001594
1595
1596/**
1597 * auth_sae_init_committed - Send COMMIT and start SAE in committed state
1598 * @hapd: BSS data for the device initiating the authentication
1599 * @sta: the peer to which commit authentication frame is sent
1600 *
1601 * This function implements Init event handling (IEEE Std 802.11-2012,
1602 * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
1603 * sta->sae structure should be initialized appropriately via a call to
1604 * sae_prepare_commit().
1605 */
1606int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
1607{
1608 int ret;
1609
1610 if (!sta->sae || !sta->sae->tmp)
1611 return -1;
1612
1613 if (sta->sae->state != SAE_NOTHING)
1614 return -1;
1615
Hai Shalomc3565922019-10-28 11:58:20 -07001616 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001617 if (ret)
1618 return -1;
1619
Roshan Pius3a1667e2018-07-03 15:17:14 -07001620 sae_set_state(sta, SAE_COMMITTED, "Init and sent commit");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001621 sta->sae->sync = 0;
1622 sae_set_retransmit_timer(hapd, sta);
1623
1624 return 0;
1625}
1626
Hai Shalom021b0b52019-04-10 11:17:58 -07001627
1628void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
1629{
1630 struct hostapd_data *hapd = eloop_ctx;
1631 struct hostapd_sae_commit_queue *q;
1632 unsigned int queue_len;
1633
1634 q = dl_list_first(&hapd->sae_commit_queue,
1635 struct hostapd_sae_commit_queue, list);
1636 if (!q)
1637 return;
1638 wpa_printf(MSG_DEBUG,
1639 "SAE: Process next available message from queue");
1640 dl_list_del(&q->list);
1641 handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
1642 q->rssi, 1);
1643 os_free(q);
1644
1645 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1646 return;
1647 queue_len = dl_list_len(&hapd->sae_commit_queue);
1648 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1649 hapd, NULL);
1650}
1651
1652
1653static void auth_sae_queue(struct hostapd_data *hapd,
1654 const struct ieee80211_mgmt *mgmt, size_t len,
1655 int rssi)
1656{
1657 struct hostapd_sae_commit_queue *q, *q2;
1658 unsigned int queue_len;
1659 const struct ieee80211_mgmt *mgmt2;
1660
1661 queue_len = dl_list_len(&hapd->sae_commit_queue);
1662 if (queue_len >= 15) {
1663 wpa_printf(MSG_DEBUG,
1664 "SAE: No more room in message queue - drop the new frame from "
1665 MACSTR, MAC2STR(mgmt->sa));
1666 return;
1667 }
1668
1669 wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
1670 MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
1671 queue_len);
1672 q = os_zalloc(sizeof(*q) + len);
1673 if (!q)
1674 return;
1675 q->rssi = rssi;
1676 q->len = len;
1677 os_memcpy(q->msg, mgmt, len);
1678
1679 /* Check whether there is already a queued Authentication frame from the
1680 * same station with the same transaction number and if so, replace that
1681 * queue entry with the new one. This avoids issues with a peer that
1682 * sends multiple times (e.g., due to frequent SAE retries). There is no
1683 * point in us trying to process the old attempts after a new one has
1684 * obsoleted them. */
1685 dl_list_for_each(q2, &hapd->sae_commit_queue,
1686 struct hostapd_sae_commit_queue, list) {
1687 mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
Sunil Ravi72e01222024-03-09 01:25:43 +00001688 if (ether_addr_equal(mgmt->sa, mgmt2->sa) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07001689 mgmt->u.auth.auth_transaction ==
1690 mgmt2->u.auth.auth_transaction) {
1691 wpa_printf(MSG_DEBUG,
1692 "SAE: Replace queued message from same STA with same transaction number");
1693 dl_list_add(&q2->list, &q->list);
1694 dl_list_del(&q2->list);
1695 os_free(q2);
1696 goto queued;
1697 }
1698 }
1699
1700 /* No pending identical entry, so add to the end of the queue */
1701 dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
1702
1703queued:
1704 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1705 return;
1706 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1707 hapd, NULL);
1708}
1709
1710
1711static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
1712{
1713 struct hostapd_sae_commit_queue *q;
1714 const struct ieee80211_mgmt *mgmt;
1715
1716 dl_list_for_each(q, &hapd->sae_commit_queue,
1717 struct hostapd_sae_commit_queue, list) {
1718 mgmt = (const struct ieee80211_mgmt *) q->msg;
Sunil Ravi72e01222024-03-09 01:25:43 +00001719 if (ether_addr_equal(addr, mgmt->sa))
Hai Shalom021b0b52019-04-10 11:17:58 -07001720 return 1;
1721 }
1722
1723 return 0;
1724}
1725
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001726#endif /* CONFIG_SAE */
1727
1728
Hai Shalomfdcde762020-04-02 11:19:20 -07001729static u16 wpa_res_to_status_code(enum wpa_validate_result res)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001730{
Hai Shalomfdcde762020-04-02 11:19:20 -07001731 switch (res) {
1732 case WPA_IE_OK:
1733 return WLAN_STATUS_SUCCESS;
1734 case WPA_INVALID_IE:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001735 return WLAN_STATUS_INVALID_IE;
Hai Shalomfdcde762020-04-02 11:19:20 -07001736 case WPA_INVALID_GROUP:
1737 return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
1738 case WPA_INVALID_PAIRWISE:
1739 return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
1740 case WPA_INVALID_AKMP:
1741 return WLAN_STATUS_AKMP_NOT_VALID;
1742 case WPA_NOT_ENABLED:
1743 return WLAN_STATUS_INVALID_IE;
1744 case WPA_ALLOC_FAIL:
1745 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1746 case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
1747 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
1748 case WPA_INVALID_MGMT_GROUP_CIPHER:
1749 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
1750 case WPA_INVALID_MDIE:
1751 return WLAN_STATUS_INVALID_MDIE;
1752 case WPA_INVALID_PROTO:
1753 return WLAN_STATUS_INVALID_IE;
1754 case WPA_INVALID_PMKID:
1755 return WLAN_STATUS_INVALID_PMKID;
1756 case WPA_DENIED_OTHER_REASON:
1757 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
1758 }
1759 return WLAN_STATUS_INVALID_IE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001760}
1761
1762
1763#ifdef CONFIG_FILS
1764
1765static void handle_auth_fils_finish(struct hostapd_data *hapd,
1766 struct sta_info *sta, u16 resp,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001767 struct wpabuf *data, int pub);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001768
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001769void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
1770 const u8 *pos, size_t len, u16 auth_alg,
1771 u16 auth_transaction, u16 status_code,
1772 void (*cb)(struct hostapd_data *hapd,
1773 struct sta_info *sta, u16 resp,
1774 struct wpabuf *data, int pub))
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001775{
1776 u16 resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001777 const u8 *end;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001778 struct ieee802_11_elems elems;
Hai Shalomfdcde762020-04-02 11:19:20 -07001779 enum wpa_validate_result res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001780 struct wpa_ie_data rsn;
1781 struct rsn_pmksa_cache_entry *pmksa = NULL;
1782
1783 if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
1784 return;
1785
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001786 end = pos + len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001787
1788 wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
1789 pos, end - pos);
1790
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001791 /* TODO: FILS PK */
1792#ifdef CONFIG_FILS_SK_PFS
1793 if (auth_alg == WLAN_AUTH_FILS_SK_PFS) {
1794 u16 group;
1795 struct wpabuf *pub;
1796 size_t elem_len;
1797
1798 /* Using FILS PFS */
1799
1800 /* Finite Cyclic Group */
1801 if (end - pos < 2) {
1802 wpa_printf(MSG_DEBUG,
1803 "FILS: No room for Finite Cyclic Group");
1804 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1805 goto fail;
1806 }
1807 group = WPA_GET_LE16(pos);
1808 pos += 2;
1809 if (group != hapd->conf->fils_dh_group) {
1810 wpa_printf(MSG_DEBUG,
1811 "FILS: Unsupported Finite Cyclic Group: %u (expected %u)",
1812 group, hapd->conf->fils_dh_group);
1813 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1814 goto fail;
1815 }
1816
1817 crypto_ecdh_deinit(sta->fils_ecdh);
1818 sta->fils_ecdh = crypto_ecdh_init(group);
1819 if (!sta->fils_ecdh) {
1820 wpa_printf(MSG_INFO,
1821 "FILS: Could not initialize ECDH with group %d",
1822 group);
1823 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1824 goto fail;
1825 }
1826
1827 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
1828 if (!pub) {
1829 wpa_printf(MSG_DEBUG,
1830 "FILS: Failed to derive ECDH public key");
1831 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1832 goto fail;
1833 }
1834 elem_len = wpabuf_len(pub);
1835 wpabuf_free(pub);
1836
1837 /* Element */
1838 if ((size_t) (end - pos) < elem_len) {
1839 wpa_printf(MSG_DEBUG, "FILS: No room for Element");
1840 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1841 goto fail;
1842 }
1843
1844 wpabuf_free(sta->fils_g_sta);
1845 sta->fils_g_sta = wpabuf_alloc_copy(pos, elem_len);
1846 wpabuf_clear_free(sta->fils_dh_ss);
1847 sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1,
1848 pos, elem_len);
1849 if (!sta->fils_dh_ss) {
1850 wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
1851 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1852 goto fail;
1853 }
1854 wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss);
1855 pos += elem_len;
1856 } else {
1857 crypto_ecdh_deinit(sta->fils_ecdh);
1858 sta->fils_ecdh = NULL;
1859 wpabuf_clear_free(sta->fils_dh_ss);
1860 sta->fils_dh_ss = NULL;
1861 }
1862#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001863
1864 wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
1865 if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
1866 wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
1867 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1868 goto fail;
1869 }
1870
1871 /* RSNE */
1872 wpa_hexdump(MSG_DEBUG, "FILS: RSN element",
1873 elems.rsn_ie, elems.rsn_ie_len);
1874 if (!elems.rsn_ie ||
1875 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
1876 &rsn) < 0) {
1877 wpa_printf(MSG_DEBUG, "FILS: No valid RSN element");
1878 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1879 goto fail;
1880 }
1881
1882 if (!sta->wpa_sm)
1883 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
1884 NULL);
1885 if (!sta->wpa_sm) {
1886 wpa_printf(MSG_DEBUG,
1887 "FILS: Failed to initialize RSN state machine");
1888 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1889 goto fail;
1890 }
1891
1892 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07001893 hapd->iface->freq,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001894 elems.rsn_ie - 2, elems.rsn_ie_len + 2,
Hai Shalomc3565922019-10-28 11:58:20 -07001895 elems.rsnxe ? elems.rsnxe - 2 : NULL,
1896 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001897 elems.mdie, elems.mdie_len, NULL, 0);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001898 resp = wpa_res_to_status_code(res);
1899 if (resp != WLAN_STATUS_SUCCESS)
1900 goto fail;
1901
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001902 if (!elems.fils_nonce) {
1903 wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
1904 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1905 goto fail;
1906 }
1907 wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce,
1908 FILS_NONCE_LEN);
1909 os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN);
1910
1911 /* PMKID List */
1912 if (rsn.pmkid && rsn.num_pmkid > 0) {
1913 u8 num;
1914 const u8 *pmkid;
1915
1916 wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
1917 rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
1918
1919 pmkid = rsn.pmkid;
1920 num = rsn.num_pmkid;
1921 while (num) {
1922 wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
1923 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
1924 pmkid);
1925 if (pmksa)
1926 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001927 pmksa = wpa_auth_pmksa_get_fils_cache_id(hapd->wpa_auth,
1928 sta->addr,
1929 pmkid);
1930 if (pmksa)
1931 break;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001932 pmkid += PMKID_LEN;
1933 num--;
1934 }
1935 }
1936 if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) {
1937 wpa_printf(MSG_DEBUG,
1938 "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore",
1939 wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp);
1940 pmksa = NULL;
1941 }
1942 if (pmksa)
1943 wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry");
1944
1945 /* FILS Session */
1946 if (!elems.fils_session) {
1947 wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
1948 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1949 goto fail;
1950 }
1951 wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
1952 FILS_SESSION_LEN);
1953 os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
1954
Hai Shalomfdcde762020-04-02 11:19:20 -07001955 /* Wrapped Data */
1956 if (elems.wrapped_data) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001957 wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
Hai Shalomfdcde762020-04-02 11:19:20 -07001958 elems.wrapped_data,
1959 elems.wrapped_data_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001960 if (!pmksa) {
1961#ifndef CONFIG_NO_RADIUS
1962 if (!sta->eapol_sm) {
1963 sta->eapol_sm =
1964 ieee802_1x_alloc_eapol_sm(hapd, sta);
1965 }
1966 wpa_printf(MSG_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001967 "FILS: Forward EAP-Initiate/Re-auth to authentication server");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001968 ieee802_1x_encapsulate_radius(
Hai Shalomfdcde762020-04-02 11:19:20 -07001969 hapd, sta, elems.wrapped_data,
1970 elems.wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001971 sta->fils_pending_cb = cb;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001972 wpa_printf(MSG_DEBUG,
1973 "FILS: Will send Authentication frame once the response from authentication server is available");
1974 sta->flags |= WLAN_STA_PENDING_FILS_ERP;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001975 /* Calculate pending PMKID here so that we do not need
1976 * to maintain a copy of the EAP-Initiate/Reauth
1977 * message. */
1978 if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
Hai Shalomfdcde762020-04-02 11:19:20 -07001979 elems.wrapped_data,
1980 elems.wrapped_data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001981 sta->fils_erp_pmkid) == 0)
1982 sta->fils_erp_pmkid_set = 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001983 return;
1984#else /* CONFIG_NO_RADIUS */
1985 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1986 goto fail;
1987#endif /* CONFIG_NO_RADIUS */
1988 }
1989 }
1990
1991fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001992 if (cb) {
1993 struct wpabuf *data;
1994 int pub = 0;
1995
1996 data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, NULL,
1997 NULL, 0, &pub);
1998 if (!data) {
1999 wpa_printf(MSG_DEBUG,
2000 "%s: prepare_auth_resp_fils() returned failure",
2001 __func__);
2002 }
2003
2004 cb(hapd, sta, resp, data, pub);
2005 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002006}
2007
2008
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002009static struct wpabuf *
2010prepare_auth_resp_fils(struct hostapd_data *hapd,
2011 struct sta_info *sta, u16 *resp,
2012 struct rsn_pmksa_cache_entry *pmksa,
2013 struct wpabuf *erp_resp,
2014 const u8 *msk, size_t msk_len,
2015 int *is_pub)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002016{
2017 u8 fils_nonce[FILS_NONCE_LEN];
2018 size_t ielen;
2019 struct wpabuf *data = NULL;
2020 const u8 *ie;
2021 u8 *ie_buf = NULL;
2022 const u8 *pmk = NULL;
2023 size_t pmk_len = 0;
Paul Stewart092955c2017-02-06 09:13:09 -08002024 u8 pmk_buf[PMK_LEN_MAX];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002025 struct wpabuf *pub = NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002026
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002027 if (*resp != WLAN_STATUS_SUCCESS)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002028 goto fail;
2029
2030 ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
2031 if (!ie) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002032 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002033 goto fail;
2034 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002035
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002036 if (pmksa) {
2037 /* Add PMKID of the selected PMKSA into RSNE */
2038 ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN);
2039 if (!ie_buf) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002040 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002041 goto fail;
2042 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002043
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002044 os_memcpy(ie_buf, ie, ielen);
Sunil Ravi72e01222024-03-09 01:25:43 +00002045 if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid, true) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002046 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002047 goto fail;
2048 }
2049 ie = ie_buf;
2050 }
2051
2052 if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002053 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002054 goto fail;
2055 }
2056 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
2057 fils_nonce, FILS_NONCE_LEN);
2058
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002059#ifdef CONFIG_FILS_SK_PFS
2060 if (sta->fils_dh_ss && sta->fils_ecdh) {
2061 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
2062 if (!pub) {
2063 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2064 goto fail;
2065 }
2066 }
2067#endif /* CONFIG_FILS_SK_PFS */
2068
2069 data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0));
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002070 if (!data) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002071 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002072 goto fail;
2073 }
2074
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002075 /* TODO: FILS PK */
2076#ifdef CONFIG_FILS_SK_PFS
2077 if (pub) {
2078 /* Finite Cyclic Group */
2079 wpabuf_put_le16(data, hapd->conf->fils_dh_group);
2080
2081 /* Element */
2082 wpabuf_put_buf(data, pub);
2083 }
2084#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002085
2086 /* RSNE */
2087 wpabuf_put_data(data, ie, ielen);
2088
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002089 /* MDE when using FILS+FT (already included in ie,ielen with RSNE) */
2090
2091#ifdef CONFIG_IEEE80211R_AP
2092 if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
2093 /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
2094 int res;
2095
Sunil Ravi77d572f2023-01-17 23:58:31 +00002096 res = wpa_auth_write_fte(hapd->wpa_auth, sta->wpa_sm,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002097 wpabuf_put(data, 0),
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002098 wpabuf_tailroom(data));
2099 if (res < 0) {
2100 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2101 goto fail;
2102 }
2103 wpabuf_put(data, res);
2104 }
2105#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002106
2107 /* FILS Nonce */
2108 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2109 wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */
2110 /* Element ID Extension */
2111 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE);
2112 wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN);
2113
2114 /* FILS Session */
2115 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2116 wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */
2117 /* Element ID Extension */
2118 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
2119 wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
2120
Hai Shalomfdcde762020-04-02 11:19:20 -07002121 /* Wrapped Data */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002122 if (!pmksa && erp_resp) {
2123 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2124 wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
2125 /* Element ID Extension */
Hai Shalomfdcde762020-04-02 11:19:20 -07002126 wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002127 wpabuf_put_buf(data, erp_resp);
2128
Paul Stewart092955c2017-02-06 09:13:09 -08002129 if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
2130 msk, msk_len, sta->fils_snonce, fils_nonce,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002131 sta->fils_dh_ss ?
2132 wpabuf_head(sta->fils_dh_ss) : NULL,
2133 sta->fils_dh_ss ?
2134 wpabuf_len(sta->fils_dh_ss) : 0,
2135 pmk_buf, &pmk_len)) {
Paul Stewart092955c2017-02-06 09:13:09 -08002136 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002137 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Paul Stewart092955c2017-02-06 09:13:09 -08002138 wpabuf_free(data);
2139 data = NULL;
2140 goto fail;
2141 }
2142 pmk = pmk_buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002143
2144 /* Don't use DHss in PTK derivation if PMKSA caching is not
2145 * used. */
2146 wpabuf_clear_free(sta->fils_dh_ss);
2147 sta->fils_dh_ss = NULL;
2148
2149 if (sta->fils_erp_pmkid_set) {
2150 /* TODO: get PMKLifetime from WPA parameters */
2151 unsigned int dot11RSNAConfigPMKLifetime = 43200;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002152 int session_timeout;
2153
2154 session_timeout = dot11RSNAConfigPMKLifetime;
2155 if (sta->session_timeout_set) {
2156 struct os_reltime now, diff;
2157
2158 os_get_reltime(&now);
2159 os_reltime_sub(&sta->session_timeout, &now,
2160 &diff);
2161 session_timeout = diff.sec;
2162 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002163
2164 sta->fils_erp_pmkid_set = 0;
Hai Shalom81f62d82019-07-22 12:10:00 -07002165 wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
2166 sta->fils_erp_pmkid);
Hai Shalom021b0b52019-04-10 11:17:58 -07002167 if (!hapd->conf->disable_pmksa_caching &&
2168 wpa_auth_pmksa_add2(
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002169 hapd->wpa_auth, sta->addr,
2170 pmk, pmk_len,
2171 sta->fils_erp_pmkid,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002172 session_timeout,
Sunil Ravi72e01222024-03-09 01:25:43 +00002173 wpa_auth_sta_key_mgmt(sta->wpa_sm),
2174 NULL) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002175 wpa_printf(MSG_ERROR,
2176 "FILS: Failed to add PMKSA cache entry based on ERP");
2177 }
2178 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002179 } else if (pmksa) {
2180 pmk = pmksa->pmk;
2181 pmk_len = pmksa->pmk_len;
2182 }
2183
2184 if (!pmk) {
2185 wpa_printf(MSG_DEBUG, "FILS: No PMK available");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002186 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002187 wpabuf_free(data);
2188 data = NULL;
2189 goto fail;
2190 }
2191
2192 if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002193 sta->fils_snonce, fils_nonce,
2194 sta->fils_dh_ss ?
2195 wpabuf_head(sta->fils_dh_ss) : NULL,
2196 sta->fils_dh_ss ?
2197 wpabuf_len(sta->fils_dh_ss) : 0,
2198 sta->fils_g_sta, pub) < 0) {
2199 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002200 wpabuf_free(data);
2201 data = NULL;
2202 goto fail;
2203 }
2204
2205fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002206 if (is_pub)
2207 *is_pub = pub != NULL;
2208 os_free(ie_buf);
2209 wpabuf_free(pub);
2210 wpabuf_clear_free(sta->fils_dh_ss);
2211 sta->fils_dh_ss = NULL;
2212#ifdef CONFIG_FILS_SK_PFS
2213 crypto_ecdh_deinit(sta->fils_ecdh);
2214 sta->fils_ecdh = NULL;
2215#endif /* CONFIG_FILS_SK_PFS */
2216 return data;
2217}
2218
2219
2220static void handle_auth_fils_finish(struct hostapd_data *hapd,
2221 struct sta_info *sta, u16 resp,
2222 struct wpabuf *data, int pub)
2223{
2224 u16 auth_alg;
2225
2226 auth_alg = (pub ||
2227 resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
2228 WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Hai Shalomfdcde762020-04-02 11:19:20 -07002229 send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002230 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07002231 data ? wpabuf_len(data) : 0, "auth-fils-finish");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002232 wpabuf_free(data);
2233
2234 if (resp == WLAN_STATUS_SUCCESS) {
2235 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2236 HOSTAPD_LEVEL_DEBUG,
2237 "authentication OK (FILS)");
2238 sta->flags |= WLAN_STA_AUTH;
2239 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002240 sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002241 mlme_authenticate_indication(hapd, sta);
2242 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002243}
2244
2245
2246void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
2247 struct sta_info *sta, int success,
2248 struct wpabuf *erp_resp,
2249 const u8 *msk, size_t msk_len)
2250{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002251 u16 resp;
Hai Shalom60840252021-02-19 19:02:11 -08002252 u32 flags = sta->flags;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002253
Hai Shalom60840252021-02-19 19:02:11 -08002254 sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
2255 WLAN_STA_PENDING_PASN_FILS_ERP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002256
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002257 resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
Hai Shalom60840252021-02-19 19:02:11 -08002258
2259 if (flags & WLAN_STA_PENDING_FILS_ERP) {
2260 struct wpabuf *data;
2261 int pub = 0;
2262
2263 if (!sta->fils_pending_cb)
2264 return;
2265
2266 data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
2267 msk, msk_len, &pub);
2268 if (!data) {
2269 wpa_printf(MSG_DEBUG,
2270 "%s: prepare_auth_resp_fils() failure",
2271 __func__);
2272 }
2273 sta->fils_pending_cb(hapd, sta, resp, data, pub);
2274#ifdef CONFIG_PASN
2275 } else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
2276 pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
2277 msk, msk_len);
2278#endif /* CONFIG_PASN */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002279 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002280}
2281
2282#endif /* CONFIG_FILS */
2283
2284
Hai Shalomfdcde762020-04-02 11:19:20 -07002285static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
2286 const u8 *msg, size_t len,
2287 struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002288{
2289 int res;
2290
Hai Shalomfdcde762020-04-02 11:19:20 -07002291 res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002292
2293 if (res == HOSTAPD_ACL_REJECT) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002294 wpa_printf(MSG_DEBUG, "Station " MACSTR
2295 " not allowed to authenticate",
2296 MAC2STR(addr));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002297 return HOSTAPD_ACL_REJECT;
2298 }
2299
2300 if (res == HOSTAPD_ACL_PENDING) {
2301 wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
2302 " waiting for an external authentication",
2303 MAC2STR(addr));
2304 /* Authentication code will re-send the authentication frame
2305 * after it has received (and cached) information from the
2306 * external source. */
2307 return HOSTAPD_ACL_PENDING;
2308 }
2309
2310 return res;
2311}
2312
2313
Sunil Ravia04bd252022-05-02 22:54:18 -07002314int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
2315 int res, struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002316{
Hai Shalomfdcde762020-04-02 11:19:20 -07002317 u32 session_timeout = info->session_timeout;
2318 u32 acct_interim_interval = info->acct_interim_interval;
2319 struct vlan_description *vlan_id = &info->vlan_id;
2320 struct hostapd_sta_wpa_psk_short *psk = info->psk;
2321 char *identity = info->identity;
2322 char *radius_cui = info->radius_cui;
2323
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002324 if (vlan_id->notempty &&
2325 !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
2326 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2327 HOSTAPD_LEVEL_INFO,
2328 "Invalid VLAN %d%s received from RADIUS server",
2329 vlan_id->untagged,
2330 vlan_id->tagged[0] ? "+" : "");
2331 return -1;
2332 }
2333 if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
2334 return -1;
2335 if (sta->vlan_id)
2336 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2337 HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
2338
2339 hostapd_free_psk_list(sta->psk);
Hai Shalomfdcde762020-04-02 11:19:20 -07002340 if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
2341 hostapd_copy_psk_list(&sta->psk, psk);
2342 else
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002343 sta->psk = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002344
Roshan Pius3a1667e2018-07-03 15:17:14 -07002345 os_free(sta->identity);
Hai Shalomfdcde762020-04-02 11:19:20 -07002346 if (identity)
2347 sta->identity = os_strdup(identity);
2348 else
2349 sta->identity = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002350
2351 os_free(sta->radius_cui);
Hai Shalomfdcde762020-04-02 11:19:20 -07002352 if (radius_cui)
2353 sta->radius_cui = os_strdup(radius_cui);
2354 else
2355 sta->radius_cui = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002356
2357 if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
2358 sta->acct_interim_interval = acct_interim_interval;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002359 if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
2360 sta->session_timeout_set = 1;
2361 os_get_reltime(&sta->session_timeout);
2362 sta->session_timeout.sec += session_timeout;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002363 ap_sta_session_timeout(hapd, sta, session_timeout);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002364 } else {
2365 sta->session_timeout_set = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002366 ap_sta_no_session_timeout(hapd, sta);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002367 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002368
2369 return 0;
2370}
2371
2372
Hai Shalom60840252021-02-19 19:02:11 -08002373#ifdef CONFIG_PASN
Hai Shalom60840252021-02-19 19:02:11 -08002374#ifdef CONFIG_FILS
2375
Hai Shalom60840252021-02-19 19:02:11 -08002376static void pasn_fils_auth_resp(struct hostapd_data *hapd,
2377 struct sta_info *sta, u16 status,
2378 struct wpabuf *erp_resp,
2379 const u8 *msk, size_t msk_len)
2380{
2381 struct pasn_data *pasn = sta->pasn;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002382 struct pasn_fils *fils = &pasn->fils;
Hai Shalom60840252021-02-19 19:02:11 -08002383 u8 pmk[PMK_LEN_MAX];
2384 size_t pmk_len;
2385 int ret;
2386
2387 wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
2388 status);
2389
2390 if (status != WLAN_STATUS_SUCCESS)
2391 goto fail;
2392
2393 if (!pasn->secret) {
2394 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
2395 goto fail;
2396 }
2397
2398 if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
2399 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
2400 goto fail;
2401 }
2402
2403 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
2404 fils->anonce, FILS_NONCE_LEN);
2405
Sunil Raviaf399a82024-05-05 20:56:55 +00002406 ret = fils_rmsk_to_pmk(pasn_get_akmp(pasn), msk, msk_len, fils->nonce,
Hai Shalom60840252021-02-19 19:02:11 -08002407 fils->anonce, NULL, 0, pmk, &pmk_len);
2408 if (ret) {
2409 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
2410 goto fail;
2411 }
2412
2413 ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
2414 wpabuf_head(pasn->secret),
2415 wpabuf_len(pasn->secret),
Sunil Raviaf399a82024-05-05 20:56:55 +00002416 pasn_get_ptk(sta->pasn), pasn_get_akmp(sta->pasn),
2417 pasn_get_cipher(sta->pasn), sta->pasn->kdk_len);
Hai Shalom60840252021-02-19 19:02:11 -08002418 if (ret) {
2419 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
2420 goto fail;
2421 }
2422
Sunil Ravi89eba102022-09-13 21:04:37 -07002423 if (pasn->secure_ltf) {
Sunil Raviaf399a82024-05-05 20:56:55 +00002424 ret = wpa_ltf_keyseed(pasn_get_ptk(pasn), pasn_get_akmp(pasn),
2425 pasn_get_cipher(pasn));
Sunil Ravi89eba102022-09-13 21:04:37 -07002426 if (ret) {
2427 wpa_printf(MSG_DEBUG,
2428 "PASN: FILS: Failed to derive LTF keyseed");
2429 goto fail;
2430 }
2431 }
2432
Hai Shalom60840252021-02-19 19:02:11 -08002433 wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
2434
2435 wpabuf_free(pasn->secret);
2436 pasn->secret = NULL;
2437
2438 fils->erp_resp = erp_resp;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002439 ret = handle_auth_pasn_resp(sta->pasn, hapd->own_addr, sta->addr, NULL,
2440 WLAN_STATUS_SUCCESS);
Hai Shalom60840252021-02-19 19:02:11 -08002441 fils->erp_resp = NULL;
2442
2443 if (ret) {
2444 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
2445 goto fail;
2446 }
2447
2448 fils->state = PASN_FILS_STATE_COMPLETE;
2449 return;
2450fail:
2451 ap_free_sta(hapd, sta);
2452}
2453
2454
2455static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
2456 struct wpabuf *wd)
2457{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002458#ifdef CONFIG_NO_RADIUS
2459 wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
2460 return -1;
2461#else /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002462 struct pasn_data *pasn = sta->pasn;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002463 struct pasn_fils *fils = &pasn->fils;
Hai Shalom60840252021-02-19 19:02:11 -08002464 struct ieee802_11_elems elems;
2465 struct wpa_ie_data rsne_data;
2466 struct wpabuf *fils_wd;
2467 const u8 *data;
2468 size_t buf_len;
2469 u16 alg, seq, status;
2470 int ret;
2471
2472 if (fils->state != PASN_FILS_STATE_NONE) {
2473 wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
2474 return -1;
2475 }
2476
2477 if (!wd) {
2478 wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
2479 return -1;
2480 }
2481
2482 data = wpabuf_head_u8(wd);
2483 buf_len = wpabuf_len(wd);
2484
2485 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002486 wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002487 buf_len);
2488 return -1;
2489 }
2490
2491 alg = WPA_GET_LE16(data);
2492 seq = WPA_GET_LE16(data + 2);
2493 status = WPA_GET_LE16(data + 4);
2494
2495 wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
2496 alg, seq, status);
2497
2498 if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
2499 status != WLAN_STATUS_SUCCESS) {
2500 wpa_printf(MSG_DEBUG,
2501 "PASN: FILS: Dropping peer authentication");
2502 return -1;
2503 }
2504
2505 data += 6;
2506 buf_len -= 6;
2507
2508 if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
2509 wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
2510 return -1;
2511 }
2512
2513 if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00002514 !elems.wrapped_data || !elems.fils_session) {
Hai Shalom60840252021-02-19 19:02:11 -08002515 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
2516 return -1;
2517 }
2518
2519 ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2520 &rsne_data);
2521 if (ret) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002522 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RSNE");
Hai Shalom60840252021-02-19 19:02:11 -08002523 return -1;
2524 }
2525
2526 ret = wpa_pasn_validate_rsne(&rsne_data);
2527 if (ret) {
2528 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
2529 return -1;
2530 }
2531
2532 if (rsne_data.num_pmkid) {
2533 wpa_printf(MSG_DEBUG,
2534 "PASN: FILS: Not expecting PMKID in RSNE");
2535 return -1;
2536 }
2537
2538 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
2539 FILS_NONCE_LEN);
2540 os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
2541
2542 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
2543 FILS_SESSION_LEN);
2544 os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
2545
Sunil Ravi72e01222024-03-09 01:25:43 +00002546 fils_wd = ieee802_11_defrag(elems.wrapped_data, elems.wrapped_data_len,
2547 true);
Hai Shalom60840252021-02-19 19:02:11 -08002548
2549 if (!fils_wd) {
2550 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
2551 return -1;
2552 }
2553
2554 if (!sta->eapol_sm)
2555 sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
2556
2557 wpa_printf(MSG_DEBUG,
2558 "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
2559
2560 ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
2561 wpabuf_len(fils_wd));
2562
2563 sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
2564
2565 fils->state = PASN_FILS_STATE_PENDING_AS;
2566
2567 /*
2568 * Calculate pending PMKID here so that we do not need to maintain a
2569 * copy of the EAP-Initiate/Reautt message.
2570 */
Sunil Raviaf399a82024-05-05 20:56:55 +00002571 fils_pmkid_erp(pasn_get_akmp(pasn),
2572 wpabuf_head(fils_wd), wpabuf_len(fils_wd),
Hai Shalom60840252021-02-19 19:02:11 -08002573 fils->erp_pmkid);
2574
2575 wpabuf_free(fils_wd);
2576 return 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002577#endif /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002578}
2579
2580#endif /* CONFIG_FILS */
2581
2582
Sunil Ravi77d572f2023-01-17 23:58:31 +00002583static int hapd_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len,
2584 int noack, unsigned int freq, unsigned int wait)
Hai Shalom60840252021-02-19 19:02:11 -08002585{
Sunil Ravi77d572f2023-01-17 23:58:31 +00002586 struct hostapd_data *hapd = ctx;
2587
2588 return hostapd_drv_send_mlme(hapd, data, data_len, 0, NULL, 0, 0);
2589}
2590
2591
2592static void hapd_initialize_pasn(struct hostapd_data *hapd,
2593 struct sta_info *sta)
2594{
2595 struct pasn_data *pasn = sta->pasn;
2596
Sunil Raviaf399a82024-05-05 20:56:55 +00002597 pasn_register_callbacks(pasn, hapd, hapd_pasn_send_mlme, NULL);
2598 pasn_set_bssid(pasn, hapd->own_addr);
2599 pasn_set_own_addr(pasn, hapd->own_addr);
2600 pasn_set_peer_addr(pasn, sta->addr);
2601 pasn_set_wpa_key_mgmt(pasn, hapd->conf->wpa_key_mgmt);
2602 pasn_set_rsn_pairwise(pasn, hapd->conf->rsn_pairwise);
Sunil Ravi77d572f2023-01-17 23:58:31 +00002603 pasn->pasn_groups = hapd->conf->pasn_groups;
Sunil Ravi640215c2023-06-28 23:08:09 +00002604 pasn->noauth = hapd->conf->pasn_noauth;
Sunil Raviaf399a82024-05-05 20:56:55 +00002605 if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP)
2606 pasn_enable_kdk_derivation(pasn);
2607
Sunil Ravi77d572f2023-01-17 23:58:31 +00002608#ifdef CONFIG_TESTING_OPTIONS
2609 pasn->corrupt_mic = hapd->conf->pasn_corrupt_mic;
2610 if (hapd->conf->force_kdk_derivation)
Sunil Raviaf399a82024-05-05 20:56:55 +00002611 pasn_enable_kdk_derivation(pasn);
Sunil Ravi77d572f2023-01-17 23:58:31 +00002612#endif /* CONFIG_TESTING_OPTIONS */
2613 pasn->use_anti_clogging = use_anti_clogging(hapd);
Sunil Raviaf399a82024-05-05 20:56:55 +00002614 pasn_set_password(pasn, sae_get_password(hapd, sta, NULL, NULL,
2615 &pasn->pt, NULL));
Sunil Ravi77d572f2023-01-17 23:58:31 +00002616 pasn->rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &pasn->rsn_ie_len);
Sunil Raviaf399a82024-05-05 20:56:55 +00002617 pasn_set_rsnxe_ie(pasn, hostapd_wpa_ie(hapd, WLAN_EID_RSNX));
Sunil Ravi77d572f2023-01-17 23:58:31 +00002618 pasn->disable_pmksa_caching = hapd->conf->disable_pmksa_caching;
Sunil Raviaf399a82024-05-05 20:56:55 +00002619 pasn_set_responder_pmksa(pasn,
2620 wpa_auth_get_pmksa_cache(hapd->wpa_auth));
Sunil Ravi77d572f2023-01-17 23:58:31 +00002621
2622 pasn->comeback_after = hapd->conf->pasn_comeback_after;
2623 pasn->comeback_idx = hapd->comeback_idx;
2624 pasn->comeback_key = hapd->comeback_key;
2625 pasn->comeback_pending_idx = hapd->comeback_pending_idx;
Hai Shalom60840252021-02-19 19:02:11 -08002626}
2627
2628
Sunil Ravi89eba102022-09-13 21:04:37 -07002629static int pasn_set_keys_from_cache(struct hostapd_data *hapd,
2630 const u8 *own_addr, const u8 *sta_addr,
2631 int cipher, int akmp)
2632{
2633 struct ptksa_cache_entry *entry;
2634
2635 entry = ptksa_cache_get(hapd->ptksa, sta_addr, cipher);
2636 if (!entry) {
2637 wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR
2638 " not present in PTKSA cache", MAC2STR(sta_addr));
2639 return -1;
2640 }
2641
Sunil Ravi72e01222024-03-09 01:25:43 +00002642 if (!ether_addr_equal(entry->own_addr, own_addr)) {
Sunil Ravi89eba102022-09-13 21:04:37 -07002643 wpa_printf(MSG_DEBUG,
2644 "PASN: own addr " MACSTR " and PTKSA entry own addr "
2645 MACSTR " differ",
2646 MAC2STR(own_addr), MAC2STR(entry->own_addr));
2647 return -1;
2648 }
2649
2650 wpa_printf(MSG_DEBUG, "PASN: " MACSTR " present in PTKSA cache",
2651 MAC2STR(sta_addr));
2652 hostapd_drv_set_secure_ranging_ctx(hapd, own_addr, sta_addr, cipher,
2653 entry->ptk.tk_len, entry->ptk.tk,
2654 entry->ptk.ltf_keyseed_len,
2655 entry->ptk.ltf_keyseed, 0);
2656
2657 return 0;
2658}
2659
2660
Sunil Ravi77d572f2023-01-17 23:58:31 +00002661static void hapd_pasn_update_params(struct hostapd_data *hapd,
2662 struct sta_info *sta,
2663 const struct ieee80211_mgmt *mgmt,
2664 size_t len)
Hai Shalom60840252021-02-19 19:02:11 -08002665{
Sunil Ravi77d572f2023-01-17 23:58:31 +00002666 struct pasn_data *pasn = sta->pasn;
Hai Shalom60840252021-02-19 19:02:11 -08002667 struct ieee802_11_elems elems;
2668 struct wpa_ie_data rsn_data;
Sunil Ravi72e01222024-03-09 01:25:43 +00002669#ifdef CONFIG_FILS
Hai Shalom60840252021-02-19 19:02:11 -08002670 struct wpa_pasn_params_data pasn_params;
Hai Shalom60840252021-02-19 19:02:11 -08002671 struct wpabuf *wrapped_data = NULL;
Sunil Ravi72e01222024-03-09 01:25:43 +00002672#endif /* CONFIG_FILS */
Sunil Raviaf399a82024-05-05 20:56:55 +00002673 int akmp;
Hai Shalom60840252021-02-19 19:02:11 -08002674
2675 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
2676 len - offsetof(struct ieee80211_mgmt,
2677 u.auth.variable),
2678 &elems, 0) == ParseFailed) {
2679 wpa_printf(MSG_DEBUG,
2680 "PASN: Failed parsing Authentication frame");
Sunil Ravi77d572f2023-01-17 23:58:31 +00002681 return;
Hai Shalom60840252021-02-19 19:02:11 -08002682 }
2683
Sunil Ravi77d572f2023-01-17 23:58:31 +00002684 if (!elems.rsn_ie ||
2685 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2686 &rsn_data)) {
2687 wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE");
2688 return;
2689 }
2690
2691 if (!(rsn_data.key_mgmt & pasn->wpa_key_mgmt) ||
2692 !(rsn_data.pairwise_cipher & pasn->rsn_pairwise)) {
2693 wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
2694 return;
2695 }
2696
Sunil Raviaf399a82024-05-05 20:56:55 +00002697 pasn_set_akmp(pasn, rsn_data.key_mgmt);
2698 pasn_set_cipher(pasn, rsn_data.pairwise_cipher);
Sunil Ravi77d572f2023-01-17 23:58:31 +00002699
Sunil Raviaf399a82024-05-05 20:56:55 +00002700 akmp = pasn_get_akmp(pasn);
2701
2702 if (wpa_key_mgmt_ft(akmp) && rsn_data.num_pmkid) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002703#ifdef CONFIG_IEEE80211R_AP
2704 pasn->pmk_r1_len = 0;
2705 wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
2706 rsn_data.pmkid,
2707 pasn->pmk_r1, &pasn->pmk_r1_len, NULL,
2708 NULL, NULL, NULL,
2709 NULL, NULL, NULL);
2710#endif /* CONFIG_IEEE80211R_AP */
2711 }
2712#ifdef CONFIG_FILS
Sunil Raviaf399a82024-05-05 20:56:55 +00002713 if (akmp != WPA_KEY_MGMT_FILS_SHA256 &&
2714 akmp != WPA_KEY_MGMT_FILS_SHA384)
Sunil Ravi77d572f2023-01-17 23:58:31 +00002715 return;
2716 if (!elems.pasn_params ||
2717 wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
2718 elems.pasn_params_len + 3,
2719 false, &pasn_params)) {
Hai Shalom60840252021-02-19 19:02:11 -08002720 wpa_printf(MSG_DEBUG,
Sunil Ravi77d572f2023-01-17 23:58:31 +00002721 "PASN: Failed validation of PASN Parameters element");
2722 return;
Hai Shalom60840252021-02-19 19:02:11 -08002723 }
Hai Shalom60840252021-02-19 19:02:11 -08002724 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
Sunil Ravi72e01222024-03-09 01:25:43 +00002725 wrapped_data = ieee802_11_defrag(elems.wrapped_data,
2726 elems.wrapped_data_len, true);
Hai Shalom60840252021-02-19 19:02:11 -08002727 if (!wrapped_data) {
2728 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
Sunil Ravi77d572f2023-01-17 23:58:31 +00002729 return;
Hai Shalom60840252021-02-19 19:02:11 -08002730 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00002731 if (pasn_wd_handle_fils(hapd, sta, wrapped_data))
2732 wpa_printf(MSG_DEBUG,
2733 "PASN: Failed processing FILS wrapped data");
2734 else
2735 pasn->fils_wd_valid = true;
Hai Shalom60840252021-02-19 19:02:11 -08002736 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00002737 wpabuf_free(wrapped_data);
2738#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08002739}
2740
2741
2742static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
2743 const struct ieee80211_mgmt *mgmt, size_t len,
2744 u16 trans_seq, u16 status)
2745{
2746 if (hapd->conf->wpa != WPA_PROTO_RSN) {
2747 wpa_printf(MSG_INFO, "PASN: RSN is not configured");
2748 return;
2749 }
2750
2751 wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR,
2752 MAC2STR(sta->addr));
2753
2754 if (trans_seq == 1) {
2755 if (sta->pasn) {
2756 wpa_printf(MSG_DEBUG,
2757 "PASN: Not expecting transaction == 1");
2758 return;
2759 }
2760
2761 if (status != WLAN_STATUS_SUCCESS) {
2762 wpa_printf(MSG_DEBUG,
2763 "PASN: Failure status in transaction == 1");
2764 return;
2765 }
2766
Sunil Raviaf399a82024-05-05 20:56:55 +00002767 sta->pasn = pasn_data_init();
Hai Shalom60840252021-02-19 19:02:11 -08002768 if (!sta->pasn) {
2769 wpa_printf(MSG_DEBUG,
2770 "PASN: Failed to allocate PASN context");
2771 return;
2772 }
2773
Sunil Ravi77d572f2023-01-17 23:58:31 +00002774 hapd_initialize_pasn(hapd, sta);
2775
2776 hapd_pasn_update_params(hapd, sta, mgmt, len);
2777 if (handle_auth_pasn_1(sta->pasn, hapd->own_addr,
2778 sta->addr, mgmt, len) < 0)
2779 ap_free_sta(hapd, sta);
Hai Shalom60840252021-02-19 19:02:11 -08002780 } else if (trans_seq == 3) {
2781 if (!sta->pasn) {
2782 wpa_printf(MSG_DEBUG,
2783 "PASN: Not expecting transaction == 3");
2784 return;
2785 }
2786
2787 if (status != WLAN_STATUS_SUCCESS) {
2788 wpa_printf(MSG_DEBUG,
2789 "PASN: Failure status in transaction == 3");
2790 ap_free_sta_pasn(hapd, sta);
2791 return;
2792 }
2793
Sunil Ravi77d572f2023-01-17 23:58:31 +00002794 if (handle_auth_pasn_3(sta->pasn, hapd->own_addr,
2795 sta->addr, mgmt, len) == 0) {
2796 ptksa_cache_add(hapd->ptksa, hapd->own_addr, sta->addr,
Sunil Raviaf399a82024-05-05 20:56:55 +00002797 pasn_get_cipher(sta->pasn), 43200,
2798 pasn_get_ptk(sta->pasn), NULL, NULL,
2799 pasn_get_akmp(sta->pasn));
Sunil Ravi77d572f2023-01-17 23:58:31 +00002800
2801 pasn_set_keys_from_cache(hapd, hapd->own_addr,
Sunil Raviaf399a82024-05-05 20:56:55 +00002802 sta->addr,
2803 pasn_get_cipher(sta->pasn),
2804 pasn_get_akmp(sta->pasn));
Sunil Ravi77d572f2023-01-17 23:58:31 +00002805 }
2806 ap_free_sta(hapd, sta);
Hai Shalom60840252021-02-19 19:02:11 -08002807 } else {
2808 wpa_printf(MSG_DEBUG,
2809 "PASN: Invalid transaction %u - ignore", trans_seq);
2810 }
2811}
2812
2813#endif /* CONFIG_PASN */
2814
2815
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002816static void handle_auth(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08002817 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom021b0b52019-04-10 11:17:58 -07002818 int rssi, int from_queue)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002819{
2820 u16 auth_alg, auth_transaction, status_code;
2821 u16 resp = WLAN_STATUS_SUCCESS;
2822 struct sta_info *sta = NULL;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002823 int res, reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002824 u16 fc;
2825 const u8 *challenge = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002826 u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
2827 size_t resp_ies_len = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002828 u16 seq_ctrl;
Hai Shalomfdcde762020-04-02 11:19:20 -07002829 struct radius_sta rad_info;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002830 const u8 *dst, *sa, *bssid;
Sunil Raviaf399a82024-05-05 20:56:55 +00002831#ifdef CONFIG_IEEE80211BE
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002832 bool mld_sta = false;
Sunil Raviaf399a82024-05-05 20:56:55 +00002833#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002834
2835 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002836 wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
2837 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002838 return;
2839 }
2840
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002841#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002842 if (hapd->iconf->ignore_auth_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002843 drand48() < hapd->iconf->ignore_auth_probability) {
2844 wpa_printf(MSG_INFO,
2845 "TESTING: ignoring auth frame from " MACSTR,
2846 MAC2STR(mgmt->sa));
2847 return;
2848 }
2849#endif /* CONFIG_TESTING_OPTIONS */
2850
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002851 sa = mgmt->sa;
2852#ifdef CONFIG_IEEE80211BE
2853 /*
2854 * Handle MLO authentication before the station is added to hostapd and
2855 * the driver so that the station MLD MAC address would be used in both
2856 * hostapd and the driver.
2857 */
2858 sa = hostapd_process_ml_auth(hapd, mgmt, len);
2859 if (sa)
2860 mld_sta = true;
2861 else
2862 sa = mgmt->sa;
2863#endif /* CONFIG_IEEE80211BE */
2864
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002865 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
2866 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
2867 status_code = le_to_host16(mgmt->u.auth.status_code);
2868 fc = le_to_host16(mgmt->frame_control);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002869 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002870
2871 if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
2872 2 + WLAN_AUTH_CHALLENGE_LEN &&
2873 mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
2874 mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
2875 challenge = &mgmt->u.auth.variable[2];
2876
2877 wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002878 "auth_transaction=%d status_code=%d wep=%d%s "
Hai Shalom021b0b52019-04-10 11:17:58 -07002879 "seq_ctrl=0x%x%s%s",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002880 MAC2STR(sa), auth_alg, auth_transaction,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002881 status_code, !!(fc & WLAN_FC_ISWEP),
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002882 challenge ? " challenge" : "",
Hai Shalom021b0b52019-04-10 11:17:58 -07002883 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
2884 from_queue ? " (from queue)" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002885
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002886#ifdef CONFIG_NO_RC4
2887 if (auth_alg == WLAN_AUTH_SHARED_KEY) {
2888 wpa_printf(MSG_INFO,
2889 "Unsupported authentication algorithm (%d)",
2890 auth_alg);
2891 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
2892 goto fail;
2893 }
2894#endif /* CONFIG_NO_RC4 */
2895
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002896 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002897 wpa_printf(MSG_DEBUG,
2898 "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
2899 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002900 goto fail;
2901 }
2902
2903 if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
2904 auth_alg == WLAN_AUTH_OPEN) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002905#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002906 (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002907 auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002908#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002909#ifdef CONFIG_SAE
2910 (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
2911 auth_alg == WLAN_AUTH_SAE) ||
2912#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002913#ifdef CONFIG_FILS
2914 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
2915 auth_alg == WLAN_AUTH_FILS_SK) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002916 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
2917 hapd->conf->fils_dh_group &&
2918 auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002919#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08002920#ifdef CONFIG_PASN
2921 (hapd->conf->wpa &&
2922 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) &&
2923 auth_alg == WLAN_AUTH_PASN) ||
2924#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002925 ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
2926 auth_alg == WLAN_AUTH_SHARED_KEY))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002927 wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
2928 auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002929 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
2930 goto fail;
2931 }
2932
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002933 if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
Hai Shalom60840252021-02-19 19:02:11 -08002934#ifdef CONFIG_PASN
2935 (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) ||
2936#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002937 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002938 wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
2939 auth_transaction);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002940 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
2941 goto fail;
2942 }
2943
Sunil Ravi72e01222024-03-09 01:25:43 +00002944 if (ether_addr_equal(mgmt->sa, hapd->own_addr)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002945 wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002946 MAC2STR(sa));
2947 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2948 goto fail;
2949 }
2950
Sunil Raviaf399a82024-05-05 20:56:55 +00002951#ifdef CONFIG_IEEE80211BE
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002952 if (mld_sta &&
Sunil Ravi72e01222024-03-09 01:25:43 +00002953 (ether_addr_equal(sa, hapd->own_addr) ||
Sunil Raviaf399a82024-05-05 20:56:55 +00002954 ether_addr_equal(sa, hapd->mld->mld_addr))) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002955 wpa_printf(MSG_INFO,
2956 "Station " MACSTR " not allowed to authenticate",
2957 MAC2STR(sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002958 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2959 goto fail;
2960 }
Sunil Raviaf399a82024-05-05 20:56:55 +00002961#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002962
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002963 if (hapd->conf->no_auth_if_seen_on) {
2964 struct hostapd_data *other;
2965
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002966 other = sta_track_seen_on(hapd->iface, sa,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002967 hapd->conf->no_auth_if_seen_on);
2968 if (other) {
2969 u8 *pos;
2970 u32 info;
2971 u8 op_class, channel, phytype;
2972
2973 wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
2974 MACSTR " since STA has been seen on %s",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002975 hapd->conf->iface, MAC2STR(sa),
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002976 hapd->conf->no_auth_if_seen_on);
2977
2978 resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
2979 pos = &resp_ies[0];
2980 *pos++ = WLAN_EID_NEIGHBOR_REPORT;
2981 *pos++ = 13;
2982 os_memcpy(pos, other->own_addr, ETH_ALEN);
2983 pos += ETH_ALEN;
2984 info = 0; /* TODO: BSSID Information */
2985 WPA_PUT_LE32(pos, info);
2986 pos += 4;
2987 if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
2988 phytype = 8; /* dmg */
2989 else if (other->iconf->ieee80211ac)
2990 phytype = 9; /* vht */
2991 else if (other->iconf->ieee80211n)
2992 phytype = 7; /* ht */
2993 else if (other->iconf->hw_mode ==
2994 HOSTAPD_MODE_IEEE80211A)
2995 phytype = 4; /* ofdm */
2996 else if (other->iconf->hw_mode ==
2997 HOSTAPD_MODE_IEEE80211G)
2998 phytype = 6; /* erp */
2999 else
3000 phytype = 5; /* hrdsss */
3001 if (ieee80211_freq_to_channel_ext(
3002 hostapd_hw_get_freq(other,
3003 other->iconf->channel),
3004 other->iconf->secondary_channel,
3005 other->iconf->ieee80211ac,
3006 &op_class, &channel) == NUM_HOSTAPD_MODES) {
3007 op_class = 0;
3008 channel = other->iconf->channel;
3009 }
3010 *pos++ = op_class;
3011 *pos++ = channel;
3012 *pos++ = phytype;
3013 resp_ies_len = pos - &resp_ies[0];
3014 goto fail;
3015 }
3016 }
3017
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003018 res = ieee802_11_allowed_address(hapd, sa, (const u8 *) mgmt, len,
Hai Shalomfdcde762020-04-02 11:19:20 -07003019 &rad_info);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003020 if (res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003021 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
3022 "Ignore Authentication frame from " MACSTR
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003023 " due to ACL reject", MAC2STR(sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003024 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3025 goto fail;
3026 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003027 if (res == HOSTAPD_ACL_PENDING)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003028 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003029
Hai Shalom021b0b52019-04-10 11:17:58 -07003030#ifdef CONFIG_SAE
3031 if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
3032 (auth_transaction == 1 ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003033 (auth_transaction == 2 && auth_sae_queued_addr(hapd, sa)))) {
Hai Shalom021b0b52019-04-10 11:17:58 -07003034 /* Handle SAE Authentication commit message through a queue to
3035 * provide more control for postponing the needed heavy
3036 * processing under a possible DoS attack scenario. In addition,
3037 * queue SAE Authentication confirm message if there happens to
3038 * be a queued commit message from the same peer. This is needed
3039 * to avoid reordering Authentication frames within the same
3040 * SAE exchange. */
3041 auth_sae_queue(hapd, mgmt, len, rssi);
3042 return;
3043 }
3044#endif /* CONFIG_SAE */
3045
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003046 sta = ap_get_sta(hapd, sa);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003047 if (sta) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003048 sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
Hai Shalom74f70d42019-02-11 14:42:39 -08003049 sta->ft_over_ds = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003050 if ((fc & WLAN_FC_RETRY) &&
3051 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
3052 sta->last_seq_ctrl == seq_ctrl &&
3053 sta->last_subtype == WLAN_FC_STYPE_AUTH) {
3054 hostapd_logger(hapd, sta->addr,
3055 HOSTAPD_MODULE_IEEE80211,
3056 HOSTAPD_LEVEL_DEBUG,
3057 "Drop repeated authentication frame seq_ctrl=0x%x",
3058 seq_ctrl);
3059 return;
3060 }
Hai Shalom60840252021-02-19 19:02:11 -08003061#ifdef CONFIG_PASN
3062 if (auth_alg == WLAN_AUTH_PASN &&
3063 (sta->flags & WLAN_STA_ASSOC)) {
3064 wpa_printf(MSG_DEBUG,
3065 "PASN: auth: Existing station: " MACSTR,
3066 MAC2STR(sta->addr));
3067 return;
3068 }
3069#endif /* CONFIG_PASN */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003070 } else {
3071#ifdef CONFIG_MESH
3072 if (hapd->conf->mesh & MESH_ENABLED) {
3073 /* if the mesh peer is not available, we don't do auth.
3074 */
3075 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003076 " not yet known - drop Authentication frame",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003077 MAC2STR(sa));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003078 /*
3079 * Save a copy of the frame so that it can be processed
3080 * if a new peer entry is added shortly after this.
3081 */
3082 wpabuf_free(hapd->mesh_pending_auth);
3083 hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len);
3084 os_get_reltime(&hapd->mesh_pending_auth_time);
3085 return;
3086 }
3087#endif /* CONFIG_MESH */
3088
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003089 sta = ap_sta_add(hapd, sa);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003090 if (!sta) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003091 wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003092 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3093 goto fail;
3094 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003095 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003096
3097#ifdef CONFIG_IEEE80211BE
Sunil Raviaf399a82024-05-05 20:56:55 +00003098 /* Set the non-AP MLD information based on the initial Authentication
3099 * frame. Once the STA entry has been added to the driver, the driver
3100 * will translate addresses in the frame and we need to avoid overriding
3101 * peer_addr based on mgmt->sa which would have been translated to the
3102 * MLD MAC address. */
3103 if (!sta->added_unassoc && auth_transaction == 1) {
Sunil Ravi72e01222024-03-09 01:25:43 +00003104 ap_sta_free_sta_profile(&sta->mld_info);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003105 os_memset(&sta->mld_info, 0, sizeof(sta->mld_info));
3106
3107 if (mld_sta) {
3108 u8 link_id = hapd->mld_link_id;
3109
Sunil Ravi72e01222024-03-09 01:25:43 +00003110 ap_sta_set_mld(sta, true);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003111 sta->mld_assoc_link_id = link_id;
3112
3113 /*
3114 * Set the MLD address as the station address and the
3115 * station addresses.
3116 */
3117 os_memcpy(sta->mld_info.common_info.mld_addr, sa,
3118 ETH_ALEN);
3119 os_memcpy(sta->mld_info.links[link_id].peer_addr,
3120 mgmt->sa, ETH_ALEN);
3121 os_memcpy(sta->mld_info.links[link_id].local_addr,
3122 hapd->own_addr, ETH_ALEN);
3123 }
3124 }
3125#endif /* CONFIG_IEEE80211BE */
3126
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003127 sta->last_seq_ctrl = seq_ctrl;
3128 sta->last_subtype = WLAN_FC_STYPE_AUTH;
Hai Shalom74f70d42019-02-11 14:42:39 -08003129#ifdef CONFIG_MBO
3130 sta->auth_rssi = rssi;
3131#endif /* CONFIG_MBO */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003132
Hai Shalomfdcde762020-04-02 11:19:20 -07003133 res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003134 if (res) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003135 wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003136 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3137 goto fail;
3138 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003139
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003140 sta->flags &= ~WLAN_STA_PREAUTH;
3141 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
3142
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003143 /*
3144 * If the driver supports full AP client state, add a station to the
3145 * driver before sending authentication reply to make sure the driver
3146 * has resources, and not to go through the entire authentication and
3147 * association handshake, and fail it at the end.
3148 *
3149 * If this is not the first transaction, in a multi-step authentication
3150 * algorithm, the station already exists in the driver
3151 * (sta->added_unassoc = 1) so skip it.
3152 *
3153 * In mesh mode, the station was already added to the driver when the
3154 * NEW_PEER_CANDIDATE event is received.
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003155 *
3156 * If PMF was negotiated for the existing association, skip this to
3157 * avoid dropping the STA entry and the associated keys. This is needed
3158 * to allow the original connection work until the attempt can complete
3159 * (re)association, so that unprotected Authentication frame cannot be
3160 * used to bypass PMF protection.
Hai Shalom60840252021-02-19 19:02:11 -08003161 *
3162 * PASN authentication does not require adding/removing station to the
3163 * driver so skip this flow in case of PASN authentication.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003164 */
3165 if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003166 (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003167 !(hapd->conf->mesh & MESH_ENABLED) &&
Hai Shalom60840252021-02-19 19:02:11 -08003168 !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) {
Hai Shalomb755a2a2020-04-23 21:49:02 -07003169 if (ap_sta_re_add(hapd, sta) < 0) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003170 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3171 goto fail;
3172 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003173 }
3174
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003175 switch (auth_alg) {
3176 case WLAN_AUTH_OPEN:
3177 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3178 HOSTAPD_LEVEL_DEBUG,
3179 "authentication OK (open system)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003180 sta->flags |= WLAN_STA_AUTH;
3181 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
3182 sta->auth_alg = WLAN_AUTH_OPEN;
3183 mlme_authenticate_indication(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003184 break;
Hai Shalomfdcde762020-04-02 11:19:20 -07003185#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003186#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003187 case WLAN_AUTH_SHARED_KEY:
3188 resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
3189 fc & WLAN_FC_ISWEP);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003190 if (resp != 0)
3191 wpa_printf(MSG_DEBUG,
3192 "auth_shared_key() failed: status=%d", resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003193 sta->auth_alg = WLAN_AUTH_SHARED_KEY;
3194 mlme_authenticate_indication(hapd, sta);
3195 if (sta->challenge && auth_transaction == 1) {
3196 resp_ies[0] = WLAN_EID_CHALLENGE;
3197 resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
3198 os_memcpy(resp_ies + 2, sta->challenge,
3199 WLAN_AUTH_CHALLENGE_LEN);
3200 resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
3201 }
3202 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003203#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003204#endif /* CONFIG_WEP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003205#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003206 case WLAN_AUTH_FT:
3207 sta->auth_alg = WLAN_AUTH_FT;
3208 if (sta->wpa_sm == NULL)
3209 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003210 sta->addr, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003211 if (sta->wpa_sm == NULL) {
3212 wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
3213 "state machine");
3214 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3215 goto fail;
3216 }
3217 wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
3218 auth_transaction, mgmt->u.auth.variable,
3219 len - IEEE80211_HDRLEN -
3220 sizeof(mgmt->u.auth),
3221 handle_auth_ft_finish, hapd);
3222 /* handle_auth_ft_finish() callback will complete auth. */
3223 return;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003224#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003225#ifdef CONFIG_SAE
3226 case WLAN_AUTH_SAE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003227#ifdef CONFIG_MESH
3228 if (status_code == WLAN_STATUS_SUCCESS &&
3229 hapd->conf->mesh & MESH_ENABLED) {
3230 if (sta->wpa_sm == NULL)
3231 sta->wpa_sm =
3232 wpa_auth_sta_init(hapd->wpa_auth,
3233 sta->addr, NULL);
3234 if (sta->wpa_sm == NULL) {
3235 wpa_printf(MSG_DEBUG,
3236 "SAE: Failed to initialize WPA state machine");
3237 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3238 goto fail;
3239 }
3240 }
3241#endif /* CONFIG_MESH */
3242 handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
3243 status_code);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003244 return;
3245#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003246#ifdef CONFIG_FILS
3247 case WLAN_AUTH_FILS_SK:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003248 case WLAN_AUTH_FILS_SK_PFS:
3249 handle_auth_fils(hapd, sta, mgmt->u.auth.variable,
3250 len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth),
3251 auth_alg, auth_transaction, status_code,
3252 handle_auth_fils_finish);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003253 return;
3254#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08003255#ifdef CONFIG_PASN
3256 case WLAN_AUTH_PASN:
3257 handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction,
3258 status_code);
3259 return;
3260#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003261 }
3262
3263 fail:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003264 dst = mgmt->sa;
3265 bssid = mgmt->bssid;
3266
3267#ifdef CONFIG_IEEE80211BE
3268 /*
3269 * Once a non-AP MLD is added to the driver, the addressing should use
3270 * the MLD MAC address. It is the responsibility of the driver to
3271 * handle the translations.
3272 */
Sunil Ravi72e01222024-03-09 01:25:43 +00003273 if (ap_sta_is_mld(hapd, sta)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003274 dst = sta->addr;
Sunil Raviaf399a82024-05-05 20:56:55 +00003275 bssid = hapd->mld->mld_addr;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003276 }
3277#endif /* CONFIG_IEEE80211BE */
3278
3279 reply_res = send_auth_reply(hapd, sta, dst, bssid, auth_alg,
Hai Shaloma20dcd72022-02-04 13:43:00 -08003280 auth_alg == WLAN_AUTH_SAE ?
3281 auth_transaction : auth_transaction + 1,
3282 resp, resp_ies, resp_ies_len,
3283 "handle-auth");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003284
3285 if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
3286 reply_res != WLAN_STATUS_SUCCESS)) {
3287 hostapd_drv_sta_remove(hapd, sta->addr);
3288 sta->added_unassoc = 0;
3289 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003290}
3291
3292
Sunil Ravi77d572f2023-01-17 23:58:31 +00003293static u8 hostapd_max_bssid_indicator(struct hostapd_data *hapd)
3294{
3295 size_t num_bss_nontx;
3296 u8 max_bssid_ind = 0;
3297
3298 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1)
3299 return 0;
3300
3301 num_bss_nontx = hapd->iface->num_bss - 1;
3302 while (num_bss_nontx > 0) {
3303 max_bssid_ind++;
3304 num_bss_nontx >>= 1;
3305 }
3306 return max_bssid_ind;
3307}
3308
3309
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003310static u32 hostapd_get_aid_word(struct hostapd_data *hapd,
3311 struct sta_info *sta, int i)
3312{
3313#ifdef CONFIG_IEEE80211BE
3314 u32 aid_word = 0;
3315
3316 /* Do not assign an AID that is in use on any of the affiliated links
3317 * when finding an AID for a non-AP MLD. */
Sunil Ravi72e01222024-03-09 01:25:43 +00003318 if (hapd->conf->mld_ap && sta->mld_info.mld_sta) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003319 int j;
3320
3321 for (j = 0; j < MAX_NUM_MLD_LINKS; j++) {
3322 struct hostapd_data *link_bss;
3323
3324 if (!sta->mld_info.links[j].valid)
3325 continue;
3326
3327 link_bss = hostapd_mld_get_link_bss(hapd, j);
3328 if (!link_bss) {
3329 /* This shouldn't happen, just skip */
3330 wpa_printf(MSG_ERROR,
3331 "MLD: Failed to get link BSS for AID");
3332 continue;
3333 }
3334
3335 aid_word |= link_bss->sta_aid[i];
3336 }
3337
3338 return aid_word;
3339 }
3340#endif /* CONFIG_IEEE80211BE */
3341
3342 return hapd->sta_aid[i];
3343}
3344
3345
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003346int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003347{
3348 int i, j = 32, aid;
3349
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003350 /* Transmitted and non-transmitted BSSIDs share the same AID pool, so
3351 * use the shared storage in the transmitted BSS to find the next
3352 * available value. */
3353 hapd = hostapd_mbssid_get_tx_bss(hapd);
3354
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003355 /* get a unique AID */
3356 if (sta->aid > 0) {
3357 wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
3358 return 0;
3359 }
3360
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003361 if (TEST_FAIL())
3362 return -1;
3363
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003364 for (i = 0; i < AID_WORDS; i++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003365 u32 aid_word = hostapd_get_aid_word(hapd, sta, i);
3366
3367 if (aid_word == (u32) -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003368 continue;
3369 for (j = 0; j < 32; j++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003370 if (!(aid_word & BIT(j)))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003371 break;
3372 }
3373 if (j < 32)
3374 break;
3375 }
3376 if (j == 32)
3377 return -1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003378 aid = i * 32 + j + (1 << hostapd_max_bssid_indicator(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003379 if (aid > 2007)
3380 return -1;
3381
3382 sta->aid = aid;
3383 hapd->sta_aid[i] |= BIT(j);
3384 wpa_printf(MSG_DEBUG, " new AID %d", sta->aid);
3385 return 0;
3386}
3387
3388
3389static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
3390 const u8 *ssid_ie, size_t ssid_ie_len)
3391{
3392 if (ssid_ie == NULL)
3393 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3394
3395 if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
3396 os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003397 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3398 HOSTAPD_LEVEL_INFO,
3399 "Station tried to associate with unknown SSID "
Dmitry Shmidt3c479372014-02-04 10:50:36 -08003400 "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003401 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3402 }
3403
3404 return WLAN_STATUS_SUCCESS;
3405}
3406
3407
3408static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
3409 const u8 *wmm_ie, size_t wmm_ie_len)
3410{
3411 sta->flags &= ~WLAN_STA_WMM;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003412 sta->qosinfo = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003413 if (wmm_ie && hapd->conf->wmm_enabled) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003414 struct wmm_information_element *wmm;
3415
3416 if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003417 hostapd_logger(hapd, sta->addr,
3418 HOSTAPD_MODULE_WPA,
3419 HOSTAPD_LEVEL_DEBUG,
3420 "invalid WMM element in association "
3421 "request");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003422 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3423 }
3424
3425 sta->flags |= WLAN_STA_WMM;
3426 wmm = (struct wmm_information_element *) wmm_ie;
3427 sta->qosinfo = wmm->qos_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003428 }
3429 return WLAN_STATUS_SUCCESS;
3430}
3431
Hai Shalom74f70d42019-02-11 14:42:39 -08003432static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
3433 const u8 *multi_ap_ie, size_t multi_ap_len)
3434{
Sunil Raviaf399a82024-05-05 20:56:55 +00003435 struct multi_ap_params multi_ap;
3436 u16 status;
Hai Shalom74f70d42019-02-11 14:42:39 -08003437
3438 sta->flags &= ~WLAN_STA_MULTI_AP;
3439
3440 if (!hapd->conf->multi_ap)
3441 return WLAN_STATUS_SUCCESS;
3442
Sunil Raviaf399a82024-05-05 20:56:55 +00003443 if (!multi_ap_ie) {
3444 if (!(hapd->conf->multi_ap & FRONTHAUL_BSS)) {
Hai Shalom74f70d42019-02-11 14:42:39 -08003445 hostapd_logger(hapd, sta->addr,
3446 HOSTAPD_MODULE_IEEE80211,
3447 HOSTAPD_LEVEL_INFO,
Sunil Raviaf399a82024-05-05 20:56:55 +00003448 "Non-Multi-AP STA tries to associate with backhaul-only BSS");
3449 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
Hai Shalom74f70d42019-02-11 14:42:39 -08003450 }
Sunil Raviaf399a82024-05-05 20:56:55 +00003451
3452 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08003453 }
3454
Sunil Raviaf399a82024-05-05 20:56:55 +00003455 status = check_multi_ap_ie(multi_ap_ie + 4, multi_ap_len - 4,
3456 &multi_ap);
3457 if (status != WLAN_STATUS_SUCCESS)
3458 return status;
3459
3460 if (multi_ap.capability && multi_ap.capability != MULTI_AP_BACKHAUL_STA)
Hai Shalom021b0b52019-04-10 11:17:58 -07003461 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3462 HOSTAPD_LEVEL_INFO,
3463 "Multi-AP IE with unexpected value 0x%02x",
Sunil Raviaf399a82024-05-05 20:56:55 +00003464 multi_ap.capability);
Hai Shalom74f70d42019-02-11 14:42:39 -08003465
Sunil Raviaf399a82024-05-05 20:56:55 +00003466 if (multi_ap.profile == MULTI_AP_PROFILE_1 &&
3467 (hapd->conf->multi_ap_client_disallow &
3468 PROFILE1_CLIENT_ASSOC_DISALLOW)) {
3469 hostapd_logger(hapd, sta->addr,
3470 HOSTAPD_MODULE_IEEE80211,
3471 HOSTAPD_LEVEL_INFO,
3472 "Multi-AP Profile-1 clients not allowed");
3473 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
3474 }
3475
3476 if (multi_ap.profile >= MULTI_AP_PROFILE_2 &&
3477 (hapd->conf->multi_ap_client_disallow &
3478 PROFILE2_CLIENT_ASSOC_DISALLOW)) {
3479 hostapd_logger(hapd, sta->addr,
3480 HOSTAPD_MODULE_IEEE80211,
3481 HOSTAPD_LEVEL_INFO,
3482 "Multi-AP Profile-2 clients not allowed");
3483 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
3484 }
3485
3486 if (!(multi_ap.capability & MULTI_AP_BACKHAUL_STA)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07003487 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
3488 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08003489
Hai Shalom021b0b52019-04-10 11:17:58 -07003490 hostapd_logger(hapd, sta->addr,
3491 HOSTAPD_MODULE_IEEE80211,
3492 HOSTAPD_LEVEL_INFO,
3493 "Non-Multi-AP STA tries to associate with backhaul-only BSS");
3494 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
Hai Shalom74f70d42019-02-11 14:42:39 -08003495 }
3496
Hai Shalom021b0b52019-04-10 11:17:58 -07003497 if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
3498 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3499 HOSTAPD_LEVEL_DEBUG,
3500 "Backhaul STA tries to associate with fronthaul-only BSS");
3501
3502 sta->flags |= WLAN_STA_MULTI_AP;
3503 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08003504}
3505
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003506
3507static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
3508 struct ieee802_11_elems *elems)
3509{
Dmitry Shmidt29333592017-01-09 12:27:11 -08003510 /* Supported rates not used in IEEE 802.11ad/DMG */
3511 if (hapd->iface->current_mode &&
3512 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
3513 return WLAN_STATUS_SUCCESS;
3514
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003515 if (!elems->supp_rates) {
3516 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3517 HOSTAPD_LEVEL_DEBUG,
3518 "No supported rates element in AssocReq");
3519 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3520 }
3521
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003522 if (elems->supp_rates_len + elems->ext_supp_rates_len >
3523 sizeof(sta->supported_rates)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003524 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3525 HOSTAPD_LEVEL_DEBUG,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003526 "Invalid supported rates element length %d+%d",
3527 elems->supp_rates_len,
3528 elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003529 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3530 }
3531
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003532 sta->supported_rates_len = merge_byte_arrays(
3533 sta->supported_rates, sizeof(sta->supported_rates),
3534 elems->supp_rates, elems->supp_rates_len,
3535 elems->ext_supp_rates, elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003536
3537 return WLAN_STATUS_SUCCESS;
3538}
3539
3540
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003541#ifdef CONFIG_OWE
3542
3543static int owe_group_supported(struct hostapd_data *hapd, u16 group)
3544{
3545 int i;
3546 int *groups = hapd->conf->owe_groups;
3547
3548 if (group != 19 && group != 20 && group != 21)
3549 return 0;
3550
3551 if (!groups)
3552 return 1;
3553
3554 for (i = 0; groups[i] > 0; i++) {
3555 if (groups[i] == group)
3556 return 1;
3557 }
3558
3559 return 0;
3560}
3561
3562
3563static u16 owe_process_assoc_req(struct hostapd_data *hapd,
3564 struct sta_info *sta, const u8 *owe_dh,
3565 u8 owe_dh_len)
3566{
3567 struct wpabuf *secret, *pub, *hkey;
3568 int res;
3569 u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN];
3570 const char *info = "OWE Key Generation";
3571 const u8 *addr[2];
3572 size_t len[2];
3573 u16 group;
3574 size_t hash_len, prime_len;
3575
3576 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
3577 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
3578 return WLAN_STATUS_SUCCESS;
3579 }
3580
3581 group = WPA_GET_LE16(owe_dh);
3582 if (!owe_group_supported(hapd, group)) {
3583 wpa_printf(MSG_DEBUG, "OWE: Unsupported DH group %u", group);
3584 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3585 }
3586 if (group == 19)
3587 prime_len = 32;
3588 else if (group == 20)
3589 prime_len = 48;
3590 else if (group == 21)
3591 prime_len = 66;
3592 else
3593 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3594
Sunil Ravia04bd252022-05-02 22:54:18 -07003595 if (sta->owe_group == group && sta->owe_ecdh) {
3596 /* This is a workaround for mac80211 behavior of retransmitting
3597 * the Association Request frames multiple times if the link
3598 * layer retries (i.e., seq# remains same) fail. The mac80211
3599 * initiated retransmission will use a different seq# and as
3600 * such, will go through duplicate detection. If we were to
3601 * change our DH key for that attempt, there would be two
3602 * different DH shared secrets and the STA would likely select
3603 * the wrong one. */
3604 wpa_printf(MSG_DEBUG,
3605 "OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again");
3606 } else {
3607 crypto_ecdh_deinit(sta->owe_ecdh);
3608 sta->owe_ecdh = crypto_ecdh_init(group);
3609 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003610 if (!sta->owe_ecdh)
3611 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3612 sta->owe_group = group;
3613
3614 secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2,
3615 owe_dh_len - 2);
3616 secret = wpabuf_zeropad(secret, prime_len);
3617 if (!secret) {
3618 wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
3619 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3620 }
3621 wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
3622
3623 /* prk = HKDF-extract(C | A | group, z) */
3624
3625 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
3626 if (!pub) {
3627 wpabuf_clear_free(secret);
3628 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3629 }
3630
3631 /* PMKID = Truncate-128(Hash(C | A)) */
3632 addr[0] = owe_dh + 2;
3633 len[0] = owe_dh_len - 2;
3634 addr[1] = wpabuf_head(pub);
3635 len[1] = wpabuf_len(pub);
3636 if (group == 19) {
3637 res = sha256_vector(2, addr, len, pmkid);
3638 hash_len = SHA256_MAC_LEN;
3639 } else if (group == 20) {
3640 res = sha384_vector(2, addr, len, pmkid);
3641 hash_len = SHA384_MAC_LEN;
3642 } else if (group == 21) {
3643 res = sha512_vector(2, addr, len, pmkid);
3644 hash_len = SHA512_MAC_LEN;
3645 } else {
3646 wpabuf_free(pub);
3647 wpabuf_clear_free(secret);
3648 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3649 }
3650 pub = wpabuf_zeropad(pub, prime_len);
3651 if (res < 0 || !pub) {
3652 wpabuf_free(pub);
3653 wpabuf_clear_free(secret);
3654 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3655 }
3656
3657 hkey = wpabuf_alloc(owe_dh_len - 2 + wpabuf_len(pub) + 2);
3658 if (!hkey) {
3659 wpabuf_free(pub);
3660 wpabuf_clear_free(secret);
3661 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3662 }
3663
3664 wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */
3665 wpabuf_put_buf(hkey, pub); /* A */
3666 wpabuf_free(pub);
3667 wpabuf_put_le16(hkey, group); /* group */
3668 if (group == 19)
3669 res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
3670 wpabuf_head(secret), wpabuf_len(secret), prk);
3671 else if (group == 20)
3672 res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey),
3673 wpabuf_head(secret), wpabuf_len(secret), prk);
3674 else if (group == 21)
3675 res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey),
3676 wpabuf_head(secret), wpabuf_len(secret), prk);
3677 wpabuf_clear_free(hkey);
3678 wpabuf_clear_free(secret);
3679 if (res < 0)
3680 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3681
3682 wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
3683
3684 /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
3685
3686 os_free(sta->owe_pmk);
3687 sta->owe_pmk = os_malloc(hash_len);
3688 if (!sta->owe_pmk) {
3689 os_memset(prk, 0, SHA512_MAC_LEN);
3690 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3691 }
3692
3693 if (group == 19)
3694 res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info,
3695 os_strlen(info), sta->owe_pmk, hash_len);
3696 else if (group == 20)
3697 res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info,
3698 os_strlen(info), sta->owe_pmk, hash_len);
3699 else if (group == 21)
3700 res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
3701 os_strlen(info), sta->owe_pmk, hash_len);
3702 os_memset(prk, 0, SHA512_MAC_LEN);
3703 if (res < 0) {
3704 os_free(sta->owe_pmk);
3705 sta->owe_pmk = NULL;
3706 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3707 }
3708 sta->owe_pmk_len = hash_len;
3709
3710 wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
3711 wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
3712 wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk,
Sunil Ravi72e01222024-03-09 01:25:43 +00003713 sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003714
3715 return WLAN_STATUS_SUCCESS;
3716}
3717
Hai Shalom81f62d82019-07-22 12:10:00 -07003718
3719u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
3720 const u8 *rsn_ie, size_t rsn_ie_len,
3721 const u8 *owe_dh, size_t owe_dh_len)
3722{
3723 struct wpa_ie_data data;
3724 int res;
3725
3726 if (!rsn_ie || rsn_ie_len < 2) {
3727 wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
3728 MAC2STR(peer));
3729 return WLAN_STATUS_INVALID_IE;
3730 }
3731 rsn_ie -= 2;
3732 rsn_ie_len += 2;
3733
3734 res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
3735 if (res) {
3736 wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
3737 " (res=%d)", MAC2STR(peer), res);
3738 wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
3739 return wpa_res_to_status_code(res);
3740 }
3741 if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
3742 wpa_printf(MSG_DEBUG,
3743 "OWE: Unexpected key mgmt 0x%x from " MACSTR,
3744 (unsigned int) data.key_mgmt, MAC2STR(peer));
3745 return WLAN_STATUS_AKMP_NOT_VALID;
3746 }
3747 if (!owe_dh) {
3748 wpa_printf(MSG_DEBUG,
3749 "OWE: No Diffie-Hellman Parameter element from "
3750 MACSTR, MAC2STR(peer));
3751 return WLAN_STATUS_AKMP_NOT_VALID;
3752 }
3753
3754 return WLAN_STATUS_SUCCESS;
3755}
3756
3757
3758u16 owe_process_rsn_ie(struct hostapd_data *hapd,
3759 struct sta_info *sta,
3760 const u8 *rsn_ie, size_t rsn_ie_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003761 const u8 *owe_dh, size_t owe_dh_len,
3762 const u8 *link_addr)
Hai Shalom81f62d82019-07-22 12:10:00 -07003763{
3764 u16 status;
3765 u8 *owe_buf, ie[256 * 2];
3766 size_t ie_len = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07003767 enum wpa_validate_result res;
Hai Shalom81f62d82019-07-22 12:10:00 -07003768
3769 if (!rsn_ie || rsn_ie_len < 2) {
3770 wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
3771 status = WLAN_STATUS_INVALID_IE;
3772 goto end;
3773 }
3774
3775 if (!sta->wpa_sm)
3776 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
3777 NULL);
3778 if (!sta->wpa_sm) {
3779 wpa_printf(MSG_WARNING,
3780 "OWE: Failed to initialize WPA state machine");
3781 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3782 goto end;
3783 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003784#ifdef CONFIG_IEEE80211BE
Sunil Ravi72e01222024-03-09 01:25:43 +00003785 if (ap_sta_is_mld(hapd, sta))
Sunil Raviaf399a82024-05-05 20:56:55 +00003786 wpa_auth_set_ml_info(sta->wpa_sm, hapd->mld->mld_addr,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003787 sta->mld_assoc_link_id, &sta->mld_info);
3788#endif /* CONFIG_IEEE80211BE */
Hai Shalom81f62d82019-07-22 12:10:00 -07003789 rsn_ie -= 2;
3790 rsn_ie_len += 2;
3791 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
3792 hapd->iface->freq, rsn_ie, rsn_ie_len,
Hai Shalomc3565922019-10-28 11:58:20 -07003793 NULL, 0, NULL, 0, owe_dh, owe_dh_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07003794 status = wpa_res_to_status_code(res);
3795 if (status != WLAN_STATUS_SUCCESS)
3796 goto end;
3797 status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
3798 if (status != WLAN_STATUS_SUCCESS)
3799 goto end;
3800 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
3801 NULL, 0);
3802 if (!owe_buf) {
3803 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3804 goto end;
3805 }
3806
3807 if (sta->owe_ecdh) {
3808 struct wpabuf *pub;
3809
3810 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
3811 if (!pub) {
3812 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3813 goto end;
3814 }
3815
3816 /* OWE Diffie-Hellman Parameter element */
3817 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
3818 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
3819 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
3820 */
3821 WPA_PUT_LE16(owe_buf, sta->owe_group);
3822 owe_buf += 2;
3823 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
3824 owe_buf += wpabuf_len(pub);
3825 wpabuf_free(pub);
3826 sta->external_dh_updated = 1;
3827 }
3828 ie_len = owe_buf - ie;
3829
3830end:
3831 wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
3832 MACSTR, status, (unsigned int) ie_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003833 MAC2STR(link_addr ? link_addr : sta->addr));
3834 hostapd_drv_update_dh_ie(hapd, link_addr ? link_addr : sta->addr,
3835 status,
Hai Shalom81f62d82019-07-22 12:10:00 -07003836 status == WLAN_STATUS_SUCCESS ? ie : NULL,
3837 ie_len);
3838
3839 return status;
3840}
3841
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003842#endif /* CONFIG_OWE */
3843
3844
Hai Shalom899fcc72020-10-19 14:38:18 -07003845static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
3846 int reassoc)
3847{
3848 if ((sta->flags &
3849 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
3850 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
3851 return false;
3852
3853 if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
3854 ap_check_sa_query_timeout(hapd, sta);
3855
3856 if (!sta->sa_query_timed_out &&
3857 (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
3858 /*
3859 * STA has already been associated with MFP and SA Query timeout
3860 * has not been reached. Reject the association attempt
3861 * temporarily and start SA Query, if one is not pending.
3862 */
3863 if (sta->sa_query_count == 0)
3864 ap_sta_start_sa_query(hapd, sta);
3865
3866 return true;
3867 }
3868
3869 return false;
3870}
3871
3872
Sunil Ravi036cec52023-03-29 11:35:17 -07003873static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
3874 const u8 *ies, size_t ies_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003875 struct ieee802_11_elems *elems, int reassoc,
3876 bool link)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003877{
Hai Shalomb755a2a2020-04-23 21:49:02 -07003878 int resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003879 const u8 *wpa_ie;
3880 size_t wpa_ie_len;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003881 const u8 *p2p_dev_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003882
Sunil Ravi036cec52023-03-29 11:35:17 -07003883 resp = check_ssid(hapd, sta, elems->ssid, elems->ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003884 if (resp != WLAN_STATUS_SUCCESS)
3885 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003886 resp = check_wmm(hapd, sta, elems->wmm, elems->wmm_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003887 if (resp != WLAN_STATUS_SUCCESS)
3888 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003889 resp = check_ext_capab(hapd, sta, elems->ext_capab,
3890 elems->ext_capab_len);
Dmitry Shmidt051af732013-10-22 13:52:46 -07003891 if (resp != WLAN_STATUS_SUCCESS)
3892 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003893 resp = copy_supp_rates(hapd, sta, elems);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003894 if (resp != WLAN_STATUS_SUCCESS)
3895 return resp;
Hai Shalom74f70d42019-02-11 14:42:39 -08003896
Sunil Ravi036cec52023-03-29 11:35:17 -07003897 resp = check_multi_ap(hapd, sta, elems->multi_ap, elems->multi_ap_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08003898 if (resp != WLAN_STATUS_SUCCESS)
3899 return resp;
3900
Sunil Ravi036cec52023-03-29 11:35:17 -07003901 resp = copy_sta_ht_capab(hapd, sta, elems->ht_capabilities);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003902 if (resp != WLAN_STATUS_SUCCESS)
3903 return resp;
3904 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
3905 !(sta->flags & WLAN_STA_HT)) {
3906 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3907 HOSTAPD_LEVEL_INFO, "Station does not support "
3908 "mandatory HT PHY - reject association");
3909 return WLAN_STATUS_ASSOC_DENIED_NO_HT;
3910 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003911
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003912#ifdef CONFIG_IEEE80211AC
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003913 if (hapd->iconf->ieee80211ac) {
Sunil Ravi036cec52023-03-29 11:35:17 -07003914 resp = copy_sta_vht_capab(hapd, sta, elems->vht_capabilities);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003915 if (resp != WLAN_STATUS_SUCCESS)
3916 return resp;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08003917
Sunil Ravi640215c2023-06-28 23:08:09 +00003918 resp = set_sta_vht_opmode(hapd, sta, elems->opmode_notif);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003919 if (resp != WLAN_STATUS_SUCCESS)
3920 return resp;
3921 }
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08003922
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003923 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
3924 !(sta->flags & WLAN_STA_VHT)) {
3925 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3926 HOSTAPD_LEVEL_INFO, "Station does not support "
3927 "mandatory VHT PHY - reject association");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003928 return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003929 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003930
Sunil Ravi036cec52023-03-29 11:35:17 -07003931 if (hapd->conf->vendor_vht && !elems->vht_capabilities) {
3932 resp = copy_sta_vendor_vht(hapd, sta, elems->vendor_vht,
3933 elems->vendor_vht_len);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003934 if (resp != WLAN_STATUS_SUCCESS)
3935 return resp;
3936 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003937#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07003938#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08003939 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07003940 resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
Sunil Ravi036cec52023-03-29 11:35:17 -07003941 elems->he_capabilities,
3942 elems->he_capabilities_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07003943 if (resp != WLAN_STATUS_SUCCESS)
3944 return resp;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003945
3946 if (hapd->iconf->require_he && !(sta->flags & WLAN_STA_HE)) {
3947 hostapd_logger(hapd, sta->addr,
3948 HOSTAPD_MODULE_IEEE80211,
3949 HOSTAPD_LEVEL_INFO,
3950 "Station does not support mandatory HE PHY - reject association");
3951 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
3952 }
3953
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003954 if (is_6ghz_op_class(hapd->iconf->op_class)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07003955 if (!(sta->flags & WLAN_STA_HE)) {
3956 hostapd_logger(hapd, sta->addr,
3957 HOSTAPD_MODULE_IEEE80211,
3958 HOSTAPD_LEVEL_INFO,
3959 "Station does not support mandatory HE PHY - reject association");
3960 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
3961 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003962 resp = copy_sta_he_6ghz_capab(hapd, sta,
Sunil Ravi036cec52023-03-29 11:35:17 -07003963 elems->he_6ghz_band_cap);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003964 if (resp != WLAN_STATUS_SUCCESS)
3965 return resp;
3966 }
Hai Shalom81f62d82019-07-22 12:10:00 -07003967 }
3968#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07003969#ifdef CONFIG_IEEE80211BE
3970 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
3971 resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP,
Sunil Ravi036cec52023-03-29 11:35:17 -07003972 elems->he_capabilities,
3973 elems->he_capabilities_len,
3974 elems->eht_capabilities,
3975 elems->eht_capabilities_len);
Sunil Ravia04bd252022-05-02 22:54:18 -07003976 if (resp != WLAN_STATUS_SUCCESS)
3977 return resp;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003978
3979 if (!link) {
3980 resp = hostapd_process_ml_assoc_req(hapd, elems, sta);
3981 if (resp != WLAN_STATUS_SUCCESS)
3982 return resp;
3983 }
Sunil Ravia04bd252022-05-02 22:54:18 -07003984 }
3985#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003986
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003987#ifdef CONFIG_P2P
Sunil Ravi036cec52023-03-29 11:35:17 -07003988 if (elems->p2p && ies && ies_len) {
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003989 wpabuf_free(sta->p2p_ie);
3990 sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
3991 P2P_IE_VENDOR_TYPE);
3992 if (sta->p2p_ie)
3993 p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
3994 } else {
3995 wpabuf_free(sta->p2p_ie);
3996 sta->p2p_ie = NULL;
3997 }
3998#endif /* CONFIG_P2P */
3999
Sunil Ravi036cec52023-03-29 11:35:17 -07004000 if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems->rsn_ie) {
4001 wpa_ie = elems->rsn_ie;
4002 wpa_ie_len = elems->rsn_ie_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004003 } else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004004 elems->wpa_ie) {
4005 wpa_ie = elems->wpa_ie;
4006 wpa_ie_len = elems->wpa_ie_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004007 } else {
4008 wpa_ie = NULL;
4009 wpa_ie_len = 0;
4010 }
4011
4012#ifdef CONFIG_WPS
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004013 sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
Sunil Ravi036cec52023-03-29 11:35:17 -07004014 if (hapd->conf->wps_state && elems->wps_ie && ies && ies_len) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004015 wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
4016 "Request - assume WPS is used");
4017 sta->flags |= WLAN_STA_WPS;
4018 wpabuf_free(sta->wps_ie);
4019 sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
4020 WPS_IE_VENDOR_TYPE);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004021 if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
4022 wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
4023 sta->flags |= WLAN_STA_WPS2;
4024 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004025 wpa_ie = NULL;
4026 wpa_ie_len = 0;
4027 if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
4028 wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
4029 "(Re)Association Request - reject");
4030 return WLAN_STATUS_INVALID_IE;
4031 }
4032 } else if (hapd->conf->wps_state && wpa_ie == NULL) {
4033 wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
4034 "(Re)Association Request - possible WPS use");
4035 sta->flags |= WLAN_STA_MAYBE_WPS;
4036 } else
4037#endif /* CONFIG_WPS */
4038 if (hapd->conf->wpa && wpa_ie == NULL) {
4039 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4040 HOSTAPD_LEVEL_INFO,
4041 "No WPA/RSN IE in association request");
4042 return WLAN_STATUS_INVALID_IE;
4043 }
4044
4045 if (hapd->conf->wpa && wpa_ie) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004046 enum wpa_validate_result res;
4047
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004048 wpa_ie -= 2;
4049 wpa_ie_len += 2;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004050
4051 if (!sta->wpa_sm) {
4052#ifdef CONFIG_IEEE80211BE
4053 struct mld_info *info = &sta->mld_info;
4054#endif /* CONFIG_IEEE80211BE */
4055
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004056 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004057 sta->addr,
4058 p2p_dev_addr);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004059
4060 if (!sta->wpa_sm) {
4061 wpa_printf(MSG_WARNING,
4062 "Failed to initialize RSN state machine");
4063 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4064 }
4065
4066#ifdef CONFIG_IEEE80211BE
Sunil Ravi72e01222024-03-09 01:25:43 +00004067 if (ap_sta_is_mld(hapd, sta)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004068 wpa_printf(MSG_DEBUG,
4069 "MLD: Set ML info in RSN Authenticator");
4070 wpa_auth_set_ml_info(sta->wpa_sm,
Sunil Raviaf399a82024-05-05 20:56:55 +00004071 hapd->mld->mld_addr,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004072 sta->mld_assoc_link_id,
4073 info);
4074 }
4075#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004076 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004077
Hai Shalom021b0b52019-04-10 11:17:58 -07004078 wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004079 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07004080 hapd->iface->freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004081 wpa_ie, wpa_ie_len,
Sunil Ravi036cec52023-03-29 11:35:17 -07004082 elems->rsnxe ? elems->rsnxe - 2 :
4083 NULL,
4084 elems->rsnxe ? elems->rsnxe_len + 2 :
4085 0,
4086 elems->mdie, elems->mdie_len,
4087 elems->owe_dh, elems->owe_dh_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004088 resp = wpa_res_to_status_code(res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004089 if (resp != WLAN_STATUS_SUCCESS)
4090 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004091
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004092 if (wpa_auth_uses_mfp(sta->wpa_sm))
4093 sta->flags |= WLAN_STA_MFP;
4094 else
4095 sta->flags &= ~WLAN_STA_MFP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004096
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004097#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004098 if (sta->auth_alg == WLAN_AUTH_FT) {
4099 if (!reassoc) {
4100 wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
4101 "to use association (not "
4102 "re-association) with FT auth_alg",
4103 MAC2STR(sta->addr));
4104 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4105 }
4106
4107 resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
4108 ies_len);
4109 if (resp != WLAN_STATUS_SUCCESS)
4110 return resp;
4111 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004112#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004113
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004114 if (link)
4115 goto skip_sae_owe;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004116#ifdef CONFIG_SAE
Roshan Pius3a1667e2018-07-03 15:17:14 -07004117 if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
4118 sta->sae->state == SAE_ACCEPTED)
4119 wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
4120
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004121 if (wpa_auth_uses_sae(sta->wpa_sm) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004122 sta->auth_alg == WLAN_AUTH_OPEN) {
4123 struct rsn_pmksa_cache_entry *sa;
4124 sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
Sunil Ravi89eba102022-09-13 21:04:37 -07004125 if (!sa || !wpa_key_mgmt_sae(sa->akmp)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004126 wpa_printf(MSG_DEBUG,
4127 "SAE: No PMKSA cache entry found for "
4128 MACSTR, MAC2STR(sta->addr));
4129 return WLAN_STATUS_INVALID_PMKID;
4130 }
4131 wpa_printf(MSG_DEBUG, "SAE: " MACSTR
4132 " using PMKSA caching", MAC2STR(sta->addr));
4133 } else if (wpa_auth_uses_sae(sta->wpa_sm) &&
4134 sta->auth_alg != WLAN_AUTH_SAE &&
4135 !(sta->auth_alg == WLAN_AUTH_FT &&
4136 wpa_auth_uses_ft_sae(sta->wpa_sm))) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004137 wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
4138 "SAE AKM after non-SAE auth_alg %u",
4139 MAC2STR(sta->addr), sta->auth_alg);
4140 return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
4141 }
Hai Shalomc3565922019-10-28 11:58:20 -07004142
Sunil Ravi77d572f2023-01-17 23:58:31 +00004143 if (hapd->conf->sae_pwe == SAE_PWE_BOTH &&
Hai Shalomc3565922019-10-28 11:58:20 -07004144 sta->auth_alg == WLAN_AUTH_SAE &&
Hai Shalom899fcc72020-10-19 14:38:18 -07004145 sta->sae && !sta->sae->h2e &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004146 ieee802_11_rsnx_capab_len(elems->rsnxe, elems->rsnxe_len,
Hai Shaloma20dcd72022-02-04 13:43:00 -08004147 WLAN_RSNX_CAPAB_SAE_H2E)) {
Hai Shalomc3565922019-10-28 11:58:20 -07004148 wpa_printf(MSG_INFO, "SAE: " MACSTR
4149 " indicates support for SAE H2E, but did not use it",
4150 MAC2STR(sta->addr));
4151 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4152 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004153#endif /* CONFIG_SAE */
4154
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004155#ifdef CONFIG_OWE
4156 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
4157 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004158 elems->owe_dh) {
4159 resp = owe_process_assoc_req(hapd, sta, elems->owe_dh,
4160 elems->owe_dh_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004161 if (resp != WLAN_STATUS_SUCCESS)
4162 return resp;
4163 }
4164#endif /* CONFIG_OWE */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004165 skip_sae_owe:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004166
Hai Shalom021b0b52019-04-10 11:17:58 -07004167#ifdef CONFIG_DPP2
4168 dpp_pfs_free(sta->dpp_pfs);
4169 sta->dpp_pfs = NULL;
4170
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004171 if (DPP_VERSION > 1 &&
4172 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07004173 hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
4174 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004175 elems->owe_dh) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004176 sta->dpp_pfs = dpp_pfs_init(
4177 wpabuf_head(hapd->conf->dpp_netaccesskey),
4178 wpabuf_len(hapd->conf->dpp_netaccesskey));
4179 if (!sta->dpp_pfs) {
4180 wpa_printf(MSG_DEBUG,
4181 "DPP: Could not initialize PFS");
4182 /* Try to continue without PFS */
4183 goto pfs_fail;
4184 }
4185
Sunil Ravi036cec52023-03-29 11:35:17 -07004186 if (dpp_pfs_process(sta->dpp_pfs, elems->owe_dh,
4187 elems->owe_dh_len) < 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004188 dpp_pfs_free(sta->dpp_pfs);
4189 sta->dpp_pfs = NULL;
4190 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4191 }
4192 }
4193
4194 wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
4195 sta->dpp_pfs->secret : NULL);
4196 pfs_fail:
4197#endif /* CONFIG_DPP2 */
4198
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004199 if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004200 wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
4201 hostapd_logger(hapd, sta->addr,
4202 HOSTAPD_MODULE_IEEE80211,
4203 HOSTAPD_LEVEL_INFO,
4204 "Station tried to use TKIP with HT "
4205 "association");
4206 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
4207 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004208#ifdef CONFIG_HS20
4209 } else if (hapd->conf->osen) {
Sunil Ravi036cec52023-03-29 11:35:17 -07004210 if (!elems->osen) {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004211 hostapd_logger(
4212 hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4213 HOSTAPD_LEVEL_INFO,
4214 "No HS 2.0 OSEN element in association request");
4215 return WLAN_STATUS_INVALID_IE;
4216 }
4217
4218 wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
4219 if (sta->wpa_sm == NULL)
4220 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
4221 sta->addr, NULL);
4222 if (sta->wpa_sm == NULL) {
4223 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
4224 "state machine");
4225 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4226 }
4227 if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
Sunil Ravi036cec52023-03-29 11:35:17 -07004228 elems->osen - 2, elems->osen_len + 2) < 0)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004229 return WLAN_STATUS_INVALID_IE;
4230#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004231 } else
4232 wpa_auth_sta_no_wpa(sta->wpa_sm);
4233
4234#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004235 p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
4236#endif /* CONFIG_P2P */
4237
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004238#ifdef CONFIG_HS20
4239 wpabuf_free(sta->hs20_ie);
Sunil Ravi036cec52023-03-29 11:35:17 -07004240 if (elems->hs20 && elems->hs20_len > 4) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004241 int release;
4242
Sunil Ravi036cec52023-03-29 11:35:17 -07004243 sta->hs20_ie = wpabuf_alloc_copy(elems->hs20 + 4,
4244 elems->hs20_len - 4);
4245 release = ((elems->hs20[4] >> 4) & 0x0f) + 1;
Hai Shalomc3565922019-10-28 11:58:20 -07004246 if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
4247 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004248 wpa_printf(MSG_DEBUG,
4249 "HS 2.0: PMF not negotiated by release %d station "
4250 MACSTR, release, MAC2STR(sta->addr));
4251 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
4252 }
4253 } else {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004254 sta->hs20_ie = NULL;
Hai Shalom74f70d42019-02-11 14:42:39 -08004255 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07004256
4257 wpabuf_free(sta->roaming_consortium);
Sunil Ravi036cec52023-03-29 11:35:17 -07004258 if (elems->roaming_cons_sel)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004259 sta->roaming_consortium = wpabuf_alloc_copy(
Sunil Ravi036cec52023-03-29 11:35:17 -07004260 elems->roaming_cons_sel + 4,
4261 elems->roaming_cons_sel_len - 4);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004262 else
4263 sta->roaming_consortium = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004264#endif /* CONFIG_HS20 */
4265
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004266#ifdef CONFIG_FST
4267 wpabuf_free(sta->mb_ies);
4268 if (hapd->iface->fst)
Sunil Ravi036cec52023-03-29 11:35:17 -07004269 sta->mb_ies = mb_ies_by_info(&elems->mb_ies);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004270 else
4271 sta->mb_ies = NULL;
4272#endif /* CONFIG_FST */
4273
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004274#ifdef CONFIG_MBO
Sunil Ravi036cec52023-03-29 11:35:17 -07004275 mbo_ap_check_sta_assoc(hapd, sta, elems);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004276
4277 if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004278 elems->mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004279 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
4280 wpa_printf(MSG_INFO,
4281 "MBO: Reject WPA2 association without PMF");
4282 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4283 }
4284#endif /* CONFIG_MBO */
4285
Hai Shalom74f70d42019-02-11 14:42:39 -08004286#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
4287 if (wpa_auth_uses_ocv(sta->wpa_sm) &&
4288 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4289 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4290 sta->auth_alg == WLAN_AUTH_FILS_PK)) {
4291 struct wpa_channel_info ci;
4292 int tx_chanwidth;
4293 int tx_seg1_idx;
Hai Shalom899fcc72020-10-19 14:38:18 -07004294 enum oci_verify_result res;
Hai Shalom74f70d42019-02-11 14:42:39 -08004295
4296 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
4297 wpa_printf(MSG_WARNING,
4298 "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
4299 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4300 }
4301
4302 if (get_sta_tx_parameters(sta->wpa_sm,
4303 channel_width_to_int(ci.chanwidth),
4304 ci.seg1_idx, &tx_chanwidth,
4305 &tx_seg1_idx) < 0)
4306 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4307
Sunil Ravi036cec52023-03-29 11:35:17 -07004308 res = ocv_verify_tx_params(elems->oci, elems->oci_len, &ci,
Hai Shalom899fcc72020-10-19 14:38:18 -07004309 tx_chanwidth, tx_seg1_idx);
4310 if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
4311 res == OCI_NOT_FOUND) {
4312 /* Work around misbehaving STAs */
4313 wpa_printf(MSG_INFO,
4314 "FILS: Disable OCV with a STA that does not send OCI");
4315 wpa_auth_set_ocv(sta->wpa_sm, 0);
4316 } else if (res != OCI_SUCCESS) {
4317 wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
4318 ocv_errorstr);
4319 wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
4320 MACSTR " frame=fils-reassoc-req error=%s",
4321 MAC2STR(sta->addr), ocv_errorstr);
Hai Shalom74f70d42019-02-11 14:42:39 -08004322 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4323 }
4324 }
4325#endif /* CONFIG_FILS && CONFIG_OCV */
4326
Sunil Ravi036cec52023-03-29 11:35:17 -07004327 ap_copy_sta_supp_op_classes(sta, elems->supp_op_classes,
4328 elems->supp_op_classes_len);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08004329
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004330 if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004331 elems->rrm_enabled &&
4332 elems->rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
4333 os_memcpy(sta->rrm_enabled_capa, elems->rrm_enabled,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004334 sizeof(sta->rrm_enabled_capa));
4335
Sunil Ravi036cec52023-03-29 11:35:17 -07004336 if (elems->power_capab) {
4337 sta->min_tx_power = elems->power_capab[0];
4338 sta->max_tx_power = elems->power_capab[1];
Roshan Pius3a1667e2018-07-03 15:17:14 -07004339 sta->power_capab = 1;
4340 } else {
4341 sta->power_capab = 0;
4342 }
4343
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004344 return WLAN_STATUS_SUCCESS;
4345}
4346
4347
Sunil Ravi036cec52023-03-29 11:35:17 -07004348static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
4349 const u8 *ies, size_t ies_len, int reassoc)
4350{
4351 struct ieee802_11_elems elems;
4352
4353 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
4354 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4355 HOSTAPD_LEVEL_INFO,
4356 "Station sent an invalid association request");
4357 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4358 }
4359
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004360 return __check_assoc_ies(hapd, sta, ies, ies_len, &elems, reassoc,
4361 false);
4362}
4363
4364
4365#ifdef CONFIG_IEEE80211BE
4366
Sunil Ravi72e01222024-03-09 01:25:43 +00004367static void ieee80211_ml_build_assoc_resp(struct hostapd_data *hapd,
4368 struct mld_link_info *link)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004369{
Sunil Ravi72e01222024-03-09 01:25:43 +00004370 u8 buf[EHT_ML_MAX_STA_PROF_LEN];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004371 u8 *p = buf;
Sunil Ravi72e01222024-03-09 01:25:43 +00004372 size_t buflen = sizeof(buf);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004373
4374 /* Capability Info */
4375 WPA_PUT_LE16(p, hostapd_own_capab_info(hapd));
4376 p += 2;
4377
4378 /* Status Code */
Sunil Ravi72e01222024-03-09 01:25:43 +00004379 WPA_PUT_LE16(p, link->status);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004380 p += 2;
4381
Sunil Ravi72e01222024-03-09 01:25:43 +00004382 if (link->status != WLAN_STATUS_SUCCESS)
4383 goto out;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004384
4385 /* AID is not included */
4386 p = hostapd_eid_supp_rates(hapd, p);
4387 p = hostapd_eid_ext_supp_rates(hapd, p);
4388 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
4389 p = hostapd_eid_ht_capabilities(hapd, p);
4390 p = hostapd_eid_ht_operation(hapd, p);
4391
4392 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
4393 p = hostapd_eid_vht_capabilities(hapd, p, 0);
4394 p = hostapd_eid_vht_operation(hapd, p);
4395 }
4396
4397 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
4398 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
4399 p = hostapd_eid_he_operation(hapd, p);
4400 p = hostapd_eid_spatial_reuse(hapd, p);
4401 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
4402 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
4403 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4404 p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
4405 p = hostapd_eid_eht_operation(hapd, p);
4406 }
4407 }
4408
4409 p = hostapd_eid_ext_capab(hapd, p, false);
4410 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
4411 p = hostapd_eid_wmm(hapd, p);
4412
4413 if (hapd->conf->assocresp_elements &&
4414 (size_t) (buf + buflen - p) >=
4415 wpabuf_len(hapd->conf->assocresp_elements)) {
4416 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
4417 wpabuf_len(hapd->conf->assocresp_elements));
4418 p += wpabuf_len(hapd->conf->assocresp_elements);
4419 }
4420
Sunil Ravi72e01222024-03-09 01:25:43 +00004421out:
4422 os_free(link->resp_sta_profile);
4423 link->resp_sta_profile = os_memdup(buf, p - buf);
4424 link->resp_sta_profile_len = link->resp_sta_profile ? p - buf : 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004425}
4426
4427
Sunil Ravi72e01222024-03-09 01:25:43 +00004428static int ieee80211_ml_process_link(struct hostapd_data *hapd,
4429 struct sta_info *origin_sta,
4430 struct mld_link_info *link,
4431 const u8 *ies, size_t ies_len,
4432 bool reassoc, bool offload)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004433{
4434 struct ieee802_11_elems elems;
4435 struct wpabuf *mlbuf = NULL;
4436 struct sta_info *sta = NULL;
4437 u16 status = WLAN_STATUS_SUCCESS;
Sunil Ravi72e01222024-03-09 01:25:43 +00004438 int i;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004439
4440 wpa_printf(MSG_DEBUG, "MLD: link: link_id=%u, peer=" MACSTR,
4441 hapd->mld_link_id, MAC2STR(link->peer_addr));
4442
4443 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
4444 wpa_printf(MSG_DEBUG, "MLD: link: Element parsing failed");
4445 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4446 goto out;
4447 }
4448
4449 sta = ap_get_sta(hapd, origin_sta->addr);
4450 if (sta) {
4451 wpa_printf(MSG_INFO, "MLD: link: Station already exists");
4452 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4453 sta = NULL;
4454 goto out;
4455 }
4456
4457 sta = ap_sta_add(hapd, origin_sta->addr);
4458 if (!sta) {
4459 wpa_printf(MSG_DEBUG, "MLD: link: ap_sta_add() failed");
4460 status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4461 goto out;
4462 }
4463
Sunil Ravi72e01222024-03-09 01:25:43 +00004464 mlbuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004465 if (!mlbuf)
4466 goto out;
4467
4468 if (ieee802_11_parse_link_assoc_req(ies, ies_len, &elems, mlbuf,
4469 hapd->mld_link_id, true) ==
4470 ParseFailed) {
4471 wpa_printf(MSG_DEBUG,
4472 "MLD: link: Failed to parse association request Multi-Link element");
4473 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4474 goto out;
4475 }
4476
4477 sta->flags |= origin_sta->flags | WLAN_STA_ASSOC_REQ_OK;
4478 status = __check_assoc_ies(hapd, sta, NULL, 0, &elems, reassoc, true);
4479 if (status != WLAN_STATUS_SUCCESS) {
4480 wpa_printf(MSG_DEBUG, "MLD: link: Element check failed");
4481 goto out;
4482 }
4483
Sunil Ravi72e01222024-03-09 01:25:43 +00004484 ap_sta_set_mld(sta, true);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004485 sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id;
4486
4487 os_memcpy(&sta->mld_info, &origin_sta->mld_info, sizeof(sta->mld_info));
Sunil Ravi72e01222024-03-09 01:25:43 +00004488 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
4489 struct mld_link_info *li = &sta->mld_info.links[i];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004490
Sunil Ravi72e01222024-03-09 01:25:43 +00004491 li->resp_sta_profile = NULL;
4492 li->resp_sta_profile_len = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004493 }
Sunil Ravi72e01222024-03-09 01:25:43 +00004494
4495 if (!offload) {
4496 /*
4497 * Get the AID from the station on which the association was
4498 * performed, and mark it as used.
4499 */
4500 sta->aid = origin_sta->aid;
4501 if (sta->aid == 0) {
4502 wpa_printf(MSG_DEBUG, "MLD: link: No AID assigned");
4503 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4504 goto out;
4505 }
4506 hapd->sta_aid[(sta->aid - 1) / 32] |= BIT((sta->aid - 1) % 32);
4507 sta->listen_interval = origin_sta->listen_interval;
4508 if (update_ht_state(hapd, sta) > 0)
4509 ieee802_11_update_beacons(hapd->iface);
4510 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004511
4512 /* RSN Authenticator should always be the one on the original station */
4513 wpa_auth_sta_deinit(sta->wpa_sm);
4514 sta->wpa_sm = NULL;
4515
4516 /*
4517 * Do not initialize the EAPOL state machine.
4518 * TODO: Maybe it is needed?
4519 */
4520 sta->eapol_sm = NULL;
4521
4522 wpa_printf(MSG_DEBUG, "MLD: link=%u, association OK (aid=%u)",
4523 hapd->mld_link_id, sta->aid);
4524
4525 /*
4526 * Get RSNE and RSNXE for the current BSS as they are required by the
4527 * Authenticator.
4528 */
4529 link->rsne = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
4530 link->rsnxe = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
4531
4532 sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC_REQ_OK;
4533
4534 /* TODO: What other processing is required? */
4535
Sunil Ravi72e01222024-03-09 01:25:43 +00004536 if (!offload && add_associated_sta(hapd, sta, reassoc))
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004537 status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4538out:
4539 wpabuf_free(mlbuf);
4540 link->status = status;
4541
Sunil Ravi72e01222024-03-09 01:25:43 +00004542 if (!offload)
4543 ieee80211_ml_build_assoc_resp(hapd, link);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004544
Sunil Ravi72e01222024-03-09 01:25:43 +00004545 wpa_printf(MSG_DEBUG, "MLD: link: status=%u", status);
4546 if (status != WLAN_STATUS_SUCCESS) {
4547 if (sta)
4548 ap_free_sta(hapd, sta);
4549 return -1;
4550 }
4551
4552 return 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004553}
4554
4555
4556bool hostapd_is_mld_ap(struct hostapd_data *hapd)
4557{
4558 if (!hapd->conf->mld_ap)
4559 return false;
4560
4561 if (!hapd->iface || !hapd->iface->interfaces ||
4562 hapd->iface->interfaces->count <= 1)
4563 return false;
4564
4565 return true;
4566}
4567
4568#endif /* CONFIG_IEEE80211BE */
4569
4570
Sunil Ravi72e01222024-03-09 01:25:43 +00004571int hostapd_process_assoc_ml_info(struct hostapd_data *hapd,
4572 struct sta_info *sta,
4573 const u8 *ies, size_t ies_len,
4574 bool reassoc, int tx_link_status,
4575 bool offload)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004576{
4577#ifdef CONFIG_IEEE80211BE
4578 unsigned int i, j;
4579
4580 if (!hostapd_is_mld_ap(hapd))
Sunil Ravi72e01222024-03-09 01:25:43 +00004581 return 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004582
4583 /*
4584 * This is not really needed, but make the interaction with the RSN
4585 * Authenticator more consistent
4586 */
4587 sta->mld_info.links[hapd->mld_link_id].rsne =
4588 hostapd_wpa_ie(hapd, WLAN_EID_RSN);
4589 sta->mld_info.links[hapd->mld_link_id].rsnxe =
4590 hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
4591
4592 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
4593 struct hostapd_iface *iface = NULL;
4594 struct mld_link_info *link = &sta->mld_info.links[i];
4595
4596 if (!link->valid)
4597 continue;
4598
4599 for (j = 0; j < hapd->iface->interfaces->count; j++) {
4600 iface = hapd->iface->interfaces->iface[j];
4601
4602 if (hapd->iface == iface)
4603 continue;
4604
Sunil Raviaf399a82024-05-05 20:56:55 +00004605 if (hostapd_is_ml_partner(hapd, iface->bss[0]) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004606 i == iface->bss[0]->mld_link_id)
4607 break;
4608 }
4609
Sunil Ravi72e01222024-03-09 01:25:43 +00004610 if (!iface || j == hapd->iface->interfaces->count ||
4611 TEST_FAIL()) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004612 wpa_printf(MSG_DEBUG,
4613 "MLD: No link match for link_id=%u", i);
4614
4615 link->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
Sunil Ravi72e01222024-03-09 01:25:43 +00004616 if (!offload)
4617 ieee80211_ml_build_assoc_resp(hapd, link);
4618 } else if (tx_link_status != WLAN_STATUS_SUCCESS) {
4619 /* TX link rejected the connection */
4620 link->status = WLAN_STATUS_DENIED_TX_LINK_NOT_ACCEPTED;
4621 if (!offload)
4622 ieee80211_ml_build_assoc_resp(hapd, link);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004623 } else {
Sunil Ravi72e01222024-03-09 01:25:43 +00004624 if (ieee80211_ml_process_link(iface->bss[0], sta, link,
4625 ies, ies_len, reassoc,
4626 offload))
4627 return -1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004628 }
4629 }
4630#endif /* CONFIG_IEEE80211BE */
Sunil Ravi72e01222024-03-09 01:25:43 +00004631
4632 return 0;
Sunil Ravi036cec52023-03-29 11:35:17 -07004633}
4634
4635
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004636static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
4637 u16 reason_code)
4638{
4639 int send_len;
4640 struct ieee80211_mgmt reply;
4641
4642 os_memset(&reply, 0, sizeof(reply));
4643 reply.frame_control =
4644 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
4645 os_memcpy(reply.da, addr, ETH_ALEN);
4646 os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
4647 os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
4648
4649 send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
4650 reply.u.deauth.reason_code = host_to_le16(reason_code);
4651
Hai Shalomfdcde762020-04-02 11:19:20 -07004652 if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004653 wpa_printf(MSG_INFO, "Failed to send deauth: %s",
4654 strerror(errno));
4655}
4656
4657
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004658static int add_associated_sta(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08004659 struct sta_info *sta, int reassoc)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004660{
4661 struct ieee80211_ht_capabilities ht_cap;
4662 struct ieee80211_vht_capabilities vht_cap;
Hai Shalom81f62d82019-07-22 12:10:00 -07004663 struct ieee80211_he_capabilities he_cap;
Sunil Ravia04bd252022-05-02 22:54:18 -07004664 struct ieee80211_eht_capabilities eht_cap;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004665 int set = 1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004666 const u8 *mld_link_addr = NULL;
4667 bool mld_link_sta = false;
4668
4669#ifdef CONFIG_IEEE80211BE
Sunil Ravi72e01222024-03-09 01:25:43 +00004670 if (ap_sta_is_mld(hapd, sta)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004671 u8 mld_link_id = hapd->mld_link_id;
4672
4673 mld_link_sta = sta->mld_assoc_link_id != mld_link_id;
4674 mld_link_addr = sta->mld_info.links[mld_link_id].peer_addr;
4675
4676 if (hapd->mld_link_id != sta->mld_assoc_link_id)
4677 set = 0;
4678 }
4679#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004680
4681 /*
4682 * Remove the STA entry to ensure the STA PS state gets cleared and
4683 * configuration gets updated. This is relevant for cases, such as
4684 * FT-over-the-DS, where a station re-associates back to the same AP but
4685 * skips the authentication flow, or if working with a driver that
4686 * does not support full AP client state.
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004687 *
4688 * Skip this if the STA has already completed FT reassociation and the
4689 * TK has been configured since the TX/RX PN must not be reset to 0 for
4690 * the same key.
Hai Shalom74f70d42019-02-11 14:42:39 -08004691 *
4692 * FT-over-the-DS has a special case where the STA entry (and as such,
4693 * the TK) has not yet been configured to the driver depending on which
4694 * driver interface is used. For that case, allow add-STA operation to
4695 * be used (instead of set-STA). This is needed to allow mac80211-based
4696 * drivers to accept the STA parameter configuration. Since this is
4697 * after a new FT-over-DS exchange, a new TK has been derived, so key
4698 * reinstallation is not a concern for this case.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004699 */
Hai Shalom74f70d42019-02-11 14:42:39 -08004700 wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
4701 " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
4702 MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
4703 sta->ft_over_ds, reassoc,
4704 !!(sta->flags & WLAN_STA_AUTHORIZED),
4705 wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
4706 wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
4707
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004708 if (!mld_link_sta && !sta->added_unassoc &&
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004709 (!(sta->flags & WLAN_STA_AUTHORIZED) ||
Hai Shalom74f70d42019-02-11 14:42:39 -08004710 (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004711 (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
4712 !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004713 hostapd_drv_sta_remove(hapd, sta->addr);
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004714 wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
4715 set = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08004716
4717 /* Do not allow the FT-over-DS exception to be used more than
4718 * once per authentication exchange to guarantee a new TK is
4719 * used here */
4720 sta->ft_over_ds = 0;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004721 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004722
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004723 if (sta->flags & WLAN_STA_HT)
4724 hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004725#ifdef CONFIG_IEEE80211AC
4726 if (sta->flags & WLAN_STA_VHT)
4727 hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
4728#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07004729#ifdef CONFIG_IEEE80211AX
4730 if (sta->flags & WLAN_STA_HE) {
4731 hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
4732 sta->he_capab_len);
4733 }
4734#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07004735#ifdef CONFIG_IEEE80211BE
4736 if (sta->flags & WLAN_STA_EHT)
4737 hostapd_get_eht_capab(hapd, sta->eht_capab, &eht_cap,
4738 sta->eht_capab_len);
4739#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004740
4741 /*
4742 * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
4743 * will be set when the ACK frame for the (Re)Association Response frame
4744 * is processed (TX status driver event).
4745 */
4746 if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
4747 sta->supported_rates, sta->supported_rates_len,
4748 sta->listen_interval,
4749 sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
4750 sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
Hai Shalom81f62d82019-07-22 12:10:00 -07004751 sta->flags & WLAN_STA_HE ? &he_cap : NULL,
4752 sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
Sunil Ravia04bd252022-05-02 22:54:18 -07004753 sta->flags & WLAN_STA_EHT ? &eht_cap : NULL,
4754 sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004755 sta->he_6ghz_capab,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004756 sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004757 sta->vht_opmode, sta->p2p_ie ? 1 : 0,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004758 set, mld_link_addr, mld_link_sta)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004759 hostapd_logger(hapd, sta->addr,
4760 HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
4761 "Could not %s STA to kernel driver",
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004762 set ? "set" : "add");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004763
4764 if (sta->added_unassoc) {
4765 hostapd_drv_sta_remove(hapd, sta->addr);
4766 sta->added_unassoc = 0;
4767 }
4768
4769 return -1;
4770 }
4771
4772 sta->added_unassoc = 0;
4773
4774 return 0;
4775}
4776
4777
4778static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt29333592017-01-09 12:27:11 -08004779 const u8 *addr, u16 status_code, int reassoc,
Hai Shalomfdcde762020-04-02 11:19:20 -07004780 const u8 *ies, size_t ies_len, int rssi,
Sunil Ravi72e01222024-03-09 01:25:43 +00004781 int omit_rsnxe, bool allow_mld_addr_trans)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004782{
4783 int send_len;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004784 u8 *buf;
4785 size_t buflen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004786 struct ieee80211_mgmt *reply;
4787 u8 *p;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004788 u16 res = WLAN_STATUS_SUCCESS;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004789 const u8 *sa = hapd->own_addr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004790
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004791 buflen = sizeof(struct ieee80211_mgmt) + 1024;
4792#ifdef CONFIG_FILS
4793 if (sta && sta->fils_hlp_resp)
4794 buflen += wpabuf_len(sta->fils_hlp_resp);
Hai Shalom81f62d82019-07-22 12:10:00 -07004795 if (sta)
4796 buflen += 150;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004797#endif /* CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004798#ifdef CONFIG_OWE
4799 if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
4800 buflen += 150;
4801#endif /* CONFIG_OWE */
Hai Shalom021b0b52019-04-10 11:17:58 -07004802#ifdef CONFIG_DPP2
4803 if (sta && sta->dpp_pfs)
4804 buflen += 5 + sta->dpp_pfs->curve->prime_len;
4805#endif /* CONFIG_DPP2 */
Sunil Ravia04bd252022-05-02 22:54:18 -07004806#ifdef CONFIG_IEEE80211BE
4807 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4808 buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
4809 buflen += 3 + sizeof(struct ieee80211_eht_operation);
Sunil Ravi036cec52023-03-29 11:35:17 -07004810 if (hapd->iconf->punct_bitmap)
4811 buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
Sunil Ravia04bd252022-05-02 22:54:18 -07004812 }
4813#endif /* CONFIG_IEEE80211BE */
4814
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004815 buf = os_zalloc(buflen);
4816 if (!buf) {
4817 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4818 goto done;
4819 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004820 reply = (struct ieee80211_mgmt *) buf;
4821 reply->frame_control =
4822 IEEE80211_FC(WLAN_FC_TYPE_MGMT,
4823 (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
4824 WLAN_FC_STYPE_ASSOC_RESP));
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004825
4826#ifdef CONFIG_IEEE80211BE
4827 /*
4828 * Once a non-AP MLD is added to the driver, the addressing should use
4829 * MLD MAC address.
4830 */
Sunil Ravi72e01222024-03-09 01:25:43 +00004831 if (ap_sta_is_mld(hapd, sta) && allow_mld_addr_trans)
Sunil Raviaf399a82024-05-05 20:56:55 +00004832 sa = hapd->mld->mld_addr;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004833#endif /* CONFIG_IEEE80211BE */
4834
Dmitry Shmidt29333592017-01-09 12:27:11 -08004835 os_memcpy(reply->da, addr, ETH_ALEN);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004836 os_memcpy(reply->sa, sa, ETH_ALEN);
4837 os_memcpy(reply->bssid, sa, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004838
4839 send_len = IEEE80211_HDRLEN;
4840 send_len += sizeof(reply->u.assoc_resp);
4841 reply->u.assoc_resp.capab_info =
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07004842 host_to_le16(hostapd_own_capab_info(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004843 reply->u.assoc_resp.status_code = host_to_le16(status_code);
Dmitry Shmidt29333592017-01-09 12:27:11 -08004844
4845 reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
4846 BIT(14) | BIT(15));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004847 /* Supported rates */
4848 p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
4849 /* Extended supported rates */
4850 p = hostapd_eid_ext_supp_rates(hapd, p);
4851
Hai Shalomfdcde762020-04-02 11:19:20 -07004852 /* Radio measurement capabilities */
4853 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
4854
Hai Shalom74f70d42019-02-11 14:42:39 -08004855#ifdef CONFIG_MBO
4856 if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
4857 rssi != 0) {
4858 int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
4859
4860 p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
4861 delta);
4862 }
4863#endif /* CONFIG_MBO */
4864
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004865#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt29333592017-01-09 12:27:11 -08004866 if (sta && status_code == WLAN_STATUS_SUCCESS) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004867 /* IEEE 802.11r: Mobility Domain Information, Fast BSS
4868 * Transition Information, RSN, [RIC Response] */
4869 p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004870 buf + buflen - p,
Hai Shalomfdcde762020-04-02 11:19:20 -07004871 sta->auth_alg, ies, ies_len,
4872 omit_rsnxe);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004873 if (!p) {
4874 wpa_printf(MSG_DEBUG,
4875 "FT: Failed to write AssocResp IEs");
4876 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4877 goto done;
4878 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004879 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004880#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom81f62d82019-07-22 12:10:00 -07004881#ifdef CONFIG_FILS
4882 if (sta && status_code == WLAN_STATUS_SUCCESS &&
4883 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4884 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4885 sta->auth_alg == WLAN_AUTH_FILS_PK))
4886 p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
4887 buf + buflen - p,
4888 ies, ies_len);
4889#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004890
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004891#ifdef CONFIG_OWE
Hai Shalom74f70d42019-02-11 14:42:39 -08004892 if (sta && status_code == WLAN_STATUS_SUCCESS &&
4893 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004894 p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
4895 buf + buflen - p,
4896 ies, ies_len);
4897#endif /* CONFIG_OWE */
4898
Dmitry Shmidt29333592017-01-09 12:27:11 -08004899 if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004900 p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004901
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004902 p = hostapd_eid_ht_capabilities(hapd, p);
4903 p = hostapd_eid_ht_operation(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004904
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004905#ifdef CONFIG_IEEE80211AC
Hai Shalomc3565922019-10-28 11:58:20 -07004906 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
4907 !is_6ghz_op_class(hapd->iconf->op_class)) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07004908 u32 nsts = 0, sta_nsts;
4909
Dmitry Shmidt29333592017-01-09 12:27:11 -08004910 if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07004911 struct ieee80211_vht_capabilities *capa;
4912
4913 nsts = (hapd->iface->conf->vht_capab >>
4914 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
4915 capa = sta->vht_capabilities;
4916 sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
4917 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
4918
4919 if (nsts < sta_nsts)
4920 nsts = 0;
4921 else
4922 nsts = sta_nsts;
4923 }
4924 p = hostapd_eid_vht_capabilities(hapd, p, nsts);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004925 p = hostapd_eid_vht_operation(hapd, p);
4926 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004927#endif /* CONFIG_IEEE80211AC */
4928
Hai Shalom81f62d82019-07-22 12:10:00 -07004929#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08004930 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07004931 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
4932 p = hostapd_eid_he_operation(hapd, p);
Sunil Ravia04bd252022-05-02 22:54:18 -07004933 p = hostapd_eid_cca(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07004934 p = hostapd_eid_spatial_reuse(hapd, p);
4935 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004936 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07004937 }
4938#endif /* CONFIG_IEEE80211AX */
4939
Sunil Ravi77d572f2023-01-17 23:58:31 +00004940 p = hostapd_eid_ext_capab(hapd, p, false);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004941 p = hostapd_eid_bss_max_idle_period(hapd, p);
Dmitry Shmidt29333592017-01-09 12:27:11 -08004942 if (sta && sta->qos_map_enabled)
Dmitry Shmidt051af732013-10-22 13:52:46 -07004943 p = hostapd_eid_qos_map_set(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004944
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004945#ifdef CONFIG_FST
4946 if (hapd->iface->fst_ies) {
4947 os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
4948 wpabuf_len(hapd->iface->fst_ies));
4949 p += wpabuf_len(hapd->iface->fst_ies);
4950 }
4951#endif /* CONFIG_FST */
4952
Hai Shalomfdcde762020-04-02 11:19:20 -07004953#ifdef CONFIG_TESTING_OPTIONS
4954 if (hapd->conf->rsnxe_override_ft &&
4955 buf + buflen - p >=
4956 (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
4957 sta && sta->auth_alg == WLAN_AUTH_FT) {
4958 wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
4959 os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
4960 wpabuf_len(hapd->conf->rsnxe_override_ft));
4961 p += wpabuf_len(hapd->conf->rsnxe_override_ft);
4962 goto rsnxe_done;
4963 }
4964#endif /* CONFIG_TESTING_OPTIONS */
4965 if (!omit_rsnxe)
4966 p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
4967#ifdef CONFIG_TESTING_OPTIONS
4968rsnxe_done:
4969#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomc3565922019-10-28 11:58:20 -07004970
Sunil Ravia04bd252022-05-02 22:54:18 -07004971#ifdef CONFIG_IEEE80211BE
4972 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004973 if (hapd->conf->mld_ap)
Sunil Ravi72e01222024-03-09 01:25:43 +00004974 p = hostapd_eid_eht_ml_assoc(hapd, sta, p);
Sunil Ravia04bd252022-05-02 22:54:18 -07004975 p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
4976 p = hostapd_eid_eht_operation(hapd, p);
4977 }
4978#endif /* CONFIG_IEEE80211BE */
4979
Hai Shalom021b0b52019-04-10 11:17:58 -07004980#ifdef CONFIG_OWE
4981 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
4982 sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
Hai Shalom899fcc72020-10-19 14:38:18 -07004983 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
4984 !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004985 struct wpabuf *pub;
4986
4987 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
4988 if (!pub) {
4989 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4990 goto done;
4991 }
4992 /* OWE Diffie-Hellman Parameter element */
4993 *p++ = WLAN_EID_EXTENSION; /* Element ID */
4994 *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
4995 *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
4996 WPA_PUT_LE16(p, sta->owe_group);
4997 p += 2;
4998 os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
4999 p += wpabuf_len(pub);
5000 wpabuf_free(pub);
5001 }
5002#endif /* CONFIG_OWE */
5003
5004#ifdef CONFIG_DPP2
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005005 if (DPP_VERSION > 1 && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07005006 sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
5007 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
5008 os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
5009 wpabuf_len(sta->dpp_pfs->ie));
5010 p += wpabuf_len(sta->dpp_pfs->ie);
5011 }
5012#endif /* CONFIG_DPP2 */
5013
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005014#ifdef CONFIG_IEEE80211AC
Dmitry Shmidt29333592017-01-09 12:27:11 -08005015 if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005016 p = hostapd_eid_vendor_vht(hapd, p);
5017#endif /* CONFIG_IEEE80211AC */
5018
Dmitry Shmidt29333592017-01-09 12:27:11 -08005019 if (sta && (sta->flags & WLAN_STA_WMM))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005020 p = hostapd_eid_wmm(hapd, p);
5021
5022#ifdef CONFIG_WPS
Dmitry Shmidt29333592017-01-09 12:27:11 -08005023 if (sta &&
5024 ((sta->flags & WLAN_STA_WPS) ||
5025 ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005026 struct wpabuf *wps = wps_build_assoc_resp_ie();
5027 if (wps) {
5028 os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
5029 p += wpabuf_len(wps);
5030 wpabuf_free(wps);
5031 }
5032 }
5033#endif /* CONFIG_WPS */
5034
Hai Shalom74f70d42019-02-11 14:42:39 -08005035 if (sta && (sta->flags & WLAN_STA_MULTI_AP))
Sunil Raviaf399a82024-05-05 20:56:55 +00005036 p = hostapd_eid_multi_ap(hapd, p, buf + buflen - p);
Hai Shalom74f70d42019-02-11 14:42:39 -08005037
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005038#ifdef CONFIG_P2P
Dmitry Shmidt29333592017-01-09 12:27:11 -08005039 if (sta && sta->p2p_ie && hapd->p2p_group) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005040 struct wpabuf *p2p_resp_ie;
5041 enum p2p_status_code status;
5042 switch (status_code) {
5043 case WLAN_STATUS_SUCCESS:
5044 status = P2P_SC_SUCCESS;
5045 break;
5046 case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
5047 status = P2P_SC_FAIL_LIMIT_REACHED;
5048 break;
5049 default:
5050 status = P2P_SC_FAIL_INVALID_PARAMS;
5051 break;
5052 }
5053 p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
5054 if (p2p_resp_ie) {
5055 os_memcpy(p, wpabuf_head(p2p_resp_ie),
5056 wpabuf_len(p2p_resp_ie));
5057 p += wpabuf_len(p2p_resp_ie);
5058 wpabuf_free(p2p_resp_ie);
5059 }
5060 }
5061#endif /* CONFIG_P2P */
5062
5063#ifdef CONFIG_P2P_MANAGER
5064 if (hapd->conf->p2p & P2P_MANAGE)
5065 p = hostapd_eid_p2p_manage(hapd, p);
5066#endif /* CONFIG_P2P_MANAGER */
5067
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005068 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005069
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005070 if (hapd->conf->assocresp_elements &&
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005071 (size_t) (buf + buflen - p) >=
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005072 wpabuf_len(hapd->conf->assocresp_elements)) {
5073 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
5074 wpabuf_len(hapd->conf->assocresp_elements));
5075 p += wpabuf_len(hapd->conf->assocresp_elements);
5076 }
5077
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005078 send_len += p - reply->u.assoc_resp.variable;
5079
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005080#ifdef CONFIG_FILS
Dmitry Shmidt29333592017-01-09 12:27:11 -08005081 if (sta &&
5082 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005083 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5084 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
5085 status_code == WLAN_STATUS_SUCCESS) {
5086 struct ieee802_11_elems elems;
5087
5088 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005089 ParseFailed || !elems.fils_session) {
5090 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5091 goto done;
5092 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005093
5094 /* FILS Session */
5095 *p++ = WLAN_EID_EXTENSION; /* Element ID */
5096 *p++ = 1 + FILS_SESSION_LEN; /* Length */
5097 *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
5098 os_memcpy(p, elems.fils_session, FILS_SESSION_LEN);
5099 send_len += 2 + 1 + FILS_SESSION_LEN;
5100
5101 send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005102 buflen, sta->fils_hlp_resp);
5103 if (send_len < 0) {
5104 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5105 goto done;
5106 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005107 }
5108#endif /* CONFIG_FILS */
5109
Hai Shalomfdcde762020-04-02 11:19:20 -07005110 if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005111 wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
5112 strerror(errno));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005113 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005114 }
5115
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005116done:
5117 os_free(buf);
5118 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005119}
5120
5121
Roshan Pius3a1667e2018-07-03 15:17:14 -07005122#ifdef CONFIG_OWE
5123u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
5124 const u8 *owe_dh, u8 owe_dh_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07005125 u8 *owe_buf, size_t owe_buf_len, u16 *status)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005126{
5127#ifdef CONFIG_TESTING_OPTIONS
5128 if (hapd->conf->own_ie_override) {
5129 wpa_printf(MSG_DEBUG, "OWE: Using IE override");
Hai Shalomfdcde762020-04-02 11:19:20 -07005130 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005131 return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5132 owe_buf_len, NULL, 0);
5133 }
5134#endif /* CONFIG_TESTING_OPTIONS */
5135
5136 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
5137 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
5138 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5139 owe_buf_len, NULL, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -07005140 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005141 return owe_buf;
5142 }
5143
Hai Shalom81f62d82019-07-22 12:10:00 -07005144 if (sta->owe_pmk && sta->external_dh_updated) {
5145 wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
Hai Shalomfdcde762020-04-02 11:19:20 -07005146 *status = WLAN_STATUS_SUCCESS;
Hai Shalom81f62d82019-07-22 12:10:00 -07005147 return owe_buf;
5148 }
5149
Hai Shalomfdcde762020-04-02 11:19:20 -07005150 *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
5151 if (*status != WLAN_STATUS_SUCCESS)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005152 return NULL;
5153
5154 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5155 owe_buf_len, NULL, 0);
5156
5157 if (sta->owe_ecdh && owe_buf) {
5158 struct wpabuf *pub;
5159
5160 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
5161 if (!pub) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005162 *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005163 return owe_buf;
5164 }
5165
5166 /* OWE Diffie-Hellman Parameter element */
5167 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
5168 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
5169 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
5170 */
5171 WPA_PUT_LE16(owe_buf, sta->owe_group);
5172 owe_buf += 2;
5173 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
5174 owe_buf += wpabuf_len(pub);
5175 wpabuf_free(pub);
5176 }
5177
5178 return owe_buf;
5179}
5180#endif /* CONFIG_OWE */
5181
5182
Paul Stewart092955c2017-02-06 09:13:09 -08005183#ifdef CONFIG_FILS
5184
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005185void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
Paul Stewart092955c2017-02-06 09:13:09 -08005186{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005187 u16 reply_res;
Paul Stewart092955c2017-02-06 09:13:09 -08005188
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005189 wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
5190 MAC2STR(sta->addr));
5191 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5192 if (!sta->fils_pending_assoc_req)
Paul Stewart092955c2017-02-06 09:13:09 -08005193 return;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005194 reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
5195 sta->fils_pending_assoc_is_reassoc,
5196 sta->fils_pending_assoc_req,
Sunil Ravi72e01222024-03-09 01:25:43 +00005197 sta->fils_pending_assoc_req_len, 0, 0,
5198 true);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005199 os_free(sta->fils_pending_assoc_req);
5200 sta->fils_pending_assoc_req = NULL;
5201 sta->fils_pending_assoc_req_len = 0;
5202 wpabuf_free(sta->fils_hlp_resp);
5203 sta->fils_hlp_resp = NULL;
5204 wpabuf_free(sta->hlp_dhcp_discover);
5205 sta->hlp_dhcp_discover = NULL;
Paul Stewart092955c2017-02-06 09:13:09 -08005206
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005207 /*
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005208 * Remove the station in case transmission of a success response fails.
5209 * At this point the station was already added associated to the driver.
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005210 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005211 if (reply_res != WLAN_STATUS_SUCCESS)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005212 hostapd_drv_sta_remove(hapd, sta->addr);
Paul Stewart092955c2017-02-06 09:13:09 -08005213}
5214
5215
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005216void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
Paul Stewart092955c2017-02-06 09:13:09 -08005217{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005218 struct hostapd_data *hapd = eloop_ctx;
5219 struct sta_info *sta = eloop_data;
Paul Stewart092955c2017-02-06 09:13:09 -08005220
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005221 wpa_printf(MSG_DEBUG,
5222 "FILS: HLP response timeout - continue with association response for "
5223 MACSTR, MAC2STR(sta->addr));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005224 if (sta->fils_drv_assoc_finish)
5225 hostapd_notify_assoc_fils_finish(hapd, sta);
5226 else
5227 fils_hlp_finish_assoc(hapd, sta);
Paul Stewart092955c2017-02-06 09:13:09 -08005228}
5229
5230#endif /* CONFIG_FILS */
5231
5232
Sunil Ravi72e01222024-03-09 01:25:43 +00005233#ifdef CONFIG_IEEE80211BE
5234static struct sta_info * handle_mlo_translate(struct hostapd_data *hapd,
5235 const struct ieee80211_mgmt *mgmt,
5236 size_t len, bool reassoc,
5237 struct hostapd_data **assoc_hapd)
5238{
5239 struct sta_info *sta;
5240 struct ieee802_11_elems elems;
5241 u8 mld_addr[ETH_ALEN];
5242 const u8 *pos;
5243
5244 if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be)
5245 return NULL;
5246
5247 if (reassoc) {
5248 len -= IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req);
5249 pos = mgmt->u.reassoc_req.variable;
5250 } else {
5251 len -= IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req);
5252 pos = mgmt->u.assoc_req.variable;
5253 }
5254
5255 if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed)
5256 return NULL;
5257
5258 if (hostapd_process_ml_assoc_req_addr(hapd, elems.basic_mle,
5259 elems.basic_mle_len,
5260 mld_addr))
5261 return NULL;
5262
5263 sta = ap_get_sta(hapd, mld_addr);
5264 if (!sta)
5265 return NULL;
5266
5267 wpa_printf(MSG_DEBUG, "MLD: assoc: mld=" MACSTR ", link=" MACSTR,
5268 MAC2STR(mld_addr), MAC2STR(mgmt->sa));
5269
5270 return hostapd_ml_get_assoc_sta(hapd, sta, assoc_hapd);
5271}
5272#endif /* CONFIG_IEEE80211BE */
5273
5274
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005275static void handle_assoc(struct hostapd_data *hapd,
5276 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom74f70d42019-02-11 14:42:39 -08005277 int reassoc, int rssi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005278{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005279 u16 capab_info, listen_interval, seq_ctrl, fc;
Hai Shalomb755a2a2020-04-23 21:49:02 -07005280 int resp = WLAN_STATUS_SUCCESS;
Hai Shalom899fcc72020-10-19 14:38:18 -07005281 u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005282 const u8 *pos;
5283 int left, i;
5284 struct sta_info *sta;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005285 u8 *tmp = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005286#ifdef CONFIG_FILS
5287 int delay_assoc = 0;
5288#endif /* CONFIG_FILS */
Hai Shalomfdcde762020-04-02 11:19:20 -07005289 int omit_rsnxe = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005290 bool set_beacon = false;
Sunil Ravi72e01222024-03-09 01:25:43 +00005291 bool mld_addrs_not_translated = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005292
5293 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
5294 sizeof(mgmt->u.assoc_req))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005295 wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
5296 reassoc, (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005297 return;
5298 }
5299
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005300#ifdef CONFIG_TESTING_OPTIONS
5301 if (reassoc) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005302 if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005303 drand48() < hapd->iconf->ignore_reassoc_probability) {
5304 wpa_printf(MSG_INFO,
5305 "TESTING: ignoring reassoc request from "
5306 MACSTR, MAC2STR(mgmt->sa));
5307 return;
5308 }
5309 } else {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005310 if (hapd->iconf->ignore_assoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005311 drand48() < hapd->iconf->ignore_assoc_probability) {
5312 wpa_printf(MSG_INFO,
5313 "TESTING: ignoring assoc request from "
5314 MACSTR, MAC2STR(mgmt->sa));
5315 return;
5316 }
5317 }
5318#endif /* CONFIG_TESTING_OPTIONS */
5319
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005320 fc = le_to_host16(mgmt->frame_control);
5321 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
5322
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005323 if (reassoc) {
5324 capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
5325 listen_interval = le_to_host16(
5326 mgmt->u.reassoc_req.listen_interval);
5327 wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
5328 " capab_info=0x%02x listen_interval=%d current_ap="
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005329 MACSTR " seq_ctrl=0x%x%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005330 MAC2STR(mgmt->sa), capab_info, listen_interval,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005331 MAC2STR(mgmt->u.reassoc_req.current_ap),
5332 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005333 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
5334 pos = mgmt->u.reassoc_req.variable;
5335 } else {
5336 capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
5337 listen_interval = le_to_host16(
5338 mgmt->u.assoc_req.listen_interval);
5339 wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005340 " capab_info=0x%02x listen_interval=%d "
5341 "seq_ctrl=0x%x%s",
5342 MAC2STR(mgmt->sa), capab_info, listen_interval,
5343 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005344 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
5345 pos = mgmt->u.assoc_req.variable;
5346 }
5347
5348 sta = ap_get_sta(hapd, mgmt->sa);
Sunil Ravi72e01222024-03-09 01:25:43 +00005349
5350#ifdef CONFIG_IEEE80211BE
5351 /*
5352 * It is possible that the association frame is from an associated
5353 * non-AP MLD station, that tries to re-associate using different link
5354 * addresses. In such a case, try to find the station based on the AP
5355 * MLD MAC address.
5356 */
5357 if (!sta) {
5358 struct hostapd_data *assoc_hapd;
5359
5360 sta = handle_mlo_translate(hapd, mgmt, len, reassoc,
5361 &assoc_hapd);
5362 if (sta) {
5363 wpa_printf(MSG_DEBUG,
5364 "MLD: Switching to assoc hapd/station");
5365 hapd = assoc_hapd;
5366 mld_addrs_not_translated = true;
5367 }
5368 }
5369#endif /* CONFIG_IEEE80211BE */
5370
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005371#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005372 if (sta && sta->auth_alg == WLAN_AUTH_FT &&
5373 (sta->flags & WLAN_STA_AUTH) == 0) {
5374 wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
5375 "prior to authentication since it is using "
5376 "over-the-DS FT", MAC2STR(mgmt->sa));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005377
5378 /*
5379 * Mark station as authenticated, to avoid adding station
5380 * entry in the driver as associated and not authenticated
5381 */
5382 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005383 } else
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005384#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005385 if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
Dmitry Shmidt29333592017-01-09 12:27:11 -08005386 if (hapd->iface->current_mode &&
5387 hapd->iface->current_mode->mode ==
5388 HOSTAPD_MODE_IEEE80211AD) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005389 int acl_res;
Hai Shalomfdcde762020-04-02 11:19:20 -07005390 struct radius_sta info;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005391
Hai Shalomfdcde762020-04-02 11:19:20 -07005392 acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
5393 (const u8 *) mgmt,
5394 len, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005395 if (acl_res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005396 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5397 "Ignore Association Request frame from "
5398 MACSTR " due to ACL reject",
5399 MAC2STR(mgmt->sa));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005400 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5401 goto fail;
5402 }
5403 if (acl_res == HOSTAPD_ACL_PENDING)
5404 return;
5405
Dmitry Shmidt29333592017-01-09 12:27:11 -08005406 /* DMG/IEEE 802.11ad does not use authentication.
5407 * Allocate sta entry upon association. */
5408 sta = ap_sta_add(hapd, mgmt->sa);
5409 if (!sta) {
5410 hostapd_logger(hapd, mgmt->sa,
5411 HOSTAPD_MODULE_IEEE80211,
5412 HOSTAPD_LEVEL_INFO,
5413 "Failed to add STA");
5414 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5415 goto fail;
5416 }
5417
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005418 acl_res = ieee802_11_set_radius_info(
Hai Shalomfdcde762020-04-02 11:19:20 -07005419 hapd, sta, acl_res, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005420 if (acl_res) {
5421 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5422 goto fail;
5423 }
5424
Dmitry Shmidt29333592017-01-09 12:27:11 -08005425 hostapd_logger(hapd, sta->addr,
5426 HOSTAPD_MODULE_IEEE80211,
5427 HOSTAPD_LEVEL_DEBUG,
5428 "Skip authentication for DMG/IEEE 802.11ad");
5429 sta->flags |= WLAN_STA_AUTH;
5430 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
5431 sta->auth_alg = WLAN_AUTH_OPEN;
5432 } else {
5433 hostapd_logger(hapd, mgmt->sa,
5434 HOSTAPD_MODULE_IEEE80211,
5435 HOSTAPD_LEVEL_INFO,
5436 "Station tried to associate before authentication (aid=%d flags=0x%x)",
5437 sta ? sta->aid : -1,
5438 sta ? sta->flags : 0);
5439 send_deauth(hapd, mgmt->sa,
5440 WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
5441 return;
5442 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005443 }
5444
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005445 if ((fc & WLAN_FC_RETRY) &&
5446 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
5447 sta->last_seq_ctrl == seq_ctrl &&
Paul Stewart092955c2017-02-06 09:13:09 -08005448 sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5449 WLAN_FC_STYPE_ASSOC_REQ)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005450 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5451 HOSTAPD_LEVEL_DEBUG,
5452 "Drop repeated association frame seq_ctrl=0x%x",
5453 seq_ctrl);
5454 return;
5455 }
5456 sta->last_seq_ctrl = seq_ctrl;
5457 sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5458 WLAN_FC_STYPE_ASSOC_REQ;
5459
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005460 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005461 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005462 goto fail;
5463 }
5464
5465 if (listen_interval > hapd->conf->max_listen_interval) {
5466 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5467 HOSTAPD_LEVEL_DEBUG,
5468 "Too large Listen Interval (%d)",
5469 listen_interval);
5470 resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
5471 goto fail;
5472 }
5473
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005474#ifdef CONFIG_MBO
5475 if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
5476 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5477 goto fail;
5478 }
Hai Shalom74f70d42019-02-11 14:42:39 -08005479
5480 if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
5481 rssi < hapd->iconf->rssi_reject_assoc_rssi &&
5482 (sta->auth_rssi == 0 ||
5483 sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
5484 resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
5485 goto fail;
5486 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005487#endif /* CONFIG_MBO */
5488
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005489 if (hapd->conf->wpa && check_sa_query(hapd, sta, reassoc)) {
5490 resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
5491 goto fail;
5492 }
5493
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005494 /*
5495 * sta->capability is used in check_assoc_ies() for RRM enabled
5496 * capability element.
5497 */
5498 sta->capability = capab_info;
5499
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005500#ifdef CONFIG_FILS
5501 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5502 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5503 sta->auth_alg == WLAN_AUTH_FILS_PK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005504 int res;
5505
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005506 /* The end of the payload is encrypted. Need to decrypt it
5507 * before parsing. */
5508
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005509 tmp = os_memdup(pos, left);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005510 if (!tmp) {
5511 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5512 goto fail;
5513 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005514
Roshan Pius3a1667e2018-07-03 15:17:14 -07005515 res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
5516 len, tmp, left);
5517 if (res < 0) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005518 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5519 goto fail;
5520 }
5521 pos = tmp;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005522 left = res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005523 }
5524#endif /* CONFIG_FILS */
5525
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005526 /* followed by SSID and Supported rates; and HT capabilities if 802.11n
5527 * is used */
5528 resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
5529 if (resp != WLAN_STATUS_SUCCESS)
5530 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07005531 omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005532
5533 if (hostapd_get_aid(hapd, sta) < 0) {
5534 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5535 HOSTAPD_LEVEL_INFO, "No room for more AIDs");
5536 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5537 goto fail;
5538 }
5539
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005540 sta->listen_interval = listen_interval;
5541
Roshan Pius3a1667e2018-07-03 15:17:14 -07005542 if (hapd->iface->current_mode &&
5543 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005544 sta->flags |= WLAN_STA_NONERP;
5545 for (i = 0; i < sta->supported_rates_len; i++) {
5546 if ((sta->supported_rates[i] & 0x7f) > 22) {
5547 sta->flags &= ~WLAN_STA_NONERP;
5548 break;
5549 }
5550 }
5551 if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
5552 sta->nonerp_set = 1;
5553 hapd->iface->num_sta_non_erp++;
5554 if (hapd->iface->num_sta_non_erp == 1)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005555 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005556 }
5557
5558 if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
5559 !sta->no_short_slot_time_set) {
5560 sta->no_short_slot_time_set = 1;
5561 hapd->iface->num_sta_no_short_slot_time++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005562 if (hapd->iface->current_mode &&
5563 hapd->iface->current_mode->mode ==
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005564 HOSTAPD_MODE_IEEE80211G &&
5565 hapd->iface->num_sta_no_short_slot_time == 1)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005566 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005567 }
5568
5569 if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
5570 sta->flags |= WLAN_STA_SHORT_PREAMBLE;
5571 else
5572 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
5573
5574 if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
5575 !sta->no_short_preamble_set) {
5576 sta->no_short_preamble_set = 1;
5577 hapd->iface->num_sta_no_short_preamble++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005578 if (hapd->iface->current_mode &&
5579 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005580 && hapd->iface->num_sta_no_short_preamble == 1)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005581 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005582 }
5583
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005584 if (update_ht_state(hapd, sta) > 0)
5585 set_beacon = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005586
5587 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5588 HOSTAPD_LEVEL_DEBUG,
5589 "association OK (aid %d)", sta->aid);
5590 /* Station will be marked associated, after it acknowledges AssocResp
5591 */
5592 sta->flags |= WLAN_STA_ASSOC_REQ_OK;
5593
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005594 if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
5595 wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
5596 "SA Query procedure", reassoc ? "re" : "");
5597 /* TODO: Send a protected Disassociate frame to the STA using
5598 * the old key and Reason Code "Previous Authentication no
5599 * longer valid". Make sure this is only sent protected since
5600 * unprotected frame would be received by the STA that is now
5601 * trying to associate.
5602 */
5603 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005604
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005605 /* Make sure that the previously registered inactivity timer will not
5606 * remove the STA immediately. */
5607 sta->timeout_next = STA_NULLFUNC;
5608
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005609#ifdef CONFIG_TAXONOMY
5610 taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
5611#endif /* CONFIG_TAXONOMY */
5612
Dmitry Shmidt29333592017-01-09 12:27:11 -08005613 sta->pending_wds_enable = 0;
5614
Paul Stewart092955c2017-02-06 09:13:09 -08005615#ifdef CONFIG_FILS
5616 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5617 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005618 sta->auth_alg == WLAN_AUTH_FILS_PK) {
5619 if (fils_process_hlp(hapd, sta, pos, left) > 0)
5620 delay_assoc = 1;
5621 }
Paul Stewart092955c2017-02-06 09:13:09 -08005622#endif /* CONFIG_FILS */
5623
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005624 if (set_beacon)
5625 ieee802_11_set_beacons(hapd->iface);
5626
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005627 fail:
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005628
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005629 /*
5630 * In case of a successful response, add the station to the driver.
5631 * Otherwise, the kernel may ignore Data frames before we process the
5632 * ACK frame (TX status). In case of a failure, this station will be
5633 * removed.
5634 *
5635 * Note that this is not compliant with the IEEE 802.11 standard that
5636 * states that a non-AP station should transition into the
5637 * authenticated/associated state only after the station acknowledges
5638 * the (Re)Association Response frame. However, still do this as:
5639 *
5640 * 1. In case the station does not acknowledge the (Re)Association
5641 * Response frame, it will be removed.
5642 * 2. Data frames will be dropped in the kernel until the station is
5643 * set into authorized state, and there are no significant known
5644 * issues with processing other non-Data Class 3 frames during this
5645 * window.
5646 */
Sunil Ravi72e01222024-03-09 01:25:43 +00005647 if (sta)
5648 hostapd_process_assoc_ml_info(hapd, sta, pos, left, reassoc,
5649 resp, false);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005650
Hai Shalom74f70d42019-02-11 14:42:39 -08005651 if (resp == WLAN_STATUS_SUCCESS && sta &&
5652 add_associated_sta(hapd, sta, reassoc))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005653 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5654
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005655#ifdef CONFIG_FILS
Hai Shalom74f70d42019-02-11 14:42:39 -08005656 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
5657 eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
5658 sta->fils_pending_assoc_req) {
5659 /* Do not reschedule fils_hlp_timeout in case the station
5660 * retransmits (Re)Association Request frame while waiting for
5661 * the previously started FILS HLP wait, so that the timeout can
5662 * be determined from the first pending attempt. */
5663 wpa_printf(MSG_DEBUG,
5664 "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
5665 MACSTR, MAC2STR(sta->addr));
5666 os_free(tmp);
5667 return;
5668 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005669 if (sta) {
5670 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5671 os_free(sta->fils_pending_assoc_req);
5672 sta->fils_pending_assoc_req = NULL;
5673 sta->fils_pending_assoc_req_len = 0;
5674 wpabuf_free(sta->fils_hlp_resp);
5675 sta->fils_hlp_resp = NULL;
5676 }
5677 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
5678 sta->fils_pending_assoc_req = tmp;
5679 sta->fils_pending_assoc_req_len = left;
5680 sta->fils_pending_assoc_is_reassoc = reassoc;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005681 sta->fils_drv_assoc_finish = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005682 wpa_printf(MSG_DEBUG,
5683 "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
5684 MACSTR, MAC2STR(sta->addr));
5685 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5686 eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
5687 fils_hlp_timeout, hapd, sta);
5688 return;
5689 }
5690#endif /* CONFIG_FILS */
5691
Hai Shalomb755a2a2020-04-23 21:49:02 -07005692 if (resp >= 0)
Sunil Ravi72e01222024-03-09 01:25:43 +00005693 reply_res = send_assoc_resp(hapd,
5694 mld_addrs_not_translated ?
5695 NULL : sta,
5696 mgmt->sa, resp, reassoc,
5697 pos, left, rssi, omit_rsnxe,
5698 !mld_addrs_not_translated);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005699 os_free(tmp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005700
5701 /*
Hai Shalom899fcc72020-10-19 14:38:18 -07005702 * Remove the station in case transmission of a success response fails
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005703 * (the STA was added associated to the driver) or if the station was
5704 * previously added unassociated.
5705 */
Dmitry Shmidt29333592017-01-09 12:27:11 -08005706 if (sta && ((reply_res != WLAN_STATUS_SUCCESS &&
5707 resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005708 hostapd_drv_sta_remove(hapd, sta->addr);
5709 sta->added_unassoc = 0;
5710 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005711}
5712
5713
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005714static void hostapd_deauth_sta(struct hostapd_data *hapd,
5715 struct sta_info *sta,
5716 const struct ieee80211_mgmt *mgmt)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005717{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005718 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5719 "deauthentication: STA=" MACSTR " reason_code=%d",
5720 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005721
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005722 ap_sta_set_authorized(hapd, sta, 0);
5723 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
5724 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
5725 WLAN_STA_ASSOC_REQ_OK);
5726 hostapd_set_sta_flags(hapd, sta);
5727 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5728 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5729 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5730 mlme_deauthenticate_indication(
5731 hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
5732 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5733 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5734 ap_free_sta(hapd, sta);
5735}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005736
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005737
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005738static void hostapd_disassoc_sta(struct hostapd_data *hapd,
5739 struct sta_info *sta,
5740 const struct ieee80211_mgmt *mgmt)
5741{
5742 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5743 "disassocation: STA=" MACSTR " reason_code=%d",
5744 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005745
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005746 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005747 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005748 sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07005749 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005750 wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
5751 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5752 HOSTAPD_LEVEL_INFO, "disassociated");
5753 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5754 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5755 /* Stop Accounting and IEEE 802.1X sessions, but leave the STA
5756 * authenticated. */
5757 accounting_sta_stop(hapd, sta);
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005758 ieee802_1x_free_station(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005759 if (sta->ipaddr)
5760 hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
5761 ap_sta_ip6addr_del(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005762 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005763 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005764
5765 if (sta->timeout_next == STA_NULLFUNC ||
5766 sta->timeout_next == STA_DISASSOC) {
5767 sta->timeout_next = STA_DEAUTH;
5768 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
5769 eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
5770 hapd, sta);
5771 }
5772
5773 mlme_disassociate_indication(
5774 hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt29333592017-01-09 12:27:11 -08005775
5776 /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon
5777 * disassociation. */
5778 if (hapd->iface->current_mode &&
5779 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
5780 sta->flags &= ~WLAN_STA_AUTH;
5781 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5782 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5783 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5784 ap_free_sta(hapd, sta);
5785 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005786}
5787
5788
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005789static bool hostapd_ml_handle_disconnect(struct hostapd_data *hapd,
5790 struct sta_info *sta,
5791 const struct ieee80211_mgmt *mgmt,
5792 bool disassoc)
5793{
5794#ifdef CONFIG_IEEE80211BE
5795 struct hostapd_data *assoc_hapd, *tmp_hapd;
5796 struct sta_info *assoc_sta;
5797 unsigned int i, link_id;
5798
5799 if (!hostapd_is_mld_ap(hapd))
5800 return false;
5801
5802 /*
5803 * Get the station on which the association was performed, as it holds
5804 * the information about all the other links.
5805 */
5806 assoc_sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd);
Sunil Ravi72e01222024-03-09 01:25:43 +00005807 if (!assoc_sta)
5808 return false;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005809
5810 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
5811 for (i = 0; i < assoc_hapd->iface->interfaces->count; i++) {
5812 struct sta_info *tmp_sta;
5813
5814 if (!assoc_sta->mld_info.links[link_id].valid)
5815 continue;
5816
5817 tmp_hapd =
5818 assoc_hapd->iface->interfaces->iface[i]->bss[0];
5819
Sunil Raviaf399a82024-05-05 20:56:55 +00005820 if (!hostapd_is_ml_partner(assoc_hapd, tmp_hapd))
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005821 continue;
5822
5823 for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
5824 tmp_sta = tmp_sta->next) {
5825 /*
5826 * Remove the station on which the association
5827 * was done only after all other link stations
5828 * are removed. Since there is only a single
5829 * station per struct hostapd_hapd with the
5830 * same association link simply break out from
5831 * the loop.
5832 */
5833 if (tmp_sta == assoc_sta)
5834 break;
5835
5836 if (tmp_sta->mld_assoc_link_id !=
5837 assoc_sta->mld_assoc_link_id ||
5838 tmp_sta->aid != assoc_sta->aid)
5839 continue;
5840
5841 if (!disassoc)
5842 hostapd_deauth_sta(tmp_hapd, tmp_sta,
5843 mgmt);
5844 else
5845 hostapd_disassoc_sta(tmp_hapd, tmp_sta,
5846 mgmt);
5847 break;
5848 }
5849 }
5850 }
5851
5852 /* Remove the station on which the association was performed. */
5853 if (!disassoc)
5854 hostapd_deauth_sta(assoc_hapd, assoc_sta, mgmt);
5855 else
5856 hostapd_disassoc_sta(assoc_hapd, assoc_sta, mgmt);
5857
5858 return true;
5859#else /* CONFIG_IEEE80211BE */
5860 return false;
5861#endif /* CONFIG_IEEE80211BE */
5862}
5863
5864
5865static void handle_disassoc(struct hostapd_data *hapd,
5866 const struct ieee80211_mgmt *mgmt, size_t len)
5867{
5868 struct sta_info *sta;
5869
5870 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
5871 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5872 "handle_disassoc - too short payload (len=%lu)",
5873 (unsigned long) len);
5874 return;
5875 }
5876
5877 sta = ap_get_sta(hapd, mgmt->sa);
5878 if (!sta) {
5879 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
5880 " trying to disassociate, but it is not associated",
5881 MAC2STR(mgmt->sa));
5882 return;
5883 }
5884
5885 if (hostapd_ml_handle_disconnect(hapd, sta, mgmt, true))
5886 return;
5887
5888 hostapd_disassoc_sta(hapd, sta, mgmt);
5889}
5890
5891
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005892static void handle_deauth(struct hostapd_data *hapd,
5893 const struct ieee80211_mgmt *mgmt, size_t len)
5894{
5895 struct sta_info *sta;
5896
5897 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005898 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5899 "handle_deauth - too short payload (len=%lu)",
5900 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005901 return;
5902 }
5903
Hai Shaloma20dcd72022-02-04 13:43:00 -08005904 /* Clear the PTKSA cache entries for PASN */
5905 ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
5906
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005907 sta = ap_get_sta(hapd, mgmt->sa);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005908 if (!sta) {
5909 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
5910 " trying to deauthenticate, but it is not authenticated",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005911 MAC2STR(mgmt->sa));
5912 return;
5913 }
5914
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005915 if (hostapd_ml_handle_disconnect(hapd, sta, mgmt, false))
5916 return;
5917
5918 hostapd_deauth_sta(hapd, sta, mgmt);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005919}
5920
5921
5922static void handle_beacon(struct hostapd_data *hapd,
5923 const struct ieee80211_mgmt *mgmt, size_t len,
5924 struct hostapd_frame_info *fi)
5925{
5926 struct ieee802_11_elems elems;
5927
5928 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005929 wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
5930 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005931 return;
5932 }
5933
5934 (void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
5935 len - (IEEE80211_HDRLEN +
5936 sizeof(mgmt->u.beacon)), &elems,
5937 0);
5938
5939 ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
5940}
5941
5942
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005943static int robust_action_frame(u8 category)
5944{
5945 return category != WLAN_ACTION_PUBLIC &&
5946 category != WLAN_ACTION_HT;
5947}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005948
5949
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005950static int handle_action(struct hostapd_data *hapd,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005951 const struct ieee80211_mgmt *mgmt, size_t len,
5952 unsigned int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005953{
5954 struct sta_info *sta;
Hai Shalom74f70d42019-02-11 14:42:39 -08005955 u8 *action __maybe_unused;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005956
Hai Shalom74f70d42019-02-11 14:42:39 -08005957 if (len < IEEE80211_HDRLEN + 2 + 1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005958 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5959 HOSTAPD_LEVEL_DEBUG,
5960 "handle_action - too short payload (len=%lu)",
5961 (unsigned long) len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005962 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005963 }
5964
Hai Shalom74f70d42019-02-11 14:42:39 -08005965 action = (u8 *) &mgmt->u.action.u;
5966 wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
5967 " da " MACSTR " len %d freq %u",
5968 mgmt->u.action.category, *action,
5969 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
5970
5971 sta = ap_get_sta(hapd, mgmt->sa);
5972
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005973 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
5974 (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
5975 wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
5976 "frame (category=%u) from unassociated STA " MACSTR,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005977 mgmt->u.action.category, MAC2STR(mgmt->sa));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005978 return 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005979 }
5980
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005981 if (sta && (sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt18463232014-01-24 12:29:41 -08005982 !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
5983 robust_action_frame(mgmt->u.action.category)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005984 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5985 HOSTAPD_LEVEL_DEBUG,
5986 "Dropped unprotected Robust Action frame from "
5987 "an MFP STA");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005988 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005989 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005990
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005991 if (sta) {
5992 u16 fc = le_to_host16(mgmt->frame_control);
5993 u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
5994
5995 if ((fc & WLAN_FC_RETRY) &&
5996 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
5997 sta->last_seq_ctrl == seq_ctrl &&
5998 sta->last_subtype == WLAN_FC_STYPE_ACTION) {
5999 hostapd_logger(hapd, sta->addr,
6000 HOSTAPD_MODULE_IEEE80211,
6001 HOSTAPD_LEVEL_DEBUG,
6002 "Drop repeated action frame seq_ctrl=0x%x",
6003 seq_ctrl);
6004 return 1;
6005 }
6006
6007 sta->last_seq_ctrl = seq_ctrl;
6008 sta->last_subtype = WLAN_FC_STYPE_ACTION;
6009 }
6010
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006011 switch (mgmt->u.action.category) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006012#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006013 case WLAN_ACTION_FT:
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006014 if (!sta ||
6015 wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006016 len - IEEE80211_HDRLEN))
6017 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006018 return 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006019#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006020 case WLAN_ACTION_WMM:
6021 hostapd_wmm_action(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006022 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006023 case WLAN_ACTION_SA_QUERY:
Hai Shalom021b0b52019-04-10 11:17:58 -07006024 ieee802_11_sa_query_action(hapd, mgmt, len);
6025 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006026#ifdef CONFIG_WNM_AP
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006027 case WLAN_ACTION_WNM:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006028 ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
6029 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006030#endif /* CONFIG_WNM_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006031#ifdef CONFIG_FST
6032 case WLAN_ACTION_FST:
6033 if (hapd->iface->fst)
6034 fst_rx_action(hapd->iface->fst, mgmt, len);
6035 else
6036 wpa_printf(MSG_DEBUG,
6037 "FST: Ignore FST Action frame - no FST attached");
6038 return 1;
6039#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006040 case WLAN_ACTION_PUBLIC:
Dmitry Shmidt18463232014-01-24 12:29:41 -08006041 case WLAN_ACTION_PROTECTED_DUAL:
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07006042 if (len >= IEEE80211_HDRLEN + 2 &&
6043 mgmt->u.action.u.public_action.action ==
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006044 WLAN_PA_20_40_BSS_COEX) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006045 hostapd_2040_coex_action(hapd, mgmt, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006046 return 1;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006047 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006048#ifdef CONFIG_DPP
6049 if (len >= IEEE80211_HDRLEN + 6 &&
6050 mgmt->u.action.u.vs_public_action.action ==
6051 WLAN_PA_VENDOR_SPECIFIC &&
6052 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6053 OUI_WFA &&
6054 mgmt->u.action.u.vs_public_action.variable[0] ==
6055 DPP_OUI_TYPE) {
6056 const u8 *pos, *end;
6057
6058 pos = mgmt->u.action.u.vs_public_action.oui;
6059 end = ((const u8 *) mgmt) + len;
6060 hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006061 freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006062 return 1;
6063 }
6064 if (len >= IEEE80211_HDRLEN + 2 &&
6065 (mgmt->u.action.u.public_action.action ==
6066 WLAN_PA_GAS_INITIAL_RESP ||
6067 mgmt->u.action.u.public_action.action ==
6068 WLAN_PA_GAS_COMEBACK_RESP)) {
6069 const u8 *pos, *end;
6070
6071 pos = &mgmt->u.action.u.public_action.action;
6072 end = ((const u8 *) mgmt) + len;
Sunil Ravi036cec52023-03-29 11:35:17 -07006073 if (gas_query_ap_rx(hapd->gas, mgmt->sa,
6074 mgmt->u.action.category,
6075 pos, end - pos, freq) == 0)
6076 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006077 }
6078#endif /* CONFIG_DPP */
Sunil Ravi72e01222024-03-09 01:25:43 +00006079#ifdef CONFIG_NAN_USD
6080 if (mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6081 len >= IEEE80211_HDRLEN + 5 &&
6082 mgmt->u.action.u.vs_public_action.action ==
6083 WLAN_PA_VENDOR_SPECIFIC &&
6084 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6085 OUI_WFA &&
6086 mgmt->u.action.u.vs_public_action.variable[0] ==
6087 NAN_OUI_TYPE) {
6088 const u8 *pos, *end;
6089
6090 pos = mgmt->u.action.u.vs_public_action.variable;
6091 end = ((const u8 *) mgmt) + len;
6092 pos++;
6093 hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, freq,
6094 pos, end - pos);
6095 return 1;
6096 }
6097#endif /* CONFIG_NAN_USD */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006098 if (hapd->public_action_cb) {
6099 hapd->public_action_cb(hapd->public_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006100 (u8 *) mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006101 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006102 if (hapd->public_action_cb2) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -08006103 hapd->public_action_cb2(hapd->public_action_cb2_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006104 (u8 *) mgmt, len, freq);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006105 }
6106 if (hapd->public_action_cb || hapd->public_action_cb2)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006107 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006108 break;
6109 case WLAN_ACTION_VENDOR_SPECIFIC:
6110 if (hapd->vendor_action_cb) {
6111 if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006112 (u8 *) mgmt, len, freq) == 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006113 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006114 }
6115 break;
Sunil Ravi72e01222024-03-09 01:25:43 +00006116#ifndef CONFIG_NO_RRM
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006117 case WLAN_ACTION_RADIO_MEASUREMENT:
6118 hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
6119 return 1;
Sunil Ravi72e01222024-03-09 01:25:43 +00006120#endif /* CONFIG_NO_RRM */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006121 }
6122
6123 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6124 HOSTAPD_LEVEL_DEBUG,
6125 "handle_action - unknown action category %d or invalid "
6126 "frame",
6127 mgmt->u.action.category);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006128 if (!is_multicast_ether_addr(mgmt->da) &&
6129 !(mgmt->u.action.category & 0x80) &&
6130 !is_multicast_ether_addr(mgmt->sa)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006131 struct ieee80211_mgmt *resp;
6132
6133 /*
6134 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
6135 * Return the Action frame to the source without change
6136 * except that MSB of the Category set to 1.
6137 */
6138 wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
6139 "frame back to sender");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006140 resp = os_memdup(mgmt, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006141 if (resp == NULL)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006142 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006143 os_memcpy(resp->da, resp->sa, ETH_ALEN);
6144 os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
6145 os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
6146 resp->u.action.category |= 0x80;
6147
Hai Shalomfdcde762020-04-02 11:19:20 -07006148 if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006149 wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
6150 "Action frame");
6151 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006152 os_free(resp);
6153 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006154
6155 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006156}
6157
6158
6159/**
Hai Shalom60840252021-02-19 19:02:11 -08006160 * notify_mgmt_frame - Notify of Management frames on the control interface
6161 * @hapd: hostapd BSS data structure (the BSS to which the Management frame was
6162 * sent to)
6163 * @buf: Management frame data (starting from the IEEE 802.11 header)
6164 * @len: Length of frame data in octets
6165 *
6166 * Notify the control interface of any received Management frame.
6167 */
6168static void notify_mgmt_frame(struct hostapd_data *hapd, const u8 *buf,
6169 size_t len)
6170{
6171
6172 int hex_len = len * 2 + 1;
6173 char *hex = os_malloc(hex_len);
6174
6175 if (hex) {
6176 wpa_snprintf_hex(hex, hex_len, buf, len);
6177 wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO,
6178 AP_MGMT_FRAME_RECEIVED "buf=%s", hex);
6179 os_free(hex);
6180 }
6181}
6182
6183
6184/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006185 * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
6186 * @hapd: hostapd BSS data structure (the BSS to which the management frame was
6187 * sent to)
6188 * @buf: management frame data (starting from IEEE 802.11 header)
6189 * @len: length of frame data in octets
6190 * @fi: meta data about received frame (signal level, etc.)
6191 *
6192 * Process all incoming IEEE 802.11 management frames. This will be called for
6193 * each frame received from the kernel driver through wlan#ap interface. In
6194 * addition, it can be called to re-inserted pending frames (e.g., when using
6195 * external RADIUS server as an MAC ACL).
6196 */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006197int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
6198 struct hostapd_frame_info *fi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006199{
6200 struct ieee80211_mgmt *mgmt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006201 u16 fc, stype;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006202 int ret = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006203 unsigned int freq;
6204 int ssi_signal = fi ? fi->ssi_signal : 0;
Sunil Ravi72e01222024-03-09 01:25:43 +00006205#ifdef CONFIG_NAN_USD
6206 static const u8 nan_network_id[ETH_ALEN] =
6207 { 0x51, 0x6f, 0x9a, 0x01, 0x00, 0x00 };
6208#endif /* CONFIG_NAN_USD */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006209
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006210 if (len < 24)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006211 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006212
Roshan Pius3a1667e2018-07-03 15:17:14 -07006213 if (fi && fi->freq)
6214 freq = fi->freq;
6215 else
6216 freq = hapd->iface->freq;
6217
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006218 mgmt = (struct ieee80211_mgmt *) buf;
6219 fc = le_to_host16(mgmt->frame_control);
6220 stype = WLAN_FC_GET_STYPE(fc);
6221
Hai Shalomc3565922019-10-28 11:58:20 -07006222 if (is_multicast_ether_addr(mgmt->sa) ||
6223 is_zero_ether_addr(mgmt->sa) ||
Sunil Ravi72e01222024-03-09 01:25:43 +00006224 ether_addr_equal(mgmt->sa, hapd->own_addr)) {
Hai Shalomc3565922019-10-28 11:58:20 -07006225 /* Do not process any frames with unexpected/invalid SA so that
6226 * we do not add any state for unexpected STA addresses or end
6227 * up sending out frames to unexpected destination. */
6228 wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
6229 " in received frame - ignore this frame silently",
6230 MAC2STR(mgmt->sa));
6231 return 0;
6232 }
6233
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006234 if (stype == WLAN_FC_STYPE_BEACON) {
6235 handle_beacon(hapd, mgmt, len, fi);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006236 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006237 }
6238
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07006239 if (!is_broadcast_ether_addr(mgmt->bssid) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006240#ifdef CONFIG_P2P
6241 /* Invitation responses can be sent with the peer MAC as BSSID */
6242 !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
6243 stype == WLAN_FC_STYPE_ACTION) &&
6244#endif /* CONFIG_P2P */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006245#ifdef CONFIG_MESH
6246 !(hapd->conf->mesh & MESH_ENABLED) &&
6247#endif /* CONFIG_MESH */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006248#ifdef CONFIG_IEEE80211BE
6249 !(hapd->conf->mld_ap &&
Sunil Raviaf399a82024-05-05 20:56:55 +00006250 ether_addr_equal(hapd->mld->mld_addr, mgmt->bssid)) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006251#endif /* CONFIG_IEEE80211BE */
Sunil Ravi72e01222024-03-09 01:25:43 +00006252 !ether_addr_equal(mgmt->bssid, hapd->own_addr)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006253 wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
6254 MAC2STR(mgmt->bssid));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006255 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006256 }
6257
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006258 if (hapd->iface->state != HAPD_IFACE_ENABLED) {
6259 wpa_printf(MSG_DEBUG, "MGMT: Ignore management frame while interface is not enabled (SA=" MACSTR " DA=" MACSTR " subtype=%u)",
6260 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), stype);
6261 return 1;
6262 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006263
6264 if (stype == WLAN_FC_STYPE_PROBE_REQ) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006265 handle_probe_req(hapd, mgmt, len, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006266 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006267 }
6268
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006269 if ((!is_broadcast_ether_addr(mgmt->da) ||
6270 stype != WLAN_FC_STYPE_ACTION) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006271#ifdef CONFIG_IEEE80211BE
6272 !(hapd->conf->mld_ap &&
Sunil Raviaf399a82024-05-05 20:56:55 +00006273 ether_addr_equal(hapd->mld->mld_addr, mgmt->bssid)) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006274#endif /* CONFIG_IEEE80211BE */
Sunil Ravi72e01222024-03-09 01:25:43 +00006275#ifdef CONFIG_NAN_USD
6276 !ether_addr_equal(mgmt->da, nan_network_id) &&
6277#endif /* CONFIG_NAN_USD */
6278 !ether_addr_equal(mgmt->da, hapd->own_addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006279 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6280 HOSTAPD_LEVEL_DEBUG,
6281 "MGMT: DA=" MACSTR " not our address",
6282 MAC2STR(mgmt->da));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006283 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006284 }
6285
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006286 if (hapd->iconf->track_sta_max_num)
Roshan Pius3a1667e2018-07-03 15:17:14 -07006287 sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006288
Hai Shalom60840252021-02-19 19:02:11 -08006289 if (hapd->conf->notify_mgmt_frames)
6290 notify_mgmt_frame(hapd, buf, len);
6291
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006292 switch (stype) {
6293 case WLAN_FC_STYPE_AUTH:
6294 wpa_printf(MSG_DEBUG, "mgmt::auth");
Hai Shalom021b0b52019-04-10 11:17:58 -07006295 handle_auth(hapd, mgmt, len, ssi_signal, 0);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006296 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006297 break;
6298 case WLAN_FC_STYPE_ASSOC_REQ:
6299 wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006300 handle_assoc(hapd, mgmt, len, 0, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006301 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006302 break;
6303 case WLAN_FC_STYPE_REASSOC_REQ:
6304 wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006305 handle_assoc(hapd, mgmt, len, 1, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006306 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006307 break;
6308 case WLAN_FC_STYPE_DISASSOC:
6309 wpa_printf(MSG_DEBUG, "mgmt::disassoc");
6310 handle_disassoc(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006311 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006312 break;
6313 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006314 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006315 handle_deauth(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006316 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006317 break;
6318 case WLAN_FC_STYPE_ACTION:
6319 wpa_printf(MSG_DEBUG, "mgmt::action");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006320 ret = handle_action(hapd, mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006321 break;
6322 default:
6323 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6324 HOSTAPD_LEVEL_DEBUG,
6325 "unknown mgmt frame subtype %d", stype);
6326 break;
6327 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006328
6329 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006330}
6331
6332
6333static void handle_auth_cb(struct hostapd_data *hapd,
6334 const struct ieee80211_mgmt *mgmt,
6335 size_t len, int ok)
6336{
6337 u16 auth_alg, auth_transaction, status_code;
6338 struct sta_info *sta;
Hai Shalom60840252021-02-19 19:02:11 -08006339 bool success_status;
Hai Shalome5e28bb2019-01-28 14:51:04 -08006340
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006341 sta = ap_get_sta(hapd, mgmt->da);
6342 if (!sta) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006343 wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
6344 " not found",
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006345 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006346 return;
6347 }
6348
Hai Shalom60840252021-02-19 19:02:11 -08006349 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
6350 wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
6351 (unsigned long) len);
6352 auth_alg = 0;
6353 auth_transaction = 0;
6354 status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
6355 goto fail;
6356 }
6357
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006358 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
6359 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
6360 status_code = le_to_host16(mgmt->u.auth.status_code);
6361
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006362 if (!ok) {
6363 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6364 HOSTAPD_LEVEL_NOTICE,
6365 "did not acknowledge authentication response");
6366 goto fail;
6367 }
6368
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006369 if (status_code == WLAN_STATUS_SUCCESS &&
6370 ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
6371 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
6372 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6373 HOSTAPD_LEVEL_INFO, "authenticated");
6374 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006375 if (sta->added_unassoc)
6376 hostapd_set_sta_flags(hapd, sta);
6377 return;
6378 }
6379
6380fail:
Hai Shalom60840252021-02-19 19:02:11 -08006381 success_status = status_code == WLAN_STATUS_SUCCESS;
6382#ifdef CONFIG_SAE
6383 if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1)
6384 success_status = sae_status_success(hapd, status_code);
6385#endif /* CONFIG_SAE */
6386 if (!success_status && sta->added_unassoc) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006387 hostapd_drv_sta_remove(hapd, sta->addr);
6388 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006389 }
6390}
6391
6392
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006393static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
6394 struct sta_info *sta,
6395 char *ifname_wds)
6396{
Hai Shalomfdcde762020-04-02 11:19:20 -07006397#ifdef CONFIG_WEP
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006398 int i;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07006399 struct hostapd_ssid *ssid = &hapd->conf->ssid;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006400
6401 if (hapd->conf->ieee802_1x || hapd->conf->wpa)
6402 return;
6403
6404 for (i = 0; i < 4; i++) {
6405 if (ssid->wep.key[i] &&
6406 hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
Hai Shalomfdcde762020-04-02 11:19:20 -07006407 0, i == ssid->wep.idx, NULL, 0,
6408 ssid->wep.key[i], ssid->wep.len[i],
6409 i == ssid->wep.idx ?
6410 KEY_FLAG_GROUP_RX_TX_DEFAULT :
6411 KEY_FLAG_GROUP_RX_TX)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006412 wpa_printf(MSG_WARNING,
6413 "Could not set WEP keys for WDS interface; %s",
6414 ifname_wds);
6415 break;
6416 }
6417 }
Hai Shalomfdcde762020-04-02 11:19:20 -07006418#endif /* CONFIG_WEP */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006419}
6420
6421
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006422#ifdef CONFIG_IEEE80211BE
6423static void ieee80211_ml_link_sta_assoc_cb(struct hostapd_data *hapd,
6424 struct sta_info *sta,
6425 struct mld_link_info *link,
6426 bool ok)
6427{
Sunil Ravi72e01222024-03-09 01:25:43 +00006428 bool updated = false;
6429
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006430 if (!ok) {
6431 hostapd_logger(hapd, link->peer_addr, HOSTAPD_MODULE_IEEE80211,
6432 HOSTAPD_LEVEL_DEBUG,
6433 "did not acknowledge association response");
6434 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
6435
6436 /* The STA is added only in case of SUCCESS */
6437 if (link->status == WLAN_STATUS_SUCCESS)
6438 hostapd_drv_sta_remove(hapd, sta->addr);
6439
6440 return;
6441 }
6442
6443 if (link->status != WLAN_STATUS_SUCCESS)
6444 return;
6445
6446 sta->flags |= WLAN_STA_ASSOC;
6447 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
6448
6449 if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
Sunil Ravi72e01222024-03-09 01:25:43 +00006450 updated = ap_sta_set_authorized_flag(hapd, sta, 1);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006451
6452 hostapd_set_sta_flags(hapd, sta);
Sunil Ravi72e01222024-03-09 01:25:43 +00006453 if (updated)
6454 ap_sta_set_authorized_event(hapd, sta, 1);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006455
6456 /*
6457 * TODOs:
6458 * - IEEE 802.1X port enablement is not needed as done on the station
6459 * doing the connection.
6460 * - Not handling accounting
6461 * - Need to handle VLAN configuration
6462 */
6463}
6464#endif /* CONFIG_IEEE80211BE */
6465
6466
6467static void hostapd_ml_handle_assoc_cb(struct hostapd_data *hapd,
6468 struct sta_info *sta, bool ok)
6469{
6470#ifdef CONFIG_IEEE80211BE
6471 unsigned int i, link_id;
6472
6473 if (!hostapd_is_mld_ap(hapd))
6474 return;
6475
6476 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
6477 struct mld_link_info *link = &sta->mld_info.links[link_id];
6478
6479 if (!link->valid)
6480 continue;
6481
6482 for (i = 0; i < hapd->iface->interfaces->count; i++) {
6483 struct sta_info *tmp_sta;
6484 struct hostapd_data *tmp_hapd =
6485 hapd->iface->interfaces->iface[i]->bss[0];
6486
Sunil Raviaf399a82024-05-05 20:56:55 +00006487 if (!hostapd_is_ml_partner(tmp_hapd, hapd))
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006488 continue;
6489
6490 for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
6491 tmp_sta = tmp_sta->next) {
6492 if (tmp_sta == sta ||
6493 tmp_sta->mld_assoc_link_id !=
6494 sta->mld_assoc_link_id ||
6495 tmp_sta->aid != sta->aid)
6496 continue;
6497
6498 ieee80211_ml_link_sta_assoc_cb(tmp_hapd,
6499 tmp_sta, link,
6500 ok);
6501 break;
6502 }
6503 }
6504 }
6505#endif /* CONFIG_IEEE80211BE */
6506}
6507
6508
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006509static void handle_assoc_cb(struct hostapd_data *hapd,
6510 const struct ieee80211_mgmt *mgmt,
6511 size_t len, int reassoc, int ok)
6512{
6513 u16 status;
6514 struct sta_info *sta;
6515 int new_assoc = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006516
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006517 sta = ap_get_sta(hapd, mgmt->da);
6518 if (!sta) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006519 wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
6520 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006521 return;
6522 }
6523
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006524#ifdef CONFIG_IEEE80211BE
Sunil Ravi72e01222024-03-09 01:25:43 +00006525 if (ap_sta_is_mld(hapd, sta) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006526 hapd->mld_link_id != sta->mld_assoc_link_id) {
6527 /* See ieee80211_ml_link_sta_assoc_cb() for the MLD case */
6528 wpa_printf(MSG_DEBUG,
6529 "%s: MLD: ignore on link station (%d != %d)",
6530 __func__, hapd->mld_link_id, sta->mld_assoc_link_id);
6531 return;
6532 }
6533#endif /* CONFIG_IEEE80211BE */
6534
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006535 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
6536 sizeof(mgmt->u.assoc_resp))) {
6537 wpa_printf(MSG_INFO,
6538 "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
6539 reassoc, (unsigned long) len);
6540 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006541 return;
6542 }
6543
6544 if (reassoc)
6545 status = le_to_host16(mgmt->u.reassoc_resp.status_code);
6546 else
6547 status = le_to_host16(mgmt->u.assoc_resp.status_code);
6548
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006549 if (!ok) {
6550 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6551 HOSTAPD_LEVEL_DEBUG,
6552 "did not acknowledge association response");
6553 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
6554 /* The STA is added only in case of SUCCESS */
6555 if (status == WLAN_STATUS_SUCCESS)
6556 hostapd_drv_sta_remove(hapd, sta->addr);
6557
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006558 goto handle_ml;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006559 }
6560
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006561 if (status != WLAN_STATUS_SUCCESS)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006562 goto handle_ml;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006563
6564 /* Stop previous accounting session, if one is started, and allocate
6565 * new session id for the new session. */
6566 accounting_sta_stop(hapd, sta);
6567
6568 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6569 HOSTAPD_LEVEL_INFO,
6570 "associated (aid %d)",
6571 sta->aid);
6572
6573 if (sta->flags & WLAN_STA_ASSOC)
6574 new_assoc = 0;
6575 sta->flags |= WLAN_STA_ASSOC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006576 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006577 if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
6578 !hapd->conf->osen) ||
6579 sta->auth_alg == WLAN_AUTH_FILS_SK ||
6580 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6581 sta->auth_alg == WLAN_AUTH_FILS_PK ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006582 sta->auth_alg == WLAN_AUTH_FT) {
6583 /*
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006584 * Open, static WEP, FT protocol, or FILS; no separate
6585 * authorization step.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006586 */
6587 ap_sta_set_authorized(hapd, sta, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006588 }
6589
6590 if (reassoc)
6591 mlme_reassociate_indication(hapd, sta);
6592 else
6593 mlme_associate_indication(hapd, sta);
6594
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006595 sta->sa_query_timed_out = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006596
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006597 if (sta->eapol_sm == NULL) {
6598 /*
6599 * This STA does not use RADIUS server for EAP authentication,
6600 * so bind it to the selected VLAN interface now, since the
6601 * interface selection is not going to change anymore.
6602 */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006603 if (ap_sta_bind_vlan(hapd, sta) < 0)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006604 goto handle_ml;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006605 } else if (sta->vlan_id) {
6606 /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006607 if (ap_sta_bind_vlan(hapd, sta) < 0)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006608 goto handle_ml;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006609 }
6610
6611 hostapd_set_sta_flags(hapd, sta);
6612
Dmitry Shmidt29333592017-01-09 12:27:11 -08006613 if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) {
6614 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA "
6615 MACSTR " based on pending request",
6616 MAC2STR(sta->addr));
6617 sta->pending_wds_enable = 0;
6618 sta->flags |= WLAN_STA_WDS;
6619 }
6620
Sunil Ravi640215c2023-06-28 23:08:09 +00006621 /* WPS not supported on backhaul BSS. Disable 4addr mode on fronthaul */
6622 if ((sta->flags & WLAN_STA_WDS) ||
6623 (sta->flags & WLAN_STA_MULTI_AP &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006624 (hapd->conf->multi_ap & BACKHAUL_BSS) &&
Sunil Ravi640215c2023-06-28 23:08:09 +00006625 !(sta->flags & WLAN_STA_WPS))) {
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08006626 int ret;
6627 char ifname_wds[IFNAMSIZ + 1];
6628
6629 wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA "
6630 MACSTR " (aid %u)",
6631 MAC2STR(sta->addr), sta->aid);
6632 ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
6633 sta->aid, 1);
6634 if (!ret)
6635 hostapd_set_wds_encryption(hapd, sta, ifname_wds);
6636 }
6637
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006638 if (sta->auth_alg == WLAN_AUTH_FT)
6639 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
6640 else
6641 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
6642 hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006643 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006644
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006645#ifdef CONFIG_FILS
6646 if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
6647 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6648 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
6649 fils_set_tk(sta->wpa_sm) < 0) {
6650 wpa_printf(MSG_DEBUG, "FILS: TK configuration failed");
6651 ap_sta_disconnect(hapd, sta, sta->addr,
6652 WLAN_REASON_UNSPECIFIED);
6653 return;
6654 }
6655#endif /* CONFIG_FILS */
6656
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006657 if (sta->pending_eapol_rx) {
6658 struct os_reltime now, age;
6659
6660 os_get_reltime(&now);
6661 os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
6662 if (age.sec == 0 && age.usec < 200000) {
6663 wpa_printf(MSG_DEBUG,
6664 "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
6665 MAC2STR(sta->addr));
6666 ieee802_1x_receive(
6667 hapd, mgmt->da,
6668 wpabuf_head(sta->pending_eapol_rx->buf),
Sunil8cd6f4d2022-06-28 18:40:46 +00006669 wpabuf_len(sta->pending_eapol_rx->buf),
6670 sta->pending_eapol_rx->encrypted);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006671 }
6672 wpabuf_free(sta->pending_eapol_rx->buf);
6673 os_free(sta->pending_eapol_rx);
6674 sta->pending_eapol_rx = NULL;
6675 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006676
6677handle_ml:
6678 hostapd_ml_handle_assoc_cb(hapd, sta, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006679}
6680
6681
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006682static void handle_deauth_cb(struct hostapd_data *hapd,
6683 const struct ieee80211_mgmt *mgmt,
6684 size_t len, int ok)
6685{
6686 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006687 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006688 return;
6689 sta = ap_get_sta(hapd, mgmt->da);
6690 if (!sta) {
6691 wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
6692 " not found", MAC2STR(mgmt->da));
6693 return;
6694 }
6695 if (ok)
6696 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
6697 MAC2STR(sta->addr));
6698 else
6699 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6700 "deauth", MAC2STR(sta->addr));
6701
6702 ap_sta_deauth_cb(hapd, sta);
6703}
6704
6705
6706static void handle_disassoc_cb(struct hostapd_data *hapd,
6707 const struct ieee80211_mgmt *mgmt,
6708 size_t len, int ok)
6709{
6710 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006711 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006712 return;
6713 sta = ap_get_sta(hapd, mgmt->da);
6714 if (!sta) {
6715 wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
6716 " not found", MAC2STR(mgmt->da));
6717 return;
6718 }
6719 if (ok)
6720 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
6721 MAC2STR(sta->addr));
6722 else
6723 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6724 "disassoc", MAC2STR(sta->addr));
6725
6726 ap_sta_disassoc_cb(hapd, sta);
6727}
6728
6729
Dmitry Shmidt29333592017-01-09 12:27:11 -08006730static void handle_action_cb(struct hostapd_data *hapd,
6731 const struct ieee80211_mgmt *mgmt,
6732 size_t len, int ok)
6733{
6734 struct sta_info *sta;
Sunil Ravi72e01222024-03-09 01:25:43 +00006735#ifndef CONFIG_NO_RRM
Paul Stewart092955c2017-02-06 09:13:09 -08006736 const struct rrm_measurement_report_element *report;
Sunil Ravi72e01222024-03-09 01:25:43 +00006737#endif /* CONFIG_NO_RRM */
Dmitry Shmidt29333592017-01-09 12:27:11 -08006738
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006739#ifdef CONFIG_DPP
6740 if (len >= IEEE80211_HDRLEN + 6 &&
6741 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6742 mgmt->u.action.u.vs_public_action.action ==
6743 WLAN_PA_VENDOR_SPECIFIC &&
6744 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6745 OUI_WFA &&
6746 mgmt->u.action.u.vs_public_action.variable[0] ==
6747 DPP_OUI_TYPE) {
6748 const u8 *pos, *end;
6749
6750 pos = &mgmt->u.action.u.vs_public_action.variable[1];
6751 end = ((const u8 *) mgmt) + len;
6752 hostapd_dpp_tx_status(hapd, mgmt->da, pos, end - pos, ok);
6753 return;
6754 }
6755 if (len >= IEEE80211_HDRLEN + 2 &&
6756 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6757 (mgmt->u.action.u.public_action.action ==
6758 WLAN_PA_GAS_INITIAL_REQ ||
6759 mgmt->u.action.u.public_action.action ==
6760 WLAN_PA_GAS_COMEBACK_REQ)) {
6761 const u8 *pos, *end;
6762
6763 pos = mgmt->u.action.u.public_action.variable;
6764 end = ((const u8 *) mgmt) + len;
6765 gas_query_ap_tx_status(hapd->gas, mgmt->da, pos, end - pos, ok);
6766 return;
6767 }
6768#endif /* CONFIG_DPP */
Hai Shaloma20dcd72022-02-04 13:43:00 -08006769 if (is_multicast_ether_addr(mgmt->da))
6770 return;
Dmitry Shmidt29333592017-01-09 12:27:11 -08006771 sta = ap_get_sta(hapd, mgmt->da);
6772 if (!sta) {
6773 wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR
6774 " not found", MAC2STR(mgmt->da));
6775 return;
6776 }
6777
Sunil Ravi77d572f2023-01-17 23:58:31 +00006778#ifdef CONFIG_HS20
6779 if (ok && len >= IEEE80211_HDRLEN + 2 &&
6780 mgmt->u.action.category == WLAN_ACTION_WNM &&
6781 mgmt->u.action.u.vs_public_action.action == WNM_NOTIFICATION_REQ &&
6782 sta->hs20_deauth_on_ack) {
6783 wpa_printf(MSG_DEBUG, "HS 2.0: Deauthenticate STA " MACSTR
6784 " on acknowledging the WNM-Notification",
6785 MAC2STR(sta->addr));
6786 ap_sta_session_timeout(hapd, sta, 0);
6787 return;
6788 }
6789#endif /* CONFIG_HS20 */
6790
Sunil Ravi72e01222024-03-09 01:25:43 +00006791#ifndef CONFIG_NO_RRM
Paul Stewart092955c2017-02-06 09:13:09 -08006792 if (len < 24 + 5 + sizeof(*report))
Dmitry Shmidt29333592017-01-09 12:27:11 -08006793 return;
Paul Stewart092955c2017-02-06 09:13:09 -08006794 report = (const struct rrm_measurement_report_element *)
6795 &mgmt->u.action.u.rrm.variable[2];
Dmitry Shmidt29333592017-01-09 12:27:11 -08006796 if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT &&
Paul Stewart092955c2017-02-06 09:13:09 -08006797 mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST &&
6798 report->eid == WLAN_EID_MEASURE_REQUEST &&
6799 report->len >= 3 &&
6800 report->type == MEASURE_TYPE_BEACON)
Dmitry Shmidt29333592017-01-09 12:27:11 -08006801 hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok);
Sunil Ravi72e01222024-03-09 01:25:43 +00006802#endif /* CONFIG_NO_RRM */
Dmitry Shmidt29333592017-01-09 12:27:11 -08006803}
6804
6805
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006806/**
6807 * ieee802_11_mgmt_cb - Process management frame TX status callback
6808 * @hapd: hostapd BSS data structure (the BSS from which the management frame
6809 * was sent from)
6810 * @buf: management frame data (starting from IEEE 802.11 header)
6811 * @len: length of frame data in octets
6812 * @stype: management frame subtype from frame control field
6813 * @ok: Whether the frame was ACK'ed
6814 */
6815void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
6816 u16 stype, int ok)
6817{
6818 const struct ieee80211_mgmt *mgmt;
6819 mgmt = (const struct ieee80211_mgmt *) buf;
6820
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006821#ifdef CONFIG_TESTING_OPTIONS
6822 if (hapd->ext_mgmt_frame_handling) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006823 size_t hex_len = 2 * len + 1;
6824 char *hex = os_malloc(hex_len);
6825
6826 if (hex) {
6827 wpa_snprintf_hex(hex, hex_len, buf, len);
6828 wpa_msg(hapd->msg_ctx, MSG_INFO,
6829 "MGMT-TX-STATUS stype=%u ok=%d buf=%s",
6830 stype, ok, hex);
6831 os_free(hex);
6832 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006833 return;
6834 }
6835#endif /* CONFIG_TESTING_OPTIONS */
6836
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006837 switch (stype) {
6838 case WLAN_FC_STYPE_AUTH:
6839 wpa_printf(MSG_DEBUG, "mgmt::auth cb");
6840 handle_auth_cb(hapd, mgmt, len, ok);
6841 break;
6842 case WLAN_FC_STYPE_ASSOC_RESP:
6843 wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
6844 handle_assoc_cb(hapd, mgmt, len, 0, ok);
6845 break;
6846 case WLAN_FC_STYPE_REASSOC_RESP:
6847 wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
6848 handle_assoc_cb(hapd, mgmt, len, 1, ok);
6849 break;
6850 case WLAN_FC_STYPE_PROBE_RESP:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006851 wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006852 break;
6853 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006854 wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
6855 handle_deauth_cb(hapd, mgmt, len, ok);
6856 break;
6857 case WLAN_FC_STYPE_DISASSOC:
6858 wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
6859 handle_disassoc_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006860 break;
6861 case WLAN_FC_STYPE_ACTION:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006862 wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006863 handle_action_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006864 break;
6865 default:
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006866 wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006867 break;
6868 }
6869}
6870
6871
6872int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
6873{
6874 /* TODO */
6875 return 0;
6876}
6877
6878
6879int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
6880 char *buf, size_t buflen)
6881{
6882 /* TODO */
6883 return 0;
6884}
6885
6886
6887void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
6888 const u8 *buf, size_t len, int ack)
6889{
6890 struct sta_info *sta;
6891 struct hostapd_iface *iface = hapd->iface;
6892
6893 sta = ap_get_sta(hapd, addr);
6894 if (sta == NULL && iface->num_bss > 1) {
6895 size_t j;
6896 for (j = 0; j < iface->num_bss; j++) {
6897 hapd = iface->bss[j];
6898 sta = ap_get_sta(hapd, addr);
6899 if (sta)
6900 break;
6901 }
6902 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006903 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006904 return;
6905 if (sta->flags & WLAN_STA_PENDING_POLL) {
6906 wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
6907 "activity poll", MAC2STR(sta->addr),
6908 ack ? "ACKed" : "did not ACK");
6909 if (ack)
6910 sta->flags &= ~WLAN_STA_PENDING_POLL;
6911 }
6912
6913 ieee802_1x_tx_status(hapd, sta, buf, len, ack);
6914}
6915
6916
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006917void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
6918 const u8 *data, size_t len, int ack)
6919{
6920 struct sta_info *sta;
6921 struct hostapd_iface *iface = hapd->iface;
6922
6923 sta = ap_get_sta(hapd, dst);
6924 if (sta == NULL && iface->num_bss > 1) {
6925 size_t j;
6926 for (j = 0; j < iface->num_bss; j++) {
6927 hapd = iface->bss[j];
6928 sta = ap_get_sta(hapd, dst);
6929 if (sta)
6930 break;
6931 }
6932 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006933 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
6934 wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA "
6935 MACSTR " that is not currently associated",
6936 MAC2STR(dst));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006937 return;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006938 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006939
6940 ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
6941}
6942
6943
6944void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
6945{
6946 struct sta_info *sta;
6947 struct hostapd_iface *iface = hapd->iface;
6948
6949 sta = ap_get_sta(hapd, addr);
6950 if (sta == NULL && iface->num_bss > 1) {
6951 size_t j;
6952 for (j = 0; j < iface->num_bss; j++) {
6953 hapd = iface->bss[j];
6954 sta = ap_get_sta(hapd, addr);
6955 if (sta)
6956 break;
6957 }
6958 }
6959 if (sta == NULL)
6960 return;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006961 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
6962 MAC2STR(sta->addr));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006963 if (!(sta->flags & WLAN_STA_PENDING_POLL))
6964 return;
6965
6966 wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
6967 "activity poll", MAC2STR(sta->addr));
6968 sta->flags &= ~WLAN_STA_PENDING_POLL;
6969}
6970
6971
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006972void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
6973 int wds)
6974{
6975 struct sta_info *sta;
6976
6977 sta = ap_get_sta(hapd, src);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006978 if (sta &&
6979 ((sta->flags & WLAN_STA_ASSOC) ||
6980 ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006981 if (!hapd->conf->wds_sta)
6982 return;
6983
Dmitry Shmidt29333592017-01-09 12:27:11 -08006984 if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) ==
6985 WLAN_STA_ASSOC_REQ_OK) {
6986 wpa_printf(MSG_DEBUG,
6987 "Postpone 4-address WDS mode enabling for STA "
6988 MACSTR " since TX status for AssocResp is not yet known",
6989 MAC2STR(sta->addr));
6990 sta->pending_wds_enable = 1;
6991 return;
6992 }
6993
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006994 if (wds && !(sta->flags & WLAN_STA_WDS)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006995 int ret;
6996 char ifname_wds[IFNAMSIZ + 1];
6997
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006998 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
6999 "STA " MACSTR " (aid %u)",
7000 MAC2STR(sta->addr), sta->aid);
7001 sta->flags |= WLAN_STA_WDS;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07007002 ret = hostapd_set_wds_sta(hapd, ifname_wds,
7003 sta->addr, sta->aid, 1);
7004 if (!ret)
7005 hostapd_set_wds_encryption(hapd, sta,
7006 ifname_wds);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007007 }
7008 return;
7009 }
7010
7011 wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
7012 MACSTR, MAC2STR(src));
Hai Shalomc3565922019-10-28 11:58:20 -07007013 if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
Sunil Ravi72e01222024-03-09 01:25:43 +00007014 ether_addr_equal(src, hapd->own_addr)) {
Hai Shalomc3565922019-10-28 11:58:20 -07007015 /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
7016 * silently. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007017 return;
7018 }
7019
7020 if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) {
7021 wpa_printf(MSG_DEBUG, "Association Response to the STA has "
7022 "already been sent, but no TX status yet known - "
7023 "ignore Class 3 frame issue with " MACSTR,
7024 MAC2STR(src));
7025 return;
7026 }
7027
7028 if (sta && (sta->flags & WLAN_STA_AUTH))
7029 hostapd_drv_sta_disassoc(
7030 hapd, src,
7031 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
7032 else
7033 hostapd_drv_sta_deauth(
7034 hapd, src,
7035 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
7036}
7037
7038
Sunil Ravia04bd252022-05-02 22:54:18 -07007039static u8 * hostapd_add_tpe_info(u8 *eid, u8 tx_pwr_count,
7040 enum max_tx_pwr_interpretation tx_pwr_intrpn,
7041 u8 tx_pwr_cat, u8 tx_pwr)
7042{
7043 int i;
7044
7045 *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE; /* Element ID */
7046 *eid++ = 2 + tx_pwr_count; /* Length */
7047
7048 /*
7049 * Transmit Power Information field
7050 * bits 0-2 : Maximum Transmit Power Count
7051 * bits 3-5 : Maximum Transmit Power Interpretation
7052 * bits 6-7 : Maximum Transmit Power Category
7053 */
7054 *eid++ = tx_pwr_count | (tx_pwr_intrpn << 3) | (tx_pwr_cat << 6);
7055
7056 /* Maximum Transmit Power field */
7057 for (i = 0; i <= tx_pwr_count; i++)
7058 *eid++ = tx_pwr;
7059
7060 return eid;
7061}
7062
7063
7064/*
7065 * TODO: Extract power limits from channel data after 6G regulatory
7066 * support.
7067 */
7068#define REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT (-1) /* dBm/MHz */
7069#define REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT 5 /* dBm/MHz */
7070
Hai Shalom60840252021-02-19 19:02:11 -08007071u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
7072{
7073 struct hostapd_iface *iface = hapd->iface;
7074 struct hostapd_config *iconf = iface->conf;
7075 struct hostapd_hw_modes *mode = iface->current_mode;
7076 struct hostapd_channel_data *chan;
7077 int dfs, i;
7078 u8 channel, tx_pwr_count, local_pwr_constraint;
7079 int max_tx_power;
7080 u8 tx_pwr;
7081
7082 if (!mode)
7083 return eid;
7084
7085 if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
7086 return eid;
7087
7088 for (i = 0; i < mode->num_channels; i++) {
7089 if (mode->channels[i].freq == iface->freq)
7090 break;
7091 }
7092 if (i == mode->num_channels)
7093 return eid;
7094
Sunil Ravia04bd252022-05-02 22:54:18 -07007095#ifdef CONFIG_IEEE80211AX
7096 /* IEEE Std 802.11ax-2021, Annex E.2.7 (6 GHz band in the United
7097 * States): An AP that is an Indoor Access Point per regulatory rules
7098 * shall send at least two Transmit Power Envelope elements in Beacon
7099 * and Probe Response frames as follows:
7100 * - Maximum Transmit Power Category subfield = Default;
7101 * Unit interpretation = Regulatory client EIRP PSD
7102 * - Maximum Transmit Power Category subfield = Subordinate Device;
7103 * Unit interpretation = Regulatory client EIRP PSD
7104 */
7105 if (is_6ghz_op_class(iconf->op_class)) {
7106 enum max_tx_pwr_interpretation tx_pwr_intrpn;
7107
7108 /* Same Maximum Transmit Power for all 20 MHz bands */
7109 tx_pwr_count = 0;
7110 tx_pwr_intrpn = REGULATORY_CLIENT_EIRP_PSD;
7111
7112 /* Default Transmit Power Envelope for Global Operating Class */
Sunil Ravi72e01222024-03-09 01:25:43 +00007113 if (hapd->iconf->reg_def_cli_eirp_psd != -1)
7114 tx_pwr = hapd->iconf->reg_def_cli_eirp_psd;
7115 else
7116 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT * 2;
7117
Sunil Ravia04bd252022-05-02 22:54:18 -07007118 eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn,
7119 REG_DEFAULT_CLIENT, tx_pwr);
7120
7121 /* Indoor Access Point must include an additional TPE for
7122 * subordinate devices */
Sunil Ravi72e01222024-03-09 01:25:43 +00007123 if (he_reg_is_indoor(iconf->he_6ghz_reg_pwr_type)) {
Sunil Ravia04bd252022-05-02 22:54:18 -07007124 /* TODO: Extract PSD limits from channel data */
Sunil Ravi72e01222024-03-09 01:25:43 +00007125 if (hapd->iconf->reg_sub_cli_eirp_psd != -1)
7126 tx_pwr = hapd->iconf->reg_sub_cli_eirp_psd;
7127 else
7128 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT * 2;
Sunil Ravia04bd252022-05-02 22:54:18 -07007129 eid = hostapd_add_tpe_info(eid, tx_pwr_count,
7130 tx_pwr_intrpn,
7131 REG_SUBORDINATE_CLIENT,
7132 tx_pwr);
7133 }
7134
Sunil Ravi72e01222024-03-09 01:25:43 +00007135 if (iconf->reg_def_cli_eirp != -1 &&
7136 he_reg_is_sp(iconf->he_6ghz_reg_pwr_type))
7137 eid = hostapd_add_tpe_info(
7138 eid, tx_pwr_count, REGULATORY_CLIENT_EIRP,
7139 REG_DEFAULT_CLIENT,
7140 hapd->iconf->reg_def_cli_eirp);
7141
Sunil Ravia04bd252022-05-02 22:54:18 -07007142 return eid;
7143 }
7144#endif /* CONFIG_IEEE80211AX */
7145
Hai Shalom60840252021-02-19 19:02:11 -08007146 switch (hostapd_get_oper_chwidth(iconf)) {
Sunil8cd6f4d2022-06-28 18:40:46 +00007147 case CONF_OPER_CHWIDTH_USE_HT:
Hai Shalom60840252021-02-19 19:02:11 -08007148 if (iconf->secondary_channel == 0) {
7149 /* Max Transmit Power count = 0 (20 MHz) */
7150 tx_pwr_count = 0;
7151 } else {
7152 /* Max Transmit Power count = 1 (20, 40 MHz) */
7153 tx_pwr_count = 1;
7154 }
7155 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00007156 case CONF_OPER_CHWIDTH_80MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08007157 /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
7158 tx_pwr_count = 2;
7159 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00007160 case CONF_OPER_CHWIDTH_80P80MHZ:
7161 case CONF_OPER_CHWIDTH_160MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08007162 /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
7163 tx_pwr_count = 3;
7164 break;
7165 default:
7166 return eid;
7167 }
7168
7169 /*
7170 * Below local_pwr_constraint logic is referred from
7171 * hostapd_eid_pwr_constraint.
7172 *
7173 * Check if DFS is required by regulatory.
7174 */
7175 dfs = hostapd_is_dfs_required(hapd->iface);
7176 if (dfs < 0)
7177 dfs = 0;
7178
7179 /*
7180 * In order to meet regulations when TPC is not implemented using
7181 * a transmit power that is below the legal maximum (including any
7182 * mitigation factor) should help. In this case, indicate 3 dB below
7183 * maximum allowed transmit power.
7184 */
7185 if (hapd->iconf->local_pwr_constraint == -1)
7186 local_pwr_constraint = (dfs == 0) ? 0 : 3;
7187 else
7188 local_pwr_constraint = hapd->iconf->local_pwr_constraint;
7189
7190 /*
7191 * A STA that is not an AP shall use a transmit power less than or
7192 * equal to the local maximum transmit power level for the channel.
7193 * The local maximum transmit power can be calculated from the formula:
7194 * local max TX pwr = max TX pwr - local pwr constraint
7195 * Where max TX pwr is maximum transmit power level specified for
7196 * channel in Country element and local pwr constraint is specified
7197 * for channel in this Power Constraint element.
7198 */
7199 chan = &mode->channels[i];
7200 max_tx_power = chan->max_tx_power - local_pwr_constraint;
7201
7202 /*
7203 * Local Maximum Transmit power is encoded as two's complement
7204 * with a 0.5 dB step.
7205 */
7206 max_tx_power *= 2; /* in 0.5 dB steps */
7207 if (max_tx_power > 127) {
7208 /* 63.5 has special meaning of 63.5 dBm or higher */
7209 max_tx_power = 127;
7210 }
7211 if (max_tx_power < -128)
7212 max_tx_power = -128;
7213 if (max_tx_power < 0)
7214 tx_pwr = 0x80 + max_tx_power + 128;
7215 else
7216 tx_pwr = max_tx_power;
7217
Sunil Ravia04bd252022-05-02 22:54:18 -07007218 return hostapd_add_tpe_info(eid, tx_pwr_count, LOCAL_EIRP,
7219 0 /* Reserved for bands other than 6 GHz */,
7220 tx_pwr);
Hai Shalom60840252021-02-19 19:02:11 -08007221}
7222
7223
Hai Shalom899fcc72020-10-19 14:38:18 -07007224u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
7225{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007226 u8 bw, chan1 = 0, chan2 = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -07007227 int freq1;
7228
7229 if (!hapd->cs_freq_params.channel ||
7230 (!hapd->cs_freq_params.vht_enabled &&
Sunil Ravia04bd252022-05-02 22:54:18 -07007231 !hapd->cs_freq_params.he_enabled &&
7232 !hapd->cs_freq_params.eht_enabled))
Hai Shalom899fcc72020-10-19 14:38:18 -07007233 return eid;
7234
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007235 /* bandwidth: 0: 40, 1: 80, 160, 80+80, 4: 320 as per
7236 * IEEE P802.11-REVme/D4.0, 9.4.2.159 and Table 9-314. */
Hai Shalom899fcc72020-10-19 14:38:18 -07007237 switch (hapd->cs_freq_params.bandwidth) {
7238 case 40:
7239 bw = 0;
7240 break;
7241 case 80:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007242 bw = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07007243 break;
7244 case 160:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007245 bw = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07007246 break;
Sunil Ravi640215c2023-06-28 23:08:09 +00007247 case 320:
7248 bw = 4;
7249 break;
Hai Shalom899fcc72020-10-19 14:38:18 -07007250 default:
7251 /* not valid VHT bandwidth or not in CSA */
7252 return eid;
7253 }
7254
7255 freq1 = hapd->cs_freq_params.center_freq1 ?
7256 hapd->cs_freq_params.center_freq1 :
7257 hapd->cs_freq_params.freq;
7258 if (ieee80211_freq_to_chan(freq1, &chan1) !=
7259 HOSTAPD_MODE_IEEE80211A)
7260 return eid;
7261
7262 if (hapd->cs_freq_params.center_freq2 &&
7263 ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
7264 &chan2) != HOSTAPD_MODE_IEEE80211A)
7265 return eid;
7266
Sunil Ravi640215c2023-06-28 23:08:09 +00007267 *eid++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER;
Hai Shalom899fcc72020-10-19 14:38:18 -07007268 *eid++ = 5; /* Length of Channel Switch Wrapper */
Sunil Ravi640215c2023-06-28 23:08:09 +00007269 *eid++ = WLAN_EID_WIDE_BW_CHSWITCH;
Hai Shalom899fcc72020-10-19 14:38:18 -07007270 *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
7271 *eid++ = bw; /* New Channel Width */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007272 if (hapd->cs_freq_params.bandwidth == 160) {
7273 /* Update the CCFS0 and CCFS1 values in the element based on
7274 * IEEE P802.11-REVme/D4.0, Table 9-314 */
7275
7276 /* CCFS1 - The channel center frequency index of the 160 MHz
7277 * channel. */
7278 chan2 = chan1;
7279
7280 /* CCFS0 - The channel center frequency index of the 80 MHz
7281 * channel segment that contains the primary channel. */
7282 if (hapd->cs_freq_params.channel < chan1)
7283 chan1 -= 8;
7284 else
7285 chan1 += 8;
7286 }
Hai Shalom899fcc72020-10-19 14:38:18 -07007287 *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
7288 *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
7289
7290 return eid;
7291}
7292
Hai Shaloma20dcd72022-02-04 13:43:00 -08007293
7294static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd,
7295 size_t *current_len)
7296{
7297 struct hostapd_neighbor_entry *nr;
7298 size_t total_len = 0, len = *current_len;
7299
7300 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7301 list) {
7302 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7303 continue;
7304
7305 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7306 continue;
7307
7308 /* Start a new element */
7309 if (!len ||
7310 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7311 len = RNR_HEADER_LEN;
7312 total_len += RNR_HEADER_LEN;
7313 }
7314
7315 len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7316 total_len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7317 }
7318
7319 *current_len = len;
7320 return total_len;
7321}
7322
7323
Sunil Ravi640215c2023-06-28 23:08:09 +00007324struct mbssid_ie_profiles {
7325 u8 start;
7326 u8 end;
7327};
7328
7329static size_t
7330hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
7331 struct hostapd_data *reporting_hapd,
7332 size_t *current_len,
7333 struct mbssid_ie_profiles *skip_profiles)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007334{
7335 size_t total_len = 0, len = *current_len;
7336 int tbtt_count = 0;
7337 size_t i, start = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007338 bool ap_mld = false;
7339
7340#ifdef CONFIG_IEEE80211BE
7341 ap_mld = !!hapd->conf->mld_ap;
7342#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007343
7344 while (start < hapd->iface->num_bss) {
7345 if (!len ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007346 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255 ||
7347 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08007348 len = RNR_HEADER_LEN;
7349 total_len += RNR_HEADER_LEN;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007350 tbtt_count = 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007351 }
7352
7353 len += RNR_TBTT_HEADER_LEN;
7354 total_len += RNR_TBTT_HEADER_LEN;
7355
7356 for (i = start; i < hapd->iface->num_bss; i++) {
7357 struct hostapd_data *bss = hapd->iface->bss[i];
7358
7359 if (!bss || !bss->conf || !bss->started)
7360 continue;
7361
7362 if (bss == reporting_hapd ||
7363 bss->conf->ignore_broadcast_ssid)
7364 continue;
7365
Sunil Ravi640215c2023-06-28 23:08:09 +00007366 if (skip_profiles &&
7367 i >= skip_profiles->start && i < skip_profiles->end)
7368 continue;
7369
Hai Shaloma20dcd72022-02-04 13:43:00 -08007370 if (len + RNR_TBTT_INFO_LEN > 255 ||
7371 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7372 break;
7373
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007374 if (!ap_mld) {
7375 len += RNR_TBTT_INFO_LEN;
7376 total_len += RNR_TBTT_INFO_LEN;
7377 } else {
7378 len += RNR_TBTT_INFO_MLD_LEN;
7379 total_len += RNR_TBTT_INFO_MLD_LEN;
7380 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08007381 tbtt_count++;
7382 }
7383 start = i;
7384 }
7385
7386 if (!tbtt_count)
7387 total_len = 0;
7388 else
7389 *current_len = len;
7390
7391 return total_len;
7392}
7393
7394
7395enum colocation_mode {
7396 NO_COLOCATED_6GHZ,
7397 STANDALONE_6GHZ,
7398 COLOCATED_6GHZ,
7399 COLOCATED_LOWER_BAND,
7400};
7401
7402static enum colocation_mode get_colocation_mode(struct hostapd_data *hapd)
7403{
7404 u8 i;
7405 bool is_6ghz = is_6ghz_op_class(hapd->iconf->op_class);
7406
7407 if (!hapd->iface || !hapd->iface->interfaces)
7408 return NO_COLOCATED_6GHZ;
7409
7410 if (is_6ghz && hapd->iface->interfaces->count == 1)
7411 return STANDALONE_6GHZ;
7412
7413 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7414 struct hostapd_iface *iface;
7415 bool is_colocated_6ghz;
7416
7417 iface = hapd->iface->interfaces->iface[i];
7418 if (iface == hapd->iface || !iface || !iface->conf)
7419 continue;
7420
7421 is_colocated_6ghz = is_6ghz_op_class(iface->conf->op_class);
7422 if (!is_6ghz && is_colocated_6ghz)
7423 return COLOCATED_LOWER_BAND;
7424 if (is_6ghz && !is_colocated_6ghz)
7425 return COLOCATED_6GHZ;
7426 }
7427
7428 if (is_6ghz)
7429 return STANDALONE_6GHZ;
7430
7431 return NO_COLOCATED_6GHZ;
7432}
7433
7434
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007435static size_t hostapd_eid_rnr_multi_iface_len(struct hostapd_data *hapd,
7436 size_t *current_len)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007437{
7438 struct hostapd_iface *iface;
7439 size_t len = 0;
7440 size_t i;
7441
7442 if (!hapd->iface || !hapd->iface->interfaces)
7443 return 0;
7444
7445 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7446 iface = hapd->iface->interfaces->iface[i];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007447 bool ap_mld = false;
7448
7449#ifdef CONFIG_IEEE80211BE
Sunil Raviaf399a82024-05-05 20:56:55 +00007450 if (hostapd_is_ml_partner(hapd, iface->bss[0]))
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007451 ap_mld = true;
7452#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007453
7454 if (iface == hapd->iface ||
Sunil Raviaf399a82024-05-05 20:56:55 +00007455 iface->state != HAPD_IFACE_ENABLED ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007456 !(is_6ghz_op_class(iface->conf->op_class) || ap_mld))
Hai Shaloma20dcd72022-02-04 13:43:00 -08007457 continue;
7458
7459 len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007460 current_len, NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007461 }
7462
7463 return len;
7464}
7465
7466
7467size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type)
7468{
7469 size_t total_len = 0, current_len = 0;
7470 enum colocation_mode mode = get_colocation_mode(hapd);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007471 bool ap_mld = false;
7472
7473#ifdef CONFIG_IEEE80211BE
7474 ap_mld = !!hapd->conf->mld_ap;
7475#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007476
7477 switch (type) {
7478 case WLAN_FC_STYPE_BEACON:
7479 if (hapd->conf->rnr)
7480 total_len += hostapd_eid_nr_db_len(hapd, &current_len);
7481 /* fallthrough */
7482
7483 case WLAN_FC_STYPE_PROBE_RESP:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007484 if (mode == COLOCATED_LOWER_BAND || ap_mld)
7485 total_len +=
7486 hostapd_eid_rnr_multi_iface_len(hapd,
7487 &current_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007488
Sunil Ravi640215c2023-06-28 23:08:09 +00007489 if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
7490 !hapd->iconf->mbssid)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007491 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007492 &current_len,
7493 NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007494 break;
7495
7496 case WLAN_FC_STYPE_ACTION:
7497 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
7498 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007499 &current_len,
7500 NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007501 break;
7502
7503 default:
7504 break;
7505 }
7506
7507 return total_len;
7508}
7509
7510
7511static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid,
7512 size_t *current_len)
7513{
7514 struct hostapd_neighbor_entry *nr;
7515 size_t len = *current_len;
7516 u8 *size_offset = (eid - len) + 1;
7517
7518 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7519 list) {
7520 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7521 continue;
7522
7523 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7524 continue;
7525
7526 /* Start a new element */
7527 if (!len ||
7528 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7529 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7530 size_offset = eid++;
7531 len = RNR_HEADER_LEN;
7532 }
7533
7534 /* TBTT Information Header subfield (2 octets) */
7535 *eid++ = 0;
7536 /* TBTT Information Length */
7537 *eid++ = RNR_TBTT_INFO_LEN;
7538 /* Operating Class */
7539 *eid++ = wpabuf_head_u8(nr->nr)[10];
7540 /* Channel Number */
7541 *eid++ = wpabuf_head_u8(nr->nr)[11];
7542 len += RNR_TBTT_HEADER_LEN;
7543 /* TBTT Information Set */
7544 /* TBTT Information field */
7545 /* Neighbor AP TBTT Offset */
7546 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
7547 /* BSSID */
7548 os_memcpy(eid, nr->bssid, ETH_ALEN);
7549 eid += ETH_ALEN;
7550 /* Short SSID */
7551 os_memcpy(eid, &nr->short_ssid, 4);
7552 eid += 4;
7553 /* BSS parameters */
7554 *eid++ = nr->bss_parameters;
7555 /* 20 MHz PSD */
Sunil Ravi72e01222024-03-09 01:25:43 +00007556 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007557 len += RNR_TBTT_INFO_LEN;
7558 *size_offset = (eid - size_offset) - 1;
7559 }
7560
7561 *current_len = len;
7562 return eid;
7563}
7564
7565
Sunil Ravi72e01222024-03-09 01:25:43 +00007566static bool hostapd_eid_rnr_bss(struct hostapd_data *hapd,
7567 struct hostapd_data *reporting_hapd,
7568 struct mbssid_ie_profiles *skip_profiles,
7569 size_t i, u8 *tbtt_count, size_t *len,
7570 u8 **pos)
7571{
7572 struct hostapd_iface *iface = hapd->iface;
7573 struct hostapd_data *bss = iface->bss[i];
7574 u8 bss_param = 0;
7575 bool ap_mld = false;
7576 u8 *eid = *pos;
7577
7578#ifdef CONFIG_IEEE80211BE
7579 ap_mld = !!hapd->conf->mld_ap;
7580#endif /* CONFIG_IEEE80211BE */
7581
7582 if (!bss || !bss->conf || !bss->started ||
7583 bss == reporting_hapd || bss->conf->ignore_broadcast_ssid)
7584 return false;
7585
7586 if (skip_profiles
7587 && i >= skip_profiles->start && i < skip_profiles->end)
7588 return false;
7589
7590 if (*len + RNR_TBTT_INFO_LEN > 255 ||
7591 *tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7592 return true;
7593
7594 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
7595 os_memcpy(eid, bss->own_addr, ETH_ALEN);
7596 eid += ETH_ALEN;
7597 os_memcpy(eid, &bss->conf->ssid.short_ssid, 4);
7598 eid += 4;
7599 if (bss->conf->ssid.short_ssid == reporting_hapd->conf->ssid.short_ssid)
7600 bss_param |= RNR_BSS_PARAM_SAME_SSID;
7601
7602 if (iface->conf->mbssid != MBSSID_DISABLED && iface->num_bss > 1) {
7603 bss_param |= RNR_BSS_PARAM_MULTIPLE_BSSID;
7604 if (bss == hostapd_mbssid_get_tx_bss(hapd))
7605 bss_param |= RNR_BSS_PARAM_TRANSMITTED_BSSID;
7606 }
7607
7608 if (is_6ghz_op_class(hapd->iconf->op_class) &&
7609 bss->conf->unsol_bcast_probe_resp_interval)
7610 bss_param |= RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE;
7611
7612 bss_param |= RNR_BSS_PARAM_CO_LOCATED;
7613
7614 *eid++ = bss_param;
7615 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER;
7616
7617 if (!ap_mld) {
7618 *len += RNR_TBTT_INFO_LEN;
7619 } else {
7620#ifdef CONFIG_IEEE80211BE
7621 u8 param_ch = hapd->eht_mld_bss_param_change;
7622
Sunil Raviaf399a82024-05-05 20:56:55 +00007623 if (hostapd_is_ml_partner(bss, reporting_hapd))
Sunil Ravi72e01222024-03-09 01:25:43 +00007624 *eid++ = 0;
7625 else
Sunil Raviaf399a82024-05-05 20:56:55 +00007626 *eid++ = hostapd_get_mld_id(hapd);
Sunil Ravi72e01222024-03-09 01:25:43 +00007627
7628 *eid++ = hapd->mld_link_id | ((param_ch & 0xF) << 4);
7629 *eid = (param_ch >> 4) & 0xF;
7630#ifdef CONFIG_TESTING_OPTIONS
7631 if (hapd->conf->mld_indicate_disabled)
7632 *eid |= RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED;
7633#endif /* CONFIG_TESTING_OPTIONS */
7634 eid++;
7635
7636 *len += RNR_TBTT_INFO_MLD_LEN;
7637#endif /* CONFIG_IEEE80211BE */
7638 }
7639
7640 (*tbtt_count)++;
7641 *pos = eid;
7642
7643 return false;
7644}
7645
7646
Hai Shaloma20dcd72022-02-04 13:43:00 -08007647static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
7648 struct hostapd_data *reporting_hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00007649 u8 *eid, size_t *current_len,
7650 struct mbssid_ie_profiles *skip_profiles)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007651{
Hai Shaloma20dcd72022-02-04 13:43:00 -08007652 struct hostapd_iface *iface = hapd->iface;
7653 size_t i, start = 0;
7654 size_t len = *current_len;
7655 u8 *tbtt_count_pos, *eid_start = eid, *size_offset = (eid - len) + 1;
Sunil Ravi72e01222024-03-09 01:25:43 +00007656 u8 tbtt_count = 0, op_class, channel;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007657 bool ap_mld = false;
7658
7659#ifdef CONFIG_IEEE80211BE
7660 ap_mld = !!hapd->conf->mld_ap;
7661#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007662
7663 if (!(iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !iface->freq)
7664 return eid;
7665
7666 if (ieee80211_freq_to_channel_ext(iface->freq,
7667 hapd->iconf->secondary_channel,
7668 hostapd_get_oper_chwidth(hapd->iconf),
7669 &op_class, &channel) ==
7670 NUM_HOSTAPD_MODES)
7671 return eid;
7672
7673 while (start < iface->num_bss) {
7674 if (!len ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007675 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255 ||
7676 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08007677 eid_start = eid;
7678 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7679 size_offset = eid++;
7680 len = RNR_HEADER_LEN;
7681 tbtt_count = 0;
7682 }
7683
7684 tbtt_count_pos = eid++;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007685 *eid++ = ap_mld ? RNR_TBTT_INFO_MLD_LEN : RNR_TBTT_INFO_LEN;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007686 *eid++ = op_class;
7687 *eid++ = hapd->iconf->channel;
7688 len += RNR_TBTT_HEADER_LEN;
7689
7690 for (i = start; i < iface->num_bss; i++) {
Sunil Ravi72e01222024-03-09 01:25:43 +00007691 if (hostapd_eid_rnr_bss(hapd, reporting_hapd,
7692 skip_profiles, i,
7693 &tbtt_count, &len, &eid))
Hai Shaloma20dcd72022-02-04 13:43:00 -08007694 break;
Hai Shaloma20dcd72022-02-04 13:43:00 -08007695 }
7696
7697 start = i;
7698 *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
7699 *size_offset = (eid - size_offset) - 1;
7700 }
7701
7702 if (tbtt_count == 0)
7703 return eid_start;
7704
7705 *current_len = len;
7706 return eid;
7707}
7708
7709
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007710static u8 * hostapd_eid_rnr_multi_iface(struct hostapd_data *hapd, u8 *eid,
7711 size_t *current_len)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007712{
7713 struct hostapd_iface *iface;
7714 size_t i;
7715
7716 if (!hapd->iface || !hapd->iface->interfaces)
7717 return eid;
7718
7719 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7720 iface = hapd->iface->interfaces->iface[i];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007721 bool ap_mld = false;
7722
7723#ifdef CONFIG_IEEE80211BE
Sunil Raviaf399a82024-05-05 20:56:55 +00007724 if (hostapd_is_ml_partner(hapd, iface->bss[0]))
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007725 ap_mld = true;
7726#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007727
7728 if (iface == hapd->iface ||
Sunil Raviaf399a82024-05-05 20:56:55 +00007729 iface->state != HAPD_IFACE_ENABLED ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007730 !(is_6ghz_op_class(iface->conf->op_class) || ap_mld))
Hai Shaloma20dcd72022-02-04 13:43:00 -08007731 continue;
7732
7733 eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
Sunil Ravi640215c2023-06-28 23:08:09 +00007734 current_len, NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007735 }
7736
7737 return eid;
7738}
7739
7740
7741u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
7742{
7743 u8 *eid_start = eid;
7744 size_t current_len = 0;
7745 enum colocation_mode mode = get_colocation_mode(hapd);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007746 bool ap_mld = false;
7747
7748#ifdef CONFIG_IEEE80211BE
7749 ap_mld = !!hapd->conf->mld_ap;
7750#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08007751
7752 switch (type) {
7753 case WLAN_FC_STYPE_BEACON:
7754 if (hapd->conf->rnr)
7755 eid = hostapd_eid_nr_db(hapd, eid, &current_len);
7756 /* fallthrough */
7757
7758 case WLAN_FC_STYPE_PROBE_RESP:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007759 if (mode == COLOCATED_LOWER_BAND || ap_mld)
7760 eid = hostapd_eid_rnr_multi_iface(hapd, eid,
7761 &current_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007762
Sunil Ravi640215c2023-06-28 23:08:09 +00007763 if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
7764 !hapd->iconf->mbssid)
Hai Shaloma20dcd72022-02-04 13:43:00 -08007765 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
Sunil Ravi640215c2023-06-28 23:08:09 +00007766 &current_len, NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007767 break;
7768
7769 case WLAN_FC_STYPE_ACTION:
7770 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
Sunil Ravi72e01222024-03-09 01:25:43 +00007771 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
Sunil Ravi640215c2023-06-28 23:08:09 +00007772 &current_len, NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007773 break;
7774
7775 default:
7776 return eid_start;
7777 }
7778
7779 if (eid == eid_start + 2)
7780 return eid_start;
7781
7782 return eid;
7783}
7784
Sunil Ravi77d572f2023-01-17 23:58:31 +00007785
7786static bool mbssid_known_bss(unsigned int i, const u8 *known_bss,
7787 size_t known_bss_len)
7788{
7789 if (!known_bss || known_bss_len <= i / 8)
7790 return false;
7791 known_bss = &known_bss[i / 8];
7792 return *known_bss & (u8) (BIT(i % 8));
7793}
7794
7795
Sunil Raviaf399a82024-05-05 20:56:55 +00007796static size_t hostapd_mbssid_ext_capa(struct hostapd_data *bss,
7797 struct hostapd_data *tx_bss, u8 *buf)
7798{
7799 u8 ext_capa_tx[20], *ext_capa_tx_end, ext_capa[20], *ext_capa_end;
7800 size_t ext_capa_len, ext_capa_tx_len;
7801
7802 ext_capa_tx_end = hostapd_eid_ext_capab(tx_bss, ext_capa_tx,
7803 true);
7804 ext_capa_tx_len = ext_capa_tx_end - ext_capa_tx;
7805 ext_capa_end = hostapd_eid_ext_capab(bss, ext_capa, true);
7806 ext_capa_len = ext_capa_end - ext_capa;
7807 if (ext_capa_tx_len != ext_capa_len ||
7808 os_memcmp(ext_capa_tx, ext_capa, ext_capa_len) != 0) {
7809 os_memcpy(buf, ext_capa, ext_capa_len);
7810 return ext_capa_len;
7811 }
7812
7813 return 0;
7814}
7815
7816
Sunil Ravi77d572f2023-01-17 23:58:31 +00007817static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd,
7818 u32 frame_type, size_t *bss_index,
7819 const u8 *known_bss,
7820 size_t known_bss_len)
7821{
7822 struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
Sunil Ravi72e01222024-03-09 01:25:43 +00007823 size_t len, i;
Sunil Raviaf399a82024-05-05 20:56:55 +00007824 u8 ext_capa[20];
Sunil Ravi72e01222024-03-09 01:25:43 +00007825
7826 /* Element ID: 1 octet
7827 * Length: 1 octet
7828 * MaxBSSID Indicator: 1 octet
7829 * Optional Subelements: vatiable
7830 *
7831 * Total fixed length: 3 octets
7832 *
7833 * 1 octet in len for the MaxBSSID Indicator field.
7834 */
7835 len = 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00007836
7837 for (i = *bss_index; i < hapd->iface->num_bss; i++) {
7838 struct hostapd_data *bss = hapd->iface->bss[i];
7839 const u8 *auth, *rsn = NULL, *rsnx = NULL;
7840 size_t nontx_profile_len, auth_len;
7841 u8 ie_count = 0;
7842
7843 if (!bss || !bss->conf || !bss->started ||
7844 mbssid_known_bss(i, known_bss, known_bss_len))
7845 continue;
7846
7847 /*
7848 * Sublement ID: 1 octet
7849 * Length: 1 octet
7850 * Nontransmitted capabilities: 4 octets
7851 * SSID element: 2 + variable
7852 * Multiple BSSID Index Element: 3 octets (+2 octets in beacons)
7853 * Fixed length = 1 + 1 + 4 + 2 + 3 = 11
7854 */
7855 nontx_profile_len = 11 + bss->conf->ssid.ssid_len;
7856
7857 if (frame_type == WLAN_FC_STYPE_BEACON)
7858 nontx_profile_len += 2;
7859
7860 auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
7861 if (auth) {
7862 rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
7863 if (rsn)
7864 nontx_profile_len += 2 + rsn[1];
7865
7866 rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
7867 if (rsnx)
7868 nontx_profile_len += 2 + rsnx[1];
7869 }
Sunil Raviaf399a82024-05-05 20:56:55 +00007870
7871 nontx_profile_len += hostapd_mbssid_ext_capa(bss, tx_bss,
7872 ext_capa);
7873
Sunil Ravi77d572f2023-01-17 23:58:31 +00007874 if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
7875 ie_count++;
7876 if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
7877 ie_count++;
7878 if (bss->conf->xrates_supported)
7879 nontx_profile_len += 8;
7880 else if (hapd->conf->xrates_supported)
7881 ie_count++;
7882 if (ie_count)
7883 nontx_profile_len += 4 + ie_count;
7884
7885 if (len + nontx_profile_len > 255)
7886 break;
7887
7888 len += nontx_profile_len;
7889 }
7890
7891 *bss_index = i;
Sunil Ravi72e01222024-03-09 01:25:43 +00007892
7893 /* Add 2 octets to get the full size of the element */
7894 return len + 2;
Sunil Ravi77d572f2023-01-17 23:58:31 +00007895}
7896
7897
7898size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
7899 u8 *elem_count, const u8 *known_bss,
Sunil Ravi640215c2023-06-28 23:08:09 +00007900 size_t known_bss_len, size_t *rnr_len)
Sunil Ravi77d572f2023-01-17 23:58:31 +00007901{
7902 size_t len = 0, bss_index = 1;
7903
7904 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
7905 (frame_type != WLAN_FC_STYPE_BEACON &&
7906 frame_type != WLAN_FC_STYPE_PROBE_RESP))
7907 return 0;
7908
7909 if (frame_type == WLAN_FC_STYPE_BEACON) {
7910 if (!elem_count) {
7911 wpa_printf(MSG_INFO,
7912 "MBSSID: Insufficient data for Beacon frames");
7913 return 0;
7914 }
7915 *elem_count = 0;
7916 }
7917
7918 while (bss_index < hapd->iface->num_bss) {
Sunil Ravi640215c2023-06-28 23:08:09 +00007919 size_t rnr_count = bss_index;
7920
Sunil Ravi77d572f2023-01-17 23:58:31 +00007921 len += hostapd_eid_mbssid_elem_len(hapd, frame_type,
7922 &bss_index, known_bss,
7923 known_bss_len);
7924
7925 if (frame_type == WLAN_FC_STYPE_BEACON)
7926 *elem_count += 1;
Sunil Ravi640215c2023-06-28 23:08:09 +00007927 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len) {
7928 size_t rnr_cur_len = 0;
7929 struct mbssid_ie_profiles skip_profiles = {
7930 rnr_count, bss_index
7931 };
7932
7933 *rnr_len += hostapd_eid_rnr_iface_len(
7934 hapd, hostapd_mbssid_get_tx_bss(hapd),
7935 &rnr_cur_len, &skip_profiles);
7936 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00007937 }
Sunil Ravi640215c2023-06-28 23:08:09 +00007938
7939 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len)
7940 *rnr_len += hostapd_eid_rnr_len(hapd, frame_type);
7941
Sunil Ravi77d572f2023-01-17 23:58:31 +00007942 return len;
7943}
7944
7945
7946static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end,
7947 u32 frame_type, u8 max_bssid_indicator,
7948 size_t *bss_index, u8 elem_count,
7949 const u8 *known_bss, size_t known_bss_len)
7950{
7951 struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
7952 size_t i;
7953 u8 *eid_len_offset, *max_bssid_indicator_offset;
7954
7955 *eid++ = WLAN_EID_MULTIPLE_BSSID;
7956 eid_len_offset = eid++;
7957 max_bssid_indicator_offset = eid++;
7958
7959 for (i = *bss_index; i < hapd->iface->num_bss; i++) {
7960 struct hostapd_data *bss = hapd->iface->bss[i];
7961 struct hostapd_bss_config *conf;
7962 u8 *eid_len_pos, *nontx_bss_start = eid;
7963 const u8 *auth, *rsn = NULL, *rsnx = NULL;
7964 u8 ie_count = 0, non_inherit_ie[3];
7965 size_t auth_len = 0;
7966 u16 capab_info;
7967
7968 if (!bss || !bss->conf || !bss->started ||
7969 mbssid_known_bss(i, known_bss, known_bss_len))
7970 continue;
7971 conf = bss->conf;
7972
7973 *eid++ = WLAN_MBSSID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE;
7974 eid_len_pos = eid++;
7975
7976 capab_info = hostapd_own_capab_info(bss);
7977 *eid++ = WLAN_EID_NONTRANSMITTED_BSSID_CAPA;
7978 *eid++ = sizeof(capab_info);
7979 WPA_PUT_LE16(eid, capab_info);
7980 eid += sizeof(capab_info);
7981
7982 *eid++ = WLAN_EID_SSID;
7983 *eid++ = conf->ssid.ssid_len;
7984 os_memcpy(eid, conf->ssid.ssid, conf->ssid.ssid_len);
7985 eid += conf->ssid.ssid_len;
7986
7987 *eid++ = WLAN_EID_MULTIPLE_BSSID_INDEX;
7988 if (frame_type == WLAN_FC_STYPE_BEACON) {
7989 *eid++ = 3;
7990 *eid++ = i; /* BSSID Index */
7991 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
7992 (conf->dtim_period % elem_count))
7993 conf->dtim_period = elem_count;
7994 *eid++ = conf->dtim_period;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007995 /* The driver is expected to update the DTIM Count
7996 * field for each BSS that corresponds to a
7997 * nontransmitted BSSID. The value is initialized to
7998 * 0 here so that the DTIM count would be somewhat
7999 * functional even if the driver were not to update
8000 * this. */
8001 *eid++ = 0; /* DTIM Count */
Sunil Ravi77d572f2023-01-17 23:58:31 +00008002 } else {
8003 /* Probe Request frame does not include DTIM Period and
8004 * DTIM Count fields. */
8005 *eid++ = 1;
8006 *eid++ = i; /* BSSID Index */
8007 }
8008
8009 auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
8010 if (auth) {
8011 rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
8012 if (rsn) {
8013 os_memcpy(eid, rsn, 2 + rsn[1]);
8014 eid += 2 + rsn[1];
8015 }
8016
8017 rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
8018 if (rsnx) {
8019 os_memcpy(eid, rsnx, 2 + rsnx[1]);
8020 eid += 2 + rsnx[1];
8021 }
8022 }
Sunil Raviaf399a82024-05-05 20:56:55 +00008023
8024 eid += hostapd_mbssid_ext_capa(bss, tx_bss, eid);
8025
Sunil Ravi72e01222024-03-09 01:25:43 +00008026 /* List of Element ID values in increasing order */
Sunil Ravi77d572f2023-01-17 23:58:31 +00008027 if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
8028 non_inherit_ie[ie_count++] = WLAN_EID_RSN;
Sunil Ravi77d572f2023-01-17 23:58:31 +00008029 if (hapd->conf->xrates_supported &&
8030 !bss->conf->xrates_supported)
8031 non_inherit_ie[ie_count++] = WLAN_EID_EXT_SUPP_RATES;
Sunil Ravi72e01222024-03-09 01:25:43 +00008032 if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
8033 non_inherit_ie[ie_count++] = WLAN_EID_RSNX;
Sunil Ravi77d572f2023-01-17 23:58:31 +00008034 if (ie_count) {
8035 *eid++ = WLAN_EID_EXTENSION;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008036 *eid++ = 2 + ie_count + 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00008037 *eid++ = WLAN_EID_EXT_NON_INHERITANCE;
8038 *eid++ = ie_count;
8039 os_memcpy(eid, non_inherit_ie, ie_count);
8040 eid += ie_count;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008041 *eid++ = 0; /* No Element ID Extension List */
Sunil Ravi77d572f2023-01-17 23:58:31 +00008042 }
8043
8044 *eid_len_pos = (eid - eid_len_pos) - 1;
8045
8046 if (((eid - eid_len_offset) - 1) > 255) {
8047 eid = nontx_bss_start;
8048 break;
8049 }
8050 }
8051
8052 *bss_index = i;
8053 *max_bssid_indicator_offset = max_bssid_indicator;
8054 if (*max_bssid_indicator_offset < 1)
8055 *max_bssid_indicator_offset = 1;
8056 *eid_len_offset = (eid - eid_len_offset) - 1;
8057 return eid;
8058}
8059
8060
8061u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
8062 unsigned int frame_stype, u8 elem_count,
8063 u8 **elem_offset,
Sunil Ravi640215c2023-06-28 23:08:09 +00008064 const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid,
8065 u8 *rnr_count, u8 **rnr_offset, size_t rnr_len)
Sunil Ravi77d572f2023-01-17 23:58:31 +00008066{
Sunil Ravi640215c2023-06-28 23:08:09 +00008067 size_t bss_index = 1, cur_len = 0;
8068 u8 elem_index = 0, *rnr_start_eid = rnr_eid;
8069 bool add_rnr;
Sunil Ravi77d572f2023-01-17 23:58:31 +00008070
8071 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
8072 (frame_stype != WLAN_FC_STYPE_BEACON &&
8073 frame_stype != WLAN_FC_STYPE_PROBE_RESP))
8074 return eid;
8075
8076 if (frame_stype == WLAN_FC_STYPE_BEACON && !elem_offset) {
8077 wpa_printf(MSG_INFO,
8078 "MBSSID: Insufficient data for Beacon frames");
8079 return eid;
8080 }
8081
Sunil Ravi640215c2023-06-28 23:08:09 +00008082 add_rnr = hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
8083 frame_stype == WLAN_FC_STYPE_BEACON &&
8084 rnr_eid && rnr_count && rnr_offset && rnr_len;
8085
Sunil Ravi77d572f2023-01-17 23:58:31 +00008086 while (bss_index < hapd->iface->num_bss) {
Sunil Ravi640215c2023-06-28 23:08:09 +00008087 unsigned int rnr_start_count = bss_index;
8088
Sunil Ravi77d572f2023-01-17 23:58:31 +00008089 if (frame_stype == WLAN_FC_STYPE_BEACON) {
8090 if (elem_index == elem_count) {
8091 wpa_printf(MSG_WARNING,
8092 "MBSSID: Larger number of elements than there is room in the provided array");
8093 break;
8094 }
8095
8096 elem_offset[elem_index] = eid;
8097 elem_index = elem_index + 1;
8098 }
8099 eid = hostapd_eid_mbssid_elem(hapd, eid, end, frame_stype,
8100 hostapd_max_bssid_indicator(hapd),
8101 &bss_index, elem_count,
8102 known_bss, known_bss_len);
Sunil Ravi640215c2023-06-28 23:08:09 +00008103
8104 if (add_rnr) {
8105 struct mbssid_ie_profiles skip_profiles = {
8106 rnr_start_count, bss_index
8107 };
8108
8109 rnr_offset[*rnr_count] = rnr_eid;
8110 *rnr_count = *rnr_count + 1;
8111 cur_len = 0;
8112 rnr_eid = hostapd_eid_rnr_iface(
8113 hapd, hostapd_mbssid_get_tx_bss(hapd),
8114 rnr_eid, &cur_len, &skip_profiles);
8115 }
8116 }
8117
8118 if (add_rnr && (size_t) (rnr_eid - rnr_start_eid) < rnr_len) {
8119 rnr_offset[*rnr_count] = rnr_eid;
8120 *rnr_count = *rnr_count + 1;
8121 cur_len = 0;
8122
8123 if (hapd->conf->rnr)
8124 rnr_eid = hostapd_eid_nr_db(hapd, rnr_eid, &cur_len);
8125 if (get_colocation_mode(hapd) == COLOCATED_LOWER_BAND)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008126 rnr_eid = hostapd_eid_rnr_multi_iface(hapd, rnr_eid,
8127 &cur_len);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008128 }
8129
8130 return eid;
8131}
8132
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008133#endif /* CONFIG_NATIVE_WINDOWS */