blob: 0142ee44acacfafe1fa28435b42ee360b5b44041 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / IEEE 802.11 Management
Dmitry Shmidt29333592017-01-09 12:27:11 -08003 * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "utils/includes.h"
10
11#ifndef CONFIG_NATIVE_WINDOWS
12
13#include "utils/common.h"
14#include "utils/eloop.h"
15#include "crypto/crypto.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080016#include "crypto/sha256.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070017#include "crypto/sha384.h"
18#include "crypto/sha512.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080019#include "crypto/random.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070020#include "common/ieee802_11_defs.h"
21#include "common/ieee802_11_common.h"
22#include "common/wpa_ctrl.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080023#include "common/sae.h"
Hai Shalom021b0b52019-04-10 11:17:58 -070024#include "common/dpp.h"
Hai Shalom74f70d42019-02-11 14:42:39 -080025#include "common/ocv.h"
Hai Shalom81f62d82019-07-22 12:10:00 -070026#include "common/wpa_common.h"
Hai Shalom899fcc72020-10-19 14:38:18 -070027#include "common/wpa_ctrl.h"
Hai Shalom60840252021-02-19 19:02:11 -080028#include "common/ptksa_cache.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070029#include "radius/radius.h"
30#include "radius/radius_client.h"
31#include "p2p/p2p.h"
32#include "wps/wps.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080033#include "fst/fst.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070034#include "hostapd.h"
35#include "beacon.h"
36#include "ieee802_11_auth.h"
37#include "sta_info.h"
38#include "ieee802_1x.h"
39#include "wpa_auth.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080040#include "pmksa_cache_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070041#include "wmm.h"
42#include "ap_list.h"
43#include "accounting.h"
44#include "ap_config.h"
45#include "ap_mlme.h"
46#include "p2p_hostapd.h"
47#include "ap_drv_ops.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080048#include "wnm_ap.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080049#include "hw_features.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070050#include "ieee802_11.h"
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080051#include "dfs.h"
Dmitry Shmidt57c2d392016-02-23 13:40:19 -080052#include "mbo_ap.h"
Dmitry Shmidt849734c2016-05-27 09:59:01 -070053#include "rrm.h"
Dmitry Shmidtaca489e2016-09-28 15:44:14 -070054#include "taxonomy.h"
Dmitry Shmidtebd93af2017-02-21 13:40:44 -080055#include "fils_hlp.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070056#include "dpp_hostapd.h"
57#include "gas_query_ap.h"
Sunil Ravi77d572f2023-01-17 23:58:31 +000058#include "comeback_token.h"
59#include "pasn/pasn_common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070060
61
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070062#ifdef CONFIG_FILS
63static struct wpabuf *
64prepare_auth_resp_fils(struct hostapd_data *hapd,
65 struct sta_info *sta, u16 *resp,
66 struct rsn_pmksa_cache_entry *pmksa,
67 struct wpabuf *erp_resp,
68 const u8 *msk, size_t msk_len,
69 int *is_pub);
70#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -080071
72#ifdef CONFIG_PASN
Hai Shalom60840252021-02-19 19:02:11 -080073#ifdef CONFIG_FILS
74
75static void pasn_fils_auth_resp(struct hostapd_data *hapd,
76 struct sta_info *sta, u16 status,
77 struct wpabuf *erp_resp,
78 const u8 *msk, size_t msk_len);
79
80#endif /* CONFIG_FILS */
81#endif /* CONFIG_PASN */
82
Hai Shalom021b0b52019-04-10 11:17:58 -070083static void handle_auth(struct hostapd_data *hapd,
84 const struct ieee80211_mgmt *mgmt, size_t len,
85 int rssi, int from_queue);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070086
Hai Shalom74f70d42019-02-11 14:42:39 -080087
88u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
89{
90 u8 multi_ap_val = 0;
91
92 if (!hapd->conf->multi_ap)
93 return eid;
94 if (hapd->conf->multi_ap & BACKHAUL_BSS)
95 multi_ap_val |= MULTI_AP_BACKHAUL_BSS;
96 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
97 multi_ap_val |= MULTI_AP_FRONTHAUL_BSS;
98
99 return eid + add_multi_ap_ie(eid, 9, multi_ap_val);
100}
101
102
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700103u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
104{
105 u8 *pos = eid;
106 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700107 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700108
109 if (hapd->iface->current_rates == NULL)
110 return eid;
111
112 *pos++ = WLAN_EID_SUPP_RATES;
113 num = hapd->iface->num_rates;
114 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
115 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800116 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
117 num++;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000118#ifdef CONFIG_IEEE80211AX
119 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
120 num++;
121#endif /* CONFIG_IEEE80211AX */
122 h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
Hai Shalomfdcde762020-04-02 11:19:20 -0700123 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +0000124 hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700125 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
126 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700127 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700128 if (num > 8) {
129 /* rest of the rates are encoded in Extended supported
130 * rates element */
131 num = 8;
132 }
133
134 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700135 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
136 i++) {
137 count++;
138 *pos = hapd->iface->current_rates[i].rate / 5;
139 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
140 *pos |= 0x80;
141 pos++;
142 }
143
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800144 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
145 count++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700146 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800147 }
148
149 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
150 count++;
151 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
152 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700153
Sunil Ravi77d572f2023-01-17 23:58:31 +0000154#ifdef CONFIG_IEEE80211AX
155 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he && count < 8) {
156 count++;
157 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY;
158 }
159#endif /* CONFIG_IEEE80211AX */
160
Hai Shalomfdcde762020-04-02 11:19:20 -0700161 if (h2e_required && count < 8) {
Hai Shalomc3565922019-10-28 11:58:20 -0700162 count++;
163 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
164 }
165
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700166 return pos;
167}
168
169
170u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
171{
172 u8 *pos = eid;
173 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700174 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700175
Sunil Ravi77d572f2023-01-17 23:58:31 +0000176 hapd->conf->xrates_supported = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700177 if (hapd->iface->current_rates == NULL)
178 return eid;
179
180 num = hapd->iface->num_rates;
181 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
182 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800183 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
184 num++;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000185#ifdef CONFIG_IEEE80211AX
186 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
187 num++;
188#endif /* CONFIG_IEEE80211AX */
189 h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
Hai Shalomfdcde762020-04-02 11:19:20 -0700190 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
Sunil Ravi77d572f2023-01-17 23:58:31 +0000191 hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700192 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
193 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700194 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700195 if (num <= 8)
196 return eid;
197 num -= 8;
198
199 *pos++ = WLAN_EID_EXT_SUPP_RATES;
200 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700201 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
202 i++) {
203 count++;
204 if (count <= 8)
205 continue; /* already in SuppRates IE */
206 *pos = hapd->iface->current_rates[i].rate / 5;
207 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
208 *pos |= 0x80;
209 pos++;
210 }
211
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800212 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
213 count++;
214 if (count > 8)
215 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
216 }
217
218 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
219 count++;
220 if (count > 8)
221 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
222 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700223
Sunil Ravi77d572f2023-01-17 23:58:31 +0000224#ifdef CONFIG_IEEE80211AX
225 if (hapd->iconf->ieee80211ax && hapd->iconf->require_he) {
226 count++;
227 if (count > 8)
228 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY;
229 }
230#endif /* CONFIG_IEEE80211AX */
231
Hai Shalomfdcde762020-04-02 11:19:20 -0700232 if (h2e_required) {
Hai Shalomc3565922019-10-28 11:58:20 -0700233 count++;
234 if (count > 8)
235 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
236 }
237
Sunil Ravi77d572f2023-01-17 23:58:31 +0000238 hapd->conf->xrates_supported = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700239 return pos;
240}
241
242
Hai Shalomfdcde762020-04-02 11:19:20 -0700243u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
244 size_t len)
245{
246 size_t i;
247
248 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
249 if (hapd->conf->radio_measurements[i])
250 break;
251 }
252
253 if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
254 return eid;
255
256 *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
257 *eid++ = RRM_CAPABILITIES_IE_LEN;
258 os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
259
260 return eid + RRM_CAPABILITIES_IE_LEN;
261}
262
263
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700264u16 hostapd_own_capab_info(struct hostapd_data *hapd)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700265{
266 int capab = WLAN_CAPABILITY_ESS;
Hai Shalomfdcde762020-04-02 11:19:20 -0700267 int privacy = 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800268 int dfs;
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700269 int i;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800270
271 /* Check if any of configured channels require DFS */
272 dfs = hostapd_is_dfs_required(hapd->iface);
273 if (dfs < 0) {
274 wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
275 dfs);
276 dfs = 0;
277 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700278
279 if (hapd->iface->num_sta_no_short_preamble == 0 &&
280 hapd->iconf->preamble == SHORT_PREAMBLE)
281 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
282
Hai Shalomfdcde762020-04-02 11:19:20 -0700283#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700284 privacy = hapd->conf->ssid.wep.keys_set;
285
286 if (hapd->conf->ieee802_1x &&
287 (hapd->conf->default_wep_key_len ||
288 hapd->conf->individual_wep_key_len))
289 privacy = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -0700290#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700291
292 if (hapd->conf->wpa)
293 privacy = 1;
294
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800295#ifdef CONFIG_HS20
296 if (hapd->conf->osen)
297 privacy = 1;
298#endif /* CONFIG_HS20 */
299
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700300 if (privacy)
301 capab |= WLAN_CAPABILITY_PRIVACY;
302
303 if (hapd->iface->current_mode &&
304 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
305 hapd->iface->num_sta_no_short_slot_time == 0)
306 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
307
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800308 /*
309 * Currently, Spectrum Management capability bit is set when directly
310 * requested in configuration by spectrum_mgmt_required or when AP is
311 * running on DFS channel.
312 * TODO: Also consider driver support for TPC to set Spectrum Mgmt bit
313 */
314 if (hapd->iface->current_mode &&
315 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
316 (hapd->iconf->spectrum_mgmt_required || dfs))
317 capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
318
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700319 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
320 if (hapd->conf->radio_measurements[i]) {
321 capab |= IEEE80211_CAP_RRM;
322 break;
323 }
324 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800325
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700326 return capab;
327}
328
329
Hai Shalomfdcde762020-04-02 11:19:20 -0700330#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800331#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700332static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
333 u16 auth_transaction, const u8 *challenge,
334 int iswep)
335{
336 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
337 HOSTAPD_LEVEL_DEBUG,
338 "authentication (shared key, transaction %d)",
339 auth_transaction);
340
341 if (auth_transaction == 1) {
342 if (!sta->challenge) {
343 /* Generate a pseudo-random challenge */
344 u8 key[8];
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800345
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700346 sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
347 if (sta->challenge == NULL)
348 return WLAN_STATUS_UNSPECIFIED_FAILURE;
349
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800350 if (os_get_random(key, sizeof(key)) < 0) {
351 os_free(sta->challenge);
352 sta->challenge = NULL;
353 return WLAN_STATUS_UNSPECIFIED_FAILURE;
354 }
355
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700356 rc4_skip(key, sizeof(key), 0,
357 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
358 }
359 return 0;
360 }
361
362 if (auth_transaction != 3)
363 return WLAN_STATUS_UNSPECIFIED_FAILURE;
364
365 /* Transaction 3 */
366 if (!iswep || !sta->challenge || !challenge ||
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700367 os_memcmp_const(sta->challenge, challenge,
368 WLAN_AUTH_CHALLENGE_LEN)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700369 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
370 HOSTAPD_LEVEL_INFO,
371 "shared key authentication - invalid "
372 "challenge-response");
373 return WLAN_STATUS_CHALLENGE_FAIL;
374 }
375
376 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
377 HOSTAPD_LEVEL_DEBUG,
378 "authentication OK (shared key)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700379 sta->flags |= WLAN_STA_AUTH;
380 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700381 os_free(sta->challenge);
382 sta->challenge = NULL;
383
384 return 0;
385}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800386#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700387#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700388
389
Hai Shalomfdcde762020-04-02 11:19:20 -0700390static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800391 const u8 *dst, const u8 *bssid,
392 u16 auth_alg, u16 auth_transaction, u16 resp,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700393 const u8 *ies, size_t ies_len, const char *dbg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700394{
395 struct ieee80211_mgmt *reply;
396 u8 *buf;
397 size_t rlen;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800398 int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700399
400 rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
401 buf = os_zalloc(rlen);
402 if (buf == NULL)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800403 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700404
405 reply = (struct ieee80211_mgmt *) buf;
406 reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
407 WLAN_FC_STYPE_AUTH);
408 os_memcpy(reply->da, dst, ETH_ALEN);
409 os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
410 os_memcpy(reply->bssid, bssid, ETH_ALEN);
411
412 reply->u.auth.auth_alg = host_to_le16(auth_alg);
413 reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
414 reply->u.auth.status_code = host_to_le16(resp);
415
416 if (ies && ies_len)
417 os_memcpy(reply->u.auth.variable, ies, ies_len);
418
419 wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700420 " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700421 MAC2STR(dst), auth_alg, auth_transaction,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700422 resp, (unsigned long) ies_len, dbg);
Hai Shalomfdcde762020-04-02 11:19:20 -0700423#ifdef CONFIG_TESTING_OPTIONS
424#ifdef CONFIG_SAE
425 if (hapd->conf->sae_confirm_immediate == 2 &&
426 auth_alg == WLAN_AUTH_SAE) {
427 if (auth_transaction == 1 && sta &&
428 (resp == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -0700429 resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
430 resp == WLAN_STATUS_SAE_PK)) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700431 wpa_printf(MSG_DEBUG,
432 "TESTING: Postpone SAE Commit transmission until Confirm is ready");
433 os_free(sta->sae_postponed_commit);
434 sta->sae_postponed_commit = buf;
435 sta->sae_postponed_commit_len = rlen;
436 return WLAN_STATUS_SUCCESS;
437 }
438
439 if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
440 wpa_printf(MSG_DEBUG,
441 "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
442 if (hostapd_drv_send_mlme(hapd,
443 sta->sae_postponed_commit,
444 sta->sae_postponed_commit_len,
445 0, NULL, 0, 0) < 0)
446 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
447 os_free(sta->sae_postponed_commit);
448 sta->sae_postponed_commit = NULL;
449 sta->sae_postponed_commit_len = 0;
450 }
451 }
452#endif /* CONFIG_SAE */
453#endif /* CONFIG_TESTING_OPTIONS */
454 if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800455 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
456 else
457 reply_res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700458
459 os_free(buf);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800460
461 return reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700462}
463
464
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800465#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700466static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
467 u16 auth_transaction, u16 status,
468 const u8 *ies, size_t ies_len)
469{
470 struct hostapd_data *hapd = ctx;
471 struct sta_info *sta;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800472 int reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700473
Hai Shalomfdcde762020-04-02 11:19:20 -0700474 reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700475 auth_transaction, status, ies, ies_len,
476 "auth-ft-finish");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700477
478 sta = ap_get_sta(hapd, dst);
479 if (sta == NULL)
480 return;
481
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800482 if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
483 status != WLAN_STATUS_SUCCESS)) {
484 hostapd_drv_sta_remove(hapd, sta->addr);
485 sta->added_unassoc = 0;
486 return;
487 }
488
489 if (status != WLAN_STATUS_SUCCESS)
490 return;
491
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700492 hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
493 HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
494 sta->flags |= WLAN_STA_AUTH;
495 mlme_authenticate_indication(hapd, sta);
496}
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800497#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700498
499
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800500#ifdef CONFIG_SAE
501
Roshan Pius3a1667e2018-07-03 15:17:14 -0700502static void sae_set_state(struct sta_info *sta, enum sae_state state,
503 const char *reason)
504{
505 wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
506 sae_state_txt(sta->sae->state), sae_state_txt(state),
507 MAC2STR(sta->addr), reason);
508 sta->sae->state = state;
509}
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800510
511
Hai Shalom60840252021-02-19 19:02:11 -0800512static const char * sae_get_password(struct hostapd_data *hapd,
513 struct sta_info *sta,
514 const char *rx_id,
515 struct sae_password_entry **pw_entry,
516 struct sae_pt **s_pt,
517 const struct sae_pk **s_pk)
518{
519 const char *password = NULL;
520 struct sae_password_entry *pw;
521 struct sae_pt *pt = NULL;
522 const struct sae_pk *pk = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -0700523 struct hostapd_sta_wpa_psk_short *psk = NULL;
Hai Shalom60840252021-02-19 19:02:11 -0800524
525 for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
526 if (!is_broadcast_ether_addr(pw->peer_addr) &&
527 os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
528 continue;
529 if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
530 continue;
531 if (rx_id && pw->identifier &&
532 os_strcmp(rx_id, pw->identifier) != 0)
533 continue;
534 password = pw->password;
535 pt = pw->pt;
536 if (!(hapd->conf->mesh & MESH_ENABLED))
537 pk = pw->pk;
538 break;
539 }
540 if (!password) {
541 password = hapd->conf->ssid.wpa_passphrase;
542 pt = hapd->conf->ssid.pt;
543 }
544
Sunil Ravia04bd252022-05-02 22:54:18 -0700545 if (!password) {
546 for (psk = sta->psk; psk; psk = psk->next) {
547 if (psk->is_passphrase) {
548 password = psk->passphrase;
549 break;
550 }
551 }
552 }
553
Hai Shalom60840252021-02-19 19:02:11 -0800554 if (pw_entry)
555 *pw_entry = pw;
556 if (s_pt)
557 *s_pt = pt;
558 if (s_pk)
559 *s_pk = pk;
560
561 return password;
562}
563
564
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800565static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
Hai Shalomc3565922019-10-28 11:58:20 -0700566 struct sta_info *sta, int update,
567 int status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800568{
569 struct wpabuf *buf;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700570 const char *password = NULL;
571 struct sae_password_entry *pw;
572 const char *rx_id = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700573 int use_pt = 0;
574 struct sae_pt *pt = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700575 const struct sae_pk *pk = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800576
Hai Shalomc3565922019-10-28 11:58:20 -0700577 if (sta->sae->tmp) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700578 rx_id = sta->sae->tmp->pw_id;
Hai Shalom899fcc72020-10-19 14:38:18 -0700579 use_pt = sta->sae->h2e;
580#ifdef CONFIG_SAE_PK
581 os_memcpy(sta->sae->tmp->own_addr, hapd->own_addr, ETH_ALEN);
582 os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
583#endif /* CONFIG_SAE_PK */
Hai Shalomc3565922019-10-28 11:58:20 -0700584 }
585
Sunil Ravi77d572f2023-01-17 23:58:31 +0000586 if (rx_id && hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
Hai Shalomfdcde762020-04-02 11:19:20 -0700587 use_pt = 1;
588 else if (status_code == WLAN_STATUS_SUCCESS)
Hai Shalomc3565922019-10-28 11:58:20 -0700589 use_pt = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700590 else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
591 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomc3565922019-10-28 11:58:20 -0700592 use_pt = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700593
Hai Shalom60840252021-02-19 19:02:11 -0800594 password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk);
Hai Shalomc3565922019-10-28 11:58:20 -0700595 if (!password || (use_pt && !pt)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800596 wpa_printf(MSG_DEBUG, "SAE: No password available");
597 return NULL;
598 }
599
Hai Shalomc3565922019-10-28 11:58:20 -0700600 if (update && use_pt &&
601 sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
Hai Shalom899fcc72020-10-19 14:38:18 -0700602 NULL, pk) < 0)
Hai Shalomc3565922019-10-28 11:58:20 -0700603 return NULL;
604
605 if (update && !use_pt &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800606 sae_prepare_commit(hapd->own_addr, sta->addr,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800607 (u8 *) password, os_strlen(password),
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800608 sta->sae) < 0) {
609 wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
610 return NULL;
611 }
612
Hai Shalom021b0b52019-04-10 11:17:58 -0700613 if (pw && pw->vlan_id) {
614 if (!sta->sae->tmp) {
615 wpa_printf(MSG_INFO,
616 "SAE: No temporary data allocated - cannot store VLAN ID");
617 return NULL;
618 }
619 sta->sae->tmp->vlan_id = pw->vlan_id;
620 }
621
Roshan Pius3a1667e2018-07-03 15:17:14 -0700622 buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
623 (rx_id ? 3 + os_strlen(rx_id) : 0));
Hai Shalomfdcde762020-04-02 11:19:20 -0700624 if (buf &&
625 sae_write_commit(sta->sae, buf, sta->sae->tmp ?
626 sta->sae->tmp->anti_clogging_token : NULL,
627 rx_id) < 0) {
628 wpabuf_free(buf);
629 buf = NULL;
630 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800631
632 return buf;
633}
634
635
636static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
637 struct sta_info *sta)
638{
639 struct wpabuf *buf;
640
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800641 buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800642 if (buf == NULL)
643 return NULL;
644
Hai Shalom899fcc72020-10-19 14:38:18 -0700645#ifdef CONFIG_SAE_PK
646#ifdef CONFIG_TESTING_OPTIONS
647 if (sta->sae->tmp)
648 sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
649#endif /* CONFIG_TESTING_OPTIONS */
650#endif /* CONFIG_SAE_PK */
651
652 if (sae_write_confirm(sta->sae, buf) < 0) {
653 wpabuf_free(buf);
654 return NULL;
655 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800656
657 return buf;
658}
659
660
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800661static int auth_sae_send_commit(struct hostapd_data *hapd,
662 struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700663 const u8 *bssid, int update, int status_code)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800664{
665 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800666 int reply_res;
Hai Shalomc3565922019-10-28 11:58:20 -0700667 u16 status;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800668
Hai Shalomc3565922019-10-28 11:58:20 -0700669 data = auth_build_sae_commit(hapd, sta, update, status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700670 if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
671 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800672 if (data == NULL)
673 return WLAN_STATUS_UNSPECIFIED_FAILURE;
674
Hai Shalom899fcc72020-10-19 14:38:18 -0700675 if (sta->sae->tmp && sta->sae->pk)
676 status = WLAN_STATUS_SAE_PK;
677 else if (sta->sae->tmp && sta->sae->h2e)
678 status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
679 else
680 status = WLAN_STATUS_SUCCESS;
681#ifdef CONFIG_TESTING_OPTIONS
682 if (hapd->conf->sae_commit_status >= 0 &&
683 hapd->conf->sae_commit_status != status) {
684 wpa_printf(MSG_INFO,
685 "TESTING: Override SAE commit status code %u --> %d",
686 status, hapd->conf->sae_commit_status);
687 status = hapd->conf->sae_commit_status;
688 }
689#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomfdcde762020-04-02 11:19:20 -0700690 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
691 WLAN_AUTH_SAE, 1,
Hai Shalomc3565922019-10-28 11:58:20 -0700692 status, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700693 wpabuf_len(data), "sae-send-commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800694
695 wpabuf_free(data);
696
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800697 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800698}
699
700
701static int auth_sae_send_confirm(struct hostapd_data *hapd,
702 struct sta_info *sta,
703 const u8 *bssid)
704{
705 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800706 int reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800707
708 data = auth_build_sae_confirm(hapd, sta);
709 if (data == NULL)
710 return WLAN_STATUS_UNSPECIFIED_FAILURE;
711
Hai Shalomfdcde762020-04-02 11:19:20 -0700712 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
713 WLAN_AUTH_SAE, 2,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800714 WLAN_STATUS_SUCCESS, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700715 wpabuf_len(data), "sae-send-confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800716
717 wpabuf_free(data);
718
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800719 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800720}
721
Hai Shaloma20dcd72022-02-04 13:43:00 -0800722#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800723
Hai Shaloma20dcd72022-02-04 13:43:00 -0800724
725#if defined(CONFIG_SAE) || defined(CONFIG_PASN)
726
727static int use_anti_clogging(struct hostapd_data *hapd)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800728{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800729 struct sta_info *sta;
730 unsigned int open = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800731
Hai Shaloma20dcd72022-02-04 13:43:00 -0800732 if (hapd->conf->anti_clogging_threshold == 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800733 return 1;
734
735 for (sta = hapd->sta_list; sta; sta = sta->next) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800736#ifdef CONFIG_SAE
737 if (sta->sae &&
738 (sta->sae->state == SAE_COMMITTED ||
739 sta->sae->state == SAE_CONFIRMED))
740 open++;
741#endif /* CONFIG_SAE */
742#ifdef CONFIG_PASN
743 if (sta->pasn && sta->pasn->ecdh)
744 open++;
745#endif /* CONFIG_PASN */
746 if (open >= hapd->conf->anti_clogging_threshold)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800747 return 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800748 }
749
Hai Shaloma20dcd72022-02-04 13:43:00 -0800750#ifdef CONFIG_SAE
Hai Shalom021b0b52019-04-10 11:17:58 -0700751 /* In addition to already existing open SAE sessions, check whether
752 * there are enough pending commit messages in the processing queue to
753 * potentially result in too many open sessions. */
754 if (open + dl_list_len(&hapd->sae_commit_queue) >=
Hai Shaloma20dcd72022-02-04 13:43:00 -0800755 hapd->conf->anti_clogging_threshold)
Hai Shalom021b0b52019-04-10 11:17:58 -0700756 return 1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800757#endif /* CONFIG_SAE */
Hai Shalom021b0b52019-04-10 11:17:58 -0700758
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800759 return 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800760}
761
Hai Shaloma20dcd72022-02-04 13:43:00 -0800762#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
763
764
765#ifdef CONFIG_SAE
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800766
Roshan Pius3a1667e2018-07-03 15:17:14 -0700767static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800768{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700769 if (sta->sae->sync > hapd->conf->sae_sync) {
770 sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800771 sta->sae->sync = 0;
772 return -1;
773 }
774 return 0;
775}
776
777
778static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
779{
780 struct hostapd_data *hapd = eloop_ctx;
781 struct sta_info *sta = eloop_data;
782 int ret;
783
Roshan Pius3a1667e2018-07-03 15:17:14 -0700784 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800785 return;
786 sta->sae->sync++;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700787 wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700788 " (sync=%d state=%s)",
789 MAC2STR(sta->addr), sta->sae->sync,
790 sae_state_txt(sta->sae->state));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800791
792 switch (sta->sae->state) {
793 case SAE_COMMITTED:
Hai Shalomc3565922019-10-28 11:58:20 -0700794 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800795 eloop_register_timeout(0,
796 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800797 auth_sae_retransmit_timer, hapd, sta);
798 break;
799 case SAE_CONFIRMED:
800 ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800801 eloop_register_timeout(0,
802 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800803 auth_sae_retransmit_timer, hapd, sta);
804 break;
805 default:
806 ret = -1;
807 break;
808 }
809
810 if (ret != WLAN_STATUS_SUCCESS)
811 wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
812}
813
814
815void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
816{
817 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
818}
819
820
821static void sae_set_retransmit_timer(struct hostapd_data *hapd,
822 struct sta_info *sta)
823{
824 if (!(hapd->conf->mesh & MESH_ENABLED))
825 return;
826
827 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800828 eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800829 auth_sae_retransmit_timer, hapd, sta);
830}
831
832
Hai Shalom5f92bc92019-04-18 11:54:11 -0700833static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
834 struct sta_info *sta, u16 status)
835{
836 struct external_auth params;
837
838 os_memset(&params, 0, sizeof(params));
839 params.status = status;
840 params.bssid = sta->addr;
Hai Shalom81f62d82019-07-22 12:10:00 -0700841 if (status == WLAN_STATUS_SUCCESS && sta->sae &&
842 !hapd->conf->disable_pmksa_caching)
Hai Shalom5f92bc92019-04-18 11:54:11 -0700843 params.pmkid = sta->sae->pmkid;
844
845 hostapd_drv_send_external_auth_status(hapd, &params);
846}
847
848
Dmitry Shmidte4663042016-04-04 10:07:49 -0700849void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
850{
Hai Shalom021b0b52019-04-10 11:17:58 -0700851#ifndef CONFIG_NO_VLAN
852 struct vlan_description vlan_desc;
853
854 if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
855 wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
856 " to VLAN ID %d",
857 MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
858
859 os_memset(&vlan_desc, 0, sizeof(vlan_desc));
860 vlan_desc.notempty = 1;
861 vlan_desc.untagged = sta->sae->tmp->vlan_id;
862 if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
863 wpa_printf(MSG_INFO,
864 "Invalid VLAN ID %d in sae_password",
865 sta->sae->tmp->vlan_id);
866 return;
867 }
868
869 if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
870 ap_sta_bind_vlan(hapd, sta) < 0) {
871 wpa_printf(MSG_INFO,
872 "Failed to assign VLAN ID %d from sae_password to "
873 MACSTR, sta->sae->tmp->vlan_id,
874 MAC2STR(sta->addr));
875 return;
876 }
877 }
878#endif /* CONFIG_NO_VLAN */
879
Dmitry Shmidte4663042016-04-04 10:07:49 -0700880 sta->flags |= WLAN_STA_AUTH;
881 sta->auth_alg = WLAN_AUTH_SAE;
882 mlme_authenticate_indication(hapd, sta);
883 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700884 sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
Hai Shalomfdcde762020-04-02 11:19:20 -0700885 crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
886 sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
887 sta->sae->peer_commit_scalar = NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -0700888 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
Sunil Ravi89eba102022-09-13 21:04:37 -0700889 sta->sae->pmk, sta->sae->pmk_len,
890 sta->sae->pmkid, sta->sae->akmp);
Hai Shalom5f92bc92019-04-18 11:54:11 -0700891 sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
Dmitry Shmidte4663042016-04-04 10:07:49 -0700892}
893
894
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800895static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700896 const u8 *bssid, u16 auth_transaction, u16 status_code,
897 int allow_reuse, int *sta_removed)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800898{
899 int ret;
900
Hai Shalom5f92bc92019-04-18 11:54:11 -0700901 *sta_removed = 0;
902
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800903 if (auth_transaction != 1 && auth_transaction != 2)
904 return WLAN_STATUS_UNSPECIFIED_FAILURE;
905
Roshan Pius3a1667e2018-07-03 15:17:14 -0700906 wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
907 MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
908 auth_transaction);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800909 switch (sta->sae->state) {
910 case SAE_NOTHING:
911 if (auth_transaction == 1) {
Hai Shalom899fcc72020-10-19 14:38:18 -0700912 if (sta->sae->tmp) {
913 sta->sae->h2e =
914 (status_code ==
915 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
916 status_code == WLAN_STATUS_SAE_PK);
917 sta->sae->pk =
918 status_code == WLAN_STATUS_SAE_PK;
919 }
Hai Shalom021b0b52019-04-10 11:17:58 -0700920 ret = auth_sae_send_commit(hapd, sta, bssid,
Hai Shalomc3565922019-10-28 11:58:20 -0700921 !allow_reuse, status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800922 if (ret)
923 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700924 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800925
926 if (sae_process_commit(sta->sae) < 0)
927 return WLAN_STATUS_UNSPECIFIED_FAILURE;
928
929 /*
Hai Shalomc3565922019-10-28 11:58:20 -0700930 * In mesh case, both Commit and Confirm are sent
931 * immediately. In infrastructure BSS, by default, only
932 * a single Authentication frame (Commit) is expected
933 * from the AP here and the second one (Confirm) will
934 * be sent once the STA has sent its second
935 * Authentication frame (Confirm). This behavior can be
936 * overridden with explicit configuration so that the
937 * infrastructure BSS case sends both frames together.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800938 */
Hai Shalomc3565922019-10-28 11:58:20 -0700939 if ((hapd->conf->mesh & MESH_ENABLED) ||
940 hapd->conf->sae_confirm_immediate) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800941 /*
942 * Send both Commit and Confirm immediately
943 * based on SAE finite state machine
944 * Nothing -> Confirm transition.
945 */
946 ret = auth_sae_send_confirm(hapd, sta, bssid);
947 if (ret)
948 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700949 sae_set_state(sta, SAE_CONFIRMED,
950 "Sent Confirm (mesh)");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800951 } else {
952 /*
953 * For infrastructure BSS, send only the Commit
954 * message now to get alternating sequence of
955 * Authentication frames between the AP and STA.
956 * Confirm will be sent in
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800957 * Committed -> Confirmed/Accepted transition
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800958 * when receiving Confirm from STA.
959 */
960 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800961 sta->sae->sync = 0;
962 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800963 } else {
964 hostapd_logger(hapd, sta->addr,
965 HOSTAPD_MODULE_IEEE80211,
966 HOSTAPD_LEVEL_DEBUG,
967 "SAE confirm before commit");
968 }
969 break;
970 case SAE_COMMITTED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800971 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800972 if (auth_transaction == 1) {
973 if (sae_process_commit(sta->sae) < 0)
974 return WLAN_STATUS_UNSPECIFIED_FAILURE;
975
976 ret = auth_sae_send_confirm(hapd, sta, bssid);
977 if (ret)
978 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700979 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800980 sta->sae->sync = 0;
981 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800982 } else if (hapd->conf->mesh & MESH_ENABLED) {
983 /*
984 * In mesh case, follow SAE finite state machine and
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800985 * send Commit now, if sync count allows.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800986 */
Roshan Pius3a1667e2018-07-03 15:17:14 -0700987 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800988 return WLAN_STATUS_SUCCESS;
989 sta->sae->sync++;
990
Hai Shalomc3565922019-10-28 11:58:20 -0700991 ret = auth_sae_send_commit(hapd, sta, bssid, 0,
992 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800993 if (ret)
994 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800995
996 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800997 } else {
998 /*
999 * For instructure BSS, send the postponed Confirm from
1000 * Nothing -> Confirmed transition that was reduced to
1001 * Nothing -> Committed above.
1002 */
1003 ret = auth_sae_send_confirm(hapd, sta, bssid);
1004 if (ret)
1005 return ret;
1006
Roshan Pius3a1667e2018-07-03 15:17:14 -07001007 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001008
1009 /*
1010 * Since this was triggered on Confirm RX, run another
1011 * step to get to Accepted without waiting for
1012 * additional events.
1013 */
Hai Shalom021b0b52019-04-10 11:17:58 -07001014 return sae_sm_step(hapd, sta, bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001015 WLAN_STATUS_SUCCESS, 0, sta_removed);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001016 }
1017 break;
1018 case SAE_CONFIRMED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001019 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001020 if (auth_transaction == 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001021 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001022 return WLAN_STATUS_SUCCESS;
1023 sta->sae->sync++;
1024
Hai Shalomc3565922019-10-28 11:58:20 -07001025 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1026 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001027 if (ret)
1028 return ret;
1029
1030 if (sae_process_commit(sta->sae) < 0)
1031 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1032
1033 ret = auth_sae_send_confirm(hapd, sta, bssid);
1034 if (ret)
1035 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001036
1037 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001038 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001039 sta->sae->send_confirm = 0xffff;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001040 sae_accept_sta(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001041 }
1042 break;
1043 case SAE_ACCEPTED:
Roshan Pius3a1667e2018-07-03 15:17:14 -07001044 if (auth_transaction == 1 &&
1045 (hapd->conf->mesh & MESH_ENABLED)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001046 wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
1047 ") doing reauthentication",
1048 MAC2STR(sta->addr));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001049 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
Hai Shalom5f92bc92019-04-18 11:54:11 -07001050 ap_free_sta(hapd, sta);
1051 *sta_removed = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001052 } else if (auth_transaction == 1) {
1053 wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
Hai Shalomc3565922019-10-28 11:58:20 -07001054 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1055 status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001056 if (ret)
1057 return ret;
1058 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
1059
1060 if (sae_process_commit(sta->sae) < 0)
1061 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1062 sta->sae->sync = 0;
1063 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001064 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001065 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001066 return WLAN_STATUS_SUCCESS;
1067 sta->sae->sync++;
1068
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001069 ret = auth_sae_send_confirm(hapd, sta, bssid);
1070 sae_clear_temp_data(sta->sae);
1071 if (ret)
1072 return ret;
1073 }
1074 break;
1075 default:
1076 wpa_printf(MSG_ERROR, "SAE: invalid state %d",
1077 sta->sae->state);
1078 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1079 }
1080 return WLAN_STATUS_SUCCESS;
1081}
1082
1083
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001084static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
1085{
1086 struct sae_data *sae = sta->sae;
1087 int i, *groups = hapd->conf->sae_groups;
Hai Shalom021b0b52019-04-10 11:17:58 -07001088 int default_groups[] = { 19, 0 };
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001089
1090 if (sae->state != SAE_COMMITTED)
1091 return;
1092
1093 wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
1094
Hai Shalom021b0b52019-04-10 11:17:58 -07001095 if (!groups)
1096 groups = default_groups;
1097 for (i = 0; groups[i] > 0; i++) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001098 if (sae->group == groups[i])
1099 break;
1100 }
1101
Hai Shalom021b0b52019-04-10 11:17:58 -07001102 if (groups[i] <= 0) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001103 wpa_printf(MSG_DEBUG,
1104 "SAE: Previously selected group not found from the current configuration");
1105 return;
1106 }
1107
1108 for (;;) {
1109 i++;
1110 if (groups[i] <= 0) {
1111 wpa_printf(MSG_DEBUG,
1112 "SAE: No alternative group enabled");
1113 return;
1114 }
1115
1116 if (sae_set_group(sae, groups[i]) < 0)
1117 continue;
1118
1119 break;
1120 }
1121 wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
1122}
1123
1124
Hai Shalomc3565922019-10-28 11:58:20 -07001125static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
1126{
Sunil Ravi77d572f2023-01-17 23:58:31 +00001127 enum sae_pwe sae_pwe = hapd->conf->sae_pwe;
Hai Shalomfdcde762020-04-02 11:19:20 -07001128 int id_in_use;
Hai Shalom60840252021-02-19 19:02:11 -08001129 bool sae_pk = false;
Hai Shalomfdcde762020-04-02 11:19:20 -07001130
1131 id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001132 if (id_in_use == 2 && sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
1133 sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
1134 else if (id_in_use == 1 && sae_pwe == SAE_PWE_HUNT_AND_PECK)
1135 sae_pwe = SAE_PWE_BOTH;
Hai Shalom899fcc72020-10-19 14:38:18 -07001136#ifdef CONFIG_SAE_PK
Hai Shalom60840252021-02-19 19:02:11 -08001137 sae_pk = hostapd_sae_pk_in_use(hapd->conf);
Sunil Ravi77d572f2023-01-17 23:58:31 +00001138 if (sae_pwe == SAE_PWE_HUNT_AND_PECK && sae_pk)
1139 sae_pwe = SAE_PWE_BOTH;
Hai Shalom899fcc72020-10-19 14:38:18 -07001140#endif /* CONFIG_SAE_PK */
Sunil Ravi77d572f2023-01-17 23:58:31 +00001141 if (sae_pwe == SAE_PWE_HUNT_AND_PECK &&
Sunil Ravi89eba102022-09-13 21:04:37 -07001142 (hapd->conf->wpa_key_mgmt &
1143 (WPA_KEY_MGMT_SAE_EXT_KEY | WPA_KEY_MGMT_FT_SAE_EXT_KEY)))
Sunil Ravi77d572f2023-01-17 23:58:31 +00001144 sae_pwe = SAE_PWE_BOTH;
Hai Shalomfdcde762020-04-02 11:19:20 -07001145
Sunil Ravi77d572f2023-01-17 23:58:31 +00001146 return ((sae_pwe == SAE_PWE_HUNT_AND_PECK ||
1147 sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001148 status_code == WLAN_STATUS_SUCCESS) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001149 (sae_pwe == SAE_PWE_HASH_TO_ELEMENT &&
Hai Shalom899fcc72020-10-19 14:38:18 -07001150 (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001151 (sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001152 (sae_pwe == SAE_PWE_BOTH &&
Hai Shalomc3565922019-10-28 11:58:20 -07001153 (status_code == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -07001154 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001155 (sae_pk && status_code == WLAN_STATUS_SAE_PK)));
Hai Shalomc3565922019-10-28 11:58:20 -07001156}
1157
1158
1159static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
1160{
1161 int *groups = hapd->conf->sae_groups;
1162 int default_groups[] = { 19, 0 };
1163 int i;
1164
1165 if (!groups)
1166 groups = default_groups;
1167
1168 for (i = 0; groups[i] > 0; i++) {
1169 if (groups[i] == group)
1170 return 1;
1171 }
1172
1173 return 0;
1174}
1175
1176
1177static int check_sae_rejected_groups(struct hostapd_data *hapd,
Hai Shalom899fcc72020-10-19 14:38:18 -07001178 struct sae_data *sae)
Hai Shalomc3565922019-10-28 11:58:20 -07001179{
Hai Shalom899fcc72020-10-19 14:38:18 -07001180 const struct wpabuf *groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001181 size_t i, count;
1182 const u8 *pos;
1183
Hai Shalom899fcc72020-10-19 14:38:18 -07001184 if (!sae->tmp)
1185 return 0;
1186 groups = sae->tmp->peer_rejected_groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001187 if (!groups)
1188 return 0;
1189
1190 pos = wpabuf_head(groups);
1191 count = wpabuf_len(groups) / 2;
1192 for (i = 0; i < count; i++) {
1193 int enabled;
1194 u16 group;
1195
1196 group = WPA_GET_LE16(pos);
1197 pos += 2;
1198 enabled = sae_is_group_enabled(hapd, group);
1199 wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
1200 group, enabled ? "enabled" : "disabled");
1201 if (enabled)
1202 return 1;
1203 }
1204
1205 return 0;
1206}
1207
1208
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001209static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
1210 const struct ieee80211_mgmt *mgmt, size_t len,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001211 u16 auth_transaction, u16 status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001212{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001213 int resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001214 struct wpabuf *data = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07001215 int *groups = hapd->conf->sae_groups;
1216 int default_groups[] = { 19, 0 };
1217 const u8 *pos, *end;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001218 int sta_removed = 0;
Hai Shalom60840252021-02-19 19:02:11 -08001219 bool success_status;
Hai Shalom021b0b52019-04-10 11:17:58 -07001220
1221 if (!groups)
1222 groups = default_groups;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001223
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001224#ifdef CONFIG_TESTING_OPTIONS
1225 if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001226 wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
1227 pos = mgmt->u.auth.variable;
1228 end = ((const u8 *) mgmt) + len;
Hai Shalom899fcc72020-10-19 14:38:18 -07001229 resp = status_code;
Hai Shalomfdcde762020-04-02 11:19:20 -07001230 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001231 auth_transaction, resp, pos, end - pos,
1232 "auth-sae-reflection-attack");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001233 goto remove_sta;
1234 }
1235
1236 if (hapd->conf->sae_commit_override && auth_transaction == 1) {
1237 wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
Hai Shalomfdcde762020-04-02 11:19:20 -07001238 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001239 auth_transaction, resp,
1240 wpabuf_head(hapd->conf->sae_commit_override),
Roshan Pius3a1667e2018-07-03 15:17:14 -07001241 wpabuf_len(hapd->conf->sae_commit_override),
1242 "sae-commit-override");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001243 goto remove_sta;
1244 }
1245#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001246 if (!sta->sae) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001247 if (auth_transaction != 1 ||
Hai Shalomc3565922019-10-28 11:58:20 -07001248 !sae_status_success(hapd, status_code)) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001249 wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
1250 status_code);
1251 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1252 goto reply;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001253 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001254 sta->sae = os_zalloc(sizeof(*sta->sae));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001255 if (!sta->sae) {
1256 resp = -1;
1257 goto remove_sta;
1258 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001259 sae_set_state(sta, SAE_NOTHING, "Init");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001260 sta->sae->sync = 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001261 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001262
Dmitry Shmidte4663042016-04-04 10:07:49 -07001263 if (sta->mesh_sae_pmksa_caching) {
1264 wpa_printf(MSG_DEBUG,
1265 "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
1266 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
1267 sta->mesh_sae_pmksa_caching = 0;
1268 }
1269
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001270 if (auth_transaction == 1) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001271 const u8 *token = NULL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001272 size_t token_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07001273 int allow_reuse = 0;
1274
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001275 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1276 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001277 "start SAE authentication (RX commit, status=%u (%s))",
1278 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001279
1280 if ((hapd->conf->mesh & MESH_ENABLED) &&
1281 status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
1282 sta->sae->tmp) {
1283 pos = mgmt->u.auth.variable;
1284 end = ((const u8 *) mgmt) + len;
1285 if (pos + sizeof(le16) > end) {
1286 wpa_printf(MSG_ERROR,
1287 "SAE: Too short anti-clogging token request");
1288 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1289 goto reply;
1290 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001291 resp = sae_group_allowed(sta->sae, groups,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001292 WPA_GET_LE16(pos));
1293 if (resp != WLAN_STATUS_SUCCESS) {
1294 wpa_printf(MSG_ERROR,
1295 "SAE: Invalid group in anti-clogging token request");
1296 goto reply;
1297 }
1298 pos += sizeof(le16);
1299
1300 wpabuf_free(sta->sae->tmp->anti_clogging_token);
1301 sta->sae->tmp->anti_clogging_token =
1302 wpabuf_alloc_copy(pos, end - pos);
1303 if (sta->sae->tmp->anti_clogging_token == NULL) {
1304 wpa_printf(MSG_ERROR,
1305 "SAE: Failed to alloc for anti-clogging token");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001306 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1307 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001308 }
1309
1310 /*
1311 * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code
1312 * is 76, a new Commit Message shall be constructed
1313 * with the Anti-Clogging Token from the received
1314 * Authentication frame, and the commit-scalar and
1315 * COMMIT-ELEMENT previously sent.
1316 */
Hai Shalomc3565922019-10-28 11:58:20 -07001317 resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
1318 status_code);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001319 if (resp != WLAN_STATUS_SUCCESS) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001320 wpa_printf(MSG_ERROR,
1321 "SAE: Failed to send commit message");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001322 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001323 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001324 sae_set_state(sta, SAE_COMMITTED,
1325 "Sent Commit (anti-clogging token case in mesh)");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001326 sta->sae->sync = 0;
1327 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001328 return;
1329 }
1330
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001331 if ((hapd->conf->mesh & MESH_ENABLED) &&
1332 status_code ==
1333 WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1334 sta->sae->tmp) {
1335 wpa_printf(MSG_DEBUG,
1336 "SAE: Peer did not accept our SAE group");
1337 sae_pick_next_group(hapd, sta);
1338 goto remove_sta;
1339 }
1340
Hai Shalomc3565922019-10-28 11:58:20 -07001341 if (!sae_status_success(hapd, status_code))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001342 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001343
Roshan Pius3a1667e2018-07-03 15:17:14 -07001344 if (!(hapd->conf->mesh & MESH_ENABLED) &&
1345 sta->sae->state == SAE_COMMITTED) {
1346 /* This is needed in the infrastructure BSS case to
1347 * address a sequence where a STA entry may remain in
1348 * hostapd across two attempts to do SAE authentication
1349 * by the same STA. The second attempt may end up trying
1350 * to use a different group and that would not be
1351 * allowed if we remain in Committed state with the
1352 * previously set parameters. */
Hai Shalom021b0b52019-04-10 11:17:58 -07001353 pos = mgmt->u.auth.variable;
1354 end = ((const u8 *) mgmt) + len;
1355 if (end - pos >= (int) sizeof(le16) &&
1356 sae_group_allowed(sta->sae, groups,
1357 WPA_GET_LE16(pos)) ==
1358 WLAN_STATUS_SUCCESS) {
1359 /* Do not waste resources deriving the same PWE
1360 * again since the same group is reused. */
1361 sae_set_state(sta, SAE_NOTHING,
1362 "Allow previous PWE to be reused");
1363 allow_reuse = 1;
1364 } else {
1365 sae_set_state(sta, SAE_NOTHING,
1366 "Clear existing state to allow restart");
1367 sae_clear_data(sta->sae);
1368 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001369 }
1370
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001371 resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
1372 ((const u8 *) mgmt) + len -
1373 mgmt->u.auth.variable, &token,
Hai Shalomc3565922019-10-28 11:58:20 -07001374 &token_len, groups, status_code ==
Hai Shalom899fcc72020-10-19 14:38:18 -07001375 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001376 status_code == WLAN_STATUS_SAE_PK,
1377 NULL);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001378 if (resp == SAE_SILENTLY_DISCARD) {
1379 wpa_printf(MSG_DEBUG,
1380 "SAE: Drop commit message from " MACSTR " due to reflection attack",
1381 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001382 goto remove_sta;
Dmitry Shmidt41712582015-06-29 11:02:15 -07001383 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001384
1385 if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
1386 wpa_msg(hapd->msg_ctx, MSG_INFO,
1387 WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
1388 MACSTR, MAC2STR(sta->addr));
1389 sae_clear_retransmit_timer(hapd, sta);
1390 sae_set_state(sta, SAE_NOTHING,
1391 "Unknown Password Identifier");
1392 goto remove_sta;
1393 }
1394
Hai Shaloma20dcd72022-02-04 13:43:00 -08001395 if (token &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00001396 check_comeback_token(hapd->comeback_key,
1397 hapd->comeback_pending_idx, sta->addr,
1398 token, token_len)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001399 < 0) {
1400 wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
1401 "incorrect token from " MACSTR,
1402 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001403 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1404 goto remove_sta;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001405 }
1406
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001407 if (resp != WLAN_STATUS_SUCCESS)
1408 goto reply;
1409
Hai Shalom899fcc72020-10-19 14:38:18 -07001410 if (check_sae_rejected_groups(hapd, sta->sae)) {
Hai Shalomc3565922019-10-28 11:58:20 -07001411 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001412 goto reply;
Hai Shalomc3565922019-10-28 11:58:20 -07001413 }
1414
Hai Shaloma20dcd72022-02-04 13:43:00 -08001415 if (!token && use_anti_clogging(hapd) && !allow_reuse) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001416 int h2e = 0;
1417
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001418 wpa_printf(MSG_DEBUG,
1419 "SAE: Request anti-clogging token from "
1420 MACSTR, MAC2STR(sta->addr));
Hai Shalomfdcde762020-04-02 11:19:20 -07001421 if (sta->sae->tmp)
Hai Shalom899fcc72020-10-19 14:38:18 -07001422 h2e = sta->sae->h2e;
1423 if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1424 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomfdcde762020-04-02 11:19:20 -07001425 h2e = 1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001426 data = auth_build_token_req(
1427 &hapd->last_comeback_key_update,
1428 hapd->comeback_key,
1429 hapd->comeback_idx,
1430 hapd->comeback_pending_idx,
1431 sizeof(hapd->comeback_pending_idx),
1432 sta->sae->group,
1433 sta->addr, h2e);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001434 resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
1435 if (hapd->conf->mesh & MESH_ENABLED)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001436 sae_set_state(sta, SAE_NOTHING,
1437 "Request anti-clogging token case in mesh");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001438 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001439 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001440
Hai Shalom021b0b52019-04-10 11:17:58 -07001441 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001442 status_code, allow_reuse, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001443 } else if (auth_transaction == 2) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001444 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1445 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001446 "SAE authentication (RX confirm, status=%u (%s))",
1447 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001448 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001449 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001450 if (sta->sae->state >= SAE_CONFIRMED ||
1451 !(hapd->conf->mesh & MESH_ENABLED)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001452 const u8 *var;
1453 size_t var_len;
1454 u16 peer_send_confirm;
1455
1456 var = mgmt->u.auth.variable;
1457 var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable;
1458 if (var_len < 2) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001459 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001460 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001461 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001462
1463 peer_send_confirm = WPA_GET_LE16(var);
1464
1465 if (sta->sae->state == SAE_ACCEPTED &&
1466 (peer_send_confirm <= sta->sae->rc ||
1467 peer_send_confirm == 0xffff)) {
1468 wpa_printf(MSG_DEBUG,
1469 "SAE: Silently ignore unexpected Confirm from peer "
1470 MACSTR
1471 " (peer-send-confirm=%u Rc=%u)",
1472 MAC2STR(sta->addr),
1473 peer_send_confirm, sta->sae->rc);
1474 return;
1475 }
1476
Sunil Ravi77d572f2023-01-17 23:58:31 +00001477 if (sae_check_confirm(sta->sae, var, var_len,
1478 NULL) < 0) {
1479 resp = WLAN_STATUS_CHALLENGE_FAIL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001480 goto reply;
1481 }
1482 sta->sae->rc = peer_send_confirm;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001483 }
Hai Shalomc3565922019-10-28 11:58:20 -07001484 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
1485 status_code, 0, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001486 } else {
1487 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1488 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001489 "unexpected SAE authentication transaction %u (status=%u (%s))",
1490 auth_transaction, status_code,
1491 status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001492 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001493 goto remove_sta;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001494 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1495 }
1496
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001497reply:
Hai Shalom5f92bc92019-04-18 11:54:11 -07001498 if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001499 pos = mgmt->u.auth.variable;
1500 end = ((const u8 *) mgmt) + len;
1501
1502 /* Copy the Finite Cyclic Group field from the request if we
1503 * rejected it as unsupported group. */
1504 if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1505 !data && end - pos >= 2)
1506 data = wpabuf_alloc_copy(pos, 2);
1507
Hai Shalom5f92bc92019-04-18 11:54:11 -07001508 sae_sme_send_external_auth_status(hapd, sta, resp);
Hai Shalomfdcde762020-04-02 11:19:20 -07001509 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001510 auth_transaction, resp,
1511 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07001512 data ? wpabuf_len(data) : 0, "auth-sae");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001513 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001514
1515remove_sta:
Hai Shalom60840252021-02-19 19:02:11 -08001516 if (auth_transaction == 1)
1517 success_status = sae_status_success(hapd, status_code);
1518 else
1519 success_status = status_code == WLAN_STATUS_SUCCESS;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001520 if (!sta_removed && sta->added_unassoc &&
Hai Shalom60840252021-02-19 19:02:11 -08001521 (resp != WLAN_STATUS_SUCCESS || !success_status)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001522 hostapd_drv_sta_remove(hapd, sta->addr);
1523 sta->added_unassoc = 0;
1524 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001525 wpabuf_free(data);
1526}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001527
1528
1529/**
1530 * auth_sae_init_committed - Send COMMIT and start SAE in committed state
1531 * @hapd: BSS data for the device initiating the authentication
1532 * @sta: the peer to which commit authentication frame is sent
1533 *
1534 * This function implements Init event handling (IEEE Std 802.11-2012,
1535 * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
1536 * sta->sae structure should be initialized appropriately via a call to
1537 * sae_prepare_commit().
1538 */
1539int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
1540{
1541 int ret;
1542
1543 if (!sta->sae || !sta->sae->tmp)
1544 return -1;
1545
1546 if (sta->sae->state != SAE_NOTHING)
1547 return -1;
1548
Hai Shalomc3565922019-10-28 11:58:20 -07001549 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001550 if (ret)
1551 return -1;
1552
Roshan Pius3a1667e2018-07-03 15:17:14 -07001553 sae_set_state(sta, SAE_COMMITTED, "Init and sent commit");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001554 sta->sae->sync = 0;
1555 sae_set_retransmit_timer(hapd, sta);
1556
1557 return 0;
1558}
1559
Hai Shalom021b0b52019-04-10 11:17:58 -07001560
1561void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
1562{
1563 struct hostapd_data *hapd = eloop_ctx;
1564 struct hostapd_sae_commit_queue *q;
1565 unsigned int queue_len;
1566
1567 q = dl_list_first(&hapd->sae_commit_queue,
1568 struct hostapd_sae_commit_queue, list);
1569 if (!q)
1570 return;
1571 wpa_printf(MSG_DEBUG,
1572 "SAE: Process next available message from queue");
1573 dl_list_del(&q->list);
1574 handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
1575 q->rssi, 1);
1576 os_free(q);
1577
1578 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1579 return;
1580 queue_len = dl_list_len(&hapd->sae_commit_queue);
1581 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1582 hapd, NULL);
1583}
1584
1585
1586static void auth_sae_queue(struct hostapd_data *hapd,
1587 const struct ieee80211_mgmt *mgmt, size_t len,
1588 int rssi)
1589{
1590 struct hostapd_sae_commit_queue *q, *q2;
1591 unsigned int queue_len;
1592 const struct ieee80211_mgmt *mgmt2;
1593
1594 queue_len = dl_list_len(&hapd->sae_commit_queue);
1595 if (queue_len >= 15) {
1596 wpa_printf(MSG_DEBUG,
1597 "SAE: No more room in message queue - drop the new frame from "
1598 MACSTR, MAC2STR(mgmt->sa));
1599 return;
1600 }
1601
1602 wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
1603 MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
1604 queue_len);
1605 q = os_zalloc(sizeof(*q) + len);
1606 if (!q)
1607 return;
1608 q->rssi = rssi;
1609 q->len = len;
1610 os_memcpy(q->msg, mgmt, len);
1611
1612 /* Check whether there is already a queued Authentication frame from the
1613 * same station with the same transaction number and if so, replace that
1614 * queue entry with the new one. This avoids issues with a peer that
1615 * sends multiple times (e.g., due to frequent SAE retries). There is no
1616 * point in us trying to process the old attempts after a new one has
1617 * obsoleted them. */
1618 dl_list_for_each(q2, &hapd->sae_commit_queue,
1619 struct hostapd_sae_commit_queue, list) {
1620 mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
1621 if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 &&
1622 mgmt->u.auth.auth_transaction ==
1623 mgmt2->u.auth.auth_transaction) {
1624 wpa_printf(MSG_DEBUG,
1625 "SAE: Replace queued message from same STA with same transaction number");
1626 dl_list_add(&q2->list, &q->list);
1627 dl_list_del(&q2->list);
1628 os_free(q2);
1629 goto queued;
1630 }
1631 }
1632
1633 /* No pending identical entry, so add to the end of the queue */
1634 dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
1635
1636queued:
1637 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1638 return;
1639 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1640 hapd, NULL);
1641}
1642
1643
1644static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
1645{
1646 struct hostapd_sae_commit_queue *q;
1647 const struct ieee80211_mgmt *mgmt;
1648
1649 dl_list_for_each(q, &hapd->sae_commit_queue,
1650 struct hostapd_sae_commit_queue, list) {
1651 mgmt = (const struct ieee80211_mgmt *) q->msg;
1652 if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0)
1653 return 1;
1654 }
1655
1656 return 0;
1657}
1658
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001659#endif /* CONFIG_SAE */
1660
1661
Hai Shalomfdcde762020-04-02 11:19:20 -07001662static u16 wpa_res_to_status_code(enum wpa_validate_result res)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001663{
Hai Shalomfdcde762020-04-02 11:19:20 -07001664 switch (res) {
1665 case WPA_IE_OK:
1666 return WLAN_STATUS_SUCCESS;
1667 case WPA_INVALID_IE:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001668 return WLAN_STATUS_INVALID_IE;
Hai Shalomfdcde762020-04-02 11:19:20 -07001669 case WPA_INVALID_GROUP:
1670 return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
1671 case WPA_INVALID_PAIRWISE:
1672 return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
1673 case WPA_INVALID_AKMP:
1674 return WLAN_STATUS_AKMP_NOT_VALID;
1675 case WPA_NOT_ENABLED:
1676 return WLAN_STATUS_INVALID_IE;
1677 case WPA_ALLOC_FAIL:
1678 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1679 case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
1680 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
1681 case WPA_INVALID_MGMT_GROUP_CIPHER:
1682 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
1683 case WPA_INVALID_MDIE:
1684 return WLAN_STATUS_INVALID_MDIE;
1685 case WPA_INVALID_PROTO:
1686 return WLAN_STATUS_INVALID_IE;
1687 case WPA_INVALID_PMKID:
1688 return WLAN_STATUS_INVALID_PMKID;
1689 case WPA_DENIED_OTHER_REASON:
1690 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
1691 }
1692 return WLAN_STATUS_INVALID_IE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001693}
1694
1695
1696#ifdef CONFIG_FILS
1697
1698static void handle_auth_fils_finish(struct hostapd_data *hapd,
1699 struct sta_info *sta, u16 resp,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001700 struct wpabuf *data, int pub);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001701
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001702void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
1703 const u8 *pos, size_t len, u16 auth_alg,
1704 u16 auth_transaction, u16 status_code,
1705 void (*cb)(struct hostapd_data *hapd,
1706 struct sta_info *sta, u16 resp,
1707 struct wpabuf *data, int pub))
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001708{
1709 u16 resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001710 const u8 *end;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001711 struct ieee802_11_elems elems;
Hai Shalomfdcde762020-04-02 11:19:20 -07001712 enum wpa_validate_result res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001713 struct wpa_ie_data rsn;
1714 struct rsn_pmksa_cache_entry *pmksa = NULL;
1715
1716 if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
1717 return;
1718
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001719 end = pos + len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001720
1721 wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
1722 pos, end - pos);
1723
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001724 /* TODO: FILS PK */
1725#ifdef CONFIG_FILS_SK_PFS
1726 if (auth_alg == WLAN_AUTH_FILS_SK_PFS) {
1727 u16 group;
1728 struct wpabuf *pub;
1729 size_t elem_len;
1730
1731 /* Using FILS PFS */
1732
1733 /* Finite Cyclic Group */
1734 if (end - pos < 2) {
1735 wpa_printf(MSG_DEBUG,
1736 "FILS: No room for Finite Cyclic Group");
1737 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1738 goto fail;
1739 }
1740 group = WPA_GET_LE16(pos);
1741 pos += 2;
1742 if (group != hapd->conf->fils_dh_group) {
1743 wpa_printf(MSG_DEBUG,
1744 "FILS: Unsupported Finite Cyclic Group: %u (expected %u)",
1745 group, hapd->conf->fils_dh_group);
1746 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1747 goto fail;
1748 }
1749
1750 crypto_ecdh_deinit(sta->fils_ecdh);
1751 sta->fils_ecdh = crypto_ecdh_init(group);
1752 if (!sta->fils_ecdh) {
1753 wpa_printf(MSG_INFO,
1754 "FILS: Could not initialize ECDH with group %d",
1755 group);
1756 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1757 goto fail;
1758 }
1759
1760 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
1761 if (!pub) {
1762 wpa_printf(MSG_DEBUG,
1763 "FILS: Failed to derive ECDH public key");
1764 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1765 goto fail;
1766 }
1767 elem_len = wpabuf_len(pub);
1768 wpabuf_free(pub);
1769
1770 /* Element */
1771 if ((size_t) (end - pos) < elem_len) {
1772 wpa_printf(MSG_DEBUG, "FILS: No room for Element");
1773 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1774 goto fail;
1775 }
1776
1777 wpabuf_free(sta->fils_g_sta);
1778 sta->fils_g_sta = wpabuf_alloc_copy(pos, elem_len);
1779 wpabuf_clear_free(sta->fils_dh_ss);
1780 sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1,
1781 pos, elem_len);
1782 if (!sta->fils_dh_ss) {
1783 wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
1784 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1785 goto fail;
1786 }
1787 wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss);
1788 pos += elem_len;
1789 } else {
1790 crypto_ecdh_deinit(sta->fils_ecdh);
1791 sta->fils_ecdh = NULL;
1792 wpabuf_clear_free(sta->fils_dh_ss);
1793 sta->fils_dh_ss = NULL;
1794 }
1795#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001796
1797 wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
1798 if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
1799 wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
1800 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1801 goto fail;
1802 }
1803
1804 /* RSNE */
1805 wpa_hexdump(MSG_DEBUG, "FILS: RSN element",
1806 elems.rsn_ie, elems.rsn_ie_len);
1807 if (!elems.rsn_ie ||
1808 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
1809 &rsn) < 0) {
1810 wpa_printf(MSG_DEBUG, "FILS: No valid RSN element");
1811 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1812 goto fail;
1813 }
1814
1815 if (!sta->wpa_sm)
1816 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
1817 NULL);
1818 if (!sta->wpa_sm) {
1819 wpa_printf(MSG_DEBUG,
1820 "FILS: Failed to initialize RSN state machine");
1821 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1822 goto fail;
1823 }
1824
1825 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07001826 hapd->iface->freq,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001827 elems.rsn_ie - 2, elems.rsn_ie_len + 2,
Hai Shalomc3565922019-10-28 11:58:20 -07001828 elems.rsnxe ? elems.rsnxe - 2 : NULL,
1829 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001830 elems.mdie, elems.mdie_len, NULL, 0);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001831 resp = wpa_res_to_status_code(res);
1832 if (resp != WLAN_STATUS_SUCCESS)
1833 goto fail;
1834
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001835 if (!elems.fils_nonce) {
1836 wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
1837 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1838 goto fail;
1839 }
1840 wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce,
1841 FILS_NONCE_LEN);
1842 os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN);
1843
1844 /* PMKID List */
1845 if (rsn.pmkid && rsn.num_pmkid > 0) {
1846 u8 num;
1847 const u8 *pmkid;
1848
1849 wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
1850 rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
1851
1852 pmkid = rsn.pmkid;
1853 num = rsn.num_pmkid;
1854 while (num) {
1855 wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
1856 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
1857 pmkid);
1858 if (pmksa)
1859 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001860 pmksa = wpa_auth_pmksa_get_fils_cache_id(hapd->wpa_auth,
1861 sta->addr,
1862 pmkid);
1863 if (pmksa)
1864 break;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001865 pmkid += PMKID_LEN;
1866 num--;
1867 }
1868 }
1869 if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) {
1870 wpa_printf(MSG_DEBUG,
1871 "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore",
1872 wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp);
1873 pmksa = NULL;
1874 }
1875 if (pmksa)
1876 wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry");
1877
1878 /* FILS Session */
1879 if (!elems.fils_session) {
1880 wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
1881 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1882 goto fail;
1883 }
1884 wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
1885 FILS_SESSION_LEN);
1886 os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
1887
Hai Shalomfdcde762020-04-02 11:19:20 -07001888 /* Wrapped Data */
1889 if (elems.wrapped_data) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001890 wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
Hai Shalomfdcde762020-04-02 11:19:20 -07001891 elems.wrapped_data,
1892 elems.wrapped_data_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001893 if (!pmksa) {
1894#ifndef CONFIG_NO_RADIUS
1895 if (!sta->eapol_sm) {
1896 sta->eapol_sm =
1897 ieee802_1x_alloc_eapol_sm(hapd, sta);
1898 }
1899 wpa_printf(MSG_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001900 "FILS: Forward EAP-Initiate/Re-auth to authentication server");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001901 ieee802_1x_encapsulate_radius(
Hai Shalomfdcde762020-04-02 11:19:20 -07001902 hapd, sta, elems.wrapped_data,
1903 elems.wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001904 sta->fils_pending_cb = cb;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001905 wpa_printf(MSG_DEBUG,
1906 "FILS: Will send Authentication frame once the response from authentication server is available");
1907 sta->flags |= WLAN_STA_PENDING_FILS_ERP;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001908 /* Calculate pending PMKID here so that we do not need
1909 * to maintain a copy of the EAP-Initiate/Reauth
1910 * message. */
1911 if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
Hai Shalomfdcde762020-04-02 11:19:20 -07001912 elems.wrapped_data,
1913 elems.wrapped_data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001914 sta->fils_erp_pmkid) == 0)
1915 sta->fils_erp_pmkid_set = 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001916 return;
1917#else /* CONFIG_NO_RADIUS */
1918 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1919 goto fail;
1920#endif /* CONFIG_NO_RADIUS */
1921 }
1922 }
1923
1924fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001925 if (cb) {
1926 struct wpabuf *data;
1927 int pub = 0;
1928
1929 data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, NULL,
1930 NULL, 0, &pub);
1931 if (!data) {
1932 wpa_printf(MSG_DEBUG,
1933 "%s: prepare_auth_resp_fils() returned failure",
1934 __func__);
1935 }
1936
1937 cb(hapd, sta, resp, data, pub);
1938 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001939}
1940
1941
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001942static struct wpabuf *
1943prepare_auth_resp_fils(struct hostapd_data *hapd,
1944 struct sta_info *sta, u16 *resp,
1945 struct rsn_pmksa_cache_entry *pmksa,
1946 struct wpabuf *erp_resp,
1947 const u8 *msk, size_t msk_len,
1948 int *is_pub)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001949{
1950 u8 fils_nonce[FILS_NONCE_LEN];
1951 size_t ielen;
1952 struct wpabuf *data = NULL;
1953 const u8 *ie;
1954 u8 *ie_buf = NULL;
1955 const u8 *pmk = NULL;
1956 size_t pmk_len = 0;
Paul Stewart092955c2017-02-06 09:13:09 -08001957 u8 pmk_buf[PMK_LEN_MAX];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001958 struct wpabuf *pub = NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001959
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001960 if (*resp != WLAN_STATUS_SUCCESS)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001961 goto fail;
1962
1963 ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
1964 if (!ie) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001965 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001966 goto fail;
1967 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001968
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001969 if (pmksa) {
1970 /* Add PMKID of the selected PMKSA into RSNE */
1971 ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN);
1972 if (!ie_buf) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001973 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001974 goto fail;
1975 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001976
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001977 os_memcpy(ie_buf, ie, ielen);
1978 if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001979 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001980 goto fail;
1981 }
1982 ie = ie_buf;
1983 }
1984
1985 if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001986 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001987 goto fail;
1988 }
1989 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
1990 fils_nonce, FILS_NONCE_LEN);
1991
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001992#ifdef CONFIG_FILS_SK_PFS
1993 if (sta->fils_dh_ss && sta->fils_ecdh) {
1994 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
1995 if (!pub) {
1996 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1997 goto fail;
1998 }
1999 }
2000#endif /* CONFIG_FILS_SK_PFS */
2001
2002 data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0));
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002003 if (!data) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002004 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002005 goto fail;
2006 }
2007
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002008 /* TODO: FILS PK */
2009#ifdef CONFIG_FILS_SK_PFS
2010 if (pub) {
2011 /* Finite Cyclic Group */
2012 wpabuf_put_le16(data, hapd->conf->fils_dh_group);
2013
2014 /* Element */
2015 wpabuf_put_buf(data, pub);
2016 }
2017#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002018
2019 /* RSNE */
2020 wpabuf_put_data(data, ie, ielen);
2021
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002022 /* MDE when using FILS+FT (already included in ie,ielen with RSNE) */
2023
2024#ifdef CONFIG_IEEE80211R_AP
2025 if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
2026 /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
2027 int res;
2028
Sunil Ravi77d572f2023-01-17 23:58:31 +00002029 res = wpa_auth_write_fte(hapd->wpa_auth, sta->wpa_sm,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002030 wpabuf_put(data, 0),
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002031 wpabuf_tailroom(data));
2032 if (res < 0) {
2033 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2034 goto fail;
2035 }
2036 wpabuf_put(data, res);
2037 }
2038#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002039
2040 /* FILS Nonce */
2041 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2042 wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */
2043 /* Element ID Extension */
2044 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE);
2045 wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN);
2046
2047 /* FILS Session */
2048 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2049 wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */
2050 /* Element ID Extension */
2051 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
2052 wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
2053
Hai Shalomfdcde762020-04-02 11:19:20 -07002054 /* Wrapped Data */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002055 if (!pmksa && erp_resp) {
2056 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2057 wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
2058 /* Element ID Extension */
Hai Shalomfdcde762020-04-02 11:19:20 -07002059 wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002060 wpabuf_put_buf(data, erp_resp);
2061
Paul Stewart092955c2017-02-06 09:13:09 -08002062 if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
2063 msk, msk_len, sta->fils_snonce, fils_nonce,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002064 sta->fils_dh_ss ?
2065 wpabuf_head(sta->fils_dh_ss) : NULL,
2066 sta->fils_dh_ss ?
2067 wpabuf_len(sta->fils_dh_ss) : 0,
2068 pmk_buf, &pmk_len)) {
Paul Stewart092955c2017-02-06 09:13:09 -08002069 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002070 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Paul Stewart092955c2017-02-06 09:13:09 -08002071 wpabuf_free(data);
2072 data = NULL;
2073 goto fail;
2074 }
2075 pmk = pmk_buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002076
2077 /* Don't use DHss in PTK derivation if PMKSA caching is not
2078 * used. */
2079 wpabuf_clear_free(sta->fils_dh_ss);
2080 sta->fils_dh_ss = NULL;
2081
2082 if (sta->fils_erp_pmkid_set) {
2083 /* TODO: get PMKLifetime from WPA parameters */
2084 unsigned int dot11RSNAConfigPMKLifetime = 43200;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002085 int session_timeout;
2086
2087 session_timeout = dot11RSNAConfigPMKLifetime;
2088 if (sta->session_timeout_set) {
2089 struct os_reltime now, diff;
2090
2091 os_get_reltime(&now);
2092 os_reltime_sub(&sta->session_timeout, &now,
2093 &diff);
2094 session_timeout = diff.sec;
2095 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002096
2097 sta->fils_erp_pmkid_set = 0;
Hai Shalom81f62d82019-07-22 12:10:00 -07002098 wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
2099 sta->fils_erp_pmkid);
Hai Shalom021b0b52019-04-10 11:17:58 -07002100 if (!hapd->conf->disable_pmksa_caching &&
2101 wpa_auth_pmksa_add2(
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002102 hapd->wpa_auth, sta->addr,
2103 pmk, pmk_len,
2104 sta->fils_erp_pmkid,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002105 session_timeout,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002106 wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) {
2107 wpa_printf(MSG_ERROR,
2108 "FILS: Failed to add PMKSA cache entry based on ERP");
2109 }
2110 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002111 } else if (pmksa) {
2112 pmk = pmksa->pmk;
2113 pmk_len = pmksa->pmk_len;
2114 }
2115
2116 if (!pmk) {
2117 wpa_printf(MSG_DEBUG, "FILS: No PMK available");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002118 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002119 wpabuf_free(data);
2120 data = NULL;
2121 goto fail;
2122 }
2123
2124 if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002125 sta->fils_snonce, fils_nonce,
2126 sta->fils_dh_ss ?
2127 wpabuf_head(sta->fils_dh_ss) : NULL,
2128 sta->fils_dh_ss ?
2129 wpabuf_len(sta->fils_dh_ss) : 0,
2130 sta->fils_g_sta, pub) < 0) {
2131 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002132 wpabuf_free(data);
2133 data = NULL;
2134 goto fail;
2135 }
2136
2137fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002138 if (is_pub)
2139 *is_pub = pub != NULL;
2140 os_free(ie_buf);
2141 wpabuf_free(pub);
2142 wpabuf_clear_free(sta->fils_dh_ss);
2143 sta->fils_dh_ss = NULL;
2144#ifdef CONFIG_FILS_SK_PFS
2145 crypto_ecdh_deinit(sta->fils_ecdh);
2146 sta->fils_ecdh = NULL;
2147#endif /* CONFIG_FILS_SK_PFS */
2148 return data;
2149}
2150
2151
2152static void handle_auth_fils_finish(struct hostapd_data *hapd,
2153 struct sta_info *sta, u16 resp,
2154 struct wpabuf *data, int pub)
2155{
2156 u16 auth_alg;
2157
2158 auth_alg = (pub ||
2159 resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
2160 WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Hai Shalomfdcde762020-04-02 11:19:20 -07002161 send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002162 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07002163 data ? wpabuf_len(data) : 0, "auth-fils-finish");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002164 wpabuf_free(data);
2165
2166 if (resp == WLAN_STATUS_SUCCESS) {
2167 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2168 HOSTAPD_LEVEL_DEBUG,
2169 "authentication OK (FILS)");
2170 sta->flags |= WLAN_STA_AUTH;
2171 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002172 sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002173 mlme_authenticate_indication(hapd, sta);
2174 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002175}
2176
2177
2178void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
2179 struct sta_info *sta, int success,
2180 struct wpabuf *erp_resp,
2181 const u8 *msk, size_t msk_len)
2182{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002183 u16 resp;
Hai Shalom60840252021-02-19 19:02:11 -08002184 u32 flags = sta->flags;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002185
Hai Shalom60840252021-02-19 19:02:11 -08002186 sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
2187 WLAN_STA_PENDING_PASN_FILS_ERP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002188
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002189 resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
Hai Shalom60840252021-02-19 19:02:11 -08002190
2191 if (flags & WLAN_STA_PENDING_FILS_ERP) {
2192 struct wpabuf *data;
2193 int pub = 0;
2194
2195 if (!sta->fils_pending_cb)
2196 return;
2197
2198 data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
2199 msk, msk_len, &pub);
2200 if (!data) {
2201 wpa_printf(MSG_DEBUG,
2202 "%s: prepare_auth_resp_fils() failure",
2203 __func__);
2204 }
2205 sta->fils_pending_cb(hapd, sta, resp, data, pub);
2206#ifdef CONFIG_PASN
2207 } else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
2208 pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
2209 msk, msk_len);
2210#endif /* CONFIG_PASN */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002211 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002212}
2213
2214#endif /* CONFIG_FILS */
2215
2216
Hai Shalomfdcde762020-04-02 11:19:20 -07002217static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
2218 const u8 *msg, size_t len,
2219 struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002220{
2221 int res;
2222
Hai Shalomfdcde762020-04-02 11:19:20 -07002223 res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002224
2225 if (res == HOSTAPD_ACL_REJECT) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002226 wpa_printf(MSG_DEBUG, "Station " MACSTR
2227 " not allowed to authenticate",
2228 MAC2STR(addr));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002229 return HOSTAPD_ACL_REJECT;
2230 }
2231
2232 if (res == HOSTAPD_ACL_PENDING) {
2233 wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
2234 " waiting for an external authentication",
2235 MAC2STR(addr));
2236 /* Authentication code will re-send the authentication frame
2237 * after it has received (and cached) information from the
2238 * external source. */
2239 return HOSTAPD_ACL_PENDING;
2240 }
2241
2242 return res;
2243}
2244
2245
Sunil Ravia04bd252022-05-02 22:54:18 -07002246int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
2247 int res, struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002248{
Hai Shalomfdcde762020-04-02 11:19:20 -07002249 u32 session_timeout = info->session_timeout;
2250 u32 acct_interim_interval = info->acct_interim_interval;
2251 struct vlan_description *vlan_id = &info->vlan_id;
2252 struct hostapd_sta_wpa_psk_short *psk = info->psk;
2253 char *identity = info->identity;
2254 char *radius_cui = info->radius_cui;
2255
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002256 if (vlan_id->notempty &&
2257 !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
2258 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2259 HOSTAPD_LEVEL_INFO,
2260 "Invalid VLAN %d%s received from RADIUS server",
2261 vlan_id->untagged,
2262 vlan_id->tagged[0] ? "+" : "");
2263 return -1;
2264 }
2265 if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
2266 return -1;
2267 if (sta->vlan_id)
2268 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2269 HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
2270
2271 hostapd_free_psk_list(sta->psk);
Hai Shalomfdcde762020-04-02 11:19:20 -07002272 if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
2273 hostapd_copy_psk_list(&sta->psk, psk);
2274 else
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002275 sta->psk = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002276
Roshan Pius3a1667e2018-07-03 15:17:14 -07002277 os_free(sta->identity);
Hai Shalomfdcde762020-04-02 11:19:20 -07002278 if (identity)
2279 sta->identity = os_strdup(identity);
2280 else
2281 sta->identity = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002282
2283 os_free(sta->radius_cui);
Hai Shalomfdcde762020-04-02 11:19:20 -07002284 if (radius_cui)
2285 sta->radius_cui = os_strdup(radius_cui);
2286 else
2287 sta->radius_cui = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002288
2289 if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
2290 sta->acct_interim_interval = acct_interim_interval;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002291 if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
2292 sta->session_timeout_set = 1;
2293 os_get_reltime(&sta->session_timeout);
2294 sta->session_timeout.sec += session_timeout;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002295 ap_sta_session_timeout(hapd, sta, session_timeout);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002296 } else {
2297 sta->session_timeout_set = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002298 ap_sta_no_session_timeout(hapd, sta);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002299 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002300
2301 return 0;
2302}
2303
2304
Hai Shalom60840252021-02-19 19:02:11 -08002305#ifdef CONFIG_PASN
Hai Shalom60840252021-02-19 19:02:11 -08002306#ifdef CONFIG_FILS
2307
Hai Shalom60840252021-02-19 19:02:11 -08002308static void pasn_fils_auth_resp(struct hostapd_data *hapd,
2309 struct sta_info *sta, u16 status,
2310 struct wpabuf *erp_resp,
2311 const u8 *msk, size_t msk_len)
2312{
2313 struct pasn_data *pasn = sta->pasn;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002314 struct pasn_fils *fils = &pasn->fils;
Hai Shalom60840252021-02-19 19:02:11 -08002315 u8 pmk[PMK_LEN_MAX];
2316 size_t pmk_len;
2317 int ret;
2318
2319 wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
2320 status);
2321
2322 if (status != WLAN_STATUS_SUCCESS)
2323 goto fail;
2324
2325 if (!pasn->secret) {
2326 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
2327 goto fail;
2328 }
2329
2330 if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
2331 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
2332 goto fail;
2333 }
2334
2335 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
2336 fils->anonce, FILS_NONCE_LEN);
2337
2338 ret = fils_rmsk_to_pmk(pasn->akmp, msk, msk_len, fils->nonce,
2339 fils->anonce, NULL, 0, pmk, &pmk_len);
2340 if (ret) {
2341 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
2342 goto fail;
2343 }
2344
2345 ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
2346 wpabuf_head(pasn->secret),
2347 wpabuf_len(pasn->secret),
2348 &sta->pasn->ptk, sta->pasn->akmp,
Hai Shaloma20dcd72022-02-04 13:43:00 -08002349 sta->pasn->cipher, sta->pasn->kdk_len);
Hai Shalom60840252021-02-19 19:02:11 -08002350 if (ret) {
2351 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
2352 goto fail;
2353 }
2354
Sunil Ravi89eba102022-09-13 21:04:37 -07002355 if (pasn->secure_ltf) {
2356 ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp, pasn->cipher);
2357 if (ret) {
2358 wpa_printf(MSG_DEBUG,
2359 "PASN: FILS: Failed to derive LTF keyseed");
2360 goto fail;
2361 }
2362 }
2363
Hai Shalom60840252021-02-19 19:02:11 -08002364 wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
2365
2366 wpabuf_free(pasn->secret);
2367 pasn->secret = NULL;
2368
2369 fils->erp_resp = erp_resp;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002370 ret = handle_auth_pasn_resp(sta->pasn, hapd->own_addr, sta->addr, NULL,
2371 WLAN_STATUS_SUCCESS);
Hai Shalom60840252021-02-19 19:02:11 -08002372 fils->erp_resp = NULL;
2373
2374 if (ret) {
2375 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
2376 goto fail;
2377 }
2378
2379 fils->state = PASN_FILS_STATE_COMPLETE;
2380 return;
2381fail:
2382 ap_free_sta(hapd, sta);
2383}
2384
2385
2386static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
2387 struct wpabuf *wd)
2388{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002389#ifdef CONFIG_NO_RADIUS
2390 wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
2391 return -1;
2392#else /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002393 struct pasn_data *pasn = sta->pasn;
Sunil Ravi77d572f2023-01-17 23:58:31 +00002394 struct pasn_fils *fils = &pasn->fils;
Hai Shalom60840252021-02-19 19:02:11 -08002395 struct ieee802_11_elems elems;
2396 struct wpa_ie_data rsne_data;
2397 struct wpabuf *fils_wd;
2398 const u8 *data;
2399 size_t buf_len;
2400 u16 alg, seq, status;
2401 int ret;
2402
2403 if (fils->state != PASN_FILS_STATE_NONE) {
2404 wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
2405 return -1;
2406 }
2407
2408 if (!wd) {
2409 wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
2410 return -1;
2411 }
2412
2413 data = wpabuf_head_u8(wd);
2414 buf_len = wpabuf_len(wd);
2415
2416 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002417 wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002418 buf_len);
2419 return -1;
2420 }
2421
2422 alg = WPA_GET_LE16(data);
2423 seq = WPA_GET_LE16(data + 2);
2424 status = WPA_GET_LE16(data + 4);
2425
2426 wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
2427 alg, seq, status);
2428
2429 if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
2430 status != WLAN_STATUS_SUCCESS) {
2431 wpa_printf(MSG_DEBUG,
2432 "PASN: FILS: Dropping peer authentication");
2433 return -1;
2434 }
2435
2436 data += 6;
2437 buf_len -= 6;
2438
2439 if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
2440 wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
2441 return -1;
2442 }
2443
2444 if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00002445 !elems.wrapped_data || !elems.fils_session) {
Hai Shalom60840252021-02-19 19:02:11 -08002446 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
2447 return -1;
2448 }
2449
2450 ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2451 &rsne_data);
2452 if (ret) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002453 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RSNE");
Hai Shalom60840252021-02-19 19:02:11 -08002454 return -1;
2455 }
2456
2457 ret = wpa_pasn_validate_rsne(&rsne_data);
2458 if (ret) {
2459 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
2460 return -1;
2461 }
2462
2463 if (rsne_data.num_pmkid) {
2464 wpa_printf(MSG_DEBUG,
2465 "PASN: FILS: Not expecting PMKID in RSNE");
2466 return -1;
2467 }
2468
2469 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
2470 FILS_NONCE_LEN);
2471 os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
2472
2473 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
2474 FILS_SESSION_LEN);
2475 os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
2476
Hai Shalom60840252021-02-19 19:02:11 -08002477 fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
2478 WLAN_EID_EXT_WRAPPED_DATA);
2479
2480 if (!fils_wd) {
2481 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
2482 return -1;
2483 }
2484
2485 if (!sta->eapol_sm)
2486 sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
2487
2488 wpa_printf(MSG_DEBUG,
2489 "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
2490
2491 ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
2492 wpabuf_len(fils_wd));
2493
2494 sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
2495
2496 fils->state = PASN_FILS_STATE_PENDING_AS;
2497
2498 /*
2499 * Calculate pending PMKID here so that we do not need to maintain a
2500 * copy of the EAP-Initiate/Reautt message.
2501 */
2502 fils_pmkid_erp(pasn->akmp, wpabuf_head(fils_wd), wpabuf_len(fils_wd),
2503 fils->erp_pmkid);
2504
2505 wpabuf_free(fils_wd);
2506 return 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002507#endif /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002508}
2509
2510#endif /* CONFIG_FILS */
2511
2512
Sunil Ravi77d572f2023-01-17 23:58:31 +00002513static int hapd_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len,
2514 int noack, unsigned int freq, unsigned int wait)
Hai Shalom60840252021-02-19 19:02:11 -08002515{
Sunil Ravi77d572f2023-01-17 23:58:31 +00002516 struct hostapd_data *hapd = ctx;
2517
2518 return hostapd_drv_send_mlme(hapd, data, data_len, 0, NULL, 0, 0);
2519}
2520
2521
2522static void hapd_initialize_pasn(struct hostapd_data *hapd,
2523 struct sta_info *sta)
2524{
2525 struct pasn_data *pasn = sta->pasn;
2526
2527 pasn->cb_ctx = hapd;
2528 pasn->send_mgmt = hapd_pasn_send_mlme;
2529 pasn->pasn_groups = hapd->conf->pasn_groups;
2530 pasn->wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
2531 pasn->rsn_pairwise = hapd->conf->rsn_pairwise;
2532 pasn->derive_kdk = hapd->iface->drv_flags2 &
2533 WPA_DRIVER_FLAGS2_SEC_LTF_AP;
2534#ifdef CONFIG_TESTING_OPTIONS
2535 pasn->corrupt_mic = hapd->conf->pasn_corrupt_mic;
2536 if (hapd->conf->force_kdk_derivation)
2537 pasn->derive_kdk = true;
2538#endif /* CONFIG_TESTING_OPTIONS */
2539 pasn->use_anti_clogging = use_anti_clogging(hapd);
2540 pasn->password = sae_get_password(hapd, sta, NULL, NULL, &pasn->pt,
2541 NULL);
2542 pasn->rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &pasn->rsn_ie_len);
2543 pasn->rsnxe_ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
2544 pasn->disable_pmksa_caching = hapd->conf->disable_pmksa_caching;
2545 pasn->pmksa = wpa_auth_get_pmksa_cache(hapd->wpa_auth);
2546
2547 pasn->comeback_after = hapd->conf->pasn_comeback_after;
2548 pasn->comeback_idx = hapd->comeback_idx;
2549 pasn->comeback_key = hapd->comeback_key;
2550 pasn->comeback_pending_idx = hapd->comeback_pending_idx;
2551 os_memcpy(pasn->bssid, hapd->own_addr, ETH_ALEN);
Hai Shalom60840252021-02-19 19:02:11 -08002552}
2553
2554
Sunil Ravi89eba102022-09-13 21:04:37 -07002555static int pasn_set_keys_from_cache(struct hostapd_data *hapd,
2556 const u8 *own_addr, const u8 *sta_addr,
2557 int cipher, int akmp)
2558{
2559 struct ptksa_cache_entry *entry;
2560
2561 entry = ptksa_cache_get(hapd->ptksa, sta_addr, cipher);
2562 if (!entry) {
2563 wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR
2564 " not present in PTKSA cache", MAC2STR(sta_addr));
2565 return -1;
2566 }
2567
2568 if (os_memcmp(entry->own_addr, own_addr, ETH_ALEN) != 0) {
2569 wpa_printf(MSG_DEBUG,
2570 "PASN: own addr " MACSTR " and PTKSA entry own addr "
2571 MACSTR " differ",
2572 MAC2STR(own_addr), MAC2STR(entry->own_addr));
2573 return -1;
2574 }
2575
2576 wpa_printf(MSG_DEBUG, "PASN: " MACSTR " present in PTKSA cache",
2577 MAC2STR(sta_addr));
2578 hostapd_drv_set_secure_ranging_ctx(hapd, own_addr, sta_addr, cipher,
2579 entry->ptk.tk_len, entry->ptk.tk,
2580 entry->ptk.ltf_keyseed_len,
2581 entry->ptk.ltf_keyseed, 0);
2582
2583 return 0;
2584}
2585
2586
Sunil Ravi77d572f2023-01-17 23:58:31 +00002587static void hapd_pasn_update_params(struct hostapd_data *hapd,
2588 struct sta_info *sta,
2589 const struct ieee80211_mgmt *mgmt,
2590 size_t len)
Hai Shalom60840252021-02-19 19:02:11 -08002591{
Sunil Ravi77d572f2023-01-17 23:58:31 +00002592 struct pasn_data *pasn = sta->pasn;
Hai Shalom60840252021-02-19 19:02:11 -08002593 struct ieee802_11_elems elems;
2594 struct wpa_ie_data rsn_data;
2595 struct wpa_pasn_params_data pasn_params;
Hai Shalom60840252021-02-19 19:02:11 -08002596 struct wpabuf *wrapped_data = NULL;
Hai Shalom60840252021-02-19 19:02:11 -08002597
2598 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
2599 len - offsetof(struct ieee80211_mgmt,
2600 u.auth.variable),
2601 &elems, 0) == ParseFailed) {
2602 wpa_printf(MSG_DEBUG,
2603 "PASN: Failed parsing Authentication frame");
Sunil Ravi77d572f2023-01-17 23:58:31 +00002604 return;
Hai Shalom60840252021-02-19 19:02:11 -08002605 }
2606
Sunil Ravi77d572f2023-01-17 23:58:31 +00002607 if (!elems.rsn_ie ||
2608 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2609 &rsn_data)) {
2610 wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE");
2611 return;
2612 }
2613
2614 if (!(rsn_data.key_mgmt & pasn->wpa_key_mgmt) ||
2615 !(rsn_data.pairwise_cipher & pasn->rsn_pairwise)) {
2616 wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
2617 return;
2618 }
2619
2620 pasn->akmp = rsn_data.key_mgmt;
2621 pasn->cipher = rsn_data.pairwise_cipher;
2622
2623 if (wpa_key_mgmt_ft(pasn->akmp) && rsn_data.num_pmkid) {
2624#ifdef CONFIG_IEEE80211R_AP
2625 pasn->pmk_r1_len = 0;
2626 wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
2627 rsn_data.pmkid,
2628 pasn->pmk_r1, &pasn->pmk_r1_len, NULL,
2629 NULL, NULL, NULL,
2630 NULL, NULL, NULL);
2631#endif /* CONFIG_IEEE80211R_AP */
2632 }
2633#ifdef CONFIG_FILS
2634 if (pasn->akmp != WPA_KEY_MGMT_FILS_SHA256 &&
2635 pasn->akmp != WPA_KEY_MGMT_FILS_SHA384)
2636 return;
2637 if (!elems.pasn_params ||
2638 wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
2639 elems.pasn_params_len + 3,
2640 false, &pasn_params)) {
Hai Shalom60840252021-02-19 19:02:11 -08002641 wpa_printf(MSG_DEBUG,
Sunil Ravi77d572f2023-01-17 23:58:31 +00002642 "PASN: Failed validation of PASN Parameters element");
2643 return;
Hai Shalom60840252021-02-19 19:02:11 -08002644 }
Hai Shalom60840252021-02-19 19:02:11 -08002645 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00002646 wrapped_data = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
Hai Shalom60840252021-02-19 19:02:11 -08002647 WLAN_EID_EXT_WRAPPED_DATA);
Hai Shalom60840252021-02-19 19:02:11 -08002648 if (!wrapped_data) {
2649 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
Sunil Ravi77d572f2023-01-17 23:58:31 +00002650 return;
Hai Shalom60840252021-02-19 19:02:11 -08002651 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00002652 if (pasn_wd_handle_fils(hapd, sta, wrapped_data))
2653 wpa_printf(MSG_DEBUG,
2654 "PASN: Failed processing FILS wrapped data");
2655 else
2656 pasn->fils_wd_valid = true;
Hai Shalom60840252021-02-19 19:02:11 -08002657 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00002658 wpabuf_free(wrapped_data);
2659#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08002660}
2661
2662
2663static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
2664 const struct ieee80211_mgmt *mgmt, size_t len,
2665 u16 trans_seq, u16 status)
2666{
2667 if (hapd->conf->wpa != WPA_PROTO_RSN) {
2668 wpa_printf(MSG_INFO, "PASN: RSN is not configured");
2669 return;
2670 }
2671
2672 wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR,
2673 MAC2STR(sta->addr));
2674
2675 if (trans_seq == 1) {
2676 if (sta->pasn) {
2677 wpa_printf(MSG_DEBUG,
2678 "PASN: Not expecting transaction == 1");
2679 return;
2680 }
2681
2682 if (status != WLAN_STATUS_SUCCESS) {
2683 wpa_printf(MSG_DEBUG,
2684 "PASN: Failure status in transaction == 1");
2685 return;
2686 }
2687
2688 sta->pasn = os_zalloc(sizeof(*sta->pasn));
2689 if (!sta->pasn) {
2690 wpa_printf(MSG_DEBUG,
2691 "PASN: Failed to allocate PASN context");
2692 return;
2693 }
2694
Sunil Ravi77d572f2023-01-17 23:58:31 +00002695 hapd_initialize_pasn(hapd, sta);
2696
2697 hapd_pasn_update_params(hapd, sta, mgmt, len);
2698 if (handle_auth_pasn_1(sta->pasn, hapd->own_addr,
2699 sta->addr, mgmt, len) < 0)
2700 ap_free_sta(hapd, sta);
Hai Shalom60840252021-02-19 19:02:11 -08002701 } else if (trans_seq == 3) {
2702 if (!sta->pasn) {
2703 wpa_printf(MSG_DEBUG,
2704 "PASN: Not expecting transaction == 3");
2705 return;
2706 }
2707
2708 if (status != WLAN_STATUS_SUCCESS) {
2709 wpa_printf(MSG_DEBUG,
2710 "PASN: Failure status in transaction == 3");
2711 ap_free_sta_pasn(hapd, sta);
2712 return;
2713 }
2714
Sunil Ravi77d572f2023-01-17 23:58:31 +00002715 if (handle_auth_pasn_3(sta->pasn, hapd->own_addr,
2716 sta->addr, mgmt, len) == 0) {
2717 ptksa_cache_add(hapd->ptksa, hapd->own_addr, sta->addr,
2718 sta->pasn->cipher, 43200,
2719 &sta->pasn->ptk, NULL, NULL,
2720 sta->pasn->akmp);
2721
2722 pasn_set_keys_from_cache(hapd, hapd->own_addr,
2723 sta->addr, sta->pasn->cipher,
2724 sta->pasn->akmp);
2725 }
2726 ap_free_sta(hapd, sta);
Hai Shalom60840252021-02-19 19:02:11 -08002727 } else {
2728 wpa_printf(MSG_DEBUG,
2729 "PASN: Invalid transaction %u - ignore", trans_seq);
2730 }
2731}
2732
2733#endif /* CONFIG_PASN */
2734
2735
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002736static void handle_auth(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08002737 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom021b0b52019-04-10 11:17:58 -07002738 int rssi, int from_queue)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002739{
2740 u16 auth_alg, auth_transaction, status_code;
2741 u16 resp = WLAN_STATUS_SUCCESS;
2742 struct sta_info *sta = NULL;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002743 int res, reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002744 u16 fc;
2745 const u8 *challenge = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002746 u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
2747 size_t resp_ies_len = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002748 u16 seq_ctrl;
Hai Shalomfdcde762020-04-02 11:19:20 -07002749 struct radius_sta rad_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002750
2751 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002752 wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
2753 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002754 return;
2755 }
2756
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002757#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002758 if (hapd->iconf->ignore_auth_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002759 drand48() < hapd->iconf->ignore_auth_probability) {
2760 wpa_printf(MSG_INFO,
2761 "TESTING: ignoring auth frame from " MACSTR,
2762 MAC2STR(mgmt->sa));
2763 return;
2764 }
2765#endif /* CONFIG_TESTING_OPTIONS */
2766
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002767 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
2768 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
2769 status_code = le_to_host16(mgmt->u.auth.status_code);
2770 fc = le_to_host16(mgmt->frame_control);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002771 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002772
2773 if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
2774 2 + WLAN_AUTH_CHALLENGE_LEN &&
2775 mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
2776 mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
2777 challenge = &mgmt->u.auth.variable[2];
2778
2779 wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002780 "auth_transaction=%d status_code=%d wep=%d%s "
Hai Shalom021b0b52019-04-10 11:17:58 -07002781 "seq_ctrl=0x%x%s%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002782 MAC2STR(mgmt->sa), auth_alg, auth_transaction,
2783 status_code, !!(fc & WLAN_FC_ISWEP),
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002784 challenge ? " challenge" : "",
Hai Shalom021b0b52019-04-10 11:17:58 -07002785 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
2786 from_queue ? " (from queue)" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002787
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002788#ifdef CONFIG_NO_RC4
2789 if (auth_alg == WLAN_AUTH_SHARED_KEY) {
2790 wpa_printf(MSG_INFO,
2791 "Unsupported authentication algorithm (%d)",
2792 auth_alg);
2793 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
2794 goto fail;
2795 }
2796#endif /* CONFIG_NO_RC4 */
2797
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002798 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002799 wpa_printf(MSG_DEBUG,
2800 "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
2801 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002802 goto fail;
2803 }
2804
2805 if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
2806 auth_alg == WLAN_AUTH_OPEN) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002807#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002808 (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002809 auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002810#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002811#ifdef CONFIG_SAE
2812 (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
2813 auth_alg == WLAN_AUTH_SAE) ||
2814#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002815#ifdef CONFIG_FILS
2816 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
2817 auth_alg == WLAN_AUTH_FILS_SK) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002818 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
2819 hapd->conf->fils_dh_group &&
2820 auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002821#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08002822#ifdef CONFIG_PASN
2823 (hapd->conf->wpa &&
2824 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) &&
2825 auth_alg == WLAN_AUTH_PASN) ||
2826#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002827 ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
2828 auth_alg == WLAN_AUTH_SHARED_KEY))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002829 wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
2830 auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002831 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
2832 goto fail;
2833 }
2834
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002835 if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
Hai Shalom60840252021-02-19 19:02:11 -08002836#ifdef CONFIG_PASN
2837 (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) ||
2838#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002839 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002840 wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
2841 auth_transaction);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002842 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
2843 goto fail;
2844 }
2845
2846 if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002847 wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
2848 MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002849 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2850 goto fail;
2851 }
2852
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002853 if (hapd->conf->no_auth_if_seen_on) {
2854 struct hostapd_data *other;
2855
2856 other = sta_track_seen_on(hapd->iface, mgmt->sa,
2857 hapd->conf->no_auth_if_seen_on);
2858 if (other) {
2859 u8 *pos;
2860 u32 info;
2861 u8 op_class, channel, phytype;
2862
2863 wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
2864 MACSTR " since STA has been seen on %s",
2865 hapd->conf->iface, MAC2STR(mgmt->sa),
2866 hapd->conf->no_auth_if_seen_on);
2867
2868 resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
2869 pos = &resp_ies[0];
2870 *pos++ = WLAN_EID_NEIGHBOR_REPORT;
2871 *pos++ = 13;
2872 os_memcpy(pos, other->own_addr, ETH_ALEN);
2873 pos += ETH_ALEN;
2874 info = 0; /* TODO: BSSID Information */
2875 WPA_PUT_LE32(pos, info);
2876 pos += 4;
2877 if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
2878 phytype = 8; /* dmg */
2879 else if (other->iconf->ieee80211ac)
2880 phytype = 9; /* vht */
2881 else if (other->iconf->ieee80211n)
2882 phytype = 7; /* ht */
2883 else if (other->iconf->hw_mode ==
2884 HOSTAPD_MODE_IEEE80211A)
2885 phytype = 4; /* ofdm */
2886 else if (other->iconf->hw_mode ==
2887 HOSTAPD_MODE_IEEE80211G)
2888 phytype = 6; /* erp */
2889 else
2890 phytype = 5; /* hrdsss */
2891 if (ieee80211_freq_to_channel_ext(
2892 hostapd_hw_get_freq(other,
2893 other->iconf->channel),
2894 other->iconf->secondary_channel,
2895 other->iconf->ieee80211ac,
2896 &op_class, &channel) == NUM_HOSTAPD_MODES) {
2897 op_class = 0;
2898 channel = other->iconf->channel;
2899 }
2900 *pos++ = op_class;
2901 *pos++ = channel;
2902 *pos++ = phytype;
2903 resp_ies_len = pos - &resp_ies[0];
2904 goto fail;
2905 }
2906 }
2907
Hai Shalomfdcde762020-04-02 11:19:20 -07002908 res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
2909 &rad_info);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002910 if (res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002911 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
2912 "Ignore Authentication frame from " MACSTR
2913 " due to ACL reject", MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002914 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2915 goto fail;
2916 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002917 if (res == HOSTAPD_ACL_PENDING)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002918 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002919
Hai Shalom021b0b52019-04-10 11:17:58 -07002920#ifdef CONFIG_SAE
2921 if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
2922 (auth_transaction == 1 ||
2923 (auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) {
2924 /* Handle SAE Authentication commit message through a queue to
2925 * provide more control for postponing the needed heavy
2926 * processing under a possible DoS attack scenario. In addition,
2927 * queue SAE Authentication confirm message if there happens to
2928 * be a queued commit message from the same peer. This is needed
2929 * to avoid reordering Authentication frames within the same
2930 * SAE exchange. */
2931 auth_sae_queue(hapd, mgmt, len, rssi);
2932 return;
2933 }
2934#endif /* CONFIG_SAE */
2935
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002936 sta = ap_get_sta(hapd, mgmt->sa);
2937 if (sta) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002938 sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
Hai Shalom74f70d42019-02-11 14:42:39 -08002939 sta->ft_over_ds = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002940 if ((fc & WLAN_FC_RETRY) &&
2941 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
2942 sta->last_seq_ctrl == seq_ctrl &&
2943 sta->last_subtype == WLAN_FC_STYPE_AUTH) {
2944 hostapd_logger(hapd, sta->addr,
2945 HOSTAPD_MODULE_IEEE80211,
2946 HOSTAPD_LEVEL_DEBUG,
2947 "Drop repeated authentication frame seq_ctrl=0x%x",
2948 seq_ctrl);
2949 return;
2950 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002951#ifdef CONFIG_MESH
2952 if ((hapd->conf->mesh & MESH_ENABLED) &&
2953 sta->plink_state == PLINK_BLOCKED) {
2954 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
2955 " is blocked - drop Authentication frame",
2956 MAC2STR(mgmt->sa));
2957 return;
2958 }
2959#endif /* CONFIG_MESH */
Hai Shalom60840252021-02-19 19:02:11 -08002960#ifdef CONFIG_PASN
2961 if (auth_alg == WLAN_AUTH_PASN &&
2962 (sta->flags & WLAN_STA_ASSOC)) {
2963 wpa_printf(MSG_DEBUG,
2964 "PASN: auth: Existing station: " MACSTR,
2965 MAC2STR(sta->addr));
2966 return;
2967 }
2968#endif /* CONFIG_PASN */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002969 } else {
2970#ifdef CONFIG_MESH
2971 if (hapd->conf->mesh & MESH_ENABLED) {
2972 /* if the mesh peer is not available, we don't do auth.
2973 */
2974 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002975 " not yet known - drop Authentication frame",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002976 MAC2STR(mgmt->sa));
2977 /*
2978 * Save a copy of the frame so that it can be processed
2979 * if a new peer entry is added shortly after this.
2980 */
2981 wpabuf_free(hapd->mesh_pending_auth);
2982 hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len);
2983 os_get_reltime(&hapd->mesh_pending_auth_time);
2984 return;
2985 }
2986#endif /* CONFIG_MESH */
2987
2988 sta = ap_sta_add(hapd, mgmt->sa);
2989 if (!sta) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002990 wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002991 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
2992 goto fail;
2993 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002994 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002995 sta->last_seq_ctrl = seq_ctrl;
2996 sta->last_subtype = WLAN_FC_STYPE_AUTH;
Hai Shalom74f70d42019-02-11 14:42:39 -08002997#ifdef CONFIG_MBO
2998 sta->auth_rssi = rssi;
2999#endif /* CONFIG_MBO */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003000
Hai Shalomfdcde762020-04-02 11:19:20 -07003001 res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003002 if (res) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003003 wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003004 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3005 goto fail;
3006 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003007
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003008 sta->flags &= ~WLAN_STA_PREAUTH;
3009 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
3010
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003011 /*
3012 * If the driver supports full AP client state, add a station to the
3013 * driver before sending authentication reply to make sure the driver
3014 * has resources, and not to go through the entire authentication and
3015 * association handshake, and fail it at the end.
3016 *
3017 * If this is not the first transaction, in a multi-step authentication
3018 * algorithm, the station already exists in the driver
3019 * (sta->added_unassoc = 1) so skip it.
3020 *
3021 * In mesh mode, the station was already added to the driver when the
3022 * NEW_PEER_CANDIDATE event is received.
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003023 *
3024 * If PMF was negotiated for the existing association, skip this to
3025 * avoid dropping the STA entry and the associated keys. This is needed
3026 * to allow the original connection work until the attempt can complete
3027 * (re)association, so that unprotected Authentication frame cannot be
3028 * used to bypass PMF protection.
Hai Shalom60840252021-02-19 19:02:11 -08003029 *
3030 * PASN authentication does not require adding/removing station to the
3031 * driver so skip this flow in case of PASN authentication.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003032 */
3033 if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003034 (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003035 !(hapd->conf->mesh & MESH_ENABLED) &&
Hai Shalom60840252021-02-19 19:02:11 -08003036 !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) {
Hai Shalomb755a2a2020-04-23 21:49:02 -07003037 if (ap_sta_re_add(hapd, sta) < 0) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003038 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3039 goto fail;
3040 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003041 }
3042
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003043 switch (auth_alg) {
3044 case WLAN_AUTH_OPEN:
3045 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3046 HOSTAPD_LEVEL_DEBUG,
3047 "authentication OK (open system)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003048 sta->flags |= WLAN_STA_AUTH;
3049 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
3050 sta->auth_alg = WLAN_AUTH_OPEN;
3051 mlme_authenticate_indication(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003052 break;
Hai Shalomfdcde762020-04-02 11:19:20 -07003053#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003054#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003055 case WLAN_AUTH_SHARED_KEY:
3056 resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
3057 fc & WLAN_FC_ISWEP);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003058 if (resp != 0)
3059 wpa_printf(MSG_DEBUG,
3060 "auth_shared_key() failed: status=%d", resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003061 sta->auth_alg = WLAN_AUTH_SHARED_KEY;
3062 mlme_authenticate_indication(hapd, sta);
3063 if (sta->challenge && auth_transaction == 1) {
3064 resp_ies[0] = WLAN_EID_CHALLENGE;
3065 resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
3066 os_memcpy(resp_ies + 2, sta->challenge,
3067 WLAN_AUTH_CHALLENGE_LEN);
3068 resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
3069 }
3070 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003071#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003072#endif /* CONFIG_WEP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003073#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003074 case WLAN_AUTH_FT:
3075 sta->auth_alg = WLAN_AUTH_FT;
3076 if (sta->wpa_sm == NULL)
3077 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003078 sta->addr, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003079 if (sta->wpa_sm == NULL) {
3080 wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
3081 "state machine");
3082 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3083 goto fail;
3084 }
3085 wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
3086 auth_transaction, mgmt->u.auth.variable,
3087 len - IEEE80211_HDRLEN -
3088 sizeof(mgmt->u.auth),
3089 handle_auth_ft_finish, hapd);
3090 /* handle_auth_ft_finish() callback will complete auth. */
3091 return;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003092#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003093#ifdef CONFIG_SAE
3094 case WLAN_AUTH_SAE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003095#ifdef CONFIG_MESH
3096 if (status_code == WLAN_STATUS_SUCCESS &&
3097 hapd->conf->mesh & MESH_ENABLED) {
3098 if (sta->wpa_sm == NULL)
3099 sta->wpa_sm =
3100 wpa_auth_sta_init(hapd->wpa_auth,
3101 sta->addr, NULL);
3102 if (sta->wpa_sm == NULL) {
3103 wpa_printf(MSG_DEBUG,
3104 "SAE: Failed to initialize WPA state machine");
3105 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3106 goto fail;
3107 }
3108 }
3109#endif /* CONFIG_MESH */
3110 handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
3111 status_code);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003112 return;
3113#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003114#ifdef CONFIG_FILS
3115 case WLAN_AUTH_FILS_SK:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003116 case WLAN_AUTH_FILS_SK_PFS:
3117 handle_auth_fils(hapd, sta, mgmt->u.auth.variable,
3118 len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth),
3119 auth_alg, auth_transaction, status_code,
3120 handle_auth_fils_finish);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003121 return;
3122#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08003123#ifdef CONFIG_PASN
3124 case WLAN_AUTH_PASN:
3125 handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction,
3126 status_code);
3127 return;
3128#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003129 }
3130
3131 fail:
Hai Shalomfdcde762020-04-02 11:19:20 -07003132 reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg,
Hai Shaloma20dcd72022-02-04 13:43:00 -08003133 auth_alg == WLAN_AUTH_SAE ?
3134 auth_transaction : auth_transaction + 1,
3135 resp, resp_ies, resp_ies_len,
3136 "handle-auth");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003137
3138 if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
3139 reply_res != WLAN_STATUS_SUCCESS)) {
3140 hostapd_drv_sta_remove(hapd, sta->addr);
3141 sta->added_unassoc = 0;
3142 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003143}
3144
3145
Sunil Ravi77d572f2023-01-17 23:58:31 +00003146static u8 hostapd_max_bssid_indicator(struct hostapd_data *hapd)
3147{
3148 size_t num_bss_nontx;
3149 u8 max_bssid_ind = 0;
3150
3151 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1)
3152 return 0;
3153
3154 num_bss_nontx = hapd->iface->num_bss - 1;
3155 while (num_bss_nontx > 0) {
3156 max_bssid_ind++;
3157 num_bss_nontx >>= 1;
3158 }
3159 return max_bssid_ind;
3160}
3161
3162
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003163int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003164{
3165 int i, j = 32, aid;
3166
3167 /* get a unique AID */
3168 if (sta->aid > 0) {
3169 wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
3170 return 0;
3171 }
3172
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003173 if (TEST_FAIL())
3174 return -1;
3175
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003176 for (i = 0; i < AID_WORDS; i++) {
3177 if (hapd->sta_aid[i] == (u32) -1)
3178 continue;
3179 for (j = 0; j < 32; j++) {
3180 if (!(hapd->sta_aid[i] & BIT(j)))
3181 break;
3182 }
3183 if (j < 32)
3184 break;
3185 }
3186 if (j == 32)
3187 return -1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003188 aid = i * 32 + j + (1 << hostapd_max_bssid_indicator(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003189 if (aid > 2007)
3190 return -1;
3191
3192 sta->aid = aid;
3193 hapd->sta_aid[i] |= BIT(j);
3194 wpa_printf(MSG_DEBUG, " new AID %d", sta->aid);
3195 return 0;
3196}
3197
3198
3199static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
3200 const u8 *ssid_ie, size_t ssid_ie_len)
3201{
3202 if (ssid_ie == NULL)
3203 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3204
3205 if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
3206 os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003207 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3208 HOSTAPD_LEVEL_INFO,
3209 "Station tried to associate with unknown SSID "
Dmitry Shmidt3c479372014-02-04 10:50:36 -08003210 "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003211 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3212 }
3213
3214 return WLAN_STATUS_SUCCESS;
3215}
3216
3217
3218static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
3219 const u8 *wmm_ie, size_t wmm_ie_len)
3220{
3221 sta->flags &= ~WLAN_STA_WMM;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003222 sta->qosinfo = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003223 if (wmm_ie && hapd->conf->wmm_enabled) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003224 struct wmm_information_element *wmm;
3225
3226 if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003227 hostapd_logger(hapd, sta->addr,
3228 HOSTAPD_MODULE_WPA,
3229 HOSTAPD_LEVEL_DEBUG,
3230 "invalid WMM element in association "
3231 "request");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003232 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3233 }
3234
3235 sta->flags |= WLAN_STA_WMM;
3236 wmm = (struct wmm_information_element *) wmm_ie;
3237 sta->qosinfo = wmm->qos_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003238 }
3239 return WLAN_STATUS_SUCCESS;
3240}
3241
Hai Shalom74f70d42019-02-11 14:42:39 -08003242static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
3243 const u8 *multi_ap_ie, size_t multi_ap_len)
3244{
3245 u8 multi_ap_value = 0;
3246
3247 sta->flags &= ~WLAN_STA_MULTI_AP;
3248
3249 if (!hapd->conf->multi_ap)
3250 return WLAN_STATUS_SUCCESS;
3251
3252 if (multi_ap_ie) {
3253 const u8 *multi_ap_subelem;
3254
3255 multi_ap_subelem = get_ie(multi_ap_ie + 4,
3256 multi_ap_len - 4,
3257 MULTI_AP_SUB_ELEM_TYPE);
3258 if (multi_ap_subelem && multi_ap_subelem[1] == 1) {
3259 multi_ap_value = multi_ap_subelem[2];
3260 } else {
3261 hostapd_logger(hapd, sta->addr,
3262 HOSTAPD_MODULE_IEEE80211,
3263 HOSTAPD_LEVEL_INFO,
3264 "Multi-AP IE has missing or invalid Multi-AP subelement");
3265 return WLAN_STATUS_INVALID_IE;
3266 }
3267 }
3268
Hai Shalom021b0b52019-04-10 11:17:58 -07003269 if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA)
3270 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3271 HOSTAPD_LEVEL_INFO,
3272 "Multi-AP IE with unexpected value 0x%02x",
3273 multi_ap_value);
Hai Shalom74f70d42019-02-11 14:42:39 -08003274
Hai Shalom021b0b52019-04-10 11:17:58 -07003275 if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) {
3276 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
3277 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08003278
Hai Shalom021b0b52019-04-10 11:17:58 -07003279 hostapd_logger(hapd, sta->addr,
3280 HOSTAPD_MODULE_IEEE80211,
3281 HOSTAPD_LEVEL_INFO,
3282 "Non-Multi-AP STA tries to associate with backhaul-only BSS");
3283 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
Hai Shalom74f70d42019-02-11 14:42:39 -08003284 }
3285
Hai Shalom021b0b52019-04-10 11:17:58 -07003286 if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
3287 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3288 HOSTAPD_LEVEL_DEBUG,
3289 "Backhaul STA tries to associate with fronthaul-only BSS");
3290
3291 sta->flags |= WLAN_STA_MULTI_AP;
3292 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08003293}
3294
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003295
3296static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
3297 struct ieee802_11_elems *elems)
3298{
Dmitry Shmidt29333592017-01-09 12:27:11 -08003299 /* Supported rates not used in IEEE 802.11ad/DMG */
3300 if (hapd->iface->current_mode &&
3301 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
3302 return WLAN_STATUS_SUCCESS;
3303
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003304 if (!elems->supp_rates) {
3305 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3306 HOSTAPD_LEVEL_DEBUG,
3307 "No supported rates element in AssocReq");
3308 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3309 }
3310
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003311 if (elems->supp_rates_len + elems->ext_supp_rates_len >
3312 sizeof(sta->supported_rates)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003313 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3314 HOSTAPD_LEVEL_DEBUG,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003315 "Invalid supported rates element length %d+%d",
3316 elems->supp_rates_len,
3317 elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003318 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3319 }
3320
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003321 sta->supported_rates_len = merge_byte_arrays(
3322 sta->supported_rates, sizeof(sta->supported_rates),
3323 elems->supp_rates, elems->supp_rates_len,
3324 elems->ext_supp_rates, elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003325
3326 return WLAN_STATUS_SUCCESS;
3327}
3328
3329
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003330#ifdef CONFIG_OWE
3331
3332static int owe_group_supported(struct hostapd_data *hapd, u16 group)
3333{
3334 int i;
3335 int *groups = hapd->conf->owe_groups;
3336
3337 if (group != 19 && group != 20 && group != 21)
3338 return 0;
3339
3340 if (!groups)
3341 return 1;
3342
3343 for (i = 0; groups[i] > 0; i++) {
3344 if (groups[i] == group)
3345 return 1;
3346 }
3347
3348 return 0;
3349}
3350
3351
3352static u16 owe_process_assoc_req(struct hostapd_data *hapd,
3353 struct sta_info *sta, const u8 *owe_dh,
3354 u8 owe_dh_len)
3355{
3356 struct wpabuf *secret, *pub, *hkey;
3357 int res;
3358 u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN];
3359 const char *info = "OWE Key Generation";
3360 const u8 *addr[2];
3361 size_t len[2];
3362 u16 group;
3363 size_t hash_len, prime_len;
3364
3365 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
3366 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
3367 return WLAN_STATUS_SUCCESS;
3368 }
3369
3370 group = WPA_GET_LE16(owe_dh);
3371 if (!owe_group_supported(hapd, group)) {
3372 wpa_printf(MSG_DEBUG, "OWE: Unsupported DH group %u", group);
3373 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3374 }
3375 if (group == 19)
3376 prime_len = 32;
3377 else if (group == 20)
3378 prime_len = 48;
3379 else if (group == 21)
3380 prime_len = 66;
3381 else
3382 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3383
Sunil Ravia04bd252022-05-02 22:54:18 -07003384 if (sta->owe_group == group && sta->owe_ecdh) {
3385 /* This is a workaround for mac80211 behavior of retransmitting
3386 * the Association Request frames multiple times if the link
3387 * layer retries (i.e., seq# remains same) fail. The mac80211
3388 * initiated retransmission will use a different seq# and as
3389 * such, will go through duplicate detection. If we were to
3390 * change our DH key for that attempt, there would be two
3391 * different DH shared secrets and the STA would likely select
3392 * the wrong one. */
3393 wpa_printf(MSG_DEBUG,
3394 "OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again");
3395 } else {
3396 crypto_ecdh_deinit(sta->owe_ecdh);
3397 sta->owe_ecdh = crypto_ecdh_init(group);
3398 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003399 if (!sta->owe_ecdh)
3400 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3401 sta->owe_group = group;
3402
3403 secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2,
3404 owe_dh_len - 2);
3405 secret = wpabuf_zeropad(secret, prime_len);
3406 if (!secret) {
3407 wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
3408 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3409 }
3410 wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
3411
3412 /* prk = HKDF-extract(C | A | group, z) */
3413
3414 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
3415 if (!pub) {
3416 wpabuf_clear_free(secret);
3417 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3418 }
3419
3420 /* PMKID = Truncate-128(Hash(C | A)) */
3421 addr[0] = owe_dh + 2;
3422 len[0] = owe_dh_len - 2;
3423 addr[1] = wpabuf_head(pub);
3424 len[1] = wpabuf_len(pub);
3425 if (group == 19) {
3426 res = sha256_vector(2, addr, len, pmkid);
3427 hash_len = SHA256_MAC_LEN;
3428 } else if (group == 20) {
3429 res = sha384_vector(2, addr, len, pmkid);
3430 hash_len = SHA384_MAC_LEN;
3431 } else if (group == 21) {
3432 res = sha512_vector(2, addr, len, pmkid);
3433 hash_len = SHA512_MAC_LEN;
3434 } else {
3435 wpabuf_free(pub);
3436 wpabuf_clear_free(secret);
3437 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3438 }
3439 pub = wpabuf_zeropad(pub, prime_len);
3440 if (res < 0 || !pub) {
3441 wpabuf_free(pub);
3442 wpabuf_clear_free(secret);
3443 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3444 }
3445
3446 hkey = wpabuf_alloc(owe_dh_len - 2 + wpabuf_len(pub) + 2);
3447 if (!hkey) {
3448 wpabuf_free(pub);
3449 wpabuf_clear_free(secret);
3450 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3451 }
3452
3453 wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */
3454 wpabuf_put_buf(hkey, pub); /* A */
3455 wpabuf_free(pub);
3456 wpabuf_put_le16(hkey, group); /* group */
3457 if (group == 19)
3458 res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
3459 wpabuf_head(secret), wpabuf_len(secret), prk);
3460 else if (group == 20)
3461 res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey),
3462 wpabuf_head(secret), wpabuf_len(secret), prk);
3463 else if (group == 21)
3464 res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey),
3465 wpabuf_head(secret), wpabuf_len(secret), prk);
3466 wpabuf_clear_free(hkey);
3467 wpabuf_clear_free(secret);
3468 if (res < 0)
3469 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3470
3471 wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
3472
3473 /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
3474
3475 os_free(sta->owe_pmk);
3476 sta->owe_pmk = os_malloc(hash_len);
3477 if (!sta->owe_pmk) {
3478 os_memset(prk, 0, SHA512_MAC_LEN);
3479 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3480 }
3481
3482 if (group == 19)
3483 res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info,
3484 os_strlen(info), sta->owe_pmk, hash_len);
3485 else if (group == 20)
3486 res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info,
3487 os_strlen(info), sta->owe_pmk, hash_len);
3488 else if (group == 21)
3489 res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
3490 os_strlen(info), sta->owe_pmk, hash_len);
3491 os_memset(prk, 0, SHA512_MAC_LEN);
3492 if (res < 0) {
3493 os_free(sta->owe_pmk);
3494 sta->owe_pmk = NULL;
3495 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3496 }
3497 sta->owe_pmk_len = hash_len;
3498
3499 wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
3500 wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
3501 wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk,
3502 sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE);
3503
3504 return WLAN_STATUS_SUCCESS;
3505}
3506
Hai Shalom81f62d82019-07-22 12:10:00 -07003507
3508u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
3509 const u8 *rsn_ie, size_t rsn_ie_len,
3510 const u8 *owe_dh, size_t owe_dh_len)
3511{
3512 struct wpa_ie_data data;
3513 int res;
3514
3515 if (!rsn_ie || rsn_ie_len < 2) {
3516 wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
3517 MAC2STR(peer));
3518 return WLAN_STATUS_INVALID_IE;
3519 }
3520 rsn_ie -= 2;
3521 rsn_ie_len += 2;
3522
3523 res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
3524 if (res) {
3525 wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
3526 " (res=%d)", MAC2STR(peer), res);
3527 wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
3528 return wpa_res_to_status_code(res);
3529 }
3530 if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
3531 wpa_printf(MSG_DEBUG,
3532 "OWE: Unexpected key mgmt 0x%x from " MACSTR,
3533 (unsigned int) data.key_mgmt, MAC2STR(peer));
3534 return WLAN_STATUS_AKMP_NOT_VALID;
3535 }
3536 if (!owe_dh) {
3537 wpa_printf(MSG_DEBUG,
3538 "OWE: No Diffie-Hellman Parameter element from "
3539 MACSTR, MAC2STR(peer));
3540 return WLAN_STATUS_AKMP_NOT_VALID;
3541 }
3542
3543 return WLAN_STATUS_SUCCESS;
3544}
3545
3546
3547u16 owe_process_rsn_ie(struct hostapd_data *hapd,
3548 struct sta_info *sta,
3549 const u8 *rsn_ie, size_t rsn_ie_len,
3550 const u8 *owe_dh, size_t owe_dh_len)
3551{
3552 u16 status;
3553 u8 *owe_buf, ie[256 * 2];
3554 size_t ie_len = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07003555 enum wpa_validate_result res;
Hai Shalom81f62d82019-07-22 12:10:00 -07003556
3557 if (!rsn_ie || rsn_ie_len < 2) {
3558 wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
3559 status = WLAN_STATUS_INVALID_IE;
3560 goto end;
3561 }
3562
3563 if (!sta->wpa_sm)
3564 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
3565 NULL);
3566 if (!sta->wpa_sm) {
3567 wpa_printf(MSG_WARNING,
3568 "OWE: Failed to initialize WPA state machine");
3569 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3570 goto end;
3571 }
3572 rsn_ie -= 2;
3573 rsn_ie_len += 2;
3574 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
3575 hapd->iface->freq, rsn_ie, rsn_ie_len,
Hai Shalomc3565922019-10-28 11:58:20 -07003576 NULL, 0, NULL, 0, owe_dh, owe_dh_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07003577 status = wpa_res_to_status_code(res);
3578 if (status != WLAN_STATUS_SUCCESS)
3579 goto end;
3580 status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
3581 if (status != WLAN_STATUS_SUCCESS)
3582 goto end;
3583 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
3584 NULL, 0);
3585 if (!owe_buf) {
3586 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3587 goto end;
3588 }
3589
3590 if (sta->owe_ecdh) {
3591 struct wpabuf *pub;
3592
3593 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
3594 if (!pub) {
3595 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3596 goto end;
3597 }
3598
3599 /* OWE Diffie-Hellman Parameter element */
3600 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
3601 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
3602 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
3603 */
3604 WPA_PUT_LE16(owe_buf, sta->owe_group);
3605 owe_buf += 2;
3606 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
3607 owe_buf += wpabuf_len(pub);
3608 wpabuf_free(pub);
3609 sta->external_dh_updated = 1;
3610 }
3611 ie_len = owe_buf - ie;
3612
3613end:
3614 wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
3615 MACSTR, status, (unsigned int) ie_len,
3616 MAC2STR(sta->addr));
3617 hostapd_drv_update_dh_ie(hapd, sta->addr, status,
3618 status == WLAN_STATUS_SUCCESS ? ie : NULL,
3619 ie_len);
3620
3621 return status;
3622}
3623
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003624#endif /* CONFIG_OWE */
3625
3626
Hai Shalom899fcc72020-10-19 14:38:18 -07003627static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
3628 int reassoc)
3629{
3630 if ((sta->flags &
3631 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
3632 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
3633 return false;
3634
3635 if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
3636 ap_check_sa_query_timeout(hapd, sta);
3637
3638 if (!sta->sa_query_timed_out &&
3639 (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
3640 /*
3641 * STA has already been associated with MFP and SA Query timeout
3642 * has not been reached. Reject the association attempt
3643 * temporarily and start SA Query, if one is not pending.
3644 */
3645 if (sta->sa_query_count == 0)
3646 ap_sta_start_sa_query(hapd, sta);
3647
3648 return true;
3649 }
3650
3651 return false;
3652}
3653
3654
Sunil Ravi036cec52023-03-29 11:35:17 -07003655static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
3656 const u8 *ies, size_t ies_len,
3657 struct ieee802_11_elems *elems, int reassoc)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003658{
Hai Shalomb755a2a2020-04-23 21:49:02 -07003659 int resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003660 const u8 *wpa_ie;
3661 size_t wpa_ie_len;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003662 const u8 *p2p_dev_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003663
Sunil Ravi036cec52023-03-29 11:35:17 -07003664 resp = check_ssid(hapd, sta, elems->ssid, elems->ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003665 if (resp != WLAN_STATUS_SUCCESS)
3666 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003667 resp = check_wmm(hapd, sta, elems->wmm, elems->wmm_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003668 if (resp != WLAN_STATUS_SUCCESS)
3669 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003670 resp = check_ext_capab(hapd, sta, elems->ext_capab,
3671 elems->ext_capab_len);
Dmitry Shmidt051af732013-10-22 13:52:46 -07003672 if (resp != WLAN_STATUS_SUCCESS)
3673 return resp;
Sunil Ravi036cec52023-03-29 11:35:17 -07003674 resp = copy_supp_rates(hapd, sta, elems);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003675 if (resp != WLAN_STATUS_SUCCESS)
3676 return resp;
Hai Shalom74f70d42019-02-11 14:42:39 -08003677
Sunil Ravi036cec52023-03-29 11:35:17 -07003678 resp = check_multi_ap(hapd, sta, elems->multi_ap, elems->multi_ap_len);
Hai Shalom74f70d42019-02-11 14:42:39 -08003679 if (resp != WLAN_STATUS_SUCCESS)
3680 return resp;
3681
Sunil Ravi036cec52023-03-29 11:35:17 -07003682 resp = copy_sta_ht_capab(hapd, sta, elems->ht_capabilities);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003683 if (resp != WLAN_STATUS_SUCCESS)
3684 return resp;
3685 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
3686 !(sta->flags & WLAN_STA_HT)) {
3687 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3688 HOSTAPD_LEVEL_INFO, "Station does not support "
3689 "mandatory HT PHY - reject association");
3690 return WLAN_STATUS_ASSOC_DENIED_NO_HT;
3691 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003692
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003693#ifdef CONFIG_IEEE80211AC
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003694 if (hapd->iconf->ieee80211ac) {
Sunil Ravi036cec52023-03-29 11:35:17 -07003695 resp = copy_sta_vht_capab(hapd, sta, elems->vht_capabilities);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003696 if (resp != WLAN_STATUS_SUCCESS)
3697 return resp;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08003698
Sunil Ravi036cec52023-03-29 11:35:17 -07003699 resp = set_sta_vht_opmode(hapd, sta, elems->vht_opmode_notif);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003700 if (resp != WLAN_STATUS_SUCCESS)
3701 return resp;
3702 }
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08003703
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003704 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
3705 !(sta->flags & WLAN_STA_VHT)) {
3706 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3707 HOSTAPD_LEVEL_INFO, "Station does not support "
3708 "mandatory VHT PHY - reject association");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003709 return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003710 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003711
Sunil Ravi036cec52023-03-29 11:35:17 -07003712 if (hapd->conf->vendor_vht && !elems->vht_capabilities) {
3713 resp = copy_sta_vendor_vht(hapd, sta, elems->vendor_vht,
3714 elems->vendor_vht_len);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003715 if (resp != WLAN_STATUS_SUCCESS)
3716 return resp;
3717 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003718#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07003719#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08003720 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07003721 resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
Sunil Ravi036cec52023-03-29 11:35:17 -07003722 elems->he_capabilities,
3723 elems->he_capabilities_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07003724 if (resp != WLAN_STATUS_SUCCESS)
3725 return resp;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003726
3727 if (hapd->iconf->require_he && !(sta->flags & WLAN_STA_HE)) {
3728 hostapd_logger(hapd, sta->addr,
3729 HOSTAPD_MODULE_IEEE80211,
3730 HOSTAPD_LEVEL_INFO,
3731 "Station does not support mandatory HE PHY - reject association");
3732 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
3733 }
3734
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003735 if (is_6ghz_op_class(hapd->iconf->op_class)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07003736 if (!(sta->flags & WLAN_STA_HE)) {
3737 hostapd_logger(hapd, sta->addr,
3738 HOSTAPD_MODULE_IEEE80211,
3739 HOSTAPD_LEVEL_INFO,
3740 "Station does not support mandatory HE PHY - reject association");
3741 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
3742 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003743 resp = copy_sta_he_6ghz_capab(hapd, sta,
Sunil Ravi036cec52023-03-29 11:35:17 -07003744 elems->he_6ghz_band_cap);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003745 if (resp != WLAN_STATUS_SUCCESS)
3746 return resp;
3747 }
Hai Shalom81f62d82019-07-22 12:10:00 -07003748 }
3749#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07003750#ifdef CONFIG_IEEE80211BE
3751 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
3752 resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP,
Sunil Ravi036cec52023-03-29 11:35:17 -07003753 elems->he_capabilities,
3754 elems->he_capabilities_len,
3755 elems->eht_capabilities,
3756 elems->eht_capabilities_len);
Sunil Ravia04bd252022-05-02 22:54:18 -07003757 if (resp != WLAN_STATUS_SUCCESS)
3758 return resp;
3759 }
3760#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003761
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003762#ifdef CONFIG_P2P
Sunil Ravi036cec52023-03-29 11:35:17 -07003763 if (elems->p2p && ies && ies_len) {
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003764 wpabuf_free(sta->p2p_ie);
3765 sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
3766 P2P_IE_VENDOR_TYPE);
3767 if (sta->p2p_ie)
3768 p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
3769 } else {
3770 wpabuf_free(sta->p2p_ie);
3771 sta->p2p_ie = NULL;
3772 }
3773#endif /* CONFIG_P2P */
3774
Sunil Ravi036cec52023-03-29 11:35:17 -07003775 if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems->rsn_ie) {
3776 wpa_ie = elems->rsn_ie;
3777 wpa_ie_len = elems->rsn_ie_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003778 } else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07003779 elems->wpa_ie) {
3780 wpa_ie = elems->wpa_ie;
3781 wpa_ie_len = elems->wpa_ie_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003782 } else {
3783 wpa_ie = NULL;
3784 wpa_ie_len = 0;
3785 }
3786
3787#ifdef CONFIG_WPS
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003788 sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
Sunil Ravi036cec52023-03-29 11:35:17 -07003789 if (hapd->conf->wps_state && elems->wps_ie && ies && ies_len) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003790 wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
3791 "Request - assume WPS is used");
Hai Shalom899fcc72020-10-19 14:38:18 -07003792 if (check_sa_query(hapd, sta, reassoc))
3793 return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003794 sta->flags |= WLAN_STA_WPS;
3795 wpabuf_free(sta->wps_ie);
3796 sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
3797 WPS_IE_VENDOR_TYPE);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003798 if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
3799 wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
3800 sta->flags |= WLAN_STA_WPS2;
3801 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003802 wpa_ie = NULL;
3803 wpa_ie_len = 0;
3804 if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
3805 wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
3806 "(Re)Association Request - reject");
3807 return WLAN_STATUS_INVALID_IE;
3808 }
3809 } else if (hapd->conf->wps_state && wpa_ie == NULL) {
3810 wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
3811 "(Re)Association Request - possible WPS use");
3812 sta->flags |= WLAN_STA_MAYBE_WPS;
3813 } else
3814#endif /* CONFIG_WPS */
3815 if (hapd->conf->wpa && wpa_ie == NULL) {
3816 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3817 HOSTAPD_LEVEL_INFO,
3818 "No WPA/RSN IE in association request");
3819 return WLAN_STATUS_INVALID_IE;
3820 }
3821
3822 if (hapd->conf->wpa && wpa_ie) {
Hai Shalomfdcde762020-04-02 11:19:20 -07003823 enum wpa_validate_result res;
3824
Sunil8cd6f4d2022-06-28 18:40:46 +00003825 if (check_sa_query(hapd, sta, reassoc))
3826 return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
3827
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003828 wpa_ie -= 2;
3829 wpa_ie_len += 2;
3830 if (sta->wpa_sm == NULL)
3831 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003832 sta->addr,
3833 p2p_dev_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003834 if (sta->wpa_sm == NULL) {
3835 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
3836 "state machine");
3837 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3838 }
Hai Shalom021b0b52019-04-10 11:17:58 -07003839 wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003840 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07003841 hapd->iface->freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003842 wpa_ie, wpa_ie_len,
Sunil Ravi036cec52023-03-29 11:35:17 -07003843 elems->rsnxe ? elems->rsnxe - 2 :
3844 NULL,
3845 elems->rsnxe ? elems->rsnxe_len + 2 :
3846 0,
3847 elems->mdie, elems->mdie_len,
3848 elems->owe_dh, elems->owe_dh_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003849 resp = wpa_res_to_status_code(res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003850 if (resp != WLAN_STATUS_SUCCESS)
3851 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003852
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003853 if (wpa_auth_uses_mfp(sta->wpa_sm))
3854 sta->flags |= WLAN_STA_MFP;
3855 else
3856 sta->flags &= ~WLAN_STA_MFP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003857
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003858#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003859 if (sta->auth_alg == WLAN_AUTH_FT) {
3860 if (!reassoc) {
3861 wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
3862 "to use association (not "
3863 "re-association) with FT auth_alg",
3864 MAC2STR(sta->addr));
3865 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3866 }
3867
3868 resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
3869 ies_len);
3870 if (resp != WLAN_STATUS_SUCCESS)
3871 return resp;
3872 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003873#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003874
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003875#ifdef CONFIG_SAE
Roshan Pius3a1667e2018-07-03 15:17:14 -07003876 if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
3877 sta->sae->state == SAE_ACCEPTED)
3878 wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
3879
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003880 if (wpa_auth_uses_sae(sta->wpa_sm) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003881 sta->auth_alg == WLAN_AUTH_OPEN) {
3882 struct rsn_pmksa_cache_entry *sa;
3883 sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
Sunil Ravi89eba102022-09-13 21:04:37 -07003884 if (!sa || !wpa_key_mgmt_sae(sa->akmp)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003885 wpa_printf(MSG_DEBUG,
3886 "SAE: No PMKSA cache entry found for "
3887 MACSTR, MAC2STR(sta->addr));
3888 return WLAN_STATUS_INVALID_PMKID;
3889 }
3890 wpa_printf(MSG_DEBUG, "SAE: " MACSTR
3891 " using PMKSA caching", MAC2STR(sta->addr));
3892 } else if (wpa_auth_uses_sae(sta->wpa_sm) &&
3893 sta->auth_alg != WLAN_AUTH_SAE &&
3894 !(sta->auth_alg == WLAN_AUTH_FT &&
3895 wpa_auth_uses_ft_sae(sta->wpa_sm))) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003896 wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
3897 "SAE AKM after non-SAE auth_alg %u",
3898 MAC2STR(sta->addr), sta->auth_alg);
3899 return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
3900 }
Hai Shalomc3565922019-10-28 11:58:20 -07003901
Sunil Ravi77d572f2023-01-17 23:58:31 +00003902 if (hapd->conf->sae_pwe == SAE_PWE_BOTH &&
Hai Shalomc3565922019-10-28 11:58:20 -07003903 sta->auth_alg == WLAN_AUTH_SAE &&
Hai Shalom899fcc72020-10-19 14:38:18 -07003904 sta->sae && !sta->sae->h2e &&
Sunil Ravi036cec52023-03-29 11:35:17 -07003905 ieee802_11_rsnx_capab_len(elems->rsnxe, elems->rsnxe_len,
Hai Shaloma20dcd72022-02-04 13:43:00 -08003906 WLAN_RSNX_CAPAB_SAE_H2E)) {
Hai Shalomc3565922019-10-28 11:58:20 -07003907 wpa_printf(MSG_INFO, "SAE: " MACSTR
3908 " indicates support for SAE H2E, but did not use it",
3909 MAC2STR(sta->addr));
3910 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3911 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003912#endif /* CONFIG_SAE */
3913
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003914#ifdef CONFIG_OWE
3915 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
3916 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
Sunil Ravi036cec52023-03-29 11:35:17 -07003917 elems->owe_dh) {
3918 resp = owe_process_assoc_req(hapd, sta, elems->owe_dh,
3919 elems->owe_dh_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003920 if (resp != WLAN_STATUS_SUCCESS)
3921 return resp;
3922 }
3923#endif /* CONFIG_OWE */
3924
Hai Shalom021b0b52019-04-10 11:17:58 -07003925#ifdef CONFIG_DPP2
3926 dpp_pfs_free(sta->dpp_pfs);
3927 sta->dpp_pfs = NULL;
3928
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003929 if (DPP_VERSION > 1 &&
3930 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07003931 hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
3932 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
Sunil Ravi036cec52023-03-29 11:35:17 -07003933 elems->owe_dh) {
Hai Shalom021b0b52019-04-10 11:17:58 -07003934 sta->dpp_pfs = dpp_pfs_init(
3935 wpabuf_head(hapd->conf->dpp_netaccesskey),
3936 wpabuf_len(hapd->conf->dpp_netaccesskey));
3937 if (!sta->dpp_pfs) {
3938 wpa_printf(MSG_DEBUG,
3939 "DPP: Could not initialize PFS");
3940 /* Try to continue without PFS */
3941 goto pfs_fail;
3942 }
3943
Sunil Ravi036cec52023-03-29 11:35:17 -07003944 if (dpp_pfs_process(sta->dpp_pfs, elems->owe_dh,
3945 elems->owe_dh_len) < 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07003946 dpp_pfs_free(sta->dpp_pfs);
3947 sta->dpp_pfs = NULL;
3948 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3949 }
3950 }
3951
3952 wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
3953 sta->dpp_pfs->secret : NULL);
3954 pfs_fail:
3955#endif /* CONFIG_DPP2 */
3956
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003957 if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003958 wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
3959 hostapd_logger(hapd, sta->addr,
3960 HOSTAPD_MODULE_IEEE80211,
3961 HOSTAPD_LEVEL_INFO,
3962 "Station tried to use TKIP with HT "
3963 "association");
3964 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
3965 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003966#ifdef CONFIG_HS20
3967 } else if (hapd->conf->osen) {
Sunil Ravi036cec52023-03-29 11:35:17 -07003968 if (!elems->osen) {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003969 hostapd_logger(
3970 hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3971 HOSTAPD_LEVEL_INFO,
3972 "No HS 2.0 OSEN element in association request");
3973 return WLAN_STATUS_INVALID_IE;
3974 }
3975
3976 wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
3977 if (sta->wpa_sm == NULL)
3978 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
3979 sta->addr, NULL);
3980 if (sta->wpa_sm == NULL) {
3981 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
3982 "state machine");
3983 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3984 }
3985 if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
Sunil Ravi036cec52023-03-29 11:35:17 -07003986 elems->osen - 2, elems->osen_len + 2) < 0)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003987 return WLAN_STATUS_INVALID_IE;
3988#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003989 } else
3990 wpa_auth_sta_no_wpa(sta->wpa_sm);
3991
3992#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003993 p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
3994#endif /* CONFIG_P2P */
3995
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003996#ifdef CONFIG_HS20
3997 wpabuf_free(sta->hs20_ie);
Sunil Ravi036cec52023-03-29 11:35:17 -07003998 if (elems->hs20 && elems->hs20_len > 4) {
Hai Shalom74f70d42019-02-11 14:42:39 -08003999 int release;
4000
Sunil Ravi036cec52023-03-29 11:35:17 -07004001 sta->hs20_ie = wpabuf_alloc_copy(elems->hs20 + 4,
4002 elems->hs20_len - 4);
4003 release = ((elems->hs20[4] >> 4) & 0x0f) + 1;
Hai Shalomc3565922019-10-28 11:58:20 -07004004 if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
4005 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004006 wpa_printf(MSG_DEBUG,
4007 "HS 2.0: PMF not negotiated by release %d station "
4008 MACSTR, release, MAC2STR(sta->addr));
4009 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
4010 }
4011 } else {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004012 sta->hs20_ie = NULL;
Hai Shalom74f70d42019-02-11 14:42:39 -08004013 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07004014
4015 wpabuf_free(sta->roaming_consortium);
Sunil Ravi036cec52023-03-29 11:35:17 -07004016 if (elems->roaming_cons_sel)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004017 sta->roaming_consortium = wpabuf_alloc_copy(
Sunil Ravi036cec52023-03-29 11:35:17 -07004018 elems->roaming_cons_sel + 4,
4019 elems->roaming_cons_sel_len - 4);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004020 else
4021 sta->roaming_consortium = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004022#endif /* CONFIG_HS20 */
4023
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004024#ifdef CONFIG_FST
4025 wpabuf_free(sta->mb_ies);
4026 if (hapd->iface->fst)
Sunil Ravi036cec52023-03-29 11:35:17 -07004027 sta->mb_ies = mb_ies_by_info(&elems->mb_ies);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004028 else
4029 sta->mb_ies = NULL;
4030#endif /* CONFIG_FST */
4031
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004032#ifdef CONFIG_MBO
Sunil Ravi036cec52023-03-29 11:35:17 -07004033 mbo_ap_check_sta_assoc(hapd, sta, elems);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004034
4035 if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004036 elems->mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004037 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
4038 wpa_printf(MSG_INFO,
4039 "MBO: Reject WPA2 association without PMF");
4040 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4041 }
4042#endif /* CONFIG_MBO */
4043
Hai Shalom74f70d42019-02-11 14:42:39 -08004044#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
4045 if (wpa_auth_uses_ocv(sta->wpa_sm) &&
4046 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4047 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4048 sta->auth_alg == WLAN_AUTH_FILS_PK)) {
4049 struct wpa_channel_info ci;
4050 int tx_chanwidth;
4051 int tx_seg1_idx;
Hai Shalom899fcc72020-10-19 14:38:18 -07004052 enum oci_verify_result res;
Hai Shalom74f70d42019-02-11 14:42:39 -08004053
4054 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
4055 wpa_printf(MSG_WARNING,
4056 "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
4057 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4058 }
4059
4060 if (get_sta_tx_parameters(sta->wpa_sm,
4061 channel_width_to_int(ci.chanwidth),
4062 ci.seg1_idx, &tx_chanwidth,
4063 &tx_seg1_idx) < 0)
4064 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4065
Sunil Ravi036cec52023-03-29 11:35:17 -07004066 res = ocv_verify_tx_params(elems->oci, elems->oci_len, &ci,
Hai Shalom899fcc72020-10-19 14:38:18 -07004067 tx_chanwidth, tx_seg1_idx);
4068 if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
4069 res == OCI_NOT_FOUND) {
4070 /* Work around misbehaving STAs */
4071 wpa_printf(MSG_INFO,
4072 "FILS: Disable OCV with a STA that does not send OCI");
4073 wpa_auth_set_ocv(sta->wpa_sm, 0);
4074 } else if (res != OCI_SUCCESS) {
4075 wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
4076 ocv_errorstr);
4077 wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
4078 MACSTR " frame=fils-reassoc-req error=%s",
4079 MAC2STR(sta->addr), ocv_errorstr);
Hai Shalom74f70d42019-02-11 14:42:39 -08004080 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4081 }
4082 }
4083#endif /* CONFIG_FILS && CONFIG_OCV */
4084
Sunil Ravi036cec52023-03-29 11:35:17 -07004085 ap_copy_sta_supp_op_classes(sta, elems->supp_op_classes,
4086 elems->supp_op_classes_len);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08004087
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004088 if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
Sunil Ravi036cec52023-03-29 11:35:17 -07004089 elems->rrm_enabled &&
4090 elems->rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
4091 os_memcpy(sta->rrm_enabled_capa, elems->rrm_enabled,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004092 sizeof(sta->rrm_enabled_capa));
4093
Sunil Ravi036cec52023-03-29 11:35:17 -07004094 if (elems->power_capab) {
4095 sta->min_tx_power = elems->power_capab[0];
4096 sta->max_tx_power = elems->power_capab[1];
Roshan Pius3a1667e2018-07-03 15:17:14 -07004097 sta->power_capab = 1;
4098 } else {
4099 sta->power_capab = 0;
4100 }
4101
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004102 return WLAN_STATUS_SUCCESS;
4103}
4104
4105
Sunil Ravi036cec52023-03-29 11:35:17 -07004106static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
4107 const u8 *ies, size_t ies_len, int reassoc)
4108{
4109 struct ieee802_11_elems elems;
4110
4111 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
4112 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4113 HOSTAPD_LEVEL_INFO,
4114 "Station sent an invalid association request");
4115 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4116 }
4117
4118 return __check_assoc_ies(hapd, sta, ies, ies_len, &elems, reassoc);
4119}
4120
4121
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004122static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
4123 u16 reason_code)
4124{
4125 int send_len;
4126 struct ieee80211_mgmt reply;
4127
4128 os_memset(&reply, 0, sizeof(reply));
4129 reply.frame_control =
4130 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
4131 os_memcpy(reply.da, addr, ETH_ALEN);
4132 os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
4133 os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
4134
4135 send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
4136 reply.u.deauth.reason_code = host_to_le16(reason_code);
4137
Hai Shalomfdcde762020-04-02 11:19:20 -07004138 if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004139 wpa_printf(MSG_INFO, "Failed to send deauth: %s",
4140 strerror(errno));
4141}
4142
4143
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004144static int add_associated_sta(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08004145 struct sta_info *sta, int reassoc)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004146{
4147 struct ieee80211_ht_capabilities ht_cap;
4148 struct ieee80211_vht_capabilities vht_cap;
Hai Shalom81f62d82019-07-22 12:10:00 -07004149 struct ieee80211_he_capabilities he_cap;
Sunil Ravia04bd252022-05-02 22:54:18 -07004150 struct ieee80211_eht_capabilities eht_cap;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004151 int set = 1;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004152
4153 /*
4154 * Remove the STA entry to ensure the STA PS state gets cleared and
4155 * configuration gets updated. This is relevant for cases, such as
4156 * FT-over-the-DS, where a station re-associates back to the same AP but
4157 * skips the authentication flow, or if working with a driver that
4158 * does not support full AP client state.
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004159 *
4160 * Skip this if the STA has already completed FT reassociation and the
4161 * TK has been configured since the TX/RX PN must not be reset to 0 for
4162 * the same key.
Hai Shalom74f70d42019-02-11 14:42:39 -08004163 *
4164 * FT-over-the-DS has a special case where the STA entry (and as such,
4165 * the TK) has not yet been configured to the driver depending on which
4166 * driver interface is used. For that case, allow add-STA operation to
4167 * be used (instead of set-STA). This is needed to allow mac80211-based
4168 * drivers to accept the STA parameter configuration. Since this is
4169 * after a new FT-over-DS exchange, a new TK has been derived, so key
4170 * reinstallation is not a concern for this case.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004171 */
Hai Shalom74f70d42019-02-11 14:42:39 -08004172 wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
4173 " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
4174 MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
4175 sta->ft_over_ds, reassoc,
4176 !!(sta->flags & WLAN_STA_AUTHORIZED),
4177 wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
4178 wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
4179
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004180 if (!sta->added_unassoc &&
4181 (!(sta->flags & WLAN_STA_AUTHORIZED) ||
Hai Shalom74f70d42019-02-11 14:42:39 -08004182 (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004183 (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
4184 !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004185 hostapd_drv_sta_remove(hapd, sta->addr);
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004186 wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
4187 set = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08004188
4189 /* Do not allow the FT-over-DS exception to be used more than
4190 * once per authentication exchange to guarantee a new TK is
4191 * used here */
4192 sta->ft_over_ds = 0;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004193 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004194
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004195 if (sta->flags & WLAN_STA_HT)
4196 hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004197#ifdef CONFIG_IEEE80211AC
4198 if (sta->flags & WLAN_STA_VHT)
4199 hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
4200#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07004201#ifdef CONFIG_IEEE80211AX
4202 if (sta->flags & WLAN_STA_HE) {
4203 hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
4204 sta->he_capab_len);
4205 }
4206#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07004207#ifdef CONFIG_IEEE80211BE
4208 if (sta->flags & WLAN_STA_EHT)
4209 hostapd_get_eht_capab(hapd, sta->eht_capab, &eht_cap,
4210 sta->eht_capab_len);
4211#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004212
4213 /*
4214 * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
4215 * will be set when the ACK frame for the (Re)Association Response frame
4216 * is processed (TX status driver event).
4217 */
4218 if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
4219 sta->supported_rates, sta->supported_rates_len,
4220 sta->listen_interval,
4221 sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
4222 sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
Hai Shalom81f62d82019-07-22 12:10:00 -07004223 sta->flags & WLAN_STA_HE ? &he_cap : NULL,
4224 sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
Sunil Ravia04bd252022-05-02 22:54:18 -07004225 sta->flags & WLAN_STA_EHT ? &eht_cap : NULL,
4226 sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004227 sta->he_6ghz_capab,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004228 sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004229 sta->vht_opmode, sta->p2p_ie ? 1 : 0,
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004230 set)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004231 hostapd_logger(hapd, sta->addr,
4232 HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
4233 "Could not %s STA to kernel driver",
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004234 set ? "set" : "add");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004235
4236 if (sta->added_unassoc) {
4237 hostapd_drv_sta_remove(hapd, sta->addr);
4238 sta->added_unassoc = 0;
4239 }
4240
4241 return -1;
4242 }
4243
4244 sta->added_unassoc = 0;
4245
4246 return 0;
4247}
4248
4249
4250static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt29333592017-01-09 12:27:11 -08004251 const u8 *addr, u16 status_code, int reassoc,
Hai Shalomfdcde762020-04-02 11:19:20 -07004252 const u8 *ies, size_t ies_len, int rssi,
4253 int omit_rsnxe)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004254{
4255 int send_len;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004256 u8 *buf;
4257 size_t buflen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004258 struct ieee80211_mgmt *reply;
4259 u8 *p;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004260 u16 res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004261
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004262 buflen = sizeof(struct ieee80211_mgmt) + 1024;
4263#ifdef CONFIG_FILS
4264 if (sta && sta->fils_hlp_resp)
4265 buflen += wpabuf_len(sta->fils_hlp_resp);
Hai Shalom81f62d82019-07-22 12:10:00 -07004266 if (sta)
4267 buflen += 150;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004268#endif /* CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004269#ifdef CONFIG_OWE
4270 if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
4271 buflen += 150;
4272#endif /* CONFIG_OWE */
Hai Shalom021b0b52019-04-10 11:17:58 -07004273#ifdef CONFIG_DPP2
4274 if (sta && sta->dpp_pfs)
4275 buflen += 5 + sta->dpp_pfs->curve->prime_len;
4276#endif /* CONFIG_DPP2 */
Sunil Ravia04bd252022-05-02 22:54:18 -07004277#ifdef CONFIG_IEEE80211BE
4278 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4279 buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
4280 buflen += 3 + sizeof(struct ieee80211_eht_operation);
Sunil Ravi036cec52023-03-29 11:35:17 -07004281 if (hapd->iconf->punct_bitmap)
4282 buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
Sunil Ravia04bd252022-05-02 22:54:18 -07004283 }
4284#endif /* CONFIG_IEEE80211BE */
4285
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004286 buf = os_zalloc(buflen);
4287 if (!buf) {
4288 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4289 goto done;
4290 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004291 reply = (struct ieee80211_mgmt *) buf;
4292 reply->frame_control =
4293 IEEE80211_FC(WLAN_FC_TYPE_MGMT,
4294 (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
4295 WLAN_FC_STYPE_ASSOC_RESP));
Dmitry Shmidt29333592017-01-09 12:27:11 -08004296 os_memcpy(reply->da, addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004297 os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
4298 os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
4299
4300 send_len = IEEE80211_HDRLEN;
4301 send_len += sizeof(reply->u.assoc_resp);
4302 reply->u.assoc_resp.capab_info =
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07004303 host_to_le16(hostapd_own_capab_info(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004304 reply->u.assoc_resp.status_code = host_to_le16(status_code);
Dmitry Shmidt29333592017-01-09 12:27:11 -08004305
4306 reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
4307 BIT(14) | BIT(15));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004308 /* Supported rates */
4309 p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
4310 /* Extended supported rates */
4311 p = hostapd_eid_ext_supp_rates(hapd, p);
4312
Hai Shalomfdcde762020-04-02 11:19:20 -07004313 /* Radio measurement capabilities */
4314 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
4315
Hai Shalom74f70d42019-02-11 14:42:39 -08004316#ifdef CONFIG_MBO
4317 if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
4318 rssi != 0) {
4319 int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
4320
4321 p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
4322 delta);
4323 }
4324#endif /* CONFIG_MBO */
4325
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004326#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt29333592017-01-09 12:27:11 -08004327 if (sta && status_code == WLAN_STATUS_SUCCESS) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004328 /* IEEE 802.11r: Mobility Domain Information, Fast BSS
4329 * Transition Information, RSN, [RIC Response] */
4330 p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004331 buf + buflen - p,
Hai Shalomfdcde762020-04-02 11:19:20 -07004332 sta->auth_alg, ies, ies_len,
4333 omit_rsnxe);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004334 if (!p) {
4335 wpa_printf(MSG_DEBUG,
4336 "FT: Failed to write AssocResp IEs");
4337 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4338 goto done;
4339 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004340 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004341#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom81f62d82019-07-22 12:10:00 -07004342#ifdef CONFIG_FILS
4343 if (sta && status_code == WLAN_STATUS_SUCCESS &&
4344 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4345 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4346 sta->auth_alg == WLAN_AUTH_FILS_PK))
4347 p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
4348 buf + buflen - p,
4349 ies, ies_len);
4350#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004351
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004352#ifdef CONFIG_OWE
Hai Shalom74f70d42019-02-11 14:42:39 -08004353 if (sta && status_code == WLAN_STATUS_SUCCESS &&
4354 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004355 p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
4356 buf + buflen - p,
4357 ies, ies_len);
4358#endif /* CONFIG_OWE */
4359
Dmitry Shmidt29333592017-01-09 12:27:11 -08004360 if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004361 p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004362
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004363 p = hostapd_eid_ht_capabilities(hapd, p);
4364 p = hostapd_eid_ht_operation(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004365
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004366#ifdef CONFIG_IEEE80211AC
Hai Shalomc3565922019-10-28 11:58:20 -07004367 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
4368 !is_6ghz_op_class(hapd->iconf->op_class)) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07004369 u32 nsts = 0, sta_nsts;
4370
Dmitry Shmidt29333592017-01-09 12:27:11 -08004371 if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07004372 struct ieee80211_vht_capabilities *capa;
4373
4374 nsts = (hapd->iface->conf->vht_capab >>
4375 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
4376 capa = sta->vht_capabilities;
4377 sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
4378 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
4379
4380 if (nsts < sta_nsts)
4381 nsts = 0;
4382 else
4383 nsts = sta_nsts;
4384 }
4385 p = hostapd_eid_vht_capabilities(hapd, p, nsts);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004386 p = hostapd_eid_vht_operation(hapd, p);
4387 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004388#endif /* CONFIG_IEEE80211AC */
4389
Hai Shalom81f62d82019-07-22 12:10:00 -07004390#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08004391 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07004392 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
4393 p = hostapd_eid_he_operation(hapd, p);
Sunil Ravia04bd252022-05-02 22:54:18 -07004394 p = hostapd_eid_cca(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07004395 p = hostapd_eid_spatial_reuse(hapd, p);
4396 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004397 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07004398 }
4399#endif /* CONFIG_IEEE80211AX */
4400
Sunil Ravi77d572f2023-01-17 23:58:31 +00004401 p = hostapd_eid_ext_capab(hapd, p, false);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004402 p = hostapd_eid_bss_max_idle_period(hapd, p);
Dmitry Shmidt29333592017-01-09 12:27:11 -08004403 if (sta && sta->qos_map_enabled)
Dmitry Shmidt051af732013-10-22 13:52:46 -07004404 p = hostapd_eid_qos_map_set(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004405
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004406#ifdef CONFIG_FST
4407 if (hapd->iface->fst_ies) {
4408 os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
4409 wpabuf_len(hapd->iface->fst_ies));
4410 p += wpabuf_len(hapd->iface->fst_ies);
4411 }
4412#endif /* CONFIG_FST */
4413
Hai Shalomfdcde762020-04-02 11:19:20 -07004414#ifdef CONFIG_TESTING_OPTIONS
4415 if (hapd->conf->rsnxe_override_ft &&
4416 buf + buflen - p >=
4417 (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
4418 sta && sta->auth_alg == WLAN_AUTH_FT) {
4419 wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
4420 os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
4421 wpabuf_len(hapd->conf->rsnxe_override_ft));
4422 p += wpabuf_len(hapd->conf->rsnxe_override_ft);
4423 goto rsnxe_done;
4424 }
4425#endif /* CONFIG_TESTING_OPTIONS */
4426 if (!omit_rsnxe)
4427 p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
4428#ifdef CONFIG_TESTING_OPTIONS
4429rsnxe_done:
4430#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomc3565922019-10-28 11:58:20 -07004431
Sunil Ravia04bd252022-05-02 22:54:18 -07004432#ifdef CONFIG_IEEE80211BE
4433 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4434 p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
4435 p = hostapd_eid_eht_operation(hapd, p);
4436 }
4437#endif /* CONFIG_IEEE80211BE */
4438
Hai Shalom021b0b52019-04-10 11:17:58 -07004439#ifdef CONFIG_OWE
4440 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
4441 sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
Hai Shalom899fcc72020-10-19 14:38:18 -07004442 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
4443 !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004444 struct wpabuf *pub;
4445
4446 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
4447 if (!pub) {
4448 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4449 goto done;
4450 }
4451 /* OWE Diffie-Hellman Parameter element */
4452 *p++ = WLAN_EID_EXTENSION; /* Element ID */
4453 *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
4454 *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
4455 WPA_PUT_LE16(p, sta->owe_group);
4456 p += 2;
4457 os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
4458 p += wpabuf_len(pub);
4459 wpabuf_free(pub);
4460 }
4461#endif /* CONFIG_OWE */
4462
4463#ifdef CONFIG_DPP2
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004464 if (DPP_VERSION > 1 && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07004465 sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
4466 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
4467 os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
4468 wpabuf_len(sta->dpp_pfs->ie));
4469 p += wpabuf_len(sta->dpp_pfs->ie);
4470 }
4471#endif /* CONFIG_DPP2 */
4472
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004473#ifdef CONFIG_IEEE80211AC
Dmitry Shmidt29333592017-01-09 12:27:11 -08004474 if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004475 p = hostapd_eid_vendor_vht(hapd, p);
4476#endif /* CONFIG_IEEE80211AC */
4477
Dmitry Shmidt29333592017-01-09 12:27:11 -08004478 if (sta && (sta->flags & WLAN_STA_WMM))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004479 p = hostapd_eid_wmm(hapd, p);
4480
4481#ifdef CONFIG_WPS
Dmitry Shmidt29333592017-01-09 12:27:11 -08004482 if (sta &&
4483 ((sta->flags & WLAN_STA_WPS) ||
4484 ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004485 struct wpabuf *wps = wps_build_assoc_resp_ie();
4486 if (wps) {
4487 os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
4488 p += wpabuf_len(wps);
4489 wpabuf_free(wps);
4490 }
4491 }
4492#endif /* CONFIG_WPS */
4493
Hai Shalom74f70d42019-02-11 14:42:39 -08004494 if (sta && (sta->flags & WLAN_STA_MULTI_AP))
4495 p = hostapd_eid_multi_ap(hapd, p);
4496
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004497#ifdef CONFIG_P2P
Dmitry Shmidt29333592017-01-09 12:27:11 -08004498 if (sta && sta->p2p_ie && hapd->p2p_group) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004499 struct wpabuf *p2p_resp_ie;
4500 enum p2p_status_code status;
4501 switch (status_code) {
4502 case WLAN_STATUS_SUCCESS:
4503 status = P2P_SC_SUCCESS;
4504 break;
4505 case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
4506 status = P2P_SC_FAIL_LIMIT_REACHED;
4507 break;
4508 default:
4509 status = P2P_SC_FAIL_INVALID_PARAMS;
4510 break;
4511 }
4512 p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
4513 if (p2p_resp_ie) {
4514 os_memcpy(p, wpabuf_head(p2p_resp_ie),
4515 wpabuf_len(p2p_resp_ie));
4516 p += wpabuf_len(p2p_resp_ie);
4517 wpabuf_free(p2p_resp_ie);
4518 }
4519 }
4520#endif /* CONFIG_P2P */
4521
4522#ifdef CONFIG_P2P_MANAGER
4523 if (hapd->conf->p2p & P2P_MANAGE)
4524 p = hostapd_eid_p2p_manage(hapd, p);
4525#endif /* CONFIG_P2P_MANAGER */
4526
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004527 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004528
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004529 if (hapd->conf->assocresp_elements &&
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004530 (size_t) (buf + buflen - p) >=
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004531 wpabuf_len(hapd->conf->assocresp_elements)) {
4532 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
4533 wpabuf_len(hapd->conf->assocresp_elements));
4534 p += wpabuf_len(hapd->conf->assocresp_elements);
4535 }
4536
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004537 send_len += p - reply->u.assoc_resp.variable;
4538
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004539#ifdef CONFIG_FILS
Dmitry Shmidt29333592017-01-09 12:27:11 -08004540 if (sta &&
4541 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004542 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4543 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
4544 status_code == WLAN_STATUS_SUCCESS) {
4545 struct ieee802_11_elems elems;
4546
4547 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004548 ParseFailed || !elems.fils_session) {
4549 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4550 goto done;
4551 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004552
4553 /* FILS Session */
4554 *p++ = WLAN_EID_EXTENSION; /* Element ID */
4555 *p++ = 1 + FILS_SESSION_LEN; /* Length */
4556 *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
4557 os_memcpy(p, elems.fils_session, FILS_SESSION_LEN);
4558 send_len += 2 + 1 + FILS_SESSION_LEN;
4559
4560 send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004561 buflen, sta->fils_hlp_resp);
4562 if (send_len < 0) {
4563 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4564 goto done;
4565 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004566 }
4567#endif /* CONFIG_FILS */
4568
Hai Shalomfdcde762020-04-02 11:19:20 -07004569 if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004570 wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
4571 strerror(errno));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004572 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004573 }
4574
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004575done:
4576 os_free(buf);
4577 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004578}
4579
4580
Roshan Pius3a1667e2018-07-03 15:17:14 -07004581#ifdef CONFIG_OWE
4582u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
4583 const u8 *owe_dh, u8 owe_dh_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07004584 u8 *owe_buf, size_t owe_buf_len, u16 *status)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004585{
4586#ifdef CONFIG_TESTING_OPTIONS
4587 if (hapd->conf->own_ie_override) {
4588 wpa_printf(MSG_DEBUG, "OWE: Using IE override");
Hai Shalomfdcde762020-04-02 11:19:20 -07004589 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004590 return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
4591 owe_buf_len, NULL, 0);
4592 }
4593#endif /* CONFIG_TESTING_OPTIONS */
4594
4595 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
4596 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
4597 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
4598 owe_buf_len, NULL, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -07004599 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004600 return owe_buf;
4601 }
4602
Hai Shalom81f62d82019-07-22 12:10:00 -07004603 if (sta->owe_pmk && sta->external_dh_updated) {
4604 wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
Hai Shalomfdcde762020-04-02 11:19:20 -07004605 *status = WLAN_STATUS_SUCCESS;
Hai Shalom81f62d82019-07-22 12:10:00 -07004606 return owe_buf;
4607 }
4608
Hai Shalomfdcde762020-04-02 11:19:20 -07004609 *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
4610 if (*status != WLAN_STATUS_SUCCESS)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004611 return NULL;
4612
4613 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
4614 owe_buf_len, NULL, 0);
4615
4616 if (sta->owe_ecdh && owe_buf) {
4617 struct wpabuf *pub;
4618
4619 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
4620 if (!pub) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004621 *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004622 return owe_buf;
4623 }
4624
4625 /* OWE Diffie-Hellman Parameter element */
4626 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
4627 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
4628 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
4629 */
4630 WPA_PUT_LE16(owe_buf, sta->owe_group);
4631 owe_buf += 2;
4632 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
4633 owe_buf += wpabuf_len(pub);
4634 wpabuf_free(pub);
4635 }
4636
4637 return owe_buf;
4638}
4639#endif /* CONFIG_OWE */
4640
4641
Paul Stewart092955c2017-02-06 09:13:09 -08004642#ifdef CONFIG_FILS
4643
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004644void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
Paul Stewart092955c2017-02-06 09:13:09 -08004645{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004646 u16 reply_res;
Paul Stewart092955c2017-02-06 09:13:09 -08004647
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004648 wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
4649 MAC2STR(sta->addr));
4650 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
4651 if (!sta->fils_pending_assoc_req)
Paul Stewart092955c2017-02-06 09:13:09 -08004652 return;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004653 reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
4654 sta->fils_pending_assoc_is_reassoc,
4655 sta->fils_pending_assoc_req,
Hai Shalomfdcde762020-04-02 11:19:20 -07004656 sta->fils_pending_assoc_req_len, 0, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004657 os_free(sta->fils_pending_assoc_req);
4658 sta->fils_pending_assoc_req = NULL;
4659 sta->fils_pending_assoc_req_len = 0;
4660 wpabuf_free(sta->fils_hlp_resp);
4661 sta->fils_hlp_resp = NULL;
4662 wpabuf_free(sta->hlp_dhcp_discover);
4663 sta->hlp_dhcp_discover = NULL;
Paul Stewart092955c2017-02-06 09:13:09 -08004664
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004665 /*
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004666 * Remove the station in case transmission of a success response fails.
4667 * At this point the station was already added associated to the driver.
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004668 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004669 if (reply_res != WLAN_STATUS_SUCCESS)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004670 hostapd_drv_sta_remove(hapd, sta->addr);
Paul Stewart092955c2017-02-06 09:13:09 -08004671}
4672
4673
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004674void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
Paul Stewart092955c2017-02-06 09:13:09 -08004675{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004676 struct hostapd_data *hapd = eloop_ctx;
4677 struct sta_info *sta = eloop_data;
Paul Stewart092955c2017-02-06 09:13:09 -08004678
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004679 wpa_printf(MSG_DEBUG,
4680 "FILS: HLP response timeout - continue with association response for "
4681 MACSTR, MAC2STR(sta->addr));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004682 if (sta->fils_drv_assoc_finish)
4683 hostapd_notify_assoc_fils_finish(hapd, sta);
4684 else
4685 fils_hlp_finish_assoc(hapd, sta);
Paul Stewart092955c2017-02-06 09:13:09 -08004686}
4687
4688#endif /* CONFIG_FILS */
4689
4690
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004691static void handle_assoc(struct hostapd_data *hapd,
4692 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom74f70d42019-02-11 14:42:39 -08004693 int reassoc, int rssi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004694{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004695 u16 capab_info, listen_interval, seq_ctrl, fc;
Hai Shalomb755a2a2020-04-23 21:49:02 -07004696 int resp = WLAN_STATUS_SUCCESS;
Hai Shalom899fcc72020-10-19 14:38:18 -07004697 u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004698 const u8 *pos;
4699 int left, i;
4700 struct sta_info *sta;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004701 u8 *tmp = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004702#ifdef CONFIG_FILS
4703 int delay_assoc = 0;
4704#endif /* CONFIG_FILS */
Hai Shalomfdcde762020-04-02 11:19:20 -07004705 int omit_rsnxe = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004706
4707 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
4708 sizeof(mgmt->u.assoc_req))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004709 wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
4710 reassoc, (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004711 return;
4712 }
4713
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004714#ifdef CONFIG_TESTING_OPTIONS
4715 if (reassoc) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004716 if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004717 drand48() < hapd->iconf->ignore_reassoc_probability) {
4718 wpa_printf(MSG_INFO,
4719 "TESTING: ignoring reassoc request from "
4720 MACSTR, MAC2STR(mgmt->sa));
4721 return;
4722 }
4723 } else {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004724 if (hapd->iconf->ignore_assoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004725 drand48() < hapd->iconf->ignore_assoc_probability) {
4726 wpa_printf(MSG_INFO,
4727 "TESTING: ignoring assoc request from "
4728 MACSTR, MAC2STR(mgmt->sa));
4729 return;
4730 }
4731 }
4732#endif /* CONFIG_TESTING_OPTIONS */
4733
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004734 fc = le_to_host16(mgmt->frame_control);
4735 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
4736
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004737 if (reassoc) {
4738 capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
4739 listen_interval = le_to_host16(
4740 mgmt->u.reassoc_req.listen_interval);
4741 wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
4742 " capab_info=0x%02x listen_interval=%d current_ap="
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004743 MACSTR " seq_ctrl=0x%x%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004744 MAC2STR(mgmt->sa), capab_info, listen_interval,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004745 MAC2STR(mgmt->u.reassoc_req.current_ap),
4746 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004747 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
4748 pos = mgmt->u.reassoc_req.variable;
4749 } else {
4750 capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
4751 listen_interval = le_to_host16(
4752 mgmt->u.assoc_req.listen_interval);
4753 wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004754 " capab_info=0x%02x listen_interval=%d "
4755 "seq_ctrl=0x%x%s",
4756 MAC2STR(mgmt->sa), capab_info, listen_interval,
4757 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004758 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
4759 pos = mgmt->u.assoc_req.variable;
4760 }
4761
4762 sta = ap_get_sta(hapd, mgmt->sa);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004763#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004764 if (sta && sta->auth_alg == WLAN_AUTH_FT &&
4765 (sta->flags & WLAN_STA_AUTH) == 0) {
4766 wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
4767 "prior to authentication since it is using "
4768 "over-the-DS FT", MAC2STR(mgmt->sa));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004769
4770 /*
4771 * Mark station as authenticated, to avoid adding station
4772 * entry in the driver as associated and not authenticated
4773 */
4774 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004775 } else
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004776#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004777 if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
Dmitry Shmidt29333592017-01-09 12:27:11 -08004778 if (hapd->iface->current_mode &&
4779 hapd->iface->current_mode->mode ==
4780 HOSTAPD_MODE_IEEE80211AD) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004781 int acl_res;
Hai Shalomfdcde762020-04-02 11:19:20 -07004782 struct radius_sta info;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004783
Hai Shalomfdcde762020-04-02 11:19:20 -07004784 acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
4785 (const u8 *) mgmt,
4786 len, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004787 if (acl_res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004788 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
4789 "Ignore Association Request frame from "
4790 MACSTR " due to ACL reject",
4791 MAC2STR(mgmt->sa));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004792 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
4793 goto fail;
4794 }
4795 if (acl_res == HOSTAPD_ACL_PENDING)
4796 return;
4797
Dmitry Shmidt29333592017-01-09 12:27:11 -08004798 /* DMG/IEEE 802.11ad does not use authentication.
4799 * Allocate sta entry upon association. */
4800 sta = ap_sta_add(hapd, mgmt->sa);
4801 if (!sta) {
4802 hostapd_logger(hapd, mgmt->sa,
4803 HOSTAPD_MODULE_IEEE80211,
4804 HOSTAPD_LEVEL_INFO,
4805 "Failed to add STA");
4806 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4807 goto fail;
4808 }
4809
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004810 acl_res = ieee802_11_set_radius_info(
Hai Shalomfdcde762020-04-02 11:19:20 -07004811 hapd, sta, acl_res, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004812 if (acl_res) {
4813 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
4814 goto fail;
4815 }
4816
Dmitry Shmidt29333592017-01-09 12:27:11 -08004817 hostapd_logger(hapd, sta->addr,
4818 HOSTAPD_MODULE_IEEE80211,
4819 HOSTAPD_LEVEL_DEBUG,
4820 "Skip authentication for DMG/IEEE 802.11ad");
4821 sta->flags |= WLAN_STA_AUTH;
4822 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
4823 sta->auth_alg = WLAN_AUTH_OPEN;
4824 } else {
4825 hostapd_logger(hapd, mgmt->sa,
4826 HOSTAPD_MODULE_IEEE80211,
4827 HOSTAPD_LEVEL_INFO,
4828 "Station tried to associate before authentication (aid=%d flags=0x%x)",
4829 sta ? sta->aid : -1,
4830 sta ? sta->flags : 0);
4831 send_deauth(hapd, mgmt->sa,
4832 WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
4833 return;
4834 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004835 }
4836
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004837 if ((fc & WLAN_FC_RETRY) &&
4838 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
4839 sta->last_seq_ctrl == seq_ctrl &&
Paul Stewart092955c2017-02-06 09:13:09 -08004840 sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
4841 WLAN_FC_STYPE_ASSOC_REQ)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004842 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4843 HOSTAPD_LEVEL_DEBUG,
4844 "Drop repeated association frame seq_ctrl=0x%x",
4845 seq_ctrl);
4846 return;
4847 }
4848 sta->last_seq_ctrl = seq_ctrl;
4849 sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
4850 WLAN_FC_STYPE_ASSOC_REQ;
4851
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004852 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004853 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004854 goto fail;
4855 }
4856
4857 if (listen_interval > hapd->conf->max_listen_interval) {
4858 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
4859 HOSTAPD_LEVEL_DEBUG,
4860 "Too large Listen Interval (%d)",
4861 listen_interval);
4862 resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
4863 goto fail;
4864 }
4865
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004866#ifdef CONFIG_MBO
4867 if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
4868 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4869 goto fail;
4870 }
Hai Shalom74f70d42019-02-11 14:42:39 -08004871
4872 if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
4873 rssi < hapd->iconf->rssi_reject_assoc_rssi &&
4874 (sta->auth_rssi == 0 ||
4875 sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
4876 resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
4877 goto fail;
4878 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004879#endif /* CONFIG_MBO */
4880
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004881 /*
4882 * sta->capability is used in check_assoc_ies() for RRM enabled
4883 * capability element.
4884 */
4885 sta->capability = capab_info;
4886
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004887#ifdef CONFIG_FILS
4888 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4889 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4890 sta->auth_alg == WLAN_AUTH_FILS_PK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004891 int res;
4892
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004893 /* The end of the payload is encrypted. Need to decrypt it
4894 * before parsing. */
4895
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004896 tmp = os_memdup(pos, left);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004897 if (!tmp) {
4898 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
4899 goto fail;
4900 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004901
Roshan Pius3a1667e2018-07-03 15:17:14 -07004902 res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
4903 len, tmp, left);
4904 if (res < 0) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004905 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
4906 goto fail;
4907 }
4908 pos = tmp;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004909 left = res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004910 }
4911#endif /* CONFIG_FILS */
4912
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004913 /* followed by SSID and Supported rates; and HT capabilities if 802.11n
4914 * is used */
4915 resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
4916 if (resp != WLAN_STATUS_SUCCESS)
4917 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07004918 omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004919
4920 if (hostapd_get_aid(hapd, sta) < 0) {
4921 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
4922 HOSTAPD_LEVEL_INFO, "No room for more AIDs");
4923 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4924 goto fail;
4925 }
4926
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004927 sta->listen_interval = listen_interval;
4928
Roshan Pius3a1667e2018-07-03 15:17:14 -07004929 if (hapd->iface->current_mode &&
4930 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004931 sta->flags |= WLAN_STA_NONERP;
4932 for (i = 0; i < sta->supported_rates_len; i++) {
4933 if ((sta->supported_rates[i] & 0x7f) > 22) {
4934 sta->flags &= ~WLAN_STA_NONERP;
4935 break;
4936 }
4937 }
4938 if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
4939 sta->nonerp_set = 1;
4940 hapd->iface->num_sta_non_erp++;
4941 if (hapd->iface->num_sta_non_erp == 1)
4942 ieee802_11_set_beacons(hapd->iface);
4943 }
4944
4945 if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
4946 !sta->no_short_slot_time_set) {
4947 sta->no_short_slot_time_set = 1;
4948 hapd->iface->num_sta_no_short_slot_time++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004949 if (hapd->iface->current_mode &&
4950 hapd->iface->current_mode->mode ==
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004951 HOSTAPD_MODE_IEEE80211G &&
4952 hapd->iface->num_sta_no_short_slot_time == 1)
4953 ieee802_11_set_beacons(hapd->iface);
4954 }
4955
4956 if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
4957 sta->flags |= WLAN_STA_SHORT_PREAMBLE;
4958 else
4959 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
4960
4961 if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
4962 !sta->no_short_preamble_set) {
4963 sta->no_short_preamble_set = 1;
4964 hapd->iface->num_sta_no_short_preamble++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004965 if (hapd->iface->current_mode &&
4966 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004967 && hapd->iface->num_sta_no_short_preamble == 1)
4968 ieee802_11_set_beacons(hapd->iface);
4969 }
4970
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004971 update_ht_state(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004972
4973 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4974 HOSTAPD_LEVEL_DEBUG,
4975 "association OK (aid %d)", sta->aid);
4976 /* Station will be marked associated, after it acknowledges AssocResp
4977 */
4978 sta->flags |= WLAN_STA_ASSOC_REQ_OK;
4979
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004980 if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
4981 wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
4982 "SA Query procedure", reassoc ? "re" : "");
4983 /* TODO: Send a protected Disassociate frame to the STA using
4984 * the old key and Reason Code "Previous Authentication no
4985 * longer valid". Make sure this is only sent protected since
4986 * unprotected frame would be received by the STA that is now
4987 * trying to associate.
4988 */
4989 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004990
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004991 /* Make sure that the previously registered inactivity timer will not
4992 * remove the STA immediately. */
4993 sta->timeout_next = STA_NULLFUNC;
4994
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07004995#ifdef CONFIG_TAXONOMY
4996 taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
4997#endif /* CONFIG_TAXONOMY */
4998
Dmitry Shmidt29333592017-01-09 12:27:11 -08004999 sta->pending_wds_enable = 0;
5000
Paul Stewart092955c2017-02-06 09:13:09 -08005001#ifdef CONFIG_FILS
5002 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5003 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005004 sta->auth_alg == WLAN_AUTH_FILS_PK) {
5005 if (fils_process_hlp(hapd, sta, pos, left) > 0)
5006 delay_assoc = 1;
5007 }
Paul Stewart092955c2017-02-06 09:13:09 -08005008#endif /* CONFIG_FILS */
5009
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005010 fail:
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005011
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005012 /*
5013 * In case of a successful response, add the station to the driver.
5014 * Otherwise, the kernel may ignore Data frames before we process the
5015 * ACK frame (TX status). In case of a failure, this station will be
5016 * removed.
5017 *
5018 * Note that this is not compliant with the IEEE 802.11 standard that
5019 * states that a non-AP station should transition into the
5020 * authenticated/associated state only after the station acknowledges
5021 * the (Re)Association Response frame. However, still do this as:
5022 *
5023 * 1. In case the station does not acknowledge the (Re)Association
5024 * Response frame, it will be removed.
5025 * 2. Data frames will be dropped in the kernel until the station is
5026 * set into authorized state, and there are no significant known
5027 * issues with processing other non-Data Class 3 frames during this
5028 * window.
5029 */
Hai Shalom74f70d42019-02-11 14:42:39 -08005030 if (resp == WLAN_STATUS_SUCCESS && sta &&
5031 add_associated_sta(hapd, sta, reassoc))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005032 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5033
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005034#ifdef CONFIG_FILS
Hai Shalom74f70d42019-02-11 14:42:39 -08005035 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
5036 eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
5037 sta->fils_pending_assoc_req) {
5038 /* Do not reschedule fils_hlp_timeout in case the station
5039 * retransmits (Re)Association Request frame while waiting for
5040 * the previously started FILS HLP wait, so that the timeout can
5041 * be determined from the first pending attempt. */
5042 wpa_printf(MSG_DEBUG,
5043 "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
5044 MACSTR, MAC2STR(sta->addr));
5045 os_free(tmp);
5046 return;
5047 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005048 if (sta) {
5049 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5050 os_free(sta->fils_pending_assoc_req);
5051 sta->fils_pending_assoc_req = NULL;
5052 sta->fils_pending_assoc_req_len = 0;
5053 wpabuf_free(sta->fils_hlp_resp);
5054 sta->fils_hlp_resp = NULL;
5055 }
5056 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
5057 sta->fils_pending_assoc_req = tmp;
5058 sta->fils_pending_assoc_req_len = left;
5059 sta->fils_pending_assoc_is_reassoc = reassoc;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005060 sta->fils_drv_assoc_finish = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005061 wpa_printf(MSG_DEBUG,
5062 "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
5063 MACSTR, MAC2STR(sta->addr));
5064 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5065 eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
5066 fils_hlp_timeout, hapd, sta);
5067 return;
5068 }
5069#endif /* CONFIG_FILS */
5070
Hai Shalomb755a2a2020-04-23 21:49:02 -07005071 if (resp >= 0)
5072 reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc,
5073 pos, left, rssi, omit_rsnxe);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005074 os_free(tmp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005075
5076 /*
Hai Shalom899fcc72020-10-19 14:38:18 -07005077 * Remove the station in case transmission of a success response fails
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005078 * (the STA was added associated to the driver) or if the station was
5079 * previously added unassociated.
5080 */
Dmitry Shmidt29333592017-01-09 12:27:11 -08005081 if (sta && ((reply_res != WLAN_STATUS_SUCCESS &&
5082 resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005083 hostapd_drv_sta_remove(hapd, sta->addr);
5084 sta->added_unassoc = 0;
5085 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005086}
5087
5088
5089static void handle_disassoc(struct hostapd_data *hapd,
5090 const struct ieee80211_mgmt *mgmt, size_t len)
5091{
5092 struct sta_info *sta;
5093
5094 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005095 wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)",
5096 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005097 return;
5098 }
5099
5100 wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
5101 MAC2STR(mgmt->sa),
5102 le_to_host16(mgmt->u.disassoc.reason_code));
5103
5104 sta = ap_get_sta(hapd, mgmt->sa);
5105 if (sta == NULL) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005106 wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated",
5107 MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005108 return;
5109 }
5110
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005111 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005112 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005113 sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07005114 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005115 wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
5116 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5117 HOSTAPD_LEVEL_INFO, "disassociated");
5118 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5119 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5120 /* Stop Accounting and IEEE 802.1X sessions, but leave the STA
5121 * authenticated. */
5122 accounting_sta_stop(hapd, sta);
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005123 ieee802_1x_free_station(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005124 if (sta->ipaddr)
5125 hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
5126 ap_sta_ip6addr_del(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005127 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005128 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005129
5130 if (sta->timeout_next == STA_NULLFUNC ||
5131 sta->timeout_next == STA_DISASSOC) {
5132 sta->timeout_next = STA_DEAUTH;
5133 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
5134 eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
5135 hapd, sta);
5136 }
5137
5138 mlme_disassociate_indication(
5139 hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt29333592017-01-09 12:27:11 -08005140
5141 /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon
5142 * disassociation. */
5143 if (hapd->iface->current_mode &&
5144 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
5145 sta->flags &= ~WLAN_STA_AUTH;
5146 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5147 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5148 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5149 ap_free_sta(hapd, sta);
5150 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005151}
5152
5153
5154static void handle_deauth(struct hostapd_data *hapd,
5155 const struct ieee80211_mgmt *mgmt, size_t len)
5156{
5157 struct sta_info *sta;
5158
5159 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005160 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short "
5161 "payload (len=%lu)", (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005162 return;
5163 }
5164
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005165 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005166 " reason_code=%d",
5167 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
5168
Hai Shaloma20dcd72022-02-04 13:43:00 -08005169 /* Clear the PTKSA cache entries for PASN */
5170 ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
5171
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005172 sta = ap_get_sta(hapd, mgmt->sa);
5173 if (sta == NULL) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005174 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
5175 "to deauthenticate, but it is not authenticated",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005176 MAC2STR(mgmt->sa));
5177 return;
5178 }
5179
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005180 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005181 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005182 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
5183 WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07005184 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005185 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5186 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5187 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5188 mlme_deauthenticate_indication(
5189 hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
5190 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5191 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5192 ap_free_sta(hapd, sta);
5193}
5194
5195
5196static void handle_beacon(struct hostapd_data *hapd,
5197 const struct ieee80211_mgmt *mgmt, size_t len,
5198 struct hostapd_frame_info *fi)
5199{
5200 struct ieee802_11_elems elems;
5201
5202 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005203 wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
5204 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005205 return;
5206 }
5207
5208 (void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
5209 len - (IEEE80211_HDRLEN +
5210 sizeof(mgmt->u.beacon)), &elems,
5211 0);
5212
5213 ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
5214}
5215
5216
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005217static int robust_action_frame(u8 category)
5218{
5219 return category != WLAN_ACTION_PUBLIC &&
5220 category != WLAN_ACTION_HT;
5221}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005222
5223
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005224static int handle_action(struct hostapd_data *hapd,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005225 const struct ieee80211_mgmt *mgmt, size_t len,
5226 unsigned int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005227{
5228 struct sta_info *sta;
Hai Shalom74f70d42019-02-11 14:42:39 -08005229 u8 *action __maybe_unused;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005230
Hai Shalom74f70d42019-02-11 14:42:39 -08005231 if (len < IEEE80211_HDRLEN + 2 + 1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005232 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5233 HOSTAPD_LEVEL_DEBUG,
5234 "handle_action - too short payload (len=%lu)",
5235 (unsigned long) len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005236 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005237 }
5238
Hai Shalom74f70d42019-02-11 14:42:39 -08005239 action = (u8 *) &mgmt->u.action.u;
5240 wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
5241 " da " MACSTR " len %d freq %u",
5242 mgmt->u.action.category, *action,
5243 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
5244
5245 sta = ap_get_sta(hapd, mgmt->sa);
5246
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005247 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
5248 (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
5249 wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
5250 "frame (category=%u) from unassociated STA " MACSTR,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005251 mgmt->u.action.category, MAC2STR(mgmt->sa));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005252 return 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005253 }
5254
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005255 if (sta && (sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt18463232014-01-24 12:29:41 -08005256 !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
5257 robust_action_frame(mgmt->u.action.category)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005258 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5259 HOSTAPD_LEVEL_DEBUG,
5260 "Dropped unprotected Robust Action frame from "
5261 "an MFP STA");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005262 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005263 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005264
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005265 if (sta) {
5266 u16 fc = le_to_host16(mgmt->frame_control);
5267 u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
5268
5269 if ((fc & WLAN_FC_RETRY) &&
5270 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
5271 sta->last_seq_ctrl == seq_ctrl &&
5272 sta->last_subtype == WLAN_FC_STYPE_ACTION) {
5273 hostapd_logger(hapd, sta->addr,
5274 HOSTAPD_MODULE_IEEE80211,
5275 HOSTAPD_LEVEL_DEBUG,
5276 "Drop repeated action frame seq_ctrl=0x%x",
5277 seq_ctrl);
5278 return 1;
5279 }
5280
5281 sta->last_seq_ctrl = seq_ctrl;
5282 sta->last_subtype = WLAN_FC_STYPE_ACTION;
5283 }
5284
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005285 switch (mgmt->u.action.category) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005286#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005287 case WLAN_ACTION_FT:
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005288 if (!sta ||
5289 wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005290 len - IEEE80211_HDRLEN))
5291 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005292 return 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005293#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005294 case WLAN_ACTION_WMM:
5295 hostapd_wmm_action(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005296 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005297 case WLAN_ACTION_SA_QUERY:
Hai Shalom021b0b52019-04-10 11:17:58 -07005298 ieee802_11_sa_query_action(hapd, mgmt, len);
5299 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005300#ifdef CONFIG_WNM_AP
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005301 case WLAN_ACTION_WNM:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005302 ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
5303 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005304#endif /* CONFIG_WNM_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005305#ifdef CONFIG_FST
5306 case WLAN_ACTION_FST:
5307 if (hapd->iface->fst)
5308 fst_rx_action(hapd->iface->fst, mgmt, len);
5309 else
5310 wpa_printf(MSG_DEBUG,
5311 "FST: Ignore FST Action frame - no FST attached");
5312 return 1;
5313#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005314 case WLAN_ACTION_PUBLIC:
Dmitry Shmidt18463232014-01-24 12:29:41 -08005315 case WLAN_ACTION_PROTECTED_DUAL:
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07005316 if (len >= IEEE80211_HDRLEN + 2 &&
5317 mgmt->u.action.u.public_action.action ==
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005318 WLAN_PA_20_40_BSS_COEX) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005319 hostapd_2040_coex_action(hapd, mgmt, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005320 return 1;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005321 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005322#ifdef CONFIG_DPP
5323 if (len >= IEEE80211_HDRLEN + 6 &&
5324 mgmt->u.action.u.vs_public_action.action ==
5325 WLAN_PA_VENDOR_SPECIFIC &&
5326 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
5327 OUI_WFA &&
5328 mgmt->u.action.u.vs_public_action.variable[0] ==
5329 DPP_OUI_TYPE) {
5330 const u8 *pos, *end;
5331
5332 pos = mgmt->u.action.u.vs_public_action.oui;
5333 end = ((const u8 *) mgmt) + len;
5334 hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005335 freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005336 return 1;
5337 }
5338 if (len >= IEEE80211_HDRLEN + 2 &&
5339 (mgmt->u.action.u.public_action.action ==
5340 WLAN_PA_GAS_INITIAL_RESP ||
5341 mgmt->u.action.u.public_action.action ==
5342 WLAN_PA_GAS_COMEBACK_RESP)) {
5343 const u8 *pos, *end;
5344
5345 pos = &mgmt->u.action.u.public_action.action;
5346 end = ((const u8 *) mgmt) + len;
Sunil Ravi036cec52023-03-29 11:35:17 -07005347 if (gas_query_ap_rx(hapd->gas, mgmt->sa,
5348 mgmt->u.action.category,
5349 pos, end - pos, freq) == 0)
5350 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005351 }
5352#endif /* CONFIG_DPP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005353 if (hapd->public_action_cb) {
5354 hapd->public_action_cb(hapd->public_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08005355 (u8 *) mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005356 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08005357 if (hapd->public_action_cb2) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005358 hapd->public_action_cb2(hapd->public_action_cb2_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08005359 (u8 *) mgmt, len, freq);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08005360 }
5361 if (hapd->public_action_cb || hapd->public_action_cb2)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005362 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005363 break;
5364 case WLAN_ACTION_VENDOR_SPECIFIC:
5365 if (hapd->vendor_action_cb) {
5366 if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08005367 (u8 *) mgmt, len, freq) == 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005368 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005369 }
5370 break;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005371 case WLAN_ACTION_RADIO_MEASUREMENT:
5372 hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
5373 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005374 }
5375
5376 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5377 HOSTAPD_LEVEL_DEBUG,
5378 "handle_action - unknown action category %d or invalid "
5379 "frame",
5380 mgmt->u.action.category);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07005381 if (!is_multicast_ether_addr(mgmt->da) &&
5382 !(mgmt->u.action.category & 0x80) &&
5383 !is_multicast_ether_addr(mgmt->sa)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005384 struct ieee80211_mgmt *resp;
5385
5386 /*
5387 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
5388 * Return the Action frame to the source without change
5389 * except that MSB of the Category set to 1.
5390 */
5391 wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
5392 "frame back to sender");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005393 resp = os_memdup(mgmt, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005394 if (resp == NULL)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005395 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005396 os_memcpy(resp->da, resp->sa, ETH_ALEN);
5397 os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
5398 os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
5399 resp->u.action.category |= 0x80;
5400
Hai Shalomfdcde762020-04-02 11:19:20 -07005401 if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005402 wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
5403 "Action frame");
5404 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005405 os_free(resp);
5406 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005407
5408 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005409}
5410
5411
5412/**
Hai Shalom60840252021-02-19 19:02:11 -08005413 * notify_mgmt_frame - Notify of Management frames on the control interface
5414 * @hapd: hostapd BSS data structure (the BSS to which the Management frame was
5415 * sent to)
5416 * @buf: Management frame data (starting from the IEEE 802.11 header)
5417 * @len: Length of frame data in octets
5418 *
5419 * Notify the control interface of any received Management frame.
5420 */
5421static void notify_mgmt_frame(struct hostapd_data *hapd, const u8 *buf,
5422 size_t len)
5423{
5424
5425 int hex_len = len * 2 + 1;
5426 char *hex = os_malloc(hex_len);
5427
5428 if (hex) {
5429 wpa_snprintf_hex(hex, hex_len, buf, len);
5430 wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO,
5431 AP_MGMT_FRAME_RECEIVED "buf=%s", hex);
5432 os_free(hex);
5433 }
5434}
5435
5436
5437/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005438 * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
5439 * @hapd: hostapd BSS data structure (the BSS to which the management frame was
5440 * sent to)
5441 * @buf: management frame data (starting from IEEE 802.11 header)
5442 * @len: length of frame data in octets
5443 * @fi: meta data about received frame (signal level, etc.)
5444 *
5445 * Process all incoming IEEE 802.11 management frames. This will be called for
5446 * each frame received from the kernel driver through wlan#ap interface. In
5447 * addition, it can be called to re-inserted pending frames (e.g., when using
5448 * external RADIUS server as an MAC ACL).
5449 */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005450int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
5451 struct hostapd_frame_info *fi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005452{
5453 struct ieee80211_mgmt *mgmt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005454 u16 fc, stype;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005455 int ret = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005456 unsigned int freq;
5457 int ssi_signal = fi ? fi->ssi_signal : 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005458
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005459 if (len < 24)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005460 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005461
Roshan Pius3a1667e2018-07-03 15:17:14 -07005462 if (fi && fi->freq)
5463 freq = fi->freq;
5464 else
5465 freq = hapd->iface->freq;
5466
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005467 mgmt = (struct ieee80211_mgmt *) buf;
5468 fc = le_to_host16(mgmt->frame_control);
5469 stype = WLAN_FC_GET_STYPE(fc);
5470
Hai Shalomc3565922019-10-28 11:58:20 -07005471 if (is_multicast_ether_addr(mgmt->sa) ||
5472 is_zero_ether_addr(mgmt->sa) ||
5473 os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
5474 /* Do not process any frames with unexpected/invalid SA so that
5475 * we do not add any state for unexpected STA addresses or end
5476 * up sending out frames to unexpected destination. */
5477 wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
5478 " in received frame - ignore this frame silently",
5479 MAC2STR(mgmt->sa));
5480 return 0;
5481 }
5482
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005483 if (stype == WLAN_FC_STYPE_BEACON) {
5484 handle_beacon(hapd, mgmt, len, fi);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005485 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005486 }
5487
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07005488 if (!is_broadcast_ether_addr(mgmt->bssid) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005489#ifdef CONFIG_P2P
5490 /* Invitation responses can be sent with the peer MAC as BSSID */
5491 !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
5492 stype == WLAN_FC_STYPE_ACTION) &&
5493#endif /* CONFIG_P2P */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005494#ifdef CONFIG_MESH
5495 !(hapd->conf->mesh & MESH_ENABLED) &&
5496#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005497 os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005498 wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
5499 MAC2STR(mgmt->bssid));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005500 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005501 }
5502
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005503 if (hapd->iface->state != HAPD_IFACE_ENABLED) {
5504 wpa_printf(MSG_DEBUG, "MGMT: Ignore management frame while interface is not enabled (SA=" MACSTR " DA=" MACSTR " subtype=%u)",
5505 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), stype);
5506 return 1;
5507 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005508
5509 if (stype == WLAN_FC_STYPE_PROBE_REQ) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005510 handle_probe_req(hapd, mgmt, len, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005511 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005512 }
5513
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005514 if ((!is_broadcast_ether_addr(mgmt->da) ||
5515 stype != WLAN_FC_STYPE_ACTION) &&
5516 os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005517 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5518 HOSTAPD_LEVEL_DEBUG,
5519 "MGMT: DA=" MACSTR " not our address",
5520 MAC2STR(mgmt->da));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005521 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005522 }
5523
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005524 if (hapd->iconf->track_sta_max_num)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005525 sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005526
Hai Shalom60840252021-02-19 19:02:11 -08005527 if (hapd->conf->notify_mgmt_frames)
5528 notify_mgmt_frame(hapd, buf, len);
5529
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005530 switch (stype) {
5531 case WLAN_FC_STYPE_AUTH:
5532 wpa_printf(MSG_DEBUG, "mgmt::auth");
Hai Shalom021b0b52019-04-10 11:17:58 -07005533 handle_auth(hapd, mgmt, len, ssi_signal, 0);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005534 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005535 break;
5536 case WLAN_FC_STYPE_ASSOC_REQ:
5537 wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08005538 handle_assoc(hapd, mgmt, len, 0, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005539 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005540 break;
5541 case WLAN_FC_STYPE_REASSOC_REQ:
5542 wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08005543 handle_assoc(hapd, mgmt, len, 1, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005544 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005545 break;
5546 case WLAN_FC_STYPE_DISASSOC:
5547 wpa_printf(MSG_DEBUG, "mgmt::disassoc");
5548 handle_disassoc(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005549 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005550 break;
5551 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005552 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005553 handle_deauth(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005554 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005555 break;
5556 case WLAN_FC_STYPE_ACTION:
5557 wpa_printf(MSG_DEBUG, "mgmt::action");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005558 ret = handle_action(hapd, mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005559 break;
5560 default:
5561 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5562 HOSTAPD_LEVEL_DEBUG,
5563 "unknown mgmt frame subtype %d", stype);
5564 break;
5565 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005566
5567 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005568}
5569
5570
5571static void handle_auth_cb(struct hostapd_data *hapd,
5572 const struct ieee80211_mgmt *mgmt,
5573 size_t len, int ok)
5574{
5575 u16 auth_alg, auth_transaction, status_code;
5576 struct sta_info *sta;
Hai Shalom60840252021-02-19 19:02:11 -08005577 bool success_status;
Hai Shalome5e28bb2019-01-28 14:51:04 -08005578
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005579 sta = ap_get_sta(hapd, mgmt->da);
5580 if (!sta) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08005581 wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
5582 " not found",
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005583 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005584 return;
5585 }
5586
Hai Shalom60840252021-02-19 19:02:11 -08005587 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
5588 wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
5589 (unsigned long) len);
5590 auth_alg = 0;
5591 auth_transaction = 0;
5592 status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
5593 goto fail;
5594 }
5595
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005596 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
5597 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
5598 status_code = le_to_host16(mgmt->u.auth.status_code);
5599
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005600 if (!ok) {
5601 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
5602 HOSTAPD_LEVEL_NOTICE,
5603 "did not acknowledge authentication response");
5604 goto fail;
5605 }
5606
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005607 if (status_code == WLAN_STATUS_SUCCESS &&
5608 ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
5609 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
5610 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5611 HOSTAPD_LEVEL_INFO, "authenticated");
5612 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005613 if (sta->added_unassoc)
5614 hostapd_set_sta_flags(hapd, sta);
5615 return;
5616 }
5617
5618fail:
Hai Shalom60840252021-02-19 19:02:11 -08005619 success_status = status_code == WLAN_STATUS_SUCCESS;
5620#ifdef CONFIG_SAE
5621 if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1)
5622 success_status = sae_status_success(hapd, status_code);
5623#endif /* CONFIG_SAE */
5624 if (!success_status && sta->added_unassoc) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005625 hostapd_drv_sta_remove(hapd, sta->addr);
5626 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005627 }
5628}
5629
5630
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005631static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
5632 struct sta_info *sta,
5633 char *ifname_wds)
5634{
Hai Shalomfdcde762020-04-02 11:19:20 -07005635#ifdef CONFIG_WEP
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005636 int i;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07005637 struct hostapd_ssid *ssid = &hapd->conf->ssid;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005638
5639 if (hapd->conf->ieee802_1x || hapd->conf->wpa)
5640 return;
5641
5642 for (i = 0; i < 4; i++) {
5643 if (ssid->wep.key[i] &&
5644 hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
Hai Shalomfdcde762020-04-02 11:19:20 -07005645 0, i == ssid->wep.idx, NULL, 0,
5646 ssid->wep.key[i], ssid->wep.len[i],
5647 i == ssid->wep.idx ?
5648 KEY_FLAG_GROUP_RX_TX_DEFAULT :
5649 KEY_FLAG_GROUP_RX_TX)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005650 wpa_printf(MSG_WARNING,
5651 "Could not set WEP keys for WDS interface; %s",
5652 ifname_wds);
5653 break;
5654 }
5655 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005656#endif /* CONFIG_WEP */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005657}
5658
5659
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005660static void handle_assoc_cb(struct hostapd_data *hapd,
5661 const struct ieee80211_mgmt *mgmt,
5662 size_t len, int reassoc, int ok)
5663{
5664 u16 status;
5665 struct sta_info *sta;
5666 int new_assoc = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005667
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005668 sta = ap_get_sta(hapd, mgmt->da);
5669 if (!sta) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005670 wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
5671 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005672 return;
5673 }
5674
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005675 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
5676 sizeof(mgmt->u.assoc_resp))) {
5677 wpa_printf(MSG_INFO,
5678 "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
5679 reassoc, (unsigned long) len);
5680 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07005681 return;
5682 }
5683
5684 if (reassoc)
5685 status = le_to_host16(mgmt->u.reassoc_resp.status_code);
5686 else
5687 status = le_to_host16(mgmt->u.assoc_resp.status_code);
5688
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005689 if (!ok) {
5690 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
5691 HOSTAPD_LEVEL_DEBUG,
5692 "did not acknowledge association response");
5693 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
5694 /* The STA is added only in case of SUCCESS */
5695 if (status == WLAN_STATUS_SUCCESS)
5696 hostapd_drv_sta_remove(hapd, sta->addr);
5697
5698 return;
5699 }
5700
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005701 if (status != WLAN_STATUS_SUCCESS)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005702 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005703
5704 /* Stop previous accounting session, if one is started, and allocate
5705 * new session id for the new session. */
5706 accounting_sta_stop(hapd, sta);
5707
5708 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5709 HOSTAPD_LEVEL_INFO,
5710 "associated (aid %d)",
5711 sta->aid);
5712
5713 if (sta->flags & WLAN_STA_ASSOC)
5714 new_assoc = 0;
5715 sta->flags |= WLAN_STA_ASSOC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005716 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005717 if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
5718 !hapd->conf->osen) ||
5719 sta->auth_alg == WLAN_AUTH_FILS_SK ||
5720 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5721 sta->auth_alg == WLAN_AUTH_FILS_PK ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005722 sta->auth_alg == WLAN_AUTH_FT) {
5723 /*
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005724 * Open, static WEP, FT protocol, or FILS; no separate
5725 * authorization step.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005726 */
5727 ap_sta_set_authorized(hapd, sta, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005728 }
5729
5730 if (reassoc)
5731 mlme_reassociate_indication(hapd, sta);
5732 else
5733 mlme_associate_indication(hapd, sta);
5734
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005735 sta->sa_query_timed_out = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005736
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005737 if (sta->eapol_sm == NULL) {
5738 /*
5739 * This STA does not use RADIUS server for EAP authentication,
5740 * so bind it to the selected VLAN interface now, since the
5741 * interface selection is not going to change anymore.
5742 */
Dmitry Shmidt83474442015-04-15 13:47:09 -07005743 if (ap_sta_bind_vlan(hapd, sta) < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005744 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005745 } else if (sta->vlan_id) {
5746 /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
Dmitry Shmidt83474442015-04-15 13:47:09 -07005747 if (ap_sta_bind_vlan(hapd, sta) < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005748 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005749 }
5750
5751 hostapd_set_sta_flags(hapd, sta);
5752
Dmitry Shmidt29333592017-01-09 12:27:11 -08005753 if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) {
5754 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA "
5755 MACSTR " based on pending request",
5756 MAC2STR(sta->addr));
5757 sta->pending_wds_enable = 0;
5758 sta->flags |= WLAN_STA_WDS;
5759 }
5760
Hai Shalom74f70d42019-02-11 14:42:39 -08005761 if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) {
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08005762 int ret;
5763 char ifname_wds[IFNAMSIZ + 1];
5764
5765 wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA "
5766 MACSTR " (aid %u)",
5767 MAC2STR(sta->addr), sta->aid);
5768 ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
5769 sta->aid, 1);
5770 if (!ret)
5771 hostapd_set_wds_encryption(hapd, sta, ifname_wds);
5772 }
5773
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005774 if (sta->auth_alg == WLAN_AUTH_FT)
5775 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
5776 else
5777 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
5778 hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005779 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005780
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005781#ifdef CONFIG_FILS
5782 if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
5783 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5784 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
5785 fils_set_tk(sta->wpa_sm) < 0) {
5786 wpa_printf(MSG_DEBUG, "FILS: TK configuration failed");
5787 ap_sta_disconnect(hapd, sta, sta->addr,
5788 WLAN_REASON_UNSPECIFIED);
5789 return;
5790 }
5791#endif /* CONFIG_FILS */
5792
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005793 if (sta->pending_eapol_rx) {
5794 struct os_reltime now, age;
5795
5796 os_get_reltime(&now);
5797 os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
5798 if (age.sec == 0 && age.usec < 200000) {
5799 wpa_printf(MSG_DEBUG,
5800 "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
5801 MAC2STR(sta->addr));
5802 ieee802_1x_receive(
5803 hapd, mgmt->da,
5804 wpabuf_head(sta->pending_eapol_rx->buf),
Sunil8cd6f4d2022-06-28 18:40:46 +00005805 wpabuf_len(sta->pending_eapol_rx->buf),
5806 sta->pending_eapol_rx->encrypted);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005807 }
5808 wpabuf_free(sta->pending_eapol_rx->buf);
5809 os_free(sta->pending_eapol_rx);
5810 sta->pending_eapol_rx = NULL;
5811 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005812}
5813
5814
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005815static void handle_deauth_cb(struct hostapd_data *hapd,
5816 const struct ieee80211_mgmt *mgmt,
5817 size_t len, int ok)
5818{
5819 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07005820 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005821 return;
5822 sta = ap_get_sta(hapd, mgmt->da);
5823 if (!sta) {
5824 wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
5825 " not found", MAC2STR(mgmt->da));
5826 return;
5827 }
5828 if (ok)
5829 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
5830 MAC2STR(sta->addr));
5831 else
5832 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
5833 "deauth", MAC2STR(sta->addr));
5834
5835 ap_sta_deauth_cb(hapd, sta);
5836}
5837
5838
5839static void handle_disassoc_cb(struct hostapd_data *hapd,
5840 const struct ieee80211_mgmt *mgmt,
5841 size_t len, int ok)
5842{
5843 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07005844 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005845 return;
5846 sta = ap_get_sta(hapd, mgmt->da);
5847 if (!sta) {
5848 wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
5849 " not found", MAC2STR(mgmt->da));
5850 return;
5851 }
5852 if (ok)
5853 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
5854 MAC2STR(sta->addr));
5855 else
5856 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
5857 "disassoc", MAC2STR(sta->addr));
5858
5859 ap_sta_disassoc_cb(hapd, sta);
5860}
5861
5862
Dmitry Shmidt29333592017-01-09 12:27:11 -08005863static void handle_action_cb(struct hostapd_data *hapd,
5864 const struct ieee80211_mgmt *mgmt,
5865 size_t len, int ok)
5866{
5867 struct sta_info *sta;
Paul Stewart092955c2017-02-06 09:13:09 -08005868 const struct rrm_measurement_report_element *report;
Dmitry Shmidt29333592017-01-09 12:27:11 -08005869
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005870#ifdef CONFIG_DPP
5871 if (len >= IEEE80211_HDRLEN + 6 &&
5872 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
5873 mgmt->u.action.u.vs_public_action.action ==
5874 WLAN_PA_VENDOR_SPECIFIC &&
5875 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
5876 OUI_WFA &&
5877 mgmt->u.action.u.vs_public_action.variable[0] ==
5878 DPP_OUI_TYPE) {
5879 const u8 *pos, *end;
5880
5881 pos = &mgmt->u.action.u.vs_public_action.variable[1];
5882 end = ((const u8 *) mgmt) + len;
5883 hostapd_dpp_tx_status(hapd, mgmt->da, pos, end - pos, ok);
5884 return;
5885 }
5886 if (len >= IEEE80211_HDRLEN + 2 &&
5887 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
5888 (mgmt->u.action.u.public_action.action ==
5889 WLAN_PA_GAS_INITIAL_REQ ||
5890 mgmt->u.action.u.public_action.action ==
5891 WLAN_PA_GAS_COMEBACK_REQ)) {
5892 const u8 *pos, *end;
5893
5894 pos = mgmt->u.action.u.public_action.variable;
5895 end = ((const u8 *) mgmt) + len;
5896 gas_query_ap_tx_status(hapd->gas, mgmt->da, pos, end - pos, ok);
5897 return;
5898 }
5899#endif /* CONFIG_DPP */
Hai Shaloma20dcd72022-02-04 13:43:00 -08005900 if (is_multicast_ether_addr(mgmt->da))
5901 return;
Dmitry Shmidt29333592017-01-09 12:27:11 -08005902 sta = ap_get_sta(hapd, mgmt->da);
5903 if (!sta) {
5904 wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR
5905 " not found", MAC2STR(mgmt->da));
5906 return;
5907 }
5908
Sunil Ravi77d572f2023-01-17 23:58:31 +00005909#ifdef CONFIG_HS20
5910 if (ok && len >= IEEE80211_HDRLEN + 2 &&
5911 mgmt->u.action.category == WLAN_ACTION_WNM &&
5912 mgmt->u.action.u.vs_public_action.action == WNM_NOTIFICATION_REQ &&
5913 sta->hs20_deauth_on_ack) {
5914 wpa_printf(MSG_DEBUG, "HS 2.0: Deauthenticate STA " MACSTR
5915 " on acknowledging the WNM-Notification",
5916 MAC2STR(sta->addr));
5917 ap_sta_session_timeout(hapd, sta, 0);
5918 return;
5919 }
5920#endif /* CONFIG_HS20 */
5921
Paul Stewart092955c2017-02-06 09:13:09 -08005922 if (len < 24 + 5 + sizeof(*report))
Dmitry Shmidt29333592017-01-09 12:27:11 -08005923 return;
Paul Stewart092955c2017-02-06 09:13:09 -08005924 report = (const struct rrm_measurement_report_element *)
5925 &mgmt->u.action.u.rrm.variable[2];
Dmitry Shmidt29333592017-01-09 12:27:11 -08005926 if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT &&
Paul Stewart092955c2017-02-06 09:13:09 -08005927 mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST &&
5928 report->eid == WLAN_EID_MEASURE_REQUEST &&
5929 report->len >= 3 &&
5930 report->type == MEASURE_TYPE_BEACON)
Dmitry Shmidt29333592017-01-09 12:27:11 -08005931 hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok);
5932}
5933
5934
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005935/**
5936 * ieee802_11_mgmt_cb - Process management frame TX status callback
5937 * @hapd: hostapd BSS data structure (the BSS from which the management frame
5938 * was sent from)
5939 * @buf: management frame data (starting from IEEE 802.11 header)
5940 * @len: length of frame data in octets
5941 * @stype: management frame subtype from frame control field
5942 * @ok: Whether the frame was ACK'ed
5943 */
5944void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
5945 u16 stype, int ok)
5946{
5947 const struct ieee80211_mgmt *mgmt;
5948 mgmt = (const struct ieee80211_mgmt *) buf;
5949
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005950#ifdef CONFIG_TESTING_OPTIONS
5951 if (hapd->ext_mgmt_frame_handling) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005952 size_t hex_len = 2 * len + 1;
5953 char *hex = os_malloc(hex_len);
5954
5955 if (hex) {
5956 wpa_snprintf_hex(hex, hex_len, buf, len);
5957 wpa_msg(hapd->msg_ctx, MSG_INFO,
5958 "MGMT-TX-STATUS stype=%u ok=%d buf=%s",
5959 stype, ok, hex);
5960 os_free(hex);
5961 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005962 return;
5963 }
5964#endif /* CONFIG_TESTING_OPTIONS */
5965
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005966 switch (stype) {
5967 case WLAN_FC_STYPE_AUTH:
5968 wpa_printf(MSG_DEBUG, "mgmt::auth cb");
5969 handle_auth_cb(hapd, mgmt, len, ok);
5970 break;
5971 case WLAN_FC_STYPE_ASSOC_RESP:
5972 wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
5973 handle_assoc_cb(hapd, mgmt, len, 0, ok);
5974 break;
5975 case WLAN_FC_STYPE_REASSOC_RESP:
5976 wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
5977 handle_assoc_cb(hapd, mgmt, len, 1, ok);
5978 break;
5979 case WLAN_FC_STYPE_PROBE_RESP:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005980 wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005981 break;
5982 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005983 wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
5984 handle_deauth_cb(hapd, mgmt, len, ok);
5985 break;
5986 case WLAN_FC_STYPE_DISASSOC:
5987 wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
5988 handle_disassoc_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005989 break;
5990 case WLAN_FC_STYPE_ACTION:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005991 wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
Dmitry Shmidt29333592017-01-09 12:27:11 -08005992 handle_action_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005993 break;
5994 default:
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005995 wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005996 break;
5997 }
5998}
5999
6000
6001int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
6002{
6003 /* TODO */
6004 return 0;
6005}
6006
6007
6008int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
6009 char *buf, size_t buflen)
6010{
6011 /* TODO */
6012 return 0;
6013}
6014
6015
6016void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
6017 const u8 *buf, size_t len, int ack)
6018{
6019 struct sta_info *sta;
6020 struct hostapd_iface *iface = hapd->iface;
6021
6022 sta = ap_get_sta(hapd, addr);
6023 if (sta == NULL && iface->num_bss > 1) {
6024 size_t j;
6025 for (j = 0; j < iface->num_bss; j++) {
6026 hapd = iface->bss[j];
6027 sta = ap_get_sta(hapd, addr);
6028 if (sta)
6029 break;
6030 }
6031 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006032 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006033 return;
6034 if (sta->flags & WLAN_STA_PENDING_POLL) {
6035 wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
6036 "activity poll", MAC2STR(sta->addr),
6037 ack ? "ACKed" : "did not ACK");
6038 if (ack)
6039 sta->flags &= ~WLAN_STA_PENDING_POLL;
6040 }
6041
6042 ieee802_1x_tx_status(hapd, sta, buf, len, ack);
6043}
6044
6045
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006046void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
6047 const u8 *data, size_t len, int ack)
6048{
6049 struct sta_info *sta;
6050 struct hostapd_iface *iface = hapd->iface;
6051
6052 sta = ap_get_sta(hapd, dst);
6053 if (sta == NULL && iface->num_bss > 1) {
6054 size_t j;
6055 for (j = 0; j < iface->num_bss; j++) {
6056 hapd = iface->bss[j];
6057 sta = ap_get_sta(hapd, dst);
6058 if (sta)
6059 break;
6060 }
6061 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006062 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
6063 wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA "
6064 MACSTR " that is not currently associated",
6065 MAC2STR(dst));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006066 return;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006067 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006068
6069 ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
6070}
6071
6072
6073void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
6074{
6075 struct sta_info *sta;
6076 struct hostapd_iface *iface = hapd->iface;
6077
6078 sta = ap_get_sta(hapd, addr);
6079 if (sta == NULL && iface->num_bss > 1) {
6080 size_t j;
6081 for (j = 0; j < iface->num_bss; j++) {
6082 hapd = iface->bss[j];
6083 sta = ap_get_sta(hapd, addr);
6084 if (sta)
6085 break;
6086 }
6087 }
6088 if (sta == NULL)
6089 return;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006090 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
6091 MAC2STR(sta->addr));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006092 if (!(sta->flags & WLAN_STA_PENDING_POLL))
6093 return;
6094
6095 wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
6096 "activity poll", MAC2STR(sta->addr));
6097 sta->flags &= ~WLAN_STA_PENDING_POLL;
6098}
6099
6100
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006101void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
6102 int wds)
6103{
6104 struct sta_info *sta;
6105
6106 sta = ap_get_sta(hapd, src);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006107 if (sta &&
6108 ((sta->flags & WLAN_STA_ASSOC) ||
6109 ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006110 if (!hapd->conf->wds_sta)
6111 return;
6112
Dmitry Shmidt29333592017-01-09 12:27:11 -08006113 if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) ==
6114 WLAN_STA_ASSOC_REQ_OK) {
6115 wpa_printf(MSG_DEBUG,
6116 "Postpone 4-address WDS mode enabling for STA "
6117 MACSTR " since TX status for AssocResp is not yet known",
6118 MAC2STR(sta->addr));
6119 sta->pending_wds_enable = 1;
6120 return;
6121 }
6122
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006123 if (wds && !(sta->flags & WLAN_STA_WDS)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006124 int ret;
6125 char ifname_wds[IFNAMSIZ + 1];
6126
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006127 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
6128 "STA " MACSTR " (aid %u)",
6129 MAC2STR(sta->addr), sta->aid);
6130 sta->flags |= WLAN_STA_WDS;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006131 ret = hostapd_set_wds_sta(hapd, ifname_wds,
6132 sta->addr, sta->aid, 1);
6133 if (!ret)
6134 hostapd_set_wds_encryption(hapd, sta,
6135 ifname_wds);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006136 }
6137 return;
6138 }
6139
6140 wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
6141 MACSTR, MAC2STR(src));
Hai Shalomc3565922019-10-28 11:58:20 -07006142 if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
6143 os_memcmp(src, hapd->own_addr, ETH_ALEN) == 0) {
6144 /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
6145 * silently. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006146 return;
6147 }
6148
6149 if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) {
6150 wpa_printf(MSG_DEBUG, "Association Response to the STA has "
6151 "already been sent, but no TX status yet known - "
6152 "ignore Class 3 frame issue with " MACSTR,
6153 MAC2STR(src));
6154 return;
6155 }
6156
6157 if (sta && (sta->flags & WLAN_STA_AUTH))
6158 hostapd_drv_sta_disassoc(
6159 hapd, src,
6160 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
6161 else
6162 hostapd_drv_sta_deauth(
6163 hapd, src,
6164 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
6165}
6166
6167
Sunil Ravia04bd252022-05-02 22:54:18 -07006168static u8 * hostapd_add_tpe_info(u8 *eid, u8 tx_pwr_count,
6169 enum max_tx_pwr_interpretation tx_pwr_intrpn,
6170 u8 tx_pwr_cat, u8 tx_pwr)
6171{
6172 int i;
6173
6174 *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE; /* Element ID */
6175 *eid++ = 2 + tx_pwr_count; /* Length */
6176
6177 /*
6178 * Transmit Power Information field
6179 * bits 0-2 : Maximum Transmit Power Count
6180 * bits 3-5 : Maximum Transmit Power Interpretation
6181 * bits 6-7 : Maximum Transmit Power Category
6182 */
6183 *eid++ = tx_pwr_count | (tx_pwr_intrpn << 3) | (tx_pwr_cat << 6);
6184
6185 /* Maximum Transmit Power field */
6186 for (i = 0; i <= tx_pwr_count; i++)
6187 *eid++ = tx_pwr;
6188
6189 return eid;
6190}
6191
6192
6193/*
6194 * TODO: Extract power limits from channel data after 6G regulatory
6195 * support.
6196 */
6197#define REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT (-1) /* dBm/MHz */
6198#define REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT 5 /* dBm/MHz */
6199
Hai Shalom60840252021-02-19 19:02:11 -08006200u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
6201{
6202 struct hostapd_iface *iface = hapd->iface;
6203 struct hostapd_config *iconf = iface->conf;
6204 struct hostapd_hw_modes *mode = iface->current_mode;
6205 struct hostapd_channel_data *chan;
6206 int dfs, i;
6207 u8 channel, tx_pwr_count, local_pwr_constraint;
6208 int max_tx_power;
6209 u8 tx_pwr;
6210
6211 if (!mode)
6212 return eid;
6213
6214 if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
6215 return eid;
6216
6217 for (i = 0; i < mode->num_channels; i++) {
6218 if (mode->channels[i].freq == iface->freq)
6219 break;
6220 }
6221 if (i == mode->num_channels)
6222 return eid;
6223
Sunil Ravia04bd252022-05-02 22:54:18 -07006224#ifdef CONFIG_IEEE80211AX
6225 /* IEEE Std 802.11ax-2021, Annex E.2.7 (6 GHz band in the United
6226 * States): An AP that is an Indoor Access Point per regulatory rules
6227 * shall send at least two Transmit Power Envelope elements in Beacon
6228 * and Probe Response frames as follows:
6229 * - Maximum Transmit Power Category subfield = Default;
6230 * Unit interpretation = Regulatory client EIRP PSD
6231 * - Maximum Transmit Power Category subfield = Subordinate Device;
6232 * Unit interpretation = Regulatory client EIRP PSD
6233 */
6234 if (is_6ghz_op_class(iconf->op_class)) {
6235 enum max_tx_pwr_interpretation tx_pwr_intrpn;
6236
6237 /* Same Maximum Transmit Power for all 20 MHz bands */
6238 tx_pwr_count = 0;
6239 tx_pwr_intrpn = REGULATORY_CLIENT_EIRP_PSD;
6240
6241 /* Default Transmit Power Envelope for Global Operating Class */
6242 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT * 2;
6243 eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn,
6244 REG_DEFAULT_CLIENT, tx_pwr);
6245
6246 /* Indoor Access Point must include an additional TPE for
6247 * subordinate devices */
6248 if (iconf->he_6ghz_reg_pwr_type == HE_6GHZ_INDOOR_AP) {
6249 /* TODO: Extract PSD limits from channel data */
6250 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT * 2;
6251 eid = hostapd_add_tpe_info(eid, tx_pwr_count,
6252 tx_pwr_intrpn,
6253 REG_SUBORDINATE_CLIENT,
6254 tx_pwr);
6255 }
6256
6257 return eid;
6258 }
6259#endif /* CONFIG_IEEE80211AX */
6260
Hai Shalom60840252021-02-19 19:02:11 -08006261 switch (hostapd_get_oper_chwidth(iconf)) {
Sunil8cd6f4d2022-06-28 18:40:46 +00006262 case CONF_OPER_CHWIDTH_USE_HT:
Hai Shalom60840252021-02-19 19:02:11 -08006263 if (iconf->secondary_channel == 0) {
6264 /* Max Transmit Power count = 0 (20 MHz) */
6265 tx_pwr_count = 0;
6266 } else {
6267 /* Max Transmit Power count = 1 (20, 40 MHz) */
6268 tx_pwr_count = 1;
6269 }
6270 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00006271 case CONF_OPER_CHWIDTH_80MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08006272 /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
6273 tx_pwr_count = 2;
6274 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00006275 case CONF_OPER_CHWIDTH_80P80MHZ:
6276 case CONF_OPER_CHWIDTH_160MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08006277 /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
6278 tx_pwr_count = 3;
6279 break;
6280 default:
6281 return eid;
6282 }
6283
6284 /*
6285 * Below local_pwr_constraint logic is referred from
6286 * hostapd_eid_pwr_constraint.
6287 *
6288 * Check if DFS is required by regulatory.
6289 */
6290 dfs = hostapd_is_dfs_required(hapd->iface);
6291 if (dfs < 0)
6292 dfs = 0;
6293
6294 /*
6295 * In order to meet regulations when TPC is not implemented using
6296 * a transmit power that is below the legal maximum (including any
6297 * mitigation factor) should help. In this case, indicate 3 dB below
6298 * maximum allowed transmit power.
6299 */
6300 if (hapd->iconf->local_pwr_constraint == -1)
6301 local_pwr_constraint = (dfs == 0) ? 0 : 3;
6302 else
6303 local_pwr_constraint = hapd->iconf->local_pwr_constraint;
6304
6305 /*
6306 * A STA that is not an AP shall use a transmit power less than or
6307 * equal to the local maximum transmit power level for the channel.
6308 * The local maximum transmit power can be calculated from the formula:
6309 * local max TX pwr = max TX pwr - local pwr constraint
6310 * Where max TX pwr is maximum transmit power level specified for
6311 * channel in Country element and local pwr constraint is specified
6312 * for channel in this Power Constraint element.
6313 */
6314 chan = &mode->channels[i];
6315 max_tx_power = chan->max_tx_power - local_pwr_constraint;
6316
6317 /*
6318 * Local Maximum Transmit power is encoded as two's complement
6319 * with a 0.5 dB step.
6320 */
6321 max_tx_power *= 2; /* in 0.5 dB steps */
6322 if (max_tx_power > 127) {
6323 /* 63.5 has special meaning of 63.5 dBm or higher */
6324 max_tx_power = 127;
6325 }
6326 if (max_tx_power < -128)
6327 max_tx_power = -128;
6328 if (max_tx_power < 0)
6329 tx_pwr = 0x80 + max_tx_power + 128;
6330 else
6331 tx_pwr = max_tx_power;
6332
Sunil Ravia04bd252022-05-02 22:54:18 -07006333 return hostapd_add_tpe_info(eid, tx_pwr_count, LOCAL_EIRP,
6334 0 /* Reserved for bands other than 6 GHz */,
6335 tx_pwr);
Hai Shalom60840252021-02-19 19:02:11 -08006336}
6337
6338
Hai Shalom899fcc72020-10-19 14:38:18 -07006339u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
6340{
6341 u8 bw, chan1, chan2 = 0;
6342 int freq1;
6343
6344 if (!hapd->cs_freq_params.channel ||
6345 (!hapd->cs_freq_params.vht_enabled &&
Sunil Ravia04bd252022-05-02 22:54:18 -07006346 !hapd->cs_freq_params.he_enabled &&
6347 !hapd->cs_freq_params.eht_enabled))
Hai Shalom899fcc72020-10-19 14:38:18 -07006348 return eid;
6349
6350 /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
6351 switch (hapd->cs_freq_params.bandwidth) {
6352 case 40:
6353 bw = 0;
6354 break;
6355 case 80:
6356 /* check if it's 80+80 */
6357 if (!hapd->cs_freq_params.center_freq2)
6358 bw = 1;
6359 else
6360 bw = 3;
6361 break;
6362 case 160:
6363 bw = 2;
6364 break;
6365 default:
6366 /* not valid VHT bandwidth or not in CSA */
6367 return eid;
6368 }
6369
6370 freq1 = hapd->cs_freq_params.center_freq1 ?
6371 hapd->cs_freq_params.center_freq1 :
6372 hapd->cs_freq_params.freq;
6373 if (ieee80211_freq_to_chan(freq1, &chan1) !=
6374 HOSTAPD_MODE_IEEE80211A)
6375 return eid;
6376
6377 if (hapd->cs_freq_params.center_freq2 &&
6378 ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
6379 &chan2) != HOSTAPD_MODE_IEEE80211A)
6380 return eid;
6381
6382 *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
6383 *eid++ = 5; /* Length of Channel Switch Wrapper */
6384 *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
6385 *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
6386 *eid++ = bw; /* New Channel Width */
6387 *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
6388 *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
6389
6390 return eid;
6391}
6392
Hai Shaloma20dcd72022-02-04 13:43:00 -08006393
6394static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd,
6395 size_t *current_len)
6396{
6397 struct hostapd_neighbor_entry *nr;
6398 size_t total_len = 0, len = *current_len;
6399
6400 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
6401 list) {
6402 if (!nr->nr || wpabuf_len(nr->nr) < 12)
6403 continue;
6404
6405 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
6406 continue;
6407
6408 /* Start a new element */
6409 if (!len ||
6410 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
6411 len = RNR_HEADER_LEN;
6412 total_len += RNR_HEADER_LEN;
6413 }
6414
6415 len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
6416 total_len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
6417 }
6418
6419 *current_len = len;
6420 return total_len;
6421}
6422
6423
6424static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
6425 struct hostapd_data *reporting_hapd,
6426 size_t *current_len)
6427{
6428 size_t total_len = 0, len = *current_len;
6429 int tbtt_count = 0;
6430 size_t i, start = 0;
6431
6432 while (start < hapd->iface->num_bss) {
6433 if (!len ||
6434 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
6435 len = RNR_HEADER_LEN;
6436 total_len += RNR_HEADER_LEN;
6437 }
6438
6439 len += RNR_TBTT_HEADER_LEN;
6440 total_len += RNR_TBTT_HEADER_LEN;
6441
6442 for (i = start; i < hapd->iface->num_bss; i++) {
6443 struct hostapd_data *bss = hapd->iface->bss[i];
6444
6445 if (!bss || !bss->conf || !bss->started)
6446 continue;
6447
6448 if (bss == reporting_hapd ||
6449 bss->conf->ignore_broadcast_ssid)
6450 continue;
6451
6452 if (len + RNR_TBTT_INFO_LEN > 255 ||
6453 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
6454 break;
6455
6456 len += RNR_TBTT_INFO_LEN;
6457 total_len += RNR_TBTT_INFO_LEN;
6458 tbtt_count++;
6459 }
6460 start = i;
6461 }
6462
6463 if (!tbtt_count)
6464 total_len = 0;
6465 else
6466 *current_len = len;
6467
6468 return total_len;
6469}
6470
6471
6472enum colocation_mode {
6473 NO_COLOCATED_6GHZ,
6474 STANDALONE_6GHZ,
6475 COLOCATED_6GHZ,
6476 COLOCATED_LOWER_BAND,
6477};
6478
6479static enum colocation_mode get_colocation_mode(struct hostapd_data *hapd)
6480{
6481 u8 i;
6482 bool is_6ghz = is_6ghz_op_class(hapd->iconf->op_class);
6483
6484 if (!hapd->iface || !hapd->iface->interfaces)
6485 return NO_COLOCATED_6GHZ;
6486
6487 if (is_6ghz && hapd->iface->interfaces->count == 1)
6488 return STANDALONE_6GHZ;
6489
6490 for (i = 0; i < hapd->iface->interfaces->count; i++) {
6491 struct hostapd_iface *iface;
6492 bool is_colocated_6ghz;
6493
6494 iface = hapd->iface->interfaces->iface[i];
6495 if (iface == hapd->iface || !iface || !iface->conf)
6496 continue;
6497
6498 is_colocated_6ghz = is_6ghz_op_class(iface->conf->op_class);
6499 if (!is_6ghz && is_colocated_6ghz)
6500 return COLOCATED_LOWER_BAND;
6501 if (is_6ghz && !is_colocated_6ghz)
6502 return COLOCATED_6GHZ;
6503 }
6504
6505 if (is_6ghz)
6506 return STANDALONE_6GHZ;
6507
6508 return NO_COLOCATED_6GHZ;
6509}
6510
6511
6512static size_t hostapd_eid_rnr_colocation_len(struct hostapd_data *hapd,
6513 size_t *current_len)
6514{
6515 struct hostapd_iface *iface;
6516 size_t len = 0;
6517 size_t i;
6518
6519 if (!hapd->iface || !hapd->iface->interfaces)
6520 return 0;
6521
6522 for (i = 0; i < hapd->iface->interfaces->count; i++) {
6523 iface = hapd->iface->interfaces->iface[i];
6524
6525 if (iface == hapd->iface ||
6526 !is_6ghz_op_class(iface->conf->op_class))
6527 continue;
6528
6529 len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
6530 current_len);
6531 }
6532
6533 return len;
6534}
6535
6536
6537size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type)
6538{
6539 size_t total_len = 0, current_len = 0;
6540 enum colocation_mode mode = get_colocation_mode(hapd);
6541
6542 switch (type) {
6543 case WLAN_FC_STYPE_BEACON:
6544 if (hapd->conf->rnr)
6545 total_len += hostapd_eid_nr_db_len(hapd, &current_len);
6546 /* fallthrough */
6547
6548 case WLAN_FC_STYPE_PROBE_RESP:
6549 if (mode == COLOCATED_LOWER_BAND)
6550 total_len += hostapd_eid_rnr_colocation_len(
6551 hapd, &current_len);
6552
6553 if (hapd->conf->rnr && hapd->iface->num_bss > 1)
6554 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
6555 &current_len);
6556 break;
6557
6558 case WLAN_FC_STYPE_ACTION:
6559 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
6560 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
6561 &current_len);
6562 break;
6563
6564 default:
6565 break;
6566 }
6567
6568 return total_len;
6569}
6570
6571
6572static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid,
6573 size_t *current_len)
6574{
6575 struct hostapd_neighbor_entry *nr;
6576 size_t len = *current_len;
6577 u8 *size_offset = (eid - len) + 1;
6578
6579 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
6580 list) {
6581 if (!nr->nr || wpabuf_len(nr->nr) < 12)
6582 continue;
6583
6584 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
6585 continue;
6586
6587 /* Start a new element */
6588 if (!len ||
6589 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
6590 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
6591 size_offset = eid++;
6592 len = RNR_HEADER_LEN;
6593 }
6594
6595 /* TBTT Information Header subfield (2 octets) */
6596 *eid++ = 0;
6597 /* TBTT Information Length */
6598 *eid++ = RNR_TBTT_INFO_LEN;
6599 /* Operating Class */
6600 *eid++ = wpabuf_head_u8(nr->nr)[10];
6601 /* Channel Number */
6602 *eid++ = wpabuf_head_u8(nr->nr)[11];
6603 len += RNR_TBTT_HEADER_LEN;
6604 /* TBTT Information Set */
6605 /* TBTT Information field */
6606 /* Neighbor AP TBTT Offset */
6607 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
6608 /* BSSID */
6609 os_memcpy(eid, nr->bssid, ETH_ALEN);
6610 eid += ETH_ALEN;
6611 /* Short SSID */
6612 os_memcpy(eid, &nr->short_ssid, 4);
6613 eid += 4;
6614 /* BSS parameters */
6615 *eid++ = nr->bss_parameters;
6616 /* 20 MHz PSD */
6617 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1;
6618 len += RNR_TBTT_INFO_LEN;
6619 *size_offset = (eid - size_offset) - 1;
6620 }
6621
6622 *current_len = len;
6623 return eid;
6624}
6625
6626
6627static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
6628 struct hostapd_data *reporting_hapd,
6629 u8 *eid, size_t *current_len)
6630{
6631 struct hostapd_data *bss;
6632 struct hostapd_iface *iface = hapd->iface;
6633 size_t i, start = 0;
6634 size_t len = *current_len;
6635 u8 *tbtt_count_pos, *eid_start = eid, *size_offset = (eid - len) + 1;
6636 u8 tbtt_count = 0, op_class, channel, bss_param;
6637
6638 if (!(iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !iface->freq)
6639 return eid;
6640
6641 if (ieee80211_freq_to_channel_ext(iface->freq,
6642 hapd->iconf->secondary_channel,
6643 hostapd_get_oper_chwidth(hapd->iconf),
6644 &op_class, &channel) ==
6645 NUM_HOSTAPD_MODES)
6646 return eid;
6647
6648 while (start < iface->num_bss) {
6649 if (!len ||
6650 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
6651 eid_start = eid;
6652 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
6653 size_offset = eid++;
6654 len = RNR_HEADER_LEN;
6655 tbtt_count = 0;
6656 }
6657
6658 tbtt_count_pos = eid++;
6659 *eid++ = RNR_TBTT_INFO_LEN;
6660 *eid++ = op_class;
6661 *eid++ = hapd->iconf->channel;
6662 len += RNR_TBTT_HEADER_LEN;
6663
6664 for (i = start; i < iface->num_bss; i++) {
6665 bss_param = 0;
6666 bss = iface->bss[i];
6667 if (!bss || !bss->conf || !bss->started)
6668 continue;
6669
6670 if (bss == reporting_hapd ||
6671 bss->conf->ignore_broadcast_ssid)
6672 continue;
6673
6674 if (len + RNR_TBTT_INFO_LEN > 255 ||
6675 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
6676 break;
6677
6678 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
Sunil Ravi89eba102022-09-13 21:04:37 -07006679 os_memcpy(eid, bss->own_addr, ETH_ALEN);
Hai Shaloma20dcd72022-02-04 13:43:00 -08006680 eid += ETH_ALEN;
6681 os_memcpy(eid, &bss->conf->ssid.short_ssid, 4);
6682 eid += 4;
6683 if (bss->conf->ssid.short_ssid ==
6684 reporting_hapd->conf->ssid.short_ssid)
6685 bss_param |= RNR_BSS_PARAM_SAME_SSID;
6686
Sunil Ravi77d572f2023-01-17 23:58:31 +00006687 if (iface->conf->mbssid != MBSSID_DISABLED &&
6688 iface->num_bss > 1) {
6689 bss_param |= RNR_BSS_PARAM_MULTIPLE_BSSID;
6690 if (i == 0)
6691 bss_param |=
6692 RNR_BSS_PARAM_TRANSMITTED_BSSID;
6693 }
6694
Hai Shaloma20dcd72022-02-04 13:43:00 -08006695 if (is_6ghz_op_class(hapd->iconf->op_class) &&
6696 bss->conf->unsol_bcast_probe_resp_interval)
6697 bss_param |=
6698 RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE;
6699
6700 bss_param |= RNR_BSS_PARAM_CO_LOCATED;
6701
6702 *eid++ = bss_param;
6703 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1;
6704 len += RNR_TBTT_INFO_LEN;
6705 tbtt_count += 1;
6706 }
6707
6708 start = i;
6709 *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
6710 *size_offset = (eid - size_offset) - 1;
6711 }
6712
6713 if (tbtt_count == 0)
6714 return eid_start;
6715
6716 *current_len = len;
6717 return eid;
6718}
6719
6720
6721static u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid,
6722 size_t *current_len)
6723{
6724 struct hostapd_iface *iface;
6725 size_t i;
6726
6727 if (!hapd->iface || !hapd->iface->interfaces)
6728 return eid;
6729
6730 for (i = 0; i < hapd->iface->interfaces->count; i++) {
6731 iface = hapd->iface->interfaces->iface[i];
6732
6733 if (iface == hapd->iface ||
6734 !is_6ghz_op_class(iface->conf->op_class))
6735 continue;
6736
6737 eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
6738 current_len);
6739 }
6740
6741 return eid;
6742}
6743
6744
6745u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
6746{
6747 u8 *eid_start = eid;
6748 size_t current_len = 0;
6749 enum colocation_mode mode = get_colocation_mode(hapd);
6750
6751 switch (type) {
6752 case WLAN_FC_STYPE_BEACON:
6753 if (hapd->conf->rnr)
6754 eid = hostapd_eid_nr_db(hapd, eid, &current_len);
6755 /* fallthrough */
6756
6757 case WLAN_FC_STYPE_PROBE_RESP:
6758 if (mode == COLOCATED_LOWER_BAND)
6759 eid = hostapd_eid_rnr_colocation(hapd, eid,
6760 &current_len);
6761
6762 if (hapd->conf->rnr && hapd->iface->num_bss > 1)
6763 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
6764 &current_len);
6765 break;
6766
6767 case WLAN_FC_STYPE_ACTION:
6768 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
6769 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
6770 &current_len);
6771 break;
6772
6773 default:
6774 return eid_start;
6775 }
6776
6777 if (eid == eid_start + 2)
6778 return eid_start;
6779
6780 return eid;
6781}
6782
Sunil Ravi77d572f2023-01-17 23:58:31 +00006783
6784static bool mbssid_known_bss(unsigned int i, const u8 *known_bss,
6785 size_t known_bss_len)
6786{
6787 if (!known_bss || known_bss_len <= i / 8)
6788 return false;
6789 known_bss = &known_bss[i / 8];
6790 return *known_bss & (u8) (BIT(i % 8));
6791}
6792
6793
6794static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd,
6795 u32 frame_type, size_t *bss_index,
6796 const u8 *known_bss,
6797 size_t known_bss_len)
6798{
6799 struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
6800 size_t len = 3, i;
6801
6802 for (i = *bss_index; i < hapd->iface->num_bss; i++) {
6803 struct hostapd_data *bss = hapd->iface->bss[i];
6804 const u8 *auth, *rsn = NULL, *rsnx = NULL;
6805 size_t nontx_profile_len, auth_len;
6806 u8 ie_count = 0;
6807
6808 if (!bss || !bss->conf || !bss->started ||
6809 mbssid_known_bss(i, known_bss, known_bss_len))
6810 continue;
6811
6812 /*
6813 * Sublement ID: 1 octet
6814 * Length: 1 octet
6815 * Nontransmitted capabilities: 4 octets
6816 * SSID element: 2 + variable
6817 * Multiple BSSID Index Element: 3 octets (+2 octets in beacons)
6818 * Fixed length = 1 + 1 + 4 + 2 + 3 = 11
6819 */
6820 nontx_profile_len = 11 + bss->conf->ssid.ssid_len;
6821
6822 if (frame_type == WLAN_FC_STYPE_BEACON)
6823 nontx_profile_len += 2;
6824
6825 auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
6826 if (auth) {
6827 rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
6828 if (rsn)
6829 nontx_profile_len += 2 + rsn[1];
6830
6831 rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
6832 if (rsnx)
6833 nontx_profile_len += 2 + rsnx[1];
6834 }
6835 if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
6836 ie_count++;
6837 if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
6838 ie_count++;
6839 if (bss->conf->xrates_supported)
6840 nontx_profile_len += 8;
6841 else if (hapd->conf->xrates_supported)
6842 ie_count++;
6843 if (ie_count)
6844 nontx_profile_len += 4 + ie_count;
6845
6846 if (len + nontx_profile_len > 255)
6847 break;
6848
6849 len += nontx_profile_len;
6850 }
6851
6852 *bss_index = i;
6853 return len;
6854}
6855
6856
6857size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
6858 u8 *elem_count, const u8 *known_bss,
6859 size_t known_bss_len)
6860{
6861 size_t len = 0, bss_index = 1;
6862
6863 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
6864 (frame_type != WLAN_FC_STYPE_BEACON &&
6865 frame_type != WLAN_FC_STYPE_PROBE_RESP))
6866 return 0;
6867
6868 if (frame_type == WLAN_FC_STYPE_BEACON) {
6869 if (!elem_count) {
6870 wpa_printf(MSG_INFO,
6871 "MBSSID: Insufficient data for Beacon frames");
6872 return 0;
6873 }
6874 *elem_count = 0;
6875 }
6876
6877 while (bss_index < hapd->iface->num_bss) {
6878 len += hostapd_eid_mbssid_elem_len(hapd, frame_type,
6879 &bss_index, known_bss,
6880 known_bss_len);
6881
6882 if (frame_type == WLAN_FC_STYPE_BEACON)
6883 *elem_count += 1;
6884 }
6885 return len;
6886}
6887
6888
6889static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end,
6890 u32 frame_type, u8 max_bssid_indicator,
6891 size_t *bss_index, u8 elem_count,
6892 const u8 *known_bss, size_t known_bss_len)
6893{
6894 struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
6895 size_t i;
6896 u8 *eid_len_offset, *max_bssid_indicator_offset;
6897
6898 *eid++ = WLAN_EID_MULTIPLE_BSSID;
6899 eid_len_offset = eid++;
6900 max_bssid_indicator_offset = eid++;
6901
6902 for (i = *bss_index; i < hapd->iface->num_bss; i++) {
6903 struct hostapd_data *bss = hapd->iface->bss[i];
6904 struct hostapd_bss_config *conf;
6905 u8 *eid_len_pos, *nontx_bss_start = eid;
6906 const u8 *auth, *rsn = NULL, *rsnx = NULL;
6907 u8 ie_count = 0, non_inherit_ie[3];
6908 size_t auth_len = 0;
6909 u16 capab_info;
6910
6911 if (!bss || !bss->conf || !bss->started ||
6912 mbssid_known_bss(i, known_bss, known_bss_len))
6913 continue;
6914 conf = bss->conf;
6915
6916 *eid++ = WLAN_MBSSID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE;
6917 eid_len_pos = eid++;
6918
6919 capab_info = hostapd_own_capab_info(bss);
6920 *eid++ = WLAN_EID_NONTRANSMITTED_BSSID_CAPA;
6921 *eid++ = sizeof(capab_info);
6922 WPA_PUT_LE16(eid, capab_info);
6923 eid += sizeof(capab_info);
6924
6925 *eid++ = WLAN_EID_SSID;
6926 *eid++ = conf->ssid.ssid_len;
6927 os_memcpy(eid, conf->ssid.ssid, conf->ssid.ssid_len);
6928 eid += conf->ssid.ssid_len;
6929
6930 *eid++ = WLAN_EID_MULTIPLE_BSSID_INDEX;
6931 if (frame_type == WLAN_FC_STYPE_BEACON) {
6932 *eid++ = 3;
6933 *eid++ = i; /* BSSID Index */
6934 if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
6935 (conf->dtim_period % elem_count))
6936 conf->dtim_period = elem_count;
6937 *eid++ = conf->dtim_period;
6938 *eid++ = 0xFF; /* DTIM Count */
6939 } else {
6940 /* Probe Request frame does not include DTIM Period and
6941 * DTIM Count fields. */
6942 *eid++ = 1;
6943 *eid++ = i; /* BSSID Index */
6944 }
6945
6946 auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
6947 if (auth) {
6948 rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
6949 if (rsn) {
6950 os_memcpy(eid, rsn, 2 + rsn[1]);
6951 eid += 2 + rsn[1];
6952 }
6953
6954 rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
6955 if (rsnx) {
6956 os_memcpy(eid, rsnx, 2 + rsnx[1]);
6957 eid += 2 + rsnx[1];
6958 }
6959 }
6960 if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
6961 non_inherit_ie[ie_count++] = WLAN_EID_RSN;
6962 if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
6963 non_inherit_ie[ie_count++] = WLAN_EID_RSNX;
6964 if (hapd->conf->xrates_supported &&
6965 !bss->conf->xrates_supported)
6966 non_inherit_ie[ie_count++] = WLAN_EID_EXT_SUPP_RATES;
6967 if (ie_count) {
6968 *eid++ = WLAN_EID_EXTENSION;
6969 *eid++ = 2 + ie_count;
6970 *eid++ = WLAN_EID_EXT_NON_INHERITANCE;
6971 *eid++ = ie_count;
6972 os_memcpy(eid, non_inherit_ie, ie_count);
6973 eid += ie_count;
6974 }
6975
6976 *eid_len_pos = (eid - eid_len_pos) - 1;
6977
6978 if (((eid - eid_len_offset) - 1) > 255) {
6979 eid = nontx_bss_start;
6980 break;
6981 }
6982 }
6983
6984 *bss_index = i;
6985 *max_bssid_indicator_offset = max_bssid_indicator;
6986 if (*max_bssid_indicator_offset < 1)
6987 *max_bssid_indicator_offset = 1;
6988 *eid_len_offset = (eid - eid_len_offset) - 1;
6989 return eid;
6990}
6991
6992
6993u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
6994 unsigned int frame_stype, u8 elem_count,
6995 u8 **elem_offset,
6996 const u8 *known_bss, size_t known_bss_len)
6997{
6998 size_t bss_index = 1;
6999 u8 elem_index = 0;
7000
7001 if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
7002 (frame_stype != WLAN_FC_STYPE_BEACON &&
7003 frame_stype != WLAN_FC_STYPE_PROBE_RESP))
7004 return eid;
7005
7006 if (frame_stype == WLAN_FC_STYPE_BEACON && !elem_offset) {
7007 wpa_printf(MSG_INFO,
7008 "MBSSID: Insufficient data for Beacon frames");
7009 return eid;
7010 }
7011
7012 while (bss_index < hapd->iface->num_bss) {
7013 if (frame_stype == WLAN_FC_STYPE_BEACON) {
7014 if (elem_index == elem_count) {
7015 wpa_printf(MSG_WARNING,
7016 "MBSSID: Larger number of elements than there is room in the provided array");
7017 break;
7018 }
7019
7020 elem_offset[elem_index] = eid;
7021 elem_index = elem_index + 1;
7022 }
7023 eid = hostapd_eid_mbssid_elem(hapd, eid, end, frame_stype,
7024 hostapd_max_bssid_indicator(hapd),
7025 &bss_index, elem_count,
7026 known_bss, known_bss_len);
7027 }
7028
7029 return eid;
7030}
7031
Sunil Ravi036cec52023-03-29 11:35:17 -07007032
7033static void punct_update_legacy_bw_80(u8 bitmap, u8 pri_chan, u8 *seg0)
7034{
7035 u8 first_chan = *seg0 - 6, sec_chan;
7036
7037 switch (bitmap) {
7038 case 0x6:
7039 *seg0 = 0;
7040 return;
7041 case 0x8:
7042 case 0x4:
7043 case 0x2:
7044 case 0x1:
7045 case 0xC:
7046 case 0x3:
7047 if (pri_chan < *seg0)
7048 *seg0 -= 4;
7049 else
7050 *seg0 += 4;
7051 break;
7052 }
7053
7054 if (pri_chan < *seg0)
7055 sec_chan = pri_chan + 4;
7056 else
7057 sec_chan = pri_chan - 4;
7058
7059 if (bitmap & BIT((sec_chan - first_chan) / 4))
7060 *seg0 = 0;
7061}
7062
7063
7064static void punct_update_legacy_bw_160(u8 bitmap, u8 pri,
7065 enum oper_chan_width *width, u8 *seg0)
7066{
7067 if (pri < *seg0) {
7068 *seg0 -= 8;
7069 if (bitmap & 0x0F) {
7070 *width = 0;
7071 punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0);
7072 }
7073 } else {
7074 *seg0 += 8;
7075 if (bitmap & 0xF0) {
7076 *width = 0;
7077 punct_update_legacy_bw_80((bitmap & 0xF0) >> 4, pri,
7078 seg0);
7079 }
7080 }
7081}
7082
7083
7084void punct_update_legacy_bw(u16 bitmap, u8 pri, enum oper_chan_width *width,
7085 u8 *seg0, u8 *seg1)
7086{
7087 if (*width == CONF_OPER_CHWIDTH_80MHZ && (bitmap & 0xF)) {
7088 *width = CONF_OPER_CHWIDTH_USE_HT;
7089 punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0);
7090 }
7091
7092 if (*width == CONF_OPER_CHWIDTH_160MHZ && (bitmap & 0xFF)) {
7093 *width = CONF_OPER_CHWIDTH_80MHZ;
7094 *seg1 = 0;
7095 punct_update_legacy_bw_160(bitmap & 0xFF, pri, width, seg0);
7096 }
7097
7098 /* TODO: 320 MHz */
7099}
7100
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007101#endif /* CONFIG_NATIVE_WINDOWS */