blob: a65a2964b1a7ef408fa51c820e9516fba7e2f45b [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / IEEE 802.11 Management
Dmitry Shmidt29333592017-01-09 12:27:11 -08003 * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "utils/includes.h"
10
11#ifndef CONFIG_NATIVE_WINDOWS
12
13#include "utils/common.h"
14#include "utils/eloop.h"
15#include "crypto/crypto.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080016#include "crypto/sha256.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070017#include "crypto/sha384.h"
18#include "crypto/sha512.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080019#include "crypto/random.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070020#include "common/ieee802_11_defs.h"
21#include "common/ieee802_11_common.h"
22#include "common/wpa_ctrl.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080023#include "common/sae.h"
Hai Shalom021b0b52019-04-10 11:17:58 -070024#include "common/dpp.h"
Hai Shalom74f70d42019-02-11 14:42:39 -080025#include "common/ocv.h"
Hai Shalom81f62d82019-07-22 12:10:00 -070026#include "common/wpa_common.h"
Hai Shalom899fcc72020-10-19 14:38:18 -070027#include "common/wpa_ctrl.h"
Hai Shalom60840252021-02-19 19:02:11 -080028#include "common/ptksa_cache.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070029#include "radius/radius.h"
30#include "radius/radius_client.h"
31#include "p2p/p2p.h"
32#include "wps/wps.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080033#include "fst/fst.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070034#include "hostapd.h"
35#include "beacon.h"
36#include "ieee802_11_auth.h"
37#include "sta_info.h"
38#include "ieee802_1x.h"
39#include "wpa_auth.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080040#include "pmksa_cache_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070041#include "wmm.h"
42#include "ap_list.h"
43#include "accounting.h"
44#include "ap_config.h"
45#include "ap_mlme.h"
46#include "p2p_hostapd.h"
47#include "ap_drv_ops.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080048#include "wnm_ap.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080049#include "hw_features.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070050#include "ieee802_11.h"
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080051#include "dfs.h"
Dmitry Shmidt57c2d392016-02-23 13:40:19 -080052#include "mbo_ap.h"
Dmitry Shmidt849734c2016-05-27 09:59:01 -070053#include "rrm.h"
Dmitry Shmidtaca489e2016-09-28 15:44:14 -070054#include "taxonomy.h"
Dmitry Shmidtebd93af2017-02-21 13:40:44 -080055#include "fils_hlp.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070056#include "dpp_hostapd.h"
57#include "gas_query_ap.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070058
59
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070060#ifdef CONFIG_FILS
61static struct wpabuf *
62prepare_auth_resp_fils(struct hostapd_data *hapd,
63 struct sta_info *sta, u16 *resp,
64 struct rsn_pmksa_cache_entry *pmksa,
65 struct wpabuf *erp_resp,
66 const u8 *msk, size_t msk_len,
67 int *is_pub);
68#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -080069
70#ifdef CONFIG_PASN
71
72static int handle_auth_pasn_resp(struct hostapd_data *hapd,
73 struct sta_info *sta,
74 struct rsn_pmksa_cache_entry *pmksa,
75 u16 status);
76#ifdef CONFIG_FILS
77
78static void pasn_fils_auth_resp(struct hostapd_data *hapd,
79 struct sta_info *sta, u16 status,
80 struct wpabuf *erp_resp,
81 const u8 *msk, size_t msk_len);
82
83#endif /* CONFIG_FILS */
84#endif /* CONFIG_PASN */
85
Hai Shalom021b0b52019-04-10 11:17:58 -070086static void handle_auth(struct hostapd_data *hapd,
87 const struct ieee80211_mgmt *mgmt, size_t len,
88 int rssi, int from_queue);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070089
Hai Shalom74f70d42019-02-11 14:42:39 -080090
91u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
92{
93 u8 multi_ap_val = 0;
94
95 if (!hapd->conf->multi_ap)
96 return eid;
97 if (hapd->conf->multi_ap & BACKHAUL_BSS)
98 multi_ap_val |= MULTI_AP_BACKHAUL_BSS;
99 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
100 multi_ap_val |= MULTI_AP_FRONTHAUL_BSS;
101
102 return eid + add_multi_ap_ie(eid, 9, multi_ap_val);
103}
104
105
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700106u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
107{
108 u8 *pos = eid;
109 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700110 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700111
112 if (hapd->iface->current_rates == NULL)
113 return eid;
114
115 *pos++ = WLAN_EID_SUPP_RATES;
116 num = hapd->iface->num_rates;
117 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
118 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800119 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
120 num++;
Hai Shalomfdcde762020-04-02 11:19:20 -0700121 h2e_required = (hapd->conf->sae_pwe == 1 ||
122 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
123 hapd->conf->sae_pwe != 3 &&
124 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
125 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700126 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700127 if (num > 8) {
128 /* rest of the rates are encoded in Extended supported
129 * rates element */
130 num = 8;
131 }
132
133 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700134 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
135 i++) {
136 count++;
137 *pos = hapd->iface->current_rates[i].rate / 5;
138 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
139 *pos |= 0x80;
140 pos++;
141 }
142
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800143 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
144 count++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700145 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800146 }
147
148 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
149 count++;
150 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
151 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700152
Hai Shalomfdcde762020-04-02 11:19:20 -0700153 if (h2e_required && count < 8) {
Hai Shalomc3565922019-10-28 11:58:20 -0700154 count++;
155 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
156 }
157
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700158 return pos;
159}
160
161
162u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
163{
164 u8 *pos = eid;
165 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700166 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700167
168 if (hapd->iface->current_rates == NULL)
169 return eid;
170
171 num = hapd->iface->num_rates;
172 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
173 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800174 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
175 num++;
Hai Shalomfdcde762020-04-02 11:19:20 -0700176 h2e_required = (hapd->conf->sae_pwe == 1 ||
177 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
178 hapd->conf->sae_pwe != 3 &&
179 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
180 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700181 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700182 if (num <= 8)
183 return eid;
184 num -= 8;
185
186 *pos++ = WLAN_EID_EXT_SUPP_RATES;
187 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700188 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
189 i++) {
190 count++;
191 if (count <= 8)
192 continue; /* already in SuppRates IE */
193 *pos = hapd->iface->current_rates[i].rate / 5;
194 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
195 *pos |= 0x80;
196 pos++;
197 }
198
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800199 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
200 count++;
201 if (count > 8)
202 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
203 }
204
205 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
206 count++;
207 if (count > 8)
208 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
209 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700210
Hai Shalomfdcde762020-04-02 11:19:20 -0700211 if (h2e_required) {
Hai Shalomc3565922019-10-28 11:58:20 -0700212 count++;
213 if (count > 8)
214 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
215 }
216
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700217 return pos;
218}
219
220
Hai Shalomfdcde762020-04-02 11:19:20 -0700221u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
222 size_t len)
223{
224 size_t i;
225
226 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
227 if (hapd->conf->radio_measurements[i])
228 break;
229 }
230
231 if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
232 return eid;
233
234 *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
235 *eid++ = RRM_CAPABILITIES_IE_LEN;
236 os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
237
238 return eid + RRM_CAPABILITIES_IE_LEN;
239}
240
241
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700242u16 hostapd_own_capab_info(struct hostapd_data *hapd)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700243{
244 int capab = WLAN_CAPABILITY_ESS;
Hai Shalomfdcde762020-04-02 11:19:20 -0700245 int privacy = 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800246 int dfs;
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700247 int i;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800248
249 /* Check if any of configured channels require DFS */
250 dfs = hostapd_is_dfs_required(hapd->iface);
251 if (dfs < 0) {
252 wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
253 dfs);
254 dfs = 0;
255 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700256
257 if (hapd->iface->num_sta_no_short_preamble == 0 &&
258 hapd->iconf->preamble == SHORT_PREAMBLE)
259 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
260
Hai Shalomfdcde762020-04-02 11:19:20 -0700261#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700262 privacy = hapd->conf->ssid.wep.keys_set;
263
264 if (hapd->conf->ieee802_1x &&
265 (hapd->conf->default_wep_key_len ||
266 hapd->conf->individual_wep_key_len))
267 privacy = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -0700268#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700269
270 if (hapd->conf->wpa)
271 privacy = 1;
272
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800273#ifdef CONFIG_HS20
274 if (hapd->conf->osen)
275 privacy = 1;
276#endif /* CONFIG_HS20 */
277
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700278 if (privacy)
279 capab |= WLAN_CAPABILITY_PRIVACY;
280
281 if (hapd->iface->current_mode &&
282 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
283 hapd->iface->num_sta_no_short_slot_time == 0)
284 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
285
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800286 /*
287 * Currently, Spectrum Management capability bit is set when directly
288 * requested in configuration by spectrum_mgmt_required or when AP is
289 * running on DFS channel.
290 * TODO: Also consider driver support for TPC to set Spectrum Mgmt bit
291 */
292 if (hapd->iface->current_mode &&
293 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
294 (hapd->iconf->spectrum_mgmt_required || dfs))
295 capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
296
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700297 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
298 if (hapd->conf->radio_measurements[i]) {
299 capab |= IEEE80211_CAP_RRM;
300 break;
301 }
302 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800303
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700304 return capab;
305}
306
307
Hai Shalomfdcde762020-04-02 11:19:20 -0700308#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800309#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700310static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
311 u16 auth_transaction, const u8 *challenge,
312 int iswep)
313{
314 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
315 HOSTAPD_LEVEL_DEBUG,
316 "authentication (shared key, transaction %d)",
317 auth_transaction);
318
319 if (auth_transaction == 1) {
320 if (!sta->challenge) {
321 /* Generate a pseudo-random challenge */
322 u8 key[8];
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800323
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700324 sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
325 if (sta->challenge == NULL)
326 return WLAN_STATUS_UNSPECIFIED_FAILURE;
327
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800328 if (os_get_random(key, sizeof(key)) < 0) {
329 os_free(sta->challenge);
330 sta->challenge = NULL;
331 return WLAN_STATUS_UNSPECIFIED_FAILURE;
332 }
333
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700334 rc4_skip(key, sizeof(key), 0,
335 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
336 }
337 return 0;
338 }
339
340 if (auth_transaction != 3)
341 return WLAN_STATUS_UNSPECIFIED_FAILURE;
342
343 /* Transaction 3 */
344 if (!iswep || !sta->challenge || !challenge ||
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700345 os_memcmp_const(sta->challenge, challenge,
346 WLAN_AUTH_CHALLENGE_LEN)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700347 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
348 HOSTAPD_LEVEL_INFO,
349 "shared key authentication - invalid "
350 "challenge-response");
351 return WLAN_STATUS_CHALLENGE_FAIL;
352 }
353
354 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
355 HOSTAPD_LEVEL_DEBUG,
356 "authentication OK (shared key)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700357 sta->flags |= WLAN_STA_AUTH;
358 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700359 os_free(sta->challenge);
360 sta->challenge = NULL;
361
362 return 0;
363}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800364#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700365#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700366
367
Hai Shalomfdcde762020-04-02 11:19:20 -0700368static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800369 const u8 *dst, const u8 *bssid,
370 u16 auth_alg, u16 auth_transaction, u16 resp,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700371 const u8 *ies, size_t ies_len, const char *dbg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700372{
373 struct ieee80211_mgmt *reply;
374 u8 *buf;
375 size_t rlen;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800376 int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700377
378 rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
379 buf = os_zalloc(rlen);
380 if (buf == NULL)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800381 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700382
383 reply = (struct ieee80211_mgmt *) buf;
384 reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
385 WLAN_FC_STYPE_AUTH);
386 os_memcpy(reply->da, dst, ETH_ALEN);
387 os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
388 os_memcpy(reply->bssid, bssid, ETH_ALEN);
389
390 reply->u.auth.auth_alg = host_to_le16(auth_alg);
391 reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
392 reply->u.auth.status_code = host_to_le16(resp);
393
394 if (ies && ies_len)
395 os_memcpy(reply->u.auth.variable, ies, ies_len);
396
397 wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700398 " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700399 MAC2STR(dst), auth_alg, auth_transaction,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700400 resp, (unsigned long) ies_len, dbg);
Hai Shalomfdcde762020-04-02 11:19:20 -0700401#ifdef CONFIG_TESTING_OPTIONS
402#ifdef CONFIG_SAE
403 if (hapd->conf->sae_confirm_immediate == 2 &&
404 auth_alg == WLAN_AUTH_SAE) {
405 if (auth_transaction == 1 && sta &&
406 (resp == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -0700407 resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
408 resp == WLAN_STATUS_SAE_PK)) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700409 wpa_printf(MSG_DEBUG,
410 "TESTING: Postpone SAE Commit transmission until Confirm is ready");
411 os_free(sta->sae_postponed_commit);
412 sta->sae_postponed_commit = buf;
413 sta->sae_postponed_commit_len = rlen;
414 return WLAN_STATUS_SUCCESS;
415 }
416
417 if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
418 wpa_printf(MSG_DEBUG,
419 "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
420 if (hostapd_drv_send_mlme(hapd,
421 sta->sae_postponed_commit,
422 sta->sae_postponed_commit_len,
423 0, NULL, 0, 0) < 0)
424 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
425 os_free(sta->sae_postponed_commit);
426 sta->sae_postponed_commit = NULL;
427 sta->sae_postponed_commit_len = 0;
428 }
429 }
430#endif /* CONFIG_SAE */
431#endif /* CONFIG_TESTING_OPTIONS */
432 if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800433 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
434 else
435 reply_res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700436
437 os_free(buf);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800438
439 return reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700440}
441
442
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800443#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700444static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
445 u16 auth_transaction, u16 status,
446 const u8 *ies, size_t ies_len)
447{
448 struct hostapd_data *hapd = ctx;
449 struct sta_info *sta;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800450 int reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700451
Hai Shalomfdcde762020-04-02 11:19:20 -0700452 reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700453 auth_transaction, status, ies, ies_len,
454 "auth-ft-finish");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700455
456 sta = ap_get_sta(hapd, dst);
457 if (sta == NULL)
458 return;
459
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800460 if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
461 status != WLAN_STATUS_SUCCESS)) {
462 hostapd_drv_sta_remove(hapd, sta->addr);
463 sta->added_unassoc = 0;
464 return;
465 }
466
467 if (status != WLAN_STATUS_SUCCESS)
468 return;
469
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700470 hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
471 HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
472 sta->flags |= WLAN_STA_AUTH;
473 mlme_authenticate_indication(hapd, sta);
474}
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800475#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700476
477
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800478#ifdef CONFIG_SAE
479
Roshan Pius3a1667e2018-07-03 15:17:14 -0700480static void sae_set_state(struct sta_info *sta, enum sae_state state,
481 const char *reason)
482{
483 wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
484 sae_state_txt(sta->sae->state), sae_state_txt(state),
485 MAC2STR(sta->addr), reason);
486 sta->sae->state = state;
487}
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800488
489
Hai Shalom60840252021-02-19 19:02:11 -0800490static const char * sae_get_password(struct hostapd_data *hapd,
491 struct sta_info *sta,
492 const char *rx_id,
493 struct sae_password_entry **pw_entry,
494 struct sae_pt **s_pt,
495 const struct sae_pk **s_pk)
496{
497 const char *password = NULL;
498 struct sae_password_entry *pw;
499 struct sae_pt *pt = NULL;
500 const struct sae_pk *pk = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -0700501 struct hostapd_sta_wpa_psk_short *psk = NULL;
Hai Shalom60840252021-02-19 19:02:11 -0800502
503 for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
504 if (!is_broadcast_ether_addr(pw->peer_addr) &&
505 os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
506 continue;
507 if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
508 continue;
509 if (rx_id && pw->identifier &&
510 os_strcmp(rx_id, pw->identifier) != 0)
511 continue;
512 password = pw->password;
513 pt = pw->pt;
514 if (!(hapd->conf->mesh & MESH_ENABLED))
515 pk = pw->pk;
516 break;
517 }
518 if (!password) {
519 password = hapd->conf->ssid.wpa_passphrase;
520 pt = hapd->conf->ssid.pt;
521 }
522
Sunil Ravia04bd252022-05-02 22:54:18 -0700523 if (!password) {
524 for (psk = sta->psk; psk; psk = psk->next) {
525 if (psk->is_passphrase) {
526 password = psk->passphrase;
527 break;
528 }
529 }
530 }
531
Hai Shalom60840252021-02-19 19:02:11 -0800532 if (pw_entry)
533 *pw_entry = pw;
534 if (s_pt)
535 *s_pt = pt;
536 if (s_pk)
537 *s_pk = pk;
538
539 return password;
540}
541
542
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800543static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
Hai Shalomc3565922019-10-28 11:58:20 -0700544 struct sta_info *sta, int update,
545 int status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800546{
547 struct wpabuf *buf;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700548 const char *password = NULL;
549 struct sae_password_entry *pw;
550 const char *rx_id = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700551 int use_pt = 0;
552 struct sae_pt *pt = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700553 const struct sae_pk *pk = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800554
Hai Shalomc3565922019-10-28 11:58:20 -0700555 if (sta->sae->tmp) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700556 rx_id = sta->sae->tmp->pw_id;
Hai Shalom899fcc72020-10-19 14:38:18 -0700557 use_pt = sta->sae->h2e;
558#ifdef CONFIG_SAE_PK
559 os_memcpy(sta->sae->tmp->own_addr, hapd->own_addr, ETH_ALEN);
560 os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
561#endif /* CONFIG_SAE_PK */
Hai Shalomc3565922019-10-28 11:58:20 -0700562 }
563
Hai Shalomfdcde762020-04-02 11:19:20 -0700564 if (rx_id && hapd->conf->sae_pwe != 3)
565 use_pt = 1;
566 else if (status_code == WLAN_STATUS_SUCCESS)
Hai Shalomc3565922019-10-28 11:58:20 -0700567 use_pt = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700568 else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
569 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomc3565922019-10-28 11:58:20 -0700570 use_pt = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700571
Hai Shalom60840252021-02-19 19:02:11 -0800572 password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk);
Hai Shalomc3565922019-10-28 11:58:20 -0700573 if (!password || (use_pt && !pt)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800574 wpa_printf(MSG_DEBUG, "SAE: No password available");
575 return NULL;
576 }
577
Hai Shalomc3565922019-10-28 11:58:20 -0700578 if (update && use_pt &&
579 sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
Hai Shalom899fcc72020-10-19 14:38:18 -0700580 NULL, pk) < 0)
Hai Shalomc3565922019-10-28 11:58:20 -0700581 return NULL;
582
583 if (update && !use_pt &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800584 sae_prepare_commit(hapd->own_addr, sta->addr,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800585 (u8 *) password, os_strlen(password),
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800586 sta->sae) < 0) {
587 wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
588 return NULL;
589 }
590
Hai Shalom021b0b52019-04-10 11:17:58 -0700591 if (pw && pw->vlan_id) {
592 if (!sta->sae->tmp) {
593 wpa_printf(MSG_INFO,
594 "SAE: No temporary data allocated - cannot store VLAN ID");
595 return NULL;
596 }
597 sta->sae->tmp->vlan_id = pw->vlan_id;
598 }
599
Roshan Pius3a1667e2018-07-03 15:17:14 -0700600 buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
601 (rx_id ? 3 + os_strlen(rx_id) : 0));
Hai Shalomfdcde762020-04-02 11:19:20 -0700602 if (buf &&
603 sae_write_commit(sta->sae, buf, sta->sae->tmp ?
604 sta->sae->tmp->anti_clogging_token : NULL,
605 rx_id) < 0) {
606 wpabuf_free(buf);
607 buf = NULL;
608 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800609
610 return buf;
611}
612
613
614static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
615 struct sta_info *sta)
616{
617 struct wpabuf *buf;
618
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800619 buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800620 if (buf == NULL)
621 return NULL;
622
Hai Shalom899fcc72020-10-19 14:38:18 -0700623#ifdef CONFIG_SAE_PK
624#ifdef CONFIG_TESTING_OPTIONS
625 if (sta->sae->tmp)
626 sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
627#endif /* CONFIG_TESTING_OPTIONS */
628#endif /* CONFIG_SAE_PK */
629
630 if (sae_write_confirm(sta->sae, buf) < 0) {
631 wpabuf_free(buf);
632 return NULL;
633 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800634
635 return buf;
636}
637
638
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800639static int auth_sae_send_commit(struct hostapd_data *hapd,
640 struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700641 const u8 *bssid, int update, int status_code)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800642{
643 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800644 int reply_res;
Hai Shalomc3565922019-10-28 11:58:20 -0700645 u16 status;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800646
Hai Shalomc3565922019-10-28 11:58:20 -0700647 data = auth_build_sae_commit(hapd, sta, update, status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700648 if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
649 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800650 if (data == NULL)
651 return WLAN_STATUS_UNSPECIFIED_FAILURE;
652
Hai Shalom899fcc72020-10-19 14:38:18 -0700653 if (sta->sae->tmp && sta->sae->pk)
654 status = WLAN_STATUS_SAE_PK;
655 else if (sta->sae->tmp && sta->sae->h2e)
656 status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
657 else
658 status = WLAN_STATUS_SUCCESS;
659#ifdef CONFIG_TESTING_OPTIONS
660 if (hapd->conf->sae_commit_status >= 0 &&
661 hapd->conf->sae_commit_status != status) {
662 wpa_printf(MSG_INFO,
663 "TESTING: Override SAE commit status code %u --> %d",
664 status, hapd->conf->sae_commit_status);
665 status = hapd->conf->sae_commit_status;
666 }
667#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomfdcde762020-04-02 11:19:20 -0700668 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
669 WLAN_AUTH_SAE, 1,
Hai Shalomc3565922019-10-28 11:58:20 -0700670 status, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700671 wpabuf_len(data), "sae-send-commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800672
673 wpabuf_free(data);
674
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800675 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800676}
677
678
679static int auth_sae_send_confirm(struct hostapd_data *hapd,
680 struct sta_info *sta,
681 const u8 *bssid)
682{
683 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800684 int reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800685
686 data = auth_build_sae_confirm(hapd, sta);
687 if (data == NULL)
688 return WLAN_STATUS_UNSPECIFIED_FAILURE;
689
Hai Shalomfdcde762020-04-02 11:19:20 -0700690 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
691 WLAN_AUTH_SAE, 2,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800692 WLAN_STATUS_SUCCESS, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700693 wpabuf_len(data), "sae-send-confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800694
695 wpabuf_free(data);
696
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800697 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800698}
699
Hai Shaloma20dcd72022-02-04 13:43:00 -0800700#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800701
Hai Shaloma20dcd72022-02-04 13:43:00 -0800702
703#if defined(CONFIG_SAE) || defined(CONFIG_PASN)
704
705static int use_anti_clogging(struct hostapd_data *hapd)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800706{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800707 struct sta_info *sta;
708 unsigned int open = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800709
Hai Shaloma20dcd72022-02-04 13:43:00 -0800710 if (hapd->conf->anti_clogging_threshold == 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800711 return 1;
712
713 for (sta = hapd->sta_list; sta; sta = sta->next) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800714#ifdef CONFIG_SAE
715 if (sta->sae &&
716 (sta->sae->state == SAE_COMMITTED ||
717 sta->sae->state == SAE_CONFIRMED))
718 open++;
719#endif /* CONFIG_SAE */
720#ifdef CONFIG_PASN
721 if (sta->pasn && sta->pasn->ecdh)
722 open++;
723#endif /* CONFIG_PASN */
724 if (open >= hapd->conf->anti_clogging_threshold)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800725 return 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800726 }
727
Hai Shaloma20dcd72022-02-04 13:43:00 -0800728#ifdef CONFIG_SAE
Hai Shalom021b0b52019-04-10 11:17:58 -0700729 /* In addition to already existing open SAE sessions, check whether
730 * there are enough pending commit messages in the processing queue to
731 * potentially result in too many open sessions. */
732 if (open + dl_list_len(&hapd->sae_commit_queue) >=
Hai Shaloma20dcd72022-02-04 13:43:00 -0800733 hapd->conf->anti_clogging_threshold)
Hai Shalom021b0b52019-04-10 11:17:58 -0700734 return 1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800735#endif /* CONFIG_SAE */
Hai Shalom021b0b52019-04-10 11:17:58 -0700736
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800737 return 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800738}
739
740
Hai Shaloma20dcd72022-02-04 13:43:00 -0800741static int comeback_token_hash(struct hostapd_data *hapd, const u8 *addr,
742 u8 *idx)
Hai Shalom021b0b52019-04-10 11:17:58 -0700743{
744 u8 hash[SHA256_MAC_LEN];
745
Hai Shaloma20dcd72022-02-04 13:43:00 -0800746 if (hmac_sha256(hapd->comeback_key, sizeof(hapd->comeback_key),
Hai Shalomfdcde762020-04-02 11:19:20 -0700747 addr, ETH_ALEN, hash) < 0)
748 return -1;
749 *idx = hash[0];
750 return 0;
Hai Shalom021b0b52019-04-10 11:17:58 -0700751}
752
753
Hai Shaloma20dcd72022-02-04 13:43:00 -0800754static int check_comeback_token(struct hostapd_data *hapd, const u8 *addr,
755 const u8 *token, size_t token_len)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800756{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800757 u8 mac[SHA256_MAC_LEN];
Hai Shalom021b0b52019-04-10 11:17:58 -0700758 const u8 *addrs[2];
759 size_t len[2];
760 u16 token_idx;
761 u8 idx;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800762
Hai Shaloma20dcd72022-02-04 13:43:00 -0800763 if (token_len != SHA256_MAC_LEN ||
764 comeback_token_hash(hapd, addr, &idx) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800765 return -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800766 token_idx = hapd->comeback_pending_idx[idx];
Hai Shalom021b0b52019-04-10 11:17:58 -0700767 if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800768 wpa_printf(MSG_DEBUG,
769 "Comeback: Invalid anti-clogging token from "
Hai Shalom021b0b52019-04-10 11:17:58 -0700770 MACSTR " - token_idx 0x%04x, expected 0x%04x",
771 MAC2STR(addr), WPA_GET_BE16(token), token_idx);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800772 return -1;
Hai Shalom021b0b52019-04-10 11:17:58 -0700773 }
774
775 addrs[0] = addr;
776 len[0] = ETH_ALEN;
777 addrs[1] = token;
778 len[1] = 2;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800779 if (hmac_sha256_vector(hapd->comeback_key, sizeof(hapd->comeback_key),
Hai Shalom021b0b52019-04-10 11:17:58 -0700780 2, addrs, len, mac) < 0 ||
781 os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
782 return -1;
783
Hai Shaloma20dcd72022-02-04 13:43:00 -0800784 hapd->comeback_pending_idx[idx] = 0; /* invalidate used token */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800785
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800786 return 0;
787}
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800788
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800789
790static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
Hai Shalomfdcde762020-04-02 11:19:20 -0700791 int group, const u8 *addr, int h2e)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800792{
793 struct wpabuf *buf;
794 u8 *token;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800795 struct os_reltime now;
Hai Shalom021b0b52019-04-10 11:17:58 -0700796 u8 idx[2];
797 const u8 *addrs[2];
798 size_t len[2];
799 u8 p_idx;
800 u16 token_idx;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800801
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800802 os_get_reltime(&now);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800803 if (!os_reltime_initialized(&hapd->last_comeback_key_update) ||
804 os_reltime_expired(&now, &hapd->last_comeback_key_update, 60) ||
805 hapd->comeback_idx == 0xffff) {
806 if (random_get_bytes(hapd->comeback_key,
807 sizeof(hapd->comeback_key)) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800808 return NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800809 wpa_hexdump(MSG_DEBUG, "Comeback: Updated token key",
810 hapd->comeback_key, sizeof(hapd->comeback_key));
811 hapd->last_comeback_key_update = now;
812 hapd->comeback_idx = 0;
813 os_memset(hapd->comeback_pending_idx, 0,
814 sizeof(hapd->comeback_pending_idx));
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800815 }
816
Hai Shalomfdcde762020-04-02 11:19:20 -0700817 buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800818 if (buf == NULL)
819 return NULL;
820
Hai Shaloma20dcd72022-02-04 13:43:00 -0800821 if (group)
822 wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800823
Hai Shalomfdcde762020-04-02 11:19:20 -0700824 if (h2e) {
825 /* Encapsulate Anti-clogging Token field in a container IE */
826 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
827 wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
828 wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
829 }
830
Hai Shaloma20dcd72022-02-04 13:43:00 -0800831 if (comeback_token_hash(hapd, addr, &p_idx) < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700832 wpabuf_free(buf);
833 return NULL;
834 }
Hai Shaloma20dcd72022-02-04 13:43:00 -0800835
836 token_idx = hapd->comeback_pending_idx[p_idx];
Hai Shalom021b0b52019-04-10 11:17:58 -0700837 if (!token_idx) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800838 hapd->comeback_idx++;
839 token_idx = hapd->comeback_idx;
840 hapd->comeback_pending_idx[p_idx] = token_idx;
Hai Shalom021b0b52019-04-10 11:17:58 -0700841 }
842 WPA_PUT_BE16(idx, token_idx);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800843 token = wpabuf_put(buf, SHA256_MAC_LEN);
Hai Shalom021b0b52019-04-10 11:17:58 -0700844 addrs[0] = addr;
845 len[0] = ETH_ALEN;
846 addrs[1] = idx;
847 len[1] = sizeof(idx);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800848 if (hmac_sha256_vector(hapd->comeback_key, sizeof(hapd->comeback_key),
Hai Shalom021b0b52019-04-10 11:17:58 -0700849 2, addrs, len, token) < 0) {
850 wpabuf_free(buf);
851 return NULL;
852 }
853 WPA_PUT_BE16(token, token_idx);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800854
855 return buf;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800856}
857
Hai Shaloma20dcd72022-02-04 13:43:00 -0800858#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
859
860
861#ifdef CONFIG_SAE
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800862
Roshan Pius3a1667e2018-07-03 15:17:14 -0700863static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800864{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700865 if (sta->sae->sync > hapd->conf->sae_sync) {
866 sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800867 sta->sae->sync = 0;
868 return -1;
869 }
870 return 0;
871}
872
873
874static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
875{
876 struct hostapd_data *hapd = eloop_ctx;
877 struct sta_info *sta = eloop_data;
878 int ret;
879
Roshan Pius3a1667e2018-07-03 15:17:14 -0700880 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800881 return;
882 sta->sae->sync++;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700883 wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700884 " (sync=%d state=%s)",
885 MAC2STR(sta->addr), sta->sae->sync,
886 sae_state_txt(sta->sae->state));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800887
888 switch (sta->sae->state) {
889 case SAE_COMMITTED:
Hai Shalomc3565922019-10-28 11:58:20 -0700890 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800891 eloop_register_timeout(0,
892 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800893 auth_sae_retransmit_timer, hapd, sta);
894 break;
895 case SAE_CONFIRMED:
896 ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800897 eloop_register_timeout(0,
898 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800899 auth_sae_retransmit_timer, hapd, sta);
900 break;
901 default:
902 ret = -1;
903 break;
904 }
905
906 if (ret != WLAN_STATUS_SUCCESS)
907 wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
908}
909
910
911void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
912{
913 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
914}
915
916
917static void sae_set_retransmit_timer(struct hostapd_data *hapd,
918 struct sta_info *sta)
919{
920 if (!(hapd->conf->mesh & MESH_ENABLED))
921 return;
922
923 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800924 eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800925 auth_sae_retransmit_timer, hapd, sta);
926}
927
928
Hai Shalom5f92bc92019-04-18 11:54:11 -0700929static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
930 struct sta_info *sta, u16 status)
931{
932 struct external_auth params;
933
934 os_memset(&params, 0, sizeof(params));
935 params.status = status;
936 params.bssid = sta->addr;
Hai Shalom81f62d82019-07-22 12:10:00 -0700937 if (status == WLAN_STATUS_SUCCESS && sta->sae &&
938 !hapd->conf->disable_pmksa_caching)
Hai Shalom5f92bc92019-04-18 11:54:11 -0700939 params.pmkid = sta->sae->pmkid;
940
941 hostapd_drv_send_external_auth_status(hapd, &params);
942}
943
944
Dmitry Shmidte4663042016-04-04 10:07:49 -0700945void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
946{
Hai Shalom021b0b52019-04-10 11:17:58 -0700947#ifndef CONFIG_NO_VLAN
948 struct vlan_description vlan_desc;
949
950 if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
951 wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
952 " to VLAN ID %d",
953 MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
954
955 os_memset(&vlan_desc, 0, sizeof(vlan_desc));
956 vlan_desc.notempty = 1;
957 vlan_desc.untagged = sta->sae->tmp->vlan_id;
958 if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
959 wpa_printf(MSG_INFO,
960 "Invalid VLAN ID %d in sae_password",
961 sta->sae->tmp->vlan_id);
962 return;
963 }
964
965 if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
966 ap_sta_bind_vlan(hapd, sta) < 0) {
967 wpa_printf(MSG_INFO,
968 "Failed to assign VLAN ID %d from sae_password to "
969 MACSTR, sta->sae->tmp->vlan_id,
970 MAC2STR(sta->addr));
971 return;
972 }
973 }
974#endif /* CONFIG_NO_VLAN */
975
Dmitry Shmidte4663042016-04-04 10:07:49 -0700976 sta->flags |= WLAN_STA_AUTH;
977 sta->auth_alg = WLAN_AUTH_SAE;
978 mlme_authenticate_indication(hapd, sta);
979 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700980 sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
Hai Shalomfdcde762020-04-02 11:19:20 -0700981 crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
982 sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
983 sta->sae->peer_commit_scalar = NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -0700984 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
Sunil Ravi89eba102022-09-13 21:04:37 -0700985 sta->sae->pmk, sta->sae->pmk_len,
986 sta->sae->pmkid, sta->sae->akmp);
Hai Shalom5f92bc92019-04-18 11:54:11 -0700987 sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
Dmitry Shmidte4663042016-04-04 10:07:49 -0700988}
989
990
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800991static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700992 const u8 *bssid, u16 auth_transaction, u16 status_code,
993 int allow_reuse, int *sta_removed)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800994{
995 int ret;
996
Hai Shalom5f92bc92019-04-18 11:54:11 -0700997 *sta_removed = 0;
998
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800999 if (auth_transaction != 1 && auth_transaction != 2)
1000 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1001
Roshan Pius3a1667e2018-07-03 15:17:14 -07001002 wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
1003 MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
1004 auth_transaction);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001005 switch (sta->sae->state) {
1006 case SAE_NOTHING:
1007 if (auth_transaction == 1) {
Hai Shalom899fcc72020-10-19 14:38:18 -07001008 if (sta->sae->tmp) {
1009 sta->sae->h2e =
1010 (status_code ==
1011 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1012 status_code == WLAN_STATUS_SAE_PK);
1013 sta->sae->pk =
1014 status_code == WLAN_STATUS_SAE_PK;
1015 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001016 ret = auth_sae_send_commit(hapd, sta, bssid,
Hai Shalomc3565922019-10-28 11:58:20 -07001017 !allow_reuse, status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001018 if (ret)
1019 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001020 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001021
1022 if (sae_process_commit(sta->sae) < 0)
1023 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1024
1025 /*
Hai Shalomc3565922019-10-28 11:58:20 -07001026 * In mesh case, both Commit and Confirm are sent
1027 * immediately. In infrastructure BSS, by default, only
1028 * a single Authentication frame (Commit) is expected
1029 * from the AP here and the second one (Confirm) will
1030 * be sent once the STA has sent its second
1031 * Authentication frame (Confirm). This behavior can be
1032 * overridden with explicit configuration so that the
1033 * infrastructure BSS case sends both frames together.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001034 */
Hai Shalomc3565922019-10-28 11:58:20 -07001035 if ((hapd->conf->mesh & MESH_ENABLED) ||
1036 hapd->conf->sae_confirm_immediate) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001037 /*
1038 * Send both Commit and Confirm immediately
1039 * based on SAE finite state machine
1040 * Nothing -> Confirm transition.
1041 */
1042 ret = auth_sae_send_confirm(hapd, sta, bssid);
1043 if (ret)
1044 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001045 sae_set_state(sta, SAE_CONFIRMED,
1046 "Sent Confirm (mesh)");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001047 } else {
1048 /*
1049 * For infrastructure BSS, send only the Commit
1050 * message now to get alternating sequence of
1051 * Authentication frames between the AP and STA.
1052 * Confirm will be sent in
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001053 * Committed -> Confirmed/Accepted transition
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001054 * when receiving Confirm from STA.
1055 */
1056 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001057 sta->sae->sync = 0;
1058 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001059 } else {
1060 hostapd_logger(hapd, sta->addr,
1061 HOSTAPD_MODULE_IEEE80211,
1062 HOSTAPD_LEVEL_DEBUG,
1063 "SAE confirm before commit");
1064 }
1065 break;
1066 case SAE_COMMITTED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001067 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001068 if (auth_transaction == 1) {
1069 if (sae_process_commit(sta->sae) < 0)
1070 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1071
1072 ret = auth_sae_send_confirm(hapd, sta, bssid);
1073 if (ret)
1074 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001075 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001076 sta->sae->sync = 0;
1077 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001078 } else if (hapd->conf->mesh & MESH_ENABLED) {
1079 /*
1080 * In mesh case, follow SAE finite state machine and
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001081 * send Commit now, if sync count allows.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001082 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001083 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001084 return WLAN_STATUS_SUCCESS;
1085 sta->sae->sync++;
1086
Hai Shalomc3565922019-10-28 11:58:20 -07001087 ret = auth_sae_send_commit(hapd, sta, bssid, 0,
1088 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001089 if (ret)
1090 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001091
1092 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001093 } else {
1094 /*
1095 * For instructure BSS, send the postponed Confirm from
1096 * Nothing -> Confirmed transition that was reduced to
1097 * Nothing -> Committed above.
1098 */
1099 ret = auth_sae_send_confirm(hapd, sta, bssid);
1100 if (ret)
1101 return ret;
1102
Roshan Pius3a1667e2018-07-03 15:17:14 -07001103 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001104
1105 /*
1106 * Since this was triggered on Confirm RX, run another
1107 * step to get to Accepted without waiting for
1108 * additional events.
1109 */
Hai Shalom021b0b52019-04-10 11:17:58 -07001110 return sae_sm_step(hapd, sta, bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001111 WLAN_STATUS_SUCCESS, 0, sta_removed);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001112 }
1113 break;
1114 case SAE_CONFIRMED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001115 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001116 if (auth_transaction == 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001117 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001118 return WLAN_STATUS_SUCCESS;
1119 sta->sae->sync++;
1120
Hai Shalomc3565922019-10-28 11:58:20 -07001121 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1122 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001123 if (ret)
1124 return ret;
1125
1126 if (sae_process_commit(sta->sae) < 0)
1127 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1128
1129 ret = auth_sae_send_confirm(hapd, sta, bssid);
1130 if (ret)
1131 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001132
1133 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001134 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001135 sta->sae->send_confirm = 0xffff;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001136 sae_accept_sta(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001137 }
1138 break;
1139 case SAE_ACCEPTED:
Roshan Pius3a1667e2018-07-03 15:17:14 -07001140 if (auth_transaction == 1 &&
1141 (hapd->conf->mesh & MESH_ENABLED)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001142 wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
1143 ") doing reauthentication",
1144 MAC2STR(sta->addr));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001145 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
Hai Shalom5f92bc92019-04-18 11:54:11 -07001146 ap_free_sta(hapd, sta);
1147 *sta_removed = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001148 } else if (auth_transaction == 1) {
1149 wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
Hai Shalomc3565922019-10-28 11:58:20 -07001150 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1151 status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001152 if (ret)
1153 return ret;
1154 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
1155
1156 if (sae_process_commit(sta->sae) < 0)
1157 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1158 sta->sae->sync = 0;
1159 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001160 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001161 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001162 return WLAN_STATUS_SUCCESS;
1163 sta->sae->sync++;
1164
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001165 ret = auth_sae_send_confirm(hapd, sta, bssid);
1166 sae_clear_temp_data(sta->sae);
1167 if (ret)
1168 return ret;
1169 }
1170 break;
1171 default:
1172 wpa_printf(MSG_ERROR, "SAE: invalid state %d",
1173 sta->sae->state);
1174 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1175 }
1176 return WLAN_STATUS_SUCCESS;
1177}
1178
1179
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001180static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
1181{
1182 struct sae_data *sae = sta->sae;
1183 int i, *groups = hapd->conf->sae_groups;
Hai Shalom021b0b52019-04-10 11:17:58 -07001184 int default_groups[] = { 19, 0 };
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001185
1186 if (sae->state != SAE_COMMITTED)
1187 return;
1188
1189 wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
1190
Hai Shalom021b0b52019-04-10 11:17:58 -07001191 if (!groups)
1192 groups = default_groups;
1193 for (i = 0; groups[i] > 0; i++) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001194 if (sae->group == groups[i])
1195 break;
1196 }
1197
Hai Shalom021b0b52019-04-10 11:17:58 -07001198 if (groups[i] <= 0) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001199 wpa_printf(MSG_DEBUG,
1200 "SAE: Previously selected group not found from the current configuration");
1201 return;
1202 }
1203
1204 for (;;) {
1205 i++;
1206 if (groups[i] <= 0) {
1207 wpa_printf(MSG_DEBUG,
1208 "SAE: No alternative group enabled");
1209 return;
1210 }
1211
1212 if (sae_set_group(sae, groups[i]) < 0)
1213 continue;
1214
1215 break;
1216 }
1217 wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
1218}
1219
1220
Hai Shalomc3565922019-10-28 11:58:20 -07001221static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
1222{
Hai Shalomfdcde762020-04-02 11:19:20 -07001223 int sae_pwe = hapd->conf->sae_pwe;
1224 int id_in_use;
Hai Shalom60840252021-02-19 19:02:11 -08001225 bool sae_pk = false;
Hai Shalomfdcde762020-04-02 11:19:20 -07001226
1227 id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
1228 if (id_in_use == 2 && sae_pwe != 3)
1229 sae_pwe = 1;
1230 else if (id_in_use == 1 && sae_pwe == 0)
1231 sae_pwe = 2;
Hai Shalom899fcc72020-10-19 14:38:18 -07001232#ifdef CONFIG_SAE_PK
Hai Shalom60840252021-02-19 19:02:11 -08001233 sae_pk = hostapd_sae_pk_in_use(hapd->conf);
1234 if (sae_pwe == 0 && sae_pk)
Hai Shalom899fcc72020-10-19 14:38:18 -07001235 sae_pwe = 2;
1236#endif /* CONFIG_SAE_PK */
Sunil Ravi89eba102022-09-13 21:04:37 -07001237 if (sae_pwe == 0 &&
1238 (hapd->conf->wpa_key_mgmt &
1239 (WPA_KEY_MGMT_SAE_EXT_KEY | WPA_KEY_MGMT_FT_SAE_EXT_KEY)))
1240 sae_pwe = 2;
Hai Shalomfdcde762020-04-02 11:19:20 -07001241
1242 return ((sae_pwe == 0 || sae_pwe == 3) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001243 status_code == WLAN_STATUS_SUCCESS) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07001244 (sae_pwe == 1 &&
Hai Shalom899fcc72020-10-19 14:38:18 -07001245 (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001246 (sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07001247 (sae_pwe == 2 &&
Hai Shalomc3565922019-10-28 11:58:20 -07001248 (status_code == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -07001249 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
Hai Shalom60840252021-02-19 19:02:11 -08001250 (sae_pk && status_code == WLAN_STATUS_SAE_PK)));
Hai Shalomc3565922019-10-28 11:58:20 -07001251}
1252
1253
1254static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
1255{
1256 int *groups = hapd->conf->sae_groups;
1257 int default_groups[] = { 19, 0 };
1258 int i;
1259
1260 if (!groups)
1261 groups = default_groups;
1262
1263 for (i = 0; groups[i] > 0; i++) {
1264 if (groups[i] == group)
1265 return 1;
1266 }
1267
1268 return 0;
1269}
1270
1271
1272static int check_sae_rejected_groups(struct hostapd_data *hapd,
Hai Shalom899fcc72020-10-19 14:38:18 -07001273 struct sae_data *sae)
Hai Shalomc3565922019-10-28 11:58:20 -07001274{
Hai Shalom899fcc72020-10-19 14:38:18 -07001275 const struct wpabuf *groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001276 size_t i, count;
1277 const u8 *pos;
1278
Hai Shalom899fcc72020-10-19 14:38:18 -07001279 if (!sae->tmp)
1280 return 0;
1281 groups = sae->tmp->peer_rejected_groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001282 if (!groups)
1283 return 0;
1284
1285 pos = wpabuf_head(groups);
1286 count = wpabuf_len(groups) / 2;
1287 for (i = 0; i < count; i++) {
1288 int enabled;
1289 u16 group;
1290
1291 group = WPA_GET_LE16(pos);
1292 pos += 2;
1293 enabled = sae_is_group_enabled(hapd, group);
1294 wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
1295 group, enabled ? "enabled" : "disabled");
1296 if (enabled)
1297 return 1;
1298 }
1299
1300 return 0;
1301}
1302
1303
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001304static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
1305 const struct ieee80211_mgmt *mgmt, size_t len,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001306 u16 auth_transaction, u16 status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001307{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001308 int resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001309 struct wpabuf *data = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07001310 int *groups = hapd->conf->sae_groups;
1311 int default_groups[] = { 19, 0 };
1312 const u8 *pos, *end;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001313 int sta_removed = 0;
Hai Shalom60840252021-02-19 19:02:11 -08001314 bool success_status;
Hai Shalom021b0b52019-04-10 11:17:58 -07001315
1316 if (!groups)
1317 groups = default_groups;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001318
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001319#ifdef CONFIG_TESTING_OPTIONS
1320 if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001321 wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
1322 pos = mgmt->u.auth.variable;
1323 end = ((const u8 *) mgmt) + len;
Hai Shalom899fcc72020-10-19 14:38:18 -07001324 resp = status_code;
Hai Shalomfdcde762020-04-02 11:19:20 -07001325 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001326 auth_transaction, resp, pos, end - pos,
1327 "auth-sae-reflection-attack");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001328 goto remove_sta;
1329 }
1330
1331 if (hapd->conf->sae_commit_override && auth_transaction == 1) {
1332 wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
Hai Shalomfdcde762020-04-02 11:19:20 -07001333 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001334 auth_transaction, resp,
1335 wpabuf_head(hapd->conf->sae_commit_override),
Roshan Pius3a1667e2018-07-03 15:17:14 -07001336 wpabuf_len(hapd->conf->sae_commit_override),
1337 "sae-commit-override");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001338 goto remove_sta;
1339 }
1340#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001341 if (!sta->sae) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001342 if (auth_transaction != 1 ||
Hai Shalomc3565922019-10-28 11:58:20 -07001343 !sae_status_success(hapd, status_code)) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001344 wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
1345 status_code);
1346 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1347 goto reply;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001348 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001349 sta->sae = os_zalloc(sizeof(*sta->sae));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001350 if (!sta->sae) {
1351 resp = -1;
1352 goto remove_sta;
1353 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001354 sae_set_state(sta, SAE_NOTHING, "Init");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001355 sta->sae->sync = 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001356 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001357
Dmitry Shmidte4663042016-04-04 10:07:49 -07001358 if (sta->mesh_sae_pmksa_caching) {
1359 wpa_printf(MSG_DEBUG,
1360 "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
1361 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
1362 sta->mesh_sae_pmksa_caching = 0;
1363 }
1364
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001365 if (auth_transaction == 1) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001366 const u8 *token = NULL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001367 size_t token_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07001368 int allow_reuse = 0;
1369
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001370 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1371 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001372 "start SAE authentication (RX commit, status=%u (%s))",
1373 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001374
1375 if ((hapd->conf->mesh & MESH_ENABLED) &&
1376 status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
1377 sta->sae->tmp) {
1378 pos = mgmt->u.auth.variable;
1379 end = ((const u8 *) mgmt) + len;
1380 if (pos + sizeof(le16) > end) {
1381 wpa_printf(MSG_ERROR,
1382 "SAE: Too short anti-clogging token request");
1383 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1384 goto reply;
1385 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001386 resp = sae_group_allowed(sta->sae, groups,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001387 WPA_GET_LE16(pos));
1388 if (resp != WLAN_STATUS_SUCCESS) {
1389 wpa_printf(MSG_ERROR,
1390 "SAE: Invalid group in anti-clogging token request");
1391 goto reply;
1392 }
1393 pos += sizeof(le16);
1394
1395 wpabuf_free(sta->sae->tmp->anti_clogging_token);
1396 sta->sae->tmp->anti_clogging_token =
1397 wpabuf_alloc_copy(pos, end - pos);
1398 if (sta->sae->tmp->anti_clogging_token == NULL) {
1399 wpa_printf(MSG_ERROR,
1400 "SAE: Failed to alloc for anti-clogging token");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001401 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1402 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001403 }
1404
1405 /*
1406 * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code
1407 * is 76, a new Commit Message shall be constructed
1408 * with the Anti-Clogging Token from the received
1409 * Authentication frame, and the commit-scalar and
1410 * COMMIT-ELEMENT previously sent.
1411 */
Hai Shalomc3565922019-10-28 11:58:20 -07001412 resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
1413 status_code);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001414 if (resp != WLAN_STATUS_SUCCESS) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001415 wpa_printf(MSG_ERROR,
1416 "SAE: Failed to send commit message");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001417 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001418 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001419 sae_set_state(sta, SAE_COMMITTED,
1420 "Sent Commit (anti-clogging token case in mesh)");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001421 sta->sae->sync = 0;
1422 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001423 return;
1424 }
1425
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001426 if ((hapd->conf->mesh & MESH_ENABLED) &&
1427 status_code ==
1428 WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1429 sta->sae->tmp) {
1430 wpa_printf(MSG_DEBUG,
1431 "SAE: Peer did not accept our SAE group");
1432 sae_pick_next_group(hapd, sta);
1433 goto remove_sta;
1434 }
1435
Hai Shalomc3565922019-10-28 11:58:20 -07001436 if (!sae_status_success(hapd, status_code))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001437 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001438
Roshan Pius3a1667e2018-07-03 15:17:14 -07001439 if (!(hapd->conf->mesh & MESH_ENABLED) &&
1440 sta->sae->state == SAE_COMMITTED) {
1441 /* This is needed in the infrastructure BSS case to
1442 * address a sequence where a STA entry may remain in
1443 * hostapd across two attempts to do SAE authentication
1444 * by the same STA. The second attempt may end up trying
1445 * to use a different group and that would not be
1446 * allowed if we remain in Committed state with the
1447 * previously set parameters. */
Hai Shalom021b0b52019-04-10 11:17:58 -07001448 pos = mgmt->u.auth.variable;
1449 end = ((const u8 *) mgmt) + len;
1450 if (end - pos >= (int) sizeof(le16) &&
1451 sae_group_allowed(sta->sae, groups,
1452 WPA_GET_LE16(pos)) ==
1453 WLAN_STATUS_SUCCESS) {
1454 /* Do not waste resources deriving the same PWE
1455 * again since the same group is reused. */
1456 sae_set_state(sta, SAE_NOTHING,
1457 "Allow previous PWE to be reused");
1458 allow_reuse = 1;
1459 } else {
1460 sae_set_state(sta, SAE_NOTHING,
1461 "Clear existing state to allow restart");
1462 sae_clear_data(sta->sae);
1463 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001464 }
1465
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001466 resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
1467 ((const u8 *) mgmt) + len -
1468 mgmt->u.auth.variable, &token,
Hai Shalomc3565922019-10-28 11:58:20 -07001469 &token_len, groups, status_code ==
Hai Shalom899fcc72020-10-19 14:38:18 -07001470 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1471 status_code == WLAN_STATUS_SAE_PK);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001472 if (resp == SAE_SILENTLY_DISCARD) {
1473 wpa_printf(MSG_DEBUG,
1474 "SAE: Drop commit message from " MACSTR " due to reflection attack",
1475 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001476 goto remove_sta;
Dmitry Shmidt41712582015-06-29 11:02:15 -07001477 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001478
1479 if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
1480 wpa_msg(hapd->msg_ctx, MSG_INFO,
1481 WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
1482 MACSTR, MAC2STR(sta->addr));
1483 sae_clear_retransmit_timer(hapd, sta);
1484 sae_set_state(sta, SAE_NOTHING,
1485 "Unknown Password Identifier");
1486 goto remove_sta;
1487 }
1488
Hai Shaloma20dcd72022-02-04 13:43:00 -08001489 if (token &&
1490 check_comeback_token(hapd, sta->addr, token, token_len)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001491 < 0) {
1492 wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
1493 "incorrect token from " MACSTR,
1494 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001495 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1496 goto remove_sta;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001497 }
1498
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001499 if (resp != WLAN_STATUS_SUCCESS)
1500 goto reply;
1501
Hai Shalom899fcc72020-10-19 14:38:18 -07001502 if (check_sae_rejected_groups(hapd, sta->sae)) {
Hai Shalomc3565922019-10-28 11:58:20 -07001503 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001504 goto reply;
Hai Shalomc3565922019-10-28 11:58:20 -07001505 }
1506
Hai Shaloma20dcd72022-02-04 13:43:00 -08001507 if (!token && use_anti_clogging(hapd) && !allow_reuse) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001508 int h2e = 0;
1509
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001510 wpa_printf(MSG_DEBUG,
1511 "SAE: Request anti-clogging token from "
1512 MACSTR, MAC2STR(sta->addr));
Hai Shalomfdcde762020-04-02 11:19:20 -07001513 if (sta->sae->tmp)
Hai Shalom899fcc72020-10-19 14:38:18 -07001514 h2e = sta->sae->h2e;
1515 if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1516 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomfdcde762020-04-02 11:19:20 -07001517 h2e = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001518 data = auth_build_token_req(hapd, sta->sae->group,
Hai Shalomfdcde762020-04-02 11:19:20 -07001519 sta->addr, h2e);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001520 resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
1521 if (hapd->conf->mesh & MESH_ENABLED)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001522 sae_set_state(sta, SAE_NOTHING,
1523 "Request anti-clogging token case in mesh");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001524 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001525 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001526
Hai Shalom021b0b52019-04-10 11:17:58 -07001527 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001528 status_code, allow_reuse, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001529 } else if (auth_transaction == 2) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001530 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1531 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001532 "SAE authentication (RX confirm, status=%u (%s))",
1533 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001534 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001535 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001536 if (sta->sae->state >= SAE_CONFIRMED ||
1537 !(hapd->conf->mesh & MESH_ENABLED)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001538 const u8 *var;
1539 size_t var_len;
1540 u16 peer_send_confirm;
1541
1542 var = mgmt->u.auth.variable;
1543 var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable;
1544 if (var_len < 2) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001545 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001546 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001547 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001548
1549 peer_send_confirm = WPA_GET_LE16(var);
1550
1551 if (sta->sae->state == SAE_ACCEPTED &&
1552 (peer_send_confirm <= sta->sae->rc ||
1553 peer_send_confirm == 0xffff)) {
1554 wpa_printf(MSG_DEBUG,
1555 "SAE: Silently ignore unexpected Confirm from peer "
1556 MACSTR
1557 " (peer-send-confirm=%u Rc=%u)",
1558 MAC2STR(sta->addr),
1559 peer_send_confirm, sta->sae->rc);
1560 return;
1561 }
1562
1563 if (sae_check_confirm(sta->sae, var, var_len) < 0) {
1564 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1565 goto reply;
1566 }
1567 sta->sae->rc = peer_send_confirm;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001568 }
Hai Shalomc3565922019-10-28 11:58:20 -07001569 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
1570 status_code, 0, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001571 } else {
1572 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1573 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001574 "unexpected SAE authentication transaction %u (status=%u (%s))",
1575 auth_transaction, status_code,
1576 status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001577 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001578 goto remove_sta;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001579 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1580 }
1581
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001582reply:
Hai Shalom5f92bc92019-04-18 11:54:11 -07001583 if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001584 pos = mgmt->u.auth.variable;
1585 end = ((const u8 *) mgmt) + len;
1586
1587 /* Copy the Finite Cyclic Group field from the request if we
1588 * rejected it as unsupported group. */
1589 if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1590 !data && end - pos >= 2)
1591 data = wpabuf_alloc_copy(pos, 2);
1592
Hai Shalom5f92bc92019-04-18 11:54:11 -07001593 sae_sme_send_external_auth_status(hapd, sta, resp);
Hai Shalomfdcde762020-04-02 11:19:20 -07001594 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001595 auth_transaction, resp,
1596 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07001597 data ? wpabuf_len(data) : 0, "auth-sae");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001598 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001599
1600remove_sta:
Hai Shalom60840252021-02-19 19:02:11 -08001601 if (auth_transaction == 1)
1602 success_status = sae_status_success(hapd, status_code);
1603 else
1604 success_status = status_code == WLAN_STATUS_SUCCESS;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001605 if (!sta_removed && sta->added_unassoc &&
Hai Shalom60840252021-02-19 19:02:11 -08001606 (resp != WLAN_STATUS_SUCCESS || !success_status)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001607 hostapd_drv_sta_remove(hapd, sta->addr);
1608 sta->added_unassoc = 0;
1609 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001610 wpabuf_free(data);
1611}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001612
1613
1614/**
1615 * auth_sae_init_committed - Send COMMIT and start SAE in committed state
1616 * @hapd: BSS data for the device initiating the authentication
1617 * @sta: the peer to which commit authentication frame is sent
1618 *
1619 * This function implements Init event handling (IEEE Std 802.11-2012,
1620 * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
1621 * sta->sae structure should be initialized appropriately via a call to
1622 * sae_prepare_commit().
1623 */
1624int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
1625{
1626 int ret;
1627
1628 if (!sta->sae || !sta->sae->tmp)
1629 return -1;
1630
1631 if (sta->sae->state != SAE_NOTHING)
1632 return -1;
1633
Hai Shalomc3565922019-10-28 11:58:20 -07001634 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001635 if (ret)
1636 return -1;
1637
Roshan Pius3a1667e2018-07-03 15:17:14 -07001638 sae_set_state(sta, SAE_COMMITTED, "Init and sent commit");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001639 sta->sae->sync = 0;
1640 sae_set_retransmit_timer(hapd, sta);
1641
1642 return 0;
1643}
1644
Hai Shalom021b0b52019-04-10 11:17:58 -07001645
1646void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
1647{
1648 struct hostapd_data *hapd = eloop_ctx;
1649 struct hostapd_sae_commit_queue *q;
1650 unsigned int queue_len;
1651
1652 q = dl_list_first(&hapd->sae_commit_queue,
1653 struct hostapd_sae_commit_queue, list);
1654 if (!q)
1655 return;
1656 wpa_printf(MSG_DEBUG,
1657 "SAE: Process next available message from queue");
1658 dl_list_del(&q->list);
1659 handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
1660 q->rssi, 1);
1661 os_free(q);
1662
1663 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1664 return;
1665 queue_len = dl_list_len(&hapd->sae_commit_queue);
1666 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1667 hapd, NULL);
1668}
1669
1670
1671static void auth_sae_queue(struct hostapd_data *hapd,
1672 const struct ieee80211_mgmt *mgmt, size_t len,
1673 int rssi)
1674{
1675 struct hostapd_sae_commit_queue *q, *q2;
1676 unsigned int queue_len;
1677 const struct ieee80211_mgmt *mgmt2;
1678
1679 queue_len = dl_list_len(&hapd->sae_commit_queue);
1680 if (queue_len >= 15) {
1681 wpa_printf(MSG_DEBUG,
1682 "SAE: No more room in message queue - drop the new frame from "
1683 MACSTR, MAC2STR(mgmt->sa));
1684 return;
1685 }
1686
1687 wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
1688 MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
1689 queue_len);
1690 q = os_zalloc(sizeof(*q) + len);
1691 if (!q)
1692 return;
1693 q->rssi = rssi;
1694 q->len = len;
1695 os_memcpy(q->msg, mgmt, len);
1696
1697 /* Check whether there is already a queued Authentication frame from the
1698 * same station with the same transaction number and if so, replace that
1699 * queue entry with the new one. This avoids issues with a peer that
1700 * sends multiple times (e.g., due to frequent SAE retries). There is no
1701 * point in us trying to process the old attempts after a new one has
1702 * obsoleted them. */
1703 dl_list_for_each(q2, &hapd->sae_commit_queue,
1704 struct hostapd_sae_commit_queue, list) {
1705 mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
1706 if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 &&
1707 mgmt->u.auth.auth_transaction ==
1708 mgmt2->u.auth.auth_transaction) {
1709 wpa_printf(MSG_DEBUG,
1710 "SAE: Replace queued message from same STA with same transaction number");
1711 dl_list_add(&q2->list, &q->list);
1712 dl_list_del(&q2->list);
1713 os_free(q2);
1714 goto queued;
1715 }
1716 }
1717
1718 /* No pending identical entry, so add to the end of the queue */
1719 dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
1720
1721queued:
1722 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1723 return;
1724 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1725 hapd, NULL);
1726}
1727
1728
1729static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
1730{
1731 struct hostapd_sae_commit_queue *q;
1732 const struct ieee80211_mgmt *mgmt;
1733
1734 dl_list_for_each(q, &hapd->sae_commit_queue,
1735 struct hostapd_sae_commit_queue, list) {
1736 mgmt = (const struct ieee80211_mgmt *) q->msg;
1737 if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0)
1738 return 1;
1739 }
1740
1741 return 0;
1742}
1743
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001744#endif /* CONFIG_SAE */
1745
1746
Hai Shalomfdcde762020-04-02 11:19:20 -07001747static u16 wpa_res_to_status_code(enum wpa_validate_result res)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001748{
Hai Shalomfdcde762020-04-02 11:19:20 -07001749 switch (res) {
1750 case WPA_IE_OK:
1751 return WLAN_STATUS_SUCCESS;
1752 case WPA_INVALID_IE:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001753 return WLAN_STATUS_INVALID_IE;
Hai Shalomfdcde762020-04-02 11:19:20 -07001754 case WPA_INVALID_GROUP:
1755 return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
1756 case WPA_INVALID_PAIRWISE:
1757 return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
1758 case WPA_INVALID_AKMP:
1759 return WLAN_STATUS_AKMP_NOT_VALID;
1760 case WPA_NOT_ENABLED:
1761 return WLAN_STATUS_INVALID_IE;
1762 case WPA_ALLOC_FAIL:
1763 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1764 case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
1765 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
1766 case WPA_INVALID_MGMT_GROUP_CIPHER:
1767 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
1768 case WPA_INVALID_MDIE:
1769 return WLAN_STATUS_INVALID_MDIE;
1770 case WPA_INVALID_PROTO:
1771 return WLAN_STATUS_INVALID_IE;
1772 case WPA_INVALID_PMKID:
1773 return WLAN_STATUS_INVALID_PMKID;
1774 case WPA_DENIED_OTHER_REASON:
1775 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
1776 }
1777 return WLAN_STATUS_INVALID_IE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001778}
1779
1780
1781#ifdef CONFIG_FILS
1782
1783static void handle_auth_fils_finish(struct hostapd_data *hapd,
1784 struct sta_info *sta, u16 resp,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001785 struct wpabuf *data, int pub);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001786
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001787void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
1788 const u8 *pos, size_t len, u16 auth_alg,
1789 u16 auth_transaction, u16 status_code,
1790 void (*cb)(struct hostapd_data *hapd,
1791 struct sta_info *sta, u16 resp,
1792 struct wpabuf *data, int pub))
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001793{
1794 u16 resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001795 const u8 *end;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001796 struct ieee802_11_elems elems;
Hai Shalomfdcde762020-04-02 11:19:20 -07001797 enum wpa_validate_result res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001798 struct wpa_ie_data rsn;
1799 struct rsn_pmksa_cache_entry *pmksa = NULL;
1800
1801 if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
1802 return;
1803
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001804 end = pos + len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001805
1806 wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
1807 pos, end - pos);
1808
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001809 /* TODO: FILS PK */
1810#ifdef CONFIG_FILS_SK_PFS
1811 if (auth_alg == WLAN_AUTH_FILS_SK_PFS) {
1812 u16 group;
1813 struct wpabuf *pub;
1814 size_t elem_len;
1815
1816 /* Using FILS PFS */
1817
1818 /* Finite Cyclic Group */
1819 if (end - pos < 2) {
1820 wpa_printf(MSG_DEBUG,
1821 "FILS: No room for Finite Cyclic Group");
1822 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1823 goto fail;
1824 }
1825 group = WPA_GET_LE16(pos);
1826 pos += 2;
1827 if (group != hapd->conf->fils_dh_group) {
1828 wpa_printf(MSG_DEBUG,
1829 "FILS: Unsupported Finite Cyclic Group: %u (expected %u)",
1830 group, hapd->conf->fils_dh_group);
1831 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1832 goto fail;
1833 }
1834
1835 crypto_ecdh_deinit(sta->fils_ecdh);
1836 sta->fils_ecdh = crypto_ecdh_init(group);
1837 if (!sta->fils_ecdh) {
1838 wpa_printf(MSG_INFO,
1839 "FILS: Could not initialize ECDH with group %d",
1840 group);
1841 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1842 goto fail;
1843 }
1844
1845 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
1846 if (!pub) {
1847 wpa_printf(MSG_DEBUG,
1848 "FILS: Failed to derive ECDH public key");
1849 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1850 goto fail;
1851 }
1852 elem_len = wpabuf_len(pub);
1853 wpabuf_free(pub);
1854
1855 /* Element */
1856 if ((size_t) (end - pos) < elem_len) {
1857 wpa_printf(MSG_DEBUG, "FILS: No room for Element");
1858 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1859 goto fail;
1860 }
1861
1862 wpabuf_free(sta->fils_g_sta);
1863 sta->fils_g_sta = wpabuf_alloc_copy(pos, elem_len);
1864 wpabuf_clear_free(sta->fils_dh_ss);
1865 sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1,
1866 pos, elem_len);
1867 if (!sta->fils_dh_ss) {
1868 wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
1869 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1870 goto fail;
1871 }
1872 wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss);
1873 pos += elem_len;
1874 } else {
1875 crypto_ecdh_deinit(sta->fils_ecdh);
1876 sta->fils_ecdh = NULL;
1877 wpabuf_clear_free(sta->fils_dh_ss);
1878 sta->fils_dh_ss = NULL;
1879 }
1880#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001881
1882 wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
1883 if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
1884 wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
1885 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1886 goto fail;
1887 }
1888
1889 /* RSNE */
1890 wpa_hexdump(MSG_DEBUG, "FILS: RSN element",
1891 elems.rsn_ie, elems.rsn_ie_len);
1892 if (!elems.rsn_ie ||
1893 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
1894 &rsn) < 0) {
1895 wpa_printf(MSG_DEBUG, "FILS: No valid RSN element");
1896 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1897 goto fail;
1898 }
1899
1900 if (!sta->wpa_sm)
1901 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
1902 NULL);
1903 if (!sta->wpa_sm) {
1904 wpa_printf(MSG_DEBUG,
1905 "FILS: Failed to initialize RSN state machine");
1906 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1907 goto fail;
1908 }
1909
1910 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07001911 hapd->iface->freq,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001912 elems.rsn_ie - 2, elems.rsn_ie_len + 2,
Hai Shalomc3565922019-10-28 11:58:20 -07001913 elems.rsnxe ? elems.rsnxe - 2 : NULL,
1914 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001915 elems.mdie, elems.mdie_len, NULL, 0);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001916 resp = wpa_res_to_status_code(res);
1917 if (resp != WLAN_STATUS_SUCCESS)
1918 goto fail;
1919
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001920 if (!elems.fils_nonce) {
1921 wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
1922 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1923 goto fail;
1924 }
1925 wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce,
1926 FILS_NONCE_LEN);
1927 os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN);
1928
1929 /* PMKID List */
1930 if (rsn.pmkid && rsn.num_pmkid > 0) {
1931 u8 num;
1932 const u8 *pmkid;
1933
1934 wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
1935 rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
1936
1937 pmkid = rsn.pmkid;
1938 num = rsn.num_pmkid;
1939 while (num) {
1940 wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
1941 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
1942 pmkid);
1943 if (pmksa)
1944 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001945 pmksa = wpa_auth_pmksa_get_fils_cache_id(hapd->wpa_auth,
1946 sta->addr,
1947 pmkid);
1948 if (pmksa)
1949 break;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001950 pmkid += PMKID_LEN;
1951 num--;
1952 }
1953 }
1954 if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) {
1955 wpa_printf(MSG_DEBUG,
1956 "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore",
1957 wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp);
1958 pmksa = NULL;
1959 }
1960 if (pmksa)
1961 wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry");
1962
1963 /* FILS Session */
1964 if (!elems.fils_session) {
1965 wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
1966 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1967 goto fail;
1968 }
1969 wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
1970 FILS_SESSION_LEN);
1971 os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
1972
Hai Shalomfdcde762020-04-02 11:19:20 -07001973 /* Wrapped Data */
1974 if (elems.wrapped_data) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001975 wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
Hai Shalomfdcde762020-04-02 11:19:20 -07001976 elems.wrapped_data,
1977 elems.wrapped_data_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001978 if (!pmksa) {
1979#ifndef CONFIG_NO_RADIUS
1980 if (!sta->eapol_sm) {
1981 sta->eapol_sm =
1982 ieee802_1x_alloc_eapol_sm(hapd, sta);
1983 }
1984 wpa_printf(MSG_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001985 "FILS: Forward EAP-Initiate/Re-auth to authentication server");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001986 ieee802_1x_encapsulate_radius(
Hai Shalomfdcde762020-04-02 11:19:20 -07001987 hapd, sta, elems.wrapped_data,
1988 elems.wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001989 sta->fils_pending_cb = cb;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001990 wpa_printf(MSG_DEBUG,
1991 "FILS: Will send Authentication frame once the response from authentication server is available");
1992 sta->flags |= WLAN_STA_PENDING_FILS_ERP;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001993 /* Calculate pending PMKID here so that we do not need
1994 * to maintain a copy of the EAP-Initiate/Reauth
1995 * message. */
1996 if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
Hai Shalomfdcde762020-04-02 11:19:20 -07001997 elems.wrapped_data,
1998 elems.wrapped_data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001999 sta->fils_erp_pmkid) == 0)
2000 sta->fils_erp_pmkid_set = 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002001 return;
2002#else /* CONFIG_NO_RADIUS */
2003 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2004 goto fail;
2005#endif /* CONFIG_NO_RADIUS */
2006 }
2007 }
2008
2009fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002010 if (cb) {
2011 struct wpabuf *data;
2012 int pub = 0;
2013
2014 data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, NULL,
2015 NULL, 0, &pub);
2016 if (!data) {
2017 wpa_printf(MSG_DEBUG,
2018 "%s: prepare_auth_resp_fils() returned failure",
2019 __func__);
2020 }
2021
2022 cb(hapd, sta, resp, data, pub);
2023 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002024}
2025
2026
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002027static struct wpabuf *
2028prepare_auth_resp_fils(struct hostapd_data *hapd,
2029 struct sta_info *sta, u16 *resp,
2030 struct rsn_pmksa_cache_entry *pmksa,
2031 struct wpabuf *erp_resp,
2032 const u8 *msk, size_t msk_len,
2033 int *is_pub)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002034{
2035 u8 fils_nonce[FILS_NONCE_LEN];
2036 size_t ielen;
2037 struct wpabuf *data = NULL;
2038 const u8 *ie;
2039 u8 *ie_buf = NULL;
2040 const u8 *pmk = NULL;
2041 size_t pmk_len = 0;
Paul Stewart092955c2017-02-06 09:13:09 -08002042 u8 pmk_buf[PMK_LEN_MAX];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002043 struct wpabuf *pub = NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002044
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002045 if (*resp != WLAN_STATUS_SUCCESS)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002046 goto fail;
2047
2048 ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
2049 if (!ie) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002050 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002051 goto fail;
2052 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002053
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002054 if (pmksa) {
2055 /* Add PMKID of the selected PMKSA into RSNE */
2056 ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN);
2057 if (!ie_buf) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002058 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002059 goto fail;
2060 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002061
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002062 os_memcpy(ie_buf, ie, ielen);
2063 if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002064 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002065 goto fail;
2066 }
2067 ie = ie_buf;
2068 }
2069
2070 if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002071 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002072 goto fail;
2073 }
2074 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
2075 fils_nonce, FILS_NONCE_LEN);
2076
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002077#ifdef CONFIG_FILS_SK_PFS
2078 if (sta->fils_dh_ss && sta->fils_ecdh) {
2079 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
2080 if (!pub) {
2081 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2082 goto fail;
2083 }
2084 }
2085#endif /* CONFIG_FILS_SK_PFS */
2086
2087 data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0));
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002088 if (!data) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002089 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002090 goto fail;
2091 }
2092
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002093 /* TODO: FILS PK */
2094#ifdef CONFIG_FILS_SK_PFS
2095 if (pub) {
2096 /* Finite Cyclic Group */
2097 wpabuf_put_le16(data, hapd->conf->fils_dh_group);
2098
2099 /* Element */
2100 wpabuf_put_buf(data, pub);
2101 }
2102#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002103
2104 /* RSNE */
2105 wpabuf_put_data(data, ie, ielen);
2106
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002107 /* MDE when using FILS+FT (already included in ie,ielen with RSNE) */
2108
2109#ifdef CONFIG_IEEE80211R_AP
2110 if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
2111 /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
2112 int res;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002113 int use_sha384 = wpa_key_mgmt_sha384(
2114 wpa_auth_sta_key_mgmt(sta->wpa_sm));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002115
Roshan Pius3a1667e2018-07-03 15:17:14 -07002116 res = wpa_auth_write_fte(hapd->wpa_auth, use_sha384,
2117 wpabuf_put(data, 0),
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002118 wpabuf_tailroom(data));
2119 if (res < 0) {
2120 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2121 goto fail;
2122 }
2123 wpabuf_put(data, res);
2124 }
2125#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002126
2127 /* FILS Nonce */
2128 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2129 wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */
2130 /* Element ID Extension */
2131 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE);
2132 wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN);
2133
2134 /* FILS Session */
2135 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2136 wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */
2137 /* Element ID Extension */
2138 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
2139 wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
2140
Hai Shalomfdcde762020-04-02 11:19:20 -07002141 /* Wrapped Data */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002142 if (!pmksa && erp_resp) {
2143 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2144 wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
2145 /* Element ID Extension */
Hai Shalomfdcde762020-04-02 11:19:20 -07002146 wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002147 wpabuf_put_buf(data, erp_resp);
2148
Paul Stewart092955c2017-02-06 09:13:09 -08002149 if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
2150 msk, msk_len, sta->fils_snonce, fils_nonce,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002151 sta->fils_dh_ss ?
2152 wpabuf_head(sta->fils_dh_ss) : NULL,
2153 sta->fils_dh_ss ?
2154 wpabuf_len(sta->fils_dh_ss) : 0,
2155 pmk_buf, &pmk_len)) {
Paul Stewart092955c2017-02-06 09:13:09 -08002156 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002157 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Paul Stewart092955c2017-02-06 09:13:09 -08002158 wpabuf_free(data);
2159 data = NULL;
2160 goto fail;
2161 }
2162 pmk = pmk_buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002163
2164 /* Don't use DHss in PTK derivation if PMKSA caching is not
2165 * used. */
2166 wpabuf_clear_free(sta->fils_dh_ss);
2167 sta->fils_dh_ss = NULL;
2168
2169 if (sta->fils_erp_pmkid_set) {
2170 /* TODO: get PMKLifetime from WPA parameters */
2171 unsigned int dot11RSNAConfigPMKLifetime = 43200;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002172 int session_timeout;
2173
2174 session_timeout = dot11RSNAConfigPMKLifetime;
2175 if (sta->session_timeout_set) {
2176 struct os_reltime now, diff;
2177
2178 os_get_reltime(&now);
2179 os_reltime_sub(&sta->session_timeout, &now,
2180 &diff);
2181 session_timeout = diff.sec;
2182 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002183
2184 sta->fils_erp_pmkid_set = 0;
Hai Shalom81f62d82019-07-22 12:10:00 -07002185 wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
2186 sta->fils_erp_pmkid);
Hai Shalom021b0b52019-04-10 11:17:58 -07002187 if (!hapd->conf->disable_pmksa_caching &&
2188 wpa_auth_pmksa_add2(
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002189 hapd->wpa_auth, sta->addr,
2190 pmk, pmk_len,
2191 sta->fils_erp_pmkid,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002192 session_timeout,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002193 wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) {
2194 wpa_printf(MSG_ERROR,
2195 "FILS: Failed to add PMKSA cache entry based on ERP");
2196 }
2197 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002198 } else if (pmksa) {
2199 pmk = pmksa->pmk;
2200 pmk_len = pmksa->pmk_len;
2201 }
2202
2203 if (!pmk) {
2204 wpa_printf(MSG_DEBUG, "FILS: No PMK available");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002205 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002206 wpabuf_free(data);
2207 data = NULL;
2208 goto fail;
2209 }
2210
2211 if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002212 sta->fils_snonce, fils_nonce,
2213 sta->fils_dh_ss ?
2214 wpabuf_head(sta->fils_dh_ss) : NULL,
2215 sta->fils_dh_ss ?
2216 wpabuf_len(sta->fils_dh_ss) : 0,
2217 sta->fils_g_sta, pub) < 0) {
2218 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002219 wpabuf_free(data);
2220 data = NULL;
2221 goto fail;
2222 }
2223
2224fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002225 if (is_pub)
2226 *is_pub = pub != NULL;
2227 os_free(ie_buf);
2228 wpabuf_free(pub);
2229 wpabuf_clear_free(sta->fils_dh_ss);
2230 sta->fils_dh_ss = NULL;
2231#ifdef CONFIG_FILS_SK_PFS
2232 crypto_ecdh_deinit(sta->fils_ecdh);
2233 sta->fils_ecdh = NULL;
2234#endif /* CONFIG_FILS_SK_PFS */
2235 return data;
2236}
2237
2238
2239static void handle_auth_fils_finish(struct hostapd_data *hapd,
2240 struct sta_info *sta, u16 resp,
2241 struct wpabuf *data, int pub)
2242{
2243 u16 auth_alg;
2244
2245 auth_alg = (pub ||
2246 resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
2247 WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Hai Shalomfdcde762020-04-02 11:19:20 -07002248 send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002249 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07002250 data ? wpabuf_len(data) : 0, "auth-fils-finish");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002251 wpabuf_free(data);
2252
2253 if (resp == WLAN_STATUS_SUCCESS) {
2254 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2255 HOSTAPD_LEVEL_DEBUG,
2256 "authentication OK (FILS)");
2257 sta->flags |= WLAN_STA_AUTH;
2258 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002259 sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002260 mlme_authenticate_indication(hapd, sta);
2261 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002262}
2263
2264
2265void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
2266 struct sta_info *sta, int success,
2267 struct wpabuf *erp_resp,
2268 const u8 *msk, size_t msk_len)
2269{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002270 u16 resp;
Hai Shalom60840252021-02-19 19:02:11 -08002271 u32 flags = sta->flags;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002272
Hai Shalom60840252021-02-19 19:02:11 -08002273 sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
2274 WLAN_STA_PENDING_PASN_FILS_ERP);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002275
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002276 resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
Hai Shalom60840252021-02-19 19:02:11 -08002277
2278 if (flags & WLAN_STA_PENDING_FILS_ERP) {
2279 struct wpabuf *data;
2280 int pub = 0;
2281
2282 if (!sta->fils_pending_cb)
2283 return;
2284
2285 data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
2286 msk, msk_len, &pub);
2287 if (!data) {
2288 wpa_printf(MSG_DEBUG,
2289 "%s: prepare_auth_resp_fils() failure",
2290 __func__);
2291 }
2292 sta->fils_pending_cb(hapd, sta, resp, data, pub);
2293#ifdef CONFIG_PASN
2294 } else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
2295 pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
2296 msk, msk_len);
2297#endif /* CONFIG_PASN */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002298 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002299}
2300
2301#endif /* CONFIG_FILS */
2302
2303
Hai Shalomfdcde762020-04-02 11:19:20 -07002304static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
2305 const u8 *msg, size_t len,
2306 struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002307{
2308 int res;
2309
Hai Shalomfdcde762020-04-02 11:19:20 -07002310 res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002311
2312 if (res == HOSTAPD_ACL_REJECT) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002313 wpa_printf(MSG_DEBUG, "Station " MACSTR
2314 " not allowed to authenticate",
2315 MAC2STR(addr));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002316 return HOSTAPD_ACL_REJECT;
2317 }
2318
2319 if (res == HOSTAPD_ACL_PENDING) {
2320 wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
2321 " waiting for an external authentication",
2322 MAC2STR(addr));
2323 /* Authentication code will re-send the authentication frame
2324 * after it has received (and cached) information from the
2325 * external source. */
2326 return HOSTAPD_ACL_PENDING;
2327 }
2328
2329 return res;
2330}
2331
2332
Sunil Ravia04bd252022-05-02 22:54:18 -07002333int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
2334 int res, struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002335{
Hai Shalomfdcde762020-04-02 11:19:20 -07002336 u32 session_timeout = info->session_timeout;
2337 u32 acct_interim_interval = info->acct_interim_interval;
2338 struct vlan_description *vlan_id = &info->vlan_id;
2339 struct hostapd_sta_wpa_psk_short *psk = info->psk;
2340 char *identity = info->identity;
2341 char *radius_cui = info->radius_cui;
2342
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002343 if (vlan_id->notempty &&
2344 !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
2345 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2346 HOSTAPD_LEVEL_INFO,
2347 "Invalid VLAN %d%s received from RADIUS server",
2348 vlan_id->untagged,
2349 vlan_id->tagged[0] ? "+" : "");
2350 return -1;
2351 }
2352 if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
2353 return -1;
2354 if (sta->vlan_id)
2355 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2356 HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
2357
2358 hostapd_free_psk_list(sta->psk);
Hai Shalomfdcde762020-04-02 11:19:20 -07002359 if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
2360 hostapd_copy_psk_list(&sta->psk, psk);
2361 else
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002362 sta->psk = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002363
Roshan Pius3a1667e2018-07-03 15:17:14 -07002364 os_free(sta->identity);
Hai Shalomfdcde762020-04-02 11:19:20 -07002365 if (identity)
2366 sta->identity = os_strdup(identity);
2367 else
2368 sta->identity = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002369
2370 os_free(sta->radius_cui);
Hai Shalomfdcde762020-04-02 11:19:20 -07002371 if (radius_cui)
2372 sta->radius_cui = os_strdup(radius_cui);
2373 else
2374 sta->radius_cui = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002375
2376 if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
2377 sta->acct_interim_interval = acct_interim_interval;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002378 if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
2379 sta->session_timeout_set = 1;
2380 os_get_reltime(&sta->session_timeout);
2381 sta->session_timeout.sec += session_timeout;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002382 ap_sta_session_timeout(hapd, sta, session_timeout);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002383 } else {
2384 sta->session_timeout_set = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002385 ap_sta_no_session_timeout(hapd, sta);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002386 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002387
2388 return 0;
2389}
2390
2391
Hai Shalom60840252021-02-19 19:02:11 -08002392#ifdef CONFIG_PASN
2393#ifdef CONFIG_SAE
2394
2395static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd,
2396 struct sta_info *sta,
2397 struct wpabuf *wd)
2398{
2399 struct pasn_data *pasn = sta->pasn;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002400 const char *password;
Hai Shalom60840252021-02-19 19:02:11 -08002401 const u8 *data;
2402 size_t buf_len;
2403 u16 res, alg, seq, status;
2404 int groups[] = { pasn->group, 0 };
Hai Shaloma20dcd72022-02-04 13:43:00 -08002405 struct sae_pt *pt = NULL;
Hai Shalom60840252021-02-19 19:02:11 -08002406 int ret;
2407
2408 if (!wd)
2409 return -1;
2410
2411 data = wpabuf_head_u8(wd);
2412 buf_len = wpabuf_len(wd);
2413
2414 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002415 wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002416 buf_len);
2417 return -1;
2418 }
2419
2420 alg = WPA_GET_LE16(data);
2421 seq = WPA_GET_LE16(data + 2);
2422 status = WPA_GET_LE16(data + 4);
2423
2424 wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u",
2425 alg, seq, status);
2426
Hai Shaloma20dcd72022-02-04 13:43:00 -08002427 if (alg != WLAN_AUTH_SAE || seq != 1 ||
2428 status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
Hai Shalom60840252021-02-19 19:02:11 -08002429 wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit");
2430 return -1;
2431 }
2432
2433 sae_clear_data(&pasn->sae);
2434 pasn->sae.state = SAE_NOTHING;
2435
2436 ret = sae_set_group(&pasn->sae, pasn->group);
2437 if (ret) {
2438 wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group");
2439 return -1;
2440 }
2441
Hai Shaloma20dcd72022-02-04 13:43:00 -08002442 password = sae_get_password(hapd, sta, NULL, NULL, &pt, NULL);
2443 if (!password || !pt) {
2444 wpa_printf(MSG_DEBUG, "PASN: No SAE PT found");
Hai Shalom60840252021-02-19 19:02:11 -08002445 return -1;
2446 }
2447
Hai Shaloma20dcd72022-02-04 13:43:00 -08002448 ret = sae_prepare_commit_pt(&pasn->sae, pt, hapd->own_addr, sta->addr,
2449 NULL, NULL);
Hai Shalom60840252021-02-19 19:02:11 -08002450 if (ret) {
2451 wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
2452 return -1;
2453 }
2454
2455 res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0,
2456 groups, 0);
2457 if (res != WLAN_STATUS_SUCCESS) {
2458 wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit");
2459 return -1;
2460 }
2461
2462 /* Process the commit message and derive the PMK */
2463 ret = sae_process_commit(&pasn->sae);
2464 if (ret) {
2465 wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
2466 return -1;
2467 }
2468
2469 pasn->sae.state = SAE_COMMITTED;
2470
2471 return 0;
2472}
2473
2474
2475static int pasn_wd_handle_sae_confirm(struct hostapd_data *hapd,
2476 struct sta_info *sta,
2477 struct wpabuf *wd)
2478{
2479 struct pasn_data *pasn = sta->pasn;
2480 const u8 *data;
2481 size_t buf_len;
2482 u16 res, alg, seq, status;
2483
2484 if (!wd)
2485 return -1;
2486
2487 data = wpabuf_head_u8(wd);
2488 buf_len = wpabuf_len(wd);
2489
2490 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002491 wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002492 buf_len);
2493 return -1;
2494 }
2495
2496 alg = WPA_GET_LE16(data);
2497 seq = WPA_GET_LE16(data + 2);
2498 status = WPA_GET_LE16(data + 4);
2499
2500 wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u",
2501 alg, seq, status);
2502
2503 if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) {
2504 wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm");
2505 return -1;
2506 }
2507
2508 res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6);
2509 if (res != WLAN_STATUS_SUCCESS) {
2510 wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm");
2511 return -1;
2512 }
2513
2514 pasn->sae.state = SAE_ACCEPTED;
2515
2516 /*
2517 * TODO: Based on on IEEE P802.11az/D2.6, the PMKSA derived with
2518 * PASN/SAE should only be allowed with future PASN only. For now do not
2519 * restrict this only for PASN.
2520 */
2521 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
Sunil Ravi89eba102022-09-13 21:04:37 -07002522 pasn->sae.pmk, pasn->sae.pmk_len,
2523 pasn->sae.pmkid, pasn->sae.akmp);
Hai Shalom60840252021-02-19 19:02:11 -08002524 return 0;
2525}
2526
2527
2528static struct wpabuf * pasn_get_sae_wd(struct hostapd_data *hapd,
2529 struct sta_info *sta)
2530{
2531 struct pasn_data *pasn = sta->pasn;
2532 struct wpabuf *buf = NULL;
2533 u8 *len_ptr;
2534 size_t len;
2535
2536 /* Need to add the entire Authentication frame body */
2537 buf = wpabuf_alloc(8 + SAE_COMMIT_MAX_LEN + 8 + SAE_CONFIRM_MAX_LEN);
2538 if (!buf) {
2539 wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
2540 return NULL;
2541 }
2542
2543 /* Need to add the entire authentication frame body for the commit */
2544 len_ptr = wpabuf_put(buf, 2);
2545 wpabuf_put_le16(buf, WLAN_AUTH_SAE);
2546 wpabuf_put_le16(buf, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002547 wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
Hai Shalom60840252021-02-19 19:02:11 -08002548
2549 /* Write the actual commit and update the length accordingly */
2550 sae_write_commit(&pasn->sae, buf, NULL, 0);
2551 len = wpabuf_len(buf);
2552 WPA_PUT_LE16(len_ptr, len - 2);
2553
2554 /* Need to add the entire Authentication frame body for the confirm */
2555 len_ptr = wpabuf_put(buf, 2);
2556 wpabuf_put_le16(buf, WLAN_AUTH_SAE);
2557 wpabuf_put_le16(buf, 2);
2558 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
2559
2560 sae_write_confirm(&pasn->sae, buf);
2561 WPA_PUT_LE16(len_ptr, wpabuf_len(buf) - len - 2);
2562
2563 pasn->sae.state = SAE_CONFIRMED;
2564
2565 return buf;
2566}
2567
2568#endif /* CONFIG_SAE */
2569
2570
2571#ifdef CONFIG_FILS
2572
2573static struct wpabuf * pasn_get_fils_wd(struct hostapd_data *hapd,
2574 struct sta_info *sta)
2575{
2576 struct pasn_data *pasn = sta->pasn;
2577 struct pasn_fils_data *fils = &pasn->fils;
2578 struct wpabuf *buf = NULL;
2579
2580 if (!fils->erp_resp) {
2581 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing erp_resp");
2582 return NULL;
2583 }
2584
2585 buf = wpabuf_alloc(1500);
2586 if (!buf)
2587 return NULL;
2588
2589 /* Add the authentication algorithm */
2590 wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
2591
2592 /* Authentication Transaction seq# */
2593 wpabuf_put_le16(buf, 2);
2594
2595 /* Status Code */
2596 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
2597
2598 /* Own RSNE */
2599 wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
2600
2601 /* FILS Nonce */
2602 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
2603 wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
2604 wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
2605 wpabuf_put_data(buf, fils->anonce, FILS_NONCE_LEN);
2606
2607 /* FILS Session */
2608 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
2609 wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
2610 wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
2611 wpabuf_put_data(buf, fils->session, FILS_SESSION_LEN);
2612
2613 /* Wrapped Data */
2614 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
2615 wpabuf_put_u8(buf, 1 + wpabuf_len(fils->erp_resp));
2616 wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
2617 wpabuf_put_buf(buf, fils->erp_resp);
2618
2619 return buf;
2620}
2621
2622
2623static void pasn_fils_auth_resp(struct hostapd_data *hapd,
2624 struct sta_info *sta, u16 status,
2625 struct wpabuf *erp_resp,
2626 const u8 *msk, size_t msk_len)
2627{
2628 struct pasn_data *pasn = sta->pasn;
2629 struct pasn_fils_data *fils = &pasn->fils;
2630 u8 pmk[PMK_LEN_MAX];
2631 size_t pmk_len;
2632 int ret;
2633
2634 wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
2635 status);
2636
2637 if (status != WLAN_STATUS_SUCCESS)
2638 goto fail;
2639
2640 if (!pasn->secret) {
2641 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
2642 goto fail;
2643 }
2644
2645 if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
2646 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
2647 goto fail;
2648 }
2649
2650 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
2651 fils->anonce, FILS_NONCE_LEN);
2652
2653 ret = fils_rmsk_to_pmk(pasn->akmp, msk, msk_len, fils->nonce,
2654 fils->anonce, NULL, 0, pmk, &pmk_len);
2655 if (ret) {
2656 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
2657 goto fail;
2658 }
2659
2660 ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
2661 wpabuf_head(pasn->secret),
2662 wpabuf_len(pasn->secret),
2663 &sta->pasn->ptk, sta->pasn->akmp,
Hai Shaloma20dcd72022-02-04 13:43:00 -08002664 sta->pasn->cipher, sta->pasn->kdk_len);
Hai Shalom60840252021-02-19 19:02:11 -08002665 if (ret) {
2666 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
2667 goto fail;
2668 }
2669
Sunil Ravi89eba102022-09-13 21:04:37 -07002670 if (pasn->secure_ltf) {
2671 ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp, pasn->cipher);
2672 if (ret) {
2673 wpa_printf(MSG_DEBUG,
2674 "PASN: FILS: Failed to derive LTF keyseed");
2675 goto fail;
2676 }
2677 }
2678
Hai Shalom60840252021-02-19 19:02:11 -08002679 wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
2680
2681 wpabuf_free(pasn->secret);
2682 pasn->secret = NULL;
2683
2684 fils->erp_resp = erp_resp;
2685 ret = handle_auth_pasn_resp(hapd, sta, NULL, WLAN_STATUS_SUCCESS);
2686 fils->erp_resp = NULL;
2687
2688 if (ret) {
2689 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
2690 goto fail;
2691 }
2692
2693 fils->state = PASN_FILS_STATE_COMPLETE;
2694 return;
2695fail:
2696 ap_free_sta(hapd, sta);
2697}
2698
2699
2700static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
2701 struct wpabuf *wd)
2702{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002703#ifdef CONFIG_NO_RADIUS
2704 wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
2705 return -1;
2706#else /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002707 struct pasn_data *pasn = sta->pasn;
2708 struct pasn_fils_data *fils = &pasn->fils;
2709 struct ieee802_11_elems elems;
2710 struct wpa_ie_data rsne_data;
2711 struct wpabuf *fils_wd;
2712 const u8 *data;
2713 size_t buf_len;
2714 u16 alg, seq, status;
2715 int ret;
2716
2717 if (fils->state != PASN_FILS_STATE_NONE) {
2718 wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
2719 return -1;
2720 }
2721
2722 if (!wd) {
2723 wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
2724 return -1;
2725 }
2726
2727 data = wpabuf_head_u8(wd);
2728 buf_len = wpabuf_len(wd);
2729
2730 if (buf_len < 6) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002731 wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%zu",
Hai Shalom60840252021-02-19 19:02:11 -08002732 buf_len);
2733 return -1;
2734 }
2735
2736 alg = WPA_GET_LE16(data);
2737 seq = WPA_GET_LE16(data + 2);
2738 status = WPA_GET_LE16(data + 4);
2739
2740 wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
2741 alg, seq, status);
2742
2743 if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
2744 status != WLAN_STATUS_SUCCESS) {
2745 wpa_printf(MSG_DEBUG,
2746 "PASN: FILS: Dropping peer authentication");
2747 return -1;
2748 }
2749
2750 data += 6;
2751 buf_len -= 6;
2752
2753 if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
2754 wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
2755 return -1;
2756 }
2757
2758 if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
2759 !elems.wrapped_data) {
2760 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
2761 return -1;
2762 }
2763
2764 ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2765 &rsne_data);
2766 if (ret) {
2767 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RNSE");
2768 return -1;
2769 }
2770
2771 ret = wpa_pasn_validate_rsne(&rsne_data);
2772 if (ret) {
2773 wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
2774 return -1;
2775 }
2776
2777 if (rsne_data.num_pmkid) {
2778 wpa_printf(MSG_DEBUG,
2779 "PASN: FILS: Not expecting PMKID in RSNE");
2780 return -1;
2781 }
2782
2783 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
2784 FILS_NONCE_LEN);
2785 os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
2786
2787 wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
2788 FILS_SESSION_LEN);
2789 os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
2790
Hai Shalom60840252021-02-19 19:02:11 -08002791 fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
2792 WLAN_EID_EXT_WRAPPED_DATA);
2793
2794 if (!fils_wd) {
2795 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
2796 return -1;
2797 }
2798
2799 if (!sta->eapol_sm)
2800 sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
2801
2802 wpa_printf(MSG_DEBUG,
2803 "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
2804
2805 ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
2806 wpabuf_len(fils_wd));
2807
2808 sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
2809
2810 fils->state = PASN_FILS_STATE_PENDING_AS;
2811
2812 /*
2813 * Calculate pending PMKID here so that we do not need to maintain a
2814 * copy of the EAP-Initiate/Reautt message.
2815 */
2816 fils_pmkid_erp(pasn->akmp, wpabuf_head(fils_wd), wpabuf_len(fils_wd),
2817 fils->erp_pmkid);
2818
2819 wpabuf_free(fils_wd);
2820 return 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002821#endif /* CONFIG_NO_RADIUS */
Hai Shalom60840252021-02-19 19:02:11 -08002822}
2823
2824#endif /* CONFIG_FILS */
2825
2826
2827static struct wpabuf * pasn_get_wrapped_data(struct hostapd_data *hapd,
2828 struct sta_info *sta)
2829{
2830 switch (sta->pasn->akmp) {
2831 case WPA_KEY_MGMT_PASN:
2832 /* no wrapped data */
2833 return NULL;
2834 case WPA_KEY_MGMT_SAE:
2835#ifdef CONFIG_SAE
2836 return pasn_get_sae_wd(hapd, sta);
2837#else /* CONFIG_SAE */
2838 wpa_printf(MSG_ERROR,
2839 "PASN: SAE: Cannot derive wrapped data");
2840 return NULL;
2841#endif /* CONFIG_SAE */
2842 case WPA_KEY_MGMT_FILS_SHA256:
2843 case WPA_KEY_MGMT_FILS_SHA384:
2844#ifdef CONFIG_FILS
2845 return pasn_get_fils_wd(hapd, sta);
2846#endif /* CONFIG_FILS */
2847 /* fall through */
2848 case WPA_KEY_MGMT_FT_PSK:
2849 case WPA_KEY_MGMT_FT_IEEE8021X:
2850 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
2851 default:
2852 wpa_printf(MSG_ERROR,
2853 "PASN: TODO: Wrapped data for akmp=0x%x",
2854 sta->pasn->akmp);
2855 return NULL;
2856 }
2857}
2858
2859
Sunil Ravi89eba102022-09-13 21:04:37 -07002860static int pasn_set_keys_from_cache(struct hostapd_data *hapd,
2861 const u8 *own_addr, const u8 *sta_addr,
2862 int cipher, int akmp)
2863{
2864 struct ptksa_cache_entry *entry;
2865
2866 entry = ptksa_cache_get(hapd->ptksa, sta_addr, cipher);
2867 if (!entry) {
2868 wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR
2869 " not present in PTKSA cache", MAC2STR(sta_addr));
2870 return -1;
2871 }
2872
2873 if (os_memcmp(entry->own_addr, own_addr, ETH_ALEN) != 0) {
2874 wpa_printf(MSG_DEBUG,
2875 "PASN: own addr " MACSTR " and PTKSA entry own addr "
2876 MACSTR " differ",
2877 MAC2STR(own_addr), MAC2STR(entry->own_addr));
2878 return -1;
2879 }
2880
2881 wpa_printf(MSG_DEBUG, "PASN: " MACSTR " present in PTKSA cache",
2882 MAC2STR(sta_addr));
2883 hostapd_drv_set_secure_ranging_ctx(hapd, own_addr, sta_addr, cipher,
2884 entry->ptk.tk_len, entry->ptk.tk,
2885 entry->ptk.ltf_keyseed_len,
2886 entry->ptk.ltf_keyseed, 0);
2887
2888 return 0;
2889}
2890
2891
Hai Shalom60840252021-02-19 19:02:11 -08002892static int
2893pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta,
2894 const u8 *cached_pmk, size_t cached_pmk_len,
2895 struct wpa_pasn_params_data *pasn_data,
2896 struct wpabuf *wrapped_data,
2897 struct wpabuf *secret)
2898{
2899 static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'};
2900 u8 pmk[PMK_LEN_MAX];
2901 u8 pmk_len;
2902 int ret;
2903
2904 os_memset(pmk, 0, sizeof(pmk));
2905 pmk_len = 0;
2906
2907 if (!cached_pmk || !cached_pmk_len)
2908 wpa_printf(MSG_DEBUG, "PASN: No valid PMKSA entry");
2909
2910 if (sta->pasn->akmp == WPA_KEY_MGMT_PASN) {
2911 wpa_printf(MSG_DEBUG, "PASN: Using default PMK");
2912
2913 pmk_len = WPA_PASN_PMK_LEN;
2914 os_memcpy(pmk, pasn_default_pmk, sizeof(pasn_default_pmk));
2915 } else if (cached_pmk && cached_pmk_len) {
2916 wpa_printf(MSG_DEBUG, "PASN: Using PMKSA entry");
2917
2918 pmk_len = cached_pmk_len;
2919 os_memcpy(pmk, cached_pmk, cached_pmk_len);
2920 } else {
2921 switch (sta->pasn->akmp) {
2922#ifdef CONFIG_SAE
2923 case WPA_KEY_MGMT_SAE:
2924 if (sta->pasn->sae.state == SAE_COMMITTED) {
2925 pmk_len = PMK_LEN;
2926 os_memcpy(pmk, sta->pasn->sae.pmk, PMK_LEN);
2927 break;
2928 }
2929#endif /* CONFIG_SAE */
2930 /* fall through */
2931 default:
2932 /* TODO: Derive PMK based on wrapped data */
2933 wpa_printf(MSG_DEBUG,
2934 "PASN: Missing PMK derivation");
2935 return -1;
2936 }
2937 }
2938
2939 ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
2940 wpabuf_head(secret), wpabuf_len(secret),
2941 &sta->pasn->ptk, sta->pasn->akmp,
Hai Shaloma20dcd72022-02-04 13:43:00 -08002942 sta->pasn->cipher, sta->pasn->kdk_len);
Hai Shalom60840252021-02-19 19:02:11 -08002943 if (ret) {
2944 wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
2945 return -1;
2946 }
2947
Sunil Ravi89eba102022-09-13 21:04:37 -07002948 if (sta->pasn->secure_ltf) {
2949 ret = wpa_ltf_keyseed(&sta->pasn->ptk, sta->pasn->akmp,
2950 sta->pasn->cipher);
2951 if (ret) {
2952 wpa_printf(MSG_DEBUG,
2953 "PASN: Failed to derive LTF keyseed");
2954 return -1;
2955 }
2956 }
2957
Hai Shalom60840252021-02-19 19:02:11 -08002958 wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
2959 return 0;
2960}
2961
2962
Hai Shaloma20dcd72022-02-04 13:43:00 -08002963static void handle_auth_pasn_comeback(struct hostapd_data *hapd,
2964 struct sta_info *sta, u16 group)
2965{
2966 struct wpabuf *buf, *comeback;
2967 int ret;
2968
2969 wpa_printf(MSG_DEBUG,
2970 "PASN: Building comeback frame 2. Comeback after=%u",
2971 hapd->conf->pasn_comeback_after);
2972
2973 buf = wpabuf_alloc(1500);
2974 if (!buf)
2975 return;
2976
2977 wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
2978 sta->addr, 2,
2979 WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY);
2980
2981 /*
2982 * Do not include the group as a part of the token since it is not going
2983 * to be used.
2984 */
2985 comeback = auth_build_token_req(hapd, 0, sta->addr, 0);
2986 if (!comeback) {
2987 wpa_printf(MSG_DEBUG,
2988 "PASN: Failed sending auth with comeback");
2989 wpabuf_free(buf);
2990 return;
2991 }
2992
2993 wpa_pasn_add_parameter_ie(buf, group,
2994 WPA_PASN_WRAPPED_DATA_NO,
2995 NULL, 0, comeback,
2996 hapd->conf->pasn_comeback_after);
2997 wpabuf_free(comeback);
2998
2999 wpa_printf(MSG_DEBUG,
3000 "PASN: comeback: STA=" MACSTR, MAC2STR(sta->addr));
3001
3002 ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
3003 NULL, 0, 0);
3004 if (ret)
3005 wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2");
3006
3007 wpabuf_free(buf);
3008}
3009
3010
Hai Shalom60840252021-02-19 19:02:11 -08003011static int handle_auth_pasn_resp(struct hostapd_data *hapd,
3012 struct sta_info *sta,
3013 struct rsn_pmksa_cache_entry *pmksa,
3014 u16 status)
3015{
3016 struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
3017 u8 mic[WPA_PASN_MAX_MIC_LEN];
Hai Shaloma20dcd72022-02-04 13:43:00 -08003018 u8 mic_len;
Hai Shalom60840252021-02-19 19:02:11 -08003019 u8 *ptr;
3020 const u8 *frame, *data, *rsn_ie, *rsnxe_ie;
3021 u8 *data_buf = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003022 size_t rsn_ie_len, frame_len, data_len;
Hai Shalom60840252021-02-19 19:02:11 -08003023 int ret;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003024 const u8 *pmkid = NULL;
Hai Shalom60840252021-02-19 19:02:11 -08003025
3026 wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status);
3027
3028 buf = wpabuf_alloc(1500);
3029 if (!buf)
3030 goto fail;
3031
3032 wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
3033 sta->addr, 2, status);
3034
3035 if (status != WLAN_STATUS_SUCCESS)
3036 goto done;
3037
Hai Shaloma20dcd72022-02-04 13:43:00 -08003038 if (pmksa) {
3039 pmkid = pmksa->pmkid;
3040#ifdef CONFIG_SAE
3041 } else if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
3042 wpa_printf(MSG_DEBUG, "PASN: Use SAE PMKID");
3043 pmkid = sta->pasn->sae.pmkid;
3044#endif /* CONFIG_SAE */
3045#ifdef CONFIG_FILS
3046 } else if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
3047 sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
3048 wpa_printf(MSG_DEBUG, "PASN: Use FILS ERP PMKID");
3049 pmkid = sta->pasn->fils.erp_pmkid;
3050#endif /* CONFIG_FILS */
3051 }
3052
3053 if (wpa_pasn_add_rsne(buf, pmkid,
Hai Shalom60840252021-02-19 19:02:11 -08003054 sta->pasn->akmp, sta->pasn->cipher) < 0)
3055 goto fail;
3056
3057 /* No need to derive PMK if PMKSA is given */
3058 if (!pmksa)
3059 wrapped_data_buf = pasn_get_wrapped_data(hapd, sta);
3060 else
3061 sta->pasn->wrapped_data_format = WPA_PASN_WRAPPED_DATA_NO;
3062
3063 /* Get public key */
3064 pubkey = crypto_ecdh_get_pubkey(sta->pasn->ecdh, 0);
3065 pubkey = wpabuf_zeropad(pubkey,
3066 crypto_ecdh_prime_len(sta->pasn->ecdh));
3067 if (!pubkey) {
3068 wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey");
3069 goto fail;
3070 }
3071
3072 wpa_pasn_add_parameter_ie(buf, sta->pasn->group,
3073 sta->pasn->wrapped_data_format,
Hai Shaloma20dcd72022-02-04 13:43:00 -08003074 pubkey, true, NULL, 0);
Hai Shalom60840252021-02-19 19:02:11 -08003075
3076 if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
3077 goto fail;
3078
3079 wpabuf_free(wrapped_data_buf);
3080 wrapped_data_buf = NULL;
3081 wpabuf_free(pubkey);
3082 pubkey = NULL;
3083
3084 /* Add RSNXE if needed */
3085 rsnxe_ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
3086 if (rsnxe_ie)
3087 wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
3088
3089 /* Add the mic */
3090 mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
3091 wpabuf_put_u8(buf, WLAN_EID_MIC);
3092 wpabuf_put_u8(buf, mic_len);
3093 ptr = wpabuf_put(buf, mic_len);
3094
3095 os_memset(ptr, 0, mic_len);
3096
3097 frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
3098 frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
3099
3100 rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &rsn_ie_len);
3101 if (!rsn_ie || !rsn_ie_len)
3102 goto fail;
3103
3104 /*
3105 * Note: wpa_auth_get_wpa_ie() might return not only the RSNE but also
3106 * MDE, etc. Thus, do not use the returned length but instead use the
3107 * length specified in the IE header.
3108 */
3109 data_len = rsn_ie[1] + 2;
3110 if (rsnxe_ie) {
3111 data_buf = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2);
3112 if (!data_buf)
3113 goto fail;
3114
3115 os_memcpy(data_buf, rsn_ie, rsn_ie[1] + 2);
3116 os_memcpy(data_buf + rsn_ie[1] + 2, rsnxe_ie, rsnxe_ie[1] + 2);
3117 data_len += rsnxe_ie[1] + 2;
3118 data = data_buf;
3119 } else {
3120 data = rsn_ie;
3121 }
3122
3123 ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
3124 hapd->own_addr, sta->addr, data, data_len,
3125 frame, frame_len, mic);
3126 os_free(data_buf);
3127 if (ret) {
3128 wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation");
3129 goto fail;
3130 }
3131
Hai Shaloma20dcd72022-02-04 13:43:00 -08003132#ifdef CONFIG_TESTING_OPTIONS
3133 if (hapd->conf->pasn_corrupt_mic) {
3134 wpa_printf(MSG_DEBUG, "PASN: frame 2: Corrupt MIC");
3135 mic[0] = ~mic[0];
3136 }
3137#endif /* CONFIG_TESTING_OPTIONS */
3138
Hai Shalom60840252021-02-19 19:02:11 -08003139 os_memcpy(ptr, mic, mic_len);
3140
3141done:
3142 wpa_printf(MSG_DEBUG,
3143 "PASN: Building frame 2: success; resp STA=" MACSTR,
3144 MAC2STR(sta->addr));
3145
3146 ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
3147 NULL, 0, 0);
3148 if (ret)
3149 wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
3150
3151 wpabuf_free(buf);
3152 return ret;
3153fail:
3154 wpabuf_free(wrapped_data_buf);
3155 wpabuf_free(pubkey);
3156 wpabuf_free(buf);
3157 return -1;
3158}
3159
3160
3161static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
3162 const struct ieee80211_mgmt *mgmt, size_t len)
3163{
3164 struct ieee802_11_elems elems;
3165 struct wpa_ie_data rsn_data;
3166 struct wpa_pasn_params_data pasn_params;
3167 struct rsn_pmksa_cache_entry *pmksa = NULL;
3168 const u8 *cached_pmk = NULL;
3169 size_t cached_pmk_len = 0;
3170#ifdef CONFIG_IEEE80211R_AP
3171 u8 pmk_r1[PMK_LEN_MAX];
3172 size_t pmk_r1_len;
3173#endif /* CONFIG_IEEE80211R_AP */
3174 struct wpabuf *wrapped_data = NULL, *secret = NULL;
3175 const int *groups = hapd->conf->pasn_groups;
3176 static const int default_groups[] = { 19, 0 };
3177 u16 status = WLAN_STATUS_SUCCESS;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003178 int ret, inc_y;
Hai Shalom60840252021-02-19 19:02:11 -08003179 bool derive_keys;
3180 u32 i;
Sunil Ravia04bd252022-05-02 22:54:18 -07003181 bool derive_kdk;
Hai Shalom60840252021-02-19 19:02:11 -08003182
3183 if (!groups)
3184 groups = default_groups;
3185
3186 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
3187 len - offsetof(struct ieee80211_mgmt,
3188 u.auth.variable),
3189 &elems, 0) == ParseFailed) {
3190 wpa_printf(MSG_DEBUG,
3191 "PASN: Failed parsing Authentication frame");
3192 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3193 goto send_resp;
3194 }
3195
3196 ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
3197 &rsn_data);
3198 if (ret) {
3199 wpa_printf(MSG_DEBUG, "PASN: Failed parsing RNSE");
3200 status = WLAN_STATUS_INVALID_RSNIE;
3201 goto send_resp;
3202 }
3203
3204 ret = wpa_pasn_validate_rsne(&rsn_data);
3205 if (ret) {
3206 wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
3207 status = WLAN_STATUS_INVALID_RSNIE;
3208 goto send_resp;
3209 }
3210
3211 if (!(rsn_data.key_mgmt & hapd->conf->wpa_key_mgmt) ||
3212 !(rsn_data.pairwise_cipher & hapd->conf->rsn_pairwise)) {
3213 wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
3214 status = WLAN_STATUS_INVALID_RSNIE;
3215 goto send_resp;
3216 }
3217
3218 sta->pasn->akmp = rsn_data.key_mgmt;
3219 sta->pasn->cipher = rsn_data.pairwise_cipher;
3220
Sunil Ravi89eba102022-09-13 21:04:37 -07003221 derive_kdk = (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP) &&
Sunil Ravia04bd252022-05-02 22:54:18 -07003222 ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
3223 WLAN_RSNX_CAPAB_SECURE_LTF);
3224#ifdef CONFIG_TESTING_OPTIONS
3225 if (!derive_kdk)
3226 derive_kdk = hapd->conf->force_kdk_derivation;
3227#endif /* CONFIG_TESTING_OPTIONS */
3228 if (derive_kdk)
Hai Shaloma20dcd72022-02-04 13:43:00 -08003229 sta->pasn->kdk_len = WPA_KDK_MAX_LEN;
3230 else
3231 sta->pasn->kdk_len = 0;
3232 wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", sta->pasn->kdk_len);
3233
Sunil Ravi89eba102022-09-13 21:04:37 -07003234 if ((hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP) &&
3235 ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
3236 WLAN_RSNX_CAPAB_SECURE_LTF))
3237 sta->pasn->secure_ltf = true;
3238 else
3239 sta->pasn->secure_ltf = false;
3240
Hai Shalom60840252021-02-19 19:02:11 -08003241 if (!elems.pasn_params || !elems.pasn_params_len) {
3242 wpa_printf(MSG_DEBUG,
3243 "PASN: No PASN Parameters element found");
3244 status = WLAN_STATUS_INVALID_PARAMETERS;
3245 goto send_resp;
3246 }
3247
3248 ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
3249 elems.pasn_params_len + 3,
3250 false, &pasn_params);
3251 if (ret) {
3252 wpa_printf(MSG_DEBUG,
3253 "PASN: Failed validation of PASN Parameters IE");
3254 status = WLAN_STATUS_INVALID_PARAMETERS;
3255 goto send_resp;
3256 }
3257
3258 for (i = 0; groups[i] > 0 && groups[i] != pasn_params.group; i++)
3259 ;
3260
3261 if (!pasn_params.group || groups[i] != pasn_params.group) {
3262 wpa_printf(MSG_DEBUG, "PASN: Requested group=%hu not allowed",
3263 pasn_params.group);
3264 status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
3265 goto send_resp;
3266 }
3267
3268 if (!pasn_params.pubkey || !pasn_params.pubkey_len) {
3269 wpa_printf(MSG_DEBUG, "PASN: Invalid public key");
3270 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3271 goto send_resp;
3272 }
3273
Hai Shaloma20dcd72022-02-04 13:43:00 -08003274 if (pasn_params.comeback) {
3275 wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token");
3276
3277 ret = check_comeback_token(hapd, sta->addr,
3278 pasn_params.comeback,
3279 pasn_params.comeback_len);
3280
3281 if (ret) {
3282 wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token");
3283 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3284 goto send_resp;
3285 }
3286 } else if (use_anti_clogging(hapd)) {
3287 wpa_printf(MSG_DEBUG, "PASN: Respond with comeback");
3288 handle_auth_pasn_comeback(hapd, sta, pasn_params.group);
3289 ap_free_sta(hapd, sta);
3290 return;
3291 }
3292
Hai Shalom60840252021-02-19 19:02:11 -08003293 sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group);
3294 if (!sta->pasn->ecdh) {
3295 wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
3296 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3297 goto send_resp;
3298 }
3299
3300 sta->pasn->group = pasn_params.group;
3301
Hai Shaloma20dcd72022-02-04 13:43:00 -08003302 if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) {
3303 inc_y = 1;
3304 } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 ||
3305 pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) {
3306 inc_y = 0;
3307 } else {
3308 wpa_printf(MSG_DEBUG,
3309 "PASN: Invalid first octet in pubkey=0x%x",
3310 pasn_params.pubkey[0]);
3311 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3312 goto send_resp;
3313 }
3314
3315 secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, inc_y,
3316 pasn_params.pubkey + 1,
3317 pasn_params.pubkey_len - 1);
Hai Shalom60840252021-02-19 19:02:11 -08003318 if (!secret) {
3319 wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
3320 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3321 goto send_resp;
3322 }
3323
3324 derive_keys = true;
3325 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
3326 wrapped_data = ieee802_11_defrag(&elems,
3327 WLAN_EID_EXTENSION,
3328 WLAN_EID_EXT_WRAPPED_DATA);
3329 if (!wrapped_data) {
3330 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
3331 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3332 goto send_resp;
3333 }
3334
3335#ifdef CONFIG_SAE
3336 if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
3337 ret = pasn_wd_handle_sae_commit(hapd, sta,
3338 wrapped_data);
3339 if (ret) {
3340 wpa_printf(MSG_DEBUG,
3341 "PASN: Failed processing SAE commit");
3342 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3343 goto send_resp;
3344 }
3345 }
3346#endif /* CONFIG_SAE */
3347#ifdef CONFIG_FILS
3348 if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
3349 sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
3350 ret = pasn_wd_handle_fils(hapd, sta, wrapped_data);
3351 if (ret) {
3352 wpa_printf(MSG_DEBUG,
3353 "PASN: Failed processing FILS wrapped data");
3354 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3355 goto send_resp;
3356 }
3357
3358 wpa_printf(MSG_DEBUG,
3359 "PASN: FILS: Pending AS response");
3360
3361 /*
3362 * With PASN/FILS, keys can be derived only after a
3363 * response from the AS is processed.
3364 */
3365 derive_keys = false;
3366 }
3367#endif /* CONFIG_FILS */
3368 }
3369
3370 sta->pasn->wrapped_data_format = pasn_params.wrapped_data_format;
3371
3372 ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
3373 ((const u8 *) mgmt) + IEEE80211_HDRLEN,
3374 len - IEEE80211_HDRLEN, sta->pasn->hash);
3375 if (ret) {
3376 wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
3377 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3378 goto send_resp;
3379 }
3380
3381 if (!derive_keys) {
3382 wpa_printf(MSG_DEBUG, "PASN: Storing secret");
3383 sta->pasn->secret = secret;
3384 wpabuf_free(wrapped_data);
3385 return;
3386 }
3387
3388 if (rsn_data.num_pmkid) {
3389 if (wpa_key_mgmt_ft(sta->pasn->akmp)) {
3390#ifdef CONFIG_IEEE80211R_AP
3391 wpa_printf(MSG_DEBUG, "PASN: FT: Fetch PMK-R1");
3392
3393 ret = wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
3394 rsn_data.pmkid,
3395 pmk_r1, &pmk_r1_len, NULL,
3396 NULL, NULL, NULL,
3397 NULL, NULL, NULL);
3398 if (ret) {
3399 wpa_printf(MSG_DEBUG,
3400 "PASN: FT: Failed getting PMK-R1");
3401 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3402 goto send_resp;
3403 }
3404 cached_pmk = pmk_r1;
3405 cached_pmk_len = pmk_r1_len;
3406#else /* CONFIG_IEEE80211R_AP */
3407 wpa_printf(MSG_DEBUG, "PASN: FT: Not supported");
3408 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3409 goto send_resp;
3410#endif /* CONFIG_IEEE80211R_AP */
3411 } else {
3412 wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry");
3413
3414 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
3415 rsn_data.pmkid);
3416 if (pmksa) {
3417 cached_pmk = pmksa->pmk;
3418 cached_pmk_len = pmksa->pmk_len;
3419 }
3420 }
3421 } else {
3422 wpa_printf(MSG_DEBUG, "PASN: No PMKID specified");
3423 }
3424
3425 ret = pasn_derive_keys(hapd, sta, cached_pmk, cached_pmk_len,
3426 &pasn_params, wrapped_data, secret);
3427 if (ret) {
3428 wpa_printf(MSG_DEBUG, "PASN: Failed to derive keys");
3429 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3430 goto send_resp;
3431 }
3432
3433 ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
3434 ((const u8 *) mgmt) + IEEE80211_HDRLEN,
3435 len - IEEE80211_HDRLEN, sta->pasn->hash);
3436 if (ret) {
3437 wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
3438 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3439 }
3440
3441send_resp:
3442 ret = handle_auth_pasn_resp(hapd, sta, pmksa, status);
3443 if (ret) {
3444 wpa_printf(MSG_DEBUG, "PASN: Failed to send response");
3445 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3446 } else {
3447 wpa_printf(MSG_DEBUG,
3448 "PASN: Success handling transaction == 1");
3449 }
3450
3451 wpabuf_free(secret);
3452 wpabuf_free(wrapped_data);
3453
3454 if (status != WLAN_STATUS_SUCCESS)
3455 ap_free_sta(hapd, sta);
3456}
3457
3458
3459static void handle_auth_pasn_3(struct hostapd_data *hapd, struct sta_info *sta,
3460 const struct ieee80211_mgmt *mgmt, size_t len)
3461{
3462 struct ieee802_11_elems elems;
3463 struct wpa_pasn_params_data pasn_params;
3464 struct wpabuf *wrapped_data = NULL;
3465 u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
3466 u8 mic_len;
3467 int ret;
3468
3469 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
3470 len - offsetof(struct ieee80211_mgmt,
3471 u.auth.variable),
3472 &elems, 0) == ParseFailed) {
3473 wpa_printf(MSG_DEBUG,
3474 "PASN: Failed parsing Authentication frame");
3475 goto fail;
3476 }
3477
3478 /* Check that the MIC IE exists. Save it and zero out the memory. */
3479 mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
3480 if (!elems.mic || elems.mic_len != mic_len) {
3481 wpa_printf(MSG_DEBUG,
3482 "PASN: Invalid MIC. Expecting len=%u", mic_len);
3483 goto fail;
3484 } else {
3485 os_memcpy(mic, elems.mic, mic_len);
3486 /* TODO: Clean this up.. Should not modify received frame
3487 * buffer. */
3488 os_memset((u8 *) elems.mic, 0, mic_len);
3489 }
3490
3491 if (!elems.pasn_params || !elems.pasn_params_len) {
3492 wpa_printf(MSG_DEBUG,
3493 "PASN: No PASN Parameters element found");
3494 goto fail;
3495 }
3496
3497 ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
3498 elems.pasn_params_len + 3,
3499 false, &pasn_params);
3500 if (ret) {
3501 wpa_printf(MSG_DEBUG,
3502 "PASN: Failed validation of PASN Parameters IE");
3503 goto fail;
3504 }
3505
3506 if (pasn_params.pubkey || pasn_params.pubkey_len) {
3507 wpa_printf(MSG_DEBUG,
3508 "PASN: Public key should not be included");
3509 goto fail;
3510 }
3511
3512 /* Verify the MIC */
3513 ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
3514 sta->addr, hapd->own_addr,
3515 sta->pasn->hash, mic_len * 2,
3516 (u8 *) &mgmt->u.auth,
3517 len - offsetof(struct ieee80211_mgmt, u.auth),
3518 out_mic);
3519
3520 wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len);
3521 if (ret || os_memcmp(mic, out_mic, mic_len) != 0) {
3522 wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification");
3523 goto fail;
3524 }
3525
3526 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
3527 wrapped_data = ieee802_11_defrag(&elems,
3528 WLAN_EID_EXTENSION,
3529 WLAN_EID_EXT_WRAPPED_DATA);
3530
3531 if (!wrapped_data) {
3532 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
3533 goto fail;
3534 }
3535
3536#ifdef CONFIG_SAE
3537 if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
3538 ret = pasn_wd_handle_sae_confirm(hapd, sta,
3539 wrapped_data);
3540 if (ret) {
3541 wpa_printf(MSG_DEBUG,
3542 "PASN: Failed processing SAE confirm");
3543 wpabuf_free(wrapped_data);
3544 goto fail;
3545 }
3546 }
3547#endif /* CONFIG_SAE */
3548#ifdef CONFIG_FILS
3549 if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
3550 sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
3551 if (wrapped_data) {
3552 wpa_printf(MSG_DEBUG,
3553 "PASN: FILS: Ignore wrapped data");
3554 }
3555 }
3556#endif /* CONFIG_FILS */
3557 wpabuf_free(wrapped_data);
3558 }
3559
3560 wpa_printf(MSG_INFO,
3561 "PASN: Success handling transaction == 3. Store PTK");
3562
Sunil Ravi89eba102022-09-13 21:04:37 -07003563 ptksa_cache_add(hapd->ptksa, hapd->own_addr, sta->addr,
3564 sta->pasn->cipher, 43200, &sta->pasn->ptk, NULL, NULL);
3565 pasn_set_keys_from_cache(hapd, hapd->own_addr, sta->addr,
3566 sta->pasn->cipher, sta->pasn->akmp);
Hai Shalom60840252021-02-19 19:02:11 -08003567fail:
3568 ap_free_sta(hapd, sta);
3569}
3570
3571
3572static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
3573 const struct ieee80211_mgmt *mgmt, size_t len,
3574 u16 trans_seq, u16 status)
3575{
3576 if (hapd->conf->wpa != WPA_PROTO_RSN) {
3577 wpa_printf(MSG_INFO, "PASN: RSN is not configured");
3578 return;
3579 }
3580
3581 wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR,
3582 MAC2STR(sta->addr));
3583
3584 if (trans_seq == 1) {
3585 if (sta->pasn) {
3586 wpa_printf(MSG_DEBUG,
3587 "PASN: Not expecting transaction == 1");
3588 return;
3589 }
3590
3591 if (status != WLAN_STATUS_SUCCESS) {
3592 wpa_printf(MSG_DEBUG,
3593 "PASN: Failure status in transaction == 1");
3594 return;
3595 }
3596
3597 sta->pasn = os_zalloc(sizeof(*sta->pasn));
3598 if (!sta->pasn) {
3599 wpa_printf(MSG_DEBUG,
3600 "PASN: Failed to allocate PASN context");
3601 return;
3602 }
3603
3604 handle_auth_pasn_1(hapd, sta, mgmt, len);
3605 } else if (trans_seq == 3) {
3606 if (!sta->pasn) {
3607 wpa_printf(MSG_DEBUG,
3608 "PASN: Not expecting transaction == 3");
3609 return;
3610 }
3611
3612 if (status != WLAN_STATUS_SUCCESS) {
3613 wpa_printf(MSG_DEBUG,
3614 "PASN: Failure status in transaction == 3");
3615 ap_free_sta_pasn(hapd, sta);
3616 return;
3617 }
3618
3619 handle_auth_pasn_3(hapd, sta, mgmt, len);
3620 } else {
3621 wpa_printf(MSG_DEBUG,
3622 "PASN: Invalid transaction %u - ignore", trans_seq);
3623 }
3624}
3625
3626#endif /* CONFIG_PASN */
3627
3628
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003629static void handle_auth(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08003630 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom021b0b52019-04-10 11:17:58 -07003631 int rssi, int from_queue)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003632{
3633 u16 auth_alg, auth_transaction, status_code;
3634 u16 resp = WLAN_STATUS_SUCCESS;
3635 struct sta_info *sta = NULL;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003636 int res, reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003637 u16 fc;
3638 const u8 *challenge = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003639 u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
3640 size_t resp_ies_len = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003641 u16 seq_ctrl;
Hai Shalomfdcde762020-04-02 11:19:20 -07003642 struct radius_sta rad_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003643
3644 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003645 wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
3646 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003647 return;
3648 }
3649
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003650#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07003651 if (hapd->iconf->ignore_auth_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003652 drand48() < hapd->iconf->ignore_auth_probability) {
3653 wpa_printf(MSG_INFO,
3654 "TESTING: ignoring auth frame from " MACSTR,
3655 MAC2STR(mgmt->sa));
3656 return;
3657 }
3658#endif /* CONFIG_TESTING_OPTIONS */
3659
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003660 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
3661 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
3662 status_code = le_to_host16(mgmt->u.auth.status_code);
3663 fc = le_to_host16(mgmt->frame_control);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003664 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003665
3666 if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
3667 2 + WLAN_AUTH_CHALLENGE_LEN &&
3668 mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
3669 mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
3670 challenge = &mgmt->u.auth.variable[2];
3671
3672 wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003673 "auth_transaction=%d status_code=%d wep=%d%s "
Hai Shalom021b0b52019-04-10 11:17:58 -07003674 "seq_ctrl=0x%x%s%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003675 MAC2STR(mgmt->sa), auth_alg, auth_transaction,
3676 status_code, !!(fc & WLAN_FC_ISWEP),
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003677 challenge ? " challenge" : "",
Hai Shalom021b0b52019-04-10 11:17:58 -07003678 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
3679 from_queue ? " (from queue)" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003680
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003681#ifdef CONFIG_NO_RC4
3682 if (auth_alg == WLAN_AUTH_SHARED_KEY) {
3683 wpa_printf(MSG_INFO,
3684 "Unsupported authentication algorithm (%d)",
3685 auth_alg);
3686 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
3687 goto fail;
3688 }
3689#endif /* CONFIG_NO_RC4 */
3690
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003691 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003692 wpa_printf(MSG_DEBUG,
3693 "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
3694 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003695 goto fail;
3696 }
3697
3698 if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
3699 auth_alg == WLAN_AUTH_OPEN) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003700#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003701 (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003702 auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003703#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003704#ifdef CONFIG_SAE
3705 (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
3706 auth_alg == WLAN_AUTH_SAE) ||
3707#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003708#ifdef CONFIG_FILS
3709 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
3710 auth_alg == WLAN_AUTH_FILS_SK) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003711 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
3712 hapd->conf->fils_dh_group &&
3713 auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003714#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08003715#ifdef CONFIG_PASN
3716 (hapd->conf->wpa &&
3717 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) &&
3718 auth_alg == WLAN_AUTH_PASN) ||
3719#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003720 ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
3721 auth_alg == WLAN_AUTH_SHARED_KEY))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003722 wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
3723 auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003724 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
3725 goto fail;
3726 }
3727
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003728 if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
Hai Shalom60840252021-02-19 19:02:11 -08003729#ifdef CONFIG_PASN
3730 (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) ||
3731#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003732 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003733 wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
3734 auth_transaction);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003735 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
3736 goto fail;
3737 }
3738
3739 if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003740 wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
3741 MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003742 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3743 goto fail;
3744 }
3745
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003746 if (hapd->conf->no_auth_if_seen_on) {
3747 struct hostapd_data *other;
3748
3749 other = sta_track_seen_on(hapd->iface, mgmt->sa,
3750 hapd->conf->no_auth_if_seen_on);
3751 if (other) {
3752 u8 *pos;
3753 u32 info;
3754 u8 op_class, channel, phytype;
3755
3756 wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
3757 MACSTR " since STA has been seen on %s",
3758 hapd->conf->iface, MAC2STR(mgmt->sa),
3759 hapd->conf->no_auth_if_seen_on);
3760
3761 resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
3762 pos = &resp_ies[0];
3763 *pos++ = WLAN_EID_NEIGHBOR_REPORT;
3764 *pos++ = 13;
3765 os_memcpy(pos, other->own_addr, ETH_ALEN);
3766 pos += ETH_ALEN;
3767 info = 0; /* TODO: BSSID Information */
3768 WPA_PUT_LE32(pos, info);
3769 pos += 4;
3770 if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
3771 phytype = 8; /* dmg */
3772 else if (other->iconf->ieee80211ac)
3773 phytype = 9; /* vht */
3774 else if (other->iconf->ieee80211n)
3775 phytype = 7; /* ht */
3776 else if (other->iconf->hw_mode ==
3777 HOSTAPD_MODE_IEEE80211A)
3778 phytype = 4; /* ofdm */
3779 else if (other->iconf->hw_mode ==
3780 HOSTAPD_MODE_IEEE80211G)
3781 phytype = 6; /* erp */
3782 else
3783 phytype = 5; /* hrdsss */
3784 if (ieee80211_freq_to_channel_ext(
3785 hostapd_hw_get_freq(other,
3786 other->iconf->channel),
3787 other->iconf->secondary_channel,
3788 other->iconf->ieee80211ac,
3789 &op_class, &channel) == NUM_HOSTAPD_MODES) {
3790 op_class = 0;
3791 channel = other->iconf->channel;
3792 }
3793 *pos++ = op_class;
3794 *pos++ = channel;
3795 *pos++ = phytype;
3796 resp_ies_len = pos - &resp_ies[0];
3797 goto fail;
3798 }
3799 }
3800
Hai Shalomfdcde762020-04-02 11:19:20 -07003801 res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
3802 &rad_info);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003803 if (res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003804 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
3805 "Ignore Authentication frame from " MACSTR
3806 " due to ACL reject", MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003807 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3808 goto fail;
3809 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003810 if (res == HOSTAPD_ACL_PENDING)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003811 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003812
Hai Shalom021b0b52019-04-10 11:17:58 -07003813#ifdef CONFIG_SAE
3814 if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
3815 (auth_transaction == 1 ||
3816 (auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) {
3817 /* Handle SAE Authentication commit message through a queue to
3818 * provide more control for postponing the needed heavy
3819 * processing under a possible DoS attack scenario. In addition,
3820 * queue SAE Authentication confirm message if there happens to
3821 * be a queued commit message from the same peer. This is needed
3822 * to avoid reordering Authentication frames within the same
3823 * SAE exchange. */
3824 auth_sae_queue(hapd, mgmt, len, rssi);
3825 return;
3826 }
3827#endif /* CONFIG_SAE */
3828
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003829 sta = ap_get_sta(hapd, mgmt->sa);
3830 if (sta) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003831 sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
Hai Shalom74f70d42019-02-11 14:42:39 -08003832 sta->ft_over_ds = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003833 if ((fc & WLAN_FC_RETRY) &&
3834 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
3835 sta->last_seq_ctrl == seq_ctrl &&
3836 sta->last_subtype == WLAN_FC_STYPE_AUTH) {
3837 hostapd_logger(hapd, sta->addr,
3838 HOSTAPD_MODULE_IEEE80211,
3839 HOSTAPD_LEVEL_DEBUG,
3840 "Drop repeated authentication frame seq_ctrl=0x%x",
3841 seq_ctrl);
3842 return;
3843 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003844#ifdef CONFIG_MESH
3845 if ((hapd->conf->mesh & MESH_ENABLED) &&
3846 sta->plink_state == PLINK_BLOCKED) {
3847 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
3848 " is blocked - drop Authentication frame",
3849 MAC2STR(mgmt->sa));
3850 return;
3851 }
3852#endif /* CONFIG_MESH */
Hai Shalom60840252021-02-19 19:02:11 -08003853#ifdef CONFIG_PASN
3854 if (auth_alg == WLAN_AUTH_PASN &&
3855 (sta->flags & WLAN_STA_ASSOC)) {
3856 wpa_printf(MSG_DEBUG,
3857 "PASN: auth: Existing station: " MACSTR,
3858 MAC2STR(sta->addr));
3859 return;
3860 }
3861#endif /* CONFIG_PASN */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003862 } else {
3863#ifdef CONFIG_MESH
3864 if (hapd->conf->mesh & MESH_ENABLED) {
3865 /* if the mesh peer is not available, we don't do auth.
3866 */
3867 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003868 " not yet known - drop Authentication frame",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003869 MAC2STR(mgmt->sa));
3870 /*
3871 * Save a copy of the frame so that it can be processed
3872 * if a new peer entry is added shortly after this.
3873 */
3874 wpabuf_free(hapd->mesh_pending_auth);
3875 hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len);
3876 os_get_reltime(&hapd->mesh_pending_auth_time);
3877 return;
3878 }
3879#endif /* CONFIG_MESH */
3880
3881 sta = ap_sta_add(hapd, mgmt->sa);
3882 if (!sta) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003883 wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003884 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3885 goto fail;
3886 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003887 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003888 sta->last_seq_ctrl = seq_ctrl;
3889 sta->last_subtype = WLAN_FC_STYPE_AUTH;
Hai Shalom74f70d42019-02-11 14:42:39 -08003890#ifdef CONFIG_MBO
3891 sta->auth_rssi = rssi;
3892#endif /* CONFIG_MBO */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003893
Hai Shalomfdcde762020-04-02 11:19:20 -07003894 res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003895 if (res) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003896 wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003897 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3898 goto fail;
3899 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003900
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003901 sta->flags &= ~WLAN_STA_PREAUTH;
3902 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
3903
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003904 /*
3905 * If the driver supports full AP client state, add a station to the
3906 * driver before sending authentication reply to make sure the driver
3907 * has resources, and not to go through the entire authentication and
3908 * association handshake, and fail it at the end.
3909 *
3910 * If this is not the first transaction, in a multi-step authentication
3911 * algorithm, the station already exists in the driver
3912 * (sta->added_unassoc = 1) so skip it.
3913 *
3914 * In mesh mode, the station was already added to the driver when the
3915 * NEW_PEER_CANDIDATE event is received.
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003916 *
3917 * If PMF was negotiated for the existing association, skip this to
3918 * avoid dropping the STA entry and the associated keys. This is needed
3919 * to allow the original connection work until the attempt can complete
3920 * (re)association, so that unprotected Authentication frame cannot be
3921 * used to bypass PMF protection.
Hai Shalom60840252021-02-19 19:02:11 -08003922 *
3923 * PASN authentication does not require adding/removing station to the
3924 * driver so skip this flow in case of PASN authentication.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003925 */
3926 if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003927 (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003928 !(hapd->conf->mesh & MESH_ENABLED) &&
Hai Shalom60840252021-02-19 19:02:11 -08003929 !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) {
Hai Shalomb755a2a2020-04-23 21:49:02 -07003930 if (ap_sta_re_add(hapd, sta) < 0) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003931 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
3932 goto fail;
3933 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003934 }
3935
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003936 switch (auth_alg) {
3937 case WLAN_AUTH_OPEN:
3938 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3939 HOSTAPD_LEVEL_DEBUG,
3940 "authentication OK (open system)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003941 sta->flags |= WLAN_STA_AUTH;
3942 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
3943 sta->auth_alg = WLAN_AUTH_OPEN;
3944 mlme_authenticate_indication(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003945 break;
Hai Shalomfdcde762020-04-02 11:19:20 -07003946#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003947#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003948 case WLAN_AUTH_SHARED_KEY:
3949 resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
3950 fc & WLAN_FC_ISWEP);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003951 if (resp != 0)
3952 wpa_printf(MSG_DEBUG,
3953 "auth_shared_key() failed: status=%d", resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003954 sta->auth_alg = WLAN_AUTH_SHARED_KEY;
3955 mlme_authenticate_indication(hapd, sta);
3956 if (sta->challenge && auth_transaction == 1) {
3957 resp_ies[0] = WLAN_EID_CHALLENGE;
3958 resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
3959 os_memcpy(resp_ies + 2, sta->challenge,
3960 WLAN_AUTH_CHALLENGE_LEN);
3961 resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
3962 }
3963 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003964#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003965#endif /* CONFIG_WEP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003966#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003967 case WLAN_AUTH_FT:
3968 sta->auth_alg = WLAN_AUTH_FT;
3969 if (sta->wpa_sm == NULL)
3970 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003971 sta->addr, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003972 if (sta->wpa_sm == NULL) {
3973 wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
3974 "state machine");
3975 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3976 goto fail;
3977 }
3978 wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
3979 auth_transaction, mgmt->u.auth.variable,
3980 len - IEEE80211_HDRLEN -
3981 sizeof(mgmt->u.auth),
3982 handle_auth_ft_finish, hapd);
3983 /* handle_auth_ft_finish() callback will complete auth. */
3984 return;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003985#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003986#ifdef CONFIG_SAE
3987 case WLAN_AUTH_SAE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003988#ifdef CONFIG_MESH
3989 if (status_code == WLAN_STATUS_SUCCESS &&
3990 hapd->conf->mesh & MESH_ENABLED) {
3991 if (sta->wpa_sm == NULL)
3992 sta->wpa_sm =
3993 wpa_auth_sta_init(hapd->wpa_auth,
3994 sta->addr, NULL);
3995 if (sta->wpa_sm == NULL) {
3996 wpa_printf(MSG_DEBUG,
3997 "SAE: Failed to initialize WPA state machine");
3998 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
3999 goto fail;
4000 }
4001 }
4002#endif /* CONFIG_MESH */
4003 handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
4004 status_code);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004005 return;
4006#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004007#ifdef CONFIG_FILS
4008 case WLAN_AUTH_FILS_SK:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004009 case WLAN_AUTH_FILS_SK_PFS:
4010 handle_auth_fils(hapd, sta, mgmt->u.auth.variable,
4011 len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth),
4012 auth_alg, auth_transaction, status_code,
4013 handle_auth_fils_finish);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004014 return;
4015#endif /* CONFIG_FILS */
Hai Shalom60840252021-02-19 19:02:11 -08004016#ifdef CONFIG_PASN
4017 case WLAN_AUTH_PASN:
4018 handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction,
4019 status_code);
4020 return;
4021#endif /* CONFIG_PASN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004022 }
4023
4024 fail:
Hai Shalomfdcde762020-04-02 11:19:20 -07004025 reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg,
Hai Shaloma20dcd72022-02-04 13:43:00 -08004026 auth_alg == WLAN_AUTH_SAE ?
4027 auth_transaction : auth_transaction + 1,
4028 resp, resp_ies, resp_ies_len,
4029 "handle-auth");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004030
4031 if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
4032 reply_res != WLAN_STATUS_SUCCESS)) {
4033 hostapd_drv_sta_remove(hapd, sta->addr);
4034 sta->added_unassoc = 0;
4035 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004036}
4037
4038
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004039int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004040{
4041 int i, j = 32, aid;
4042
4043 /* get a unique AID */
4044 if (sta->aid > 0) {
4045 wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
4046 return 0;
4047 }
4048
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004049 if (TEST_FAIL())
4050 return -1;
4051
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004052 for (i = 0; i < AID_WORDS; i++) {
4053 if (hapd->sta_aid[i] == (u32) -1)
4054 continue;
4055 for (j = 0; j < 32; j++) {
4056 if (!(hapd->sta_aid[i] & BIT(j)))
4057 break;
4058 }
4059 if (j < 32)
4060 break;
4061 }
4062 if (j == 32)
4063 return -1;
4064 aid = i * 32 + j + 1;
4065 if (aid > 2007)
4066 return -1;
4067
4068 sta->aid = aid;
4069 hapd->sta_aid[i] |= BIT(j);
4070 wpa_printf(MSG_DEBUG, " new AID %d", sta->aid);
4071 return 0;
4072}
4073
4074
4075static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
4076 const u8 *ssid_ie, size_t ssid_ie_len)
4077{
4078 if (ssid_ie == NULL)
4079 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4080
4081 if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
4082 os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004083 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4084 HOSTAPD_LEVEL_INFO,
4085 "Station tried to associate with unknown SSID "
Dmitry Shmidt3c479372014-02-04 10:50:36 -08004086 "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004087 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4088 }
4089
4090 return WLAN_STATUS_SUCCESS;
4091}
4092
4093
4094static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
4095 const u8 *wmm_ie, size_t wmm_ie_len)
4096{
4097 sta->flags &= ~WLAN_STA_WMM;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004098 sta->qosinfo = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004099 if (wmm_ie && hapd->conf->wmm_enabled) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004100 struct wmm_information_element *wmm;
4101
4102 if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004103 hostapd_logger(hapd, sta->addr,
4104 HOSTAPD_MODULE_WPA,
4105 HOSTAPD_LEVEL_DEBUG,
4106 "invalid WMM element in association "
4107 "request");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004108 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4109 }
4110
4111 sta->flags |= WLAN_STA_WMM;
4112 wmm = (struct wmm_information_element *) wmm_ie;
4113 sta->qosinfo = wmm->qos_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004114 }
4115 return WLAN_STATUS_SUCCESS;
4116}
4117
Hai Shalom74f70d42019-02-11 14:42:39 -08004118static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
4119 const u8 *multi_ap_ie, size_t multi_ap_len)
4120{
4121 u8 multi_ap_value = 0;
4122
4123 sta->flags &= ~WLAN_STA_MULTI_AP;
4124
4125 if (!hapd->conf->multi_ap)
4126 return WLAN_STATUS_SUCCESS;
4127
4128 if (multi_ap_ie) {
4129 const u8 *multi_ap_subelem;
4130
4131 multi_ap_subelem = get_ie(multi_ap_ie + 4,
4132 multi_ap_len - 4,
4133 MULTI_AP_SUB_ELEM_TYPE);
4134 if (multi_ap_subelem && multi_ap_subelem[1] == 1) {
4135 multi_ap_value = multi_ap_subelem[2];
4136 } else {
4137 hostapd_logger(hapd, sta->addr,
4138 HOSTAPD_MODULE_IEEE80211,
4139 HOSTAPD_LEVEL_INFO,
4140 "Multi-AP IE has missing or invalid Multi-AP subelement");
4141 return WLAN_STATUS_INVALID_IE;
4142 }
4143 }
4144
Hai Shalom021b0b52019-04-10 11:17:58 -07004145 if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA)
4146 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4147 HOSTAPD_LEVEL_INFO,
4148 "Multi-AP IE with unexpected value 0x%02x",
4149 multi_ap_value);
Hai Shalom74f70d42019-02-11 14:42:39 -08004150
Hai Shalom021b0b52019-04-10 11:17:58 -07004151 if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) {
4152 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
4153 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08004154
Hai Shalom021b0b52019-04-10 11:17:58 -07004155 hostapd_logger(hapd, sta->addr,
4156 HOSTAPD_MODULE_IEEE80211,
4157 HOSTAPD_LEVEL_INFO,
4158 "Non-Multi-AP STA tries to associate with backhaul-only BSS");
4159 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
Hai Shalom74f70d42019-02-11 14:42:39 -08004160 }
4161
Hai Shalom021b0b52019-04-10 11:17:58 -07004162 if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
4163 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4164 HOSTAPD_LEVEL_DEBUG,
4165 "Backhaul STA tries to associate with fronthaul-only BSS");
4166
4167 sta->flags |= WLAN_STA_MULTI_AP;
4168 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08004169}
4170
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004171
4172static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
4173 struct ieee802_11_elems *elems)
4174{
Dmitry Shmidt29333592017-01-09 12:27:11 -08004175 /* Supported rates not used in IEEE 802.11ad/DMG */
4176 if (hapd->iface->current_mode &&
4177 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
4178 return WLAN_STATUS_SUCCESS;
4179
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004180 if (!elems->supp_rates) {
4181 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4182 HOSTAPD_LEVEL_DEBUG,
4183 "No supported rates element in AssocReq");
4184 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4185 }
4186
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004187 if (elems->supp_rates_len + elems->ext_supp_rates_len >
4188 sizeof(sta->supported_rates)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004189 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4190 HOSTAPD_LEVEL_DEBUG,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004191 "Invalid supported rates element length %d+%d",
4192 elems->supp_rates_len,
4193 elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004194 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4195 }
4196
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004197 sta->supported_rates_len = merge_byte_arrays(
4198 sta->supported_rates, sizeof(sta->supported_rates),
4199 elems->supp_rates, elems->supp_rates_len,
4200 elems->ext_supp_rates, elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004201
4202 return WLAN_STATUS_SUCCESS;
4203}
4204
4205
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004206#ifdef CONFIG_OWE
4207
4208static int owe_group_supported(struct hostapd_data *hapd, u16 group)
4209{
4210 int i;
4211 int *groups = hapd->conf->owe_groups;
4212
4213 if (group != 19 && group != 20 && group != 21)
4214 return 0;
4215
4216 if (!groups)
4217 return 1;
4218
4219 for (i = 0; groups[i] > 0; i++) {
4220 if (groups[i] == group)
4221 return 1;
4222 }
4223
4224 return 0;
4225}
4226
4227
4228static u16 owe_process_assoc_req(struct hostapd_data *hapd,
4229 struct sta_info *sta, const u8 *owe_dh,
4230 u8 owe_dh_len)
4231{
4232 struct wpabuf *secret, *pub, *hkey;
4233 int res;
4234 u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN];
4235 const char *info = "OWE Key Generation";
4236 const u8 *addr[2];
4237 size_t len[2];
4238 u16 group;
4239 size_t hash_len, prime_len;
4240
4241 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
4242 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
4243 return WLAN_STATUS_SUCCESS;
4244 }
4245
4246 group = WPA_GET_LE16(owe_dh);
4247 if (!owe_group_supported(hapd, group)) {
4248 wpa_printf(MSG_DEBUG, "OWE: Unsupported DH group %u", group);
4249 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
4250 }
4251 if (group == 19)
4252 prime_len = 32;
4253 else if (group == 20)
4254 prime_len = 48;
4255 else if (group == 21)
4256 prime_len = 66;
4257 else
4258 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
4259
Sunil Ravia04bd252022-05-02 22:54:18 -07004260 if (sta->owe_group == group && sta->owe_ecdh) {
4261 /* This is a workaround for mac80211 behavior of retransmitting
4262 * the Association Request frames multiple times if the link
4263 * layer retries (i.e., seq# remains same) fail. The mac80211
4264 * initiated retransmission will use a different seq# and as
4265 * such, will go through duplicate detection. If we were to
4266 * change our DH key for that attempt, there would be two
4267 * different DH shared secrets and the STA would likely select
4268 * the wrong one. */
4269 wpa_printf(MSG_DEBUG,
4270 "OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again");
4271 } else {
4272 crypto_ecdh_deinit(sta->owe_ecdh);
4273 sta->owe_ecdh = crypto_ecdh_init(group);
4274 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004275 if (!sta->owe_ecdh)
4276 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
4277 sta->owe_group = group;
4278
4279 secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2,
4280 owe_dh_len - 2);
4281 secret = wpabuf_zeropad(secret, prime_len);
4282 if (!secret) {
4283 wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
4284 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4285 }
4286 wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
4287
4288 /* prk = HKDF-extract(C | A | group, z) */
4289
4290 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
4291 if (!pub) {
4292 wpabuf_clear_free(secret);
4293 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4294 }
4295
4296 /* PMKID = Truncate-128(Hash(C | A)) */
4297 addr[0] = owe_dh + 2;
4298 len[0] = owe_dh_len - 2;
4299 addr[1] = wpabuf_head(pub);
4300 len[1] = wpabuf_len(pub);
4301 if (group == 19) {
4302 res = sha256_vector(2, addr, len, pmkid);
4303 hash_len = SHA256_MAC_LEN;
4304 } else if (group == 20) {
4305 res = sha384_vector(2, addr, len, pmkid);
4306 hash_len = SHA384_MAC_LEN;
4307 } else if (group == 21) {
4308 res = sha512_vector(2, addr, len, pmkid);
4309 hash_len = SHA512_MAC_LEN;
4310 } else {
4311 wpabuf_free(pub);
4312 wpabuf_clear_free(secret);
4313 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4314 }
4315 pub = wpabuf_zeropad(pub, prime_len);
4316 if (res < 0 || !pub) {
4317 wpabuf_free(pub);
4318 wpabuf_clear_free(secret);
4319 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4320 }
4321
4322 hkey = wpabuf_alloc(owe_dh_len - 2 + wpabuf_len(pub) + 2);
4323 if (!hkey) {
4324 wpabuf_free(pub);
4325 wpabuf_clear_free(secret);
4326 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4327 }
4328
4329 wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */
4330 wpabuf_put_buf(hkey, pub); /* A */
4331 wpabuf_free(pub);
4332 wpabuf_put_le16(hkey, group); /* group */
4333 if (group == 19)
4334 res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
4335 wpabuf_head(secret), wpabuf_len(secret), prk);
4336 else if (group == 20)
4337 res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey),
4338 wpabuf_head(secret), wpabuf_len(secret), prk);
4339 else if (group == 21)
4340 res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey),
4341 wpabuf_head(secret), wpabuf_len(secret), prk);
4342 wpabuf_clear_free(hkey);
4343 wpabuf_clear_free(secret);
4344 if (res < 0)
4345 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4346
4347 wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
4348
4349 /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
4350
4351 os_free(sta->owe_pmk);
4352 sta->owe_pmk = os_malloc(hash_len);
4353 if (!sta->owe_pmk) {
4354 os_memset(prk, 0, SHA512_MAC_LEN);
4355 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4356 }
4357
4358 if (group == 19)
4359 res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info,
4360 os_strlen(info), sta->owe_pmk, hash_len);
4361 else if (group == 20)
4362 res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info,
4363 os_strlen(info), sta->owe_pmk, hash_len);
4364 else if (group == 21)
4365 res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
4366 os_strlen(info), sta->owe_pmk, hash_len);
4367 os_memset(prk, 0, SHA512_MAC_LEN);
4368 if (res < 0) {
4369 os_free(sta->owe_pmk);
4370 sta->owe_pmk = NULL;
4371 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4372 }
4373 sta->owe_pmk_len = hash_len;
4374
4375 wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
4376 wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
4377 wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk,
4378 sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE);
4379
4380 return WLAN_STATUS_SUCCESS;
4381}
4382
Hai Shalom81f62d82019-07-22 12:10:00 -07004383
4384u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
4385 const u8 *rsn_ie, size_t rsn_ie_len,
4386 const u8 *owe_dh, size_t owe_dh_len)
4387{
4388 struct wpa_ie_data data;
4389 int res;
4390
4391 if (!rsn_ie || rsn_ie_len < 2) {
4392 wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
4393 MAC2STR(peer));
4394 return WLAN_STATUS_INVALID_IE;
4395 }
4396 rsn_ie -= 2;
4397 rsn_ie_len += 2;
4398
4399 res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
4400 if (res) {
4401 wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
4402 " (res=%d)", MAC2STR(peer), res);
4403 wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
4404 return wpa_res_to_status_code(res);
4405 }
4406 if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
4407 wpa_printf(MSG_DEBUG,
4408 "OWE: Unexpected key mgmt 0x%x from " MACSTR,
4409 (unsigned int) data.key_mgmt, MAC2STR(peer));
4410 return WLAN_STATUS_AKMP_NOT_VALID;
4411 }
4412 if (!owe_dh) {
4413 wpa_printf(MSG_DEBUG,
4414 "OWE: No Diffie-Hellman Parameter element from "
4415 MACSTR, MAC2STR(peer));
4416 return WLAN_STATUS_AKMP_NOT_VALID;
4417 }
4418
4419 return WLAN_STATUS_SUCCESS;
4420}
4421
4422
4423u16 owe_process_rsn_ie(struct hostapd_data *hapd,
4424 struct sta_info *sta,
4425 const u8 *rsn_ie, size_t rsn_ie_len,
4426 const u8 *owe_dh, size_t owe_dh_len)
4427{
4428 u16 status;
4429 u8 *owe_buf, ie[256 * 2];
4430 size_t ie_len = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07004431 enum wpa_validate_result res;
Hai Shalom81f62d82019-07-22 12:10:00 -07004432
4433 if (!rsn_ie || rsn_ie_len < 2) {
4434 wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
4435 status = WLAN_STATUS_INVALID_IE;
4436 goto end;
4437 }
4438
4439 if (!sta->wpa_sm)
4440 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
4441 NULL);
4442 if (!sta->wpa_sm) {
4443 wpa_printf(MSG_WARNING,
4444 "OWE: Failed to initialize WPA state machine");
4445 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4446 goto end;
4447 }
4448 rsn_ie -= 2;
4449 rsn_ie_len += 2;
4450 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
4451 hapd->iface->freq, rsn_ie, rsn_ie_len,
Hai Shalomc3565922019-10-28 11:58:20 -07004452 NULL, 0, NULL, 0, owe_dh, owe_dh_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07004453 status = wpa_res_to_status_code(res);
4454 if (status != WLAN_STATUS_SUCCESS)
4455 goto end;
4456 status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
4457 if (status != WLAN_STATUS_SUCCESS)
4458 goto end;
4459 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
4460 NULL, 0);
4461 if (!owe_buf) {
4462 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4463 goto end;
4464 }
4465
4466 if (sta->owe_ecdh) {
4467 struct wpabuf *pub;
4468
4469 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
4470 if (!pub) {
4471 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
4472 goto end;
4473 }
4474
4475 /* OWE Diffie-Hellman Parameter element */
4476 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
4477 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
4478 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
4479 */
4480 WPA_PUT_LE16(owe_buf, sta->owe_group);
4481 owe_buf += 2;
4482 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
4483 owe_buf += wpabuf_len(pub);
4484 wpabuf_free(pub);
4485 sta->external_dh_updated = 1;
4486 }
4487 ie_len = owe_buf - ie;
4488
4489end:
4490 wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
4491 MACSTR, status, (unsigned int) ie_len,
4492 MAC2STR(sta->addr));
4493 hostapd_drv_update_dh_ie(hapd, sta->addr, status,
4494 status == WLAN_STATUS_SUCCESS ? ie : NULL,
4495 ie_len);
4496
4497 return status;
4498}
4499
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004500#endif /* CONFIG_OWE */
4501
4502
Hai Shalom899fcc72020-10-19 14:38:18 -07004503static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
4504 int reassoc)
4505{
4506 if ((sta->flags &
4507 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
4508 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
4509 return false;
4510
4511 if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
4512 ap_check_sa_query_timeout(hapd, sta);
4513
4514 if (!sta->sa_query_timed_out &&
4515 (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
4516 /*
4517 * STA has already been associated with MFP and SA Query timeout
4518 * has not been reached. Reject the association attempt
4519 * temporarily and start SA Query, if one is not pending.
4520 */
4521 if (sta->sa_query_count == 0)
4522 ap_sta_start_sa_query(hapd, sta);
4523
4524 return true;
4525 }
4526
4527 return false;
4528}
4529
4530
Hai Shalomb755a2a2020-04-23 21:49:02 -07004531static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004532 const u8 *ies, size_t ies_len, int reassoc)
4533{
4534 struct ieee802_11_elems elems;
Hai Shalomb755a2a2020-04-23 21:49:02 -07004535 int resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004536 const u8 *wpa_ie;
4537 size_t wpa_ie_len;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004538 const u8 *p2p_dev_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004539
4540 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
4541 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4542 HOSTAPD_LEVEL_INFO, "Station sent an invalid "
4543 "association request");
4544 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4545 }
4546
4547 resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len);
4548 if (resp != WLAN_STATUS_SUCCESS)
4549 return resp;
4550 resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
4551 if (resp != WLAN_STATUS_SUCCESS)
4552 return resp;
Dmitry Shmidt051af732013-10-22 13:52:46 -07004553 resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len);
4554 if (resp != WLAN_STATUS_SUCCESS)
4555 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004556 resp = copy_supp_rates(hapd, sta, &elems);
4557 if (resp != WLAN_STATUS_SUCCESS)
4558 return resp;
Hai Shalom74f70d42019-02-11 14:42:39 -08004559
4560 resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len);
4561 if (resp != WLAN_STATUS_SUCCESS)
4562 return resp;
4563
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07004564 resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004565 if (resp != WLAN_STATUS_SUCCESS)
4566 return resp;
4567 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
4568 !(sta->flags & WLAN_STA_HT)) {
4569 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4570 HOSTAPD_LEVEL_INFO, "Station does not support "
4571 "mandatory HT PHY - reject association");
4572 return WLAN_STATUS_ASSOC_DENIED_NO_HT;
4573 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004574
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004575#ifdef CONFIG_IEEE80211AC
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004576 if (hapd->iconf->ieee80211ac) {
4577 resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities);
4578 if (resp != WLAN_STATUS_SUCCESS)
4579 return resp;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08004580
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004581 resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
4582 if (resp != WLAN_STATUS_SUCCESS)
4583 return resp;
4584 }
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08004585
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004586 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
4587 !(sta->flags & WLAN_STA_VHT)) {
4588 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4589 HOSTAPD_LEVEL_INFO, "Station does not support "
4590 "mandatory VHT PHY - reject association");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004591 return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004592 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08004593
4594 if (hapd->conf->vendor_vht && !elems.vht_capabilities) {
4595 resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht,
4596 elems.vendor_vht_len);
4597 if (resp != WLAN_STATUS_SUCCESS)
4598 return resp;
4599 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004600#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07004601#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08004602 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07004603 resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
4604 elems.he_capabilities,
4605 elems.he_capabilities_len);
4606 if (resp != WLAN_STATUS_SUCCESS)
4607 return resp;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004608 if (is_6ghz_op_class(hapd->iconf->op_class)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004609 if (!(sta->flags & WLAN_STA_HE)) {
4610 hostapd_logger(hapd, sta->addr,
4611 HOSTAPD_MODULE_IEEE80211,
4612 HOSTAPD_LEVEL_INFO,
4613 "Station does not support mandatory HE PHY - reject association");
4614 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
4615 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004616 resp = copy_sta_he_6ghz_capab(hapd, sta,
4617 elems.he_6ghz_band_cap);
4618 if (resp != WLAN_STATUS_SUCCESS)
4619 return resp;
4620 }
Hai Shalom81f62d82019-07-22 12:10:00 -07004621 }
4622#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07004623#ifdef CONFIG_IEEE80211BE
4624 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
4625 resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP,
4626 elems.he_capabilities,
4627 elems.he_capabilities_len,
4628 elems.eht_capabilities,
4629 elems.eht_capabilities_len);
4630 if (resp != WLAN_STATUS_SUCCESS)
4631 return resp;
4632 }
4633#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004634
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004635#ifdef CONFIG_P2P
4636 if (elems.p2p) {
4637 wpabuf_free(sta->p2p_ie);
4638 sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
4639 P2P_IE_VENDOR_TYPE);
4640 if (sta->p2p_ie)
4641 p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
4642 } else {
4643 wpabuf_free(sta->p2p_ie);
4644 sta->p2p_ie = NULL;
4645 }
4646#endif /* CONFIG_P2P */
4647
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004648 if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
4649 wpa_ie = elems.rsn_ie;
4650 wpa_ie_len = elems.rsn_ie_len;
4651 } else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
4652 elems.wpa_ie) {
4653 wpa_ie = elems.wpa_ie;
4654 wpa_ie_len = elems.wpa_ie_len;
4655 } else {
4656 wpa_ie = NULL;
4657 wpa_ie_len = 0;
4658 }
4659
4660#ifdef CONFIG_WPS
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004661 sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004662 if (hapd->conf->wps_state && elems.wps_ie) {
4663 wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
4664 "Request - assume WPS is used");
Hai Shalom899fcc72020-10-19 14:38:18 -07004665 if (check_sa_query(hapd, sta, reassoc))
4666 return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004667 sta->flags |= WLAN_STA_WPS;
4668 wpabuf_free(sta->wps_ie);
4669 sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
4670 WPS_IE_VENDOR_TYPE);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004671 if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
4672 wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
4673 sta->flags |= WLAN_STA_WPS2;
4674 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004675 wpa_ie = NULL;
4676 wpa_ie_len = 0;
4677 if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
4678 wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
4679 "(Re)Association Request - reject");
4680 return WLAN_STATUS_INVALID_IE;
4681 }
4682 } else if (hapd->conf->wps_state && wpa_ie == NULL) {
4683 wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
4684 "(Re)Association Request - possible WPS use");
4685 sta->flags |= WLAN_STA_MAYBE_WPS;
4686 } else
4687#endif /* CONFIG_WPS */
4688 if (hapd->conf->wpa && wpa_ie == NULL) {
4689 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4690 HOSTAPD_LEVEL_INFO,
4691 "No WPA/RSN IE in association request");
4692 return WLAN_STATUS_INVALID_IE;
4693 }
4694
4695 if (hapd->conf->wpa && wpa_ie) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004696 enum wpa_validate_result res;
4697
Sunil8cd6f4d2022-06-28 18:40:46 +00004698 if (check_sa_query(hapd, sta, reassoc))
4699 return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
4700
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004701 wpa_ie -= 2;
4702 wpa_ie_len += 2;
4703 if (sta->wpa_sm == NULL)
4704 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07004705 sta->addr,
4706 p2p_dev_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004707 if (sta->wpa_sm == NULL) {
4708 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
4709 "state machine");
4710 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4711 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004712 wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004713 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07004714 hapd->iface->freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004715 wpa_ie, wpa_ie_len,
Hai Shalomc3565922019-10-28 11:58:20 -07004716 elems.rsnxe ? elems.rsnxe - 2 : NULL,
4717 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004718 elems.mdie, elems.mdie_len,
4719 elems.owe_dh, elems.owe_dh_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004720 resp = wpa_res_to_status_code(res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004721 if (resp != WLAN_STATUS_SUCCESS)
4722 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004723
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004724 if (wpa_auth_uses_mfp(sta->wpa_sm))
4725 sta->flags |= WLAN_STA_MFP;
4726 else
4727 sta->flags &= ~WLAN_STA_MFP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004728
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004729#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004730 if (sta->auth_alg == WLAN_AUTH_FT) {
4731 if (!reassoc) {
4732 wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
4733 "to use association (not "
4734 "re-association) with FT auth_alg",
4735 MAC2STR(sta->addr));
4736 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4737 }
4738
4739 resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
4740 ies_len);
4741 if (resp != WLAN_STATUS_SUCCESS)
4742 return resp;
4743 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004744#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004745
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004746#ifdef CONFIG_SAE
Roshan Pius3a1667e2018-07-03 15:17:14 -07004747 if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
4748 sta->sae->state == SAE_ACCEPTED)
4749 wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
4750
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004751 if (wpa_auth_uses_sae(sta->wpa_sm) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004752 sta->auth_alg == WLAN_AUTH_OPEN) {
4753 struct rsn_pmksa_cache_entry *sa;
4754 sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
Sunil Ravi89eba102022-09-13 21:04:37 -07004755 if (!sa || !wpa_key_mgmt_sae(sa->akmp)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004756 wpa_printf(MSG_DEBUG,
4757 "SAE: No PMKSA cache entry found for "
4758 MACSTR, MAC2STR(sta->addr));
4759 return WLAN_STATUS_INVALID_PMKID;
4760 }
4761 wpa_printf(MSG_DEBUG, "SAE: " MACSTR
4762 " using PMKSA caching", MAC2STR(sta->addr));
4763 } else if (wpa_auth_uses_sae(sta->wpa_sm) &&
4764 sta->auth_alg != WLAN_AUTH_SAE &&
4765 !(sta->auth_alg == WLAN_AUTH_FT &&
4766 wpa_auth_uses_ft_sae(sta->wpa_sm))) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004767 wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
4768 "SAE AKM after non-SAE auth_alg %u",
4769 MAC2STR(sta->addr), sta->auth_alg);
4770 return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
4771 }
Hai Shalomc3565922019-10-28 11:58:20 -07004772
4773 if (hapd->conf->sae_pwe == 2 &&
4774 sta->auth_alg == WLAN_AUTH_SAE &&
Hai Shalom899fcc72020-10-19 14:38:18 -07004775 sta->sae && !sta->sae->h2e &&
Hai Shaloma20dcd72022-02-04 13:43:00 -08004776 ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
4777 WLAN_RSNX_CAPAB_SAE_H2E)) {
Hai Shalomc3565922019-10-28 11:58:20 -07004778 wpa_printf(MSG_INFO, "SAE: " MACSTR
4779 " indicates support for SAE H2E, but did not use it",
4780 MAC2STR(sta->addr));
4781 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4782 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004783#endif /* CONFIG_SAE */
4784
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004785#ifdef CONFIG_OWE
4786 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
4787 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
4788 elems.owe_dh) {
4789 resp = owe_process_assoc_req(hapd, sta, elems.owe_dh,
4790 elems.owe_dh_len);
4791 if (resp != WLAN_STATUS_SUCCESS)
4792 return resp;
4793 }
4794#endif /* CONFIG_OWE */
4795
Hai Shalom021b0b52019-04-10 11:17:58 -07004796#ifdef CONFIG_DPP2
4797 dpp_pfs_free(sta->dpp_pfs);
4798 sta->dpp_pfs = NULL;
4799
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004800 if (DPP_VERSION > 1 &&
4801 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07004802 hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
4803 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
4804 elems.owe_dh) {
4805 sta->dpp_pfs = dpp_pfs_init(
4806 wpabuf_head(hapd->conf->dpp_netaccesskey),
4807 wpabuf_len(hapd->conf->dpp_netaccesskey));
4808 if (!sta->dpp_pfs) {
4809 wpa_printf(MSG_DEBUG,
4810 "DPP: Could not initialize PFS");
4811 /* Try to continue without PFS */
4812 goto pfs_fail;
4813 }
4814
4815 if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
4816 elems.owe_dh_len) < 0) {
4817 dpp_pfs_free(sta->dpp_pfs);
4818 sta->dpp_pfs = NULL;
4819 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4820 }
4821 }
4822
4823 wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
4824 sta->dpp_pfs->secret : NULL);
4825 pfs_fail:
4826#endif /* CONFIG_DPP2 */
4827
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004828 if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004829 wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
4830 hostapd_logger(hapd, sta->addr,
4831 HOSTAPD_MODULE_IEEE80211,
4832 HOSTAPD_LEVEL_INFO,
4833 "Station tried to use TKIP with HT "
4834 "association");
4835 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
4836 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004837#ifdef CONFIG_HS20
4838 } else if (hapd->conf->osen) {
4839 if (elems.osen == NULL) {
4840 hostapd_logger(
4841 hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4842 HOSTAPD_LEVEL_INFO,
4843 "No HS 2.0 OSEN element in association request");
4844 return WLAN_STATUS_INVALID_IE;
4845 }
4846
4847 wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
4848 if (sta->wpa_sm == NULL)
4849 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
4850 sta->addr, NULL);
4851 if (sta->wpa_sm == NULL) {
4852 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
4853 "state machine");
4854 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4855 }
4856 if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
4857 elems.osen - 2, elems.osen_len + 2) < 0)
4858 return WLAN_STATUS_INVALID_IE;
4859#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004860 } else
4861 wpa_auth_sta_no_wpa(sta->wpa_sm);
4862
4863#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004864 p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
4865#endif /* CONFIG_P2P */
4866
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004867#ifdef CONFIG_HS20
4868 wpabuf_free(sta->hs20_ie);
4869 if (elems.hs20 && elems.hs20_len > 4) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004870 int release;
4871
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004872 sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
4873 elems.hs20_len - 4);
Hai Shalom74f70d42019-02-11 14:42:39 -08004874 release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
Hai Shalomc3565922019-10-28 11:58:20 -07004875 if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
4876 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004877 wpa_printf(MSG_DEBUG,
4878 "HS 2.0: PMF not negotiated by release %d station "
4879 MACSTR, release, MAC2STR(sta->addr));
4880 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
4881 }
4882 } else {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004883 sta->hs20_ie = NULL;
Hai Shalom74f70d42019-02-11 14:42:39 -08004884 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07004885
4886 wpabuf_free(sta->roaming_consortium);
4887 if (elems.roaming_cons_sel)
4888 sta->roaming_consortium = wpabuf_alloc_copy(
4889 elems.roaming_cons_sel + 4,
4890 elems.roaming_cons_sel_len - 4);
4891 else
4892 sta->roaming_consortium = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004893#endif /* CONFIG_HS20 */
4894
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004895#ifdef CONFIG_FST
4896 wpabuf_free(sta->mb_ies);
4897 if (hapd->iface->fst)
4898 sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
4899 else
4900 sta->mb_ies = NULL;
4901#endif /* CONFIG_FST */
4902
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004903#ifdef CONFIG_MBO
4904 mbo_ap_check_sta_assoc(hapd, sta, &elems);
4905
4906 if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
4907 elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
4908 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
4909 wpa_printf(MSG_INFO,
4910 "MBO: Reject WPA2 association without PMF");
4911 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4912 }
4913#endif /* CONFIG_MBO */
4914
Hai Shalom74f70d42019-02-11 14:42:39 -08004915#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
4916 if (wpa_auth_uses_ocv(sta->wpa_sm) &&
4917 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4918 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4919 sta->auth_alg == WLAN_AUTH_FILS_PK)) {
4920 struct wpa_channel_info ci;
4921 int tx_chanwidth;
4922 int tx_seg1_idx;
Hai Shalom899fcc72020-10-19 14:38:18 -07004923 enum oci_verify_result res;
Hai Shalom74f70d42019-02-11 14:42:39 -08004924
4925 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
4926 wpa_printf(MSG_WARNING,
4927 "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
4928 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4929 }
4930
4931 if (get_sta_tx_parameters(sta->wpa_sm,
4932 channel_width_to_int(ci.chanwidth),
4933 ci.seg1_idx, &tx_chanwidth,
4934 &tx_seg1_idx) < 0)
4935 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4936
Hai Shalom899fcc72020-10-19 14:38:18 -07004937 res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
4938 tx_chanwidth, tx_seg1_idx);
4939 if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
4940 res == OCI_NOT_FOUND) {
4941 /* Work around misbehaving STAs */
4942 wpa_printf(MSG_INFO,
4943 "FILS: Disable OCV with a STA that does not send OCI");
4944 wpa_auth_set_ocv(sta->wpa_sm, 0);
4945 } else if (res != OCI_SUCCESS) {
4946 wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
4947 ocv_errorstr);
4948 wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
4949 MACSTR " frame=fils-reassoc-req error=%s",
4950 MAC2STR(sta->addr), ocv_errorstr);
Hai Shalom74f70d42019-02-11 14:42:39 -08004951 return WLAN_STATUS_UNSPECIFIED_FAILURE;
4952 }
4953 }
4954#endif /* CONFIG_FILS && CONFIG_OCV */
4955
Dmitry Shmidt9c175262016-03-03 10:20:07 -08004956 ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
4957 elems.supp_op_classes_len);
4958
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004959 if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
4960 elems.rrm_enabled &&
4961 elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
4962 os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
4963 sizeof(sta->rrm_enabled_capa));
4964
Roshan Pius3a1667e2018-07-03 15:17:14 -07004965 if (elems.power_capab) {
4966 sta->min_tx_power = elems.power_capab[0];
4967 sta->max_tx_power = elems.power_capab[1];
4968 sta->power_capab = 1;
4969 } else {
4970 sta->power_capab = 0;
4971 }
4972
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004973 return WLAN_STATUS_SUCCESS;
4974}
4975
4976
4977static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
4978 u16 reason_code)
4979{
4980 int send_len;
4981 struct ieee80211_mgmt reply;
4982
4983 os_memset(&reply, 0, sizeof(reply));
4984 reply.frame_control =
4985 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
4986 os_memcpy(reply.da, addr, ETH_ALEN);
4987 os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
4988 os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
4989
4990 send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
4991 reply.u.deauth.reason_code = host_to_le16(reason_code);
4992
Hai Shalomfdcde762020-04-02 11:19:20 -07004993 if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004994 wpa_printf(MSG_INFO, "Failed to send deauth: %s",
4995 strerror(errno));
4996}
4997
4998
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004999static int add_associated_sta(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08005000 struct sta_info *sta, int reassoc)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005001{
5002 struct ieee80211_ht_capabilities ht_cap;
5003 struct ieee80211_vht_capabilities vht_cap;
Hai Shalom81f62d82019-07-22 12:10:00 -07005004 struct ieee80211_he_capabilities he_cap;
Sunil Ravia04bd252022-05-02 22:54:18 -07005005 struct ieee80211_eht_capabilities eht_cap;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02005006 int set = 1;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005007
5008 /*
5009 * Remove the STA entry to ensure the STA PS state gets cleared and
5010 * configuration gets updated. This is relevant for cases, such as
5011 * FT-over-the-DS, where a station re-associates back to the same AP but
5012 * skips the authentication flow, or if working with a driver that
5013 * does not support full AP client state.
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02005014 *
5015 * Skip this if the STA has already completed FT reassociation and the
5016 * TK has been configured since the TX/RX PN must not be reset to 0 for
5017 * the same key.
Hai Shalom74f70d42019-02-11 14:42:39 -08005018 *
5019 * FT-over-the-DS has a special case where the STA entry (and as such,
5020 * the TK) has not yet been configured to the driver depending on which
5021 * driver interface is used. For that case, allow add-STA operation to
5022 * be used (instead of set-STA). This is needed to allow mac80211-based
5023 * drivers to accept the STA parameter configuration. Since this is
5024 * after a new FT-over-DS exchange, a new TK has been derived, so key
5025 * reinstallation is not a concern for this case.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005026 */
Hai Shalom74f70d42019-02-11 14:42:39 -08005027 wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
5028 " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
5029 MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
5030 sta->ft_over_ds, reassoc,
5031 !!(sta->flags & WLAN_STA_AUTHORIZED),
5032 wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
5033 wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
5034
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02005035 if (!sta->added_unassoc &&
5036 (!(sta->flags & WLAN_STA_AUTHORIZED) ||
Hai Shalom74f70d42019-02-11 14:42:39 -08005037 (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005038 (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
5039 !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005040 hostapd_drv_sta_remove(hapd, sta->addr);
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02005041 wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
5042 set = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08005043
5044 /* Do not allow the FT-over-DS exception to be used more than
5045 * once per authentication exchange to guarantee a new TK is
5046 * used here */
5047 sta->ft_over_ds = 0;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02005048 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005049
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005050 if (sta->flags & WLAN_STA_HT)
5051 hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005052#ifdef CONFIG_IEEE80211AC
5053 if (sta->flags & WLAN_STA_VHT)
5054 hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
5055#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07005056#ifdef CONFIG_IEEE80211AX
5057 if (sta->flags & WLAN_STA_HE) {
5058 hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
5059 sta->he_capab_len);
5060 }
5061#endif /* CONFIG_IEEE80211AX */
Sunil Ravia04bd252022-05-02 22:54:18 -07005062#ifdef CONFIG_IEEE80211BE
5063 if (sta->flags & WLAN_STA_EHT)
5064 hostapd_get_eht_capab(hapd, sta->eht_capab, &eht_cap,
5065 sta->eht_capab_len);
5066#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005067
5068 /*
5069 * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
5070 * will be set when the ACK frame for the (Re)Association Response frame
5071 * is processed (TX status driver event).
5072 */
5073 if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
5074 sta->supported_rates, sta->supported_rates_len,
5075 sta->listen_interval,
5076 sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
5077 sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
Hai Shalom81f62d82019-07-22 12:10:00 -07005078 sta->flags & WLAN_STA_HE ? &he_cap : NULL,
5079 sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
Sunil Ravia04bd252022-05-02 22:54:18 -07005080 sta->flags & WLAN_STA_EHT ? &eht_cap : NULL,
5081 sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005082 sta->he_6ghz_capab,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005083 sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005084 sta->vht_opmode, sta->p2p_ie ? 1 : 0,
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02005085 set)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005086 hostapd_logger(hapd, sta->addr,
5087 HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
5088 "Could not %s STA to kernel driver",
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02005089 set ? "set" : "add");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005090
5091 if (sta->added_unassoc) {
5092 hostapd_drv_sta_remove(hapd, sta->addr);
5093 sta->added_unassoc = 0;
5094 }
5095
5096 return -1;
5097 }
5098
5099 sta->added_unassoc = 0;
5100
5101 return 0;
5102}
5103
5104
5105static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt29333592017-01-09 12:27:11 -08005106 const u8 *addr, u16 status_code, int reassoc,
Hai Shalomfdcde762020-04-02 11:19:20 -07005107 const u8 *ies, size_t ies_len, int rssi,
5108 int omit_rsnxe)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005109{
5110 int send_len;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005111 u8 *buf;
5112 size_t buflen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005113 struct ieee80211_mgmt *reply;
5114 u8 *p;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005115 u16 res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005116
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005117 buflen = sizeof(struct ieee80211_mgmt) + 1024;
5118#ifdef CONFIG_FILS
5119 if (sta && sta->fils_hlp_resp)
5120 buflen += wpabuf_len(sta->fils_hlp_resp);
Hai Shalom81f62d82019-07-22 12:10:00 -07005121 if (sta)
5122 buflen += 150;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005123#endif /* CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005124#ifdef CONFIG_OWE
5125 if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
5126 buflen += 150;
5127#endif /* CONFIG_OWE */
Hai Shalom021b0b52019-04-10 11:17:58 -07005128#ifdef CONFIG_DPP2
5129 if (sta && sta->dpp_pfs)
5130 buflen += 5 + sta->dpp_pfs->curve->prime_len;
5131#endif /* CONFIG_DPP2 */
Sunil Ravia04bd252022-05-02 22:54:18 -07005132#ifdef CONFIG_IEEE80211BE
5133 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
5134 buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
5135 buflen += 3 + sizeof(struct ieee80211_eht_operation);
5136 }
5137#endif /* CONFIG_IEEE80211BE */
5138
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005139 buf = os_zalloc(buflen);
5140 if (!buf) {
5141 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5142 goto done;
5143 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005144 reply = (struct ieee80211_mgmt *) buf;
5145 reply->frame_control =
5146 IEEE80211_FC(WLAN_FC_TYPE_MGMT,
5147 (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
5148 WLAN_FC_STYPE_ASSOC_RESP));
Dmitry Shmidt29333592017-01-09 12:27:11 -08005149 os_memcpy(reply->da, addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005150 os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
5151 os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
5152
5153 send_len = IEEE80211_HDRLEN;
5154 send_len += sizeof(reply->u.assoc_resp);
5155 reply->u.assoc_resp.capab_info =
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07005156 host_to_le16(hostapd_own_capab_info(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005157 reply->u.assoc_resp.status_code = host_to_le16(status_code);
Dmitry Shmidt29333592017-01-09 12:27:11 -08005158
5159 reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
5160 BIT(14) | BIT(15));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005161 /* Supported rates */
5162 p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
5163 /* Extended supported rates */
5164 p = hostapd_eid_ext_supp_rates(hapd, p);
5165
Hai Shalomfdcde762020-04-02 11:19:20 -07005166 /* Radio measurement capabilities */
5167 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
5168
Hai Shalom74f70d42019-02-11 14:42:39 -08005169#ifdef CONFIG_MBO
5170 if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
5171 rssi != 0) {
5172 int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
5173
5174 p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
5175 delta);
5176 }
5177#endif /* CONFIG_MBO */
5178
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005179#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt29333592017-01-09 12:27:11 -08005180 if (sta && status_code == WLAN_STATUS_SUCCESS) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005181 /* IEEE 802.11r: Mobility Domain Information, Fast BSS
5182 * Transition Information, RSN, [RIC Response] */
5183 p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005184 buf + buflen - p,
Hai Shalomfdcde762020-04-02 11:19:20 -07005185 sta->auth_alg, ies, ies_len,
5186 omit_rsnxe);
Roshan Pius3a1667e2018-07-03 15:17:14 -07005187 if (!p) {
5188 wpa_printf(MSG_DEBUG,
5189 "FT: Failed to write AssocResp IEs");
5190 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5191 goto done;
5192 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005193 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005194#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom81f62d82019-07-22 12:10:00 -07005195#ifdef CONFIG_FILS
5196 if (sta && status_code == WLAN_STATUS_SUCCESS &&
5197 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5198 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5199 sta->auth_alg == WLAN_AUTH_FILS_PK))
5200 p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
5201 buf + buflen - p,
5202 ies, ies_len);
5203#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005204
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005205#ifdef CONFIG_OWE
Hai Shalom74f70d42019-02-11 14:42:39 -08005206 if (sta && status_code == WLAN_STATUS_SUCCESS &&
5207 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005208 p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
5209 buf + buflen - p,
5210 ies, ies_len);
5211#endif /* CONFIG_OWE */
5212
Dmitry Shmidt29333592017-01-09 12:27:11 -08005213 if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005214 p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005215
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005216 p = hostapd_eid_ht_capabilities(hapd, p);
5217 p = hostapd_eid_ht_operation(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005218
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005219#ifdef CONFIG_IEEE80211AC
Hai Shalomc3565922019-10-28 11:58:20 -07005220 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
5221 !is_6ghz_op_class(hapd->iconf->op_class)) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07005222 u32 nsts = 0, sta_nsts;
5223
Dmitry Shmidt29333592017-01-09 12:27:11 -08005224 if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07005225 struct ieee80211_vht_capabilities *capa;
5226
5227 nsts = (hapd->iface->conf->vht_capab >>
5228 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
5229 capa = sta->vht_capabilities;
5230 sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
5231 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
5232
5233 if (nsts < sta_nsts)
5234 nsts = 0;
5235 else
5236 nsts = sta_nsts;
5237 }
5238 p = hostapd_eid_vht_capabilities(hapd, p, nsts);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005239 p = hostapd_eid_vht_operation(hapd, p);
5240 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005241#endif /* CONFIG_IEEE80211AC */
5242
Hai Shalom81f62d82019-07-22 12:10:00 -07005243#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08005244 if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
Hai Shalom81f62d82019-07-22 12:10:00 -07005245 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
5246 p = hostapd_eid_he_operation(hapd, p);
Sunil Ravia04bd252022-05-02 22:54:18 -07005247 p = hostapd_eid_cca(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07005248 p = hostapd_eid_spatial_reuse(hapd, p);
5249 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005250 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07005251 }
5252#endif /* CONFIG_IEEE80211AX */
5253
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005254 p = hostapd_eid_ext_capab(hapd, p);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005255 p = hostapd_eid_bss_max_idle_period(hapd, p);
Dmitry Shmidt29333592017-01-09 12:27:11 -08005256 if (sta && sta->qos_map_enabled)
Dmitry Shmidt051af732013-10-22 13:52:46 -07005257 p = hostapd_eid_qos_map_set(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005258
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005259#ifdef CONFIG_FST
5260 if (hapd->iface->fst_ies) {
5261 os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
5262 wpabuf_len(hapd->iface->fst_ies));
5263 p += wpabuf_len(hapd->iface->fst_ies);
5264 }
5265#endif /* CONFIG_FST */
5266
Hai Shalomfdcde762020-04-02 11:19:20 -07005267#ifdef CONFIG_TESTING_OPTIONS
5268 if (hapd->conf->rsnxe_override_ft &&
5269 buf + buflen - p >=
5270 (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
5271 sta && sta->auth_alg == WLAN_AUTH_FT) {
5272 wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
5273 os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
5274 wpabuf_len(hapd->conf->rsnxe_override_ft));
5275 p += wpabuf_len(hapd->conf->rsnxe_override_ft);
5276 goto rsnxe_done;
5277 }
5278#endif /* CONFIG_TESTING_OPTIONS */
5279 if (!omit_rsnxe)
5280 p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
5281#ifdef CONFIG_TESTING_OPTIONS
5282rsnxe_done:
5283#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomc3565922019-10-28 11:58:20 -07005284
Sunil Ravia04bd252022-05-02 22:54:18 -07005285#ifdef CONFIG_IEEE80211BE
5286 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
5287 p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
5288 p = hostapd_eid_eht_operation(hapd, p);
5289 }
5290#endif /* CONFIG_IEEE80211BE */
5291
Hai Shalom021b0b52019-04-10 11:17:58 -07005292#ifdef CONFIG_OWE
5293 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
5294 sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
Hai Shalom899fcc72020-10-19 14:38:18 -07005295 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
5296 !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07005297 struct wpabuf *pub;
5298
5299 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
5300 if (!pub) {
5301 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5302 goto done;
5303 }
5304 /* OWE Diffie-Hellman Parameter element */
5305 *p++ = WLAN_EID_EXTENSION; /* Element ID */
5306 *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
5307 *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
5308 WPA_PUT_LE16(p, sta->owe_group);
5309 p += 2;
5310 os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
5311 p += wpabuf_len(pub);
5312 wpabuf_free(pub);
5313 }
5314#endif /* CONFIG_OWE */
5315
5316#ifdef CONFIG_DPP2
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005317 if (DPP_VERSION > 1 && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07005318 sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
5319 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
5320 os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
5321 wpabuf_len(sta->dpp_pfs->ie));
5322 p += wpabuf_len(sta->dpp_pfs->ie);
5323 }
5324#endif /* CONFIG_DPP2 */
5325
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005326#ifdef CONFIG_IEEE80211AC
Dmitry Shmidt29333592017-01-09 12:27:11 -08005327 if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005328 p = hostapd_eid_vendor_vht(hapd, p);
5329#endif /* CONFIG_IEEE80211AC */
5330
Dmitry Shmidt29333592017-01-09 12:27:11 -08005331 if (sta && (sta->flags & WLAN_STA_WMM))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005332 p = hostapd_eid_wmm(hapd, p);
5333
5334#ifdef CONFIG_WPS
Dmitry Shmidt29333592017-01-09 12:27:11 -08005335 if (sta &&
5336 ((sta->flags & WLAN_STA_WPS) ||
5337 ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005338 struct wpabuf *wps = wps_build_assoc_resp_ie();
5339 if (wps) {
5340 os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
5341 p += wpabuf_len(wps);
5342 wpabuf_free(wps);
5343 }
5344 }
5345#endif /* CONFIG_WPS */
5346
Hai Shalom74f70d42019-02-11 14:42:39 -08005347 if (sta && (sta->flags & WLAN_STA_MULTI_AP))
5348 p = hostapd_eid_multi_ap(hapd, p);
5349
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005350#ifdef CONFIG_P2P
Dmitry Shmidt29333592017-01-09 12:27:11 -08005351 if (sta && sta->p2p_ie && hapd->p2p_group) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005352 struct wpabuf *p2p_resp_ie;
5353 enum p2p_status_code status;
5354 switch (status_code) {
5355 case WLAN_STATUS_SUCCESS:
5356 status = P2P_SC_SUCCESS;
5357 break;
5358 case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
5359 status = P2P_SC_FAIL_LIMIT_REACHED;
5360 break;
5361 default:
5362 status = P2P_SC_FAIL_INVALID_PARAMS;
5363 break;
5364 }
5365 p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
5366 if (p2p_resp_ie) {
5367 os_memcpy(p, wpabuf_head(p2p_resp_ie),
5368 wpabuf_len(p2p_resp_ie));
5369 p += wpabuf_len(p2p_resp_ie);
5370 wpabuf_free(p2p_resp_ie);
5371 }
5372 }
5373#endif /* CONFIG_P2P */
5374
5375#ifdef CONFIG_P2P_MANAGER
5376 if (hapd->conf->p2p & P2P_MANAGE)
5377 p = hostapd_eid_p2p_manage(hapd, p);
5378#endif /* CONFIG_P2P_MANAGER */
5379
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005380 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005381
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005382 if (hapd->conf->assocresp_elements &&
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005383 (size_t) (buf + buflen - p) >=
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005384 wpabuf_len(hapd->conf->assocresp_elements)) {
5385 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
5386 wpabuf_len(hapd->conf->assocresp_elements));
5387 p += wpabuf_len(hapd->conf->assocresp_elements);
5388 }
5389
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005390 send_len += p - reply->u.assoc_resp.variable;
5391
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005392#ifdef CONFIG_FILS
Dmitry Shmidt29333592017-01-09 12:27:11 -08005393 if (sta &&
5394 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005395 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5396 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
5397 status_code == WLAN_STATUS_SUCCESS) {
5398 struct ieee802_11_elems elems;
5399
5400 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005401 ParseFailed || !elems.fils_session) {
5402 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5403 goto done;
5404 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005405
5406 /* FILS Session */
5407 *p++ = WLAN_EID_EXTENSION; /* Element ID */
5408 *p++ = 1 + FILS_SESSION_LEN; /* Length */
5409 *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
5410 os_memcpy(p, elems.fils_session, FILS_SESSION_LEN);
5411 send_len += 2 + 1 + FILS_SESSION_LEN;
5412
5413 send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005414 buflen, sta->fils_hlp_resp);
5415 if (send_len < 0) {
5416 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
5417 goto done;
5418 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005419 }
5420#endif /* CONFIG_FILS */
5421
Hai Shalomfdcde762020-04-02 11:19:20 -07005422 if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005423 wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
5424 strerror(errno));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005425 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005426 }
5427
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005428done:
5429 os_free(buf);
5430 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005431}
5432
5433
Roshan Pius3a1667e2018-07-03 15:17:14 -07005434#ifdef CONFIG_OWE
5435u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
5436 const u8 *owe_dh, u8 owe_dh_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07005437 u8 *owe_buf, size_t owe_buf_len, u16 *status)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005438{
5439#ifdef CONFIG_TESTING_OPTIONS
5440 if (hapd->conf->own_ie_override) {
5441 wpa_printf(MSG_DEBUG, "OWE: Using IE override");
Hai Shalomfdcde762020-04-02 11:19:20 -07005442 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005443 return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5444 owe_buf_len, NULL, 0);
5445 }
5446#endif /* CONFIG_TESTING_OPTIONS */
5447
5448 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
5449 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
5450 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5451 owe_buf_len, NULL, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -07005452 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005453 return owe_buf;
5454 }
5455
Hai Shalom81f62d82019-07-22 12:10:00 -07005456 if (sta->owe_pmk && sta->external_dh_updated) {
5457 wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
Hai Shalomfdcde762020-04-02 11:19:20 -07005458 *status = WLAN_STATUS_SUCCESS;
Hai Shalom81f62d82019-07-22 12:10:00 -07005459 return owe_buf;
5460 }
5461
Hai Shalomfdcde762020-04-02 11:19:20 -07005462 *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
5463 if (*status != WLAN_STATUS_SUCCESS)
Roshan Pius3a1667e2018-07-03 15:17:14 -07005464 return NULL;
5465
5466 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
5467 owe_buf_len, NULL, 0);
5468
5469 if (sta->owe_ecdh && owe_buf) {
5470 struct wpabuf *pub;
5471
5472 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
5473 if (!pub) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005474 *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005475 return owe_buf;
5476 }
5477
5478 /* OWE Diffie-Hellman Parameter element */
5479 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
5480 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
5481 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
5482 */
5483 WPA_PUT_LE16(owe_buf, sta->owe_group);
5484 owe_buf += 2;
5485 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
5486 owe_buf += wpabuf_len(pub);
5487 wpabuf_free(pub);
5488 }
5489
5490 return owe_buf;
5491}
5492#endif /* CONFIG_OWE */
5493
5494
Paul Stewart092955c2017-02-06 09:13:09 -08005495#ifdef CONFIG_FILS
5496
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005497void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
Paul Stewart092955c2017-02-06 09:13:09 -08005498{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005499 u16 reply_res;
Paul Stewart092955c2017-02-06 09:13:09 -08005500
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005501 wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
5502 MAC2STR(sta->addr));
5503 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5504 if (!sta->fils_pending_assoc_req)
Paul Stewart092955c2017-02-06 09:13:09 -08005505 return;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005506 reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
5507 sta->fils_pending_assoc_is_reassoc,
5508 sta->fils_pending_assoc_req,
Hai Shalomfdcde762020-04-02 11:19:20 -07005509 sta->fils_pending_assoc_req_len, 0, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005510 os_free(sta->fils_pending_assoc_req);
5511 sta->fils_pending_assoc_req = NULL;
5512 sta->fils_pending_assoc_req_len = 0;
5513 wpabuf_free(sta->fils_hlp_resp);
5514 sta->fils_hlp_resp = NULL;
5515 wpabuf_free(sta->hlp_dhcp_discover);
5516 sta->hlp_dhcp_discover = NULL;
Paul Stewart092955c2017-02-06 09:13:09 -08005517
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005518 /*
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005519 * Remove the station in case transmission of a success response fails.
5520 * At this point the station was already added associated to the driver.
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005521 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005522 if (reply_res != WLAN_STATUS_SUCCESS)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005523 hostapd_drv_sta_remove(hapd, sta->addr);
Paul Stewart092955c2017-02-06 09:13:09 -08005524}
5525
5526
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005527void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
Paul Stewart092955c2017-02-06 09:13:09 -08005528{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005529 struct hostapd_data *hapd = eloop_ctx;
5530 struct sta_info *sta = eloop_data;
Paul Stewart092955c2017-02-06 09:13:09 -08005531
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005532 wpa_printf(MSG_DEBUG,
5533 "FILS: HLP response timeout - continue with association response for "
5534 MACSTR, MAC2STR(sta->addr));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005535 if (sta->fils_drv_assoc_finish)
5536 hostapd_notify_assoc_fils_finish(hapd, sta);
5537 else
5538 fils_hlp_finish_assoc(hapd, sta);
Paul Stewart092955c2017-02-06 09:13:09 -08005539}
5540
5541#endif /* CONFIG_FILS */
5542
5543
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005544static void handle_assoc(struct hostapd_data *hapd,
5545 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom74f70d42019-02-11 14:42:39 -08005546 int reassoc, int rssi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005547{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005548 u16 capab_info, listen_interval, seq_ctrl, fc;
Hai Shalomb755a2a2020-04-23 21:49:02 -07005549 int resp = WLAN_STATUS_SUCCESS;
Hai Shalom899fcc72020-10-19 14:38:18 -07005550 u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005551 const u8 *pos;
5552 int left, i;
5553 struct sta_info *sta;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005554 u8 *tmp = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005555#ifdef CONFIG_FILS
5556 int delay_assoc = 0;
5557#endif /* CONFIG_FILS */
Hai Shalomfdcde762020-04-02 11:19:20 -07005558 int omit_rsnxe = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005559
5560 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
5561 sizeof(mgmt->u.assoc_req))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005562 wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
5563 reassoc, (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005564 return;
5565 }
5566
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005567#ifdef CONFIG_TESTING_OPTIONS
5568 if (reassoc) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005569 if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005570 drand48() < hapd->iconf->ignore_reassoc_probability) {
5571 wpa_printf(MSG_INFO,
5572 "TESTING: ignoring reassoc request from "
5573 MACSTR, MAC2STR(mgmt->sa));
5574 return;
5575 }
5576 } else {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005577 if (hapd->iconf->ignore_assoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005578 drand48() < hapd->iconf->ignore_assoc_probability) {
5579 wpa_printf(MSG_INFO,
5580 "TESTING: ignoring assoc request from "
5581 MACSTR, MAC2STR(mgmt->sa));
5582 return;
5583 }
5584 }
5585#endif /* CONFIG_TESTING_OPTIONS */
5586
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005587 fc = le_to_host16(mgmt->frame_control);
5588 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
5589
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005590 if (reassoc) {
5591 capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
5592 listen_interval = le_to_host16(
5593 mgmt->u.reassoc_req.listen_interval);
5594 wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
5595 " capab_info=0x%02x listen_interval=%d current_ap="
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005596 MACSTR " seq_ctrl=0x%x%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005597 MAC2STR(mgmt->sa), capab_info, listen_interval,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005598 MAC2STR(mgmt->u.reassoc_req.current_ap),
5599 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005600 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
5601 pos = mgmt->u.reassoc_req.variable;
5602 } else {
5603 capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
5604 listen_interval = le_to_host16(
5605 mgmt->u.assoc_req.listen_interval);
5606 wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005607 " capab_info=0x%02x listen_interval=%d "
5608 "seq_ctrl=0x%x%s",
5609 MAC2STR(mgmt->sa), capab_info, listen_interval,
5610 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005611 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
5612 pos = mgmt->u.assoc_req.variable;
5613 }
5614
5615 sta = ap_get_sta(hapd, mgmt->sa);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005616#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005617 if (sta && sta->auth_alg == WLAN_AUTH_FT &&
5618 (sta->flags & WLAN_STA_AUTH) == 0) {
5619 wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
5620 "prior to authentication since it is using "
5621 "over-the-DS FT", MAC2STR(mgmt->sa));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005622
5623 /*
5624 * Mark station as authenticated, to avoid adding station
5625 * entry in the driver as associated and not authenticated
5626 */
5627 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005628 } else
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005629#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005630 if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
Dmitry Shmidt29333592017-01-09 12:27:11 -08005631 if (hapd->iface->current_mode &&
5632 hapd->iface->current_mode->mode ==
5633 HOSTAPD_MODE_IEEE80211AD) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005634 int acl_res;
Hai Shalomfdcde762020-04-02 11:19:20 -07005635 struct radius_sta info;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005636
Hai Shalomfdcde762020-04-02 11:19:20 -07005637 acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
5638 (const u8 *) mgmt,
5639 len, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005640 if (acl_res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005641 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
5642 "Ignore Association Request frame from "
5643 MACSTR " due to ACL reject",
5644 MAC2STR(mgmt->sa));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005645 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5646 goto fail;
5647 }
5648 if (acl_res == HOSTAPD_ACL_PENDING)
5649 return;
5650
Dmitry Shmidt29333592017-01-09 12:27:11 -08005651 /* DMG/IEEE 802.11ad does not use authentication.
5652 * Allocate sta entry upon association. */
5653 sta = ap_sta_add(hapd, mgmt->sa);
5654 if (!sta) {
5655 hostapd_logger(hapd, mgmt->sa,
5656 HOSTAPD_MODULE_IEEE80211,
5657 HOSTAPD_LEVEL_INFO,
5658 "Failed to add STA");
5659 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5660 goto fail;
5661 }
5662
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005663 acl_res = ieee802_11_set_radius_info(
Hai Shalomfdcde762020-04-02 11:19:20 -07005664 hapd, sta, acl_res, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005665 if (acl_res) {
5666 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5667 goto fail;
5668 }
5669
Dmitry Shmidt29333592017-01-09 12:27:11 -08005670 hostapd_logger(hapd, sta->addr,
5671 HOSTAPD_MODULE_IEEE80211,
5672 HOSTAPD_LEVEL_DEBUG,
5673 "Skip authentication for DMG/IEEE 802.11ad");
5674 sta->flags |= WLAN_STA_AUTH;
5675 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
5676 sta->auth_alg = WLAN_AUTH_OPEN;
5677 } else {
5678 hostapd_logger(hapd, mgmt->sa,
5679 HOSTAPD_MODULE_IEEE80211,
5680 HOSTAPD_LEVEL_INFO,
5681 "Station tried to associate before authentication (aid=%d flags=0x%x)",
5682 sta ? sta->aid : -1,
5683 sta ? sta->flags : 0);
5684 send_deauth(hapd, mgmt->sa,
5685 WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
5686 return;
5687 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005688 }
5689
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005690 if ((fc & WLAN_FC_RETRY) &&
5691 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
5692 sta->last_seq_ctrl == seq_ctrl &&
Paul Stewart092955c2017-02-06 09:13:09 -08005693 sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5694 WLAN_FC_STYPE_ASSOC_REQ)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005695 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5696 HOSTAPD_LEVEL_DEBUG,
5697 "Drop repeated association frame seq_ctrl=0x%x",
5698 seq_ctrl);
5699 return;
5700 }
5701 sta->last_seq_ctrl = seq_ctrl;
5702 sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
5703 WLAN_FC_STYPE_ASSOC_REQ;
5704
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005705 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005706 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005707 goto fail;
5708 }
5709
5710 if (listen_interval > hapd->conf->max_listen_interval) {
5711 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5712 HOSTAPD_LEVEL_DEBUG,
5713 "Too large Listen Interval (%d)",
5714 listen_interval);
5715 resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
5716 goto fail;
5717 }
5718
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005719#ifdef CONFIG_MBO
5720 if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
5721 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5722 goto fail;
5723 }
Hai Shalom74f70d42019-02-11 14:42:39 -08005724
5725 if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
5726 rssi < hapd->iconf->rssi_reject_assoc_rssi &&
5727 (sta->auth_rssi == 0 ||
5728 sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
5729 resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
5730 goto fail;
5731 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005732#endif /* CONFIG_MBO */
5733
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005734 /*
5735 * sta->capability is used in check_assoc_ies() for RRM enabled
5736 * capability element.
5737 */
5738 sta->capability = capab_info;
5739
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005740#ifdef CONFIG_FILS
5741 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5742 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5743 sta->auth_alg == WLAN_AUTH_FILS_PK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07005744 int res;
5745
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005746 /* The end of the payload is encrypted. Need to decrypt it
5747 * before parsing. */
5748
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005749 tmp = os_memdup(pos, left);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005750 if (!tmp) {
5751 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5752 goto fail;
5753 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005754
Roshan Pius3a1667e2018-07-03 15:17:14 -07005755 res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
5756 len, tmp, left);
5757 if (res < 0) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005758 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
5759 goto fail;
5760 }
5761 pos = tmp;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005762 left = res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005763 }
5764#endif /* CONFIG_FILS */
5765
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005766 /* followed by SSID and Supported rates; and HT capabilities if 802.11n
5767 * is used */
5768 resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
5769 if (resp != WLAN_STATUS_SUCCESS)
5770 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07005771 omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005772
5773 if (hostapd_get_aid(hapd, sta) < 0) {
5774 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5775 HOSTAPD_LEVEL_INFO, "No room for more AIDs");
5776 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5777 goto fail;
5778 }
5779
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005780 sta->listen_interval = listen_interval;
5781
Roshan Pius3a1667e2018-07-03 15:17:14 -07005782 if (hapd->iface->current_mode &&
5783 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005784 sta->flags |= WLAN_STA_NONERP;
5785 for (i = 0; i < sta->supported_rates_len; i++) {
5786 if ((sta->supported_rates[i] & 0x7f) > 22) {
5787 sta->flags &= ~WLAN_STA_NONERP;
5788 break;
5789 }
5790 }
5791 if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
5792 sta->nonerp_set = 1;
5793 hapd->iface->num_sta_non_erp++;
5794 if (hapd->iface->num_sta_non_erp == 1)
5795 ieee802_11_set_beacons(hapd->iface);
5796 }
5797
5798 if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
5799 !sta->no_short_slot_time_set) {
5800 sta->no_short_slot_time_set = 1;
5801 hapd->iface->num_sta_no_short_slot_time++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005802 if (hapd->iface->current_mode &&
5803 hapd->iface->current_mode->mode ==
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005804 HOSTAPD_MODE_IEEE80211G &&
5805 hapd->iface->num_sta_no_short_slot_time == 1)
5806 ieee802_11_set_beacons(hapd->iface);
5807 }
5808
5809 if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
5810 sta->flags |= WLAN_STA_SHORT_PREAMBLE;
5811 else
5812 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
5813
5814 if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
5815 !sta->no_short_preamble_set) {
5816 sta->no_short_preamble_set = 1;
5817 hapd->iface->num_sta_no_short_preamble++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005818 if (hapd->iface->current_mode &&
5819 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005820 && hapd->iface->num_sta_no_short_preamble == 1)
5821 ieee802_11_set_beacons(hapd->iface);
5822 }
5823
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005824 update_ht_state(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005825
5826 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5827 HOSTAPD_LEVEL_DEBUG,
5828 "association OK (aid %d)", sta->aid);
5829 /* Station will be marked associated, after it acknowledges AssocResp
5830 */
5831 sta->flags |= WLAN_STA_ASSOC_REQ_OK;
5832
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005833 if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
5834 wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
5835 "SA Query procedure", reassoc ? "re" : "");
5836 /* TODO: Send a protected Disassociate frame to the STA using
5837 * the old key and Reason Code "Previous Authentication no
5838 * longer valid". Make sure this is only sent protected since
5839 * unprotected frame would be received by the STA that is now
5840 * trying to associate.
5841 */
5842 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005843
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005844 /* Make sure that the previously registered inactivity timer will not
5845 * remove the STA immediately. */
5846 sta->timeout_next = STA_NULLFUNC;
5847
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005848#ifdef CONFIG_TAXONOMY
5849 taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
5850#endif /* CONFIG_TAXONOMY */
5851
Dmitry Shmidt29333592017-01-09 12:27:11 -08005852 sta->pending_wds_enable = 0;
5853
Paul Stewart092955c2017-02-06 09:13:09 -08005854#ifdef CONFIG_FILS
5855 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
5856 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005857 sta->auth_alg == WLAN_AUTH_FILS_PK) {
5858 if (fils_process_hlp(hapd, sta, pos, left) > 0)
5859 delay_assoc = 1;
5860 }
Paul Stewart092955c2017-02-06 09:13:09 -08005861#endif /* CONFIG_FILS */
5862
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005863 fail:
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005864
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005865 /*
5866 * In case of a successful response, add the station to the driver.
5867 * Otherwise, the kernel may ignore Data frames before we process the
5868 * ACK frame (TX status). In case of a failure, this station will be
5869 * removed.
5870 *
5871 * Note that this is not compliant with the IEEE 802.11 standard that
5872 * states that a non-AP station should transition into the
5873 * authenticated/associated state only after the station acknowledges
5874 * the (Re)Association Response frame. However, still do this as:
5875 *
5876 * 1. In case the station does not acknowledge the (Re)Association
5877 * Response frame, it will be removed.
5878 * 2. Data frames will be dropped in the kernel until the station is
5879 * set into authorized state, and there are no significant known
5880 * issues with processing other non-Data Class 3 frames during this
5881 * window.
5882 */
Hai Shalom74f70d42019-02-11 14:42:39 -08005883 if (resp == WLAN_STATUS_SUCCESS && sta &&
5884 add_associated_sta(hapd, sta, reassoc))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005885 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
5886
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005887#ifdef CONFIG_FILS
Hai Shalom74f70d42019-02-11 14:42:39 -08005888 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
5889 eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
5890 sta->fils_pending_assoc_req) {
5891 /* Do not reschedule fils_hlp_timeout in case the station
5892 * retransmits (Re)Association Request frame while waiting for
5893 * the previously started FILS HLP wait, so that the timeout can
5894 * be determined from the first pending attempt. */
5895 wpa_printf(MSG_DEBUG,
5896 "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
5897 MACSTR, MAC2STR(sta->addr));
5898 os_free(tmp);
5899 return;
5900 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005901 if (sta) {
5902 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5903 os_free(sta->fils_pending_assoc_req);
5904 sta->fils_pending_assoc_req = NULL;
5905 sta->fils_pending_assoc_req_len = 0;
5906 wpabuf_free(sta->fils_hlp_resp);
5907 sta->fils_hlp_resp = NULL;
5908 }
5909 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
5910 sta->fils_pending_assoc_req = tmp;
5911 sta->fils_pending_assoc_req_len = left;
5912 sta->fils_pending_assoc_is_reassoc = reassoc;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005913 sta->fils_drv_assoc_finish = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005914 wpa_printf(MSG_DEBUG,
5915 "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
5916 MACSTR, MAC2STR(sta->addr));
5917 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5918 eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
5919 fils_hlp_timeout, hapd, sta);
5920 return;
5921 }
5922#endif /* CONFIG_FILS */
5923
Hai Shalomb755a2a2020-04-23 21:49:02 -07005924 if (resp >= 0)
5925 reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc,
5926 pos, left, rssi, omit_rsnxe);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005927 os_free(tmp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005928
5929 /*
Hai Shalom899fcc72020-10-19 14:38:18 -07005930 * Remove the station in case transmission of a success response fails
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005931 * (the STA was added associated to the driver) or if the station was
5932 * previously added unassociated.
5933 */
Dmitry Shmidt29333592017-01-09 12:27:11 -08005934 if (sta && ((reply_res != WLAN_STATUS_SUCCESS &&
5935 resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005936 hostapd_drv_sta_remove(hapd, sta->addr);
5937 sta->added_unassoc = 0;
5938 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005939}
5940
5941
5942static void handle_disassoc(struct hostapd_data *hapd,
5943 const struct ieee80211_mgmt *mgmt, size_t len)
5944{
5945 struct sta_info *sta;
5946
5947 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005948 wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)",
5949 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005950 return;
5951 }
5952
5953 wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
5954 MAC2STR(mgmt->sa),
5955 le_to_host16(mgmt->u.disassoc.reason_code));
5956
5957 sta = ap_get_sta(hapd, mgmt->sa);
5958 if (sta == NULL) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005959 wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated",
5960 MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005961 return;
5962 }
5963
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005964 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005965 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005966 sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07005967 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005968 wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
5969 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5970 HOSTAPD_LEVEL_INFO, "disassociated");
5971 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
5972 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
5973 /* Stop Accounting and IEEE 802.1X sessions, but leave the STA
5974 * authenticated. */
5975 accounting_sta_stop(hapd, sta);
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005976 ieee802_1x_free_station(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005977 if (sta->ipaddr)
5978 hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
5979 ap_sta_ip6addr_del(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005980 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005981 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005982
5983 if (sta->timeout_next == STA_NULLFUNC ||
5984 sta->timeout_next == STA_DISASSOC) {
5985 sta->timeout_next = STA_DEAUTH;
5986 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
5987 eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
5988 hapd, sta);
5989 }
5990
5991 mlme_disassociate_indication(
5992 hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt29333592017-01-09 12:27:11 -08005993
5994 /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon
5995 * disassociation. */
5996 if (hapd->iface->current_mode &&
5997 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
5998 sta->flags &= ~WLAN_STA_AUTH;
5999 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
6000 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6001 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
6002 ap_free_sta(hapd, sta);
6003 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006004}
6005
6006
6007static void handle_deauth(struct hostapd_data *hapd,
6008 const struct ieee80211_mgmt *mgmt, size_t len)
6009{
6010 struct sta_info *sta;
6011
6012 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006013 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short "
6014 "payload (len=%lu)", (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006015 return;
6016 }
6017
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006018 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006019 " reason_code=%d",
6020 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
6021
Hai Shaloma20dcd72022-02-04 13:43:00 -08006022 /* Clear the PTKSA cache entries for PASN */
6023 ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
6024
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006025 sta = ap_get_sta(hapd, mgmt->sa);
6026 if (sta == NULL) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006027 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
6028 "to deauthenticate, but it is not authenticated",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006029 MAC2STR(mgmt->sa));
6030 return;
6031 }
6032
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006033 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006034 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006035 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
6036 WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07006037 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006038 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
6039 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6040 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
6041 mlme_deauthenticate_indication(
6042 hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
6043 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
6044 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
6045 ap_free_sta(hapd, sta);
6046}
6047
6048
6049static void handle_beacon(struct hostapd_data *hapd,
6050 const struct ieee80211_mgmt *mgmt, size_t len,
6051 struct hostapd_frame_info *fi)
6052{
6053 struct ieee802_11_elems elems;
6054
6055 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006056 wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
6057 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006058 return;
6059 }
6060
6061 (void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
6062 len - (IEEE80211_HDRLEN +
6063 sizeof(mgmt->u.beacon)), &elems,
6064 0);
6065
6066 ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
6067}
6068
6069
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006070static int robust_action_frame(u8 category)
6071{
6072 return category != WLAN_ACTION_PUBLIC &&
6073 category != WLAN_ACTION_HT;
6074}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006075
6076
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006077static int handle_action(struct hostapd_data *hapd,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006078 const struct ieee80211_mgmt *mgmt, size_t len,
6079 unsigned int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006080{
6081 struct sta_info *sta;
Hai Shalom74f70d42019-02-11 14:42:39 -08006082 u8 *action __maybe_unused;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006083
Hai Shalom74f70d42019-02-11 14:42:39 -08006084 if (len < IEEE80211_HDRLEN + 2 + 1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006085 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6086 HOSTAPD_LEVEL_DEBUG,
6087 "handle_action - too short payload (len=%lu)",
6088 (unsigned long) len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006089 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006090 }
6091
Hai Shalom74f70d42019-02-11 14:42:39 -08006092 action = (u8 *) &mgmt->u.action.u;
6093 wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
6094 " da " MACSTR " len %d freq %u",
6095 mgmt->u.action.category, *action,
6096 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
6097
6098 sta = ap_get_sta(hapd, mgmt->sa);
6099
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006100 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
6101 (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
6102 wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
6103 "frame (category=%u) from unassociated STA " MACSTR,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08006104 mgmt->u.action.category, MAC2STR(mgmt->sa));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006105 return 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006106 }
6107
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006108 if (sta && (sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt18463232014-01-24 12:29:41 -08006109 !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
6110 robust_action_frame(mgmt->u.action.category)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006111 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6112 HOSTAPD_LEVEL_DEBUG,
6113 "Dropped unprotected Robust Action frame from "
6114 "an MFP STA");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006115 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006116 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006117
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006118 if (sta) {
6119 u16 fc = le_to_host16(mgmt->frame_control);
6120 u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
6121
6122 if ((fc & WLAN_FC_RETRY) &&
6123 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
6124 sta->last_seq_ctrl == seq_ctrl &&
6125 sta->last_subtype == WLAN_FC_STYPE_ACTION) {
6126 hostapd_logger(hapd, sta->addr,
6127 HOSTAPD_MODULE_IEEE80211,
6128 HOSTAPD_LEVEL_DEBUG,
6129 "Drop repeated action frame seq_ctrl=0x%x",
6130 seq_ctrl);
6131 return 1;
6132 }
6133
6134 sta->last_seq_ctrl = seq_ctrl;
6135 sta->last_subtype = WLAN_FC_STYPE_ACTION;
6136 }
6137
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006138 switch (mgmt->u.action.category) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006139#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006140 case WLAN_ACTION_FT:
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006141 if (!sta ||
6142 wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006143 len - IEEE80211_HDRLEN))
6144 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006145 return 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006146#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006147 case WLAN_ACTION_WMM:
6148 hostapd_wmm_action(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006149 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006150 case WLAN_ACTION_SA_QUERY:
Hai Shalom021b0b52019-04-10 11:17:58 -07006151 ieee802_11_sa_query_action(hapd, mgmt, len);
6152 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006153#ifdef CONFIG_WNM_AP
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006154 case WLAN_ACTION_WNM:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006155 ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
6156 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006157#endif /* CONFIG_WNM_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006158#ifdef CONFIG_FST
6159 case WLAN_ACTION_FST:
6160 if (hapd->iface->fst)
6161 fst_rx_action(hapd->iface->fst, mgmt, len);
6162 else
6163 wpa_printf(MSG_DEBUG,
6164 "FST: Ignore FST Action frame - no FST attached");
6165 return 1;
6166#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006167 case WLAN_ACTION_PUBLIC:
Dmitry Shmidt18463232014-01-24 12:29:41 -08006168 case WLAN_ACTION_PROTECTED_DUAL:
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07006169 if (len >= IEEE80211_HDRLEN + 2 &&
6170 mgmt->u.action.u.public_action.action ==
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006171 WLAN_PA_20_40_BSS_COEX) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006172 hostapd_2040_coex_action(hapd, mgmt, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006173 return 1;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006174 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006175#ifdef CONFIG_DPP
6176 if (len >= IEEE80211_HDRLEN + 6 &&
6177 mgmt->u.action.u.vs_public_action.action ==
6178 WLAN_PA_VENDOR_SPECIFIC &&
6179 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6180 OUI_WFA &&
6181 mgmt->u.action.u.vs_public_action.variable[0] ==
6182 DPP_OUI_TYPE) {
6183 const u8 *pos, *end;
6184
6185 pos = mgmt->u.action.u.vs_public_action.oui;
6186 end = ((const u8 *) mgmt) + len;
6187 hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006188 freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006189 return 1;
6190 }
6191 if (len >= IEEE80211_HDRLEN + 2 &&
6192 (mgmt->u.action.u.public_action.action ==
6193 WLAN_PA_GAS_INITIAL_RESP ||
6194 mgmt->u.action.u.public_action.action ==
6195 WLAN_PA_GAS_COMEBACK_RESP)) {
6196 const u8 *pos, *end;
6197
6198 pos = &mgmt->u.action.u.public_action.action;
6199 end = ((const u8 *) mgmt) + len;
6200 gas_query_ap_rx(hapd->gas, mgmt->sa,
6201 mgmt->u.action.category,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006202 pos, end - pos, freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006203 return 1;
6204 }
6205#endif /* CONFIG_DPP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006206 if (hapd->public_action_cb) {
6207 hapd->public_action_cb(hapd->public_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006208 (u8 *) mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006209 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006210 if (hapd->public_action_cb2) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -08006211 hapd->public_action_cb2(hapd->public_action_cb2_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006212 (u8 *) mgmt, len, freq);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006213 }
6214 if (hapd->public_action_cb || hapd->public_action_cb2)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006215 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006216 break;
6217 case WLAN_ACTION_VENDOR_SPECIFIC:
6218 if (hapd->vendor_action_cb) {
6219 if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
Hai Shaloma20dcd72022-02-04 13:43:00 -08006220 (u8 *) mgmt, len, freq) == 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006221 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006222 }
6223 break;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006224 case WLAN_ACTION_RADIO_MEASUREMENT:
6225 hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
6226 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006227 }
6228
6229 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6230 HOSTAPD_LEVEL_DEBUG,
6231 "handle_action - unknown action category %d or invalid "
6232 "frame",
6233 mgmt->u.action.category);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006234 if (!is_multicast_ether_addr(mgmt->da) &&
6235 !(mgmt->u.action.category & 0x80) &&
6236 !is_multicast_ether_addr(mgmt->sa)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006237 struct ieee80211_mgmt *resp;
6238
6239 /*
6240 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
6241 * Return the Action frame to the source without change
6242 * except that MSB of the Category set to 1.
6243 */
6244 wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
6245 "frame back to sender");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006246 resp = os_memdup(mgmt, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006247 if (resp == NULL)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006248 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006249 os_memcpy(resp->da, resp->sa, ETH_ALEN);
6250 os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
6251 os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
6252 resp->u.action.category |= 0x80;
6253
Hai Shalomfdcde762020-04-02 11:19:20 -07006254 if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006255 wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
6256 "Action frame");
6257 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006258 os_free(resp);
6259 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006260
6261 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006262}
6263
6264
6265/**
Hai Shalom60840252021-02-19 19:02:11 -08006266 * notify_mgmt_frame - Notify of Management frames on the control interface
6267 * @hapd: hostapd BSS data structure (the BSS to which the Management frame was
6268 * sent to)
6269 * @buf: Management frame data (starting from the IEEE 802.11 header)
6270 * @len: Length of frame data in octets
6271 *
6272 * Notify the control interface of any received Management frame.
6273 */
6274static void notify_mgmt_frame(struct hostapd_data *hapd, const u8 *buf,
6275 size_t len)
6276{
6277
6278 int hex_len = len * 2 + 1;
6279 char *hex = os_malloc(hex_len);
6280
6281 if (hex) {
6282 wpa_snprintf_hex(hex, hex_len, buf, len);
6283 wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO,
6284 AP_MGMT_FRAME_RECEIVED "buf=%s", hex);
6285 os_free(hex);
6286 }
6287}
6288
6289
6290/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006291 * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
6292 * @hapd: hostapd BSS data structure (the BSS to which the management frame was
6293 * sent to)
6294 * @buf: management frame data (starting from IEEE 802.11 header)
6295 * @len: length of frame data in octets
6296 * @fi: meta data about received frame (signal level, etc.)
6297 *
6298 * Process all incoming IEEE 802.11 management frames. This will be called for
6299 * each frame received from the kernel driver through wlan#ap interface. In
6300 * addition, it can be called to re-inserted pending frames (e.g., when using
6301 * external RADIUS server as an MAC ACL).
6302 */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006303int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
6304 struct hostapd_frame_info *fi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006305{
6306 struct ieee80211_mgmt *mgmt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006307 u16 fc, stype;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006308 int ret = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006309 unsigned int freq;
6310 int ssi_signal = fi ? fi->ssi_signal : 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006311
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006312 if (len < 24)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006313 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006314
Roshan Pius3a1667e2018-07-03 15:17:14 -07006315 if (fi && fi->freq)
6316 freq = fi->freq;
6317 else
6318 freq = hapd->iface->freq;
6319
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006320 mgmt = (struct ieee80211_mgmt *) buf;
6321 fc = le_to_host16(mgmt->frame_control);
6322 stype = WLAN_FC_GET_STYPE(fc);
6323
Hai Shalomc3565922019-10-28 11:58:20 -07006324 if (is_multicast_ether_addr(mgmt->sa) ||
6325 is_zero_ether_addr(mgmt->sa) ||
6326 os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
6327 /* Do not process any frames with unexpected/invalid SA so that
6328 * we do not add any state for unexpected STA addresses or end
6329 * up sending out frames to unexpected destination. */
6330 wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
6331 " in received frame - ignore this frame silently",
6332 MAC2STR(mgmt->sa));
6333 return 0;
6334 }
6335
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006336 if (stype == WLAN_FC_STYPE_BEACON) {
6337 handle_beacon(hapd, mgmt, len, fi);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006338 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006339 }
6340
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07006341 if (!is_broadcast_ether_addr(mgmt->bssid) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006342#ifdef CONFIG_P2P
6343 /* Invitation responses can be sent with the peer MAC as BSSID */
6344 !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
6345 stype == WLAN_FC_STYPE_ACTION) &&
6346#endif /* CONFIG_P2P */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006347#ifdef CONFIG_MESH
6348 !(hapd->conf->mesh & MESH_ENABLED) &&
6349#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006350 os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006351 wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
6352 MAC2STR(mgmt->bssid));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006353 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006354 }
6355
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006356 if (hapd->iface->state != HAPD_IFACE_ENABLED) {
6357 wpa_printf(MSG_DEBUG, "MGMT: Ignore management frame while interface is not enabled (SA=" MACSTR " DA=" MACSTR " subtype=%u)",
6358 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), stype);
6359 return 1;
6360 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006361
6362 if (stype == WLAN_FC_STYPE_PROBE_REQ) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006363 handle_probe_req(hapd, mgmt, len, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006364 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006365 }
6366
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006367 if ((!is_broadcast_ether_addr(mgmt->da) ||
6368 stype != WLAN_FC_STYPE_ACTION) &&
6369 os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006370 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6371 HOSTAPD_LEVEL_DEBUG,
6372 "MGMT: DA=" MACSTR " not our address",
6373 MAC2STR(mgmt->da));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006374 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006375 }
6376
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006377 if (hapd->iconf->track_sta_max_num)
Roshan Pius3a1667e2018-07-03 15:17:14 -07006378 sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006379
Hai Shalom60840252021-02-19 19:02:11 -08006380 if (hapd->conf->notify_mgmt_frames)
6381 notify_mgmt_frame(hapd, buf, len);
6382
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006383 switch (stype) {
6384 case WLAN_FC_STYPE_AUTH:
6385 wpa_printf(MSG_DEBUG, "mgmt::auth");
Hai Shalom021b0b52019-04-10 11:17:58 -07006386 handle_auth(hapd, mgmt, len, ssi_signal, 0);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006387 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006388 break;
6389 case WLAN_FC_STYPE_ASSOC_REQ:
6390 wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006391 handle_assoc(hapd, mgmt, len, 0, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006392 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006393 break;
6394 case WLAN_FC_STYPE_REASSOC_REQ:
6395 wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08006396 handle_assoc(hapd, mgmt, len, 1, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006397 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006398 break;
6399 case WLAN_FC_STYPE_DISASSOC:
6400 wpa_printf(MSG_DEBUG, "mgmt::disassoc");
6401 handle_disassoc(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006402 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006403 break;
6404 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006405 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006406 handle_deauth(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006407 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006408 break;
6409 case WLAN_FC_STYPE_ACTION:
6410 wpa_printf(MSG_DEBUG, "mgmt::action");
Roshan Pius3a1667e2018-07-03 15:17:14 -07006411 ret = handle_action(hapd, mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006412 break;
6413 default:
6414 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
6415 HOSTAPD_LEVEL_DEBUG,
6416 "unknown mgmt frame subtype %d", stype);
6417 break;
6418 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006419
6420 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006421}
6422
6423
6424static void handle_auth_cb(struct hostapd_data *hapd,
6425 const struct ieee80211_mgmt *mgmt,
6426 size_t len, int ok)
6427{
6428 u16 auth_alg, auth_transaction, status_code;
6429 struct sta_info *sta;
Hai Shalom60840252021-02-19 19:02:11 -08006430 bool success_status;
Hai Shalome5e28bb2019-01-28 14:51:04 -08006431
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006432 sta = ap_get_sta(hapd, mgmt->da);
6433 if (!sta) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08006434 wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
6435 " not found",
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006436 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006437 return;
6438 }
6439
Hai Shalom60840252021-02-19 19:02:11 -08006440 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
6441 wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
6442 (unsigned long) len);
6443 auth_alg = 0;
6444 auth_transaction = 0;
6445 status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
6446 goto fail;
6447 }
6448
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006449 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
6450 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
6451 status_code = le_to_host16(mgmt->u.auth.status_code);
6452
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006453 if (!ok) {
6454 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6455 HOSTAPD_LEVEL_NOTICE,
6456 "did not acknowledge authentication response");
6457 goto fail;
6458 }
6459
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006460 if (status_code == WLAN_STATUS_SUCCESS &&
6461 ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
6462 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
6463 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6464 HOSTAPD_LEVEL_INFO, "authenticated");
6465 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006466 if (sta->added_unassoc)
6467 hostapd_set_sta_flags(hapd, sta);
6468 return;
6469 }
6470
6471fail:
Hai Shalom60840252021-02-19 19:02:11 -08006472 success_status = status_code == WLAN_STATUS_SUCCESS;
6473#ifdef CONFIG_SAE
6474 if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1)
6475 success_status = sae_status_success(hapd, status_code);
6476#endif /* CONFIG_SAE */
6477 if (!success_status && sta->added_unassoc) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006478 hostapd_drv_sta_remove(hapd, sta->addr);
6479 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006480 }
6481}
6482
6483
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006484static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
6485 struct sta_info *sta,
6486 char *ifname_wds)
6487{
Hai Shalomfdcde762020-04-02 11:19:20 -07006488#ifdef CONFIG_WEP
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006489 int i;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07006490 struct hostapd_ssid *ssid = &hapd->conf->ssid;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006491
6492 if (hapd->conf->ieee802_1x || hapd->conf->wpa)
6493 return;
6494
6495 for (i = 0; i < 4; i++) {
6496 if (ssid->wep.key[i] &&
6497 hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
Hai Shalomfdcde762020-04-02 11:19:20 -07006498 0, i == ssid->wep.idx, NULL, 0,
6499 ssid->wep.key[i], ssid->wep.len[i],
6500 i == ssid->wep.idx ?
6501 KEY_FLAG_GROUP_RX_TX_DEFAULT :
6502 KEY_FLAG_GROUP_RX_TX)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006503 wpa_printf(MSG_WARNING,
6504 "Could not set WEP keys for WDS interface; %s",
6505 ifname_wds);
6506 break;
6507 }
6508 }
Hai Shalomfdcde762020-04-02 11:19:20 -07006509#endif /* CONFIG_WEP */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006510}
6511
6512
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006513static void handle_assoc_cb(struct hostapd_data *hapd,
6514 const struct ieee80211_mgmt *mgmt,
6515 size_t len, int reassoc, int ok)
6516{
6517 u16 status;
6518 struct sta_info *sta;
6519 int new_assoc = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006520
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006521 sta = ap_get_sta(hapd, mgmt->da);
6522 if (!sta) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006523 wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
6524 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006525 return;
6526 }
6527
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006528 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
6529 sizeof(mgmt->u.assoc_resp))) {
6530 wpa_printf(MSG_INFO,
6531 "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
6532 reassoc, (unsigned long) len);
6533 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006534 return;
6535 }
6536
6537 if (reassoc)
6538 status = le_to_host16(mgmt->u.reassoc_resp.status_code);
6539 else
6540 status = le_to_host16(mgmt->u.assoc_resp.status_code);
6541
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006542 if (!ok) {
6543 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
6544 HOSTAPD_LEVEL_DEBUG,
6545 "did not acknowledge association response");
6546 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
6547 /* The STA is added only in case of SUCCESS */
6548 if (status == WLAN_STATUS_SUCCESS)
6549 hostapd_drv_sta_remove(hapd, sta->addr);
6550
6551 return;
6552 }
6553
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006554 if (status != WLAN_STATUS_SUCCESS)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07006555 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006556
6557 /* Stop previous accounting session, if one is started, and allocate
6558 * new session id for the new session. */
6559 accounting_sta_stop(hapd, sta);
6560
6561 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6562 HOSTAPD_LEVEL_INFO,
6563 "associated (aid %d)",
6564 sta->aid);
6565
6566 if (sta->flags & WLAN_STA_ASSOC)
6567 new_assoc = 0;
6568 sta->flags |= WLAN_STA_ASSOC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006569 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006570 if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
6571 !hapd->conf->osen) ||
6572 sta->auth_alg == WLAN_AUTH_FILS_SK ||
6573 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6574 sta->auth_alg == WLAN_AUTH_FILS_PK ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006575 sta->auth_alg == WLAN_AUTH_FT) {
6576 /*
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006577 * Open, static WEP, FT protocol, or FILS; no separate
6578 * authorization step.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006579 */
6580 ap_sta_set_authorized(hapd, sta, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006581 }
6582
6583 if (reassoc)
6584 mlme_reassociate_indication(hapd, sta);
6585 else
6586 mlme_associate_indication(hapd, sta);
6587
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006588 sta->sa_query_timed_out = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006589
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006590 if (sta->eapol_sm == NULL) {
6591 /*
6592 * This STA does not use RADIUS server for EAP authentication,
6593 * so bind it to the selected VLAN interface now, since the
6594 * interface selection is not going to change anymore.
6595 */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006596 if (ap_sta_bind_vlan(hapd, sta) < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07006597 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006598 } else if (sta->vlan_id) {
6599 /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
Dmitry Shmidt83474442015-04-15 13:47:09 -07006600 if (ap_sta_bind_vlan(hapd, sta) < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07006601 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006602 }
6603
6604 hostapd_set_sta_flags(hapd, sta);
6605
Dmitry Shmidt29333592017-01-09 12:27:11 -08006606 if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) {
6607 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA "
6608 MACSTR " based on pending request",
6609 MAC2STR(sta->addr));
6610 sta->pending_wds_enable = 0;
6611 sta->flags |= WLAN_STA_WDS;
6612 }
6613
Hai Shalom74f70d42019-02-11 14:42:39 -08006614 if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) {
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08006615 int ret;
6616 char ifname_wds[IFNAMSIZ + 1];
6617
6618 wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA "
6619 MACSTR " (aid %u)",
6620 MAC2STR(sta->addr), sta->aid);
6621 ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
6622 sta->aid, 1);
6623 if (!ret)
6624 hostapd_set_wds_encryption(hapd, sta, ifname_wds);
6625 }
6626
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006627 if (sta->auth_alg == WLAN_AUTH_FT)
6628 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
6629 else
6630 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
6631 hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006632 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006633
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006634#ifdef CONFIG_FILS
6635 if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
6636 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
6637 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
6638 fils_set_tk(sta->wpa_sm) < 0) {
6639 wpa_printf(MSG_DEBUG, "FILS: TK configuration failed");
6640 ap_sta_disconnect(hapd, sta, sta->addr,
6641 WLAN_REASON_UNSPECIFIED);
6642 return;
6643 }
6644#endif /* CONFIG_FILS */
6645
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006646 if (sta->pending_eapol_rx) {
6647 struct os_reltime now, age;
6648
6649 os_get_reltime(&now);
6650 os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
6651 if (age.sec == 0 && age.usec < 200000) {
6652 wpa_printf(MSG_DEBUG,
6653 "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
6654 MAC2STR(sta->addr));
6655 ieee802_1x_receive(
6656 hapd, mgmt->da,
6657 wpabuf_head(sta->pending_eapol_rx->buf),
Sunil8cd6f4d2022-06-28 18:40:46 +00006658 wpabuf_len(sta->pending_eapol_rx->buf),
6659 sta->pending_eapol_rx->encrypted);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006660 }
6661 wpabuf_free(sta->pending_eapol_rx->buf);
6662 os_free(sta->pending_eapol_rx);
6663 sta->pending_eapol_rx = NULL;
6664 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006665}
6666
6667
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006668static void handle_deauth_cb(struct hostapd_data *hapd,
6669 const struct ieee80211_mgmt *mgmt,
6670 size_t len, int ok)
6671{
6672 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006673 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006674 return;
6675 sta = ap_get_sta(hapd, mgmt->da);
6676 if (!sta) {
6677 wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
6678 " not found", MAC2STR(mgmt->da));
6679 return;
6680 }
6681 if (ok)
6682 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
6683 MAC2STR(sta->addr));
6684 else
6685 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6686 "deauth", MAC2STR(sta->addr));
6687
6688 ap_sta_deauth_cb(hapd, sta);
6689}
6690
6691
6692static void handle_disassoc_cb(struct hostapd_data *hapd,
6693 const struct ieee80211_mgmt *mgmt,
6694 size_t len, int ok)
6695{
6696 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006697 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006698 return;
6699 sta = ap_get_sta(hapd, mgmt->da);
6700 if (!sta) {
6701 wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
6702 " not found", MAC2STR(mgmt->da));
6703 return;
6704 }
6705 if (ok)
6706 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
6707 MAC2STR(sta->addr));
6708 else
6709 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
6710 "disassoc", MAC2STR(sta->addr));
6711
6712 ap_sta_disassoc_cb(hapd, sta);
6713}
6714
6715
Dmitry Shmidt29333592017-01-09 12:27:11 -08006716static void handle_action_cb(struct hostapd_data *hapd,
6717 const struct ieee80211_mgmt *mgmt,
6718 size_t len, int ok)
6719{
6720 struct sta_info *sta;
Paul Stewart092955c2017-02-06 09:13:09 -08006721 const struct rrm_measurement_report_element *report;
Dmitry Shmidt29333592017-01-09 12:27:11 -08006722
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006723#ifdef CONFIG_DPP
6724 if (len >= IEEE80211_HDRLEN + 6 &&
6725 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6726 mgmt->u.action.u.vs_public_action.action ==
6727 WLAN_PA_VENDOR_SPECIFIC &&
6728 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
6729 OUI_WFA &&
6730 mgmt->u.action.u.vs_public_action.variable[0] ==
6731 DPP_OUI_TYPE) {
6732 const u8 *pos, *end;
6733
6734 pos = &mgmt->u.action.u.vs_public_action.variable[1];
6735 end = ((const u8 *) mgmt) + len;
6736 hostapd_dpp_tx_status(hapd, mgmt->da, pos, end - pos, ok);
6737 return;
6738 }
6739 if (len >= IEEE80211_HDRLEN + 2 &&
6740 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
6741 (mgmt->u.action.u.public_action.action ==
6742 WLAN_PA_GAS_INITIAL_REQ ||
6743 mgmt->u.action.u.public_action.action ==
6744 WLAN_PA_GAS_COMEBACK_REQ)) {
6745 const u8 *pos, *end;
6746
6747 pos = mgmt->u.action.u.public_action.variable;
6748 end = ((const u8 *) mgmt) + len;
6749 gas_query_ap_tx_status(hapd->gas, mgmt->da, pos, end - pos, ok);
6750 return;
6751 }
6752#endif /* CONFIG_DPP */
Hai Shaloma20dcd72022-02-04 13:43:00 -08006753 if (is_multicast_ether_addr(mgmt->da))
6754 return;
Dmitry Shmidt29333592017-01-09 12:27:11 -08006755 sta = ap_get_sta(hapd, mgmt->da);
6756 if (!sta) {
6757 wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR
6758 " not found", MAC2STR(mgmt->da));
6759 return;
6760 }
6761
Paul Stewart092955c2017-02-06 09:13:09 -08006762 if (len < 24 + 5 + sizeof(*report))
Dmitry Shmidt29333592017-01-09 12:27:11 -08006763 return;
Paul Stewart092955c2017-02-06 09:13:09 -08006764 report = (const struct rrm_measurement_report_element *)
6765 &mgmt->u.action.u.rrm.variable[2];
Dmitry Shmidt29333592017-01-09 12:27:11 -08006766 if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT &&
Paul Stewart092955c2017-02-06 09:13:09 -08006767 mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST &&
6768 report->eid == WLAN_EID_MEASURE_REQUEST &&
6769 report->len >= 3 &&
6770 report->type == MEASURE_TYPE_BEACON)
Dmitry Shmidt29333592017-01-09 12:27:11 -08006771 hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok);
6772}
6773
6774
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006775/**
6776 * ieee802_11_mgmt_cb - Process management frame TX status callback
6777 * @hapd: hostapd BSS data structure (the BSS from which the management frame
6778 * was sent from)
6779 * @buf: management frame data (starting from IEEE 802.11 header)
6780 * @len: length of frame data in octets
6781 * @stype: management frame subtype from frame control field
6782 * @ok: Whether the frame was ACK'ed
6783 */
6784void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
6785 u16 stype, int ok)
6786{
6787 const struct ieee80211_mgmt *mgmt;
6788 mgmt = (const struct ieee80211_mgmt *) buf;
6789
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006790#ifdef CONFIG_TESTING_OPTIONS
6791 if (hapd->ext_mgmt_frame_handling) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006792 size_t hex_len = 2 * len + 1;
6793 char *hex = os_malloc(hex_len);
6794
6795 if (hex) {
6796 wpa_snprintf_hex(hex, hex_len, buf, len);
6797 wpa_msg(hapd->msg_ctx, MSG_INFO,
6798 "MGMT-TX-STATUS stype=%u ok=%d buf=%s",
6799 stype, ok, hex);
6800 os_free(hex);
6801 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006802 return;
6803 }
6804#endif /* CONFIG_TESTING_OPTIONS */
6805
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006806 switch (stype) {
6807 case WLAN_FC_STYPE_AUTH:
6808 wpa_printf(MSG_DEBUG, "mgmt::auth cb");
6809 handle_auth_cb(hapd, mgmt, len, ok);
6810 break;
6811 case WLAN_FC_STYPE_ASSOC_RESP:
6812 wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
6813 handle_assoc_cb(hapd, mgmt, len, 0, ok);
6814 break;
6815 case WLAN_FC_STYPE_REASSOC_RESP:
6816 wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
6817 handle_assoc_cb(hapd, mgmt, len, 1, ok);
6818 break;
6819 case WLAN_FC_STYPE_PROBE_RESP:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006820 wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006821 break;
6822 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006823 wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
6824 handle_deauth_cb(hapd, mgmt, len, ok);
6825 break;
6826 case WLAN_FC_STYPE_DISASSOC:
6827 wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
6828 handle_disassoc_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006829 break;
6830 case WLAN_FC_STYPE_ACTION:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006831 wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006832 handle_action_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006833 break;
6834 default:
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006835 wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006836 break;
6837 }
6838}
6839
6840
6841int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
6842{
6843 /* TODO */
6844 return 0;
6845}
6846
6847
6848int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
6849 char *buf, size_t buflen)
6850{
6851 /* TODO */
6852 return 0;
6853}
6854
6855
6856void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
6857 const u8 *buf, size_t len, int ack)
6858{
6859 struct sta_info *sta;
6860 struct hostapd_iface *iface = hapd->iface;
6861
6862 sta = ap_get_sta(hapd, addr);
6863 if (sta == NULL && iface->num_bss > 1) {
6864 size_t j;
6865 for (j = 0; j < iface->num_bss; j++) {
6866 hapd = iface->bss[j];
6867 sta = ap_get_sta(hapd, addr);
6868 if (sta)
6869 break;
6870 }
6871 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006872 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006873 return;
6874 if (sta->flags & WLAN_STA_PENDING_POLL) {
6875 wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
6876 "activity poll", MAC2STR(sta->addr),
6877 ack ? "ACKed" : "did not ACK");
6878 if (ack)
6879 sta->flags &= ~WLAN_STA_PENDING_POLL;
6880 }
6881
6882 ieee802_1x_tx_status(hapd, sta, buf, len, ack);
6883}
6884
6885
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006886void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
6887 const u8 *data, size_t len, int ack)
6888{
6889 struct sta_info *sta;
6890 struct hostapd_iface *iface = hapd->iface;
6891
6892 sta = ap_get_sta(hapd, dst);
6893 if (sta == NULL && iface->num_bss > 1) {
6894 size_t j;
6895 for (j = 0; j < iface->num_bss; j++) {
6896 hapd = iface->bss[j];
6897 sta = ap_get_sta(hapd, dst);
6898 if (sta)
6899 break;
6900 }
6901 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006902 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
6903 wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA "
6904 MACSTR " that is not currently associated",
6905 MAC2STR(dst));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006906 return;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006907 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006908
6909 ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
6910}
6911
6912
6913void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
6914{
6915 struct sta_info *sta;
6916 struct hostapd_iface *iface = hapd->iface;
6917
6918 sta = ap_get_sta(hapd, addr);
6919 if (sta == NULL && iface->num_bss > 1) {
6920 size_t j;
6921 for (j = 0; j < iface->num_bss; j++) {
6922 hapd = iface->bss[j];
6923 sta = ap_get_sta(hapd, addr);
6924 if (sta)
6925 break;
6926 }
6927 }
6928 if (sta == NULL)
6929 return;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006930 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
6931 MAC2STR(sta->addr));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006932 if (!(sta->flags & WLAN_STA_PENDING_POLL))
6933 return;
6934
6935 wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
6936 "activity poll", MAC2STR(sta->addr));
6937 sta->flags &= ~WLAN_STA_PENDING_POLL;
6938}
6939
6940
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006941void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
6942 int wds)
6943{
6944 struct sta_info *sta;
6945
6946 sta = ap_get_sta(hapd, src);
Dmitry Shmidt29333592017-01-09 12:27:11 -08006947 if (sta &&
6948 ((sta->flags & WLAN_STA_ASSOC) ||
6949 ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006950 if (!hapd->conf->wds_sta)
6951 return;
6952
Dmitry Shmidt29333592017-01-09 12:27:11 -08006953 if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) ==
6954 WLAN_STA_ASSOC_REQ_OK) {
6955 wpa_printf(MSG_DEBUG,
6956 "Postpone 4-address WDS mode enabling for STA "
6957 MACSTR " since TX status for AssocResp is not yet known",
6958 MAC2STR(sta->addr));
6959 sta->pending_wds_enable = 1;
6960 return;
6961 }
6962
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006963 if (wds && !(sta->flags & WLAN_STA_WDS)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006964 int ret;
6965 char ifname_wds[IFNAMSIZ + 1];
6966
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006967 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
6968 "STA " MACSTR " (aid %u)",
6969 MAC2STR(sta->addr), sta->aid);
6970 sta->flags |= WLAN_STA_WDS;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07006971 ret = hostapd_set_wds_sta(hapd, ifname_wds,
6972 sta->addr, sta->aid, 1);
6973 if (!ret)
6974 hostapd_set_wds_encryption(hapd, sta,
6975 ifname_wds);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006976 }
6977 return;
6978 }
6979
6980 wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
6981 MACSTR, MAC2STR(src));
Hai Shalomc3565922019-10-28 11:58:20 -07006982 if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
6983 os_memcmp(src, hapd->own_addr, ETH_ALEN) == 0) {
6984 /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
6985 * silently. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006986 return;
6987 }
6988
6989 if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) {
6990 wpa_printf(MSG_DEBUG, "Association Response to the STA has "
6991 "already been sent, but no TX status yet known - "
6992 "ignore Class 3 frame issue with " MACSTR,
6993 MAC2STR(src));
6994 return;
6995 }
6996
6997 if (sta && (sta->flags & WLAN_STA_AUTH))
6998 hostapd_drv_sta_disassoc(
6999 hapd, src,
7000 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
7001 else
7002 hostapd_drv_sta_deauth(
7003 hapd, src,
7004 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
7005}
7006
7007
Sunil Ravia04bd252022-05-02 22:54:18 -07007008static u8 * hostapd_add_tpe_info(u8 *eid, u8 tx_pwr_count,
7009 enum max_tx_pwr_interpretation tx_pwr_intrpn,
7010 u8 tx_pwr_cat, u8 tx_pwr)
7011{
7012 int i;
7013
7014 *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE; /* Element ID */
7015 *eid++ = 2 + tx_pwr_count; /* Length */
7016
7017 /*
7018 * Transmit Power Information field
7019 * bits 0-2 : Maximum Transmit Power Count
7020 * bits 3-5 : Maximum Transmit Power Interpretation
7021 * bits 6-7 : Maximum Transmit Power Category
7022 */
7023 *eid++ = tx_pwr_count | (tx_pwr_intrpn << 3) | (tx_pwr_cat << 6);
7024
7025 /* Maximum Transmit Power field */
7026 for (i = 0; i <= tx_pwr_count; i++)
7027 *eid++ = tx_pwr;
7028
7029 return eid;
7030}
7031
7032
7033/*
7034 * TODO: Extract power limits from channel data after 6G regulatory
7035 * support.
7036 */
7037#define REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT (-1) /* dBm/MHz */
7038#define REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT 5 /* dBm/MHz */
7039
Hai Shalom60840252021-02-19 19:02:11 -08007040u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
7041{
7042 struct hostapd_iface *iface = hapd->iface;
7043 struct hostapd_config *iconf = iface->conf;
7044 struct hostapd_hw_modes *mode = iface->current_mode;
7045 struct hostapd_channel_data *chan;
7046 int dfs, i;
7047 u8 channel, tx_pwr_count, local_pwr_constraint;
7048 int max_tx_power;
7049 u8 tx_pwr;
7050
7051 if (!mode)
7052 return eid;
7053
7054 if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
7055 return eid;
7056
7057 for (i = 0; i < mode->num_channels; i++) {
7058 if (mode->channels[i].freq == iface->freq)
7059 break;
7060 }
7061 if (i == mode->num_channels)
7062 return eid;
7063
Sunil Ravia04bd252022-05-02 22:54:18 -07007064#ifdef CONFIG_IEEE80211AX
7065 /* IEEE Std 802.11ax-2021, Annex E.2.7 (6 GHz band in the United
7066 * States): An AP that is an Indoor Access Point per regulatory rules
7067 * shall send at least two Transmit Power Envelope elements in Beacon
7068 * and Probe Response frames as follows:
7069 * - Maximum Transmit Power Category subfield = Default;
7070 * Unit interpretation = Regulatory client EIRP PSD
7071 * - Maximum Transmit Power Category subfield = Subordinate Device;
7072 * Unit interpretation = Regulatory client EIRP PSD
7073 */
7074 if (is_6ghz_op_class(iconf->op_class)) {
7075 enum max_tx_pwr_interpretation tx_pwr_intrpn;
7076
7077 /* Same Maximum Transmit Power for all 20 MHz bands */
7078 tx_pwr_count = 0;
7079 tx_pwr_intrpn = REGULATORY_CLIENT_EIRP_PSD;
7080
7081 /* Default Transmit Power Envelope for Global Operating Class */
7082 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT * 2;
7083 eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn,
7084 REG_DEFAULT_CLIENT, tx_pwr);
7085
7086 /* Indoor Access Point must include an additional TPE for
7087 * subordinate devices */
7088 if (iconf->he_6ghz_reg_pwr_type == HE_6GHZ_INDOOR_AP) {
7089 /* TODO: Extract PSD limits from channel data */
7090 tx_pwr = REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT * 2;
7091 eid = hostapd_add_tpe_info(eid, tx_pwr_count,
7092 tx_pwr_intrpn,
7093 REG_SUBORDINATE_CLIENT,
7094 tx_pwr);
7095 }
7096
7097 return eid;
7098 }
7099#endif /* CONFIG_IEEE80211AX */
7100
Hai Shalom60840252021-02-19 19:02:11 -08007101 switch (hostapd_get_oper_chwidth(iconf)) {
Sunil8cd6f4d2022-06-28 18:40:46 +00007102 case CONF_OPER_CHWIDTH_USE_HT:
Hai Shalom60840252021-02-19 19:02:11 -08007103 if (iconf->secondary_channel == 0) {
7104 /* Max Transmit Power count = 0 (20 MHz) */
7105 tx_pwr_count = 0;
7106 } else {
7107 /* Max Transmit Power count = 1 (20, 40 MHz) */
7108 tx_pwr_count = 1;
7109 }
7110 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00007111 case CONF_OPER_CHWIDTH_80MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08007112 /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
7113 tx_pwr_count = 2;
7114 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00007115 case CONF_OPER_CHWIDTH_80P80MHZ:
7116 case CONF_OPER_CHWIDTH_160MHZ:
Hai Shalom60840252021-02-19 19:02:11 -08007117 /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
7118 tx_pwr_count = 3;
7119 break;
7120 default:
7121 return eid;
7122 }
7123
7124 /*
7125 * Below local_pwr_constraint logic is referred from
7126 * hostapd_eid_pwr_constraint.
7127 *
7128 * Check if DFS is required by regulatory.
7129 */
7130 dfs = hostapd_is_dfs_required(hapd->iface);
7131 if (dfs < 0)
7132 dfs = 0;
7133
7134 /*
7135 * In order to meet regulations when TPC is not implemented using
7136 * a transmit power that is below the legal maximum (including any
7137 * mitigation factor) should help. In this case, indicate 3 dB below
7138 * maximum allowed transmit power.
7139 */
7140 if (hapd->iconf->local_pwr_constraint == -1)
7141 local_pwr_constraint = (dfs == 0) ? 0 : 3;
7142 else
7143 local_pwr_constraint = hapd->iconf->local_pwr_constraint;
7144
7145 /*
7146 * A STA that is not an AP shall use a transmit power less than or
7147 * equal to the local maximum transmit power level for the channel.
7148 * The local maximum transmit power can be calculated from the formula:
7149 * local max TX pwr = max TX pwr - local pwr constraint
7150 * Where max TX pwr is maximum transmit power level specified for
7151 * channel in Country element and local pwr constraint is specified
7152 * for channel in this Power Constraint element.
7153 */
7154 chan = &mode->channels[i];
7155 max_tx_power = chan->max_tx_power - local_pwr_constraint;
7156
7157 /*
7158 * Local Maximum Transmit power is encoded as two's complement
7159 * with a 0.5 dB step.
7160 */
7161 max_tx_power *= 2; /* in 0.5 dB steps */
7162 if (max_tx_power > 127) {
7163 /* 63.5 has special meaning of 63.5 dBm or higher */
7164 max_tx_power = 127;
7165 }
7166 if (max_tx_power < -128)
7167 max_tx_power = -128;
7168 if (max_tx_power < 0)
7169 tx_pwr = 0x80 + max_tx_power + 128;
7170 else
7171 tx_pwr = max_tx_power;
7172
Sunil Ravia04bd252022-05-02 22:54:18 -07007173 return hostapd_add_tpe_info(eid, tx_pwr_count, LOCAL_EIRP,
7174 0 /* Reserved for bands other than 6 GHz */,
7175 tx_pwr);
Hai Shalom60840252021-02-19 19:02:11 -08007176}
7177
7178
Hai Shalom899fcc72020-10-19 14:38:18 -07007179u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
7180{
7181 u8 bw, chan1, chan2 = 0;
7182 int freq1;
7183
7184 if (!hapd->cs_freq_params.channel ||
7185 (!hapd->cs_freq_params.vht_enabled &&
Sunil Ravia04bd252022-05-02 22:54:18 -07007186 !hapd->cs_freq_params.he_enabled &&
7187 !hapd->cs_freq_params.eht_enabled))
Hai Shalom899fcc72020-10-19 14:38:18 -07007188 return eid;
7189
7190 /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
7191 switch (hapd->cs_freq_params.bandwidth) {
7192 case 40:
7193 bw = 0;
7194 break;
7195 case 80:
7196 /* check if it's 80+80 */
7197 if (!hapd->cs_freq_params.center_freq2)
7198 bw = 1;
7199 else
7200 bw = 3;
7201 break;
7202 case 160:
7203 bw = 2;
7204 break;
7205 default:
7206 /* not valid VHT bandwidth or not in CSA */
7207 return eid;
7208 }
7209
7210 freq1 = hapd->cs_freq_params.center_freq1 ?
7211 hapd->cs_freq_params.center_freq1 :
7212 hapd->cs_freq_params.freq;
7213 if (ieee80211_freq_to_chan(freq1, &chan1) !=
7214 HOSTAPD_MODE_IEEE80211A)
7215 return eid;
7216
7217 if (hapd->cs_freq_params.center_freq2 &&
7218 ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
7219 &chan2) != HOSTAPD_MODE_IEEE80211A)
7220 return eid;
7221
7222 *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
7223 *eid++ = 5; /* Length of Channel Switch Wrapper */
7224 *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
7225 *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
7226 *eid++ = bw; /* New Channel Width */
7227 *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
7228 *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
7229
7230 return eid;
7231}
7232
Hai Shaloma20dcd72022-02-04 13:43:00 -08007233
7234static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd,
7235 size_t *current_len)
7236{
7237 struct hostapd_neighbor_entry *nr;
7238 size_t total_len = 0, len = *current_len;
7239
7240 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7241 list) {
7242 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7243 continue;
7244
7245 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7246 continue;
7247
7248 /* Start a new element */
7249 if (!len ||
7250 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7251 len = RNR_HEADER_LEN;
7252 total_len += RNR_HEADER_LEN;
7253 }
7254
7255 len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7256 total_len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
7257 }
7258
7259 *current_len = len;
7260 return total_len;
7261}
7262
7263
7264static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
7265 struct hostapd_data *reporting_hapd,
7266 size_t *current_len)
7267{
7268 size_t total_len = 0, len = *current_len;
7269 int tbtt_count = 0;
7270 size_t i, start = 0;
7271
7272 while (start < hapd->iface->num_bss) {
7273 if (!len ||
7274 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7275 len = RNR_HEADER_LEN;
7276 total_len += RNR_HEADER_LEN;
7277 }
7278
7279 len += RNR_TBTT_HEADER_LEN;
7280 total_len += RNR_TBTT_HEADER_LEN;
7281
7282 for (i = start; i < hapd->iface->num_bss; i++) {
7283 struct hostapd_data *bss = hapd->iface->bss[i];
7284
7285 if (!bss || !bss->conf || !bss->started)
7286 continue;
7287
7288 if (bss == reporting_hapd ||
7289 bss->conf->ignore_broadcast_ssid)
7290 continue;
7291
7292 if (len + RNR_TBTT_INFO_LEN > 255 ||
7293 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7294 break;
7295
7296 len += RNR_TBTT_INFO_LEN;
7297 total_len += RNR_TBTT_INFO_LEN;
7298 tbtt_count++;
7299 }
7300 start = i;
7301 }
7302
7303 if (!tbtt_count)
7304 total_len = 0;
7305 else
7306 *current_len = len;
7307
7308 return total_len;
7309}
7310
7311
7312enum colocation_mode {
7313 NO_COLOCATED_6GHZ,
7314 STANDALONE_6GHZ,
7315 COLOCATED_6GHZ,
7316 COLOCATED_LOWER_BAND,
7317};
7318
7319static enum colocation_mode get_colocation_mode(struct hostapd_data *hapd)
7320{
7321 u8 i;
7322 bool is_6ghz = is_6ghz_op_class(hapd->iconf->op_class);
7323
7324 if (!hapd->iface || !hapd->iface->interfaces)
7325 return NO_COLOCATED_6GHZ;
7326
7327 if (is_6ghz && hapd->iface->interfaces->count == 1)
7328 return STANDALONE_6GHZ;
7329
7330 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7331 struct hostapd_iface *iface;
7332 bool is_colocated_6ghz;
7333
7334 iface = hapd->iface->interfaces->iface[i];
7335 if (iface == hapd->iface || !iface || !iface->conf)
7336 continue;
7337
7338 is_colocated_6ghz = is_6ghz_op_class(iface->conf->op_class);
7339 if (!is_6ghz && is_colocated_6ghz)
7340 return COLOCATED_LOWER_BAND;
7341 if (is_6ghz && !is_colocated_6ghz)
7342 return COLOCATED_6GHZ;
7343 }
7344
7345 if (is_6ghz)
7346 return STANDALONE_6GHZ;
7347
7348 return NO_COLOCATED_6GHZ;
7349}
7350
7351
7352static size_t hostapd_eid_rnr_colocation_len(struct hostapd_data *hapd,
7353 size_t *current_len)
7354{
7355 struct hostapd_iface *iface;
7356 size_t len = 0;
7357 size_t i;
7358
7359 if (!hapd->iface || !hapd->iface->interfaces)
7360 return 0;
7361
7362 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7363 iface = hapd->iface->interfaces->iface[i];
7364
7365 if (iface == hapd->iface ||
7366 !is_6ghz_op_class(iface->conf->op_class))
7367 continue;
7368
7369 len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
7370 current_len);
7371 }
7372
7373 return len;
7374}
7375
7376
7377size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type)
7378{
7379 size_t total_len = 0, current_len = 0;
7380 enum colocation_mode mode = get_colocation_mode(hapd);
7381
7382 switch (type) {
7383 case WLAN_FC_STYPE_BEACON:
7384 if (hapd->conf->rnr)
7385 total_len += hostapd_eid_nr_db_len(hapd, &current_len);
7386 /* fallthrough */
7387
7388 case WLAN_FC_STYPE_PROBE_RESP:
7389 if (mode == COLOCATED_LOWER_BAND)
7390 total_len += hostapd_eid_rnr_colocation_len(
7391 hapd, &current_len);
7392
7393 if (hapd->conf->rnr && hapd->iface->num_bss > 1)
7394 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
7395 &current_len);
7396 break;
7397
7398 case WLAN_FC_STYPE_ACTION:
7399 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
7400 total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
7401 &current_len);
7402 break;
7403
7404 default:
7405 break;
7406 }
7407
7408 return total_len;
7409}
7410
7411
7412static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid,
7413 size_t *current_len)
7414{
7415 struct hostapd_neighbor_entry *nr;
7416 size_t len = *current_len;
7417 u8 *size_offset = (eid - len) + 1;
7418
7419 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
7420 list) {
7421 if (!nr->nr || wpabuf_len(nr->nr) < 12)
7422 continue;
7423
7424 if (nr->short_ssid == hapd->conf->ssid.short_ssid)
7425 continue;
7426
7427 /* Start a new element */
7428 if (!len ||
7429 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7430 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7431 size_offset = eid++;
7432 len = RNR_HEADER_LEN;
7433 }
7434
7435 /* TBTT Information Header subfield (2 octets) */
7436 *eid++ = 0;
7437 /* TBTT Information Length */
7438 *eid++ = RNR_TBTT_INFO_LEN;
7439 /* Operating Class */
7440 *eid++ = wpabuf_head_u8(nr->nr)[10];
7441 /* Channel Number */
7442 *eid++ = wpabuf_head_u8(nr->nr)[11];
7443 len += RNR_TBTT_HEADER_LEN;
7444 /* TBTT Information Set */
7445 /* TBTT Information field */
7446 /* Neighbor AP TBTT Offset */
7447 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
7448 /* BSSID */
7449 os_memcpy(eid, nr->bssid, ETH_ALEN);
7450 eid += ETH_ALEN;
7451 /* Short SSID */
7452 os_memcpy(eid, &nr->short_ssid, 4);
7453 eid += 4;
7454 /* BSS parameters */
7455 *eid++ = nr->bss_parameters;
7456 /* 20 MHz PSD */
7457 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1;
7458 len += RNR_TBTT_INFO_LEN;
7459 *size_offset = (eid - size_offset) - 1;
7460 }
7461
7462 *current_len = len;
7463 return eid;
7464}
7465
7466
7467static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
7468 struct hostapd_data *reporting_hapd,
7469 u8 *eid, size_t *current_len)
7470{
7471 struct hostapd_data *bss;
7472 struct hostapd_iface *iface = hapd->iface;
7473 size_t i, start = 0;
7474 size_t len = *current_len;
7475 u8 *tbtt_count_pos, *eid_start = eid, *size_offset = (eid - len) + 1;
7476 u8 tbtt_count = 0, op_class, channel, bss_param;
7477
7478 if (!(iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !iface->freq)
7479 return eid;
7480
7481 if (ieee80211_freq_to_channel_ext(iface->freq,
7482 hapd->iconf->secondary_channel,
7483 hostapd_get_oper_chwidth(hapd->iconf),
7484 &op_class, &channel) ==
7485 NUM_HOSTAPD_MODES)
7486 return eid;
7487
7488 while (start < iface->num_bss) {
7489 if (!len ||
7490 len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
7491 eid_start = eid;
7492 *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
7493 size_offset = eid++;
7494 len = RNR_HEADER_LEN;
7495 tbtt_count = 0;
7496 }
7497
7498 tbtt_count_pos = eid++;
7499 *eid++ = RNR_TBTT_INFO_LEN;
7500 *eid++ = op_class;
7501 *eid++ = hapd->iconf->channel;
7502 len += RNR_TBTT_HEADER_LEN;
7503
7504 for (i = start; i < iface->num_bss; i++) {
7505 bss_param = 0;
7506 bss = iface->bss[i];
7507 if (!bss || !bss->conf || !bss->started)
7508 continue;
7509
7510 if (bss == reporting_hapd ||
7511 bss->conf->ignore_broadcast_ssid)
7512 continue;
7513
7514 if (len + RNR_TBTT_INFO_LEN > 255 ||
7515 tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
7516 break;
7517
7518 *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
Sunil Ravi89eba102022-09-13 21:04:37 -07007519 os_memcpy(eid, bss->own_addr, ETH_ALEN);
Hai Shaloma20dcd72022-02-04 13:43:00 -08007520 eid += ETH_ALEN;
7521 os_memcpy(eid, &bss->conf->ssid.short_ssid, 4);
7522 eid += 4;
7523 if (bss->conf->ssid.short_ssid ==
7524 reporting_hapd->conf->ssid.short_ssid)
7525 bss_param |= RNR_BSS_PARAM_SAME_SSID;
7526
7527 if (is_6ghz_op_class(hapd->iconf->op_class) &&
7528 bss->conf->unsol_bcast_probe_resp_interval)
7529 bss_param |=
7530 RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE;
7531
7532 bss_param |= RNR_BSS_PARAM_CO_LOCATED;
7533
7534 *eid++ = bss_param;
7535 *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1;
7536 len += RNR_TBTT_INFO_LEN;
7537 tbtt_count += 1;
7538 }
7539
7540 start = i;
7541 *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
7542 *size_offset = (eid - size_offset) - 1;
7543 }
7544
7545 if (tbtt_count == 0)
7546 return eid_start;
7547
7548 *current_len = len;
7549 return eid;
7550}
7551
7552
7553static u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid,
7554 size_t *current_len)
7555{
7556 struct hostapd_iface *iface;
7557 size_t i;
7558
7559 if (!hapd->iface || !hapd->iface->interfaces)
7560 return eid;
7561
7562 for (i = 0; i < hapd->iface->interfaces->count; i++) {
7563 iface = hapd->iface->interfaces->iface[i];
7564
7565 if (iface == hapd->iface ||
7566 !is_6ghz_op_class(iface->conf->op_class))
7567 continue;
7568
7569 eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
7570 current_len);
7571 }
7572
7573 return eid;
7574}
7575
7576
7577u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
7578{
7579 u8 *eid_start = eid;
7580 size_t current_len = 0;
7581 enum colocation_mode mode = get_colocation_mode(hapd);
7582
7583 switch (type) {
7584 case WLAN_FC_STYPE_BEACON:
7585 if (hapd->conf->rnr)
7586 eid = hostapd_eid_nr_db(hapd, eid, &current_len);
7587 /* fallthrough */
7588
7589 case WLAN_FC_STYPE_PROBE_RESP:
7590 if (mode == COLOCATED_LOWER_BAND)
7591 eid = hostapd_eid_rnr_colocation(hapd, eid,
7592 &current_len);
7593
7594 if (hapd->conf->rnr && hapd->iface->num_bss > 1)
7595 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
7596 &current_len);
7597 break;
7598
7599 case WLAN_FC_STYPE_ACTION:
7600 if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
7601 eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
7602 &current_len);
7603 break;
7604
7605 default:
7606 return eid_start;
7607 }
7608
7609 if (eid == eid_start + 2)
7610 return eid_start;
7611
7612 return eid;
7613}
7614
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007615#endif /* CONFIG_NATIVE_WINDOWS */