blob: a872893d11c32639d02840058b3eb78ea81cf974 [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"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070028#include "radius/radius.h"
29#include "radius/radius_client.h"
30#include "p2p/p2p.h"
31#include "wps/wps.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080032#include "fst/fst.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070033#include "hostapd.h"
34#include "beacon.h"
35#include "ieee802_11_auth.h"
36#include "sta_info.h"
37#include "ieee802_1x.h"
38#include "wpa_auth.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080039#include "pmksa_cache_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070040#include "wmm.h"
41#include "ap_list.h"
42#include "accounting.h"
43#include "ap_config.h"
44#include "ap_mlme.h"
45#include "p2p_hostapd.h"
46#include "ap_drv_ops.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080047#include "wnm_ap.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080048#include "hw_features.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070049#include "ieee802_11.h"
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080050#include "dfs.h"
Dmitry Shmidt57c2d392016-02-23 13:40:19 -080051#include "mbo_ap.h"
Dmitry Shmidt849734c2016-05-27 09:59:01 -070052#include "rrm.h"
Dmitry Shmidtaca489e2016-09-28 15:44:14 -070053#include "taxonomy.h"
Dmitry Shmidtebd93af2017-02-21 13:40:44 -080054#include "fils_hlp.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070055#include "dpp_hostapd.h"
56#include "gas_query_ap.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070057
58
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070059#ifdef CONFIG_FILS
60static struct wpabuf *
61prepare_auth_resp_fils(struct hostapd_data *hapd,
62 struct sta_info *sta, u16 *resp,
63 struct rsn_pmksa_cache_entry *pmksa,
64 struct wpabuf *erp_resp,
65 const u8 *msk, size_t msk_len,
66 int *is_pub);
67#endif /* CONFIG_FILS */
Hai Shalom021b0b52019-04-10 11:17:58 -070068static void handle_auth(struct hostapd_data *hapd,
69 const struct ieee80211_mgmt *mgmt, size_t len,
70 int rssi, int from_queue);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070071
Hai Shalom74f70d42019-02-11 14:42:39 -080072
73u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
74{
75 u8 multi_ap_val = 0;
76
77 if (!hapd->conf->multi_ap)
78 return eid;
79 if (hapd->conf->multi_ap & BACKHAUL_BSS)
80 multi_ap_val |= MULTI_AP_BACKHAUL_BSS;
81 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
82 multi_ap_val |= MULTI_AP_FRONTHAUL_BSS;
83
84 return eid + add_multi_ap_ie(eid, 9, multi_ap_val);
85}
86
87
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070088u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
89{
90 u8 *pos = eid;
91 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -070092 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070093
94 if (hapd->iface->current_rates == NULL)
95 return eid;
96
97 *pos++ = WLAN_EID_SUPP_RATES;
98 num = hapd->iface->num_rates;
99 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
100 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800101 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
102 num++;
Hai Shalomfdcde762020-04-02 11:19:20 -0700103 h2e_required = (hapd->conf->sae_pwe == 1 ||
104 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
105 hapd->conf->sae_pwe != 3 &&
106 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
107 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700108 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700109 if (num > 8) {
110 /* rest of the rates are encoded in Extended supported
111 * rates element */
112 num = 8;
113 }
114
115 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700116 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
117 i++) {
118 count++;
119 *pos = hapd->iface->current_rates[i].rate / 5;
120 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
121 *pos |= 0x80;
122 pos++;
123 }
124
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800125 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
126 count++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700127 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800128 }
129
130 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
131 count++;
132 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
133 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700134
Hai Shalomfdcde762020-04-02 11:19:20 -0700135 if (h2e_required && count < 8) {
Hai Shalomc3565922019-10-28 11:58:20 -0700136 count++;
137 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
138 }
139
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700140 return pos;
141}
142
143
144u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
145{
146 u8 *pos = eid;
147 int i, num, count;
Hai Shalomfdcde762020-04-02 11:19:20 -0700148 int h2e_required;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700149
150 if (hapd->iface->current_rates == NULL)
151 return eid;
152
153 num = hapd->iface->num_rates;
154 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
155 num++;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800156 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
157 num++;
Hai Shalomfdcde762020-04-02 11:19:20 -0700158 h2e_required = (hapd->conf->sae_pwe == 1 ||
159 hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
160 hapd->conf->sae_pwe != 3 &&
161 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
162 if (h2e_required)
Hai Shalomc3565922019-10-28 11:58:20 -0700163 num++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700164 if (num <= 8)
165 return eid;
166 num -= 8;
167
168 *pos++ = WLAN_EID_EXT_SUPP_RATES;
169 *pos++ = num;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700170 for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
171 i++) {
172 count++;
173 if (count <= 8)
174 continue; /* already in SuppRates IE */
175 *pos = hapd->iface->current_rates[i].rate / 5;
176 if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
177 *pos |= 0x80;
178 pos++;
179 }
180
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800181 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
182 count++;
183 if (count > 8)
184 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
185 }
186
187 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
188 count++;
189 if (count > 8)
190 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
191 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700192
Hai Shalomfdcde762020-04-02 11:19:20 -0700193 if (h2e_required) {
Hai Shalomc3565922019-10-28 11:58:20 -0700194 count++;
195 if (count > 8)
196 *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
197 }
198
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700199 return pos;
200}
201
202
Hai Shalomfdcde762020-04-02 11:19:20 -0700203u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
204 size_t len)
205{
206 size_t i;
207
208 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
209 if (hapd->conf->radio_measurements[i])
210 break;
211 }
212
213 if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
214 return eid;
215
216 *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
217 *eid++ = RRM_CAPABILITIES_IE_LEN;
218 os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
219
220 return eid + RRM_CAPABILITIES_IE_LEN;
221}
222
223
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700224u16 hostapd_own_capab_info(struct hostapd_data *hapd)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700225{
226 int capab = WLAN_CAPABILITY_ESS;
Hai Shalomfdcde762020-04-02 11:19:20 -0700227 int privacy = 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800228 int dfs;
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700229 int i;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800230
231 /* Check if any of configured channels require DFS */
232 dfs = hostapd_is_dfs_required(hapd->iface);
233 if (dfs < 0) {
234 wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
235 dfs);
236 dfs = 0;
237 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700238
239 if (hapd->iface->num_sta_no_short_preamble == 0 &&
240 hapd->iconf->preamble == SHORT_PREAMBLE)
241 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
242
Hai Shalomfdcde762020-04-02 11:19:20 -0700243#ifdef CONFIG_WEP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700244 privacy = hapd->conf->ssid.wep.keys_set;
245
246 if (hapd->conf->ieee802_1x &&
247 (hapd->conf->default_wep_key_len ||
248 hapd->conf->individual_wep_key_len))
249 privacy = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -0700250#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700251
252 if (hapd->conf->wpa)
253 privacy = 1;
254
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800255#ifdef CONFIG_HS20
256 if (hapd->conf->osen)
257 privacy = 1;
258#endif /* CONFIG_HS20 */
259
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700260 if (privacy)
261 capab |= WLAN_CAPABILITY_PRIVACY;
262
263 if (hapd->iface->current_mode &&
264 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
265 hapd->iface->num_sta_no_short_slot_time == 0)
266 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
267
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800268 /*
269 * Currently, Spectrum Management capability bit is set when directly
270 * requested in configuration by spectrum_mgmt_required or when AP is
271 * running on DFS channel.
272 * TODO: Also consider driver support for TPC to set Spectrum Mgmt bit
273 */
274 if (hapd->iface->current_mode &&
275 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
276 (hapd->iconf->spectrum_mgmt_required || dfs))
277 capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
278
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700279 for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
280 if (hapd->conf->radio_measurements[i]) {
281 capab |= IEEE80211_CAP_RRM;
282 break;
283 }
284 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800285
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700286 return capab;
287}
288
289
Hai Shalomfdcde762020-04-02 11:19:20 -0700290#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800291#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700292static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
293 u16 auth_transaction, const u8 *challenge,
294 int iswep)
295{
296 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
297 HOSTAPD_LEVEL_DEBUG,
298 "authentication (shared key, transaction %d)",
299 auth_transaction);
300
301 if (auth_transaction == 1) {
302 if (!sta->challenge) {
303 /* Generate a pseudo-random challenge */
304 u8 key[8];
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800305
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700306 sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
307 if (sta->challenge == NULL)
308 return WLAN_STATUS_UNSPECIFIED_FAILURE;
309
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800310 if (os_get_random(key, sizeof(key)) < 0) {
311 os_free(sta->challenge);
312 sta->challenge = NULL;
313 return WLAN_STATUS_UNSPECIFIED_FAILURE;
314 }
315
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700316 rc4_skip(key, sizeof(key), 0,
317 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
318 }
319 return 0;
320 }
321
322 if (auth_transaction != 3)
323 return WLAN_STATUS_UNSPECIFIED_FAILURE;
324
325 /* Transaction 3 */
326 if (!iswep || !sta->challenge || !challenge ||
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700327 os_memcmp_const(sta->challenge, challenge,
328 WLAN_AUTH_CHALLENGE_LEN)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700329 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
330 HOSTAPD_LEVEL_INFO,
331 "shared key authentication - invalid "
332 "challenge-response");
333 return WLAN_STATUS_CHALLENGE_FAIL;
334 }
335
336 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
337 HOSTAPD_LEVEL_DEBUG,
338 "authentication OK (shared key)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700339 sta->flags |= WLAN_STA_AUTH;
340 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700341 os_free(sta->challenge);
342 sta->challenge = NULL;
343
344 return 0;
345}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800346#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700347#endif /* CONFIG_WEP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700348
349
Hai Shalomfdcde762020-04-02 11:19:20 -0700350static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800351 const u8 *dst, const u8 *bssid,
352 u16 auth_alg, u16 auth_transaction, u16 resp,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700353 const u8 *ies, size_t ies_len, const char *dbg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700354{
355 struct ieee80211_mgmt *reply;
356 u8 *buf;
357 size_t rlen;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800358 int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700359
360 rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
361 buf = os_zalloc(rlen);
362 if (buf == NULL)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800363 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700364
365 reply = (struct ieee80211_mgmt *) buf;
366 reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
367 WLAN_FC_STYPE_AUTH);
368 os_memcpy(reply->da, dst, ETH_ALEN);
369 os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
370 os_memcpy(reply->bssid, bssid, ETH_ALEN);
371
372 reply->u.auth.auth_alg = host_to_le16(auth_alg);
373 reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
374 reply->u.auth.status_code = host_to_le16(resp);
375
376 if (ies && ies_len)
377 os_memcpy(reply->u.auth.variable, ies, ies_len);
378
379 wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700380 " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700381 MAC2STR(dst), auth_alg, auth_transaction,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700382 resp, (unsigned long) ies_len, dbg);
Hai Shalomfdcde762020-04-02 11:19:20 -0700383#ifdef CONFIG_TESTING_OPTIONS
384#ifdef CONFIG_SAE
385 if (hapd->conf->sae_confirm_immediate == 2 &&
386 auth_alg == WLAN_AUTH_SAE) {
387 if (auth_transaction == 1 && sta &&
388 (resp == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -0700389 resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
390 resp == WLAN_STATUS_SAE_PK)) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700391 wpa_printf(MSG_DEBUG,
392 "TESTING: Postpone SAE Commit transmission until Confirm is ready");
393 os_free(sta->sae_postponed_commit);
394 sta->sae_postponed_commit = buf;
395 sta->sae_postponed_commit_len = rlen;
396 return WLAN_STATUS_SUCCESS;
397 }
398
399 if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
400 wpa_printf(MSG_DEBUG,
401 "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
402 if (hostapd_drv_send_mlme(hapd,
403 sta->sae_postponed_commit,
404 sta->sae_postponed_commit_len,
405 0, NULL, 0, 0) < 0)
406 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
407 os_free(sta->sae_postponed_commit);
408 sta->sae_postponed_commit = NULL;
409 sta->sae_postponed_commit_len = 0;
410 }
411 }
412#endif /* CONFIG_SAE */
413#endif /* CONFIG_TESTING_OPTIONS */
414 if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800415 wpa_printf(MSG_INFO, "send_auth_reply: send failed");
416 else
417 reply_res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700418
419 os_free(buf);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800420
421 return reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700422}
423
424
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800425#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700426static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
427 u16 auth_transaction, u16 status,
428 const u8 *ies, size_t ies_len)
429{
430 struct hostapd_data *hapd = ctx;
431 struct sta_info *sta;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800432 int reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700433
Hai Shalomfdcde762020-04-02 11:19:20 -0700434 reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700435 auth_transaction, status, ies, ies_len,
436 "auth-ft-finish");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700437
438 sta = ap_get_sta(hapd, dst);
439 if (sta == NULL)
440 return;
441
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800442 if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
443 status != WLAN_STATUS_SUCCESS)) {
444 hostapd_drv_sta_remove(hapd, sta->addr);
445 sta->added_unassoc = 0;
446 return;
447 }
448
449 if (status != WLAN_STATUS_SUCCESS)
450 return;
451
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700452 hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
453 HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
454 sta->flags |= WLAN_STA_AUTH;
455 mlme_authenticate_indication(hapd, sta);
456}
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800457#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700458
459
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800460#ifdef CONFIG_SAE
461
Roshan Pius3a1667e2018-07-03 15:17:14 -0700462static void sae_set_state(struct sta_info *sta, enum sae_state state,
463 const char *reason)
464{
465 wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
466 sae_state_txt(sta->sae->state), sae_state_txt(state),
467 MAC2STR(sta->addr), reason);
468 sta->sae->state = state;
469}
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800470
471
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800472static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
Hai Shalomc3565922019-10-28 11:58:20 -0700473 struct sta_info *sta, int update,
474 int status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800475{
476 struct wpabuf *buf;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700477 const char *password = NULL;
478 struct sae_password_entry *pw;
479 const char *rx_id = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700480 int use_pt = 0;
481 struct sae_pt *pt = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700482 const struct sae_pk *pk = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800483
Hai Shalomc3565922019-10-28 11:58:20 -0700484 if (sta->sae->tmp) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700485 rx_id = sta->sae->tmp->pw_id;
Hai Shalom899fcc72020-10-19 14:38:18 -0700486 use_pt = sta->sae->h2e;
487#ifdef CONFIG_SAE_PK
488 os_memcpy(sta->sae->tmp->own_addr, hapd->own_addr, ETH_ALEN);
489 os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
490#endif /* CONFIG_SAE_PK */
Hai Shalomc3565922019-10-28 11:58:20 -0700491 }
492
Hai Shalomfdcde762020-04-02 11:19:20 -0700493 if (rx_id && hapd->conf->sae_pwe != 3)
494 use_pt = 1;
495 else if (status_code == WLAN_STATUS_SUCCESS)
Hai Shalomc3565922019-10-28 11:58:20 -0700496 use_pt = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700497 else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
498 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomc3565922019-10-28 11:58:20 -0700499 use_pt = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700500
501 for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
502 if (!is_broadcast_ether_addr(pw->peer_addr) &&
503 os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
504 continue;
505 if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
506 continue;
507 if (rx_id && pw->identifier &&
508 os_strcmp(rx_id, pw->identifier) != 0)
509 continue;
510 password = pw->password;
Hai Shalomc3565922019-10-28 11:58:20 -0700511 pt = pw->pt;
Hai Shalom899fcc72020-10-19 14:38:18 -0700512 if (!(hapd->conf->mesh & MESH_ENABLED))
513 pk = pw->pk;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700514 break;
515 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700516 if (!password) {
Hai Shalomc3565922019-10-28 11:58:20 -0700517 password = hapd->conf->ssid.wpa_passphrase;
518 pt = hapd->conf->ssid.pt;
519 }
520 if (!password || (use_pt && !pt)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800521 wpa_printf(MSG_DEBUG, "SAE: No password available");
522 return NULL;
523 }
524
Hai Shalomc3565922019-10-28 11:58:20 -0700525 if (update && use_pt &&
526 sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
Hai Shalom899fcc72020-10-19 14:38:18 -0700527 NULL, pk) < 0)
Hai Shalomc3565922019-10-28 11:58:20 -0700528 return NULL;
529
530 if (update && !use_pt &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800531 sae_prepare_commit(hapd->own_addr, sta->addr,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700532 (u8 *) password, os_strlen(password), rx_id,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800533 sta->sae) < 0) {
534 wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
535 return NULL;
536 }
537
Hai Shalom021b0b52019-04-10 11:17:58 -0700538 if (pw && pw->vlan_id) {
539 if (!sta->sae->tmp) {
540 wpa_printf(MSG_INFO,
541 "SAE: No temporary data allocated - cannot store VLAN ID");
542 return NULL;
543 }
544 sta->sae->tmp->vlan_id = pw->vlan_id;
545 }
546
Roshan Pius3a1667e2018-07-03 15:17:14 -0700547 buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
548 (rx_id ? 3 + os_strlen(rx_id) : 0));
Hai Shalomfdcde762020-04-02 11:19:20 -0700549 if (buf &&
550 sae_write_commit(sta->sae, buf, sta->sae->tmp ?
551 sta->sae->tmp->anti_clogging_token : NULL,
552 rx_id) < 0) {
553 wpabuf_free(buf);
554 buf = NULL;
555 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800556
557 return buf;
558}
559
560
561static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
562 struct sta_info *sta)
563{
564 struct wpabuf *buf;
565
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800566 buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800567 if (buf == NULL)
568 return NULL;
569
Hai Shalom899fcc72020-10-19 14:38:18 -0700570#ifdef CONFIG_SAE_PK
571#ifdef CONFIG_TESTING_OPTIONS
572 if (sta->sae->tmp)
573 sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
574#endif /* CONFIG_TESTING_OPTIONS */
575#endif /* CONFIG_SAE_PK */
576
577 if (sae_write_confirm(sta->sae, buf) < 0) {
578 wpabuf_free(buf);
579 return NULL;
580 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800581
582 return buf;
583}
584
585
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800586static int auth_sae_send_commit(struct hostapd_data *hapd,
587 struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700588 const u8 *bssid, int update, int status_code)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800589{
590 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800591 int reply_res;
Hai Shalomc3565922019-10-28 11:58:20 -0700592 u16 status;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800593
Hai Shalomc3565922019-10-28 11:58:20 -0700594 data = auth_build_sae_commit(hapd, sta, update, status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700595 if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
596 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800597 if (data == NULL)
598 return WLAN_STATUS_UNSPECIFIED_FAILURE;
599
Hai Shalom899fcc72020-10-19 14:38:18 -0700600 if (sta->sae->tmp && sta->sae->pk)
601 status = WLAN_STATUS_SAE_PK;
602 else if (sta->sae->tmp && sta->sae->h2e)
603 status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
604 else
605 status = WLAN_STATUS_SUCCESS;
606#ifdef CONFIG_TESTING_OPTIONS
607 if (hapd->conf->sae_commit_status >= 0 &&
608 hapd->conf->sae_commit_status != status) {
609 wpa_printf(MSG_INFO,
610 "TESTING: Override SAE commit status code %u --> %d",
611 status, hapd->conf->sae_commit_status);
612 status = hapd->conf->sae_commit_status;
613 }
614#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomfdcde762020-04-02 11:19:20 -0700615 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
616 WLAN_AUTH_SAE, 1,
Hai Shalomc3565922019-10-28 11:58:20 -0700617 status, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700618 wpabuf_len(data), "sae-send-commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800619
620 wpabuf_free(data);
621
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800622 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800623}
624
625
626static int auth_sae_send_confirm(struct hostapd_data *hapd,
627 struct sta_info *sta,
628 const u8 *bssid)
629{
630 struct wpabuf *data;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800631 int reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800632
633 data = auth_build_sae_confirm(hapd, sta);
634 if (data == NULL)
635 return WLAN_STATUS_UNSPECIFIED_FAILURE;
636
Hai Shalomfdcde762020-04-02 11:19:20 -0700637 reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
638 WLAN_AUTH_SAE, 2,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800639 WLAN_STATUS_SUCCESS, wpabuf_head(data),
Roshan Pius3a1667e2018-07-03 15:17:14 -0700640 wpabuf_len(data), "sae-send-confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800641
642 wpabuf_free(data);
643
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800644 return reply_res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800645}
646
647
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800648static int use_sae_anti_clogging(struct hostapd_data *hapd)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800649{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800650 struct sta_info *sta;
651 unsigned int open = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800652
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800653 if (hapd->conf->sae_anti_clogging_threshold == 0)
654 return 1;
655
656 for (sta = hapd->sta_list; sta; sta = sta->next) {
657 if (!sta->sae)
658 continue;
659 if (sta->sae->state != SAE_COMMITTED &&
660 sta->sae->state != SAE_CONFIRMED)
661 continue;
662 open++;
663 if (open >= hapd->conf->sae_anti_clogging_threshold)
664 return 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800665 }
666
Hai Shalom021b0b52019-04-10 11:17:58 -0700667 /* In addition to already existing open SAE sessions, check whether
668 * there are enough pending commit messages in the processing queue to
669 * potentially result in too many open sessions. */
670 if (open + dl_list_len(&hapd->sae_commit_queue) >=
671 hapd->conf->sae_anti_clogging_threshold)
672 return 1;
673
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800674 return 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800675}
676
677
Hai Shalomfdcde762020-04-02 11:19:20 -0700678static int sae_token_hash(struct hostapd_data *hapd, const u8 *addr, u8 *idx)
Hai Shalom021b0b52019-04-10 11:17:58 -0700679{
680 u8 hash[SHA256_MAC_LEN];
681
Hai Shalomfdcde762020-04-02 11:19:20 -0700682 if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
683 addr, ETH_ALEN, hash) < 0)
684 return -1;
685 *idx = hash[0];
686 return 0;
Hai Shalom021b0b52019-04-10 11:17:58 -0700687}
688
689
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800690static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
691 const u8 *token, size_t token_len)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800692{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800693 u8 mac[SHA256_MAC_LEN];
Hai Shalom021b0b52019-04-10 11:17:58 -0700694 const u8 *addrs[2];
695 size_t len[2];
696 u16 token_idx;
697 u8 idx;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800698
Hai Shalomfdcde762020-04-02 11:19:20 -0700699 if (token_len != SHA256_MAC_LEN || sae_token_hash(hapd, addr, &idx) < 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800700 return -1;
Hai Shalom021b0b52019-04-10 11:17:58 -0700701 token_idx = hapd->sae_pending_token_idx[idx];
702 if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
703 wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
704 MACSTR " - token_idx 0x%04x, expected 0x%04x",
705 MAC2STR(addr), WPA_GET_BE16(token), token_idx);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800706 return -1;
Hai Shalom021b0b52019-04-10 11:17:58 -0700707 }
708
709 addrs[0] = addr;
710 len[0] = ETH_ALEN;
711 addrs[1] = token;
712 len[1] = 2;
713 if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
714 2, addrs, len, mac) < 0 ||
715 os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
716 return -1;
717
718 hapd->sae_pending_token_idx[idx] = 0; /* invalidate used token */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800719
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800720 return 0;
721}
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800722
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800723
724static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
Hai Shalomfdcde762020-04-02 11:19:20 -0700725 int group, const u8 *addr, int h2e)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800726{
727 struct wpabuf *buf;
728 u8 *token;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800729 struct os_reltime now;
Hai Shalom021b0b52019-04-10 11:17:58 -0700730 u8 idx[2];
731 const u8 *addrs[2];
732 size_t len[2];
733 u8 p_idx;
734 u16 token_idx;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800735
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800736 os_get_reltime(&now);
737 if (!os_reltime_initialized(&hapd->last_sae_token_key_update) ||
Hai Shalom021b0b52019-04-10 11:17:58 -0700738 os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60) ||
739 hapd->sae_token_idx == 0xffff) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800740 if (random_get_bytes(hapd->sae_token_key,
741 sizeof(hapd->sae_token_key)) < 0)
742 return NULL;
743 wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
744 hapd->sae_token_key, sizeof(hapd->sae_token_key));
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800745 hapd->last_sae_token_key_update = now;
Hai Shalom021b0b52019-04-10 11:17:58 -0700746 hapd->sae_token_idx = 0;
747 os_memset(hapd->sae_pending_token_idx, 0,
748 sizeof(hapd->sae_pending_token_idx));
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800749 }
750
Hai Shalomfdcde762020-04-02 11:19:20 -0700751 buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800752 if (buf == NULL)
753 return NULL;
754
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800755 wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
756
Hai Shalomfdcde762020-04-02 11:19:20 -0700757 if (h2e) {
758 /* Encapsulate Anti-clogging Token field in a container IE */
759 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
760 wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
761 wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
762 }
763
764 if (sae_token_hash(hapd, addr, &p_idx) < 0) {
765 wpabuf_free(buf);
766 return NULL;
767 }
Hai Shalom021b0b52019-04-10 11:17:58 -0700768 token_idx = hapd->sae_pending_token_idx[p_idx];
769 if (!token_idx) {
770 hapd->sae_token_idx++;
771 token_idx = hapd->sae_token_idx;
772 hapd->sae_pending_token_idx[p_idx] = token_idx;
773 }
774 WPA_PUT_BE16(idx, token_idx);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800775 token = wpabuf_put(buf, SHA256_MAC_LEN);
Hai Shalom021b0b52019-04-10 11:17:58 -0700776 addrs[0] = addr;
777 len[0] = ETH_ALEN;
778 addrs[1] = idx;
779 len[1] = sizeof(idx);
780 if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
781 2, addrs, len, token) < 0) {
782 wpabuf_free(buf);
783 return NULL;
784 }
785 WPA_PUT_BE16(token, token_idx);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800786
787 return buf;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800788}
789
790
Roshan Pius3a1667e2018-07-03 15:17:14 -0700791static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800792{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700793 if (sta->sae->sync > hapd->conf->sae_sync) {
794 sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800795 sta->sae->sync = 0;
796 return -1;
797 }
798 return 0;
799}
800
801
802static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
803{
804 struct hostapd_data *hapd = eloop_ctx;
805 struct sta_info *sta = eloop_data;
806 int ret;
807
Roshan Pius3a1667e2018-07-03 15:17:14 -0700808 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800809 return;
810 sta->sae->sync++;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700811 wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
Roshan Pius3a1667e2018-07-03 15:17:14 -0700812 " (sync=%d state=%s)",
813 MAC2STR(sta->addr), sta->sae->sync,
814 sae_state_txt(sta->sae->state));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800815
816 switch (sta->sae->state) {
817 case SAE_COMMITTED:
Hai Shalomc3565922019-10-28 11:58:20 -0700818 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800819 eloop_register_timeout(0,
820 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800821 auth_sae_retransmit_timer, hapd, sta);
822 break;
823 case SAE_CONFIRMED:
824 ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800825 eloop_register_timeout(0,
826 hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800827 auth_sae_retransmit_timer, hapd, sta);
828 break;
829 default:
830 ret = -1;
831 break;
832 }
833
834 if (ret != WLAN_STATUS_SUCCESS)
835 wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
836}
837
838
839void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
840{
841 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
842}
843
844
845static void sae_set_retransmit_timer(struct hostapd_data *hapd,
846 struct sta_info *sta)
847{
848 if (!(hapd->conf->mesh & MESH_ENABLED))
849 return;
850
851 eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800852 eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800853 auth_sae_retransmit_timer, hapd, sta);
854}
855
856
Hai Shalom5f92bc92019-04-18 11:54:11 -0700857static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
858 struct sta_info *sta, u16 status)
859{
860 struct external_auth params;
861
862 os_memset(&params, 0, sizeof(params));
863 params.status = status;
864 params.bssid = sta->addr;
Hai Shalom81f62d82019-07-22 12:10:00 -0700865 if (status == WLAN_STATUS_SUCCESS && sta->sae &&
866 !hapd->conf->disable_pmksa_caching)
Hai Shalom5f92bc92019-04-18 11:54:11 -0700867 params.pmkid = sta->sae->pmkid;
868
869 hostapd_drv_send_external_auth_status(hapd, &params);
870}
871
872
Dmitry Shmidte4663042016-04-04 10:07:49 -0700873void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
874{
Hai Shalom021b0b52019-04-10 11:17:58 -0700875#ifndef CONFIG_NO_VLAN
876 struct vlan_description vlan_desc;
877
878 if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
879 wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
880 " to VLAN ID %d",
881 MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
882
883 os_memset(&vlan_desc, 0, sizeof(vlan_desc));
884 vlan_desc.notempty = 1;
885 vlan_desc.untagged = sta->sae->tmp->vlan_id;
886 if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
887 wpa_printf(MSG_INFO,
888 "Invalid VLAN ID %d in sae_password",
889 sta->sae->tmp->vlan_id);
890 return;
891 }
892
893 if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
894 ap_sta_bind_vlan(hapd, sta) < 0) {
895 wpa_printf(MSG_INFO,
896 "Failed to assign VLAN ID %d from sae_password to "
897 MACSTR, sta->sae->tmp->vlan_id,
898 MAC2STR(sta->addr));
899 return;
900 }
901 }
902#endif /* CONFIG_NO_VLAN */
903
Dmitry Shmidte4663042016-04-04 10:07:49 -0700904 sta->flags |= WLAN_STA_AUTH;
905 sta->auth_alg = WLAN_AUTH_SAE;
906 mlme_authenticate_indication(hapd, sta);
907 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700908 sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
Hai Shalomfdcde762020-04-02 11:19:20 -0700909 crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
910 sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
911 sta->sae->peer_commit_scalar = NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -0700912 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
913 sta->sae->pmk, sta->sae->pmkid);
Hai Shalom5f92bc92019-04-18 11:54:11 -0700914 sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
Dmitry Shmidte4663042016-04-04 10:07:49 -0700915}
916
917
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800918static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
Hai Shalomc3565922019-10-28 11:58:20 -0700919 const u8 *bssid, u16 auth_transaction, u16 status_code,
920 int allow_reuse, int *sta_removed)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800921{
922 int ret;
923
Hai Shalom5f92bc92019-04-18 11:54:11 -0700924 *sta_removed = 0;
925
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800926 if (auth_transaction != 1 && auth_transaction != 2)
927 return WLAN_STATUS_UNSPECIFIED_FAILURE;
928
Roshan Pius3a1667e2018-07-03 15:17:14 -0700929 wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
930 MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
931 auth_transaction);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800932 switch (sta->sae->state) {
933 case SAE_NOTHING:
934 if (auth_transaction == 1) {
Hai Shalom899fcc72020-10-19 14:38:18 -0700935 if (sta->sae->tmp) {
936 sta->sae->h2e =
937 (status_code ==
938 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
939 status_code == WLAN_STATUS_SAE_PK);
940 sta->sae->pk =
941 status_code == WLAN_STATUS_SAE_PK;
942 }
Hai Shalom021b0b52019-04-10 11:17:58 -0700943 ret = auth_sae_send_commit(hapd, sta, bssid,
Hai Shalomc3565922019-10-28 11:58:20 -0700944 !allow_reuse, status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800945 if (ret)
946 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700947 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800948
949 if (sae_process_commit(sta->sae) < 0)
950 return WLAN_STATUS_UNSPECIFIED_FAILURE;
951
952 /*
Hai Shalomc3565922019-10-28 11:58:20 -0700953 * In mesh case, both Commit and Confirm are sent
954 * immediately. In infrastructure BSS, by default, only
955 * a single Authentication frame (Commit) is expected
956 * from the AP here and the second one (Confirm) will
957 * be sent once the STA has sent its second
958 * Authentication frame (Confirm). This behavior can be
959 * overridden with explicit configuration so that the
960 * infrastructure BSS case sends both frames together.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800961 */
Hai Shalomc3565922019-10-28 11:58:20 -0700962 if ((hapd->conf->mesh & MESH_ENABLED) ||
963 hapd->conf->sae_confirm_immediate) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800964 /*
965 * Send both Commit and Confirm immediately
966 * based on SAE finite state machine
967 * Nothing -> Confirm transition.
968 */
969 ret = auth_sae_send_confirm(hapd, sta, bssid);
970 if (ret)
971 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700972 sae_set_state(sta, SAE_CONFIRMED,
973 "Sent Confirm (mesh)");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800974 } else {
975 /*
976 * For infrastructure BSS, send only the Commit
977 * message now to get alternating sequence of
978 * Authentication frames between the AP and STA.
979 * Confirm will be sent in
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800980 * Committed -> Confirmed/Accepted transition
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800981 * when receiving Confirm from STA.
982 */
983 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800984 sta->sae->sync = 0;
985 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800986 } else {
987 hostapd_logger(hapd, sta->addr,
988 HOSTAPD_MODULE_IEEE80211,
989 HOSTAPD_LEVEL_DEBUG,
990 "SAE confirm before commit");
991 }
992 break;
993 case SAE_COMMITTED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800994 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800995 if (auth_transaction == 1) {
996 if (sae_process_commit(sta->sae) < 0)
997 return WLAN_STATUS_UNSPECIFIED_FAILURE;
998
999 ret = auth_sae_send_confirm(hapd, sta, bssid);
1000 if (ret)
1001 return ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001002 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001003 sta->sae->sync = 0;
1004 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001005 } else if (hapd->conf->mesh & MESH_ENABLED) {
1006 /*
1007 * In mesh case, follow SAE finite state machine and
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001008 * send Commit now, if sync count allows.
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001009 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001010 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001011 return WLAN_STATUS_SUCCESS;
1012 sta->sae->sync++;
1013
Hai Shalomc3565922019-10-28 11:58:20 -07001014 ret = auth_sae_send_commit(hapd, sta, bssid, 0,
1015 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001016 if (ret)
1017 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001018
1019 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001020 } else {
1021 /*
1022 * For instructure BSS, send the postponed Confirm from
1023 * Nothing -> Confirmed transition that was reduced to
1024 * Nothing -> Committed above.
1025 */
1026 ret = auth_sae_send_confirm(hapd, sta, bssid);
1027 if (ret)
1028 return ret;
1029
Roshan Pius3a1667e2018-07-03 15:17:14 -07001030 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001031
1032 /*
1033 * Since this was triggered on Confirm RX, run another
1034 * step to get to Accepted without waiting for
1035 * additional events.
1036 */
Hai Shalom021b0b52019-04-10 11:17:58 -07001037 return sae_sm_step(hapd, sta, bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001038 WLAN_STATUS_SUCCESS, 0, sta_removed);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001039 }
1040 break;
1041 case SAE_CONFIRMED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001042 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001043 if (auth_transaction == 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001044 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001045 return WLAN_STATUS_SUCCESS;
1046 sta->sae->sync++;
1047
Hai Shalomc3565922019-10-28 11:58:20 -07001048 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1049 status_code);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001050 if (ret)
1051 return ret;
1052
1053 if (sae_process_commit(sta->sae) < 0)
1054 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1055
1056 ret = auth_sae_send_confirm(hapd, sta, bssid);
1057 if (ret)
1058 return ret;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001059
1060 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001061 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001062 sta->sae->send_confirm = 0xffff;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001063 sae_accept_sta(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001064 }
1065 break;
1066 case SAE_ACCEPTED:
Roshan Pius3a1667e2018-07-03 15:17:14 -07001067 if (auth_transaction == 1 &&
1068 (hapd->conf->mesh & MESH_ENABLED)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001069 wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
1070 ") doing reauthentication",
1071 MAC2STR(sta->addr));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001072 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
Hai Shalom5f92bc92019-04-18 11:54:11 -07001073 ap_free_sta(hapd, sta);
1074 *sta_removed = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001075 } else if (auth_transaction == 1) {
1076 wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
Hai Shalomc3565922019-10-28 11:58:20 -07001077 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
1078 status_code);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001079 if (ret)
1080 return ret;
1081 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
1082
1083 if (sae_process_commit(sta->sae) < 0)
1084 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1085 sta->sae->sync = 0;
1086 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001087 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001088 if (sae_check_big_sync(hapd, sta))
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001089 return WLAN_STATUS_SUCCESS;
1090 sta->sae->sync++;
1091
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001092 ret = auth_sae_send_confirm(hapd, sta, bssid);
1093 sae_clear_temp_data(sta->sae);
1094 if (ret)
1095 return ret;
1096 }
1097 break;
1098 default:
1099 wpa_printf(MSG_ERROR, "SAE: invalid state %d",
1100 sta->sae->state);
1101 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1102 }
1103 return WLAN_STATUS_SUCCESS;
1104}
1105
1106
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001107static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
1108{
1109 struct sae_data *sae = sta->sae;
1110 int i, *groups = hapd->conf->sae_groups;
Hai Shalom021b0b52019-04-10 11:17:58 -07001111 int default_groups[] = { 19, 0 };
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001112
1113 if (sae->state != SAE_COMMITTED)
1114 return;
1115
1116 wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
1117
Hai Shalom021b0b52019-04-10 11:17:58 -07001118 if (!groups)
1119 groups = default_groups;
1120 for (i = 0; groups[i] > 0; i++) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001121 if (sae->group == groups[i])
1122 break;
1123 }
1124
Hai Shalom021b0b52019-04-10 11:17:58 -07001125 if (groups[i] <= 0) {
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001126 wpa_printf(MSG_DEBUG,
1127 "SAE: Previously selected group not found from the current configuration");
1128 return;
1129 }
1130
1131 for (;;) {
1132 i++;
1133 if (groups[i] <= 0) {
1134 wpa_printf(MSG_DEBUG,
1135 "SAE: No alternative group enabled");
1136 return;
1137 }
1138
1139 if (sae_set_group(sae, groups[i]) < 0)
1140 continue;
1141
1142 break;
1143 }
1144 wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
1145}
1146
1147
Hai Shalomc3565922019-10-28 11:58:20 -07001148static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
1149{
Hai Shalomfdcde762020-04-02 11:19:20 -07001150 int sae_pwe = hapd->conf->sae_pwe;
1151 int id_in_use;
1152
1153 id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
1154 if (id_in_use == 2 && sae_pwe != 3)
1155 sae_pwe = 1;
1156 else if (id_in_use == 1 && sae_pwe == 0)
1157 sae_pwe = 2;
Hai Shalom899fcc72020-10-19 14:38:18 -07001158#ifdef CONFIG_SAE_PK
1159 if (sae_pwe == 0 && hostapd_sae_pk_in_use(hapd->conf))
1160 sae_pwe = 2;
1161#endif /* CONFIG_SAE_PK */
Hai Shalomfdcde762020-04-02 11:19:20 -07001162
1163 return ((sae_pwe == 0 || sae_pwe == 3) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001164 status_code == WLAN_STATUS_SUCCESS) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07001165 (sae_pwe == 1 &&
Hai Shalom899fcc72020-10-19 14:38:18 -07001166 (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1167 status_code == WLAN_STATUS_SAE_PK)) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07001168 (sae_pwe == 2 &&
Hai Shalomc3565922019-10-28 11:58:20 -07001169 (status_code == WLAN_STATUS_SUCCESS ||
Hai Shalom899fcc72020-10-19 14:38:18 -07001170 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1171 status_code == WLAN_STATUS_SAE_PK));
Hai Shalomc3565922019-10-28 11:58:20 -07001172}
1173
1174
1175static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
1176{
1177 int *groups = hapd->conf->sae_groups;
1178 int default_groups[] = { 19, 0 };
1179 int i;
1180
1181 if (!groups)
1182 groups = default_groups;
1183
1184 for (i = 0; groups[i] > 0; i++) {
1185 if (groups[i] == group)
1186 return 1;
1187 }
1188
1189 return 0;
1190}
1191
1192
1193static int check_sae_rejected_groups(struct hostapd_data *hapd,
Hai Shalom899fcc72020-10-19 14:38:18 -07001194 struct sae_data *sae)
Hai Shalomc3565922019-10-28 11:58:20 -07001195{
Hai Shalom899fcc72020-10-19 14:38:18 -07001196 const struct wpabuf *groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001197 size_t i, count;
1198 const u8 *pos;
1199
Hai Shalom899fcc72020-10-19 14:38:18 -07001200 if (!sae->tmp)
1201 return 0;
1202 groups = sae->tmp->peer_rejected_groups;
Hai Shalomc3565922019-10-28 11:58:20 -07001203 if (!groups)
1204 return 0;
1205
1206 pos = wpabuf_head(groups);
1207 count = wpabuf_len(groups) / 2;
1208 for (i = 0; i < count; i++) {
1209 int enabled;
1210 u16 group;
1211
1212 group = WPA_GET_LE16(pos);
1213 pos += 2;
1214 enabled = sae_is_group_enabled(hapd, group);
1215 wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
1216 group, enabled ? "enabled" : "disabled");
1217 if (enabled)
1218 return 1;
1219 }
1220
1221 return 0;
1222}
1223
1224
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001225static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
1226 const struct ieee80211_mgmt *mgmt, size_t len,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001227 u16 auth_transaction, u16 status_code)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001228{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001229 int resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001230 struct wpabuf *data = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07001231 int *groups = hapd->conf->sae_groups;
1232 int default_groups[] = { 19, 0 };
1233 const u8 *pos, *end;
Hai Shalom5f92bc92019-04-18 11:54:11 -07001234 int sta_removed = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07001235
1236 if (!groups)
1237 groups = default_groups;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001238
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001239#ifdef CONFIG_TESTING_OPTIONS
1240 if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001241 wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
1242 pos = mgmt->u.auth.variable;
1243 end = ((const u8 *) mgmt) + len;
Hai Shalom899fcc72020-10-19 14:38:18 -07001244 resp = status_code;
Hai Shalomfdcde762020-04-02 11:19:20 -07001245 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001246 auth_transaction, resp, pos, end - pos,
1247 "auth-sae-reflection-attack");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001248 goto remove_sta;
1249 }
1250
1251 if (hapd->conf->sae_commit_override && auth_transaction == 1) {
1252 wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
Hai Shalomfdcde762020-04-02 11:19:20 -07001253 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001254 auth_transaction, resp,
1255 wpabuf_head(hapd->conf->sae_commit_override),
Roshan Pius3a1667e2018-07-03 15:17:14 -07001256 wpabuf_len(hapd->conf->sae_commit_override),
1257 "sae-commit-override");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001258 goto remove_sta;
1259 }
1260#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001261 if (!sta->sae) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001262 if (auth_transaction != 1 ||
Hai Shalomc3565922019-10-28 11:58:20 -07001263 !sae_status_success(hapd, status_code)) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001264 wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
1265 status_code);
1266 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1267 goto reply;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001268 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001269 sta->sae = os_zalloc(sizeof(*sta->sae));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001270 if (!sta->sae) {
1271 resp = -1;
1272 goto remove_sta;
1273 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001274 sae_set_state(sta, SAE_NOTHING, "Init");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001275 sta->sae->sync = 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001276 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001277
Dmitry Shmidte4663042016-04-04 10:07:49 -07001278 if (sta->mesh_sae_pmksa_caching) {
1279 wpa_printf(MSG_DEBUG,
1280 "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
1281 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
1282 sta->mesh_sae_pmksa_caching = 0;
1283 }
1284
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001285 if (auth_transaction == 1) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001286 const u8 *token = NULL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001287 size_t token_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07001288 int allow_reuse = 0;
1289
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001290 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1291 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001292 "start SAE authentication (RX commit, status=%u (%s))",
1293 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001294
1295 if ((hapd->conf->mesh & MESH_ENABLED) &&
1296 status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
1297 sta->sae->tmp) {
1298 pos = mgmt->u.auth.variable;
1299 end = ((const u8 *) mgmt) + len;
1300 if (pos + sizeof(le16) > end) {
1301 wpa_printf(MSG_ERROR,
1302 "SAE: Too short anti-clogging token request");
1303 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1304 goto reply;
1305 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001306 resp = sae_group_allowed(sta->sae, groups,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001307 WPA_GET_LE16(pos));
1308 if (resp != WLAN_STATUS_SUCCESS) {
1309 wpa_printf(MSG_ERROR,
1310 "SAE: Invalid group in anti-clogging token request");
1311 goto reply;
1312 }
1313 pos += sizeof(le16);
1314
1315 wpabuf_free(sta->sae->tmp->anti_clogging_token);
1316 sta->sae->tmp->anti_clogging_token =
1317 wpabuf_alloc_copy(pos, end - pos);
1318 if (sta->sae->tmp->anti_clogging_token == NULL) {
1319 wpa_printf(MSG_ERROR,
1320 "SAE: Failed to alloc for anti-clogging token");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001321 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1322 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001323 }
1324
1325 /*
1326 * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code
1327 * is 76, a new Commit Message shall be constructed
1328 * with the Anti-Clogging Token from the received
1329 * Authentication frame, and the commit-scalar and
1330 * COMMIT-ELEMENT previously sent.
1331 */
Hai Shalomc3565922019-10-28 11:58:20 -07001332 resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
1333 status_code);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001334 if (resp != WLAN_STATUS_SUCCESS) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001335 wpa_printf(MSG_ERROR,
1336 "SAE: Failed to send commit message");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001337 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001338 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001339 sae_set_state(sta, SAE_COMMITTED,
1340 "Sent Commit (anti-clogging token case in mesh)");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001341 sta->sae->sync = 0;
1342 sae_set_retransmit_timer(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001343 return;
1344 }
1345
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001346 if ((hapd->conf->mesh & MESH_ENABLED) &&
1347 status_code ==
1348 WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1349 sta->sae->tmp) {
1350 wpa_printf(MSG_DEBUG,
1351 "SAE: Peer did not accept our SAE group");
1352 sae_pick_next_group(hapd, sta);
1353 goto remove_sta;
1354 }
1355
Hai Shalomc3565922019-10-28 11:58:20 -07001356 if (!sae_status_success(hapd, status_code))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001357 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001358
Roshan Pius3a1667e2018-07-03 15:17:14 -07001359 if (!(hapd->conf->mesh & MESH_ENABLED) &&
1360 sta->sae->state == SAE_COMMITTED) {
1361 /* This is needed in the infrastructure BSS case to
1362 * address a sequence where a STA entry may remain in
1363 * hostapd across two attempts to do SAE authentication
1364 * by the same STA. The second attempt may end up trying
1365 * to use a different group and that would not be
1366 * allowed if we remain in Committed state with the
1367 * previously set parameters. */
Hai Shalom021b0b52019-04-10 11:17:58 -07001368 pos = mgmt->u.auth.variable;
1369 end = ((const u8 *) mgmt) + len;
1370 if (end - pos >= (int) sizeof(le16) &&
1371 sae_group_allowed(sta->sae, groups,
1372 WPA_GET_LE16(pos)) ==
1373 WLAN_STATUS_SUCCESS) {
1374 /* Do not waste resources deriving the same PWE
1375 * again since the same group is reused. */
1376 sae_set_state(sta, SAE_NOTHING,
1377 "Allow previous PWE to be reused");
1378 allow_reuse = 1;
1379 } else {
1380 sae_set_state(sta, SAE_NOTHING,
1381 "Clear existing state to allow restart");
1382 sae_clear_data(sta->sae);
1383 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001384 }
1385
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001386 resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
1387 ((const u8 *) mgmt) + len -
1388 mgmt->u.auth.variable, &token,
Hai Shalomc3565922019-10-28 11:58:20 -07001389 &token_len, groups, status_code ==
Hai Shalom899fcc72020-10-19 14:38:18 -07001390 WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1391 status_code == WLAN_STATUS_SAE_PK);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001392 if (resp == SAE_SILENTLY_DISCARD) {
1393 wpa_printf(MSG_DEBUG,
1394 "SAE: Drop commit message from " MACSTR " due to reflection attack",
1395 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001396 goto remove_sta;
Dmitry Shmidt41712582015-06-29 11:02:15 -07001397 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001398
1399 if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
1400 wpa_msg(hapd->msg_ctx, MSG_INFO,
1401 WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
1402 MACSTR, MAC2STR(sta->addr));
1403 sae_clear_retransmit_timer(hapd, sta);
1404 sae_set_state(sta, SAE_NOTHING,
1405 "Unknown Password Identifier");
1406 goto remove_sta;
1407 }
1408
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001409 if (token && check_sae_token(hapd, sta->addr, token, token_len)
1410 < 0) {
1411 wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
1412 "incorrect token from " MACSTR,
1413 MAC2STR(sta->addr));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001414 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1415 goto remove_sta;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001416 }
1417
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001418 if (resp != WLAN_STATUS_SUCCESS)
1419 goto reply;
1420
Hai Shalom899fcc72020-10-19 14:38:18 -07001421 if (check_sae_rejected_groups(hapd, sta->sae)) {
Hai Shalomc3565922019-10-28 11:58:20 -07001422 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001423 goto reply;
Hai Shalomc3565922019-10-28 11:58:20 -07001424 }
1425
Hai Shalom021b0b52019-04-10 11:17:58 -07001426 if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001427 int h2e = 0;
1428
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001429 wpa_printf(MSG_DEBUG,
1430 "SAE: Request anti-clogging token from "
1431 MACSTR, MAC2STR(sta->addr));
Hai Shalomfdcde762020-04-02 11:19:20 -07001432 if (sta->sae->tmp)
Hai Shalom899fcc72020-10-19 14:38:18 -07001433 h2e = sta->sae->h2e;
1434 if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
1435 status_code == WLAN_STATUS_SAE_PK)
Hai Shalomfdcde762020-04-02 11:19:20 -07001436 h2e = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001437 data = auth_build_token_req(hapd, sta->sae->group,
Hai Shalomfdcde762020-04-02 11:19:20 -07001438 sta->addr, h2e);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001439 resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
1440 if (hapd->conf->mesh & MESH_ENABLED)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001441 sae_set_state(sta, SAE_NOTHING,
1442 "Request anti-clogging token case in mesh");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001443 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001444 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001445
Hai Shalom021b0b52019-04-10 11:17:58 -07001446 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
Hai Shalomc3565922019-10-28 11:58:20 -07001447 status_code, allow_reuse, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001448 } else if (auth_transaction == 2) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001449 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1450 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001451 "SAE authentication (RX confirm, status=%u (%s))",
1452 status_code, status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001453 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001454 goto remove_sta;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001455 if (sta->sae->state >= SAE_CONFIRMED ||
1456 !(hapd->conf->mesh & MESH_ENABLED)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001457 const u8 *var;
1458 size_t var_len;
1459 u16 peer_send_confirm;
1460
1461 var = mgmt->u.auth.variable;
1462 var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable;
1463 if (var_len < 2) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001464 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001465 goto reply;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001466 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001467
1468 peer_send_confirm = WPA_GET_LE16(var);
1469
1470 if (sta->sae->state == SAE_ACCEPTED &&
1471 (peer_send_confirm <= sta->sae->rc ||
1472 peer_send_confirm == 0xffff)) {
1473 wpa_printf(MSG_DEBUG,
1474 "SAE: Silently ignore unexpected Confirm from peer "
1475 MACSTR
1476 " (peer-send-confirm=%u Rc=%u)",
1477 MAC2STR(sta->addr),
1478 peer_send_confirm, sta->sae->rc);
1479 return;
1480 }
1481
1482 if (sae_check_confirm(sta->sae, var, var_len) < 0) {
1483 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1484 goto reply;
1485 }
1486 sta->sae->rc = peer_send_confirm;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001487 }
Hai Shalomc3565922019-10-28 11:58:20 -07001488 resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
1489 status_code, 0, &sta_removed);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001490 } else {
1491 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1492 HOSTAPD_LEVEL_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07001493 "unexpected SAE authentication transaction %u (status=%u (%s))",
1494 auth_transaction, status_code,
1495 status2str(status_code));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001496 if (status_code != WLAN_STATUS_SUCCESS)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001497 goto remove_sta;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001498 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1499 }
1500
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001501reply:
Hai Shalom5f92bc92019-04-18 11:54:11 -07001502 if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001503 pos = mgmt->u.auth.variable;
1504 end = ((const u8 *) mgmt) + len;
1505
1506 /* Copy the Finite Cyclic Group field from the request if we
1507 * rejected it as unsupported group. */
1508 if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
1509 !data && end - pos >= 2)
1510 data = wpabuf_alloc_copy(pos, 2);
1511
Hai Shalom5f92bc92019-04-18 11:54:11 -07001512 sae_sme_send_external_auth_status(hapd, sta, resp);
Hai Shalomfdcde762020-04-02 11:19:20 -07001513 send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001514 auth_transaction, resp,
1515 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07001516 data ? wpabuf_len(data) : 0, "auth-sae");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001517 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001518
1519remove_sta:
Hai Shalom5f92bc92019-04-18 11:54:11 -07001520 if (!sta_removed && sta->added_unassoc &&
1521 (resp != WLAN_STATUS_SUCCESS ||
1522 status_code != WLAN_STATUS_SUCCESS)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001523 hostapd_drv_sta_remove(hapd, sta->addr);
1524 sta->added_unassoc = 0;
1525 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001526 wpabuf_free(data);
1527}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001528
1529
1530/**
1531 * auth_sae_init_committed - Send COMMIT and start SAE in committed state
1532 * @hapd: BSS data for the device initiating the authentication
1533 * @sta: the peer to which commit authentication frame is sent
1534 *
1535 * This function implements Init event handling (IEEE Std 802.11-2012,
1536 * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
1537 * sta->sae structure should be initialized appropriately via a call to
1538 * sae_prepare_commit().
1539 */
1540int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
1541{
1542 int ret;
1543
1544 if (!sta->sae || !sta->sae->tmp)
1545 return -1;
1546
1547 if (sta->sae->state != SAE_NOTHING)
1548 return -1;
1549
Hai Shalomc3565922019-10-28 11:58:20 -07001550 ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001551 if (ret)
1552 return -1;
1553
Roshan Pius3a1667e2018-07-03 15:17:14 -07001554 sae_set_state(sta, SAE_COMMITTED, "Init and sent commit");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001555 sta->sae->sync = 0;
1556 sae_set_retransmit_timer(hapd, sta);
1557
1558 return 0;
1559}
1560
Hai Shalom021b0b52019-04-10 11:17:58 -07001561
1562void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
1563{
1564 struct hostapd_data *hapd = eloop_ctx;
1565 struct hostapd_sae_commit_queue *q;
1566 unsigned int queue_len;
1567
1568 q = dl_list_first(&hapd->sae_commit_queue,
1569 struct hostapd_sae_commit_queue, list);
1570 if (!q)
1571 return;
1572 wpa_printf(MSG_DEBUG,
1573 "SAE: Process next available message from queue");
1574 dl_list_del(&q->list);
1575 handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
1576 q->rssi, 1);
1577 os_free(q);
1578
1579 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1580 return;
1581 queue_len = dl_list_len(&hapd->sae_commit_queue);
1582 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1583 hapd, NULL);
1584}
1585
1586
1587static void auth_sae_queue(struct hostapd_data *hapd,
1588 const struct ieee80211_mgmt *mgmt, size_t len,
1589 int rssi)
1590{
1591 struct hostapd_sae_commit_queue *q, *q2;
1592 unsigned int queue_len;
1593 const struct ieee80211_mgmt *mgmt2;
1594
1595 queue_len = dl_list_len(&hapd->sae_commit_queue);
1596 if (queue_len >= 15) {
1597 wpa_printf(MSG_DEBUG,
1598 "SAE: No more room in message queue - drop the new frame from "
1599 MACSTR, MAC2STR(mgmt->sa));
1600 return;
1601 }
1602
1603 wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
1604 MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
1605 queue_len);
1606 q = os_zalloc(sizeof(*q) + len);
1607 if (!q)
1608 return;
1609 q->rssi = rssi;
1610 q->len = len;
1611 os_memcpy(q->msg, mgmt, len);
1612
1613 /* Check whether there is already a queued Authentication frame from the
1614 * same station with the same transaction number and if so, replace that
1615 * queue entry with the new one. This avoids issues with a peer that
1616 * sends multiple times (e.g., due to frequent SAE retries). There is no
1617 * point in us trying to process the old attempts after a new one has
1618 * obsoleted them. */
1619 dl_list_for_each(q2, &hapd->sae_commit_queue,
1620 struct hostapd_sae_commit_queue, list) {
1621 mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
1622 if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 &&
1623 mgmt->u.auth.auth_transaction ==
1624 mgmt2->u.auth.auth_transaction) {
1625 wpa_printf(MSG_DEBUG,
1626 "SAE: Replace queued message from same STA with same transaction number");
1627 dl_list_add(&q2->list, &q->list);
1628 dl_list_del(&q2->list);
1629 os_free(q2);
1630 goto queued;
1631 }
1632 }
1633
1634 /* No pending identical entry, so add to the end of the queue */
1635 dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
1636
1637queued:
1638 if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
1639 return;
1640 eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
1641 hapd, NULL);
1642}
1643
1644
1645static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
1646{
1647 struct hostapd_sae_commit_queue *q;
1648 const struct ieee80211_mgmt *mgmt;
1649
1650 dl_list_for_each(q, &hapd->sae_commit_queue,
1651 struct hostapd_sae_commit_queue, list) {
1652 mgmt = (const struct ieee80211_mgmt *) q->msg;
1653 if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0)
1654 return 1;
1655 }
1656
1657 return 0;
1658}
1659
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001660#endif /* CONFIG_SAE */
1661
1662
Hai Shalomfdcde762020-04-02 11:19:20 -07001663static u16 wpa_res_to_status_code(enum wpa_validate_result res)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001664{
Hai Shalomfdcde762020-04-02 11:19:20 -07001665 switch (res) {
1666 case WPA_IE_OK:
1667 return WLAN_STATUS_SUCCESS;
1668 case WPA_INVALID_IE:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001669 return WLAN_STATUS_INVALID_IE;
Hai Shalomfdcde762020-04-02 11:19:20 -07001670 case WPA_INVALID_GROUP:
1671 return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
1672 case WPA_INVALID_PAIRWISE:
1673 return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
1674 case WPA_INVALID_AKMP:
1675 return WLAN_STATUS_AKMP_NOT_VALID;
1676 case WPA_NOT_ENABLED:
1677 return WLAN_STATUS_INVALID_IE;
1678 case WPA_ALLOC_FAIL:
1679 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1680 case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
1681 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
1682 case WPA_INVALID_MGMT_GROUP_CIPHER:
1683 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
1684 case WPA_INVALID_MDIE:
1685 return WLAN_STATUS_INVALID_MDIE;
1686 case WPA_INVALID_PROTO:
1687 return WLAN_STATUS_INVALID_IE;
1688 case WPA_INVALID_PMKID:
1689 return WLAN_STATUS_INVALID_PMKID;
1690 case WPA_DENIED_OTHER_REASON:
1691 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
1692 }
1693 return WLAN_STATUS_INVALID_IE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001694}
1695
1696
1697#ifdef CONFIG_FILS
1698
1699static void handle_auth_fils_finish(struct hostapd_data *hapd,
1700 struct sta_info *sta, u16 resp,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001701 struct wpabuf *data, int pub);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001702
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001703void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
1704 const u8 *pos, size_t len, u16 auth_alg,
1705 u16 auth_transaction, u16 status_code,
1706 void (*cb)(struct hostapd_data *hapd,
1707 struct sta_info *sta, u16 resp,
1708 struct wpabuf *data, int pub))
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001709{
1710 u16 resp = WLAN_STATUS_SUCCESS;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001711 const u8 *end;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001712 struct ieee802_11_elems elems;
Hai Shalomfdcde762020-04-02 11:19:20 -07001713 enum wpa_validate_result res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001714 struct wpa_ie_data rsn;
1715 struct rsn_pmksa_cache_entry *pmksa = NULL;
1716
1717 if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
1718 return;
1719
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001720 end = pos + len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001721
1722 wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
1723 pos, end - pos);
1724
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001725 /* TODO: FILS PK */
1726#ifdef CONFIG_FILS_SK_PFS
1727 if (auth_alg == WLAN_AUTH_FILS_SK_PFS) {
1728 u16 group;
1729 struct wpabuf *pub;
1730 size_t elem_len;
1731
1732 /* Using FILS PFS */
1733
1734 /* Finite Cyclic Group */
1735 if (end - pos < 2) {
1736 wpa_printf(MSG_DEBUG,
1737 "FILS: No room for Finite Cyclic Group");
1738 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1739 goto fail;
1740 }
1741 group = WPA_GET_LE16(pos);
1742 pos += 2;
1743 if (group != hapd->conf->fils_dh_group) {
1744 wpa_printf(MSG_DEBUG,
1745 "FILS: Unsupported Finite Cyclic Group: %u (expected %u)",
1746 group, hapd->conf->fils_dh_group);
1747 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1748 goto fail;
1749 }
1750
1751 crypto_ecdh_deinit(sta->fils_ecdh);
1752 sta->fils_ecdh = crypto_ecdh_init(group);
1753 if (!sta->fils_ecdh) {
1754 wpa_printf(MSG_INFO,
1755 "FILS: Could not initialize ECDH with group %d",
1756 group);
1757 resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1758 goto fail;
1759 }
1760
1761 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
1762 if (!pub) {
1763 wpa_printf(MSG_DEBUG,
1764 "FILS: Failed to derive ECDH public key");
1765 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1766 goto fail;
1767 }
1768 elem_len = wpabuf_len(pub);
1769 wpabuf_free(pub);
1770
1771 /* Element */
1772 if ((size_t) (end - pos) < elem_len) {
1773 wpa_printf(MSG_DEBUG, "FILS: No room for Element");
1774 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1775 goto fail;
1776 }
1777
1778 wpabuf_free(sta->fils_g_sta);
1779 sta->fils_g_sta = wpabuf_alloc_copy(pos, elem_len);
1780 wpabuf_clear_free(sta->fils_dh_ss);
1781 sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1,
1782 pos, elem_len);
1783 if (!sta->fils_dh_ss) {
1784 wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
1785 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1786 goto fail;
1787 }
1788 wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss);
1789 pos += elem_len;
1790 } else {
1791 crypto_ecdh_deinit(sta->fils_ecdh);
1792 sta->fils_ecdh = NULL;
1793 wpabuf_clear_free(sta->fils_dh_ss);
1794 sta->fils_dh_ss = NULL;
1795 }
1796#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001797
1798 wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
1799 if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
1800 wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
1801 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1802 goto fail;
1803 }
1804
1805 /* RSNE */
1806 wpa_hexdump(MSG_DEBUG, "FILS: RSN element",
1807 elems.rsn_ie, elems.rsn_ie_len);
1808 if (!elems.rsn_ie ||
1809 wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
1810 &rsn) < 0) {
1811 wpa_printf(MSG_DEBUG, "FILS: No valid RSN element");
1812 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1813 goto fail;
1814 }
1815
1816 if (!sta->wpa_sm)
1817 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
1818 NULL);
1819 if (!sta->wpa_sm) {
1820 wpa_printf(MSG_DEBUG,
1821 "FILS: Failed to initialize RSN state machine");
1822 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1823 goto fail;
1824 }
1825
1826 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07001827 hapd->iface->freq,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001828 elems.rsn_ie - 2, elems.rsn_ie_len + 2,
Hai Shalomc3565922019-10-28 11:58:20 -07001829 elems.rsnxe ? elems.rsnxe - 2 : NULL,
1830 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001831 elems.mdie, elems.mdie_len, NULL, 0);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001832 resp = wpa_res_to_status_code(res);
1833 if (resp != WLAN_STATUS_SUCCESS)
1834 goto fail;
1835
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001836 if (!elems.fils_nonce) {
1837 wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
1838 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1839 goto fail;
1840 }
1841 wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce,
1842 FILS_NONCE_LEN);
1843 os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN);
1844
1845 /* PMKID List */
1846 if (rsn.pmkid && rsn.num_pmkid > 0) {
1847 u8 num;
1848 const u8 *pmkid;
1849
1850 wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
1851 rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
1852
1853 pmkid = rsn.pmkid;
1854 num = rsn.num_pmkid;
1855 while (num) {
1856 wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
1857 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
1858 pmkid);
1859 if (pmksa)
1860 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001861 pmksa = wpa_auth_pmksa_get_fils_cache_id(hapd->wpa_auth,
1862 sta->addr,
1863 pmkid);
1864 if (pmksa)
1865 break;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001866 pmkid += PMKID_LEN;
1867 num--;
1868 }
1869 }
1870 if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) {
1871 wpa_printf(MSG_DEBUG,
1872 "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore",
1873 wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp);
1874 pmksa = NULL;
1875 }
1876 if (pmksa)
1877 wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry");
1878
1879 /* FILS Session */
1880 if (!elems.fils_session) {
1881 wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
1882 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1883 goto fail;
1884 }
1885 wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
1886 FILS_SESSION_LEN);
1887 os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
1888
Hai Shalomfdcde762020-04-02 11:19:20 -07001889 /* Wrapped Data */
1890 if (elems.wrapped_data) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001891 wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
Hai Shalomfdcde762020-04-02 11:19:20 -07001892 elems.wrapped_data,
1893 elems.wrapped_data_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001894 if (!pmksa) {
1895#ifndef CONFIG_NO_RADIUS
1896 if (!sta->eapol_sm) {
1897 sta->eapol_sm =
1898 ieee802_1x_alloc_eapol_sm(hapd, sta);
1899 }
1900 wpa_printf(MSG_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001901 "FILS: Forward EAP-Initiate/Re-auth to authentication server");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001902 ieee802_1x_encapsulate_radius(
Hai Shalomfdcde762020-04-02 11:19:20 -07001903 hapd, sta, elems.wrapped_data,
1904 elems.wrapped_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001905 sta->fils_pending_cb = cb;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001906 wpa_printf(MSG_DEBUG,
1907 "FILS: Will send Authentication frame once the response from authentication server is available");
1908 sta->flags |= WLAN_STA_PENDING_FILS_ERP;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001909 /* Calculate pending PMKID here so that we do not need
1910 * to maintain a copy of the EAP-Initiate/Reauth
1911 * message. */
1912 if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
Hai Shalomfdcde762020-04-02 11:19:20 -07001913 elems.wrapped_data,
1914 elems.wrapped_data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001915 sta->fils_erp_pmkid) == 0)
1916 sta->fils_erp_pmkid_set = 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001917 return;
1918#else /* CONFIG_NO_RADIUS */
1919 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1920 goto fail;
1921#endif /* CONFIG_NO_RADIUS */
1922 }
1923 }
1924
1925fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001926 if (cb) {
1927 struct wpabuf *data;
1928 int pub = 0;
1929
1930 data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, NULL,
1931 NULL, 0, &pub);
1932 if (!data) {
1933 wpa_printf(MSG_DEBUG,
1934 "%s: prepare_auth_resp_fils() returned failure",
1935 __func__);
1936 }
1937
1938 cb(hapd, sta, resp, data, pub);
1939 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001940}
1941
1942
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001943static struct wpabuf *
1944prepare_auth_resp_fils(struct hostapd_data *hapd,
1945 struct sta_info *sta, u16 *resp,
1946 struct rsn_pmksa_cache_entry *pmksa,
1947 struct wpabuf *erp_resp,
1948 const u8 *msk, size_t msk_len,
1949 int *is_pub)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001950{
1951 u8 fils_nonce[FILS_NONCE_LEN];
1952 size_t ielen;
1953 struct wpabuf *data = NULL;
1954 const u8 *ie;
1955 u8 *ie_buf = NULL;
1956 const u8 *pmk = NULL;
1957 size_t pmk_len = 0;
Paul Stewart092955c2017-02-06 09:13:09 -08001958 u8 pmk_buf[PMK_LEN_MAX];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001959 struct wpabuf *pub = NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001960
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001961 if (*resp != WLAN_STATUS_SUCCESS)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001962 goto fail;
1963
1964 ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
1965 if (!ie) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001966 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001967 goto fail;
1968 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001969
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001970 if (pmksa) {
1971 /* Add PMKID of the selected PMKSA into RSNE */
1972 ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN);
1973 if (!ie_buf) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001974 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001975 goto fail;
1976 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001977
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001978 os_memcpy(ie_buf, ie, ielen);
1979 if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001980 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001981 goto fail;
1982 }
1983 ie = ie_buf;
1984 }
1985
1986 if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001987 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001988 goto fail;
1989 }
1990 wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
1991 fils_nonce, FILS_NONCE_LEN);
1992
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001993#ifdef CONFIG_FILS_SK_PFS
1994 if (sta->fils_dh_ss && sta->fils_ecdh) {
1995 pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
1996 if (!pub) {
1997 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1998 goto fail;
1999 }
2000 }
2001#endif /* CONFIG_FILS_SK_PFS */
2002
2003 data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0));
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002004 if (!data) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002005 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002006 goto fail;
2007 }
2008
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002009 /* TODO: FILS PK */
2010#ifdef CONFIG_FILS_SK_PFS
2011 if (pub) {
2012 /* Finite Cyclic Group */
2013 wpabuf_put_le16(data, hapd->conf->fils_dh_group);
2014
2015 /* Element */
2016 wpabuf_put_buf(data, pub);
2017 }
2018#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002019
2020 /* RSNE */
2021 wpabuf_put_data(data, ie, ielen);
2022
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002023 /* MDE when using FILS+FT (already included in ie,ielen with RSNE) */
2024
2025#ifdef CONFIG_IEEE80211R_AP
2026 if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
2027 /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
2028 int res;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002029 int use_sha384 = wpa_key_mgmt_sha384(
2030 wpa_auth_sta_key_mgmt(sta->wpa_sm));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002031
Roshan Pius3a1667e2018-07-03 15:17:14 -07002032 res = wpa_auth_write_fte(hapd->wpa_auth, use_sha384,
2033 wpabuf_put(data, 0),
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002034 wpabuf_tailroom(data));
2035 if (res < 0) {
2036 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2037 goto fail;
2038 }
2039 wpabuf_put(data, res);
2040 }
2041#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002042
2043 /* FILS Nonce */
2044 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2045 wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */
2046 /* Element ID Extension */
2047 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE);
2048 wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN);
2049
2050 /* FILS Session */
2051 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2052 wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */
2053 /* Element ID Extension */
2054 wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
2055 wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
2056
Hai Shalomfdcde762020-04-02 11:19:20 -07002057 /* Wrapped Data */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002058 if (!pmksa && erp_resp) {
2059 wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
2060 wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
2061 /* Element ID Extension */
Hai Shalomfdcde762020-04-02 11:19:20 -07002062 wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002063 wpabuf_put_buf(data, erp_resp);
2064
Paul Stewart092955c2017-02-06 09:13:09 -08002065 if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
2066 msk, msk_len, sta->fils_snonce, fils_nonce,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002067 sta->fils_dh_ss ?
2068 wpabuf_head(sta->fils_dh_ss) : NULL,
2069 sta->fils_dh_ss ?
2070 wpabuf_len(sta->fils_dh_ss) : 0,
2071 pmk_buf, &pmk_len)) {
Paul Stewart092955c2017-02-06 09:13:09 -08002072 wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002073 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Paul Stewart092955c2017-02-06 09:13:09 -08002074 wpabuf_free(data);
2075 data = NULL;
2076 goto fail;
2077 }
2078 pmk = pmk_buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002079
2080 /* Don't use DHss in PTK derivation if PMKSA caching is not
2081 * used. */
2082 wpabuf_clear_free(sta->fils_dh_ss);
2083 sta->fils_dh_ss = NULL;
2084
2085 if (sta->fils_erp_pmkid_set) {
2086 /* TODO: get PMKLifetime from WPA parameters */
2087 unsigned int dot11RSNAConfigPMKLifetime = 43200;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002088 int session_timeout;
2089
2090 session_timeout = dot11RSNAConfigPMKLifetime;
2091 if (sta->session_timeout_set) {
2092 struct os_reltime now, diff;
2093
2094 os_get_reltime(&now);
2095 os_reltime_sub(&sta->session_timeout, &now,
2096 &diff);
2097 session_timeout = diff.sec;
2098 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002099
2100 sta->fils_erp_pmkid_set = 0;
Hai Shalom81f62d82019-07-22 12:10:00 -07002101 wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
2102 sta->fils_erp_pmkid);
Hai Shalom021b0b52019-04-10 11:17:58 -07002103 if (!hapd->conf->disable_pmksa_caching &&
2104 wpa_auth_pmksa_add2(
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002105 hapd->wpa_auth, sta->addr,
2106 pmk, pmk_len,
2107 sta->fils_erp_pmkid,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002108 session_timeout,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002109 wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) {
2110 wpa_printf(MSG_ERROR,
2111 "FILS: Failed to add PMKSA cache entry based on ERP");
2112 }
2113 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002114 } else if (pmksa) {
2115 pmk = pmksa->pmk;
2116 pmk_len = pmksa->pmk_len;
2117 }
2118
2119 if (!pmk) {
2120 wpa_printf(MSG_DEBUG, "FILS: No PMK available");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002121 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002122 wpabuf_free(data);
2123 data = NULL;
2124 goto fail;
2125 }
2126
2127 if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002128 sta->fils_snonce, fils_nonce,
2129 sta->fils_dh_ss ?
2130 wpabuf_head(sta->fils_dh_ss) : NULL,
2131 sta->fils_dh_ss ?
2132 wpabuf_len(sta->fils_dh_ss) : 0,
2133 sta->fils_g_sta, pub) < 0) {
2134 *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002135 wpabuf_free(data);
2136 data = NULL;
2137 goto fail;
2138 }
2139
2140fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002141 if (is_pub)
2142 *is_pub = pub != NULL;
2143 os_free(ie_buf);
2144 wpabuf_free(pub);
2145 wpabuf_clear_free(sta->fils_dh_ss);
2146 sta->fils_dh_ss = NULL;
2147#ifdef CONFIG_FILS_SK_PFS
2148 crypto_ecdh_deinit(sta->fils_ecdh);
2149 sta->fils_ecdh = NULL;
2150#endif /* CONFIG_FILS_SK_PFS */
2151 return data;
2152}
2153
2154
2155static void handle_auth_fils_finish(struct hostapd_data *hapd,
2156 struct sta_info *sta, u16 resp,
2157 struct wpabuf *data, int pub)
2158{
2159 u16 auth_alg;
2160
2161 auth_alg = (pub ||
2162 resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
2163 WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Hai Shalomfdcde762020-04-02 11:19:20 -07002164 send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002165 data ? wpabuf_head(data) : (u8 *) "",
Roshan Pius3a1667e2018-07-03 15:17:14 -07002166 data ? wpabuf_len(data) : 0, "auth-fils-finish");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002167 wpabuf_free(data);
2168
2169 if (resp == WLAN_STATUS_SUCCESS) {
2170 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2171 HOSTAPD_LEVEL_DEBUG,
2172 "authentication OK (FILS)");
2173 sta->flags |= WLAN_STA_AUTH;
2174 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002175 sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002176 mlme_authenticate_indication(hapd, sta);
2177 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002178}
2179
2180
2181void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
2182 struct sta_info *sta, int success,
2183 struct wpabuf *erp_resp,
2184 const u8 *msk, size_t msk_len)
2185{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002186 struct wpabuf *data;
2187 int pub = 0;
2188 u16 resp;
2189
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002190 sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002191
2192 if (!sta->fils_pending_cb)
2193 return;
2194 resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
2195 data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
2196 msk, msk_len, &pub);
2197 if (!data) {
2198 wpa_printf(MSG_DEBUG,
2199 "%s: prepare_auth_resp_fils() returned failure",
2200 __func__);
2201 }
2202 sta->fils_pending_cb(hapd, sta, resp, data, pub);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002203}
2204
2205#endif /* CONFIG_FILS */
2206
2207
Hai Shalomfdcde762020-04-02 11:19:20 -07002208static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
2209 const u8 *msg, size_t len,
2210 struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002211{
2212 int res;
2213
Hai Shalomfdcde762020-04-02 11:19:20 -07002214 res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002215
2216 if (res == HOSTAPD_ACL_REJECT) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002217 wpa_printf(MSG_DEBUG, "Station " MACSTR
2218 " not allowed to authenticate",
2219 MAC2STR(addr));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002220 return HOSTAPD_ACL_REJECT;
2221 }
2222
2223 if (res == HOSTAPD_ACL_PENDING) {
2224 wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
2225 " waiting for an external authentication",
2226 MAC2STR(addr));
2227 /* Authentication code will re-send the authentication frame
2228 * after it has received (and cached) information from the
2229 * external source. */
2230 return HOSTAPD_ACL_PENDING;
2231 }
2232
2233 return res;
2234}
2235
2236
2237static int
2238ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
Hai Shalomfdcde762020-04-02 11:19:20 -07002239 int res, struct radius_sta *info)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002240{
Hai Shalomfdcde762020-04-02 11:19:20 -07002241 u32 session_timeout = info->session_timeout;
2242 u32 acct_interim_interval = info->acct_interim_interval;
2243 struct vlan_description *vlan_id = &info->vlan_id;
2244 struct hostapd_sta_wpa_psk_short *psk = info->psk;
2245 char *identity = info->identity;
2246 char *radius_cui = info->radius_cui;
2247
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002248 if (vlan_id->notempty &&
2249 !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
2250 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2251 HOSTAPD_LEVEL_INFO,
2252 "Invalid VLAN %d%s received from RADIUS server",
2253 vlan_id->untagged,
2254 vlan_id->tagged[0] ? "+" : "");
2255 return -1;
2256 }
2257 if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
2258 return -1;
2259 if (sta->vlan_id)
2260 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2261 HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
2262
2263 hostapd_free_psk_list(sta->psk);
Hai Shalomfdcde762020-04-02 11:19:20 -07002264 if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
2265 hostapd_copy_psk_list(&sta->psk, psk);
2266 else
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002267 sta->psk = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002268
Roshan Pius3a1667e2018-07-03 15:17:14 -07002269 os_free(sta->identity);
Hai Shalomfdcde762020-04-02 11:19:20 -07002270 if (identity)
2271 sta->identity = os_strdup(identity);
2272 else
2273 sta->identity = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002274
2275 os_free(sta->radius_cui);
Hai Shalomfdcde762020-04-02 11:19:20 -07002276 if (radius_cui)
2277 sta->radius_cui = os_strdup(radius_cui);
2278 else
2279 sta->radius_cui = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002280
2281 if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
2282 sta->acct_interim_interval = acct_interim_interval;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002283 if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
2284 sta->session_timeout_set = 1;
2285 os_get_reltime(&sta->session_timeout);
2286 sta->session_timeout.sec += session_timeout;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002287 ap_sta_session_timeout(hapd, sta, session_timeout);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002288 } else {
2289 sta->session_timeout_set = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002290 ap_sta_no_session_timeout(hapd, sta);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002291 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002292
2293 return 0;
2294}
2295
2296
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002297static void handle_auth(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08002298 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom021b0b52019-04-10 11:17:58 -07002299 int rssi, int from_queue)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002300{
2301 u16 auth_alg, auth_transaction, status_code;
2302 u16 resp = WLAN_STATUS_SUCCESS;
2303 struct sta_info *sta = NULL;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002304 int res, reply_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002305 u16 fc;
2306 const u8 *challenge = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002307 u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
2308 size_t resp_ies_len = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002309 u16 seq_ctrl;
Hai Shalomfdcde762020-04-02 11:19:20 -07002310 struct radius_sta rad_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002311
2312 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002313 wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
2314 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002315 return;
2316 }
2317
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002318#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002319 if (hapd->iconf->ignore_auth_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002320 drand48() < hapd->iconf->ignore_auth_probability) {
2321 wpa_printf(MSG_INFO,
2322 "TESTING: ignoring auth frame from " MACSTR,
2323 MAC2STR(mgmt->sa));
2324 return;
2325 }
2326#endif /* CONFIG_TESTING_OPTIONS */
2327
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002328 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
2329 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
2330 status_code = le_to_host16(mgmt->u.auth.status_code);
2331 fc = le_to_host16(mgmt->frame_control);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002332 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002333
2334 if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
2335 2 + WLAN_AUTH_CHALLENGE_LEN &&
2336 mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
2337 mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
2338 challenge = &mgmt->u.auth.variable[2];
2339
2340 wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002341 "auth_transaction=%d status_code=%d wep=%d%s "
Hai Shalom021b0b52019-04-10 11:17:58 -07002342 "seq_ctrl=0x%x%s%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002343 MAC2STR(mgmt->sa), auth_alg, auth_transaction,
2344 status_code, !!(fc & WLAN_FC_ISWEP),
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002345 challenge ? " challenge" : "",
Hai Shalom021b0b52019-04-10 11:17:58 -07002346 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
2347 from_queue ? " (from queue)" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002348
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002349#ifdef CONFIG_NO_RC4
2350 if (auth_alg == WLAN_AUTH_SHARED_KEY) {
2351 wpa_printf(MSG_INFO,
2352 "Unsupported authentication algorithm (%d)",
2353 auth_alg);
2354 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
2355 goto fail;
2356 }
2357#endif /* CONFIG_NO_RC4 */
2358
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002359 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002360 wpa_printf(MSG_DEBUG,
2361 "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
2362 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002363 goto fail;
2364 }
2365
2366 if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
2367 auth_alg == WLAN_AUTH_OPEN) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002368#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002369 (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002370 auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002371#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002372#ifdef CONFIG_SAE
2373 (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
2374 auth_alg == WLAN_AUTH_SAE) ||
2375#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002376#ifdef CONFIG_FILS
2377 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
2378 auth_alg == WLAN_AUTH_FILS_SK) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002379 (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
2380 hapd->conf->fils_dh_group &&
2381 auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002382#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002383 ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
2384 auth_alg == WLAN_AUTH_SHARED_KEY))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002385 wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
2386 auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002387 resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
2388 goto fail;
2389 }
2390
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002391 if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002392 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002393 wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
2394 auth_transaction);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002395 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
2396 goto fail;
2397 }
2398
2399 if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002400 wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
2401 MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002402 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2403 goto fail;
2404 }
2405
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002406 if (hapd->conf->no_auth_if_seen_on) {
2407 struct hostapd_data *other;
2408
2409 other = sta_track_seen_on(hapd->iface, mgmt->sa,
2410 hapd->conf->no_auth_if_seen_on);
2411 if (other) {
2412 u8 *pos;
2413 u32 info;
2414 u8 op_class, channel, phytype;
2415
2416 wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
2417 MACSTR " since STA has been seen on %s",
2418 hapd->conf->iface, MAC2STR(mgmt->sa),
2419 hapd->conf->no_auth_if_seen_on);
2420
2421 resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
2422 pos = &resp_ies[0];
2423 *pos++ = WLAN_EID_NEIGHBOR_REPORT;
2424 *pos++ = 13;
2425 os_memcpy(pos, other->own_addr, ETH_ALEN);
2426 pos += ETH_ALEN;
2427 info = 0; /* TODO: BSSID Information */
2428 WPA_PUT_LE32(pos, info);
2429 pos += 4;
2430 if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
2431 phytype = 8; /* dmg */
2432 else if (other->iconf->ieee80211ac)
2433 phytype = 9; /* vht */
2434 else if (other->iconf->ieee80211n)
2435 phytype = 7; /* ht */
2436 else if (other->iconf->hw_mode ==
2437 HOSTAPD_MODE_IEEE80211A)
2438 phytype = 4; /* ofdm */
2439 else if (other->iconf->hw_mode ==
2440 HOSTAPD_MODE_IEEE80211G)
2441 phytype = 6; /* erp */
2442 else
2443 phytype = 5; /* hrdsss */
2444 if (ieee80211_freq_to_channel_ext(
2445 hostapd_hw_get_freq(other,
2446 other->iconf->channel),
2447 other->iconf->secondary_channel,
2448 other->iconf->ieee80211ac,
2449 &op_class, &channel) == NUM_HOSTAPD_MODES) {
2450 op_class = 0;
2451 channel = other->iconf->channel;
2452 }
2453 *pos++ = op_class;
2454 *pos++ = channel;
2455 *pos++ = phytype;
2456 resp_ies_len = pos - &resp_ies[0];
2457 goto fail;
2458 }
2459 }
2460
Hai Shalomfdcde762020-04-02 11:19:20 -07002461 res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
2462 &rad_info);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002463 if (res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002464 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
2465 "Ignore Authentication frame from " MACSTR
2466 " due to ACL reject", MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002467 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2468 goto fail;
2469 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002470 if (res == HOSTAPD_ACL_PENDING)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002471 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002472
Hai Shalom021b0b52019-04-10 11:17:58 -07002473#ifdef CONFIG_SAE
2474 if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
2475 (auth_transaction == 1 ||
2476 (auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) {
2477 /* Handle SAE Authentication commit message through a queue to
2478 * provide more control for postponing the needed heavy
2479 * processing under a possible DoS attack scenario. In addition,
2480 * queue SAE Authentication confirm message if there happens to
2481 * be a queued commit message from the same peer. This is needed
2482 * to avoid reordering Authentication frames within the same
2483 * SAE exchange. */
2484 auth_sae_queue(hapd, mgmt, len, rssi);
2485 return;
2486 }
2487#endif /* CONFIG_SAE */
2488
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002489 sta = ap_get_sta(hapd, mgmt->sa);
2490 if (sta) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002491 sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
Hai Shalom74f70d42019-02-11 14:42:39 -08002492 sta->ft_over_ds = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002493 if ((fc & WLAN_FC_RETRY) &&
2494 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
2495 sta->last_seq_ctrl == seq_ctrl &&
2496 sta->last_subtype == WLAN_FC_STYPE_AUTH) {
2497 hostapd_logger(hapd, sta->addr,
2498 HOSTAPD_MODULE_IEEE80211,
2499 HOSTAPD_LEVEL_DEBUG,
2500 "Drop repeated authentication frame seq_ctrl=0x%x",
2501 seq_ctrl);
2502 return;
2503 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002504#ifdef CONFIG_MESH
2505 if ((hapd->conf->mesh & MESH_ENABLED) &&
2506 sta->plink_state == PLINK_BLOCKED) {
2507 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
2508 " is blocked - drop Authentication frame",
2509 MAC2STR(mgmt->sa));
2510 return;
2511 }
2512#endif /* CONFIG_MESH */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002513 } else {
2514#ifdef CONFIG_MESH
2515 if (hapd->conf->mesh & MESH_ENABLED) {
2516 /* if the mesh peer is not available, we don't do auth.
2517 */
2518 wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002519 " not yet known - drop Authentication frame",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002520 MAC2STR(mgmt->sa));
2521 /*
2522 * Save a copy of the frame so that it can be processed
2523 * if a new peer entry is added shortly after this.
2524 */
2525 wpabuf_free(hapd->mesh_pending_auth);
2526 hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len);
2527 os_get_reltime(&hapd->mesh_pending_auth_time);
2528 return;
2529 }
2530#endif /* CONFIG_MESH */
2531
2532 sta = ap_sta_add(hapd, mgmt->sa);
2533 if (!sta) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002534 wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002535 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
2536 goto fail;
2537 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002538 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002539 sta->last_seq_ctrl = seq_ctrl;
2540 sta->last_subtype = WLAN_FC_STYPE_AUTH;
Hai Shalom74f70d42019-02-11 14:42:39 -08002541#ifdef CONFIG_MBO
2542 sta->auth_rssi = rssi;
2543#endif /* CONFIG_MBO */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002544
Hai Shalomfdcde762020-04-02 11:19:20 -07002545 res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002546 if (res) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002547 wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002548 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2549 goto fail;
2550 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002551
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002552 sta->flags &= ~WLAN_STA_PREAUTH;
2553 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
2554
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002555 /*
2556 * If the driver supports full AP client state, add a station to the
2557 * driver before sending authentication reply to make sure the driver
2558 * has resources, and not to go through the entire authentication and
2559 * association handshake, and fail it at the end.
2560 *
2561 * If this is not the first transaction, in a multi-step authentication
2562 * algorithm, the station already exists in the driver
2563 * (sta->added_unassoc = 1) so skip it.
2564 *
2565 * In mesh mode, the station was already added to the driver when the
2566 * NEW_PEER_CANDIDATE event is received.
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002567 *
2568 * If PMF was negotiated for the existing association, skip this to
2569 * avoid dropping the STA entry and the associated keys. This is needed
2570 * to allow the original connection work until the attempt can complete
2571 * (re)association, so that unprotected Authentication frame cannot be
2572 * used to bypass PMF protection.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002573 */
2574 if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08002575 (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002576 !(hapd->conf->mesh & MESH_ENABLED) &&
2577 !(sta->added_unassoc)) {
Hai Shalomb755a2a2020-04-23 21:49:02 -07002578 if (ap_sta_re_add(hapd, sta) < 0) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002579 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
2580 goto fail;
2581 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002582 }
2583
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002584 switch (auth_alg) {
2585 case WLAN_AUTH_OPEN:
2586 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2587 HOSTAPD_LEVEL_DEBUG,
2588 "authentication OK (open system)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002589 sta->flags |= WLAN_STA_AUTH;
2590 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
2591 sta->auth_alg = WLAN_AUTH_OPEN;
2592 mlme_authenticate_indication(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002593 break;
Hai Shalomfdcde762020-04-02 11:19:20 -07002594#ifdef CONFIG_WEP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002595#ifndef CONFIG_NO_RC4
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002596 case WLAN_AUTH_SHARED_KEY:
2597 resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
2598 fc & WLAN_FC_ISWEP);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002599 if (resp != 0)
2600 wpa_printf(MSG_DEBUG,
2601 "auth_shared_key() failed: status=%d", resp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002602 sta->auth_alg = WLAN_AUTH_SHARED_KEY;
2603 mlme_authenticate_indication(hapd, sta);
2604 if (sta->challenge && auth_transaction == 1) {
2605 resp_ies[0] = WLAN_EID_CHALLENGE;
2606 resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
2607 os_memcpy(resp_ies + 2, sta->challenge,
2608 WLAN_AUTH_CHALLENGE_LEN);
2609 resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
2610 }
2611 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002612#endif /* CONFIG_NO_RC4 */
Hai Shalomfdcde762020-04-02 11:19:20 -07002613#endif /* CONFIG_WEP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002614#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002615 case WLAN_AUTH_FT:
2616 sta->auth_alg = WLAN_AUTH_FT;
2617 if (sta->wpa_sm == NULL)
2618 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07002619 sta->addr, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002620 if (sta->wpa_sm == NULL) {
2621 wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
2622 "state machine");
2623 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2624 goto fail;
2625 }
2626 wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
2627 auth_transaction, mgmt->u.auth.variable,
2628 len - IEEE80211_HDRLEN -
2629 sizeof(mgmt->u.auth),
2630 handle_auth_ft_finish, hapd);
2631 /* handle_auth_ft_finish() callback will complete auth. */
2632 return;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002633#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002634#ifdef CONFIG_SAE
2635 case WLAN_AUTH_SAE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002636#ifdef CONFIG_MESH
2637 if (status_code == WLAN_STATUS_SUCCESS &&
2638 hapd->conf->mesh & MESH_ENABLED) {
2639 if (sta->wpa_sm == NULL)
2640 sta->wpa_sm =
2641 wpa_auth_sta_init(hapd->wpa_auth,
2642 sta->addr, NULL);
2643 if (sta->wpa_sm == NULL) {
2644 wpa_printf(MSG_DEBUG,
2645 "SAE: Failed to initialize WPA state machine");
2646 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
2647 goto fail;
2648 }
2649 }
2650#endif /* CONFIG_MESH */
2651 handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
2652 status_code);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002653 return;
2654#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002655#ifdef CONFIG_FILS
2656 case WLAN_AUTH_FILS_SK:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002657 case WLAN_AUTH_FILS_SK_PFS:
2658 handle_auth_fils(hapd, sta, mgmt->u.auth.variable,
2659 len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth),
2660 auth_alg, auth_transaction, status_code,
2661 handle_auth_fils_finish);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002662 return;
2663#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002664 }
2665
2666 fail:
Hai Shalomfdcde762020-04-02 11:19:20 -07002667 reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002668 auth_transaction + 1, resp, resp_ies,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002669 resp_ies_len, "handle-auth");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002670
2671 if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
2672 reply_res != WLAN_STATUS_SUCCESS)) {
2673 hostapd_drv_sta_remove(hapd, sta->addr);
2674 sta->added_unassoc = 0;
2675 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002676}
2677
2678
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002679int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002680{
2681 int i, j = 32, aid;
2682
2683 /* get a unique AID */
2684 if (sta->aid > 0) {
2685 wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
2686 return 0;
2687 }
2688
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07002689 if (TEST_FAIL())
2690 return -1;
2691
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002692 for (i = 0; i < AID_WORDS; i++) {
2693 if (hapd->sta_aid[i] == (u32) -1)
2694 continue;
2695 for (j = 0; j < 32; j++) {
2696 if (!(hapd->sta_aid[i] & BIT(j)))
2697 break;
2698 }
2699 if (j < 32)
2700 break;
2701 }
2702 if (j == 32)
2703 return -1;
2704 aid = i * 32 + j + 1;
2705 if (aid > 2007)
2706 return -1;
2707
2708 sta->aid = aid;
2709 hapd->sta_aid[i] |= BIT(j);
2710 wpa_printf(MSG_DEBUG, " new AID %d", sta->aid);
2711 return 0;
2712}
2713
2714
2715static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
2716 const u8 *ssid_ie, size_t ssid_ie_len)
2717{
2718 if (ssid_ie == NULL)
2719 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2720
2721 if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
2722 os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002723 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2724 HOSTAPD_LEVEL_INFO,
2725 "Station tried to associate with unknown SSID "
Dmitry Shmidt3c479372014-02-04 10:50:36 -08002726 "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002727 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2728 }
2729
2730 return WLAN_STATUS_SUCCESS;
2731}
2732
2733
2734static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
2735 const u8 *wmm_ie, size_t wmm_ie_len)
2736{
2737 sta->flags &= ~WLAN_STA_WMM;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002738 sta->qosinfo = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002739 if (wmm_ie && hapd->conf->wmm_enabled) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002740 struct wmm_information_element *wmm;
2741
2742 if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002743 hostapd_logger(hapd, sta->addr,
2744 HOSTAPD_MODULE_WPA,
2745 HOSTAPD_LEVEL_DEBUG,
2746 "invalid WMM element in association "
2747 "request");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002748 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2749 }
2750
2751 sta->flags |= WLAN_STA_WMM;
2752 wmm = (struct wmm_information_element *) wmm_ie;
2753 sta->qosinfo = wmm->qos_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002754 }
2755 return WLAN_STATUS_SUCCESS;
2756}
2757
Hai Shalom74f70d42019-02-11 14:42:39 -08002758static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
2759 const u8 *multi_ap_ie, size_t multi_ap_len)
2760{
2761 u8 multi_ap_value = 0;
2762
2763 sta->flags &= ~WLAN_STA_MULTI_AP;
2764
2765 if (!hapd->conf->multi_ap)
2766 return WLAN_STATUS_SUCCESS;
2767
2768 if (multi_ap_ie) {
2769 const u8 *multi_ap_subelem;
2770
2771 multi_ap_subelem = get_ie(multi_ap_ie + 4,
2772 multi_ap_len - 4,
2773 MULTI_AP_SUB_ELEM_TYPE);
2774 if (multi_ap_subelem && multi_ap_subelem[1] == 1) {
2775 multi_ap_value = multi_ap_subelem[2];
2776 } else {
2777 hostapd_logger(hapd, sta->addr,
2778 HOSTAPD_MODULE_IEEE80211,
2779 HOSTAPD_LEVEL_INFO,
2780 "Multi-AP IE has missing or invalid Multi-AP subelement");
2781 return WLAN_STATUS_INVALID_IE;
2782 }
2783 }
2784
Hai Shalom021b0b52019-04-10 11:17:58 -07002785 if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA)
2786 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2787 HOSTAPD_LEVEL_INFO,
2788 "Multi-AP IE with unexpected value 0x%02x",
2789 multi_ap_value);
Hai Shalom74f70d42019-02-11 14:42:39 -08002790
Hai Shalom021b0b52019-04-10 11:17:58 -07002791 if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) {
2792 if (hapd->conf->multi_ap & FRONTHAUL_BSS)
2793 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08002794
Hai Shalom021b0b52019-04-10 11:17:58 -07002795 hostapd_logger(hapd, sta->addr,
2796 HOSTAPD_MODULE_IEEE80211,
2797 HOSTAPD_LEVEL_INFO,
2798 "Non-Multi-AP STA tries to associate with backhaul-only BSS");
2799 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
Hai Shalom74f70d42019-02-11 14:42:39 -08002800 }
2801
Hai Shalom021b0b52019-04-10 11:17:58 -07002802 if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
2803 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2804 HOSTAPD_LEVEL_DEBUG,
2805 "Backhaul STA tries to associate with fronthaul-only BSS");
2806
2807 sta->flags |= WLAN_STA_MULTI_AP;
2808 return WLAN_STATUS_SUCCESS;
Hai Shalom74f70d42019-02-11 14:42:39 -08002809}
2810
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002811
2812static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
2813 struct ieee802_11_elems *elems)
2814{
Dmitry Shmidt29333592017-01-09 12:27:11 -08002815 /* Supported rates not used in IEEE 802.11ad/DMG */
2816 if (hapd->iface->current_mode &&
2817 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
2818 return WLAN_STATUS_SUCCESS;
2819
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002820 if (!elems->supp_rates) {
2821 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2822 HOSTAPD_LEVEL_DEBUG,
2823 "No supported rates element in AssocReq");
2824 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2825 }
2826
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002827 if (elems->supp_rates_len + elems->ext_supp_rates_len >
2828 sizeof(sta->supported_rates)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002829 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
2830 HOSTAPD_LEVEL_DEBUG,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002831 "Invalid supported rates element length %d+%d",
2832 elems->supp_rates_len,
2833 elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002834 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2835 }
2836
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002837 sta->supported_rates_len = merge_byte_arrays(
2838 sta->supported_rates, sizeof(sta->supported_rates),
2839 elems->supp_rates, elems->supp_rates_len,
2840 elems->ext_supp_rates, elems->ext_supp_rates_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002841
2842 return WLAN_STATUS_SUCCESS;
2843}
2844
2845
Dmitry Shmidt051af732013-10-22 13:52:46 -07002846static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
2847 const u8 *ext_capab_ie, size_t ext_capab_ie_len)
2848{
2849#ifdef CONFIG_INTERWORKING
2850 /* check for QoS Map support */
2851 if (ext_capab_ie_len >= 5) {
2852 if (ext_capab_ie[4] & 0x01)
2853 sta->qos_map_enabled = 1;
2854 }
2855#endif /* CONFIG_INTERWORKING */
2856
Roshan Pius3a1667e2018-07-03 15:17:14 -07002857 if (ext_capab_ie_len > 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002858 sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
Roshan Pius3a1667e2018-07-03 15:17:14 -07002859 os_free(sta->ext_capability);
2860 sta->ext_capability = os_malloc(1 + ext_capab_ie_len);
2861 if (sta->ext_capability) {
2862 sta->ext_capability[0] = ext_capab_ie_len;
2863 os_memcpy(sta->ext_capability + 1, ext_capab_ie,
2864 ext_capab_ie_len);
2865 }
2866 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002867
Dmitry Shmidt051af732013-10-22 13:52:46 -07002868 return WLAN_STATUS_SUCCESS;
2869}
2870
2871
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002872#ifdef CONFIG_OWE
2873
2874static int owe_group_supported(struct hostapd_data *hapd, u16 group)
2875{
2876 int i;
2877 int *groups = hapd->conf->owe_groups;
2878
2879 if (group != 19 && group != 20 && group != 21)
2880 return 0;
2881
2882 if (!groups)
2883 return 1;
2884
2885 for (i = 0; groups[i] > 0; i++) {
2886 if (groups[i] == group)
2887 return 1;
2888 }
2889
2890 return 0;
2891}
2892
2893
2894static u16 owe_process_assoc_req(struct hostapd_data *hapd,
2895 struct sta_info *sta, const u8 *owe_dh,
2896 u8 owe_dh_len)
2897{
2898 struct wpabuf *secret, *pub, *hkey;
2899 int res;
2900 u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN];
2901 const char *info = "OWE Key Generation";
2902 const u8 *addr[2];
2903 size_t len[2];
2904 u16 group;
2905 size_t hash_len, prime_len;
2906
2907 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
2908 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
2909 return WLAN_STATUS_SUCCESS;
2910 }
2911
2912 group = WPA_GET_LE16(owe_dh);
2913 if (!owe_group_supported(hapd, group)) {
2914 wpa_printf(MSG_DEBUG, "OWE: Unsupported DH group %u", group);
2915 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
2916 }
2917 if (group == 19)
2918 prime_len = 32;
2919 else if (group == 20)
2920 prime_len = 48;
2921 else if (group == 21)
2922 prime_len = 66;
2923 else
2924 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
2925
2926 crypto_ecdh_deinit(sta->owe_ecdh);
2927 sta->owe_ecdh = crypto_ecdh_init(group);
2928 if (!sta->owe_ecdh)
2929 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
2930 sta->owe_group = group;
2931
2932 secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2,
2933 owe_dh_len - 2);
2934 secret = wpabuf_zeropad(secret, prime_len);
2935 if (!secret) {
2936 wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
2937 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2938 }
2939 wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
2940
2941 /* prk = HKDF-extract(C | A | group, z) */
2942
2943 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
2944 if (!pub) {
2945 wpabuf_clear_free(secret);
2946 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2947 }
2948
2949 /* PMKID = Truncate-128(Hash(C | A)) */
2950 addr[0] = owe_dh + 2;
2951 len[0] = owe_dh_len - 2;
2952 addr[1] = wpabuf_head(pub);
2953 len[1] = wpabuf_len(pub);
2954 if (group == 19) {
2955 res = sha256_vector(2, addr, len, pmkid);
2956 hash_len = SHA256_MAC_LEN;
2957 } else if (group == 20) {
2958 res = sha384_vector(2, addr, len, pmkid);
2959 hash_len = SHA384_MAC_LEN;
2960 } else if (group == 21) {
2961 res = sha512_vector(2, addr, len, pmkid);
2962 hash_len = SHA512_MAC_LEN;
2963 } else {
2964 wpabuf_free(pub);
2965 wpabuf_clear_free(secret);
2966 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2967 }
2968 pub = wpabuf_zeropad(pub, prime_len);
2969 if (res < 0 || !pub) {
2970 wpabuf_free(pub);
2971 wpabuf_clear_free(secret);
2972 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2973 }
2974
2975 hkey = wpabuf_alloc(owe_dh_len - 2 + wpabuf_len(pub) + 2);
2976 if (!hkey) {
2977 wpabuf_free(pub);
2978 wpabuf_clear_free(secret);
2979 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2980 }
2981
2982 wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */
2983 wpabuf_put_buf(hkey, pub); /* A */
2984 wpabuf_free(pub);
2985 wpabuf_put_le16(hkey, group); /* group */
2986 if (group == 19)
2987 res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
2988 wpabuf_head(secret), wpabuf_len(secret), prk);
2989 else if (group == 20)
2990 res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey),
2991 wpabuf_head(secret), wpabuf_len(secret), prk);
2992 else if (group == 21)
2993 res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey),
2994 wpabuf_head(secret), wpabuf_len(secret), prk);
2995 wpabuf_clear_free(hkey);
2996 wpabuf_clear_free(secret);
2997 if (res < 0)
2998 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2999
3000 wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
3001
3002 /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
3003
3004 os_free(sta->owe_pmk);
3005 sta->owe_pmk = os_malloc(hash_len);
3006 if (!sta->owe_pmk) {
3007 os_memset(prk, 0, SHA512_MAC_LEN);
3008 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3009 }
3010
3011 if (group == 19)
3012 res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info,
3013 os_strlen(info), sta->owe_pmk, hash_len);
3014 else if (group == 20)
3015 res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info,
3016 os_strlen(info), sta->owe_pmk, hash_len);
3017 else if (group == 21)
3018 res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
3019 os_strlen(info), sta->owe_pmk, hash_len);
3020 os_memset(prk, 0, SHA512_MAC_LEN);
3021 if (res < 0) {
3022 os_free(sta->owe_pmk);
3023 sta->owe_pmk = NULL;
3024 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3025 }
3026 sta->owe_pmk_len = hash_len;
3027
3028 wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
3029 wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
3030 wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk,
3031 sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE);
3032
3033 return WLAN_STATUS_SUCCESS;
3034}
3035
Hai Shalom81f62d82019-07-22 12:10:00 -07003036
3037u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
3038 const u8 *rsn_ie, size_t rsn_ie_len,
3039 const u8 *owe_dh, size_t owe_dh_len)
3040{
3041 struct wpa_ie_data data;
3042 int res;
3043
3044 if (!rsn_ie || rsn_ie_len < 2) {
3045 wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
3046 MAC2STR(peer));
3047 return WLAN_STATUS_INVALID_IE;
3048 }
3049 rsn_ie -= 2;
3050 rsn_ie_len += 2;
3051
3052 res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
3053 if (res) {
3054 wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
3055 " (res=%d)", MAC2STR(peer), res);
3056 wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
3057 return wpa_res_to_status_code(res);
3058 }
3059 if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
3060 wpa_printf(MSG_DEBUG,
3061 "OWE: Unexpected key mgmt 0x%x from " MACSTR,
3062 (unsigned int) data.key_mgmt, MAC2STR(peer));
3063 return WLAN_STATUS_AKMP_NOT_VALID;
3064 }
3065 if (!owe_dh) {
3066 wpa_printf(MSG_DEBUG,
3067 "OWE: No Diffie-Hellman Parameter element from "
3068 MACSTR, MAC2STR(peer));
3069 return WLAN_STATUS_AKMP_NOT_VALID;
3070 }
3071
3072 return WLAN_STATUS_SUCCESS;
3073}
3074
3075
3076u16 owe_process_rsn_ie(struct hostapd_data *hapd,
3077 struct sta_info *sta,
3078 const u8 *rsn_ie, size_t rsn_ie_len,
3079 const u8 *owe_dh, size_t owe_dh_len)
3080{
3081 u16 status;
3082 u8 *owe_buf, ie[256 * 2];
3083 size_t ie_len = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07003084 enum wpa_validate_result res;
Hai Shalom81f62d82019-07-22 12:10:00 -07003085
3086 if (!rsn_ie || rsn_ie_len < 2) {
3087 wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
3088 status = WLAN_STATUS_INVALID_IE;
3089 goto end;
3090 }
3091
3092 if (!sta->wpa_sm)
3093 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
3094 NULL);
3095 if (!sta->wpa_sm) {
3096 wpa_printf(MSG_WARNING,
3097 "OWE: Failed to initialize WPA state machine");
3098 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3099 goto end;
3100 }
3101 rsn_ie -= 2;
3102 rsn_ie_len += 2;
3103 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
3104 hapd->iface->freq, rsn_ie, rsn_ie_len,
Hai Shalomc3565922019-10-28 11:58:20 -07003105 NULL, 0, NULL, 0, owe_dh, owe_dh_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07003106 status = wpa_res_to_status_code(res);
3107 if (status != WLAN_STATUS_SUCCESS)
3108 goto end;
3109 status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
3110 if (status != WLAN_STATUS_SUCCESS)
3111 goto end;
3112 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
3113 NULL, 0);
3114 if (!owe_buf) {
3115 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3116 goto end;
3117 }
3118
3119 if (sta->owe_ecdh) {
3120 struct wpabuf *pub;
3121
3122 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
3123 if (!pub) {
3124 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
3125 goto end;
3126 }
3127
3128 /* OWE Diffie-Hellman Parameter element */
3129 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
3130 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
3131 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
3132 */
3133 WPA_PUT_LE16(owe_buf, sta->owe_group);
3134 owe_buf += 2;
3135 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
3136 owe_buf += wpabuf_len(pub);
3137 wpabuf_free(pub);
3138 sta->external_dh_updated = 1;
3139 }
3140 ie_len = owe_buf - ie;
3141
3142end:
3143 wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
3144 MACSTR, status, (unsigned int) ie_len,
3145 MAC2STR(sta->addr));
3146 hostapd_drv_update_dh_ie(hapd, sta->addr, status,
3147 status == WLAN_STATUS_SUCCESS ? ie : NULL,
3148 ie_len);
3149
3150 return status;
3151}
3152
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003153#endif /* CONFIG_OWE */
3154
3155
Hai Shalom899fcc72020-10-19 14:38:18 -07003156static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
3157 int reassoc)
3158{
3159 if ((sta->flags &
3160 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
3161 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
3162 return false;
3163
3164 if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
3165 ap_check_sa_query_timeout(hapd, sta);
3166
3167 if (!sta->sa_query_timed_out &&
3168 (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
3169 /*
3170 * STA has already been associated with MFP and SA Query timeout
3171 * has not been reached. Reject the association attempt
3172 * temporarily and start SA Query, if one is not pending.
3173 */
3174 if (sta->sa_query_count == 0)
3175 ap_sta_start_sa_query(hapd, sta);
3176
3177 return true;
3178 }
3179
3180 return false;
3181}
3182
3183
Hai Shalomb755a2a2020-04-23 21:49:02 -07003184static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003185 const u8 *ies, size_t ies_len, int reassoc)
3186{
3187 struct ieee802_11_elems elems;
Hai Shalomb755a2a2020-04-23 21:49:02 -07003188 int resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003189 const u8 *wpa_ie;
3190 size_t wpa_ie_len;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003191 const u8 *p2p_dev_addr = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003192
3193 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
3194 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3195 HOSTAPD_LEVEL_INFO, "Station sent an invalid "
3196 "association request");
3197 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3198 }
3199
3200 resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len);
3201 if (resp != WLAN_STATUS_SUCCESS)
3202 return resp;
3203 resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
3204 if (resp != WLAN_STATUS_SUCCESS)
3205 return resp;
Dmitry Shmidt051af732013-10-22 13:52:46 -07003206 resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len);
3207 if (resp != WLAN_STATUS_SUCCESS)
3208 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003209 resp = copy_supp_rates(hapd, sta, &elems);
3210 if (resp != WLAN_STATUS_SUCCESS)
3211 return resp;
Hai Shalom74f70d42019-02-11 14:42:39 -08003212
3213 resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len);
3214 if (resp != WLAN_STATUS_SUCCESS)
3215 return resp;
3216
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07003217 resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003218 if (resp != WLAN_STATUS_SUCCESS)
3219 return resp;
3220 if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
3221 !(sta->flags & WLAN_STA_HT)) {
3222 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3223 HOSTAPD_LEVEL_INFO, "Station does not support "
3224 "mandatory HT PHY - reject association");
3225 return WLAN_STATUS_ASSOC_DENIED_NO_HT;
3226 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003227
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003228#ifdef CONFIG_IEEE80211AC
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003229 if (hapd->iconf->ieee80211ac) {
3230 resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities);
3231 if (resp != WLAN_STATUS_SUCCESS)
3232 return resp;
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08003233
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003234 resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
3235 if (resp != WLAN_STATUS_SUCCESS)
3236 return resp;
3237 }
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08003238
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003239 if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
3240 !(sta->flags & WLAN_STA_VHT)) {
3241 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3242 HOSTAPD_LEVEL_INFO, "Station does not support "
3243 "mandatory VHT PHY - reject association");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003244 return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003245 }
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003246
3247 if (hapd->conf->vendor_vht && !elems.vht_capabilities) {
3248 resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht,
3249 elems.vendor_vht_len);
3250 if (resp != WLAN_STATUS_SUCCESS)
3251 return resp;
3252 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003253#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07003254#ifdef CONFIG_IEEE80211AX
3255 if (hapd->iconf->ieee80211ax) {
3256 resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
3257 elems.he_capabilities,
3258 elems.he_capabilities_len);
3259 if (resp != WLAN_STATUS_SUCCESS)
3260 return resp;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003261 if (is_6ghz_op_class(hapd->iconf->op_class)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07003262 if (!(sta->flags & WLAN_STA_HE)) {
3263 hostapd_logger(hapd, sta->addr,
3264 HOSTAPD_MODULE_IEEE80211,
3265 HOSTAPD_LEVEL_INFO,
3266 "Station does not support mandatory HE PHY - reject association");
3267 return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
3268 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003269 resp = copy_sta_he_6ghz_capab(hapd, sta,
3270 elems.he_6ghz_band_cap);
3271 if (resp != WLAN_STATUS_SUCCESS)
3272 return resp;
3273 }
Hai Shalom81f62d82019-07-22 12:10:00 -07003274 }
3275#endif /* CONFIG_IEEE80211AX */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003276
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003277#ifdef CONFIG_P2P
3278 if (elems.p2p) {
3279 wpabuf_free(sta->p2p_ie);
3280 sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
3281 P2P_IE_VENDOR_TYPE);
3282 if (sta->p2p_ie)
3283 p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
3284 } else {
3285 wpabuf_free(sta->p2p_ie);
3286 sta->p2p_ie = NULL;
3287 }
3288#endif /* CONFIG_P2P */
3289
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003290 if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
3291 wpa_ie = elems.rsn_ie;
3292 wpa_ie_len = elems.rsn_ie_len;
3293 } else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
3294 elems.wpa_ie) {
3295 wpa_ie = elems.wpa_ie;
3296 wpa_ie_len = elems.wpa_ie_len;
3297 } else {
3298 wpa_ie = NULL;
3299 wpa_ie_len = 0;
3300 }
3301
3302#ifdef CONFIG_WPS
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003303 sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003304 if (hapd->conf->wps_state && elems.wps_ie) {
3305 wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
3306 "Request - assume WPS is used");
Hai Shalom899fcc72020-10-19 14:38:18 -07003307 if (check_sa_query(hapd, sta, reassoc))
3308 return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003309 sta->flags |= WLAN_STA_WPS;
3310 wpabuf_free(sta->wps_ie);
3311 sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
3312 WPS_IE_VENDOR_TYPE);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003313 if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
3314 wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
3315 sta->flags |= WLAN_STA_WPS2;
3316 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003317 wpa_ie = NULL;
3318 wpa_ie_len = 0;
3319 if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
3320 wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
3321 "(Re)Association Request - reject");
3322 return WLAN_STATUS_INVALID_IE;
3323 }
3324 } else if (hapd->conf->wps_state && wpa_ie == NULL) {
3325 wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
3326 "(Re)Association Request - possible WPS use");
3327 sta->flags |= WLAN_STA_MAYBE_WPS;
3328 } else
3329#endif /* CONFIG_WPS */
3330 if (hapd->conf->wpa && wpa_ie == NULL) {
3331 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3332 HOSTAPD_LEVEL_INFO,
3333 "No WPA/RSN IE in association request");
3334 return WLAN_STATUS_INVALID_IE;
3335 }
3336
3337 if (hapd->conf->wpa && wpa_ie) {
Hai Shalomfdcde762020-04-02 11:19:20 -07003338 enum wpa_validate_result res;
3339
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003340 wpa_ie -= 2;
3341 wpa_ie_len += 2;
3342 if (sta->wpa_sm == NULL)
3343 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003344 sta->addr,
3345 p2p_dev_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003346 if (sta->wpa_sm == NULL) {
3347 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
3348 "state machine");
3349 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3350 }
Hai Shalom021b0b52019-04-10 11:17:58 -07003351 wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003352 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -07003353 hapd->iface->freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003354 wpa_ie, wpa_ie_len,
Hai Shalomc3565922019-10-28 11:58:20 -07003355 elems.rsnxe ? elems.rsnxe - 2 : NULL,
3356 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003357 elems.mdie, elems.mdie_len,
3358 elems.owe_dh, elems.owe_dh_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003359 resp = wpa_res_to_status_code(res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003360 if (resp != WLAN_STATUS_SUCCESS)
3361 return resp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003362
Hai Shalom899fcc72020-10-19 14:38:18 -07003363 if (check_sa_query(hapd, sta, reassoc))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003364 return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003365
3366 if (wpa_auth_uses_mfp(sta->wpa_sm))
3367 sta->flags |= WLAN_STA_MFP;
3368 else
3369 sta->flags &= ~WLAN_STA_MFP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003370
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003371#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003372 if (sta->auth_alg == WLAN_AUTH_FT) {
3373 if (!reassoc) {
3374 wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
3375 "to use association (not "
3376 "re-association) with FT auth_alg",
3377 MAC2STR(sta->addr));
3378 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3379 }
3380
3381 resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
3382 ies_len);
3383 if (resp != WLAN_STATUS_SUCCESS)
3384 return resp;
3385 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003386#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003387
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003388#ifdef CONFIG_SAE
Roshan Pius3a1667e2018-07-03 15:17:14 -07003389 if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
3390 sta->sae->state == SAE_ACCEPTED)
3391 wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
3392
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003393 if (wpa_auth_uses_sae(sta->wpa_sm) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003394 sta->auth_alg == WLAN_AUTH_OPEN) {
3395 struct rsn_pmksa_cache_entry *sa;
3396 sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
3397 if (!sa || sa->akmp != WPA_KEY_MGMT_SAE) {
3398 wpa_printf(MSG_DEBUG,
3399 "SAE: No PMKSA cache entry found for "
3400 MACSTR, MAC2STR(sta->addr));
3401 return WLAN_STATUS_INVALID_PMKID;
3402 }
3403 wpa_printf(MSG_DEBUG, "SAE: " MACSTR
3404 " using PMKSA caching", MAC2STR(sta->addr));
3405 } else if (wpa_auth_uses_sae(sta->wpa_sm) &&
3406 sta->auth_alg != WLAN_AUTH_SAE &&
3407 !(sta->auth_alg == WLAN_AUTH_FT &&
3408 wpa_auth_uses_ft_sae(sta->wpa_sm))) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003409 wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
3410 "SAE AKM after non-SAE auth_alg %u",
3411 MAC2STR(sta->addr), sta->auth_alg);
3412 return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
3413 }
Hai Shalomc3565922019-10-28 11:58:20 -07003414
3415 if (hapd->conf->sae_pwe == 2 &&
3416 sta->auth_alg == WLAN_AUTH_SAE &&
Hai Shalom899fcc72020-10-19 14:38:18 -07003417 sta->sae && !sta->sae->h2e &&
Hai Shalomc3565922019-10-28 11:58:20 -07003418 elems.rsnxe && elems.rsnxe_len >= 1 &&
3419 (elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
3420 wpa_printf(MSG_INFO, "SAE: " MACSTR
3421 " indicates support for SAE H2E, but did not use it",
3422 MAC2STR(sta->addr));
3423 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3424 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003425#endif /* CONFIG_SAE */
3426
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003427#ifdef CONFIG_OWE
3428 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
3429 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
3430 elems.owe_dh) {
3431 resp = owe_process_assoc_req(hapd, sta, elems.owe_dh,
3432 elems.owe_dh_len);
3433 if (resp != WLAN_STATUS_SUCCESS)
3434 return resp;
3435 }
3436#endif /* CONFIG_OWE */
3437
Hai Shalom021b0b52019-04-10 11:17:58 -07003438#ifdef CONFIG_DPP2
3439 dpp_pfs_free(sta->dpp_pfs);
3440 sta->dpp_pfs = NULL;
3441
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003442 if (DPP_VERSION > 1 &&
3443 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07003444 hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
3445 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
3446 elems.owe_dh) {
3447 sta->dpp_pfs = dpp_pfs_init(
3448 wpabuf_head(hapd->conf->dpp_netaccesskey),
3449 wpabuf_len(hapd->conf->dpp_netaccesskey));
3450 if (!sta->dpp_pfs) {
3451 wpa_printf(MSG_DEBUG,
3452 "DPP: Could not initialize PFS");
3453 /* Try to continue without PFS */
3454 goto pfs_fail;
3455 }
3456
3457 if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
3458 elems.owe_dh_len) < 0) {
3459 dpp_pfs_free(sta->dpp_pfs);
3460 sta->dpp_pfs = NULL;
3461 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3462 }
3463 }
3464
3465 wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
3466 sta->dpp_pfs->secret : NULL);
3467 pfs_fail:
3468#endif /* CONFIG_DPP2 */
3469
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003470 if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003471 wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
3472 hostapd_logger(hapd, sta->addr,
3473 HOSTAPD_MODULE_IEEE80211,
3474 HOSTAPD_LEVEL_INFO,
3475 "Station tried to use TKIP with HT "
3476 "association");
3477 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
3478 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003479#ifdef CONFIG_HS20
3480 } else if (hapd->conf->osen) {
3481 if (elems.osen == NULL) {
3482 hostapd_logger(
3483 hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
3484 HOSTAPD_LEVEL_INFO,
3485 "No HS 2.0 OSEN element in association request");
3486 return WLAN_STATUS_INVALID_IE;
3487 }
3488
3489 wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
3490 if (sta->wpa_sm == NULL)
3491 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
3492 sta->addr, NULL);
3493 if (sta->wpa_sm == NULL) {
3494 wpa_printf(MSG_WARNING, "Failed to initialize WPA "
3495 "state machine");
3496 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3497 }
3498 if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
3499 elems.osen - 2, elems.osen_len + 2) < 0)
3500 return WLAN_STATUS_INVALID_IE;
3501#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003502 } else
3503 wpa_auth_sta_no_wpa(sta->wpa_sm);
3504
3505#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003506 p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
3507#endif /* CONFIG_P2P */
3508
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003509#ifdef CONFIG_HS20
3510 wpabuf_free(sta->hs20_ie);
3511 if (elems.hs20 && elems.hs20_len > 4) {
Hai Shalom74f70d42019-02-11 14:42:39 -08003512 int release;
3513
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003514 sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
3515 elems.hs20_len - 4);
Hai Shalom74f70d42019-02-11 14:42:39 -08003516 release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
Hai Shalomc3565922019-10-28 11:58:20 -07003517 if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
3518 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
Hai Shalom74f70d42019-02-11 14:42:39 -08003519 wpa_printf(MSG_DEBUG,
3520 "HS 2.0: PMF not negotiated by release %d station "
3521 MACSTR, release, MAC2STR(sta->addr));
3522 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
3523 }
3524 } else {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003525 sta->hs20_ie = NULL;
Hai Shalom74f70d42019-02-11 14:42:39 -08003526 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003527
3528 wpabuf_free(sta->roaming_consortium);
3529 if (elems.roaming_cons_sel)
3530 sta->roaming_consortium = wpabuf_alloc_copy(
3531 elems.roaming_cons_sel + 4,
3532 elems.roaming_cons_sel_len - 4);
3533 else
3534 sta->roaming_consortium = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003535#endif /* CONFIG_HS20 */
3536
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003537#ifdef CONFIG_FST
3538 wpabuf_free(sta->mb_ies);
3539 if (hapd->iface->fst)
3540 sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
3541 else
3542 sta->mb_ies = NULL;
3543#endif /* CONFIG_FST */
3544
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003545#ifdef CONFIG_MBO
3546 mbo_ap_check_sta_assoc(hapd, sta, &elems);
3547
3548 if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
3549 elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
3550 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
3551 wpa_printf(MSG_INFO,
3552 "MBO: Reject WPA2 association without PMF");
3553 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3554 }
3555#endif /* CONFIG_MBO */
3556
Hai Shalom74f70d42019-02-11 14:42:39 -08003557#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
3558 if (wpa_auth_uses_ocv(sta->wpa_sm) &&
3559 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
3560 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
3561 sta->auth_alg == WLAN_AUTH_FILS_PK)) {
3562 struct wpa_channel_info ci;
3563 int tx_chanwidth;
3564 int tx_seg1_idx;
Hai Shalom899fcc72020-10-19 14:38:18 -07003565 enum oci_verify_result res;
Hai Shalom74f70d42019-02-11 14:42:39 -08003566
3567 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
3568 wpa_printf(MSG_WARNING,
3569 "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
3570 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3571 }
3572
3573 if (get_sta_tx_parameters(sta->wpa_sm,
3574 channel_width_to_int(ci.chanwidth),
3575 ci.seg1_idx, &tx_chanwidth,
3576 &tx_seg1_idx) < 0)
3577 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3578
Hai Shalom899fcc72020-10-19 14:38:18 -07003579 res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
3580 tx_chanwidth, tx_seg1_idx);
3581 if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
3582 res == OCI_NOT_FOUND) {
3583 /* Work around misbehaving STAs */
3584 wpa_printf(MSG_INFO,
3585 "FILS: Disable OCV with a STA that does not send OCI");
3586 wpa_auth_set_ocv(sta->wpa_sm, 0);
3587 } else if (res != OCI_SUCCESS) {
3588 wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
3589 ocv_errorstr);
3590 wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
3591 MACSTR " frame=fils-reassoc-req error=%s",
3592 MAC2STR(sta->addr), ocv_errorstr);
Hai Shalom74f70d42019-02-11 14:42:39 -08003593 return WLAN_STATUS_UNSPECIFIED_FAILURE;
3594 }
3595 }
3596#endif /* CONFIG_FILS && CONFIG_OCV */
3597
Dmitry Shmidt9c175262016-03-03 10:20:07 -08003598 ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
3599 elems.supp_op_classes_len);
3600
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003601 if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
3602 elems.rrm_enabled &&
3603 elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
3604 os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
3605 sizeof(sta->rrm_enabled_capa));
3606
Roshan Pius3a1667e2018-07-03 15:17:14 -07003607 if (elems.power_capab) {
3608 sta->min_tx_power = elems.power_capab[0];
3609 sta->max_tx_power = elems.power_capab[1];
3610 sta->power_capab = 1;
3611 } else {
3612 sta->power_capab = 0;
3613 }
3614
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003615 return WLAN_STATUS_SUCCESS;
3616}
3617
3618
3619static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
3620 u16 reason_code)
3621{
3622 int send_len;
3623 struct ieee80211_mgmt reply;
3624
3625 os_memset(&reply, 0, sizeof(reply));
3626 reply.frame_control =
3627 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
3628 os_memcpy(reply.da, addr, ETH_ALEN);
3629 os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
3630 os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
3631
3632 send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
3633 reply.u.deauth.reason_code = host_to_le16(reason_code);
3634
Hai Shalomfdcde762020-04-02 11:19:20 -07003635 if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003636 wpa_printf(MSG_INFO, "Failed to send deauth: %s",
3637 strerror(errno));
3638}
3639
3640
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003641static int add_associated_sta(struct hostapd_data *hapd,
Hai Shalom74f70d42019-02-11 14:42:39 -08003642 struct sta_info *sta, int reassoc)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003643{
3644 struct ieee80211_ht_capabilities ht_cap;
3645 struct ieee80211_vht_capabilities vht_cap;
Hai Shalom81f62d82019-07-22 12:10:00 -07003646 struct ieee80211_he_capabilities he_cap;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02003647 int set = 1;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003648
3649 /*
3650 * Remove the STA entry to ensure the STA PS state gets cleared and
3651 * configuration gets updated. This is relevant for cases, such as
3652 * FT-over-the-DS, where a station re-associates back to the same AP but
3653 * skips the authentication flow, or if working with a driver that
3654 * does not support full AP client state.
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02003655 *
3656 * Skip this if the STA has already completed FT reassociation and the
3657 * TK has been configured since the TX/RX PN must not be reset to 0 for
3658 * the same key.
Hai Shalom74f70d42019-02-11 14:42:39 -08003659 *
3660 * FT-over-the-DS has a special case where the STA entry (and as such,
3661 * the TK) has not yet been configured to the driver depending on which
3662 * driver interface is used. For that case, allow add-STA operation to
3663 * be used (instead of set-STA). This is needed to allow mac80211-based
3664 * drivers to accept the STA parameter configuration. Since this is
3665 * after a new FT-over-DS exchange, a new TK has been derived, so key
3666 * reinstallation is not a concern for this case.
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003667 */
Hai Shalom74f70d42019-02-11 14:42:39 -08003668 wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
3669 " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
3670 MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
3671 sta->ft_over_ds, reassoc,
3672 !!(sta->flags & WLAN_STA_AUTHORIZED),
3673 wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
3674 wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
3675
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02003676 if (!sta->added_unassoc &&
3677 (!(sta->flags & WLAN_STA_AUTHORIZED) ||
Hai Shalom74f70d42019-02-11 14:42:39 -08003678 (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003679 (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
3680 !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003681 hostapd_drv_sta_remove(hapd, sta->addr);
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02003682 wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
3683 set = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08003684
3685 /* Do not allow the FT-over-DS exception to be used more than
3686 * once per authentication exchange to guarantee a new TK is
3687 * used here */
3688 sta->ft_over_ds = 0;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02003689 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003690
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003691 if (sta->flags & WLAN_STA_HT)
3692 hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003693#ifdef CONFIG_IEEE80211AC
3694 if (sta->flags & WLAN_STA_VHT)
3695 hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
3696#endif /* CONFIG_IEEE80211AC */
Hai Shalom81f62d82019-07-22 12:10:00 -07003697#ifdef CONFIG_IEEE80211AX
3698 if (sta->flags & WLAN_STA_HE) {
3699 hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
3700 sta->he_capab_len);
3701 }
3702#endif /* CONFIG_IEEE80211AX */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003703
3704 /*
3705 * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
3706 * will be set when the ACK frame for the (Re)Association Response frame
3707 * is processed (TX status driver event).
3708 */
3709 if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
3710 sta->supported_rates, sta->supported_rates_len,
3711 sta->listen_interval,
3712 sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
3713 sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
Hai Shalom81f62d82019-07-22 12:10:00 -07003714 sta->flags & WLAN_STA_HE ? &he_cap : NULL,
3715 sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003716 sta->he_6ghz_capab,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003717 sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003718 sta->vht_opmode, sta->p2p_ie ? 1 : 0,
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02003719 set)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003720 hostapd_logger(hapd, sta->addr,
3721 HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
3722 "Could not %s STA to kernel driver",
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02003723 set ? "set" : "add");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003724
3725 if (sta->added_unassoc) {
3726 hostapd_drv_sta_remove(hapd, sta->addr);
3727 sta->added_unassoc = 0;
3728 }
3729
3730 return -1;
3731 }
3732
3733 sta->added_unassoc = 0;
3734
3735 return 0;
3736}
3737
3738
3739static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
Dmitry Shmidt29333592017-01-09 12:27:11 -08003740 const u8 *addr, u16 status_code, int reassoc,
Hai Shalomfdcde762020-04-02 11:19:20 -07003741 const u8 *ies, size_t ies_len, int rssi,
3742 int omit_rsnxe)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003743{
3744 int send_len;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003745 u8 *buf;
3746 size_t buflen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003747 struct ieee80211_mgmt *reply;
3748 u8 *p;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003749 u16 res = WLAN_STATUS_SUCCESS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003750
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003751 buflen = sizeof(struct ieee80211_mgmt) + 1024;
3752#ifdef CONFIG_FILS
3753 if (sta && sta->fils_hlp_resp)
3754 buflen += wpabuf_len(sta->fils_hlp_resp);
Hai Shalom81f62d82019-07-22 12:10:00 -07003755 if (sta)
3756 buflen += 150;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003757#endif /* CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003758#ifdef CONFIG_OWE
3759 if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
3760 buflen += 150;
3761#endif /* CONFIG_OWE */
Hai Shalom021b0b52019-04-10 11:17:58 -07003762#ifdef CONFIG_DPP2
3763 if (sta && sta->dpp_pfs)
3764 buflen += 5 + sta->dpp_pfs->curve->prime_len;
3765#endif /* CONFIG_DPP2 */
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003766 buf = os_zalloc(buflen);
3767 if (!buf) {
3768 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
3769 goto done;
3770 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003771 reply = (struct ieee80211_mgmt *) buf;
3772 reply->frame_control =
3773 IEEE80211_FC(WLAN_FC_TYPE_MGMT,
3774 (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
3775 WLAN_FC_STYPE_ASSOC_RESP));
Dmitry Shmidt29333592017-01-09 12:27:11 -08003776 os_memcpy(reply->da, addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003777 os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
3778 os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
3779
3780 send_len = IEEE80211_HDRLEN;
3781 send_len += sizeof(reply->u.assoc_resp);
3782 reply->u.assoc_resp.capab_info =
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07003783 host_to_le16(hostapd_own_capab_info(hapd));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003784 reply->u.assoc_resp.status_code = host_to_le16(status_code);
Dmitry Shmidt29333592017-01-09 12:27:11 -08003785
3786 reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
3787 BIT(14) | BIT(15));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003788 /* Supported rates */
3789 p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
3790 /* Extended supported rates */
3791 p = hostapd_eid_ext_supp_rates(hapd, p);
3792
Hai Shalomfdcde762020-04-02 11:19:20 -07003793 /* Radio measurement capabilities */
3794 p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
3795
Hai Shalom74f70d42019-02-11 14:42:39 -08003796#ifdef CONFIG_MBO
3797 if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
3798 rssi != 0) {
3799 int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
3800
3801 p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
3802 delta);
3803 }
3804#endif /* CONFIG_MBO */
3805
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003806#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt29333592017-01-09 12:27:11 -08003807 if (sta && status_code == WLAN_STATUS_SUCCESS) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003808 /* IEEE 802.11r: Mobility Domain Information, Fast BSS
3809 * Transition Information, RSN, [RIC Response] */
3810 p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003811 buf + buflen - p,
Hai Shalomfdcde762020-04-02 11:19:20 -07003812 sta->auth_alg, ies, ies_len,
3813 omit_rsnxe);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003814 if (!p) {
3815 wpa_printf(MSG_DEBUG,
3816 "FT: Failed to write AssocResp IEs");
3817 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
3818 goto done;
3819 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003820 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003821#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom81f62d82019-07-22 12:10:00 -07003822#ifdef CONFIG_FILS
3823 if (sta && status_code == WLAN_STATUS_SUCCESS &&
3824 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
3825 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
3826 sta->auth_alg == WLAN_AUTH_FILS_PK))
3827 p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
3828 buf + buflen - p,
3829 ies, ies_len);
3830#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003831
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003832#ifdef CONFIG_OWE
Hai Shalom74f70d42019-02-11 14:42:39 -08003833 if (sta && status_code == WLAN_STATUS_SUCCESS &&
3834 (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003835 p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
3836 buf + buflen - p,
3837 ies, ies_len);
3838#endif /* CONFIG_OWE */
3839
Dmitry Shmidt29333592017-01-09 12:27:11 -08003840 if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003841 p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003842
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003843 p = hostapd_eid_ht_capabilities(hapd, p);
3844 p = hostapd_eid_ht_operation(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003845
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003846#ifdef CONFIG_IEEE80211AC
Hai Shalomc3565922019-10-28 11:58:20 -07003847 if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
3848 !is_6ghz_op_class(hapd->iconf->op_class)) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07003849 u32 nsts = 0, sta_nsts;
3850
Dmitry Shmidt29333592017-01-09 12:27:11 -08003851 if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
Dmitry Shmidt7d175302016-09-06 13:11:34 -07003852 struct ieee80211_vht_capabilities *capa;
3853
3854 nsts = (hapd->iface->conf->vht_capab >>
3855 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
3856 capa = sta->vht_capabilities;
3857 sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
3858 VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
3859
3860 if (nsts < sta_nsts)
3861 nsts = 0;
3862 else
3863 nsts = sta_nsts;
3864 }
3865 p = hostapd_eid_vht_capabilities(hapd, p, nsts);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003866 p = hostapd_eid_vht_operation(hapd, p);
3867 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003868#endif /* CONFIG_IEEE80211AC */
3869
Hai Shalom81f62d82019-07-22 12:10:00 -07003870#ifdef CONFIG_IEEE80211AX
3871 if (hapd->iconf->ieee80211ax) {
3872 p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
3873 p = hostapd_eid_he_operation(hapd, p);
3874 p = hostapd_eid_spatial_reuse(hapd, p);
3875 p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003876 p = hostapd_eid_he_6ghz_band_cap(hapd, p);
Hai Shalom81f62d82019-07-22 12:10:00 -07003877 }
3878#endif /* CONFIG_IEEE80211AX */
3879
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003880 p = hostapd_eid_ext_capab(hapd, p);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003881 p = hostapd_eid_bss_max_idle_period(hapd, p);
Dmitry Shmidt29333592017-01-09 12:27:11 -08003882 if (sta && sta->qos_map_enabled)
Dmitry Shmidt051af732013-10-22 13:52:46 -07003883 p = hostapd_eid_qos_map_set(hapd, p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003884
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003885#ifdef CONFIG_FST
3886 if (hapd->iface->fst_ies) {
3887 os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
3888 wpabuf_len(hapd->iface->fst_ies));
3889 p += wpabuf_len(hapd->iface->fst_ies);
3890 }
3891#endif /* CONFIG_FST */
3892
Hai Shalomfdcde762020-04-02 11:19:20 -07003893#ifdef CONFIG_TESTING_OPTIONS
3894 if (hapd->conf->rsnxe_override_ft &&
3895 buf + buflen - p >=
3896 (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
3897 sta && sta->auth_alg == WLAN_AUTH_FT) {
3898 wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
3899 os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
3900 wpabuf_len(hapd->conf->rsnxe_override_ft));
3901 p += wpabuf_len(hapd->conf->rsnxe_override_ft);
3902 goto rsnxe_done;
3903 }
3904#endif /* CONFIG_TESTING_OPTIONS */
3905 if (!omit_rsnxe)
3906 p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
3907#ifdef CONFIG_TESTING_OPTIONS
3908rsnxe_done:
3909#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomc3565922019-10-28 11:58:20 -07003910
Hai Shalom021b0b52019-04-10 11:17:58 -07003911#ifdef CONFIG_OWE
3912 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
3913 sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
Hai Shalom899fcc72020-10-19 14:38:18 -07003914 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
3915 !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07003916 struct wpabuf *pub;
3917
3918 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
3919 if (!pub) {
3920 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
3921 goto done;
3922 }
3923 /* OWE Diffie-Hellman Parameter element */
3924 *p++ = WLAN_EID_EXTENSION; /* Element ID */
3925 *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
3926 *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
3927 WPA_PUT_LE16(p, sta->owe_group);
3928 p += 2;
3929 os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
3930 p += wpabuf_len(pub);
3931 wpabuf_free(pub);
3932 }
3933#endif /* CONFIG_OWE */
3934
3935#ifdef CONFIG_DPP2
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003936 if (DPP_VERSION > 1 && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
Hai Shalom021b0b52019-04-10 11:17:58 -07003937 sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
3938 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
3939 os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
3940 wpabuf_len(sta->dpp_pfs->ie));
3941 p += wpabuf_len(sta->dpp_pfs->ie);
3942 }
3943#endif /* CONFIG_DPP2 */
3944
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003945#ifdef CONFIG_IEEE80211AC
Dmitry Shmidt29333592017-01-09 12:27:11 -08003946 if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003947 p = hostapd_eid_vendor_vht(hapd, p);
3948#endif /* CONFIG_IEEE80211AC */
3949
Dmitry Shmidt29333592017-01-09 12:27:11 -08003950 if (sta && (sta->flags & WLAN_STA_WMM))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003951 p = hostapd_eid_wmm(hapd, p);
3952
3953#ifdef CONFIG_WPS
Dmitry Shmidt29333592017-01-09 12:27:11 -08003954 if (sta &&
3955 ((sta->flags & WLAN_STA_WPS) ||
3956 ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003957 struct wpabuf *wps = wps_build_assoc_resp_ie();
3958 if (wps) {
3959 os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
3960 p += wpabuf_len(wps);
3961 wpabuf_free(wps);
3962 }
3963 }
3964#endif /* CONFIG_WPS */
3965
Hai Shalom74f70d42019-02-11 14:42:39 -08003966 if (sta && (sta->flags & WLAN_STA_MULTI_AP))
3967 p = hostapd_eid_multi_ap(hapd, p);
3968
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003969#ifdef CONFIG_P2P
Dmitry Shmidt29333592017-01-09 12:27:11 -08003970 if (sta && sta->p2p_ie && hapd->p2p_group) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003971 struct wpabuf *p2p_resp_ie;
3972 enum p2p_status_code status;
3973 switch (status_code) {
3974 case WLAN_STATUS_SUCCESS:
3975 status = P2P_SC_SUCCESS;
3976 break;
3977 case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
3978 status = P2P_SC_FAIL_LIMIT_REACHED;
3979 break;
3980 default:
3981 status = P2P_SC_FAIL_INVALID_PARAMS;
3982 break;
3983 }
3984 p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
3985 if (p2p_resp_ie) {
3986 os_memcpy(p, wpabuf_head(p2p_resp_ie),
3987 wpabuf_len(p2p_resp_ie));
3988 p += wpabuf_len(p2p_resp_ie);
3989 wpabuf_free(p2p_resp_ie);
3990 }
3991 }
3992#endif /* CONFIG_P2P */
3993
3994#ifdef CONFIG_P2P_MANAGER
3995 if (hapd->conf->p2p & P2P_MANAGE)
3996 p = hostapd_eid_p2p_manage(hapd, p);
3997#endif /* CONFIG_P2P_MANAGER */
3998
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003999 p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004000
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004001 if (hapd->conf->assocresp_elements &&
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004002 (size_t) (buf + buflen - p) >=
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004003 wpabuf_len(hapd->conf->assocresp_elements)) {
4004 os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
4005 wpabuf_len(hapd->conf->assocresp_elements));
4006 p += wpabuf_len(hapd->conf->assocresp_elements);
4007 }
4008
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004009 send_len += p - reply->u.assoc_resp.variable;
4010
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004011#ifdef CONFIG_FILS
Dmitry Shmidt29333592017-01-09 12:27:11 -08004012 if (sta &&
4013 (sta->auth_alg == WLAN_AUTH_FILS_SK ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004014 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4015 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
4016 status_code == WLAN_STATUS_SUCCESS) {
4017 struct ieee802_11_elems elems;
4018
4019 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004020 ParseFailed || !elems.fils_session) {
4021 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4022 goto done;
4023 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004024
4025 /* FILS Session */
4026 *p++ = WLAN_EID_EXTENSION; /* Element ID */
4027 *p++ = 1 + FILS_SESSION_LEN; /* Length */
4028 *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
4029 os_memcpy(p, elems.fils_session, FILS_SESSION_LEN);
4030 send_len += 2 + 1 + FILS_SESSION_LEN;
4031
4032 send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004033 buflen, sta->fils_hlp_resp);
4034 if (send_len < 0) {
4035 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
4036 goto done;
4037 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004038 }
4039#endif /* CONFIG_FILS */
4040
Hai Shalomfdcde762020-04-02 11:19:20 -07004041 if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004042 wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
4043 strerror(errno));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004044 res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004045 }
4046
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004047done:
4048 os_free(buf);
4049 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004050}
4051
4052
Roshan Pius3a1667e2018-07-03 15:17:14 -07004053#ifdef CONFIG_OWE
4054u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
4055 const u8 *owe_dh, u8 owe_dh_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07004056 u8 *owe_buf, size_t owe_buf_len, u16 *status)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004057{
4058#ifdef CONFIG_TESTING_OPTIONS
4059 if (hapd->conf->own_ie_override) {
4060 wpa_printf(MSG_DEBUG, "OWE: Using IE override");
Hai Shalomfdcde762020-04-02 11:19:20 -07004061 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004062 return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
4063 owe_buf_len, NULL, 0);
4064 }
4065#endif /* CONFIG_TESTING_OPTIONS */
4066
4067 if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
4068 wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
4069 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
4070 owe_buf_len, NULL, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -07004071 *status = WLAN_STATUS_SUCCESS;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004072 return owe_buf;
4073 }
4074
Hai Shalom81f62d82019-07-22 12:10:00 -07004075 if (sta->owe_pmk && sta->external_dh_updated) {
4076 wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
Hai Shalomfdcde762020-04-02 11:19:20 -07004077 *status = WLAN_STATUS_SUCCESS;
Hai Shalom81f62d82019-07-22 12:10:00 -07004078 return owe_buf;
4079 }
4080
Hai Shalomfdcde762020-04-02 11:19:20 -07004081 *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
4082 if (*status != WLAN_STATUS_SUCCESS)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004083 return NULL;
4084
4085 owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
4086 owe_buf_len, NULL, 0);
4087
4088 if (sta->owe_ecdh && owe_buf) {
4089 struct wpabuf *pub;
4090
4091 pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
4092 if (!pub) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004093 *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004094 return owe_buf;
4095 }
4096
4097 /* OWE Diffie-Hellman Parameter element */
4098 *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
4099 *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
4100 *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
4101 */
4102 WPA_PUT_LE16(owe_buf, sta->owe_group);
4103 owe_buf += 2;
4104 os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
4105 owe_buf += wpabuf_len(pub);
4106 wpabuf_free(pub);
4107 }
4108
4109 return owe_buf;
4110}
4111#endif /* CONFIG_OWE */
4112
4113
Paul Stewart092955c2017-02-06 09:13:09 -08004114#ifdef CONFIG_FILS
4115
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004116void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
Paul Stewart092955c2017-02-06 09:13:09 -08004117{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004118 u16 reply_res;
Paul Stewart092955c2017-02-06 09:13:09 -08004119
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004120 wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
4121 MAC2STR(sta->addr));
4122 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
4123 if (!sta->fils_pending_assoc_req)
Paul Stewart092955c2017-02-06 09:13:09 -08004124 return;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004125 reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
4126 sta->fils_pending_assoc_is_reassoc,
4127 sta->fils_pending_assoc_req,
Hai Shalomfdcde762020-04-02 11:19:20 -07004128 sta->fils_pending_assoc_req_len, 0, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004129 os_free(sta->fils_pending_assoc_req);
4130 sta->fils_pending_assoc_req = NULL;
4131 sta->fils_pending_assoc_req_len = 0;
4132 wpabuf_free(sta->fils_hlp_resp);
4133 sta->fils_hlp_resp = NULL;
4134 wpabuf_free(sta->hlp_dhcp_discover);
4135 sta->hlp_dhcp_discover = NULL;
Paul Stewart092955c2017-02-06 09:13:09 -08004136
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004137 /*
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004138 * Remove the station in case transmission of a success response fails.
4139 * At this point the station was already added associated to the driver.
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004140 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004141 if (reply_res != WLAN_STATUS_SUCCESS)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004142 hostapd_drv_sta_remove(hapd, sta->addr);
Paul Stewart092955c2017-02-06 09:13:09 -08004143}
4144
4145
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004146void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
Paul Stewart092955c2017-02-06 09:13:09 -08004147{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004148 struct hostapd_data *hapd = eloop_ctx;
4149 struct sta_info *sta = eloop_data;
Paul Stewart092955c2017-02-06 09:13:09 -08004150
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004151 wpa_printf(MSG_DEBUG,
4152 "FILS: HLP response timeout - continue with association response for "
4153 MACSTR, MAC2STR(sta->addr));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004154 if (sta->fils_drv_assoc_finish)
4155 hostapd_notify_assoc_fils_finish(hapd, sta);
4156 else
4157 fils_hlp_finish_assoc(hapd, sta);
Paul Stewart092955c2017-02-06 09:13:09 -08004158}
4159
4160#endif /* CONFIG_FILS */
4161
4162
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004163static void handle_assoc(struct hostapd_data *hapd,
4164 const struct ieee80211_mgmt *mgmt, size_t len,
Hai Shalom74f70d42019-02-11 14:42:39 -08004165 int reassoc, int rssi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004166{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004167 u16 capab_info, listen_interval, seq_ctrl, fc;
Hai Shalomb755a2a2020-04-23 21:49:02 -07004168 int resp = WLAN_STATUS_SUCCESS;
Hai Shalom899fcc72020-10-19 14:38:18 -07004169 u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004170 const u8 *pos;
4171 int left, i;
4172 struct sta_info *sta;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004173 u8 *tmp = NULL;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004174#ifdef CONFIG_FILS
4175 int delay_assoc = 0;
4176#endif /* CONFIG_FILS */
Hai Shalomfdcde762020-04-02 11:19:20 -07004177 int omit_rsnxe = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004178
4179 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
4180 sizeof(mgmt->u.assoc_req))) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004181 wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
4182 reassoc, (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004183 return;
4184 }
4185
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004186#ifdef CONFIG_TESTING_OPTIONS
4187 if (reassoc) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004188 if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004189 drand48() < hapd->iconf->ignore_reassoc_probability) {
4190 wpa_printf(MSG_INFO,
4191 "TESTING: ignoring reassoc request from "
4192 MACSTR, MAC2STR(mgmt->sa));
4193 return;
4194 }
4195 } else {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004196 if (hapd->iconf->ignore_assoc_probability > 0.0 &&
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004197 drand48() < hapd->iconf->ignore_assoc_probability) {
4198 wpa_printf(MSG_INFO,
4199 "TESTING: ignoring assoc request from "
4200 MACSTR, MAC2STR(mgmt->sa));
4201 return;
4202 }
4203 }
4204#endif /* CONFIG_TESTING_OPTIONS */
4205
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004206 fc = le_to_host16(mgmt->frame_control);
4207 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
4208
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004209 if (reassoc) {
4210 capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
4211 listen_interval = le_to_host16(
4212 mgmt->u.reassoc_req.listen_interval);
4213 wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
4214 " capab_info=0x%02x listen_interval=%d current_ap="
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004215 MACSTR " seq_ctrl=0x%x%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004216 MAC2STR(mgmt->sa), capab_info, listen_interval,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004217 MAC2STR(mgmt->u.reassoc_req.current_ap),
4218 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004219 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
4220 pos = mgmt->u.reassoc_req.variable;
4221 } else {
4222 capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
4223 listen_interval = le_to_host16(
4224 mgmt->u.assoc_req.listen_interval);
4225 wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004226 " capab_info=0x%02x listen_interval=%d "
4227 "seq_ctrl=0x%x%s",
4228 MAC2STR(mgmt->sa), capab_info, listen_interval,
4229 seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004230 left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
4231 pos = mgmt->u.assoc_req.variable;
4232 }
4233
4234 sta = ap_get_sta(hapd, mgmt->sa);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004235#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004236 if (sta && sta->auth_alg == WLAN_AUTH_FT &&
4237 (sta->flags & WLAN_STA_AUTH) == 0) {
4238 wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
4239 "prior to authentication since it is using "
4240 "over-the-DS FT", MAC2STR(mgmt->sa));
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004241
4242 /*
4243 * Mark station as authenticated, to avoid adding station
4244 * entry in the driver as associated and not authenticated
4245 */
4246 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004247 } else
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004248#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004249 if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
Dmitry Shmidt29333592017-01-09 12:27:11 -08004250 if (hapd->iface->current_mode &&
4251 hapd->iface->current_mode->mode ==
4252 HOSTAPD_MODE_IEEE80211AD) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004253 int acl_res;
Hai Shalomfdcde762020-04-02 11:19:20 -07004254 struct radius_sta info;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004255
Hai Shalomfdcde762020-04-02 11:19:20 -07004256 acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
4257 (const u8 *) mgmt,
4258 len, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004259 if (acl_res == HOSTAPD_ACL_REJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004260 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
4261 "Ignore Association Request frame from "
4262 MACSTR " due to ACL reject",
4263 MAC2STR(mgmt->sa));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004264 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
4265 goto fail;
4266 }
4267 if (acl_res == HOSTAPD_ACL_PENDING)
4268 return;
4269
Dmitry Shmidt29333592017-01-09 12:27:11 -08004270 /* DMG/IEEE 802.11ad does not use authentication.
4271 * Allocate sta entry upon association. */
4272 sta = ap_sta_add(hapd, mgmt->sa);
4273 if (!sta) {
4274 hostapd_logger(hapd, mgmt->sa,
4275 HOSTAPD_MODULE_IEEE80211,
4276 HOSTAPD_LEVEL_INFO,
4277 "Failed to add STA");
4278 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4279 goto fail;
4280 }
4281
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004282 acl_res = ieee802_11_set_radius_info(
Hai Shalomfdcde762020-04-02 11:19:20 -07004283 hapd, sta, acl_res, &info);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004284 if (acl_res) {
4285 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
4286 goto fail;
4287 }
4288
Dmitry Shmidt29333592017-01-09 12:27:11 -08004289 hostapd_logger(hapd, sta->addr,
4290 HOSTAPD_MODULE_IEEE80211,
4291 HOSTAPD_LEVEL_DEBUG,
4292 "Skip authentication for DMG/IEEE 802.11ad");
4293 sta->flags |= WLAN_STA_AUTH;
4294 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
4295 sta->auth_alg = WLAN_AUTH_OPEN;
4296 } else {
4297 hostapd_logger(hapd, mgmt->sa,
4298 HOSTAPD_MODULE_IEEE80211,
4299 HOSTAPD_LEVEL_INFO,
4300 "Station tried to associate before authentication (aid=%d flags=0x%x)",
4301 sta ? sta->aid : -1,
4302 sta ? sta->flags : 0);
4303 send_deauth(hapd, mgmt->sa,
4304 WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
4305 return;
4306 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004307 }
4308
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004309 if ((fc & WLAN_FC_RETRY) &&
4310 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
4311 sta->last_seq_ctrl == seq_ctrl &&
Paul Stewart092955c2017-02-06 09:13:09 -08004312 sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
4313 WLAN_FC_STYPE_ASSOC_REQ)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004314 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4315 HOSTAPD_LEVEL_DEBUG,
4316 "Drop repeated association frame seq_ctrl=0x%x",
4317 seq_ctrl);
4318 return;
4319 }
4320 sta->last_seq_ctrl = seq_ctrl;
4321 sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
4322 WLAN_FC_STYPE_ASSOC_REQ;
4323
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004324 if (hapd->tkip_countermeasures) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004325 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004326 goto fail;
4327 }
4328
4329 if (listen_interval > hapd->conf->max_listen_interval) {
4330 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
4331 HOSTAPD_LEVEL_DEBUG,
4332 "Too large Listen Interval (%d)",
4333 listen_interval);
4334 resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
4335 goto fail;
4336 }
4337
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004338#ifdef CONFIG_MBO
4339 if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
4340 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4341 goto fail;
4342 }
Hai Shalom74f70d42019-02-11 14:42:39 -08004343
4344 if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
4345 rssi < hapd->iconf->rssi_reject_assoc_rssi &&
4346 (sta->auth_rssi == 0 ||
4347 sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
4348 resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
4349 goto fail;
4350 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004351#endif /* CONFIG_MBO */
4352
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004353 /*
4354 * sta->capability is used in check_assoc_ies() for RRM enabled
4355 * capability element.
4356 */
4357 sta->capability = capab_info;
4358
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004359#ifdef CONFIG_FILS
4360 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4361 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
4362 sta->auth_alg == WLAN_AUTH_FILS_PK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004363 int res;
4364
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004365 /* The end of the payload is encrypted. Need to decrypt it
4366 * before parsing. */
4367
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004368 tmp = os_memdup(pos, left);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004369 if (!tmp) {
4370 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
4371 goto fail;
4372 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004373
Roshan Pius3a1667e2018-07-03 15:17:14 -07004374 res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
4375 len, tmp, left);
4376 if (res < 0) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004377 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
4378 goto fail;
4379 }
4380 pos = tmp;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004381 left = res;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004382 }
4383#endif /* CONFIG_FILS */
4384
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004385 /* followed by SSID and Supported rates; and HT capabilities if 802.11n
4386 * is used */
4387 resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
4388 if (resp != WLAN_STATUS_SUCCESS)
4389 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07004390 omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004391
4392 if (hostapd_get_aid(hapd, sta) < 0) {
4393 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
4394 HOSTAPD_LEVEL_INFO, "No room for more AIDs");
4395 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4396 goto fail;
4397 }
4398
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004399 sta->listen_interval = listen_interval;
4400
Roshan Pius3a1667e2018-07-03 15:17:14 -07004401 if (hapd->iface->current_mode &&
4402 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004403 sta->flags |= WLAN_STA_NONERP;
4404 for (i = 0; i < sta->supported_rates_len; i++) {
4405 if ((sta->supported_rates[i] & 0x7f) > 22) {
4406 sta->flags &= ~WLAN_STA_NONERP;
4407 break;
4408 }
4409 }
4410 if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
4411 sta->nonerp_set = 1;
4412 hapd->iface->num_sta_non_erp++;
4413 if (hapd->iface->num_sta_non_erp == 1)
4414 ieee802_11_set_beacons(hapd->iface);
4415 }
4416
4417 if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
4418 !sta->no_short_slot_time_set) {
4419 sta->no_short_slot_time_set = 1;
4420 hapd->iface->num_sta_no_short_slot_time++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004421 if (hapd->iface->current_mode &&
4422 hapd->iface->current_mode->mode ==
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004423 HOSTAPD_MODE_IEEE80211G &&
4424 hapd->iface->num_sta_no_short_slot_time == 1)
4425 ieee802_11_set_beacons(hapd->iface);
4426 }
4427
4428 if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
4429 sta->flags |= WLAN_STA_SHORT_PREAMBLE;
4430 else
4431 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
4432
4433 if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
4434 !sta->no_short_preamble_set) {
4435 sta->no_short_preamble_set = 1;
4436 hapd->iface->num_sta_no_short_preamble++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004437 if (hapd->iface->current_mode &&
4438 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004439 && hapd->iface->num_sta_no_short_preamble == 1)
4440 ieee802_11_set_beacons(hapd->iface);
4441 }
4442
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004443 update_ht_state(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004444
4445 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4446 HOSTAPD_LEVEL_DEBUG,
4447 "association OK (aid %d)", sta->aid);
4448 /* Station will be marked associated, after it acknowledges AssocResp
4449 */
4450 sta->flags |= WLAN_STA_ASSOC_REQ_OK;
4451
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004452 if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
4453 wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
4454 "SA Query procedure", reassoc ? "re" : "");
4455 /* TODO: Send a protected Disassociate frame to the STA using
4456 * the old key and Reason Code "Previous Authentication no
4457 * longer valid". Make sure this is only sent protected since
4458 * unprotected frame would be received by the STA that is now
4459 * trying to associate.
4460 */
4461 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004462
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004463 /* Make sure that the previously registered inactivity timer will not
4464 * remove the STA immediately. */
4465 sta->timeout_next = STA_NULLFUNC;
4466
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07004467#ifdef CONFIG_TAXONOMY
4468 taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
4469#endif /* CONFIG_TAXONOMY */
4470
Dmitry Shmidt29333592017-01-09 12:27:11 -08004471 sta->pending_wds_enable = 0;
4472
Paul Stewart092955c2017-02-06 09:13:09 -08004473#ifdef CONFIG_FILS
4474 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
4475 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004476 sta->auth_alg == WLAN_AUTH_FILS_PK) {
4477 if (fils_process_hlp(hapd, sta, pos, left) > 0)
4478 delay_assoc = 1;
4479 }
Paul Stewart092955c2017-02-06 09:13:09 -08004480#endif /* CONFIG_FILS */
4481
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004482 fail:
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004483
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004484 /*
4485 * In case of a successful response, add the station to the driver.
4486 * Otherwise, the kernel may ignore Data frames before we process the
4487 * ACK frame (TX status). In case of a failure, this station will be
4488 * removed.
4489 *
4490 * Note that this is not compliant with the IEEE 802.11 standard that
4491 * states that a non-AP station should transition into the
4492 * authenticated/associated state only after the station acknowledges
4493 * the (Re)Association Response frame. However, still do this as:
4494 *
4495 * 1. In case the station does not acknowledge the (Re)Association
4496 * Response frame, it will be removed.
4497 * 2. Data frames will be dropped in the kernel until the station is
4498 * set into authorized state, and there are no significant known
4499 * issues with processing other non-Data Class 3 frames during this
4500 * window.
4501 */
Hai Shalom74f70d42019-02-11 14:42:39 -08004502 if (resp == WLAN_STATUS_SUCCESS && sta &&
4503 add_associated_sta(hapd, sta, reassoc))
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004504 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
4505
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004506#ifdef CONFIG_FILS
Hai Shalom74f70d42019-02-11 14:42:39 -08004507 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
4508 eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
4509 sta->fils_pending_assoc_req) {
4510 /* Do not reschedule fils_hlp_timeout in case the station
4511 * retransmits (Re)Association Request frame while waiting for
4512 * the previously started FILS HLP wait, so that the timeout can
4513 * be determined from the first pending attempt. */
4514 wpa_printf(MSG_DEBUG,
4515 "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
4516 MACSTR, MAC2STR(sta->addr));
4517 os_free(tmp);
4518 return;
4519 }
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004520 if (sta) {
4521 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
4522 os_free(sta->fils_pending_assoc_req);
4523 sta->fils_pending_assoc_req = NULL;
4524 sta->fils_pending_assoc_req_len = 0;
4525 wpabuf_free(sta->fils_hlp_resp);
4526 sta->fils_hlp_resp = NULL;
4527 }
4528 if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
4529 sta->fils_pending_assoc_req = tmp;
4530 sta->fils_pending_assoc_req_len = left;
4531 sta->fils_pending_assoc_is_reassoc = reassoc;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004532 sta->fils_drv_assoc_finish = 0;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004533 wpa_printf(MSG_DEBUG,
4534 "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
4535 MACSTR, MAC2STR(sta->addr));
4536 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
4537 eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
4538 fils_hlp_timeout, hapd, sta);
4539 return;
4540 }
4541#endif /* CONFIG_FILS */
4542
Hai Shalomb755a2a2020-04-23 21:49:02 -07004543 if (resp >= 0)
4544 reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc,
4545 pos, left, rssi, omit_rsnxe);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004546 os_free(tmp);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004547
4548 /*
Hai Shalom899fcc72020-10-19 14:38:18 -07004549 * Remove the station in case transmission of a success response fails
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004550 * (the STA was added associated to the driver) or if the station was
4551 * previously added unassociated.
4552 */
Dmitry Shmidt29333592017-01-09 12:27:11 -08004553 if (sta && ((reply_res != WLAN_STATUS_SUCCESS &&
4554 resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004555 hostapd_drv_sta_remove(hapd, sta->addr);
4556 sta->added_unassoc = 0;
4557 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004558}
4559
4560
4561static void handle_disassoc(struct hostapd_data *hapd,
4562 const struct ieee80211_mgmt *mgmt, size_t len)
4563{
4564 struct sta_info *sta;
4565
4566 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004567 wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)",
4568 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004569 return;
4570 }
4571
4572 wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
4573 MAC2STR(mgmt->sa),
4574 le_to_host16(mgmt->u.disassoc.reason_code));
4575
4576 sta = ap_get_sta(hapd, mgmt->sa);
4577 if (sta == NULL) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004578 wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated",
4579 MAC2STR(mgmt->sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004580 return;
4581 }
4582
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004583 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004584 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004585 sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07004586 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004587 wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
4588 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4589 HOSTAPD_LEVEL_INFO, "disassociated");
4590 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
4591 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
4592 /* Stop Accounting and IEEE 802.1X sessions, but leave the STA
4593 * authenticated. */
4594 accounting_sta_stop(hapd, sta);
Dmitry Shmidtde47be72016-01-07 12:52:55 -08004595 ieee802_1x_free_station(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004596 if (sta->ipaddr)
4597 hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
4598 ap_sta_ip6addr_del(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004599 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004600 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004601
4602 if (sta->timeout_next == STA_NULLFUNC ||
4603 sta->timeout_next == STA_DISASSOC) {
4604 sta->timeout_next = STA_DEAUTH;
4605 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
4606 eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
4607 hapd, sta);
4608 }
4609
4610 mlme_disassociate_indication(
4611 hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
Dmitry Shmidt29333592017-01-09 12:27:11 -08004612
4613 /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon
4614 * disassociation. */
4615 if (hapd->iface->current_mode &&
4616 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
4617 sta->flags &= ~WLAN_STA_AUTH;
4618 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
4619 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4620 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
4621 ap_free_sta(hapd, sta);
4622 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004623}
4624
4625
4626static void handle_deauth(struct hostapd_data *hapd,
4627 const struct ieee80211_mgmt *mgmt, size_t len)
4628{
4629 struct sta_info *sta;
4630
4631 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004632 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short "
4633 "payload (len=%lu)", (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004634 return;
4635 }
4636
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004637 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004638 " reason_code=%d",
4639 MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
4640
4641 sta = ap_get_sta(hapd, mgmt->sa);
4642 if (sta == NULL) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004643 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
4644 "to deauthenticate, but it is not authenticated",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004645 MAC2STR(mgmt->sa));
4646 return;
4647 }
4648
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004649 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004650 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004651 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
4652 WLAN_STA_ASSOC_REQ_OK);
Hai Shalomfdcde762020-04-02 11:19:20 -07004653 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004654 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
4655 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4656 HOSTAPD_LEVEL_DEBUG, "deauthenticated");
4657 mlme_deauthenticate_indication(
4658 hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
4659 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
4660 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
4661 ap_free_sta(hapd, sta);
4662}
4663
4664
4665static void handle_beacon(struct hostapd_data *hapd,
4666 const struct ieee80211_mgmt *mgmt, size_t len,
4667 struct hostapd_frame_info *fi)
4668{
4669 struct ieee802_11_elems elems;
4670
4671 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004672 wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
4673 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004674 return;
4675 }
4676
4677 (void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
4678 len - (IEEE80211_HDRLEN +
4679 sizeof(mgmt->u.beacon)), &elems,
4680 0);
4681
4682 ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
4683}
4684
4685
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004686static int robust_action_frame(u8 category)
4687{
4688 return category != WLAN_ACTION_PUBLIC &&
4689 category != WLAN_ACTION_HT;
4690}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004691
4692
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004693static int handle_action(struct hostapd_data *hapd,
Roshan Pius3a1667e2018-07-03 15:17:14 -07004694 const struct ieee80211_mgmt *mgmt, size_t len,
4695 unsigned int freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004696{
4697 struct sta_info *sta;
Hai Shalom74f70d42019-02-11 14:42:39 -08004698 u8 *action __maybe_unused;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004699
Hai Shalom74f70d42019-02-11 14:42:39 -08004700 if (len < IEEE80211_HDRLEN + 2 + 1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004701 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
4702 HOSTAPD_LEVEL_DEBUG,
4703 "handle_action - too short payload (len=%lu)",
4704 (unsigned long) len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004705 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004706 }
4707
Hai Shalom74f70d42019-02-11 14:42:39 -08004708 action = (u8 *) &mgmt->u.action.u;
4709 wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
4710 " da " MACSTR " len %d freq %u",
4711 mgmt->u.action.category, *action,
4712 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
4713
4714 sta = ap_get_sta(hapd, mgmt->sa);
4715
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004716 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
4717 (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
4718 wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
4719 "frame (category=%u) from unassociated STA " MACSTR,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08004720 mgmt->u.action.category, MAC2STR(mgmt->sa));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004721 return 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004722 }
4723
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004724 if (sta && (sta->flags & WLAN_STA_MFP) &&
Dmitry Shmidt18463232014-01-24 12:29:41 -08004725 !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
4726 robust_action_frame(mgmt->u.action.category)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004727 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
4728 HOSTAPD_LEVEL_DEBUG,
4729 "Dropped unprotected Robust Action frame from "
4730 "an MFP STA");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004731 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004732 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004733
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004734 if (sta) {
4735 u16 fc = le_to_host16(mgmt->frame_control);
4736 u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
4737
4738 if ((fc & WLAN_FC_RETRY) &&
4739 sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
4740 sta->last_seq_ctrl == seq_ctrl &&
4741 sta->last_subtype == WLAN_FC_STYPE_ACTION) {
4742 hostapd_logger(hapd, sta->addr,
4743 HOSTAPD_MODULE_IEEE80211,
4744 HOSTAPD_LEVEL_DEBUG,
4745 "Drop repeated action frame seq_ctrl=0x%x",
4746 seq_ctrl);
4747 return 1;
4748 }
4749
4750 sta->last_seq_ctrl = seq_ctrl;
4751 sta->last_subtype = WLAN_FC_STYPE_ACTION;
4752 }
4753
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004754 switch (mgmt->u.action.category) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004755#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004756 case WLAN_ACTION_FT:
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004757 if (!sta ||
4758 wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004759 len - IEEE80211_HDRLEN))
4760 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004761 return 1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004762#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004763 case WLAN_ACTION_WMM:
4764 hostapd_wmm_action(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004765 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004766 case WLAN_ACTION_SA_QUERY:
Hai Shalom021b0b52019-04-10 11:17:58 -07004767 ieee802_11_sa_query_action(hapd, mgmt, len);
4768 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004769#ifdef CONFIG_WNM_AP
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004770 case WLAN_ACTION_WNM:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004771 ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
4772 return 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004773#endif /* CONFIG_WNM_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004774#ifdef CONFIG_FST
4775 case WLAN_ACTION_FST:
4776 if (hapd->iface->fst)
4777 fst_rx_action(hapd->iface->fst, mgmt, len);
4778 else
4779 wpa_printf(MSG_DEBUG,
4780 "FST: Ignore FST Action frame - no FST attached");
4781 return 1;
4782#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004783 case WLAN_ACTION_PUBLIC:
Dmitry Shmidt18463232014-01-24 12:29:41 -08004784 case WLAN_ACTION_PROTECTED_DUAL:
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07004785 if (len >= IEEE80211_HDRLEN + 2 &&
4786 mgmt->u.action.u.public_action.action ==
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004787 WLAN_PA_20_40_BSS_COEX) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004788 hostapd_2040_coex_action(hapd, mgmt, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004789 return 1;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004790 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004791#ifdef CONFIG_DPP
4792 if (len >= IEEE80211_HDRLEN + 6 &&
4793 mgmt->u.action.u.vs_public_action.action ==
4794 WLAN_PA_VENDOR_SPECIFIC &&
4795 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
4796 OUI_WFA &&
4797 mgmt->u.action.u.vs_public_action.variable[0] ==
4798 DPP_OUI_TYPE) {
4799 const u8 *pos, *end;
4800
4801 pos = mgmt->u.action.u.vs_public_action.oui;
4802 end = ((const u8 *) mgmt) + len;
4803 hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
Roshan Pius3a1667e2018-07-03 15:17:14 -07004804 freq);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004805 return 1;
4806 }
4807 if (len >= IEEE80211_HDRLEN + 2 &&
4808 (mgmt->u.action.u.public_action.action ==
4809 WLAN_PA_GAS_INITIAL_RESP ||
4810 mgmt->u.action.u.public_action.action ==
4811 WLAN_PA_GAS_COMEBACK_RESP)) {
4812 const u8 *pos, *end;
4813
4814 pos = &mgmt->u.action.u.public_action.action;
4815 end = ((const u8 *) mgmt) + len;
4816 gas_query_ap_rx(hapd->gas, mgmt->sa,
4817 mgmt->u.action.category,
4818 pos, end - pos, hapd->iface->freq);
4819 return 1;
4820 }
4821#endif /* CONFIG_DPP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004822 if (hapd->public_action_cb) {
4823 hapd->public_action_cb(hapd->public_action_cb_ctx,
4824 (u8 *) mgmt, len,
4825 hapd->iface->freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004826 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004827 if (hapd->public_action_cb2) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -08004828 hapd->public_action_cb2(hapd->public_action_cb2_ctx,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004829 (u8 *) mgmt, len,
4830 hapd->iface->freq);
4831 }
4832 if (hapd->public_action_cb || hapd->public_action_cb2)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004833 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004834 break;
4835 case WLAN_ACTION_VENDOR_SPECIFIC:
4836 if (hapd->vendor_action_cb) {
4837 if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
4838 (u8 *) mgmt, len,
4839 hapd->iface->freq) == 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004840 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004841 }
4842 break;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004843 case WLAN_ACTION_RADIO_MEASUREMENT:
4844 hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
4845 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004846 }
4847
4848 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
4849 HOSTAPD_LEVEL_DEBUG,
4850 "handle_action - unknown action category %d or invalid "
4851 "frame",
4852 mgmt->u.action.category);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004853 if (!is_multicast_ether_addr(mgmt->da) &&
4854 !(mgmt->u.action.category & 0x80) &&
4855 !is_multicast_ether_addr(mgmt->sa)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004856 struct ieee80211_mgmt *resp;
4857
4858 /*
4859 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
4860 * Return the Action frame to the source without change
4861 * except that MSB of the Category set to 1.
4862 */
4863 wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
4864 "frame back to sender");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004865 resp = os_memdup(mgmt, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004866 if (resp == NULL)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004867 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004868 os_memcpy(resp->da, resp->sa, ETH_ALEN);
4869 os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
4870 os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
4871 resp->u.action.category |= 0x80;
4872
Hai Shalomfdcde762020-04-02 11:19:20 -07004873 if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004874 wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
4875 "Action frame");
4876 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004877 os_free(resp);
4878 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004879
4880 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004881}
4882
4883
4884/**
4885 * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
4886 * @hapd: hostapd BSS data structure (the BSS to which the management frame was
4887 * sent to)
4888 * @buf: management frame data (starting from IEEE 802.11 header)
4889 * @len: length of frame data in octets
4890 * @fi: meta data about received frame (signal level, etc.)
4891 *
4892 * Process all incoming IEEE 802.11 management frames. This will be called for
4893 * each frame received from the kernel driver through wlan#ap interface. In
4894 * addition, it can be called to re-inserted pending frames (e.g., when using
4895 * external RADIUS server as an MAC ACL).
4896 */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004897int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
4898 struct hostapd_frame_info *fi)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004899{
4900 struct ieee80211_mgmt *mgmt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004901 u16 fc, stype;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004902 int ret = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004903 unsigned int freq;
4904 int ssi_signal = fi ? fi->ssi_signal : 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004905
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004906 if (len < 24)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004907 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004908
Roshan Pius3a1667e2018-07-03 15:17:14 -07004909 if (fi && fi->freq)
4910 freq = fi->freq;
4911 else
4912 freq = hapd->iface->freq;
4913
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004914 mgmt = (struct ieee80211_mgmt *) buf;
4915 fc = le_to_host16(mgmt->frame_control);
4916 stype = WLAN_FC_GET_STYPE(fc);
4917
Hai Shalomc3565922019-10-28 11:58:20 -07004918 if (is_multicast_ether_addr(mgmt->sa) ||
4919 is_zero_ether_addr(mgmt->sa) ||
4920 os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
4921 /* Do not process any frames with unexpected/invalid SA so that
4922 * we do not add any state for unexpected STA addresses or end
4923 * up sending out frames to unexpected destination. */
4924 wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
4925 " in received frame - ignore this frame silently",
4926 MAC2STR(mgmt->sa));
4927 return 0;
4928 }
4929
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004930 if (stype == WLAN_FC_STYPE_BEACON) {
4931 handle_beacon(hapd, mgmt, len, fi);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004932 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004933 }
4934
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07004935 if (!is_broadcast_ether_addr(mgmt->bssid) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004936#ifdef CONFIG_P2P
4937 /* Invitation responses can be sent with the peer MAC as BSSID */
4938 !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
4939 stype == WLAN_FC_STYPE_ACTION) &&
4940#endif /* CONFIG_P2P */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004941#ifdef CONFIG_MESH
4942 !(hapd->conf->mesh & MESH_ENABLED) &&
4943#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004944 os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004945 wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
4946 MAC2STR(mgmt->bssid));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004947 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004948 }
4949
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004950 if (hapd->iface->state != HAPD_IFACE_ENABLED) {
4951 wpa_printf(MSG_DEBUG, "MGMT: Ignore management frame while interface is not enabled (SA=" MACSTR " DA=" MACSTR " subtype=%u)",
4952 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), stype);
4953 return 1;
4954 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004955
4956 if (stype == WLAN_FC_STYPE_PROBE_REQ) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004957 handle_probe_req(hapd, mgmt, len, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004958 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004959 }
4960
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004961 if ((!is_broadcast_ether_addr(mgmt->da) ||
4962 stype != WLAN_FC_STYPE_ACTION) &&
4963 os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004964 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
4965 HOSTAPD_LEVEL_DEBUG,
4966 "MGMT: DA=" MACSTR " not our address",
4967 MAC2STR(mgmt->da));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004968 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004969 }
4970
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004971 if (hapd->iconf->track_sta_max_num)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004972 sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004973
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004974 switch (stype) {
4975 case WLAN_FC_STYPE_AUTH:
4976 wpa_printf(MSG_DEBUG, "mgmt::auth");
Hai Shalom021b0b52019-04-10 11:17:58 -07004977 handle_auth(hapd, mgmt, len, ssi_signal, 0);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004978 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004979 break;
4980 case WLAN_FC_STYPE_ASSOC_REQ:
4981 wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08004982 handle_assoc(hapd, mgmt, len, 0, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004983 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004984 break;
4985 case WLAN_FC_STYPE_REASSOC_REQ:
4986 wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
Hai Shalom74f70d42019-02-11 14:42:39 -08004987 handle_assoc(hapd, mgmt, len, 1, ssi_signal);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004988 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004989 break;
4990 case WLAN_FC_STYPE_DISASSOC:
4991 wpa_printf(MSG_DEBUG, "mgmt::disassoc");
4992 handle_disassoc(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004993 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004994 break;
4995 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004996 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004997 handle_deauth(hapd, mgmt, len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004998 ret = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004999 break;
5000 case WLAN_FC_STYPE_ACTION:
5001 wpa_printf(MSG_DEBUG, "mgmt::action");
Roshan Pius3a1667e2018-07-03 15:17:14 -07005002 ret = handle_action(hapd, mgmt, len, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005003 break;
5004 default:
5005 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
5006 HOSTAPD_LEVEL_DEBUG,
5007 "unknown mgmt frame subtype %d", stype);
5008 break;
5009 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005010
5011 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005012}
5013
5014
5015static void handle_auth_cb(struct hostapd_data *hapd,
5016 const struct ieee80211_mgmt *mgmt,
5017 size_t len, int ok)
5018{
5019 u16 auth_alg, auth_transaction, status_code;
5020 struct sta_info *sta;
5021
Hai Shalome5e28bb2019-01-28 14:51:04 -08005022 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
5023 wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
5024 (unsigned long) len);
5025
5026 /*
5027 * Initialize status_code here because we are not able to read
5028 * it from the short payload.
5029 */
5030 status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
5031 goto fail;
5032 }
5033
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005034 sta = ap_get_sta(hapd, mgmt->da);
5035 if (!sta) {
Hai Shalom39ba6fc2019-01-22 12:40:38 -08005036 wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
5037 " not found",
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005038 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005039 return;
5040 }
5041
5042 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
5043 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
5044 status_code = le_to_host16(mgmt->u.auth.status_code);
5045
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005046 if (!ok) {
5047 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
5048 HOSTAPD_LEVEL_NOTICE,
5049 "did not acknowledge authentication response");
5050 goto fail;
5051 }
5052
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005053 if (status_code == WLAN_STATUS_SUCCESS &&
5054 ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
5055 (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
5056 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5057 HOSTAPD_LEVEL_INFO, "authenticated");
5058 sta->flags |= WLAN_STA_AUTH;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005059 if (sta->added_unassoc)
5060 hostapd_set_sta_flags(hapd, sta);
5061 return;
5062 }
5063
5064fail:
5065 if (status_code != WLAN_STATUS_SUCCESS && sta->added_unassoc) {
5066 hostapd_drv_sta_remove(hapd, sta->addr);
5067 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005068 }
5069}
5070
5071
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005072static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
5073 struct sta_info *sta,
5074 char *ifname_wds)
5075{
Hai Shalomfdcde762020-04-02 11:19:20 -07005076#ifdef CONFIG_WEP
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005077 int i;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07005078 struct hostapd_ssid *ssid = &hapd->conf->ssid;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005079
5080 if (hapd->conf->ieee802_1x || hapd->conf->wpa)
5081 return;
5082
5083 for (i = 0; i < 4; i++) {
5084 if (ssid->wep.key[i] &&
5085 hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
Hai Shalomfdcde762020-04-02 11:19:20 -07005086 0, i == ssid->wep.idx, NULL, 0,
5087 ssid->wep.key[i], ssid->wep.len[i],
5088 i == ssid->wep.idx ?
5089 KEY_FLAG_GROUP_RX_TX_DEFAULT :
5090 KEY_FLAG_GROUP_RX_TX)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005091 wpa_printf(MSG_WARNING,
5092 "Could not set WEP keys for WDS interface; %s",
5093 ifname_wds);
5094 break;
5095 }
5096 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005097#endif /* CONFIG_WEP */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005098}
5099
5100
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005101static void handle_assoc_cb(struct hostapd_data *hapd,
5102 const struct ieee80211_mgmt *mgmt,
5103 size_t len, int reassoc, int ok)
5104{
5105 u16 status;
5106 struct sta_info *sta;
5107 int new_assoc = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005108
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005109 sta = ap_get_sta(hapd, mgmt->da);
5110 if (!sta) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005111 wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
5112 MAC2STR(mgmt->da));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005113 return;
5114 }
5115
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005116 if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
5117 sizeof(mgmt->u.assoc_resp))) {
5118 wpa_printf(MSG_INFO,
5119 "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
5120 reassoc, (unsigned long) len);
5121 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07005122 return;
5123 }
5124
5125 if (reassoc)
5126 status = le_to_host16(mgmt->u.reassoc_resp.status_code);
5127 else
5128 status = le_to_host16(mgmt->u.assoc_resp.status_code);
5129
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005130 if (!ok) {
5131 hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
5132 HOSTAPD_LEVEL_DEBUG,
5133 "did not acknowledge association response");
5134 sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
5135 /* The STA is added only in case of SUCCESS */
5136 if (status == WLAN_STATUS_SUCCESS)
5137 hostapd_drv_sta_remove(hapd, sta->addr);
5138
5139 return;
5140 }
5141
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005142 if (status != WLAN_STATUS_SUCCESS)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005143 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005144
5145 /* Stop previous accounting session, if one is started, and allocate
5146 * new session id for the new session. */
5147 accounting_sta_stop(hapd, sta);
5148
5149 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
5150 HOSTAPD_LEVEL_INFO,
5151 "associated (aid %d)",
5152 sta->aid);
5153
5154 if (sta->flags & WLAN_STA_ASSOC)
5155 new_assoc = 0;
5156 sta->flags |= WLAN_STA_ASSOC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005157 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005158 if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
5159 !hapd->conf->osen) ||
5160 sta->auth_alg == WLAN_AUTH_FILS_SK ||
5161 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5162 sta->auth_alg == WLAN_AUTH_FILS_PK ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005163 sta->auth_alg == WLAN_AUTH_FT) {
5164 /*
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005165 * Open, static WEP, FT protocol, or FILS; no separate
5166 * authorization step.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005167 */
5168 ap_sta_set_authorized(hapd, sta, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005169 }
5170
5171 if (reassoc)
5172 mlme_reassociate_indication(hapd, sta);
5173 else
5174 mlme_associate_indication(hapd, sta);
5175
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005176 sta->sa_query_timed_out = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005177
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005178 if (sta->eapol_sm == NULL) {
5179 /*
5180 * This STA does not use RADIUS server for EAP authentication,
5181 * so bind it to the selected VLAN interface now, since the
5182 * interface selection is not going to change anymore.
5183 */
Dmitry Shmidt83474442015-04-15 13:47:09 -07005184 if (ap_sta_bind_vlan(hapd, sta) < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005185 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005186 } else if (sta->vlan_id) {
5187 /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
Dmitry Shmidt83474442015-04-15 13:47:09 -07005188 if (ap_sta_bind_vlan(hapd, sta) < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005189 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005190 }
5191
5192 hostapd_set_sta_flags(hapd, sta);
5193
Dmitry Shmidt29333592017-01-09 12:27:11 -08005194 if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) {
5195 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA "
5196 MACSTR " based on pending request",
5197 MAC2STR(sta->addr));
5198 sta->pending_wds_enable = 0;
5199 sta->flags |= WLAN_STA_WDS;
5200 }
5201
Hai Shalom74f70d42019-02-11 14:42:39 -08005202 if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) {
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08005203 int ret;
5204 char ifname_wds[IFNAMSIZ + 1];
5205
5206 wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA "
5207 MACSTR " (aid %u)",
5208 MAC2STR(sta->addr), sta->aid);
5209 ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
5210 sta->aid, 1);
5211 if (!ret)
5212 hostapd_set_wds_encryption(hapd, sta, ifname_wds);
5213 }
5214
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005215 if (sta->auth_alg == WLAN_AUTH_FT)
5216 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
5217 else
5218 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
5219 hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005220 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005221
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005222#ifdef CONFIG_FILS
5223 if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
5224 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
5225 sta->auth_alg == WLAN_AUTH_FILS_PK) &&
5226 fils_set_tk(sta->wpa_sm) < 0) {
5227 wpa_printf(MSG_DEBUG, "FILS: TK configuration failed");
5228 ap_sta_disconnect(hapd, sta, sta->addr,
5229 WLAN_REASON_UNSPECIFIED);
5230 return;
5231 }
5232#endif /* CONFIG_FILS */
5233
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005234 if (sta->pending_eapol_rx) {
5235 struct os_reltime now, age;
5236
5237 os_get_reltime(&now);
5238 os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
5239 if (age.sec == 0 && age.usec < 200000) {
5240 wpa_printf(MSG_DEBUG,
5241 "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
5242 MAC2STR(sta->addr));
5243 ieee802_1x_receive(
5244 hapd, mgmt->da,
5245 wpabuf_head(sta->pending_eapol_rx->buf),
5246 wpabuf_len(sta->pending_eapol_rx->buf));
5247 }
5248 wpabuf_free(sta->pending_eapol_rx->buf);
5249 os_free(sta->pending_eapol_rx);
5250 sta->pending_eapol_rx = NULL;
5251 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005252}
5253
5254
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005255static void handle_deauth_cb(struct hostapd_data *hapd,
5256 const struct ieee80211_mgmt *mgmt,
5257 size_t len, int ok)
5258{
5259 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07005260 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005261 return;
5262 sta = ap_get_sta(hapd, mgmt->da);
5263 if (!sta) {
5264 wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
5265 " not found", MAC2STR(mgmt->da));
5266 return;
5267 }
5268 if (ok)
5269 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
5270 MAC2STR(sta->addr));
5271 else
5272 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
5273 "deauth", MAC2STR(sta->addr));
5274
5275 ap_sta_deauth_cb(hapd, sta);
5276}
5277
5278
5279static void handle_disassoc_cb(struct hostapd_data *hapd,
5280 const struct ieee80211_mgmt *mgmt,
5281 size_t len, int ok)
5282{
5283 struct sta_info *sta;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07005284 if (is_multicast_ether_addr(mgmt->da))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005285 return;
5286 sta = ap_get_sta(hapd, mgmt->da);
5287 if (!sta) {
5288 wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
5289 " not found", MAC2STR(mgmt->da));
5290 return;
5291 }
5292 if (ok)
5293 wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
5294 MAC2STR(sta->addr));
5295 else
5296 wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
5297 "disassoc", MAC2STR(sta->addr));
5298
5299 ap_sta_disassoc_cb(hapd, sta);
5300}
5301
5302
Dmitry Shmidt29333592017-01-09 12:27:11 -08005303static void handle_action_cb(struct hostapd_data *hapd,
5304 const struct ieee80211_mgmt *mgmt,
5305 size_t len, int ok)
5306{
5307 struct sta_info *sta;
Paul Stewart092955c2017-02-06 09:13:09 -08005308 const struct rrm_measurement_report_element *report;
Dmitry Shmidt29333592017-01-09 12:27:11 -08005309
5310 if (is_multicast_ether_addr(mgmt->da))
5311 return;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005312#ifdef CONFIG_DPP
5313 if (len >= IEEE80211_HDRLEN + 6 &&
5314 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
5315 mgmt->u.action.u.vs_public_action.action ==
5316 WLAN_PA_VENDOR_SPECIFIC &&
5317 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
5318 OUI_WFA &&
5319 mgmt->u.action.u.vs_public_action.variable[0] ==
5320 DPP_OUI_TYPE) {
5321 const u8 *pos, *end;
5322
5323 pos = &mgmt->u.action.u.vs_public_action.variable[1];
5324 end = ((const u8 *) mgmt) + len;
5325 hostapd_dpp_tx_status(hapd, mgmt->da, pos, end - pos, ok);
5326 return;
5327 }
5328 if (len >= IEEE80211_HDRLEN + 2 &&
5329 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
5330 (mgmt->u.action.u.public_action.action ==
5331 WLAN_PA_GAS_INITIAL_REQ ||
5332 mgmt->u.action.u.public_action.action ==
5333 WLAN_PA_GAS_COMEBACK_REQ)) {
5334 const u8 *pos, *end;
5335
5336 pos = mgmt->u.action.u.public_action.variable;
5337 end = ((const u8 *) mgmt) + len;
5338 gas_query_ap_tx_status(hapd->gas, mgmt->da, pos, end - pos, ok);
5339 return;
5340 }
5341#endif /* CONFIG_DPP */
Dmitry Shmidt29333592017-01-09 12:27:11 -08005342 sta = ap_get_sta(hapd, mgmt->da);
5343 if (!sta) {
5344 wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR
5345 " not found", MAC2STR(mgmt->da));
5346 return;
5347 }
5348
Paul Stewart092955c2017-02-06 09:13:09 -08005349 if (len < 24 + 5 + sizeof(*report))
Dmitry Shmidt29333592017-01-09 12:27:11 -08005350 return;
Paul Stewart092955c2017-02-06 09:13:09 -08005351 report = (const struct rrm_measurement_report_element *)
5352 &mgmt->u.action.u.rrm.variable[2];
Dmitry Shmidt29333592017-01-09 12:27:11 -08005353 if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT &&
Paul Stewart092955c2017-02-06 09:13:09 -08005354 mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST &&
5355 report->eid == WLAN_EID_MEASURE_REQUEST &&
5356 report->len >= 3 &&
5357 report->type == MEASURE_TYPE_BEACON)
Dmitry Shmidt29333592017-01-09 12:27:11 -08005358 hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok);
5359}
5360
5361
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005362/**
5363 * ieee802_11_mgmt_cb - Process management frame TX status callback
5364 * @hapd: hostapd BSS data structure (the BSS from which the management frame
5365 * was sent from)
5366 * @buf: management frame data (starting from IEEE 802.11 header)
5367 * @len: length of frame data in octets
5368 * @stype: management frame subtype from frame control field
5369 * @ok: Whether the frame was ACK'ed
5370 */
5371void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
5372 u16 stype, int ok)
5373{
5374 const struct ieee80211_mgmt *mgmt;
5375 mgmt = (const struct ieee80211_mgmt *) buf;
5376
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005377#ifdef CONFIG_TESTING_OPTIONS
5378 if (hapd->ext_mgmt_frame_handling) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005379 size_t hex_len = 2 * len + 1;
5380 char *hex = os_malloc(hex_len);
5381
5382 if (hex) {
5383 wpa_snprintf_hex(hex, hex_len, buf, len);
5384 wpa_msg(hapd->msg_ctx, MSG_INFO,
5385 "MGMT-TX-STATUS stype=%u ok=%d buf=%s",
5386 stype, ok, hex);
5387 os_free(hex);
5388 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005389 return;
5390 }
5391#endif /* CONFIG_TESTING_OPTIONS */
5392
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005393 switch (stype) {
5394 case WLAN_FC_STYPE_AUTH:
5395 wpa_printf(MSG_DEBUG, "mgmt::auth cb");
5396 handle_auth_cb(hapd, mgmt, len, ok);
5397 break;
5398 case WLAN_FC_STYPE_ASSOC_RESP:
5399 wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
5400 handle_assoc_cb(hapd, mgmt, len, 0, ok);
5401 break;
5402 case WLAN_FC_STYPE_REASSOC_RESP:
5403 wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
5404 handle_assoc_cb(hapd, mgmt, len, 1, ok);
5405 break;
5406 case WLAN_FC_STYPE_PROBE_RESP:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005407 wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005408 break;
5409 case WLAN_FC_STYPE_DEAUTH:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005410 wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
5411 handle_deauth_cb(hapd, mgmt, len, ok);
5412 break;
5413 case WLAN_FC_STYPE_DISASSOC:
5414 wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
5415 handle_disassoc_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005416 break;
5417 case WLAN_FC_STYPE_ACTION:
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005418 wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
Dmitry Shmidt29333592017-01-09 12:27:11 -08005419 handle_action_cb(hapd, mgmt, len, ok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005420 break;
5421 default:
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005422 wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005423 break;
5424 }
5425}
5426
5427
5428int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
5429{
5430 /* TODO */
5431 return 0;
5432}
5433
5434
5435int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
5436 char *buf, size_t buflen)
5437{
5438 /* TODO */
5439 return 0;
5440}
5441
5442
5443void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
5444 const u8 *buf, size_t len, int ack)
5445{
5446 struct sta_info *sta;
5447 struct hostapd_iface *iface = hapd->iface;
5448
5449 sta = ap_get_sta(hapd, addr);
5450 if (sta == NULL && iface->num_bss > 1) {
5451 size_t j;
5452 for (j = 0; j < iface->num_bss; j++) {
5453 hapd = iface->bss[j];
5454 sta = ap_get_sta(hapd, addr);
5455 if (sta)
5456 break;
5457 }
5458 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005459 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005460 return;
5461 if (sta->flags & WLAN_STA_PENDING_POLL) {
5462 wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
5463 "activity poll", MAC2STR(sta->addr),
5464 ack ? "ACKed" : "did not ACK");
5465 if (ack)
5466 sta->flags &= ~WLAN_STA_PENDING_POLL;
5467 }
5468
5469 ieee802_1x_tx_status(hapd, sta, buf, len, ack);
5470}
5471
5472
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005473void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
5474 const u8 *data, size_t len, int ack)
5475{
5476 struct sta_info *sta;
5477 struct hostapd_iface *iface = hapd->iface;
5478
5479 sta = ap_get_sta(hapd, dst);
5480 if (sta == NULL && iface->num_bss > 1) {
5481 size_t j;
5482 for (j = 0; j < iface->num_bss; j++) {
5483 hapd = iface->bss[j];
5484 sta = ap_get_sta(hapd, dst);
5485 if (sta)
5486 break;
5487 }
5488 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005489 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
5490 wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA "
5491 MACSTR " that is not currently associated",
5492 MAC2STR(dst));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005493 return;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005494 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005495
5496 ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
5497}
5498
5499
5500void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
5501{
5502 struct sta_info *sta;
5503 struct hostapd_iface *iface = hapd->iface;
5504
5505 sta = ap_get_sta(hapd, addr);
5506 if (sta == NULL && iface->num_bss > 1) {
5507 size_t j;
5508 for (j = 0; j < iface->num_bss; j++) {
5509 hapd = iface->bss[j];
5510 sta = ap_get_sta(hapd, addr);
5511 if (sta)
5512 break;
5513 }
5514 }
5515 if (sta == NULL)
5516 return;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005517 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
5518 MAC2STR(sta->addr));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005519 if (!(sta->flags & WLAN_STA_PENDING_POLL))
5520 return;
5521
5522 wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
5523 "activity poll", MAC2STR(sta->addr));
5524 sta->flags &= ~WLAN_STA_PENDING_POLL;
5525}
5526
5527
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005528void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
5529 int wds)
5530{
5531 struct sta_info *sta;
5532
5533 sta = ap_get_sta(hapd, src);
Dmitry Shmidt29333592017-01-09 12:27:11 -08005534 if (sta &&
5535 ((sta->flags & WLAN_STA_ASSOC) ||
5536 ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07005537 if (!hapd->conf->wds_sta)
5538 return;
5539
Dmitry Shmidt29333592017-01-09 12:27:11 -08005540 if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) ==
5541 WLAN_STA_ASSOC_REQ_OK) {
5542 wpa_printf(MSG_DEBUG,
5543 "Postpone 4-address WDS mode enabling for STA "
5544 MACSTR " since TX status for AssocResp is not yet known",
5545 MAC2STR(sta->addr));
5546 sta->pending_wds_enable = 1;
5547 return;
5548 }
5549
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005550 if (wds && !(sta->flags & WLAN_STA_WDS)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005551 int ret;
5552 char ifname_wds[IFNAMSIZ + 1];
5553
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005554 wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
5555 "STA " MACSTR " (aid %u)",
5556 MAC2STR(sta->addr), sta->aid);
5557 sta->flags |= WLAN_STA_WDS;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07005558 ret = hostapd_set_wds_sta(hapd, ifname_wds,
5559 sta->addr, sta->aid, 1);
5560 if (!ret)
5561 hostapd_set_wds_encryption(hapd, sta,
5562 ifname_wds);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005563 }
5564 return;
5565 }
5566
5567 wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
5568 MACSTR, MAC2STR(src));
Hai Shalomc3565922019-10-28 11:58:20 -07005569 if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
5570 os_memcmp(src, hapd->own_addr, ETH_ALEN) == 0) {
5571 /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
5572 * silently. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005573 return;
5574 }
5575
5576 if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) {
5577 wpa_printf(MSG_DEBUG, "Association Response to the STA has "
5578 "already been sent, but no TX status yet known - "
5579 "ignore Class 3 frame issue with " MACSTR,
5580 MAC2STR(src));
5581 return;
5582 }
5583
5584 if (sta && (sta->flags & WLAN_STA_AUTH))
5585 hostapd_drv_sta_disassoc(
5586 hapd, src,
5587 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
5588 else
5589 hostapd_drv_sta_deauth(
5590 hapd, src,
5591 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
5592}
5593
5594
Hai Shalom899fcc72020-10-19 14:38:18 -07005595u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
5596{
5597 u8 bw, chan1, chan2 = 0;
5598 int freq1;
5599
5600 if (!hapd->cs_freq_params.channel ||
5601 (!hapd->cs_freq_params.vht_enabled &&
5602 !hapd->cs_freq_params.he_enabled))
5603 return eid;
5604
5605 /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
5606 switch (hapd->cs_freq_params.bandwidth) {
5607 case 40:
5608 bw = 0;
5609 break;
5610 case 80:
5611 /* check if it's 80+80 */
5612 if (!hapd->cs_freq_params.center_freq2)
5613 bw = 1;
5614 else
5615 bw = 3;
5616 break;
5617 case 160:
5618 bw = 2;
5619 break;
5620 default:
5621 /* not valid VHT bandwidth or not in CSA */
5622 return eid;
5623 }
5624
5625 freq1 = hapd->cs_freq_params.center_freq1 ?
5626 hapd->cs_freq_params.center_freq1 :
5627 hapd->cs_freq_params.freq;
5628 if (ieee80211_freq_to_chan(freq1, &chan1) !=
5629 HOSTAPD_MODE_IEEE80211A)
5630 return eid;
5631
5632 if (hapd->cs_freq_params.center_freq2 &&
5633 ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
5634 &chan2) != HOSTAPD_MODE_IEEE80211A)
5635 return eid;
5636
5637 *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
5638 *eid++ = 5; /* Length of Channel Switch Wrapper */
5639 *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
5640 *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
5641 *eid++ = bw; /* New Channel Width */
5642 *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
5643 *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
5644
5645 return eid;
5646}
5647
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005648#endif /* CONFIG_NATIVE_WINDOWS */