blob: b0fcd1c21a8c328b85c55248987e771d78d3919c [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / Callback functions for driver wrappers
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003 * Copyright (c) 2002-2013, 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#include "utils/common.h"
Dmitry Shmidt7832adb2014-04-29 10:53:02 -070012#include "utils/eloop.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013#include "radius/radius.h"
14#include "drivers/driver.h"
15#include "common/ieee802_11_defs.h"
16#include "common/ieee802_11_common.h"
Dmitry Shmidtf8623282013-02-20 14:34:59 -080017#include "common/wpa_ctrl.h"
Hai Shalom021b0b52019-04-10 11:17:58 -070018#include "common/dpp.h"
Hai Shalomc3565922019-10-28 11:58:20 -070019#include "common/sae.h"
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080020#include "common/hw_features_common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021#include "crypto/random.h"
22#include "p2p/p2p.h"
23#include "wps/wps.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080024#include "fst/fst.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070025#include "wnm_ap.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070026#include "hostapd.h"
27#include "ieee802_11.h"
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080028#include "ieee802_11_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070029#include "sta_info.h"
30#include "accounting.h"
31#include "tkip_countermeasures.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070032#include "ieee802_1x.h"
33#include "wpa_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070034#include "wps_hostapd.h"
35#include "ap_drv_ops.h"
36#include "ap_config.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070037#include "ap_mlme.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070038#include "hw_features.h"
Dmitry Shmidt051af732013-10-22 13:52:46 -070039#include "dfs.h"
Dmitry Shmidt7832adb2014-04-29 10:53:02 -070040#include "beacon.h"
Dmitry Shmidt57c2d392016-02-23 13:40:19 -080041#include "mbo_ap.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070042#include "dpp_hostapd.h"
43#include "fils_hlp.h"
Hai Shalom74f70d42019-02-11 14:42:39 -080044#include "neighbor_db.h"
Sunil Ravib0ac25f2024-07-12 01:42:03 +000045#include "nan_usd_ap.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070046
47
48#ifdef CONFIG_FILS
49void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
50 struct sta_info *sta)
51{
52 u16 reply_res = WLAN_STATUS_SUCCESS;
53 struct ieee802_11_elems elems;
54 u8 buf[IEEE80211_MAX_MMPDU_SIZE], *p = buf;
55 int new_assoc;
Sunil Ravib0ac25f2024-07-12 01:42:03 +000056 bool updated;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070057
58 wpa_printf(MSG_DEBUG, "%s FILS: Finish association with " MACSTR,
59 __func__, MAC2STR(sta->addr));
60 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
61 if (!sta->fils_pending_assoc_req)
62 return;
63
Sunil Ravi2a14cf12023-11-21 00:54:38 +000064 if (ieee802_11_parse_elems(sta->fils_pending_assoc_req,
65 sta->fils_pending_assoc_req_len, &elems,
66 0) == ParseFailed ||
67 !elems.fils_session) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070068 wpa_printf(MSG_DEBUG, "%s failed to find FILS Session element",
69 __func__);
70 return;
71 }
72
73 p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
74 elems.fils_session,
75 sta->fils_hlp_resp);
76
77 reply_res = hostapd_sta_assoc(hapd, sta->addr,
78 sta->fils_pending_assoc_is_reassoc,
79 WLAN_STATUS_SUCCESS,
80 buf, p - buf);
Sunil Ravib0ac25f2024-07-12 01:42:03 +000081 updated = ap_sta_set_authorized_flag(hapd, sta, 1);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070082 new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
83 sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
84 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
85 hostapd_set_sta_flags(hapd, sta);
Sunil Ravib0ac25f2024-07-12 01:42:03 +000086 if (updated)
87 ap_sta_set_authorized_event(hapd, sta, 1);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070088 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
89 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
90 hostapd_new_assoc_sta(hapd, sta, !new_assoc);
91 os_free(sta->fils_pending_assoc_req);
92 sta->fils_pending_assoc_req = NULL;
93 sta->fils_pending_assoc_req_len = 0;
94 wpabuf_free(sta->fils_hlp_resp);
95 sta->fils_hlp_resp = NULL;
96 wpabuf_free(sta->hlp_dhcp_discover);
97 sta->hlp_dhcp_discover = NULL;
98 fils_hlp_deinit(hapd);
99
100 /*
101 * Remove the station in case transmission of a success response fails
102 * (the STA was added associated to the driver) or if the station was
103 * previously added unassociated.
104 */
105 if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) {
106 hostapd_drv_sta_remove(hapd, sta->addr);
107 sta->added_unassoc = 0;
108 }
109}
110#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700111
112
Hai Shalom899fcc72020-10-19 14:38:18 -0700113static bool check_sa_query_need(struct hostapd_data *hapd, struct sta_info *sta)
114{
115 if ((sta->flags &
116 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
117 (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
118 return false;
119
120 if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
121 ap_check_sa_query_timeout(hapd, sta);
122
123 if (!sta->sa_query_timed_out && (sta->auth_alg != WLAN_AUTH_FT)) {
124 /*
125 * STA has already been associated with MFP and SA Query timeout
126 * has not been reached. Reject the association attempt
127 * temporarily and start SA Query, if one is not pending.
128 */
129 if (sta->sa_query_count == 0)
130 ap_sta_start_sa_query(hapd, sta);
131
132 return true;
133 }
134
135 return false;
136}
137
138
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000139#ifdef CONFIG_IEEE80211BE
140static int hostapd_update_sta_links_status(struct hostapd_data *hapd,
141 struct sta_info *sta,
142 const u8 *resp_ies,
143 size_t resp_ies_len)
144{
145 struct mld_info *info = &sta->mld_info;
146 struct wpabuf *mlebuf;
147 const u8 *mle, *pos;
148 struct ieee802_11_elems elems;
149 size_t mle_len, rem_len;
150 int ret = 0;
151
152 if (!resp_ies) {
153 wpa_printf(MSG_DEBUG,
154 "MLO: (Re)Association Response frame elements not available");
155 return -1;
156 }
157
158 if (ieee802_11_parse_elems(resp_ies, resp_ies_len, &elems, 0) ==
159 ParseFailed) {
160 wpa_printf(MSG_DEBUG,
161 "MLO: Failed to parse (Re)Association Response frame elements");
162 return -1;
163 }
164
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000165 mlebuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000166 if (!mlebuf) {
167 wpa_printf(MSG_ERROR,
168 "MLO: Basic Multi-Link element not found in (Re)Association Response frame");
169 return -1;
170 }
171
172 mle = wpabuf_head(mlebuf);
173 mle_len = wpabuf_len(mlebuf);
174 if (mle_len < MULTI_LINK_CONTROL_LEN + 1 ||
175 mle_len - MULTI_LINK_CONTROL_LEN < mle[MULTI_LINK_CONTROL_LEN]) {
176 wpa_printf(MSG_ERROR,
177 "MLO: Invalid Multi-Link element in (Re)Association Response frame");
178 ret = -1;
179 goto out;
180 }
181
182 /* Skip Common Info */
183 pos = mle + MULTI_LINK_CONTROL_LEN + mle[MULTI_LINK_CONTROL_LEN];
184 rem_len = mle_len -
185 (MULTI_LINK_CONTROL_LEN + mle[MULTI_LINK_CONTROL_LEN]);
186
187 /* Parse Subelements */
188 while (rem_len > 2) {
189 size_t ie_len = 2 + pos[1];
190
191 if (rem_len < ie_len)
192 break;
193
194 if (pos[0] == MULTI_LINK_SUB_ELEM_ID_PER_STA_PROFILE) {
195 u8 link_id;
196 const u8 *sta_profile;
197 size_t sta_profile_len;
198 u16 sta_ctrl;
199
200 if (pos[1] < BASIC_MLE_STA_CTRL_LEN + 1) {
201 wpa_printf(MSG_DEBUG,
202 "MLO: Invalid per-STA profile IE");
203 goto next_subelem;
204 }
205
206 sta_profile_len = pos[1];
207 sta_profile = &pos[2];
208 sta_ctrl = WPA_GET_LE16(sta_profile);
209 link_id = sta_ctrl & BASIC_MLE_STA_CTRL_LINK_ID_MASK;
210 if (link_id >= MAX_NUM_MLD_LINKS) {
211 wpa_printf(MSG_DEBUG,
212 "MLO: Invalid link ID in per-STA profile IE");
213 goto next_subelem;
214 }
215
216 /* Skip STA Control and STA Info */
217 if (sta_profile_len - BASIC_MLE_STA_CTRL_LEN <
218 sta_profile[BASIC_MLE_STA_CTRL_LEN]) {
219 wpa_printf(MSG_DEBUG,
220 "MLO: Invalid STA info in per-STA profile IE");
221 goto next_subelem;
222 }
223
224 sta_profile_len = sta_profile_len -
225 (BASIC_MLE_STA_CTRL_LEN +
226 sta_profile[BASIC_MLE_STA_CTRL_LEN]);
227 sta_profile = sta_profile + BASIC_MLE_STA_CTRL_LEN +
228 sta_profile[BASIC_MLE_STA_CTRL_LEN];
229
230 /* Skip Capabilities Information field */
231 if (sta_profile_len < 2)
232 goto next_subelem;
233 sta_profile_len -= 2;
234 sta_profile += 2;
235
236 /* Get status of the link */
237 info->links[link_id].status = WPA_GET_LE16(sta_profile);
238 }
239next_subelem:
240 pos += ie_len;
241 rem_len -= ie_len;
242 }
243
244out:
245 wpabuf_free(mlebuf);
246 return ret;
247}
248#endif /* CONFIG_IEEE80211BE */
249
250
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700251int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000252 const u8 *req_ies, size_t req_ies_len,
253 const u8 *resp_ies, size_t resp_ies_len,
254 const u8 *link_addr, int reassoc)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700255{
256 struct sta_info *sta;
Hai Shalomfdcde762020-04-02 11:19:20 -0700257 int new_assoc;
258 enum wpa_validate_result res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700259 struct ieee802_11_elems elems;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800260 const u8 *ie;
261 size_t ielen;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700262 u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
263 u8 *p = buf;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800264 u16 reason = WLAN_REASON_UNSPECIFIED;
Hai Shalomb755a2a2020-04-23 21:49:02 -0700265 int status = WLAN_STATUS_SUCCESS;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700266 const u8 *p2p_dev_addr = NULL;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000267#ifdef CONFIG_OWE
268 struct hostapd_iface *iface = hapd->iface;
269#endif /* CONFIG_OWE */
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000270 bool updated = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700271
272 if (addr == NULL) {
273 /*
274 * This could potentially happen with unexpected event from the
275 * driver wrapper. This was seen at least in one case where the
276 * driver ended up being set to station mode while hostapd was
277 * running, so better make sure we stop processing such an
278 * event here.
279 */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800280 wpa_printf(MSG_DEBUG,
281 "hostapd_notif_assoc: Skip event with no address");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700282 return -1;
283 }
Hai Shalomc3565922019-10-28 11:58:20 -0700284
285 if (is_multicast_ether_addr(addr) ||
286 is_zero_ether_addr(addr) ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000287 ether_addr_equal(addr, hapd->own_addr)) {
Hai Shalomc3565922019-10-28 11:58:20 -0700288 /* Do not process any frames with unexpected/invalid SA so that
289 * we do not add any state for unexpected STA addresses or end
290 * up sending out frames to unexpected destination. */
291 wpa_printf(MSG_DEBUG, "%s: Invalid SA=" MACSTR
292 " in received indication - ignore this indication silently",
293 __func__, MAC2STR(addr));
294 return 0;
295 }
296
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700297 random_add_randomness(addr, ETH_ALEN);
298
299 hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
300 HOSTAPD_LEVEL_INFO, "associated");
301
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000302 if (ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0) ==
303 ParseFailed) {
304 wpa_printf(MSG_DEBUG, "%s: Could not parse elements", __func__);
305 return -1;
306 }
307
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700308 if (elems.wps_ie) {
309 ie = elems.wps_ie - 2;
310 ielen = elems.wps_ie_len + 2;
311 wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
312 } else if (elems.rsn_ie) {
313 ie = elems.rsn_ie - 2;
314 ielen = elems.rsn_ie_len + 2;
315 wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
316 } else if (elems.wpa_ie) {
317 ie = elems.wpa_ie - 2;
318 ielen = elems.wpa_ie_len + 2;
319 wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800320#ifdef CONFIG_HS20
321 } else if (elems.osen) {
322 ie = elems.osen - 2;
323 ielen = elems.osen_len + 2;
324 wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq");
325#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700326 } else {
327 ie = NULL;
328 ielen = 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800329 wpa_printf(MSG_DEBUG,
330 "STA did not include WPS/RSN/WPA IE in (Re)AssocReq");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700331 }
332
333 sta = ap_get_sta(hapd, addr);
334 if (sta) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700335 ap_sta_no_session_timeout(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700336 accounting_sta_stop(hapd, sta);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700337
338 /*
339 * Make sure that the previously registered inactivity timer
340 * will not remove the STA immediately.
341 */
342 sta->timeout_next = STA_NULLFUNC;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700343 } else {
344 sta = ap_sta_add(hapd, addr);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700345 if (sta == NULL) {
346 hostapd_drv_sta_disassoc(hapd, addr,
347 WLAN_REASON_DISASSOC_AP_BUSY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700348 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700349 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700350 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000351
352 if (hapd->conf->wpa && check_sa_query_need(hapd, sta)) {
353 status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
354 p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
355 hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
356
357 return 0;
358 }
359
360#ifdef CONFIG_IEEE80211BE
361 if (link_addr) {
362 struct mld_info *info = &sta->mld_info;
363 int i, num_valid_links = 0;
364 u8 link_id = hapd->mld_link_id;
365
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000366 ap_sta_set_mld(sta, true);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000367 sta->mld_assoc_link_id = link_id;
368 os_memcpy(info->common_info.mld_addr, addr, ETH_ALEN);
369 info->links[link_id].valid = true;
370 os_memcpy(info->links[link_id].peer_addr, link_addr, ETH_ALEN);
371 os_memcpy(info->links[link_id].local_addr, hapd->own_addr,
372 ETH_ALEN);
373
374 if (!elems.basic_mle ||
375 hostapd_process_ml_assoc_req(hapd, &elems, sta) !=
376 WLAN_STATUS_SUCCESS) {
377 reason = WLAN_REASON_UNSPECIFIED;
378 wpa_printf(MSG_DEBUG,
379 "Failed to get STA non-assoc links info");
380 goto fail;
381 }
382
383 for (i = 0 ; i < MAX_NUM_MLD_LINKS; i++) {
384 if (info->links[i].valid)
385 num_valid_links++;
386 }
387 if (num_valid_links > 1 &&
388 hostapd_update_sta_links_status(hapd, sta, resp_ies,
389 resp_ies_len)) {
390 wpa_printf(MSG_DEBUG,
391 "Failed to get STA non-assoc links status info");
392 reason = WLAN_REASON_UNSPECIFIED;
393 goto fail;
394 }
395 }
396#endif /* CONFIG_IEEE80211BE */
397
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800398 sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700399
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700400 /*
401 * ACL configurations to the drivers (implementing AP SME and ACL
402 * offload) without hostapd's knowledge, can result in a disconnection
403 * though the driver accepts the connection. Skip the hostapd check for
404 * ACL if the driver supports ACL offload to avoid potentially
405 * conflicting ACL rules.
406 */
407 if (hapd->iface->drv_max_acl_mac_addrs == 0 &&
408 hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800409 wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect",
410 MAC2STR(addr));
411 reason = WLAN_REASON_UNSPECIFIED;
412 goto fail;
413 }
414
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700415#ifdef CONFIG_P2P
416 if (elems.p2p) {
417 wpabuf_free(sta->p2p_ie);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800418 sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700419 P2P_IE_VENDOR_TYPE);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700420 if (sta->p2p_ie)
421 p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700422 }
423#endif /* CONFIG_P2P */
424
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700425#ifdef NEED_AP_MLME
426 if (elems.ht_capabilities &&
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700427 (hapd->iface->conf->ht_capab &
428 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
429 struct ieee80211_ht_capabilities *ht_cap =
430 (struct ieee80211_ht_capabilities *)
431 elems.ht_capabilities;
432
433 if (le_to_host16(ht_cap->ht_capabilities_info) &
434 HT_CAP_INFO_40MHZ_INTOLERANT)
435 ht40_intolerant_add(hapd->iface, sta);
436 }
437#endif /* NEED_AP_MLME */
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700438
Sunil Ravia04bd252022-05-02 22:54:18 -0700439 check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700440
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800441#ifdef CONFIG_HS20
442 wpabuf_free(sta->hs20_ie);
443 if (elems.hs20 && elems.hs20_len > 4) {
444 sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
445 elems.hs20_len - 4);
446 } else
447 sta->hs20_ie = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700448
449 wpabuf_free(sta->roaming_consortium);
450 if (elems.roaming_cons_sel)
451 sta->roaming_consortium = wpabuf_alloc_copy(
452 elems.roaming_cons_sel + 4,
453 elems.roaming_cons_sel_len - 4);
454 else
455 sta->roaming_consortium = NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800456#endif /* CONFIG_HS20 */
457
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800458#ifdef CONFIG_FST
459 wpabuf_free(sta->mb_ies);
460 if (hapd->iface->fst)
461 sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
462 else
463 sta->mb_ies = NULL;
464#endif /* CONFIG_FST */
465
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800466 mbo_ap_check_sta_assoc(hapd, sta, &elems);
467
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800468 ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
469 elems.supp_op_classes_len);
470
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700471 if (hapd->conf->wpa) {
472 if (ie == NULL || ielen == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800473#ifdef CONFIG_WPS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700474 if (hapd->conf->wps_state) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800475 wpa_printf(MSG_DEBUG,
476 "STA did not include WPA/RSN IE in (Re)Association Request - possible WPS use");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700477 sta->flags |= WLAN_STA_MAYBE_WPS;
478 goto skip_wpa_check;
479 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800480#endif /* CONFIG_WPS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700481
482 wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
Roshan Pius3a1667e2018-07-03 15:17:14 -0700483 reason = WLAN_REASON_INVALID_IE;
484 status = WLAN_STATUS_INVALID_IE;
485 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700486 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800487#ifdef CONFIG_WPS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700488 if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
489 os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800490 struct wpabuf *wps;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800491
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700492 sta->flags |= WLAN_STA_WPS;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800493 wps = ieee802_11_vendor_ie_concat(ie, ielen,
494 WPS_IE_VENDOR_TYPE);
495 if (wps) {
496 if (wps_is_20(wps)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800497 wpa_printf(MSG_DEBUG,
498 "WPS: STA supports WPS 2.0");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800499 sta->flags |= WLAN_STA_WPS2;
500 }
501 wpabuf_free(wps);
502 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700503 goto skip_wpa_check;
504 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800505#endif /* CONFIG_WPS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700506
507 if (sta->wpa_sm == NULL)
508 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700509 sta->addr,
510 p2p_dev_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700511 if (sta->wpa_sm == NULL) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800512 wpa_printf(MSG_ERROR,
513 "Failed to initialize WPA state machine");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700514 return -1;
515 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000516#ifdef CONFIG_IEEE80211BE
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000517 if (ap_sta_is_mld(hapd, sta)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000518 wpa_printf(MSG_DEBUG,
519 "MLD: Set ML info in RSN Authenticator");
Sunil Ravi99c035e2024-07-12 01:42:03 +0000520 wpa_auth_set_ml_info(sta->wpa_sm, hapd->mld->mld_addr,
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000521 sta->mld_assoc_link_id,
522 &sta->mld_info);
523 }
524#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700525 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
Hai Shalom021b0b52019-04-10 11:17:58 -0700526 hapd->iface->freq,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700527 ie, ielen,
Hai Shalomc3565922019-10-28 11:58:20 -0700528 elems.rsnxe ? elems.rsnxe - 2 : NULL,
529 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700530 elems.mdie, elems.mdie_len,
531 elems.owe_dh, elems.owe_dh_len);
Hai Shalomfdcde762020-04-02 11:19:20 -0700532 reason = WLAN_REASON_INVALID_IE;
533 status = WLAN_STATUS_INVALID_IE;
534 switch (res) {
535 case WPA_IE_OK:
536 reason = WLAN_REASON_UNSPECIFIED;
537 status = WLAN_STATUS_SUCCESS;
538 break;
539 case WPA_INVALID_IE:
540 reason = WLAN_REASON_INVALID_IE;
541 status = WLAN_STATUS_INVALID_IE;
542 break;
543 case WPA_INVALID_GROUP:
544 reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
545 status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
546 break;
547 case WPA_INVALID_PAIRWISE:
548 reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
549 status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
550 break;
551 case WPA_INVALID_AKMP:
552 reason = WLAN_REASON_AKMP_NOT_VALID;
553 status = WLAN_STATUS_AKMP_NOT_VALID;
554 break;
555 case WPA_NOT_ENABLED:
556 reason = WLAN_REASON_INVALID_IE;
557 status = WLAN_STATUS_INVALID_IE;
558 break;
559 case WPA_ALLOC_FAIL:
560 reason = WLAN_REASON_UNSPECIFIED;
561 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
562 break;
563 case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
564 reason = WLAN_REASON_INVALID_IE;
565 status = WLAN_STATUS_INVALID_IE;
566 break;
567 case WPA_INVALID_MGMT_GROUP_CIPHER:
568 reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
569 status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
570 break;
571 case WPA_INVALID_MDIE:
572 reason = WLAN_REASON_INVALID_MDE;
573 status = WLAN_STATUS_INVALID_MDIE;
574 break;
575 case WPA_INVALID_PROTO:
576 reason = WLAN_REASON_INVALID_IE;
577 status = WLAN_STATUS_INVALID_IE;
578 break;
579 case WPA_INVALID_PMKID:
580 reason = WLAN_REASON_INVALID_PMKID;
581 status = WLAN_STATUS_INVALID_PMKID;
582 break;
583 case WPA_DENIED_OTHER_REASON:
584 reason = WLAN_REASON_UNSPECIFIED;
585 status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
586 break;
587 }
588 if (status != WLAN_STATUS_SUCCESS) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800589 wpa_printf(MSG_DEBUG,
590 "WPA/RSN information element rejected? (res %u)",
591 res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700592 wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800593 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700594 }
Hai Shalomc3565922019-10-28 11:58:20 -0700595
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700596 if (wpa_auth_uses_mfp(sta->wpa_sm))
597 sta->flags |= WLAN_STA_MFP;
598 else
599 sta->flags &= ~WLAN_STA_MFP;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700600
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800601#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700602 if (sta->auth_alg == WLAN_AUTH_FT) {
603 status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
604 req_ies_len);
605 if (status != WLAN_STATUS_SUCCESS) {
606 if (status == WLAN_STATUS_INVALID_PMKID)
607 reason = WLAN_REASON_INVALID_IE;
608 if (status == WLAN_STATUS_INVALID_MDIE)
609 reason = WLAN_REASON_INVALID_IE;
610 if (status == WLAN_STATUS_INVALID_FTIE)
611 reason = WLAN_REASON_INVALID_IE;
612 goto fail;
613 }
614 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800615#endif /* CONFIG_IEEE80211R_AP */
Hai Shalomc3565922019-10-28 11:58:20 -0700616#ifdef CONFIG_SAE
Sunil Ravi77d572f2023-01-17 23:58:31 +0000617 if (hapd->conf->sae_pwe == SAE_PWE_BOTH &&
Hai Shalomc3565922019-10-28 11:58:20 -0700618 sta->auth_alg == WLAN_AUTH_SAE &&
Hai Shalom899fcc72020-10-19 14:38:18 -0700619 sta->sae && !sta->sae->h2e &&
Hai Shaloma20dcd72022-02-04 13:43:00 -0800620 ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
621 WLAN_RSNX_CAPAB_SAE_H2E)) {
Hai Shalomc3565922019-10-28 11:58:20 -0700622 wpa_printf(MSG_INFO, "SAE: " MACSTR
623 " indicates support for SAE H2E, but did not use it",
624 MAC2STR(sta->addr));
625 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
626 reason = WLAN_REASON_UNSPECIFIED;
627 goto fail;
628 }
629#endif /* CONFIG_SAE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700630 } else if (hapd->conf->wps_state) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800631#ifdef CONFIG_WPS
632 struct wpabuf *wps;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800633
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800634 if (req_ies)
635 wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700636 WPS_IE_VENDOR_TYPE);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800637 else
638 wps = NULL;
639#ifdef CONFIG_WPS_STRICT
640 if (wps && wps_validate_assoc_req(wps) < 0) {
641 reason = WLAN_REASON_INVALID_IE;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700642 status = WLAN_STATUS_INVALID_IE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700643 wpabuf_free(wps);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800644 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700645 }
646#endif /* CONFIG_WPS_STRICT */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800647 if (wps) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700648 sta->flags |= WLAN_STA_WPS;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800649 if (wps_is_20(wps)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800650 wpa_printf(MSG_DEBUG,
651 "WPS: STA supports WPS 2.0");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800652 sta->flags |= WLAN_STA_WPS2;
653 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700654 } else
655 sta->flags |= WLAN_STA_MAYBE_WPS;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800656 wpabuf_free(wps);
657#endif /* CONFIG_WPS */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800658#ifdef CONFIG_HS20
659 } else if (hapd->conf->osen) {
660 if (elems.osen == NULL) {
661 hostapd_logger(
662 hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
663 HOSTAPD_LEVEL_INFO,
664 "No HS 2.0 OSEN element in association request");
665 return WLAN_STATUS_INVALID_IE;
666 }
667
668 wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
669 if (sta->wpa_sm == NULL)
670 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
671 sta->addr, NULL);
672 if (sta->wpa_sm == NULL) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800673 wpa_printf(MSG_WARNING,
674 "Failed to initialize WPA state machine");
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800675 return WLAN_STATUS_UNSPECIFIED_FAILURE;
676 }
677 if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
678 elems.osen - 2, elems.osen_len + 2) < 0)
679 return WLAN_STATUS_INVALID_IE;
680#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700681 }
Hai Shalomfdcde762020-04-02 11:19:20 -0700682#ifdef CONFIG_WPS
683skip_wpa_check:
684#endif /* CONFIG_WPS */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800685
686#ifdef CONFIG_MBO
687 if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
688 elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
689 hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
690 wpa_printf(MSG_INFO,
691 "MBO: Reject WPA2 association without PMF");
692 return WLAN_STATUS_UNSPECIFIED_FAILURE;
693 }
694#endif /* CONFIG_MBO */
695
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800696#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700697 p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
Hai Shalomfdcde762020-04-02 11:19:20 -0700698 sta->auth_alg, req_ies, req_ies_len,
699 !elems.rsnxe);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700700 if (!p) {
701 wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
702 return WLAN_STATUS_UNSPECIFIED_FAILURE;
703 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700704#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700705
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700706#ifdef CONFIG_FILS
707 if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
708 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
709 sta->auth_alg == WLAN_AUTH_FILS_PK) {
710 int delay_assoc = 0;
711
712 if (!req_ies)
713 return WLAN_STATUS_UNSPECIFIED_FAILURE;
714
715 if (!wpa_fils_validate_fils_session(sta->wpa_sm, req_ies,
716 req_ies_len,
717 sta->fils_session)) {
718 wpa_printf(MSG_DEBUG,
719 "FILS: Session validation failed");
720 return WLAN_STATUS_UNSPECIFIED_FAILURE;
721 }
722
723 res = wpa_fils_validate_key_confirm(sta->wpa_sm, req_ies,
724 req_ies_len);
725 if (res < 0) {
726 wpa_printf(MSG_DEBUG,
727 "FILS: Key Confirm validation failed");
728 return WLAN_STATUS_UNSPECIFIED_FAILURE;
729 }
730
731 if (fils_process_hlp(hapd, sta, req_ies, req_ies_len) > 0) {
732 wpa_printf(MSG_DEBUG,
733 "FILS: Delaying Assoc Response (HLP)");
734 delay_assoc = 1;
735 } else {
736 wpa_printf(MSG_DEBUG,
737 "FILS: Going ahead with Assoc Response (no HLP)");
738 }
739
740 if (sta) {
741 wpa_printf(MSG_DEBUG, "FILS: HLP callback cleanup");
742 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
743 os_free(sta->fils_pending_assoc_req);
744 sta->fils_pending_assoc_req = NULL;
745 sta->fils_pending_assoc_req_len = 0;
746 wpabuf_free(sta->fils_hlp_resp);
747 sta->fils_hlp_resp = NULL;
748 sta->fils_drv_assoc_finish = 0;
749 }
750
751 if (sta && delay_assoc && status == WLAN_STATUS_SUCCESS) {
752 u8 *req_tmp;
753
754 req_tmp = os_malloc(req_ies_len);
755 if (!req_tmp) {
756 wpa_printf(MSG_DEBUG,
757 "FILS: buffer allocation failed for assoc req");
758 goto fail;
759 }
760 os_memcpy(req_tmp, req_ies, req_ies_len);
761 sta->fils_pending_assoc_req = req_tmp;
762 sta->fils_pending_assoc_req_len = req_ies_len;
763 sta->fils_pending_assoc_is_reassoc = reassoc;
764 sta->fils_drv_assoc_finish = 1;
765 wpa_printf(MSG_DEBUG,
766 "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
767 MACSTR, MAC2STR(sta->addr));
768 eloop_register_timeout(
769 0, hapd->conf->fils_hlp_wait_time * 1024,
770 fils_hlp_timeout, hapd, sta);
771 return 0;
772 }
773 p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
774 elems.fils_session,
775 sta->fils_hlp_resp);
776 wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)",
777 buf, p - buf);
778 }
779#endif /* CONFIG_FILS */
780
Roshan Pius3a1667e2018-07-03 15:17:14 -0700781#ifdef CONFIG_OWE
782 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000783 !(iface->drv_flags2 & WPA_DRIVER_FLAGS2_OWE_OFFLOAD_AP) &&
Roshan Pius3a1667e2018-07-03 15:17:14 -0700784 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
785 elems.owe_dh) {
786 u8 *npos;
Hai Shalomb755a2a2020-04-23 21:49:02 -0700787 u16 ret_status;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700788
789 npos = owe_assoc_req_process(hapd, sta,
790 elems.owe_dh, elems.owe_dh_len,
791 p, sizeof(buf) - (p - buf),
Hai Shalomb755a2a2020-04-23 21:49:02 -0700792 &ret_status);
793 status = ret_status;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700794 if (npos)
795 p = npos;
Hai Shalomfdcde762020-04-02 11:19:20 -0700796
Roshan Pius3a1667e2018-07-03 15:17:14 -0700797 if (!npos &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700798 status == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
Hai Shalomb755a2a2020-04-23 21:49:02 -0700799 hostapd_sta_assoc(hapd, addr, reassoc, ret_status, buf,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700800 p - buf);
801 return 0;
802 }
803
Hai Shalomfdcde762020-04-02 11:19:20 -0700804 if (!npos || status != WLAN_STATUS_SUCCESS)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700805 goto fail;
806 }
807#endif /* CONFIG_OWE */
808
Hai Shalom021b0b52019-04-10 11:17:58 -0700809#ifdef CONFIG_DPP2
810 dpp_pfs_free(sta->dpp_pfs);
811 sta->dpp_pfs = NULL;
812
813 if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
814 hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
815 wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
816 elems.owe_dh) {
817 sta->dpp_pfs = dpp_pfs_init(
818 wpabuf_head(hapd->conf->dpp_netaccesskey),
819 wpabuf_len(hapd->conf->dpp_netaccesskey));
820 if (!sta->dpp_pfs) {
821 wpa_printf(MSG_DEBUG,
822 "DPP: Could not initialize PFS");
823 /* Try to continue without PFS */
824 goto pfs_fail;
825 }
826
827 if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
828 elems.owe_dh_len) < 0) {
829 dpp_pfs_free(sta->dpp_pfs);
830 sta->dpp_pfs = NULL;
831 reason = WLAN_REASON_UNSPECIFIED;
832 goto fail;
833 }
834 }
835
836 wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
837 sta->dpp_pfs->secret : NULL);
838 pfs_fail:
839#endif /* CONFIG_DPP2 */
840
Hai Shalomfdcde762020-04-02 11:19:20 -0700841 if (elems.rrm_enabled &&
842 elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
843 os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
844 sizeof(sta->rrm_enabled_capa));
845
Roshan Pius3a1667e2018-07-03 15:17:14 -0700846#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700847 hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700848
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700849 if (sta->auth_alg == WLAN_AUTH_FT ||
850 sta->auth_alg == WLAN_AUTH_FILS_SK ||
851 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
852 sta->auth_alg == WLAN_AUTH_FILS_PK)
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000853 updated = ap_sta_set_authorized_flag(hapd, sta, 1);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700854#else /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700855 /* Keep compiler silent about unused variables */
856 if (status) {
857 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700858#endif /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700859
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000860#ifdef CONFIG_IEEE80211BE
861 if (hostapd_process_assoc_ml_info(hapd, sta, req_ies, req_ies_len,
862 !!reassoc, WLAN_STATUS_SUCCESS,
863 true)) {
864 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
865 reason = WLAN_REASON_UNSPECIFIED;
866 goto fail;
867 }
868#endif /* CONFIG_IEEE80211BE */
869
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700870 new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
871 sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800872 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700873
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700874 hostapd_set_sta_flags(hapd, sta);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000875 if (updated)
876 ap_sta_set_authorized_event(hapd, sta, 1);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700877
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700878 if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
879 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700880#ifdef CONFIG_FILS
881 else if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
882 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
883 sta->auth_alg == WLAN_AUTH_FILS_PK)
884 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
885#endif /* CONFIG_FILS */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700886 else
887 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700888
889 hostapd_new_assoc_sta(hapd, sta, !new_assoc);
890
891 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
892
893#ifdef CONFIG_P2P
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800894 if (req_ies) {
895 p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
896 req_ies, req_ies_len);
897 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700898#endif /* CONFIG_P2P */
899
900 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800901
902fail:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800903#ifdef CONFIG_IEEE80211R_AP
Hai Shalomb755a2a2020-04-23 21:49:02 -0700904 if (status >= 0)
905 hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800906#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800907 hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
908 ap_free_sta(hapd, sta);
909 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700910}
911
912
Sunil Ravi99c035e2024-07-12 01:42:03 +0000913static void hostapd_remove_sta(struct hostapd_data *hapd, struct sta_info *sta)
914{
915 ap_sta_set_authorized(hapd, sta, 0);
916 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
917 hostapd_set_sta_flags(hapd, sta);
918 wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
919 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
920 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
921 ap_free_sta(hapd, sta);
922}
923
924
925#ifdef CONFIG_IEEE80211BE
926static void hostapd_notif_disassoc_mld(struct hostapd_data *assoc_hapd,
927 struct sta_info *sta,
928 const u8 *addr)
929{
930 unsigned int link_id, i;
931 struct hostapd_data *tmp_hapd;
932 struct hapd_interfaces *interfaces = assoc_hapd->iface->interfaces;
933
934 /* Remove STA entry in non-assoc links */
935 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
936 if (!sta->mld_info.links[link_id].valid)
937 continue;
938
939 for (i = 0; i < interfaces->count; i++) {
940 struct sta_info *tmp_sta;
941
942 tmp_hapd = interfaces->iface[i]->bss[0];
943
944 if (!tmp_hapd->conf->mld_ap ||
945 assoc_hapd == tmp_hapd ||
946 assoc_hapd->conf->mld_id != tmp_hapd->conf->mld_id)
947 continue;
948
949 tmp_sta = ap_get_sta(tmp_hapd, addr);
950 if (tmp_sta)
951 ap_free_sta(tmp_hapd, tmp_sta);
952 }
953 }
954
955 /* Remove STA in assoc link */
956 hostapd_remove_sta(assoc_hapd, sta);
957}
958#endif /* CONFIG_IEEE80211BE */
959
960
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700961void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
962{
963 struct sta_info *sta;
964
965 if (addr == NULL) {
966 /*
967 * This could potentially happen with unexpected event from the
968 * driver wrapper. This was seen at least in one case where the
969 * driver ended up reporting a station mode event while hostapd
970 * was running, so better make sure we stop processing such an
971 * event here.
972 */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800973 wpa_printf(MSG_DEBUG,
974 "hostapd_notif_disassoc: Skip event with no address");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700975 return;
976 }
977
978 hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
979 HOSTAPD_LEVEL_INFO, "disassociated");
980
981 sta = ap_get_sta(hapd, addr);
Sunil Ravi99c035e2024-07-12 01:42:03 +0000982#ifdef CONFIG_IEEE80211BE
983 if (hostapd_is_mld_ap(hapd)) {
984 struct hostapd_data *assoc_hapd;
985 unsigned int i;
986
987 if (!sta) {
988 /* Find non-MLO cases from any of the affiliated AP
989 * links. */
990 for (i = 0; i < hapd->iface->interfaces->count; ++i) {
991 struct hostapd_iface *h =
992 hapd->iface->interfaces->iface[i];
993 struct hostapd_data *h_hapd = h->bss[0];
994 struct hostapd_bss_config *hconf = h_hapd->conf;
995
996 if (!hconf->mld_ap ||
997 hconf->mld_id != hapd->conf->mld_id)
998 continue;
999
1000 sta = ap_get_sta(h_hapd, addr);
1001 if (sta) {
1002 if (!sta->mld_info.mld_sta) {
1003 hapd = h_hapd;
1004 goto legacy;
1005 }
1006 break;
1007 }
1008 }
1009 } else if (!sta->mld_info.mld_sta) {
1010 goto legacy;
1011 }
1012 if (!sta) {
1013 wpa_printf(MSG_DEBUG,
1014 "Disassociation notification for unknown STA "
1015 MACSTR, MAC2STR(addr));
1016 return;
1017 }
1018 sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd);
1019 if (sta)
1020 hostapd_notif_disassoc_mld(assoc_hapd, sta, addr);
1021 return;
1022 }
1023
1024legacy:
1025#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001026 if (sta == NULL) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001027 wpa_printf(MSG_DEBUG,
1028 "Disassociation notification for unknown STA "
1029 MACSTR, MAC2STR(addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001030 return;
1031 }
1032
Sunil Ravi99c035e2024-07-12 01:42:03 +00001033 hostapd_remove_sta(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001034}
1035
1036
1037void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
1038{
1039 struct sta_info *sta = ap_get_sta(hapd, addr);
1040
Roshan Pius3a1667e2018-07-03 15:17:14 -07001041 if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001042 return;
1043
1044 hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001045 HOSTAPD_LEVEL_INFO,
1046 "disconnected due to excessive missing ACKs");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001047 hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001048 ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001049}
1050
1051
Roshan Pius3a1667e2018-07-03 15:17:14 -07001052void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
1053 enum smps_mode smps_mode,
1054 enum chan_width chan_width, u8 rx_nss)
1055{
1056 struct sta_info *sta = ap_get_sta(hapd, addr);
1057 const char *txt;
1058
1059 if (!sta)
1060 return;
1061
1062 switch (smps_mode) {
1063 case SMPS_AUTOMATIC:
1064 txt = "automatic";
1065 break;
1066 case SMPS_OFF:
1067 txt = "off";
1068 break;
1069 case SMPS_DYNAMIC:
1070 txt = "dynamic";
1071 break;
1072 case SMPS_STATIC:
1073 txt = "static";
1074 break;
1075 default:
1076 txt = NULL;
1077 break;
1078 }
1079 if (txt) {
1080 wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_SMPS_MODE_CHANGED
1081 MACSTR " %s", MAC2STR(addr), txt);
1082 }
1083
1084 switch (chan_width) {
1085 case CHAN_WIDTH_20_NOHT:
1086 txt = "20(no-HT)";
1087 break;
1088 case CHAN_WIDTH_20:
1089 txt = "20";
1090 break;
1091 case CHAN_WIDTH_40:
1092 txt = "40";
1093 break;
1094 case CHAN_WIDTH_80:
1095 txt = "80";
1096 break;
1097 case CHAN_WIDTH_80P80:
1098 txt = "80+80";
1099 break;
1100 case CHAN_WIDTH_160:
1101 txt = "160";
1102 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00001103 case CHAN_WIDTH_320:
1104 txt = "320";
1105 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001106 default:
1107 txt = NULL;
1108 break;
1109 }
1110 if (txt) {
1111 wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_MAX_BW_CHANGED
1112 MACSTR " %s", MAC2STR(addr), txt);
1113 }
1114
1115 if (rx_nss != 0xff) {
1116 wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_N_SS_CHANGED
1117 MACSTR " %d", MAC2STR(addr), rx_nss);
1118 }
1119}
1120
1121
Dmitry Shmidt04949592012-07-19 12:16:46 -07001122void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
Hai Shalom81f62d82019-07-22 12:10:00 -07001123 int offset, int width, int cf1, int cf2,
Sunil Ravi036cec52023-03-29 11:35:17 -07001124 u16 punct_bitmap, int finished)
Dmitry Shmidt04949592012-07-19 12:16:46 -07001125{
1126#ifdef NEED_AP_MLME
Sunil Ravi77d572f2023-01-17 23:58:31 +00001127 int channel, chwidth, is_dfs0, is_dfs;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001128 u8 seg0_idx = 0, seg1_idx = 0, op_class, chan_no;
Hai Shalom74f70d42019-02-11 14:42:39 -08001129 size_t i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001130
1131 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001132 HOSTAPD_LEVEL_INFO,
Sunil Ravi036cec52023-03-29 11:35:17 -07001133 "driver %s channel switch: iface->freq=%d, freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, eht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d, puncturing_bitmap=0x%x",
Hai Shalom81f62d82019-07-22 12:10:00 -07001134 finished ? "had" : "starting",
Sunil Ravi77d572f2023-01-17 23:58:31 +00001135 hapd->iface->freq,
Hai Shalom60840252021-02-19 19:02:11 -08001136 freq, ht, hapd->iconf->ch_switch_vht_config,
Sunil Ravia04bd252022-05-02 22:54:18 -07001137 hapd->iconf->ch_switch_he_config,
1138 hapd->iconf->ch_switch_eht_config, offset,
Sunil Ravi036cec52023-03-29 11:35:17 -07001139 width, channel_width_to_string(width), cf1, cf2,
1140 punct_bitmap);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001141
Hai Shalom1dc4d202019-04-29 16:22:27 -07001142 if (!hapd->iface->current_mode) {
1143 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
1144 HOSTAPD_LEVEL_WARNING,
1145 "ignore channel switch since the interface is not yet ready");
1146 return;
1147 }
1148
Sunil Ravi77d572f2023-01-17 23:58:31 +00001149 /* Check if any of configured channels require DFS */
1150 is_dfs0 = hostapd_is_dfs_required(hapd->iface);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001151 hapd->iface->freq = freq;
1152
1153 channel = hostapd_hw_get_channel(hapd, freq);
1154 if (!channel) {
1155 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001156 HOSTAPD_LEVEL_WARNING,
1157 "driver switched to bad channel!");
Dmitry Shmidt04949592012-07-19 12:16:46 -07001158 return;
1159 }
1160
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08001161 switch (width) {
1162 case CHAN_WIDTH_80:
Sunil8cd6f4d2022-06-28 18:40:46 +00001163 chwidth = CONF_OPER_CHWIDTH_80MHZ;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08001164 break;
1165 case CHAN_WIDTH_80P80:
Sunil8cd6f4d2022-06-28 18:40:46 +00001166 chwidth = CONF_OPER_CHWIDTH_80P80MHZ;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08001167 break;
1168 case CHAN_WIDTH_160:
Sunil8cd6f4d2022-06-28 18:40:46 +00001169 chwidth = CONF_OPER_CHWIDTH_160MHZ;
1170 break;
1171 case CHAN_WIDTH_320:
1172 chwidth = CONF_OPER_CHWIDTH_320MHZ;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08001173 break;
1174 case CHAN_WIDTH_20_NOHT:
1175 case CHAN_WIDTH_20:
1176 case CHAN_WIDTH_40:
1177 default:
Sunil8cd6f4d2022-06-28 18:40:46 +00001178 chwidth = CONF_OPER_CHWIDTH_USE_HT;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08001179 break;
1180 }
1181
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001182 /* The operating channel changed when CSA finished, so need to update
1183 * hw_mode for all following operations to cover the cases where the
1184 * driver changed the operating band. */
1185 if (finished && hostapd_csa_update_hwmode(hapd->iface))
1186 return;
1187
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08001188 switch (hapd->iface->current_mode->mode) {
1189 case HOSTAPD_MODE_IEEE80211A:
Hai Shalom899fcc72020-10-19 14:38:18 -07001190 if (cf1 == 5935)
1191 seg0_idx = (cf1 - 5925) / 5;
1192 else if (cf1 > 5950)
1193 seg0_idx = (cf1 - 5950) / 5;
1194 else if (cf1 > 5000)
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08001195 seg0_idx = (cf1 - 5000) / 5;
Hai Shalom899fcc72020-10-19 14:38:18 -07001196
1197 if (cf2 == 5935)
1198 seg1_idx = (cf2 - 5925) / 5;
1199 else if (cf2 > 5950)
1200 seg1_idx = (cf2 - 5950) / 5;
1201 else if (cf2 > 5000)
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08001202 seg1_idx = (cf2 - 5000) / 5;
1203 break;
1204 default:
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001205 ieee80211_freq_to_chan(cf1, &seg0_idx);
1206 ieee80211_freq_to_chan(cf2, &seg1_idx);
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08001207 break;
1208 }
1209
Dmitry Shmidt04949592012-07-19 12:16:46 -07001210 hapd->iconf->channel = channel;
1211 hapd->iconf->ieee80211n = ht;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001212 if (!ht)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001213 hapd->iconf->ieee80211ac = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001214 if (hapd->iconf->ch_switch_vht_config) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001215 /* CHAN_SWITCH VHT config */
1216 if (hapd->iconf->ch_switch_vht_config &
1217 CH_SWITCH_VHT_ENABLED)
1218 hapd->iconf->ieee80211ac = 1;
1219 else if (hapd->iconf->ch_switch_vht_config &
1220 CH_SWITCH_VHT_DISABLED)
1221 hapd->iconf->ieee80211ac = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001222 }
1223 if (hapd->iconf->ch_switch_he_config) {
Hai Shalom60840252021-02-19 19:02:11 -08001224 /* CHAN_SWITCH HE config */
1225 if (hapd->iconf->ch_switch_he_config &
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001226 CH_SWITCH_HE_ENABLED) {
Hai Shalom60840252021-02-19 19:02:11 -08001227 hapd->iconf->ieee80211ax = 1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001228 if (hapd->iface->freq > 4000 &&
1229 hapd->iface->freq < 5895)
1230 hapd->iconf->ieee80211ac = 1;
1231 }
Hai Shalom60840252021-02-19 19:02:11 -08001232 else if (hapd->iconf->ch_switch_he_config &
1233 CH_SWITCH_HE_DISABLED)
1234 hapd->iconf->ieee80211ax = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001235 }
Sunil Ravia04bd252022-05-02 22:54:18 -07001236#ifdef CONFIG_IEEE80211BE
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001237 if (hapd->iconf->ch_switch_eht_config) {
Sunil Ravia04bd252022-05-02 22:54:18 -07001238 /* CHAN_SWITCH EHT config */
1239 if (hapd->iconf->ch_switch_eht_config &
1240 CH_SWITCH_EHT_ENABLED) {
1241 hapd->iconf->ieee80211be = 1;
1242 hapd->iconf->ieee80211ax = 1;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001243 if (!is_6ghz_freq(hapd->iface->freq) &&
1244 hapd->iface->freq > 4000)
Sunil Ravia04bd252022-05-02 22:54:18 -07001245 hapd->iconf->ieee80211ac = 1;
1246 } else if (hapd->iconf->ch_switch_eht_config &
1247 CH_SWITCH_EHT_DISABLED)
1248 hapd->iconf->ieee80211be = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001249 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001250#endif /* CONFIG_IEEE80211BE */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001251 hapd->iconf->ch_switch_vht_config = 0;
Hai Shalom60840252021-02-19 19:02:11 -08001252 hapd->iconf->ch_switch_he_config = 0;
Sunil Ravia04bd252022-05-02 22:54:18 -07001253 hapd->iconf->ch_switch_eht_config = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001254
Hai Shaloma20dcd72022-02-04 13:43:00 -08001255 if (width == CHAN_WIDTH_40 || width == CHAN_WIDTH_80 ||
Sunil Ravi640215c2023-06-28 23:08:09 +00001256 width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160 ||
1257 width == CHAN_WIDTH_320)
Hai Shaloma20dcd72022-02-04 13:43:00 -08001258 hapd->iconf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
1259 else if (width == CHAN_WIDTH_20 || width == CHAN_WIDTH_20_NOHT)
1260 hapd->iconf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
1261
Dmitry Shmidt04949592012-07-19 12:16:46 -07001262 hapd->iconf->secondary_channel = offset;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001263 if (ieee80211_freq_to_channel_ext(freq, offset, chwidth,
1264 &op_class, &chan_no) !=
1265 NUM_HOSTAPD_MODES)
1266 hapd->iconf->op_class = op_class;
Hai Shalom81f62d82019-07-22 12:10:00 -07001267 hostapd_set_oper_chwidth(hapd->iconf, chwidth);
1268 hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx);
1269 hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001270 /* Auto-detect new bw320_offset */
1271 hostapd_set_and_check_bw320_offset(hapd->iconf, 0);
Sunil Ravi036cec52023-03-29 11:35:17 -07001272#ifdef CONFIG_IEEE80211BE
1273 hapd->iconf->punct_bitmap = punct_bitmap;
1274#endif /* CONFIG_IEEE80211BE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08001275 if (hapd->iconf->ieee80211ac) {
1276 hapd->iconf->vht_capab &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
Sunil8cd6f4d2022-06-28 18:40:46 +00001277 if (chwidth == CONF_OPER_CHWIDTH_160MHZ)
Hai Shaloma20dcd72022-02-04 13:43:00 -08001278 hapd->iconf->vht_capab |=
1279 VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
Sunil8cd6f4d2022-06-28 18:40:46 +00001280 else if (chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
Hai Shaloma20dcd72022-02-04 13:43:00 -08001281 hapd->iconf->vht_capab |=
1282 VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
1283 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001284
Roshan Pius3a1667e2018-07-03 15:17:14 -07001285 is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
1286 hapd->iface->num_hw_features);
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001287
Hai Shalom81f62d82019-07-22 12:10:00 -07001288 wpa_msg(hapd->msg_ctx, MSG_INFO,
Sunil Ravi036cec52023-03-29 11:35:17 -07001289 "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d is_dfs0=%d dfs=%d puncturing_bitmap=0x%04x",
Hai Shalom81f62d82019-07-22 12:10:00 -07001290 finished ? WPA_EVENT_CHANNEL_SWITCH :
1291 WPA_EVENT_CHANNEL_SWITCH_STARTED,
1292 freq, ht, offset, channel_width_to_string(width),
Sunil Ravi036cec52023-03-29 11:35:17 -07001293 cf1, cf2, is_dfs0, is_dfs, punct_bitmap);
Hai Shalom81f62d82019-07-22 12:10:00 -07001294 if (!finished)
1295 return;
1296
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07001297 if (hapd->csa_in_progress &&
1298 freq == hapd->cs_freq_params.freq) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001299 hostapd_cleanup_cs_params(hapd);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07001300 ieee802_11_set_beacon(hapd);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001301
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001302 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
1303 "freq=%d dfs=%d", freq, is_dfs);
1304 } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00001305 /* Complete AP configuration for the first bring up. */
1306 if (is_dfs0 > 0 &&
1307 hostapd_is_dfs_required(hapd->iface) <= 0 &&
1308 hapd->iface->state != HAPD_IFACE_ENABLED) {
1309 /* Fake a CAC start bit to skip setting channel */
1310 hapd->iface->cac_started = 1;
1311 hostapd_setup_interface_complete(hapd->iface, 0);
1312 }
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001313 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
1314 "freq=%d dfs=%d", freq, is_dfs);
Hai Shalomfdcde762020-04-02 11:19:20 -07001315 } else if (is_dfs &&
1316 hostapd_is_dfs_required(hapd->iface) &&
1317 !hostapd_is_dfs_chan_available(hapd->iface) &&
1318 !hapd->iface->cac_started) {
1319 hostapd_disable_iface(hapd->iface);
1320 hostapd_enable_iface(hapd->iface);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001321 }
Hai Shalom74f70d42019-02-11 14:42:39 -08001322
1323 for (i = 0; i < hapd->iface->num_bss; i++)
1324 hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
Hai Shalom899fcc72020-10-19 14:38:18 -07001325
1326#ifdef CONFIG_OCV
Sunil Ravia04bd252022-05-02 22:54:18 -07001327 if (hapd->conf->ocv &&
1328 !(hapd->iface->drv_flags2 &
1329 WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07001330 struct sta_info *sta;
1331 bool check_sa_query = false;
1332
1333 for (sta = hapd->sta_list; sta; sta = sta->next) {
1334 if (wpa_auth_uses_ocv(sta->wpa_sm) &&
1335 !(sta->flags & WLAN_STA_WNM_SLEEP_MODE)) {
1336 sta->post_csa_sa_query = 1;
1337 check_sa_query = true;
1338 }
1339 }
1340
1341 if (check_sa_query) {
1342 wpa_printf(MSG_DEBUG,
1343 "OCV: Check post-CSA SA Query initiation in 15 seconds");
1344 eloop_register_timeout(15, 0,
1345 hostapd_ocv_check_csa_sa_query,
1346 hapd, NULL);
1347 }
1348 }
1349#endif /* CONFIG_OCV */
Dmitry Shmidt04949592012-07-19 12:16:46 -07001350#endif /* NEED_AP_MLME */
1351}
1352
1353
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001354void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
1355 const u8 *addr, int reason_code)
1356{
1357 switch (reason_code) {
1358 case MAX_CLIENT_REACHED:
1359 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR,
1360 MAC2STR(addr));
1361 break;
1362 case BLOCKED_CLIENT:
1363 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR,
1364 MAC2STR(addr));
1365 break;
1366 }
1367}
1368
1369
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001370#ifdef CONFIG_ACS
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08001371void hostapd_acs_channel_selected(struct hostapd_data *hapd,
1372 struct acs_selected_channels *acs_res)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001373{
Dmitry Shmidtb1e52102015-05-29 12:36:29 -07001374 int ret, i;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001375 int err = 0;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001376 struct hostapd_channel_data *pri_chan;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001377
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001378#ifdef CONFIG_IEEE80211BE
1379 if (acs_res->link_id != -1) {
1380 hapd = hostapd_mld_get_link_bss(hapd, acs_res->link_id);
1381 if (!hapd) {
1382 wpa_printf(MSG_ERROR,
1383 "MLD: Failed to get link BSS for EVENT_ACS_CHANNEL_SELECTED link_id=%d",
1384 acs_res->link_id);
1385 return;
1386 }
1387 }
1388#endif /* CONFIG_IEEE80211BE */
1389
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001390 if (hapd->iconf->channel) {
1391 wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
1392 hapd->iconf->channel);
1393 return;
1394 }
1395
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001396 hapd->iface->freq = acs_res->pri_freq;
1397
Dmitry Shmidtb1e52102015-05-29 12:36:29 -07001398 if (!hapd->iface->current_mode) {
1399 for (i = 0; i < hapd->iface->num_hw_features; i++) {
1400 struct hostapd_hw_modes *mode =
1401 &hapd->iface->hw_features[i];
1402
1403 if (mode->mode == acs_res->hw_mode) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001404 if (hapd->iface->freq > 0 &&
1405 !hw_get_chan(mode->mode,
1406 hapd->iface->freq,
1407 hapd->iface->hw_features,
1408 hapd->iface->num_hw_features))
1409 continue;
Dmitry Shmidtb1e52102015-05-29 12:36:29 -07001410 hapd->iface->current_mode = mode;
1411 break;
1412 }
1413 }
1414 if (!hapd->iface->current_mode) {
1415 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
1416 HOSTAPD_LEVEL_WARNING,
1417 "driver selected to bad hw_mode");
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001418 err = 1;
1419 goto out;
Dmitry Shmidtb1e52102015-05-29 12:36:29 -07001420 }
1421 }
1422
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001423 if (!acs_res->pri_freq) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001424 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
1425 HOSTAPD_LEVEL_WARNING,
1426 "driver switched to bad channel");
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001427 err = 1;
1428 goto out;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001429 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001430 pri_chan = hw_get_channel_freq(hapd->iface->current_mode->mode,
1431 acs_res->pri_freq, NULL,
1432 hapd->iface->hw_features,
1433 hapd->iface->num_hw_features);
1434 if (!pri_chan) {
1435 wpa_printf(MSG_ERROR,
1436 "ACS: Could not determine primary channel number from pri_freq %u",
1437 acs_res->pri_freq);
1438 err = 1;
1439 goto out;
1440 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001441
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001442 hapd->iconf->channel = pri_chan->chan;
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07001443 hapd->iconf->acs = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001444
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001445 if (acs_res->sec_freq == 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001446 hapd->iconf->secondary_channel = 0;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001447 else if (acs_res->sec_freq < acs_res->pri_freq)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001448 hapd->iconf->secondary_channel = -1;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001449 else if (acs_res->sec_freq > acs_res->pri_freq)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001450 hapd->iconf->secondary_channel = 1;
1451 else {
1452 wpa_printf(MSG_ERROR, "Invalid secondary channel!");
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001453 err = 1;
1454 goto out;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001455 }
1456
Hai Shalomfdcde762020-04-02 11:19:20 -07001457 hapd->iconf->edmg_channel = acs_res->edmg_channel;
1458
Hai Shalom81f62d82019-07-22 12:10:00 -07001459 if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07001460 /* set defaults for backwards compatibility */
Hai Shalom81f62d82019-07-22 12:10:00 -07001461 hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
1462 hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0);
Sunil8cd6f4d2022-06-28 18:40:46 +00001463 hostapd_set_oper_chwidth(hapd->iconf, CONF_OPER_CHWIDTH_USE_HT);
Hai Shalomfdcde762020-04-02 11:19:20 -07001464 if (acs_res->ch_width == 40) {
1465 if (is_6ghz_freq(acs_res->pri_freq))
1466 hostapd_set_oper_centr_freq_seg0_idx(
1467 hapd->iconf,
1468 acs_res->vht_seg0_center_ch);
1469 } else if (acs_res->ch_width == 80) {
Hai Shalom81f62d82019-07-22 12:10:00 -07001470 hostapd_set_oper_centr_freq_seg0_idx(
1471 hapd->iconf, acs_res->vht_seg0_center_ch);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07001472 if (acs_res->vht_seg1_center_ch == 0) {
Sunil8cd6f4d2022-06-28 18:40:46 +00001473 hostapd_set_oper_chwidth(
1474 hapd->iconf, CONF_OPER_CHWIDTH_80MHZ);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07001475 } else {
Sunil8cd6f4d2022-06-28 18:40:46 +00001476 hostapd_set_oper_chwidth(
1477 hapd->iconf,
1478 CONF_OPER_CHWIDTH_80P80MHZ);
Hai Shalom81f62d82019-07-22 12:10:00 -07001479 hostapd_set_oper_centr_freq_seg1_idx(
1480 hapd->iconf,
1481 acs_res->vht_seg1_center_ch);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07001482 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001483 } else if (acs_res->ch_width == 160) {
Sunil8cd6f4d2022-06-28 18:40:46 +00001484 hostapd_set_oper_chwidth(hapd->iconf,
1485 CONF_OPER_CHWIDTH_160MHZ);
Hai Shalomfdcde762020-04-02 11:19:20 -07001486 hostapd_set_oper_centr_freq_seg0_idx(
1487 hapd->iconf, acs_res->vht_seg1_center_ch);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07001488 }
1489 }
1490
Sunil8cd6f4d2022-06-28 18:40:46 +00001491#ifdef CONFIG_IEEE80211BE
1492 if (hapd->iface->conf->ieee80211be && acs_res->ch_width == 320) {
1493 hostapd_set_oper_chwidth(hapd->iconf, CONF_OPER_CHWIDTH_320MHZ);
1494 hostapd_set_oper_centr_freq_seg0_idx(
1495 hapd->iconf, acs_res->vht_seg1_center_ch);
1496 hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
1497 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001498
1499 if (hapd->iface->conf->ieee80211be && acs_res->puncture_bitmap)
1500 hapd->iconf->punct_bitmap = acs_res->puncture_bitmap;
Sunil8cd6f4d2022-06-28 18:40:46 +00001501#endif /* CONFIG_IEEE80211BE */
1502
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001503out:
1504 ret = hostapd_acs_completed(hapd->iface, err);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001505 if (ret) {
1506 wpa_printf(MSG_ERROR,
1507 "ACS: Possibly channel configuration is invalid");
1508 }
1509}
1510#endif /* CONFIG_ACS */
1511
1512
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001513int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
Dmitry Shmidt04949592012-07-19 12:16:46 -07001514 const u8 *bssid, const u8 *ie, size_t ie_len,
1515 int ssi_signal)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001516{
1517 size_t i;
1518 int ret = 0;
1519
1520 if (sa == NULL || ie == NULL)
1521 return -1;
1522
1523 random_add_randomness(sa, ETH_ALEN);
1524 for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
1525 if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
Dmitry Shmidt04949592012-07-19 12:16:46 -07001526 sa, da, bssid, ie, ie_len,
1527 ssi_signal) > 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001528 ret = 1;
1529 break;
1530 }
1531 }
1532 return ret;
1533}
1534
1535
1536#ifdef HOSTAPD
1537
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001538#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001539static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
1540 const u8 *bssid,
1541 u16 auth_transaction, u16 status,
1542 const u8 *ies, size_t ies_len)
1543{
1544 struct hostapd_data *hapd = ctx;
1545 struct sta_info *sta;
1546
1547 sta = ap_get_sta(hapd, dst);
1548 if (sta == NULL)
1549 return;
1550
1551 hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
1552 HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
1553 sta->flags |= WLAN_STA_AUTH;
1554
1555 hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
1556}
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001557#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001558
1559
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001560#ifdef CONFIG_FILS
1561static void hostapd_notify_auth_fils_finish(struct hostapd_data *hapd,
1562 struct sta_info *sta, u16 resp,
1563 struct wpabuf *data, int pub)
1564{
1565 if (resp == WLAN_STATUS_SUCCESS) {
1566 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1567 HOSTAPD_LEVEL_DEBUG, "authentication OK (FILS)");
1568 sta->flags |= WLAN_STA_AUTH;
1569 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
1570 sta->auth_alg = WLAN_AUTH_FILS_SK;
1571 mlme_authenticate_indication(hapd, sta);
1572 } else {
1573 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1574 HOSTAPD_LEVEL_DEBUG,
1575 "authentication failed (FILS)");
1576 }
1577
1578 hostapd_sta_auth(hapd, sta->addr, 2, resp,
1579 data ? wpabuf_head(data) : NULL,
1580 data ? wpabuf_len(data) : 0);
1581 wpabuf_free(data);
1582}
1583#endif /* CONFIG_FILS */
1584
1585
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001586static void hostapd_notif_auth(struct hostapd_data *hapd,
1587 struct auth_info *rx_auth)
1588{
1589 struct sta_info *sta;
1590 u16 status = WLAN_STATUS_SUCCESS;
1591 u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
1592 size_t resp_ies_len = 0;
1593
1594 sta = ap_get_sta(hapd, rx_auth->peer);
1595 if (!sta) {
1596 sta = ap_sta_add(hapd, rx_auth->peer);
1597 if (sta == NULL) {
Dmitry Shmidt4b060592013-04-29 16:42:49 -07001598 status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001599 goto fail;
1600 }
1601 }
1602 sta->flags &= ~WLAN_STA_PREAUTH;
1603 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001604#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001605 if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
1606 sta->auth_alg = WLAN_AUTH_FT;
1607 if (sta->wpa_sm == NULL)
1608 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001609 sta->addr, NULL);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001610 if (sta->wpa_sm == NULL) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001611 wpa_printf(MSG_DEBUG,
1612 "FT: Failed to initialize WPA state machine");
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001613 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1614 goto fail;
1615 }
1616 wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
1617 rx_auth->auth_transaction, rx_auth->ies,
1618 rx_auth->ies_len,
1619 hostapd_notify_auth_ft_finish, hapd);
1620 return;
1621 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001622#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001623
1624#ifdef CONFIG_FILS
1625 if (rx_auth->auth_type == WLAN_AUTH_FILS_SK) {
1626 sta->auth_alg = WLAN_AUTH_FILS_SK;
1627 handle_auth_fils(hapd, sta, rx_auth->ies, rx_auth->ies_len,
1628 rx_auth->auth_type, rx_auth->auth_transaction,
1629 rx_auth->status_code,
1630 hostapd_notify_auth_fils_finish);
1631 return;
1632 }
1633#endif /* CONFIG_FILS */
1634
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001635fail:
1636 hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
1637 status, resp_ies, resp_ies_len);
1638}
1639
1640
Hai Shalom021b0b52019-04-10 11:17:58 -07001641#ifndef NEED_AP_MLME
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001642static void hostapd_action_rx(struct hostapd_data *hapd,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001643 struct rx_mgmt *drv_mgmt)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001644{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001645 struct ieee80211_mgmt *mgmt;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001646 struct sta_info *sta;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001647 size_t plen __maybe_unused;
1648 u16 fc;
Hai Shalom74f70d42019-02-11 14:42:39 -08001649 u8 *action __maybe_unused;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001650
Hai Shalom74f70d42019-02-11 14:42:39 -08001651 if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001652 return;
1653
Hai Shalom021b0b52019-04-10 11:17:58 -07001654 plen = drv_mgmt->frame_len - IEEE80211_HDRLEN;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001655
1656 mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
1657 fc = le_to_host16(mgmt->frame_control);
1658 if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
1659 return; /* handled by the driver */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001660
Hai Shalom74f70d42019-02-11 14:42:39 -08001661 action = (u8 *) &mgmt->u.action.u;
1662 wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
1663 " da " MACSTR " plen %d",
1664 mgmt->u.action.category, *action,
1665 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001666
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001667 sta = ap_get_sta(hapd, mgmt->sa);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001668 if (sta == NULL) {
1669 wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
1670 return;
1671 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001672#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001673 if (mgmt->u.action.category == WLAN_ACTION_FT) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001674 wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, plen);
1675 return;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001676 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001677#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom021b0b52019-04-10 11:17:58 -07001678 if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) {
Hai Shalom74f70d42019-02-11 14:42:39 -08001679 ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07001680 return;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001681 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001682#ifdef CONFIG_WNM_AP
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001683 if (mgmt->u.action.category == WLAN_ACTION_WNM) {
1684 ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07001685 return;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001686 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001687#endif /* CONFIG_WNM_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001688#ifdef CONFIG_FST
1689 if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) {
1690 fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len);
1691 return;
1692 }
1693#endif /* CONFIG_FST */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001694#ifdef CONFIG_DPP
Hai Shalom021b0b52019-04-10 11:17:58 -07001695 if (plen >= 2 + 4 &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001696 mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001697 mgmt->u.action.u.vs_public_action.action ==
1698 WLAN_PA_VENDOR_SPECIFIC &&
1699 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
1700 OUI_WFA &&
1701 mgmt->u.action.u.vs_public_action.variable[0] ==
1702 DPP_OUI_TYPE) {
1703 const u8 *pos, *end;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001704
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001705 pos = mgmt->u.action.u.vs_public_action.oui;
1706 end = drv_mgmt->frame + drv_mgmt->frame_len;
1707 hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
1708 drv_mgmt->freq);
1709 return;
1710 }
1711#endif /* CONFIG_DPP */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001712#ifdef CONFIG_NAN_USD
1713 if (mgmt->u.action.category == WLAN_ACTION_PUBLIC && plen >= 5 &&
1714 mgmt->u.action.u.vs_public_action.action ==
1715 WLAN_PA_VENDOR_SPECIFIC &&
1716 WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
1717 OUI_WFA &&
1718 mgmt->u.action.u.vs_public_action.variable[0] == NAN_OUI_TYPE) {
1719 const u8 *pos, *end;
1720
1721 pos = mgmt->u.action.u.vs_public_action.variable;
1722 end = drv_mgmt->frame + drv_mgmt->frame_len;
1723 pos++;
1724 hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, drv_mgmt->freq,
1725 pos, end - pos);
1726 return;
1727 }
1728#endif /* CONFIG_NAN_USD */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001729}
Hai Shalom021b0b52019-04-10 11:17:58 -07001730#endif /* NEED_AP_MLME */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001731
1732
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001733#ifdef NEED_AP_MLME
1734
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001735static struct hostapd_data *
1736switch_link_hapd(struct hostapd_data *hapd, int link_id)
1737{
1738#ifdef CONFIG_IEEE80211BE
1739 if (hapd->conf->mld_ap && link_id >= 0) {
1740 struct hostapd_data *link_bss;
1741
1742 link_bss = hostapd_mld_get_link_bss(hapd, link_id);
1743 if (link_bss)
1744 return link_bss;
1745 }
1746#endif /* CONFIG_IEEE80211BE */
1747
1748 return hapd;
1749}
1750
1751
Sunil Ravi99c035e2024-07-12 01:42:03 +00001752static struct hostapd_data *
1753switch_link_scan(struct hostapd_data *hapd, u64 scan_cookie)
1754{
1755#ifdef CONFIG_IEEE80211BE
1756 if (hapd->conf->mld_ap && scan_cookie != 0) {
1757 unsigned int i;
1758
1759 for (i = 0; i < hapd->iface->interfaces->count; i++) {
1760 struct hostapd_iface *h;
1761 struct hostapd_data *h_hapd;
1762
1763 h = hapd->iface->interfaces->iface[i];
1764 h_hapd = h->bss[0];
1765 if (!hostapd_is_ml_partner(hapd, h_hapd))
1766 continue;
1767
1768 if (h_hapd->scan_cookie == scan_cookie) {
1769 h_hapd->scan_cookie = 0;
1770 return h_hapd;
1771 }
1772 }
1773 }
1774#endif /* CONFIG_IEEE80211BE */
1775
1776 return hapd;
1777}
1778
1779
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001780#define HAPD_BROADCAST ((struct hostapd_data *) -1)
1781
1782static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
1783 const u8 *bssid)
1784{
1785 size_t i;
1786
1787 if (bssid == NULL)
1788 return NULL;
1789 if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
1790 bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
1791 return HAPD_BROADCAST;
1792
1793 for (i = 0; i < iface->num_bss; i++) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001794 if (ether_addr_equal(bssid, iface->bss[i]->own_addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001795 return iface->bss[i];
1796 }
1797
1798 return NULL;
1799}
1800
1801
1802static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001803 const u8 *bssid, const u8 *addr,
1804 int wds)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001805{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001806 hapd = get_hapd_bssid(hapd->iface, bssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001807 if (hapd == NULL || hapd == HAPD_BROADCAST)
1808 return;
1809
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001810 ieee802_11_rx_from_unknown(hapd, addr, wds);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001811}
1812
1813
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001814static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001815{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001816 struct hostapd_iface *iface;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001817 const struct ieee80211_hdr *hdr;
1818 const u8 *bssid;
1819 struct hostapd_frame_info fi;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001820 int ret;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001821 bool is_mld = false;
1822
1823 hapd = switch_link_hapd(hapd, rx_mgmt->link_id);
1824 iface = hapd->iface;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001825
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08001826#ifdef CONFIG_TESTING_OPTIONS
1827 if (hapd->ext_mgmt_frame_handling) {
1828 size_t hex_len = 2 * rx_mgmt->frame_len + 1;
1829 char *hex = os_malloc(hex_len);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001830
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08001831 if (hex) {
1832 wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame,
1833 rx_mgmt->frame_len);
1834 wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex);
1835 os_free(hex);
1836 }
1837 return 1;
1838 }
1839#endif /* CONFIG_TESTING_OPTIONS */
1840
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001841 hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
1842 bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
1843 if (bssid == NULL)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001844 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001845
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001846#ifdef CONFIG_IEEE80211BE
1847 if (hapd->conf->mld_ap &&
Sunil Ravi99c035e2024-07-12 01:42:03 +00001848 ether_addr_equal(hapd->mld->mld_addr, bssid))
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001849 is_mld = true;
1850#endif /* CONFIG_IEEE80211BE */
1851
1852 if (!is_mld)
1853 hapd = get_hapd_bssid(iface, bssid);
1854
1855 if (!hapd) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001856 u16 fc = le_to_host16(hdr->frame_control);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001857
1858 /*
1859 * Drop frames to unknown BSSIDs except for Beacon frames which
1860 * could be used to update neighbor information.
1861 */
1862 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
1863 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
1864 hapd = iface->bss[0];
1865 else
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001866 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001867 }
1868
1869 os_memset(&fi, 0, sizeof(fi));
Roshan Pius3a1667e2018-07-03 15:17:14 -07001870 fi.freq = rx_mgmt->freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001871 fi.datarate = rx_mgmt->datarate;
1872 fi.ssi_signal = rx_mgmt->ssi_signal;
1873
1874 if (hapd == HAPD_BROADCAST) {
1875 size_t i;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001876
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001877 ret = 0;
1878 for (i = 0; i < iface->num_bss; i++) {
Dmitry Shmidt98660862014-03-11 17:26:21 -07001879 /* if bss is set, driver will call this function for
1880 * each bss individually. */
1881 if (rx_mgmt->drv_priv &&
1882 (iface->bss[i]->drv_priv != rx_mgmt->drv_priv))
1883 continue;
1884
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001885 if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
1886 rx_mgmt->frame_len, &fi) > 0)
1887 ret = 1;
1888 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001889 } else
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001890 ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len,
1891 &fi);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001892
1893 random_add_randomness(&fi, sizeof(fi));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001894
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001895 return ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07001896}
1897
1898
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001899static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001900 size_t len, u16 stype, int ok, int link_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001901{
1902 struct ieee80211_hdr *hdr;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001903 struct hostapd_data *orig_hapd, *tmp_hapd;
1904
1905#ifdef CONFIG_IEEE80211BE
1906 if (hapd->conf->mld_ap && link_id != -1) {
1907 tmp_hapd = hostapd_mld_get_link_bss(hapd, link_id);
1908 if (tmp_hapd)
1909 hapd = tmp_hapd;
1910 }
1911#endif /* CONFIG_IEEE80211BE */
1912 orig_hapd = hapd;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001913
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001914 hdr = (struct ieee80211_hdr *) buf;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001915 tmp_hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
1916 if (tmp_hapd) {
1917 hapd = tmp_hapd;
1918#ifdef CONFIG_IEEE80211BE
1919 } else if (hapd->conf->mld_ap &&
Sunil Ravi99c035e2024-07-12 01:42:03 +00001920 ether_addr_equal(hapd->mld->mld_addr,
1921 get_hdr_bssid(hdr, len))) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001922 /* AP MLD address match - use hapd pointer as-is */
1923#endif /* CONFIG_IEEE80211BE */
1924 } else {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001925 return;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001926 }
1927
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001928 if (hapd == HAPD_BROADCAST) {
1929 if (stype != WLAN_FC_STYPE_ACTION || len <= 25 ||
1930 buf[24] != WLAN_ACTION_PUBLIC)
1931 return;
1932 hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2);
1933 if (!hapd || hapd == HAPD_BROADCAST)
1934 return;
1935 /*
1936 * Allow processing of TX status for a Public Action frame that
1937 * used wildcard BBSID.
1938 */
1939 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001940 ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
1941}
1942
1943#endif /* NEED_AP_MLME */
1944
1945
1946static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
1947{
1948 struct sta_info *sta = ap_get_sta(hapd, addr);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001949
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001950 if (sta)
1951 return 0;
1952
1953 wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
1954 " - adding a new STA", MAC2STR(addr));
1955 sta = ap_sta_add(hapd, addr);
1956 if (sta) {
1957 hostapd_new_assoc_sta(hapd, sta, 0);
1958 } else {
1959 wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
1960 MAC2STR(addr));
1961 return -1;
1962 }
1963
1964 return 0;
1965}
1966
1967
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001968static struct hostapd_data * hostapd_find_by_sta(struct hostapd_iface *iface,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001969 const u8 *src, bool rsn)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001970{
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001971 struct sta_info *sta;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001972 unsigned int j;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001973
1974 for (j = 0; j < iface->num_bss; j++) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001975 sta = ap_get_sta(iface->bss[j], src);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001976 if (sta && (sta->flags & WLAN_STA_ASSOC) &&
1977 (!rsn || sta->wpa_sm))
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001978 return iface->bss[j];
1979 }
1980
1981 return NULL;
1982}
1983
1984
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001985#ifdef CONFIG_IEEE80211BE
1986static bool search_mld_sta(struct hostapd_data **p_hapd, const u8 *src)
1987{
1988 struct hostapd_data *hapd = *p_hapd;
1989 unsigned int i;
1990
1991 /* Search for STA on other MLO BSSs */
1992 for (i = 0; i < hapd->iface->interfaces->count; i++) {
1993 struct hostapd_iface *h =
1994 hapd->iface->interfaces->iface[i];
1995 struct hostapd_data *h_hapd = h->bss[0];
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001996
Sunil Ravi99c035e2024-07-12 01:42:03 +00001997 if (!hostapd_is_ml_partner(h_hapd, hapd))
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001998 continue;
1999
2000 h_hapd = hostapd_find_by_sta(h, src, false);
2001 if (h_hapd) {
2002 struct sta_info *sta = ap_get_sta(h_hapd, src);
2003
2004 if (sta && sta->mld_info.mld_sta &&
2005 sta->mld_assoc_link_id != h_hapd->mld_link_id)
2006 continue;
2007 *p_hapd = h_hapd;
2008 return true;
2009 }
2010 }
2011
2012 return false;
2013}
2014#endif /* CONFIG_IEEE80211BE */
2015
2016
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002017static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
2018 const u8 *data, size_t data_len,
2019 enum frame_encryption encrypted,
2020 int link_id)
2021{
2022 struct hostapd_data *orig_hapd = hapd;
2023
2024#ifdef CONFIG_IEEE80211BE
2025 if (link_id != -1) {
2026 struct hostapd_data *h_hapd;
2027
2028 hapd = switch_link_hapd(hapd, link_id);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002029 h_hapd = hostapd_find_by_sta(hapd->iface, src, true);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002030 if (!h_hapd)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002031 h_hapd = hostapd_find_by_sta(orig_hapd->iface, src,
2032 true);
2033 if (!h_hapd)
2034 h_hapd = hostapd_find_by_sta(hapd->iface, src, false);
2035 if (!h_hapd)
2036 h_hapd = hostapd_find_by_sta(orig_hapd->iface, src,
2037 false);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002038 if (h_hapd)
2039 hapd = h_hapd;
2040 } else if (hapd->conf->mld_ap) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002041 search_mld_sta(&hapd, src);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002042 } else {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002043 hapd = hostapd_find_by_sta(hapd->iface, src, false);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002044 }
2045#else /* CONFIG_IEEE80211BE */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002046 hapd = hostapd_find_by_sta(hapd->iface, src, false);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002047#endif /* CONFIG_IEEE80211BE */
2048
2049 if (!hapd) {
2050 /* WLAN cases need to have an existing association, but non-WLAN
2051 * cases (mainly, wired IEEE 802.1X) need to be able to process
2052 * EAPOL frames from new devices that do not yet have a STA
2053 * entry and as such, do not get a match in
2054 * hostapd_find_by_sta(). */
2055 wpa_printf(MSG_DEBUG,
2056 "No STA-specific hostapd instance for EAPOL RX found - fall back to initial context");
2057 hapd = orig_hapd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002058 }
2059
Sunil8cd6f4d2022-06-28 18:40:46 +00002060 ieee802_1x_receive(hapd, src, data, data_len, encrypted);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002061}
2062
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08002063#endif /* HOSTAPD */
2064
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002065
Hai Shalomfdcde762020-04-02 11:19:20 -07002066static struct hostapd_channel_data *
2067hostapd_get_mode_chan(struct hostapd_hw_modes *mode, unsigned int freq)
2068{
2069 int i;
2070 struct hostapd_channel_data *chan;
2071
2072 for (i = 0; i < mode->num_channels; i++) {
2073 chan = &mode->channels[i];
2074 if ((unsigned int) chan->freq == freq)
2075 return chan;
2076 }
2077
2078 return NULL;
2079}
2080
2081
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002082static struct hostapd_channel_data * hostapd_get_mode_channel(
2083 struct hostapd_iface *iface, unsigned int freq)
2084{
2085 int i;
2086 struct hostapd_channel_data *chan;
2087
Hai Shalomfdcde762020-04-02 11:19:20 -07002088 for (i = 0; i < iface->num_hw_features; i++) {
2089 if (hostapd_hw_skip_mode(iface, &iface->hw_features[i]))
2090 continue;
2091 chan = hostapd_get_mode_chan(&iface->hw_features[i], freq);
2092 if (chan)
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002093 return chan;
2094 }
2095
2096 return NULL;
2097}
2098
2099
2100static void hostapd_update_nf(struct hostapd_iface *iface,
2101 struct hostapd_channel_data *chan,
2102 struct freq_survey *survey)
2103{
2104 if (!iface->chans_surveyed) {
2105 chan->min_nf = survey->nf;
2106 iface->lowest_nf = survey->nf;
2107 } else {
2108 if (dl_list_empty(&chan->survey_list))
2109 chan->min_nf = survey->nf;
2110 else if (survey->nf < chan->min_nf)
2111 chan->min_nf = survey->nf;
2112 if (survey->nf < iface->lowest_nf)
2113 iface->lowest_nf = survey->nf;
2114 }
2115}
2116
2117
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002118static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
2119 struct survey_results *survey_res)
2120{
2121 struct hostapd_channel_data *chan;
2122 struct freq_survey *survey;
2123 u64 divisor, dividend;
2124
2125 survey = dl_list_first(&survey_res->survey_list, struct freq_survey,
2126 list);
2127 if (!survey || !survey->freq)
2128 return;
2129
2130 chan = hostapd_get_mode_channel(iface, survey->freq);
2131 if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
2132 return;
2133
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002134 wpa_printf(MSG_DEBUG,
2135 "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002136 survey->freq,
2137 (unsigned long int) survey->channel_time,
2138 (unsigned long int) survey->channel_time_busy);
2139
2140 if (survey->channel_time > iface->last_channel_time &&
2141 survey->channel_time > survey->channel_time_busy) {
2142 dividend = survey->channel_time_busy -
2143 iface->last_channel_time_busy;
2144 divisor = survey->channel_time - iface->last_channel_time;
2145
2146 iface->channel_utilization = dividend * 255 / divisor;
2147 wpa_printf(MSG_DEBUG, "Channel Utilization: %d",
2148 iface->channel_utilization);
2149 }
2150 iface->last_channel_time = survey->channel_time;
2151 iface->last_channel_time_busy = survey->channel_time_busy;
2152}
2153
2154
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08002155void hostapd_event_get_survey(struct hostapd_iface *iface,
2156 struct survey_results *survey_results)
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002157{
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002158 struct freq_survey *survey, *tmp;
2159 struct hostapd_channel_data *chan;
2160
2161 if (dl_list_empty(&survey_results->survey_list)) {
2162 wpa_printf(MSG_DEBUG, "No survey data received");
2163 return;
2164 }
2165
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002166 if (survey_results->freq_filter) {
2167 hostapd_single_channel_get_survey(iface, survey_results);
2168 return;
2169 }
2170
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002171 dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
2172 struct freq_survey, list) {
2173 chan = hostapd_get_mode_channel(iface, survey->freq);
2174 if (!chan)
2175 continue;
2176 if (chan->flag & HOSTAPD_CHAN_DISABLED)
2177 continue;
2178
2179 dl_list_del(&survey->list);
2180 dl_list_add_tail(&chan->survey_list, &survey->list);
2181
2182 hostapd_update_nf(iface, chan, survey);
2183
2184 iface->chans_surveyed++;
2185 }
2186}
2187
2188
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08002189#ifdef HOSTAPD
Dmitry Shmidt051af732013-10-22 13:52:46 -07002190#ifdef NEED_AP_MLME
2191
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07002192static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
2193{
2194 wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped",
2195 hapd->conf->iface);
2196
2197 if (hapd->csa_in_progress) {
2198 wpa_printf(MSG_INFO, "CSA failed (%s was stopped)",
2199 hapd->conf->iface);
2200 hostapd_switch_channel_fallback(hapd->iface,
2201 &hapd->cs_freq_params);
2202 }
Yu Ouyang378d3c42021-08-20 17:31:08 +08002203
2204 // inform framework that interface is unavailable
2205 hostapd_disable_iface(hapd->iface);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07002206}
2207
2208
Dmitry Shmidt051af732013-10-22 13:52:46 -07002209static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
2210 struct dfs_event *radar)
2211{
2212 wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002213 hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled,
Dmitry Shmidt051af732013-10-22 13:52:46 -07002214 radar->chan_offset, radar->chan_width,
2215 radar->cf1, radar->cf2);
2216}
2217
2218
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002219static void hostapd_event_dfs_pre_cac_expired(struct hostapd_data *hapd,
2220 struct dfs_event *radar)
2221{
2222 wpa_printf(MSG_DEBUG, "DFS Pre-CAC expired on %d MHz", radar->freq);
2223 hostapd_dfs_pre_cac_expired(hapd->iface, radar->freq, radar->ht_enabled,
2224 radar->chan_offset, radar->chan_width,
2225 radar->cf1, radar->cf2);
2226}
2227
2228
Dmitry Shmidt051af732013-10-22 13:52:46 -07002229static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd,
2230 struct dfs_event *radar)
2231{
2232 wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002233 hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled,
Dmitry Shmidt051af732013-10-22 13:52:46 -07002234 radar->chan_offset, radar->chan_width,
2235 radar->cf1, radar->cf2);
2236}
2237
2238
2239static void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd,
2240 struct dfs_event *radar)
2241{
2242 wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002243 hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled,
Dmitry Shmidt051af732013-10-22 13:52:46 -07002244 radar->chan_offset, radar->chan_width,
2245 radar->cf1, radar->cf2);
2246}
2247
2248
2249static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd,
2250 struct dfs_event *radar)
2251{
2252 wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002253 hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled,
Dmitry Shmidt051af732013-10-22 13:52:46 -07002254 radar->chan_offset, radar->chan_width,
2255 radar->cf1, radar->cf2);
2256}
2257
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08002258
2259static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
2260 struct dfs_event *radar)
2261{
2262 wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq);
2263 hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled,
2264 radar->chan_offset, radar->chan_width,
2265 radar->cf1, radar->cf2);
2266}
2267
Dmitry Shmidt051af732013-10-22 13:52:46 -07002268#endif /* NEED_AP_MLME */
2269
2270
Roshan Pius3a1667e2018-07-03 15:17:14 -07002271static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd,
2272 int istatus,
2273 const char *ifname,
2274 const u8 *addr)
2275{
2276 struct sta_info *sta = ap_get_sta(hapd, addr);
2277
2278 if (sta) {
2279 os_free(sta->ifname_wds);
2280 if (istatus == INTERFACE_ADDED)
2281 sta->ifname_wds = os_strdup(ifname);
2282 else
2283 sta->ifname_wds = NULL;
2284 }
2285
2286 wpa_msg(hapd->msg_ctx, MSG_INFO, "%sifname=%s sta_addr=" MACSTR,
2287 istatus == INTERFACE_ADDED ?
2288 WDS_STA_INTERFACE_ADDED : WDS_STA_INTERFACE_REMOVED,
2289 ifname, MAC2STR(addr));
2290}
2291
2292
Hai Shalom81f62d82019-07-22 12:10:00 -07002293#ifdef CONFIG_OWE
2294static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd,
2295 const u8 *peer, const u8 *ie,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002296 size_t ie_len, const u8 *link_addr)
Hai Shalom81f62d82019-07-22 12:10:00 -07002297{
2298 u16 status;
2299 struct sta_info *sta;
2300 struct ieee802_11_elems elems;
2301
2302 if (!hapd || !hapd->wpa_auth) {
2303 wpa_printf(MSG_DEBUG, "OWE: Invalid hapd context");
2304 return -1;
2305 }
2306 if (!peer) {
2307 wpa_printf(MSG_DEBUG, "OWE: Peer unknown");
2308 return -1;
2309 }
2310 if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) {
2311 wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured");
2312 status = WLAN_STATUS_AKMP_NOT_VALID;
2313 goto err;
2314 }
2315 if (ieee802_11_parse_elems(ie, ie_len, &elems, 1) == ParseFailed) {
2316 wpa_printf(MSG_DEBUG, "OWE: Failed to parse OWE IE for "
2317 MACSTR, MAC2STR(peer));
2318 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
2319 goto err;
2320 }
2321 status = owe_validate_request(hapd, peer, elems.rsn_ie,
2322 elems.rsn_ie_len,
2323 elems.owe_dh, elems.owe_dh_len);
2324 if (status != WLAN_STATUS_SUCCESS)
2325 goto err;
2326
2327 sta = ap_get_sta(hapd, peer);
2328 if (sta) {
2329 ap_sta_no_session_timeout(hapd, sta);
2330 accounting_sta_stop(hapd, sta);
2331
2332 /*
2333 * Make sure that the previously registered inactivity timer
2334 * will not remove the STA immediately.
2335 */
2336 sta->timeout_next = STA_NULLFUNC;
2337 } else {
2338 sta = ap_sta_add(hapd, peer);
2339 if (!sta) {
2340 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
2341 goto err;
2342 }
2343 }
2344 sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
2345
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002346#ifdef CONFIG_IEEE80211BE
2347 if (link_addr) {
2348 struct mld_info *info = &sta->mld_info;
2349 u8 link_id = hapd->mld_link_id;
2350
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002351 ap_sta_set_mld(sta, true);
2352 sta->mld_assoc_link_id = link_id;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002353 os_memcpy(info->common_info.mld_addr, peer, ETH_ALEN);
2354 info->links[link_id].valid = true;
2355 os_memcpy(info->links[link_id].local_addr, hapd->own_addr,
2356 ETH_ALEN);
2357 os_memcpy(info->links[link_id].peer_addr, link_addr, ETH_ALEN);
2358 }
2359#endif /* CONFIG_IEEE80211BE */
2360
Hai Shalom81f62d82019-07-22 12:10:00 -07002361 status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie,
2362 elems.rsn_ie_len, elems.owe_dh,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002363 elems.owe_dh_len, link_addr);
Hai Shalom81f62d82019-07-22 12:10:00 -07002364 if (status != WLAN_STATUS_SUCCESS)
2365 ap_free_sta(hapd, sta);
2366
2367 return 0;
2368err:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002369 hostapd_drv_update_dh_ie(hapd, link_addr ? link_addr : peer, status,
2370 NULL, 0);
Hai Shalom81f62d82019-07-22 12:10:00 -07002371 return 0;
2372}
2373#endif /* CONFIG_OWE */
2374
2375
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002376void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
2377 union wpa_event_data *data)
2378{
2379 struct hostapd_data *hapd = ctx;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002380 struct sta_info *sta;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002381#ifndef CONFIG_NO_STDOUT_DEBUG
2382 int level = MSG_DEBUG;
2383
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002384 if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002385 data->rx_mgmt.frame_len >= 24) {
2386 const struct ieee80211_hdr *hdr;
2387 u16 fc;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002388
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002389 hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
2390 fc = le_to_host16(hdr->frame_control);
2391 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
2392 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
2393 level = MSG_EXCESSIVE;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07002394 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
2395 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ)
2396 level = MSG_EXCESSIVE;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002397 }
2398
2399 wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
2400 event_to_string(event), event);
2401#endif /* CONFIG_NO_STDOUT_DEBUG */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002402
2403 switch (event) {
2404 case EVENT_MICHAEL_MIC_FAILURE:
2405 michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
2406 break;
2407 case EVENT_SCAN_RESULTS:
Sunil Ravi99c035e2024-07-12 01:42:03 +00002408#ifdef NEED_AP_MLME
2409 if (data)
2410 hapd = switch_link_scan(hapd,
2411 data->scan_info.scan_cookie);
2412#endif /* NEED_AP_MLME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002413 if (hapd->iface->scan_cb)
2414 hapd->iface->scan_cb(hapd->iface);
Sunil Ravi99c035e2024-07-12 01:42:03 +00002415#ifdef CONFIG_IEEE80211BE
2416 if (!hapd->iface->scan_cb && hapd->conf->mld_ap) {
2417 /* Other links may be waiting for HT scan result */
2418 unsigned int i;
2419
2420 for (i = 0; i < hapd->iface->interfaces->count; i++) {
2421 struct hostapd_iface *h =
2422 hapd->iface->interfaces->iface[i];
2423 struct hostapd_data *h_hapd = h->bss[0];
2424
2425 if (hostapd_is_ml_partner(hapd, h_hapd) &&
2426 h_hapd->iface->scan_cb)
2427 h_hapd->iface->scan_cb(h_hapd->iface);
2428 }
2429 }
2430#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002431 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002432 case EVENT_WPS_BUTTON_PUSHED:
2433 hostapd_wps_button_pushed(hapd, NULL);
2434 break;
2435#ifdef NEED_AP_MLME
2436 case EVENT_TX_STATUS:
2437 switch (data->tx_status.type) {
2438 case WLAN_FC_TYPE_MGMT:
2439 hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
2440 data->tx_status.data_len,
2441 data->tx_status.stype,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002442 data->tx_status.ack,
2443 data->tx_status.link_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002444 break;
2445 case WLAN_FC_TYPE_DATA:
2446 hostapd_tx_status(hapd, data->tx_status.dst,
2447 data->tx_status.data,
2448 data->tx_status.data_len,
2449 data->tx_status.ack);
2450 break;
2451 }
2452 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002453 case EVENT_EAPOL_TX_STATUS:
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002454 hapd = switch_link_hapd(hapd, data->eapol_tx_status.link_id);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002455 hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
2456 data->eapol_tx_status.data,
2457 data->eapol_tx_status.data_len,
2458 data->eapol_tx_status.ack);
2459 break;
2460 case EVENT_DRIVER_CLIENT_POLL_OK:
2461 hostapd_client_poll_ok(hapd, data->client_poll.addr);
2462 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002463 case EVENT_RX_FROM_UNKNOWN:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002464 hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
2465 data->rx_from_unknown.addr,
2466 data->rx_from_unknown.wds);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002467 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002468#endif /* NEED_AP_MLME */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002469 case EVENT_RX_MGMT:
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002470 if (!data->rx_mgmt.frame)
2471 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002472#ifdef NEED_AP_MLME
Hai Shalom021b0b52019-04-10 11:17:58 -07002473 hostapd_mgmt_rx(hapd, &data->rx_mgmt);
2474#else /* NEED_AP_MLME */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002475 hostapd_action_rx(hapd, &data->rx_mgmt);
Hai Shalom021b0b52019-04-10 11:17:58 -07002476#endif /* NEED_AP_MLME */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002477 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002478 case EVENT_RX_PROBE_REQ:
2479 if (data->rx_probe_req.sa == NULL ||
2480 data->rx_probe_req.ie == NULL)
2481 break;
2482 hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002483 data->rx_probe_req.da,
2484 data->rx_probe_req.bssid,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002485 data->rx_probe_req.ie,
Dmitry Shmidt04949592012-07-19 12:16:46 -07002486 data->rx_probe_req.ie_len,
2487 data->rx_probe_req.ssi_signal);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002488 break;
2489 case EVENT_NEW_STA:
2490 hostapd_event_new_sta(hapd, data->new_sta.addr);
2491 break;
2492 case EVENT_EAPOL_RX:
2493 hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
2494 data->eapol_rx.data,
Sunil8cd6f4d2022-06-28 18:40:46 +00002495 data->eapol_rx.data_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002496 data->eapol_rx.encrypted,
2497 data->eapol_rx.link_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002498 break;
2499 case EVENT_ASSOC:
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002500 if (!data)
2501 return;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002502#ifdef CONFIG_IEEE80211BE
2503 if (data->assoc_info.assoc_link_id != -1) {
2504 hapd = hostapd_mld_get_link_bss(
2505 hapd, data->assoc_info.assoc_link_id);
2506 if (!hapd) {
2507 wpa_printf(MSG_ERROR,
2508 "MLD: Failed to get link BSS for EVENT_ASSOC");
2509 return;
2510 }
2511 }
2512#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002513 hostapd_notif_assoc(hapd, data->assoc_info.addr,
2514 data->assoc_info.req_ies,
2515 data->assoc_info.req_ies_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002516 data->assoc_info.resp_ies,
2517 data->assoc_info.resp_ies_len,
2518 data->assoc_info.link_addr,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002519 data->assoc_info.reassoc);
2520 break;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002521 case EVENT_PORT_AUTHORIZED:
2522 /* Port authorized event for an associated STA */
2523 sta = ap_get_sta(hapd, data->port_authorized.sta_addr);
2524 if (sta)
2525 ap_sta_set_authorized(hapd, sta, 1);
2526 else
2527 wpa_printf(MSG_DEBUG,
2528 "No STA info matching port authorized event found");
2529 break;
Hai Shalom81f62d82019-07-22 12:10:00 -07002530#ifdef CONFIG_OWE
2531 case EVENT_UPDATE_DH:
2532 if (!data)
2533 return;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002534#ifdef CONFIG_IEEE80211BE
2535 if (data->update_dh.assoc_link_id != -1) {
2536 hapd = hostapd_mld_get_link_bss(
2537 hapd, data->update_dh.assoc_link_id);
2538 if (!hapd) {
2539 wpa_printf(MSG_ERROR,
2540 "MLD: Failed to get link BSS for EVENT_UPDATE_DH assoc_link_id=%d",
2541 data->update_dh.assoc_link_id);
2542 return;
2543 }
2544 }
2545#endif /* CONFIG_IEEE80211BE */
Hai Shalom81f62d82019-07-22 12:10:00 -07002546 hostapd_notif_update_dh_ie(hapd, data->update_dh.peer,
2547 data->update_dh.ie,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002548 data->update_dh.ie_len,
2549 data->update_dh.link_addr);
Hai Shalom81f62d82019-07-22 12:10:00 -07002550 break;
2551#endif /* CONFIG_OWE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002552 case EVENT_DISASSOC:
2553 if (data)
2554 hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
2555 break;
2556 case EVENT_DEAUTH:
2557 if (data)
2558 hostapd_notif_disassoc(hapd, data->deauth_info.addr);
2559 break;
2560 case EVENT_STATION_LOW_ACK:
2561 if (!data)
2562 break;
2563 hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
2564 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002565 case EVENT_AUTH:
2566 hostapd_notif_auth(hapd, &data->auth);
2567 break;
Hai Shalom81f62d82019-07-22 12:10:00 -07002568 case EVENT_CH_SWITCH_STARTED:
Dmitry Shmidt04949592012-07-19 12:16:46 -07002569 case EVENT_CH_SWITCH:
2570 if (!data)
2571 break;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002572#ifdef CONFIG_IEEE80211BE
2573 if (data->ch_switch.link_id != -1) {
2574 hapd = hostapd_mld_get_link_bss(
2575 hapd, data->ch_switch.link_id);
2576 if (!hapd) {
2577 wpa_printf(MSG_ERROR,
2578 "MLD: Failed to get link (ID %d) BSS for EVENT_CH_SWITCH/EVENT_CH_SWITCH_STARTED",
2579 data->ch_switch.link_id);
2580 break;
2581 }
2582 }
2583#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt04949592012-07-19 12:16:46 -07002584 hostapd_event_ch_switch(hapd, data->ch_switch.freq,
2585 data->ch_switch.ht_enabled,
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08002586 data->ch_switch.ch_offset,
2587 data->ch_switch.ch_width,
2588 data->ch_switch.cf1,
Hai Shalom81f62d82019-07-22 12:10:00 -07002589 data->ch_switch.cf2,
Sunil Ravi036cec52023-03-29 11:35:17 -07002590 data->ch_switch.punct_bitmap,
Hai Shalom81f62d82019-07-22 12:10:00 -07002591 event == EVENT_CH_SWITCH);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002592 break;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002593 case EVENT_CONNECT_FAILED_REASON:
2594 if (!data)
2595 break;
2596 hostapd_event_connect_failed_reason(
2597 hapd, data->connect_failed_reason.addr,
2598 data->connect_failed_reason.code);
2599 break;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002600 case EVENT_SURVEY:
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08002601 hostapd_event_get_survey(hapd->iface, &data->survey_results);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002602 break;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002603#ifdef NEED_AP_MLME
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07002604 case EVENT_INTERFACE_UNAVAILABLE:
2605 hostapd_event_iface_unavailable(hapd);
2606 break;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002607 case EVENT_DFS_RADAR_DETECTED:
2608 if (!data)
2609 break;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002610 hapd = switch_link_hapd(hapd, data->dfs_event.link_id);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002611 hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
2612 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002613 case EVENT_DFS_PRE_CAC_EXPIRED:
2614 if (!data)
2615 break;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002616 hapd = switch_link_hapd(hapd, data->dfs_event.link_id);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002617 hostapd_event_dfs_pre_cac_expired(hapd, &data->dfs_event);
2618 break;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002619 case EVENT_DFS_CAC_FINISHED:
2620 if (!data)
2621 break;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002622 hapd = switch_link_hapd(hapd, data->dfs_event.link_id);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002623 hostapd_event_dfs_cac_finished(hapd, &data->dfs_event);
2624 break;
2625 case EVENT_DFS_CAC_ABORTED:
2626 if (!data)
2627 break;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002628 hapd = switch_link_hapd(hapd, data->dfs_event.link_id);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002629 hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event);
2630 break;
2631 case EVENT_DFS_NOP_FINISHED:
2632 if (!data)
2633 break;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002634 hapd = switch_link_hapd(hapd, data->dfs_event.link_id);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002635 hostapd_event_dfs_nop_finished(hapd, &data->dfs_event);
2636 break;
2637 case EVENT_CHANNEL_LIST_CHANGED:
2638 /* channel list changed (regulatory?), update channel list */
2639 /* TODO: check this. hostapd_get_hw_features() initializes
2640 * too much stuff. */
2641 /* hostapd_get_hw_features(hapd->iface); */
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002642 hostapd_channel_list_updated(
2643 hapd->iface, data->channel_list_changed.initiator);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002644 break;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08002645 case EVENT_DFS_CAC_STARTED:
2646 if (!data)
2647 break;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002648 hapd = switch_link_hapd(hapd, data->dfs_event.link_id);
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08002649 hostapd_event_dfs_cac_started(hapd, &data->dfs_event);
2650 break;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002651#endif /* NEED_AP_MLME */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002652 case EVENT_INTERFACE_ENABLED:
2653 wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002654 if (hapd->disabled && hapd->started) {
2655 hapd->disabled = 0;
2656 /*
2657 * Try to re-enable interface if the driver stopped it
2658 * when the interface got disabled.
2659 */
Hai Shalomce48b4a2018-09-05 11:41:35 -07002660 if (hapd->wpa_auth)
2661 wpa_auth_reconfig_group_keys(hapd->wpa_auth);
2662 else
2663 hostapd_reconfig_encryption(hapd);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002664 hapd->reenable_beacon = 1;
2665 ieee802_11_set_beacon(hapd);
Hai Shalom74f70d42019-02-11 14:42:39 -08002666#ifdef NEED_AP_MLME
2667 } else if (hapd->disabled && hapd->iface->cac_started) {
2668 wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC");
2669 hostapd_handle_dfs(hapd->iface);
2670#endif /* NEED_AP_MLME */
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002671 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002672 break;
2673 case EVENT_INTERFACE_DISABLED:
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002674 hostapd_free_stas(hapd);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002675 wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002676 hapd->disabled = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002677 break;
2678#ifdef CONFIG_ACS
2679 case EVENT_ACS_CHANNEL_SELECTED:
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07002680 hostapd_acs_channel_selected(hapd,
2681 &data->acs_selected_channels);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002682 break;
2683#endif /* CONFIG_ACS */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002684 case EVENT_STATION_OPMODE_CHANGED:
2685 hostapd_event_sta_opmode_changed(hapd, data->sta_opmode.addr,
2686 data->sta_opmode.smps_mode,
2687 data->sta_opmode.chan_width,
2688 data->sta_opmode.rx_nss);
2689 break;
2690 case EVENT_WDS_STA_INTERFACE_STATUS:
2691 hostapd_event_wds_sta_interface_status(
2692 hapd, data->wds_sta_interface.istatus,
2693 data->wds_sta_interface.ifname,
2694 data->wds_sta_interface.sta_addr);
2695 break;
Sunil Ravia04bd252022-05-02 22:54:18 -07002696#ifdef CONFIG_IEEE80211AX
2697 case EVENT_BSS_COLOR_COLLISION:
2698 /* The BSS color is shared amongst all BBSs on a specific phy.
2699 * Therefore we always start the color change on the primary
2700 * BSS. */
2701 wpa_printf(MSG_DEBUG, "BSS color collision on %s",
2702 hapd->conf->iface);
2703 hostapd_switch_color(hapd->iface->bss[0],
2704 data->bss_color_collision.bitmap);
2705 break;
2706 case EVENT_CCA_STARTED_NOTIFY:
2707 wpa_printf(MSG_DEBUG, "CCA started on on %s",
2708 hapd->conf->iface);
2709 break;
2710 case EVENT_CCA_ABORTED_NOTIFY:
2711 wpa_printf(MSG_DEBUG, "CCA aborted on on %s",
2712 hapd->conf->iface);
2713 hostapd_cleanup_cca_params(hapd);
2714 break;
2715 case EVENT_CCA_NOTIFY:
2716 wpa_printf(MSG_DEBUG, "CCA finished on on %s",
2717 hapd->conf->iface);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002718 if (hapd->cca_color)
2719 hapd->iface->conf->he_op.he_bss_color = hapd->cca_color;
Sunil Ravia04bd252022-05-02 22:54:18 -07002720 hostapd_cleanup_cca_params(hapd);
2721 break;
2722#endif /* CONFIG_IEEE80211AX */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002723 default:
2724 wpa_printf(MSG_DEBUG, "Unknown event %d", event);
2725 break;
2726 }
2727}
2728
Dmitry Shmidte4663042016-04-04 10:07:49 -07002729
2730void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
2731 union wpa_event_data *data)
2732{
2733 struct hapd_interfaces *interfaces = ctx;
2734 struct hostapd_data *hapd;
2735
2736 if (event != EVENT_INTERFACE_STATUS)
2737 return;
2738
2739 hapd = hostapd_get_iface(interfaces, data->interface_status.ifname);
2740 if (hapd && hapd->driver && hapd->driver->get_ifindex &&
2741 hapd->drv_priv) {
2742 unsigned int ifindex;
2743
2744 ifindex = hapd->driver->get_ifindex(hapd->drv_priv);
2745 if (ifindex != data->interface_status.ifindex) {
2746 wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
2747 "interface status ifindex %d mismatch (%d)",
2748 ifindex, data->interface_status.ifindex);
2749 return;
2750 }
2751 }
2752 if (hapd)
2753 wpa_supplicant_event(hapd, event, data);
2754}
2755
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002756#endif /* HOSTAPD */