13ff40c12SJohn Marino /*
23ff40c12SJohn Marino * hostapd / Callback functions for driver wrappers
33ff40c12SJohn Marino * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
73ff40c12SJohn Marino */
83ff40c12SJohn Marino
93ff40c12SJohn Marino #include "utils/includes.h"
103ff40c12SJohn Marino
113ff40c12SJohn Marino #include "utils/common.h"
12*a1157835SDaniel Fojt #include "utils/eloop.h"
133ff40c12SJohn Marino #include "radius/radius.h"
143ff40c12SJohn Marino #include "drivers/driver.h"
153ff40c12SJohn Marino #include "common/ieee802_11_defs.h"
163ff40c12SJohn Marino #include "common/ieee802_11_common.h"
173ff40c12SJohn Marino #include "common/wpa_ctrl.h"
18*a1157835SDaniel Fojt #include "common/dpp.h"
193ff40c12SJohn Marino #include "crypto/random.h"
203ff40c12SJohn Marino #include "p2p/p2p.h"
213ff40c12SJohn Marino #include "wps/wps.h"
22*a1157835SDaniel Fojt #include "fst/fst.h"
233ff40c12SJohn Marino #include "wnm_ap.h"
243ff40c12SJohn Marino #include "hostapd.h"
253ff40c12SJohn Marino #include "ieee802_11.h"
26*a1157835SDaniel Fojt #include "ieee802_11_auth.h"
273ff40c12SJohn Marino #include "sta_info.h"
283ff40c12SJohn Marino #include "accounting.h"
293ff40c12SJohn Marino #include "tkip_countermeasures.h"
303ff40c12SJohn Marino #include "ieee802_1x.h"
313ff40c12SJohn Marino #include "wpa_auth.h"
323ff40c12SJohn Marino #include "wps_hostapd.h"
333ff40c12SJohn Marino #include "ap_drv_ops.h"
343ff40c12SJohn Marino #include "ap_config.h"
35*a1157835SDaniel Fojt #include "ap_mlme.h"
363ff40c12SJohn Marino #include "hw_features.h"
373ff40c12SJohn Marino #include "dfs.h"
38*a1157835SDaniel Fojt #include "beacon.h"
39*a1157835SDaniel Fojt #include "mbo_ap.h"
40*a1157835SDaniel Fojt #include "dpp_hostapd.h"
41*a1157835SDaniel Fojt #include "fils_hlp.h"
42*a1157835SDaniel Fojt #include "neighbor_db.h"
43*a1157835SDaniel Fojt
44*a1157835SDaniel Fojt
45*a1157835SDaniel Fojt #ifdef CONFIG_FILS
hostapd_notify_assoc_fils_finish(struct hostapd_data * hapd,struct sta_info * sta)46*a1157835SDaniel Fojt void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
47*a1157835SDaniel Fojt struct sta_info *sta)
48*a1157835SDaniel Fojt {
49*a1157835SDaniel Fojt u16 reply_res = WLAN_STATUS_SUCCESS;
50*a1157835SDaniel Fojt struct ieee802_11_elems elems;
51*a1157835SDaniel Fojt u8 buf[IEEE80211_MAX_MMPDU_SIZE], *p = buf;
52*a1157835SDaniel Fojt int new_assoc;
53*a1157835SDaniel Fojt
54*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "%s FILS: Finish association with " MACSTR,
55*a1157835SDaniel Fojt __func__, MAC2STR(sta->addr));
56*a1157835SDaniel Fojt eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
57*a1157835SDaniel Fojt if (!sta->fils_pending_assoc_req)
58*a1157835SDaniel Fojt return;
59*a1157835SDaniel Fojt
60*a1157835SDaniel Fojt ieee802_11_parse_elems(sta->fils_pending_assoc_req,
61*a1157835SDaniel Fojt sta->fils_pending_assoc_req_len, &elems, 0);
62*a1157835SDaniel Fojt if (!elems.fils_session) {
63*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "%s failed to find FILS Session element",
64*a1157835SDaniel Fojt __func__);
65*a1157835SDaniel Fojt return;
66*a1157835SDaniel Fojt }
67*a1157835SDaniel Fojt
68*a1157835SDaniel Fojt p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
69*a1157835SDaniel Fojt elems.fils_session,
70*a1157835SDaniel Fojt sta->fils_hlp_resp);
71*a1157835SDaniel Fojt
72*a1157835SDaniel Fojt reply_res = hostapd_sta_assoc(hapd, sta->addr,
73*a1157835SDaniel Fojt sta->fils_pending_assoc_is_reassoc,
74*a1157835SDaniel Fojt WLAN_STATUS_SUCCESS,
75*a1157835SDaniel Fojt buf, p - buf);
76*a1157835SDaniel Fojt ap_sta_set_authorized(hapd, sta, 1);
77*a1157835SDaniel Fojt new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
78*a1157835SDaniel Fojt sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
79*a1157835SDaniel Fojt sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
80*a1157835SDaniel Fojt hostapd_set_sta_flags(hapd, sta);
81*a1157835SDaniel Fojt wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
82*a1157835SDaniel Fojt ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
83*a1157835SDaniel Fojt hostapd_new_assoc_sta(hapd, sta, !new_assoc);
84*a1157835SDaniel Fojt os_free(sta->fils_pending_assoc_req);
85*a1157835SDaniel Fojt sta->fils_pending_assoc_req = NULL;
86*a1157835SDaniel Fojt sta->fils_pending_assoc_req_len = 0;
87*a1157835SDaniel Fojt wpabuf_free(sta->fils_hlp_resp);
88*a1157835SDaniel Fojt sta->fils_hlp_resp = NULL;
89*a1157835SDaniel Fojt wpabuf_free(sta->hlp_dhcp_discover);
90*a1157835SDaniel Fojt sta->hlp_dhcp_discover = NULL;
91*a1157835SDaniel Fojt fils_hlp_deinit(hapd);
92*a1157835SDaniel Fojt
93*a1157835SDaniel Fojt /*
94*a1157835SDaniel Fojt * Remove the station in case transmission of a success response fails
95*a1157835SDaniel Fojt * (the STA was added associated to the driver) or if the station was
96*a1157835SDaniel Fojt * previously added unassociated.
97*a1157835SDaniel Fojt */
98*a1157835SDaniel Fojt if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) {
99*a1157835SDaniel Fojt hostapd_drv_sta_remove(hapd, sta->addr);
100*a1157835SDaniel Fojt sta->added_unassoc = 0;
101*a1157835SDaniel Fojt }
102*a1157835SDaniel Fojt }
103*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
1043ff40c12SJohn Marino
1053ff40c12SJohn Marino
hostapd_notif_assoc(struct hostapd_data * hapd,const u8 * addr,const u8 * req_ies,size_t req_ies_len,int reassoc)1063ff40c12SJohn Marino int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
1073ff40c12SJohn Marino const u8 *req_ies, size_t req_ies_len, int reassoc)
1083ff40c12SJohn Marino {
1093ff40c12SJohn Marino struct sta_info *sta;
1103ff40c12SJohn Marino int new_assoc, res;
1113ff40c12SJohn Marino struct ieee802_11_elems elems;
1123ff40c12SJohn Marino const u8 *ie;
1133ff40c12SJohn Marino size_t ielen;
114*a1157835SDaniel Fojt #if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
1153ff40c12SJohn Marino u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
1163ff40c12SJohn Marino u8 *p = buf;
117*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */
1183ff40c12SJohn Marino u16 reason = WLAN_REASON_UNSPECIFIED;
1193ff40c12SJohn Marino u16 status = WLAN_STATUS_SUCCESS;
1203ff40c12SJohn Marino const u8 *p2p_dev_addr = NULL;
1213ff40c12SJohn Marino
1223ff40c12SJohn Marino if (addr == NULL) {
1233ff40c12SJohn Marino /*
1243ff40c12SJohn Marino * This could potentially happen with unexpected event from the
1253ff40c12SJohn Marino * driver wrapper. This was seen at least in one case where the
1263ff40c12SJohn Marino * driver ended up being set to station mode while hostapd was
1273ff40c12SJohn Marino * running, so better make sure we stop processing such an
1283ff40c12SJohn Marino * event here.
1293ff40c12SJohn Marino */
130*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
131*a1157835SDaniel Fojt "hostapd_notif_assoc: Skip event with no address");
1323ff40c12SJohn Marino return -1;
1333ff40c12SJohn Marino }
1343ff40c12SJohn Marino random_add_randomness(addr, ETH_ALEN);
1353ff40c12SJohn Marino
1363ff40c12SJohn Marino hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
1373ff40c12SJohn Marino HOSTAPD_LEVEL_INFO, "associated");
1383ff40c12SJohn Marino
1393ff40c12SJohn Marino ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
1403ff40c12SJohn Marino if (elems.wps_ie) {
1413ff40c12SJohn Marino ie = elems.wps_ie - 2;
1423ff40c12SJohn Marino ielen = elems.wps_ie_len + 2;
1433ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
1443ff40c12SJohn Marino } else if (elems.rsn_ie) {
1453ff40c12SJohn Marino ie = elems.rsn_ie - 2;
1463ff40c12SJohn Marino ielen = elems.rsn_ie_len + 2;
1473ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
1483ff40c12SJohn Marino } else if (elems.wpa_ie) {
1493ff40c12SJohn Marino ie = elems.wpa_ie - 2;
1503ff40c12SJohn Marino ielen = elems.wpa_ie_len + 2;
1513ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
152*a1157835SDaniel Fojt #ifdef CONFIG_HS20
153*a1157835SDaniel Fojt } else if (elems.osen) {
154*a1157835SDaniel Fojt ie = elems.osen - 2;
155*a1157835SDaniel Fojt ielen = elems.osen_len + 2;
156*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq");
157*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
1583ff40c12SJohn Marino } else {
1593ff40c12SJohn Marino ie = NULL;
1603ff40c12SJohn Marino ielen = 0;
161*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
162*a1157835SDaniel Fojt "STA did not include WPS/RSN/WPA IE in (Re)AssocReq");
1633ff40c12SJohn Marino }
1643ff40c12SJohn Marino
1653ff40c12SJohn Marino sta = ap_get_sta(hapd, addr);
1663ff40c12SJohn Marino if (sta) {
1673ff40c12SJohn Marino ap_sta_no_session_timeout(hapd, sta);
1683ff40c12SJohn Marino accounting_sta_stop(hapd, sta);
1693ff40c12SJohn Marino
1703ff40c12SJohn Marino /*
1713ff40c12SJohn Marino * Make sure that the previously registered inactivity timer
1723ff40c12SJohn Marino * will not remove the STA immediately.
1733ff40c12SJohn Marino */
1743ff40c12SJohn Marino sta->timeout_next = STA_NULLFUNC;
1753ff40c12SJohn Marino } else {
1763ff40c12SJohn Marino sta = ap_sta_add(hapd, addr);
1773ff40c12SJohn Marino if (sta == NULL) {
1783ff40c12SJohn Marino hostapd_drv_sta_disassoc(hapd, addr,
1793ff40c12SJohn Marino WLAN_REASON_DISASSOC_AP_BUSY);
1803ff40c12SJohn Marino return -1;
1813ff40c12SJohn Marino }
1823ff40c12SJohn Marino }
1833ff40c12SJohn Marino sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
1843ff40c12SJohn Marino
185*a1157835SDaniel Fojt /*
186*a1157835SDaniel Fojt * ACL configurations to the drivers (implementing AP SME and ACL
187*a1157835SDaniel Fojt * offload) without hostapd's knowledge, can result in a disconnection
188*a1157835SDaniel Fojt * though the driver accepts the connection. Skip the hostapd check for
189*a1157835SDaniel Fojt * ACL if the driver supports ACL offload to avoid potentially
190*a1157835SDaniel Fojt * conflicting ACL rules.
191*a1157835SDaniel Fojt */
192*a1157835SDaniel Fojt if (hapd->iface->drv_max_acl_mac_addrs == 0 &&
193*a1157835SDaniel Fojt hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) {
194*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect",
195*a1157835SDaniel Fojt MAC2STR(addr));
196*a1157835SDaniel Fojt reason = WLAN_REASON_UNSPECIFIED;
197*a1157835SDaniel Fojt goto fail;
198*a1157835SDaniel Fojt }
199*a1157835SDaniel Fojt
2003ff40c12SJohn Marino #ifdef CONFIG_P2P
2013ff40c12SJohn Marino if (elems.p2p) {
2023ff40c12SJohn Marino wpabuf_free(sta->p2p_ie);
2033ff40c12SJohn Marino sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
2043ff40c12SJohn Marino P2P_IE_VENDOR_TYPE);
2053ff40c12SJohn Marino if (sta->p2p_ie)
2063ff40c12SJohn Marino p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
2073ff40c12SJohn Marino }
2083ff40c12SJohn Marino #endif /* CONFIG_P2P */
2093ff40c12SJohn Marino
210*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211N
211*a1157835SDaniel Fojt #ifdef NEED_AP_MLME
212*a1157835SDaniel Fojt if (elems.ht_capabilities &&
213*a1157835SDaniel Fojt (hapd->iface->conf->ht_capab &
214*a1157835SDaniel Fojt HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
215*a1157835SDaniel Fojt struct ieee80211_ht_capabilities *ht_cap =
216*a1157835SDaniel Fojt (struct ieee80211_ht_capabilities *)
217*a1157835SDaniel Fojt elems.ht_capabilities;
218*a1157835SDaniel Fojt
219*a1157835SDaniel Fojt if (le_to_host16(ht_cap->ht_capabilities_info) &
220*a1157835SDaniel Fojt HT_CAP_INFO_40MHZ_INTOLERANT)
221*a1157835SDaniel Fojt ht40_intolerant_add(hapd->iface, sta);
222*a1157835SDaniel Fojt }
223*a1157835SDaniel Fojt #endif /* NEED_AP_MLME */
224*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211N */
225*a1157835SDaniel Fojt
2263ff40c12SJohn Marino #ifdef CONFIG_INTERWORKING
2273ff40c12SJohn Marino if (elems.ext_capab && elems.ext_capab_len > 4) {
2283ff40c12SJohn Marino if (elems.ext_capab[4] & 0x01)
2293ff40c12SJohn Marino sta->qos_map_enabled = 1;
2303ff40c12SJohn Marino }
2313ff40c12SJohn Marino #endif /* CONFIG_INTERWORKING */
2323ff40c12SJohn Marino
2333ff40c12SJohn Marino #ifdef CONFIG_HS20
2343ff40c12SJohn Marino wpabuf_free(sta->hs20_ie);
2353ff40c12SJohn Marino if (elems.hs20 && elems.hs20_len > 4) {
2363ff40c12SJohn Marino sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
2373ff40c12SJohn Marino elems.hs20_len - 4);
2383ff40c12SJohn Marino } else
2393ff40c12SJohn Marino sta->hs20_ie = NULL;
240*a1157835SDaniel Fojt
241*a1157835SDaniel Fojt wpabuf_free(sta->roaming_consortium);
242*a1157835SDaniel Fojt if (elems.roaming_cons_sel)
243*a1157835SDaniel Fojt sta->roaming_consortium = wpabuf_alloc_copy(
244*a1157835SDaniel Fojt elems.roaming_cons_sel + 4,
245*a1157835SDaniel Fojt elems.roaming_cons_sel_len - 4);
246*a1157835SDaniel Fojt else
247*a1157835SDaniel Fojt sta->roaming_consortium = NULL;
2483ff40c12SJohn Marino #endif /* CONFIG_HS20 */
2493ff40c12SJohn Marino
250*a1157835SDaniel Fojt #ifdef CONFIG_FST
251*a1157835SDaniel Fojt wpabuf_free(sta->mb_ies);
252*a1157835SDaniel Fojt if (hapd->iface->fst)
253*a1157835SDaniel Fojt sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
254*a1157835SDaniel Fojt else
255*a1157835SDaniel Fojt sta->mb_ies = NULL;
256*a1157835SDaniel Fojt #endif /* CONFIG_FST */
257*a1157835SDaniel Fojt
258*a1157835SDaniel Fojt mbo_ap_check_sta_assoc(hapd, sta, &elems);
259*a1157835SDaniel Fojt
260*a1157835SDaniel Fojt ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
261*a1157835SDaniel Fojt elems.supp_op_classes_len);
262*a1157835SDaniel Fojt
2633ff40c12SJohn Marino if (hapd->conf->wpa) {
2643ff40c12SJohn Marino if (ie == NULL || ielen == 0) {
2653ff40c12SJohn Marino #ifdef CONFIG_WPS
2663ff40c12SJohn Marino if (hapd->conf->wps_state) {
267*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
268*a1157835SDaniel Fojt "STA did not include WPA/RSN IE in (Re)Association Request - possible WPS use");
2693ff40c12SJohn Marino sta->flags |= WLAN_STA_MAYBE_WPS;
2703ff40c12SJohn Marino goto skip_wpa_check;
2713ff40c12SJohn Marino }
2723ff40c12SJohn Marino #endif /* CONFIG_WPS */
2733ff40c12SJohn Marino
2743ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
275*a1157835SDaniel Fojt reason = WLAN_REASON_INVALID_IE;
276*a1157835SDaniel Fojt status = WLAN_STATUS_INVALID_IE;
277*a1157835SDaniel Fojt goto fail;
2783ff40c12SJohn Marino }
2793ff40c12SJohn Marino #ifdef CONFIG_WPS
2803ff40c12SJohn Marino if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
2813ff40c12SJohn Marino os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
2823ff40c12SJohn Marino struct wpabuf *wps;
283*a1157835SDaniel Fojt
2843ff40c12SJohn Marino sta->flags |= WLAN_STA_WPS;
2853ff40c12SJohn Marino wps = ieee802_11_vendor_ie_concat(ie, ielen,
2863ff40c12SJohn Marino WPS_IE_VENDOR_TYPE);
2873ff40c12SJohn Marino if (wps) {
2883ff40c12SJohn Marino if (wps_is_20(wps)) {
289*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
290*a1157835SDaniel Fojt "WPS: STA supports WPS 2.0");
2913ff40c12SJohn Marino sta->flags |= WLAN_STA_WPS2;
2923ff40c12SJohn Marino }
2933ff40c12SJohn Marino wpabuf_free(wps);
2943ff40c12SJohn Marino }
2953ff40c12SJohn Marino goto skip_wpa_check;
2963ff40c12SJohn Marino }
2973ff40c12SJohn Marino #endif /* CONFIG_WPS */
2983ff40c12SJohn Marino
2993ff40c12SJohn Marino if (sta->wpa_sm == NULL)
3003ff40c12SJohn Marino sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
3013ff40c12SJohn Marino sta->addr,
3023ff40c12SJohn Marino p2p_dev_addr);
3033ff40c12SJohn Marino if (sta->wpa_sm == NULL) {
304*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
305*a1157835SDaniel Fojt "Failed to initialize WPA state machine");
3063ff40c12SJohn Marino return -1;
3073ff40c12SJohn Marino }
3083ff40c12SJohn Marino res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
309*a1157835SDaniel Fojt hapd->iface->freq,
3103ff40c12SJohn Marino ie, ielen,
311*a1157835SDaniel Fojt elems.mdie, elems.mdie_len,
312*a1157835SDaniel Fojt elems.owe_dh, elems.owe_dh_len);
3133ff40c12SJohn Marino if (res != WPA_IE_OK) {
314*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
315*a1157835SDaniel Fojt "WPA/RSN information element rejected? (res %u)",
316*a1157835SDaniel Fojt res);
3173ff40c12SJohn Marino wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
3183ff40c12SJohn Marino if (res == WPA_INVALID_GROUP) {
3193ff40c12SJohn Marino reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
3203ff40c12SJohn Marino status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
3213ff40c12SJohn Marino } else if (res == WPA_INVALID_PAIRWISE) {
3223ff40c12SJohn Marino reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
3233ff40c12SJohn Marino status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
3243ff40c12SJohn Marino } else if (res == WPA_INVALID_AKMP) {
3253ff40c12SJohn Marino reason = WLAN_REASON_AKMP_NOT_VALID;
3263ff40c12SJohn Marino status = WLAN_STATUS_AKMP_NOT_VALID;
3273ff40c12SJohn Marino }
3283ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
3293ff40c12SJohn Marino else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
3303ff40c12SJohn Marino reason = WLAN_REASON_INVALID_IE;
3313ff40c12SJohn Marino status = WLAN_STATUS_INVALID_IE;
3323ff40c12SJohn Marino } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
333*a1157835SDaniel Fojt reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
334*a1157835SDaniel Fojt status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
3353ff40c12SJohn Marino }
3363ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
3373ff40c12SJohn Marino else {
3383ff40c12SJohn Marino reason = WLAN_REASON_INVALID_IE;
3393ff40c12SJohn Marino status = WLAN_STATUS_INVALID_IE;
3403ff40c12SJohn Marino }
3413ff40c12SJohn Marino goto fail;
3423ff40c12SJohn Marino }
3433ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
344*a1157835SDaniel Fojt if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
345*a1157835SDaniel Fojt (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
346*a1157835SDaniel Fojt !sta->sa_query_timed_out &&
3473ff40c12SJohn Marino sta->sa_query_count > 0)
3483ff40c12SJohn Marino ap_check_sa_query_timeout(hapd, sta);
349*a1157835SDaniel Fojt if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
350*a1157835SDaniel Fojt (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
351*a1157835SDaniel Fojt !sta->sa_query_timed_out &&
3523ff40c12SJohn Marino (sta->auth_alg != WLAN_AUTH_FT)) {
3533ff40c12SJohn Marino /*
3543ff40c12SJohn Marino * STA has already been associated with MFP and SA
3553ff40c12SJohn Marino * Query timeout has not been reached. Reject the
3563ff40c12SJohn Marino * association attempt temporarily and start SA Query,
3573ff40c12SJohn Marino * if one is not pending.
3583ff40c12SJohn Marino */
3593ff40c12SJohn Marino
3603ff40c12SJohn Marino if (sta->sa_query_count == 0)
3613ff40c12SJohn Marino ap_sta_start_sa_query(hapd, sta);
3623ff40c12SJohn Marino
3633ff40c12SJohn Marino status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
3643ff40c12SJohn Marino
3653ff40c12SJohn Marino p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
3663ff40c12SJohn Marino
3673ff40c12SJohn Marino hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
3683ff40c12SJohn Marino p - buf);
3693ff40c12SJohn Marino return 0;
3703ff40c12SJohn Marino }
3713ff40c12SJohn Marino
3723ff40c12SJohn Marino if (wpa_auth_uses_mfp(sta->wpa_sm))
3733ff40c12SJohn Marino sta->flags |= WLAN_STA_MFP;
3743ff40c12SJohn Marino else
3753ff40c12SJohn Marino sta->flags &= ~WLAN_STA_MFP;
3763ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
3773ff40c12SJohn Marino
378*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
3793ff40c12SJohn Marino if (sta->auth_alg == WLAN_AUTH_FT) {
3803ff40c12SJohn Marino status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
3813ff40c12SJohn Marino req_ies_len);
3823ff40c12SJohn Marino if (status != WLAN_STATUS_SUCCESS) {
3833ff40c12SJohn Marino if (status == WLAN_STATUS_INVALID_PMKID)
3843ff40c12SJohn Marino reason = WLAN_REASON_INVALID_IE;
3853ff40c12SJohn Marino if (status == WLAN_STATUS_INVALID_MDIE)
3863ff40c12SJohn Marino reason = WLAN_REASON_INVALID_IE;
3873ff40c12SJohn Marino if (status == WLAN_STATUS_INVALID_FTIE)
3883ff40c12SJohn Marino reason = WLAN_REASON_INVALID_IE;
3893ff40c12SJohn Marino goto fail;
3903ff40c12SJohn Marino }
3913ff40c12SJohn Marino }
392*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
3933ff40c12SJohn Marino } else if (hapd->conf->wps_state) {
3943ff40c12SJohn Marino #ifdef CONFIG_WPS
3953ff40c12SJohn Marino struct wpabuf *wps;
396*a1157835SDaniel Fojt
3973ff40c12SJohn Marino if (req_ies)
3983ff40c12SJohn Marino wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
3993ff40c12SJohn Marino WPS_IE_VENDOR_TYPE);
4003ff40c12SJohn Marino else
4013ff40c12SJohn Marino wps = NULL;
4023ff40c12SJohn Marino #ifdef CONFIG_WPS_STRICT
4033ff40c12SJohn Marino if (wps && wps_validate_assoc_req(wps) < 0) {
4043ff40c12SJohn Marino reason = WLAN_REASON_INVALID_IE;
4053ff40c12SJohn Marino status = WLAN_STATUS_INVALID_IE;
4063ff40c12SJohn Marino wpabuf_free(wps);
4073ff40c12SJohn Marino goto fail;
4083ff40c12SJohn Marino }
4093ff40c12SJohn Marino #endif /* CONFIG_WPS_STRICT */
4103ff40c12SJohn Marino if (wps) {
4113ff40c12SJohn Marino sta->flags |= WLAN_STA_WPS;
4123ff40c12SJohn Marino if (wps_is_20(wps)) {
413*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
414*a1157835SDaniel Fojt "WPS: STA supports WPS 2.0");
4153ff40c12SJohn Marino sta->flags |= WLAN_STA_WPS2;
4163ff40c12SJohn Marino }
4173ff40c12SJohn Marino } else
4183ff40c12SJohn Marino sta->flags |= WLAN_STA_MAYBE_WPS;
4193ff40c12SJohn Marino wpabuf_free(wps);
4203ff40c12SJohn Marino #endif /* CONFIG_WPS */
421*a1157835SDaniel Fojt #ifdef CONFIG_HS20
422*a1157835SDaniel Fojt } else if (hapd->conf->osen) {
423*a1157835SDaniel Fojt if (elems.osen == NULL) {
424*a1157835SDaniel Fojt hostapd_logger(
425*a1157835SDaniel Fojt hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
426*a1157835SDaniel Fojt HOSTAPD_LEVEL_INFO,
427*a1157835SDaniel Fojt "No HS 2.0 OSEN element in association request");
428*a1157835SDaniel Fojt return WLAN_STATUS_INVALID_IE;
4293ff40c12SJohn Marino }
430*a1157835SDaniel Fojt
431*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
432*a1157835SDaniel Fojt if (sta->wpa_sm == NULL)
433*a1157835SDaniel Fojt sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
434*a1157835SDaniel Fojt sta->addr, NULL);
435*a1157835SDaniel Fojt if (sta->wpa_sm == NULL) {
436*a1157835SDaniel Fojt wpa_printf(MSG_WARNING,
437*a1157835SDaniel Fojt "Failed to initialize WPA state machine");
438*a1157835SDaniel Fojt return WLAN_STATUS_UNSPECIFIED_FAILURE;
439*a1157835SDaniel Fojt }
440*a1157835SDaniel Fojt if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
441*a1157835SDaniel Fojt elems.osen - 2, elems.osen_len + 2) < 0)
442*a1157835SDaniel Fojt return WLAN_STATUS_INVALID_IE;
443*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
444*a1157835SDaniel Fojt }
445*a1157835SDaniel Fojt
446*a1157835SDaniel Fojt #ifdef CONFIG_MBO
447*a1157835SDaniel Fojt if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
448*a1157835SDaniel Fojt elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
449*a1157835SDaniel Fojt hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
450*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
451*a1157835SDaniel Fojt "MBO: Reject WPA2 association without PMF");
452*a1157835SDaniel Fojt return WLAN_STATUS_UNSPECIFIED_FAILURE;
453*a1157835SDaniel Fojt }
454*a1157835SDaniel Fojt #endif /* CONFIG_MBO */
455*a1157835SDaniel Fojt
4563ff40c12SJohn Marino #ifdef CONFIG_WPS
4573ff40c12SJohn Marino skip_wpa_check:
4583ff40c12SJohn Marino #endif /* CONFIG_WPS */
4593ff40c12SJohn Marino
460*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
4613ff40c12SJohn Marino p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
4623ff40c12SJohn Marino sta->auth_alg, req_ies, req_ies_len);
463*a1157835SDaniel Fojt if (!p) {
464*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
465*a1157835SDaniel Fojt return WLAN_STATUS_UNSPECIFIED_FAILURE;
466*a1157835SDaniel Fojt }
467*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
4683ff40c12SJohn Marino
469*a1157835SDaniel Fojt #ifdef CONFIG_FILS
470*a1157835SDaniel Fojt if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
471*a1157835SDaniel Fojt sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
472*a1157835SDaniel Fojt sta->auth_alg == WLAN_AUTH_FILS_PK) {
473*a1157835SDaniel Fojt int delay_assoc = 0;
474*a1157835SDaniel Fojt
475*a1157835SDaniel Fojt if (!req_ies)
476*a1157835SDaniel Fojt return WLAN_STATUS_UNSPECIFIED_FAILURE;
477*a1157835SDaniel Fojt
478*a1157835SDaniel Fojt if (!wpa_fils_validate_fils_session(sta->wpa_sm, req_ies,
479*a1157835SDaniel Fojt req_ies_len,
480*a1157835SDaniel Fojt sta->fils_session)) {
481*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
482*a1157835SDaniel Fojt "FILS: Session validation failed");
483*a1157835SDaniel Fojt return WLAN_STATUS_UNSPECIFIED_FAILURE;
484*a1157835SDaniel Fojt }
485*a1157835SDaniel Fojt
486*a1157835SDaniel Fojt res = wpa_fils_validate_key_confirm(sta->wpa_sm, req_ies,
487*a1157835SDaniel Fojt req_ies_len);
488*a1157835SDaniel Fojt if (res < 0) {
489*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
490*a1157835SDaniel Fojt "FILS: Key Confirm validation failed");
491*a1157835SDaniel Fojt return WLAN_STATUS_UNSPECIFIED_FAILURE;
492*a1157835SDaniel Fojt }
493*a1157835SDaniel Fojt
494*a1157835SDaniel Fojt if (fils_process_hlp(hapd, sta, req_ies, req_ies_len) > 0) {
495*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
496*a1157835SDaniel Fojt "FILS: Delaying Assoc Response (HLP)");
497*a1157835SDaniel Fojt delay_assoc = 1;
498*a1157835SDaniel Fojt } else {
499*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
500*a1157835SDaniel Fojt "FILS: Going ahead with Assoc Response (no HLP)");
501*a1157835SDaniel Fojt }
502*a1157835SDaniel Fojt
503*a1157835SDaniel Fojt if (sta) {
504*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "FILS: HLP callback cleanup");
505*a1157835SDaniel Fojt eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
506*a1157835SDaniel Fojt os_free(sta->fils_pending_assoc_req);
507*a1157835SDaniel Fojt sta->fils_pending_assoc_req = NULL;
508*a1157835SDaniel Fojt sta->fils_pending_assoc_req_len = 0;
509*a1157835SDaniel Fojt wpabuf_free(sta->fils_hlp_resp);
510*a1157835SDaniel Fojt sta->fils_hlp_resp = NULL;
511*a1157835SDaniel Fojt sta->fils_drv_assoc_finish = 0;
512*a1157835SDaniel Fojt }
513*a1157835SDaniel Fojt
514*a1157835SDaniel Fojt if (sta && delay_assoc && status == WLAN_STATUS_SUCCESS) {
515*a1157835SDaniel Fojt u8 *req_tmp;
516*a1157835SDaniel Fojt
517*a1157835SDaniel Fojt req_tmp = os_malloc(req_ies_len);
518*a1157835SDaniel Fojt if (!req_tmp) {
519*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
520*a1157835SDaniel Fojt "FILS: buffer allocation failed for assoc req");
521*a1157835SDaniel Fojt goto fail;
522*a1157835SDaniel Fojt }
523*a1157835SDaniel Fojt os_memcpy(req_tmp, req_ies, req_ies_len);
524*a1157835SDaniel Fojt sta->fils_pending_assoc_req = req_tmp;
525*a1157835SDaniel Fojt sta->fils_pending_assoc_req_len = req_ies_len;
526*a1157835SDaniel Fojt sta->fils_pending_assoc_is_reassoc = reassoc;
527*a1157835SDaniel Fojt sta->fils_drv_assoc_finish = 1;
528*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
529*a1157835SDaniel Fojt "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
530*a1157835SDaniel Fojt MACSTR, MAC2STR(sta->addr));
531*a1157835SDaniel Fojt eloop_register_timeout(
532*a1157835SDaniel Fojt 0, hapd->conf->fils_hlp_wait_time * 1024,
533*a1157835SDaniel Fojt fils_hlp_timeout, hapd, sta);
534*a1157835SDaniel Fojt return 0;
535*a1157835SDaniel Fojt }
536*a1157835SDaniel Fojt p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
537*a1157835SDaniel Fojt elems.fils_session,
538*a1157835SDaniel Fojt sta->fils_hlp_resp);
539*a1157835SDaniel Fojt wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)",
540*a1157835SDaniel Fojt buf, p - buf);
541*a1157835SDaniel Fojt }
542*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
543*a1157835SDaniel Fojt
544*a1157835SDaniel Fojt #ifdef CONFIG_OWE
545*a1157835SDaniel Fojt if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
546*a1157835SDaniel Fojt wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
547*a1157835SDaniel Fojt elems.owe_dh) {
548*a1157835SDaniel Fojt u8 *npos;
549*a1157835SDaniel Fojt
550*a1157835SDaniel Fojt npos = owe_assoc_req_process(hapd, sta,
551*a1157835SDaniel Fojt elems.owe_dh, elems.owe_dh_len,
552*a1157835SDaniel Fojt p, sizeof(buf) - (p - buf),
553*a1157835SDaniel Fojt &reason);
554*a1157835SDaniel Fojt if (npos)
555*a1157835SDaniel Fojt p = npos;
556*a1157835SDaniel Fojt if (!npos &&
557*a1157835SDaniel Fojt reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
558*a1157835SDaniel Fojt status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
559*a1157835SDaniel Fojt hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
560*a1157835SDaniel Fojt p - buf);
561*a1157835SDaniel Fojt return 0;
562*a1157835SDaniel Fojt }
563*a1157835SDaniel Fojt
564*a1157835SDaniel Fojt if (!npos || reason != WLAN_STATUS_SUCCESS)
565*a1157835SDaniel Fojt goto fail;
566*a1157835SDaniel Fojt }
567*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
568*a1157835SDaniel Fojt
569*a1157835SDaniel Fojt #ifdef CONFIG_DPP2
570*a1157835SDaniel Fojt dpp_pfs_free(sta->dpp_pfs);
571*a1157835SDaniel Fojt sta->dpp_pfs = NULL;
572*a1157835SDaniel Fojt
573*a1157835SDaniel Fojt if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
574*a1157835SDaniel Fojt hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
575*a1157835SDaniel Fojt wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
576*a1157835SDaniel Fojt elems.owe_dh) {
577*a1157835SDaniel Fojt sta->dpp_pfs = dpp_pfs_init(
578*a1157835SDaniel Fojt wpabuf_head(hapd->conf->dpp_netaccesskey),
579*a1157835SDaniel Fojt wpabuf_len(hapd->conf->dpp_netaccesskey));
580*a1157835SDaniel Fojt if (!sta->dpp_pfs) {
581*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
582*a1157835SDaniel Fojt "DPP: Could not initialize PFS");
583*a1157835SDaniel Fojt /* Try to continue without PFS */
584*a1157835SDaniel Fojt goto pfs_fail;
585*a1157835SDaniel Fojt }
586*a1157835SDaniel Fojt
587*a1157835SDaniel Fojt if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
588*a1157835SDaniel Fojt elems.owe_dh_len) < 0) {
589*a1157835SDaniel Fojt dpp_pfs_free(sta->dpp_pfs);
590*a1157835SDaniel Fojt sta->dpp_pfs = NULL;
591*a1157835SDaniel Fojt reason = WLAN_REASON_UNSPECIFIED;
592*a1157835SDaniel Fojt goto fail;
593*a1157835SDaniel Fojt }
594*a1157835SDaniel Fojt }
595*a1157835SDaniel Fojt
596*a1157835SDaniel Fojt wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
597*a1157835SDaniel Fojt sta->dpp_pfs->secret : NULL);
598*a1157835SDaniel Fojt pfs_fail:
599*a1157835SDaniel Fojt #endif /* CONFIG_DPP2 */
600*a1157835SDaniel Fojt
601*a1157835SDaniel Fojt #if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
6023ff40c12SJohn Marino hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
603*a1157835SDaniel Fojt
604*a1157835SDaniel Fojt if (sta->auth_alg == WLAN_AUTH_FT ||
605*a1157835SDaniel Fojt sta->auth_alg == WLAN_AUTH_FILS_SK ||
606*a1157835SDaniel Fojt sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
607*a1157835SDaniel Fojt sta->auth_alg == WLAN_AUTH_FILS_PK)
608*a1157835SDaniel Fojt ap_sta_set_authorized(hapd, sta, 1);
609*a1157835SDaniel Fojt #else /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
6103ff40c12SJohn Marino /* Keep compiler silent about unused variables */
6113ff40c12SJohn Marino if (status) {
6123ff40c12SJohn Marino }
613*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
6143ff40c12SJohn Marino
6153ff40c12SJohn Marino new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
6163ff40c12SJohn Marino sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
6173ff40c12SJohn Marino sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
6183ff40c12SJohn Marino
619*a1157835SDaniel Fojt hostapd_set_sta_flags(hapd, sta);
620*a1157835SDaniel Fojt
6213ff40c12SJohn Marino if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
6223ff40c12SJohn Marino wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
623*a1157835SDaniel Fojt #ifdef CONFIG_FILS
624*a1157835SDaniel Fojt else if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
625*a1157835SDaniel Fojt sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
626*a1157835SDaniel Fojt sta->auth_alg == WLAN_AUTH_FILS_PK)
627*a1157835SDaniel Fojt wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
628*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
6293ff40c12SJohn Marino else
6303ff40c12SJohn Marino wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
6313ff40c12SJohn Marino
6323ff40c12SJohn Marino hostapd_new_assoc_sta(hapd, sta, !new_assoc);
6333ff40c12SJohn Marino
6343ff40c12SJohn Marino ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
6353ff40c12SJohn Marino
6363ff40c12SJohn Marino #ifdef CONFIG_P2P
6373ff40c12SJohn Marino if (req_ies) {
6383ff40c12SJohn Marino p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
6393ff40c12SJohn Marino req_ies, req_ies_len);
6403ff40c12SJohn Marino }
6413ff40c12SJohn Marino #endif /* CONFIG_P2P */
6423ff40c12SJohn Marino
6433ff40c12SJohn Marino return 0;
6443ff40c12SJohn Marino
6453ff40c12SJohn Marino fail:
646*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
6473ff40c12SJohn Marino hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
648*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
6493ff40c12SJohn Marino hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
6503ff40c12SJohn Marino ap_free_sta(hapd, sta);
6513ff40c12SJohn Marino return -1;
6523ff40c12SJohn Marino }
6533ff40c12SJohn Marino
6543ff40c12SJohn Marino
hostapd_notif_disassoc(struct hostapd_data * hapd,const u8 * addr)6553ff40c12SJohn Marino void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
6563ff40c12SJohn Marino {
6573ff40c12SJohn Marino struct sta_info *sta;
6583ff40c12SJohn Marino
6593ff40c12SJohn Marino if (addr == NULL) {
6603ff40c12SJohn Marino /*
6613ff40c12SJohn Marino * This could potentially happen with unexpected event from the
6623ff40c12SJohn Marino * driver wrapper. This was seen at least in one case where the
6633ff40c12SJohn Marino * driver ended up reporting a station mode event while hostapd
6643ff40c12SJohn Marino * was running, so better make sure we stop processing such an
6653ff40c12SJohn Marino * event here.
6663ff40c12SJohn Marino */
667*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
668*a1157835SDaniel Fojt "hostapd_notif_disassoc: Skip event with no address");
6693ff40c12SJohn Marino return;
6703ff40c12SJohn Marino }
6713ff40c12SJohn Marino
6723ff40c12SJohn Marino hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
6733ff40c12SJohn Marino HOSTAPD_LEVEL_INFO, "disassociated");
6743ff40c12SJohn Marino
6753ff40c12SJohn Marino sta = ap_get_sta(hapd, addr);
6763ff40c12SJohn Marino if (sta == NULL) {
677*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
678*a1157835SDaniel Fojt "Disassociation notification for unknown STA "
679*a1157835SDaniel Fojt MACSTR, MAC2STR(addr));
6803ff40c12SJohn Marino return;
6813ff40c12SJohn Marino }
6823ff40c12SJohn Marino
6833ff40c12SJohn Marino ap_sta_set_authorized(hapd, sta, 0);
6843ff40c12SJohn Marino sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
6853ff40c12SJohn Marino wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
6863ff40c12SJohn Marino sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
6873ff40c12SJohn Marino ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
6883ff40c12SJohn Marino ap_free_sta(hapd, sta);
6893ff40c12SJohn Marino }
6903ff40c12SJohn Marino
6913ff40c12SJohn Marino
hostapd_event_sta_low_ack(struct hostapd_data * hapd,const u8 * addr)6923ff40c12SJohn Marino void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
6933ff40c12SJohn Marino {
6943ff40c12SJohn Marino struct sta_info *sta = ap_get_sta(hapd, addr);
6953ff40c12SJohn Marino
696*a1157835SDaniel Fojt if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer)
6973ff40c12SJohn Marino return;
6983ff40c12SJohn Marino
6993ff40c12SJohn Marino hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
700*a1157835SDaniel Fojt HOSTAPD_LEVEL_INFO,
701*a1157835SDaniel Fojt "disconnected due to excessive missing ACKs");
7023ff40c12SJohn Marino hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
7033ff40c12SJohn Marino ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
7043ff40c12SJohn Marino }
7053ff40c12SJohn Marino
7063ff40c12SJohn Marino
hostapd_event_sta_opmode_changed(struct hostapd_data * hapd,const u8 * addr,enum smps_mode smps_mode,enum chan_width chan_width,u8 rx_nss)707*a1157835SDaniel Fojt void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
708*a1157835SDaniel Fojt enum smps_mode smps_mode,
709*a1157835SDaniel Fojt enum chan_width chan_width, u8 rx_nss)
7103ff40c12SJohn Marino {
711*a1157835SDaniel Fojt struct sta_info *sta = ap_get_sta(hapd, addr);
712*a1157835SDaniel Fojt const char *txt;
713*a1157835SDaniel Fojt
714*a1157835SDaniel Fojt if (!sta)
715*a1157835SDaniel Fojt return;
716*a1157835SDaniel Fojt
717*a1157835SDaniel Fojt switch (smps_mode) {
718*a1157835SDaniel Fojt case SMPS_AUTOMATIC:
719*a1157835SDaniel Fojt txt = "automatic";
720*a1157835SDaniel Fojt break;
721*a1157835SDaniel Fojt case SMPS_OFF:
722*a1157835SDaniel Fojt txt = "off";
723*a1157835SDaniel Fojt break;
724*a1157835SDaniel Fojt case SMPS_DYNAMIC:
725*a1157835SDaniel Fojt txt = "dynamic";
726*a1157835SDaniel Fojt break;
727*a1157835SDaniel Fojt case SMPS_STATIC:
728*a1157835SDaniel Fojt txt = "static";
729*a1157835SDaniel Fojt break;
730*a1157835SDaniel Fojt default:
731*a1157835SDaniel Fojt txt = NULL;
732*a1157835SDaniel Fojt break;
733*a1157835SDaniel Fojt }
734*a1157835SDaniel Fojt if (txt) {
735*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_SMPS_MODE_CHANGED
736*a1157835SDaniel Fojt MACSTR " %s", MAC2STR(addr), txt);
737*a1157835SDaniel Fojt }
738*a1157835SDaniel Fojt
739*a1157835SDaniel Fojt switch (chan_width) {
740*a1157835SDaniel Fojt case CHAN_WIDTH_20_NOHT:
741*a1157835SDaniel Fojt txt = "20(no-HT)";
742*a1157835SDaniel Fojt break;
743*a1157835SDaniel Fojt case CHAN_WIDTH_20:
744*a1157835SDaniel Fojt txt = "20";
745*a1157835SDaniel Fojt break;
746*a1157835SDaniel Fojt case CHAN_WIDTH_40:
747*a1157835SDaniel Fojt txt = "40";
748*a1157835SDaniel Fojt break;
749*a1157835SDaniel Fojt case CHAN_WIDTH_80:
750*a1157835SDaniel Fojt txt = "80";
751*a1157835SDaniel Fojt break;
752*a1157835SDaniel Fojt case CHAN_WIDTH_80P80:
753*a1157835SDaniel Fojt txt = "80+80";
754*a1157835SDaniel Fojt break;
755*a1157835SDaniel Fojt case CHAN_WIDTH_160:
756*a1157835SDaniel Fojt txt = "160";
757*a1157835SDaniel Fojt break;
758*a1157835SDaniel Fojt default:
759*a1157835SDaniel Fojt txt = NULL;
760*a1157835SDaniel Fojt break;
761*a1157835SDaniel Fojt }
762*a1157835SDaniel Fojt if (txt) {
763*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_MAX_BW_CHANGED
764*a1157835SDaniel Fojt MACSTR " %s", MAC2STR(addr), txt);
765*a1157835SDaniel Fojt }
766*a1157835SDaniel Fojt
767*a1157835SDaniel Fojt if (rx_nss != 0xff) {
768*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_N_SS_CHANGED
769*a1157835SDaniel Fojt MACSTR " %d", MAC2STR(addr), rx_nss);
770*a1157835SDaniel Fojt }
771*a1157835SDaniel Fojt }
772*a1157835SDaniel Fojt
773*a1157835SDaniel Fojt
hostapd_event_ch_switch(struct hostapd_data * hapd,int freq,int ht,int offset,int width,int cf1,int cf2,int finished)774*a1157835SDaniel Fojt void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
775*a1157835SDaniel Fojt int offset, int width, int cf1, int cf2,
776*a1157835SDaniel Fojt int finished)
777*a1157835SDaniel Fojt {
778*a1157835SDaniel Fojt /* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
779*a1157835SDaniel Fojt
7803ff40c12SJohn Marino #ifdef NEED_AP_MLME
781*a1157835SDaniel Fojt int channel, chwidth, is_dfs;
782*a1157835SDaniel Fojt u8 seg0_idx = 0, seg1_idx = 0;
783*a1157835SDaniel Fojt size_t i;
7843ff40c12SJohn Marino
7853ff40c12SJohn Marino hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
786*a1157835SDaniel Fojt HOSTAPD_LEVEL_INFO,
787*a1157835SDaniel Fojt "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
788*a1157835SDaniel Fojt finished ? "had" : "starting",
789*a1157835SDaniel Fojt freq, ht, hapd->iconf->ch_switch_vht_config, offset,
790*a1157835SDaniel Fojt width, channel_width_to_string(width), cf1, cf2);
791*a1157835SDaniel Fojt
792*a1157835SDaniel Fojt if (!hapd->iface->current_mode) {
793*a1157835SDaniel Fojt hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
794*a1157835SDaniel Fojt HOSTAPD_LEVEL_WARNING,
795*a1157835SDaniel Fojt "ignore channel switch since the interface is not yet ready");
796*a1157835SDaniel Fojt return;
797*a1157835SDaniel Fojt }
7983ff40c12SJohn Marino
7993ff40c12SJohn Marino hapd->iface->freq = freq;
8003ff40c12SJohn Marino
8013ff40c12SJohn Marino channel = hostapd_hw_get_channel(hapd, freq);
8023ff40c12SJohn Marino if (!channel) {
8033ff40c12SJohn Marino hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
804*a1157835SDaniel Fojt HOSTAPD_LEVEL_WARNING,
805*a1157835SDaniel Fojt "driver switched to bad channel!");
8063ff40c12SJohn Marino return;
8073ff40c12SJohn Marino }
8083ff40c12SJohn Marino
8093ff40c12SJohn Marino switch (width) {
8103ff40c12SJohn Marino case CHAN_WIDTH_80:
811*a1157835SDaniel Fojt chwidth = CHANWIDTH_80MHZ;
8123ff40c12SJohn Marino break;
8133ff40c12SJohn Marino case CHAN_WIDTH_80P80:
814*a1157835SDaniel Fojt chwidth = CHANWIDTH_80P80MHZ;
8153ff40c12SJohn Marino break;
8163ff40c12SJohn Marino case CHAN_WIDTH_160:
817*a1157835SDaniel Fojt chwidth = CHANWIDTH_160MHZ;
8183ff40c12SJohn Marino break;
8193ff40c12SJohn Marino case CHAN_WIDTH_20_NOHT:
8203ff40c12SJohn Marino case CHAN_WIDTH_20:
8213ff40c12SJohn Marino case CHAN_WIDTH_40:
8223ff40c12SJohn Marino default:
823*a1157835SDaniel Fojt chwidth = CHANWIDTH_USE_HT;
8243ff40c12SJohn Marino break;
8253ff40c12SJohn Marino }
8263ff40c12SJohn Marino
8273ff40c12SJohn Marino switch (hapd->iface->current_mode->mode) {
8283ff40c12SJohn Marino case HOSTAPD_MODE_IEEE80211A:
8293ff40c12SJohn Marino if (cf1 > 5000)
8303ff40c12SJohn Marino seg0_idx = (cf1 - 5000) / 5;
8313ff40c12SJohn Marino if (cf2 > 5000)
8323ff40c12SJohn Marino seg1_idx = (cf2 - 5000) / 5;
8333ff40c12SJohn Marino break;
8343ff40c12SJohn Marino default:
835*a1157835SDaniel Fojt ieee80211_freq_to_chan(cf1, &seg0_idx);
836*a1157835SDaniel Fojt ieee80211_freq_to_chan(cf2, &seg1_idx);
8373ff40c12SJohn Marino break;
8383ff40c12SJohn Marino }
8393ff40c12SJohn Marino
8403ff40c12SJohn Marino hapd->iconf->channel = channel;
8413ff40c12SJohn Marino hapd->iconf->ieee80211n = ht;
842*a1157835SDaniel Fojt if (!ht) {
843*a1157835SDaniel Fojt hapd->iconf->ieee80211ac = 0;
844*a1157835SDaniel Fojt } else if (hapd->iconf->ch_switch_vht_config) {
845*a1157835SDaniel Fojt /* CHAN_SWITCH VHT config */
846*a1157835SDaniel Fojt if (hapd->iconf->ch_switch_vht_config &
847*a1157835SDaniel Fojt CH_SWITCH_VHT_ENABLED)
848*a1157835SDaniel Fojt hapd->iconf->ieee80211ac = 1;
849*a1157835SDaniel Fojt else if (hapd->iconf->ch_switch_vht_config &
850*a1157835SDaniel Fojt CH_SWITCH_VHT_DISABLED)
851*a1157835SDaniel Fojt hapd->iconf->ieee80211ac = 0;
8523ff40c12SJohn Marino }
853*a1157835SDaniel Fojt hapd->iconf->ch_switch_vht_config = 0;
854*a1157835SDaniel Fojt
855*a1157835SDaniel Fojt hapd->iconf->secondary_channel = offset;
856*a1157835SDaniel Fojt hostapd_set_oper_chwidth(hapd->iconf, chwidth);
857*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx);
858*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx);
859*a1157835SDaniel Fojt
860*a1157835SDaniel Fojt is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
861*a1157835SDaniel Fojt hapd->iface->num_hw_features);
862*a1157835SDaniel Fojt
863*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO,
864*a1157835SDaniel Fojt "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d dfs=%d",
865*a1157835SDaniel Fojt finished ? WPA_EVENT_CHANNEL_SWITCH :
866*a1157835SDaniel Fojt WPA_EVENT_CHANNEL_SWITCH_STARTED,
867*a1157835SDaniel Fojt freq, ht, offset, channel_width_to_string(width),
868*a1157835SDaniel Fojt cf1, cf2, is_dfs);
869*a1157835SDaniel Fojt if (!finished)
870*a1157835SDaniel Fojt return;
871*a1157835SDaniel Fojt
872*a1157835SDaniel Fojt if (hapd->csa_in_progress &&
873*a1157835SDaniel Fojt freq == hapd->cs_freq_params.freq) {
874*a1157835SDaniel Fojt hostapd_cleanup_cs_params(hapd);
875*a1157835SDaniel Fojt ieee802_11_set_beacon(hapd);
876*a1157835SDaniel Fojt
877*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
878*a1157835SDaniel Fojt "freq=%d dfs=%d", freq, is_dfs);
879*a1157835SDaniel Fojt } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
880*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
881*a1157835SDaniel Fojt "freq=%d dfs=%d", freq, is_dfs);
882*a1157835SDaniel Fojt }
883*a1157835SDaniel Fojt
884*a1157835SDaniel Fojt for (i = 0; i < hapd->iface->num_bss; i++)
885*a1157835SDaniel Fojt hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
8863ff40c12SJohn Marino #endif /* NEED_AP_MLME */
8873ff40c12SJohn Marino }
8883ff40c12SJohn Marino
8893ff40c12SJohn Marino
hostapd_event_connect_failed_reason(struct hostapd_data * hapd,const u8 * addr,int reason_code)8903ff40c12SJohn Marino void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
8913ff40c12SJohn Marino const u8 *addr, int reason_code)
8923ff40c12SJohn Marino {
8933ff40c12SJohn Marino switch (reason_code) {
8943ff40c12SJohn Marino case MAX_CLIENT_REACHED:
8953ff40c12SJohn Marino wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR,
8963ff40c12SJohn Marino MAC2STR(addr));
8973ff40c12SJohn Marino break;
8983ff40c12SJohn Marino case BLOCKED_CLIENT:
8993ff40c12SJohn Marino wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR,
9003ff40c12SJohn Marino MAC2STR(addr));
9013ff40c12SJohn Marino break;
9023ff40c12SJohn Marino }
9033ff40c12SJohn Marino }
9043ff40c12SJohn Marino
9053ff40c12SJohn Marino
906*a1157835SDaniel Fojt #ifdef CONFIG_ACS
hostapd_acs_channel_selected(struct hostapd_data * hapd,struct acs_selected_channels * acs_res)907*a1157835SDaniel Fojt void hostapd_acs_channel_selected(struct hostapd_data *hapd,
908*a1157835SDaniel Fojt struct acs_selected_channels *acs_res)
909*a1157835SDaniel Fojt {
910*a1157835SDaniel Fojt int ret, i;
911*a1157835SDaniel Fojt int err = 0;
912*a1157835SDaniel Fojt
913*a1157835SDaniel Fojt if (hapd->iconf->channel) {
914*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
915*a1157835SDaniel Fojt hapd->iconf->channel);
916*a1157835SDaniel Fojt return;
917*a1157835SDaniel Fojt }
918*a1157835SDaniel Fojt
919*a1157835SDaniel Fojt if (!hapd->iface->current_mode) {
920*a1157835SDaniel Fojt for (i = 0; i < hapd->iface->num_hw_features; i++) {
921*a1157835SDaniel Fojt struct hostapd_hw_modes *mode =
922*a1157835SDaniel Fojt &hapd->iface->hw_features[i];
923*a1157835SDaniel Fojt
924*a1157835SDaniel Fojt if (mode->mode == acs_res->hw_mode) {
925*a1157835SDaniel Fojt hapd->iface->current_mode = mode;
926*a1157835SDaniel Fojt break;
927*a1157835SDaniel Fojt }
928*a1157835SDaniel Fojt }
929*a1157835SDaniel Fojt if (!hapd->iface->current_mode) {
930*a1157835SDaniel Fojt hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
931*a1157835SDaniel Fojt HOSTAPD_LEVEL_WARNING,
932*a1157835SDaniel Fojt "driver selected to bad hw_mode");
933*a1157835SDaniel Fojt err = 1;
934*a1157835SDaniel Fojt goto out;
935*a1157835SDaniel Fojt }
936*a1157835SDaniel Fojt }
937*a1157835SDaniel Fojt
938*a1157835SDaniel Fojt hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
939*a1157835SDaniel Fojt
940*a1157835SDaniel Fojt if (!acs_res->pri_channel) {
941*a1157835SDaniel Fojt hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
942*a1157835SDaniel Fojt HOSTAPD_LEVEL_WARNING,
943*a1157835SDaniel Fojt "driver switched to bad channel");
944*a1157835SDaniel Fojt err = 1;
945*a1157835SDaniel Fojt goto out;
946*a1157835SDaniel Fojt }
947*a1157835SDaniel Fojt
948*a1157835SDaniel Fojt hapd->iconf->channel = acs_res->pri_channel;
949*a1157835SDaniel Fojt hapd->iconf->acs = 1;
950*a1157835SDaniel Fojt
951*a1157835SDaniel Fojt if (acs_res->sec_channel == 0)
952*a1157835SDaniel Fojt hapd->iconf->secondary_channel = 0;
953*a1157835SDaniel Fojt else if (acs_res->sec_channel < acs_res->pri_channel)
954*a1157835SDaniel Fojt hapd->iconf->secondary_channel = -1;
955*a1157835SDaniel Fojt else if (acs_res->sec_channel > acs_res->pri_channel)
956*a1157835SDaniel Fojt hapd->iconf->secondary_channel = 1;
957*a1157835SDaniel Fojt else {
958*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "Invalid secondary channel!");
959*a1157835SDaniel Fojt err = 1;
960*a1157835SDaniel Fojt goto out;
961*a1157835SDaniel Fojt }
962*a1157835SDaniel Fojt
963*a1157835SDaniel Fojt if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
964*a1157835SDaniel Fojt /* set defaults for backwards compatibility */
965*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
966*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0);
967*a1157835SDaniel Fojt hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT);
968*a1157835SDaniel Fojt if (acs_res->ch_width == 80) {
969*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg0_idx(
970*a1157835SDaniel Fojt hapd->iconf, acs_res->vht_seg0_center_ch);
971*a1157835SDaniel Fojt hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_80MHZ);
972*a1157835SDaniel Fojt } else if (acs_res->ch_width == 160) {
973*a1157835SDaniel Fojt if (acs_res->vht_seg1_center_ch == 0) {
974*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg0_idx(
975*a1157835SDaniel Fojt hapd->iconf,
976*a1157835SDaniel Fojt acs_res->vht_seg0_center_ch);
977*a1157835SDaniel Fojt hostapd_set_oper_chwidth(hapd->iconf,
978*a1157835SDaniel Fojt CHANWIDTH_160MHZ);
979*a1157835SDaniel Fojt } else {
980*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg0_idx(
981*a1157835SDaniel Fojt hapd->iconf,
982*a1157835SDaniel Fojt acs_res->vht_seg0_center_ch);
983*a1157835SDaniel Fojt hostapd_set_oper_centr_freq_seg1_idx(
984*a1157835SDaniel Fojt hapd->iconf,
985*a1157835SDaniel Fojt acs_res->vht_seg1_center_ch);
986*a1157835SDaniel Fojt hostapd_set_oper_chwidth(hapd->iconf,
987*a1157835SDaniel Fojt CHANWIDTH_80P80MHZ);
988*a1157835SDaniel Fojt }
989*a1157835SDaniel Fojt }
990*a1157835SDaniel Fojt }
991*a1157835SDaniel Fojt
992*a1157835SDaniel Fojt out:
993*a1157835SDaniel Fojt ret = hostapd_acs_completed(hapd->iface, err);
994*a1157835SDaniel Fojt if (ret) {
995*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
996*a1157835SDaniel Fojt "ACS: Possibly channel configuration is invalid");
997*a1157835SDaniel Fojt }
998*a1157835SDaniel Fojt }
999*a1157835SDaniel Fojt #endif /* CONFIG_ACS */
1000*a1157835SDaniel Fojt
1001*a1157835SDaniel Fojt
hostapd_probe_req_rx(struct hostapd_data * hapd,const u8 * sa,const u8 * da,const u8 * bssid,const u8 * ie,size_t ie_len,int ssi_signal)10023ff40c12SJohn Marino int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
10033ff40c12SJohn Marino const u8 *bssid, const u8 *ie, size_t ie_len,
10043ff40c12SJohn Marino int ssi_signal)
10053ff40c12SJohn Marino {
10063ff40c12SJohn Marino size_t i;
10073ff40c12SJohn Marino int ret = 0;
10083ff40c12SJohn Marino
10093ff40c12SJohn Marino if (sa == NULL || ie == NULL)
10103ff40c12SJohn Marino return -1;
10113ff40c12SJohn Marino
10123ff40c12SJohn Marino random_add_randomness(sa, ETH_ALEN);
10133ff40c12SJohn Marino for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
10143ff40c12SJohn Marino if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
10153ff40c12SJohn Marino sa, da, bssid, ie, ie_len,
10163ff40c12SJohn Marino ssi_signal) > 0) {
10173ff40c12SJohn Marino ret = 1;
10183ff40c12SJohn Marino break;
10193ff40c12SJohn Marino }
10203ff40c12SJohn Marino }
10213ff40c12SJohn Marino return ret;
10223ff40c12SJohn Marino }
10233ff40c12SJohn Marino
10243ff40c12SJohn Marino
10253ff40c12SJohn Marino #ifdef HOSTAPD
10263ff40c12SJohn Marino
1027*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
hostapd_notify_auth_ft_finish(void * ctx,const u8 * dst,const u8 * bssid,u16 auth_transaction,u16 status,const u8 * ies,size_t ies_len)10283ff40c12SJohn Marino static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
10293ff40c12SJohn Marino const u8 *bssid,
10303ff40c12SJohn Marino u16 auth_transaction, u16 status,
10313ff40c12SJohn Marino const u8 *ies, size_t ies_len)
10323ff40c12SJohn Marino {
10333ff40c12SJohn Marino struct hostapd_data *hapd = ctx;
10343ff40c12SJohn Marino struct sta_info *sta;
10353ff40c12SJohn Marino
10363ff40c12SJohn Marino sta = ap_get_sta(hapd, dst);
10373ff40c12SJohn Marino if (sta == NULL)
10383ff40c12SJohn Marino return;
10393ff40c12SJohn Marino
10403ff40c12SJohn Marino hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
10413ff40c12SJohn Marino HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
10423ff40c12SJohn Marino sta->flags |= WLAN_STA_AUTH;
10433ff40c12SJohn Marino
10443ff40c12SJohn Marino hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
10453ff40c12SJohn Marino }
1046*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
1047*a1157835SDaniel Fojt
1048*a1157835SDaniel Fojt
1049*a1157835SDaniel Fojt #ifdef CONFIG_FILS
hostapd_notify_auth_fils_finish(struct hostapd_data * hapd,struct sta_info * sta,u16 resp,struct wpabuf * data,int pub)1050*a1157835SDaniel Fojt static void hostapd_notify_auth_fils_finish(struct hostapd_data *hapd,
1051*a1157835SDaniel Fojt struct sta_info *sta, u16 resp,
1052*a1157835SDaniel Fojt struct wpabuf *data, int pub)
1053*a1157835SDaniel Fojt {
1054*a1157835SDaniel Fojt if (resp == WLAN_STATUS_SUCCESS) {
1055*a1157835SDaniel Fojt hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1056*a1157835SDaniel Fojt HOSTAPD_LEVEL_DEBUG, "authentication OK (FILS)");
1057*a1157835SDaniel Fojt sta->flags |= WLAN_STA_AUTH;
1058*a1157835SDaniel Fojt wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
1059*a1157835SDaniel Fojt sta->auth_alg = WLAN_AUTH_FILS_SK;
1060*a1157835SDaniel Fojt mlme_authenticate_indication(hapd, sta);
1061*a1157835SDaniel Fojt } else {
1062*a1157835SDaniel Fojt hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1063*a1157835SDaniel Fojt HOSTAPD_LEVEL_DEBUG,
1064*a1157835SDaniel Fojt "authentication failed (FILS)");
1065*a1157835SDaniel Fojt }
1066*a1157835SDaniel Fojt
1067*a1157835SDaniel Fojt hostapd_sta_auth(hapd, sta->addr, 2, resp,
1068*a1157835SDaniel Fojt data ? wpabuf_head(data) : NULL,
1069*a1157835SDaniel Fojt data ? wpabuf_len(data) : 0);
1070*a1157835SDaniel Fojt wpabuf_free(data);
1071*a1157835SDaniel Fojt }
1072*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
10733ff40c12SJohn Marino
10743ff40c12SJohn Marino
hostapd_notif_auth(struct hostapd_data * hapd,struct auth_info * rx_auth)10753ff40c12SJohn Marino static void hostapd_notif_auth(struct hostapd_data *hapd,
10763ff40c12SJohn Marino struct auth_info *rx_auth)
10773ff40c12SJohn Marino {
10783ff40c12SJohn Marino struct sta_info *sta;
10793ff40c12SJohn Marino u16 status = WLAN_STATUS_SUCCESS;
10803ff40c12SJohn Marino u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
10813ff40c12SJohn Marino size_t resp_ies_len = 0;
10823ff40c12SJohn Marino
10833ff40c12SJohn Marino sta = ap_get_sta(hapd, rx_auth->peer);
10843ff40c12SJohn Marino if (!sta) {
10853ff40c12SJohn Marino sta = ap_sta_add(hapd, rx_auth->peer);
10863ff40c12SJohn Marino if (sta == NULL) {
10873ff40c12SJohn Marino status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
10883ff40c12SJohn Marino goto fail;
10893ff40c12SJohn Marino }
10903ff40c12SJohn Marino }
10913ff40c12SJohn Marino sta->flags &= ~WLAN_STA_PREAUTH;
10923ff40c12SJohn Marino ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
1093*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
10943ff40c12SJohn Marino if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
10953ff40c12SJohn Marino sta->auth_alg = WLAN_AUTH_FT;
10963ff40c12SJohn Marino if (sta->wpa_sm == NULL)
10973ff40c12SJohn Marino sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
10983ff40c12SJohn Marino sta->addr, NULL);
10993ff40c12SJohn Marino if (sta->wpa_sm == NULL) {
1100*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1101*a1157835SDaniel Fojt "FT: Failed to initialize WPA state machine");
11023ff40c12SJohn Marino status = WLAN_STATUS_UNSPECIFIED_FAILURE;
11033ff40c12SJohn Marino goto fail;
11043ff40c12SJohn Marino }
11053ff40c12SJohn Marino wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
11063ff40c12SJohn Marino rx_auth->auth_transaction, rx_auth->ies,
11073ff40c12SJohn Marino rx_auth->ies_len,
11083ff40c12SJohn Marino hostapd_notify_auth_ft_finish, hapd);
11093ff40c12SJohn Marino return;
11103ff40c12SJohn Marino }
1111*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
1112*a1157835SDaniel Fojt
1113*a1157835SDaniel Fojt #ifdef CONFIG_FILS
1114*a1157835SDaniel Fojt if (rx_auth->auth_type == WLAN_AUTH_FILS_SK) {
1115*a1157835SDaniel Fojt sta->auth_alg = WLAN_AUTH_FILS_SK;
1116*a1157835SDaniel Fojt handle_auth_fils(hapd, sta, rx_auth->ies, rx_auth->ies_len,
1117*a1157835SDaniel Fojt rx_auth->auth_type, rx_auth->auth_transaction,
1118*a1157835SDaniel Fojt rx_auth->status_code,
1119*a1157835SDaniel Fojt hostapd_notify_auth_fils_finish);
1120*a1157835SDaniel Fojt return;
1121*a1157835SDaniel Fojt }
1122*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
1123*a1157835SDaniel Fojt
11243ff40c12SJohn Marino fail:
11253ff40c12SJohn Marino hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
11263ff40c12SJohn Marino status, resp_ies, resp_ies_len);
11273ff40c12SJohn Marino }
11283ff40c12SJohn Marino
11293ff40c12SJohn Marino
1130*a1157835SDaniel Fojt #ifndef NEED_AP_MLME
hostapd_action_rx(struct hostapd_data * hapd,struct rx_mgmt * drv_mgmt)11313ff40c12SJohn Marino static void hostapd_action_rx(struct hostapd_data *hapd,
11323ff40c12SJohn Marino struct rx_mgmt *drv_mgmt)
11333ff40c12SJohn Marino {
11343ff40c12SJohn Marino struct ieee80211_mgmt *mgmt;
11353ff40c12SJohn Marino struct sta_info *sta;
11363ff40c12SJohn Marino size_t plen __maybe_unused;
11373ff40c12SJohn Marino u16 fc;
1138*a1157835SDaniel Fojt u8 *action __maybe_unused;
11393ff40c12SJohn Marino
1140*a1157835SDaniel Fojt if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1)
11413ff40c12SJohn Marino return;
11423ff40c12SJohn Marino
1143*a1157835SDaniel Fojt plen = drv_mgmt->frame_len - IEEE80211_HDRLEN;
11443ff40c12SJohn Marino
11453ff40c12SJohn Marino mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
11463ff40c12SJohn Marino fc = le_to_host16(mgmt->frame_control);
11473ff40c12SJohn Marino if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
11483ff40c12SJohn Marino return; /* handled by the driver */
11493ff40c12SJohn Marino
1150*a1157835SDaniel Fojt action = (u8 *) &mgmt->u.action.u;
1151*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
1152*a1157835SDaniel Fojt " da " MACSTR " plen %d",
1153*a1157835SDaniel Fojt mgmt->u.action.category, *action,
1154*a1157835SDaniel Fojt MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen);
11553ff40c12SJohn Marino
11563ff40c12SJohn Marino sta = ap_get_sta(hapd, mgmt->sa);
11573ff40c12SJohn Marino if (sta == NULL) {
11583ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
11593ff40c12SJohn Marino return;
11603ff40c12SJohn Marino }
1161*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
11623ff40c12SJohn Marino if (mgmt->u.action.category == WLAN_ACTION_FT) {
1163*a1157835SDaniel Fojt wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, plen);
1164*a1157835SDaniel Fojt return;
11653ff40c12SJohn Marino }
1166*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
11673ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
1168*a1157835SDaniel Fojt if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) {
1169*a1157835SDaniel Fojt ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len);
1170*a1157835SDaniel Fojt return;
11713ff40c12SJohn Marino }
11723ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
1173*a1157835SDaniel Fojt #ifdef CONFIG_WNM_AP
11743ff40c12SJohn Marino if (mgmt->u.action.category == WLAN_ACTION_WNM) {
11753ff40c12SJohn Marino ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
1176*a1157835SDaniel Fojt return;
11773ff40c12SJohn Marino }
1178*a1157835SDaniel Fojt #endif /* CONFIG_WNM_AP */
1179*a1157835SDaniel Fojt #ifdef CONFIG_FST
1180*a1157835SDaniel Fojt if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) {
1181*a1157835SDaniel Fojt fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len);
1182*a1157835SDaniel Fojt return;
11833ff40c12SJohn Marino }
1184*a1157835SDaniel Fojt #endif /* CONFIG_FST */
1185*a1157835SDaniel Fojt #ifdef CONFIG_DPP
1186*a1157835SDaniel Fojt if (plen >= 2 + 4 &&
1187*a1157835SDaniel Fojt mgmt->u.action.u.vs_public_action.action ==
1188*a1157835SDaniel Fojt WLAN_PA_VENDOR_SPECIFIC &&
1189*a1157835SDaniel Fojt WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
1190*a1157835SDaniel Fojt OUI_WFA &&
1191*a1157835SDaniel Fojt mgmt->u.action.u.vs_public_action.variable[0] ==
1192*a1157835SDaniel Fojt DPP_OUI_TYPE) {
1193*a1157835SDaniel Fojt const u8 *pos, *end;
1194*a1157835SDaniel Fojt
1195*a1157835SDaniel Fojt pos = mgmt->u.action.u.vs_public_action.oui;
1196*a1157835SDaniel Fojt end = drv_mgmt->frame + drv_mgmt->frame_len;
1197*a1157835SDaniel Fojt hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
1198*a1157835SDaniel Fojt drv_mgmt->freq);
1199*a1157835SDaniel Fojt return;
1200*a1157835SDaniel Fojt }
1201*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
1202*a1157835SDaniel Fojt }
1203*a1157835SDaniel Fojt #endif /* NEED_AP_MLME */
12043ff40c12SJohn Marino
12053ff40c12SJohn Marino
12063ff40c12SJohn Marino #ifdef NEED_AP_MLME
12073ff40c12SJohn Marino
12083ff40c12SJohn Marino #define HAPD_BROADCAST ((struct hostapd_data *) -1)
12093ff40c12SJohn Marino
get_hapd_bssid(struct hostapd_iface * iface,const u8 * bssid)12103ff40c12SJohn Marino static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
12113ff40c12SJohn Marino const u8 *bssid)
12123ff40c12SJohn Marino {
12133ff40c12SJohn Marino size_t i;
12143ff40c12SJohn Marino
12153ff40c12SJohn Marino if (bssid == NULL)
12163ff40c12SJohn Marino return NULL;
12173ff40c12SJohn Marino if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
12183ff40c12SJohn Marino bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
12193ff40c12SJohn Marino return HAPD_BROADCAST;
12203ff40c12SJohn Marino
12213ff40c12SJohn Marino for (i = 0; i < iface->num_bss; i++) {
12223ff40c12SJohn Marino if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
12233ff40c12SJohn Marino return iface->bss[i];
12243ff40c12SJohn Marino }
12253ff40c12SJohn Marino
12263ff40c12SJohn Marino return NULL;
12273ff40c12SJohn Marino }
12283ff40c12SJohn Marino
12293ff40c12SJohn Marino
hostapd_rx_from_unknown_sta(struct hostapd_data * hapd,const u8 * bssid,const u8 * addr,int wds)12303ff40c12SJohn Marino static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
12313ff40c12SJohn Marino const u8 *bssid, const u8 *addr,
12323ff40c12SJohn Marino int wds)
12333ff40c12SJohn Marino {
12343ff40c12SJohn Marino hapd = get_hapd_bssid(hapd->iface, bssid);
12353ff40c12SJohn Marino if (hapd == NULL || hapd == HAPD_BROADCAST)
12363ff40c12SJohn Marino return;
12373ff40c12SJohn Marino
12383ff40c12SJohn Marino ieee802_11_rx_from_unknown(hapd, addr, wds);
12393ff40c12SJohn Marino }
12403ff40c12SJohn Marino
12413ff40c12SJohn Marino
hostapd_mgmt_rx(struct hostapd_data * hapd,struct rx_mgmt * rx_mgmt)12423ff40c12SJohn Marino static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
12433ff40c12SJohn Marino {
12443ff40c12SJohn Marino struct hostapd_iface *iface = hapd->iface;
12453ff40c12SJohn Marino const struct ieee80211_hdr *hdr;
12463ff40c12SJohn Marino const u8 *bssid;
12473ff40c12SJohn Marino struct hostapd_frame_info fi;
12483ff40c12SJohn Marino int ret;
12493ff40c12SJohn Marino
1250*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
1251*a1157835SDaniel Fojt if (hapd->ext_mgmt_frame_handling) {
1252*a1157835SDaniel Fojt size_t hex_len = 2 * rx_mgmt->frame_len + 1;
1253*a1157835SDaniel Fojt char *hex = os_malloc(hex_len);
1254*a1157835SDaniel Fojt
1255*a1157835SDaniel Fojt if (hex) {
1256*a1157835SDaniel Fojt wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame,
1257*a1157835SDaniel Fojt rx_mgmt->frame_len);
1258*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex);
1259*a1157835SDaniel Fojt os_free(hex);
1260*a1157835SDaniel Fojt }
1261*a1157835SDaniel Fojt return 1;
1262*a1157835SDaniel Fojt }
1263*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
1264*a1157835SDaniel Fojt
12653ff40c12SJohn Marino hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
12663ff40c12SJohn Marino bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
12673ff40c12SJohn Marino if (bssid == NULL)
12683ff40c12SJohn Marino return 0;
12693ff40c12SJohn Marino
12703ff40c12SJohn Marino hapd = get_hapd_bssid(iface, bssid);
12713ff40c12SJohn Marino if (hapd == NULL) {
1272*a1157835SDaniel Fojt u16 fc = le_to_host16(hdr->frame_control);
12733ff40c12SJohn Marino
12743ff40c12SJohn Marino /*
12753ff40c12SJohn Marino * Drop frames to unknown BSSIDs except for Beacon frames which
12763ff40c12SJohn Marino * could be used to update neighbor information.
12773ff40c12SJohn Marino */
12783ff40c12SJohn Marino if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
12793ff40c12SJohn Marino WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
12803ff40c12SJohn Marino hapd = iface->bss[0];
12813ff40c12SJohn Marino else
12823ff40c12SJohn Marino return 0;
12833ff40c12SJohn Marino }
12843ff40c12SJohn Marino
12853ff40c12SJohn Marino os_memset(&fi, 0, sizeof(fi));
1286*a1157835SDaniel Fojt fi.freq = rx_mgmt->freq;
12873ff40c12SJohn Marino fi.datarate = rx_mgmt->datarate;
12883ff40c12SJohn Marino fi.ssi_signal = rx_mgmt->ssi_signal;
12893ff40c12SJohn Marino
12903ff40c12SJohn Marino if (hapd == HAPD_BROADCAST) {
12913ff40c12SJohn Marino size_t i;
1292*a1157835SDaniel Fojt
12933ff40c12SJohn Marino ret = 0;
12943ff40c12SJohn Marino for (i = 0; i < iface->num_bss; i++) {
1295*a1157835SDaniel Fojt /* if bss is set, driver will call this function for
1296*a1157835SDaniel Fojt * each bss individually. */
1297*a1157835SDaniel Fojt if (rx_mgmt->drv_priv &&
1298*a1157835SDaniel Fojt (iface->bss[i]->drv_priv != rx_mgmt->drv_priv))
1299*a1157835SDaniel Fojt continue;
1300*a1157835SDaniel Fojt
13013ff40c12SJohn Marino if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
13023ff40c12SJohn Marino rx_mgmt->frame_len, &fi) > 0)
13033ff40c12SJohn Marino ret = 1;
13043ff40c12SJohn Marino }
13053ff40c12SJohn Marino } else
13063ff40c12SJohn Marino ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len,
13073ff40c12SJohn Marino &fi);
13083ff40c12SJohn Marino
13093ff40c12SJohn Marino random_add_randomness(&fi, sizeof(fi));
13103ff40c12SJohn Marino
13113ff40c12SJohn Marino return ret;
13123ff40c12SJohn Marino }
13133ff40c12SJohn Marino
13143ff40c12SJohn Marino
hostapd_mgmt_tx_cb(struct hostapd_data * hapd,const u8 * buf,size_t len,u16 stype,int ok)13153ff40c12SJohn Marino static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
13163ff40c12SJohn Marino size_t len, u16 stype, int ok)
13173ff40c12SJohn Marino {
13183ff40c12SJohn Marino struct ieee80211_hdr *hdr;
1319*a1157835SDaniel Fojt struct hostapd_data *orig_hapd = hapd;
1320*a1157835SDaniel Fojt
13213ff40c12SJohn Marino hdr = (struct ieee80211_hdr *) buf;
13223ff40c12SJohn Marino hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
1323*a1157835SDaniel Fojt if (!hapd)
13243ff40c12SJohn Marino return;
1325*a1157835SDaniel Fojt if (hapd == HAPD_BROADCAST) {
1326*a1157835SDaniel Fojt if (stype != WLAN_FC_STYPE_ACTION || len <= 25 ||
1327*a1157835SDaniel Fojt buf[24] != WLAN_ACTION_PUBLIC)
1328*a1157835SDaniel Fojt return;
1329*a1157835SDaniel Fojt hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2);
1330*a1157835SDaniel Fojt if (!hapd || hapd == HAPD_BROADCAST)
1331*a1157835SDaniel Fojt return;
1332*a1157835SDaniel Fojt /*
1333*a1157835SDaniel Fojt * Allow processing of TX status for a Public Action frame that
1334*a1157835SDaniel Fojt * used wildcard BBSID.
1335*a1157835SDaniel Fojt */
1336*a1157835SDaniel Fojt }
13373ff40c12SJohn Marino ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
13383ff40c12SJohn Marino }
13393ff40c12SJohn Marino
13403ff40c12SJohn Marino #endif /* NEED_AP_MLME */
13413ff40c12SJohn Marino
13423ff40c12SJohn Marino
hostapd_event_new_sta(struct hostapd_data * hapd,const u8 * addr)13433ff40c12SJohn Marino static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
13443ff40c12SJohn Marino {
13453ff40c12SJohn Marino struct sta_info *sta = ap_get_sta(hapd, addr);
1346*a1157835SDaniel Fojt
13473ff40c12SJohn Marino if (sta)
13483ff40c12SJohn Marino return 0;
13493ff40c12SJohn Marino
13503ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
13513ff40c12SJohn Marino " - adding a new STA", MAC2STR(addr));
13523ff40c12SJohn Marino sta = ap_sta_add(hapd, addr);
13533ff40c12SJohn Marino if (sta) {
13543ff40c12SJohn Marino hostapd_new_assoc_sta(hapd, sta, 0);
13553ff40c12SJohn Marino } else {
13563ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
13573ff40c12SJohn Marino MAC2STR(addr));
13583ff40c12SJohn Marino return -1;
13593ff40c12SJohn Marino }
13603ff40c12SJohn Marino
13613ff40c12SJohn Marino return 0;
13623ff40c12SJohn Marino }
13633ff40c12SJohn Marino
13643ff40c12SJohn Marino
hostapd_event_eapol_rx(struct hostapd_data * hapd,const u8 * src,const u8 * data,size_t data_len)13653ff40c12SJohn Marino static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
13663ff40c12SJohn Marino const u8 *data, size_t data_len)
13673ff40c12SJohn Marino {
13683ff40c12SJohn Marino struct hostapd_iface *iface = hapd->iface;
13693ff40c12SJohn Marino struct sta_info *sta;
13703ff40c12SJohn Marino size_t j;
13713ff40c12SJohn Marino
13723ff40c12SJohn Marino for (j = 0; j < iface->num_bss; j++) {
1373*a1157835SDaniel Fojt sta = ap_get_sta(iface->bss[j], src);
1374*a1157835SDaniel Fojt if (sta && sta->flags & WLAN_STA_ASSOC) {
13753ff40c12SJohn Marino hapd = iface->bss[j];
13763ff40c12SJohn Marino break;
13773ff40c12SJohn Marino }
13783ff40c12SJohn Marino }
13793ff40c12SJohn Marino
13803ff40c12SJohn Marino ieee802_1x_receive(hapd, src, data, data_len);
13813ff40c12SJohn Marino }
13823ff40c12SJohn Marino
1383*a1157835SDaniel Fojt #endif /* HOSTAPD */
1384*a1157835SDaniel Fojt
13853ff40c12SJohn Marino
hostapd_get_mode_channel(struct hostapd_iface * iface,unsigned int freq)13863ff40c12SJohn Marino static struct hostapd_channel_data * hostapd_get_mode_channel(
13873ff40c12SJohn Marino struct hostapd_iface *iface, unsigned int freq)
13883ff40c12SJohn Marino {
13893ff40c12SJohn Marino int i;
13903ff40c12SJohn Marino struct hostapd_channel_data *chan;
13913ff40c12SJohn Marino
13923ff40c12SJohn Marino for (i = 0; i < iface->current_mode->num_channels; i++) {
13933ff40c12SJohn Marino chan = &iface->current_mode->channels[i];
13943ff40c12SJohn Marino if ((unsigned int) chan->freq == freq)
13953ff40c12SJohn Marino return chan;
13963ff40c12SJohn Marino }
13973ff40c12SJohn Marino
13983ff40c12SJohn Marino return NULL;
13993ff40c12SJohn Marino }
14003ff40c12SJohn Marino
14013ff40c12SJohn Marino
hostapd_update_nf(struct hostapd_iface * iface,struct hostapd_channel_data * chan,struct freq_survey * survey)14023ff40c12SJohn Marino static void hostapd_update_nf(struct hostapd_iface *iface,
14033ff40c12SJohn Marino struct hostapd_channel_data *chan,
14043ff40c12SJohn Marino struct freq_survey *survey)
14053ff40c12SJohn Marino {
14063ff40c12SJohn Marino if (!iface->chans_surveyed) {
14073ff40c12SJohn Marino chan->min_nf = survey->nf;
14083ff40c12SJohn Marino iface->lowest_nf = survey->nf;
14093ff40c12SJohn Marino } else {
14103ff40c12SJohn Marino if (dl_list_empty(&chan->survey_list))
14113ff40c12SJohn Marino chan->min_nf = survey->nf;
14123ff40c12SJohn Marino else if (survey->nf < chan->min_nf)
14133ff40c12SJohn Marino chan->min_nf = survey->nf;
14143ff40c12SJohn Marino if (survey->nf < iface->lowest_nf)
14153ff40c12SJohn Marino iface->lowest_nf = survey->nf;
14163ff40c12SJohn Marino }
14173ff40c12SJohn Marino }
14183ff40c12SJohn Marino
14193ff40c12SJohn Marino
hostapd_single_channel_get_survey(struct hostapd_iface * iface,struct survey_results * survey_res)1420*a1157835SDaniel Fojt static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
1421*a1157835SDaniel Fojt struct survey_results *survey_res)
1422*a1157835SDaniel Fojt {
1423*a1157835SDaniel Fojt struct hostapd_channel_data *chan;
1424*a1157835SDaniel Fojt struct freq_survey *survey;
1425*a1157835SDaniel Fojt u64 divisor, dividend;
1426*a1157835SDaniel Fojt
1427*a1157835SDaniel Fojt survey = dl_list_first(&survey_res->survey_list, struct freq_survey,
1428*a1157835SDaniel Fojt list);
1429*a1157835SDaniel Fojt if (!survey || !survey->freq)
1430*a1157835SDaniel Fojt return;
1431*a1157835SDaniel Fojt
1432*a1157835SDaniel Fojt chan = hostapd_get_mode_channel(iface, survey->freq);
1433*a1157835SDaniel Fojt if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
1434*a1157835SDaniel Fojt return;
1435*a1157835SDaniel Fojt
1436*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1437*a1157835SDaniel Fojt "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
1438*a1157835SDaniel Fojt survey->freq,
1439*a1157835SDaniel Fojt (unsigned long int) survey->channel_time,
1440*a1157835SDaniel Fojt (unsigned long int) survey->channel_time_busy);
1441*a1157835SDaniel Fojt
1442*a1157835SDaniel Fojt if (survey->channel_time > iface->last_channel_time &&
1443*a1157835SDaniel Fojt survey->channel_time > survey->channel_time_busy) {
1444*a1157835SDaniel Fojt dividend = survey->channel_time_busy -
1445*a1157835SDaniel Fojt iface->last_channel_time_busy;
1446*a1157835SDaniel Fojt divisor = survey->channel_time - iface->last_channel_time;
1447*a1157835SDaniel Fojt
1448*a1157835SDaniel Fojt iface->channel_utilization = dividend * 255 / divisor;
1449*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "Channel Utilization: %d",
1450*a1157835SDaniel Fojt iface->channel_utilization);
1451*a1157835SDaniel Fojt }
1452*a1157835SDaniel Fojt iface->last_channel_time = survey->channel_time;
1453*a1157835SDaniel Fojt iface->last_channel_time_busy = survey->channel_time_busy;
1454*a1157835SDaniel Fojt }
1455*a1157835SDaniel Fojt
1456*a1157835SDaniel Fojt
hostapd_event_get_survey(struct hostapd_iface * iface,struct survey_results * survey_results)1457*a1157835SDaniel Fojt void hostapd_event_get_survey(struct hostapd_iface *iface,
14583ff40c12SJohn Marino struct survey_results *survey_results)
14593ff40c12SJohn Marino {
14603ff40c12SJohn Marino struct freq_survey *survey, *tmp;
14613ff40c12SJohn Marino struct hostapd_channel_data *chan;
14623ff40c12SJohn Marino
14633ff40c12SJohn Marino if (dl_list_empty(&survey_results->survey_list)) {
14643ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "No survey data received");
14653ff40c12SJohn Marino return;
14663ff40c12SJohn Marino }
14673ff40c12SJohn Marino
1468*a1157835SDaniel Fojt if (survey_results->freq_filter) {
1469*a1157835SDaniel Fojt hostapd_single_channel_get_survey(iface, survey_results);
1470*a1157835SDaniel Fojt return;
1471*a1157835SDaniel Fojt }
1472*a1157835SDaniel Fojt
14733ff40c12SJohn Marino dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
14743ff40c12SJohn Marino struct freq_survey, list) {
14753ff40c12SJohn Marino chan = hostapd_get_mode_channel(iface, survey->freq);
14763ff40c12SJohn Marino if (!chan)
14773ff40c12SJohn Marino continue;
14783ff40c12SJohn Marino if (chan->flag & HOSTAPD_CHAN_DISABLED)
14793ff40c12SJohn Marino continue;
14803ff40c12SJohn Marino
14813ff40c12SJohn Marino dl_list_del(&survey->list);
14823ff40c12SJohn Marino dl_list_add_tail(&chan->survey_list, &survey->list);
14833ff40c12SJohn Marino
14843ff40c12SJohn Marino hostapd_update_nf(iface, chan, survey);
14853ff40c12SJohn Marino
14863ff40c12SJohn Marino iface->chans_surveyed++;
14873ff40c12SJohn Marino }
14883ff40c12SJohn Marino }
14893ff40c12SJohn Marino
14903ff40c12SJohn Marino
1491*a1157835SDaniel Fojt #ifdef HOSTAPD
14923ff40c12SJohn Marino #ifdef NEED_AP_MLME
14933ff40c12SJohn Marino
hostapd_event_iface_unavailable(struct hostapd_data * hapd)1494*a1157835SDaniel Fojt static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
1495*a1157835SDaniel Fojt {
1496*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped",
1497*a1157835SDaniel Fojt hapd->conf->iface);
1498*a1157835SDaniel Fojt
1499*a1157835SDaniel Fojt if (hapd->csa_in_progress) {
1500*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "CSA failed (%s was stopped)",
1501*a1157835SDaniel Fojt hapd->conf->iface);
1502*a1157835SDaniel Fojt hostapd_switch_channel_fallback(hapd->iface,
1503*a1157835SDaniel Fojt &hapd->cs_freq_params);
1504*a1157835SDaniel Fojt }
1505*a1157835SDaniel Fojt }
1506*a1157835SDaniel Fojt
1507*a1157835SDaniel Fojt
hostapd_event_dfs_radar_detected(struct hostapd_data * hapd,struct dfs_event * radar)15083ff40c12SJohn Marino static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
15093ff40c12SJohn Marino struct dfs_event *radar)
15103ff40c12SJohn Marino {
15113ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
15123ff40c12SJohn Marino hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled,
15133ff40c12SJohn Marino radar->chan_offset, radar->chan_width,
15143ff40c12SJohn Marino radar->cf1, radar->cf2);
15153ff40c12SJohn Marino }
15163ff40c12SJohn Marino
15173ff40c12SJohn Marino
hostapd_event_dfs_pre_cac_expired(struct hostapd_data * hapd,struct dfs_event * radar)1518*a1157835SDaniel Fojt static void hostapd_event_dfs_pre_cac_expired(struct hostapd_data *hapd,
1519*a1157835SDaniel Fojt struct dfs_event *radar)
1520*a1157835SDaniel Fojt {
1521*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "DFS Pre-CAC expired on %d MHz", radar->freq);
1522*a1157835SDaniel Fojt hostapd_dfs_pre_cac_expired(hapd->iface, radar->freq, radar->ht_enabled,
1523*a1157835SDaniel Fojt radar->chan_offset, radar->chan_width,
1524*a1157835SDaniel Fojt radar->cf1, radar->cf2);
1525*a1157835SDaniel Fojt }
1526*a1157835SDaniel Fojt
1527*a1157835SDaniel Fojt
hostapd_event_dfs_cac_finished(struct hostapd_data * hapd,struct dfs_event * radar)15283ff40c12SJohn Marino static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd,
15293ff40c12SJohn Marino struct dfs_event *radar)
15303ff40c12SJohn Marino {
15313ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
15323ff40c12SJohn Marino hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled,
15333ff40c12SJohn Marino radar->chan_offset, radar->chan_width,
15343ff40c12SJohn Marino radar->cf1, radar->cf2);
15353ff40c12SJohn Marino }
15363ff40c12SJohn Marino
15373ff40c12SJohn Marino
hostapd_event_dfs_cac_aborted(struct hostapd_data * hapd,struct dfs_event * radar)15383ff40c12SJohn Marino static void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd,
15393ff40c12SJohn Marino struct dfs_event *radar)
15403ff40c12SJohn Marino {
15413ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
15423ff40c12SJohn Marino hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled,
15433ff40c12SJohn Marino radar->chan_offset, radar->chan_width,
15443ff40c12SJohn Marino radar->cf1, radar->cf2);
15453ff40c12SJohn Marino }
15463ff40c12SJohn Marino
15473ff40c12SJohn Marino
hostapd_event_dfs_nop_finished(struct hostapd_data * hapd,struct dfs_event * radar)15483ff40c12SJohn Marino static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd,
15493ff40c12SJohn Marino struct dfs_event *radar)
15503ff40c12SJohn Marino {
15513ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
15523ff40c12SJohn Marino hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled,
15533ff40c12SJohn Marino radar->chan_offset, radar->chan_width,
15543ff40c12SJohn Marino radar->cf1, radar->cf2);
15553ff40c12SJohn Marino }
15563ff40c12SJohn Marino
1557*a1157835SDaniel Fojt
hostapd_event_dfs_cac_started(struct hostapd_data * hapd,struct dfs_event * radar)1558*a1157835SDaniel Fojt static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
1559*a1157835SDaniel Fojt struct dfs_event *radar)
1560*a1157835SDaniel Fojt {
1561*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq);
1562*a1157835SDaniel Fojt hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled,
1563*a1157835SDaniel Fojt radar->chan_offset, radar->chan_width,
1564*a1157835SDaniel Fojt radar->cf1, radar->cf2);
1565*a1157835SDaniel Fojt }
1566*a1157835SDaniel Fojt
15673ff40c12SJohn Marino #endif /* NEED_AP_MLME */
15683ff40c12SJohn Marino
15693ff40c12SJohn Marino
hostapd_event_wds_sta_interface_status(struct hostapd_data * hapd,int istatus,const char * ifname,const u8 * addr)1570*a1157835SDaniel Fojt static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd,
1571*a1157835SDaniel Fojt int istatus,
1572*a1157835SDaniel Fojt const char *ifname,
1573*a1157835SDaniel Fojt const u8 *addr)
1574*a1157835SDaniel Fojt {
1575*a1157835SDaniel Fojt struct sta_info *sta = ap_get_sta(hapd, addr);
1576*a1157835SDaniel Fojt
1577*a1157835SDaniel Fojt if (sta) {
1578*a1157835SDaniel Fojt os_free(sta->ifname_wds);
1579*a1157835SDaniel Fojt if (istatus == INTERFACE_ADDED)
1580*a1157835SDaniel Fojt sta->ifname_wds = os_strdup(ifname);
1581*a1157835SDaniel Fojt else
1582*a1157835SDaniel Fojt sta->ifname_wds = NULL;
1583*a1157835SDaniel Fojt }
1584*a1157835SDaniel Fojt
1585*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, "%sifname=%s sta_addr=" MACSTR,
1586*a1157835SDaniel Fojt istatus == INTERFACE_ADDED ?
1587*a1157835SDaniel Fojt WDS_STA_INTERFACE_ADDED : WDS_STA_INTERFACE_REMOVED,
1588*a1157835SDaniel Fojt ifname, MAC2STR(addr));
1589*a1157835SDaniel Fojt }
1590*a1157835SDaniel Fojt
1591*a1157835SDaniel Fojt
1592*a1157835SDaniel Fojt #ifdef CONFIG_OWE
hostapd_notif_update_dh_ie(struct hostapd_data * hapd,const u8 * peer,const u8 * ie,size_t ie_len)1593*a1157835SDaniel Fojt static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd,
1594*a1157835SDaniel Fojt const u8 *peer, const u8 *ie,
1595*a1157835SDaniel Fojt size_t ie_len)
1596*a1157835SDaniel Fojt {
1597*a1157835SDaniel Fojt u16 status;
1598*a1157835SDaniel Fojt struct sta_info *sta;
1599*a1157835SDaniel Fojt struct ieee802_11_elems elems;
1600*a1157835SDaniel Fojt
1601*a1157835SDaniel Fojt if (!hapd || !hapd->wpa_auth) {
1602*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "OWE: Invalid hapd context");
1603*a1157835SDaniel Fojt return -1;
1604*a1157835SDaniel Fojt }
1605*a1157835SDaniel Fojt if (!peer) {
1606*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "OWE: Peer unknown");
1607*a1157835SDaniel Fojt return -1;
1608*a1157835SDaniel Fojt }
1609*a1157835SDaniel Fojt if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) {
1610*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured");
1611*a1157835SDaniel Fojt status = WLAN_STATUS_AKMP_NOT_VALID;
1612*a1157835SDaniel Fojt goto err;
1613*a1157835SDaniel Fojt }
1614*a1157835SDaniel Fojt if (ieee802_11_parse_elems(ie, ie_len, &elems, 1) == ParseFailed) {
1615*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "OWE: Failed to parse OWE IE for "
1616*a1157835SDaniel Fojt MACSTR, MAC2STR(peer));
1617*a1157835SDaniel Fojt status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1618*a1157835SDaniel Fojt goto err;
1619*a1157835SDaniel Fojt }
1620*a1157835SDaniel Fojt status = owe_validate_request(hapd, peer, elems.rsn_ie,
1621*a1157835SDaniel Fojt elems.rsn_ie_len,
1622*a1157835SDaniel Fojt elems.owe_dh, elems.owe_dh_len);
1623*a1157835SDaniel Fojt if (status != WLAN_STATUS_SUCCESS)
1624*a1157835SDaniel Fojt goto err;
1625*a1157835SDaniel Fojt
1626*a1157835SDaniel Fojt sta = ap_get_sta(hapd, peer);
1627*a1157835SDaniel Fojt if (sta) {
1628*a1157835SDaniel Fojt ap_sta_no_session_timeout(hapd, sta);
1629*a1157835SDaniel Fojt accounting_sta_stop(hapd, sta);
1630*a1157835SDaniel Fojt
1631*a1157835SDaniel Fojt /*
1632*a1157835SDaniel Fojt * Make sure that the previously registered inactivity timer
1633*a1157835SDaniel Fojt * will not remove the STA immediately.
1634*a1157835SDaniel Fojt */
1635*a1157835SDaniel Fojt sta->timeout_next = STA_NULLFUNC;
1636*a1157835SDaniel Fojt } else {
1637*a1157835SDaniel Fojt sta = ap_sta_add(hapd, peer);
1638*a1157835SDaniel Fojt if (!sta) {
1639*a1157835SDaniel Fojt status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1640*a1157835SDaniel Fojt goto err;
1641*a1157835SDaniel Fojt }
1642*a1157835SDaniel Fojt }
1643*a1157835SDaniel Fojt sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
1644*a1157835SDaniel Fojt
1645*a1157835SDaniel Fojt status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie,
1646*a1157835SDaniel Fojt elems.rsn_ie_len, elems.owe_dh,
1647*a1157835SDaniel Fojt elems.owe_dh_len);
1648*a1157835SDaniel Fojt if (status != WLAN_STATUS_SUCCESS)
1649*a1157835SDaniel Fojt ap_free_sta(hapd, sta);
1650*a1157835SDaniel Fojt
1651*a1157835SDaniel Fojt return 0;
1652*a1157835SDaniel Fojt err:
1653*a1157835SDaniel Fojt hostapd_drv_update_dh_ie(hapd, peer, status, NULL, 0);
1654*a1157835SDaniel Fojt return 0;
1655*a1157835SDaniel Fojt }
1656*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
1657*a1157835SDaniel Fojt
1658*a1157835SDaniel Fojt
wpa_supplicant_event(void * ctx,enum wpa_event_type event,union wpa_event_data * data)16593ff40c12SJohn Marino void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
16603ff40c12SJohn Marino union wpa_event_data *data)
16613ff40c12SJohn Marino {
16623ff40c12SJohn Marino struct hostapd_data *hapd = ctx;
16633ff40c12SJohn Marino #ifndef CONFIG_NO_STDOUT_DEBUG
16643ff40c12SJohn Marino int level = MSG_DEBUG;
16653ff40c12SJohn Marino
16663ff40c12SJohn Marino if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
16673ff40c12SJohn Marino data->rx_mgmt.frame_len >= 24) {
16683ff40c12SJohn Marino const struct ieee80211_hdr *hdr;
16693ff40c12SJohn Marino u16 fc;
1670*a1157835SDaniel Fojt
16713ff40c12SJohn Marino hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
16723ff40c12SJohn Marino fc = le_to_host16(hdr->frame_control);
16733ff40c12SJohn Marino if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
16743ff40c12SJohn Marino WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
16753ff40c12SJohn Marino level = MSG_EXCESSIVE;
16763ff40c12SJohn Marino if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
16773ff40c12SJohn Marino WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ)
16783ff40c12SJohn Marino level = MSG_EXCESSIVE;
16793ff40c12SJohn Marino }
16803ff40c12SJohn Marino
16813ff40c12SJohn Marino wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
16823ff40c12SJohn Marino event_to_string(event), event);
16833ff40c12SJohn Marino #endif /* CONFIG_NO_STDOUT_DEBUG */
16843ff40c12SJohn Marino
16853ff40c12SJohn Marino switch (event) {
16863ff40c12SJohn Marino case EVENT_MICHAEL_MIC_FAILURE:
16873ff40c12SJohn Marino michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
16883ff40c12SJohn Marino break;
16893ff40c12SJohn Marino case EVENT_SCAN_RESULTS:
16903ff40c12SJohn Marino if (hapd->iface->scan_cb)
16913ff40c12SJohn Marino hapd->iface->scan_cb(hapd->iface);
16923ff40c12SJohn Marino break;
16933ff40c12SJohn Marino case EVENT_WPS_BUTTON_PUSHED:
16943ff40c12SJohn Marino hostapd_wps_button_pushed(hapd, NULL);
16953ff40c12SJohn Marino break;
16963ff40c12SJohn Marino #ifdef NEED_AP_MLME
16973ff40c12SJohn Marino case EVENT_TX_STATUS:
16983ff40c12SJohn Marino switch (data->tx_status.type) {
16993ff40c12SJohn Marino case WLAN_FC_TYPE_MGMT:
17003ff40c12SJohn Marino hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
17013ff40c12SJohn Marino data->tx_status.data_len,
17023ff40c12SJohn Marino data->tx_status.stype,
17033ff40c12SJohn Marino data->tx_status.ack);
17043ff40c12SJohn Marino break;
17053ff40c12SJohn Marino case WLAN_FC_TYPE_DATA:
17063ff40c12SJohn Marino hostapd_tx_status(hapd, data->tx_status.dst,
17073ff40c12SJohn Marino data->tx_status.data,
17083ff40c12SJohn Marino data->tx_status.data_len,
17093ff40c12SJohn Marino data->tx_status.ack);
17103ff40c12SJohn Marino break;
17113ff40c12SJohn Marino }
17123ff40c12SJohn Marino break;
17133ff40c12SJohn Marino case EVENT_EAPOL_TX_STATUS:
17143ff40c12SJohn Marino hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
17153ff40c12SJohn Marino data->eapol_tx_status.data,
17163ff40c12SJohn Marino data->eapol_tx_status.data_len,
17173ff40c12SJohn Marino data->eapol_tx_status.ack);
17183ff40c12SJohn Marino break;
17193ff40c12SJohn Marino case EVENT_DRIVER_CLIENT_POLL_OK:
17203ff40c12SJohn Marino hostapd_client_poll_ok(hapd, data->client_poll.addr);
17213ff40c12SJohn Marino break;
17223ff40c12SJohn Marino case EVENT_RX_FROM_UNKNOWN:
17233ff40c12SJohn Marino hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
17243ff40c12SJohn Marino data->rx_from_unknown.addr,
17253ff40c12SJohn Marino data->rx_from_unknown.wds);
17263ff40c12SJohn Marino break;
17273ff40c12SJohn Marino #endif /* NEED_AP_MLME */
17283ff40c12SJohn Marino case EVENT_RX_MGMT:
1729*a1157835SDaniel Fojt if (!data->rx_mgmt.frame)
17303ff40c12SJohn Marino break;
1731*a1157835SDaniel Fojt #ifdef NEED_AP_MLME
1732*a1157835SDaniel Fojt hostapd_mgmt_rx(hapd, &data->rx_mgmt);
1733*a1157835SDaniel Fojt #else /* NEED_AP_MLME */
17343ff40c12SJohn Marino hostapd_action_rx(hapd, &data->rx_mgmt);
1735*a1157835SDaniel Fojt #endif /* NEED_AP_MLME */
17363ff40c12SJohn Marino break;
17373ff40c12SJohn Marino case EVENT_RX_PROBE_REQ:
17383ff40c12SJohn Marino if (data->rx_probe_req.sa == NULL ||
17393ff40c12SJohn Marino data->rx_probe_req.ie == NULL)
17403ff40c12SJohn Marino break;
17413ff40c12SJohn Marino hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
17423ff40c12SJohn Marino data->rx_probe_req.da,
17433ff40c12SJohn Marino data->rx_probe_req.bssid,
17443ff40c12SJohn Marino data->rx_probe_req.ie,
17453ff40c12SJohn Marino data->rx_probe_req.ie_len,
17463ff40c12SJohn Marino data->rx_probe_req.ssi_signal);
17473ff40c12SJohn Marino break;
17483ff40c12SJohn Marino case EVENT_NEW_STA:
17493ff40c12SJohn Marino hostapd_event_new_sta(hapd, data->new_sta.addr);
17503ff40c12SJohn Marino break;
17513ff40c12SJohn Marino case EVENT_EAPOL_RX:
17523ff40c12SJohn Marino hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
17533ff40c12SJohn Marino data->eapol_rx.data,
17543ff40c12SJohn Marino data->eapol_rx.data_len);
17553ff40c12SJohn Marino break;
17563ff40c12SJohn Marino case EVENT_ASSOC:
1757*a1157835SDaniel Fojt if (!data)
1758*a1157835SDaniel Fojt return;
17593ff40c12SJohn Marino hostapd_notif_assoc(hapd, data->assoc_info.addr,
17603ff40c12SJohn Marino data->assoc_info.req_ies,
17613ff40c12SJohn Marino data->assoc_info.req_ies_len,
17623ff40c12SJohn Marino data->assoc_info.reassoc);
17633ff40c12SJohn Marino break;
1764*a1157835SDaniel Fojt #ifdef CONFIG_OWE
1765*a1157835SDaniel Fojt case EVENT_UPDATE_DH:
1766*a1157835SDaniel Fojt if (!data)
1767*a1157835SDaniel Fojt return;
1768*a1157835SDaniel Fojt hostapd_notif_update_dh_ie(hapd, data->update_dh.peer,
1769*a1157835SDaniel Fojt data->update_dh.ie,
1770*a1157835SDaniel Fojt data->update_dh.ie_len);
1771*a1157835SDaniel Fojt break;
1772*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
17733ff40c12SJohn Marino case EVENT_DISASSOC:
17743ff40c12SJohn Marino if (data)
17753ff40c12SJohn Marino hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
17763ff40c12SJohn Marino break;
17773ff40c12SJohn Marino case EVENT_DEAUTH:
17783ff40c12SJohn Marino if (data)
17793ff40c12SJohn Marino hostapd_notif_disassoc(hapd, data->deauth_info.addr);
17803ff40c12SJohn Marino break;
17813ff40c12SJohn Marino case EVENT_STATION_LOW_ACK:
17823ff40c12SJohn Marino if (!data)
17833ff40c12SJohn Marino break;
17843ff40c12SJohn Marino hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
17853ff40c12SJohn Marino break;
17863ff40c12SJohn Marino case EVENT_AUTH:
17873ff40c12SJohn Marino hostapd_notif_auth(hapd, &data->auth);
17883ff40c12SJohn Marino break;
1789*a1157835SDaniel Fojt case EVENT_CH_SWITCH_STARTED:
17903ff40c12SJohn Marino case EVENT_CH_SWITCH:
17913ff40c12SJohn Marino if (!data)
17923ff40c12SJohn Marino break;
17933ff40c12SJohn Marino hostapd_event_ch_switch(hapd, data->ch_switch.freq,
17943ff40c12SJohn Marino data->ch_switch.ht_enabled,
17953ff40c12SJohn Marino data->ch_switch.ch_offset,
17963ff40c12SJohn Marino data->ch_switch.ch_width,
17973ff40c12SJohn Marino data->ch_switch.cf1,
1798*a1157835SDaniel Fojt data->ch_switch.cf2,
1799*a1157835SDaniel Fojt event == EVENT_CH_SWITCH);
18003ff40c12SJohn Marino break;
18013ff40c12SJohn Marino case EVENT_CONNECT_FAILED_REASON:
18023ff40c12SJohn Marino if (!data)
18033ff40c12SJohn Marino break;
18043ff40c12SJohn Marino hostapd_event_connect_failed_reason(
18053ff40c12SJohn Marino hapd, data->connect_failed_reason.addr,
18063ff40c12SJohn Marino data->connect_failed_reason.code);
18073ff40c12SJohn Marino break;
18083ff40c12SJohn Marino case EVENT_SURVEY:
1809*a1157835SDaniel Fojt hostapd_event_get_survey(hapd->iface, &data->survey_results);
18103ff40c12SJohn Marino break;
18113ff40c12SJohn Marino #ifdef NEED_AP_MLME
1812*a1157835SDaniel Fojt case EVENT_INTERFACE_UNAVAILABLE:
1813*a1157835SDaniel Fojt hostapd_event_iface_unavailable(hapd);
1814*a1157835SDaniel Fojt break;
18153ff40c12SJohn Marino case EVENT_DFS_RADAR_DETECTED:
18163ff40c12SJohn Marino if (!data)
18173ff40c12SJohn Marino break;
18183ff40c12SJohn Marino hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
18193ff40c12SJohn Marino break;
1820*a1157835SDaniel Fojt case EVENT_DFS_PRE_CAC_EXPIRED:
1821*a1157835SDaniel Fojt if (!data)
1822*a1157835SDaniel Fojt break;
1823*a1157835SDaniel Fojt hostapd_event_dfs_pre_cac_expired(hapd, &data->dfs_event);
1824*a1157835SDaniel Fojt break;
18253ff40c12SJohn Marino case EVENT_DFS_CAC_FINISHED:
18263ff40c12SJohn Marino if (!data)
18273ff40c12SJohn Marino break;
18283ff40c12SJohn Marino hostapd_event_dfs_cac_finished(hapd, &data->dfs_event);
18293ff40c12SJohn Marino break;
18303ff40c12SJohn Marino case EVENT_DFS_CAC_ABORTED:
18313ff40c12SJohn Marino if (!data)
18323ff40c12SJohn Marino break;
18333ff40c12SJohn Marino hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event);
18343ff40c12SJohn Marino break;
18353ff40c12SJohn Marino case EVENT_DFS_NOP_FINISHED:
18363ff40c12SJohn Marino if (!data)
18373ff40c12SJohn Marino break;
18383ff40c12SJohn Marino hostapd_event_dfs_nop_finished(hapd, &data->dfs_event);
18393ff40c12SJohn Marino break;
18403ff40c12SJohn Marino case EVENT_CHANNEL_LIST_CHANGED:
18413ff40c12SJohn Marino /* channel list changed (regulatory?), update channel list */
18423ff40c12SJohn Marino /* TODO: check this. hostapd_get_hw_features() initializes
18433ff40c12SJohn Marino * too much stuff. */
18443ff40c12SJohn Marino /* hostapd_get_hw_features(hapd->iface); */
18453ff40c12SJohn Marino hostapd_channel_list_updated(
18463ff40c12SJohn Marino hapd->iface, data->channel_list_changed.initiator);
18473ff40c12SJohn Marino break;
1848*a1157835SDaniel Fojt case EVENT_DFS_CAC_STARTED:
1849*a1157835SDaniel Fojt if (!data)
1850*a1157835SDaniel Fojt break;
1851*a1157835SDaniel Fojt hostapd_event_dfs_cac_started(hapd, &data->dfs_event);
1852*a1157835SDaniel Fojt break;
18533ff40c12SJohn Marino #endif /* NEED_AP_MLME */
1854*a1157835SDaniel Fojt case EVENT_INTERFACE_ENABLED:
1855*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
1856*a1157835SDaniel Fojt if (hapd->disabled && hapd->started) {
1857*a1157835SDaniel Fojt hapd->disabled = 0;
1858*a1157835SDaniel Fojt /*
1859*a1157835SDaniel Fojt * Try to re-enable interface if the driver stopped it
1860*a1157835SDaniel Fojt * when the interface got disabled.
1861*a1157835SDaniel Fojt */
1862*a1157835SDaniel Fojt if (hapd->wpa_auth)
1863*a1157835SDaniel Fojt wpa_auth_reconfig_group_keys(hapd->wpa_auth);
1864*a1157835SDaniel Fojt else
1865*a1157835SDaniel Fojt hostapd_reconfig_encryption(hapd);
1866*a1157835SDaniel Fojt hapd->reenable_beacon = 1;
1867*a1157835SDaniel Fojt ieee802_11_set_beacon(hapd);
1868*a1157835SDaniel Fojt #ifdef NEED_AP_MLME
1869*a1157835SDaniel Fojt } else if (hapd->disabled && hapd->iface->cac_started) {
1870*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC");
1871*a1157835SDaniel Fojt hostapd_handle_dfs(hapd->iface);
1872*a1157835SDaniel Fojt #endif /* NEED_AP_MLME */
1873*a1157835SDaniel Fojt }
1874*a1157835SDaniel Fojt break;
1875*a1157835SDaniel Fojt case EVENT_INTERFACE_DISABLED:
1876*a1157835SDaniel Fojt hostapd_free_stas(hapd);
1877*a1157835SDaniel Fojt wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
1878*a1157835SDaniel Fojt hapd->disabled = 1;
1879*a1157835SDaniel Fojt break;
1880*a1157835SDaniel Fojt #ifdef CONFIG_ACS
1881*a1157835SDaniel Fojt case EVENT_ACS_CHANNEL_SELECTED:
1882*a1157835SDaniel Fojt hostapd_acs_channel_selected(hapd,
1883*a1157835SDaniel Fojt &data->acs_selected_channels);
1884*a1157835SDaniel Fojt break;
1885*a1157835SDaniel Fojt #endif /* CONFIG_ACS */
1886*a1157835SDaniel Fojt case EVENT_STATION_OPMODE_CHANGED:
1887*a1157835SDaniel Fojt hostapd_event_sta_opmode_changed(hapd, data->sta_opmode.addr,
1888*a1157835SDaniel Fojt data->sta_opmode.smps_mode,
1889*a1157835SDaniel Fojt data->sta_opmode.chan_width,
1890*a1157835SDaniel Fojt data->sta_opmode.rx_nss);
1891*a1157835SDaniel Fojt break;
1892*a1157835SDaniel Fojt case EVENT_WDS_STA_INTERFACE_STATUS:
1893*a1157835SDaniel Fojt hostapd_event_wds_sta_interface_status(
1894*a1157835SDaniel Fojt hapd, data->wds_sta_interface.istatus,
1895*a1157835SDaniel Fojt data->wds_sta_interface.ifname,
1896*a1157835SDaniel Fojt data->wds_sta_interface.sta_addr);
1897*a1157835SDaniel Fojt break;
18983ff40c12SJohn Marino default:
18993ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Unknown event %d", event);
19003ff40c12SJohn Marino break;
19013ff40c12SJohn Marino }
19023ff40c12SJohn Marino }
19033ff40c12SJohn Marino
1904*a1157835SDaniel Fojt
wpa_supplicant_event_global(void * ctx,enum wpa_event_type event,union wpa_event_data * data)1905*a1157835SDaniel Fojt void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
1906*a1157835SDaniel Fojt union wpa_event_data *data)
1907*a1157835SDaniel Fojt {
1908*a1157835SDaniel Fojt struct hapd_interfaces *interfaces = ctx;
1909*a1157835SDaniel Fojt struct hostapd_data *hapd;
1910*a1157835SDaniel Fojt
1911*a1157835SDaniel Fojt if (event != EVENT_INTERFACE_STATUS)
1912*a1157835SDaniel Fojt return;
1913*a1157835SDaniel Fojt
1914*a1157835SDaniel Fojt hapd = hostapd_get_iface(interfaces, data->interface_status.ifname);
1915*a1157835SDaniel Fojt if (hapd && hapd->driver && hapd->driver->get_ifindex &&
1916*a1157835SDaniel Fojt hapd->drv_priv) {
1917*a1157835SDaniel Fojt unsigned int ifindex;
1918*a1157835SDaniel Fojt
1919*a1157835SDaniel Fojt ifindex = hapd->driver->get_ifindex(hapd->drv_priv);
1920*a1157835SDaniel Fojt if (ifindex != data->interface_status.ifindex) {
1921*a1157835SDaniel Fojt wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
1922*a1157835SDaniel Fojt "interface status ifindex %d mismatch (%d)",
1923*a1157835SDaniel Fojt ifindex, data->interface_status.ifindex);
1924*a1157835SDaniel Fojt return;
1925*a1157835SDaniel Fojt }
1926*a1157835SDaniel Fojt }
1927*a1157835SDaniel Fojt if (hapd)
1928*a1157835SDaniel Fojt wpa_supplicant_event(hapd, event, data);
1929*a1157835SDaniel Fojt }
1930*a1157835SDaniel Fojt
19313ff40c12SJohn Marino #endif /* HOSTAPD */
1932