blob: 6140a492c88beb69f543984d40f245ec2e0130b7 [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;
501
502 for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
503 if (!is_broadcast_ether_addr(pw->peer_addr) &&
504 os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
505 continue;
506 if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
507 continue;
508 if (rx_id && pw->identifier &&
509 os_strcmp(rx_id, pw->identifier) != 0)
510 continue;
511 password = pw->password;
512 pt = pw->pt;
513 if (!(hapd->conf->mesh & MESH_ENABLED))
514 pk = pw->pk;
515 break;
516 }
517 if (!password) {
518 password = hapd->conf->ssid.wpa_passphrase;
519 pt = hapd->conf->ssid.pt;
520 }
521
522 if (pw_entry)
523 *pw_entry = pw;
524 if (s_pt)
525 *s_pt = pt;
526 if (s_pk)
527 *s_pk = pk;
528
529 return password;
530}
531
532
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800533static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
Hai Shalomc3565922019-10-28 11:58:20 -0700534 struct sta_info *sta, int update,
535 int status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800536{
537 struct wpabuf *buf;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700538 const char *password = NULL;
539 struct sae_password_entry *pw;
540 const char *rx_id = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700541 int use_pt = 0;
542 struct sae_pt *pt = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700543 const struct sae_pk *pk = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800544
Hai Shalomc3565922019-10-28 11:58:20 -0700545 if (sta->sae->tmp) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700546 rx_id = sta->sae->tmp->pw_id;
Hai Shalom899fcc72020-10-19 14:38:18 -0700547 use_pt = sta->sae->h2e;
548#ifdef CONFIG_SAE_PK
549 os_memcpy(sta->sae->tmp->own_addr, hapd->own_addr, ETH_ALEN);
550 os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
551#endif /* CONFIG_SAE_PK */
Hai Shalomc3565922019-10-28 11:58:20 -0700552 }
553
Hai Shalomfdcde762020-04-02 11:19:20 -0700554 if (rx_id && hapd->conf->sae_pwe != 3)
555 use_pt = 1;
556 else if (status_code == WLAN_STATUS_SUCCESS)
Hai Shalomc3565922019-10-28 11:58:20 -0700557 use_pt = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700558 else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
559 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomc3565922019-10-28 11:58:20 -0700560 use_pt = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700561
Hai Shalom60840252021-02-19 19:02:11 -0800562 password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk);
Hai Shalomc3565922019-10-28 11:58:20 -0700563 if (!password || (use_pt && !pt)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800564 wpa_printf(MSG_DEBUG, "SAE: No password available");
565 return NULL;
566 }
567
Hai Shalomc3565922019-10-28 11:58:20 -0700568 if (update && use_pt &&
569 sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
Hai Shalom899fcc72020-10-19 14:38:18 -0700570 NULL, pk) < 0)
Hai Shalomc3565922019-10-28 11:58:20 -0700571 return NULL;
572
573 if (update && !use_pt &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800574 sae_prepare_commit(hapd->own_addr, sta->addr,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800575 (u8 *) password, os_strlen(password),
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800576 sta->sae) < 0) {
577 wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
578 return NULL;
579 }
580
Hai Shalom021b0b52019-04-10 11:17:58 -0700581 if (pw && pw->vlan_id) {
582 if (!sta->sae->tmp) {
583 wpa_printf(MSG_INFO,
584 "SAE: No temporary data allocated - cannot store VLAN ID");
585 return NULL;
586 }
587 sta->sae->tmp->vlan_id = pw->vlan_id;
588 }
589
Roshan Pius3a1667e2018-07-03 15:17:14 -0700590 buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
591 (rx_id ? 3 + os_strlen(rx_id) : 0));
Hai Shalomfdcde762020-04-02 11:19:20 -0700592 if (buf &&
593 sae_write_commit(sta->sae, buf, sta->sae->tmp ?
594 sta->sae->tmp->anti_clogging_token : NULL,
595 rx_id) < 0) {
596 wpabuf_free(buf);
597 buf = NULL;
598 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800599
600 return buf;
601}
602
603
604static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
605 struct sta_info *sta)
606{
607 struct wpabuf *buf;
608
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800609 buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800610 if (buf == NULL)
611 return NULL;
612
Hai Shalom899fcc72020-10-19 14:38:18 -0700613#ifdef CONFIG_SAE_PK
614#ifdef CONFIG_TESTING_OPTIONS
615 if (sta->sae->tmp)
616 sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
617#endif /* CONFIG_TESTING_OPTIONS */
618#endif /* CONFIG_SAE_PK */
619
620 if (sae_write_confirm(sta->sae, buf) < 0) {
621 wpabuf_free(buf);
622 return NULL;
623 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800624
625 return buf;
626}
627
628
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800629static int auth_sae_send_commit(struct hostapd_data *hapd,
630 struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700631 const u8 *bssid, int update, int status_code)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800632{
633 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800634 int reply_res;
Hai Shalomc3565922019-10-28 11:58:20 -0700635 u16 status;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800636
Hai Shalomc3565922019-10-28 11:58:20 -0700637 data = auth_build_sae_commit(hapd, sta, update, status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700638 if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
639 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800640 if (data == NULL)
641 return WLAN_STATUS_UNSPECIFIED_FAILURE;
642
Hai Shalom899fcc72020-10-19 14:38:18 -0700643 if (sta->sae->tmp && sta->sae->pk)
644 status = WLAN_STATUS_SAE_PK;
645 else if (sta->sae->tmp && sta->sae->h2e)
646 status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
647 else
648 status = WLAN_STATUS_SUCCESS;
649#ifdef CONFIG_TESTING_OPTIONS
650 if (hapd->conf->sae_commit_status >= 0 &&
651 hapd->conf->sae_commit_status != status) {
652 wpa_printf(MSG_INFO,
653 "TESTING: Override SAE commit status code %u --> %d",
654 status, hapd->conf->sae_commit_status);
655 status = hapd->conf->sae_commit_status;
656 }
657#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomfdcde762020-04-02 11:19:20 -0700658 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
659 WLAN_AUTH_SAE, 1,
Hai Shalomc3565922019-10-28 11:58:20 -0700660 status, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700661 wpabuf_len(data), "sae-send-commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800662
663 wpabuf_free(data);
664
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800665 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800666}
667
668
669static int auth_sae_send_confirm(struct hostapd_data *hapd,
670 struct sta_info *sta,
671 const u8 *bssid)
672{
673 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800674 int reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800675
676 data = auth_build_sae_confirm(hapd, sta);
677 if (data == NULL)
678 return WLAN_STATUS_UNSPECIFIED_FAILURE;
679
Hai Shalomfdcde762020-04-02 11:19:20 -0700680 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
681 WLAN_AUTH_SAE, 2,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800682 WLAN_STATUS_SUCCESS, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700683 wpabuf_len(data), "sae-send-confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800684
685 wpabuf_free(data);
686
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800687 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800688}
689
Hai Shaloma20dcd72022-02-04 13:43:00 -0800690#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800691
Hai Shaloma20dcd72022-02-04 13:43:00 -0800692
693#if defined(CONFIG_SAE) || defined(CONFIG_PASN)
694
695static int use_anti_clogging(struct hostapd_data *hapd)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800696{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800697 struct sta_info *sta;
698 unsigned int open = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800699
Hai Shaloma20dcd72022-02-04 13:43:00 -0800700 if (hapd->conf->anti_clogging_threshold == 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800701 return 1;
702
703 for (sta = hapd->sta_list; sta; sta = sta->next) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800704#ifdef CONFIG_SAE
705 if (sta->sae &&
706 (sta->sae->state == SAE_COMMITTED ||
707 sta->sae->state == SAE_CONFIRMED))
708 open++;
709#endif /* CONFIG_SAE */
710#ifdef CONFIG_PASN
711 if (sta->pasn && sta->pasn->ecdh)
712 open++;
713#endif /* CONFIG_PASN */
714 if (open >= hapd->conf->anti_clogging_threshold)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800715 return 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800716 }
717
Hai Shaloma20dcd72022-02-04 13:43:00 -0800718#ifdef CONFIG_SAE
Hai Shalom021b0b52019-04-10 11:17:58 -0700719 /* In addition to already existing open SAE sessions, check whether
720 * there are enough pending commit messages in the processing queue to
721 * potentially result in too many open sessions. */
722 if (open + dl_list_len(&hapd->sae_commit_queue) >=
Hai Shaloma20dcd72022-02-04 13:43:00 -0800723 hapd->conf->anti_clogging_threshold)
Hai Shalom021b0b52019-04-10 11:17:58 -0700724 return 1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800725#endif /* CONFIG_SAE */
Hai Shalom021b0b52019-04-10 11:17:58 -0700726
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800727 return 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800728}
729
730
Hai Shaloma20dcd72022-02-04 13:43:00 -0800731static int comeback_token_hash(struct hostapd_data *hapd, const u8 *addr,
732 u8 *idx)
Hai Shalom021b0b52019-04-10 11:17:58 -0700733{
734 u8 hash[SHA256_MAC_LEN];
735
Hai Shaloma20dcd72022-02-04 13:43:00 -0800736 if (hmac_sha256(hapd->comeback_key, sizeof(hapd->comeback_key),
Hai Shalomfdcde762020-04-02 11:19:20 -0700737 addr, ETH_ALEN, hash) < 0)
738 return -1;
739 *idx = hash[0];
740 return 0;
Hai Shalom021b0b52019-04-10 11:17:58 -0700741}
742
743
Hai Shaloma20dcd72022-02-04 13:43:00 -0800744static int check_comeback_token(struct hostapd_data *hapd, const u8 *addr,
745 const u8 *token, size_t token_len)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800746{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800747 u8 mac[SHA256_MAC_LEN];
Hai Shalom021b0b52019-04-10 11:17:58 -0700748 const u8 *addrs[2];
749 size_t len[2];
750 u16 token_idx;
751 u8 idx;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800752
Hai Shaloma20dcd72022-02-04 13:43:00 -0800753 if (token_len != SHA256_MAC_LEN ||
754 comeback_token_hash(hapd, addr, &idx) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800755 return -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800756 token_idx = hapd->comeback_pending_idx[idx];
Hai Shalom021b0b52019-04-10 11:17:58 -0700757 if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800758 wpa_printf(MSG_DEBUG,
759 "Comeback: Invalid anti-clogging token from "
Hai Shalom021b0b52019-04-10 11:17:58 -0700760 MACSTR " - token_idx 0x%04x, expected 0x%04x",
761 MAC2STR(addr), WPA_GET_BE16(token), token_idx);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800762 return -1;
Hai Shalom021b0b52019-04-10 11:17:58 -0700763 }
764
765 addrs[0] = addr;
766 len[0] = ETH_ALEN;
767 addrs[1] = token;
768 len[1] = 2;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800769 if (hmac_sha256_vector(hapd->comeback_key, sizeof(hapd->comeback_key),
Hai Shalom021b0b52019-04-10 11:17:58 -0700770 2, addrs, len, mac) < 0 ||
771 os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
772 return -1;
773
Hai Shaloma20dcd72022-02-04 13:43:00 -0800774 hapd->comeback_pending_idx[idx] = 0; /* invalidate used token */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800775
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800776 return 0;
777}
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800778
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800779
780static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
Hai Shalomfdcde762020-04-02 11:19:20 -0700781 int group, const u8 *addr, int h2e)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800782{
783 struct wpabuf *buf;
784 u8 *token;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800785 struct os_reltime now;
Hai Shalom021b0b52019-04-10 11:17:58 -0700786 u8 idx[2];
787 const u8 *addrs[2];
788 size_t len[2];
789 u8 p_idx;
790 u16 token_idx;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800791
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800792 os_get_reltime(&now);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800793 if (!os_reltime_initialized(&hapd->last_comeback_key_update) ||
794 os_reltime_expired(&now, &hapd->last_comeback_key_update, 60) ||
795 hapd->comeback_idx == 0xffff) {
796 if (random_get_bytes(hapd->comeback_key,
797 sizeof(hapd->comeback_key)) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800798 return NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800799 wpa_hexdump(MSG_DEBUG, "Comeback: Updated token key",
800 hapd->comeback_key, sizeof(hapd->comeback_key));
801 hapd->last_comeback_key_update = now;
802 hapd->comeback_idx = 0;
803 os_memset(hapd->comeback_pending_idx, 0,
804 sizeof(hapd->comeback_pending_idx));
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800805 }
806
Hai Shalomfdcde762020-04-02 11:19:20 -0700807 buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800808 if (buf == NULL)
809 return NULL;
810
Hai Shaloma20dcd72022-02-04 13:43:00 -0800811 if (group)
812 wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800813
Hai Shalomfdcde762020-04-02 11:19:20 -0700814 if (h2e) {
815 /* Encapsulate Anti-clogging Token field in a container IE */
816 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
817 wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
818 wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
819 }
820
Hai Shaloma20dcd72022-02-04 13:43:00 -0800821 if (comeback_token_hash(hapd, addr, &p_idx) < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700822 wpabuf_free(buf);
823 return NULL;
824 }
Hai Shaloma20dcd72022-02-04 13:43:00 -0800825
826 token_idx = hapd->comeback_pending_idx[p_idx];
Hai Shalom021b0b52019-04-10 11:17:58 -0700827 if (!token_idx) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800828 hapd->comeback_idx++;
829 token_idx = hapd->comeback_idx;
830 hapd->comeback_pending_idx[p_idx] = token_idx;
Hai Shalom021b0b52019-04-10 11:17:58 -0700831 }
832 WPA_PUT_BE16(idx, token_idx);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800833 token = wpabuf_put(buf, SHA256_MAC_LEN);
Hai Shalom021b0b52019-04-10 11:17:58 -0700834 addrs[0] = addr;
835 len[0] = ETH_ALEN;
836 addrs[1] = idx;
837 len[1] = sizeof(idx);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800838 if (hmac_sha256_vector(hapd->comeback_key, sizeof(hapd->comeback_key),
Hai Shalom021b0b52019-04-10 11:17:58 -0700839 2, addrs, len, token) < 0) {
840 wpabuf_free(buf);
841 return NULL;
842 }
843 WPA_PUT_BE16(token, token_idx);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800844
845 return buf;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800846}
847
Hai Shaloma20dcd72022-02-04 13:43:00 -0800848#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
849
850
851#ifdef CONFIG_SAE
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800852
Roshan Pius3a1667e2018-07-03 15:17:14 -0700853static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800854{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700855 if (sta->sae->sync > hapd->conf->sae_sync) {
856 sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800857 sta->sae->sync = 0;
858 return -1;
859 }
860 return 0;
861}
862
863
864static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
865{
866 struct hostapd_data *hapd = eloop_ctx;
867 struct sta_info *sta = eloop_data;
868 int ret;
869
Roshan Pius3a1667e2018-07-03 15:17:14 -0700870 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800871 return;
872 sta->sae->sync++;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700873 wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700874 " (sync=%d state=%s)",
875 MAC2STR(sta->addr), sta->sae->sync,
876 sae_state_txt(sta->sae->state));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800877
878 switch (sta->sae->state) {
879 case SAE_COMMITTED:
Hai Shalomc3565922019-10-28 11:58:20 -0700880 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800881 eloop_register_timeout(0,
882 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800883 auth_sae_retransmit_timer, hapd, sta);
884 break;
885 case SAE_CONFIRMED:
886 ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800887 eloop_register_timeout(0,
888 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800889 auth_sae_retransmit_timer, hapd, sta);
890 break;
891 default:
892 ret = -1;
893 break;
894 }
895
896 if (ret != WLAN_STATUS_SUCCESS)
897 wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
898}
899
900
901void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
902{
903 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
904}
905
906
907static void sae_set_retransmit_timer(struct hostapd_data *hapd,
908 struct sta_info *sta)
909{
910 if (!(hapd->conf->mesh & MESH_ENABLED))
911 return;
912
913 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800914 eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800915 auth_sae_retransmit_timer, hapd, sta);
916}
917
918
Hai Shalom5f92bc92019-04-18 11:54:11 -0700919static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
920 struct sta_info *sta, u16 status)
921{
922 struct external_auth params;
923
924 os_memset(&params, 0, sizeof(params));
925 params.status = status;
926 params.bssid = sta->addr;
Hai Shalom81f62d82019-07-22 12:10:00 -0700927 if (status == WLAN_STATUS_SUCCESS && sta->sae &&
928 !hapd->conf->disable_pmksa_caching)
Hai Shalom5f92bc92019-04-18 11:54:11 -0700929 params.pmkid = sta->sae->pmkid;
930
931 hostapd_drv_send_external_auth_status(hapd, &params);
932}
933
934
Dmitry Shmidte4663042016-04-04 10:07:49 -0700935void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
936{
Hai Shalom021b0b52019-04-10 11:17:58 -0700937#ifndef CONFIG_NO_VLAN
938 struct vlan_description vlan_desc;
939
940 if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
941 wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
942 " to VLAN ID %d",
943 MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
944
945 os_memset(&vlan_desc, 0, sizeof(vlan_desc));
946 vlan_desc.notempty = 1;
947 vlan_desc.untagged = sta->sae->tmp->vlan_id;
948 if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
949 wpa_printf(MSG_INFO,
950 "Invalid VLAN ID %d in sae_password",
951 sta->sae->tmp->vlan_id);
952 return;
953 }
954
955 if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
956 ap_sta_bind_vlan(hapd, sta) < 0) {
957 wpa_printf(MSG_INFO,
958 "Failed to assign VLAN ID %d from sae_password to "
959 MACSTR, sta->sae->tmp->vlan_id,
960 MAC2STR(sta->addr));
961 return;
962 }
963 }
964#endif /* CONFIG_NO_VLAN */
965
Dmitry Shmidte4663042016-04-04 10:07:49 -0700966 sta->flags |= WLAN_STA_AUTH;
967 sta->auth_alg = WLAN_AUTH_SAE;
968 mlme_authenticate_indication(hapd, sta);
969 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700970 sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
Hai Shalomfdcde762020-04-02 11:19:20 -0700971 crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
972 sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
973 sta->sae->peer_commit_scalar = NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -0700974 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
975 sta->sae->pmk, sta->sae->pmkid);
Hai Shalom5f92bc92019-04-18 11:54:11 -0700976 sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
Dmitry Shmidte4663042016-04-04 10:07:49 -0700977}
978
979
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800980static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700981 const u8 *bssid, u16 auth_transaction, u16 status_code,
982 int allow_reuse, int *sta_removed)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800983{
984 int ret;
985
Hai Shalom5f92bc92019-04-18 11:54:11 -0700986 *sta_removed = 0;
987
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800988 if (auth_transaction != 1 && auth_transaction != 2)
989 return WLAN_STATUS_UNSPECIFIED_FAILURE;
990
Roshan Pius3a1667e2018-07-03 15:17:14 -0700991 wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
992 MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
993 auth_transaction);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800994 switch (sta->sae->state) {
995 case SAE_NOTHING:
996 if (auth_transaction == 1) {
Hai Shalom899fcc72020-10-19 14:38:18 -0700997 if (sta->sae->tmp) {
998 sta->sae->h2e =
999 (status_code ==
1000 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1001 status_code == WLAN_STATUS_SAE_PK);
1002 sta->sae->pk =
1003 status_code == WLAN_STATUS_SAE_PK;
1004 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001005 ret = auth_sae_send_commit(hapd, sta, bssid,
Hai Shalomc3565922019-10-28 11:58:20 -07001006 !allow_reuse, status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001007 if (ret)
1008 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001009 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001010
1011 if (sae_process_commit(sta->sae) < 0)
1012 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1013
1014 /*
Hai Shalomc3565922019-10-28 11:58:20 -07001015 * In mesh case, both Commit and Confirm are sent
1016 * immediately. In infrastructure BSS, by default, only
1017 * a single Authentication frame (Commit) is expected
1018 * from the AP here and the second one (Confirm) will
1019 * be sent once the STA has sent its second
1020 * Authentication frame (Confirm). This behavior can be
1021 * overridden with explicit configuration so that the
1022 * infrastructure BSS case sends both frames together.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001023 */
Hai Shalomc3565922019-10-28 11:58:20 -07001024 if ((hapd->conf->mesh & MESH_ENABLED) ||
1025 hapd->conf->sae_confirm_immediate) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001026 /*
1027 * Send both Commit and Confirm immediately
1028 * based on SAE finite state machine
1029 * Nothing -> Confirm transition.
1030 */
1031 ret = auth_sae_send_confirm(hapd, sta, bssid);
1032 if (ret)
1033 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001034 sae_set_state(sta, SAE_CONFIRMED,
1035 "Sent Confirm (mesh)");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001036 } else {
1037 /*
1038 * For infrastructure BSS, send only the Commit
1039 * message now to get alternating sequence of
1040 * Authentication frames between the AP and STA.
1041 * Confirm will be sent in
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001042 * Committed -> Confirmed/Accepted transition
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001043 * when receiving Confirm from STA.
1044 */
1045 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001046 sta->sae->sync = 0;
1047 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001048 } else {
1049 hostapd_logger(hapd, sta->addr,
1050 HOSTAPD_MODULE_IEEE80211,
1051 HOSTAPD_LEVEL_DEBUG,
1052 "SAE confirm before commit");
1053 }
1054 break;
1055 case SAE_COMMITTED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001056 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001057 if (auth_transaction == 1) {
1058 if (sae_process_commit(sta->sae) < 0)
1059 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1060
1061 ret = auth_sae_send_confirm(hapd, sta, bssid);
1062 if (ret)
1063 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001064 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001065 sta->sae->sync = 0;
1066 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001067 } else if (hapd->conf->mesh & MESH_ENABLED) {
1068 /*
1069 * In mesh case, follow SAE finite state machine and
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001070 * send Commit now, if sync count allows.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001071 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001072 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001073 return WLAN_STATUS_SUCCESS;
1074 sta->sae->sync++;
1075
Hai Shalomc3565922019-10-28 11:58:20 -07001076 ret = auth_sae_send_commit(hapd, sta, bssid, 0,
1077 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001078 if (ret)
1079 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001080
1081 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001082 } else {
1083 /*
1084 * For instructure BSS, send the postponed Confirm from
1085 * Nothing -> Confirmed transition that was reduced to
1086 * Nothing -> Committed above.
1087 */
1088 ret = auth_sae_send_confirm(hapd, sta, bssid);
1089 if (ret)
1090 return ret;
1091
Roshan Pius3a1667e2018-07-03 15:17:14 -07001092 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001093
1094 /*
1095 * Since this was triggered on Confirm RX, run another
1096 * step to get to Accepted without waiting for
1097 * additional events.
1098 */
Hai Shalom021b0b52019-04-10 11:17:58 -07001099 return sae_sm_step(hapd, sta, bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001100 WLAN_STATUS_SUCCESS, 0, sta_removed);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001101 }
1102 break;
1103 case SAE_CONFIRMED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001104 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001105 if (auth_transaction == 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001106 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001107 return WLAN_STATUS_SUCCESS;
1108 sta->sae->sync++;
1109
Hai Shalomc3565922019-10-28 11:58:20 -07001110 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1111 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001112 if (ret)
1113 return ret;
1114
1115 if (sae_process_commit(sta->sae) < 0)
1116 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1117
1118 ret = auth_sae_send_confirm(hapd, sta, bssid);
1119 if (ret)
1120 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001121
1122 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001123 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001124 sta->sae->send_confirm = 0xffff;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001125 sae_accept_sta(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001126 }
1127 break;
1128 case SAE_ACCEPTED:
Roshan Pius3a1667e2018-07-03 15:17:14 -07001129 if (auth_transaction == 1 &&
1130 (hapd->conf->mesh & MESH_ENABLED)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001131 wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
1132 ") doing reauthentication",
1133 MAC2STR(sta->addr));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001134 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
Hai Shalom5f92bc92019-04-18 11:54:11 -07001135 ap_free_sta(hapd, sta);
1136 *sta_removed = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001137 } else if (auth_transaction == 1) {
1138 wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
Hai Shalomc3565922019-10-28 11:58:20 -07001139 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1140 status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001141 if (ret)
1142 return ret;
1143 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
1144
1145 if (sae_process_commit(sta->sae) < 0)
1146 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1147 sta->sae->sync = 0;
1148 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001149 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001150 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001151 return WLAN_STATUS_SUCCESS;
1152 sta->sae->sync++;
1153
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001154 ret = auth_sae_send_confirm(hapd, sta, bssid);
1155 sae_clear_temp_data(sta->sae);
1156 if (ret)
1157 return ret;
1158 }
1159 break;
1160 default:
1161 wpa_printf(MSG_ERROR, "SAE: invalid state %d",
1162 sta->sae->state);
1163 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1164 }
1165 return WLAN_STATUS_SUCCESS;
1166}
1167
1168
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001169static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
1170{
1171 struct sae_data *sae = sta->sae;
1172 int i, *groups = hapd->conf->sae_groups;
Hai Shalom021b0b52019-04-10 11:17:58 -07001173 int default_groups[] = { 19, 0 };
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001174
1175 if (sae->state != SAE_COMMITTED)
1176 return;
1177
1178 wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
1179
Hai Shalom021b0b52019-04-10 11:17:58 -07001180 if (!groups)
1181 groups = default_groups;
1182 for (i = 0; groups[i] > 0; i++) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001183 if (sae->group == groups[i])
1184 break;
1185 }
1186
Hai Shalom021b0b52019-04-10 11:17:58 -07001187 if (groups[i] <= 0) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001188 wpa_printf(MSG_DEBUG,
1189 "SAE: Previously selected group not found from the current configuration");
1190 return;
1191 }
1192
1193 for (;;) {
1194 i++;
1195 if (groups[i] <= 0) {
1196 wpa_printf(MSG_DEBUG,
1197 "SAE: No alternative group enabled");
1198 return;
1199 }
1200
1201 if (sae_set_group(sae, groups[i]) < 0)
1202 continue;
1203
1204 break;
1205 }
1206 wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
1207}
1208
1209
Hai Shalomc3565922019-10-28 11:58:20 -07001210static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
1211{
Hai Shalomfdcde762020-04-02 11:19:20 -07001212 int sae_pwe = hapd->conf->sae_pwe;
1213 int id_in_use;
Hai Shalom60840252021-02-19 19:02:11 -08001214 bool sae_pk = false;
Hai Shalomfdcde762020-04-02 11:19:20 -07001215
1216 id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
1217 if (id_in_use == 2 && sae_pwe != 3)
1218 sae_pwe = 1;
1219 else if (id_in_use == 1 && sae_pwe == 0)
1220 sae_pwe = 2;
Hai Shalom899fcc72020-10-19 14:38:18 -07001221#ifdef CONFIG_SAE_PK
Hai Shalom60840252021-02-19 19:02:11 -08001222 sae_pk = hostapd_sae_pk_in_use(hapd->conf);
1223 if (sae_pwe == 0 && sae_pk)
Hai Shalom899fcc72020-10-19 14:38:18 -07001224 sae_pwe = 2;
1225#endif /* CONFIG_SAE_PK */
Hai Shalomfdcde762020-04-02 11:19:20 -07001226
1227 return ((sae_pwe == 0 || sae_pwe == 3) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001228 status_code == WLAN_STATUS_SUCCESS) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07001229 (sae_pwe == 1 &&
Hai Shalom899fcc72020-10-19 14:38:18 -07001230 (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001231 (sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07001232 (sae_pwe == 2 &&
Hai Shalomc3565922019-10-28 11:58:20 -07001233 (status_code == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -07001234 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001235 (sae_pk && status_code == WLAN_STATUS_SAE_PK)));
Hai Shalomc3565922019-10-28 11:58:20 -07001236}
1237
1238
1239static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
1240{
1241 int *groups = hapd->conf->sae_groups;
1242 int default_groups[] = { 19, 0 };
1243 int i;
1244
1245 if (!groups)
1246 groups = default_groups;
1247
1248 for (i = 0; groups[i] > 0; i++) {
1249 if (groups[i] == group)
1250 return 1;
1251 }
1252
1253 return 0;
1254}
1255
1256
1257static int check_sae_rejected_groups(struct hostapd_data *hapd,
Hai Shalom899fcc72020-10-19 14:38:18 -07001258 struct sae_data *sae)
Hai Shalomc3565922019-10-28 11:58:20 -07001259{
Hai Shalom899fcc72020-10-19 14:38:18 -07001260 const struct wpabuf *groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001261 size_t i, count;
1262 const u8 *pos;
1263
Hai Shalom899fcc72020-10-19 14:38:18 -07001264 if (!sae->tmp)
1265 return 0;
1266 groups = sae->tmp->peer_rejected_groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001267 if (!groups)
1268 return 0;
1269
1270 pos = wpabuf_head(groups);
1271 count = wpabuf_len(groups) / 2;
1272 for (i = 0; i < count; i++) {
1273 int enabled;
1274 u16 group;
1275
1276 group = WPA_GET_LE16(pos);
1277 pos += 2;
1278 enabled = sae_is_group_enabled(hapd, group);
1279 wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
1280 group, enabled ? "enabled" : "disabled");
1281 if (enabled)
1282 return 1;
1283 }
1284
1285 return 0;
1286}
1287
1288
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001289static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
1290 const struct ieee80211_mgmt *mgmt, size_t len,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001291 u16 auth_transaction, u16 status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001292{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001293 int resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001294 struct wpabuf *data = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07001295 int *groups = hapd->conf->sae_groups;
1296 int default_groups[] = { 19, 0 };
1297 const u8 *pos, *end;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001298 int sta_removed = 0;
Hai Shalom60840252021-02-19 19:02:11 -08001299 bool success_status;
Hai Shalom021b0b52019-04-10 11:17:58 -07001300
1301 if (!groups)
1302 groups = default_groups;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001303
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001304#ifdef CONFIG_TESTING_OPTIONS
1305 if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001306 wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
1307 pos = mgmt->u.auth.variable;
1308 end = ((const u8 *) mgmt) + len;
Hai Shalom899fcc72020-10-19 14:38:18 -07001309 resp = status_code;
Hai Shalomfdcde762020-04-02 11:19:20 -07001310 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001311 auth_transaction, resp, pos, end - pos,
1312 "auth-sae-reflection-attack");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001313 goto remove_sta;
1314 }
1315
1316 if (hapd->conf->sae_commit_override && auth_transaction == 1) {
1317 wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
Hai Shalomfdcde762020-04-02 11:19:20 -07001318 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001319 auth_transaction, resp,
1320 wpabuf_head(hapd->conf->sae_commit_override),
Roshan Pius3a1667e2018-07-03 15:17:14 -07001321 wpabuf_len(hapd->conf->sae_commit_override),
1322 "sae-commit-override");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001323 goto remove_sta;
1324 }
1325#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001326 if (!sta->sae) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001327 if (auth_transaction != 1 ||
Hai Shalomc3565922019-10-28 11:58:20 -07001328 !sae_status_success(hapd, status_code)) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001329 wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
1330 status_code);
1331 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1332 goto reply;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001333 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001334 sta->sae = os_zalloc(sizeof(*sta->sae));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001335 if (!sta->sae) {
1336 resp = -1;
1337 goto remove_sta;
1338 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001339 sae_set_state(sta, SAE_NOTHING, "Init");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001340 sta->sae->sync = 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001341 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001342
Dmitry Shmidte4663042016-04-04 10:07:49 -07001343 if (sta->mesh_sae_pmksa_caching) {
1344 wpa_printf(MSG_DEBUG,
1345 "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
1346 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
1347 sta->mesh_sae_pmksa_caching = 0;
1348 }
1349
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001350 if (auth_transaction == 1) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001351 const u8 *token = NULL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001352 size_t token_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07001353 int allow_reuse = 0;
1354
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001355 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1356 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001357 "start SAE authentication (RX commit, status=%u (%s))",
1358 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001359
1360 if ((hapd->conf->mesh & MESH_ENABLED) &&
1361 status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
1362 sta->sae->tmp) {
1363 pos = mgmt->u.auth.variable;
1364 end = ((const u8 *) mgmt) + len;
1365 if (pos + sizeof(le16) > end) {
1366 wpa_printf(MSG_ERROR,
1367 "SAE: Too short anti-clogging token request");
1368 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1369 goto reply;
1370 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001371 resp = sae_group_allowed(sta->sae, groups,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001372 WPA_GET_LE16(pos));
1373 if (resp != WLAN_STATUS_SUCCESS) {
1374 wpa_printf(MSG_ERROR,
1375 "SAE: Invalid group in anti-clogging token request");
1376 goto reply;
1377 }
1378 pos += sizeof(le16);
1379
1380 wpabuf_free(sta->sae->tmp->anti_clogging_token);
1381 sta->sae->tmp->anti_clogging_token =
1382 wpabuf_alloc_copy(pos, end - pos);
1383 if (sta->sae->tmp->anti_clogging_token == NULL) {
1384 wpa_printf(MSG_ERROR,
1385 "SAE: Failed to alloc for anti-clogging token");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001386 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1387 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001388 }
1389
1390 /*
1391 * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code
1392 * is 76, a new Commit Message shall be constructed
1393 * with the Anti-Clogging Token from the received
1394 * Authentication frame, and the commit-scalar and
1395 * COMMIT-ELEMENT previously sent.
1396 */
Hai Shalomc3565922019-10-28 11:58:20 -07001397 resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
1398 status_code);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001399 if (resp != WLAN_STATUS_SUCCESS) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001400 wpa_printf(MSG_ERROR,
1401 "SAE: Failed to send commit message");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001402 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001403 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001404 sae_set_state(sta, SAE_COMMITTED,
1405 "Sent Commit (anti-clogging token case in mesh)");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001406 sta->sae->sync = 0;
1407 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001408 return;
1409 }
1410
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001411 if ((hapd->conf->mesh & MESH_ENABLED) &&
1412 status_code ==
1413 WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1414 sta->sae->tmp) {
1415 wpa_printf(MSG_DEBUG,
1416 "SAE: Peer did not accept our SAE group");
1417 sae_pick_next_group(hapd, sta);
1418 goto remove_sta;
1419 }
1420
Hai Shalomc3565922019-10-28 11:58:20 -07001421 if (!sae_status_success(hapd, status_code))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001422 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001423
Roshan Pius3a1667e2018-07-03 15:17:14 -07001424 if (!(hapd->conf->mesh & MESH_ENABLED) &&
1425 sta->sae->state == SAE_COMMITTED) {
1426 /* This is needed in the infrastructure BSS case to
1427 * address a sequence where a STA entry may remain in
1428 * hostapd across two attempts to do SAE authentication
1429 * by the same STA. The second attempt may end up trying
1430 * to use a different group and that would not be
1431 * allowed if we remain in Committed state with the
1432 * previously set parameters. */
Hai Shalom021b0b52019-04-10 11:17:58 -07001433 pos = mgmt->u.auth.variable;
1434 end = ((const u8 *) mgmt) + len;
1435 if (end - pos >= (int) sizeof(le16) &&
1436 sae_group_allowed(sta->sae, groups,
1437 WPA_GET_LE16(pos)) ==
1438 WLAN_STATUS_SUCCESS) {
1439 /* Do not waste resources deriving the same PWE
1440 * again since the same group is reused. */
1441 sae_set_state(sta, SAE_NOTHING,
1442 "Allow previous PWE to be reused");
1443 allow_reuse = 1;
1444 } else {
1445 sae_set_state(sta, SAE_NOTHING,
1446 "Clear existing state to allow restart");
1447 sae_clear_data(sta->sae);
1448 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001449 }
1450
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001451 resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
1452 ((const u8 *) mgmt) + len -
1453 mgmt->u.auth.variable, &token,
Hai Shalomc3565922019-10-28 11:58:20 -07001454 &token_len, groups, status_code ==
Hai Shalom899fcc72020-10-19 14:38:18 -07001455 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1456 status_code == WLAN_STATUS_SAE_PK);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001457 if (resp == SAE_SILENTLY_DISCARD) {
1458 wpa_printf(MSG_DEBUG,
1459 "SAE: Drop commit message from " MACSTR " due to reflection attack",
1460 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001461 goto remove_sta;
Dmitry Shmidt41712582015-06-29 11:02:15 -07001462 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001463
1464 if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
1465 wpa_msg(hapd->msg_ctx, MSG_INFO,
1466 WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
1467 MACSTR, MAC2STR(sta->addr));
1468 sae_clear_retransmit_timer(hapd, sta);
1469 sae_set_state(sta, SAE_NOTHING,
1470 "Unknown Password Identifier");
1471 goto remove_sta;
1472 }
1473
Hai Shaloma20dcd72022-02-04 13:43:00 -08001474 if (token &&
1475 check_comeback_token(hapd, sta->addr, token, token_len)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001476 < 0) {
1477 wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
1478 "incorrect token from " MACSTR,
1479 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001480 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1481 goto remove_sta;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001482 }
1483
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001484 if (resp != WLAN_STATUS_SUCCESS)
1485 goto reply;
1486
Hai Shalom899fcc72020-10-19 14:38:18 -07001487 if (check_sae_rejected_groups(hapd, sta->sae)) {
Hai Shalomc3565922019-10-28 11:58:20 -07001488 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001489 goto reply;
Hai Shalomc3565922019-10-28 11:58:20 -07001490 }
1491
Hai Shaloma20dcd72022-02-04 13:43:00 -08001492 if (!token && use_anti_clogging(hapd) && !allow_reuse) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001493 int h2e = 0;
1494
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001495 wpa_printf(MSG_DEBUG,
1496 "SAE: Request anti-clogging token from "
1497 MACSTR, MAC2STR(sta->addr));
Hai Shalomfdcde762020-04-02 11:19:20 -07001498 if (sta->sae->tmp)
Hai Shalom899fcc72020-10-19 14:38:18 -07001499 h2e = sta->sae->h2e;
1500 if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1501 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomfdcde762020-04-02 11:19:20 -07001502 h2e = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001503 data = auth_build_token_req(hapd, sta->sae->group,
Hai Shalomfdcde762020-04-02 11:19:20 -07001504 sta->addr, h2e);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001505 resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
1506 if (hapd->conf->mesh & MESH_ENABLED)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001507 sae_set_state(sta, SAE_NOTHING,
1508 "Request anti-clogging token case in mesh");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001509 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001510 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001511
Hai Shalom021b0b52019-04-10 11:17:58 -07001512 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001513 status_code, allow_reuse, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001514 } else if (auth_transaction == 2) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001515 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1516 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001517 "SAE authentication (RX confirm, status=%u (%s))",
1518 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001519 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001520 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001521 if (sta->sae->state >= SAE_CONFIRMED ||
1522 !(hapd->conf->mesh & MESH_ENABLED)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001523 const u8 *var;
1524 size_t var_len;
1525 u16 peer_send_confirm;
1526
1527 var = mgmt->u.auth.variable;
1528 var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable;
1529 if (var_len < 2) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001530 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001531 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001532 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001533
1534 peer_send_confirm = WPA_GET_LE16(var);
1535
1536 if (sta->sae->state == SAE_ACCEPTED &&
1537 (peer_send_confirm <= sta->sae->rc ||
1538 peer_send_confirm == 0xffff)) {
1539 wpa_printf(MSG_DEBUG,
1540 "SAE: Silently ignore unexpected Confirm from peer "
1541 MACSTR
1542 " (peer-send-confirm=%u Rc=%u)",
1543 MAC2STR(sta->addr),
1544 peer_send_confirm, sta->sae->rc);
1545 return;
1546 }
1547
1548 if (sae_check_confirm(sta->sae, var, var_len) < 0) {
1549 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1550 goto reply;
1551 }
1552 sta->sae->rc = peer_send_confirm;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001553 }
Hai Shalomc3565922019-10-28 11:58:20 -07001554 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
1555 status_code, 0, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001556 } else {
1557 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1558 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001559 "unexpected SAE authentication transaction %u (status=%u (%s))",
1560 auth_transaction, status_code,
1561 status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001562 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001563 goto remove_sta;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001564 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1565 }
1566
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001567reply:
Hai Shalom5f92bc92019-04-18 11:54:11 -07001568 if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001569 pos = mgmt->u.auth.variable;
1570 end = ((const u8 *) mgmt) + len;
1571
1572 /* Copy the Finite Cyclic Group field from the request if we
1573 * rejected it as unsupported group. */
1574 if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1575 !data && end - pos >= 2)
1576 data = wpabuf_alloc_copy(pos, 2);
1577
Hai Shalom5f92bc92019-04-18 11:54:11 -07001578 sae_sme_send_external_auth_status(hapd, sta, resp);
Hai Shalomfdcde762020-04-02 11:19:20 -07001579 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001580 auth_transaction, resp,
1581 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07001582 data ? wpabuf_len(data) : 0, "auth-sae");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001583 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001584
1585remove_sta:
Hai Shalom60840252021-02-19 19:02:11 -08001586 if (auth_transaction == 1)
1587 success_status = sae_status_success(hapd, status_code);
1588 else
1589 success_status = status_code == WLAN_STATUS_SUCCESS;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001590 if (!sta_removed && sta->added_unassoc &&
Hai Shalom60840252021-02-19 19:02:11 -08001591 (resp != WLAN_STATUS_SUCCESS || !success_status)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001592 hostapd_drv_sta_remove(hapd, sta->addr);
1593 sta->added_unassoc = 0;
1594 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001595 wpabuf_free(data);
1596}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001597
1598
1599/**
1600 * auth_sae_init_committed - Send COMMIT and start SAE in committed state
1601 * @hapd: BSS data for the device initiating the authentication
1602 * @sta: the peer to which commit authentication frame is sent
1603 *
1604 * This function implements Init event handling (IEEE Std 802.11-2012,
1605 * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
1606 * sta->sae structure should be initialized appropriately via a call to
1607 * sae_prepare_commit().
1608 */
1609int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
1610{
1611 int ret;
1612
1613 if (!sta->sae || !sta->sae->tmp)
1614 return -1;
1615
1616 if (sta->sae->state != SAE_NOTHING)
1617 return -1;
1618
Hai Shalomc3565922019-10-28 11:58:20 -07001619 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001620 if (ret)
1621 return -1;
1622
Roshan Pius3a1667e2018-07-03 15:17:14 -07001623 sae_set_state(sta, SAE_COMMITTED, "Init and sent commit");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001624 sta->sae->sync = 0;
1625 sae_set_retransmit_timer(hapd, sta);
1626
1627 return 0;
1628}
1629
Hai Shalom021b0b52019-04-10 11:17:58 -07001630
1631void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
1632{
1633 struct hostapd_data *hapd = eloop_ctx;
1634 struct hostapd_sae_commit_queue *q;
1635 unsigned int queue_len;
1636
1637 q = dl_list_first(&hapd->sae_commit_queue,
1638 struct hostapd_sae_commit_queue, list);
1639 if (!q)
1640 return;
1641 wpa_printf(MSG_DEBUG,
1642 "SAE: Process next available message from queue");
1643 dl_list_del(&q->list);
1644 handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
1645 q->rssi, 1);
1646 os_free(q);
1647
1648 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1649 return;
1650 queue_len = dl_list_len(&hapd->sae_commit_queue);
1651 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1652 hapd, NULL);
1653}
1654
1655
1656static void auth_sae_queue(struct hostapd_data *hapd,
1657 const struct ieee80211_mgmt *mgmt, size_t len,
1658 int rssi)
1659{
1660 struct hostapd_sae_commit_queue *q, *q2;
1661 unsigned int queue_len;
1662 const struct ieee80211_mgmt *mgmt2;
1663
1664 queue_len = dl_list_len(&hapd->sae_commit_queue);
1665 if (queue_len >= 15) {
1666 wpa_printf(MSG_DEBUG,
1667 "SAE: No more room in message queue - drop the new frame from "
1668 MACSTR, MAC2STR(mgmt->sa));
1669 return;
1670 }
1671
1672 wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
1673 MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
1674 queue_len);
1675 q = os_zalloc(sizeof(*q) + len);
1676 if (!q)
1677 return;
1678 q->rssi = rssi;
1679 q->len = len;
1680 os_memcpy(q->msg, mgmt, len);
1681
1682 /* Check whether there is already a queued Authentication frame from the
1683 * same station with the same transaction number and if so, replace that
1684 * queue entry with the new one. This avoids issues with a peer that
1685 * sends multiple times (e.g., due to frequent SAE retries). There is no
1686 * point in us trying to process the old attempts after a new one has
1687 * obsoleted them. */
1688 dl_list_for_each(q2, &hapd->sae_commit_queue,
1689 struct hostapd_sae_commit_queue, list) {
1690 mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
1691 if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 &&
1692 mgmt->u.auth.auth_transaction ==
1693 mgmt2->u.auth.auth_transaction) {
1694 wpa_printf(MSG_DEBUG,
1695 "SAE: Replace queued message from same STA with same transaction number");
1696 dl_list_add(&q2->list, &q->list);
1697 dl_list_del(&q2->list);
1698 os_free(q2);
1699 goto queued;
1700 }
1701 }
1702
1703 /* No pending identical entry, so add to the end of the queue */
1704 dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
1705
1706queued:
1707 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1708 return;
1709 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1710 hapd, NULL);
1711}
1712
1713
1714static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
1715{
1716 struct hostapd_sae_commit_queue *q;
1717 const struct ieee80211_mgmt *mgmt;
1718
1719 dl_list_for_each(q, &hapd->sae_commit_queue,
1720 struct hostapd_sae_commit_queue, list) {
1721 mgmt = (const struct ieee80211_mgmt *) q->msg;
1722 if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0)
1723 return 1;
1724 }
1725
1726 return 0;
1727}
1728
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001729#endif /* CONFIG_SAE */
1730
1731
Hai Shalomfdcde762020-04-02 11:19:20 -07001732static u16 wpa_res_to_status_code(enum wpa_validate_result res)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001733{
Hai Shalomfdcde762020-04-02 11:19:20 -07001734 switch (res) {
1735 case WPA_IE_OK:
1736 return WLAN_STATUS_SUCCESS;
1737 case WPA_INVALID_IE:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001738 return WLAN_STATUS_INVALID_IE;
Hai Shalomfdcde762020-04-02 11:19:20 -07001739 case WPA_INVALID_GROUP:
1740 return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
1741 case WPA_INVALID_PAIRWISE:
1742 return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
1743 case WPA_INVALID_AKMP:
1744 return WLAN_STATUS_AKMP_NOT_VALID;
1745 case WPA_NOT_ENABLED:
1746 return WLAN_STATUS_INVALID_IE;
1747 case WPA_ALLOC_FAIL:
1748 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1749 case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
1750 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
1751 case WPA_INVALID_MGMT_GROUP_CIPHER:
1752 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
1753 case WPA_INVALID_MDIE:
1754 return WLAN_STATUS_INVALID_MDIE;
1755 case WPA_INVALID_PROTO:
1756 return WLAN_STATUS_INVALID_IE;
1757 case WPA_INVALID_PMKID:
1758 return WLAN_STATUS_INVALID_PMKID;
1759 case WPA_DENIED_OTHER_REASON:
1760 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
1761 }
1762 return WLAN_STATUS_INVALID_IE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001763}
1764
1765
1766#ifdef CONFIG_FILS
1767
1768static void handle_auth_fils_finish(struct hostapd_data *hapd,
1769 struct sta_info *sta, u16 resp,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001770 struct wpabuf *data, int pub);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001771
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001772void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
1773 const u8 *pos, size_t len, u16 auth_alg,
1774 u16 auth_transaction, u16 status_code,
1775 void (*cb)(struct hostapd_data *hapd,
1776 struct sta_info *sta, u16 resp,
1777 struct wpabuf *data, int pub))
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001778{
1779 u16 resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001780 const u8 *end;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001781 struct ieee802_11_elems elems;
Hai Shalomfdcde762020-04-02 11:19:20 -07001782 enum wpa_validate_result res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001783 struct wpa_ie_data rsn;
1784 struct rsn_pmksa_cache_entry *pmksa = NULL;
1785
1786 if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
1787 return;
1788
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001789 end = pos + len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001790
1791 wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
1792 pos, end - pos);
1793
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001794 /* TODO: FILS PK */
1795#ifdef CONFIG_FILS_SK_PFS
1796 if (auth_alg == WLAN_AUTH_FILS_SK_PFS) {
1797 u16 group;
1798 struct wpabuf *pub;
1799 size_t elem_len;
1800
1801 /* Using FILS PFS */
1802
1803 /* Finite Cyclic Group */
1804 if (end - pos < 2) {
1805 wpa_printf(MSG_DEBUG,
1806 "FILS: No room for Finite Cyclic Group");
1807 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1808 goto fail;
1809 }
1810 group = WPA_GET_LE16(pos);
1811 pos += 2;
1812 if (group != hapd->conf->fils_dh_group) {
1813 wpa_printf(MSG_DEBUG,
1814 "FILS: Unsupported Finite Cyclic Group: %u (expected %u)",
1815 group, hapd->conf->fils_dh_group);
1816 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1817 goto fail;
1818 }
1819
1820 crypto_ecdh_deinit(sta->fils_ecdh);
1821 sta->fils_ecdh = crypto_ecdh_init(group);
1822 if (!sta->fils_ecdh) {
1823 wpa_printf(MSG_INFO,
1824 "FILS: Could not initialize ECDH with group %d",
1825 group);
1826 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1827 goto fail;
1828 }
1829
1830 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
1831 if (!pub) {
1832 wpa_printf(MSG_DEBUG,
1833 "FILS: Failed to derive ECDH public key");
1834 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1835 goto fail;
1836 }
1837 elem_len = wpabuf_len(pub);
1838 wpabuf_free(pub);
1839
1840 /* Element */
1841 if ((size_t) (end - pos) < elem_len) {
1842 wpa_printf(MSG_DEBUG, "FILS: No room for Element");
1843 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1844 goto fail;
1845 }
1846
1847 wpabuf_free(sta->fils_g_sta);
1848 sta->fils_g_sta = wpabuf_alloc_copy(pos, elem_len);
1849 wpabuf_clear_free(sta->fils_dh_ss);
1850 sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1,
1851 pos, elem_len);
1852 if (!sta->fils_dh_ss) {
1853 wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
1854 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1855 goto fail;
1856 }
1857 wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss);
1858 pos += elem_len;
1859 } else {
1860 crypto_ecdh_deinit(sta->fils_ecdh);
1861 sta->fils_ecdh = NULL;
1862 wpabuf_clear_free(sta->fils_dh_ss);
1863 sta->fils_dh_ss = NULL;
1864 }
1865#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001866
1867 wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
1868 if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
1869 wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
1870 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1871 goto fail;
1872 }
1873
1874 /* RSNE */
1875 wpa_hexdump(MSG_DEBUG, "FILS: RSN element",
1876 elems.rsn_ie, elems.rsn_ie_len);
1877 if (!elems.rsn_ie ||
1878 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
1879 &rsn) < 0) {
1880 wpa_printf(MSG_DEBUG, "FILS: No valid RSN element");
1881 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1882 goto fail;
1883 }
1884
1885 if (!sta->wpa_sm)
1886 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
1887 NULL);
1888 if (!sta->wpa_sm) {
1889 wpa_printf(MSG_DEBUG,
1890 "FILS: Failed to initialize RSN state machine");
1891 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1892 goto fail;
1893 }
1894
1895 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07001896 hapd->iface->freq,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001897 elems.rsn_ie - 2, elems.rsn_ie_len + 2,
Hai Shalomc3565922019-10-28 11:58:20 -07001898 elems.rsnxe ? elems.rsnxe - 2 : NULL,
1899 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001900 elems.mdie, elems.mdie_len, NULL, 0);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001901 resp = wpa_res_to_status_code(res);
1902 if (resp != WLAN_STATUS_SUCCESS)
1903 goto fail;
1904
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001905 if (!elems.fils_nonce) {
1906 wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
1907 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1908 goto fail;
1909 }
1910 wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce,
1911 FILS_NONCE_LEN);
1912 os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN);
1913
1914 /* PMKID List */
1915 if (rsn.pmkid && rsn.num_pmkid > 0) {
1916 u8 num;
1917 const u8 *pmkid;
1918
1919 wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
1920 rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
1921
1922 pmkid = rsn.pmkid;
1923 num = rsn.num_pmkid;
1924 while (num) {
1925 wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
1926 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
1927 pmkid);
1928 if (pmksa)
1929 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001930 pmksa = wpa_auth_pmksa_get_fils_cache_id(hapd->wpa_auth,
1931 sta->addr,
1932 pmkid);
1933 if (pmksa)
1934 break;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001935 pmkid += PMKID_LEN;
1936 num--;
1937 }
1938 }
1939 if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) {
1940 wpa_printf(MSG_DEBUG,
1941 "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore",
1942 wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp);
1943 pmksa = NULL;
1944 }
1945 if (pmksa)
1946 wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry");
1947
1948 /* FILS Session */
1949 if (!elems.fils_session) {
1950 wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
1951 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1952 goto fail;
1953 }
1954 wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
1955 FILS_SESSION_LEN);
1956 os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
1957
Hai Shalomfdcde762020-04-02 11:19:20 -07001958 /* Wrapped Data */
1959 if (elems.wrapped_data) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001960 wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
Hai Shalomfdcde762020-04-02 11:19:20 -07001961 elems.wrapped_data,
1962 elems.wrapped_data_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001963 if (!pmksa) {
1964#ifndef CONFIG_NO_RADIUS
1965 if (!sta->eapol_sm) {
1966 sta->eapol_sm =
1967 ieee802_1x_alloc_eapol_sm(hapd, sta);
1968 }
1969 wpa_printf(MSG_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001970 "FILS: Forward EAP-Initiate/Re-auth to authentication server");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001971 ieee802_1x_encapsulate_radius(
Hai Shalomfdcde762020-04-02 11:19:20 -07001972 hapd, sta, elems.wrapped_data,
1973 elems.wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001974 sta->fils_pending_cb = cb;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001975 wpa_printf(MSG_DEBUG,
1976 "FILS: Will send Authentication frame once the response from authentication server is available");
1977 sta->flags |= WLAN_STA_PENDING_FILS_ERP;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001978 /* Calculate pending PMKID here so that we do not need
1979 * to maintain a copy of the EAP-Initiate/Reauth
1980 * message. */
1981 if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
Hai Shalomfdcde762020-04-02 11:19:20 -07001982 elems.wrapped_data,
1983 elems.wrapped_data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001984 sta->fils_erp_pmkid) == 0)
1985 sta->fils_erp_pmkid_set = 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001986 return;
1987#else /* CONFIG_NO_RADIUS */
1988 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1989 goto fail;
1990#endif /* CONFIG_NO_RADIUS */
1991 }
1992 }
1993
1994fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001995 if (cb) {
1996 struct wpabuf *data;
1997 int pub = 0;
1998
1999 data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, NULL,
2000 NULL, 0, &pub);
2001 if (!data) {
2002 wpa_printf(MSG_DEBUG,
2003 "%s: prepare_auth_resp_fils() returned failure",
2004 __func__);
2005 }
2006
2007 cb(hapd, sta, resp, data, pub);
2008 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002009}
2010
2011
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002012static struct wpabuf *
2013prepare_auth_resp_fils(struct hostapd_data *hapd,
2014 struct sta_info *sta, u16 *resp,
2015 struct rsn_pmksa_cache_entry *pmksa,
2016 struct wpabuf *erp_resp,
2017 const u8 *msk, size_t msk_len,
2018 int *is_pub)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002019{
2020 u8 fils_nonce[FILS_NONCE_LEN];
2021 size_t ielen;
2022 struct wpabuf *data = NULL;
2023 const u8 *ie;
2024 u8 *ie_buf = NULL;
2025 const u8 *pmk = NULL;
2026 size_t pmk_len = 0;
Paul Stewart092955c2017-02-06 09:13:09 -08002027 u8 pmk_buf[PMK_LEN_MAX];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002028 struct wpabuf *pub = NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002029
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002030 if (*resp != WLAN_STATUS_SUCCESS)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002031 goto fail;
2032
2033 ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
2034 if (!ie) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002035 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002036 goto fail;
2037 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002038
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002039 if (pmksa) {
2040 /* Add PMKID of the selected PMKSA into RSNE */
2041 ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN);
2042 if (!ie_buf) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002043 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002044 goto fail;
2045 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002046
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002047 os_memcpy(ie_buf, ie, ielen);
2048 if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002049 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002050 goto fail;
2051 }
2052 ie = ie_buf;
2053 }
2054
2055 if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002056 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002057 goto fail;
2058 }
2059 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
2060 fils_nonce, FILS_NONCE_LEN);
2061
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002062#ifdef CONFIG_FILS_SK_PFS
2063 if (sta->fils_dh_ss && sta->fils_ecdh) {
2064 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
2065 if (!pub) {
2066 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2067 goto fail;
2068 }
2069 }
2070#endif /* CONFIG_FILS_SK_PFS */
2071
2072 data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0));
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002073 if (!data) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002074 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002075 goto fail;
2076 }
2077
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002078 /* TODO: FILS PK */
2079#ifdef CONFIG_FILS_SK_PFS
2080 if (pub) {
2081 /* Finite Cyclic Group */
2082 wpabuf_put_le16(data, hapd->conf->fils_dh_group);
2083
2084 /* Element */
2085 wpabuf_put_buf(data, pub);
2086 }
2087#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002088
2089 /* RSNE */
2090 wpabuf_put_data(data, ie, ielen);
2091
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002092 /* MDE when using FILS+FT (already included in ie,ielen with RSNE) */
2093
2094#ifdef CONFIG_IEEE80211R_AP
2095 if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
2096 /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
2097 int res;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002098 int use_sha384 = wpa_key_mgmt_sha384(
2099 wpa_auth_sta_key_mgmt(sta->wpa_sm));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002100
Roshan Pius3a1667e2018-07-03 15:17:14 -07002101 res = wpa_auth_write_fte(hapd->wpa_auth, use_sha384,
2102 wpabuf_put(data, 0),
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002103 wpabuf_tailroom(data));
2104 if (res < 0) {
2105 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2106 goto fail;
2107 }
2108 wpabuf_put(data, res);
2109 }
2110#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002111
2112 /* FILS Nonce */
2113 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2114 wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */
2115 /* Element ID Extension */
2116 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE);
2117 wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN);
2118
2119 /* FILS Session */
2120 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2121 wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */
2122 /* Element ID Extension */
2123 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
2124 wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
2125
Hai Shalomfdcde762020-04-02 11:19:20 -07002126 /* Wrapped Data */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002127 if (!pmksa && erp_resp) {
2128 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2129 wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
2130 /* Element ID Extension */
Hai Shalomfdcde762020-04-02 11:19:20 -07002131 wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002132 wpabuf_put_buf(data, erp_resp);
2133
Paul Stewart092955c2017-02-06 09:13:09 -08002134 if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
2135 msk, msk_len, sta->fils_snonce, fils_nonce,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002136 sta->fils_dh_ss ?
2137 wpabuf_head(sta->fils_dh_ss) : NULL,
2138 sta->fils_dh_ss ?
2139 wpabuf_len(sta->fils_dh_ss) : 0,
2140 pmk_buf, &pmk_len)) {
Paul Stewart092955c2017-02-06 09:13:09 -08002141 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002142 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Paul Stewart092955c2017-02-06 09:13:09 -08002143 wpabuf_free(data);
2144 data = NULL;
2145 goto fail;
2146 }
2147 pmk = pmk_buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002148
2149 /* Don't use DHss in PTK derivation if PMKSA caching is not
2150 * used. */
2151 wpabuf_clear_free(sta->fils_dh_ss);
2152 sta->fils_dh_ss = NULL;
2153
2154 if (sta->fils_erp_pmkid_set) {
2155 /* TODO: get PMKLifetime from WPA parameters */
2156 unsigned int dot11RSNAConfigPMKLifetime = 43200;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002157 int session_timeout;
2158
2159 session_timeout = dot11RSNAConfigPMKLifetime;
2160 if (sta->session_timeout_set) {
2161 struct os_reltime now, diff;
2162
2163 os_get_reltime(&now);
2164 os_reltime_sub(&sta->session_timeout, &now,
2165 &diff);
2166 session_timeout = diff.sec;
2167 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002168
2169 sta->fils_erp_pmkid_set = 0;
Hai Shalom81f62d82019-07-22 12:10:00 -07002170 wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
2171 sta->fils_erp_pmkid);
Hai Shalom021b0b52019-04-10 11:17:58 -07002172 if (!hapd->conf->disable_pmksa_caching &&
2173 wpa_auth_pmksa_add2(
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002174 hapd->wpa_auth, sta->addr,
2175 pmk, pmk_len,
2176 sta->fils_erp_pmkid,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002177 session_timeout,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002178 wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) {
2179 wpa_printf(MSG_ERROR,
2180 "FILS: Failed to add PMKSA cache entry based on ERP");
2181 }
2182 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002183 } else if (pmksa) {
2184 pmk = pmksa->pmk;
2185 pmk_len = pmksa->pmk_len;
2186 }
2187
2188 if (!pmk) {
2189 wpa_printf(MSG_DEBUG, "FILS: No PMK available");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002190 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002191 wpabuf_free(data);
2192 data = NULL;
2193 goto fail;
2194 }
2195
2196 if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002197 sta->fils_snonce, fils_nonce,
2198 sta->fils_dh_ss ?
2199 wpabuf_head(sta->fils_dh_ss) : NULL,
2200 sta->fils_dh_ss ?
2201 wpabuf_len(sta->fils_dh_ss) : 0,
2202 sta->fils_g_sta, pub) < 0) {
2203 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002204 wpabuf_free(data);
2205 data = NULL;
2206 goto fail;
2207 }
2208
2209fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002210 if (is_pub)
2211 *is_pub = pub != NULL;
2212 os_free(ie_buf);
2213 wpabuf_free(pub);
2214 wpabuf_clear_free(sta->fils_dh_ss);
2215 sta->fils_dh_ss = NULL;
2216#ifdef CONFIG_FILS_SK_PFS
2217 crypto_ecdh_deinit(sta->fils_ecdh);
2218 sta->fils_ecdh = NULL;
2219#endif /* CONFIG_FILS_SK_PFS */
2220 return data;
2221}
2222
2223
2224static void handle_auth_fils_finish(struct hostapd_data *hapd,
2225 struct sta_info *sta, u16 resp,
2226 struct wpabuf *data, int pub)
2227{
2228 u16 auth_alg;
2229
2230 auth_alg = (pub ||
2231 resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
2232 WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Hai Shalomfdcde762020-04-02 11:19:20 -07002233 send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002234 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07002235 data ? wpabuf_len(data) : 0, "auth-fils-finish");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002236 wpabuf_free(data);
2237
2238 if (resp == WLAN_STATUS_SUCCESS) {
2239 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2240 HOSTAPD_LEVEL_DEBUG,
2241 "authentication OK (FILS)");
2242 sta->flags |= WLAN_STA_AUTH;
2243 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002244 sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002245 mlme_authenticate_indication(hapd, sta);
2246 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002247}
2248
2249
2250void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
2251 struct sta_info *sta, int success,
2252 struct wpabuf *erp_resp,
2253 const u8 *msk, size_t msk_len)
2254{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002255 u16 resp;
Hai Shalom60840252021-02-19 19:02:11 -08002256 u32 flags = sta->flags;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002257
Hai Shalom60840252021-02-19 19:02:11 -08002258 sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
2259 WLAN_STA_PENDING_PASN_FILS_ERP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002260
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002261 resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
Hai Shalom60840252021-02-19 19:02:11 -08002262
2263 if (flags & WLAN_STA_PENDING_FILS_ERP) {
2264 struct wpabuf *data;
2265 int pub = 0;
2266
2267 if (!sta->fils_pending_cb)
2268 return;
2269
2270 data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
2271 msk, msk_len, &pub);
2272 if (!data) {
2273 wpa_printf(MSG_DEBUG,
2274 "%s: prepare_auth_resp_fils() failure",
2275 __func__);
2276 }
2277 sta->fils_pending_cb(hapd, sta, resp, data, pub);
2278#ifdef CONFIG_PASN
2279 } else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
2280 pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
2281 msk, msk_len);
2282#endif /* CONFIG_PASN */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002283 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002284}
2285
2286#endif /* CONFIG_FILS */
2287
2288
Hai Shalomfdcde762020-04-02 11:19:20 -07002289static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
2290 const u8 *msg, size_t len,
2291 struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002292{
2293 int res;
2294
Hai Shalomfdcde762020-04-02 11:19:20 -07002295 res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002296
2297 if (res == HOSTAPD_ACL_REJECT) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002298 wpa_printf(MSG_DEBUG, "Station " MACSTR
2299 " not allowed to authenticate",
2300 MAC2STR(addr));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002301 return HOSTAPD_ACL_REJECT;
2302 }
2303
2304 if (res == HOSTAPD_ACL_PENDING) {
2305 wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
2306 " waiting for an external authentication",
2307 MAC2STR(addr));
2308 /* Authentication code will re-send the authentication frame
2309 * after it has received (and cached) information from the
2310 * external source. */
2311 return HOSTAPD_ACL_PENDING;
2312 }
2313
2314 return res;
2315}
2316
2317
2318static int
2319ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
Hai Shalomfdcde762020-04-02 11:19:20 -07002320 int res, struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002321{
Hai Shalomfdcde762020-04-02 11:19:20 -07002322 u32 session_timeout = info->session_timeout;
2323 u32 acct_interim_interval = info->acct_interim_interval;
2324 struct vlan_description *vlan_id = &info->vlan_id;
2325 struct hostapd_sta_wpa_psk_short *psk = info->psk;
2326 char *identity = info->identity;
2327 char *radius_cui = info->radius_cui;
2328
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002329 if (vlan_id->notempty &&
2330 !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
2331 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2332 HOSTAPD_LEVEL_INFO,
2333 "Invalid VLAN %d%s received from RADIUS server",
2334 vlan_id->untagged,
2335 vlan_id->tagged[0] ? "+" : "");
2336 return -1;
2337 }
2338 if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
2339 return -1;
2340 if (sta->vlan_id)
2341 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2342 HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
2343
2344 hostapd_free_psk_list(sta->psk);
Hai Shalomfdcde762020-04-02 11:19:20 -07002345 if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
2346 hostapd_copy_psk_list(&sta->psk, psk);
2347 else
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002348 sta->psk = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002349
Roshan Pius3a1667e2018-07-03 15:17:14 -07002350 os_free(sta->identity);
Hai Shalomfdcde762020-04-02 11:19:20 -07002351 if (identity)
2352 sta->identity = os_strdup(identity);
2353 else
2354 sta->identity = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002355
2356 os_free(sta->radius_cui);
Hai Shalomfdcde762020-04-02 11:19:20 -07002357 if (radius_cui)
2358 sta->radius_cui = os_strdup(radius_cui);
2359 else
2360 sta->radius_cui = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002361
2362 if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
2363 sta->acct_interim_interval = acct_interim_interval;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002364 if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
2365 sta->session_timeout_set = 1;
2366 os_get_reltime(&sta->session_timeout);
2367 sta->session_timeout.sec += session_timeout;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002368 ap_sta_session_timeout(hapd, sta, session_timeout);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002369 } else {
2370 sta->session_timeout_set = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002371 ap_sta_no_session_timeout(hapd, sta);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002372 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002373
2374 return 0;
2375}
2376
2377
Hai Shalom60840252021-02-19 19:02:11 -08002378#ifdef CONFIG_PASN
2379#ifdef CONFIG_SAE
2380
2381static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd,
2382 struct sta_info *sta,
2383 struct wpabuf *wd)
2384{
2385 struct pasn_data *pasn = sta->pasn;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002386 const char *password;
Hai Shalom60840252021-02-19 19:02:11 -08002387 const u8 *data;
2388 size_t buf_len;
2389 u16 res, alg, seq, status;
2390 int groups[] = { pasn->group, 0 };
Hai Shaloma20dcd72022-02-04 13:43:00 -08002391 struct sae_pt *pt = NULL;
Hai Shalom60840252021-02-19 19:02:11 -08002392 int ret;
2393
2394 if (!wd)
2395 return -1;
2396
2397 data = wpabuf_head_u8(wd);
2398 buf_len = wpabuf_len(wd);
2399
2400 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002401 wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002402 buf_len);
2403 return -1;
2404 }
2405
2406 alg = WPA_GET_LE16(data);
2407 seq = WPA_GET_LE16(data + 2);
2408 status = WPA_GET_LE16(data + 4);
2409
2410 wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u",
2411 alg, seq, status);
2412
Hai Shaloma20dcd72022-02-04 13:43:00 -08002413 if (alg != WLAN_AUTH_SAE || seq != 1 ||
2414 status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
Hai Shalom60840252021-02-19 19:02:11 -08002415 wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit");
2416 return -1;
2417 }
2418
2419 sae_clear_data(&pasn->sae);
2420 pasn->sae.state = SAE_NOTHING;
2421
2422 ret = sae_set_group(&pasn->sae, pasn->group);
2423 if (ret) {
2424 wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group");
2425 return -1;
2426 }
2427
Hai Shaloma20dcd72022-02-04 13:43:00 -08002428 password = sae_get_password(hapd, sta, NULL, NULL, &pt, NULL);
2429 if (!password || !pt) {
2430 wpa_printf(MSG_DEBUG, "PASN: No SAE PT found");
Hai Shalom60840252021-02-19 19:02:11 -08002431 return -1;
2432 }
2433
Hai Shaloma20dcd72022-02-04 13:43:00 -08002434 ret = sae_prepare_commit_pt(&pasn->sae, pt, hapd->own_addr, sta->addr,
2435 NULL, NULL);
Hai Shalom60840252021-02-19 19:02:11 -08002436 if (ret) {
2437 wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
2438 return -1;
2439 }
2440
2441 res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0,
2442 groups, 0);
2443 if (res != WLAN_STATUS_SUCCESS) {
2444 wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit");
2445 return -1;
2446 }
2447
2448 /* Process the commit message and derive the PMK */
2449 ret = sae_process_commit(&pasn->sae);
2450 if (ret) {
2451 wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
2452 return -1;
2453 }
2454
2455 pasn->sae.state = SAE_COMMITTED;
2456
2457 return 0;
2458}
2459
2460
2461static int pasn_wd_handle_sae_confirm(struct hostapd_data *hapd,
2462 struct sta_info *sta,
2463 struct wpabuf *wd)
2464{
2465 struct pasn_data *pasn = sta->pasn;
2466 const u8 *data;
2467 size_t buf_len;
2468 u16 res, alg, seq, status;
2469
2470 if (!wd)
2471 return -1;
2472
2473 data = wpabuf_head_u8(wd);
2474 buf_len = wpabuf_len(wd);
2475
2476 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002477 wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002478 buf_len);
2479 return -1;
2480 }
2481
2482 alg = WPA_GET_LE16(data);
2483 seq = WPA_GET_LE16(data + 2);
2484 status = WPA_GET_LE16(data + 4);
2485
2486 wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u",
2487 alg, seq, status);
2488
2489 if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) {
2490 wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm");
2491 return -1;
2492 }
2493
2494 res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6);
2495 if (res != WLAN_STATUS_SUCCESS) {
2496 wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm");
2497 return -1;
2498 }
2499
2500 pasn->sae.state = SAE_ACCEPTED;
2501
2502 /*
2503 * TODO: Based on on IEEE P802.11az/D2.6, the PMKSA derived with
2504 * PASN/SAE should only be allowed with future PASN only. For now do not
2505 * restrict this only for PASN.
2506 */
2507 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
2508 pasn->sae.pmk, pasn->sae.pmkid);
2509 return 0;
2510}
2511
2512
2513static struct wpabuf * pasn_get_sae_wd(struct hostapd_data *hapd,
2514 struct sta_info *sta)
2515{
2516 struct pasn_data *pasn = sta->pasn;
2517 struct wpabuf *buf = NULL;
2518 u8 *len_ptr;
2519 size_t len;
2520
2521 /* Need to add the entire Authentication frame body */
2522 buf = wpabuf_alloc(8 + SAE_COMMIT_MAX_LEN + 8 + SAE_CONFIRM_MAX_LEN);
2523 if (!buf) {
2524 wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
2525 return NULL;
2526 }
2527
2528 /* Need to add the entire authentication frame body for the commit */
2529 len_ptr = wpabuf_put(buf, 2);
2530 wpabuf_put_le16(buf, WLAN_AUTH_SAE);
2531 wpabuf_put_le16(buf, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002532 wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
Hai Shalom60840252021-02-19 19:02:11 -08002533
2534 /* Write the actual commit and update the length accordingly */
2535 sae_write_commit(&pasn->sae, buf, NULL, 0);
2536 len = wpabuf_len(buf);
2537 WPA_PUT_LE16(len_ptr, len - 2);
2538
2539 /* Need to add the entire Authentication frame body for the confirm */
2540 len_ptr = wpabuf_put(buf, 2);
2541 wpabuf_put_le16(buf, WLAN_AUTH_SAE);
2542 wpabuf_put_le16(buf, 2);
2543 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
2544
2545 sae_write_confirm(&pasn->sae, buf);
2546 WPA_PUT_LE16(len_ptr, wpabuf_len(buf) - len - 2);
2547
2548 pasn->sae.state = SAE_CONFIRMED;
2549
2550 return buf;
2551}
2552
2553#endif /* CONFIG_SAE */
2554
2555
2556#ifdef CONFIG_FILS
2557
2558static struct wpabuf * pasn_get_fils_wd(struct hostapd_data *hapd,
2559 struct sta_info *sta)
2560{
2561 struct pasn_data *pasn = sta->pasn;
2562 struct pasn_fils_data *fils = &pasn->fils;
2563 struct wpabuf *buf = NULL;
2564
2565 if (!fils->erp_resp) {
2566 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing erp_resp");
2567 return NULL;
2568 }
2569
2570 buf = wpabuf_alloc(1500);
2571 if (!buf)
2572 return NULL;
2573
2574 /* Add the authentication algorithm */
2575 wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
2576
2577 /* Authentication Transaction seq# */
2578 wpabuf_put_le16(buf, 2);
2579
2580 /* Status Code */
2581 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
2582
2583 /* Own RSNE */
2584 wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
2585
2586 /* FILS Nonce */
2587 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
2588 wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
2589 wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
2590 wpabuf_put_data(buf, fils->anonce, FILS_NONCE_LEN);
2591
2592 /* FILS Session */
2593 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
2594 wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
2595 wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
2596 wpabuf_put_data(buf, fils->session, FILS_SESSION_LEN);
2597
2598 /* Wrapped Data */
2599 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
2600 wpabuf_put_u8(buf, 1 + wpabuf_len(fils->erp_resp));
2601 wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
2602 wpabuf_put_buf(buf, fils->erp_resp);
2603
2604 return buf;
2605}
2606
2607
2608static void pasn_fils_auth_resp(struct hostapd_data *hapd,
2609 struct sta_info *sta, u16 status,
2610 struct wpabuf *erp_resp,
2611 const u8 *msk, size_t msk_len)
2612{
2613 struct pasn_data *pasn = sta->pasn;
2614 struct pasn_fils_data *fils = &pasn->fils;
2615 u8 pmk[PMK_LEN_MAX];
2616 size_t pmk_len;
2617 int ret;
2618
2619 wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
2620 status);
2621
2622 if (status != WLAN_STATUS_SUCCESS)
2623 goto fail;
2624
2625 if (!pasn->secret) {
2626 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
2627 goto fail;
2628 }
2629
2630 if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
2631 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
2632 goto fail;
2633 }
2634
2635 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
2636 fils->anonce, FILS_NONCE_LEN);
2637
2638 ret = fils_rmsk_to_pmk(pasn->akmp, msk, msk_len, fils->nonce,
2639 fils->anonce, NULL, 0, pmk, &pmk_len);
2640 if (ret) {
2641 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
2642 goto fail;
2643 }
2644
2645 ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
2646 wpabuf_head(pasn->secret),
2647 wpabuf_len(pasn->secret),
2648 &sta->pasn->ptk, sta->pasn->akmp,
Hai Shaloma20dcd72022-02-04 13:43:00 -08002649 sta->pasn->cipher, sta->pasn->kdk_len);
Hai Shalom60840252021-02-19 19:02:11 -08002650 if (ret) {
2651 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
2652 goto fail;
2653 }
2654
2655 wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
2656
2657 wpabuf_free(pasn->secret);
2658 pasn->secret = NULL;
2659
2660 fils->erp_resp = erp_resp;
2661 ret = handle_auth_pasn_resp(hapd, sta, NULL, WLAN_STATUS_SUCCESS);
2662 fils->erp_resp = NULL;
2663
2664 if (ret) {
2665 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
2666 goto fail;
2667 }
2668
2669 fils->state = PASN_FILS_STATE_COMPLETE;
2670 return;
2671fail:
2672 ap_free_sta(hapd, sta);
2673}
2674
2675
2676static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
2677 struct wpabuf *wd)
2678{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002679#ifdef CONFIG_NO_RADIUS
2680 wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
2681 return -1;
2682#else /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002683 struct pasn_data *pasn = sta->pasn;
2684 struct pasn_fils_data *fils = &pasn->fils;
2685 struct ieee802_11_elems elems;
2686 struct wpa_ie_data rsne_data;
2687 struct wpabuf *fils_wd;
2688 const u8 *data;
2689 size_t buf_len;
2690 u16 alg, seq, status;
2691 int ret;
2692
2693 if (fils->state != PASN_FILS_STATE_NONE) {
2694 wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
2695 return -1;
2696 }
2697
2698 if (!wd) {
2699 wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
2700 return -1;
2701 }
2702
2703 data = wpabuf_head_u8(wd);
2704 buf_len = wpabuf_len(wd);
2705
2706 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002707 wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002708 buf_len);
2709 return -1;
2710 }
2711
2712 alg = WPA_GET_LE16(data);
2713 seq = WPA_GET_LE16(data + 2);
2714 status = WPA_GET_LE16(data + 4);
2715
2716 wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
2717 alg, seq, status);
2718
2719 if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
2720 status != WLAN_STATUS_SUCCESS) {
2721 wpa_printf(MSG_DEBUG,
2722 "PASN: FILS: Dropping peer authentication");
2723 return -1;
2724 }
2725
2726 data += 6;
2727 buf_len -= 6;
2728
2729 if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
2730 wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
2731 return -1;
2732 }
2733
2734 if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
2735 !elems.wrapped_data) {
2736 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
2737 return -1;
2738 }
2739
2740 ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2741 &rsne_data);
2742 if (ret) {
2743 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RNSE");
2744 return -1;
2745 }
2746
2747 ret = wpa_pasn_validate_rsne(&rsne_data);
2748 if (ret) {
2749 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
2750 return -1;
2751 }
2752
2753 if (rsne_data.num_pmkid) {
2754 wpa_printf(MSG_DEBUG,
2755 "PASN: FILS: Not expecting PMKID in RSNE");
2756 return -1;
2757 }
2758
2759 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
2760 FILS_NONCE_LEN);
2761 os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
2762
2763 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
2764 FILS_SESSION_LEN);
2765 os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
2766
Hai Shalom60840252021-02-19 19:02:11 -08002767 fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
2768 WLAN_EID_EXT_WRAPPED_DATA);
2769
2770 if (!fils_wd) {
2771 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
2772 return -1;
2773 }
2774
2775 if (!sta->eapol_sm)
2776 sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
2777
2778 wpa_printf(MSG_DEBUG,
2779 "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
2780
2781 ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
2782 wpabuf_len(fils_wd));
2783
2784 sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
2785
2786 fils->state = PASN_FILS_STATE_PENDING_AS;
2787
2788 /*
2789 * Calculate pending PMKID here so that we do not need to maintain a
2790 * copy of the EAP-Initiate/Reautt message.
2791 */
2792 fils_pmkid_erp(pasn->akmp, wpabuf_head(fils_wd), wpabuf_len(fils_wd),
2793 fils->erp_pmkid);
2794
2795 wpabuf_free(fils_wd);
2796 return 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002797#endif /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002798}
2799
2800#endif /* CONFIG_FILS */
2801
2802
2803static struct wpabuf * pasn_get_wrapped_data(struct hostapd_data *hapd,
2804 struct sta_info *sta)
2805{
2806 switch (sta->pasn->akmp) {
2807 case WPA_KEY_MGMT_PASN:
2808 /* no wrapped data */
2809 return NULL;
2810 case WPA_KEY_MGMT_SAE:
2811#ifdef CONFIG_SAE
2812 return pasn_get_sae_wd(hapd, sta);
2813#else /* CONFIG_SAE */
2814 wpa_printf(MSG_ERROR,
2815 "PASN: SAE: Cannot derive wrapped data");
2816 return NULL;
2817#endif /* CONFIG_SAE */
2818 case WPA_KEY_MGMT_FILS_SHA256:
2819 case WPA_KEY_MGMT_FILS_SHA384:
2820#ifdef CONFIG_FILS
2821 return pasn_get_fils_wd(hapd, sta);
2822#endif /* CONFIG_FILS */
2823 /* fall through */
2824 case WPA_KEY_MGMT_FT_PSK:
2825 case WPA_KEY_MGMT_FT_IEEE8021X:
2826 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
2827 default:
2828 wpa_printf(MSG_ERROR,
2829 "PASN: TODO: Wrapped data for akmp=0x%x",
2830 sta->pasn->akmp);
2831 return NULL;
2832 }
2833}
2834
2835
2836static int
2837pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta,
2838 const u8 *cached_pmk, size_t cached_pmk_len,
2839 struct wpa_pasn_params_data *pasn_data,
2840 struct wpabuf *wrapped_data,
2841 struct wpabuf *secret)
2842{
2843 static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'};
2844 u8 pmk[PMK_LEN_MAX];
2845 u8 pmk_len;
2846 int ret;
2847
2848 os_memset(pmk, 0, sizeof(pmk));
2849 pmk_len = 0;
2850
2851 if (!cached_pmk || !cached_pmk_len)
2852 wpa_printf(MSG_DEBUG, "PASN: No valid PMKSA entry");
2853
2854 if (sta->pasn->akmp == WPA_KEY_MGMT_PASN) {
2855 wpa_printf(MSG_DEBUG, "PASN: Using default PMK");
2856
2857 pmk_len = WPA_PASN_PMK_LEN;
2858 os_memcpy(pmk, pasn_default_pmk, sizeof(pasn_default_pmk));
2859 } else if (cached_pmk && cached_pmk_len) {
2860 wpa_printf(MSG_DEBUG, "PASN: Using PMKSA entry");
2861
2862 pmk_len = cached_pmk_len;
2863 os_memcpy(pmk, cached_pmk, cached_pmk_len);
2864 } else {
2865 switch (sta->pasn->akmp) {
2866#ifdef CONFIG_SAE
2867 case WPA_KEY_MGMT_SAE:
2868 if (sta->pasn->sae.state == SAE_COMMITTED) {
2869 pmk_len = PMK_LEN;
2870 os_memcpy(pmk, sta->pasn->sae.pmk, PMK_LEN);
2871 break;
2872 }
2873#endif /* CONFIG_SAE */
2874 /* fall through */
2875 default:
2876 /* TODO: Derive PMK based on wrapped data */
2877 wpa_printf(MSG_DEBUG,
2878 "PASN: Missing PMK derivation");
2879 return -1;
2880 }
2881 }
2882
2883 ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
2884 wpabuf_head(secret), wpabuf_len(secret),
2885 &sta->pasn->ptk, sta->pasn->akmp,
Hai Shaloma20dcd72022-02-04 13:43:00 -08002886 sta->pasn->cipher, sta->pasn->kdk_len);
Hai Shalom60840252021-02-19 19:02:11 -08002887 if (ret) {
2888 wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
2889 return -1;
2890 }
2891
2892 wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
2893 return 0;
2894}
2895
2896
Hai Shaloma20dcd72022-02-04 13:43:00 -08002897static void handle_auth_pasn_comeback(struct hostapd_data *hapd,
2898 struct sta_info *sta, u16 group)
2899{
2900 struct wpabuf *buf, *comeback;
2901 int ret;
2902
2903 wpa_printf(MSG_DEBUG,
2904 "PASN: Building comeback frame 2. Comeback after=%u",
2905 hapd->conf->pasn_comeback_after);
2906
2907 buf = wpabuf_alloc(1500);
2908 if (!buf)
2909 return;
2910
2911 wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
2912 sta->addr, 2,
2913 WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY);
2914
2915 /*
2916 * Do not include the group as a part of the token since it is not going
2917 * to be used.
2918 */
2919 comeback = auth_build_token_req(hapd, 0, sta->addr, 0);
2920 if (!comeback) {
2921 wpa_printf(MSG_DEBUG,
2922 "PASN: Failed sending auth with comeback");
2923 wpabuf_free(buf);
2924 return;
2925 }
2926
2927 wpa_pasn_add_parameter_ie(buf, group,
2928 WPA_PASN_WRAPPED_DATA_NO,
2929 NULL, 0, comeback,
2930 hapd->conf->pasn_comeback_after);
2931 wpabuf_free(comeback);
2932
2933 wpa_printf(MSG_DEBUG,
2934 "PASN: comeback: STA=" MACSTR, MAC2STR(sta->addr));
2935
2936 ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
2937 NULL, 0, 0);
2938 if (ret)
2939 wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2");
2940
2941 wpabuf_free(buf);
2942}
2943
2944
Hai Shalom60840252021-02-19 19:02:11 -08002945static int handle_auth_pasn_resp(struct hostapd_data *hapd,
2946 struct sta_info *sta,
2947 struct rsn_pmksa_cache_entry *pmksa,
2948 u16 status)
2949{
2950 struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
2951 u8 mic[WPA_PASN_MAX_MIC_LEN];
Hai Shaloma20dcd72022-02-04 13:43:00 -08002952 u8 mic_len;
Hai Shalom60840252021-02-19 19:02:11 -08002953 u8 *ptr;
2954 const u8 *frame, *data, *rsn_ie, *rsnxe_ie;
2955 u8 *data_buf = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002956 size_t rsn_ie_len, frame_len, data_len;
Hai Shalom60840252021-02-19 19:02:11 -08002957 int ret;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002958 const u8 *pmkid = NULL;
Hai Shalom60840252021-02-19 19:02:11 -08002959
2960 wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status);
2961
2962 buf = wpabuf_alloc(1500);
2963 if (!buf)
2964 goto fail;
2965
2966 wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
2967 sta->addr, 2, status);
2968
2969 if (status != WLAN_STATUS_SUCCESS)
2970 goto done;
2971
Hai Shaloma20dcd72022-02-04 13:43:00 -08002972 if (pmksa) {
2973 pmkid = pmksa->pmkid;
2974#ifdef CONFIG_SAE
2975 } else if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
2976 wpa_printf(MSG_DEBUG, "PASN: Use SAE PMKID");
2977 pmkid = sta->pasn->sae.pmkid;
2978#endif /* CONFIG_SAE */
2979#ifdef CONFIG_FILS
2980 } else if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
2981 sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
2982 wpa_printf(MSG_DEBUG, "PASN: Use FILS ERP PMKID");
2983 pmkid = sta->pasn->fils.erp_pmkid;
2984#endif /* CONFIG_FILS */
2985 }
2986
2987 if (wpa_pasn_add_rsne(buf, pmkid,
Hai Shalom60840252021-02-19 19:02:11 -08002988 sta->pasn->akmp, sta->pasn->cipher) < 0)
2989 goto fail;
2990
2991 /* No need to derive PMK if PMKSA is given */
2992 if (!pmksa)
2993 wrapped_data_buf = pasn_get_wrapped_data(hapd, sta);
2994 else
2995 sta->pasn->wrapped_data_format = WPA_PASN_WRAPPED_DATA_NO;
2996
2997 /* Get public key */
2998 pubkey = crypto_ecdh_get_pubkey(sta->pasn->ecdh, 0);
2999 pubkey = wpabuf_zeropad(pubkey,
3000 crypto_ecdh_prime_len(sta->pasn->ecdh));
3001 if (!pubkey) {
3002 wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey");
3003 goto fail;
3004 }
3005
3006 wpa_pasn_add_parameter_ie(buf, sta->pasn->group,
3007 sta->pasn->wrapped_data_format,
Hai Shaloma20dcd72022-02-04 13:43:00 -08003008 pubkey, true, NULL, 0);
Hai Shalom60840252021-02-19 19:02:11 -08003009
3010 if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
3011 goto fail;
3012
3013 wpabuf_free(wrapped_data_buf);
3014 wrapped_data_buf = NULL;
3015 wpabuf_free(pubkey);
3016 pubkey = NULL;
3017
3018 /* Add RSNXE if needed */
3019 rsnxe_ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
3020 if (rsnxe_ie)
3021 wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
3022
3023 /* Add the mic */
3024 mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
3025 wpabuf_put_u8(buf, WLAN_EID_MIC);
3026 wpabuf_put_u8(buf, mic_len);
3027 ptr = wpabuf_put(buf, mic_len);
3028
3029 os_memset(ptr, 0, mic_len);
3030
3031 frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
3032 frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
3033
3034 rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &rsn_ie_len);
3035 if (!rsn_ie || !rsn_ie_len)
3036 goto fail;
3037
3038 /*
3039 * Note: wpa_auth_get_wpa_ie() might return not only the RSNE but also
3040 * MDE, etc. Thus, do not use the returned length but instead use the
3041 * length specified in the IE header.
3042 */
3043 data_len = rsn_ie[1] + 2;
3044 if (rsnxe_ie) {
3045 data_buf = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2);
3046 if (!data_buf)
3047 goto fail;
3048
3049 os_memcpy(data_buf, rsn_ie, rsn_ie[1] + 2);
3050 os_memcpy(data_buf + rsn_ie[1] + 2, rsnxe_ie, rsnxe_ie[1] + 2);
3051 data_len += rsnxe_ie[1] + 2;
3052 data = data_buf;
3053 } else {
3054 data = rsn_ie;
3055 }
3056
3057 ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
3058 hapd->own_addr, sta->addr, data, data_len,
3059 frame, frame_len, mic);
3060 os_free(data_buf);
3061 if (ret) {
3062 wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation");
3063 goto fail;
3064 }
3065
Hai Shaloma20dcd72022-02-04 13:43:00 -08003066#ifdef CONFIG_TESTING_OPTIONS
3067 if (hapd->conf->pasn_corrupt_mic) {
3068 wpa_printf(MSG_DEBUG, "PASN: frame 2: Corrupt MIC");
3069 mic[0] = ~mic[0];
3070 }
3071#endif /* CONFIG_TESTING_OPTIONS */
3072
Hai Shalom60840252021-02-19 19:02:11 -08003073 os_memcpy(ptr, mic, mic_len);
3074
3075done:
3076 wpa_printf(MSG_DEBUG,
3077 "PASN: Building frame 2: success; resp STA=" MACSTR,
3078 MAC2STR(sta->addr));
3079
3080 ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
3081 NULL, 0, 0);
3082 if (ret)
3083 wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
3084
3085 wpabuf_free(buf);
3086 return ret;
3087fail:
3088 wpabuf_free(wrapped_data_buf);
3089 wpabuf_free(pubkey);
3090 wpabuf_free(buf);
3091 return -1;
3092}
3093
3094
3095static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
3096 const struct ieee80211_mgmt *mgmt, size_t len)
3097{
3098 struct ieee802_11_elems elems;
3099 struct wpa_ie_data rsn_data;
3100 struct wpa_pasn_params_data pasn_params;
3101 struct rsn_pmksa_cache_entry *pmksa = NULL;
3102 const u8 *cached_pmk = NULL;
3103 size_t cached_pmk_len = 0;
3104#ifdef CONFIG_IEEE80211R_AP
3105 u8 pmk_r1[PMK_LEN_MAX];
3106 size_t pmk_r1_len;
3107#endif /* CONFIG_IEEE80211R_AP */
3108 struct wpabuf *wrapped_data = NULL, *secret = NULL;
3109 const int *groups = hapd->conf->pasn_groups;
3110 static const int default_groups[] = { 19, 0 };
3111 u16 status = WLAN_STATUS_SUCCESS;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003112 int ret, inc_y;
Hai Shalom60840252021-02-19 19:02:11 -08003113 bool derive_keys;
3114 u32 i;
3115
3116 if (!groups)
3117 groups = default_groups;
3118
3119 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
3120 len - offsetof(struct ieee80211_mgmt,
3121 u.auth.variable),
3122 &elems, 0) == ParseFailed) {
3123 wpa_printf(MSG_DEBUG,
3124 "PASN: Failed parsing Authentication frame");
3125 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3126 goto send_resp;
3127 }
3128
3129 ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
3130 &rsn_data);
3131 if (ret) {
3132 wpa_printf(MSG_DEBUG, "PASN: Failed parsing RNSE");
3133 status = WLAN_STATUS_INVALID_RSNIE;
3134 goto send_resp;
3135 }
3136
3137 ret = wpa_pasn_validate_rsne(&rsn_data);
3138 if (ret) {
3139 wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
3140 status = WLAN_STATUS_INVALID_RSNIE;
3141 goto send_resp;
3142 }
3143
3144 if (!(rsn_data.key_mgmt & hapd->conf->wpa_key_mgmt) ||
3145 !(rsn_data.pairwise_cipher & hapd->conf->rsn_pairwise)) {
3146 wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
3147 status = WLAN_STATUS_INVALID_RSNIE;
3148 goto send_resp;
3149 }
3150
3151 sta->pasn->akmp = rsn_data.key_mgmt;
3152 sta->pasn->cipher = rsn_data.pairwise_cipher;
3153
Hai Shaloma20dcd72022-02-04 13:43:00 -08003154 if (hapd->conf->force_kdk_derivation ||
3155 ((hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) &&
3156 ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
3157 WLAN_RSNX_CAPAB_SECURE_LTF)))
3158 sta->pasn->kdk_len = WPA_KDK_MAX_LEN;
3159 else
3160 sta->pasn->kdk_len = 0;
3161 wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", sta->pasn->kdk_len);
3162
Hai Shalom60840252021-02-19 19:02:11 -08003163 if (!elems.pasn_params || !elems.pasn_params_len) {
3164 wpa_printf(MSG_DEBUG,
3165 "PASN: No PASN Parameters element found");
3166 status = WLAN_STATUS_INVALID_PARAMETERS;
3167 goto send_resp;
3168 }
3169
3170 ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
3171 elems.pasn_params_len + 3,
3172 false, &pasn_params);
3173 if (ret) {
3174 wpa_printf(MSG_DEBUG,
3175 "PASN: Failed validation of PASN Parameters IE");
3176 status = WLAN_STATUS_INVALID_PARAMETERS;
3177 goto send_resp;
3178 }
3179
3180 for (i = 0; groups[i] > 0 && groups[i] != pasn_params.group; i++)
3181 ;
3182
3183 if (!pasn_params.group || groups[i] != pasn_params.group) {
3184 wpa_printf(MSG_DEBUG, "PASN: Requested group=%hu not allowed",
3185 pasn_params.group);
3186 status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3187 goto send_resp;
3188 }
3189
3190 if (!pasn_params.pubkey || !pasn_params.pubkey_len) {
3191 wpa_printf(MSG_DEBUG, "PASN: Invalid public key");
3192 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3193 goto send_resp;
3194 }
3195
Hai Shaloma20dcd72022-02-04 13:43:00 -08003196 if (pasn_params.comeback) {
3197 wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token");
3198
3199 ret = check_comeback_token(hapd, sta->addr,
3200 pasn_params.comeback,
3201 pasn_params.comeback_len);
3202
3203 if (ret) {
3204 wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token");
3205 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3206 goto send_resp;
3207 }
3208 } else if (use_anti_clogging(hapd)) {
3209 wpa_printf(MSG_DEBUG, "PASN: Respond with comeback");
3210 handle_auth_pasn_comeback(hapd, sta, pasn_params.group);
3211 ap_free_sta(hapd, sta);
3212 return;
3213 }
3214
Hai Shalom60840252021-02-19 19:02:11 -08003215 sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group);
3216 if (!sta->pasn->ecdh) {
3217 wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
3218 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3219 goto send_resp;
3220 }
3221
3222 sta->pasn->group = pasn_params.group;
3223
Hai Shaloma20dcd72022-02-04 13:43:00 -08003224 if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) {
3225 inc_y = 1;
3226 } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 ||
3227 pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) {
3228 inc_y = 0;
3229 } else {
3230 wpa_printf(MSG_DEBUG,
3231 "PASN: Invalid first octet in pubkey=0x%x",
3232 pasn_params.pubkey[0]);
3233 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3234 goto send_resp;
3235 }
3236
3237 secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, inc_y,
3238 pasn_params.pubkey + 1,
3239 pasn_params.pubkey_len - 1);
Hai Shalom60840252021-02-19 19:02:11 -08003240 if (!secret) {
3241 wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
3242 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3243 goto send_resp;
3244 }
3245
3246 derive_keys = true;
3247 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
3248 wrapped_data = ieee802_11_defrag(&elems,
3249 WLAN_EID_EXTENSION,
3250 WLAN_EID_EXT_WRAPPED_DATA);
3251 if (!wrapped_data) {
3252 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
3253 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3254 goto send_resp;
3255 }
3256
3257#ifdef CONFIG_SAE
3258 if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
3259 ret = pasn_wd_handle_sae_commit(hapd, sta,
3260 wrapped_data);
3261 if (ret) {
3262 wpa_printf(MSG_DEBUG,
3263 "PASN: Failed processing SAE commit");
3264 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3265 goto send_resp;
3266 }
3267 }
3268#endif /* CONFIG_SAE */
3269#ifdef CONFIG_FILS
3270 if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
3271 sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
3272 ret = pasn_wd_handle_fils(hapd, sta, wrapped_data);
3273 if (ret) {
3274 wpa_printf(MSG_DEBUG,
3275 "PASN: Failed processing FILS wrapped data");
3276 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3277 goto send_resp;
3278 }
3279
3280 wpa_printf(MSG_DEBUG,
3281 "PASN: FILS: Pending AS response");
3282
3283 /*
3284 * With PASN/FILS, keys can be derived only after a
3285 * response from the AS is processed.
3286 */
3287 derive_keys = false;
3288 }
3289#endif /* CONFIG_FILS */
3290 }
3291
3292 sta->pasn->wrapped_data_format = pasn_params.wrapped_data_format;
3293
3294 ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
3295 ((const u8 *) mgmt) + IEEE80211_HDRLEN,
3296 len - IEEE80211_HDRLEN, sta->pasn->hash);
3297 if (ret) {
3298 wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
3299 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3300 goto send_resp;
3301 }
3302
3303 if (!derive_keys) {
3304 wpa_printf(MSG_DEBUG, "PASN: Storing secret");
3305 sta->pasn->secret = secret;
3306 wpabuf_free(wrapped_data);
3307 return;
3308 }
3309
3310 if (rsn_data.num_pmkid) {
3311 if (wpa_key_mgmt_ft(sta->pasn->akmp)) {
3312#ifdef CONFIG_IEEE80211R_AP
3313 wpa_printf(MSG_DEBUG, "PASN: FT: Fetch PMK-R1");
3314
3315 ret = wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
3316 rsn_data.pmkid,
3317 pmk_r1, &pmk_r1_len, NULL,
3318 NULL, NULL, NULL,
3319 NULL, NULL, NULL);
3320 if (ret) {
3321 wpa_printf(MSG_DEBUG,
3322 "PASN: FT: Failed getting PMK-R1");
3323 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3324 goto send_resp;
3325 }
3326 cached_pmk = pmk_r1;
3327 cached_pmk_len = pmk_r1_len;
3328#else /* CONFIG_IEEE80211R_AP */
3329 wpa_printf(MSG_DEBUG, "PASN: FT: Not supported");
3330 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3331 goto send_resp;
3332#endif /* CONFIG_IEEE80211R_AP */
3333 } else {
3334 wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry");
3335
3336 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
3337 rsn_data.pmkid);
3338 if (pmksa) {
3339 cached_pmk = pmksa->pmk;
3340 cached_pmk_len = pmksa->pmk_len;
3341 }
3342 }
3343 } else {
3344 wpa_printf(MSG_DEBUG, "PASN: No PMKID specified");
3345 }
3346
3347 ret = pasn_derive_keys(hapd, sta, cached_pmk, cached_pmk_len,
3348 &pasn_params, wrapped_data, secret);
3349 if (ret) {
3350 wpa_printf(MSG_DEBUG, "PASN: Failed to derive keys");
3351 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3352 goto send_resp;
3353 }
3354
3355 ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
3356 ((const u8 *) mgmt) + IEEE80211_HDRLEN,
3357 len - IEEE80211_HDRLEN, sta->pasn->hash);
3358 if (ret) {
3359 wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
3360 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3361 }
3362
3363send_resp:
3364 ret = handle_auth_pasn_resp(hapd, sta, pmksa, status);
3365 if (ret) {
3366 wpa_printf(MSG_DEBUG, "PASN: Failed to send response");
3367 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3368 } else {
3369 wpa_printf(MSG_DEBUG,
3370 "PASN: Success handling transaction == 1");
3371 }
3372
3373 wpabuf_free(secret);
3374 wpabuf_free(wrapped_data);
3375
3376 if (status != WLAN_STATUS_SUCCESS)
3377 ap_free_sta(hapd, sta);
3378}
3379
3380
3381static void handle_auth_pasn_3(struct hostapd_data *hapd, struct sta_info *sta,
3382 const struct ieee80211_mgmt *mgmt, size_t len)
3383{
3384 struct ieee802_11_elems elems;
3385 struct wpa_pasn_params_data pasn_params;
3386 struct wpabuf *wrapped_data = NULL;
3387 u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
3388 u8 mic_len;
3389 int ret;
3390
3391 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
3392 len - offsetof(struct ieee80211_mgmt,
3393 u.auth.variable),
3394 &elems, 0) == ParseFailed) {
3395 wpa_printf(MSG_DEBUG,
3396 "PASN: Failed parsing Authentication frame");
3397 goto fail;
3398 }
3399
3400 /* Check that the MIC IE exists. Save it and zero out the memory. */
3401 mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
3402 if (!elems.mic || elems.mic_len != mic_len) {
3403 wpa_printf(MSG_DEBUG,
3404 "PASN: Invalid MIC. Expecting len=%u", mic_len);
3405 goto fail;
3406 } else {
3407 os_memcpy(mic, elems.mic, mic_len);
3408 /* TODO: Clean this up.. Should not modify received frame
3409 * buffer. */
3410 os_memset((u8 *) elems.mic, 0, mic_len);
3411 }
3412
3413 if (!elems.pasn_params || !elems.pasn_params_len) {
3414 wpa_printf(MSG_DEBUG,
3415 "PASN: No PASN Parameters element found");
3416 goto fail;
3417 }
3418
3419 ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
3420 elems.pasn_params_len + 3,
3421 false, &pasn_params);
3422 if (ret) {
3423 wpa_printf(MSG_DEBUG,
3424 "PASN: Failed validation of PASN Parameters IE");
3425 goto fail;
3426 }
3427
3428 if (pasn_params.pubkey || pasn_params.pubkey_len) {
3429 wpa_printf(MSG_DEBUG,
3430 "PASN: Public key should not be included");
3431 goto fail;
3432 }
3433
3434 /* Verify the MIC */
3435 ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
3436 sta->addr, hapd->own_addr,
3437 sta->pasn->hash, mic_len * 2,
3438 (u8 *) &mgmt->u.auth,
3439 len - offsetof(struct ieee80211_mgmt, u.auth),
3440 out_mic);
3441
3442 wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len);
3443 if (ret || os_memcmp(mic, out_mic, mic_len) != 0) {
3444 wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification");
3445 goto fail;
3446 }
3447
3448 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
3449 wrapped_data = ieee802_11_defrag(&elems,
3450 WLAN_EID_EXTENSION,
3451 WLAN_EID_EXT_WRAPPED_DATA);
3452
3453 if (!wrapped_data) {
3454 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
3455 goto fail;
3456 }
3457
3458#ifdef CONFIG_SAE
3459 if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
3460 ret = pasn_wd_handle_sae_confirm(hapd, sta,
3461 wrapped_data);
3462 if (ret) {
3463 wpa_printf(MSG_DEBUG,
3464 "PASN: Failed processing SAE confirm");
3465 wpabuf_free(wrapped_data);
3466 goto fail;
3467 }
3468 }
3469#endif /* CONFIG_SAE */
3470#ifdef CONFIG_FILS
3471 if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
3472 sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
3473 if (wrapped_data) {
3474 wpa_printf(MSG_DEBUG,
3475 "PASN: FILS: Ignore wrapped data");
3476 }
3477 }
3478#endif /* CONFIG_FILS */
3479 wpabuf_free(wrapped_data);
3480 }
3481
3482 wpa_printf(MSG_INFO,
3483 "PASN: Success handling transaction == 3. Store PTK");
3484
3485 ptksa_cache_add(hapd->ptksa, sta->addr, sta->pasn->cipher, 43200,
3486 &sta->pasn->ptk);
3487fail:
3488 ap_free_sta(hapd, sta);
3489}
3490
3491
3492static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
3493 const struct ieee80211_mgmt *mgmt, size_t len,
3494 u16 trans_seq, u16 status)
3495{
3496 if (hapd->conf->wpa != WPA_PROTO_RSN) {
3497 wpa_printf(MSG_INFO, "PASN: RSN is not configured");
3498 return;
3499 }
3500
3501 wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR,
3502 MAC2STR(sta->addr));
3503
3504 if (trans_seq == 1) {
3505 if (sta->pasn) {
3506 wpa_printf(MSG_DEBUG,
3507 "PASN: Not expecting transaction == 1");
3508 return;
3509 }
3510
3511 if (status != WLAN_STATUS_SUCCESS) {
3512 wpa_printf(MSG_DEBUG,
3513 "PASN: Failure status in transaction == 1");
3514 return;
3515 }
3516
3517 sta->pasn = os_zalloc(sizeof(*sta->pasn));
3518 if (!sta->pasn) {
3519 wpa_printf(MSG_DEBUG,
3520 "PASN: Failed to allocate PASN context");
3521 return;
3522 }
3523
3524 handle_auth_pasn_1(hapd, sta, mgmt, len);
3525 } else if (trans_seq == 3) {
3526 if (!sta->pasn) {
3527 wpa_printf(MSG_DEBUG,
3528 "PASN: Not expecting transaction == 3");
3529 return;
3530 }
3531
3532 if (status != WLAN_STATUS_SUCCESS) {
3533 wpa_printf(MSG_DEBUG,
3534 "PASN: Failure status in transaction == 3");
3535 ap_free_sta_pasn(hapd, sta);
3536 return;
3537 }
3538
3539 handle_auth_pasn_3(hapd, sta, mgmt, len);
3540 } else {
3541 wpa_printf(MSG_DEBUG,
3542 "PASN: Invalid transaction %u - ignore", trans_seq);
3543 }
3544}
3545
3546#endif /* CONFIG_PASN */
3547
3548
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003549static void handle_auth(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08003550 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom021b0b52019-04-10 11:17:58 -07003551 int rssi, int from_queue)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003552{
3553 u16 auth_alg, auth_transaction, status_code;
3554 u16 resp = WLAN_STATUS_SUCCESS;
3555 struct sta_info *sta = NULL;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003556 int res, reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003557 u16 fc;
3558 const u8 *challenge = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003559 u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
3560 size_t resp_ies_len = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003561 u16 seq_ctrl;
Hai Shalomfdcde762020-04-02 11:19:20 -07003562 struct radius_sta rad_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003563
3564 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003565 wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
3566 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003567 return;
3568 }
3569
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003570#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07003571 if (hapd->iconf->ignore_auth_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003572 drand48() < hapd->iconf->ignore_auth_probability) {
3573 wpa_printf(MSG_INFO,
3574 "TESTING: ignoring auth frame from " MACSTR,
3575 MAC2STR(mgmt->sa));
3576 return;
3577 }
3578#endif /* CONFIG_TESTING_OPTIONS */
3579
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003580 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
3581 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
3582 status_code = le_to_host16(mgmt->u.auth.status_code);
3583 fc = le_to_host16(mgmt->frame_control);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003584 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003585
3586 if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
3587 2 + WLAN_AUTH_CHALLENGE_LEN &&
3588 mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
3589 mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
3590 challenge = &mgmt->u.auth.variable[2];
3591
3592 wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003593 "auth_transaction=%d status_code=%d wep=%d%s "
Hai Shalom021b0b52019-04-10 11:17:58 -07003594 "seq_ctrl=0x%x%s%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003595 MAC2STR(mgmt->sa), auth_alg, auth_transaction,
3596 status_code, !!(fc & WLAN_FC_ISWEP),
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003597 challenge ? " challenge" : "",
Hai Shalom021b0b52019-04-10 11:17:58 -07003598 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
3599 from_queue ? " (from queue)" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003600
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003601#ifdef CONFIG_NO_RC4
3602 if (auth_alg == WLAN_AUTH_SHARED_KEY) {
3603 wpa_printf(MSG_INFO,
3604 "Unsupported authentication algorithm (%d)",
3605 auth_alg);
3606 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
3607 goto fail;
3608 }
3609#endif /* CONFIG_NO_RC4 */
3610
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003611 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003612 wpa_printf(MSG_DEBUG,
3613 "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
3614 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003615 goto fail;
3616 }
3617
3618 if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
3619 auth_alg == WLAN_AUTH_OPEN) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003620#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003621 (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003622 auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003623#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003624#ifdef CONFIG_SAE
3625 (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
3626 auth_alg == WLAN_AUTH_SAE) ||
3627#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003628#ifdef CONFIG_FILS
3629 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
3630 auth_alg == WLAN_AUTH_FILS_SK) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003631 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
3632 hapd->conf->fils_dh_group &&
3633 auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003634#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08003635#ifdef CONFIG_PASN
3636 (hapd->conf->wpa &&
3637 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) &&
3638 auth_alg == WLAN_AUTH_PASN) ||
3639#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003640 ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
3641 auth_alg == WLAN_AUTH_SHARED_KEY))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003642 wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
3643 auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003644 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
3645 goto fail;
3646 }
3647
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003648 if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
Hai Shalom60840252021-02-19 19:02:11 -08003649#ifdef CONFIG_PASN
3650 (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) ||
3651#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003652 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003653 wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
3654 auth_transaction);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003655 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
3656 goto fail;
3657 }
3658
3659 if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003660 wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
3661 MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003662 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3663 goto fail;
3664 }
3665
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003666 if (hapd->conf->no_auth_if_seen_on) {
3667 struct hostapd_data *other;
3668
3669 other = sta_track_seen_on(hapd->iface, mgmt->sa,
3670 hapd->conf->no_auth_if_seen_on);
3671 if (other) {
3672 u8 *pos;
3673 u32 info;
3674 u8 op_class, channel, phytype;
3675
3676 wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
3677 MACSTR " since STA has been seen on %s",
3678 hapd->conf->iface, MAC2STR(mgmt->sa),
3679 hapd->conf->no_auth_if_seen_on);
3680
3681 resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
3682 pos = &resp_ies[0];
3683 *pos++ = WLAN_EID_NEIGHBOR_REPORT;
3684 *pos++ = 13;
3685 os_memcpy(pos, other->own_addr, ETH_ALEN);
3686 pos += ETH_ALEN;
3687 info = 0; /* TODO: BSSID Information */
3688 WPA_PUT_LE32(pos, info);
3689 pos += 4;
3690 if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
3691 phytype = 8; /* dmg */
3692 else if (other->iconf->ieee80211ac)
3693 phytype = 9; /* vht */
3694 else if (other->iconf->ieee80211n)
3695 phytype = 7; /* ht */
3696 else if (other->iconf->hw_mode ==
3697 HOSTAPD_MODE_IEEE80211A)
3698 phytype = 4; /* ofdm */
3699 else if (other->iconf->hw_mode ==
3700 HOSTAPD_MODE_IEEE80211G)
3701 phytype = 6; /* erp */
3702 else
3703 phytype = 5; /* hrdsss */
3704 if (ieee80211_freq_to_channel_ext(
3705 hostapd_hw_get_freq(other,
3706 other->iconf->channel),
3707 other->iconf->secondary_channel,
3708 other->iconf->ieee80211ac,
3709 &op_class, &channel) == NUM_HOSTAPD_MODES) {
3710 op_class = 0;
3711 channel = other->iconf->channel;
3712 }
3713 *pos++ = op_class;
3714 *pos++ = channel;
3715 *pos++ = phytype;
3716 resp_ies_len = pos - &resp_ies[0];
3717 goto fail;
3718 }
3719 }
3720
Hai Shalomfdcde762020-04-02 11:19:20 -07003721 res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
3722 &rad_info);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003723 if (res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003724 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
3725 "Ignore Authentication frame from " MACSTR
3726 " due to ACL reject", MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003727 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3728 goto fail;
3729 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003730 if (res == HOSTAPD_ACL_PENDING)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003731 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003732
Hai Shalom021b0b52019-04-10 11:17:58 -07003733#ifdef CONFIG_SAE
3734 if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
3735 (auth_transaction == 1 ||
3736 (auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) {
3737 /* Handle SAE Authentication commit message through a queue to
3738 * provide more control for postponing the needed heavy
3739 * processing under a possible DoS attack scenario. In addition,
3740 * queue SAE Authentication confirm message if there happens to
3741 * be a queued commit message from the same peer. This is needed
3742 * to avoid reordering Authentication frames within the same
3743 * SAE exchange. */
3744 auth_sae_queue(hapd, mgmt, len, rssi);
3745 return;
3746 }
3747#endif /* CONFIG_SAE */
3748
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003749 sta = ap_get_sta(hapd, mgmt->sa);
3750 if (sta) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003751 sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
Hai Shalom74f70d42019-02-11 14:42:39 -08003752 sta->ft_over_ds = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003753 if ((fc & WLAN_FC_RETRY) &&
3754 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
3755 sta->last_seq_ctrl == seq_ctrl &&
3756 sta->last_subtype == WLAN_FC_STYPE_AUTH) {
3757 hostapd_logger(hapd, sta->addr,
3758 HOSTAPD_MODULE_IEEE80211,
3759 HOSTAPD_LEVEL_DEBUG,
3760 "Drop repeated authentication frame seq_ctrl=0x%x",
3761 seq_ctrl);
3762 return;
3763 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003764#ifdef CONFIG_MESH
3765 if ((hapd->conf->mesh & MESH_ENABLED) &&
3766 sta->plink_state == PLINK_BLOCKED) {
3767 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
3768 " is blocked - drop Authentication frame",
3769 MAC2STR(mgmt->sa));
3770 return;
3771 }
3772#endif /* CONFIG_MESH */
Hai Shalom60840252021-02-19 19:02:11 -08003773#ifdef CONFIG_PASN
3774 if (auth_alg == WLAN_AUTH_PASN &&
3775 (sta->flags & WLAN_STA_ASSOC)) {
3776 wpa_printf(MSG_DEBUG,
3777 "PASN: auth: Existing station: " MACSTR,
3778 MAC2STR(sta->addr));
3779 return;
3780 }
3781#endif /* CONFIG_PASN */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003782 } else {
3783#ifdef CONFIG_MESH
3784 if (hapd->conf->mesh & MESH_ENABLED) {
3785 /* if the mesh peer is not available, we don't do auth.
3786 */
3787 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003788 " not yet known - drop Authentication frame",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003789 MAC2STR(mgmt->sa));
3790 /*
3791 * Save a copy of the frame so that it can be processed
3792 * if a new peer entry is added shortly after this.
3793 */
3794 wpabuf_free(hapd->mesh_pending_auth);
3795 hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len);
3796 os_get_reltime(&hapd->mesh_pending_auth_time);
3797 return;
3798 }
3799#endif /* CONFIG_MESH */
3800
3801 sta = ap_sta_add(hapd, mgmt->sa);
3802 if (!sta) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003803 wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003804 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3805 goto fail;
3806 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003807 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003808 sta->last_seq_ctrl = seq_ctrl;
3809 sta->last_subtype = WLAN_FC_STYPE_AUTH;
Hai Shalom74f70d42019-02-11 14:42:39 -08003810#ifdef CONFIG_MBO
3811 sta->auth_rssi = rssi;
3812#endif /* CONFIG_MBO */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003813
Hai Shalomfdcde762020-04-02 11:19:20 -07003814 res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003815 if (res) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003816 wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003817 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3818 goto fail;
3819 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003820
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003821 sta->flags &= ~WLAN_STA_PREAUTH;
3822 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
3823
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003824 /*
3825 * If the driver supports full AP client state, add a station to the
3826 * driver before sending authentication reply to make sure the driver
3827 * has resources, and not to go through the entire authentication and
3828 * association handshake, and fail it at the end.
3829 *
3830 * If this is not the first transaction, in a multi-step authentication
3831 * algorithm, the station already exists in the driver
3832 * (sta->added_unassoc = 1) so skip it.
3833 *
3834 * In mesh mode, the station was already added to the driver when the
3835 * NEW_PEER_CANDIDATE event is received.
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003836 *
3837 * If PMF was negotiated for the existing association, skip this to
3838 * avoid dropping the STA entry and the associated keys. This is needed
3839 * to allow the original connection work until the attempt can complete
3840 * (re)association, so that unprotected Authentication frame cannot be
3841 * used to bypass PMF protection.
Hai Shalom60840252021-02-19 19:02:11 -08003842 *
3843 * PASN authentication does not require adding/removing station to the
3844 * driver so skip this flow in case of PASN authentication.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003845 */
3846 if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003847 (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003848 !(hapd->conf->mesh & MESH_ENABLED) &&
Hai Shalom60840252021-02-19 19:02:11 -08003849 !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) {
Hai Shalomb755a2a2020-04-23 21:49:02 -07003850 if (ap_sta_re_add(hapd, sta) < 0) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003851 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3852 goto fail;
3853 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003854 }
3855
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003856 switch (auth_alg) {
3857 case WLAN_AUTH_OPEN:
3858 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3859 HOSTAPD_LEVEL_DEBUG,
3860 "authentication OK (open system)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003861 sta->flags |= WLAN_STA_AUTH;
3862 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
3863 sta->auth_alg = WLAN_AUTH_OPEN;
3864 mlme_authenticate_indication(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003865 break;
Hai Shalomfdcde762020-04-02 11:19:20 -07003866#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003867#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003868 case WLAN_AUTH_SHARED_KEY:
3869 resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
3870 fc & WLAN_FC_ISWEP);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003871 if (resp != 0)
3872 wpa_printf(MSG_DEBUG,
3873 "auth_shared_key() failed: status=%d", resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003874 sta->auth_alg = WLAN_AUTH_SHARED_KEY;
3875 mlme_authenticate_indication(hapd, sta);
3876 if (sta->challenge && auth_transaction == 1) {
3877 resp_ies[0] = WLAN_EID_CHALLENGE;
3878 resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
3879 os_memcpy(resp_ies + 2, sta->challenge,
3880 WLAN_AUTH_CHALLENGE_LEN);
3881 resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
3882 }
3883 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003884#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003885#endif /* CONFIG_WEP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003886#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003887 case WLAN_AUTH_FT:
3888 sta->auth_alg = WLAN_AUTH_FT;
3889 if (sta->wpa_sm == NULL)
3890 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003891 sta->addr, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003892 if (sta->wpa_sm == NULL) {
3893 wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
3894 "state machine");
3895 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3896 goto fail;
3897 }
3898 wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
3899 auth_transaction, mgmt->u.auth.variable,
3900 len - IEEE80211_HDRLEN -
3901 sizeof(mgmt->u.auth),
3902 handle_auth_ft_finish, hapd);
3903 /* handle_auth_ft_finish() callback will complete auth. */
3904 return;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003905#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003906#ifdef CONFIG_SAE
3907 case WLAN_AUTH_SAE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003908#ifdef CONFIG_MESH
3909 if (status_code == WLAN_STATUS_SUCCESS &&
3910 hapd->conf->mesh & MESH_ENABLED) {
3911 if (sta->wpa_sm == NULL)
3912 sta->wpa_sm =
3913 wpa_auth_sta_init(hapd->wpa_auth,
3914 sta->addr, NULL);
3915 if (sta->wpa_sm == NULL) {
3916 wpa_printf(MSG_DEBUG,
3917 "SAE: Failed to initialize WPA state machine");
3918 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3919 goto fail;
3920 }
3921 }
3922#endif /* CONFIG_MESH */
3923 handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
3924 status_code);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003925 return;
3926#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003927#ifdef CONFIG_FILS
3928 case WLAN_AUTH_FILS_SK:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003929 case WLAN_AUTH_FILS_SK_PFS:
3930 handle_auth_fils(hapd, sta, mgmt->u.auth.variable,
3931 len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth),
3932 auth_alg, auth_transaction, status_code,
3933 handle_auth_fils_finish);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003934 return;
3935#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08003936#ifdef CONFIG_PASN
3937 case WLAN_AUTH_PASN:
3938 handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction,
3939 status_code);
3940 return;
3941#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003942 }
3943
3944 fail:
Hai Shalomfdcde762020-04-02 11:19:20 -07003945 reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg,
Hai Shaloma20dcd72022-02-04 13:43:00 -08003946 auth_alg == WLAN_AUTH_SAE ?
3947 auth_transaction : auth_transaction + 1,
3948 resp, resp_ies, resp_ies_len,
3949 "handle-auth");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003950
3951 if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
3952 reply_res != WLAN_STATUS_SUCCESS)) {
3953 hostapd_drv_sta_remove(hapd, sta->addr);
3954 sta->added_unassoc = 0;
3955 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003956}
3957
3958
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003959int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003960{
3961 int i, j = 32, aid;
3962
3963 /* get a unique AID */
3964 if (sta->aid > 0) {
3965 wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
3966 return 0;
3967 }
3968
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003969 if (TEST_FAIL())
3970 return -1;
3971
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003972 for (i = 0; i < AID_WORDS; i++) {
3973 if (hapd->sta_aid[i] == (u32) -1)
3974 continue;
3975 for (j = 0; j < 32; j++) {
3976 if (!(hapd->sta_aid[i] & BIT(j)))
3977 break;
3978 }
3979 if (j < 32)
3980 break;
3981 }
3982 if (j == 32)
3983 return -1;
3984 aid = i * 32 + j + 1;
3985 if (aid > 2007)
3986 return -1;
3987
3988 sta->aid = aid;
3989 hapd->sta_aid[i] |= BIT(j);
3990 wpa_printf(MSG_DEBUG, " new AID %d", sta->aid);
3991 return 0;
3992}
3993
3994
3995static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
3996 const u8 *ssid_ie, size_t ssid_ie_len)
3997{
3998 if (ssid_ie == NULL)
3999 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4000
4001 if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
4002 os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004003 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4004 HOSTAPD_LEVEL_INFO,
4005 "Station tried to associate with unknown SSID "
Dmitry Shmidt3c479372014-02-04 10:50:36 -08004006 "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004007 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4008 }
4009
4010 return WLAN_STATUS_SUCCESS;
4011}
4012
4013
4014static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
4015 const u8 *wmm_ie, size_t wmm_ie_len)
4016{
4017 sta->flags &= ~WLAN_STA_WMM;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004018 sta->qosinfo = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004019 if (wmm_ie && hapd->conf->wmm_enabled) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004020 struct wmm_information_element *wmm;
4021
4022 if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004023 hostapd_logger(hapd, sta->addr,
4024 HOSTAPD_MODULE_WPA,
4025 HOSTAPD_LEVEL_DEBUG,
4026 "invalid WMM element in association "
4027 "request");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004028 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4029 }
4030
4031 sta->flags |= WLAN_STA_WMM;
4032 wmm = (struct wmm_information_element *) wmm_ie;
4033 sta->qosinfo = wmm->qos_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004034 }
4035 return WLAN_STATUS_SUCCESS;
4036}
4037
Hai Shalom74f70d42019-02-11 14:42:39 -08004038static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
4039 const u8 *multi_ap_ie, size_t multi_ap_len)
4040{
4041 u8 multi_ap_value = 0;
4042
4043 sta->flags &= ~WLAN_STA_MULTI_AP;
4044
4045 if (!hapd->conf->multi_ap)
4046 return WLAN_STATUS_SUCCESS;
4047
4048 if (multi_ap_ie) {
4049 const u8 *multi_ap_subelem;
4050
4051 multi_ap_subelem = get_ie(multi_ap_ie + 4,
4052 multi_ap_len - 4,
4053 MULTI_AP_SUB_ELEM_TYPE);
4054 if (multi_ap_subelem && multi_ap_subelem[1] == 1) {
4055 multi_ap_value = multi_ap_subelem[2];
4056 } else {
4057 hostapd_logger(hapd, sta->addr,
4058 HOSTAPD_MODULE_IEEE80211,
4059 HOSTAPD_LEVEL_INFO,
4060 "Multi-AP IE has missing or invalid Multi-AP subelement");
4061 return WLAN_STATUS_INVALID_IE;
4062 }
4063 }
4064
Hai Shalom021b0b52019-04-10 11:17:58 -07004065 if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA)
4066 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4067 HOSTAPD_LEVEL_INFO,
4068 "Multi-AP IE with unexpected value 0x%02x",
4069 multi_ap_value);
Hai Shalom74f70d42019-02-11 14:42:39 -08004070
Hai Shalom021b0b52019-04-10 11:17:58 -07004071 if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) {
4072 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
4073 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08004074
Hai Shalom021b0b52019-04-10 11:17:58 -07004075 hostapd_logger(hapd, sta->addr,
4076 HOSTAPD_MODULE_IEEE80211,
4077 HOSTAPD_LEVEL_INFO,
4078 "Non-Multi-AP STA tries to associate with backhaul-only BSS");
4079 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
Hai Shalom74f70d42019-02-11 14:42:39 -08004080 }
4081
Hai Shalom021b0b52019-04-10 11:17:58 -07004082 if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
4083 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4084 HOSTAPD_LEVEL_DEBUG,
4085 "Backhaul STA tries to associate with fronthaul-only BSS");
4086
4087 sta->flags |= WLAN_STA_MULTI_AP;
4088 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08004089}
4090
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004091
4092static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
4093 struct ieee802_11_elems *elems)
4094{
Dmitry Shmidt29333592017-01-09 12:27:11 -08004095 /* Supported rates not used in IEEE 802.11ad/DMG */
4096 if (hapd->iface->current_mode &&
4097 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
4098 return WLAN_STATUS_SUCCESS;
4099
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004100 if (!elems->supp_rates) {
4101 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4102 HOSTAPD_LEVEL_DEBUG,
4103 "No supported rates element in AssocReq");
4104 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4105 }
4106
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004107 if (elems->supp_rates_len + elems->ext_supp_rates_len >
4108 sizeof(sta->supported_rates)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004109 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4110 HOSTAPD_LEVEL_DEBUG,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004111 "Invalid supported rates element length %d+%d",
4112 elems->supp_rates_len,
4113 elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004114 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4115 }
4116
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004117 sta->supported_rates_len = merge_byte_arrays(
4118 sta->supported_rates, sizeof(sta->supported_rates),
4119 elems->supp_rates, elems->supp_rates_len,
4120 elems->ext_supp_rates, elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004121
4122 return WLAN_STATUS_SUCCESS;
4123}
4124
4125
Dmitry Shmidt051af732013-10-22 13:52:46 -07004126static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
4127 const u8 *ext_capab_ie, size_t ext_capab_ie_len)
4128{
4129#ifdef CONFIG_INTERWORKING
4130 /* check for QoS Map support */
4131 if (ext_capab_ie_len >= 5) {
4132 if (ext_capab_ie[4] & 0x01)
4133 sta->qos_map_enabled = 1;
4134 }
4135#endif /* CONFIG_INTERWORKING */
4136
Roshan Pius3a1667e2018-07-03 15:17:14 -07004137 if (ext_capab_ie_len > 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004138 sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
Roshan Pius3a1667e2018-07-03 15:17:14 -07004139 os_free(sta->ext_capability);
4140 sta->ext_capability = os_malloc(1 + ext_capab_ie_len);
4141 if (sta->ext_capability) {
4142 sta->ext_capability[0] = ext_capab_ie_len;
4143 os_memcpy(sta->ext_capability + 1, ext_capab_ie,
4144 ext_capab_ie_len);
4145 }
4146 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004147
Dmitry Shmidt051af732013-10-22 13:52:46 -07004148 return WLAN_STATUS_SUCCESS;
4149}
4150
4151
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004152#ifdef CONFIG_OWE
4153
4154static int owe_group_supported(struct hostapd_data *hapd, u16 group)
4155{
4156 int i;
4157 int *groups = hapd->conf->owe_groups;
4158
4159 if (group != 19 && group != 20 && group != 21)
4160 return 0;
4161
4162 if (!groups)
4163 return 1;
4164
4165 for (i = 0; groups[i] > 0; i++) {
4166 if (groups[i] == group)
4167 return 1;
4168 }
4169
4170 return 0;
4171}
4172
4173
4174static u16 owe_process_assoc_req(struct hostapd_data *hapd,
4175 struct sta_info *sta, const u8 *owe_dh,
4176 u8 owe_dh_len)
4177{
4178 struct wpabuf *secret, *pub, *hkey;
4179 int res;
4180 u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN];
4181 const char *info = "OWE Key Generation";
4182 const u8 *addr[2];
4183 size_t len[2];
4184 u16 group;
4185 size_t hash_len, prime_len;
4186
4187 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
4188 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
4189 return WLAN_STATUS_SUCCESS;
4190 }
4191
4192 group = WPA_GET_LE16(owe_dh);
4193 if (!owe_group_supported(hapd, group)) {
4194 wpa_printf(MSG_DEBUG, "OWE: Unsupported DH group %u", group);
4195 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
4196 }
4197 if (group == 19)
4198 prime_len = 32;
4199 else if (group == 20)
4200 prime_len = 48;
4201 else if (group == 21)
4202 prime_len = 66;
4203 else
4204 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
4205
4206 crypto_ecdh_deinit(sta->owe_ecdh);
4207 sta->owe_ecdh = crypto_ecdh_init(group);
4208 if (!sta->owe_ecdh)
4209 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
4210 sta->owe_group = group;
4211
4212 secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2,
4213 owe_dh_len - 2);
4214 secret = wpabuf_zeropad(secret, prime_len);
4215 if (!secret) {
4216 wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
4217 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4218 }
4219 wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
4220
4221 /* prk = HKDF-extract(C | A | group, z) */
4222
4223 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
4224 if (!pub) {
4225 wpabuf_clear_free(secret);
4226 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4227 }
4228
4229 /* PMKID = Truncate-128(Hash(C | A)) */
4230 addr[0] = owe_dh + 2;
4231 len[0] = owe_dh_len - 2;
4232 addr[1] = wpabuf_head(pub);
4233 len[1] = wpabuf_len(pub);
4234 if (group == 19) {
4235 res = sha256_vector(2, addr, len, pmkid);
4236 hash_len = SHA256_MAC_LEN;
4237 } else if (group == 20) {
4238 res = sha384_vector(2, addr, len, pmkid);
4239 hash_len = SHA384_MAC_LEN;
4240 } else if (group == 21) {
4241 res = sha512_vector(2, addr, len, pmkid);
4242 hash_len = SHA512_MAC_LEN;
4243 } else {
4244 wpabuf_free(pub);
4245 wpabuf_clear_free(secret);
4246 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4247 }
4248 pub = wpabuf_zeropad(pub, prime_len);
4249 if (res < 0 || !pub) {
4250 wpabuf_free(pub);
4251 wpabuf_clear_free(secret);
4252 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4253 }
4254
4255 hkey = wpabuf_alloc(owe_dh_len - 2 + wpabuf_len(pub) + 2);
4256 if (!hkey) {
4257 wpabuf_free(pub);
4258 wpabuf_clear_free(secret);
4259 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4260 }
4261
4262 wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */
4263 wpabuf_put_buf(hkey, pub); /* A */
4264 wpabuf_free(pub);
4265 wpabuf_put_le16(hkey, group); /* group */
4266 if (group == 19)
4267 res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
4268 wpabuf_head(secret), wpabuf_len(secret), prk);
4269 else if (group == 20)
4270 res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey),
4271 wpabuf_head(secret), wpabuf_len(secret), prk);
4272 else if (group == 21)
4273 res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey),
4274 wpabuf_head(secret), wpabuf_len(secret), prk);
4275 wpabuf_clear_free(hkey);
4276 wpabuf_clear_free(secret);
4277 if (res < 0)
4278 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4279
4280 wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
4281
4282 /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
4283
4284 os_free(sta->owe_pmk);
4285 sta->owe_pmk = os_malloc(hash_len);
4286 if (!sta->owe_pmk) {
4287 os_memset(prk, 0, SHA512_MAC_LEN);
4288 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4289 }
4290
4291 if (group == 19)
4292 res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info,
4293 os_strlen(info), sta->owe_pmk, hash_len);
4294 else if (group == 20)
4295 res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info,
4296 os_strlen(info), sta->owe_pmk, hash_len);
4297 else if (group == 21)
4298 res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
4299 os_strlen(info), sta->owe_pmk, hash_len);
4300 os_memset(prk, 0, SHA512_MAC_LEN);
4301 if (res < 0) {
4302 os_free(sta->owe_pmk);
4303 sta->owe_pmk = NULL;
4304 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4305 }
4306 sta->owe_pmk_len = hash_len;
4307
4308 wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
4309 wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
4310 wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk,
4311 sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE);
4312
4313 return WLAN_STATUS_SUCCESS;
4314}
4315
Hai Shalom81f62d82019-07-22 12:10:00 -07004316
4317u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
4318 const u8 *rsn_ie, size_t rsn_ie_len,
4319 const u8 *owe_dh, size_t owe_dh_len)
4320{
4321 struct wpa_ie_data data;
4322 int res;
4323
4324 if (!rsn_ie || rsn_ie_len < 2) {
4325 wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
4326 MAC2STR(peer));
4327 return WLAN_STATUS_INVALID_IE;
4328 }
4329 rsn_ie -= 2;
4330 rsn_ie_len += 2;
4331
4332 res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
4333 if (res) {
4334 wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
4335 " (res=%d)", MAC2STR(peer), res);
4336 wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
4337 return wpa_res_to_status_code(res);
4338 }
4339 if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
4340 wpa_printf(MSG_DEBUG,
4341 "OWE: Unexpected key mgmt 0x%x from " MACSTR,
4342 (unsigned int) data.key_mgmt, MAC2STR(peer));
4343 return WLAN_STATUS_AKMP_NOT_VALID;
4344 }
4345 if (!owe_dh) {
4346 wpa_printf(MSG_DEBUG,
4347 "OWE: No Diffie-Hellman Parameter element from "
4348 MACSTR, MAC2STR(peer));
4349 return WLAN_STATUS_AKMP_NOT_VALID;
4350 }
4351
4352 return WLAN_STATUS_SUCCESS;
4353}
4354
4355
4356u16 owe_process_rsn_ie(struct hostapd_data *hapd,
4357 struct sta_info *sta,
4358 const u8 *rsn_ie, size_t rsn_ie_len,
4359 const u8 *owe_dh, size_t owe_dh_len)
4360{
4361 u16 status;
4362 u8 *owe_buf, ie[256 * 2];
4363 size_t ie_len = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07004364 enum wpa_validate_result res;
Hai Shalom81f62d82019-07-22 12:10:00 -07004365
4366 if (!rsn_ie || rsn_ie_len < 2) {
4367 wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
4368 status = WLAN_STATUS_INVALID_IE;
4369 goto end;
4370 }
4371
4372 if (!sta->wpa_sm)
4373 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
4374 NULL);
4375 if (!sta->wpa_sm) {
4376 wpa_printf(MSG_WARNING,
4377 "OWE: Failed to initialize WPA state machine");
4378 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4379 goto end;
4380 }
4381 rsn_ie -= 2;
4382 rsn_ie_len += 2;
4383 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
4384 hapd->iface->freq, rsn_ie, rsn_ie_len,
Hai Shalomc3565922019-10-28 11:58:20 -07004385 NULL, 0, NULL, 0, owe_dh, owe_dh_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07004386 status = wpa_res_to_status_code(res);
4387 if (status != WLAN_STATUS_SUCCESS)
4388 goto end;
4389 status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
4390 if (status != WLAN_STATUS_SUCCESS)
4391 goto end;
4392 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
4393 NULL, 0);
4394 if (!owe_buf) {
4395 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4396 goto end;
4397 }
4398
4399 if (sta->owe_ecdh) {
4400 struct wpabuf *pub;
4401
4402 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
4403 if (!pub) {
4404 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4405 goto end;
4406 }
4407
4408 /* OWE Diffie-Hellman Parameter element */
4409 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
4410 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
4411 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
4412 */
4413 WPA_PUT_LE16(owe_buf, sta->owe_group);
4414 owe_buf += 2;
4415 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
4416 owe_buf += wpabuf_len(pub);
4417 wpabuf_free(pub);
4418 sta->external_dh_updated = 1;
4419 }
4420 ie_len = owe_buf - ie;
4421
4422end:
4423 wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
4424 MACSTR, status, (unsigned int) ie_len,
4425 MAC2STR(sta->addr));
4426 hostapd_drv_update_dh_ie(hapd, sta->addr, status,
4427 status == WLAN_STATUS_SUCCESS ? ie : NULL,
4428 ie_len);
4429
4430 return status;
4431}
4432
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004433#endif /* CONFIG_OWE */
4434
4435
Hai Shalom899fcc72020-10-19 14:38:18 -07004436static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
4437 int reassoc)
4438{
4439 if ((sta->flags &
4440 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
4441 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
4442 return false;
4443
4444 if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
4445 ap_check_sa_query_timeout(hapd, sta);
4446
4447 if (!sta->sa_query_timed_out &&
4448 (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
4449 /*
4450 * STA has already been associated with MFP and SA Query timeout
4451 * has not been reached. Reject the association attempt
4452 * temporarily and start SA Query, if one is not pending.
4453 */
4454 if (sta->sa_query_count == 0)
4455 ap_sta_start_sa_query(hapd, sta);
4456
4457 return true;
4458 }
4459
4460 return false;
4461}
4462
4463
Hai Shalomb755a2a2020-04-23 21:49:02 -07004464static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004465 const u8 *ies, size_t ies_len, int reassoc)
4466{
4467 struct ieee802_11_elems elems;
Hai Shalomb755a2a2020-04-23 21:49:02 -07004468 int resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004469 const u8 *wpa_ie;
4470 size_t wpa_ie_len;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004471 const u8 *p2p_dev_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004472
4473 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
4474 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4475 HOSTAPD_LEVEL_INFO, "Station sent an invalid "
4476 "association request");
4477 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4478 }
4479
4480 resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len);
4481 if (resp != WLAN_STATUS_SUCCESS)
4482 return resp;
4483 resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
4484 if (resp != WLAN_STATUS_SUCCESS)
4485 return resp;
Dmitry Shmidt051af732013-10-22 13:52:46 -07004486 resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len);
4487 if (resp != WLAN_STATUS_SUCCESS)
4488 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004489 resp = copy_supp_rates(hapd, sta, &elems);
4490 if (resp != WLAN_STATUS_SUCCESS)
4491 return resp;
Hai Shalom74f70d42019-02-11 14:42:39 -08004492
4493 resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len);
4494 if (resp != WLAN_STATUS_SUCCESS)
4495 return resp;
4496
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07004497 resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004498 if (resp != WLAN_STATUS_SUCCESS)
4499 return resp;
4500 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
4501 !(sta->flags & WLAN_STA_HT)) {
4502 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4503 HOSTAPD_LEVEL_INFO, "Station does not support "
4504 "mandatory HT PHY - reject association");
4505 return WLAN_STATUS_ASSOC_DENIED_NO_HT;
4506 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004507
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004508#ifdef CONFIG_IEEE80211AC
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004509 if (hapd->iconf->ieee80211ac) {
4510 resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities);
4511 if (resp != WLAN_STATUS_SUCCESS)
4512 return resp;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08004513
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004514 resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
4515 if (resp != WLAN_STATUS_SUCCESS)
4516 return resp;
4517 }
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08004518
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004519 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
4520 !(sta->flags & WLAN_STA_VHT)) {
4521 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4522 HOSTAPD_LEVEL_INFO, "Station does not support "
4523 "mandatory VHT PHY - reject association");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004524 return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004525 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004526
4527 if (hapd->conf->vendor_vht && !elems.vht_capabilities) {
4528 resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht,
4529 elems.vendor_vht_len);
4530 if (resp != WLAN_STATUS_SUCCESS)
4531 return resp;
4532 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004533#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07004534#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08004535 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07004536 resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
4537 elems.he_capabilities,
4538 elems.he_capabilities_len);
4539 if (resp != WLAN_STATUS_SUCCESS)
4540 return resp;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004541 if (is_6ghz_op_class(hapd->iconf->op_class)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004542 if (!(sta->flags & WLAN_STA_HE)) {
4543 hostapd_logger(hapd, sta->addr,
4544 HOSTAPD_MODULE_IEEE80211,
4545 HOSTAPD_LEVEL_INFO,
4546 "Station does not support mandatory HE PHY - reject association");
4547 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
4548 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004549 resp = copy_sta_he_6ghz_capab(hapd, sta,
4550 elems.he_6ghz_band_cap);
4551 if (resp != WLAN_STATUS_SUCCESS)
4552 return resp;
4553 }
Hai Shalom81f62d82019-07-22 12:10:00 -07004554 }
4555#endif /* CONFIG_IEEE80211AX */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004556
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004557#ifdef CONFIG_P2P
4558 if (elems.p2p) {
4559 wpabuf_free(sta->p2p_ie);
4560 sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
4561 P2P_IE_VENDOR_TYPE);
4562 if (sta->p2p_ie)
4563 p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
4564 } else {
4565 wpabuf_free(sta->p2p_ie);
4566 sta->p2p_ie = NULL;
4567 }
4568#endif /* CONFIG_P2P */
4569
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004570 if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
4571 wpa_ie = elems.rsn_ie;
4572 wpa_ie_len = elems.rsn_ie_len;
4573 } else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
4574 elems.wpa_ie) {
4575 wpa_ie = elems.wpa_ie;
4576 wpa_ie_len = elems.wpa_ie_len;
4577 } else {
4578 wpa_ie = NULL;
4579 wpa_ie_len = 0;
4580 }
4581
4582#ifdef CONFIG_WPS
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004583 sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004584 if (hapd->conf->wps_state && elems.wps_ie) {
4585 wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
4586 "Request - assume WPS is used");
Hai Shalom899fcc72020-10-19 14:38:18 -07004587 if (check_sa_query(hapd, sta, reassoc))
4588 return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004589 sta->flags |= WLAN_STA_WPS;
4590 wpabuf_free(sta->wps_ie);
4591 sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
4592 WPS_IE_VENDOR_TYPE);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004593 if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
4594 wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
4595 sta->flags |= WLAN_STA_WPS2;
4596 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004597 wpa_ie = NULL;
4598 wpa_ie_len = 0;
4599 if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
4600 wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
4601 "(Re)Association Request - reject");
4602 return WLAN_STATUS_INVALID_IE;
4603 }
4604 } else if (hapd->conf->wps_state && wpa_ie == NULL) {
4605 wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
4606 "(Re)Association Request - possible WPS use");
4607 sta->flags |= WLAN_STA_MAYBE_WPS;
4608 } else
4609#endif /* CONFIG_WPS */
4610 if (hapd->conf->wpa && wpa_ie == NULL) {
4611 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4612 HOSTAPD_LEVEL_INFO,
4613 "No WPA/RSN IE in association request");
4614 return WLAN_STATUS_INVALID_IE;
4615 }
4616
4617 if (hapd->conf->wpa && wpa_ie) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004618 enum wpa_validate_result res;
4619
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004620 wpa_ie -= 2;
4621 wpa_ie_len += 2;
4622 if (sta->wpa_sm == NULL)
4623 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004624 sta->addr,
4625 p2p_dev_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004626 if (sta->wpa_sm == NULL) {
4627 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
4628 "state machine");
4629 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4630 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004631 wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004632 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07004633 hapd->iface->freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004634 wpa_ie, wpa_ie_len,
Hai Shalomc3565922019-10-28 11:58:20 -07004635 elems.rsnxe ? elems.rsnxe - 2 : NULL,
4636 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004637 elems.mdie, elems.mdie_len,
4638 elems.owe_dh, elems.owe_dh_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004639 resp = wpa_res_to_status_code(res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004640 if (resp != WLAN_STATUS_SUCCESS)
4641 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004642
Hai Shalom899fcc72020-10-19 14:38:18 -07004643 if (check_sa_query(hapd, sta, reassoc))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004644 return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004645
4646 if (wpa_auth_uses_mfp(sta->wpa_sm))
4647 sta->flags |= WLAN_STA_MFP;
4648 else
4649 sta->flags &= ~WLAN_STA_MFP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004650
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004651#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004652 if (sta->auth_alg == WLAN_AUTH_FT) {
4653 if (!reassoc) {
4654 wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
4655 "to use association (not "
4656 "re-association) with FT auth_alg",
4657 MAC2STR(sta->addr));
4658 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4659 }
4660
4661 resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
4662 ies_len);
4663 if (resp != WLAN_STATUS_SUCCESS)
4664 return resp;
4665 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004666#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004667
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004668#ifdef CONFIG_SAE
Roshan Pius3a1667e2018-07-03 15:17:14 -07004669 if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
4670 sta->sae->state == SAE_ACCEPTED)
4671 wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
4672
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004673 if (wpa_auth_uses_sae(sta->wpa_sm) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004674 sta->auth_alg == WLAN_AUTH_OPEN) {
4675 struct rsn_pmksa_cache_entry *sa;
4676 sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
4677 if (!sa || sa->akmp != WPA_KEY_MGMT_SAE) {
4678 wpa_printf(MSG_DEBUG,
4679 "SAE: No PMKSA cache entry found for "
4680 MACSTR, MAC2STR(sta->addr));
4681 return WLAN_STATUS_INVALID_PMKID;
4682 }
4683 wpa_printf(MSG_DEBUG, "SAE: " MACSTR
4684 " using PMKSA caching", MAC2STR(sta->addr));
4685 } else if (wpa_auth_uses_sae(sta->wpa_sm) &&
4686 sta->auth_alg != WLAN_AUTH_SAE &&
4687 !(sta->auth_alg == WLAN_AUTH_FT &&
4688 wpa_auth_uses_ft_sae(sta->wpa_sm))) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004689 wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
4690 "SAE AKM after non-SAE auth_alg %u",
4691 MAC2STR(sta->addr), sta->auth_alg);
4692 return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
4693 }
Hai Shalomc3565922019-10-28 11:58:20 -07004694
4695 if (hapd->conf->sae_pwe == 2 &&
4696 sta->auth_alg == WLAN_AUTH_SAE &&
Hai Shalom899fcc72020-10-19 14:38:18 -07004697 sta->sae && !sta->sae->h2e &&
Hai Shaloma20dcd72022-02-04 13:43:00 -08004698 ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
4699 WLAN_RSNX_CAPAB_SAE_H2E)) {
Hai Shalomc3565922019-10-28 11:58:20 -07004700 wpa_printf(MSG_INFO, "SAE: " MACSTR
4701 " indicates support for SAE H2E, but did not use it",
4702 MAC2STR(sta->addr));
4703 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4704 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004705#endif /* CONFIG_SAE */
4706
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004707#ifdef CONFIG_OWE
4708 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
4709 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
4710 elems.owe_dh) {
4711 resp = owe_process_assoc_req(hapd, sta, elems.owe_dh,
4712 elems.owe_dh_len);
4713 if (resp != WLAN_STATUS_SUCCESS)
4714 return resp;
4715 }
4716#endif /* CONFIG_OWE */
4717
Hai Shalom021b0b52019-04-10 11:17:58 -07004718#ifdef CONFIG_DPP2
4719 dpp_pfs_free(sta->dpp_pfs);
4720 sta->dpp_pfs = NULL;
4721
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004722 if (DPP_VERSION > 1 &&
4723 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07004724 hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
4725 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
4726 elems.owe_dh) {
4727 sta->dpp_pfs = dpp_pfs_init(
4728 wpabuf_head(hapd->conf->dpp_netaccesskey),
4729 wpabuf_len(hapd->conf->dpp_netaccesskey));
4730 if (!sta->dpp_pfs) {
4731 wpa_printf(MSG_DEBUG,
4732 "DPP: Could not initialize PFS");
4733 /* Try to continue without PFS */
4734 goto pfs_fail;
4735 }
4736
4737 if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
4738 elems.owe_dh_len) < 0) {
4739 dpp_pfs_free(sta->dpp_pfs);
4740 sta->dpp_pfs = NULL;
4741 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4742 }
4743 }
4744
4745 wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
4746 sta->dpp_pfs->secret : NULL);
4747 pfs_fail:
4748#endif /* CONFIG_DPP2 */
4749
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004750 if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004751 wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
4752 hostapd_logger(hapd, sta->addr,
4753 HOSTAPD_MODULE_IEEE80211,
4754 HOSTAPD_LEVEL_INFO,
4755 "Station tried to use TKIP with HT "
4756 "association");
4757 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
4758 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004759#ifdef CONFIG_HS20
4760 } else if (hapd->conf->osen) {
4761 if (elems.osen == NULL) {
4762 hostapd_logger(
4763 hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4764 HOSTAPD_LEVEL_INFO,
4765 "No HS 2.0 OSEN element in association request");
4766 return WLAN_STATUS_INVALID_IE;
4767 }
4768
4769 wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
4770 if (sta->wpa_sm == NULL)
4771 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
4772 sta->addr, NULL);
4773 if (sta->wpa_sm == NULL) {
4774 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
4775 "state machine");
4776 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4777 }
4778 if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
4779 elems.osen - 2, elems.osen_len + 2) < 0)
4780 return WLAN_STATUS_INVALID_IE;
4781#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004782 } else
4783 wpa_auth_sta_no_wpa(sta->wpa_sm);
4784
4785#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004786 p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
4787#endif /* CONFIG_P2P */
4788
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004789#ifdef CONFIG_HS20
4790 wpabuf_free(sta->hs20_ie);
4791 if (elems.hs20 && elems.hs20_len > 4) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004792 int release;
4793
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004794 sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
4795 elems.hs20_len - 4);
Hai Shalom74f70d42019-02-11 14:42:39 -08004796 release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
Hai Shalomc3565922019-10-28 11:58:20 -07004797 if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
4798 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004799 wpa_printf(MSG_DEBUG,
4800 "HS 2.0: PMF not negotiated by release %d station "
4801 MACSTR, release, MAC2STR(sta->addr));
4802 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
4803 }
4804 } else {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004805 sta->hs20_ie = NULL;
Hai Shalom74f70d42019-02-11 14:42:39 -08004806 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07004807
4808 wpabuf_free(sta->roaming_consortium);
4809 if (elems.roaming_cons_sel)
4810 sta->roaming_consortium = wpabuf_alloc_copy(
4811 elems.roaming_cons_sel + 4,
4812 elems.roaming_cons_sel_len - 4);
4813 else
4814 sta->roaming_consortium = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004815#endif /* CONFIG_HS20 */
4816
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004817#ifdef CONFIG_FST
4818 wpabuf_free(sta->mb_ies);
4819 if (hapd->iface->fst)
4820 sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
4821 else
4822 sta->mb_ies = NULL;
4823#endif /* CONFIG_FST */
4824
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004825#ifdef CONFIG_MBO
4826 mbo_ap_check_sta_assoc(hapd, sta, &elems);
4827
4828 if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
4829 elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
4830 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
4831 wpa_printf(MSG_INFO,
4832 "MBO: Reject WPA2 association without PMF");
4833 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4834 }
4835#endif /* CONFIG_MBO */
4836
Hai Shalom74f70d42019-02-11 14:42:39 -08004837#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
4838 if (wpa_auth_uses_ocv(sta->wpa_sm) &&
4839 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4840 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4841 sta->auth_alg == WLAN_AUTH_FILS_PK)) {
4842 struct wpa_channel_info ci;
4843 int tx_chanwidth;
4844 int tx_seg1_idx;
Hai Shalom899fcc72020-10-19 14:38:18 -07004845 enum oci_verify_result res;
Hai Shalom74f70d42019-02-11 14:42:39 -08004846
4847 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
4848 wpa_printf(MSG_WARNING,
4849 "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
4850 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4851 }
4852
4853 if (get_sta_tx_parameters(sta->wpa_sm,
4854 channel_width_to_int(ci.chanwidth),
4855 ci.seg1_idx, &tx_chanwidth,
4856 &tx_seg1_idx) < 0)
4857 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4858
Hai Shalom899fcc72020-10-19 14:38:18 -07004859 res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
4860 tx_chanwidth, tx_seg1_idx);
4861 if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
4862 res == OCI_NOT_FOUND) {
4863 /* Work around misbehaving STAs */
4864 wpa_printf(MSG_INFO,
4865 "FILS: Disable OCV with a STA that does not send OCI");
4866 wpa_auth_set_ocv(sta->wpa_sm, 0);
4867 } else if (res != OCI_SUCCESS) {
4868 wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
4869 ocv_errorstr);
4870 wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
4871 MACSTR " frame=fils-reassoc-req error=%s",
4872 MAC2STR(sta->addr), ocv_errorstr);
Hai Shalom74f70d42019-02-11 14:42:39 -08004873 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4874 }
4875 }
4876#endif /* CONFIG_FILS && CONFIG_OCV */
4877
Dmitry Shmidt9c175262016-03-03 10:20:07 -08004878 ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
4879 elems.supp_op_classes_len);
4880
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004881 if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
4882 elems.rrm_enabled &&
4883 elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
4884 os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
4885 sizeof(sta->rrm_enabled_capa));
4886
Roshan Pius3a1667e2018-07-03 15:17:14 -07004887 if (elems.power_capab) {
4888 sta->min_tx_power = elems.power_capab[0];
4889 sta->max_tx_power = elems.power_capab[1];
4890 sta->power_capab = 1;
4891 } else {
4892 sta->power_capab = 0;
4893 }
4894
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004895 return WLAN_STATUS_SUCCESS;
4896}
4897
4898
4899static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
4900 u16 reason_code)
4901{
4902 int send_len;
4903 struct ieee80211_mgmt reply;
4904
4905 os_memset(&reply, 0, sizeof(reply));
4906 reply.frame_control =
4907 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
4908 os_memcpy(reply.da, addr, ETH_ALEN);
4909 os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
4910 os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
4911
4912 send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
4913 reply.u.deauth.reason_code = host_to_le16(reason_code);
4914
Hai Shalomfdcde762020-04-02 11:19:20 -07004915 if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004916 wpa_printf(MSG_INFO, "Failed to send deauth: %s",
4917 strerror(errno));
4918}
4919
4920
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004921static int add_associated_sta(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08004922 struct sta_info *sta, int reassoc)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004923{
4924 struct ieee80211_ht_capabilities ht_cap;
4925 struct ieee80211_vht_capabilities vht_cap;
Hai Shalom81f62d82019-07-22 12:10:00 -07004926 struct ieee80211_he_capabilities he_cap;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004927 int set = 1;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004928
4929 /*
4930 * Remove the STA entry to ensure the STA PS state gets cleared and
4931 * configuration gets updated. This is relevant for cases, such as
4932 * FT-over-the-DS, where a station re-associates back to the same AP but
4933 * skips the authentication flow, or if working with a driver that
4934 * does not support full AP client state.
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004935 *
4936 * Skip this if the STA has already completed FT reassociation and the
4937 * TK has been configured since the TX/RX PN must not be reset to 0 for
4938 * the same key.
Hai Shalom74f70d42019-02-11 14:42:39 -08004939 *
4940 * FT-over-the-DS has a special case where the STA entry (and as such,
4941 * the TK) has not yet been configured to the driver depending on which
4942 * driver interface is used. For that case, allow add-STA operation to
4943 * be used (instead of set-STA). This is needed to allow mac80211-based
4944 * drivers to accept the STA parameter configuration. Since this is
4945 * after a new FT-over-DS exchange, a new TK has been derived, so key
4946 * reinstallation is not a concern for this case.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004947 */
Hai Shalom74f70d42019-02-11 14:42:39 -08004948 wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
4949 " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
4950 MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
4951 sta->ft_over_ds, reassoc,
4952 !!(sta->flags & WLAN_STA_AUTHORIZED),
4953 wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
4954 wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
4955
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004956 if (!sta->added_unassoc &&
4957 (!(sta->flags & WLAN_STA_AUTHORIZED) ||
Hai Shalom74f70d42019-02-11 14:42:39 -08004958 (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004959 (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
4960 !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004961 hostapd_drv_sta_remove(hapd, sta->addr);
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004962 wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
4963 set = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08004964
4965 /* Do not allow the FT-over-DS exception to be used more than
4966 * once per authentication exchange to guarantee a new TK is
4967 * used here */
4968 sta->ft_over_ds = 0;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004969 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004970
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004971 if (sta->flags & WLAN_STA_HT)
4972 hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004973#ifdef CONFIG_IEEE80211AC
4974 if (sta->flags & WLAN_STA_VHT)
4975 hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
4976#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07004977#ifdef CONFIG_IEEE80211AX
4978 if (sta->flags & WLAN_STA_HE) {
4979 hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
4980 sta->he_capab_len);
4981 }
4982#endif /* CONFIG_IEEE80211AX */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004983
4984 /*
4985 * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
4986 * will be set when the ACK frame for the (Re)Association Response frame
4987 * is processed (TX status driver event).
4988 */
4989 if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
4990 sta->supported_rates, sta->supported_rates_len,
4991 sta->listen_interval,
4992 sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
4993 sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
Hai Shalom81f62d82019-07-22 12:10:00 -07004994 sta->flags & WLAN_STA_HE ? &he_cap : NULL,
4995 sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004996 sta->he_6ghz_capab,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004997 sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004998 sta->vht_opmode, sta->p2p_ie ? 1 : 0,
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02004999 set)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005000 hostapd_logger(hapd, sta->addr,
5001 HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
5002 "Could not %s STA to kernel driver",
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02005003 set ? "set" : "add");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005004
5005 if (sta->added_unassoc) {
5006 hostapd_drv_sta_remove(hapd, sta->addr);
5007 sta->added_unassoc = 0;
5008 }
5009
5010 return -1;
5011 }
5012
5013 sta->added_unassoc = 0;
5014
5015 return 0;
5016}
5017
5018
5019static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt29333592017-01-09 12:27:11 -08005020 const u8 *addr, u16 status_code, int reassoc,
Hai Shalomfdcde762020-04-02 11:19:20 -07005021 const u8 *ies, size_t ies_len, int rssi,
5022 int omit_rsnxe)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005023{
5024 int send_len;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005025 u8 *buf;
5026 size_t buflen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005027 struct ieee80211_mgmt *reply;
5028 u8 *p;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005029 u16 res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005030
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005031 buflen = sizeof(struct ieee80211_mgmt) + 1024;
5032#ifdef CONFIG_FILS
5033 if (sta && sta->fils_hlp_resp)
5034 buflen += wpabuf_len(sta->fils_hlp_resp);
Hai Shalom81f62d82019-07-22 12:10:00 -07005035 if (sta)
5036 buflen += 150;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005037#endif /* CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005038#ifdef CONFIG_OWE
5039 if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
5040 buflen += 150;
5041#endif /* CONFIG_OWE */
Hai Shalom021b0b52019-04-10 11:17:58 -07005042#ifdef CONFIG_DPP2
5043 if (sta && sta->dpp_pfs)
5044 buflen += 5 + sta->dpp_pfs->curve->prime_len;
5045#endif /* CONFIG_DPP2 */
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005046 buf = os_zalloc(buflen);
5047 if (!buf) {
5048 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5049 goto done;
5050 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005051 reply = (struct ieee80211_mgmt *) buf;
5052 reply->frame_control =
5053 IEEE80211_FC(WLAN_FC_TYPE_MGMT,
5054 (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
5055 WLAN_FC_STYPE_ASSOC_RESP));
Dmitry Shmidt29333592017-01-09 12:27:11 -08005056 os_memcpy(reply->da, addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005057 os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
5058 os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
5059
5060 send_len = IEEE80211_HDRLEN;
5061 send_len += sizeof(reply->u.assoc_resp);
5062 reply->u.assoc_resp.capab_info =
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07005063 host_to_le16(hostapd_own_capab_info(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005064 reply->u.assoc_resp.status_code = host_to_le16(status_code);
Dmitry Shmidt29333592017-01-09 12:27:11 -08005065
5066 reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
5067 BIT(14) | BIT(15));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005068 /* Supported rates */
5069 p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
5070 /* Extended supported rates */
5071 p = hostapd_eid_ext_supp_rates(hapd, p);
5072
Hai Shalomfdcde762020-04-02 11:19:20 -07005073 /* Radio measurement capabilities */
5074 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
5075
Hai Shalom74f70d42019-02-11 14:42:39 -08005076#ifdef CONFIG_MBO
5077 if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
5078 rssi != 0) {
5079 int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
5080
5081 p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
5082 delta);
5083 }
5084#endif /* CONFIG_MBO */
5085
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005086#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt29333592017-01-09 12:27:11 -08005087 if (sta && status_code == WLAN_STATUS_SUCCESS) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005088 /* IEEE 802.11r: Mobility Domain Information, Fast BSS
5089 * Transition Information, RSN, [RIC Response] */
5090 p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005091 buf + buflen - p,
Hai Shalomfdcde762020-04-02 11:19:20 -07005092 sta->auth_alg, ies, ies_len,
5093 omit_rsnxe);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005094 if (!p) {
5095 wpa_printf(MSG_DEBUG,
5096 "FT: Failed to write AssocResp IEs");
5097 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5098 goto done;
5099 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005100 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005101#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom81f62d82019-07-22 12:10:00 -07005102#ifdef CONFIG_FILS
5103 if (sta && status_code == WLAN_STATUS_SUCCESS &&
5104 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5105 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5106 sta->auth_alg == WLAN_AUTH_FILS_PK))
5107 p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
5108 buf + buflen - p,
5109 ies, ies_len);
5110#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005111
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005112#ifdef CONFIG_OWE
Hai Shalom74f70d42019-02-11 14:42:39 -08005113 if (sta && status_code == WLAN_STATUS_SUCCESS &&
5114 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005115 p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
5116 buf + buflen - p,
5117 ies, ies_len);
5118#endif /* CONFIG_OWE */
5119
Dmitry Shmidt29333592017-01-09 12:27:11 -08005120 if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005121 p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005122
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005123 p = hostapd_eid_ht_capabilities(hapd, p);
5124 p = hostapd_eid_ht_operation(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005125
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005126#ifdef CONFIG_IEEE80211AC
Hai Shalomc3565922019-10-28 11:58:20 -07005127 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
5128 !is_6ghz_op_class(hapd->iconf->op_class)) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07005129 u32 nsts = 0, sta_nsts;
5130
Dmitry Shmidt29333592017-01-09 12:27:11 -08005131 if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07005132 struct ieee80211_vht_capabilities *capa;
5133
5134 nsts = (hapd->iface->conf->vht_capab >>
5135 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
5136 capa = sta->vht_capabilities;
5137 sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
5138 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
5139
5140 if (nsts < sta_nsts)
5141 nsts = 0;
5142 else
5143 nsts = sta_nsts;
5144 }
5145 p = hostapd_eid_vht_capabilities(hapd, p, nsts);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005146 p = hostapd_eid_vht_operation(hapd, p);
5147 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005148#endif /* CONFIG_IEEE80211AC */
5149
Hai Shalom81f62d82019-07-22 12:10:00 -07005150#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08005151 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07005152 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
5153 p = hostapd_eid_he_operation(hapd, p);
5154 p = hostapd_eid_spatial_reuse(hapd, p);
5155 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005156 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07005157 }
5158#endif /* CONFIG_IEEE80211AX */
5159
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005160 p = hostapd_eid_ext_capab(hapd, p);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005161 p = hostapd_eid_bss_max_idle_period(hapd, p);
Dmitry Shmidt29333592017-01-09 12:27:11 -08005162 if (sta && sta->qos_map_enabled)
Dmitry Shmidt051af732013-10-22 13:52:46 -07005163 p = hostapd_eid_qos_map_set(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005164
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005165#ifdef CONFIG_FST
5166 if (hapd->iface->fst_ies) {
5167 os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
5168 wpabuf_len(hapd->iface->fst_ies));
5169 p += wpabuf_len(hapd->iface->fst_ies);
5170 }
5171#endif /* CONFIG_FST */
5172
Hai Shalomfdcde762020-04-02 11:19:20 -07005173#ifdef CONFIG_TESTING_OPTIONS
5174 if (hapd->conf->rsnxe_override_ft &&
5175 buf + buflen - p >=
5176 (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
5177 sta && sta->auth_alg == WLAN_AUTH_FT) {
5178 wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
5179 os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
5180 wpabuf_len(hapd->conf->rsnxe_override_ft));
5181 p += wpabuf_len(hapd->conf->rsnxe_override_ft);
5182 goto rsnxe_done;
5183 }
5184#endif /* CONFIG_TESTING_OPTIONS */
5185 if (!omit_rsnxe)
5186 p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
5187#ifdef CONFIG_TESTING_OPTIONS
5188rsnxe_done:
5189#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomc3565922019-10-28 11:58:20 -07005190
Hai Shalom021b0b52019-04-10 11:17:58 -07005191#ifdef CONFIG_OWE
5192 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
5193 sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
Hai Shalom899fcc72020-10-19 14:38:18 -07005194 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
5195 !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07005196 struct wpabuf *pub;
5197
5198 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
5199 if (!pub) {
5200 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5201 goto done;
5202 }
5203 /* OWE Diffie-Hellman Parameter element */
5204 *p++ = WLAN_EID_EXTENSION; /* Element ID */
5205 *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
5206 *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
5207 WPA_PUT_LE16(p, sta->owe_group);
5208 p += 2;
5209 os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
5210 p += wpabuf_len(pub);
5211 wpabuf_free(pub);
5212 }
5213#endif /* CONFIG_OWE */
5214
5215#ifdef CONFIG_DPP2
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005216 if (DPP_VERSION > 1 && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07005217 sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
5218 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
5219 os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
5220 wpabuf_len(sta->dpp_pfs->ie));
5221 p += wpabuf_len(sta->dpp_pfs->ie);
5222 }
5223#endif /* CONFIG_DPP2 */
5224
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005225#ifdef CONFIG_IEEE80211AC
Dmitry Shmidt29333592017-01-09 12:27:11 -08005226 if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005227 p = hostapd_eid_vendor_vht(hapd, p);
5228#endif /* CONFIG_IEEE80211AC */
5229
Dmitry Shmidt29333592017-01-09 12:27:11 -08005230 if (sta && (sta->flags & WLAN_STA_WMM))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005231 p = hostapd_eid_wmm(hapd, p);
5232
5233#ifdef CONFIG_WPS
Dmitry Shmidt29333592017-01-09 12:27:11 -08005234 if (sta &&
5235 ((sta->flags & WLAN_STA_WPS) ||
5236 ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005237 struct wpabuf *wps = wps_build_assoc_resp_ie();
5238 if (wps) {
5239 os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
5240 p += wpabuf_len(wps);
5241 wpabuf_free(wps);
5242 }
5243 }
5244#endif /* CONFIG_WPS */
5245
Hai Shalom74f70d42019-02-11 14:42:39 -08005246 if (sta && (sta->flags & WLAN_STA_MULTI_AP))
5247 p = hostapd_eid_multi_ap(hapd, p);
5248
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005249#ifdef CONFIG_P2P
Dmitry Shmidt29333592017-01-09 12:27:11 -08005250 if (sta && sta->p2p_ie && hapd->p2p_group) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005251 struct wpabuf *p2p_resp_ie;
5252 enum p2p_status_code status;
5253 switch (status_code) {
5254 case WLAN_STATUS_SUCCESS:
5255 status = P2P_SC_SUCCESS;
5256 break;
5257 case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
5258 status = P2P_SC_FAIL_LIMIT_REACHED;
5259 break;
5260 default:
5261 status = P2P_SC_FAIL_INVALID_PARAMS;
5262 break;
5263 }
5264 p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
5265 if (p2p_resp_ie) {
5266 os_memcpy(p, wpabuf_head(p2p_resp_ie),
5267 wpabuf_len(p2p_resp_ie));
5268 p += wpabuf_len(p2p_resp_ie);
5269 wpabuf_free(p2p_resp_ie);
5270 }
5271 }
5272#endif /* CONFIG_P2P */
5273
5274#ifdef CONFIG_P2P_MANAGER
5275 if (hapd->conf->p2p & P2P_MANAGE)
5276 p = hostapd_eid_p2p_manage(hapd, p);
5277#endif /* CONFIG_P2P_MANAGER */
5278
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005279 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005280
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005281 if (hapd->conf->assocresp_elements &&
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005282 (size_t) (buf + buflen - p) >=
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005283 wpabuf_len(hapd->conf->assocresp_elements)) {
5284 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
5285 wpabuf_len(hapd->conf->assocresp_elements));
5286 p += wpabuf_len(hapd->conf->assocresp_elements);
5287 }
5288
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005289 send_len += p - reply->u.assoc_resp.variable;
5290
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005291#ifdef CONFIG_FILS
Dmitry Shmidt29333592017-01-09 12:27:11 -08005292 if (sta &&
5293 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005294 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5295 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
5296 status_code == WLAN_STATUS_SUCCESS) {
5297 struct ieee802_11_elems elems;
5298
5299 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005300 ParseFailed || !elems.fils_session) {
5301 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5302 goto done;
5303 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005304
5305 /* FILS Session */
5306 *p++ = WLAN_EID_EXTENSION; /* Element ID */
5307 *p++ = 1 + FILS_SESSION_LEN; /* Length */
5308 *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
5309 os_memcpy(p, elems.fils_session, FILS_SESSION_LEN);
5310 send_len += 2 + 1 + FILS_SESSION_LEN;
5311
5312 send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005313 buflen, sta->fils_hlp_resp);
5314 if (send_len < 0) {
5315 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5316 goto done;
5317 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005318 }
5319#endif /* CONFIG_FILS */
5320
Hai Shalomfdcde762020-04-02 11:19:20 -07005321 if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005322 wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
5323 strerror(errno));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005324 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005325 }
5326
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005327done:
5328 os_free(buf);
5329 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005330}
5331
5332
Roshan Pius3a1667e2018-07-03 15:17:14 -07005333#ifdef CONFIG_OWE
5334u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
5335 const u8 *owe_dh, u8 owe_dh_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07005336 u8 *owe_buf, size_t owe_buf_len, u16 *status)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005337{
5338#ifdef CONFIG_TESTING_OPTIONS
5339 if (hapd->conf->own_ie_override) {
5340 wpa_printf(MSG_DEBUG, "OWE: Using IE override");
Hai Shalomfdcde762020-04-02 11:19:20 -07005341 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005342 return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5343 owe_buf_len, NULL, 0);
5344 }
5345#endif /* CONFIG_TESTING_OPTIONS */
5346
5347 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
5348 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
5349 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5350 owe_buf_len, NULL, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -07005351 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005352 return owe_buf;
5353 }
5354
Hai Shalom81f62d82019-07-22 12:10:00 -07005355 if (sta->owe_pmk && sta->external_dh_updated) {
5356 wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
Hai Shalomfdcde762020-04-02 11:19:20 -07005357 *status = WLAN_STATUS_SUCCESS;
Hai Shalom81f62d82019-07-22 12:10:00 -07005358 return owe_buf;
5359 }
5360
Hai Shalomfdcde762020-04-02 11:19:20 -07005361 *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
5362 if (*status != WLAN_STATUS_SUCCESS)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005363 return NULL;
5364
5365 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5366 owe_buf_len, NULL, 0);
5367
5368 if (sta->owe_ecdh && owe_buf) {
5369 struct wpabuf *pub;
5370
5371 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
5372 if (!pub) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005373 *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005374 return owe_buf;
5375 }
5376
5377 /* OWE Diffie-Hellman Parameter element */
5378 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
5379 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
5380 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
5381 */
5382 WPA_PUT_LE16(owe_buf, sta->owe_group);
5383 owe_buf += 2;
5384 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
5385 owe_buf += wpabuf_len(pub);
5386 wpabuf_free(pub);
5387 }
5388
5389 return owe_buf;
5390}
5391#endif /* CONFIG_OWE */
5392
5393
Paul Stewart092955c2017-02-06 09:13:09 -08005394#ifdef CONFIG_FILS
5395
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005396void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
Paul Stewart092955c2017-02-06 09:13:09 -08005397{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005398 u16 reply_res;
Paul Stewart092955c2017-02-06 09:13:09 -08005399
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005400 wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
5401 MAC2STR(sta->addr));
5402 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5403 if (!sta->fils_pending_assoc_req)
Paul Stewart092955c2017-02-06 09:13:09 -08005404 return;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005405 reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
5406 sta->fils_pending_assoc_is_reassoc,
5407 sta->fils_pending_assoc_req,
Hai Shalomfdcde762020-04-02 11:19:20 -07005408 sta->fils_pending_assoc_req_len, 0, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005409 os_free(sta->fils_pending_assoc_req);
5410 sta->fils_pending_assoc_req = NULL;
5411 sta->fils_pending_assoc_req_len = 0;
5412 wpabuf_free(sta->fils_hlp_resp);
5413 sta->fils_hlp_resp = NULL;
5414 wpabuf_free(sta->hlp_dhcp_discover);
5415 sta->hlp_dhcp_discover = NULL;
Paul Stewart092955c2017-02-06 09:13:09 -08005416
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005417 /*
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005418 * Remove the station in case transmission of a success response fails.
5419 * At this point the station was already added associated to the driver.
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005420 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005421 if (reply_res != WLAN_STATUS_SUCCESS)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005422 hostapd_drv_sta_remove(hapd, sta->addr);
Paul Stewart092955c2017-02-06 09:13:09 -08005423}
5424
5425
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005426void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
Paul Stewart092955c2017-02-06 09:13:09 -08005427{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005428 struct hostapd_data *hapd = eloop_ctx;
5429 struct sta_info *sta = eloop_data;
Paul Stewart092955c2017-02-06 09:13:09 -08005430
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005431 wpa_printf(MSG_DEBUG,
5432 "FILS: HLP response timeout - continue with association response for "
5433 MACSTR, MAC2STR(sta->addr));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005434 if (sta->fils_drv_assoc_finish)
5435 hostapd_notify_assoc_fils_finish(hapd, sta);
5436 else
5437 fils_hlp_finish_assoc(hapd, sta);
Paul Stewart092955c2017-02-06 09:13:09 -08005438}
5439
5440#endif /* CONFIG_FILS */
5441
5442
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005443static void handle_assoc(struct hostapd_data *hapd,
5444 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom74f70d42019-02-11 14:42:39 -08005445 int reassoc, int rssi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005446{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005447 u16 capab_info, listen_interval, seq_ctrl, fc;
Hai Shalomb755a2a2020-04-23 21:49:02 -07005448 int resp = WLAN_STATUS_SUCCESS;
Hai Shalom899fcc72020-10-19 14:38:18 -07005449 u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005450 const u8 *pos;
5451 int left, i;
5452 struct sta_info *sta;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005453 u8 *tmp = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005454#ifdef CONFIG_FILS
5455 int delay_assoc = 0;
5456#endif /* CONFIG_FILS */
Hai Shalomfdcde762020-04-02 11:19:20 -07005457 int omit_rsnxe = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005458
5459 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
5460 sizeof(mgmt->u.assoc_req))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005461 wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
5462 reassoc, (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005463 return;
5464 }
5465
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005466#ifdef CONFIG_TESTING_OPTIONS
5467 if (reassoc) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005468 if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005469 drand48() < hapd->iconf->ignore_reassoc_probability) {
5470 wpa_printf(MSG_INFO,
5471 "TESTING: ignoring reassoc request from "
5472 MACSTR, MAC2STR(mgmt->sa));
5473 return;
5474 }
5475 } else {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005476 if (hapd->iconf->ignore_assoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005477 drand48() < hapd->iconf->ignore_assoc_probability) {
5478 wpa_printf(MSG_INFO,
5479 "TESTING: ignoring assoc request from "
5480 MACSTR, MAC2STR(mgmt->sa));
5481 return;
5482 }
5483 }
5484#endif /* CONFIG_TESTING_OPTIONS */
5485
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005486 fc = le_to_host16(mgmt->frame_control);
5487 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
5488
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005489 if (reassoc) {
5490 capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
5491 listen_interval = le_to_host16(
5492 mgmt->u.reassoc_req.listen_interval);
5493 wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
5494 " capab_info=0x%02x listen_interval=%d current_ap="
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005495 MACSTR " seq_ctrl=0x%x%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005496 MAC2STR(mgmt->sa), capab_info, listen_interval,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005497 MAC2STR(mgmt->u.reassoc_req.current_ap),
5498 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005499 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
5500 pos = mgmt->u.reassoc_req.variable;
5501 } else {
5502 capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
5503 listen_interval = le_to_host16(
5504 mgmt->u.assoc_req.listen_interval);
5505 wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005506 " capab_info=0x%02x listen_interval=%d "
5507 "seq_ctrl=0x%x%s",
5508 MAC2STR(mgmt->sa), capab_info, listen_interval,
5509 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005510 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
5511 pos = mgmt->u.assoc_req.variable;
5512 }
5513
5514 sta = ap_get_sta(hapd, mgmt->sa);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005515#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005516 if (sta && sta->auth_alg == WLAN_AUTH_FT &&
5517 (sta->flags & WLAN_STA_AUTH) == 0) {
5518 wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
5519 "prior to authentication since it is using "
5520 "over-the-DS FT", MAC2STR(mgmt->sa));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005521
5522 /*
5523 * Mark station as authenticated, to avoid adding station
5524 * entry in the driver as associated and not authenticated
5525 */
5526 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005527 } else
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005528#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005529 if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
Dmitry Shmidt29333592017-01-09 12:27:11 -08005530 if (hapd->iface->current_mode &&
5531 hapd->iface->current_mode->mode ==
5532 HOSTAPD_MODE_IEEE80211AD) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005533 int acl_res;
Hai Shalomfdcde762020-04-02 11:19:20 -07005534 struct radius_sta info;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005535
Hai Shalomfdcde762020-04-02 11:19:20 -07005536 acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
5537 (const u8 *) mgmt,
5538 len, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005539 if (acl_res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005540 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5541 "Ignore Association Request frame from "
5542 MACSTR " due to ACL reject",
5543 MAC2STR(mgmt->sa));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005544 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5545 goto fail;
5546 }
5547 if (acl_res == HOSTAPD_ACL_PENDING)
5548 return;
5549
Dmitry Shmidt29333592017-01-09 12:27:11 -08005550 /* DMG/IEEE 802.11ad does not use authentication.
5551 * Allocate sta entry upon association. */
5552 sta = ap_sta_add(hapd, mgmt->sa);
5553 if (!sta) {
5554 hostapd_logger(hapd, mgmt->sa,
5555 HOSTAPD_MODULE_IEEE80211,
5556 HOSTAPD_LEVEL_INFO,
5557 "Failed to add STA");
5558 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5559 goto fail;
5560 }
5561
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005562 acl_res = ieee802_11_set_radius_info(
Hai Shalomfdcde762020-04-02 11:19:20 -07005563 hapd, sta, acl_res, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005564 if (acl_res) {
5565 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5566 goto fail;
5567 }
5568
Dmitry Shmidt29333592017-01-09 12:27:11 -08005569 hostapd_logger(hapd, sta->addr,
5570 HOSTAPD_MODULE_IEEE80211,
5571 HOSTAPD_LEVEL_DEBUG,
5572 "Skip authentication for DMG/IEEE 802.11ad");
5573 sta->flags |= WLAN_STA_AUTH;
5574 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
5575 sta->auth_alg = WLAN_AUTH_OPEN;
5576 } else {
5577 hostapd_logger(hapd, mgmt->sa,
5578 HOSTAPD_MODULE_IEEE80211,
5579 HOSTAPD_LEVEL_INFO,
5580 "Station tried to associate before authentication (aid=%d flags=0x%x)",
5581 sta ? sta->aid : -1,
5582 sta ? sta->flags : 0);
5583 send_deauth(hapd, mgmt->sa,
5584 WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
5585 return;
5586 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005587 }
5588
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005589 if ((fc & WLAN_FC_RETRY) &&
5590 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
5591 sta->last_seq_ctrl == seq_ctrl &&
Paul Stewart092955c2017-02-06 09:13:09 -08005592 sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5593 WLAN_FC_STYPE_ASSOC_REQ)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005594 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5595 HOSTAPD_LEVEL_DEBUG,
5596 "Drop repeated association frame seq_ctrl=0x%x",
5597 seq_ctrl);
5598 return;
5599 }
5600 sta->last_seq_ctrl = seq_ctrl;
5601 sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5602 WLAN_FC_STYPE_ASSOC_REQ;
5603
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005604 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005605 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005606 goto fail;
5607 }
5608
5609 if (listen_interval > hapd->conf->max_listen_interval) {
5610 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5611 HOSTAPD_LEVEL_DEBUG,
5612 "Too large Listen Interval (%d)",
5613 listen_interval);
5614 resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
5615 goto fail;
5616 }
5617
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005618#ifdef CONFIG_MBO
5619 if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
5620 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5621 goto fail;
5622 }
Hai Shalom74f70d42019-02-11 14:42:39 -08005623
5624 if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
5625 rssi < hapd->iconf->rssi_reject_assoc_rssi &&
5626 (sta->auth_rssi == 0 ||
5627 sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
5628 resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
5629 goto fail;
5630 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005631#endif /* CONFIG_MBO */
5632
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005633 /*
5634 * sta->capability is used in check_assoc_ies() for RRM enabled
5635 * capability element.
5636 */
5637 sta->capability = capab_info;
5638
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005639#ifdef CONFIG_FILS
5640 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5641 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5642 sta->auth_alg == WLAN_AUTH_FILS_PK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005643 int res;
5644
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005645 /* The end of the payload is encrypted. Need to decrypt it
5646 * before parsing. */
5647
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005648 tmp = os_memdup(pos, left);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005649 if (!tmp) {
5650 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5651 goto fail;
5652 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005653
Roshan Pius3a1667e2018-07-03 15:17:14 -07005654 res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
5655 len, tmp, left);
5656 if (res < 0) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005657 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5658 goto fail;
5659 }
5660 pos = tmp;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005661 left = res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005662 }
5663#endif /* CONFIG_FILS */
5664
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005665 /* followed by SSID and Supported rates; and HT capabilities if 802.11n
5666 * is used */
5667 resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
5668 if (resp != WLAN_STATUS_SUCCESS)
5669 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07005670 omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005671
5672 if (hostapd_get_aid(hapd, sta) < 0) {
5673 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5674 HOSTAPD_LEVEL_INFO, "No room for more AIDs");
5675 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5676 goto fail;
5677 }
5678
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005679 sta->listen_interval = listen_interval;
5680
Roshan Pius3a1667e2018-07-03 15:17:14 -07005681 if (hapd->iface->current_mode &&
5682 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005683 sta->flags |= WLAN_STA_NONERP;
5684 for (i = 0; i < sta->supported_rates_len; i++) {
5685 if ((sta->supported_rates[i] & 0x7f) > 22) {
5686 sta->flags &= ~WLAN_STA_NONERP;
5687 break;
5688 }
5689 }
5690 if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
5691 sta->nonerp_set = 1;
5692 hapd->iface->num_sta_non_erp++;
5693 if (hapd->iface->num_sta_non_erp == 1)
5694 ieee802_11_set_beacons(hapd->iface);
5695 }
5696
5697 if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
5698 !sta->no_short_slot_time_set) {
5699 sta->no_short_slot_time_set = 1;
5700 hapd->iface->num_sta_no_short_slot_time++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005701 if (hapd->iface->current_mode &&
5702 hapd->iface->current_mode->mode ==
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005703 HOSTAPD_MODE_IEEE80211G &&
5704 hapd->iface->num_sta_no_short_slot_time == 1)
5705 ieee802_11_set_beacons(hapd->iface);
5706 }
5707
5708 if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
5709 sta->flags |= WLAN_STA_SHORT_PREAMBLE;
5710 else
5711 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
5712
5713 if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
5714 !sta->no_short_preamble_set) {
5715 sta->no_short_preamble_set = 1;
5716 hapd->iface->num_sta_no_short_preamble++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005717 if (hapd->iface->current_mode &&
5718 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005719 && hapd->iface->num_sta_no_short_preamble == 1)
5720 ieee802_11_set_beacons(hapd->iface);
5721 }
5722
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005723 update_ht_state(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005724
5725 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5726 HOSTAPD_LEVEL_DEBUG,
5727 "association OK (aid %d)", sta->aid);
5728 /* Station will be marked associated, after it acknowledges AssocResp
5729 */
5730 sta->flags |= WLAN_STA_ASSOC_REQ_OK;
5731
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005732 if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
5733 wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
5734 "SA Query procedure", reassoc ? "re" : "");
5735 /* TODO: Send a protected Disassociate frame to the STA using
5736 * the old key and Reason Code "Previous Authentication no
5737 * longer valid". Make sure this is only sent protected since
5738 * unprotected frame would be received by the STA that is now
5739 * trying to associate.
5740 */
5741 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005742
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005743 /* Make sure that the previously registered inactivity timer will not
5744 * remove the STA immediately. */
5745 sta->timeout_next = STA_NULLFUNC;
5746
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005747#ifdef CONFIG_TAXONOMY
5748 taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
5749#endif /* CONFIG_TAXONOMY */
5750
Dmitry Shmidt29333592017-01-09 12:27:11 -08005751 sta->pending_wds_enable = 0;
5752
Paul Stewart092955c2017-02-06 09:13:09 -08005753#ifdef CONFIG_FILS
5754 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5755 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005756 sta->auth_alg == WLAN_AUTH_FILS_PK) {
5757 if (fils_process_hlp(hapd, sta, pos, left) > 0)
5758 delay_assoc = 1;
5759 }
Paul Stewart092955c2017-02-06 09:13:09 -08005760#endif /* CONFIG_FILS */
5761
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005762 fail:
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005763
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005764 /*
5765 * In case of a successful response, add the station to the driver.
5766 * Otherwise, the kernel may ignore Data frames before we process the
5767 * ACK frame (TX status). In case of a failure, this station will be
5768 * removed.
5769 *
5770 * Note that this is not compliant with the IEEE 802.11 standard that
5771 * states that a non-AP station should transition into the
5772 * authenticated/associated state only after the station acknowledges
5773 * the (Re)Association Response frame. However, still do this as:
5774 *
5775 * 1. In case the station does not acknowledge the (Re)Association
5776 * Response frame, it will be removed.
5777 * 2. Data frames will be dropped in the kernel until the station is
5778 * set into authorized state, and there are no significant known
5779 * issues with processing other non-Data Class 3 frames during this
5780 * window.
5781 */
Hai Shalom74f70d42019-02-11 14:42:39 -08005782 if (resp == WLAN_STATUS_SUCCESS && sta &&
5783 add_associated_sta(hapd, sta, reassoc))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005784 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5785
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005786#ifdef CONFIG_FILS
Hai Shalom74f70d42019-02-11 14:42:39 -08005787 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
5788 eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
5789 sta->fils_pending_assoc_req) {
5790 /* Do not reschedule fils_hlp_timeout in case the station
5791 * retransmits (Re)Association Request frame while waiting for
5792 * the previously started FILS HLP wait, so that the timeout can
5793 * be determined from the first pending attempt. */
5794 wpa_printf(MSG_DEBUG,
5795 "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
5796 MACSTR, MAC2STR(sta->addr));
5797 os_free(tmp);
5798 return;
5799 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005800 if (sta) {
5801 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5802 os_free(sta->fils_pending_assoc_req);
5803 sta->fils_pending_assoc_req = NULL;
5804 sta->fils_pending_assoc_req_len = 0;
5805 wpabuf_free(sta->fils_hlp_resp);
5806 sta->fils_hlp_resp = NULL;
5807 }
5808 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
5809 sta->fils_pending_assoc_req = tmp;
5810 sta->fils_pending_assoc_req_len = left;
5811 sta->fils_pending_assoc_is_reassoc = reassoc;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005812 sta->fils_drv_assoc_finish = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005813 wpa_printf(MSG_DEBUG,
5814 "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
5815 MACSTR, MAC2STR(sta->addr));
5816 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5817 eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
5818 fils_hlp_timeout, hapd, sta);
5819 return;
5820 }
5821#endif /* CONFIG_FILS */
5822
Hai Shalomb755a2a2020-04-23 21:49:02 -07005823 if (resp >= 0)
5824 reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc,
5825 pos, left, rssi, omit_rsnxe);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005826 os_free(tmp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005827
5828 /*
Hai Shalom899fcc72020-10-19 14:38:18 -07005829 * Remove the station in case transmission of a success response fails
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005830 * (the STA was added associated to the driver) or if the station was
5831 * previously added unassociated.
5832 */
Dmitry Shmidt29333592017-01-09 12:27:11 -08005833 if (sta && ((reply_res != WLAN_STATUS_SUCCESS &&
5834 resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005835 hostapd_drv_sta_remove(hapd, sta->addr);
5836 sta->added_unassoc = 0;
5837 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005838}
5839
5840
5841static void handle_disassoc(struct hostapd_data *hapd,
5842 const struct ieee80211_mgmt *mgmt, size_t len)
5843{
5844 struct sta_info *sta;
5845
5846 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005847 wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)",
5848 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005849 return;
5850 }
5851
5852 wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
5853 MAC2STR(mgmt->sa),
5854 le_to_host16(mgmt->u.disassoc.reason_code));
5855
5856 sta = ap_get_sta(hapd, mgmt->sa);
5857 if (sta == NULL) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005858 wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated",
5859 MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005860 return;
5861 }
5862
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005863 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005864 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005865 sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07005866 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005867 wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
5868 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5869 HOSTAPD_LEVEL_INFO, "disassociated");
5870 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5871 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5872 /* Stop Accounting and IEEE 802.1X sessions, but leave the STA
5873 * authenticated. */
5874 accounting_sta_stop(hapd, sta);
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005875 ieee802_1x_free_station(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005876 if (sta->ipaddr)
5877 hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
5878 ap_sta_ip6addr_del(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005879 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005880 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005881
5882 if (sta->timeout_next == STA_NULLFUNC ||
5883 sta->timeout_next == STA_DISASSOC) {
5884 sta->timeout_next = STA_DEAUTH;
5885 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
5886 eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
5887 hapd, sta);
5888 }
5889
5890 mlme_disassociate_indication(
5891 hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt29333592017-01-09 12:27:11 -08005892
5893 /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon
5894 * disassociation. */
5895 if (hapd->iface->current_mode &&
5896 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
5897 sta->flags &= ~WLAN_STA_AUTH;
5898 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5899 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5900 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5901 ap_free_sta(hapd, sta);
5902 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005903}
5904
5905
5906static void handle_deauth(struct hostapd_data *hapd,
5907 const struct ieee80211_mgmt *mgmt, size_t len)
5908{
5909 struct sta_info *sta;
5910
5911 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005912 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short "
5913 "payload (len=%lu)", (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005914 return;
5915 }
5916
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005917 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005918 " reason_code=%d",
5919 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
5920
Hai Shaloma20dcd72022-02-04 13:43:00 -08005921 /* Clear the PTKSA cache entries for PASN */
5922 ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
5923
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005924 sta = ap_get_sta(hapd, mgmt->sa);
5925 if (sta == NULL) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005926 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
5927 "to deauthenticate, but it is not authenticated",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005928 MAC2STR(mgmt->sa));
5929 return;
5930 }
5931
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005932 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005933 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005934 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
5935 WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07005936 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005937 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
5938 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5939 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
5940 mlme_deauthenticate_indication(
5941 hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
5942 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5943 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5944 ap_free_sta(hapd, sta);
5945}
5946
5947
5948static void handle_beacon(struct hostapd_data *hapd,
5949 const struct ieee80211_mgmt *mgmt, size_t len,
5950 struct hostapd_frame_info *fi)
5951{
5952 struct ieee802_11_elems elems;
5953
5954 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005955 wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
5956 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005957 return;
5958 }
5959
5960 (void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
5961 len - (IEEE80211_HDRLEN +
5962 sizeof(mgmt->u.beacon)), &elems,
5963 0);
5964
5965 ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
5966}
5967
5968
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005969static int robust_action_frame(u8 category)
5970{
5971 return category != WLAN_ACTION_PUBLIC &&
5972 category != WLAN_ACTION_HT;
5973}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005974
5975
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005976static int handle_action(struct hostapd_data *hapd,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005977 const struct ieee80211_mgmt *mgmt, size_t len,
5978 unsigned int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005979{
5980 struct sta_info *sta;
Hai Shalom74f70d42019-02-11 14:42:39 -08005981 u8 *action __maybe_unused;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005982
Hai Shalom74f70d42019-02-11 14:42:39 -08005983 if (len < IEEE80211_HDRLEN + 2 + 1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005984 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5985 HOSTAPD_LEVEL_DEBUG,
5986 "handle_action - too short payload (len=%lu)",
5987 (unsigned long) len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005988 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005989 }
5990
Hai Shalom74f70d42019-02-11 14:42:39 -08005991 action = (u8 *) &mgmt->u.action.u;
5992 wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
5993 " da " MACSTR " len %d freq %u",
5994 mgmt->u.action.category, *action,
5995 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
5996
5997 sta = ap_get_sta(hapd, mgmt->sa);
5998
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005999 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
6000 (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
6001 wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
6002 "frame (category=%u) from unassociated STA " MACSTR,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08006003 mgmt->u.action.category, MAC2STR(mgmt->sa));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006004 return 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006005 }
6006
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006007 if (sta && (sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt18463232014-01-24 12:29:41 -08006008 !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
6009 robust_action_frame(mgmt->u.action.category)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006010 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6011 HOSTAPD_LEVEL_DEBUG,
6012 "Dropped unprotected Robust Action frame from "
6013 "an MFP STA");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006014 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006015 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006016
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006017 if (sta) {
6018 u16 fc = le_to_host16(mgmt->frame_control);
6019 u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
6020
6021 if ((fc & WLAN_FC_RETRY) &&
6022 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
6023 sta->last_seq_ctrl == seq_ctrl &&
6024 sta->last_subtype == WLAN_FC_STYPE_ACTION) {
6025 hostapd_logger(hapd, sta->addr,
6026 HOSTAPD_MODULE_IEEE80211,
6027 HOSTAPD_LEVEL_DEBUG,
6028 "Drop repeated action frame seq_ctrl=0x%x",
6029 seq_ctrl);
6030 return 1;
6031 }
6032
6033 sta->last_seq_ctrl = seq_ctrl;
6034 sta->last_subtype = WLAN_FC_STYPE_ACTION;
6035 }
6036
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006037 switch (mgmt->u.action.category) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006038#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006039 case WLAN_ACTION_FT:
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006040 if (!sta ||
6041 wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006042 len - IEEE80211_HDRLEN))
6043 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006044 return 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006045#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006046 case WLAN_ACTION_WMM:
6047 hostapd_wmm_action(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006048 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006049 case WLAN_ACTION_SA_QUERY:
Hai Shalom021b0b52019-04-10 11:17:58 -07006050 ieee802_11_sa_query_action(hapd, mgmt, len);
6051 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006052#ifdef CONFIG_WNM_AP
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006053 case WLAN_ACTION_WNM:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006054 ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
6055 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006056#endif /* CONFIG_WNM_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006057#ifdef CONFIG_FST
6058 case WLAN_ACTION_FST:
6059 if (hapd->iface->fst)
6060 fst_rx_action(hapd->iface->fst, mgmt, len);
6061 else
6062 wpa_printf(MSG_DEBUG,
6063 "FST: Ignore FST Action frame - no FST attached");
6064 return 1;
6065#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006066 case WLAN_ACTION_PUBLIC:
Dmitry Shmidt18463232014-01-24 12:29:41 -08006067 case WLAN_ACTION_PROTECTED_DUAL:
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07006068 if (len >= IEEE80211_HDRLEN + 2 &&
6069 mgmt->u.action.u.public_action.action ==
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006070 WLAN_PA_20_40_BSS_COEX) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006071 hostapd_2040_coex_action(hapd, mgmt, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006072 return 1;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006073 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006074#ifdef CONFIG_DPP
6075 if (len >= IEEE80211_HDRLEN + 6 &&
6076 mgmt->u.action.u.vs_public_action.action ==
6077 WLAN_PA_VENDOR_SPECIFIC &&
6078 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6079 OUI_WFA &&
6080 mgmt->u.action.u.vs_public_action.variable[0] ==
6081 DPP_OUI_TYPE) {
6082 const u8 *pos, *end;
6083
6084 pos = mgmt->u.action.u.vs_public_action.oui;
6085 end = ((const u8 *) mgmt) + len;
6086 hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006087 freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006088 return 1;
6089 }
6090 if (len >= IEEE80211_HDRLEN + 2 &&
6091 (mgmt->u.action.u.public_action.action ==
6092 WLAN_PA_GAS_INITIAL_RESP ||
6093 mgmt->u.action.u.public_action.action ==
6094 WLAN_PA_GAS_COMEBACK_RESP)) {
6095 const u8 *pos, *end;
6096
6097 pos = &mgmt->u.action.u.public_action.action;
6098 end = ((const u8 *) mgmt) + len;
6099 gas_query_ap_rx(hapd->gas, mgmt->sa,
6100 mgmt->u.action.category,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006101 pos, end - pos, freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006102 return 1;
6103 }
6104#endif /* CONFIG_DPP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006105 if (hapd->public_action_cb) {
6106 hapd->public_action_cb(hapd->public_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006107 (u8 *) mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006108 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006109 if (hapd->public_action_cb2) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -08006110 hapd->public_action_cb2(hapd->public_action_cb2_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006111 (u8 *) mgmt, len, freq);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006112 }
6113 if (hapd->public_action_cb || hapd->public_action_cb2)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006114 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006115 break;
6116 case WLAN_ACTION_VENDOR_SPECIFIC:
6117 if (hapd->vendor_action_cb) {
6118 if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006119 (u8 *) mgmt, len, freq) == 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006120 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006121 }
6122 break;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006123 case WLAN_ACTION_RADIO_MEASUREMENT:
6124 hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
6125 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006126 }
6127
6128 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6129 HOSTAPD_LEVEL_DEBUG,
6130 "handle_action - unknown action category %d or invalid "
6131 "frame",
6132 mgmt->u.action.category);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006133 if (!is_multicast_ether_addr(mgmt->da) &&
6134 !(mgmt->u.action.category & 0x80) &&
6135 !is_multicast_ether_addr(mgmt->sa)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006136 struct ieee80211_mgmt *resp;
6137
6138 /*
6139 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
6140 * Return the Action frame to the source without change
6141 * except that MSB of the Category set to 1.
6142 */
6143 wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
6144 "frame back to sender");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006145 resp = os_memdup(mgmt, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006146 if (resp == NULL)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006147 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006148 os_memcpy(resp->da, resp->sa, ETH_ALEN);
6149 os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
6150 os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
6151 resp->u.action.category |= 0x80;
6152
Hai Shalomfdcde762020-04-02 11:19:20 -07006153 if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006154 wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
6155 "Action frame");
6156 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006157 os_free(resp);
6158 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006159
6160 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006161}
6162
6163
6164/**
Hai Shalom60840252021-02-19 19:02:11 -08006165 * notify_mgmt_frame - Notify of Management frames on the control interface
6166 * @hapd: hostapd BSS data structure (the BSS to which the Management frame was
6167 * sent to)
6168 * @buf: Management frame data (starting from the IEEE 802.11 header)
6169 * @len: Length of frame data in octets
6170 *
6171 * Notify the control interface of any received Management frame.
6172 */
6173static void notify_mgmt_frame(struct hostapd_data *hapd, const u8 *buf,
6174 size_t len)
6175{
6176
6177 int hex_len = len * 2 + 1;
6178 char *hex = os_malloc(hex_len);
6179
6180 if (hex) {
6181 wpa_snprintf_hex(hex, hex_len, buf, len);
6182 wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO,
6183 AP_MGMT_FRAME_RECEIVED "buf=%s", hex);
6184 os_free(hex);
6185 }
6186}
6187
6188
6189/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006190 * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
6191 * @hapd: hostapd BSS data structure (the BSS to which the management frame was
6192 * sent to)
6193 * @buf: management frame data (starting from IEEE 802.11 header)
6194 * @len: length of frame data in octets
6195 * @fi: meta data about received frame (signal level, etc.)
6196 *
6197 * Process all incoming IEEE 802.11 management frames. This will be called for
6198 * each frame received from the kernel driver through wlan#ap interface. In
6199 * addition, it can be called to re-inserted pending frames (e.g., when using
6200 * external RADIUS server as an MAC ACL).
6201 */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006202int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
6203 struct hostapd_frame_info *fi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006204{
6205 struct ieee80211_mgmt *mgmt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006206 u16 fc, stype;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006207 int ret = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006208 unsigned int freq;
6209 int ssi_signal = fi ? fi->ssi_signal : 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006210
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006211 if (len < 24)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006212 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006213
Roshan Pius3a1667e2018-07-03 15:17:14 -07006214 if (fi && fi->freq)
6215 freq = fi->freq;
6216 else
6217 freq = hapd->iface->freq;
6218
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006219 mgmt = (struct ieee80211_mgmt *) buf;
6220 fc = le_to_host16(mgmt->frame_control);
6221 stype = WLAN_FC_GET_STYPE(fc);
6222
Hai Shalomc3565922019-10-28 11:58:20 -07006223 if (is_multicast_ether_addr(mgmt->sa) ||
6224 is_zero_ether_addr(mgmt->sa) ||
6225 os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
6226 /* Do not process any frames with unexpected/invalid SA so that
6227 * we do not add any state for unexpected STA addresses or end
6228 * up sending out frames to unexpected destination. */
6229 wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
6230 " in received frame - ignore this frame silently",
6231 MAC2STR(mgmt->sa));
6232 return 0;
6233 }
6234
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006235 if (stype == WLAN_FC_STYPE_BEACON) {
6236 handle_beacon(hapd, mgmt, len, fi);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006237 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006238 }
6239
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07006240 if (!is_broadcast_ether_addr(mgmt->bssid) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006241#ifdef CONFIG_P2P
6242 /* Invitation responses can be sent with the peer MAC as BSSID */
6243 !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
6244 stype == WLAN_FC_STYPE_ACTION) &&
6245#endif /* CONFIG_P2P */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006246#ifdef CONFIG_MESH
6247 !(hapd->conf->mesh & MESH_ENABLED) &&
6248#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006249 os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006250 wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
6251 MAC2STR(mgmt->bssid));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006252 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006253 }
6254
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006255 if (hapd->iface->state != HAPD_IFACE_ENABLED) {
6256 wpa_printf(MSG_DEBUG, "MGMT: Ignore management frame while interface is not enabled (SA=" MACSTR " DA=" MACSTR " subtype=%u)",
6257 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), stype);
6258 return 1;
6259 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006260
6261 if (stype == WLAN_FC_STYPE_PROBE_REQ) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006262 handle_probe_req(hapd, mgmt, len, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006263 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006264 }
6265
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006266 if ((!is_broadcast_ether_addr(mgmt->da) ||
6267 stype != WLAN_FC_STYPE_ACTION) &&
6268 os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006269 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6270 HOSTAPD_LEVEL_DEBUG,
6271 "MGMT: DA=" MACSTR " not our address",
6272 MAC2STR(mgmt->da));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006273 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006274 }
6275
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006276 if (hapd->iconf->track_sta_max_num)
Roshan Pius3a1667e2018-07-03 15:17:14 -07006277 sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006278
Hai Shalom60840252021-02-19 19:02:11 -08006279 if (hapd->conf->notify_mgmt_frames)
6280 notify_mgmt_frame(hapd, buf, len);
6281
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006282 switch (stype) {
6283 case WLAN_FC_STYPE_AUTH:
6284 wpa_printf(MSG_DEBUG, "mgmt::auth");
Hai Shalom021b0b52019-04-10 11:17:58 -07006285 handle_auth(hapd, mgmt, len, ssi_signal, 0);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006286 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006287 break;
6288 case WLAN_FC_STYPE_ASSOC_REQ:
6289 wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006290 handle_assoc(hapd, mgmt, len, 0, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006291 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006292 break;
6293 case WLAN_FC_STYPE_REASSOC_REQ:
6294 wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006295 handle_assoc(hapd, mgmt, len, 1, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006296 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006297 break;
6298 case WLAN_FC_STYPE_DISASSOC:
6299 wpa_printf(MSG_DEBUG, "mgmt::disassoc");
6300 handle_disassoc(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006301 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006302 break;
6303 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006304 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006305 handle_deauth(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006306 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006307 break;
6308 case WLAN_FC_STYPE_ACTION:
6309 wpa_printf(MSG_DEBUG, "mgmt::action");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006310 ret = handle_action(hapd, mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006311 break;
6312 default:
6313 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6314 HOSTAPD_LEVEL_DEBUG,
6315 "unknown mgmt frame subtype %d", stype);
6316 break;
6317 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006318
6319 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006320}
6321
6322
6323static void handle_auth_cb(struct hostapd_data *hapd,
6324 const struct ieee80211_mgmt *mgmt,
6325 size_t len, int ok)
6326{
6327 u16 auth_alg, auth_transaction, status_code;
6328 struct sta_info *sta;
Hai Shalom60840252021-02-19 19:02:11 -08006329 bool success_status;
Hai Shalome5e28bb2019-01-28 14:51:04 -08006330
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006331 sta = ap_get_sta(hapd, mgmt->da);
6332 if (!sta) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006333 wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
6334 " not found",
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006335 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006336 return;
6337 }
6338
Hai Shalom60840252021-02-19 19:02:11 -08006339 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
6340 wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
6341 (unsigned long) len);
6342 auth_alg = 0;
6343 auth_transaction = 0;
6344 status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
6345 goto fail;
6346 }
6347
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006348 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
6349 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
6350 status_code = le_to_host16(mgmt->u.auth.status_code);
6351
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006352 if (!ok) {
6353 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6354 HOSTAPD_LEVEL_NOTICE,
6355 "did not acknowledge authentication response");
6356 goto fail;
6357 }
6358
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006359 if (status_code == WLAN_STATUS_SUCCESS &&
6360 ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
6361 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
6362 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6363 HOSTAPD_LEVEL_INFO, "authenticated");
6364 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006365 if (sta->added_unassoc)
6366 hostapd_set_sta_flags(hapd, sta);
6367 return;
6368 }
6369
6370fail:
Hai Shalom60840252021-02-19 19:02:11 -08006371 success_status = status_code == WLAN_STATUS_SUCCESS;
6372#ifdef CONFIG_SAE
6373 if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1)
6374 success_status = sae_status_success(hapd, status_code);
6375#endif /* CONFIG_SAE */
6376 if (!success_status && sta->added_unassoc) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006377 hostapd_drv_sta_remove(hapd, sta->addr);
6378 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006379 }
6380}
6381
6382
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006383static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
6384 struct sta_info *sta,
6385 char *ifname_wds)
6386{
Hai Shalomfdcde762020-04-02 11:19:20 -07006387#ifdef CONFIG_WEP
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006388 int i;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07006389 struct hostapd_ssid *ssid = &hapd->conf->ssid;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006390
6391 if (hapd->conf->ieee802_1x || hapd->conf->wpa)
6392 return;
6393
6394 for (i = 0; i < 4; i++) {
6395 if (ssid->wep.key[i] &&
6396 hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
Hai Shalomfdcde762020-04-02 11:19:20 -07006397 0, i == ssid->wep.idx, NULL, 0,
6398 ssid->wep.key[i], ssid->wep.len[i],
6399 i == ssid->wep.idx ?
6400 KEY_FLAG_GROUP_RX_TX_DEFAULT :
6401 KEY_FLAG_GROUP_RX_TX)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006402 wpa_printf(MSG_WARNING,
6403 "Could not set WEP keys for WDS interface; %s",
6404 ifname_wds);
6405 break;
6406 }
6407 }
Hai Shalomfdcde762020-04-02 11:19:20 -07006408#endif /* CONFIG_WEP */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006409}
6410
6411
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006412static void handle_assoc_cb(struct hostapd_data *hapd,
6413 const struct ieee80211_mgmt *mgmt,
6414 size_t len, int reassoc, int ok)
6415{
6416 u16 status;
6417 struct sta_info *sta;
6418 int new_assoc = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006419
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006420 sta = ap_get_sta(hapd, mgmt->da);
6421 if (!sta) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006422 wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
6423 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006424 return;
6425 }
6426
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006427 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
6428 sizeof(mgmt->u.assoc_resp))) {
6429 wpa_printf(MSG_INFO,
6430 "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
6431 reassoc, (unsigned long) len);
6432 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006433 return;
6434 }
6435
6436 if (reassoc)
6437 status = le_to_host16(mgmt->u.reassoc_resp.status_code);
6438 else
6439 status = le_to_host16(mgmt->u.assoc_resp.status_code);
6440
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006441 if (!ok) {
6442 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6443 HOSTAPD_LEVEL_DEBUG,
6444 "did not acknowledge association response");
6445 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
6446 /* The STA is added only in case of SUCCESS */
6447 if (status == WLAN_STATUS_SUCCESS)
6448 hostapd_drv_sta_remove(hapd, sta->addr);
6449
6450 return;
6451 }
6452
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006453 if (status != WLAN_STATUS_SUCCESS)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07006454 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006455
6456 /* Stop previous accounting session, if one is started, and allocate
6457 * new session id for the new session. */
6458 accounting_sta_stop(hapd, sta);
6459
6460 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6461 HOSTAPD_LEVEL_INFO,
6462 "associated (aid %d)",
6463 sta->aid);
6464
6465 if (sta->flags & WLAN_STA_ASSOC)
6466 new_assoc = 0;
6467 sta->flags |= WLAN_STA_ASSOC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006468 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006469 if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
6470 !hapd->conf->osen) ||
6471 sta->auth_alg == WLAN_AUTH_FILS_SK ||
6472 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6473 sta->auth_alg == WLAN_AUTH_FILS_PK ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006474 sta->auth_alg == WLAN_AUTH_FT) {
6475 /*
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006476 * Open, static WEP, FT protocol, or FILS; no separate
6477 * authorization step.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006478 */
6479 ap_sta_set_authorized(hapd, sta, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006480 }
6481
6482 if (reassoc)
6483 mlme_reassociate_indication(hapd, sta);
6484 else
6485 mlme_associate_indication(hapd, sta);
6486
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006487 sta->sa_query_timed_out = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006488
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006489 if (sta->eapol_sm == NULL) {
6490 /*
6491 * This STA does not use RADIUS server for EAP authentication,
6492 * so bind it to the selected VLAN interface now, since the
6493 * interface selection is not going to change anymore.
6494 */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006495 if (ap_sta_bind_vlan(hapd, sta) < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07006496 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006497 } else if (sta->vlan_id) {
6498 /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006499 if (ap_sta_bind_vlan(hapd, sta) < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07006500 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006501 }
6502
6503 hostapd_set_sta_flags(hapd, sta);
6504
Dmitry Shmidt29333592017-01-09 12:27:11 -08006505 if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) {
6506 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA "
6507 MACSTR " based on pending request",
6508 MAC2STR(sta->addr));
6509 sta->pending_wds_enable = 0;
6510 sta->flags |= WLAN_STA_WDS;
6511 }
6512
Hai Shalom74f70d42019-02-11 14:42:39 -08006513 if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) {
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08006514 int ret;
6515 char ifname_wds[IFNAMSIZ + 1];
6516
6517 wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA "
6518 MACSTR " (aid %u)",
6519 MAC2STR(sta->addr), sta->aid);
6520 ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
6521 sta->aid, 1);
6522 if (!ret)
6523 hostapd_set_wds_encryption(hapd, sta, ifname_wds);
6524 }
6525
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006526 if (sta->auth_alg == WLAN_AUTH_FT)
6527 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
6528 else
6529 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
6530 hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006531 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006532
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006533#ifdef CONFIG_FILS
6534 if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
6535 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6536 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
6537 fils_set_tk(sta->wpa_sm) < 0) {
6538 wpa_printf(MSG_DEBUG, "FILS: TK configuration failed");
6539 ap_sta_disconnect(hapd, sta, sta->addr,
6540 WLAN_REASON_UNSPECIFIED);
6541 return;
6542 }
6543#endif /* CONFIG_FILS */
6544
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006545 if (sta->pending_eapol_rx) {
6546 struct os_reltime now, age;
6547
6548 os_get_reltime(&now);
6549 os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
6550 if (age.sec == 0 && age.usec < 200000) {
6551 wpa_printf(MSG_DEBUG,
6552 "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
6553 MAC2STR(sta->addr));
6554 ieee802_1x_receive(
6555 hapd, mgmt->da,
6556 wpabuf_head(sta->pending_eapol_rx->buf),
6557 wpabuf_len(sta->pending_eapol_rx->buf));
6558 }
6559 wpabuf_free(sta->pending_eapol_rx->buf);
6560 os_free(sta->pending_eapol_rx);
6561 sta->pending_eapol_rx = NULL;
6562 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006563}
6564
6565
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006566static void handle_deauth_cb(struct hostapd_data *hapd,
6567 const struct ieee80211_mgmt *mgmt,
6568 size_t len, int ok)
6569{
6570 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006571 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006572 return;
6573 sta = ap_get_sta(hapd, mgmt->da);
6574 if (!sta) {
6575 wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
6576 " not found", MAC2STR(mgmt->da));
6577 return;
6578 }
6579 if (ok)
6580 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
6581 MAC2STR(sta->addr));
6582 else
6583 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6584 "deauth", MAC2STR(sta->addr));
6585
6586 ap_sta_deauth_cb(hapd, sta);
6587}
6588
6589
6590static void handle_disassoc_cb(struct hostapd_data *hapd,
6591 const struct ieee80211_mgmt *mgmt,
6592 size_t len, int ok)
6593{
6594 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006595 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006596 return;
6597 sta = ap_get_sta(hapd, mgmt->da);
6598 if (!sta) {
6599 wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
6600 " not found", MAC2STR(mgmt->da));
6601 return;
6602 }
6603 if (ok)
6604 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
6605 MAC2STR(sta->addr));
6606 else
6607 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6608 "disassoc", MAC2STR(sta->addr));
6609
6610 ap_sta_disassoc_cb(hapd, sta);
6611}
6612
6613
Dmitry Shmidt29333592017-01-09 12:27:11 -08006614static void handle_action_cb(struct hostapd_data *hapd,
6615 const struct ieee80211_mgmt *mgmt,
6616 size_t len, int ok)
6617{
6618 struct sta_info *sta;
Paul Stewart092955c2017-02-06 09:13:09 -08006619 const struct rrm_measurement_report_element *report;
Dmitry Shmidt29333592017-01-09 12:27:11 -08006620
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006621#ifdef CONFIG_DPP
6622 if (len >= IEEE80211_HDRLEN + 6 &&
6623 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6624 mgmt->u.action.u.vs_public_action.action ==
6625 WLAN_PA_VENDOR_SPECIFIC &&
6626 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6627 OUI_WFA &&
6628 mgmt->u.action.u.vs_public_action.variable[0] ==
6629 DPP_OUI_TYPE) {
6630 const u8 *pos, *end;
6631
6632 pos = &mgmt->u.action.u.vs_public_action.variable[1];
6633 end = ((const u8 *) mgmt) + len;
6634 hostapd_dpp_tx_status(hapd, mgmt->da, pos, end - pos, ok);
6635 return;
6636 }
6637 if (len >= IEEE80211_HDRLEN + 2 &&
6638 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6639 (mgmt->u.action.u.public_action.action ==
6640 WLAN_PA_GAS_INITIAL_REQ ||
6641 mgmt->u.action.u.public_action.action ==
6642 WLAN_PA_GAS_COMEBACK_REQ)) {
6643 const u8 *pos, *end;
6644
6645 pos = mgmt->u.action.u.public_action.variable;
6646 end = ((const u8 *) mgmt) + len;
6647 gas_query_ap_tx_status(hapd->gas, mgmt->da, pos, end - pos, ok);
6648 return;
6649 }
6650#endif /* CONFIG_DPP */
Hai Shaloma20dcd72022-02-04 13:43:00 -08006651 if (is_multicast_ether_addr(mgmt->da))
6652 return;
Dmitry Shmidt29333592017-01-09 12:27:11 -08006653 sta = ap_get_sta(hapd, mgmt->da);
6654 if (!sta) {
6655 wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR
6656 " not found", MAC2STR(mgmt->da));
6657 return;
6658 }
6659
Paul Stewart092955c2017-02-06 09:13:09 -08006660 if (len < 24 + 5 + sizeof(*report))
Dmitry Shmidt29333592017-01-09 12:27:11 -08006661 return;
Paul Stewart092955c2017-02-06 09:13:09 -08006662 report = (const struct rrm_measurement_report_element *)
6663 &mgmt->u.action.u.rrm.variable[2];
Dmitry Shmidt29333592017-01-09 12:27:11 -08006664 if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT &&
Paul Stewart092955c2017-02-06 09:13:09 -08006665 mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST &&
6666 report->eid == WLAN_EID_MEASURE_REQUEST &&
6667 report->len >= 3 &&
6668 report->type == MEASURE_TYPE_BEACON)
Dmitry Shmidt29333592017-01-09 12:27:11 -08006669 hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok);
6670}
6671
6672
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006673/**
6674 * ieee802_11_mgmt_cb - Process management frame TX status callback
6675 * @hapd: hostapd BSS data structure (the BSS from which the management frame
6676 * was sent from)
6677 * @buf: management frame data (starting from IEEE 802.11 header)
6678 * @len: length of frame data in octets
6679 * @stype: management frame subtype from frame control field
6680 * @ok: Whether the frame was ACK'ed
6681 */
6682void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
6683 u16 stype, int ok)
6684{
6685 const struct ieee80211_mgmt *mgmt;
6686 mgmt = (const struct ieee80211_mgmt *) buf;
6687
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006688#ifdef CONFIG_TESTING_OPTIONS
6689 if (hapd->ext_mgmt_frame_handling) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006690 size_t hex_len = 2 * len + 1;
6691 char *hex = os_malloc(hex_len);
6692
6693 if (hex) {
6694 wpa_snprintf_hex(hex, hex_len, buf, len);
6695 wpa_msg(hapd->msg_ctx, MSG_INFO,
6696 "MGMT-TX-STATUS stype=%u ok=%d buf=%s",
6697 stype, ok, hex);
6698 os_free(hex);
6699 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006700 return;
6701 }
6702#endif /* CONFIG_TESTING_OPTIONS */
6703
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006704 switch (stype) {
6705 case WLAN_FC_STYPE_AUTH:
6706 wpa_printf(MSG_DEBUG, "mgmt::auth cb");
6707 handle_auth_cb(hapd, mgmt, len, ok);
6708 break;
6709 case WLAN_FC_STYPE_ASSOC_RESP:
6710 wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
6711 handle_assoc_cb(hapd, mgmt, len, 0, ok);
6712 break;
6713 case WLAN_FC_STYPE_REASSOC_RESP:
6714 wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
6715 handle_assoc_cb(hapd, mgmt, len, 1, ok);
6716 break;
6717 case WLAN_FC_STYPE_PROBE_RESP:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006718 wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006719 break;
6720 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006721 wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
6722 handle_deauth_cb(hapd, mgmt, len, ok);
6723 break;
6724 case WLAN_FC_STYPE_DISASSOC:
6725 wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
6726 handle_disassoc_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006727 break;
6728 case WLAN_FC_STYPE_ACTION:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006729 wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006730 handle_action_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006731 break;
6732 default:
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006733 wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006734 break;
6735 }
6736}
6737
6738
6739int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
6740{
6741 /* TODO */
6742 return 0;
6743}
6744
6745
6746int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
6747 char *buf, size_t buflen)
6748{
6749 /* TODO */
6750 return 0;
6751}
6752
6753
6754void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
6755 const u8 *buf, size_t len, int ack)
6756{
6757 struct sta_info *sta;
6758 struct hostapd_iface *iface = hapd->iface;
6759
6760 sta = ap_get_sta(hapd, addr);
6761 if (sta == NULL && iface->num_bss > 1) {
6762 size_t j;
6763 for (j = 0; j < iface->num_bss; j++) {
6764 hapd = iface->bss[j];
6765 sta = ap_get_sta(hapd, addr);
6766 if (sta)
6767 break;
6768 }
6769 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006770 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006771 return;
6772 if (sta->flags & WLAN_STA_PENDING_POLL) {
6773 wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
6774 "activity poll", MAC2STR(sta->addr),
6775 ack ? "ACKed" : "did not ACK");
6776 if (ack)
6777 sta->flags &= ~WLAN_STA_PENDING_POLL;
6778 }
6779
6780 ieee802_1x_tx_status(hapd, sta, buf, len, ack);
6781}
6782
6783
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006784void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
6785 const u8 *data, size_t len, int ack)
6786{
6787 struct sta_info *sta;
6788 struct hostapd_iface *iface = hapd->iface;
6789
6790 sta = ap_get_sta(hapd, dst);
6791 if (sta == NULL && iface->num_bss > 1) {
6792 size_t j;
6793 for (j = 0; j < iface->num_bss; j++) {
6794 hapd = iface->bss[j];
6795 sta = ap_get_sta(hapd, dst);
6796 if (sta)
6797 break;
6798 }
6799 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006800 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
6801 wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA "
6802 MACSTR " that is not currently associated",
6803 MAC2STR(dst));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006804 return;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006805 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006806
6807 ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
6808}
6809
6810
6811void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
6812{
6813 struct sta_info *sta;
6814 struct hostapd_iface *iface = hapd->iface;
6815
6816 sta = ap_get_sta(hapd, addr);
6817 if (sta == NULL && iface->num_bss > 1) {
6818 size_t j;
6819 for (j = 0; j < iface->num_bss; j++) {
6820 hapd = iface->bss[j];
6821 sta = ap_get_sta(hapd, addr);
6822 if (sta)
6823 break;
6824 }
6825 }
6826 if (sta == NULL)
6827 return;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006828 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
6829 MAC2STR(sta->addr));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006830 if (!(sta->flags & WLAN_STA_PENDING_POLL))
6831 return;
6832
6833 wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
6834 "activity poll", MAC2STR(sta->addr));
6835 sta->flags &= ~WLAN_STA_PENDING_POLL;
6836}
6837
6838
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006839void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
6840 int wds)
6841{
6842 struct sta_info *sta;
6843
6844 sta = ap_get_sta(hapd, src);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006845 if (sta &&
6846 ((sta->flags & WLAN_STA_ASSOC) ||
6847 ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006848 if (!hapd->conf->wds_sta)
6849 return;
6850
Dmitry Shmidt29333592017-01-09 12:27:11 -08006851 if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) ==
6852 WLAN_STA_ASSOC_REQ_OK) {
6853 wpa_printf(MSG_DEBUG,
6854 "Postpone 4-address WDS mode enabling for STA "
6855 MACSTR " since TX status for AssocResp is not yet known",
6856 MAC2STR(sta->addr));
6857 sta->pending_wds_enable = 1;
6858 return;
6859 }
6860
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006861 if (wds && !(sta->flags & WLAN_STA_WDS)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006862 int ret;
6863 char ifname_wds[IFNAMSIZ + 1];
6864
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006865 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
6866 "STA " MACSTR " (aid %u)",
6867 MAC2STR(sta->addr), sta->aid);
6868 sta->flags |= WLAN_STA_WDS;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006869 ret = hostapd_set_wds_sta(hapd, ifname_wds,
6870 sta->addr, sta->aid, 1);
6871 if (!ret)
6872 hostapd_set_wds_encryption(hapd, sta,
6873 ifname_wds);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006874 }
6875 return;
6876 }
6877
6878 wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
6879 MACSTR, MAC2STR(src));
Hai Shalomc3565922019-10-28 11:58:20 -07006880 if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
6881 os_memcmp(src, hapd->own_addr, ETH_ALEN) == 0) {
6882 /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
6883 * silently. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006884 return;
6885 }
6886
6887 if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) {
6888 wpa_printf(MSG_DEBUG, "Association Response to the STA has "
6889 "already been sent, but no TX status yet known - "
6890 "ignore Class 3 frame issue with " MACSTR,
6891 MAC2STR(src));
6892 return;
6893 }
6894
6895 if (sta && (sta->flags & WLAN_STA_AUTH))
6896 hostapd_drv_sta_disassoc(
6897 hapd, src,
6898 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
6899 else
6900 hostapd_drv_sta_deauth(
6901 hapd, src,
6902 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
6903}
6904
6905
Hai Shalom60840252021-02-19 19:02:11 -08006906u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
6907{
6908 struct hostapd_iface *iface = hapd->iface;
6909 struct hostapd_config *iconf = iface->conf;
6910 struct hostapd_hw_modes *mode = iface->current_mode;
6911 struct hostapd_channel_data *chan;
6912 int dfs, i;
6913 u8 channel, tx_pwr_count, local_pwr_constraint;
6914 int max_tx_power;
6915 u8 tx_pwr;
6916
6917 if (!mode)
6918 return eid;
6919
6920 if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
6921 return eid;
6922
6923 for (i = 0; i < mode->num_channels; i++) {
6924 if (mode->channels[i].freq == iface->freq)
6925 break;
6926 }
6927 if (i == mode->num_channels)
6928 return eid;
6929
6930 switch (hostapd_get_oper_chwidth(iconf)) {
6931 case CHANWIDTH_USE_HT:
6932 if (iconf->secondary_channel == 0) {
6933 /* Max Transmit Power count = 0 (20 MHz) */
6934 tx_pwr_count = 0;
6935 } else {
6936 /* Max Transmit Power count = 1 (20, 40 MHz) */
6937 tx_pwr_count = 1;
6938 }
6939 break;
6940 case CHANWIDTH_80MHZ:
6941 /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
6942 tx_pwr_count = 2;
6943 break;
6944 case CHANWIDTH_80P80MHZ:
6945 case CHANWIDTH_160MHZ:
6946 /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
6947 tx_pwr_count = 3;
6948 break;
6949 default:
6950 return eid;
6951 }
6952
6953 /*
6954 * Below local_pwr_constraint logic is referred from
6955 * hostapd_eid_pwr_constraint.
6956 *
6957 * Check if DFS is required by regulatory.
6958 */
6959 dfs = hostapd_is_dfs_required(hapd->iface);
6960 if (dfs < 0)
6961 dfs = 0;
6962
6963 /*
6964 * In order to meet regulations when TPC is not implemented using
6965 * a transmit power that is below the legal maximum (including any
6966 * mitigation factor) should help. In this case, indicate 3 dB below
6967 * maximum allowed transmit power.
6968 */
6969 if (hapd->iconf->local_pwr_constraint == -1)
6970 local_pwr_constraint = (dfs == 0) ? 0 : 3;
6971 else
6972 local_pwr_constraint = hapd->iconf->local_pwr_constraint;
6973
6974 /*
6975 * A STA that is not an AP shall use a transmit power less than or
6976 * equal to the local maximum transmit power level for the channel.
6977 * The local maximum transmit power can be calculated from the formula:
6978 * local max TX pwr = max TX pwr - local pwr constraint
6979 * Where max TX pwr is maximum transmit power level specified for
6980 * channel in Country element and local pwr constraint is specified
6981 * for channel in this Power Constraint element.
6982 */
6983 chan = &mode->channels[i];
6984 max_tx_power = chan->max_tx_power - local_pwr_constraint;
6985
6986 /*
6987 * Local Maximum Transmit power is encoded as two's complement
6988 * with a 0.5 dB step.
6989 */
6990 max_tx_power *= 2; /* in 0.5 dB steps */
6991 if (max_tx_power > 127) {
6992 /* 63.5 has special meaning of 63.5 dBm or higher */
6993 max_tx_power = 127;
6994 }
6995 if (max_tx_power < -128)
6996 max_tx_power = -128;
6997 if (max_tx_power < 0)
6998 tx_pwr = 0x80 + max_tx_power + 128;
6999 else
7000 tx_pwr = max_tx_power;
7001
7002 *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE;
7003 *eid++ = 2 + tx_pwr_count;
7004
7005 /*
7006 * Max Transmit Power count and
7007 * Max Transmit Power units = 0 (EIRP)
7008 */
7009 *eid++ = tx_pwr_count;
7010
7011 for (i = 0; i <= tx_pwr_count; i++)
7012 *eid++ = tx_pwr;
7013
7014 return eid;
7015}
7016
7017
Hai Shalom899fcc72020-10-19 14:38:18 -07007018u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
7019{
7020 u8 bw, chan1, chan2 = 0;
7021 int freq1;
7022
7023 if (!hapd->cs_freq_params.channel ||
7024 (!hapd->cs_freq_params.vht_enabled &&
7025 !hapd->cs_freq_params.he_enabled))
7026 return eid;
7027
7028 /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
7029 switch (hapd->cs_freq_params.bandwidth) {
7030 case 40:
7031 bw = 0;
7032 break;
7033 case 80:
7034 /* check if it's 80+80 */
7035 if (!hapd->cs_freq_params.center_freq2)
7036 bw = 1;
7037 else
7038 bw = 3;
7039 break;
7040 case 160:
7041 bw = 2;
7042 break;
7043 default:
7044 /* not valid VHT bandwidth or not in CSA */
7045 return eid;
7046 }
7047
7048 freq1 = hapd->cs_freq_params.center_freq1 ?
7049 hapd->cs_freq_params.center_freq1 :
7050 hapd->cs_freq_params.freq;
7051 if (ieee80211_freq_to_chan(freq1, &chan1) !=
7052 HOSTAPD_MODE_IEEE80211A)
7053 return eid;
7054
7055 if (hapd->cs_freq_params.center_freq2 &&
7056 ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
7057 &chan2) != HOSTAPD_MODE_IEEE80211A)
7058 return eid;
7059
7060 *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
7061 *eid++ = 5; /* Length of Channel Switch Wrapper */
7062 *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
7063 *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
7064 *eid++ = bw; /* New Channel Width */
7065 *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
7066 *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
7067
7068 return eid;
7069}
7070
Hai Shaloma20dcd72022-02-04 13:43:00 -08007071
7072static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd,
7073 size_t *current_len)
7074{
7075 struct hostapd_neighbor_entry *nr;
7076 size_t total_len = 0, len = *current_len;
7077
7078 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7079 list) {
7080 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7081 continue;
7082
7083 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7084 continue;
7085
7086 /* Start a new element */
7087 if (!len ||
7088 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7089 len = RNR_HEADER_LEN;
7090 total_len += RNR_HEADER_LEN;
7091 }
7092
7093 len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7094 total_len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7095 }
7096
7097 *current_len = len;
7098 return total_len;
7099}
7100
7101
7102static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
7103 struct hostapd_data *reporting_hapd,
7104 size_t *current_len)
7105{
7106 size_t total_len = 0, len = *current_len;
7107 int tbtt_count = 0;
7108 size_t i, start = 0;
7109
7110 while (start < hapd->iface->num_bss) {
7111 if (!len ||
7112 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7113 len = RNR_HEADER_LEN;
7114 total_len += RNR_HEADER_LEN;
7115 }
7116
7117 len += RNR_TBTT_HEADER_LEN;
7118 total_len += RNR_TBTT_HEADER_LEN;
7119
7120 for (i = start; i < hapd->iface->num_bss; i++) {
7121 struct hostapd_data *bss = hapd->iface->bss[i];
7122
7123 if (!bss || !bss->conf || !bss->started)
7124 continue;
7125
7126 if (bss == reporting_hapd ||
7127 bss->conf->ignore_broadcast_ssid)
7128 continue;
7129
7130 if (len + RNR_TBTT_INFO_LEN > 255 ||
7131 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7132 break;
7133
7134 len += RNR_TBTT_INFO_LEN;
7135 total_len += RNR_TBTT_INFO_LEN;
7136 tbtt_count++;
7137 }
7138 start = i;
7139 }
7140
7141 if (!tbtt_count)
7142 total_len = 0;
7143 else
7144 *current_len = len;
7145
7146 return total_len;
7147}
7148
7149
7150enum colocation_mode {
7151 NO_COLOCATED_6GHZ,
7152 STANDALONE_6GHZ,
7153 COLOCATED_6GHZ,
7154 COLOCATED_LOWER_BAND,
7155};
7156
7157static enum colocation_mode get_colocation_mode(struct hostapd_data *hapd)
7158{
7159 u8 i;
7160 bool is_6ghz = is_6ghz_op_class(hapd->iconf->op_class);
7161
7162 if (!hapd->iface || !hapd->iface->interfaces)
7163 return NO_COLOCATED_6GHZ;
7164
7165 if (is_6ghz && hapd->iface->interfaces->count == 1)
7166 return STANDALONE_6GHZ;
7167
7168 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7169 struct hostapd_iface *iface;
7170 bool is_colocated_6ghz;
7171
7172 iface = hapd->iface->interfaces->iface[i];
7173 if (iface == hapd->iface || !iface || !iface->conf)
7174 continue;
7175
7176 is_colocated_6ghz = is_6ghz_op_class(iface->conf->op_class);
7177 if (!is_6ghz && is_colocated_6ghz)
7178 return COLOCATED_LOWER_BAND;
7179 if (is_6ghz && !is_colocated_6ghz)
7180 return COLOCATED_6GHZ;
7181 }
7182
7183 if (is_6ghz)
7184 return STANDALONE_6GHZ;
7185
7186 return NO_COLOCATED_6GHZ;
7187}
7188
7189
7190static size_t hostapd_eid_rnr_colocation_len(struct hostapd_data *hapd,
7191 size_t *current_len)
7192{
7193 struct hostapd_iface *iface;
7194 size_t len = 0;
7195 size_t i;
7196
7197 if (!hapd->iface || !hapd->iface->interfaces)
7198 return 0;
7199
7200 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7201 iface = hapd->iface->interfaces->iface[i];
7202
7203 if (iface == hapd->iface ||
7204 !is_6ghz_op_class(iface->conf->op_class))
7205 continue;
7206
7207 len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
7208 current_len);
7209 }
7210
7211 return len;
7212}
7213
7214
7215size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type)
7216{
7217 size_t total_len = 0, current_len = 0;
7218 enum colocation_mode mode = get_colocation_mode(hapd);
7219
7220 switch (type) {
7221 case WLAN_FC_STYPE_BEACON:
7222 if (hapd->conf->rnr)
7223 total_len += hostapd_eid_nr_db_len(hapd, &current_len);
7224 /* fallthrough */
7225
7226 case WLAN_FC_STYPE_PROBE_RESP:
7227 if (mode == COLOCATED_LOWER_BAND)
7228 total_len += hostapd_eid_rnr_colocation_len(
7229 hapd, &current_len);
7230
7231 if (hapd->conf->rnr && hapd->iface->num_bss > 1)
7232 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
7233 &current_len);
7234 break;
7235
7236 case WLAN_FC_STYPE_ACTION:
7237 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
7238 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
7239 &current_len);
7240 break;
7241
7242 default:
7243 break;
7244 }
7245
7246 return total_len;
7247}
7248
7249
7250static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid,
7251 size_t *current_len)
7252{
7253 struct hostapd_neighbor_entry *nr;
7254 size_t len = *current_len;
7255 u8 *size_offset = (eid - len) + 1;
7256
7257 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7258 list) {
7259 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7260 continue;
7261
7262 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7263 continue;
7264
7265 /* Start a new element */
7266 if (!len ||
7267 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7268 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7269 size_offset = eid++;
7270 len = RNR_HEADER_LEN;
7271 }
7272
7273 /* TBTT Information Header subfield (2 octets) */
7274 *eid++ = 0;
7275 /* TBTT Information Length */
7276 *eid++ = RNR_TBTT_INFO_LEN;
7277 /* Operating Class */
7278 *eid++ = wpabuf_head_u8(nr->nr)[10];
7279 /* Channel Number */
7280 *eid++ = wpabuf_head_u8(nr->nr)[11];
7281 len += RNR_TBTT_HEADER_LEN;
7282 /* TBTT Information Set */
7283 /* TBTT Information field */
7284 /* Neighbor AP TBTT Offset */
7285 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
7286 /* BSSID */
7287 os_memcpy(eid, nr->bssid, ETH_ALEN);
7288 eid += ETH_ALEN;
7289 /* Short SSID */
7290 os_memcpy(eid, &nr->short_ssid, 4);
7291 eid += 4;
7292 /* BSS parameters */
7293 *eid++ = nr->bss_parameters;
7294 /* 20 MHz PSD */
7295 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1;
7296 len += RNR_TBTT_INFO_LEN;
7297 *size_offset = (eid - size_offset) - 1;
7298 }
7299
7300 *current_len = len;
7301 return eid;
7302}
7303
7304
7305static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
7306 struct hostapd_data *reporting_hapd,
7307 u8 *eid, size_t *current_len)
7308{
7309 struct hostapd_data *bss;
7310 struct hostapd_iface *iface = hapd->iface;
7311 size_t i, start = 0;
7312 size_t len = *current_len;
7313 u8 *tbtt_count_pos, *eid_start = eid, *size_offset = (eid - len) + 1;
7314 u8 tbtt_count = 0, op_class, channel, bss_param;
7315
7316 if (!(iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !iface->freq)
7317 return eid;
7318
7319 if (ieee80211_freq_to_channel_ext(iface->freq,
7320 hapd->iconf->secondary_channel,
7321 hostapd_get_oper_chwidth(hapd->iconf),
7322 &op_class, &channel) ==
7323 NUM_HOSTAPD_MODES)
7324 return eid;
7325
7326 while (start < iface->num_bss) {
7327 if (!len ||
7328 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7329 eid_start = eid;
7330 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7331 size_offset = eid++;
7332 len = RNR_HEADER_LEN;
7333 tbtt_count = 0;
7334 }
7335
7336 tbtt_count_pos = eid++;
7337 *eid++ = RNR_TBTT_INFO_LEN;
7338 *eid++ = op_class;
7339 *eid++ = hapd->iconf->channel;
7340 len += RNR_TBTT_HEADER_LEN;
7341
7342 for (i = start; i < iface->num_bss; i++) {
7343 bss_param = 0;
7344 bss = iface->bss[i];
7345 if (!bss || !bss->conf || !bss->started)
7346 continue;
7347
7348 if (bss == reporting_hapd ||
7349 bss->conf->ignore_broadcast_ssid)
7350 continue;
7351
7352 if (len + RNR_TBTT_INFO_LEN > 255 ||
7353 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7354 break;
7355
7356 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
7357 os_memcpy(eid, bss->conf->bssid, ETH_ALEN);
7358 eid += ETH_ALEN;
7359 os_memcpy(eid, &bss->conf->ssid.short_ssid, 4);
7360 eid += 4;
7361 if (bss->conf->ssid.short_ssid ==
7362 reporting_hapd->conf->ssid.short_ssid)
7363 bss_param |= RNR_BSS_PARAM_SAME_SSID;
7364
7365 if (is_6ghz_op_class(hapd->iconf->op_class) &&
7366 bss->conf->unsol_bcast_probe_resp_interval)
7367 bss_param |=
7368 RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE;
7369
7370 bss_param |= RNR_BSS_PARAM_CO_LOCATED;
7371
7372 *eid++ = bss_param;
7373 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1;
7374 len += RNR_TBTT_INFO_LEN;
7375 tbtt_count += 1;
7376 }
7377
7378 start = i;
7379 *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
7380 *size_offset = (eid - size_offset) - 1;
7381 }
7382
7383 if (tbtt_count == 0)
7384 return eid_start;
7385
7386 *current_len = len;
7387 return eid;
7388}
7389
7390
7391static u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid,
7392 size_t *current_len)
7393{
7394 struct hostapd_iface *iface;
7395 size_t i;
7396
7397 if (!hapd->iface || !hapd->iface->interfaces)
7398 return eid;
7399
7400 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7401 iface = hapd->iface->interfaces->iface[i];
7402
7403 if (iface == hapd->iface ||
7404 !is_6ghz_op_class(iface->conf->op_class))
7405 continue;
7406
7407 eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
7408 current_len);
7409 }
7410
7411 return eid;
7412}
7413
7414
7415u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
7416{
7417 u8 *eid_start = eid;
7418 size_t current_len = 0;
7419 enum colocation_mode mode = get_colocation_mode(hapd);
7420
7421 switch (type) {
7422 case WLAN_FC_STYPE_BEACON:
7423 if (hapd->conf->rnr)
7424 eid = hostapd_eid_nr_db(hapd, eid, &current_len);
7425 /* fallthrough */
7426
7427 case WLAN_FC_STYPE_PROBE_RESP:
7428 if (mode == COLOCATED_LOWER_BAND)
7429 eid = hostapd_eid_rnr_colocation(hapd, eid,
7430 &current_len);
7431
7432 if (hapd->conf->rnr && hapd->iface->num_bss > 1)
7433 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
7434 &current_len);
7435 break;
7436
7437 case WLAN_FC_STYPE_ACTION:
7438 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
7439 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
7440 &current_len);
7441 break;
7442
7443 default:
7444 return eid_start;
7445 }
7446
7447 if (eid == eid_start + 2)
7448 return eid_start;
7449
7450 return eid;
7451}
7452
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007453#endif /* CONFIG_NATIVE_WINDOWS */