blob: 394e292bdd813c0a45c122c6f874997d95b198bf [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"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070058
59
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070060#ifdef CONFIG_FILS
61static struct wpabuf *
62prepare_auth_resp_fils(struct hostapd_data *hapd,
63 struct sta_info *sta, u16 *resp,
64 struct rsn_pmksa_cache_entry *pmksa,
65 struct wpabuf *erp_resp,
66 const u8 *msk, size_t msk_len,
67 int *is_pub);
68#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -080069
70#ifdef CONFIG_PASN
71
72static int handle_auth_pasn_resp(struct hostapd_data *hapd,
73 struct sta_info *sta,
74 struct rsn_pmksa_cache_entry *pmksa,
75 u16 status);
76#ifdef CONFIG_FILS
77
78static void pasn_fils_auth_resp(struct hostapd_data *hapd,
79 struct sta_info *sta, u16 status,
80 struct wpabuf *erp_resp,
81 const u8 *msk, size_t msk_len);
82
83#endif /* CONFIG_FILS */
84#endif /* CONFIG_PASN */
85
Hai Shalom021b0b52019-04-10 11:17:58 -070086static void handle_auth(struct hostapd_data *hapd,
87 const struct ieee80211_mgmt *mgmt, size_t len,
88 int rssi, int from_queue);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070089
Hai Shalom74f70d42019-02-11 14:42:39 -080090
91u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
92{
93 u8 multi_ap_val = 0;
94
95 if (!hapd->conf->multi_ap)
96 return eid;
97 if (hapd->conf->multi_ap & BACKHAUL_BSS)
98 multi_ap_val |= MULTI_AP_BACKHAUL_BSS;
99 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
100 multi_ap_val |= MULTI_AP_FRONTHAUL_BSS;
101
102 return eid + add_multi_ap_ie(eid, 9, multi_ap_val);
103}
104
105
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700106u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
107{
108 u8 *pos = eid;
109 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700110 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700111
112 if (hapd->iface->current_rates == NULL)
113 return eid;
114
115 *pos++ = WLAN_EID_SUPP_RATES;
116 num = hapd->iface->num_rates;
117 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
118 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800119 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
120 num++;
Hai Shalomfdcde762020-04-02 11:19:20 -0700121 h2e_required = (hapd->conf->sae_pwe == 1 ||
122 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
123 hapd->conf->sae_pwe != 3 &&
124 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
125 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700126 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700127 if (num > 8) {
128 /* rest of the rates are encoded in Extended supported
129 * rates element */
130 num = 8;
131 }
132
133 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700134 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
135 i++) {
136 count++;
137 *pos = hapd->iface->current_rates[i].rate / 5;
138 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
139 *pos |= 0x80;
140 pos++;
141 }
142
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800143 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
144 count++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700145 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800146 }
147
148 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
149 count++;
150 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
151 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700152
Hai Shalomfdcde762020-04-02 11:19:20 -0700153 if (h2e_required && count < 8) {
Hai Shalomc3565922019-10-28 11:58:20 -0700154 count++;
155 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
156 }
157
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700158 return pos;
159}
160
161
162u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
163{
164 u8 *pos = eid;
165 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700166 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700167
168 if (hapd->iface->current_rates == NULL)
169 return eid;
170
171 num = hapd->iface->num_rates;
172 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
173 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800174 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
175 num++;
Hai Shalomfdcde762020-04-02 11:19:20 -0700176 h2e_required = (hapd->conf->sae_pwe == 1 ||
177 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
178 hapd->conf->sae_pwe != 3 &&
179 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
180 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700181 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700182 if (num <= 8)
183 return eid;
184 num -= 8;
185
186 *pos++ = WLAN_EID_EXT_SUPP_RATES;
187 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700188 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
189 i++) {
190 count++;
191 if (count <= 8)
192 continue; /* already in SuppRates IE */
193 *pos = hapd->iface->current_rates[i].rate / 5;
194 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
195 *pos |= 0x80;
196 pos++;
197 }
198
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800199 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
200 count++;
201 if (count > 8)
202 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
203 }
204
205 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
206 count++;
207 if (count > 8)
208 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
209 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700210
Hai Shalomfdcde762020-04-02 11:19:20 -0700211 if (h2e_required) {
Hai Shalomc3565922019-10-28 11:58:20 -0700212 count++;
213 if (count > 8)
214 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
215 }
216
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700217 return pos;
218}
219
220
Hai Shalomfdcde762020-04-02 11:19:20 -0700221u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
222 size_t len)
223{
224 size_t i;
225
226 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
227 if (hapd->conf->radio_measurements[i])
228 break;
229 }
230
231 if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
232 return eid;
233
234 *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
235 *eid++ = RRM_CAPABILITIES_IE_LEN;
236 os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
237
238 return eid + RRM_CAPABILITIES_IE_LEN;
239}
240
241
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700242u16 hostapd_own_capab_info(struct hostapd_data *hapd)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700243{
244 int capab = WLAN_CAPABILITY_ESS;
Hai Shalomfdcde762020-04-02 11:19:20 -0700245 int privacy = 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800246 int dfs;
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700247 int i;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800248
249 /* Check if any of configured channels require DFS */
250 dfs = hostapd_is_dfs_required(hapd->iface);
251 if (dfs < 0) {
252 wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
253 dfs);
254 dfs = 0;
255 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700256
257 if (hapd->iface->num_sta_no_short_preamble == 0 &&
258 hapd->iconf->preamble == SHORT_PREAMBLE)
259 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
260
Hai Shalomfdcde762020-04-02 11:19:20 -0700261#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700262 privacy = hapd->conf->ssid.wep.keys_set;
263
264 if (hapd->conf->ieee802_1x &&
265 (hapd->conf->default_wep_key_len ||
266 hapd->conf->individual_wep_key_len))
267 privacy = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -0700268#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700269
270 if (hapd->conf->wpa)
271 privacy = 1;
272
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800273#ifdef CONFIG_HS20
274 if (hapd->conf->osen)
275 privacy = 1;
276#endif /* CONFIG_HS20 */
277
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700278 if (privacy)
279 capab |= WLAN_CAPABILITY_PRIVACY;
280
281 if (hapd->iface->current_mode &&
282 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
283 hapd->iface->num_sta_no_short_slot_time == 0)
284 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
285
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800286 /*
287 * Currently, Spectrum Management capability bit is set when directly
288 * requested in configuration by spectrum_mgmt_required or when AP is
289 * running on DFS channel.
290 * TODO: Also consider driver support for TPC to set Spectrum Mgmt bit
291 */
292 if (hapd->iface->current_mode &&
293 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
294 (hapd->iconf->spectrum_mgmt_required || dfs))
295 capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
296
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700297 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
298 if (hapd->conf->radio_measurements[i]) {
299 capab |= IEEE80211_CAP_RRM;
300 break;
301 }
302 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800303
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700304 return capab;
305}
306
307
Hai Shalomfdcde762020-04-02 11:19:20 -0700308#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800309#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700310static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
311 u16 auth_transaction, const u8 *challenge,
312 int iswep)
313{
314 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
315 HOSTAPD_LEVEL_DEBUG,
316 "authentication (shared key, transaction %d)",
317 auth_transaction);
318
319 if (auth_transaction == 1) {
320 if (!sta->challenge) {
321 /* Generate a pseudo-random challenge */
322 u8 key[8];
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800323
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700324 sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
325 if (sta->challenge == NULL)
326 return WLAN_STATUS_UNSPECIFIED_FAILURE;
327
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800328 if (os_get_random(key, sizeof(key)) < 0) {
329 os_free(sta->challenge);
330 sta->challenge = NULL;
331 return WLAN_STATUS_UNSPECIFIED_FAILURE;
332 }
333
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700334 rc4_skip(key, sizeof(key), 0,
335 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
336 }
337 return 0;
338 }
339
340 if (auth_transaction != 3)
341 return WLAN_STATUS_UNSPECIFIED_FAILURE;
342
343 /* Transaction 3 */
344 if (!iswep || !sta->challenge || !challenge ||
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700345 os_memcmp_const(sta->challenge, challenge,
346 WLAN_AUTH_CHALLENGE_LEN)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700347 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
348 HOSTAPD_LEVEL_INFO,
349 "shared key authentication - invalid "
350 "challenge-response");
351 return WLAN_STATUS_CHALLENGE_FAIL;
352 }
353
354 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
355 HOSTAPD_LEVEL_DEBUG,
356 "authentication OK (shared key)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700357 sta->flags |= WLAN_STA_AUTH;
358 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700359 os_free(sta->challenge);
360 sta->challenge = NULL;
361
362 return 0;
363}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800364#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700365#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700366
367
Hai Shalomfdcde762020-04-02 11:19:20 -0700368static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800369 const u8 *dst, const u8 *bssid,
370 u16 auth_alg, u16 auth_transaction, u16 resp,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700371 const u8 *ies, size_t ies_len, const char *dbg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700372{
373 struct ieee80211_mgmt *reply;
374 u8 *buf;
375 size_t rlen;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800376 int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700377
378 rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
379 buf = os_zalloc(rlen);
380 if (buf == NULL)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800381 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700382
383 reply = (struct ieee80211_mgmt *) buf;
384 reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
385 WLAN_FC_STYPE_AUTH);
386 os_memcpy(reply->da, dst, ETH_ALEN);
387 os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
388 os_memcpy(reply->bssid, bssid, ETH_ALEN);
389
390 reply->u.auth.auth_alg = host_to_le16(auth_alg);
391 reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
392 reply->u.auth.status_code = host_to_le16(resp);
393
394 if (ies && ies_len)
395 os_memcpy(reply->u.auth.variable, ies, ies_len);
396
397 wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700398 " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700399 MAC2STR(dst), auth_alg, auth_transaction,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700400 resp, (unsigned long) ies_len, dbg);
Hai Shalomfdcde762020-04-02 11:19:20 -0700401#ifdef CONFIG_TESTING_OPTIONS
402#ifdef CONFIG_SAE
403 if (hapd->conf->sae_confirm_immediate == 2 &&
404 auth_alg == WLAN_AUTH_SAE) {
405 if (auth_transaction == 1 && sta &&
406 (resp == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -0700407 resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
408 resp == WLAN_STATUS_SAE_PK)) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700409 wpa_printf(MSG_DEBUG,
410 "TESTING: Postpone SAE Commit transmission until Confirm is ready");
411 os_free(sta->sae_postponed_commit);
412 sta->sae_postponed_commit = buf;
413 sta->sae_postponed_commit_len = rlen;
414 return WLAN_STATUS_SUCCESS;
415 }
416
417 if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
418 wpa_printf(MSG_DEBUG,
419 "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
420 if (hostapd_drv_send_mlme(hapd,
421 sta->sae_postponed_commit,
422 sta->sae_postponed_commit_len,
423 0, NULL, 0, 0) < 0)
424 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
425 os_free(sta->sae_postponed_commit);
426 sta->sae_postponed_commit = NULL;
427 sta->sae_postponed_commit_len = 0;
428 }
429 }
430#endif /* CONFIG_SAE */
431#endif /* CONFIG_TESTING_OPTIONS */
432 if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800433 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
434 else
435 reply_res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700436
437 os_free(buf);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800438
439 return reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700440}
441
442
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800443#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700444static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
445 u16 auth_transaction, u16 status,
446 const u8 *ies, size_t ies_len)
447{
448 struct hostapd_data *hapd = ctx;
449 struct sta_info *sta;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800450 int reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700451
Hai Shalomfdcde762020-04-02 11:19:20 -0700452 reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700453 auth_transaction, status, ies, ies_len,
454 "auth-ft-finish");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700455
456 sta = ap_get_sta(hapd, dst);
457 if (sta == NULL)
458 return;
459
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800460 if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
461 status != WLAN_STATUS_SUCCESS)) {
462 hostapd_drv_sta_remove(hapd, sta->addr);
463 sta->added_unassoc = 0;
464 return;
465 }
466
467 if (status != WLAN_STATUS_SUCCESS)
468 return;
469
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700470 hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
471 HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
472 sta->flags |= WLAN_STA_AUTH;
473 mlme_authenticate_indication(hapd, sta);
474}
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800475#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700476
477
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800478#ifdef CONFIG_SAE
479
Roshan Pius3a1667e2018-07-03 15:17:14 -0700480static void sae_set_state(struct sta_info *sta, enum sae_state state,
481 const char *reason)
482{
483 wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
484 sae_state_txt(sta->sae->state), sae_state_txt(state),
485 MAC2STR(sta->addr), reason);
486 sta->sae->state = state;
487}
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800488
489
Hai Shalom60840252021-02-19 19:02:11 -0800490static const char * sae_get_password(struct hostapd_data *hapd,
491 struct sta_info *sta,
492 const char *rx_id,
493 struct sae_password_entry **pw_entry,
494 struct sae_pt **s_pt,
495 const struct sae_pk **s_pk)
496{
497 const char *password = NULL;
498 struct sae_password_entry *pw;
499 struct sae_pt *pt = NULL;
500 const struct sae_pk *pk = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -0700501 struct hostapd_sta_wpa_psk_short *psk = NULL;
Hai Shalom60840252021-02-19 19:02:11 -0800502
503 for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
504 if (!is_broadcast_ether_addr(pw->peer_addr) &&
505 os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
506 continue;
507 if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
508 continue;
509 if (rx_id && pw->identifier &&
510 os_strcmp(rx_id, pw->identifier) != 0)
511 continue;
512 password = pw->password;
513 pt = pw->pt;
514 if (!(hapd->conf->mesh & MESH_ENABLED))
515 pk = pw->pk;
516 break;
517 }
518 if (!password) {
519 password = hapd->conf->ssid.wpa_passphrase;
520 pt = hapd->conf->ssid.pt;
521 }
522
Sunil Ravia04bd252022-05-02 22:54:18 -0700523 if (!password) {
524 for (psk = sta->psk; psk; psk = psk->next) {
525 if (psk->is_passphrase) {
526 password = psk->passphrase;
527 break;
528 }
529 }
530 }
531
Hai Shalom60840252021-02-19 19:02:11 -0800532 if (pw_entry)
533 *pw_entry = pw;
534 if (s_pt)
535 *s_pt = pt;
536 if (s_pk)
537 *s_pk = pk;
538
539 return password;
540}
541
542
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800543static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
Hai Shalomc3565922019-10-28 11:58:20 -0700544 struct sta_info *sta, int update,
545 int status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800546{
547 struct wpabuf *buf;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700548 const char *password = NULL;
549 struct sae_password_entry *pw;
550 const char *rx_id = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700551 int use_pt = 0;
552 struct sae_pt *pt = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700553 const struct sae_pk *pk = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800554
Hai Shalomc3565922019-10-28 11:58:20 -0700555 if (sta->sae->tmp) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700556 rx_id = sta->sae->tmp->pw_id;
Hai Shalom899fcc72020-10-19 14:38:18 -0700557 use_pt = sta->sae->h2e;
558#ifdef CONFIG_SAE_PK
559 os_memcpy(sta->sae->tmp->own_addr, hapd->own_addr, ETH_ALEN);
560 os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
561#endif /* CONFIG_SAE_PK */
Hai Shalomc3565922019-10-28 11:58:20 -0700562 }
563
Hai Shalomfdcde762020-04-02 11:19:20 -0700564 if (rx_id && hapd->conf->sae_pwe != 3)
565 use_pt = 1;
566 else if (status_code == WLAN_STATUS_SUCCESS)
Hai Shalomc3565922019-10-28 11:58:20 -0700567 use_pt = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700568 else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
569 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomc3565922019-10-28 11:58:20 -0700570 use_pt = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700571
Hai Shalom60840252021-02-19 19:02:11 -0800572 password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk);
Hai Shalomc3565922019-10-28 11:58:20 -0700573 if (!password || (use_pt && !pt)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800574 wpa_printf(MSG_DEBUG, "SAE: No password available");
575 return NULL;
576 }
577
Hai Shalomc3565922019-10-28 11:58:20 -0700578 if (update && use_pt &&
579 sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
Hai Shalom899fcc72020-10-19 14:38:18 -0700580 NULL, pk) < 0)
Hai Shalomc3565922019-10-28 11:58:20 -0700581 return NULL;
582
583 if (update && !use_pt &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800584 sae_prepare_commit(hapd->own_addr, sta->addr,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800585 (u8 *) password, os_strlen(password),
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800586 sta->sae) < 0) {
587 wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
588 return NULL;
589 }
590
Hai Shalom021b0b52019-04-10 11:17:58 -0700591 if (pw && pw->vlan_id) {
592 if (!sta->sae->tmp) {
593 wpa_printf(MSG_INFO,
594 "SAE: No temporary data allocated - cannot store VLAN ID");
595 return NULL;
596 }
597 sta->sae->tmp->vlan_id = pw->vlan_id;
598 }
599
Roshan Pius3a1667e2018-07-03 15:17:14 -0700600 buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
601 (rx_id ? 3 + os_strlen(rx_id) : 0));
Hai Shalomfdcde762020-04-02 11:19:20 -0700602 if (buf &&
603 sae_write_commit(sta->sae, buf, sta->sae->tmp ?
604 sta->sae->tmp->anti_clogging_token : NULL,
605 rx_id) < 0) {
606 wpabuf_free(buf);
607 buf = NULL;
608 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800609
610 return buf;
611}
612
613
614static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
615 struct sta_info *sta)
616{
617 struct wpabuf *buf;
618
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800619 buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800620 if (buf == NULL)
621 return NULL;
622
Hai Shalom899fcc72020-10-19 14:38:18 -0700623#ifdef CONFIG_SAE_PK
624#ifdef CONFIG_TESTING_OPTIONS
625 if (sta->sae->tmp)
626 sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
627#endif /* CONFIG_TESTING_OPTIONS */
628#endif /* CONFIG_SAE_PK */
629
630 if (sae_write_confirm(sta->sae, buf) < 0) {
631 wpabuf_free(buf);
632 return NULL;
633 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800634
635 return buf;
636}
637
638
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800639static int auth_sae_send_commit(struct hostapd_data *hapd,
640 struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700641 const u8 *bssid, int update, int status_code)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800642{
643 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800644 int reply_res;
Hai Shalomc3565922019-10-28 11:58:20 -0700645 u16 status;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800646
Hai Shalomc3565922019-10-28 11:58:20 -0700647 data = auth_build_sae_commit(hapd, sta, update, status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700648 if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
649 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800650 if (data == NULL)
651 return WLAN_STATUS_UNSPECIFIED_FAILURE;
652
Hai Shalom899fcc72020-10-19 14:38:18 -0700653 if (sta->sae->tmp && sta->sae->pk)
654 status = WLAN_STATUS_SAE_PK;
655 else if (sta->sae->tmp && sta->sae->h2e)
656 status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
657 else
658 status = WLAN_STATUS_SUCCESS;
659#ifdef CONFIG_TESTING_OPTIONS
660 if (hapd->conf->sae_commit_status >= 0 &&
661 hapd->conf->sae_commit_status != status) {
662 wpa_printf(MSG_INFO,
663 "TESTING: Override SAE commit status code %u --> %d",
664 status, hapd->conf->sae_commit_status);
665 status = hapd->conf->sae_commit_status;
666 }
667#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomfdcde762020-04-02 11:19:20 -0700668 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
669 WLAN_AUTH_SAE, 1,
Hai Shalomc3565922019-10-28 11:58:20 -0700670 status, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700671 wpabuf_len(data), "sae-send-commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800672
673 wpabuf_free(data);
674
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800675 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800676}
677
678
679static int auth_sae_send_confirm(struct hostapd_data *hapd,
680 struct sta_info *sta,
681 const u8 *bssid)
682{
683 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800684 int reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800685
686 data = auth_build_sae_confirm(hapd, sta);
687 if (data == NULL)
688 return WLAN_STATUS_UNSPECIFIED_FAILURE;
689
Hai Shalomfdcde762020-04-02 11:19:20 -0700690 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
691 WLAN_AUTH_SAE, 2,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800692 WLAN_STATUS_SUCCESS, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700693 wpabuf_len(data), "sae-send-confirm");
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
Hai Shaloma20dcd72022-02-04 13:43:00 -0800700#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800701
Hai Shaloma20dcd72022-02-04 13:43:00 -0800702
703#if defined(CONFIG_SAE) || defined(CONFIG_PASN)
704
705static int use_anti_clogging(struct hostapd_data *hapd)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800706{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800707 struct sta_info *sta;
708 unsigned int open = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800709
Hai Shaloma20dcd72022-02-04 13:43:00 -0800710 if (hapd->conf->anti_clogging_threshold == 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800711 return 1;
712
713 for (sta = hapd->sta_list; sta; sta = sta->next) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800714#ifdef CONFIG_SAE
715 if (sta->sae &&
716 (sta->sae->state == SAE_COMMITTED ||
717 sta->sae->state == SAE_CONFIRMED))
718 open++;
719#endif /* CONFIG_SAE */
720#ifdef CONFIG_PASN
721 if (sta->pasn && sta->pasn->ecdh)
722 open++;
723#endif /* CONFIG_PASN */
724 if (open >= hapd->conf->anti_clogging_threshold)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800725 return 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800726 }
727
Hai Shaloma20dcd72022-02-04 13:43:00 -0800728#ifdef CONFIG_SAE
Hai Shalom021b0b52019-04-10 11:17:58 -0700729 /* In addition to already existing open SAE sessions, check whether
730 * there are enough pending commit messages in the processing queue to
731 * potentially result in too many open sessions. */
732 if (open + dl_list_len(&hapd->sae_commit_queue) >=
Hai Shaloma20dcd72022-02-04 13:43:00 -0800733 hapd->conf->anti_clogging_threshold)
Hai Shalom021b0b52019-04-10 11:17:58 -0700734 return 1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800735#endif /* CONFIG_SAE */
Hai Shalom021b0b52019-04-10 11:17:58 -0700736
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800737 return 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800738}
739
740
Hai Shaloma20dcd72022-02-04 13:43:00 -0800741static int comeback_token_hash(struct hostapd_data *hapd, const u8 *addr,
742 u8 *idx)
Hai Shalom021b0b52019-04-10 11:17:58 -0700743{
744 u8 hash[SHA256_MAC_LEN];
745
Hai Shaloma20dcd72022-02-04 13:43:00 -0800746 if (hmac_sha256(hapd->comeback_key, sizeof(hapd->comeback_key),
Hai Shalomfdcde762020-04-02 11:19:20 -0700747 addr, ETH_ALEN, hash) < 0)
748 return -1;
749 *idx = hash[0];
750 return 0;
Hai Shalom021b0b52019-04-10 11:17:58 -0700751}
752
753
Hai Shaloma20dcd72022-02-04 13:43:00 -0800754static int check_comeback_token(struct hostapd_data *hapd, const u8 *addr,
755 const u8 *token, size_t token_len)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800756{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800757 u8 mac[SHA256_MAC_LEN];
Hai Shalom021b0b52019-04-10 11:17:58 -0700758 const u8 *addrs[2];
759 size_t len[2];
760 u16 token_idx;
761 u8 idx;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800762
Hai Shaloma20dcd72022-02-04 13:43:00 -0800763 if (token_len != SHA256_MAC_LEN ||
764 comeback_token_hash(hapd, addr, &idx) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800765 return -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800766 token_idx = hapd->comeback_pending_idx[idx];
Hai Shalom021b0b52019-04-10 11:17:58 -0700767 if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800768 wpa_printf(MSG_DEBUG,
769 "Comeback: Invalid anti-clogging token from "
Hai Shalom021b0b52019-04-10 11:17:58 -0700770 MACSTR " - token_idx 0x%04x, expected 0x%04x",
771 MAC2STR(addr), WPA_GET_BE16(token), token_idx);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800772 return -1;
Hai Shalom021b0b52019-04-10 11:17:58 -0700773 }
774
775 addrs[0] = addr;
776 len[0] = ETH_ALEN;
777 addrs[1] = token;
778 len[1] = 2;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800779 if (hmac_sha256_vector(hapd->comeback_key, sizeof(hapd->comeback_key),
Hai Shalom021b0b52019-04-10 11:17:58 -0700780 2, addrs, len, mac) < 0 ||
781 os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
782 return -1;
783
Hai Shaloma20dcd72022-02-04 13:43:00 -0800784 hapd->comeback_pending_idx[idx] = 0; /* invalidate used token */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800785
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800786 return 0;
787}
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800788
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800789
790static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
Hai Shalomfdcde762020-04-02 11:19:20 -0700791 int group, const u8 *addr, int h2e)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800792{
793 struct wpabuf *buf;
794 u8 *token;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800795 struct os_reltime now;
Hai Shalom021b0b52019-04-10 11:17:58 -0700796 u8 idx[2];
797 const u8 *addrs[2];
798 size_t len[2];
799 u8 p_idx;
800 u16 token_idx;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800801
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800802 os_get_reltime(&now);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800803 if (!os_reltime_initialized(&hapd->last_comeback_key_update) ||
804 os_reltime_expired(&now, &hapd->last_comeback_key_update, 60) ||
805 hapd->comeback_idx == 0xffff) {
806 if (random_get_bytes(hapd->comeback_key,
807 sizeof(hapd->comeback_key)) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800808 return NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800809 wpa_hexdump(MSG_DEBUG, "Comeback: Updated token key",
810 hapd->comeback_key, sizeof(hapd->comeback_key));
811 hapd->last_comeback_key_update = now;
812 hapd->comeback_idx = 0;
813 os_memset(hapd->comeback_pending_idx, 0,
814 sizeof(hapd->comeback_pending_idx));
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800815 }
816
Hai Shalomfdcde762020-04-02 11:19:20 -0700817 buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800818 if (buf == NULL)
819 return NULL;
820
Hai Shaloma20dcd72022-02-04 13:43:00 -0800821 if (group)
822 wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800823
Hai Shalomfdcde762020-04-02 11:19:20 -0700824 if (h2e) {
825 /* Encapsulate Anti-clogging Token field in a container IE */
826 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
827 wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
828 wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
829 }
830
Hai Shaloma20dcd72022-02-04 13:43:00 -0800831 if (comeback_token_hash(hapd, addr, &p_idx) < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700832 wpabuf_free(buf);
833 return NULL;
834 }
Hai Shaloma20dcd72022-02-04 13:43:00 -0800835
836 token_idx = hapd->comeback_pending_idx[p_idx];
Hai Shalom021b0b52019-04-10 11:17:58 -0700837 if (!token_idx) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800838 hapd->comeback_idx++;
839 token_idx = hapd->comeback_idx;
840 hapd->comeback_pending_idx[p_idx] = token_idx;
Hai Shalom021b0b52019-04-10 11:17:58 -0700841 }
842 WPA_PUT_BE16(idx, token_idx);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800843 token = wpabuf_put(buf, SHA256_MAC_LEN);
Hai Shalom021b0b52019-04-10 11:17:58 -0700844 addrs[0] = addr;
845 len[0] = ETH_ALEN;
846 addrs[1] = idx;
847 len[1] = sizeof(idx);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800848 if (hmac_sha256_vector(hapd->comeback_key, sizeof(hapd->comeback_key),
Hai Shalom021b0b52019-04-10 11:17:58 -0700849 2, addrs, len, token) < 0) {
850 wpabuf_free(buf);
851 return NULL;
852 }
853 WPA_PUT_BE16(token, token_idx);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800854
855 return buf;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800856}
857
Hai Shaloma20dcd72022-02-04 13:43:00 -0800858#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
859
860
861#ifdef CONFIG_SAE
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800862
Roshan Pius3a1667e2018-07-03 15:17:14 -0700863static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800864{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700865 if (sta->sae->sync > hapd->conf->sae_sync) {
866 sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800867 sta->sae->sync = 0;
868 return -1;
869 }
870 return 0;
871}
872
873
874static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
875{
876 struct hostapd_data *hapd = eloop_ctx;
877 struct sta_info *sta = eloop_data;
878 int ret;
879
Roshan Pius3a1667e2018-07-03 15:17:14 -0700880 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800881 return;
882 sta->sae->sync++;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700883 wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700884 " (sync=%d state=%s)",
885 MAC2STR(sta->addr), sta->sae->sync,
886 sae_state_txt(sta->sae->state));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800887
888 switch (sta->sae->state) {
889 case SAE_COMMITTED:
Hai Shalomc3565922019-10-28 11:58:20 -0700890 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800891 eloop_register_timeout(0,
892 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800893 auth_sae_retransmit_timer, hapd, sta);
894 break;
895 case SAE_CONFIRMED:
896 ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800897 eloop_register_timeout(0,
898 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800899 auth_sae_retransmit_timer, hapd, sta);
900 break;
901 default:
902 ret = -1;
903 break;
904 }
905
906 if (ret != WLAN_STATUS_SUCCESS)
907 wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
908}
909
910
911void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
912{
913 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
914}
915
916
917static void sae_set_retransmit_timer(struct hostapd_data *hapd,
918 struct sta_info *sta)
919{
920 if (!(hapd->conf->mesh & MESH_ENABLED))
921 return;
922
923 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800924 eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800925 auth_sae_retransmit_timer, hapd, sta);
926}
927
928
Hai Shalom5f92bc92019-04-18 11:54:11 -0700929static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
930 struct sta_info *sta, u16 status)
931{
932 struct external_auth params;
933
934 os_memset(&params, 0, sizeof(params));
935 params.status = status;
936 params.bssid = sta->addr;
Hai Shalom81f62d82019-07-22 12:10:00 -0700937 if (status == WLAN_STATUS_SUCCESS && sta->sae &&
938 !hapd->conf->disable_pmksa_caching)
Hai Shalom5f92bc92019-04-18 11:54:11 -0700939 params.pmkid = sta->sae->pmkid;
940
941 hostapd_drv_send_external_auth_status(hapd, &params);
942}
943
944
Dmitry Shmidte4663042016-04-04 10:07:49 -0700945void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
946{
Hai Shalom021b0b52019-04-10 11:17:58 -0700947#ifndef CONFIG_NO_VLAN
948 struct vlan_description vlan_desc;
949
950 if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
951 wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
952 " to VLAN ID %d",
953 MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
954
955 os_memset(&vlan_desc, 0, sizeof(vlan_desc));
956 vlan_desc.notempty = 1;
957 vlan_desc.untagged = sta->sae->tmp->vlan_id;
958 if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
959 wpa_printf(MSG_INFO,
960 "Invalid VLAN ID %d in sae_password",
961 sta->sae->tmp->vlan_id);
962 return;
963 }
964
965 if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
966 ap_sta_bind_vlan(hapd, sta) < 0) {
967 wpa_printf(MSG_INFO,
968 "Failed to assign VLAN ID %d from sae_password to "
969 MACSTR, sta->sae->tmp->vlan_id,
970 MAC2STR(sta->addr));
971 return;
972 }
973 }
974#endif /* CONFIG_NO_VLAN */
975
Dmitry Shmidte4663042016-04-04 10:07:49 -0700976 sta->flags |= WLAN_STA_AUTH;
977 sta->auth_alg = WLAN_AUTH_SAE;
978 mlme_authenticate_indication(hapd, sta);
979 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700980 sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
Hai Shalomfdcde762020-04-02 11:19:20 -0700981 crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
982 sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
983 sta->sae->peer_commit_scalar = NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -0700984 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
985 sta->sae->pmk, sta->sae->pmkid);
Hai Shalom5f92bc92019-04-18 11:54:11 -0700986 sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
Dmitry Shmidte4663042016-04-04 10:07:49 -0700987}
988
989
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800990static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700991 const u8 *bssid, u16 auth_transaction, u16 status_code,
992 int allow_reuse, int *sta_removed)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800993{
994 int ret;
995
Hai Shalom5f92bc92019-04-18 11:54:11 -0700996 *sta_removed = 0;
997
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800998 if (auth_transaction != 1 && auth_transaction != 2)
999 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1000
Roshan Pius3a1667e2018-07-03 15:17:14 -07001001 wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
1002 MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
1003 auth_transaction);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001004 switch (sta->sae->state) {
1005 case SAE_NOTHING:
1006 if (auth_transaction == 1) {
Hai Shalom899fcc72020-10-19 14:38:18 -07001007 if (sta->sae->tmp) {
1008 sta->sae->h2e =
1009 (status_code ==
1010 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1011 status_code == WLAN_STATUS_SAE_PK);
1012 sta->sae->pk =
1013 status_code == WLAN_STATUS_SAE_PK;
1014 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001015 ret = auth_sae_send_commit(hapd, sta, bssid,
Hai Shalomc3565922019-10-28 11:58:20 -07001016 !allow_reuse, status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001017 if (ret)
1018 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001019 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001020
1021 if (sae_process_commit(sta->sae) < 0)
1022 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1023
1024 /*
Hai Shalomc3565922019-10-28 11:58:20 -07001025 * In mesh case, both Commit and Confirm are sent
1026 * immediately. In infrastructure BSS, by default, only
1027 * a single Authentication frame (Commit) is expected
1028 * from the AP here and the second one (Confirm) will
1029 * be sent once the STA has sent its second
1030 * Authentication frame (Confirm). This behavior can be
1031 * overridden with explicit configuration so that the
1032 * infrastructure BSS case sends both frames together.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001033 */
Hai Shalomc3565922019-10-28 11:58:20 -07001034 if ((hapd->conf->mesh & MESH_ENABLED) ||
1035 hapd->conf->sae_confirm_immediate) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001036 /*
1037 * Send both Commit and Confirm immediately
1038 * based on SAE finite state machine
1039 * Nothing -> Confirm transition.
1040 */
1041 ret = auth_sae_send_confirm(hapd, sta, bssid);
1042 if (ret)
1043 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001044 sae_set_state(sta, SAE_CONFIRMED,
1045 "Sent Confirm (mesh)");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001046 } else {
1047 /*
1048 * For infrastructure BSS, send only the Commit
1049 * message now to get alternating sequence of
1050 * Authentication frames between the AP and STA.
1051 * Confirm will be sent in
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001052 * Committed -> Confirmed/Accepted transition
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001053 * when receiving Confirm from STA.
1054 */
1055 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001056 sta->sae->sync = 0;
1057 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001058 } else {
1059 hostapd_logger(hapd, sta->addr,
1060 HOSTAPD_MODULE_IEEE80211,
1061 HOSTAPD_LEVEL_DEBUG,
1062 "SAE confirm before commit");
1063 }
1064 break;
1065 case SAE_COMMITTED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001066 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001067 if (auth_transaction == 1) {
1068 if (sae_process_commit(sta->sae) < 0)
1069 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1070
1071 ret = auth_sae_send_confirm(hapd, sta, bssid);
1072 if (ret)
1073 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001074 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001075 sta->sae->sync = 0;
1076 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001077 } else if (hapd->conf->mesh & MESH_ENABLED) {
1078 /*
1079 * In mesh case, follow SAE finite state machine and
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001080 * send Commit now, if sync count allows.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001081 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001082 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001083 return WLAN_STATUS_SUCCESS;
1084 sta->sae->sync++;
1085
Hai Shalomc3565922019-10-28 11:58:20 -07001086 ret = auth_sae_send_commit(hapd, sta, bssid, 0,
1087 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001088 if (ret)
1089 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001090
1091 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001092 } else {
1093 /*
1094 * For instructure BSS, send the postponed Confirm from
1095 * Nothing -> Confirmed transition that was reduced to
1096 * Nothing -> Committed above.
1097 */
1098 ret = auth_sae_send_confirm(hapd, sta, bssid);
1099 if (ret)
1100 return ret;
1101
Roshan Pius3a1667e2018-07-03 15:17:14 -07001102 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001103
1104 /*
1105 * Since this was triggered on Confirm RX, run another
1106 * step to get to Accepted without waiting for
1107 * additional events.
1108 */
Hai Shalom021b0b52019-04-10 11:17:58 -07001109 return sae_sm_step(hapd, sta, bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001110 WLAN_STATUS_SUCCESS, 0, sta_removed);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001111 }
1112 break;
1113 case SAE_CONFIRMED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001114 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001115 if (auth_transaction == 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001116 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001117 return WLAN_STATUS_SUCCESS;
1118 sta->sae->sync++;
1119
Hai Shalomc3565922019-10-28 11:58:20 -07001120 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1121 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001122 if (ret)
1123 return ret;
1124
1125 if (sae_process_commit(sta->sae) < 0)
1126 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1127
1128 ret = auth_sae_send_confirm(hapd, sta, bssid);
1129 if (ret)
1130 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001131
1132 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001133 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001134 sta->sae->send_confirm = 0xffff;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001135 sae_accept_sta(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001136 }
1137 break;
1138 case SAE_ACCEPTED:
Roshan Pius3a1667e2018-07-03 15:17:14 -07001139 if (auth_transaction == 1 &&
1140 (hapd->conf->mesh & MESH_ENABLED)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001141 wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
1142 ") doing reauthentication",
1143 MAC2STR(sta->addr));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001144 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
Hai Shalom5f92bc92019-04-18 11:54:11 -07001145 ap_free_sta(hapd, sta);
1146 *sta_removed = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001147 } else if (auth_transaction == 1) {
1148 wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
Hai Shalomc3565922019-10-28 11:58:20 -07001149 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1150 status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001151 if (ret)
1152 return ret;
1153 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
1154
1155 if (sae_process_commit(sta->sae) < 0)
1156 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1157 sta->sae->sync = 0;
1158 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001159 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001160 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001161 return WLAN_STATUS_SUCCESS;
1162 sta->sae->sync++;
1163
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001164 ret = auth_sae_send_confirm(hapd, sta, bssid);
1165 sae_clear_temp_data(sta->sae);
1166 if (ret)
1167 return ret;
1168 }
1169 break;
1170 default:
1171 wpa_printf(MSG_ERROR, "SAE: invalid state %d",
1172 sta->sae->state);
1173 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1174 }
1175 return WLAN_STATUS_SUCCESS;
1176}
1177
1178
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001179static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
1180{
1181 struct sae_data *sae = sta->sae;
1182 int i, *groups = hapd->conf->sae_groups;
Hai Shalom021b0b52019-04-10 11:17:58 -07001183 int default_groups[] = { 19, 0 };
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001184
1185 if (sae->state != SAE_COMMITTED)
1186 return;
1187
1188 wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
1189
Hai Shalom021b0b52019-04-10 11:17:58 -07001190 if (!groups)
1191 groups = default_groups;
1192 for (i = 0; groups[i] > 0; i++) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001193 if (sae->group == groups[i])
1194 break;
1195 }
1196
Hai Shalom021b0b52019-04-10 11:17:58 -07001197 if (groups[i] <= 0) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001198 wpa_printf(MSG_DEBUG,
1199 "SAE: Previously selected group not found from the current configuration");
1200 return;
1201 }
1202
1203 for (;;) {
1204 i++;
1205 if (groups[i] <= 0) {
1206 wpa_printf(MSG_DEBUG,
1207 "SAE: No alternative group enabled");
1208 return;
1209 }
1210
1211 if (sae_set_group(sae, groups[i]) < 0)
1212 continue;
1213
1214 break;
1215 }
1216 wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
1217}
1218
1219
Hai Shalomc3565922019-10-28 11:58:20 -07001220static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
1221{
Hai Shalomfdcde762020-04-02 11:19:20 -07001222 int sae_pwe = hapd->conf->sae_pwe;
1223 int id_in_use;
Hai Shalom60840252021-02-19 19:02:11 -08001224 bool sae_pk = false;
Hai Shalomfdcde762020-04-02 11:19:20 -07001225
1226 id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
1227 if (id_in_use == 2 && sae_pwe != 3)
1228 sae_pwe = 1;
1229 else if (id_in_use == 1 && sae_pwe == 0)
1230 sae_pwe = 2;
Hai Shalom899fcc72020-10-19 14:38:18 -07001231#ifdef CONFIG_SAE_PK
Hai Shalom60840252021-02-19 19:02:11 -08001232 sae_pk = hostapd_sae_pk_in_use(hapd->conf);
1233 if (sae_pwe == 0 && sae_pk)
Hai Shalom899fcc72020-10-19 14:38:18 -07001234 sae_pwe = 2;
1235#endif /* CONFIG_SAE_PK */
Hai Shalomfdcde762020-04-02 11:19:20 -07001236
1237 return ((sae_pwe == 0 || sae_pwe == 3) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001238 status_code == WLAN_STATUS_SUCCESS) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07001239 (sae_pwe == 1 &&
Hai Shalom899fcc72020-10-19 14:38:18 -07001240 (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001241 (sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07001242 (sae_pwe == 2 &&
Hai Shalomc3565922019-10-28 11:58:20 -07001243 (status_code == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -07001244 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001245 (sae_pk && status_code == WLAN_STATUS_SAE_PK)));
Hai Shalomc3565922019-10-28 11:58:20 -07001246}
1247
1248
1249static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
1250{
1251 int *groups = hapd->conf->sae_groups;
1252 int default_groups[] = { 19, 0 };
1253 int i;
1254
1255 if (!groups)
1256 groups = default_groups;
1257
1258 for (i = 0; groups[i] > 0; i++) {
1259 if (groups[i] == group)
1260 return 1;
1261 }
1262
1263 return 0;
1264}
1265
1266
1267static int check_sae_rejected_groups(struct hostapd_data *hapd,
Hai Shalom899fcc72020-10-19 14:38:18 -07001268 struct sae_data *sae)
Hai Shalomc3565922019-10-28 11:58:20 -07001269{
Hai Shalom899fcc72020-10-19 14:38:18 -07001270 const struct wpabuf *groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001271 size_t i, count;
1272 const u8 *pos;
1273
Hai Shalom899fcc72020-10-19 14:38:18 -07001274 if (!sae->tmp)
1275 return 0;
1276 groups = sae->tmp->peer_rejected_groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001277 if (!groups)
1278 return 0;
1279
1280 pos = wpabuf_head(groups);
1281 count = wpabuf_len(groups) / 2;
1282 for (i = 0; i < count; i++) {
1283 int enabled;
1284 u16 group;
1285
1286 group = WPA_GET_LE16(pos);
1287 pos += 2;
1288 enabled = sae_is_group_enabled(hapd, group);
1289 wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
1290 group, enabled ? "enabled" : "disabled");
1291 if (enabled)
1292 return 1;
1293 }
1294
1295 return 0;
1296}
1297
1298
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001299static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
1300 const struct ieee80211_mgmt *mgmt, size_t len,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001301 u16 auth_transaction, u16 status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001302{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001303 int resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001304 struct wpabuf *data = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07001305 int *groups = hapd->conf->sae_groups;
1306 int default_groups[] = { 19, 0 };
1307 const u8 *pos, *end;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001308 int sta_removed = 0;
Hai Shalom60840252021-02-19 19:02:11 -08001309 bool success_status;
Hai Shalom021b0b52019-04-10 11:17:58 -07001310
1311 if (!groups)
1312 groups = default_groups;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001313
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001314#ifdef CONFIG_TESTING_OPTIONS
1315 if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001316 wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
1317 pos = mgmt->u.auth.variable;
1318 end = ((const u8 *) mgmt) + len;
Hai Shalom899fcc72020-10-19 14:38:18 -07001319 resp = status_code;
Hai Shalomfdcde762020-04-02 11:19:20 -07001320 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001321 auth_transaction, resp, pos, end - pos,
1322 "auth-sae-reflection-attack");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001323 goto remove_sta;
1324 }
1325
1326 if (hapd->conf->sae_commit_override && auth_transaction == 1) {
1327 wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
Hai Shalomfdcde762020-04-02 11:19:20 -07001328 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001329 auth_transaction, resp,
1330 wpabuf_head(hapd->conf->sae_commit_override),
Roshan Pius3a1667e2018-07-03 15:17:14 -07001331 wpabuf_len(hapd->conf->sae_commit_override),
1332 "sae-commit-override");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001333 goto remove_sta;
1334 }
1335#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001336 if (!sta->sae) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001337 if (auth_transaction != 1 ||
Hai Shalomc3565922019-10-28 11:58:20 -07001338 !sae_status_success(hapd, status_code)) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001339 wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
1340 status_code);
1341 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1342 goto reply;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001343 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001344 sta->sae = os_zalloc(sizeof(*sta->sae));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001345 if (!sta->sae) {
1346 resp = -1;
1347 goto remove_sta;
1348 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001349 sae_set_state(sta, SAE_NOTHING, "Init");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001350 sta->sae->sync = 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001351 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001352
Dmitry Shmidte4663042016-04-04 10:07:49 -07001353 if (sta->mesh_sae_pmksa_caching) {
1354 wpa_printf(MSG_DEBUG,
1355 "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
1356 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
1357 sta->mesh_sae_pmksa_caching = 0;
1358 }
1359
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001360 if (auth_transaction == 1) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001361 const u8 *token = NULL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001362 size_t token_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07001363 int allow_reuse = 0;
1364
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001365 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1366 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001367 "start SAE authentication (RX commit, status=%u (%s))",
1368 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001369
1370 if ((hapd->conf->mesh & MESH_ENABLED) &&
1371 status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
1372 sta->sae->tmp) {
1373 pos = mgmt->u.auth.variable;
1374 end = ((const u8 *) mgmt) + len;
1375 if (pos + sizeof(le16) > end) {
1376 wpa_printf(MSG_ERROR,
1377 "SAE: Too short anti-clogging token request");
1378 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1379 goto reply;
1380 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001381 resp = sae_group_allowed(sta->sae, groups,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001382 WPA_GET_LE16(pos));
1383 if (resp != WLAN_STATUS_SUCCESS) {
1384 wpa_printf(MSG_ERROR,
1385 "SAE: Invalid group in anti-clogging token request");
1386 goto reply;
1387 }
1388 pos += sizeof(le16);
1389
1390 wpabuf_free(sta->sae->tmp->anti_clogging_token);
1391 sta->sae->tmp->anti_clogging_token =
1392 wpabuf_alloc_copy(pos, end - pos);
1393 if (sta->sae->tmp->anti_clogging_token == NULL) {
1394 wpa_printf(MSG_ERROR,
1395 "SAE: Failed to alloc for anti-clogging token");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001396 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1397 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001398 }
1399
1400 /*
1401 * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code
1402 * is 76, a new Commit Message shall be constructed
1403 * with the Anti-Clogging Token from the received
1404 * Authentication frame, and the commit-scalar and
1405 * COMMIT-ELEMENT previously sent.
1406 */
Hai Shalomc3565922019-10-28 11:58:20 -07001407 resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
1408 status_code);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001409 if (resp != WLAN_STATUS_SUCCESS) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001410 wpa_printf(MSG_ERROR,
1411 "SAE: Failed to send commit message");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001412 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001413 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001414 sae_set_state(sta, SAE_COMMITTED,
1415 "Sent Commit (anti-clogging token case in mesh)");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001416 sta->sae->sync = 0;
1417 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001418 return;
1419 }
1420
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001421 if ((hapd->conf->mesh & MESH_ENABLED) &&
1422 status_code ==
1423 WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1424 sta->sae->tmp) {
1425 wpa_printf(MSG_DEBUG,
1426 "SAE: Peer did not accept our SAE group");
1427 sae_pick_next_group(hapd, sta);
1428 goto remove_sta;
1429 }
1430
Hai Shalomc3565922019-10-28 11:58:20 -07001431 if (!sae_status_success(hapd, status_code))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001432 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001433
Roshan Pius3a1667e2018-07-03 15:17:14 -07001434 if (!(hapd->conf->mesh & MESH_ENABLED) &&
1435 sta->sae->state == SAE_COMMITTED) {
1436 /* This is needed in the infrastructure BSS case to
1437 * address a sequence where a STA entry may remain in
1438 * hostapd across two attempts to do SAE authentication
1439 * by the same STA. The second attempt may end up trying
1440 * to use a different group and that would not be
1441 * allowed if we remain in Committed state with the
1442 * previously set parameters. */
Hai Shalom021b0b52019-04-10 11:17:58 -07001443 pos = mgmt->u.auth.variable;
1444 end = ((const u8 *) mgmt) + len;
1445 if (end - pos >= (int) sizeof(le16) &&
1446 sae_group_allowed(sta->sae, groups,
1447 WPA_GET_LE16(pos)) ==
1448 WLAN_STATUS_SUCCESS) {
1449 /* Do not waste resources deriving the same PWE
1450 * again since the same group is reused. */
1451 sae_set_state(sta, SAE_NOTHING,
1452 "Allow previous PWE to be reused");
1453 allow_reuse = 1;
1454 } else {
1455 sae_set_state(sta, SAE_NOTHING,
1456 "Clear existing state to allow restart");
1457 sae_clear_data(sta->sae);
1458 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001459 }
1460
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001461 resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
1462 ((const u8 *) mgmt) + len -
1463 mgmt->u.auth.variable, &token,
Hai Shalomc3565922019-10-28 11:58:20 -07001464 &token_len, groups, status_code ==
Hai Shalom899fcc72020-10-19 14:38:18 -07001465 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1466 status_code == WLAN_STATUS_SAE_PK);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001467 if (resp == SAE_SILENTLY_DISCARD) {
1468 wpa_printf(MSG_DEBUG,
1469 "SAE: Drop commit message from " MACSTR " due to reflection attack",
1470 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001471 goto remove_sta;
Dmitry Shmidt41712582015-06-29 11:02:15 -07001472 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001473
1474 if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
1475 wpa_msg(hapd->msg_ctx, MSG_INFO,
1476 WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
1477 MACSTR, MAC2STR(sta->addr));
1478 sae_clear_retransmit_timer(hapd, sta);
1479 sae_set_state(sta, SAE_NOTHING,
1480 "Unknown Password Identifier");
1481 goto remove_sta;
1482 }
1483
Hai Shaloma20dcd72022-02-04 13:43:00 -08001484 if (token &&
1485 check_comeback_token(hapd, sta->addr, token, token_len)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001486 < 0) {
1487 wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
1488 "incorrect token from " MACSTR,
1489 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001490 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1491 goto remove_sta;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001492 }
1493
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001494 if (resp != WLAN_STATUS_SUCCESS)
1495 goto reply;
1496
Hai Shalom899fcc72020-10-19 14:38:18 -07001497 if (check_sae_rejected_groups(hapd, sta->sae)) {
Hai Shalomc3565922019-10-28 11:58:20 -07001498 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001499 goto reply;
Hai Shalomc3565922019-10-28 11:58:20 -07001500 }
1501
Hai Shaloma20dcd72022-02-04 13:43:00 -08001502 if (!token && use_anti_clogging(hapd) && !allow_reuse) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001503 int h2e = 0;
1504
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001505 wpa_printf(MSG_DEBUG,
1506 "SAE: Request anti-clogging token from "
1507 MACSTR, MAC2STR(sta->addr));
Hai Shalomfdcde762020-04-02 11:19:20 -07001508 if (sta->sae->tmp)
Hai Shalom899fcc72020-10-19 14:38:18 -07001509 h2e = sta->sae->h2e;
1510 if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1511 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomfdcde762020-04-02 11:19:20 -07001512 h2e = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001513 data = auth_build_token_req(hapd, sta->sae->group,
Hai Shalomfdcde762020-04-02 11:19:20 -07001514 sta->addr, h2e);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001515 resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
1516 if (hapd->conf->mesh & MESH_ENABLED)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001517 sae_set_state(sta, SAE_NOTHING,
1518 "Request anti-clogging token case in mesh");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001519 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001520 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001521
Hai Shalom021b0b52019-04-10 11:17:58 -07001522 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001523 status_code, allow_reuse, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001524 } else if (auth_transaction == 2) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001525 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1526 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001527 "SAE authentication (RX confirm, status=%u (%s))",
1528 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001529 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001530 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001531 if (sta->sae->state >= SAE_CONFIRMED ||
1532 !(hapd->conf->mesh & MESH_ENABLED)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001533 const u8 *var;
1534 size_t var_len;
1535 u16 peer_send_confirm;
1536
1537 var = mgmt->u.auth.variable;
1538 var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable;
1539 if (var_len < 2) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001540 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001541 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001542 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001543
1544 peer_send_confirm = WPA_GET_LE16(var);
1545
1546 if (sta->sae->state == SAE_ACCEPTED &&
1547 (peer_send_confirm <= sta->sae->rc ||
1548 peer_send_confirm == 0xffff)) {
1549 wpa_printf(MSG_DEBUG,
1550 "SAE: Silently ignore unexpected Confirm from peer "
1551 MACSTR
1552 " (peer-send-confirm=%u Rc=%u)",
1553 MAC2STR(sta->addr),
1554 peer_send_confirm, sta->sae->rc);
1555 return;
1556 }
1557
1558 if (sae_check_confirm(sta->sae, var, var_len) < 0) {
1559 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1560 goto reply;
1561 }
1562 sta->sae->rc = peer_send_confirm;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001563 }
Hai Shalomc3565922019-10-28 11:58:20 -07001564 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
1565 status_code, 0, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001566 } else {
1567 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1568 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001569 "unexpected SAE authentication transaction %u (status=%u (%s))",
1570 auth_transaction, status_code,
1571 status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001572 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001573 goto remove_sta;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001574 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1575 }
1576
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001577reply:
Hai Shalom5f92bc92019-04-18 11:54:11 -07001578 if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001579 pos = mgmt->u.auth.variable;
1580 end = ((const u8 *) mgmt) + len;
1581
1582 /* Copy the Finite Cyclic Group field from the request if we
1583 * rejected it as unsupported group. */
1584 if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1585 !data && end - pos >= 2)
1586 data = wpabuf_alloc_copy(pos, 2);
1587
Hai Shalom5f92bc92019-04-18 11:54:11 -07001588 sae_sme_send_external_auth_status(hapd, sta, resp);
Hai Shalomfdcde762020-04-02 11:19:20 -07001589 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001590 auth_transaction, resp,
1591 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07001592 data ? wpabuf_len(data) : 0, "auth-sae");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001593 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001594
1595remove_sta:
Hai Shalom60840252021-02-19 19:02:11 -08001596 if (auth_transaction == 1)
1597 success_status = sae_status_success(hapd, status_code);
1598 else
1599 success_status = status_code == WLAN_STATUS_SUCCESS;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001600 if (!sta_removed && sta->added_unassoc &&
Hai Shalom60840252021-02-19 19:02:11 -08001601 (resp != WLAN_STATUS_SUCCESS || !success_status)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001602 hostapd_drv_sta_remove(hapd, sta->addr);
1603 sta->added_unassoc = 0;
1604 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001605 wpabuf_free(data);
1606}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001607
1608
1609/**
1610 * auth_sae_init_committed - Send COMMIT and start SAE in committed state
1611 * @hapd: BSS data for the device initiating the authentication
1612 * @sta: the peer to which commit authentication frame is sent
1613 *
1614 * This function implements Init event handling (IEEE Std 802.11-2012,
1615 * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
1616 * sta->sae structure should be initialized appropriately via a call to
1617 * sae_prepare_commit().
1618 */
1619int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
1620{
1621 int ret;
1622
1623 if (!sta->sae || !sta->sae->tmp)
1624 return -1;
1625
1626 if (sta->sae->state != SAE_NOTHING)
1627 return -1;
1628
Hai Shalomc3565922019-10-28 11:58:20 -07001629 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001630 if (ret)
1631 return -1;
1632
Roshan Pius3a1667e2018-07-03 15:17:14 -07001633 sae_set_state(sta, SAE_COMMITTED, "Init and sent commit");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001634 sta->sae->sync = 0;
1635 sae_set_retransmit_timer(hapd, sta);
1636
1637 return 0;
1638}
1639
Hai Shalom021b0b52019-04-10 11:17:58 -07001640
1641void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
1642{
1643 struct hostapd_data *hapd = eloop_ctx;
1644 struct hostapd_sae_commit_queue *q;
1645 unsigned int queue_len;
1646
1647 q = dl_list_first(&hapd->sae_commit_queue,
1648 struct hostapd_sae_commit_queue, list);
1649 if (!q)
1650 return;
1651 wpa_printf(MSG_DEBUG,
1652 "SAE: Process next available message from queue");
1653 dl_list_del(&q->list);
1654 handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
1655 q->rssi, 1);
1656 os_free(q);
1657
1658 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1659 return;
1660 queue_len = dl_list_len(&hapd->sae_commit_queue);
1661 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1662 hapd, NULL);
1663}
1664
1665
1666static void auth_sae_queue(struct hostapd_data *hapd,
1667 const struct ieee80211_mgmt *mgmt, size_t len,
1668 int rssi)
1669{
1670 struct hostapd_sae_commit_queue *q, *q2;
1671 unsigned int queue_len;
1672 const struct ieee80211_mgmt *mgmt2;
1673
1674 queue_len = dl_list_len(&hapd->sae_commit_queue);
1675 if (queue_len >= 15) {
1676 wpa_printf(MSG_DEBUG,
1677 "SAE: No more room in message queue - drop the new frame from "
1678 MACSTR, MAC2STR(mgmt->sa));
1679 return;
1680 }
1681
1682 wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
1683 MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
1684 queue_len);
1685 q = os_zalloc(sizeof(*q) + len);
1686 if (!q)
1687 return;
1688 q->rssi = rssi;
1689 q->len = len;
1690 os_memcpy(q->msg, mgmt, len);
1691
1692 /* Check whether there is already a queued Authentication frame from the
1693 * same station with the same transaction number and if so, replace that
1694 * queue entry with the new one. This avoids issues with a peer that
1695 * sends multiple times (e.g., due to frequent SAE retries). There is no
1696 * point in us trying to process the old attempts after a new one has
1697 * obsoleted them. */
1698 dl_list_for_each(q2, &hapd->sae_commit_queue,
1699 struct hostapd_sae_commit_queue, list) {
1700 mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
1701 if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 &&
1702 mgmt->u.auth.auth_transaction ==
1703 mgmt2->u.auth.auth_transaction) {
1704 wpa_printf(MSG_DEBUG,
1705 "SAE: Replace queued message from same STA with same transaction number");
1706 dl_list_add(&q2->list, &q->list);
1707 dl_list_del(&q2->list);
1708 os_free(q2);
1709 goto queued;
1710 }
1711 }
1712
1713 /* No pending identical entry, so add to the end of the queue */
1714 dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
1715
1716queued:
1717 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1718 return;
1719 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1720 hapd, NULL);
1721}
1722
1723
1724static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
1725{
1726 struct hostapd_sae_commit_queue *q;
1727 const struct ieee80211_mgmt *mgmt;
1728
1729 dl_list_for_each(q, &hapd->sae_commit_queue,
1730 struct hostapd_sae_commit_queue, list) {
1731 mgmt = (const struct ieee80211_mgmt *) q->msg;
1732 if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0)
1733 return 1;
1734 }
1735
1736 return 0;
1737}
1738
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001739#endif /* CONFIG_SAE */
1740
1741
Hai Shalomfdcde762020-04-02 11:19:20 -07001742static u16 wpa_res_to_status_code(enum wpa_validate_result res)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001743{
Hai Shalomfdcde762020-04-02 11:19:20 -07001744 switch (res) {
1745 case WPA_IE_OK:
1746 return WLAN_STATUS_SUCCESS;
1747 case WPA_INVALID_IE:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001748 return WLAN_STATUS_INVALID_IE;
Hai Shalomfdcde762020-04-02 11:19:20 -07001749 case WPA_INVALID_GROUP:
1750 return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
1751 case WPA_INVALID_PAIRWISE:
1752 return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
1753 case WPA_INVALID_AKMP:
1754 return WLAN_STATUS_AKMP_NOT_VALID;
1755 case WPA_NOT_ENABLED:
1756 return WLAN_STATUS_INVALID_IE;
1757 case WPA_ALLOC_FAIL:
1758 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1759 case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
1760 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
1761 case WPA_INVALID_MGMT_GROUP_CIPHER:
1762 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
1763 case WPA_INVALID_MDIE:
1764 return WLAN_STATUS_INVALID_MDIE;
1765 case WPA_INVALID_PROTO:
1766 return WLAN_STATUS_INVALID_IE;
1767 case WPA_INVALID_PMKID:
1768 return WLAN_STATUS_INVALID_PMKID;
1769 case WPA_DENIED_OTHER_REASON:
1770 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
1771 }
1772 return WLAN_STATUS_INVALID_IE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001773}
1774
1775
1776#ifdef CONFIG_FILS
1777
1778static void handle_auth_fils_finish(struct hostapd_data *hapd,
1779 struct sta_info *sta, u16 resp,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001780 struct wpabuf *data, int pub);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001781
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001782void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
1783 const u8 *pos, size_t len, u16 auth_alg,
1784 u16 auth_transaction, u16 status_code,
1785 void (*cb)(struct hostapd_data *hapd,
1786 struct sta_info *sta, u16 resp,
1787 struct wpabuf *data, int pub))
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001788{
1789 u16 resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001790 const u8 *end;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001791 struct ieee802_11_elems elems;
Hai Shalomfdcde762020-04-02 11:19:20 -07001792 enum wpa_validate_result res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001793 struct wpa_ie_data rsn;
1794 struct rsn_pmksa_cache_entry *pmksa = NULL;
1795
1796 if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
1797 return;
1798
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001799 end = pos + len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001800
1801 wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
1802 pos, end - pos);
1803
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001804 /* TODO: FILS PK */
1805#ifdef CONFIG_FILS_SK_PFS
1806 if (auth_alg == WLAN_AUTH_FILS_SK_PFS) {
1807 u16 group;
1808 struct wpabuf *pub;
1809 size_t elem_len;
1810
1811 /* Using FILS PFS */
1812
1813 /* Finite Cyclic Group */
1814 if (end - pos < 2) {
1815 wpa_printf(MSG_DEBUG,
1816 "FILS: No room for Finite Cyclic Group");
1817 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1818 goto fail;
1819 }
1820 group = WPA_GET_LE16(pos);
1821 pos += 2;
1822 if (group != hapd->conf->fils_dh_group) {
1823 wpa_printf(MSG_DEBUG,
1824 "FILS: Unsupported Finite Cyclic Group: %u (expected %u)",
1825 group, hapd->conf->fils_dh_group);
1826 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1827 goto fail;
1828 }
1829
1830 crypto_ecdh_deinit(sta->fils_ecdh);
1831 sta->fils_ecdh = crypto_ecdh_init(group);
1832 if (!sta->fils_ecdh) {
1833 wpa_printf(MSG_INFO,
1834 "FILS: Could not initialize ECDH with group %d",
1835 group);
1836 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1837 goto fail;
1838 }
1839
1840 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
1841 if (!pub) {
1842 wpa_printf(MSG_DEBUG,
1843 "FILS: Failed to derive ECDH public key");
1844 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1845 goto fail;
1846 }
1847 elem_len = wpabuf_len(pub);
1848 wpabuf_free(pub);
1849
1850 /* Element */
1851 if ((size_t) (end - pos) < elem_len) {
1852 wpa_printf(MSG_DEBUG, "FILS: No room for Element");
1853 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1854 goto fail;
1855 }
1856
1857 wpabuf_free(sta->fils_g_sta);
1858 sta->fils_g_sta = wpabuf_alloc_copy(pos, elem_len);
1859 wpabuf_clear_free(sta->fils_dh_ss);
1860 sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1,
1861 pos, elem_len);
1862 if (!sta->fils_dh_ss) {
1863 wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
1864 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1865 goto fail;
1866 }
1867 wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss);
1868 pos += elem_len;
1869 } else {
1870 crypto_ecdh_deinit(sta->fils_ecdh);
1871 sta->fils_ecdh = NULL;
1872 wpabuf_clear_free(sta->fils_dh_ss);
1873 sta->fils_dh_ss = NULL;
1874 }
1875#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001876
1877 wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
1878 if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
1879 wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
1880 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1881 goto fail;
1882 }
1883
1884 /* RSNE */
1885 wpa_hexdump(MSG_DEBUG, "FILS: RSN element",
1886 elems.rsn_ie, elems.rsn_ie_len);
1887 if (!elems.rsn_ie ||
1888 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
1889 &rsn) < 0) {
1890 wpa_printf(MSG_DEBUG, "FILS: No valid RSN element");
1891 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1892 goto fail;
1893 }
1894
1895 if (!sta->wpa_sm)
1896 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
1897 NULL);
1898 if (!sta->wpa_sm) {
1899 wpa_printf(MSG_DEBUG,
1900 "FILS: Failed to initialize RSN state machine");
1901 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1902 goto fail;
1903 }
1904
1905 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07001906 hapd->iface->freq,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001907 elems.rsn_ie - 2, elems.rsn_ie_len + 2,
Hai Shalomc3565922019-10-28 11:58:20 -07001908 elems.rsnxe ? elems.rsnxe - 2 : NULL,
1909 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001910 elems.mdie, elems.mdie_len, NULL, 0);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001911 resp = wpa_res_to_status_code(res);
1912 if (resp != WLAN_STATUS_SUCCESS)
1913 goto fail;
1914
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001915 if (!elems.fils_nonce) {
1916 wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
1917 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1918 goto fail;
1919 }
1920 wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce,
1921 FILS_NONCE_LEN);
1922 os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN);
1923
1924 /* PMKID List */
1925 if (rsn.pmkid && rsn.num_pmkid > 0) {
1926 u8 num;
1927 const u8 *pmkid;
1928
1929 wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
1930 rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
1931
1932 pmkid = rsn.pmkid;
1933 num = rsn.num_pmkid;
1934 while (num) {
1935 wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
1936 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
1937 pmkid);
1938 if (pmksa)
1939 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001940 pmksa = wpa_auth_pmksa_get_fils_cache_id(hapd->wpa_auth,
1941 sta->addr,
1942 pmkid);
1943 if (pmksa)
1944 break;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001945 pmkid += PMKID_LEN;
1946 num--;
1947 }
1948 }
1949 if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) {
1950 wpa_printf(MSG_DEBUG,
1951 "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore",
1952 wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp);
1953 pmksa = NULL;
1954 }
1955 if (pmksa)
1956 wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry");
1957
1958 /* FILS Session */
1959 if (!elems.fils_session) {
1960 wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
1961 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1962 goto fail;
1963 }
1964 wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
1965 FILS_SESSION_LEN);
1966 os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
1967
Hai Shalomfdcde762020-04-02 11:19:20 -07001968 /* Wrapped Data */
1969 if (elems.wrapped_data) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001970 wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
Hai Shalomfdcde762020-04-02 11:19:20 -07001971 elems.wrapped_data,
1972 elems.wrapped_data_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001973 if (!pmksa) {
1974#ifndef CONFIG_NO_RADIUS
1975 if (!sta->eapol_sm) {
1976 sta->eapol_sm =
1977 ieee802_1x_alloc_eapol_sm(hapd, sta);
1978 }
1979 wpa_printf(MSG_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001980 "FILS: Forward EAP-Initiate/Re-auth to authentication server");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001981 ieee802_1x_encapsulate_radius(
Hai Shalomfdcde762020-04-02 11:19:20 -07001982 hapd, sta, elems.wrapped_data,
1983 elems.wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001984 sta->fils_pending_cb = cb;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001985 wpa_printf(MSG_DEBUG,
1986 "FILS: Will send Authentication frame once the response from authentication server is available");
1987 sta->flags |= WLAN_STA_PENDING_FILS_ERP;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001988 /* Calculate pending PMKID here so that we do not need
1989 * to maintain a copy of the EAP-Initiate/Reauth
1990 * message. */
1991 if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
Hai Shalomfdcde762020-04-02 11:19:20 -07001992 elems.wrapped_data,
1993 elems.wrapped_data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001994 sta->fils_erp_pmkid) == 0)
1995 sta->fils_erp_pmkid_set = 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001996 return;
1997#else /* CONFIG_NO_RADIUS */
1998 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1999 goto fail;
2000#endif /* CONFIG_NO_RADIUS */
2001 }
2002 }
2003
2004fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002005 if (cb) {
2006 struct wpabuf *data;
2007 int pub = 0;
2008
2009 data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, NULL,
2010 NULL, 0, &pub);
2011 if (!data) {
2012 wpa_printf(MSG_DEBUG,
2013 "%s: prepare_auth_resp_fils() returned failure",
2014 __func__);
2015 }
2016
2017 cb(hapd, sta, resp, data, pub);
2018 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002019}
2020
2021
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002022static struct wpabuf *
2023prepare_auth_resp_fils(struct hostapd_data *hapd,
2024 struct sta_info *sta, u16 *resp,
2025 struct rsn_pmksa_cache_entry *pmksa,
2026 struct wpabuf *erp_resp,
2027 const u8 *msk, size_t msk_len,
2028 int *is_pub)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002029{
2030 u8 fils_nonce[FILS_NONCE_LEN];
2031 size_t ielen;
2032 struct wpabuf *data = NULL;
2033 const u8 *ie;
2034 u8 *ie_buf = NULL;
2035 const u8 *pmk = NULL;
2036 size_t pmk_len = 0;
Paul Stewart092955c2017-02-06 09:13:09 -08002037 u8 pmk_buf[PMK_LEN_MAX];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002038 struct wpabuf *pub = NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002039
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002040 if (*resp != WLAN_STATUS_SUCCESS)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002041 goto fail;
2042
2043 ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
2044 if (!ie) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002045 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002046 goto fail;
2047 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002048
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002049 if (pmksa) {
2050 /* Add PMKID of the selected PMKSA into RSNE */
2051 ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN);
2052 if (!ie_buf) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002053 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002054 goto fail;
2055 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002056
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002057 os_memcpy(ie_buf, ie, ielen);
2058 if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002059 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002060 goto fail;
2061 }
2062 ie = ie_buf;
2063 }
2064
2065 if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002066 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002067 goto fail;
2068 }
2069 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
2070 fils_nonce, FILS_NONCE_LEN);
2071
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002072#ifdef CONFIG_FILS_SK_PFS
2073 if (sta->fils_dh_ss && sta->fils_ecdh) {
2074 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
2075 if (!pub) {
2076 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2077 goto fail;
2078 }
2079 }
2080#endif /* CONFIG_FILS_SK_PFS */
2081
2082 data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0));
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002083 if (!data) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002084 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002085 goto fail;
2086 }
2087
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002088 /* TODO: FILS PK */
2089#ifdef CONFIG_FILS_SK_PFS
2090 if (pub) {
2091 /* Finite Cyclic Group */
2092 wpabuf_put_le16(data, hapd->conf->fils_dh_group);
2093
2094 /* Element */
2095 wpabuf_put_buf(data, pub);
2096 }
2097#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002098
2099 /* RSNE */
2100 wpabuf_put_data(data, ie, ielen);
2101
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002102 /* MDE when using FILS+FT (already included in ie,ielen with RSNE) */
2103
2104#ifdef CONFIG_IEEE80211R_AP
2105 if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
2106 /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
2107 int res;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002108 int use_sha384 = wpa_key_mgmt_sha384(
2109 wpa_auth_sta_key_mgmt(sta->wpa_sm));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002110
Roshan Pius3a1667e2018-07-03 15:17:14 -07002111 res = wpa_auth_write_fte(hapd->wpa_auth, use_sha384,
2112 wpabuf_put(data, 0),
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002113 wpabuf_tailroom(data));
2114 if (res < 0) {
2115 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2116 goto fail;
2117 }
2118 wpabuf_put(data, res);
2119 }
2120#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002121
2122 /* FILS Nonce */
2123 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2124 wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */
2125 /* Element ID Extension */
2126 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE);
2127 wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN);
2128
2129 /* FILS Session */
2130 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2131 wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */
2132 /* Element ID Extension */
2133 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
2134 wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
2135
Hai Shalomfdcde762020-04-02 11:19:20 -07002136 /* Wrapped Data */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002137 if (!pmksa && erp_resp) {
2138 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2139 wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
2140 /* Element ID Extension */
Hai Shalomfdcde762020-04-02 11:19:20 -07002141 wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002142 wpabuf_put_buf(data, erp_resp);
2143
Paul Stewart092955c2017-02-06 09:13:09 -08002144 if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
2145 msk, msk_len, sta->fils_snonce, fils_nonce,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002146 sta->fils_dh_ss ?
2147 wpabuf_head(sta->fils_dh_ss) : NULL,
2148 sta->fils_dh_ss ?
2149 wpabuf_len(sta->fils_dh_ss) : 0,
2150 pmk_buf, &pmk_len)) {
Paul Stewart092955c2017-02-06 09:13:09 -08002151 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002152 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Paul Stewart092955c2017-02-06 09:13:09 -08002153 wpabuf_free(data);
2154 data = NULL;
2155 goto fail;
2156 }
2157 pmk = pmk_buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002158
2159 /* Don't use DHss in PTK derivation if PMKSA caching is not
2160 * used. */
2161 wpabuf_clear_free(sta->fils_dh_ss);
2162 sta->fils_dh_ss = NULL;
2163
2164 if (sta->fils_erp_pmkid_set) {
2165 /* TODO: get PMKLifetime from WPA parameters */
2166 unsigned int dot11RSNAConfigPMKLifetime = 43200;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002167 int session_timeout;
2168
2169 session_timeout = dot11RSNAConfigPMKLifetime;
2170 if (sta->session_timeout_set) {
2171 struct os_reltime now, diff;
2172
2173 os_get_reltime(&now);
2174 os_reltime_sub(&sta->session_timeout, &now,
2175 &diff);
2176 session_timeout = diff.sec;
2177 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002178
2179 sta->fils_erp_pmkid_set = 0;
Hai Shalom81f62d82019-07-22 12:10:00 -07002180 wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
2181 sta->fils_erp_pmkid);
Hai Shalom021b0b52019-04-10 11:17:58 -07002182 if (!hapd->conf->disable_pmksa_caching &&
2183 wpa_auth_pmksa_add2(
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002184 hapd->wpa_auth, sta->addr,
2185 pmk, pmk_len,
2186 sta->fils_erp_pmkid,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002187 session_timeout,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002188 wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) {
2189 wpa_printf(MSG_ERROR,
2190 "FILS: Failed to add PMKSA cache entry based on ERP");
2191 }
2192 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002193 } else if (pmksa) {
2194 pmk = pmksa->pmk;
2195 pmk_len = pmksa->pmk_len;
2196 }
2197
2198 if (!pmk) {
2199 wpa_printf(MSG_DEBUG, "FILS: No PMK available");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002200 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002201 wpabuf_free(data);
2202 data = NULL;
2203 goto fail;
2204 }
2205
2206 if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002207 sta->fils_snonce, fils_nonce,
2208 sta->fils_dh_ss ?
2209 wpabuf_head(sta->fils_dh_ss) : NULL,
2210 sta->fils_dh_ss ?
2211 wpabuf_len(sta->fils_dh_ss) : 0,
2212 sta->fils_g_sta, pub) < 0) {
2213 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002214 wpabuf_free(data);
2215 data = NULL;
2216 goto fail;
2217 }
2218
2219fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002220 if (is_pub)
2221 *is_pub = pub != NULL;
2222 os_free(ie_buf);
2223 wpabuf_free(pub);
2224 wpabuf_clear_free(sta->fils_dh_ss);
2225 sta->fils_dh_ss = NULL;
2226#ifdef CONFIG_FILS_SK_PFS
2227 crypto_ecdh_deinit(sta->fils_ecdh);
2228 sta->fils_ecdh = NULL;
2229#endif /* CONFIG_FILS_SK_PFS */
2230 return data;
2231}
2232
2233
2234static void handle_auth_fils_finish(struct hostapd_data *hapd,
2235 struct sta_info *sta, u16 resp,
2236 struct wpabuf *data, int pub)
2237{
2238 u16 auth_alg;
2239
2240 auth_alg = (pub ||
2241 resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
2242 WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Hai Shalomfdcde762020-04-02 11:19:20 -07002243 send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002244 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07002245 data ? wpabuf_len(data) : 0, "auth-fils-finish");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002246 wpabuf_free(data);
2247
2248 if (resp == WLAN_STATUS_SUCCESS) {
2249 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2250 HOSTAPD_LEVEL_DEBUG,
2251 "authentication OK (FILS)");
2252 sta->flags |= WLAN_STA_AUTH;
2253 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002254 sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002255 mlme_authenticate_indication(hapd, sta);
2256 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002257}
2258
2259
2260void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
2261 struct sta_info *sta, int success,
2262 struct wpabuf *erp_resp,
2263 const u8 *msk, size_t msk_len)
2264{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002265 u16 resp;
Hai Shalom60840252021-02-19 19:02:11 -08002266 u32 flags = sta->flags;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002267
Hai Shalom60840252021-02-19 19:02:11 -08002268 sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
2269 WLAN_STA_PENDING_PASN_FILS_ERP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002270
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002271 resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
Hai Shalom60840252021-02-19 19:02:11 -08002272
2273 if (flags & WLAN_STA_PENDING_FILS_ERP) {
2274 struct wpabuf *data;
2275 int pub = 0;
2276
2277 if (!sta->fils_pending_cb)
2278 return;
2279
2280 data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
2281 msk, msk_len, &pub);
2282 if (!data) {
2283 wpa_printf(MSG_DEBUG,
2284 "%s: prepare_auth_resp_fils() failure",
2285 __func__);
2286 }
2287 sta->fils_pending_cb(hapd, sta, resp, data, pub);
2288#ifdef CONFIG_PASN
2289 } else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
2290 pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
2291 msk, msk_len);
2292#endif /* CONFIG_PASN */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002293 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002294}
2295
2296#endif /* CONFIG_FILS */
2297
2298
Hai Shalomfdcde762020-04-02 11:19:20 -07002299static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
2300 const u8 *msg, size_t len,
2301 struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002302{
2303 int res;
2304
Hai Shalomfdcde762020-04-02 11:19:20 -07002305 res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002306
2307 if (res == HOSTAPD_ACL_REJECT) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002308 wpa_printf(MSG_DEBUG, "Station " MACSTR
2309 " not allowed to authenticate",
2310 MAC2STR(addr));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002311 return HOSTAPD_ACL_REJECT;
2312 }
2313
2314 if (res == HOSTAPD_ACL_PENDING) {
2315 wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
2316 " waiting for an external authentication",
2317 MAC2STR(addr));
2318 /* Authentication code will re-send the authentication frame
2319 * after it has received (and cached) information from the
2320 * external source. */
2321 return HOSTAPD_ACL_PENDING;
2322 }
2323
2324 return res;
2325}
2326
2327
Sunil Ravia04bd252022-05-02 22:54:18 -07002328int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
2329 int res, struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002330{
Hai Shalomfdcde762020-04-02 11:19:20 -07002331 u32 session_timeout = info->session_timeout;
2332 u32 acct_interim_interval = info->acct_interim_interval;
2333 struct vlan_description *vlan_id = &info->vlan_id;
2334 struct hostapd_sta_wpa_psk_short *psk = info->psk;
2335 char *identity = info->identity;
2336 char *radius_cui = info->radius_cui;
2337
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002338 if (vlan_id->notempty &&
2339 !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
2340 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2341 HOSTAPD_LEVEL_INFO,
2342 "Invalid VLAN %d%s received from RADIUS server",
2343 vlan_id->untagged,
2344 vlan_id->tagged[0] ? "+" : "");
2345 return -1;
2346 }
2347 if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
2348 return -1;
2349 if (sta->vlan_id)
2350 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2351 HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
2352
2353 hostapd_free_psk_list(sta->psk);
Hai Shalomfdcde762020-04-02 11:19:20 -07002354 if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
2355 hostapd_copy_psk_list(&sta->psk, psk);
2356 else
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002357 sta->psk = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002358
Roshan Pius3a1667e2018-07-03 15:17:14 -07002359 os_free(sta->identity);
Hai Shalomfdcde762020-04-02 11:19:20 -07002360 if (identity)
2361 sta->identity = os_strdup(identity);
2362 else
2363 sta->identity = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002364
2365 os_free(sta->radius_cui);
Hai Shalomfdcde762020-04-02 11:19:20 -07002366 if (radius_cui)
2367 sta->radius_cui = os_strdup(radius_cui);
2368 else
2369 sta->radius_cui = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002370
2371 if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
2372 sta->acct_interim_interval = acct_interim_interval;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002373 if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
2374 sta->session_timeout_set = 1;
2375 os_get_reltime(&sta->session_timeout);
2376 sta->session_timeout.sec += session_timeout;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002377 ap_sta_session_timeout(hapd, sta, session_timeout);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002378 } else {
2379 sta->session_timeout_set = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002380 ap_sta_no_session_timeout(hapd, sta);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002381 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002382
2383 return 0;
2384}
2385
2386
Hai Shalom60840252021-02-19 19:02:11 -08002387#ifdef CONFIG_PASN
2388#ifdef CONFIG_SAE
2389
2390static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd,
2391 struct sta_info *sta,
2392 struct wpabuf *wd)
2393{
2394 struct pasn_data *pasn = sta->pasn;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002395 const char *password;
Hai Shalom60840252021-02-19 19:02:11 -08002396 const u8 *data;
2397 size_t buf_len;
2398 u16 res, alg, seq, status;
2399 int groups[] = { pasn->group, 0 };
Hai Shaloma20dcd72022-02-04 13:43:00 -08002400 struct sae_pt *pt = NULL;
Hai Shalom60840252021-02-19 19:02:11 -08002401 int ret;
2402
2403 if (!wd)
2404 return -1;
2405
2406 data = wpabuf_head_u8(wd);
2407 buf_len = wpabuf_len(wd);
2408
2409 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002410 wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002411 buf_len);
2412 return -1;
2413 }
2414
2415 alg = WPA_GET_LE16(data);
2416 seq = WPA_GET_LE16(data + 2);
2417 status = WPA_GET_LE16(data + 4);
2418
2419 wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u",
2420 alg, seq, status);
2421
Hai Shaloma20dcd72022-02-04 13:43:00 -08002422 if (alg != WLAN_AUTH_SAE || seq != 1 ||
2423 status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
Hai Shalom60840252021-02-19 19:02:11 -08002424 wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit");
2425 return -1;
2426 }
2427
2428 sae_clear_data(&pasn->sae);
2429 pasn->sae.state = SAE_NOTHING;
2430
2431 ret = sae_set_group(&pasn->sae, pasn->group);
2432 if (ret) {
2433 wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group");
2434 return -1;
2435 }
2436
Hai Shaloma20dcd72022-02-04 13:43:00 -08002437 password = sae_get_password(hapd, sta, NULL, NULL, &pt, NULL);
2438 if (!password || !pt) {
2439 wpa_printf(MSG_DEBUG, "PASN: No SAE PT found");
Hai Shalom60840252021-02-19 19:02:11 -08002440 return -1;
2441 }
2442
Hai Shaloma20dcd72022-02-04 13:43:00 -08002443 ret = sae_prepare_commit_pt(&pasn->sae, pt, hapd->own_addr, sta->addr,
2444 NULL, NULL);
Hai Shalom60840252021-02-19 19:02:11 -08002445 if (ret) {
2446 wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
2447 return -1;
2448 }
2449
2450 res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0,
2451 groups, 0);
2452 if (res != WLAN_STATUS_SUCCESS) {
2453 wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit");
2454 return -1;
2455 }
2456
2457 /* Process the commit message and derive the PMK */
2458 ret = sae_process_commit(&pasn->sae);
2459 if (ret) {
2460 wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
2461 return -1;
2462 }
2463
2464 pasn->sae.state = SAE_COMMITTED;
2465
2466 return 0;
2467}
2468
2469
2470static int pasn_wd_handle_sae_confirm(struct hostapd_data *hapd,
2471 struct sta_info *sta,
2472 struct wpabuf *wd)
2473{
2474 struct pasn_data *pasn = sta->pasn;
2475 const u8 *data;
2476 size_t buf_len;
2477 u16 res, alg, seq, status;
2478
2479 if (!wd)
2480 return -1;
2481
2482 data = wpabuf_head_u8(wd);
2483 buf_len = wpabuf_len(wd);
2484
2485 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002486 wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002487 buf_len);
2488 return -1;
2489 }
2490
2491 alg = WPA_GET_LE16(data);
2492 seq = WPA_GET_LE16(data + 2);
2493 status = WPA_GET_LE16(data + 4);
2494
2495 wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u",
2496 alg, seq, status);
2497
2498 if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) {
2499 wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm");
2500 return -1;
2501 }
2502
2503 res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6);
2504 if (res != WLAN_STATUS_SUCCESS) {
2505 wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm");
2506 return -1;
2507 }
2508
2509 pasn->sae.state = SAE_ACCEPTED;
2510
2511 /*
2512 * TODO: Based on on IEEE P802.11az/D2.6, the PMKSA derived with
2513 * PASN/SAE should only be allowed with future PASN only. For now do not
2514 * restrict this only for PASN.
2515 */
2516 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
2517 pasn->sae.pmk, pasn->sae.pmkid);
2518 return 0;
2519}
2520
2521
2522static struct wpabuf * pasn_get_sae_wd(struct hostapd_data *hapd,
2523 struct sta_info *sta)
2524{
2525 struct pasn_data *pasn = sta->pasn;
2526 struct wpabuf *buf = NULL;
2527 u8 *len_ptr;
2528 size_t len;
2529
2530 /* Need to add the entire Authentication frame body */
2531 buf = wpabuf_alloc(8 + SAE_COMMIT_MAX_LEN + 8 + SAE_CONFIRM_MAX_LEN);
2532 if (!buf) {
2533 wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
2534 return NULL;
2535 }
2536
2537 /* Need to add the entire authentication frame body for the commit */
2538 len_ptr = wpabuf_put(buf, 2);
2539 wpabuf_put_le16(buf, WLAN_AUTH_SAE);
2540 wpabuf_put_le16(buf, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002541 wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
Hai Shalom60840252021-02-19 19:02:11 -08002542
2543 /* Write the actual commit and update the length accordingly */
2544 sae_write_commit(&pasn->sae, buf, NULL, 0);
2545 len = wpabuf_len(buf);
2546 WPA_PUT_LE16(len_ptr, len - 2);
2547
2548 /* Need to add the entire Authentication frame body for the confirm */
2549 len_ptr = wpabuf_put(buf, 2);
2550 wpabuf_put_le16(buf, WLAN_AUTH_SAE);
2551 wpabuf_put_le16(buf, 2);
2552 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
2553
2554 sae_write_confirm(&pasn->sae, buf);
2555 WPA_PUT_LE16(len_ptr, wpabuf_len(buf) - len - 2);
2556
2557 pasn->sae.state = SAE_CONFIRMED;
2558
2559 return buf;
2560}
2561
2562#endif /* CONFIG_SAE */
2563
2564
2565#ifdef CONFIG_FILS
2566
2567static struct wpabuf * pasn_get_fils_wd(struct hostapd_data *hapd,
2568 struct sta_info *sta)
2569{
2570 struct pasn_data *pasn = sta->pasn;
2571 struct pasn_fils_data *fils = &pasn->fils;
2572 struct wpabuf *buf = NULL;
2573
2574 if (!fils->erp_resp) {
2575 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing erp_resp");
2576 return NULL;
2577 }
2578
2579 buf = wpabuf_alloc(1500);
2580 if (!buf)
2581 return NULL;
2582
2583 /* Add the authentication algorithm */
2584 wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
2585
2586 /* Authentication Transaction seq# */
2587 wpabuf_put_le16(buf, 2);
2588
2589 /* Status Code */
2590 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
2591
2592 /* Own RSNE */
2593 wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
2594
2595 /* FILS Nonce */
2596 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
2597 wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
2598 wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
2599 wpabuf_put_data(buf, fils->anonce, FILS_NONCE_LEN);
2600
2601 /* FILS Session */
2602 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
2603 wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
2604 wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
2605 wpabuf_put_data(buf, fils->session, FILS_SESSION_LEN);
2606
2607 /* Wrapped Data */
2608 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
2609 wpabuf_put_u8(buf, 1 + wpabuf_len(fils->erp_resp));
2610 wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
2611 wpabuf_put_buf(buf, fils->erp_resp);
2612
2613 return buf;
2614}
2615
2616
2617static void pasn_fils_auth_resp(struct hostapd_data *hapd,
2618 struct sta_info *sta, u16 status,
2619 struct wpabuf *erp_resp,
2620 const u8 *msk, size_t msk_len)
2621{
2622 struct pasn_data *pasn = sta->pasn;
2623 struct pasn_fils_data *fils = &pasn->fils;
2624 u8 pmk[PMK_LEN_MAX];
2625 size_t pmk_len;
2626 int ret;
2627
2628 wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
2629 status);
2630
2631 if (status != WLAN_STATUS_SUCCESS)
2632 goto fail;
2633
2634 if (!pasn->secret) {
2635 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
2636 goto fail;
2637 }
2638
2639 if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
2640 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
2641 goto fail;
2642 }
2643
2644 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
2645 fils->anonce, FILS_NONCE_LEN);
2646
2647 ret = fils_rmsk_to_pmk(pasn->akmp, msk, msk_len, fils->nonce,
2648 fils->anonce, NULL, 0, pmk, &pmk_len);
2649 if (ret) {
2650 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
2651 goto fail;
2652 }
2653
2654 ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
2655 wpabuf_head(pasn->secret),
2656 wpabuf_len(pasn->secret),
2657 &sta->pasn->ptk, sta->pasn->akmp,
Hai Shaloma20dcd72022-02-04 13:43:00 -08002658 sta->pasn->cipher, sta->pasn->kdk_len);
Hai Shalom60840252021-02-19 19:02:11 -08002659 if (ret) {
2660 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
2661 goto fail;
2662 }
2663
2664 wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
2665
2666 wpabuf_free(pasn->secret);
2667 pasn->secret = NULL;
2668
2669 fils->erp_resp = erp_resp;
2670 ret = handle_auth_pasn_resp(hapd, sta, NULL, WLAN_STATUS_SUCCESS);
2671 fils->erp_resp = NULL;
2672
2673 if (ret) {
2674 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
2675 goto fail;
2676 }
2677
2678 fils->state = PASN_FILS_STATE_COMPLETE;
2679 return;
2680fail:
2681 ap_free_sta(hapd, sta);
2682}
2683
2684
2685static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
2686 struct wpabuf *wd)
2687{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002688#ifdef CONFIG_NO_RADIUS
2689 wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
2690 return -1;
2691#else /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002692 struct pasn_data *pasn = sta->pasn;
2693 struct pasn_fils_data *fils = &pasn->fils;
2694 struct ieee802_11_elems elems;
2695 struct wpa_ie_data rsne_data;
2696 struct wpabuf *fils_wd;
2697 const u8 *data;
2698 size_t buf_len;
2699 u16 alg, seq, status;
2700 int ret;
2701
2702 if (fils->state != PASN_FILS_STATE_NONE) {
2703 wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
2704 return -1;
2705 }
2706
2707 if (!wd) {
2708 wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
2709 return -1;
2710 }
2711
2712 data = wpabuf_head_u8(wd);
2713 buf_len = wpabuf_len(wd);
2714
2715 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002716 wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002717 buf_len);
2718 return -1;
2719 }
2720
2721 alg = WPA_GET_LE16(data);
2722 seq = WPA_GET_LE16(data + 2);
2723 status = WPA_GET_LE16(data + 4);
2724
2725 wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
2726 alg, seq, status);
2727
2728 if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
2729 status != WLAN_STATUS_SUCCESS) {
2730 wpa_printf(MSG_DEBUG,
2731 "PASN: FILS: Dropping peer authentication");
2732 return -1;
2733 }
2734
2735 data += 6;
2736 buf_len -= 6;
2737
2738 if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
2739 wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
2740 return -1;
2741 }
2742
2743 if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
2744 !elems.wrapped_data) {
2745 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
2746 return -1;
2747 }
2748
2749 ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2750 &rsne_data);
2751 if (ret) {
2752 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RNSE");
2753 return -1;
2754 }
2755
2756 ret = wpa_pasn_validate_rsne(&rsne_data);
2757 if (ret) {
2758 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
2759 return -1;
2760 }
2761
2762 if (rsne_data.num_pmkid) {
2763 wpa_printf(MSG_DEBUG,
2764 "PASN: FILS: Not expecting PMKID in RSNE");
2765 return -1;
2766 }
2767
2768 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
2769 FILS_NONCE_LEN);
2770 os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
2771
2772 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
2773 FILS_SESSION_LEN);
2774 os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
2775
Hai Shalom60840252021-02-19 19:02:11 -08002776 fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
2777 WLAN_EID_EXT_WRAPPED_DATA);
2778
2779 if (!fils_wd) {
2780 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
2781 return -1;
2782 }
2783
2784 if (!sta->eapol_sm)
2785 sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
2786
2787 wpa_printf(MSG_DEBUG,
2788 "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
2789
2790 ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
2791 wpabuf_len(fils_wd));
2792
2793 sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
2794
2795 fils->state = PASN_FILS_STATE_PENDING_AS;
2796
2797 /*
2798 * Calculate pending PMKID here so that we do not need to maintain a
2799 * copy of the EAP-Initiate/Reautt message.
2800 */
2801 fils_pmkid_erp(pasn->akmp, wpabuf_head(fils_wd), wpabuf_len(fils_wd),
2802 fils->erp_pmkid);
2803
2804 wpabuf_free(fils_wd);
2805 return 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002806#endif /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002807}
2808
2809#endif /* CONFIG_FILS */
2810
2811
2812static struct wpabuf * pasn_get_wrapped_data(struct hostapd_data *hapd,
2813 struct sta_info *sta)
2814{
2815 switch (sta->pasn->akmp) {
2816 case WPA_KEY_MGMT_PASN:
2817 /* no wrapped data */
2818 return NULL;
2819 case WPA_KEY_MGMT_SAE:
2820#ifdef CONFIG_SAE
2821 return pasn_get_sae_wd(hapd, sta);
2822#else /* CONFIG_SAE */
2823 wpa_printf(MSG_ERROR,
2824 "PASN: SAE: Cannot derive wrapped data");
2825 return NULL;
2826#endif /* CONFIG_SAE */
2827 case WPA_KEY_MGMT_FILS_SHA256:
2828 case WPA_KEY_MGMT_FILS_SHA384:
2829#ifdef CONFIG_FILS
2830 return pasn_get_fils_wd(hapd, sta);
2831#endif /* CONFIG_FILS */
2832 /* fall through */
2833 case WPA_KEY_MGMT_FT_PSK:
2834 case WPA_KEY_MGMT_FT_IEEE8021X:
2835 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
2836 default:
2837 wpa_printf(MSG_ERROR,
2838 "PASN: TODO: Wrapped data for akmp=0x%x",
2839 sta->pasn->akmp);
2840 return NULL;
2841 }
2842}
2843
2844
2845static int
2846pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta,
2847 const u8 *cached_pmk, size_t cached_pmk_len,
2848 struct wpa_pasn_params_data *pasn_data,
2849 struct wpabuf *wrapped_data,
2850 struct wpabuf *secret)
2851{
2852 static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'};
2853 u8 pmk[PMK_LEN_MAX];
2854 u8 pmk_len;
2855 int ret;
2856
2857 os_memset(pmk, 0, sizeof(pmk));
2858 pmk_len = 0;
2859
2860 if (!cached_pmk || !cached_pmk_len)
2861 wpa_printf(MSG_DEBUG, "PASN: No valid PMKSA entry");
2862
2863 if (sta->pasn->akmp == WPA_KEY_MGMT_PASN) {
2864 wpa_printf(MSG_DEBUG, "PASN: Using default PMK");
2865
2866 pmk_len = WPA_PASN_PMK_LEN;
2867 os_memcpy(pmk, pasn_default_pmk, sizeof(pasn_default_pmk));
2868 } else if (cached_pmk && cached_pmk_len) {
2869 wpa_printf(MSG_DEBUG, "PASN: Using PMKSA entry");
2870
2871 pmk_len = cached_pmk_len;
2872 os_memcpy(pmk, cached_pmk, cached_pmk_len);
2873 } else {
2874 switch (sta->pasn->akmp) {
2875#ifdef CONFIG_SAE
2876 case WPA_KEY_MGMT_SAE:
2877 if (sta->pasn->sae.state == SAE_COMMITTED) {
2878 pmk_len = PMK_LEN;
2879 os_memcpy(pmk, sta->pasn->sae.pmk, PMK_LEN);
2880 break;
2881 }
2882#endif /* CONFIG_SAE */
2883 /* fall through */
2884 default:
2885 /* TODO: Derive PMK based on wrapped data */
2886 wpa_printf(MSG_DEBUG,
2887 "PASN: Missing PMK derivation");
2888 return -1;
2889 }
2890 }
2891
2892 ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
2893 wpabuf_head(secret), wpabuf_len(secret),
2894 &sta->pasn->ptk, sta->pasn->akmp,
Hai Shaloma20dcd72022-02-04 13:43:00 -08002895 sta->pasn->cipher, sta->pasn->kdk_len);
Hai Shalom60840252021-02-19 19:02:11 -08002896 if (ret) {
2897 wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
2898 return -1;
2899 }
2900
2901 wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
2902 return 0;
2903}
2904
2905
Hai Shaloma20dcd72022-02-04 13:43:00 -08002906static void handle_auth_pasn_comeback(struct hostapd_data *hapd,
2907 struct sta_info *sta, u16 group)
2908{
2909 struct wpabuf *buf, *comeback;
2910 int ret;
2911
2912 wpa_printf(MSG_DEBUG,
2913 "PASN: Building comeback frame 2. Comeback after=%u",
2914 hapd->conf->pasn_comeback_after);
2915
2916 buf = wpabuf_alloc(1500);
2917 if (!buf)
2918 return;
2919
2920 wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
2921 sta->addr, 2,
2922 WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY);
2923
2924 /*
2925 * Do not include the group as a part of the token since it is not going
2926 * to be used.
2927 */
2928 comeback = auth_build_token_req(hapd, 0, sta->addr, 0);
2929 if (!comeback) {
2930 wpa_printf(MSG_DEBUG,
2931 "PASN: Failed sending auth with comeback");
2932 wpabuf_free(buf);
2933 return;
2934 }
2935
2936 wpa_pasn_add_parameter_ie(buf, group,
2937 WPA_PASN_WRAPPED_DATA_NO,
2938 NULL, 0, comeback,
2939 hapd->conf->pasn_comeback_after);
2940 wpabuf_free(comeback);
2941
2942 wpa_printf(MSG_DEBUG,
2943 "PASN: comeback: STA=" MACSTR, MAC2STR(sta->addr));
2944
2945 ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
2946 NULL, 0, 0);
2947 if (ret)
2948 wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2");
2949
2950 wpabuf_free(buf);
2951}
2952
2953
Hai Shalom60840252021-02-19 19:02:11 -08002954static int handle_auth_pasn_resp(struct hostapd_data *hapd,
2955 struct sta_info *sta,
2956 struct rsn_pmksa_cache_entry *pmksa,
2957 u16 status)
2958{
2959 struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
2960 u8 mic[WPA_PASN_MAX_MIC_LEN];
Hai Shaloma20dcd72022-02-04 13:43:00 -08002961 u8 mic_len;
Hai Shalom60840252021-02-19 19:02:11 -08002962 u8 *ptr;
2963 const u8 *frame, *data, *rsn_ie, *rsnxe_ie;
2964 u8 *data_buf = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002965 size_t rsn_ie_len, frame_len, data_len;
Hai Shalom60840252021-02-19 19:02:11 -08002966 int ret;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002967 const u8 *pmkid = NULL;
Hai Shalom60840252021-02-19 19:02:11 -08002968
2969 wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status);
2970
2971 buf = wpabuf_alloc(1500);
2972 if (!buf)
2973 goto fail;
2974
2975 wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
2976 sta->addr, 2, status);
2977
2978 if (status != WLAN_STATUS_SUCCESS)
2979 goto done;
2980
Hai Shaloma20dcd72022-02-04 13:43:00 -08002981 if (pmksa) {
2982 pmkid = pmksa->pmkid;
2983#ifdef CONFIG_SAE
2984 } else if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
2985 wpa_printf(MSG_DEBUG, "PASN: Use SAE PMKID");
2986 pmkid = sta->pasn->sae.pmkid;
2987#endif /* CONFIG_SAE */
2988#ifdef CONFIG_FILS
2989 } else if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
2990 sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
2991 wpa_printf(MSG_DEBUG, "PASN: Use FILS ERP PMKID");
2992 pmkid = sta->pasn->fils.erp_pmkid;
2993#endif /* CONFIG_FILS */
2994 }
2995
2996 if (wpa_pasn_add_rsne(buf, pmkid,
Hai Shalom60840252021-02-19 19:02:11 -08002997 sta->pasn->akmp, sta->pasn->cipher) < 0)
2998 goto fail;
2999
3000 /* No need to derive PMK if PMKSA is given */
3001 if (!pmksa)
3002 wrapped_data_buf = pasn_get_wrapped_data(hapd, sta);
3003 else
3004 sta->pasn->wrapped_data_format = WPA_PASN_WRAPPED_DATA_NO;
3005
3006 /* Get public key */
3007 pubkey = crypto_ecdh_get_pubkey(sta->pasn->ecdh, 0);
3008 pubkey = wpabuf_zeropad(pubkey,
3009 crypto_ecdh_prime_len(sta->pasn->ecdh));
3010 if (!pubkey) {
3011 wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey");
3012 goto fail;
3013 }
3014
3015 wpa_pasn_add_parameter_ie(buf, sta->pasn->group,
3016 sta->pasn->wrapped_data_format,
Hai Shaloma20dcd72022-02-04 13:43:00 -08003017 pubkey, true, NULL, 0);
Hai Shalom60840252021-02-19 19:02:11 -08003018
3019 if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
3020 goto fail;
3021
3022 wpabuf_free(wrapped_data_buf);
3023 wrapped_data_buf = NULL;
3024 wpabuf_free(pubkey);
3025 pubkey = NULL;
3026
3027 /* Add RSNXE if needed */
3028 rsnxe_ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
3029 if (rsnxe_ie)
3030 wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
3031
3032 /* Add the mic */
3033 mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
3034 wpabuf_put_u8(buf, WLAN_EID_MIC);
3035 wpabuf_put_u8(buf, mic_len);
3036 ptr = wpabuf_put(buf, mic_len);
3037
3038 os_memset(ptr, 0, mic_len);
3039
3040 frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
3041 frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
3042
3043 rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &rsn_ie_len);
3044 if (!rsn_ie || !rsn_ie_len)
3045 goto fail;
3046
3047 /*
3048 * Note: wpa_auth_get_wpa_ie() might return not only the RSNE but also
3049 * MDE, etc. Thus, do not use the returned length but instead use the
3050 * length specified in the IE header.
3051 */
3052 data_len = rsn_ie[1] + 2;
3053 if (rsnxe_ie) {
3054 data_buf = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2);
3055 if (!data_buf)
3056 goto fail;
3057
3058 os_memcpy(data_buf, rsn_ie, rsn_ie[1] + 2);
3059 os_memcpy(data_buf + rsn_ie[1] + 2, rsnxe_ie, rsnxe_ie[1] + 2);
3060 data_len += rsnxe_ie[1] + 2;
3061 data = data_buf;
3062 } else {
3063 data = rsn_ie;
3064 }
3065
3066 ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
3067 hapd->own_addr, sta->addr, data, data_len,
3068 frame, frame_len, mic);
3069 os_free(data_buf);
3070 if (ret) {
3071 wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation");
3072 goto fail;
3073 }
3074
Hai Shaloma20dcd72022-02-04 13:43:00 -08003075#ifdef CONFIG_TESTING_OPTIONS
3076 if (hapd->conf->pasn_corrupt_mic) {
3077 wpa_printf(MSG_DEBUG, "PASN: frame 2: Corrupt MIC");
3078 mic[0] = ~mic[0];
3079 }
3080#endif /* CONFIG_TESTING_OPTIONS */
3081
Hai Shalom60840252021-02-19 19:02:11 -08003082 os_memcpy(ptr, mic, mic_len);
3083
3084done:
3085 wpa_printf(MSG_DEBUG,
3086 "PASN: Building frame 2: success; resp STA=" MACSTR,
3087 MAC2STR(sta->addr));
3088
3089 ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
3090 NULL, 0, 0);
3091 if (ret)
3092 wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
3093
3094 wpabuf_free(buf);
3095 return ret;
3096fail:
3097 wpabuf_free(wrapped_data_buf);
3098 wpabuf_free(pubkey);
3099 wpabuf_free(buf);
3100 return -1;
3101}
3102
3103
3104static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
3105 const struct ieee80211_mgmt *mgmt, size_t len)
3106{
3107 struct ieee802_11_elems elems;
3108 struct wpa_ie_data rsn_data;
3109 struct wpa_pasn_params_data pasn_params;
3110 struct rsn_pmksa_cache_entry *pmksa = NULL;
3111 const u8 *cached_pmk = NULL;
3112 size_t cached_pmk_len = 0;
3113#ifdef CONFIG_IEEE80211R_AP
3114 u8 pmk_r1[PMK_LEN_MAX];
3115 size_t pmk_r1_len;
3116#endif /* CONFIG_IEEE80211R_AP */
3117 struct wpabuf *wrapped_data = NULL, *secret = NULL;
3118 const int *groups = hapd->conf->pasn_groups;
3119 static const int default_groups[] = { 19, 0 };
3120 u16 status = WLAN_STATUS_SUCCESS;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003121 int ret, inc_y;
Hai Shalom60840252021-02-19 19:02:11 -08003122 bool derive_keys;
3123 u32 i;
Sunil Ravia04bd252022-05-02 22:54:18 -07003124 bool derive_kdk;
Hai Shalom60840252021-02-19 19:02:11 -08003125
3126 if (!groups)
3127 groups = default_groups;
3128
3129 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
3130 len - offsetof(struct ieee80211_mgmt,
3131 u.auth.variable),
3132 &elems, 0) == ParseFailed) {
3133 wpa_printf(MSG_DEBUG,
3134 "PASN: Failed parsing Authentication frame");
3135 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3136 goto send_resp;
3137 }
3138
3139 ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
3140 &rsn_data);
3141 if (ret) {
3142 wpa_printf(MSG_DEBUG, "PASN: Failed parsing RNSE");
3143 status = WLAN_STATUS_INVALID_RSNIE;
3144 goto send_resp;
3145 }
3146
3147 ret = wpa_pasn_validate_rsne(&rsn_data);
3148 if (ret) {
3149 wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
3150 status = WLAN_STATUS_INVALID_RSNIE;
3151 goto send_resp;
3152 }
3153
3154 if (!(rsn_data.key_mgmt & hapd->conf->wpa_key_mgmt) ||
3155 !(rsn_data.pairwise_cipher & hapd->conf->rsn_pairwise)) {
3156 wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
3157 status = WLAN_STATUS_INVALID_RSNIE;
3158 goto send_resp;
3159 }
3160
3161 sta->pasn->akmp = rsn_data.key_mgmt;
3162 sta->pasn->cipher = rsn_data.pairwise_cipher;
3163
Sunil Ravia04bd252022-05-02 22:54:18 -07003164 derive_kdk = (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) &&
3165 ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
3166 WLAN_RSNX_CAPAB_SECURE_LTF);
3167#ifdef CONFIG_TESTING_OPTIONS
3168 if (!derive_kdk)
3169 derive_kdk = hapd->conf->force_kdk_derivation;
3170#endif /* CONFIG_TESTING_OPTIONS */
3171 if (derive_kdk)
Hai Shaloma20dcd72022-02-04 13:43:00 -08003172 sta->pasn->kdk_len = WPA_KDK_MAX_LEN;
3173 else
3174 sta->pasn->kdk_len = 0;
3175 wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", sta->pasn->kdk_len);
3176
Hai Shalom60840252021-02-19 19:02:11 -08003177 if (!elems.pasn_params || !elems.pasn_params_len) {
3178 wpa_printf(MSG_DEBUG,
3179 "PASN: No PASN Parameters element found");
3180 status = WLAN_STATUS_INVALID_PARAMETERS;
3181 goto send_resp;
3182 }
3183
3184 ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
3185 elems.pasn_params_len + 3,
3186 false, &pasn_params);
3187 if (ret) {
3188 wpa_printf(MSG_DEBUG,
3189 "PASN: Failed validation of PASN Parameters IE");
3190 status = WLAN_STATUS_INVALID_PARAMETERS;
3191 goto send_resp;
3192 }
3193
3194 for (i = 0; groups[i] > 0 && groups[i] != pasn_params.group; i++)
3195 ;
3196
3197 if (!pasn_params.group || groups[i] != pasn_params.group) {
3198 wpa_printf(MSG_DEBUG, "PASN: Requested group=%hu not allowed",
3199 pasn_params.group);
3200 status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3201 goto send_resp;
3202 }
3203
3204 if (!pasn_params.pubkey || !pasn_params.pubkey_len) {
3205 wpa_printf(MSG_DEBUG, "PASN: Invalid public key");
3206 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3207 goto send_resp;
3208 }
3209
Hai Shaloma20dcd72022-02-04 13:43:00 -08003210 if (pasn_params.comeback) {
3211 wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token");
3212
3213 ret = check_comeback_token(hapd, sta->addr,
3214 pasn_params.comeback,
3215 pasn_params.comeback_len);
3216
3217 if (ret) {
3218 wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token");
3219 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3220 goto send_resp;
3221 }
3222 } else if (use_anti_clogging(hapd)) {
3223 wpa_printf(MSG_DEBUG, "PASN: Respond with comeback");
3224 handle_auth_pasn_comeback(hapd, sta, pasn_params.group);
3225 ap_free_sta(hapd, sta);
3226 return;
3227 }
3228
Hai Shalom60840252021-02-19 19:02:11 -08003229 sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group);
3230 if (!sta->pasn->ecdh) {
3231 wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
3232 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3233 goto send_resp;
3234 }
3235
3236 sta->pasn->group = pasn_params.group;
3237
Hai Shaloma20dcd72022-02-04 13:43:00 -08003238 if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) {
3239 inc_y = 1;
3240 } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 ||
3241 pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) {
3242 inc_y = 0;
3243 } else {
3244 wpa_printf(MSG_DEBUG,
3245 "PASN: Invalid first octet in pubkey=0x%x",
3246 pasn_params.pubkey[0]);
3247 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3248 goto send_resp;
3249 }
3250
3251 secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, inc_y,
3252 pasn_params.pubkey + 1,
3253 pasn_params.pubkey_len - 1);
Hai Shalom60840252021-02-19 19:02:11 -08003254 if (!secret) {
3255 wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
3256 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3257 goto send_resp;
3258 }
3259
3260 derive_keys = true;
3261 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
3262 wrapped_data = ieee802_11_defrag(&elems,
3263 WLAN_EID_EXTENSION,
3264 WLAN_EID_EXT_WRAPPED_DATA);
3265 if (!wrapped_data) {
3266 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
3267 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3268 goto send_resp;
3269 }
3270
3271#ifdef CONFIG_SAE
3272 if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
3273 ret = pasn_wd_handle_sae_commit(hapd, sta,
3274 wrapped_data);
3275 if (ret) {
3276 wpa_printf(MSG_DEBUG,
3277 "PASN: Failed processing SAE commit");
3278 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3279 goto send_resp;
3280 }
3281 }
3282#endif /* CONFIG_SAE */
3283#ifdef CONFIG_FILS
3284 if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
3285 sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
3286 ret = pasn_wd_handle_fils(hapd, sta, wrapped_data);
3287 if (ret) {
3288 wpa_printf(MSG_DEBUG,
3289 "PASN: Failed processing FILS wrapped data");
3290 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3291 goto send_resp;
3292 }
3293
3294 wpa_printf(MSG_DEBUG,
3295 "PASN: FILS: Pending AS response");
3296
3297 /*
3298 * With PASN/FILS, keys can be derived only after a
3299 * response from the AS is processed.
3300 */
3301 derive_keys = false;
3302 }
3303#endif /* CONFIG_FILS */
3304 }
3305
3306 sta->pasn->wrapped_data_format = pasn_params.wrapped_data_format;
3307
3308 ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
3309 ((const u8 *) mgmt) + IEEE80211_HDRLEN,
3310 len - IEEE80211_HDRLEN, sta->pasn->hash);
3311 if (ret) {
3312 wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
3313 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3314 goto send_resp;
3315 }
3316
3317 if (!derive_keys) {
3318 wpa_printf(MSG_DEBUG, "PASN: Storing secret");
3319 sta->pasn->secret = secret;
3320 wpabuf_free(wrapped_data);
3321 return;
3322 }
3323
3324 if (rsn_data.num_pmkid) {
3325 if (wpa_key_mgmt_ft(sta->pasn->akmp)) {
3326#ifdef CONFIG_IEEE80211R_AP
3327 wpa_printf(MSG_DEBUG, "PASN: FT: Fetch PMK-R1");
3328
3329 ret = wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
3330 rsn_data.pmkid,
3331 pmk_r1, &pmk_r1_len, NULL,
3332 NULL, NULL, NULL,
3333 NULL, NULL, NULL);
3334 if (ret) {
3335 wpa_printf(MSG_DEBUG,
3336 "PASN: FT: Failed getting PMK-R1");
3337 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3338 goto send_resp;
3339 }
3340 cached_pmk = pmk_r1;
3341 cached_pmk_len = pmk_r1_len;
3342#else /* CONFIG_IEEE80211R_AP */
3343 wpa_printf(MSG_DEBUG, "PASN: FT: Not supported");
3344 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3345 goto send_resp;
3346#endif /* CONFIG_IEEE80211R_AP */
3347 } else {
3348 wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry");
3349
3350 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
3351 rsn_data.pmkid);
3352 if (pmksa) {
3353 cached_pmk = pmksa->pmk;
3354 cached_pmk_len = pmksa->pmk_len;
3355 }
3356 }
3357 } else {
3358 wpa_printf(MSG_DEBUG, "PASN: No PMKID specified");
3359 }
3360
3361 ret = pasn_derive_keys(hapd, sta, cached_pmk, cached_pmk_len,
3362 &pasn_params, wrapped_data, secret);
3363 if (ret) {
3364 wpa_printf(MSG_DEBUG, "PASN: Failed to derive keys");
3365 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3366 goto send_resp;
3367 }
3368
3369 ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
3370 ((const u8 *) mgmt) + IEEE80211_HDRLEN,
3371 len - IEEE80211_HDRLEN, sta->pasn->hash);
3372 if (ret) {
3373 wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
3374 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3375 }
3376
3377send_resp:
3378 ret = handle_auth_pasn_resp(hapd, sta, pmksa, status);
3379 if (ret) {
3380 wpa_printf(MSG_DEBUG, "PASN: Failed to send response");
3381 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3382 } else {
3383 wpa_printf(MSG_DEBUG,
3384 "PASN: Success handling transaction == 1");
3385 }
3386
3387 wpabuf_free(secret);
3388 wpabuf_free(wrapped_data);
3389
3390 if (status != WLAN_STATUS_SUCCESS)
3391 ap_free_sta(hapd, sta);
3392}
3393
3394
3395static void handle_auth_pasn_3(struct hostapd_data *hapd, struct sta_info *sta,
3396 const struct ieee80211_mgmt *mgmt, size_t len)
3397{
3398 struct ieee802_11_elems elems;
3399 struct wpa_pasn_params_data pasn_params;
3400 struct wpabuf *wrapped_data = NULL;
3401 u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
3402 u8 mic_len;
3403 int ret;
3404
3405 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
3406 len - offsetof(struct ieee80211_mgmt,
3407 u.auth.variable),
3408 &elems, 0) == ParseFailed) {
3409 wpa_printf(MSG_DEBUG,
3410 "PASN: Failed parsing Authentication frame");
3411 goto fail;
3412 }
3413
3414 /* Check that the MIC IE exists. Save it and zero out the memory. */
3415 mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
3416 if (!elems.mic || elems.mic_len != mic_len) {
3417 wpa_printf(MSG_DEBUG,
3418 "PASN: Invalid MIC. Expecting len=%u", mic_len);
3419 goto fail;
3420 } else {
3421 os_memcpy(mic, elems.mic, mic_len);
3422 /* TODO: Clean this up.. Should not modify received frame
3423 * buffer. */
3424 os_memset((u8 *) elems.mic, 0, mic_len);
3425 }
3426
3427 if (!elems.pasn_params || !elems.pasn_params_len) {
3428 wpa_printf(MSG_DEBUG,
3429 "PASN: No PASN Parameters element found");
3430 goto fail;
3431 }
3432
3433 ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
3434 elems.pasn_params_len + 3,
3435 false, &pasn_params);
3436 if (ret) {
3437 wpa_printf(MSG_DEBUG,
3438 "PASN: Failed validation of PASN Parameters IE");
3439 goto fail;
3440 }
3441
3442 if (pasn_params.pubkey || pasn_params.pubkey_len) {
3443 wpa_printf(MSG_DEBUG,
3444 "PASN: Public key should not be included");
3445 goto fail;
3446 }
3447
3448 /* Verify the MIC */
3449 ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
3450 sta->addr, hapd->own_addr,
3451 sta->pasn->hash, mic_len * 2,
3452 (u8 *) &mgmt->u.auth,
3453 len - offsetof(struct ieee80211_mgmt, u.auth),
3454 out_mic);
3455
3456 wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len);
3457 if (ret || os_memcmp(mic, out_mic, mic_len) != 0) {
3458 wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification");
3459 goto fail;
3460 }
3461
3462 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
3463 wrapped_data = ieee802_11_defrag(&elems,
3464 WLAN_EID_EXTENSION,
3465 WLAN_EID_EXT_WRAPPED_DATA);
3466
3467 if (!wrapped_data) {
3468 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
3469 goto fail;
3470 }
3471
3472#ifdef CONFIG_SAE
3473 if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
3474 ret = pasn_wd_handle_sae_confirm(hapd, sta,
3475 wrapped_data);
3476 if (ret) {
3477 wpa_printf(MSG_DEBUG,
3478 "PASN: Failed processing SAE confirm");
3479 wpabuf_free(wrapped_data);
3480 goto fail;
3481 }
3482 }
3483#endif /* CONFIG_SAE */
3484#ifdef CONFIG_FILS
3485 if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
3486 sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
3487 if (wrapped_data) {
3488 wpa_printf(MSG_DEBUG,
3489 "PASN: FILS: Ignore wrapped data");
3490 }
3491 }
3492#endif /* CONFIG_FILS */
3493 wpabuf_free(wrapped_data);
3494 }
3495
3496 wpa_printf(MSG_INFO,
3497 "PASN: Success handling transaction == 3. Store PTK");
3498
3499 ptksa_cache_add(hapd->ptksa, sta->addr, sta->pasn->cipher, 43200,
3500 &sta->pasn->ptk);
3501fail:
3502 ap_free_sta(hapd, sta);
3503}
3504
3505
3506static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
3507 const struct ieee80211_mgmt *mgmt, size_t len,
3508 u16 trans_seq, u16 status)
3509{
3510 if (hapd->conf->wpa != WPA_PROTO_RSN) {
3511 wpa_printf(MSG_INFO, "PASN: RSN is not configured");
3512 return;
3513 }
3514
3515 wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR,
3516 MAC2STR(sta->addr));
3517
3518 if (trans_seq == 1) {
3519 if (sta->pasn) {
3520 wpa_printf(MSG_DEBUG,
3521 "PASN: Not expecting transaction == 1");
3522 return;
3523 }
3524
3525 if (status != WLAN_STATUS_SUCCESS) {
3526 wpa_printf(MSG_DEBUG,
3527 "PASN: Failure status in transaction == 1");
3528 return;
3529 }
3530
3531 sta->pasn = os_zalloc(sizeof(*sta->pasn));
3532 if (!sta->pasn) {
3533 wpa_printf(MSG_DEBUG,
3534 "PASN: Failed to allocate PASN context");
3535 return;
3536 }
3537
3538 handle_auth_pasn_1(hapd, sta, mgmt, len);
3539 } else if (trans_seq == 3) {
3540 if (!sta->pasn) {
3541 wpa_printf(MSG_DEBUG,
3542 "PASN: Not expecting transaction == 3");
3543 return;
3544 }
3545
3546 if (status != WLAN_STATUS_SUCCESS) {
3547 wpa_printf(MSG_DEBUG,
3548 "PASN: Failure status in transaction == 3");
3549 ap_free_sta_pasn(hapd, sta);
3550 return;
3551 }
3552
3553 handle_auth_pasn_3(hapd, sta, mgmt, len);
3554 } else {
3555 wpa_printf(MSG_DEBUG,
3556 "PASN: Invalid transaction %u - ignore", trans_seq);
3557 }
3558}
3559
3560#endif /* CONFIG_PASN */
3561
3562
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003563static void handle_auth(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08003564 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom021b0b52019-04-10 11:17:58 -07003565 int rssi, int from_queue)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003566{
3567 u16 auth_alg, auth_transaction, status_code;
3568 u16 resp = WLAN_STATUS_SUCCESS;
3569 struct sta_info *sta = NULL;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003570 int res, reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003571 u16 fc;
3572 const u8 *challenge = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003573 u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
3574 size_t resp_ies_len = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003575 u16 seq_ctrl;
Hai Shalomfdcde762020-04-02 11:19:20 -07003576 struct radius_sta rad_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003577
3578 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003579 wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
3580 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003581 return;
3582 }
3583
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003584#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07003585 if (hapd->iconf->ignore_auth_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003586 drand48() < hapd->iconf->ignore_auth_probability) {
3587 wpa_printf(MSG_INFO,
3588 "TESTING: ignoring auth frame from " MACSTR,
3589 MAC2STR(mgmt->sa));
3590 return;
3591 }
3592#endif /* CONFIG_TESTING_OPTIONS */
3593
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003594 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
3595 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
3596 status_code = le_to_host16(mgmt->u.auth.status_code);
3597 fc = le_to_host16(mgmt->frame_control);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003598 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003599
3600 if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
3601 2 + WLAN_AUTH_CHALLENGE_LEN &&
3602 mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
3603 mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
3604 challenge = &mgmt->u.auth.variable[2];
3605
3606 wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003607 "auth_transaction=%d status_code=%d wep=%d%s "
Hai Shalom021b0b52019-04-10 11:17:58 -07003608 "seq_ctrl=0x%x%s%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003609 MAC2STR(mgmt->sa), auth_alg, auth_transaction,
3610 status_code, !!(fc & WLAN_FC_ISWEP),
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003611 challenge ? " challenge" : "",
Hai Shalom021b0b52019-04-10 11:17:58 -07003612 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
3613 from_queue ? " (from queue)" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003614
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003615#ifdef CONFIG_NO_RC4
3616 if (auth_alg == WLAN_AUTH_SHARED_KEY) {
3617 wpa_printf(MSG_INFO,
3618 "Unsupported authentication algorithm (%d)",
3619 auth_alg);
3620 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
3621 goto fail;
3622 }
3623#endif /* CONFIG_NO_RC4 */
3624
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003625 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003626 wpa_printf(MSG_DEBUG,
3627 "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
3628 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003629 goto fail;
3630 }
3631
3632 if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
3633 auth_alg == WLAN_AUTH_OPEN) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003634#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003635 (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003636 auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003637#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003638#ifdef CONFIG_SAE
3639 (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
3640 auth_alg == WLAN_AUTH_SAE) ||
3641#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003642#ifdef CONFIG_FILS
3643 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
3644 auth_alg == WLAN_AUTH_FILS_SK) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003645 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
3646 hapd->conf->fils_dh_group &&
3647 auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003648#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08003649#ifdef CONFIG_PASN
3650 (hapd->conf->wpa &&
3651 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) &&
3652 auth_alg == WLAN_AUTH_PASN) ||
3653#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003654 ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
3655 auth_alg == WLAN_AUTH_SHARED_KEY))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003656 wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
3657 auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003658 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
3659 goto fail;
3660 }
3661
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003662 if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
Hai Shalom60840252021-02-19 19:02:11 -08003663#ifdef CONFIG_PASN
3664 (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) ||
3665#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003666 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003667 wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
3668 auth_transaction);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003669 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
3670 goto fail;
3671 }
3672
3673 if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003674 wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
3675 MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003676 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3677 goto fail;
3678 }
3679
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003680 if (hapd->conf->no_auth_if_seen_on) {
3681 struct hostapd_data *other;
3682
3683 other = sta_track_seen_on(hapd->iface, mgmt->sa,
3684 hapd->conf->no_auth_if_seen_on);
3685 if (other) {
3686 u8 *pos;
3687 u32 info;
3688 u8 op_class, channel, phytype;
3689
3690 wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
3691 MACSTR " since STA has been seen on %s",
3692 hapd->conf->iface, MAC2STR(mgmt->sa),
3693 hapd->conf->no_auth_if_seen_on);
3694
3695 resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
3696 pos = &resp_ies[0];
3697 *pos++ = WLAN_EID_NEIGHBOR_REPORT;
3698 *pos++ = 13;
3699 os_memcpy(pos, other->own_addr, ETH_ALEN);
3700 pos += ETH_ALEN;
3701 info = 0; /* TODO: BSSID Information */
3702 WPA_PUT_LE32(pos, info);
3703 pos += 4;
3704 if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
3705 phytype = 8; /* dmg */
3706 else if (other->iconf->ieee80211ac)
3707 phytype = 9; /* vht */
3708 else if (other->iconf->ieee80211n)
3709 phytype = 7; /* ht */
3710 else if (other->iconf->hw_mode ==
3711 HOSTAPD_MODE_IEEE80211A)
3712 phytype = 4; /* ofdm */
3713 else if (other->iconf->hw_mode ==
3714 HOSTAPD_MODE_IEEE80211G)
3715 phytype = 6; /* erp */
3716 else
3717 phytype = 5; /* hrdsss */
3718 if (ieee80211_freq_to_channel_ext(
3719 hostapd_hw_get_freq(other,
3720 other->iconf->channel),
3721 other->iconf->secondary_channel,
3722 other->iconf->ieee80211ac,
3723 &op_class, &channel) == NUM_HOSTAPD_MODES) {
3724 op_class = 0;
3725 channel = other->iconf->channel;
3726 }
3727 *pos++ = op_class;
3728 *pos++ = channel;
3729 *pos++ = phytype;
3730 resp_ies_len = pos - &resp_ies[0];
3731 goto fail;
3732 }
3733 }
3734
Hai Shalomfdcde762020-04-02 11:19:20 -07003735 res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
3736 &rad_info);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003737 if (res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003738 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
3739 "Ignore Authentication frame from " MACSTR
3740 " due to ACL reject", MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003741 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3742 goto fail;
3743 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003744 if (res == HOSTAPD_ACL_PENDING)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003745 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003746
Hai Shalom021b0b52019-04-10 11:17:58 -07003747#ifdef CONFIG_SAE
3748 if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
3749 (auth_transaction == 1 ||
3750 (auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) {
3751 /* Handle SAE Authentication commit message through a queue to
3752 * provide more control for postponing the needed heavy
3753 * processing under a possible DoS attack scenario. In addition,
3754 * queue SAE Authentication confirm message if there happens to
3755 * be a queued commit message from the same peer. This is needed
3756 * to avoid reordering Authentication frames within the same
3757 * SAE exchange. */
3758 auth_sae_queue(hapd, mgmt, len, rssi);
3759 return;
3760 }
3761#endif /* CONFIG_SAE */
3762
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003763 sta = ap_get_sta(hapd, mgmt->sa);
3764 if (sta) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003765 sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
Hai Shalom74f70d42019-02-11 14:42:39 -08003766 sta->ft_over_ds = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003767 if ((fc & WLAN_FC_RETRY) &&
3768 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
3769 sta->last_seq_ctrl == seq_ctrl &&
3770 sta->last_subtype == WLAN_FC_STYPE_AUTH) {
3771 hostapd_logger(hapd, sta->addr,
3772 HOSTAPD_MODULE_IEEE80211,
3773 HOSTAPD_LEVEL_DEBUG,
3774 "Drop repeated authentication frame seq_ctrl=0x%x",
3775 seq_ctrl);
3776 return;
3777 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003778#ifdef CONFIG_MESH
3779 if ((hapd->conf->mesh & MESH_ENABLED) &&
3780 sta->plink_state == PLINK_BLOCKED) {
3781 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
3782 " is blocked - drop Authentication frame",
3783 MAC2STR(mgmt->sa));
3784 return;
3785 }
3786#endif /* CONFIG_MESH */
Hai Shalom60840252021-02-19 19:02:11 -08003787#ifdef CONFIG_PASN
3788 if (auth_alg == WLAN_AUTH_PASN &&
3789 (sta->flags & WLAN_STA_ASSOC)) {
3790 wpa_printf(MSG_DEBUG,
3791 "PASN: auth: Existing station: " MACSTR,
3792 MAC2STR(sta->addr));
3793 return;
3794 }
3795#endif /* CONFIG_PASN */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003796 } else {
3797#ifdef CONFIG_MESH
3798 if (hapd->conf->mesh & MESH_ENABLED) {
3799 /* if the mesh peer is not available, we don't do auth.
3800 */
3801 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003802 " not yet known - drop Authentication frame",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003803 MAC2STR(mgmt->sa));
3804 /*
3805 * Save a copy of the frame so that it can be processed
3806 * if a new peer entry is added shortly after this.
3807 */
3808 wpabuf_free(hapd->mesh_pending_auth);
3809 hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len);
3810 os_get_reltime(&hapd->mesh_pending_auth_time);
3811 return;
3812 }
3813#endif /* CONFIG_MESH */
3814
3815 sta = ap_sta_add(hapd, mgmt->sa);
3816 if (!sta) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003817 wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003818 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3819 goto fail;
3820 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003821 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003822 sta->last_seq_ctrl = seq_ctrl;
3823 sta->last_subtype = WLAN_FC_STYPE_AUTH;
Hai Shalom74f70d42019-02-11 14:42:39 -08003824#ifdef CONFIG_MBO
3825 sta->auth_rssi = rssi;
3826#endif /* CONFIG_MBO */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003827
Hai Shalomfdcde762020-04-02 11:19:20 -07003828 res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003829 if (res) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003830 wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003831 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3832 goto fail;
3833 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003834
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003835 sta->flags &= ~WLAN_STA_PREAUTH;
3836 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
3837
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003838 /*
3839 * If the driver supports full AP client state, add a station to the
3840 * driver before sending authentication reply to make sure the driver
3841 * has resources, and not to go through the entire authentication and
3842 * association handshake, and fail it at the end.
3843 *
3844 * If this is not the first transaction, in a multi-step authentication
3845 * algorithm, the station already exists in the driver
3846 * (sta->added_unassoc = 1) so skip it.
3847 *
3848 * In mesh mode, the station was already added to the driver when the
3849 * NEW_PEER_CANDIDATE event is received.
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003850 *
3851 * If PMF was negotiated for the existing association, skip this to
3852 * avoid dropping the STA entry and the associated keys. This is needed
3853 * to allow the original connection work until the attempt can complete
3854 * (re)association, so that unprotected Authentication frame cannot be
3855 * used to bypass PMF protection.
Hai Shalom60840252021-02-19 19:02:11 -08003856 *
3857 * PASN authentication does not require adding/removing station to the
3858 * driver so skip this flow in case of PASN authentication.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003859 */
3860 if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003861 (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003862 !(hapd->conf->mesh & MESH_ENABLED) &&
Hai Shalom60840252021-02-19 19:02:11 -08003863 !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) {
Hai Shalomb755a2a2020-04-23 21:49:02 -07003864 if (ap_sta_re_add(hapd, sta) < 0) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003865 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3866 goto fail;
3867 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003868 }
3869
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003870 switch (auth_alg) {
3871 case WLAN_AUTH_OPEN:
3872 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3873 HOSTAPD_LEVEL_DEBUG,
3874 "authentication OK (open system)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003875 sta->flags |= WLAN_STA_AUTH;
3876 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
3877 sta->auth_alg = WLAN_AUTH_OPEN;
3878 mlme_authenticate_indication(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003879 break;
Hai Shalomfdcde762020-04-02 11:19:20 -07003880#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003881#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003882 case WLAN_AUTH_SHARED_KEY:
3883 resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
3884 fc & WLAN_FC_ISWEP);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003885 if (resp != 0)
3886 wpa_printf(MSG_DEBUG,
3887 "auth_shared_key() failed: status=%d", resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003888 sta->auth_alg = WLAN_AUTH_SHARED_KEY;
3889 mlme_authenticate_indication(hapd, sta);
3890 if (sta->challenge && auth_transaction == 1) {
3891 resp_ies[0] = WLAN_EID_CHALLENGE;
3892 resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
3893 os_memcpy(resp_ies + 2, sta->challenge,
3894 WLAN_AUTH_CHALLENGE_LEN);
3895 resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
3896 }
3897 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003898#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003899#endif /* CONFIG_WEP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003900#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003901 case WLAN_AUTH_FT:
3902 sta->auth_alg = WLAN_AUTH_FT;
3903 if (sta->wpa_sm == NULL)
3904 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003905 sta->addr, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003906 if (sta->wpa_sm == NULL) {
3907 wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
3908 "state machine");
3909 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3910 goto fail;
3911 }
3912 wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
3913 auth_transaction, mgmt->u.auth.variable,
3914 len - IEEE80211_HDRLEN -
3915 sizeof(mgmt->u.auth),
3916 handle_auth_ft_finish, hapd);
3917 /* handle_auth_ft_finish() callback will complete auth. */
3918 return;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003919#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003920#ifdef CONFIG_SAE
3921 case WLAN_AUTH_SAE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003922#ifdef CONFIG_MESH
3923 if (status_code == WLAN_STATUS_SUCCESS &&
3924 hapd->conf->mesh & MESH_ENABLED) {
3925 if (sta->wpa_sm == NULL)
3926 sta->wpa_sm =
3927 wpa_auth_sta_init(hapd->wpa_auth,
3928 sta->addr, NULL);
3929 if (sta->wpa_sm == NULL) {
3930 wpa_printf(MSG_DEBUG,
3931 "SAE: Failed to initialize WPA state machine");
3932 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3933 goto fail;
3934 }
3935 }
3936#endif /* CONFIG_MESH */
3937 handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
3938 status_code);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003939 return;
3940#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003941#ifdef CONFIG_FILS
3942 case WLAN_AUTH_FILS_SK:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003943 case WLAN_AUTH_FILS_SK_PFS:
3944 handle_auth_fils(hapd, sta, mgmt->u.auth.variable,
3945 len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth),
3946 auth_alg, auth_transaction, status_code,
3947 handle_auth_fils_finish);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003948 return;
3949#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08003950#ifdef CONFIG_PASN
3951 case WLAN_AUTH_PASN:
3952 handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction,
3953 status_code);
3954 return;
3955#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003956 }
3957
3958 fail:
Hai Shalomfdcde762020-04-02 11:19:20 -07003959 reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg,
Hai Shaloma20dcd72022-02-04 13:43:00 -08003960 auth_alg == WLAN_AUTH_SAE ?
3961 auth_transaction : auth_transaction + 1,
3962 resp, resp_ies, resp_ies_len,
3963 "handle-auth");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003964
3965 if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
3966 reply_res != WLAN_STATUS_SUCCESS)) {
3967 hostapd_drv_sta_remove(hapd, sta->addr);
3968 sta->added_unassoc = 0;
3969 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003970}
3971
3972
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003973int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003974{
3975 int i, j = 32, aid;
3976
3977 /* get a unique AID */
3978 if (sta->aid > 0) {
3979 wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
3980 return 0;
3981 }
3982
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003983 if (TEST_FAIL())
3984 return -1;
3985
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003986 for (i = 0; i < AID_WORDS; i++) {
3987 if (hapd->sta_aid[i] == (u32) -1)
3988 continue;
3989 for (j = 0; j < 32; j++) {
3990 if (!(hapd->sta_aid[i] & BIT(j)))
3991 break;
3992 }
3993 if (j < 32)
3994 break;
3995 }
3996 if (j == 32)
3997 return -1;
3998 aid = i * 32 + j + 1;
3999 if (aid > 2007)
4000 return -1;
4001
4002 sta->aid = aid;
4003 hapd->sta_aid[i] |= BIT(j);
4004 wpa_printf(MSG_DEBUG, " new AID %d", sta->aid);
4005 return 0;
4006}
4007
4008
4009static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
4010 const u8 *ssid_ie, size_t ssid_ie_len)
4011{
4012 if (ssid_ie == NULL)
4013 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4014
4015 if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
4016 os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004017 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4018 HOSTAPD_LEVEL_INFO,
4019 "Station tried to associate with unknown SSID "
Dmitry Shmidt3c479372014-02-04 10:50:36 -08004020 "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004021 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4022 }
4023
4024 return WLAN_STATUS_SUCCESS;
4025}
4026
4027
4028static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
4029 const u8 *wmm_ie, size_t wmm_ie_len)
4030{
4031 sta->flags &= ~WLAN_STA_WMM;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004032 sta->qosinfo = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004033 if (wmm_ie && hapd->conf->wmm_enabled) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004034 struct wmm_information_element *wmm;
4035
4036 if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004037 hostapd_logger(hapd, sta->addr,
4038 HOSTAPD_MODULE_WPA,
4039 HOSTAPD_LEVEL_DEBUG,
4040 "invalid WMM element in association "
4041 "request");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004042 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4043 }
4044
4045 sta->flags |= WLAN_STA_WMM;
4046 wmm = (struct wmm_information_element *) wmm_ie;
4047 sta->qosinfo = wmm->qos_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004048 }
4049 return WLAN_STATUS_SUCCESS;
4050}
4051
Hai Shalom74f70d42019-02-11 14:42:39 -08004052static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
4053 const u8 *multi_ap_ie, size_t multi_ap_len)
4054{
4055 u8 multi_ap_value = 0;
4056
4057 sta->flags &= ~WLAN_STA_MULTI_AP;
4058
4059 if (!hapd->conf->multi_ap)
4060 return WLAN_STATUS_SUCCESS;
4061
4062 if (multi_ap_ie) {
4063 const u8 *multi_ap_subelem;
4064
4065 multi_ap_subelem = get_ie(multi_ap_ie + 4,
4066 multi_ap_len - 4,
4067 MULTI_AP_SUB_ELEM_TYPE);
4068 if (multi_ap_subelem && multi_ap_subelem[1] == 1) {
4069 multi_ap_value = multi_ap_subelem[2];
4070 } else {
4071 hostapd_logger(hapd, sta->addr,
4072 HOSTAPD_MODULE_IEEE80211,
4073 HOSTAPD_LEVEL_INFO,
4074 "Multi-AP IE has missing or invalid Multi-AP subelement");
4075 return WLAN_STATUS_INVALID_IE;
4076 }
4077 }
4078
Hai Shalom021b0b52019-04-10 11:17:58 -07004079 if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA)
4080 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4081 HOSTAPD_LEVEL_INFO,
4082 "Multi-AP IE with unexpected value 0x%02x",
4083 multi_ap_value);
Hai Shalom74f70d42019-02-11 14:42:39 -08004084
Hai Shalom021b0b52019-04-10 11:17:58 -07004085 if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) {
4086 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
4087 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08004088
Hai Shalom021b0b52019-04-10 11:17:58 -07004089 hostapd_logger(hapd, sta->addr,
4090 HOSTAPD_MODULE_IEEE80211,
4091 HOSTAPD_LEVEL_INFO,
4092 "Non-Multi-AP STA tries to associate with backhaul-only BSS");
4093 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
Hai Shalom74f70d42019-02-11 14:42:39 -08004094 }
4095
Hai Shalom021b0b52019-04-10 11:17:58 -07004096 if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
4097 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4098 HOSTAPD_LEVEL_DEBUG,
4099 "Backhaul STA tries to associate with fronthaul-only BSS");
4100
4101 sta->flags |= WLAN_STA_MULTI_AP;
4102 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08004103}
4104
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004105
4106static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
4107 struct ieee802_11_elems *elems)
4108{
Dmitry Shmidt29333592017-01-09 12:27:11 -08004109 /* Supported rates not used in IEEE 802.11ad/DMG */
4110 if (hapd->iface->current_mode &&
4111 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
4112 return WLAN_STATUS_SUCCESS;
4113
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004114 if (!elems->supp_rates) {
4115 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4116 HOSTAPD_LEVEL_DEBUG,
4117 "No supported rates element in AssocReq");
4118 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4119 }
4120
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004121 if (elems->supp_rates_len + elems->ext_supp_rates_len >
4122 sizeof(sta->supported_rates)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004123 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4124 HOSTAPD_LEVEL_DEBUG,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004125 "Invalid supported rates element length %d+%d",
4126 elems->supp_rates_len,
4127 elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004128 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4129 }
4130
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004131 sta->supported_rates_len = merge_byte_arrays(
4132 sta->supported_rates, sizeof(sta->supported_rates),
4133 elems->supp_rates, elems->supp_rates_len,
4134 elems->ext_supp_rates, elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004135
4136 return WLAN_STATUS_SUCCESS;
4137}
4138
4139
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004140#ifdef CONFIG_OWE
4141
4142static int owe_group_supported(struct hostapd_data *hapd, u16 group)
4143{
4144 int i;
4145 int *groups = hapd->conf->owe_groups;
4146
4147 if (group != 19 && group != 20 && group != 21)
4148 return 0;
4149
4150 if (!groups)
4151 return 1;
4152
4153 for (i = 0; groups[i] > 0; i++) {
4154 if (groups[i] == group)
4155 return 1;
4156 }
4157
4158 return 0;
4159}
4160
4161
4162static u16 owe_process_assoc_req(struct hostapd_data *hapd,
4163 struct sta_info *sta, const u8 *owe_dh,
4164 u8 owe_dh_len)
4165{
4166 struct wpabuf *secret, *pub, *hkey;
4167 int res;
4168 u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN];
4169 const char *info = "OWE Key Generation";
4170 const u8 *addr[2];
4171 size_t len[2];
4172 u16 group;
4173 size_t hash_len, prime_len;
4174
4175 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
4176 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
4177 return WLAN_STATUS_SUCCESS;
4178 }
4179
4180 group = WPA_GET_LE16(owe_dh);
4181 if (!owe_group_supported(hapd, group)) {
4182 wpa_printf(MSG_DEBUG, "OWE: Unsupported DH group %u", group);
4183 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
4184 }
4185 if (group == 19)
4186 prime_len = 32;
4187 else if (group == 20)
4188 prime_len = 48;
4189 else if (group == 21)
4190 prime_len = 66;
4191 else
4192 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
4193
Sunil Ravia04bd252022-05-02 22:54:18 -07004194 if (sta->owe_group == group && sta->owe_ecdh) {
4195 /* This is a workaround for mac80211 behavior of retransmitting
4196 * the Association Request frames multiple times if the link
4197 * layer retries (i.e., seq# remains same) fail. The mac80211
4198 * initiated retransmission will use a different seq# and as
4199 * such, will go through duplicate detection. If we were to
4200 * change our DH key for that attempt, there would be two
4201 * different DH shared secrets and the STA would likely select
4202 * the wrong one. */
4203 wpa_printf(MSG_DEBUG,
4204 "OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again");
4205 } else {
4206 crypto_ecdh_deinit(sta->owe_ecdh);
4207 sta->owe_ecdh = crypto_ecdh_init(group);
4208 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004209 if (!sta->owe_ecdh)
4210 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
4211 sta->owe_group = group;
4212
4213 secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2,
4214 owe_dh_len - 2);
4215 secret = wpabuf_zeropad(secret, prime_len);
4216 if (!secret) {
4217 wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
4218 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4219 }
4220 wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
4221
4222 /* prk = HKDF-extract(C | A | group, z) */
4223
4224 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
4225 if (!pub) {
4226 wpabuf_clear_free(secret);
4227 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4228 }
4229
4230 /* PMKID = Truncate-128(Hash(C | A)) */
4231 addr[0] = owe_dh + 2;
4232 len[0] = owe_dh_len - 2;
4233 addr[1] = wpabuf_head(pub);
4234 len[1] = wpabuf_len(pub);
4235 if (group == 19) {
4236 res = sha256_vector(2, addr, len, pmkid);
4237 hash_len = SHA256_MAC_LEN;
4238 } else if (group == 20) {
4239 res = sha384_vector(2, addr, len, pmkid);
4240 hash_len = SHA384_MAC_LEN;
4241 } else if (group == 21) {
4242 res = sha512_vector(2, addr, len, pmkid);
4243 hash_len = SHA512_MAC_LEN;
4244 } else {
4245 wpabuf_free(pub);
4246 wpabuf_clear_free(secret);
4247 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4248 }
4249 pub = wpabuf_zeropad(pub, prime_len);
4250 if (res < 0 || !pub) {
4251 wpabuf_free(pub);
4252 wpabuf_clear_free(secret);
4253 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4254 }
4255
4256 hkey = wpabuf_alloc(owe_dh_len - 2 + wpabuf_len(pub) + 2);
4257 if (!hkey) {
4258 wpabuf_free(pub);
4259 wpabuf_clear_free(secret);
4260 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4261 }
4262
4263 wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */
4264 wpabuf_put_buf(hkey, pub); /* A */
4265 wpabuf_free(pub);
4266 wpabuf_put_le16(hkey, group); /* group */
4267 if (group == 19)
4268 res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
4269 wpabuf_head(secret), wpabuf_len(secret), prk);
4270 else if (group == 20)
4271 res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey),
4272 wpabuf_head(secret), wpabuf_len(secret), prk);
4273 else if (group == 21)
4274 res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey),
4275 wpabuf_head(secret), wpabuf_len(secret), prk);
4276 wpabuf_clear_free(hkey);
4277 wpabuf_clear_free(secret);
4278 if (res < 0)
4279 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4280
4281 wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
4282
4283 /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
4284
4285 os_free(sta->owe_pmk);
4286 sta->owe_pmk = os_malloc(hash_len);
4287 if (!sta->owe_pmk) {
4288 os_memset(prk, 0, SHA512_MAC_LEN);
4289 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4290 }
4291
4292 if (group == 19)
4293 res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info,
4294 os_strlen(info), sta->owe_pmk, hash_len);
4295 else if (group == 20)
4296 res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info,
4297 os_strlen(info), sta->owe_pmk, hash_len);
4298 else if (group == 21)
4299 res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
4300 os_strlen(info), sta->owe_pmk, hash_len);
4301 os_memset(prk, 0, SHA512_MAC_LEN);
4302 if (res < 0) {
4303 os_free(sta->owe_pmk);
4304 sta->owe_pmk = NULL;
4305 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4306 }
4307 sta->owe_pmk_len = hash_len;
4308
4309 wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
4310 wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
4311 wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk,
4312 sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE);
4313
4314 return WLAN_STATUS_SUCCESS;
4315}
4316
Hai Shalom81f62d82019-07-22 12:10:00 -07004317
4318u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
4319 const u8 *rsn_ie, size_t rsn_ie_len,
4320 const u8 *owe_dh, size_t owe_dh_len)
4321{
4322 struct wpa_ie_data data;
4323 int res;
4324
4325 if (!rsn_ie || rsn_ie_len < 2) {
4326 wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
4327 MAC2STR(peer));
4328 return WLAN_STATUS_INVALID_IE;
4329 }
4330 rsn_ie -= 2;
4331 rsn_ie_len += 2;
4332
4333 res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
4334 if (res) {
4335 wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
4336 " (res=%d)", MAC2STR(peer), res);
4337 wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
4338 return wpa_res_to_status_code(res);
4339 }
4340 if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
4341 wpa_printf(MSG_DEBUG,
4342 "OWE: Unexpected key mgmt 0x%x from " MACSTR,
4343 (unsigned int) data.key_mgmt, MAC2STR(peer));
4344 return WLAN_STATUS_AKMP_NOT_VALID;
4345 }
4346 if (!owe_dh) {
4347 wpa_printf(MSG_DEBUG,
4348 "OWE: No Diffie-Hellman Parameter element from "
4349 MACSTR, MAC2STR(peer));
4350 return WLAN_STATUS_AKMP_NOT_VALID;
4351 }
4352
4353 return WLAN_STATUS_SUCCESS;
4354}
4355
4356
4357u16 owe_process_rsn_ie(struct hostapd_data *hapd,
4358 struct sta_info *sta,
4359 const u8 *rsn_ie, size_t rsn_ie_len,
4360 const u8 *owe_dh, size_t owe_dh_len)
4361{
4362 u16 status;
4363 u8 *owe_buf, ie[256 * 2];
4364 size_t ie_len = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07004365 enum wpa_validate_result res;
Hai Shalom81f62d82019-07-22 12:10:00 -07004366
4367 if (!rsn_ie || rsn_ie_len < 2) {
4368 wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
4369 status = WLAN_STATUS_INVALID_IE;
4370 goto end;
4371 }
4372
4373 if (!sta->wpa_sm)
4374 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
4375 NULL);
4376 if (!sta->wpa_sm) {
4377 wpa_printf(MSG_WARNING,
4378 "OWE: Failed to initialize WPA state machine");
4379 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4380 goto end;
4381 }
4382 rsn_ie -= 2;
4383 rsn_ie_len += 2;
4384 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
4385 hapd->iface->freq, rsn_ie, rsn_ie_len,
Hai Shalomc3565922019-10-28 11:58:20 -07004386 NULL, 0, NULL, 0, owe_dh, owe_dh_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07004387 status = wpa_res_to_status_code(res);
4388 if (status != WLAN_STATUS_SUCCESS)
4389 goto end;
4390 status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
4391 if (status != WLAN_STATUS_SUCCESS)
4392 goto end;
4393 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
4394 NULL, 0);
4395 if (!owe_buf) {
4396 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4397 goto end;
4398 }
4399
4400 if (sta->owe_ecdh) {
4401 struct wpabuf *pub;
4402
4403 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
4404 if (!pub) {
4405 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4406 goto end;
4407 }
4408
4409 /* OWE Diffie-Hellman Parameter element */
4410 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
4411 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
4412 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
4413 */
4414 WPA_PUT_LE16(owe_buf, sta->owe_group);
4415 owe_buf += 2;
4416 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
4417 owe_buf += wpabuf_len(pub);
4418 wpabuf_free(pub);
4419 sta->external_dh_updated = 1;
4420 }
4421 ie_len = owe_buf - ie;
4422
4423end:
4424 wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
4425 MACSTR, status, (unsigned int) ie_len,
4426 MAC2STR(sta->addr));
4427 hostapd_drv_update_dh_ie(hapd, sta->addr, status,
4428 status == WLAN_STATUS_SUCCESS ? ie : NULL,
4429 ie_len);
4430
4431 return status;
4432}
4433
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004434#endif /* CONFIG_OWE */
4435
4436
Hai Shalom899fcc72020-10-19 14:38:18 -07004437static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
4438 int reassoc)
4439{
4440 if ((sta->flags &
4441 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
4442 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
4443 return false;
4444
4445 if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
4446 ap_check_sa_query_timeout(hapd, sta);
4447
4448 if (!sta->sa_query_timed_out &&
4449 (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
4450 /*
4451 * STA has already been associated with MFP and SA Query timeout
4452 * has not been reached. Reject the association attempt
4453 * temporarily and start SA Query, if one is not pending.
4454 */
4455 if (sta->sa_query_count == 0)
4456 ap_sta_start_sa_query(hapd, sta);
4457
4458 return true;
4459 }
4460
4461 return false;
4462}
4463
4464
Hai Shalomb755a2a2020-04-23 21:49:02 -07004465static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004466 const u8 *ies, size_t ies_len, int reassoc)
4467{
4468 struct ieee802_11_elems elems;
Hai Shalomb755a2a2020-04-23 21:49:02 -07004469 int resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004470 const u8 *wpa_ie;
4471 size_t wpa_ie_len;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004472 const u8 *p2p_dev_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004473
4474 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
4475 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4476 HOSTAPD_LEVEL_INFO, "Station sent an invalid "
4477 "association request");
4478 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4479 }
4480
4481 resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len);
4482 if (resp != WLAN_STATUS_SUCCESS)
4483 return resp;
4484 resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
4485 if (resp != WLAN_STATUS_SUCCESS)
4486 return resp;
Dmitry Shmidt051af732013-10-22 13:52:46 -07004487 resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len);
4488 if (resp != WLAN_STATUS_SUCCESS)
4489 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004490 resp = copy_supp_rates(hapd, sta, &elems);
4491 if (resp != WLAN_STATUS_SUCCESS)
4492 return resp;
Hai Shalom74f70d42019-02-11 14:42:39 -08004493
4494 resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len);
4495 if (resp != WLAN_STATUS_SUCCESS)
4496 return resp;
4497
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07004498 resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004499 if (resp != WLAN_STATUS_SUCCESS)
4500 return resp;
4501 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
4502 !(sta->flags & WLAN_STA_HT)) {
4503 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4504 HOSTAPD_LEVEL_INFO, "Station does not support "
4505 "mandatory HT PHY - reject association");
4506 return WLAN_STATUS_ASSOC_DENIED_NO_HT;
4507 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004508
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004509#ifdef CONFIG_IEEE80211AC
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004510 if (hapd->iconf->ieee80211ac) {
4511 resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities);
4512 if (resp != WLAN_STATUS_SUCCESS)
4513 return resp;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08004514
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004515 resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
4516 if (resp != WLAN_STATUS_SUCCESS)
4517 return resp;
4518 }
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08004519
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004520 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
4521 !(sta->flags & WLAN_STA_VHT)) {
4522 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4523 HOSTAPD_LEVEL_INFO, "Station does not support "
4524 "mandatory VHT PHY - reject association");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004525 return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004526 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004527
4528 if (hapd->conf->vendor_vht && !elems.vht_capabilities) {
4529 resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht,
4530 elems.vendor_vht_len);
4531 if (resp != WLAN_STATUS_SUCCESS)
4532 return resp;
4533 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004534#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07004535#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08004536 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07004537 resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
4538 elems.he_capabilities,
4539 elems.he_capabilities_len);
4540 if (resp != WLAN_STATUS_SUCCESS)
4541 return resp;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004542 if (is_6ghz_op_class(hapd->iconf->op_class)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004543 if (!(sta->flags & WLAN_STA_HE)) {
4544 hostapd_logger(hapd, sta->addr,
4545 HOSTAPD_MODULE_IEEE80211,
4546 HOSTAPD_LEVEL_INFO,
4547 "Station does not support mandatory HE PHY - reject association");
4548 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
4549 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004550 resp = copy_sta_he_6ghz_capab(hapd, sta,
4551 elems.he_6ghz_band_cap);
4552 if (resp != WLAN_STATUS_SUCCESS)
4553 return resp;
4554 }
Hai Shalom81f62d82019-07-22 12:10:00 -07004555 }
4556#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07004557#ifdef CONFIG_IEEE80211BE
4558 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4559 resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP,
4560 elems.he_capabilities,
4561 elems.he_capabilities_len,
4562 elems.eht_capabilities,
4563 elems.eht_capabilities_len);
4564 if (resp != WLAN_STATUS_SUCCESS)
4565 return resp;
4566 }
4567#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004568
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004569#ifdef CONFIG_P2P
4570 if (elems.p2p) {
4571 wpabuf_free(sta->p2p_ie);
4572 sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
4573 P2P_IE_VENDOR_TYPE);
4574 if (sta->p2p_ie)
4575 p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
4576 } else {
4577 wpabuf_free(sta->p2p_ie);
4578 sta->p2p_ie = NULL;
4579 }
4580#endif /* CONFIG_P2P */
4581
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004582 if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
4583 wpa_ie = elems.rsn_ie;
4584 wpa_ie_len = elems.rsn_ie_len;
4585 } else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
4586 elems.wpa_ie) {
4587 wpa_ie = elems.wpa_ie;
4588 wpa_ie_len = elems.wpa_ie_len;
4589 } else {
4590 wpa_ie = NULL;
4591 wpa_ie_len = 0;
4592 }
4593
4594#ifdef CONFIG_WPS
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004595 sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004596 if (hapd->conf->wps_state && elems.wps_ie) {
4597 wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
4598 "Request - assume WPS is used");
Hai Shalom899fcc72020-10-19 14:38:18 -07004599 if (check_sa_query(hapd, sta, reassoc))
4600 return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004601 sta->flags |= WLAN_STA_WPS;
4602 wpabuf_free(sta->wps_ie);
4603 sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
4604 WPS_IE_VENDOR_TYPE);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004605 if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
4606 wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
4607 sta->flags |= WLAN_STA_WPS2;
4608 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004609 wpa_ie = NULL;
4610 wpa_ie_len = 0;
4611 if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
4612 wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
4613 "(Re)Association Request - reject");
4614 return WLAN_STATUS_INVALID_IE;
4615 }
4616 } else if (hapd->conf->wps_state && wpa_ie == NULL) {
4617 wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
4618 "(Re)Association Request - possible WPS use");
4619 sta->flags |= WLAN_STA_MAYBE_WPS;
4620 } else
4621#endif /* CONFIG_WPS */
4622 if (hapd->conf->wpa && wpa_ie == NULL) {
4623 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4624 HOSTAPD_LEVEL_INFO,
4625 "No WPA/RSN IE in association request");
4626 return WLAN_STATUS_INVALID_IE;
4627 }
4628
4629 if (hapd->conf->wpa && wpa_ie) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004630 enum wpa_validate_result res;
4631
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004632 wpa_ie -= 2;
4633 wpa_ie_len += 2;
4634 if (sta->wpa_sm == NULL)
4635 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004636 sta->addr,
4637 p2p_dev_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004638 if (sta->wpa_sm == NULL) {
4639 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
4640 "state machine");
4641 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4642 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004643 wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004644 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07004645 hapd->iface->freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004646 wpa_ie, wpa_ie_len,
Hai Shalomc3565922019-10-28 11:58:20 -07004647 elems.rsnxe ? elems.rsnxe - 2 : NULL,
4648 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004649 elems.mdie, elems.mdie_len,
4650 elems.owe_dh, elems.owe_dh_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004651 resp = wpa_res_to_status_code(res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004652 if (resp != WLAN_STATUS_SUCCESS)
4653 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004654
Hai Shalom899fcc72020-10-19 14:38:18 -07004655 if (check_sa_query(hapd, sta, reassoc))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004656 return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004657
4658 if (wpa_auth_uses_mfp(sta->wpa_sm))
4659 sta->flags |= WLAN_STA_MFP;
4660 else
4661 sta->flags &= ~WLAN_STA_MFP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004662
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004663#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004664 if (sta->auth_alg == WLAN_AUTH_FT) {
4665 if (!reassoc) {
4666 wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
4667 "to use association (not "
4668 "re-association) with FT auth_alg",
4669 MAC2STR(sta->addr));
4670 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4671 }
4672
4673 resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
4674 ies_len);
4675 if (resp != WLAN_STATUS_SUCCESS)
4676 return resp;
4677 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004678#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004679
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004680#ifdef CONFIG_SAE
Roshan Pius3a1667e2018-07-03 15:17:14 -07004681 if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
4682 sta->sae->state == SAE_ACCEPTED)
4683 wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
4684
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004685 if (wpa_auth_uses_sae(sta->wpa_sm) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004686 sta->auth_alg == WLAN_AUTH_OPEN) {
4687 struct rsn_pmksa_cache_entry *sa;
4688 sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
4689 if (!sa || sa->akmp != WPA_KEY_MGMT_SAE) {
4690 wpa_printf(MSG_DEBUG,
4691 "SAE: No PMKSA cache entry found for "
4692 MACSTR, MAC2STR(sta->addr));
4693 return WLAN_STATUS_INVALID_PMKID;
4694 }
4695 wpa_printf(MSG_DEBUG, "SAE: " MACSTR
4696 " using PMKSA caching", MAC2STR(sta->addr));
4697 } else if (wpa_auth_uses_sae(sta->wpa_sm) &&
4698 sta->auth_alg != WLAN_AUTH_SAE &&
4699 !(sta->auth_alg == WLAN_AUTH_FT &&
4700 wpa_auth_uses_ft_sae(sta->wpa_sm))) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004701 wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
4702 "SAE AKM after non-SAE auth_alg %u",
4703 MAC2STR(sta->addr), sta->auth_alg);
4704 return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
4705 }
Hai Shalomc3565922019-10-28 11:58:20 -07004706
4707 if (hapd->conf->sae_pwe == 2 &&
4708 sta->auth_alg == WLAN_AUTH_SAE &&
Hai Shalom899fcc72020-10-19 14:38:18 -07004709 sta->sae && !sta->sae->h2e &&
Hai Shaloma20dcd72022-02-04 13:43:00 -08004710 ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
4711 WLAN_RSNX_CAPAB_SAE_H2E)) {
Hai Shalomc3565922019-10-28 11:58:20 -07004712 wpa_printf(MSG_INFO, "SAE: " MACSTR
4713 " indicates support for SAE H2E, but did not use it",
4714 MAC2STR(sta->addr));
4715 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4716 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004717#endif /* CONFIG_SAE */
4718
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004719#ifdef CONFIG_OWE
4720 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
4721 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
4722 elems.owe_dh) {
4723 resp = owe_process_assoc_req(hapd, sta, elems.owe_dh,
4724 elems.owe_dh_len);
4725 if (resp != WLAN_STATUS_SUCCESS)
4726 return resp;
4727 }
4728#endif /* CONFIG_OWE */
4729
Hai Shalom021b0b52019-04-10 11:17:58 -07004730#ifdef CONFIG_DPP2
4731 dpp_pfs_free(sta->dpp_pfs);
4732 sta->dpp_pfs = NULL;
4733
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004734 if (DPP_VERSION > 1 &&
4735 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07004736 hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
4737 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
4738 elems.owe_dh) {
4739 sta->dpp_pfs = dpp_pfs_init(
4740 wpabuf_head(hapd->conf->dpp_netaccesskey),
4741 wpabuf_len(hapd->conf->dpp_netaccesskey));
4742 if (!sta->dpp_pfs) {
4743 wpa_printf(MSG_DEBUG,
4744 "DPP: Could not initialize PFS");
4745 /* Try to continue without PFS */
4746 goto pfs_fail;
4747 }
4748
4749 if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
4750 elems.owe_dh_len) < 0) {
4751 dpp_pfs_free(sta->dpp_pfs);
4752 sta->dpp_pfs = NULL;
4753 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4754 }
4755 }
4756
4757 wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
4758 sta->dpp_pfs->secret : NULL);
4759 pfs_fail:
4760#endif /* CONFIG_DPP2 */
4761
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004762 if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004763 wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
4764 hostapd_logger(hapd, sta->addr,
4765 HOSTAPD_MODULE_IEEE80211,
4766 HOSTAPD_LEVEL_INFO,
4767 "Station tried to use TKIP with HT "
4768 "association");
4769 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
4770 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004771#ifdef CONFIG_HS20
4772 } else if (hapd->conf->osen) {
4773 if (elems.osen == NULL) {
4774 hostapd_logger(
4775 hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4776 HOSTAPD_LEVEL_INFO,
4777 "No HS 2.0 OSEN element in association request");
4778 return WLAN_STATUS_INVALID_IE;
4779 }
4780
4781 wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
4782 if (sta->wpa_sm == NULL)
4783 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
4784 sta->addr, NULL);
4785 if (sta->wpa_sm == NULL) {
4786 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
4787 "state machine");
4788 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4789 }
4790 if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
4791 elems.osen - 2, elems.osen_len + 2) < 0)
4792 return WLAN_STATUS_INVALID_IE;
4793#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004794 } else
4795 wpa_auth_sta_no_wpa(sta->wpa_sm);
4796
4797#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004798 p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
4799#endif /* CONFIG_P2P */
4800
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004801#ifdef CONFIG_HS20
4802 wpabuf_free(sta->hs20_ie);
4803 if (elems.hs20 && elems.hs20_len > 4) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004804 int release;
4805
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004806 sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
4807 elems.hs20_len - 4);
Hai Shalom74f70d42019-02-11 14:42:39 -08004808 release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
Hai Shalomc3565922019-10-28 11:58:20 -07004809 if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
4810 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004811 wpa_printf(MSG_DEBUG,
4812 "HS 2.0: PMF not negotiated by release %d station "
4813 MACSTR, release, MAC2STR(sta->addr));
4814 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
4815 }
4816 } else {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004817 sta->hs20_ie = NULL;
Hai Shalom74f70d42019-02-11 14:42:39 -08004818 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07004819
4820 wpabuf_free(sta->roaming_consortium);
4821 if (elems.roaming_cons_sel)
4822 sta->roaming_consortium = wpabuf_alloc_copy(
4823 elems.roaming_cons_sel + 4,
4824 elems.roaming_cons_sel_len - 4);
4825 else
4826 sta->roaming_consortium = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004827#endif /* CONFIG_HS20 */
4828
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004829#ifdef CONFIG_FST
4830 wpabuf_free(sta->mb_ies);
4831 if (hapd->iface->fst)
4832 sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
4833 else
4834 sta->mb_ies = NULL;
4835#endif /* CONFIG_FST */
4836
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004837#ifdef CONFIG_MBO
4838 mbo_ap_check_sta_assoc(hapd, sta, &elems);
4839
4840 if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
4841 elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
4842 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
4843 wpa_printf(MSG_INFO,
4844 "MBO: Reject WPA2 association without PMF");
4845 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4846 }
4847#endif /* CONFIG_MBO */
4848
Hai Shalom74f70d42019-02-11 14:42:39 -08004849#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
4850 if (wpa_auth_uses_ocv(sta->wpa_sm) &&
4851 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4852 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4853 sta->auth_alg == WLAN_AUTH_FILS_PK)) {
4854 struct wpa_channel_info ci;
4855 int tx_chanwidth;
4856 int tx_seg1_idx;
Hai Shalom899fcc72020-10-19 14:38:18 -07004857 enum oci_verify_result res;
Hai Shalom74f70d42019-02-11 14:42:39 -08004858
4859 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
4860 wpa_printf(MSG_WARNING,
4861 "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
4862 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4863 }
4864
4865 if (get_sta_tx_parameters(sta->wpa_sm,
4866 channel_width_to_int(ci.chanwidth),
4867 ci.seg1_idx, &tx_chanwidth,
4868 &tx_seg1_idx) < 0)
4869 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4870
Hai Shalom899fcc72020-10-19 14:38:18 -07004871 res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
4872 tx_chanwidth, tx_seg1_idx);
4873 if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
4874 res == OCI_NOT_FOUND) {
4875 /* Work around misbehaving STAs */
4876 wpa_printf(MSG_INFO,
4877 "FILS: Disable OCV with a STA that does not send OCI");
4878 wpa_auth_set_ocv(sta->wpa_sm, 0);
4879 } else if (res != OCI_SUCCESS) {
4880 wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
4881 ocv_errorstr);
4882 wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
4883 MACSTR " frame=fils-reassoc-req error=%s",
4884 MAC2STR(sta->addr), ocv_errorstr);
Hai Shalom74f70d42019-02-11 14:42:39 -08004885 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4886 }
4887 }
4888#endif /* CONFIG_FILS && CONFIG_OCV */
4889
Dmitry Shmidt9c175262016-03-03 10:20:07 -08004890 ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
4891 elems.supp_op_classes_len);
4892
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004893 if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
4894 elems.rrm_enabled &&
4895 elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
4896 os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
4897 sizeof(sta->rrm_enabled_capa));
4898
Roshan Pius3a1667e2018-07-03 15:17:14 -07004899 if (elems.power_capab) {
4900 sta->min_tx_power = elems.power_capab[0];
4901 sta->max_tx_power = elems.power_capab[1];
4902 sta->power_capab = 1;
4903 } else {
4904 sta->power_capab = 0;
4905 }
4906
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004907 return WLAN_STATUS_SUCCESS;
4908}
4909
4910
4911static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
4912 u16 reason_code)
4913{
4914 int send_len;
4915 struct ieee80211_mgmt reply;
4916
4917 os_memset(&reply, 0, sizeof(reply));
4918 reply.frame_control =
4919 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
4920 os_memcpy(reply.da, addr, ETH_ALEN);
4921 os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
4922 os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
4923
4924 send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
4925 reply.u.deauth.reason_code = host_to_le16(reason_code);
4926
Hai Shalomfdcde762020-04-02 11:19:20 -07004927 if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004928 wpa_printf(MSG_INFO, "Failed to send deauth: %s",
4929 strerror(errno));
4930}
4931
4932
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004933static int add_associated_sta(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08004934 struct sta_info *sta, int reassoc)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004935{
4936 struct ieee80211_ht_capabilities ht_cap;
4937 struct ieee80211_vht_capabilities vht_cap;
Hai Shalom81f62d82019-07-22 12:10:00 -07004938 struct ieee80211_he_capabilities he_cap;
Sunil Ravia04bd252022-05-02 22:54:18 -07004939 struct ieee80211_eht_capabilities eht_cap;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004940 int set = 1;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004941
4942 /*
4943 * Remove the STA entry to ensure the STA PS state gets cleared and
4944 * configuration gets updated. This is relevant for cases, such as
4945 * FT-over-the-DS, where a station re-associates back to the same AP but
4946 * skips the authentication flow, or if working with a driver that
4947 * does not support full AP client state.
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004948 *
4949 * Skip this if the STA has already completed FT reassociation and the
4950 * TK has been configured since the TX/RX PN must not be reset to 0 for
4951 * the same key.
Hai Shalom74f70d42019-02-11 14:42:39 -08004952 *
4953 * FT-over-the-DS has a special case where the STA entry (and as such,
4954 * the TK) has not yet been configured to the driver depending on which
4955 * driver interface is used. For that case, allow add-STA operation to
4956 * be used (instead of set-STA). This is needed to allow mac80211-based
4957 * drivers to accept the STA parameter configuration. Since this is
4958 * after a new FT-over-DS exchange, a new TK has been derived, so key
4959 * reinstallation is not a concern for this case.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004960 */
Hai Shalom74f70d42019-02-11 14:42:39 -08004961 wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
4962 " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
4963 MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
4964 sta->ft_over_ds, reassoc,
4965 !!(sta->flags & WLAN_STA_AUTHORIZED),
4966 wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
4967 wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
4968
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004969 if (!sta->added_unassoc &&
4970 (!(sta->flags & WLAN_STA_AUTHORIZED) ||
Hai Shalom74f70d42019-02-11 14:42:39 -08004971 (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004972 (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
4973 !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004974 hostapd_drv_sta_remove(hapd, sta->addr);
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004975 wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
4976 set = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08004977
4978 /* Do not allow the FT-over-DS exception to be used more than
4979 * once per authentication exchange to guarantee a new TK is
4980 * used here */
4981 sta->ft_over_ds = 0;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004982 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004983
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004984 if (sta->flags & WLAN_STA_HT)
4985 hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004986#ifdef CONFIG_IEEE80211AC
4987 if (sta->flags & WLAN_STA_VHT)
4988 hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
4989#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07004990#ifdef CONFIG_IEEE80211AX
4991 if (sta->flags & WLAN_STA_HE) {
4992 hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
4993 sta->he_capab_len);
4994 }
4995#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07004996#ifdef CONFIG_IEEE80211BE
4997 if (sta->flags & WLAN_STA_EHT)
4998 hostapd_get_eht_capab(hapd, sta->eht_capab, &eht_cap,
4999 sta->eht_capab_len);
5000#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005001
5002 /*
5003 * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
5004 * will be set when the ACK frame for the (Re)Association Response frame
5005 * is processed (TX status driver event).
5006 */
5007 if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
5008 sta->supported_rates, sta->supported_rates_len,
5009 sta->listen_interval,
5010 sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
5011 sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
Hai Shalom81f62d82019-07-22 12:10:00 -07005012 sta->flags & WLAN_STA_HE ? &he_cap : NULL,
5013 sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
Sunil Ravia04bd252022-05-02 22:54:18 -07005014 sta->flags & WLAN_STA_EHT ? &eht_cap : NULL,
5015 sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005016 sta->he_6ghz_capab,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005017 sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005018 sta->vht_opmode, sta->p2p_ie ? 1 : 0,
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02005019 set)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005020 hostapd_logger(hapd, sta->addr,
5021 HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
5022 "Could not %s STA to kernel driver",
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02005023 set ? "set" : "add");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005024
5025 if (sta->added_unassoc) {
5026 hostapd_drv_sta_remove(hapd, sta->addr);
5027 sta->added_unassoc = 0;
5028 }
5029
5030 return -1;
5031 }
5032
5033 sta->added_unassoc = 0;
5034
5035 return 0;
5036}
5037
5038
5039static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt29333592017-01-09 12:27:11 -08005040 const u8 *addr, u16 status_code, int reassoc,
Hai Shalomfdcde762020-04-02 11:19:20 -07005041 const u8 *ies, size_t ies_len, int rssi,
5042 int omit_rsnxe)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005043{
5044 int send_len;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005045 u8 *buf;
5046 size_t buflen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005047 struct ieee80211_mgmt *reply;
5048 u8 *p;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005049 u16 res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005050
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005051 buflen = sizeof(struct ieee80211_mgmt) + 1024;
5052#ifdef CONFIG_FILS
5053 if (sta && sta->fils_hlp_resp)
5054 buflen += wpabuf_len(sta->fils_hlp_resp);
Hai Shalom81f62d82019-07-22 12:10:00 -07005055 if (sta)
5056 buflen += 150;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005057#endif /* CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005058#ifdef CONFIG_OWE
5059 if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
5060 buflen += 150;
5061#endif /* CONFIG_OWE */
Hai Shalom021b0b52019-04-10 11:17:58 -07005062#ifdef CONFIG_DPP2
5063 if (sta && sta->dpp_pfs)
5064 buflen += 5 + sta->dpp_pfs->curve->prime_len;
5065#endif /* CONFIG_DPP2 */
Sunil Ravia04bd252022-05-02 22:54:18 -07005066#ifdef CONFIG_IEEE80211BE
5067 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
5068 buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
5069 buflen += 3 + sizeof(struct ieee80211_eht_operation);
5070 }
5071#endif /* CONFIG_IEEE80211BE */
5072
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005073 buf = os_zalloc(buflen);
5074 if (!buf) {
5075 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5076 goto done;
5077 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005078 reply = (struct ieee80211_mgmt *) buf;
5079 reply->frame_control =
5080 IEEE80211_FC(WLAN_FC_TYPE_MGMT,
5081 (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
5082 WLAN_FC_STYPE_ASSOC_RESP));
Dmitry Shmidt29333592017-01-09 12:27:11 -08005083 os_memcpy(reply->da, addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005084 os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
5085 os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
5086
5087 send_len = IEEE80211_HDRLEN;
5088 send_len += sizeof(reply->u.assoc_resp);
5089 reply->u.assoc_resp.capab_info =
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07005090 host_to_le16(hostapd_own_capab_info(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005091 reply->u.assoc_resp.status_code = host_to_le16(status_code);
Dmitry Shmidt29333592017-01-09 12:27:11 -08005092
5093 reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
5094 BIT(14) | BIT(15));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005095 /* Supported rates */
5096 p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
5097 /* Extended supported rates */
5098 p = hostapd_eid_ext_supp_rates(hapd, p);
5099
Hai Shalomfdcde762020-04-02 11:19:20 -07005100 /* Radio measurement capabilities */
5101 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
5102
Hai Shalom74f70d42019-02-11 14:42:39 -08005103#ifdef CONFIG_MBO
5104 if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
5105 rssi != 0) {
5106 int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
5107
5108 p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
5109 delta);
5110 }
5111#endif /* CONFIG_MBO */
5112
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005113#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt29333592017-01-09 12:27:11 -08005114 if (sta && status_code == WLAN_STATUS_SUCCESS) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005115 /* IEEE 802.11r: Mobility Domain Information, Fast BSS
5116 * Transition Information, RSN, [RIC Response] */
5117 p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005118 buf + buflen - p,
Hai Shalomfdcde762020-04-02 11:19:20 -07005119 sta->auth_alg, ies, ies_len,
5120 omit_rsnxe);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005121 if (!p) {
5122 wpa_printf(MSG_DEBUG,
5123 "FT: Failed to write AssocResp IEs");
5124 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5125 goto done;
5126 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005127 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005128#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom81f62d82019-07-22 12:10:00 -07005129#ifdef CONFIG_FILS
5130 if (sta && status_code == WLAN_STATUS_SUCCESS &&
5131 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5132 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5133 sta->auth_alg == WLAN_AUTH_FILS_PK))
5134 p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
5135 buf + buflen - p,
5136 ies, ies_len);
5137#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005138
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005139#ifdef CONFIG_OWE
Hai Shalom74f70d42019-02-11 14:42:39 -08005140 if (sta && status_code == WLAN_STATUS_SUCCESS &&
5141 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005142 p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
5143 buf + buflen - p,
5144 ies, ies_len);
5145#endif /* CONFIG_OWE */
5146
Dmitry Shmidt29333592017-01-09 12:27:11 -08005147 if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005148 p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005149
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005150 p = hostapd_eid_ht_capabilities(hapd, p);
5151 p = hostapd_eid_ht_operation(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005152
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005153#ifdef CONFIG_IEEE80211AC
Hai Shalomc3565922019-10-28 11:58:20 -07005154 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
5155 !is_6ghz_op_class(hapd->iconf->op_class)) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07005156 u32 nsts = 0, sta_nsts;
5157
Dmitry Shmidt29333592017-01-09 12:27:11 -08005158 if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07005159 struct ieee80211_vht_capabilities *capa;
5160
5161 nsts = (hapd->iface->conf->vht_capab >>
5162 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
5163 capa = sta->vht_capabilities;
5164 sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
5165 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
5166
5167 if (nsts < sta_nsts)
5168 nsts = 0;
5169 else
5170 nsts = sta_nsts;
5171 }
5172 p = hostapd_eid_vht_capabilities(hapd, p, nsts);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005173 p = hostapd_eid_vht_operation(hapd, p);
5174 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005175#endif /* CONFIG_IEEE80211AC */
5176
Hai Shalom81f62d82019-07-22 12:10:00 -07005177#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08005178 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07005179 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
5180 p = hostapd_eid_he_operation(hapd, p);
Sunil Ravia04bd252022-05-02 22:54:18 -07005181 p = hostapd_eid_cca(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07005182 p = hostapd_eid_spatial_reuse(hapd, p);
5183 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005184 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07005185 }
5186#endif /* CONFIG_IEEE80211AX */
5187
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005188 p = hostapd_eid_ext_capab(hapd, p);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005189 p = hostapd_eid_bss_max_idle_period(hapd, p);
Dmitry Shmidt29333592017-01-09 12:27:11 -08005190 if (sta && sta->qos_map_enabled)
Dmitry Shmidt051af732013-10-22 13:52:46 -07005191 p = hostapd_eid_qos_map_set(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005192
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005193#ifdef CONFIG_FST
5194 if (hapd->iface->fst_ies) {
5195 os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
5196 wpabuf_len(hapd->iface->fst_ies));
5197 p += wpabuf_len(hapd->iface->fst_ies);
5198 }
5199#endif /* CONFIG_FST */
5200
Hai Shalomfdcde762020-04-02 11:19:20 -07005201#ifdef CONFIG_TESTING_OPTIONS
5202 if (hapd->conf->rsnxe_override_ft &&
5203 buf + buflen - p >=
5204 (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
5205 sta && sta->auth_alg == WLAN_AUTH_FT) {
5206 wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
5207 os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
5208 wpabuf_len(hapd->conf->rsnxe_override_ft));
5209 p += wpabuf_len(hapd->conf->rsnxe_override_ft);
5210 goto rsnxe_done;
5211 }
5212#endif /* CONFIG_TESTING_OPTIONS */
5213 if (!omit_rsnxe)
5214 p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
5215#ifdef CONFIG_TESTING_OPTIONS
5216rsnxe_done:
5217#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomc3565922019-10-28 11:58:20 -07005218
Sunil Ravia04bd252022-05-02 22:54:18 -07005219#ifdef CONFIG_IEEE80211BE
5220 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
5221 p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
5222 p = hostapd_eid_eht_operation(hapd, p);
5223 }
5224#endif /* CONFIG_IEEE80211BE */
5225
Hai Shalom021b0b52019-04-10 11:17:58 -07005226#ifdef CONFIG_OWE
5227 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
5228 sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
Hai Shalom899fcc72020-10-19 14:38:18 -07005229 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
5230 !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07005231 struct wpabuf *pub;
5232
5233 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
5234 if (!pub) {
5235 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5236 goto done;
5237 }
5238 /* OWE Diffie-Hellman Parameter element */
5239 *p++ = WLAN_EID_EXTENSION; /* Element ID */
5240 *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
5241 *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
5242 WPA_PUT_LE16(p, sta->owe_group);
5243 p += 2;
5244 os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
5245 p += wpabuf_len(pub);
5246 wpabuf_free(pub);
5247 }
5248#endif /* CONFIG_OWE */
5249
5250#ifdef CONFIG_DPP2
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005251 if (DPP_VERSION > 1 && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07005252 sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
5253 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
5254 os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
5255 wpabuf_len(sta->dpp_pfs->ie));
5256 p += wpabuf_len(sta->dpp_pfs->ie);
5257 }
5258#endif /* CONFIG_DPP2 */
5259
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005260#ifdef CONFIG_IEEE80211AC
Dmitry Shmidt29333592017-01-09 12:27:11 -08005261 if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005262 p = hostapd_eid_vendor_vht(hapd, p);
5263#endif /* CONFIG_IEEE80211AC */
5264
Dmitry Shmidt29333592017-01-09 12:27:11 -08005265 if (sta && (sta->flags & WLAN_STA_WMM))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005266 p = hostapd_eid_wmm(hapd, p);
5267
5268#ifdef CONFIG_WPS
Dmitry Shmidt29333592017-01-09 12:27:11 -08005269 if (sta &&
5270 ((sta->flags & WLAN_STA_WPS) ||
5271 ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005272 struct wpabuf *wps = wps_build_assoc_resp_ie();
5273 if (wps) {
5274 os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
5275 p += wpabuf_len(wps);
5276 wpabuf_free(wps);
5277 }
5278 }
5279#endif /* CONFIG_WPS */
5280
Hai Shalom74f70d42019-02-11 14:42:39 -08005281 if (sta && (sta->flags & WLAN_STA_MULTI_AP))
5282 p = hostapd_eid_multi_ap(hapd, p);
5283
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005284#ifdef CONFIG_P2P
Dmitry Shmidt29333592017-01-09 12:27:11 -08005285 if (sta && sta->p2p_ie && hapd->p2p_group) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005286 struct wpabuf *p2p_resp_ie;
5287 enum p2p_status_code status;
5288 switch (status_code) {
5289 case WLAN_STATUS_SUCCESS:
5290 status = P2P_SC_SUCCESS;
5291 break;
5292 case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
5293 status = P2P_SC_FAIL_LIMIT_REACHED;
5294 break;
5295 default:
5296 status = P2P_SC_FAIL_INVALID_PARAMS;
5297 break;
5298 }
5299 p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
5300 if (p2p_resp_ie) {
5301 os_memcpy(p, wpabuf_head(p2p_resp_ie),
5302 wpabuf_len(p2p_resp_ie));
5303 p += wpabuf_len(p2p_resp_ie);
5304 wpabuf_free(p2p_resp_ie);
5305 }
5306 }
5307#endif /* CONFIG_P2P */
5308
5309#ifdef CONFIG_P2P_MANAGER
5310 if (hapd->conf->p2p & P2P_MANAGE)
5311 p = hostapd_eid_p2p_manage(hapd, p);
5312#endif /* CONFIG_P2P_MANAGER */
5313
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005314 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005315
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005316 if (hapd->conf->assocresp_elements &&
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005317 (size_t) (buf + buflen - p) >=
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005318 wpabuf_len(hapd->conf->assocresp_elements)) {
5319 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
5320 wpabuf_len(hapd->conf->assocresp_elements));
5321 p += wpabuf_len(hapd->conf->assocresp_elements);
5322 }
5323
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005324 send_len += p - reply->u.assoc_resp.variable;
5325
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005326#ifdef CONFIG_FILS
Dmitry Shmidt29333592017-01-09 12:27:11 -08005327 if (sta &&
5328 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005329 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5330 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
5331 status_code == WLAN_STATUS_SUCCESS) {
5332 struct ieee802_11_elems elems;
5333
5334 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005335 ParseFailed || !elems.fils_session) {
5336 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5337 goto done;
5338 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005339
5340 /* FILS Session */
5341 *p++ = WLAN_EID_EXTENSION; /* Element ID */
5342 *p++ = 1 + FILS_SESSION_LEN; /* Length */
5343 *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
5344 os_memcpy(p, elems.fils_session, FILS_SESSION_LEN);
5345 send_len += 2 + 1 + FILS_SESSION_LEN;
5346
5347 send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005348 buflen, sta->fils_hlp_resp);
5349 if (send_len < 0) {
5350 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5351 goto done;
5352 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005353 }
5354#endif /* CONFIG_FILS */
5355
Hai Shalomfdcde762020-04-02 11:19:20 -07005356 if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005357 wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
5358 strerror(errno));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005359 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005360 }
5361
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005362done:
5363 os_free(buf);
5364 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005365}
5366
5367
Roshan Pius3a1667e2018-07-03 15:17:14 -07005368#ifdef CONFIG_OWE
5369u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
5370 const u8 *owe_dh, u8 owe_dh_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07005371 u8 *owe_buf, size_t owe_buf_len, u16 *status)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005372{
5373#ifdef CONFIG_TESTING_OPTIONS
5374 if (hapd->conf->own_ie_override) {
5375 wpa_printf(MSG_DEBUG, "OWE: Using IE override");
Hai Shalomfdcde762020-04-02 11:19:20 -07005376 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005377 return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5378 owe_buf_len, NULL, 0);
5379 }
5380#endif /* CONFIG_TESTING_OPTIONS */
5381
5382 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
5383 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
5384 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5385 owe_buf_len, NULL, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -07005386 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005387 return owe_buf;
5388 }
5389
Hai Shalom81f62d82019-07-22 12:10:00 -07005390 if (sta->owe_pmk && sta->external_dh_updated) {
5391 wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
Hai Shalomfdcde762020-04-02 11:19:20 -07005392 *status = WLAN_STATUS_SUCCESS;
Hai Shalom81f62d82019-07-22 12:10:00 -07005393 return owe_buf;
5394 }
5395
Hai Shalomfdcde762020-04-02 11:19:20 -07005396 *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
5397 if (*status != WLAN_STATUS_SUCCESS)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005398 return NULL;
5399
5400 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5401 owe_buf_len, NULL, 0);
5402
5403 if (sta->owe_ecdh && owe_buf) {
5404 struct wpabuf *pub;
5405
5406 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
5407 if (!pub) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005408 *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005409 return owe_buf;
5410 }
5411
5412 /* OWE Diffie-Hellman Parameter element */
5413 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
5414 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
5415 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
5416 */
5417 WPA_PUT_LE16(owe_buf, sta->owe_group);
5418 owe_buf += 2;
5419 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
5420 owe_buf += wpabuf_len(pub);
5421 wpabuf_free(pub);
5422 }
5423
5424 return owe_buf;
5425}
5426#endif /* CONFIG_OWE */
5427
5428
Paul Stewart092955c2017-02-06 09:13:09 -08005429#ifdef CONFIG_FILS
5430
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005431void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
Paul Stewart092955c2017-02-06 09:13:09 -08005432{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005433 u16 reply_res;
Paul Stewart092955c2017-02-06 09:13:09 -08005434
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005435 wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
5436 MAC2STR(sta->addr));
5437 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5438 if (!sta->fils_pending_assoc_req)
Paul Stewart092955c2017-02-06 09:13:09 -08005439 return;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005440 reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
5441 sta->fils_pending_assoc_is_reassoc,
5442 sta->fils_pending_assoc_req,
Hai Shalomfdcde762020-04-02 11:19:20 -07005443 sta->fils_pending_assoc_req_len, 0, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005444 os_free(sta->fils_pending_assoc_req);
5445 sta->fils_pending_assoc_req = NULL;
5446 sta->fils_pending_assoc_req_len = 0;
5447 wpabuf_free(sta->fils_hlp_resp);
5448 sta->fils_hlp_resp = NULL;
5449 wpabuf_free(sta->hlp_dhcp_discover);
5450 sta->hlp_dhcp_discover = NULL;
Paul Stewart092955c2017-02-06 09:13:09 -08005451
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005452 /*
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005453 * Remove the station in case transmission of a success response fails.
5454 * At this point the station was already added associated to the driver.
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005455 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005456 if (reply_res != WLAN_STATUS_SUCCESS)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005457 hostapd_drv_sta_remove(hapd, sta->addr);
Paul Stewart092955c2017-02-06 09:13:09 -08005458}
5459
5460
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005461void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
Paul Stewart092955c2017-02-06 09:13:09 -08005462{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005463 struct hostapd_data *hapd = eloop_ctx;
5464 struct sta_info *sta = eloop_data;
Paul Stewart092955c2017-02-06 09:13:09 -08005465
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005466 wpa_printf(MSG_DEBUG,
5467 "FILS: HLP response timeout - continue with association response for "
5468 MACSTR, MAC2STR(sta->addr));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005469 if (sta->fils_drv_assoc_finish)
5470 hostapd_notify_assoc_fils_finish(hapd, sta);
5471 else
5472 fils_hlp_finish_assoc(hapd, sta);
Paul Stewart092955c2017-02-06 09:13:09 -08005473}
5474
5475#endif /* CONFIG_FILS */
5476
5477
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005478static void handle_assoc(struct hostapd_data *hapd,
5479 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom74f70d42019-02-11 14:42:39 -08005480 int reassoc, int rssi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005481{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005482 u16 capab_info, listen_interval, seq_ctrl, fc;
Hai Shalomb755a2a2020-04-23 21:49:02 -07005483 int resp = WLAN_STATUS_SUCCESS;
Hai Shalom899fcc72020-10-19 14:38:18 -07005484 u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005485 const u8 *pos;
5486 int left, i;
5487 struct sta_info *sta;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005488 u8 *tmp = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005489#ifdef CONFIG_FILS
5490 int delay_assoc = 0;
5491#endif /* CONFIG_FILS */
Hai Shalomfdcde762020-04-02 11:19:20 -07005492 int omit_rsnxe = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005493
5494 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
5495 sizeof(mgmt->u.assoc_req))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005496 wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
5497 reassoc, (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005498 return;
5499 }
5500
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005501#ifdef CONFIG_TESTING_OPTIONS
5502 if (reassoc) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005503 if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005504 drand48() < hapd->iconf->ignore_reassoc_probability) {
5505 wpa_printf(MSG_INFO,
5506 "TESTING: ignoring reassoc request from "
5507 MACSTR, MAC2STR(mgmt->sa));
5508 return;
5509 }
5510 } else {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005511 if (hapd->iconf->ignore_assoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005512 drand48() < hapd->iconf->ignore_assoc_probability) {
5513 wpa_printf(MSG_INFO,
5514 "TESTING: ignoring assoc request from "
5515 MACSTR, MAC2STR(mgmt->sa));
5516 return;
5517 }
5518 }
5519#endif /* CONFIG_TESTING_OPTIONS */
5520
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005521 fc = le_to_host16(mgmt->frame_control);
5522 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
5523
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005524 if (reassoc) {
5525 capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
5526 listen_interval = le_to_host16(
5527 mgmt->u.reassoc_req.listen_interval);
5528 wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
5529 " capab_info=0x%02x listen_interval=%d current_ap="
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005530 MACSTR " seq_ctrl=0x%x%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005531 MAC2STR(mgmt->sa), capab_info, listen_interval,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005532 MAC2STR(mgmt->u.reassoc_req.current_ap),
5533 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005534 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
5535 pos = mgmt->u.reassoc_req.variable;
5536 } else {
5537 capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
5538 listen_interval = le_to_host16(
5539 mgmt->u.assoc_req.listen_interval);
5540 wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005541 " capab_info=0x%02x listen_interval=%d "
5542 "seq_ctrl=0x%x%s",
5543 MAC2STR(mgmt->sa), capab_info, listen_interval,
5544 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005545 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
5546 pos = mgmt->u.assoc_req.variable;
5547 }
5548
5549 sta = ap_get_sta(hapd, mgmt->sa);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005550#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005551 if (sta && sta->auth_alg == WLAN_AUTH_FT &&
5552 (sta->flags & WLAN_STA_AUTH) == 0) {
5553 wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
5554 "prior to authentication since it is using "
5555 "over-the-DS FT", MAC2STR(mgmt->sa));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005556
5557 /*
5558 * Mark station as authenticated, to avoid adding station
5559 * entry in the driver as associated and not authenticated
5560 */
5561 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005562 } else
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005563#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005564 if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
Dmitry Shmidt29333592017-01-09 12:27:11 -08005565 if (hapd->iface->current_mode &&
5566 hapd->iface->current_mode->mode ==
5567 HOSTAPD_MODE_IEEE80211AD) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005568 int acl_res;
Hai Shalomfdcde762020-04-02 11:19:20 -07005569 struct radius_sta info;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005570
Hai Shalomfdcde762020-04-02 11:19:20 -07005571 acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
5572 (const u8 *) mgmt,
5573 len, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005574 if (acl_res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005575 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5576 "Ignore Association Request frame from "
5577 MACSTR " due to ACL reject",
5578 MAC2STR(mgmt->sa));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005579 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5580 goto fail;
5581 }
5582 if (acl_res == HOSTAPD_ACL_PENDING)
5583 return;
5584
Dmitry Shmidt29333592017-01-09 12:27:11 -08005585 /* DMG/IEEE 802.11ad does not use authentication.
5586 * Allocate sta entry upon association. */
5587 sta = ap_sta_add(hapd, mgmt->sa);
5588 if (!sta) {
5589 hostapd_logger(hapd, mgmt->sa,
5590 HOSTAPD_MODULE_IEEE80211,
5591 HOSTAPD_LEVEL_INFO,
5592 "Failed to add STA");
5593 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5594 goto fail;
5595 }
5596
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005597 acl_res = ieee802_11_set_radius_info(
Hai Shalomfdcde762020-04-02 11:19:20 -07005598 hapd, sta, acl_res, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005599 if (acl_res) {
5600 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5601 goto fail;
5602 }
5603
Dmitry Shmidt29333592017-01-09 12:27:11 -08005604 hostapd_logger(hapd, sta->addr,
5605 HOSTAPD_MODULE_IEEE80211,
5606 HOSTAPD_LEVEL_DEBUG,
5607 "Skip authentication for DMG/IEEE 802.11ad");
5608 sta->flags |= WLAN_STA_AUTH;
5609 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
5610 sta->auth_alg = WLAN_AUTH_OPEN;
5611 } else {
5612 hostapd_logger(hapd, mgmt->sa,
5613 HOSTAPD_MODULE_IEEE80211,
5614 HOSTAPD_LEVEL_INFO,
5615 "Station tried to associate before authentication (aid=%d flags=0x%x)",
5616 sta ? sta->aid : -1,
5617 sta ? sta->flags : 0);
5618 send_deauth(hapd, mgmt->sa,
5619 WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
5620 return;
5621 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005622 }
5623
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005624 if ((fc & WLAN_FC_RETRY) &&
5625 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
5626 sta->last_seq_ctrl == seq_ctrl &&
Paul Stewart092955c2017-02-06 09:13:09 -08005627 sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5628 WLAN_FC_STYPE_ASSOC_REQ)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005629 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5630 HOSTAPD_LEVEL_DEBUG,
5631 "Drop repeated association frame seq_ctrl=0x%x",
5632 seq_ctrl);
5633 return;
5634 }
5635 sta->last_seq_ctrl = seq_ctrl;
5636 sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5637 WLAN_FC_STYPE_ASSOC_REQ;
5638
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005639 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005640 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005641 goto fail;
5642 }
5643
5644 if (listen_interval > hapd->conf->max_listen_interval) {
5645 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5646 HOSTAPD_LEVEL_DEBUG,
5647 "Too large Listen Interval (%d)",
5648 listen_interval);
5649 resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
5650 goto fail;
5651 }
5652
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005653#ifdef CONFIG_MBO
5654 if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
5655 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5656 goto fail;
5657 }
Hai Shalom74f70d42019-02-11 14:42:39 -08005658
5659 if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
5660 rssi < hapd->iconf->rssi_reject_assoc_rssi &&
5661 (sta->auth_rssi == 0 ||
5662 sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
5663 resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
5664 goto fail;
5665 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005666#endif /* CONFIG_MBO */
5667
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005668 /*
5669 * sta->capability is used in check_assoc_ies() for RRM enabled
5670 * capability element.
5671 */
5672 sta->capability = capab_info;
5673
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005674#ifdef CONFIG_FILS
5675 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5676 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5677 sta->auth_alg == WLAN_AUTH_FILS_PK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005678 int res;
5679
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005680 /* The end of the payload is encrypted. Need to decrypt it
5681 * before parsing. */
5682
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005683 tmp = os_memdup(pos, left);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005684 if (!tmp) {
5685 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5686 goto fail;
5687 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005688
Roshan Pius3a1667e2018-07-03 15:17:14 -07005689 res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
5690 len, tmp, left);
5691 if (res < 0) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005692 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5693 goto fail;
5694 }
5695 pos = tmp;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005696 left = res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005697 }
5698#endif /* CONFIG_FILS */
5699
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005700 /* followed by SSID and Supported rates; and HT capabilities if 802.11n
5701 * is used */
5702 resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
5703 if (resp != WLAN_STATUS_SUCCESS)
5704 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07005705 omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005706
5707 if (hostapd_get_aid(hapd, sta) < 0) {
5708 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5709 HOSTAPD_LEVEL_INFO, "No room for more AIDs");
5710 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5711 goto fail;
5712 }
5713
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005714 sta->listen_interval = listen_interval;
5715
Roshan Pius3a1667e2018-07-03 15:17:14 -07005716 if (hapd->iface->current_mode &&
5717 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005718 sta->flags |= WLAN_STA_NONERP;
5719 for (i = 0; i < sta->supported_rates_len; i++) {
5720 if ((sta->supported_rates[i] & 0x7f) > 22) {
5721 sta->flags &= ~WLAN_STA_NONERP;
5722 break;
5723 }
5724 }
5725 if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
5726 sta->nonerp_set = 1;
5727 hapd->iface->num_sta_non_erp++;
5728 if (hapd->iface->num_sta_non_erp == 1)
5729 ieee802_11_set_beacons(hapd->iface);
5730 }
5731
5732 if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
5733 !sta->no_short_slot_time_set) {
5734 sta->no_short_slot_time_set = 1;
5735 hapd->iface->num_sta_no_short_slot_time++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005736 if (hapd->iface->current_mode &&
5737 hapd->iface->current_mode->mode ==
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005738 HOSTAPD_MODE_IEEE80211G &&
5739 hapd->iface->num_sta_no_short_slot_time == 1)
5740 ieee802_11_set_beacons(hapd->iface);
5741 }
5742
5743 if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
5744 sta->flags |= WLAN_STA_SHORT_PREAMBLE;
5745 else
5746 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
5747
5748 if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
5749 !sta->no_short_preamble_set) {
5750 sta->no_short_preamble_set = 1;
5751 hapd->iface->num_sta_no_short_preamble++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005752 if (hapd->iface->current_mode &&
5753 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005754 && hapd->iface->num_sta_no_short_preamble == 1)
5755 ieee802_11_set_beacons(hapd->iface);
5756 }
5757
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005758 update_ht_state(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005759
5760 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5761 HOSTAPD_LEVEL_DEBUG,
5762 "association OK (aid %d)", sta->aid);
5763 /* Station will be marked associated, after it acknowledges AssocResp
5764 */
5765 sta->flags |= WLAN_STA_ASSOC_REQ_OK;
5766
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005767 if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
5768 wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
5769 "SA Query procedure", reassoc ? "re" : "");
5770 /* TODO: Send a protected Disassociate frame to the STA using
5771 * the old key and Reason Code "Previous Authentication no
5772 * longer valid". Make sure this is only sent protected since
5773 * unprotected frame would be received by the STA that is now
5774 * trying to associate.
5775 */
5776 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005777
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005778 /* Make sure that the previously registered inactivity timer will not
5779 * remove the STA immediately. */
5780 sta->timeout_next = STA_NULLFUNC;
5781
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005782#ifdef CONFIG_TAXONOMY
5783 taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
5784#endif /* CONFIG_TAXONOMY */
5785
Dmitry Shmidt29333592017-01-09 12:27:11 -08005786 sta->pending_wds_enable = 0;
5787
Paul Stewart092955c2017-02-06 09:13:09 -08005788#ifdef CONFIG_FILS
5789 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5790 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005791 sta->auth_alg == WLAN_AUTH_FILS_PK) {
5792 if (fils_process_hlp(hapd, sta, pos, left) > 0)
5793 delay_assoc = 1;
5794 }
Paul Stewart092955c2017-02-06 09:13:09 -08005795#endif /* CONFIG_FILS */
5796
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005797 fail:
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005798
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005799 /*
5800 * In case of a successful response, add the station to the driver.
5801 * Otherwise, the kernel may ignore Data frames before we process the
5802 * ACK frame (TX status). In case of a failure, this station will be
5803 * removed.
5804 *
5805 * Note that this is not compliant with the IEEE 802.11 standard that
5806 * states that a non-AP station should transition into the
5807 * authenticated/associated state only after the station acknowledges
5808 * the (Re)Association Response frame. However, still do this as:
5809 *
5810 * 1. In case the station does not acknowledge the (Re)Association
5811 * Response frame, it will be removed.
5812 * 2. Data frames will be dropped in the kernel until the station is
5813 * set into authorized state, and there are no significant known
5814 * issues with processing other non-Data Class 3 frames during this
5815 * window.
5816 */
Hai Shalom74f70d42019-02-11 14:42:39 -08005817 if (resp == WLAN_STATUS_SUCCESS && sta &&
5818 add_associated_sta(hapd, sta, reassoc))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005819 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5820
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005821#ifdef CONFIG_FILS
Hai Shalom74f70d42019-02-11 14:42:39 -08005822 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
5823 eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
5824 sta->fils_pending_assoc_req) {
5825 /* Do not reschedule fils_hlp_timeout in case the station
5826 * retransmits (Re)Association Request frame while waiting for
5827 * the previously started FILS HLP wait, so that the timeout can
5828 * be determined from the first pending attempt. */
5829 wpa_printf(MSG_DEBUG,
5830 "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
5831 MACSTR, MAC2STR(sta->addr));
5832 os_free(tmp);
5833 return;
5834 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005835 if (sta) {
5836 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5837 os_free(sta->fils_pending_assoc_req);
5838 sta->fils_pending_assoc_req = NULL;
5839 sta->fils_pending_assoc_req_len = 0;
5840 wpabuf_free(sta->fils_hlp_resp);
5841 sta->fils_hlp_resp = NULL;
5842 }
5843 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
5844 sta->fils_pending_assoc_req = tmp;
5845 sta->fils_pending_assoc_req_len = left;
5846 sta->fils_pending_assoc_is_reassoc = reassoc;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005847 sta->fils_drv_assoc_finish = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005848 wpa_printf(MSG_DEBUG,
5849 "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
5850 MACSTR, MAC2STR(sta->addr));
5851 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5852 eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
5853 fils_hlp_timeout, hapd, sta);
5854 return;
5855 }
5856#endif /* CONFIG_FILS */
5857
Hai Shalomb755a2a2020-04-23 21:49:02 -07005858 if (resp >= 0)
5859 reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc,
5860 pos, left, rssi, omit_rsnxe);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005861 os_free(tmp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005862
5863 /*
Hai Shalom899fcc72020-10-19 14:38:18 -07005864 * Remove the station in case transmission of a success response fails
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005865 * (the STA was added associated to the driver) or if the station was
5866 * previously added unassociated.
5867 */
Dmitry Shmidt29333592017-01-09 12:27:11 -08005868 if (sta && ((reply_res != WLAN_STATUS_SUCCESS &&
5869 resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005870 hostapd_drv_sta_remove(hapd, sta->addr);
5871 sta->added_unassoc = 0;
5872 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005873}
5874
5875
5876static void handle_disassoc(struct hostapd_data *hapd,
5877 const struct ieee80211_mgmt *mgmt, size_t len)
5878{
5879 struct sta_info *sta;
5880
5881 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005882 wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)",
5883 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005884 return;
5885 }
5886
5887 wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
5888 MAC2STR(mgmt->sa),
5889 le_to_host16(mgmt->u.disassoc.reason_code));
5890
5891 sta = ap_get_sta(hapd, mgmt->sa);
5892 if (sta == NULL) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005893 wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated",
5894 MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005895 return;
5896 }
5897
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005898 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005899 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005900 sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07005901 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005902 wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
5903 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5904 HOSTAPD_LEVEL_INFO, "disassociated");
5905 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5906 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5907 /* Stop Accounting and IEEE 802.1X sessions, but leave the STA
5908 * authenticated. */
5909 accounting_sta_stop(hapd, sta);
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005910 ieee802_1x_free_station(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005911 if (sta->ipaddr)
5912 hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
5913 ap_sta_ip6addr_del(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005914 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005915 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005916
5917 if (sta->timeout_next == STA_NULLFUNC ||
5918 sta->timeout_next == STA_DISASSOC) {
5919 sta->timeout_next = STA_DEAUTH;
5920 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
5921 eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
5922 hapd, sta);
5923 }
5924
5925 mlme_disassociate_indication(
5926 hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt29333592017-01-09 12:27:11 -08005927
5928 /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon
5929 * disassociation. */
5930 if (hapd->iface->current_mode &&
5931 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
5932 sta->flags &= ~WLAN_STA_AUTH;
5933 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5934 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5935 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5936 ap_free_sta(hapd, sta);
5937 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005938}
5939
5940
5941static void handle_deauth(struct hostapd_data *hapd,
5942 const struct ieee80211_mgmt *mgmt, size_t len)
5943{
5944 struct sta_info *sta;
5945
5946 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005947 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short "
5948 "payload (len=%lu)", (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005949 return;
5950 }
5951
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005952 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005953 " reason_code=%d",
5954 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
5955
Hai Shaloma20dcd72022-02-04 13:43:00 -08005956 /* Clear the PTKSA cache entries for PASN */
5957 ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
5958
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005959 sta = ap_get_sta(hapd, mgmt->sa);
5960 if (sta == NULL) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005961 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
5962 "to deauthenticate, but it is not authenticated",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005963 MAC2STR(mgmt->sa));
5964 return;
5965 }
5966
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005967 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005968 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005969 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
5970 WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07005971 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005972 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5973 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5974 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5975 mlme_deauthenticate_indication(
5976 hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
5977 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5978 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5979 ap_free_sta(hapd, sta);
5980}
5981
5982
5983static void handle_beacon(struct hostapd_data *hapd,
5984 const struct ieee80211_mgmt *mgmt, size_t len,
5985 struct hostapd_frame_info *fi)
5986{
5987 struct ieee802_11_elems elems;
5988
5989 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005990 wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
5991 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005992 return;
5993 }
5994
5995 (void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
5996 len - (IEEE80211_HDRLEN +
5997 sizeof(mgmt->u.beacon)), &elems,
5998 0);
5999
6000 ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
6001}
6002
6003
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006004static int robust_action_frame(u8 category)
6005{
6006 return category != WLAN_ACTION_PUBLIC &&
6007 category != WLAN_ACTION_HT;
6008}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006009
6010
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006011static int handle_action(struct hostapd_data *hapd,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006012 const struct ieee80211_mgmt *mgmt, size_t len,
6013 unsigned int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006014{
6015 struct sta_info *sta;
Hai Shalom74f70d42019-02-11 14:42:39 -08006016 u8 *action __maybe_unused;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006017
Hai Shalom74f70d42019-02-11 14:42:39 -08006018 if (len < IEEE80211_HDRLEN + 2 + 1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006019 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6020 HOSTAPD_LEVEL_DEBUG,
6021 "handle_action - too short payload (len=%lu)",
6022 (unsigned long) len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006023 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006024 }
6025
Hai Shalom74f70d42019-02-11 14:42:39 -08006026 action = (u8 *) &mgmt->u.action.u;
6027 wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
6028 " da " MACSTR " len %d freq %u",
6029 mgmt->u.action.category, *action,
6030 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
6031
6032 sta = ap_get_sta(hapd, mgmt->sa);
6033
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006034 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
6035 (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
6036 wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
6037 "frame (category=%u) from unassociated STA " MACSTR,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08006038 mgmt->u.action.category, MAC2STR(mgmt->sa));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006039 return 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006040 }
6041
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006042 if (sta && (sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt18463232014-01-24 12:29:41 -08006043 !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
6044 robust_action_frame(mgmt->u.action.category)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006045 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6046 HOSTAPD_LEVEL_DEBUG,
6047 "Dropped unprotected Robust Action frame from "
6048 "an MFP STA");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006049 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006050 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006051
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006052 if (sta) {
6053 u16 fc = le_to_host16(mgmt->frame_control);
6054 u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
6055
6056 if ((fc & WLAN_FC_RETRY) &&
6057 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
6058 sta->last_seq_ctrl == seq_ctrl &&
6059 sta->last_subtype == WLAN_FC_STYPE_ACTION) {
6060 hostapd_logger(hapd, sta->addr,
6061 HOSTAPD_MODULE_IEEE80211,
6062 HOSTAPD_LEVEL_DEBUG,
6063 "Drop repeated action frame seq_ctrl=0x%x",
6064 seq_ctrl);
6065 return 1;
6066 }
6067
6068 sta->last_seq_ctrl = seq_ctrl;
6069 sta->last_subtype = WLAN_FC_STYPE_ACTION;
6070 }
6071
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006072 switch (mgmt->u.action.category) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006073#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006074 case WLAN_ACTION_FT:
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006075 if (!sta ||
6076 wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006077 len - IEEE80211_HDRLEN))
6078 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006079 return 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006080#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006081 case WLAN_ACTION_WMM:
6082 hostapd_wmm_action(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006083 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006084 case WLAN_ACTION_SA_QUERY:
Hai Shalom021b0b52019-04-10 11:17:58 -07006085 ieee802_11_sa_query_action(hapd, mgmt, len);
6086 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006087#ifdef CONFIG_WNM_AP
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006088 case WLAN_ACTION_WNM:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006089 ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
6090 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006091#endif /* CONFIG_WNM_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006092#ifdef CONFIG_FST
6093 case WLAN_ACTION_FST:
6094 if (hapd->iface->fst)
6095 fst_rx_action(hapd->iface->fst, mgmt, len);
6096 else
6097 wpa_printf(MSG_DEBUG,
6098 "FST: Ignore FST Action frame - no FST attached");
6099 return 1;
6100#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006101 case WLAN_ACTION_PUBLIC:
Dmitry Shmidt18463232014-01-24 12:29:41 -08006102 case WLAN_ACTION_PROTECTED_DUAL:
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07006103 if (len >= IEEE80211_HDRLEN + 2 &&
6104 mgmt->u.action.u.public_action.action ==
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006105 WLAN_PA_20_40_BSS_COEX) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006106 hostapd_2040_coex_action(hapd, mgmt, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006107 return 1;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006108 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006109#ifdef CONFIG_DPP
6110 if (len >= IEEE80211_HDRLEN + 6 &&
6111 mgmt->u.action.u.vs_public_action.action ==
6112 WLAN_PA_VENDOR_SPECIFIC &&
6113 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6114 OUI_WFA &&
6115 mgmt->u.action.u.vs_public_action.variable[0] ==
6116 DPP_OUI_TYPE) {
6117 const u8 *pos, *end;
6118
6119 pos = mgmt->u.action.u.vs_public_action.oui;
6120 end = ((const u8 *) mgmt) + len;
6121 hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006122 freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006123 return 1;
6124 }
6125 if (len >= IEEE80211_HDRLEN + 2 &&
6126 (mgmt->u.action.u.public_action.action ==
6127 WLAN_PA_GAS_INITIAL_RESP ||
6128 mgmt->u.action.u.public_action.action ==
6129 WLAN_PA_GAS_COMEBACK_RESP)) {
6130 const u8 *pos, *end;
6131
6132 pos = &mgmt->u.action.u.public_action.action;
6133 end = ((const u8 *) mgmt) + len;
6134 gas_query_ap_rx(hapd->gas, mgmt->sa,
6135 mgmt->u.action.category,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006136 pos, end - pos, freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006137 return 1;
6138 }
6139#endif /* CONFIG_DPP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006140 if (hapd->public_action_cb) {
6141 hapd->public_action_cb(hapd->public_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006142 (u8 *) mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006143 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006144 if (hapd->public_action_cb2) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -08006145 hapd->public_action_cb2(hapd->public_action_cb2_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006146 (u8 *) mgmt, len, freq);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006147 }
6148 if (hapd->public_action_cb || hapd->public_action_cb2)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006149 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006150 break;
6151 case WLAN_ACTION_VENDOR_SPECIFIC:
6152 if (hapd->vendor_action_cb) {
6153 if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006154 (u8 *) mgmt, len, freq) == 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006155 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006156 }
6157 break;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006158 case WLAN_ACTION_RADIO_MEASUREMENT:
6159 hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
6160 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006161 }
6162
6163 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6164 HOSTAPD_LEVEL_DEBUG,
6165 "handle_action - unknown action category %d or invalid "
6166 "frame",
6167 mgmt->u.action.category);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006168 if (!is_multicast_ether_addr(mgmt->da) &&
6169 !(mgmt->u.action.category & 0x80) &&
6170 !is_multicast_ether_addr(mgmt->sa)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006171 struct ieee80211_mgmt *resp;
6172
6173 /*
6174 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
6175 * Return the Action frame to the source without change
6176 * except that MSB of the Category set to 1.
6177 */
6178 wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
6179 "frame back to sender");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006180 resp = os_memdup(mgmt, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006181 if (resp == NULL)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006182 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006183 os_memcpy(resp->da, resp->sa, ETH_ALEN);
6184 os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
6185 os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
6186 resp->u.action.category |= 0x80;
6187
Hai Shalomfdcde762020-04-02 11:19:20 -07006188 if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006189 wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
6190 "Action frame");
6191 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006192 os_free(resp);
6193 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006194
6195 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006196}
6197
6198
6199/**
Hai Shalom60840252021-02-19 19:02:11 -08006200 * notify_mgmt_frame - Notify of Management frames on the control interface
6201 * @hapd: hostapd BSS data structure (the BSS to which the Management frame was
6202 * sent to)
6203 * @buf: Management frame data (starting from the IEEE 802.11 header)
6204 * @len: Length of frame data in octets
6205 *
6206 * Notify the control interface of any received Management frame.
6207 */
6208static void notify_mgmt_frame(struct hostapd_data *hapd, const u8 *buf,
6209 size_t len)
6210{
6211
6212 int hex_len = len * 2 + 1;
6213 char *hex = os_malloc(hex_len);
6214
6215 if (hex) {
6216 wpa_snprintf_hex(hex, hex_len, buf, len);
6217 wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO,
6218 AP_MGMT_FRAME_RECEIVED "buf=%s", hex);
6219 os_free(hex);
6220 }
6221}
6222
6223
6224/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006225 * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
6226 * @hapd: hostapd BSS data structure (the BSS to which the management frame was
6227 * sent to)
6228 * @buf: management frame data (starting from IEEE 802.11 header)
6229 * @len: length of frame data in octets
6230 * @fi: meta data about received frame (signal level, etc.)
6231 *
6232 * Process all incoming IEEE 802.11 management frames. This will be called for
6233 * each frame received from the kernel driver through wlan#ap interface. In
6234 * addition, it can be called to re-inserted pending frames (e.g., when using
6235 * external RADIUS server as an MAC ACL).
6236 */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006237int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
6238 struct hostapd_frame_info *fi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006239{
6240 struct ieee80211_mgmt *mgmt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006241 u16 fc, stype;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006242 int ret = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006243 unsigned int freq;
6244 int ssi_signal = fi ? fi->ssi_signal : 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006245
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006246 if (len < 24)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006247 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006248
Roshan Pius3a1667e2018-07-03 15:17:14 -07006249 if (fi && fi->freq)
6250 freq = fi->freq;
6251 else
6252 freq = hapd->iface->freq;
6253
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006254 mgmt = (struct ieee80211_mgmt *) buf;
6255 fc = le_to_host16(mgmt->frame_control);
6256 stype = WLAN_FC_GET_STYPE(fc);
6257
Hai Shalomc3565922019-10-28 11:58:20 -07006258 if (is_multicast_ether_addr(mgmt->sa) ||
6259 is_zero_ether_addr(mgmt->sa) ||
6260 os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
6261 /* Do not process any frames with unexpected/invalid SA so that
6262 * we do not add any state for unexpected STA addresses or end
6263 * up sending out frames to unexpected destination. */
6264 wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
6265 " in received frame - ignore this frame silently",
6266 MAC2STR(mgmt->sa));
6267 return 0;
6268 }
6269
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006270 if (stype == WLAN_FC_STYPE_BEACON) {
6271 handle_beacon(hapd, mgmt, len, fi);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006272 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006273 }
6274
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07006275 if (!is_broadcast_ether_addr(mgmt->bssid) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006276#ifdef CONFIG_P2P
6277 /* Invitation responses can be sent with the peer MAC as BSSID */
6278 !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
6279 stype == WLAN_FC_STYPE_ACTION) &&
6280#endif /* CONFIG_P2P */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006281#ifdef CONFIG_MESH
6282 !(hapd->conf->mesh & MESH_ENABLED) &&
6283#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006284 os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006285 wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
6286 MAC2STR(mgmt->bssid));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006287 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006288 }
6289
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006290 if (hapd->iface->state != HAPD_IFACE_ENABLED) {
6291 wpa_printf(MSG_DEBUG, "MGMT: Ignore management frame while interface is not enabled (SA=" MACSTR " DA=" MACSTR " subtype=%u)",
6292 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), stype);
6293 return 1;
6294 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006295
6296 if (stype == WLAN_FC_STYPE_PROBE_REQ) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006297 handle_probe_req(hapd, mgmt, len, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006298 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006299 }
6300
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006301 if ((!is_broadcast_ether_addr(mgmt->da) ||
6302 stype != WLAN_FC_STYPE_ACTION) &&
6303 os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006304 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6305 HOSTAPD_LEVEL_DEBUG,
6306 "MGMT: DA=" MACSTR " not our address",
6307 MAC2STR(mgmt->da));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006308 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006309 }
6310
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006311 if (hapd->iconf->track_sta_max_num)
Roshan Pius3a1667e2018-07-03 15:17:14 -07006312 sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006313
Hai Shalom60840252021-02-19 19:02:11 -08006314 if (hapd->conf->notify_mgmt_frames)
6315 notify_mgmt_frame(hapd, buf, len);
6316
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006317 switch (stype) {
6318 case WLAN_FC_STYPE_AUTH:
6319 wpa_printf(MSG_DEBUG, "mgmt::auth");
Hai Shalom021b0b52019-04-10 11:17:58 -07006320 handle_auth(hapd, mgmt, len, ssi_signal, 0);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006321 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006322 break;
6323 case WLAN_FC_STYPE_ASSOC_REQ:
6324 wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006325 handle_assoc(hapd, mgmt, len, 0, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006326 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006327 break;
6328 case WLAN_FC_STYPE_REASSOC_REQ:
6329 wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006330 handle_assoc(hapd, mgmt, len, 1, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006331 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006332 break;
6333 case WLAN_FC_STYPE_DISASSOC:
6334 wpa_printf(MSG_DEBUG, "mgmt::disassoc");
6335 handle_disassoc(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006336 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006337 break;
6338 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006339 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006340 handle_deauth(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006341 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006342 break;
6343 case WLAN_FC_STYPE_ACTION:
6344 wpa_printf(MSG_DEBUG, "mgmt::action");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006345 ret = handle_action(hapd, mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006346 break;
6347 default:
6348 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6349 HOSTAPD_LEVEL_DEBUG,
6350 "unknown mgmt frame subtype %d", stype);
6351 break;
6352 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006353
6354 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006355}
6356
6357
6358static void handle_auth_cb(struct hostapd_data *hapd,
6359 const struct ieee80211_mgmt *mgmt,
6360 size_t len, int ok)
6361{
6362 u16 auth_alg, auth_transaction, status_code;
6363 struct sta_info *sta;
Hai Shalom60840252021-02-19 19:02:11 -08006364 bool success_status;
Hai Shalome5e28bb2019-01-28 14:51:04 -08006365
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006366 sta = ap_get_sta(hapd, mgmt->da);
6367 if (!sta) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006368 wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
6369 " not found",
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006370 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006371 return;
6372 }
6373
Hai Shalom60840252021-02-19 19:02:11 -08006374 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
6375 wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
6376 (unsigned long) len);
6377 auth_alg = 0;
6378 auth_transaction = 0;
6379 status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
6380 goto fail;
6381 }
6382
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006383 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
6384 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
6385 status_code = le_to_host16(mgmt->u.auth.status_code);
6386
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006387 if (!ok) {
6388 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6389 HOSTAPD_LEVEL_NOTICE,
6390 "did not acknowledge authentication response");
6391 goto fail;
6392 }
6393
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006394 if (status_code == WLAN_STATUS_SUCCESS &&
6395 ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
6396 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
6397 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6398 HOSTAPD_LEVEL_INFO, "authenticated");
6399 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006400 if (sta->added_unassoc)
6401 hostapd_set_sta_flags(hapd, sta);
6402 return;
6403 }
6404
6405fail:
Hai Shalom60840252021-02-19 19:02:11 -08006406 success_status = status_code == WLAN_STATUS_SUCCESS;
6407#ifdef CONFIG_SAE
6408 if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1)
6409 success_status = sae_status_success(hapd, status_code);
6410#endif /* CONFIG_SAE */
6411 if (!success_status && sta->added_unassoc) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006412 hostapd_drv_sta_remove(hapd, sta->addr);
6413 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006414 }
6415}
6416
6417
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006418static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
6419 struct sta_info *sta,
6420 char *ifname_wds)
6421{
Hai Shalomfdcde762020-04-02 11:19:20 -07006422#ifdef CONFIG_WEP
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006423 int i;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07006424 struct hostapd_ssid *ssid = &hapd->conf->ssid;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006425
6426 if (hapd->conf->ieee802_1x || hapd->conf->wpa)
6427 return;
6428
6429 for (i = 0; i < 4; i++) {
6430 if (ssid->wep.key[i] &&
6431 hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
Hai Shalomfdcde762020-04-02 11:19:20 -07006432 0, i == ssid->wep.idx, NULL, 0,
6433 ssid->wep.key[i], ssid->wep.len[i],
6434 i == ssid->wep.idx ?
6435 KEY_FLAG_GROUP_RX_TX_DEFAULT :
6436 KEY_FLAG_GROUP_RX_TX)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006437 wpa_printf(MSG_WARNING,
6438 "Could not set WEP keys for WDS interface; %s",
6439 ifname_wds);
6440 break;
6441 }
6442 }
Hai Shalomfdcde762020-04-02 11:19:20 -07006443#endif /* CONFIG_WEP */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006444}
6445
6446
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006447static void handle_assoc_cb(struct hostapd_data *hapd,
6448 const struct ieee80211_mgmt *mgmt,
6449 size_t len, int reassoc, int ok)
6450{
6451 u16 status;
6452 struct sta_info *sta;
6453 int new_assoc = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006454
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006455 sta = ap_get_sta(hapd, mgmt->da);
6456 if (!sta) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006457 wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
6458 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006459 return;
6460 }
6461
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006462 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
6463 sizeof(mgmt->u.assoc_resp))) {
6464 wpa_printf(MSG_INFO,
6465 "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
6466 reassoc, (unsigned long) len);
6467 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006468 return;
6469 }
6470
6471 if (reassoc)
6472 status = le_to_host16(mgmt->u.reassoc_resp.status_code);
6473 else
6474 status = le_to_host16(mgmt->u.assoc_resp.status_code);
6475
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006476 if (!ok) {
6477 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6478 HOSTAPD_LEVEL_DEBUG,
6479 "did not acknowledge association response");
6480 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
6481 /* The STA is added only in case of SUCCESS */
6482 if (status == WLAN_STATUS_SUCCESS)
6483 hostapd_drv_sta_remove(hapd, sta->addr);
6484
6485 return;
6486 }
6487
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006488 if (status != WLAN_STATUS_SUCCESS)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07006489 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006490
6491 /* Stop previous accounting session, if one is started, and allocate
6492 * new session id for the new session. */
6493 accounting_sta_stop(hapd, sta);
6494
6495 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6496 HOSTAPD_LEVEL_INFO,
6497 "associated (aid %d)",
6498 sta->aid);
6499
6500 if (sta->flags & WLAN_STA_ASSOC)
6501 new_assoc = 0;
6502 sta->flags |= WLAN_STA_ASSOC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006503 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006504 if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
6505 !hapd->conf->osen) ||
6506 sta->auth_alg == WLAN_AUTH_FILS_SK ||
6507 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6508 sta->auth_alg == WLAN_AUTH_FILS_PK ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006509 sta->auth_alg == WLAN_AUTH_FT) {
6510 /*
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006511 * Open, static WEP, FT protocol, or FILS; no separate
6512 * authorization step.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006513 */
6514 ap_sta_set_authorized(hapd, sta, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006515 }
6516
6517 if (reassoc)
6518 mlme_reassociate_indication(hapd, sta);
6519 else
6520 mlme_associate_indication(hapd, sta);
6521
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006522 sta->sa_query_timed_out = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006523
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006524 if (sta->eapol_sm == NULL) {
6525 /*
6526 * This STA does not use RADIUS server for EAP authentication,
6527 * so bind it to the selected VLAN interface now, since the
6528 * interface selection is not going to change anymore.
6529 */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006530 if (ap_sta_bind_vlan(hapd, sta) < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07006531 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006532 } else if (sta->vlan_id) {
6533 /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006534 if (ap_sta_bind_vlan(hapd, sta) < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07006535 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006536 }
6537
6538 hostapd_set_sta_flags(hapd, sta);
6539
Dmitry Shmidt29333592017-01-09 12:27:11 -08006540 if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) {
6541 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA "
6542 MACSTR " based on pending request",
6543 MAC2STR(sta->addr));
6544 sta->pending_wds_enable = 0;
6545 sta->flags |= WLAN_STA_WDS;
6546 }
6547
Hai Shalom74f70d42019-02-11 14:42:39 -08006548 if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) {
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08006549 int ret;
6550 char ifname_wds[IFNAMSIZ + 1];
6551
6552 wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA "
6553 MACSTR " (aid %u)",
6554 MAC2STR(sta->addr), sta->aid);
6555 ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
6556 sta->aid, 1);
6557 if (!ret)
6558 hostapd_set_wds_encryption(hapd, sta, ifname_wds);
6559 }
6560
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006561 if (sta->auth_alg == WLAN_AUTH_FT)
6562 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
6563 else
6564 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
6565 hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006566 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006567
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006568#ifdef CONFIG_FILS
6569 if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
6570 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6571 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
6572 fils_set_tk(sta->wpa_sm) < 0) {
6573 wpa_printf(MSG_DEBUG, "FILS: TK configuration failed");
6574 ap_sta_disconnect(hapd, sta, sta->addr,
6575 WLAN_REASON_UNSPECIFIED);
6576 return;
6577 }
6578#endif /* CONFIG_FILS */
6579
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006580 if (sta->pending_eapol_rx) {
6581 struct os_reltime now, age;
6582
6583 os_get_reltime(&now);
6584 os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
6585 if (age.sec == 0 && age.usec < 200000) {
6586 wpa_printf(MSG_DEBUG,
6587 "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
6588 MAC2STR(sta->addr));
6589 ieee802_1x_receive(
6590 hapd, mgmt->da,
6591 wpabuf_head(sta->pending_eapol_rx->buf),
6592 wpabuf_len(sta->pending_eapol_rx->buf));
6593 }
6594 wpabuf_free(sta->pending_eapol_rx->buf);
6595 os_free(sta->pending_eapol_rx);
6596 sta->pending_eapol_rx = NULL;
6597 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006598}
6599
6600
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006601static void handle_deauth_cb(struct hostapd_data *hapd,
6602 const struct ieee80211_mgmt *mgmt,
6603 size_t len, int ok)
6604{
6605 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006606 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006607 return;
6608 sta = ap_get_sta(hapd, mgmt->da);
6609 if (!sta) {
6610 wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
6611 " not found", MAC2STR(mgmt->da));
6612 return;
6613 }
6614 if (ok)
6615 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
6616 MAC2STR(sta->addr));
6617 else
6618 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6619 "deauth", MAC2STR(sta->addr));
6620
6621 ap_sta_deauth_cb(hapd, sta);
6622}
6623
6624
6625static void handle_disassoc_cb(struct hostapd_data *hapd,
6626 const struct ieee80211_mgmt *mgmt,
6627 size_t len, int ok)
6628{
6629 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006630 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006631 return;
6632 sta = ap_get_sta(hapd, mgmt->da);
6633 if (!sta) {
6634 wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
6635 " not found", MAC2STR(mgmt->da));
6636 return;
6637 }
6638 if (ok)
6639 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
6640 MAC2STR(sta->addr));
6641 else
6642 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6643 "disassoc", MAC2STR(sta->addr));
6644
6645 ap_sta_disassoc_cb(hapd, sta);
6646}
6647
6648
Dmitry Shmidt29333592017-01-09 12:27:11 -08006649static void handle_action_cb(struct hostapd_data *hapd,
6650 const struct ieee80211_mgmt *mgmt,
6651 size_t len, int ok)
6652{
6653 struct sta_info *sta;
Paul Stewart092955c2017-02-06 09:13:09 -08006654 const struct rrm_measurement_report_element *report;
Dmitry Shmidt29333592017-01-09 12:27:11 -08006655
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006656#ifdef CONFIG_DPP
6657 if (len >= IEEE80211_HDRLEN + 6 &&
6658 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6659 mgmt->u.action.u.vs_public_action.action ==
6660 WLAN_PA_VENDOR_SPECIFIC &&
6661 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6662 OUI_WFA &&
6663 mgmt->u.action.u.vs_public_action.variable[0] ==
6664 DPP_OUI_TYPE) {
6665 const u8 *pos, *end;
6666
6667 pos = &mgmt->u.action.u.vs_public_action.variable[1];
6668 end = ((const u8 *) mgmt) + len;
6669 hostapd_dpp_tx_status(hapd, mgmt->da, pos, end - pos, ok);
6670 return;
6671 }
6672 if (len >= IEEE80211_HDRLEN + 2 &&
6673 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6674 (mgmt->u.action.u.public_action.action ==
6675 WLAN_PA_GAS_INITIAL_REQ ||
6676 mgmt->u.action.u.public_action.action ==
6677 WLAN_PA_GAS_COMEBACK_REQ)) {
6678 const u8 *pos, *end;
6679
6680 pos = mgmt->u.action.u.public_action.variable;
6681 end = ((const u8 *) mgmt) + len;
6682 gas_query_ap_tx_status(hapd->gas, mgmt->da, pos, end - pos, ok);
6683 return;
6684 }
6685#endif /* CONFIG_DPP */
Hai Shaloma20dcd72022-02-04 13:43:00 -08006686 if (is_multicast_ether_addr(mgmt->da))
6687 return;
Dmitry Shmidt29333592017-01-09 12:27:11 -08006688 sta = ap_get_sta(hapd, mgmt->da);
6689 if (!sta) {
6690 wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR
6691 " not found", MAC2STR(mgmt->da));
6692 return;
6693 }
6694
Paul Stewart092955c2017-02-06 09:13:09 -08006695 if (len < 24 + 5 + sizeof(*report))
Dmitry Shmidt29333592017-01-09 12:27:11 -08006696 return;
Paul Stewart092955c2017-02-06 09:13:09 -08006697 report = (const struct rrm_measurement_report_element *)
6698 &mgmt->u.action.u.rrm.variable[2];
Dmitry Shmidt29333592017-01-09 12:27:11 -08006699 if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT &&
Paul Stewart092955c2017-02-06 09:13:09 -08006700 mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST &&
6701 report->eid == WLAN_EID_MEASURE_REQUEST &&
6702 report->len >= 3 &&
6703 report->type == MEASURE_TYPE_BEACON)
Dmitry Shmidt29333592017-01-09 12:27:11 -08006704 hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok);
6705}
6706
6707
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006708/**
6709 * ieee802_11_mgmt_cb - Process management frame TX status callback
6710 * @hapd: hostapd BSS data structure (the BSS from which the management frame
6711 * was sent from)
6712 * @buf: management frame data (starting from IEEE 802.11 header)
6713 * @len: length of frame data in octets
6714 * @stype: management frame subtype from frame control field
6715 * @ok: Whether the frame was ACK'ed
6716 */
6717void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
6718 u16 stype, int ok)
6719{
6720 const struct ieee80211_mgmt *mgmt;
6721 mgmt = (const struct ieee80211_mgmt *) buf;
6722
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006723#ifdef CONFIG_TESTING_OPTIONS
6724 if (hapd->ext_mgmt_frame_handling) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006725 size_t hex_len = 2 * len + 1;
6726 char *hex = os_malloc(hex_len);
6727
6728 if (hex) {
6729 wpa_snprintf_hex(hex, hex_len, buf, len);
6730 wpa_msg(hapd->msg_ctx, MSG_INFO,
6731 "MGMT-TX-STATUS stype=%u ok=%d buf=%s",
6732 stype, ok, hex);
6733 os_free(hex);
6734 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006735 return;
6736 }
6737#endif /* CONFIG_TESTING_OPTIONS */
6738
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006739 switch (stype) {
6740 case WLAN_FC_STYPE_AUTH:
6741 wpa_printf(MSG_DEBUG, "mgmt::auth cb");
6742 handle_auth_cb(hapd, mgmt, len, ok);
6743 break;
6744 case WLAN_FC_STYPE_ASSOC_RESP:
6745 wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
6746 handle_assoc_cb(hapd, mgmt, len, 0, ok);
6747 break;
6748 case WLAN_FC_STYPE_REASSOC_RESP:
6749 wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
6750 handle_assoc_cb(hapd, mgmt, len, 1, ok);
6751 break;
6752 case WLAN_FC_STYPE_PROBE_RESP:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006753 wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006754 break;
6755 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006756 wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
6757 handle_deauth_cb(hapd, mgmt, len, ok);
6758 break;
6759 case WLAN_FC_STYPE_DISASSOC:
6760 wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
6761 handle_disassoc_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006762 break;
6763 case WLAN_FC_STYPE_ACTION:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006764 wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006765 handle_action_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006766 break;
6767 default:
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006768 wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006769 break;
6770 }
6771}
6772
6773
6774int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
6775{
6776 /* TODO */
6777 return 0;
6778}
6779
6780
6781int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
6782 char *buf, size_t buflen)
6783{
6784 /* TODO */
6785 return 0;
6786}
6787
6788
6789void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
6790 const u8 *buf, size_t len, int ack)
6791{
6792 struct sta_info *sta;
6793 struct hostapd_iface *iface = hapd->iface;
6794
6795 sta = ap_get_sta(hapd, addr);
6796 if (sta == NULL && iface->num_bss > 1) {
6797 size_t j;
6798 for (j = 0; j < iface->num_bss; j++) {
6799 hapd = iface->bss[j];
6800 sta = ap_get_sta(hapd, addr);
6801 if (sta)
6802 break;
6803 }
6804 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006805 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006806 return;
6807 if (sta->flags & WLAN_STA_PENDING_POLL) {
6808 wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
6809 "activity poll", MAC2STR(sta->addr),
6810 ack ? "ACKed" : "did not ACK");
6811 if (ack)
6812 sta->flags &= ~WLAN_STA_PENDING_POLL;
6813 }
6814
6815 ieee802_1x_tx_status(hapd, sta, buf, len, ack);
6816}
6817
6818
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006819void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
6820 const u8 *data, size_t len, int ack)
6821{
6822 struct sta_info *sta;
6823 struct hostapd_iface *iface = hapd->iface;
6824
6825 sta = ap_get_sta(hapd, dst);
6826 if (sta == NULL && iface->num_bss > 1) {
6827 size_t j;
6828 for (j = 0; j < iface->num_bss; j++) {
6829 hapd = iface->bss[j];
6830 sta = ap_get_sta(hapd, dst);
6831 if (sta)
6832 break;
6833 }
6834 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006835 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
6836 wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA "
6837 MACSTR " that is not currently associated",
6838 MAC2STR(dst));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006839 return;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006840 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006841
6842 ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
6843}
6844
6845
6846void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
6847{
6848 struct sta_info *sta;
6849 struct hostapd_iface *iface = hapd->iface;
6850
6851 sta = ap_get_sta(hapd, addr);
6852 if (sta == NULL && iface->num_bss > 1) {
6853 size_t j;
6854 for (j = 0; j < iface->num_bss; j++) {
6855 hapd = iface->bss[j];
6856 sta = ap_get_sta(hapd, addr);
6857 if (sta)
6858 break;
6859 }
6860 }
6861 if (sta == NULL)
6862 return;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006863 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
6864 MAC2STR(sta->addr));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006865 if (!(sta->flags & WLAN_STA_PENDING_POLL))
6866 return;
6867
6868 wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
6869 "activity poll", MAC2STR(sta->addr));
6870 sta->flags &= ~WLAN_STA_PENDING_POLL;
6871}
6872
6873
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006874void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
6875 int wds)
6876{
6877 struct sta_info *sta;
6878
6879 sta = ap_get_sta(hapd, src);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006880 if (sta &&
6881 ((sta->flags & WLAN_STA_ASSOC) ||
6882 ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006883 if (!hapd->conf->wds_sta)
6884 return;
6885
Dmitry Shmidt29333592017-01-09 12:27:11 -08006886 if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) ==
6887 WLAN_STA_ASSOC_REQ_OK) {
6888 wpa_printf(MSG_DEBUG,
6889 "Postpone 4-address WDS mode enabling for STA "
6890 MACSTR " since TX status for AssocResp is not yet known",
6891 MAC2STR(sta->addr));
6892 sta->pending_wds_enable = 1;
6893 return;
6894 }
6895
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006896 if (wds && !(sta->flags & WLAN_STA_WDS)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006897 int ret;
6898 char ifname_wds[IFNAMSIZ + 1];
6899
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006900 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
6901 "STA " MACSTR " (aid %u)",
6902 MAC2STR(sta->addr), sta->aid);
6903 sta->flags |= WLAN_STA_WDS;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006904 ret = hostapd_set_wds_sta(hapd, ifname_wds,
6905 sta->addr, sta->aid, 1);
6906 if (!ret)
6907 hostapd_set_wds_encryption(hapd, sta,
6908 ifname_wds);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006909 }
6910 return;
6911 }
6912
6913 wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
6914 MACSTR, MAC2STR(src));
Hai Shalomc3565922019-10-28 11:58:20 -07006915 if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
6916 os_memcmp(src, hapd->own_addr, ETH_ALEN) == 0) {
6917 /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
6918 * silently. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006919 return;
6920 }
6921
6922 if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) {
6923 wpa_printf(MSG_DEBUG, "Association Response to the STA has "
6924 "already been sent, but no TX status yet known - "
6925 "ignore Class 3 frame issue with " MACSTR,
6926 MAC2STR(src));
6927 return;
6928 }
6929
6930 if (sta && (sta->flags & WLAN_STA_AUTH))
6931 hostapd_drv_sta_disassoc(
6932 hapd, src,
6933 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
6934 else
6935 hostapd_drv_sta_deauth(
6936 hapd, src,
6937 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
6938}
6939
6940
Sunil Ravia04bd252022-05-02 22:54:18 -07006941static u8 * hostapd_add_tpe_info(u8 *eid, u8 tx_pwr_count,
6942 enum max_tx_pwr_interpretation tx_pwr_intrpn,
6943 u8 tx_pwr_cat, u8 tx_pwr)
6944{
6945 int i;
6946
6947 *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE; /* Element ID */
6948 *eid++ = 2 + tx_pwr_count; /* Length */
6949
6950 /*
6951 * Transmit Power Information field
6952 * bits 0-2 : Maximum Transmit Power Count
6953 * bits 3-5 : Maximum Transmit Power Interpretation
6954 * bits 6-7 : Maximum Transmit Power Category
6955 */
6956 *eid++ = tx_pwr_count | (tx_pwr_intrpn << 3) | (tx_pwr_cat << 6);
6957
6958 /* Maximum Transmit Power field */
6959 for (i = 0; i <= tx_pwr_count; i++)
6960 *eid++ = tx_pwr;
6961
6962 return eid;
6963}
6964
6965
6966/*
6967 * TODO: Extract power limits from channel data after 6G regulatory
6968 * support.
6969 */
6970#define REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT (-1) /* dBm/MHz */
6971#define REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT 5 /* dBm/MHz */
6972
Hai Shalom60840252021-02-19 19:02:11 -08006973u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
6974{
6975 struct hostapd_iface *iface = hapd->iface;
6976 struct hostapd_config *iconf = iface->conf;
6977 struct hostapd_hw_modes *mode = iface->current_mode;
6978 struct hostapd_channel_data *chan;
6979 int dfs, i;
6980 u8 channel, tx_pwr_count, local_pwr_constraint;
6981 int max_tx_power;
6982 u8 tx_pwr;
6983
6984 if (!mode)
6985 return eid;
6986
6987 if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
6988 return eid;
6989
6990 for (i = 0; i < mode->num_channels; i++) {
6991 if (mode->channels[i].freq == iface->freq)
6992 break;
6993 }
6994 if (i == mode->num_channels)
6995 return eid;
6996
Sunil Ravia04bd252022-05-02 22:54:18 -07006997#ifdef CONFIG_IEEE80211AX
6998 /* IEEE Std 802.11ax-2021, Annex E.2.7 (6 GHz band in the United
6999 * States): An AP that is an Indoor Access Point per regulatory rules
7000 * shall send at least two Transmit Power Envelope elements in Beacon
7001 * and Probe Response frames as follows:
7002 * - Maximum Transmit Power Category subfield = Default;
7003 * Unit interpretation = Regulatory client EIRP PSD
7004 * - Maximum Transmit Power Category subfield = Subordinate Device;
7005 * Unit interpretation = Regulatory client EIRP PSD
7006 */
7007 if (is_6ghz_op_class(iconf->op_class)) {
7008 enum max_tx_pwr_interpretation tx_pwr_intrpn;
7009
7010 /* Same Maximum Transmit Power for all 20 MHz bands */
7011 tx_pwr_count = 0;
7012 tx_pwr_intrpn = REGULATORY_CLIENT_EIRP_PSD;
7013
7014 /* Default Transmit Power Envelope for Global Operating Class */
7015 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT * 2;
7016 eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn,
7017 REG_DEFAULT_CLIENT, tx_pwr);
7018
7019 /* Indoor Access Point must include an additional TPE for
7020 * subordinate devices */
7021 if (iconf->he_6ghz_reg_pwr_type == HE_6GHZ_INDOOR_AP) {
7022 /* TODO: Extract PSD limits from channel data */
7023 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT * 2;
7024 eid = hostapd_add_tpe_info(eid, tx_pwr_count,
7025 tx_pwr_intrpn,
7026 REG_SUBORDINATE_CLIENT,
7027 tx_pwr);
7028 }
7029
7030 return eid;
7031 }
7032#endif /* CONFIG_IEEE80211AX */
7033
Hai Shalom60840252021-02-19 19:02:11 -08007034 switch (hostapd_get_oper_chwidth(iconf)) {
7035 case CHANWIDTH_USE_HT:
7036 if (iconf->secondary_channel == 0) {
7037 /* Max Transmit Power count = 0 (20 MHz) */
7038 tx_pwr_count = 0;
7039 } else {
7040 /* Max Transmit Power count = 1 (20, 40 MHz) */
7041 tx_pwr_count = 1;
7042 }
7043 break;
7044 case CHANWIDTH_80MHZ:
7045 /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
7046 tx_pwr_count = 2;
7047 break;
7048 case CHANWIDTH_80P80MHZ:
7049 case CHANWIDTH_160MHZ:
7050 /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
7051 tx_pwr_count = 3;
7052 break;
7053 default:
7054 return eid;
7055 }
7056
7057 /*
7058 * Below local_pwr_constraint logic is referred from
7059 * hostapd_eid_pwr_constraint.
7060 *
7061 * Check if DFS is required by regulatory.
7062 */
7063 dfs = hostapd_is_dfs_required(hapd->iface);
7064 if (dfs < 0)
7065 dfs = 0;
7066
7067 /*
7068 * In order to meet regulations when TPC is not implemented using
7069 * a transmit power that is below the legal maximum (including any
7070 * mitigation factor) should help. In this case, indicate 3 dB below
7071 * maximum allowed transmit power.
7072 */
7073 if (hapd->iconf->local_pwr_constraint == -1)
7074 local_pwr_constraint = (dfs == 0) ? 0 : 3;
7075 else
7076 local_pwr_constraint = hapd->iconf->local_pwr_constraint;
7077
7078 /*
7079 * A STA that is not an AP shall use a transmit power less than or
7080 * equal to the local maximum transmit power level for the channel.
7081 * The local maximum transmit power can be calculated from the formula:
7082 * local max TX pwr = max TX pwr - local pwr constraint
7083 * Where max TX pwr is maximum transmit power level specified for
7084 * channel in Country element and local pwr constraint is specified
7085 * for channel in this Power Constraint element.
7086 */
7087 chan = &mode->channels[i];
7088 max_tx_power = chan->max_tx_power - local_pwr_constraint;
7089
7090 /*
7091 * Local Maximum Transmit power is encoded as two's complement
7092 * with a 0.5 dB step.
7093 */
7094 max_tx_power *= 2; /* in 0.5 dB steps */
7095 if (max_tx_power > 127) {
7096 /* 63.5 has special meaning of 63.5 dBm or higher */
7097 max_tx_power = 127;
7098 }
7099 if (max_tx_power < -128)
7100 max_tx_power = -128;
7101 if (max_tx_power < 0)
7102 tx_pwr = 0x80 + max_tx_power + 128;
7103 else
7104 tx_pwr = max_tx_power;
7105
Sunil Ravia04bd252022-05-02 22:54:18 -07007106 return hostapd_add_tpe_info(eid, tx_pwr_count, LOCAL_EIRP,
7107 0 /* Reserved for bands other than 6 GHz */,
7108 tx_pwr);
Hai Shalom60840252021-02-19 19:02:11 -08007109}
7110
7111
Hai Shalom899fcc72020-10-19 14:38:18 -07007112u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
7113{
7114 u8 bw, chan1, chan2 = 0;
7115 int freq1;
7116
7117 if (!hapd->cs_freq_params.channel ||
7118 (!hapd->cs_freq_params.vht_enabled &&
Sunil Ravia04bd252022-05-02 22:54:18 -07007119 !hapd->cs_freq_params.he_enabled &&
7120 !hapd->cs_freq_params.eht_enabled))
Hai Shalom899fcc72020-10-19 14:38:18 -07007121 return eid;
7122
7123 /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
7124 switch (hapd->cs_freq_params.bandwidth) {
7125 case 40:
7126 bw = 0;
7127 break;
7128 case 80:
7129 /* check if it's 80+80 */
7130 if (!hapd->cs_freq_params.center_freq2)
7131 bw = 1;
7132 else
7133 bw = 3;
7134 break;
7135 case 160:
7136 bw = 2;
7137 break;
7138 default:
7139 /* not valid VHT bandwidth or not in CSA */
7140 return eid;
7141 }
7142
7143 freq1 = hapd->cs_freq_params.center_freq1 ?
7144 hapd->cs_freq_params.center_freq1 :
7145 hapd->cs_freq_params.freq;
7146 if (ieee80211_freq_to_chan(freq1, &chan1) !=
7147 HOSTAPD_MODE_IEEE80211A)
7148 return eid;
7149
7150 if (hapd->cs_freq_params.center_freq2 &&
7151 ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
7152 &chan2) != HOSTAPD_MODE_IEEE80211A)
7153 return eid;
7154
7155 *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
7156 *eid++ = 5; /* Length of Channel Switch Wrapper */
7157 *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
7158 *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
7159 *eid++ = bw; /* New Channel Width */
7160 *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
7161 *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
7162
7163 return eid;
7164}
7165
Hai Shaloma20dcd72022-02-04 13:43:00 -08007166
7167static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd,
7168 size_t *current_len)
7169{
7170 struct hostapd_neighbor_entry *nr;
7171 size_t total_len = 0, len = *current_len;
7172
7173 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7174 list) {
7175 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7176 continue;
7177
7178 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7179 continue;
7180
7181 /* Start a new element */
7182 if (!len ||
7183 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7184 len = RNR_HEADER_LEN;
7185 total_len += RNR_HEADER_LEN;
7186 }
7187
7188 len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7189 total_len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7190 }
7191
7192 *current_len = len;
7193 return total_len;
7194}
7195
7196
7197static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
7198 struct hostapd_data *reporting_hapd,
7199 size_t *current_len)
7200{
7201 size_t total_len = 0, len = *current_len;
7202 int tbtt_count = 0;
7203 size_t i, start = 0;
7204
7205 while (start < hapd->iface->num_bss) {
7206 if (!len ||
7207 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7208 len = RNR_HEADER_LEN;
7209 total_len += RNR_HEADER_LEN;
7210 }
7211
7212 len += RNR_TBTT_HEADER_LEN;
7213 total_len += RNR_TBTT_HEADER_LEN;
7214
7215 for (i = start; i < hapd->iface->num_bss; i++) {
7216 struct hostapd_data *bss = hapd->iface->bss[i];
7217
7218 if (!bss || !bss->conf || !bss->started)
7219 continue;
7220
7221 if (bss == reporting_hapd ||
7222 bss->conf->ignore_broadcast_ssid)
7223 continue;
7224
7225 if (len + RNR_TBTT_INFO_LEN > 255 ||
7226 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7227 break;
7228
7229 len += RNR_TBTT_INFO_LEN;
7230 total_len += RNR_TBTT_INFO_LEN;
7231 tbtt_count++;
7232 }
7233 start = i;
7234 }
7235
7236 if (!tbtt_count)
7237 total_len = 0;
7238 else
7239 *current_len = len;
7240
7241 return total_len;
7242}
7243
7244
7245enum colocation_mode {
7246 NO_COLOCATED_6GHZ,
7247 STANDALONE_6GHZ,
7248 COLOCATED_6GHZ,
7249 COLOCATED_LOWER_BAND,
7250};
7251
7252static enum colocation_mode get_colocation_mode(struct hostapd_data *hapd)
7253{
7254 u8 i;
7255 bool is_6ghz = is_6ghz_op_class(hapd->iconf->op_class);
7256
7257 if (!hapd->iface || !hapd->iface->interfaces)
7258 return NO_COLOCATED_6GHZ;
7259
7260 if (is_6ghz && hapd->iface->interfaces->count == 1)
7261 return STANDALONE_6GHZ;
7262
7263 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7264 struct hostapd_iface *iface;
7265 bool is_colocated_6ghz;
7266
7267 iface = hapd->iface->interfaces->iface[i];
7268 if (iface == hapd->iface || !iface || !iface->conf)
7269 continue;
7270
7271 is_colocated_6ghz = is_6ghz_op_class(iface->conf->op_class);
7272 if (!is_6ghz && is_colocated_6ghz)
7273 return COLOCATED_LOWER_BAND;
7274 if (is_6ghz && !is_colocated_6ghz)
7275 return COLOCATED_6GHZ;
7276 }
7277
7278 if (is_6ghz)
7279 return STANDALONE_6GHZ;
7280
7281 return NO_COLOCATED_6GHZ;
7282}
7283
7284
7285static size_t hostapd_eid_rnr_colocation_len(struct hostapd_data *hapd,
7286 size_t *current_len)
7287{
7288 struct hostapd_iface *iface;
7289 size_t len = 0;
7290 size_t i;
7291
7292 if (!hapd->iface || !hapd->iface->interfaces)
7293 return 0;
7294
7295 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7296 iface = hapd->iface->interfaces->iface[i];
7297
7298 if (iface == hapd->iface ||
7299 !is_6ghz_op_class(iface->conf->op_class))
7300 continue;
7301
7302 len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
7303 current_len);
7304 }
7305
7306 return len;
7307}
7308
7309
7310size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type)
7311{
7312 size_t total_len = 0, current_len = 0;
7313 enum colocation_mode mode = get_colocation_mode(hapd);
7314
7315 switch (type) {
7316 case WLAN_FC_STYPE_BEACON:
7317 if (hapd->conf->rnr)
7318 total_len += hostapd_eid_nr_db_len(hapd, &current_len);
7319 /* fallthrough */
7320
7321 case WLAN_FC_STYPE_PROBE_RESP:
7322 if (mode == COLOCATED_LOWER_BAND)
7323 total_len += hostapd_eid_rnr_colocation_len(
7324 hapd, &current_len);
7325
7326 if (hapd->conf->rnr && hapd->iface->num_bss > 1)
7327 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
7328 &current_len);
7329 break;
7330
7331 case WLAN_FC_STYPE_ACTION:
7332 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
7333 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
7334 &current_len);
7335 break;
7336
7337 default:
7338 break;
7339 }
7340
7341 return total_len;
7342}
7343
7344
7345static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid,
7346 size_t *current_len)
7347{
7348 struct hostapd_neighbor_entry *nr;
7349 size_t len = *current_len;
7350 u8 *size_offset = (eid - len) + 1;
7351
7352 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7353 list) {
7354 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7355 continue;
7356
7357 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7358 continue;
7359
7360 /* Start a new element */
7361 if (!len ||
7362 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7363 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7364 size_offset = eid++;
7365 len = RNR_HEADER_LEN;
7366 }
7367
7368 /* TBTT Information Header subfield (2 octets) */
7369 *eid++ = 0;
7370 /* TBTT Information Length */
7371 *eid++ = RNR_TBTT_INFO_LEN;
7372 /* Operating Class */
7373 *eid++ = wpabuf_head_u8(nr->nr)[10];
7374 /* Channel Number */
7375 *eid++ = wpabuf_head_u8(nr->nr)[11];
7376 len += RNR_TBTT_HEADER_LEN;
7377 /* TBTT Information Set */
7378 /* TBTT Information field */
7379 /* Neighbor AP TBTT Offset */
7380 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
7381 /* BSSID */
7382 os_memcpy(eid, nr->bssid, ETH_ALEN);
7383 eid += ETH_ALEN;
7384 /* Short SSID */
7385 os_memcpy(eid, &nr->short_ssid, 4);
7386 eid += 4;
7387 /* BSS parameters */
7388 *eid++ = nr->bss_parameters;
7389 /* 20 MHz PSD */
7390 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1;
7391 len += RNR_TBTT_INFO_LEN;
7392 *size_offset = (eid - size_offset) - 1;
7393 }
7394
7395 *current_len = len;
7396 return eid;
7397}
7398
7399
7400static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
7401 struct hostapd_data *reporting_hapd,
7402 u8 *eid, size_t *current_len)
7403{
7404 struct hostapd_data *bss;
7405 struct hostapd_iface *iface = hapd->iface;
7406 size_t i, start = 0;
7407 size_t len = *current_len;
7408 u8 *tbtt_count_pos, *eid_start = eid, *size_offset = (eid - len) + 1;
7409 u8 tbtt_count = 0, op_class, channel, bss_param;
7410
7411 if (!(iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !iface->freq)
7412 return eid;
7413
7414 if (ieee80211_freq_to_channel_ext(iface->freq,
7415 hapd->iconf->secondary_channel,
7416 hostapd_get_oper_chwidth(hapd->iconf),
7417 &op_class, &channel) ==
7418 NUM_HOSTAPD_MODES)
7419 return eid;
7420
7421 while (start < iface->num_bss) {
7422 if (!len ||
7423 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7424 eid_start = eid;
7425 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7426 size_offset = eid++;
7427 len = RNR_HEADER_LEN;
7428 tbtt_count = 0;
7429 }
7430
7431 tbtt_count_pos = eid++;
7432 *eid++ = RNR_TBTT_INFO_LEN;
7433 *eid++ = op_class;
7434 *eid++ = hapd->iconf->channel;
7435 len += RNR_TBTT_HEADER_LEN;
7436
7437 for (i = start; i < iface->num_bss; i++) {
7438 bss_param = 0;
7439 bss = iface->bss[i];
7440 if (!bss || !bss->conf || !bss->started)
7441 continue;
7442
7443 if (bss == reporting_hapd ||
7444 bss->conf->ignore_broadcast_ssid)
7445 continue;
7446
7447 if (len + RNR_TBTT_INFO_LEN > 255 ||
7448 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7449 break;
7450
7451 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
7452 os_memcpy(eid, bss->conf->bssid, ETH_ALEN);
7453 eid += ETH_ALEN;
7454 os_memcpy(eid, &bss->conf->ssid.short_ssid, 4);
7455 eid += 4;
7456 if (bss->conf->ssid.short_ssid ==
7457 reporting_hapd->conf->ssid.short_ssid)
7458 bss_param |= RNR_BSS_PARAM_SAME_SSID;
7459
7460 if (is_6ghz_op_class(hapd->iconf->op_class) &&
7461 bss->conf->unsol_bcast_probe_resp_interval)
7462 bss_param |=
7463 RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE;
7464
7465 bss_param |= RNR_BSS_PARAM_CO_LOCATED;
7466
7467 *eid++ = bss_param;
7468 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1;
7469 len += RNR_TBTT_INFO_LEN;
7470 tbtt_count += 1;
7471 }
7472
7473 start = i;
7474 *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
7475 *size_offset = (eid - size_offset) - 1;
7476 }
7477
7478 if (tbtt_count == 0)
7479 return eid_start;
7480
7481 *current_len = len;
7482 return eid;
7483}
7484
7485
7486static u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid,
7487 size_t *current_len)
7488{
7489 struct hostapd_iface *iface;
7490 size_t i;
7491
7492 if (!hapd->iface || !hapd->iface->interfaces)
7493 return eid;
7494
7495 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7496 iface = hapd->iface->interfaces->iface[i];
7497
7498 if (iface == hapd->iface ||
7499 !is_6ghz_op_class(iface->conf->op_class))
7500 continue;
7501
7502 eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
7503 current_len);
7504 }
7505
7506 return eid;
7507}
7508
7509
7510u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
7511{
7512 u8 *eid_start = eid;
7513 size_t current_len = 0;
7514 enum colocation_mode mode = get_colocation_mode(hapd);
7515
7516 switch (type) {
7517 case WLAN_FC_STYPE_BEACON:
7518 if (hapd->conf->rnr)
7519 eid = hostapd_eid_nr_db(hapd, eid, &current_len);
7520 /* fallthrough */
7521
7522 case WLAN_FC_STYPE_PROBE_RESP:
7523 if (mode == COLOCATED_LOWER_BAND)
7524 eid = hostapd_eid_rnr_colocation(hapd, eid,
7525 &current_len);
7526
7527 if (hapd->conf->rnr && hapd->iface->num_bss > 1)
7528 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
7529 &current_len);
7530 break;
7531
7532 case WLAN_FC_STYPE_ACTION:
7533 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
7534 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
7535 &current_len);
7536 break;
7537
7538 default:
7539 return eid_start;
7540 }
7541
7542 if (eid == eid_start + 2)
7543 return eid_start;
7544
7545 return eid;
7546}
7547
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007548#endif /* CONFIG_NATIVE_WINDOWS */