1e28a4053SRui Paulo /* 2e28a4053SRui Paulo * hostapd / Station table 385732ac8SCy Schubert * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> 4e28a4053SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7e28a4053SRui Paulo */ 8e28a4053SRui Paulo 9e28a4053SRui Paulo #include "utils/includes.h" 10e28a4053SRui Paulo 11e28a4053SRui Paulo #include "utils/common.h" 12e28a4053SRui Paulo #include "utils/eloop.h" 13e28a4053SRui Paulo #include "common/ieee802_11_defs.h" 14f05cddf9SRui Paulo #include "common/wpa_ctrl.h" 155b9c547cSRui Paulo #include "common/sae.h" 164bc52338SCy Schubert #include "common/dpp.h" 17e28a4053SRui Paulo #include "radius/radius.h" 18e28a4053SRui Paulo #include "radius/radius_client.h" 19f05cddf9SRui Paulo #include "p2p/p2p.h" 20325151a3SRui Paulo #include "fst/fst.h" 2185732ac8SCy Schubert #include "crypto/crypto.h" 22e28a4053SRui Paulo #include "hostapd.h" 23e28a4053SRui Paulo #include "accounting.h" 24e28a4053SRui Paulo #include "ieee802_1x.h" 25e28a4053SRui Paulo #include "ieee802_11.h" 26f05cddf9SRui Paulo #include "ieee802_11_auth.h" 27e28a4053SRui Paulo #include "wpa_auth.h" 28e28a4053SRui Paulo #include "preauth_auth.h" 29e28a4053SRui Paulo #include "ap_config.h" 30e28a4053SRui Paulo #include "beacon.h" 31e28a4053SRui Paulo #include "ap_mlme.h" 32e28a4053SRui Paulo #include "vlan_init.h" 33f05cddf9SRui Paulo #include "p2p_hostapd.h" 34f05cddf9SRui Paulo #include "ap_drv_ops.h" 35f05cddf9SRui Paulo #include "gas_serv.h" 365b9c547cSRui Paulo #include "wnm_ap.h" 37780fb4a2SCy Schubert #include "mbo_ap.h" 385b9c547cSRui Paulo #include "ndisc_snoop.h" 39e28a4053SRui Paulo #include "sta_info.h" 40780fb4a2SCy Schubert #include "vlan.h" 4185732ac8SCy Schubert #include "wps_hostapd.h" 42e28a4053SRui Paulo 43e28a4053SRui Paulo static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, 44e28a4053SRui Paulo struct sta_info *sta); 45e28a4053SRui Paulo static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx); 465b9c547cSRui Paulo static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx); 47f05cddf9SRui Paulo static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx); 48f05cddf9SRui Paulo static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx); 49e28a4053SRui Paulo static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx); 50f05cddf9SRui Paulo static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta); 5185732ac8SCy Schubert static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx); 52e28a4053SRui Paulo 53e28a4053SRui Paulo int ap_for_each_sta(struct hostapd_data *hapd, 54e28a4053SRui Paulo int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, 55e28a4053SRui Paulo void *ctx), 56e28a4053SRui Paulo void *ctx) 57e28a4053SRui Paulo { 58e28a4053SRui Paulo struct sta_info *sta; 59e28a4053SRui Paulo 60e28a4053SRui Paulo for (sta = hapd->sta_list; sta; sta = sta->next) { 61e28a4053SRui Paulo if (cb(hapd, sta, ctx)) 62e28a4053SRui Paulo return 1; 63e28a4053SRui Paulo } 64e28a4053SRui Paulo 65e28a4053SRui Paulo return 0; 66e28a4053SRui Paulo } 67e28a4053SRui Paulo 68e28a4053SRui Paulo 69e28a4053SRui Paulo struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta) 70e28a4053SRui Paulo { 71e28a4053SRui Paulo struct sta_info *s; 72e28a4053SRui Paulo 73e28a4053SRui Paulo s = hapd->sta_hash[STA_HASH(sta)]; 74e28a4053SRui Paulo while (s != NULL && os_memcmp(s->addr, sta, 6) != 0) 75e28a4053SRui Paulo s = s->hnext; 76e28a4053SRui Paulo return s; 77e28a4053SRui Paulo } 78e28a4053SRui Paulo 79e28a4053SRui Paulo 805b9c547cSRui Paulo #ifdef CONFIG_P2P 815b9c547cSRui Paulo struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr) 825b9c547cSRui Paulo { 835b9c547cSRui Paulo struct sta_info *sta; 845b9c547cSRui Paulo 855b9c547cSRui Paulo for (sta = hapd->sta_list; sta; sta = sta->next) { 865b9c547cSRui Paulo const u8 *p2p_dev_addr; 875b9c547cSRui Paulo 885b9c547cSRui Paulo if (sta->p2p_ie == NULL) 895b9c547cSRui Paulo continue; 905b9c547cSRui Paulo 915b9c547cSRui Paulo p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); 925b9c547cSRui Paulo if (p2p_dev_addr == NULL) 935b9c547cSRui Paulo continue; 945b9c547cSRui Paulo 955b9c547cSRui Paulo if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0) 965b9c547cSRui Paulo return sta; 975b9c547cSRui Paulo } 985b9c547cSRui Paulo 995b9c547cSRui Paulo return NULL; 1005b9c547cSRui Paulo } 1015b9c547cSRui Paulo #endif /* CONFIG_P2P */ 1025b9c547cSRui Paulo 1035b9c547cSRui Paulo 104e28a4053SRui Paulo static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta) 105e28a4053SRui Paulo { 106e28a4053SRui Paulo struct sta_info *tmp; 107e28a4053SRui Paulo 108e28a4053SRui Paulo if (hapd->sta_list == sta) { 109e28a4053SRui Paulo hapd->sta_list = sta->next; 110e28a4053SRui Paulo return; 111e28a4053SRui Paulo } 112e28a4053SRui Paulo 113e28a4053SRui Paulo tmp = hapd->sta_list; 114e28a4053SRui Paulo while (tmp != NULL && tmp->next != sta) 115e28a4053SRui Paulo tmp = tmp->next; 116e28a4053SRui Paulo if (tmp == NULL) { 117e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from " 118e28a4053SRui Paulo "list.", MAC2STR(sta->addr)); 119e28a4053SRui Paulo } else 120e28a4053SRui Paulo tmp->next = sta->next; 121e28a4053SRui Paulo } 122e28a4053SRui Paulo 123e28a4053SRui Paulo 124e28a4053SRui Paulo void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta) 125e28a4053SRui Paulo { 126e28a4053SRui Paulo sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)]; 127e28a4053SRui Paulo hapd->sta_hash[STA_HASH(sta->addr)] = sta; 128e28a4053SRui Paulo } 129e28a4053SRui Paulo 130e28a4053SRui Paulo 131e28a4053SRui Paulo static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta) 132e28a4053SRui Paulo { 133e28a4053SRui Paulo struct sta_info *s; 134e28a4053SRui Paulo 135e28a4053SRui Paulo s = hapd->sta_hash[STA_HASH(sta->addr)]; 136e28a4053SRui Paulo if (s == NULL) return; 137e28a4053SRui Paulo if (os_memcmp(s->addr, sta->addr, 6) == 0) { 138e28a4053SRui Paulo hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext; 139e28a4053SRui Paulo return; 140e28a4053SRui Paulo } 141e28a4053SRui Paulo 142e28a4053SRui Paulo while (s->hnext != NULL && 143e28a4053SRui Paulo os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0) 144e28a4053SRui Paulo s = s->hnext; 145e28a4053SRui Paulo if (s->hnext != NULL) 146e28a4053SRui Paulo s->hnext = s->hnext->hnext; 147e28a4053SRui Paulo else 148e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR 149e28a4053SRui Paulo " from hash table", MAC2STR(sta->addr)); 150e28a4053SRui Paulo } 151e28a4053SRui Paulo 152e28a4053SRui Paulo 1535b9c547cSRui Paulo void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta) 1545b9c547cSRui Paulo { 1555b9c547cSRui Paulo sta_ip6addr_del(hapd, sta); 1565b9c547cSRui Paulo } 1575b9c547cSRui Paulo 1585b9c547cSRui Paulo 159*c1d255d3SCy Schubert #ifdef CONFIG_PASN 160*c1d255d3SCy Schubert 161*c1d255d3SCy Schubert void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta) 162*c1d255d3SCy Schubert { 163*c1d255d3SCy Schubert if (sta->pasn) { 164*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Free PASN context: " MACSTR, 165*c1d255d3SCy Schubert MAC2STR(sta->addr)); 166*c1d255d3SCy Schubert 167*c1d255d3SCy Schubert if (sta->pasn->ecdh) 168*c1d255d3SCy Schubert crypto_ecdh_deinit(sta->pasn->ecdh); 169*c1d255d3SCy Schubert 170*c1d255d3SCy Schubert wpabuf_free(sta->pasn->secret); 171*c1d255d3SCy Schubert sta->pasn->secret = NULL; 172*c1d255d3SCy Schubert 173*c1d255d3SCy Schubert #ifdef CONFIG_SAE 174*c1d255d3SCy Schubert sae_clear_data(&sta->pasn->sae); 175*c1d255d3SCy Schubert #endif /* CONFIG_SAE */ 176*c1d255d3SCy Schubert 177*c1d255d3SCy Schubert #ifdef CONFIG_FILS 178*c1d255d3SCy Schubert /* In practice this pointer should be NULL */ 179*c1d255d3SCy Schubert wpabuf_free(sta->pasn->fils.erp_resp); 180*c1d255d3SCy Schubert sta->pasn->fils.erp_resp = NULL; 181*c1d255d3SCy Schubert #endif /* CONFIG_FILS */ 182*c1d255d3SCy Schubert 183*c1d255d3SCy Schubert bin_clear_free(sta->pasn, sizeof(*sta->pasn)); 184*c1d255d3SCy Schubert sta->pasn = NULL; 185*c1d255d3SCy Schubert } 186*c1d255d3SCy Schubert } 187*c1d255d3SCy Schubert 188*c1d255d3SCy Schubert #endif /* CONFIG_PASN */ 189*c1d255d3SCy Schubert 190e28a4053SRui Paulo void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) 191e28a4053SRui Paulo { 192e28a4053SRui Paulo int set_beacon = 0; 193e28a4053SRui Paulo 194e28a4053SRui Paulo accounting_sta_stop(hapd, sta); 195e28a4053SRui Paulo 196f05cddf9SRui Paulo /* just in case */ 197f05cddf9SRui Paulo ap_sta_set_authorized(hapd, sta, 0); 198*c1d255d3SCy Schubert hostapd_set_sta_flags(hapd, sta); 199f05cddf9SRui Paulo 2004bc52338SCy Schubert if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) 2015b9c547cSRui Paulo hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0); 202e28a4053SRui Paulo 2035b9c547cSRui Paulo if (sta->ipaddr) 2045b9c547cSRui Paulo hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); 2055b9c547cSRui Paulo ap_sta_ip6addr_del(hapd, sta); 2065b9c547cSRui Paulo 2075b9c547cSRui Paulo if (!hapd->iface->driver_ap_teardown && 208780fb4a2SCy Schubert !(sta->flags & WLAN_STA_PREAUTH)) { 209f05cddf9SRui Paulo hostapd_drv_sta_remove(hapd, sta->addr); 210780fb4a2SCy Schubert sta->added_unassoc = 0; 211325151a3SRui Paulo } 212325151a3SRui Paulo 213e28a4053SRui Paulo ap_sta_hash_del(hapd, sta); 214e28a4053SRui Paulo ap_sta_list_del(hapd, sta); 215e28a4053SRui Paulo 216e28a4053SRui Paulo if (sta->aid > 0) 217e28a4053SRui Paulo hapd->sta_aid[(sta->aid - 1) / 32] &= 218e28a4053SRui Paulo ~BIT((sta->aid - 1) % 32); 219e28a4053SRui Paulo 220e28a4053SRui Paulo hapd->num_sta--; 221e28a4053SRui Paulo if (sta->nonerp_set) { 222e28a4053SRui Paulo sta->nonerp_set = 0; 223e28a4053SRui Paulo hapd->iface->num_sta_non_erp--; 224e28a4053SRui Paulo if (hapd->iface->num_sta_non_erp == 0) 225e28a4053SRui Paulo set_beacon++; 226e28a4053SRui Paulo } 227e28a4053SRui Paulo 228e28a4053SRui Paulo if (sta->no_short_slot_time_set) { 229e28a4053SRui Paulo sta->no_short_slot_time_set = 0; 230e28a4053SRui Paulo hapd->iface->num_sta_no_short_slot_time--; 23185732ac8SCy Schubert if (hapd->iface->current_mode && 23285732ac8SCy Schubert hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G 233e28a4053SRui Paulo && hapd->iface->num_sta_no_short_slot_time == 0) 234e28a4053SRui Paulo set_beacon++; 235e28a4053SRui Paulo } 236e28a4053SRui Paulo 237e28a4053SRui Paulo if (sta->no_short_preamble_set) { 238e28a4053SRui Paulo sta->no_short_preamble_set = 0; 239e28a4053SRui Paulo hapd->iface->num_sta_no_short_preamble--; 24085732ac8SCy Schubert if (hapd->iface->current_mode && 24185732ac8SCy Schubert hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G 242e28a4053SRui Paulo && hapd->iface->num_sta_no_short_preamble == 0) 243e28a4053SRui Paulo set_beacon++; 244e28a4053SRui Paulo } 245e28a4053SRui Paulo 246e28a4053SRui Paulo if (sta->no_ht_gf_set) { 247e28a4053SRui Paulo sta->no_ht_gf_set = 0; 248e28a4053SRui Paulo hapd->iface->num_sta_ht_no_gf--; 249e28a4053SRui Paulo } 250e28a4053SRui Paulo 251e28a4053SRui Paulo if (sta->no_ht_set) { 252e28a4053SRui Paulo sta->no_ht_set = 0; 253e28a4053SRui Paulo hapd->iface->num_sta_no_ht--; 254e28a4053SRui Paulo } 255e28a4053SRui Paulo 256e28a4053SRui Paulo if (sta->ht_20mhz_set) { 257e28a4053SRui Paulo sta->ht_20mhz_set = 0; 258e28a4053SRui Paulo hapd->iface->num_sta_ht_20mhz--; 259e28a4053SRui Paulo } 260e28a4053SRui Paulo 261780fb4a2SCy Schubert #ifdef CONFIG_TAXONOMY 262780fb4a2SCy Schubert wpabuf_free(sta->probe_ie_taxonomy); 263780fb4a2SCy Schubert sta->probe_ie_taxonomy = NULL; 264780fb4a2SCy Schubert wpabuf_free(sta->assoc_ie_taxonomy); 265780fb4a2SCy Schubert sta->assoc_ie_taxonomy = NULL; 266780fb4a2SCy Schubert #endif /* CONFIG_TAXONOMY */ 267780fb4a2SCy Schubert 2685b9c547cSRui Paulo ht40_intolerant_remove(hapd->iface, sta); 2695b9c547cSRui Paulo 270f05cddf9SRui Paulo #ifdef CONFIG_P2P 271f05cddf9SRui Paulo if (sta->no_p2p_set) { 272f05cddf9SRui Paulo sta->no_p2p_set = 0; 273f05cddf9SRui Paulo hapd->num_sta_no_p2p--; 274f05cddf9SRui Paulo if (hapd->num_sta_no_p2p == 0) 275f05cddf9SRui Paulo hostapd_p2p_non_p2p_sta_disconnected(hapd); 276f05cddf9SRui Paulo } 277f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 278f05cddf9SRui Paulo 279*c1d255d3SCy Schubert #ifdef NEED_AP_MLME 280e28a4053SRui Paulo if (hostapd_ht_operation_update(hapd->iface) > 0) 281e28a4053SRui Paulo set_beacon++; 282*c1d255d3SCy Schubert #endif /* NEED_AP_MLME */ 283e28a4053SRui Paulo 2845b9c547cSRui Paulo #ifdef CONFIG_MESH 2855b9c547cSRui Paulo if (hapd->mesh_sta_free_cb) 286780fb4a2SCy Schubert hapd->mesh_sta_free_cb(hapd, sta); 2875b9c547cSRui Paulo #endif /* CONFIG_MESH */ 2885b9c547cSRui Paulo 289e28a4053SRui Paulo if (set_beacon) 290e28a4053SRui Paulo ieee802_11_set_beacons(hapd->iface); 291e28a4053SRui Paulo 292f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR, 293f05cddf9SRui Paulo __func__, MAC2STR(sta->addr)); 294e28a4053SRui Paulo eloop_cancel_timeout(ap_handle_timer, hapd, sta); 295e28a4053SRui Paulo eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); 2965b9c547cSRui Paulo eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta); 297780fb4a2SCy Schubert ap_sta_clear_disconnect_timeouts(hapd, sta); 2985b9c547cSRui Paulo sae_clear_retransmit_timer(hapd, sta); 299e28a4053SRui Paulo 300780fb4a2SCy Schubert ieee802_1x_free_station(hapd, sta); 301e28a4053SRui Paulo wpa_auth_sta_deinit(sta->wpa_sm); 302e28a4053SRui Paulo rsn_preauth_free_station(hapd, sta); 303e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 3045b9c547cSRui Paulo if (hapd->radius) 305e28a4053SRui Paulo radius_client_flush_auth(hapd->radius, sta->addr); 306e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 307e28a4053SRui Paulo 308780fb4a2SCy Schubert #ifndef CONFIG_NO_VLAN 309780fb4a2SCy Schubert /* 310780fb4a2SCy Schubert * sta->wpa_sm->group needs to be released before so that 311780fb4a2SCy Schubert * vlan_remove_dynamic() can check that no stations are left on the 312780fb4a2SCy Schubert * AP_VLAN netdev. 313780fb4a2SCy Schubert */ 314780fb4a2SCy Schubert if (sta->vlan_id) 315780fb4a2SCy Schubert vlan_remove_dynamic(hapd, sta->vlan_id); 316780fb4a2SCy Schubert if (sta->vlan_id_bound) { 317780fb4a2SCy Schubert /* 318780fb4a2SCy Schubert * Need to remove the STA entry before potentially removing the 319780fb4a2SCy Schubert * VLAN. 320780fb4a2SCy Schubert */ 321780fb4a2SCy Schubert if (hapd->iface->driver_ap_teardown && 322780fb4a2SCy Schubert !(sta->flags & WLAN_STA_PREAUTH)) { 323780fb4a2SCy Schubert hostapd_drv_sta_remove(hapd, sta->addr); 324780fb4a2SCy Schubert sta->added_unassoc = 0; 325780fb4a2SCy Schubert } 326780fb4a2SCy Schubert vlan_remove_dynamic(hapd, sta->vlan_id_bound); 327780fb4a2SCy Schubert } 328780fb4a2SCy Schubert #endif /* CONFIG_NO_VLAN */ 329780fb4a2SCy Schubert 330e28a4053SRui Paulo os_free(sta->challenge); 331e28a4053SRui Paulo 332e28a4053SRui Paulo os_free(sta->sa_query_trans_id); 333e28a4053SRui Paulo eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); 334e28a4053SRui Paulo 335f05cddf9SRui Paulo #ifdef CONFIG_P2P 336f05cddf9SRui Paulo p2p_group_notif_disassoc(hapd->p2p_group, sta->addr); 337f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 338f05cddf9SRui Paulo 339f05cddf9SRui Paulo #ifdef CONFIG_INTERWORKING 340f05cddf9SRui Paulo if (sta->gas_dialog) { 341f05cddf9SRui Paulo int i; 342f05cddf9SRui Paulo for (i = 0; i < GAS_DIALOG_MAX; i++) 343f05cddf9SRui Paulo gas_serv_dialog_clear(&sta->gas_dialog[i]); 344f05cddf9SRui Paulo os_free(sta->gas_dialog); 345f05cddf9SRui Paulo } 346f05cddf9SRui Paulo #endif /* CONFIG_INTERWORKING */ 347f05cddf9SRui Paulo 348e28a4053SRui Paulo wpabuf_free(sta->wps_ie); 349f05cddf9SRui Paulo wpabuf_free(sta->p2p_ie); 350f05cddf9SRui Paulo wpabuf_free(sta->hs20_ie); 35185732ac8SCy Schubert wpabuf_free(sta->roaming_consortium); 352325151a3SRui Paulo #ifdef CONFIG_FST 353325151a3SRui Paulo wpabuf_free(sta->mb_ies); 354325151a3SRui Paulo #endif /* CONFIG_FST */ 355e28a4053SRui Paulo 356e28a4053SRui Paulo os_free(sta->ht_capabilities); 3575b9c547cSRui Paulo os_free(sta->vht_capabilities); 3584bc52338SCy Schubert os_free(sta->vht_operation); 359206b73d0SCy Schubert os_free(sta->he_capab); 360*c1d255d3SCy Schubert os_free(sta->he_6ghz_capab); 361f05cddf9SRui Paulo hostapd_free_psk_list(sta->psk); 362f05cddf9SRui Paulo os_free(sta->identity); 363f05cddf9SRui Paulo os_free(sta->radius_cui); 3645b9c547cSRui Paulo os_free(sta->remediation_url); 36585732ac8SCy Schubert os_free(sta->t_c_url); 3665b9c547cSRui Paulo wpabuf_free(sta->hs20_deauth_req); 3675b9c547cSRui Paulo os_free(sta->hs20_session_info_url); 3685b9c547cSRui Paulo 3695b9c547cSRui Paulo #ifdef CONFIG_SAE 3705b9c547cSRui Paulo sae_clear_data(sta->sae); 3715b9c547cSRui Paulo os_free(sta->sae); 3725b9c547cSRui Paulo #endif /* CONFIG_SAE */ 373e28a4053SRui Paulo 374780fb4a2SCy Schubert mbo_ap_sta_free(sta); 375780fb4a2SCy Schubert os_free(sta->supp_op_classes); 376780fb4a2SCy Schubert 37785732ac8SCy Schubert #ifdef CONFIG_FILS 37885732ac8SCy Schubert os_free(sta->fils_pending_assoc_req); 37985732ac8SCy Schubert wpabuf_free(sta->fils_hlp_resp); 38085732ac8SCy Schubert wpabuf_free(sta->hlp_dhcp_discover); 38185732ac8SCy Schubert eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 38285732ac8SCy Schubert #ifdef CONFIG_FILS_SK_PFS 38385732ac8SCy Schubert crypto_ecdh_deinit(sta->fils_ecdh); 38485732ac8SCy Schubert wpabuf_clear_free(sta->fils_dh_ss); 38585732ac8SCy Schubert wpabuf_free(sta->fils_g_sta); 38685732ac8SCy Schubert #endif /* CONFIG_FILS_SK_PFS */ 38785732ac8SCy Schubert #endif /* CONFIG_FILS */ 38885732ac8SCy Schubert 38985732ac8SCy Schubert #ifdef CONFIG_OWE 39085732ac8SCy Schubert bin_clear_free(sta->owe_pmk, sta->owe_pmk_len); 39185732ac8SCy Schubert crypto_ecdh_deinit(sta->owe_ecdh); 39285732ac8SCy Schubert #endif /* CONFIG_OWE */ 39385732ac8SCy Schubert 3944bc52338SCy Schubert #ifdef CONFIG_DPP2 3954bc52338SCy Schubert dpp_pfs_free(sta->dpp_pfs); 3964bc52338SCy Schubert sta->dpp_pfs = NULL; 3974bc52338SCy Schubert #endif /* CONFIG_DPP2 */ 3984bc52338SCy Schubert 39985732ac8SCy Schubert os_free(sta->ext_capability); 40085732ac8SCy Schubert 40185732ac8SCy Schubert #ifdef CONFIG_WNM_AP 40285732ac8SCy Schubert eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta); 40385732ac8SCy Schubert #endif /* CONFIG_WNM_AP */ 40485732ac8SCy Schubert 405*c1d255d3SCy Schubert #ifdef CONFIG_PASN 406*c1d255d3SCy Schubert ap_free_sta_pasn(hapd, sta); 407*c1d255d3SCy Schubert #endif /* CONFIG_PASN */ 408*c1d255d3SCy Schubert 40985732ac8SCy Schubert os_free(sta->ifname_wds); 41085732ac8SCy Schubert 411*c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 412*c1d255d3SCy Schubert os_free(sta->sae_postponed_commit); 413*c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 414*c1d255d3SCy Schubert 415e28a4053SRui Paulo os_free(sta); 416e28a4053SRui Paulo } 417e28a4053SRui Paulo 418e28a4053SRui Paulo 419e28a4053SRui Paulo void hostapd_free_stas(struct hostapd_data *hapd) 420e28a4053SRui Paulo { 421e28a4053SRui Paulo struct sta_info *sta, *prev; 422e28a4053SRui Paulo 423e28a4053SRui Paulo sta = hapd->sta_list; 424e28a4053SRui Paulo 425e28a4053SRui Paulo while (sta) { 426e28a4053SRui Paulo prev = sta; 427e28a4053SRui Paulo if (sta->flags & WLAN_STA_AUTH) { 428e28a4053SRui Paulo mlme_deauthenticate_indication( 429e28a4053SRui Paulo hapd, sta, WLAN_REASON_UNSPECIFIED); 430e28a4053SRui Paulo } 431e28a4053SRui Paulo sta = sta->next; 432e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Removing station " MACSTR, 433e28a4053SRui Paulo MAC2STR(prev->addr)); 434e28a4053SRui Paulo ap_free_sta(hapd, prev); 435e28a4053SRui Paulo } 436e28a4053SRui Paulo } 437e28a4053SRui Paulo 438e28a4053SRui Paulo 439e28a4053SRui Paulo /** 440e28a4053SRui Paulo * ap_handle_timer - Per STA timer handler 441e28a4053SRui Paulo * @eloop_ctx: struct hostapd_data * 442e28a4053SRui Paulo * @timeout_ctx: struct sta_info * 443e28a4053SRui Paulo * 444e28a4053SRui Paulo * This function is called to check station activity and to remove inactive 445e28a4053SRui Paulo * stations. 446e28a4053SRui Paulo */ 447e28a4053SRui Paulo void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) 448e28a4053SRui Paulo { 449e28a4053SRui Paulo struct hostapd_data *hapd = eloop_ctx; 450e28a4053SRui Paulo struct sta_info *sta = timeout_ctx; 451e28a4053SRui Paulo unsigned long next_time = 0; 4525b9c547cSRui Paulo int reason; 453e28a4053SRui Paulo 454780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d", 455780fb4a2SCy Schubert hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags, 456f05cddf9SRui Paulo sta->timeout_next); 457e28a4053SRui Paulo if (sta->timeout_next == STA_REMOVE) { 458e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 459e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, "deauthenticated due to " 460e28a4053SRui Paulo "local deauth request"); 461e28a4053SRui Paulo ap_free_sta(hapd, sta); 462e28a4053SRui Paulo return; 463e28a4053SRui Paulo } 464e28a4053SRui Paulo 465e28a4053SRui Paulo if ((sta->flags & WLAN_STA_ASSOC) && 466e28a4053SRui Paulo (sta->timeout_next == STA_NULLFUNC || 467e28a4053SRui Paulo sta->timeout_next == STA_DISASSOC)) { 468e28a4053SRui Paulo int inactive_sec; 469f05cddf9SRui Paulo /* 470f05cddf9SRui Paulo * Add random value to timeout so that we don't end up bouncing 471f05cddf9SRui Paulo * all stations at the same time if we have lots of associated 472f05cddf9SRui Paulo * stations that are idle (but keep re-associating). 473f05cddf9SRui Paulo */ 474f05cddf9SRui Paulo int fuzz = os_random() % 20; 475f05cddf9SRui Paulo inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr); 476e28a4053SRui Paulo if (inactive_sec == -1) { 477f05cddf9SRui Paulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, 478f05cddf9SRui Paulo "Check inactivity: Could not " 479f05cddf9SRui Paulo "get station info from kernel driver for " 480f05cddf9SRui Paulo MACSTR, MAC2STR(sta->addr)); 481f05cddf9SRui Paulo /* 482f05cddf9SRui Paulo * The driver may not support this functionality. 483f05cddf9SRui Paulo * Anyway, try again after the next inactivity timeout, 484f05cddf9SRui Paulo * but do not disconnect the station now. 485f05cddf9SRui Paulo */ 486f05cddf9SRui Paulo next_time = hapd->conf->ap_max_inactivity + fuzz; 4875b9c547cSRui Paulo } else if (inactive_sec == -ENOENT) { 4885b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, 4895b9c547cSRui Paulo "Station " MACSTR " has lost its driver entry", 4905b9c547cSRui Paulo MAC2STR(sta->addr)); 4915b9c547cSRui Paulo 4925b9c547cSRui Paulo /* Avoid sending client probe on removed client */ 4935b9c547cSRui Paulo sta->timeout_next = STA_DISASSOC; 4945b9c547cSRui Paulo goto skip_poll; 4955b9c547cSRui Paulo } else if (inactive_sec < hapd->conf->ap_max_inactivity) { 496e28a4053SRui Paulo /* station activity detected; reset timeout state */ 497f05cddf9SRui Paulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, 498f05cddf9SRui Paulo "Station " MACSTR " has been active %is ago", 499f05cddf9SRui Paulo MAC2STR(sta->addr), inactive_sec); 500e28a4053SRui Paulo sta->timeout_next = STA_NULLFUNC; 501f05cddf9SRui Paulo next_time = hapd->conf->ap_max_inactivity + fuzz - 502e28a4053SRui Paulo inactive_sec; 503f05cddf9SRui Paulo } else { 504f05cddf9SRui Paulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, 505f05cddf9SRui Paulo "Station " MACSTR " has been " 506f05cddf9SRui Paulo "inactive too long: %d sec, max allowed: %d", 507f05cddf9SRui Paulo MAC2STR(sta->addr), inactive_sec, 508f05cddf9SRui Paulo hapd->conf->ap_max_inactivity); 509f05cddf9SRui Paulo 510f05cddf9SRui Paulo if (hapd->conf->skip_inactivity_poll) 511f05cddf9SRui Paulo sta->timeout_next = STA_DISASSOC; 512e28a4053SRui Paulo } 513e28a4053SRui Paulo } 514e28a4053SRui Paulo 515e28a4053SRui Paulo if ((sta->flags & WLAN_STA_ASSOC) && 516e28a4053SRui Paulo sta->timeout_next == STA_DISASSOC && 517f05cddf9SRui Paulo !(sta->flags & WLAN_STA_PENDING_POLL) && 518f05cddf9SRui Paulo !hapd->conf->skip_inactivity_poll) { 519f05cddf9SRui Paulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR 520f05cddf9SRui Paulo " has ACKed data poll", MAC2STR(sta->addr)); 521e28a4053SRui Paulo /* data nullfunc frame poll did not produce TX errors; assume 522e28a4053SRui Paulo * station ACKed it */ 523e28a4053SRui Paulo sta->timeout_next = STA_NULLFUNC; 524e28a4053SRui Paulo next_time = hapd->conf->ap_max_inactivity; 525e28a4053SRui Paulo } 526e28a4053SRui Paulo 5275b9c547cSRui Paulo skip_poll: 528e28a4053SRui Paulo if (next_time) { 529f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " 530f05cddf9SRui Paulo "for " MACSTR " (%lu seconds)", 531f05cddf9SRui Paulo __func__, MAC2STR(sta->addr), next_time); 532e28a4053SRui Paulo eloop_register_timeout(next_time, 0, ap_handle_timer, hapd, 533e28a4053SRui Paulo sta); 534e28a4053SRui Paulo return; 535e28a4053SRui Paulo } 536e28a4053SRui Paulo 537e28a4053SRui Paulo if (sta->timeout_next == STA_NULLFUNC && 538e28a4053SRui Paulo (sta->flags & WLAN_STA_ASSOC)) { 539f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, " Polling STA"); 540e28a4053SRui Paulo sta->flags |= WLAN_STA_PENDING_POLL; 541f05cddf9SRui Paulo hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr, 542f05cddf9SRui Paulo sta->flags & WLAN_STA_WMM); 543e28a4053SRui Paulo } else if (sta->timeout_next != STA_REMOVE) { 544e28a4053SRui Paulo int deauth = sta->timeout_next == STA_DEAUTH; 545e28a4053SRui Paulo 5464bc52338SCy Schubert if (!deauth && !(sta->flags & WLAN_STA_ASSOC)) { 5474bc52338SCy Schubert /* Cannot disassociate not-associated STA, so move 5484bc52338SCy Schubert * directly to deauthentication. */ 5494bc52338SCy Schubert sta->timeout_next = STA_DEAUTH; 5504bc52338SCy Schubert deauth = 1; 5514bc52338SCy Schubert } 5524bc52338SCy Schubert 553f05cddf9SRui Paulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, 554f05cddf9SRui Paulo "Timeout, sending %s info to STA " MACSTR, 555e28a4053SRui Paulo deauth ? "deauthentication" : "disassociation", 556e28a4053SRui Paulo MAC2STR(sta->addr)); 557e28a4053SRui Paulo 558e28a4053SRui Paulo if (deauth) { 559f05cddf9SRui Paulo hostapd_drv_sta_deauth( 560f05cddf9SRui Paulo hapd, sta->addr, 561e28a4053SRui Paulo WLAN_REASON_PREV_AUTH_NOT_VALID); 562e28a4053SRui Paulo } else { 5635b9c547cSRui Paulo reason = (sta->timeout_next == STA_DISASSOC) ? 5645b9c547cSRui Paulo WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : 5655b9c547cSRui Paulo WLAN_REASON_PREV_AUTH_NOT_VALID; 5665b9c547cSRui Paulo 5675b9c547cSRui Paulo hostapd_drv_sta_disassoc(hapd, sta->addr, reason); 568e28a4053SRui Paulo } 569e28a4053SRui Paulo } 570e28a4053SRui Paulo 571e28a4053SRui Paulo switch (sta->timeout_next) { 572e28a4053SRui Paulo case STA_NULLFUNC: 573e28a4053SRui Paulo sta->timeout_next = STA_DISASSOC; 574f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " 575f05cddf9SRui Paulo "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)", 576f05cddf9SRui Paulo __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY); 577e28a4053SRui Paulo eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer, 578e28a4053SRui Paulo hapd, sta); 579e28a4053SRui Paulo break; 580e28a4053SRui Paulo case STA_DISASSOC: 5815b9c547cSRui Paulo case STA_DISASSOC_FROM_CLI: 582f05cddf9SRui Paulo ap_sta_set_authorized(hapd, sta, 0); 583e28a4053SRui Paulo sta->flags &= ~WLAN_STA_ASSOC; 584*c1d255d3SCy Schubert hostapd_set_sta_flags(hapd, sta); 585e28a4053SRui Paulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 586e28a4053SRui Paulo if (!sta->acct_terminate_cause) 587e28a4053SRui Paulo sta->acct_terminate_cause = 588e28a4053SRui Paulo RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; 589e28a4053SRui Paulo accounting_sta_stop(hapd, sta); 590780fb4a2SCy Schubert ieee802_1x_free_station(hapd, sta); 591e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 592e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, "disassociated due to " 593e28a4053SRui Paulo "inactivity"); 5945b9c547cSRui Paulo reason = (sta->timeout_next == STA_DISASSOC) ? 5955b9c547cSRui Paulo WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : 5965b9c547cSRui Paulo WLAN_REASON_PREV_AUTH_NOT_VALID; 597e28a4053SRui Paulo sta->timeout_next = STA_DEAUTH; 598f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " 599f05cddf9SRui Paulo "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)", 600f05cddf9SRui Paulo __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY); 601e28a4053SRui Paulo eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, 602e28a4053SRui Paulo hapd, sta); 6035b9c547cSRui Paulo mlme_disassociate_indication(hapd, sta, reason); 604e28a4053SRui Paulo break; 605e28a4053SRui Paulo case STA_DEAUTH: 606e28a4053SRui Paulo case STA_REMOVE: 607e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 608e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, "deauthenticated due to " 609f05cddf9SRui Paulo "inactivity (timer DEAUTH/REMOVE)"); 610e28a4053SRui Paulo if (!sta->acct_terminate_cause) 611e28a4053SRui Paulo sta->acct_terminate_cause = 612e28a4053SRui Paulo RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; 613e28a4053SRui Paulo mlme_deauthenticate_indication( 614e28a4053SRui Paulo hapd, sta, 615e28a4053SRui Paulo WLAN_REASON_PREV_AUTH_NOT_VALID); 616e28a4053SRui Paulo ap_free_sta(hapd, sta); 617e28a4053SRui Paulo break; 618e28a4053SRui Paulo } 619e28a4053SRui Paulo } 620e28a4053SRui Paulo 621e28a4053SRui Paulo 622e28a4053SRui Paulo static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx) 623e28a4053SRui Paulo { 624e28a4053SRui Paulo struct hostapd_data *hapd = eloop_ctx; 625e28a4053SRui Paulo struct sta_info *sta = timeout_ctx; 626e28a4053SRui Paulo 627780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR, 628780fb4a2SCy Schubert hapd->conf->iface, MAC2STR(sta->addr)); 629*c1d255d3SCy Schubert if (!(sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC | 630*c1d255d3SCy Schubert WLAN_STA_AUTHORIZED))) { 631f05cddf9SRui Paulo if (sta->flags & WLAN_STA_GAS) { 632f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA " 633f05cddf9SRui Paulo "entry " MACSTR, MAC2STR(sta->addr)); 634f05cddf9SRui Paulo ap_free_sta(hapd, sta); 635f05cddf9SRui Paulo } 636e28a4053SRui Paulo return; 637f05cddf9SRui Paulo } 638e28a4053SRui Paulo 6395b9c547cSRui Paulo hostapd_drv_sta_deauth(hapd, sta->addr, 6405b9c547cSRui Paulo WLAN_REASON_PREV_AUTH_NOT_VALID); 641e28a4053SRui Paulo mlme_deauthenticate_indication(hapd, sta, 642e28a4053SRui Paulo WLAN_REASON_PREV_AUTH_NOT_VALID); 643e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 644e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, "deauthenticated due to " 645e28a4053SRui Paulo "session timeout"); 646e28a4053SRui Paulo sta->acct_terminate_cause = 647e28a4053SRui Paulo RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT; 648e28a4053SRui Paulo ap_free_sta(hapd, sta); 6495b9c547cSRui Paulo } 6505b9c547cSRui Paulo 6515b9c547cSRui Paulo 6525b9c547cSRui Paulo void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta, 6535b9c547cSRui Paulo u32 session_timeout) 6545b9c547cSRui Paulo { 6555b9c547cSRui Paulo if (eloop_replenish_timeout(session_timeout, 0, 6565b9c547cSRui Paulo ap_handle_session_timer, hapd, sta) == 1) { 6575b9c547cSRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 6585b9c547cSRui Paulo HOSTAPD_LEVEL_DEBUG, "setting session timeout " 6595b9c547cSRui Paulo "to %d seconds", session_timeout); 6605b9c547cSRui Paulo } 661e28a4053SRui Paulo } 662e28a4053SRui Paulo 663e28a4053SRui Paulo 664e28a4053SRui Paulo void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, 665e28a4053SRui Paulo u32 session_timeout) 666e28a4053SRui Paulo { 667e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 668e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d " 669e28a4053SRui Paulo "seconds", session_timeout); 670e28a4053SRui Paulo eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); 671e28a4053SRui Paulo eloop_register_timeout(session_timeout, 0, ap_handle_session_timer, 672e28a4053SRui Paulo hapd, sta); 673e28a4053SRui Paulo } 674e28a4053SRui Paulo 675e28a4053SRui Paulo 676e28a4053SRui Paulo void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta) 677e28a4053SRui Paulo { 678e28a4053SRui Paulo eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); 679e28a4053SRui Paulo } 680e28a4053SRui Paulo 681e28a4053SRui Paulo 6825b9c547cSRui Paulo static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx) 6835b9c547cSRui Paulo { 68485732ac8SCy Schubert #ifdef CONFIG_WNM_AP 6855b9c547cSRui Paulo struct hostapd_data *hapd = eloop_ctx; 6865b9c547cSRui Paulo struct sta_info *sta = timeout_ctx; 6875b9c547cSRui Paulo 688780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "%s: WNM: Session warning time reached for " 689780fb4a2SCy Schubert MACSTR, hapd->conf->iface, MAC2STR(sta->addr)); 6905b9c547cSRui Paulo if (sta->hs20_session_info_url == NULL) 6915b9c547cSRui Paulo return; 6925b9c547cSRui Paulo 6935b9c547cSRui Paulo wnm_send_ess_disassoc_imminent(hapd, sta, sta->hs20_session_info_url, 6945b9c547cSRui Paulo sta->hs20_disassoc_timer); 69585732ac8SCy Schubert #endif /* CONFIG_WNM_AP */ 6965b9c547cSRui Paulo } 6975b9c547cSRui Paulo 6985b9c547cSRui Paulo 6995b9c547cSRui Paulo void ap_sta_session_warning_timeout(struct hostapd_data *hapd, 7005b9c547cSRui Paulo struct sta_info *sta, int warning_time) 7015b9c547cSRui Paulo { 7025b9c547cSRui Paulo eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta); 7035b9c547cSRui Paulo eloop_register_timeout(warning_time, 0, ap_handle_session_warning_timer, 7045b9c547cSRui Paulo hapd, sta); 7055b9c547cSRui Paulo } 7065b9c547cSRui Paulo 7075b9c547cSRui Paulo 708e28a4053SRui Paulo struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) 709e28a4053SRui Paulo { 710e28a4053SRui Paulo struct sta_info *sta; 711206b73d0SCy Schubert int i; 712e28a4053SRui Paulo 713e28a4053SRui Paulo sta = ap_get_sta(hapd, addr); 714e28a4053SRui Paulo if (sta) 715e28a4053SRui Paulo return sta; 716e28a4053SRui Paulo 717e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " New STA"); 718e28a4053SRui Paulo if (hapd->num_sta >= hapd->conf->max_num_sta) { 719e28a4053SRui Paulo /* FIX: might try to remove some old STAs first? */ 720e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)", 721e28a4053SRui Paulo hapd->num_sta, hapd->conf->max_num_sta); 722e28a4053SRui Paulo return NULL; 723e28a4053SRui Paulo } 724e28a4053SRui Paulo 725e28a4053SRui Paulo sta = os_zalloc(sizeof(struct sta_info)); 726e28a4053SRui Paulo if (sta == NULL) { 727e28a4053SRui Paulo wpa_printf(MSG_ERROR, "malloc failed"); 728e28a4053SRui Paulo return NULL; 729e28a4053SRui Paulo } 730e28a4053SRui Paulo sta->acct_interim_interval = hapd->conf->acct_interim_interval; 731780fb4a2SCy Schubert if (accounting_sta_get_id(hapd, sta) < 0) { 732780fb4a2SCy Schubert os_free(sta); 733780fb4a2SCy Schubert return NULL; 734780fb4a2SCy Schubert } 735e28a4053SRui Paulo 736206b73d0SCy Schubert for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) { 737206b73d0SCy Schubert if (!hapd->iface->basic_rates) 738206b73d0SCy Schubert break; 739206b73d0SCy Schubert if (hapd->iface->basic_rates[i] < 0) 740206b73d0SCy Schubert break; 741206b73d0SCy Schubert sta->supported_rates[i] = hapd->iface->basic_rates[i] / 5; 742206b73d0SCy Schubert } 743206b73d0SCy Schubert sta->supported_rates_len = i; 744206b73d0SCy Schubert 7455b9c547cSRui Paulo if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) { 746f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " 747f05cddf9SRui Paulo "for " MACSTR " (%d seconds - ap_max_inactivity)", 748f05cddf9SRui Paulo __func__, MAC2STR(addr), 749f05cddf9SRui Paulo hapd->conf->ap_max_inactivity); 750e28a4053SRui Paulo eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, 751e28a4053SRui Paulo ap_handle_timer, hapd, sta); 7525b9c547cSRui Paulo } 7535b9c547cSRui Paulo 7545b9c547cSRui Paulo /* initialize STA info data */ 755e28a4053SRui Paulo os_memcpy(sta->addr, addr, ETH_ALEN); 756e28a4053SRui Paulo sta->next = hapd->sta_list; 757e28a4053SRui Paulo hapd->sta_list = sta; 758e28a4053SRui Paulo hapd->num_sta++; 759e28a4053SRui Paulo ap_sta_hash_add(hapd, sta); 760e28a4053SRui Paulo ap_sta_remove_in_other_bss(hapd, sta); 7615b9c547cSRui Paulo sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; 7625b9c547cSRui Paulo dl_list_init(&sta->ip6addr); 763e28a4053SRui Paulo 764780fb4a2SCy Schubert #ifdef CONFIG_TAXONOMY 765780fb4a2SCy Schubert sta_track_claim_taxonomy_info(hapd->iface, addr, 766780fb4a2SCy Schubert &sta->probe_ie_taxonomy); 767780fb4a2SCy Schubert #endif /* CONFIG_TAXONOMY */ 768780fb4a2SCy Schubert 769e28a4053SRui Paulo return sta; 770e28a4053SRui Paulo } 771e28a4053SRui Paulo 772e28a4053SRui Paulo 773e28a4053SRui Paulo static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta) 774e28a4053SRui Paulo { 775e28a4053SRui Paulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 776e28a4053SRui Paulo 7775b9c547cSRui Paulo if (sta->ipaddr) 7785b9c547cSRui Paulo hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); 7795b9c547cSRui Paulo ap_sta_ip6addr_del(hapd, sta); 7805b9c547cSRui Paulo 781780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "%s: Removing STA " MACSTR " from kernel driver", 782780fb4a2SCy Schubert hapd->conf->iface, MAC2STR(sta->addr)); 783f05cddf9SRui Paulo if (hostapd_drv_sta_remove(hapd, sta->addr) && 784e28a4053SRui Paulo sta->flags & WLAN_STA_ASSOC) { 785780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "%s: Could not remove station " MACSTR 786780fb4a2SCy Schubert " from kernel driver", 787780fb4a2SCy Schubert hapd->conf->iface, MAC2STR(sta->addr)); 788e28a4053SRui Paulo return -1; 789e28a4053SRui Paulo } 790780fb4a2SCy Schubert sta->added_unassoc = 0; 791e28a4053SRui Paulo return 0; 792e28a4053SRui Paulo } 793e28a4053SRui Paulo 794e28a4053SRui Paulo 795e28a4053SRui Paulo static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, 796e28a4053SRui Paulo struct sta_info *sta) 797e28a4053SRui Paulo { 798e28a4053SRui Paulo struct hostapd_iface *iface = hapd->iface; 799e28a4053SRui Paulo size_t i; 800e28a4053SRui Paulo 801e28a4053SRui Paulo for (i = 0; i < iface->num_bss; i++) { 802e28a4053SRui Paulo struct hostapd_data *bss = iface->bss[i]; 803e28a4053SRui Paulo struct sta_info *sta2; 804e28a4053SRui Paulo /* bss should always be set during operation, but it may be 805e28a4053SRui Paulo * NULL during reconfiguration. Assume the STA is not 806e28a4053SRui Paulo * associated to another BSS in that case to avoid NULL pointer 807e28a4053SRui Paulo * dereferences. */ 808e28a4053SRui Paulo if (bss == hapd || bss == NULL) 809e28a4053SRui Paulo continue; 810e28a4053SRui Paulo sta2 = ap_get_sta(bss, sta->addr); 811e28a4053SRui Paulo if (!sta2) 812e28a4053SRui Paulo continue; 813e28a4053SRui Paulo 814780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "%s: disconnect old STA " MACSTR 815780fb4a2SCy Schubert " association from another BSS %s", 816780fb4a2SCy Schubert hapd->conf->iface, MAC2STR(sta2->addr), 817780fb4a2SCy Schubert bss->conf->iface); 818e28a4053SRui Paulo ap_sta_disconnect(bss, sta2, sta2->addr, 819e28a4053SRui Paulo WLAN_REASON_PREV_AUTH_NOT_VALID); 820e28a4053SRui Paulo } 821e28a4053SRui Paulo } 822e28a4053SRui Paulo 823e28a4053SRui Paulo 824f05cddf9SRui Paulo static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx) 825f05cddf9SRui Paulo { 826f05cddf9SRui Paulo struct hostapd_data *hapd = eloop_ctx; 827f05cddf9SRui Paulo struct sta_info *sta = timeout_ctx; 828f05cddf9SRui Paulo 829780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "%s: Disassociation callback for STA " MACSTR, 830780fb4a2SCy Schubert hapd->conf->iface, MAC2STR(sta->addr)); 831f05cddf9SRui Paulo ap_sta_remove(hapd, sta); 832f05cddf9SRui Paulo mlme_disassociate_indication(hapd, sta, sta->disassoc_reason); 833f05cddf9SRui Paulo } 834f05cddf9SRui Paulo 835f05cddf9SRui Paulo 836e28a4053SRui Paulo void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, 837e28a4053SRui Paulo u16 reason) 838e28a4053SRui Paulo { 839e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR, 840e28a4053SRui Paulo hapd->conf->iface, MAC2STR(sta->addr)); 8415b9c547cSRui Paulo sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; 84285732ac8SCy Schubert if (hapd->iface->current_mode && 84385732ac8SCy Schubert hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { 84485732ac8SCy Schubert /* Skip deauthentication in DMG/IEEE 802.11ad */ 84585732ac8SCy Schubert sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | 84685732ac8SCy Schubert WLAN_STA_ASSOC_REQ_OK); 84785732ac8SCy Schubert sta->timeout_next = STA_REMOVE; 84885732ac8SCy Schubert } else { 8495b9c547cSRui Paulo sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); 850e28a4053SRui Paulo sta->timeout_next = STA_DEAUTH; 85185732ac8SCy Schubert } 85285732ac8SCy Schubert ap_sta_set_authorized(hapd, sta, 0); 853*c1d255d3SCy Schubert hostapd_set_sta_flags(hapd, sta); 854f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " 855f05cddf9SRui Paulo "for " MACSTR " (%d seconds - " 856f05cddf9SRui Paulo "AP_MAX_INACTIVITY_AFTER_DISASSOC)", 857f05cddf9SRui Paulo __func__, MAC2STR(sta->addr), 858f05cddf9SRui Paulo AP_MAX_INACTIVITY_AFTER_DISASSOC); 859e28a4053SRui Paulo eloop_cancel_timeout(ap_handle_timer, hapd, sta); 860e28a4053SRui Paulo eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0, 861e28a4053SRui Paulo ap_handle_timer, hapd, sta); 862e28a4053SRui Paulo accounting_sta_stop(hapd, sta); 863780fb4a2SCy Schubert ieee802_1x_free_station(hapd, sta); 8644bc52338SCy Schubert wpa_auth_sta_deinit(sta->wpa_sm); 8654bc52338SCy Schubert sta->wpa_sm = NULL; 866e28a4053SRui Paulo 867f05cddf9SRui Paulo sta->disassoc_reason = reason; 868f05cddf9SRui Paulo sta->flags |= WLAN_STA_PENDING_DISASSOC_CB; 869f05cddf9SRui Paulo eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); 870f05cddf9SRui Paulo eloop_register_timeout(hapd->iface->drv_flags & 871f05cddf9SRui Paulo WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, 872f05cddf9SRui Paulo ap_sta_disassoc_cb_timeout, hapd, sta); 873f05cddf9SRui Paulo } 874f05cddf9SRui Paulo 875f05cddf9SRui Paulo 876f05cddf9SRui Paulo static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx) 877f05cddf9SRui Paulo { 878f05cddf9SRui Paulo struct hostapd_data *hapd = eloop_ctx; 879f05cddf9SRui Paulo struct sta_info *sta = timeout_ctx; 880f05cddf9SRui Paulo 881780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "%s: Deauthentication callback for STA " MACSTR, 882780fb4a2SCy Schubert hapd->conf->iface, MAC2STR(sta->addr)); 883f05cddf9SRui Paulo ap_sta_remove(hapd, sta); 884f05cddf9SRui Paulo mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason); 885e28a4053SRui Paulo } 886e28a4053SRui Paulo 887e28a4053SRui Paulo 888e28a4053SRui Paulo void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, 889e28a4053SRui Paulo u16 reason) 890e28a4053SRui Paulo { 89185732ac8SCy Schubert if (hapd->iface->current_mode && 89285732ac8SCy Schubert hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { 89385732ac8SCy Schubert /* Deauthentication is not used in DMG/IEEE 802.11ad; 89485732ac8SCy Schubert * disassociate the STA instead. */ 89585732ac8SCy Schubert ap_sta_disassociate(hapd, sta, reason); 89685732ac8SCy Schubert return; 89785732ac8SCy Schubert } 89885732ac8SCy Schubert 899e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR, 900e28a4053SRui Paulo hapd->conf->iface, MAC2STR(sta->addr)); 9015b9c547cSRui Paulo sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; 9025b9c547cSRui Paulo sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); 903f05cddf9SRui Paulo ap_sta_set_authorized(hapd, sta, 0); 904*c1d255d3SCy Schubert hostapd_set_sta_flags(hapd, sta); 905e28a4053SRui Paulo sta->timeout_next = STA_REMOVE; 906f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " 907f05cddf9SRui Paulo "for " MACSTR " (%d seconds - " 908f05cddf9SRui Paulo "AP_MAX_INACTIVITY_AFTER_DEAUTH)", 909f05cddf9SRui Paulo __func__, MAC2STR(sta->addr), 910f05cddf9SRui Paulo AP_MAX_INACTIVITY_AFTER_DEAUTH); 911e28a4053SRui Paulo eloop_cancel_timeout(ap_handle_timer, hapd, sta); 912e28a4053SRui Paulo eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, 913e28a4053SRui Paulo ap_handle_timer, hapd, sta); 914e28a4053SRui Paulo accounting_sta_stop(hapd, sta); 915780fb4a2SCy Schubert ieee802_1x_free_station(hapd, sta); 916e28a4053SRui Paulo 917f05cddf9SRui Paulo sta->deauth_reason = reason; 918f05cddf9SRui Paulo sta->flags |= WLAN_STA_PENDING_DEAUTH_CB; 919f05cddf9SRui Paulo eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); 920f05cddf9SRui Paulo eloop_register_timeout(hapd->iface->drv_flags & 921f05cddf9SRui Paulo WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, 922f05cddf9SRui Paulo ap_sta_deauth_cb_timeout, hapd, sta); 923e28a4053SRui Paulo } 924e28a4053SRui Paulo 925e28a4053SRui Paulo 926f05cddf9SRui Paulo #ifdef CONFIG_WPS 927f05cddf9SRui Paulo int ap_sta_wps_cancel(struct hostapd_data *hapd, 928f05cddf9SRui Paulo struct sta_info *sta, void *ctx) 929f05cddf9SRui Paulo { 930f05cddf9SRui Paulo if (sta && (sta->flags & WLAN_STA_WPS)) { 931f05cddf9SRui Paulo ap_sta_deauthenticate(hapd, sta, 932f05cddf9SRui Paulo WLAN_REASON_PREV_AUTH_NOT_VALID); 933f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR, 934f05cddf9SRui Paulo __func__, MAC2STR(sta->addr)); 935f05cddf9SRui Paulo return 1; 936f05cddf9SRui Paulo } 937f05cddf9SRui Paulo 938f05cddf9SRui Paulo return 0; 939f05cddf9SRui Paulo } 940f05cddf9SRui Paulo #endif /* CONFIG_WPS */ 941f05cddf9SRui Paulo 942f05cddf9SRui Paulo 943780fb4a2SCy Schubert static int ap_sta_get_free_vlan_id(struct hostapd_data *hapd) 944780fb4a2SCy Schubert { 945780fb4a2SCy Schubert struct hostapd_vlan *vlan; 946780fb4a2SCy Schubert int vlan_id = MAX_VLAN_ID + 2; 947780fb4a2SCy Schubert 948780fb4a2SCy Schubert retry: 949780fb4a2SCy Schubert for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) { 950780fb4a2SCy Schubert if (vlan->vlan_id == vlan_id) { 951780fb4a2SCy Schubert vlan_id++; 952780fb4a2SCy Schubert goto retry; 953780fb4a2SCy Schubert } 954780fb4a2SCy Schubert } 955780fb4a2SCy Schubert return vlan_id; 956780fb4a2SCy Schubert } 957780fb4a2SCy Schubert 958780fb4a2SCy Schubert 959780fb4a2SCy Schubert int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta, 960780fb4a2SCy Schubert struct vlan_description *vlan_desc) 961780fb4a2SCy Schubert { 962780fb4a2SCy Schubert struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL; 963780fb4a2SCy Schubert int old_vlan_id, vlan_id = 0, ret = 0; 964780fb4a2SCy Schubert 965780fb4a2SCy Schubert /* Check if there is something to do */ 966780fb4a2SCy Schubert if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) { 967780fb4a2SCy Schubert /* This sta is lacking its own vif */ 968780fb4a2SCy Schubert } else if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED && 969780fb4a2SCy Schubert !hapd->conf->ssid.per_sta_vif && sta->vlan_id) { 970780fb4a2SCy Schubert /* sta->vlan_id needs to be reset */ 971780fb4a2SCy Schubert } else if (!vlan_compare(vlan_desc, sta->vlan_desc)) { 972780fb4a2SCy Schubert return 0; /* nothing to change */ 973780fb4a2SCy Schubert } 974780fb4a2SCy Schubert 975780fb4a2SCy Schubert /* Now the real VLAN changed or the STA just needs its own vif */ 976780fb4a2SCy Schubert if (hapd->conf->ssid.per_sta_vif) { 977780fb4a2SCy Schubert /* Assign a new vif, always */ 978780fb4a2SCy Schubert /* find a free vlan_id sufficiently big */ 979780fb4a2SCy Schubert vlan_id = ap_sta_get_free_vlan_id(hapd); 980780fb4a2SCy Schubert /* Get wildcard VLAN */ 981780fb4a2SCy Schubert for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) { 982780fb4a2SCy Schubert if (vlan->vlan_id == VLAN_ID_WILDCARD) 983780fb4a2SCy Schubert break; 984780fb4a2SCy Schubert } 985780fb4a2SCy Schubert if (!vlan) { 986780fb4a2SCy Schubert hostapd_logger(hapd, sta->addr, 987780fb4a2SCy Schubert HOSTAPD_MODULE_IEEE80211, 988780fb4a2SCy Schubert HOSTAPD_LEVEL_DEBUG, 989780fb4a2SCy Schubert "per_sta_vif missing wildcard"); 990780fb4a2SCy Schubert vlan_id = 0; 991780fb4a2SCy Schubert ret = -1; 992780fb4a2SCy Schubert goto done; 993780fb4a2SCy Schubert } 994780fb4a2SCy Schubert } else if (vlan_desc && vlan_desc->notempty) { 995780fb4a2SCy Schubert for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) { 996780fb4a2SCy Schubert if (!vlan_compare(&vlan->vlan_desc, vlan_desc)) 997780fb4a2SCy Schubert break; 998780fb4a2SCy Schubert if (vlan->vlan_id == VLAN_ID_WILDCARD) 999780fb4a2SCy Schubert wildcard_vlan = vlan; 1000780fb4a2SCy Schubert } 1001780fb4a2SCy Schubert if (vlan) { 1002780fb4a2SCy Schubert vlan_id = vlan->vlan_id; 1003780fb4a2SCy Schubert } else if (wildcard_vlan) { 1004780fb4a2SCy Schubert vlan = wildcard_vlan; 1005780fb4a2SCy Schubert vlan_id = vlan_desc->untagged; 1006780fb4a2SCy Schubert if (vlan_desc->tagged[0]) { 1007780fb4a2SCy Schubert /* Tagged VLAN configuration */ 1008780fb4a2SCy Schubert vlan_id = ap_sta_get_free_vlan_id(hapd); 1009780fb4a2SCy Schubert } 1010780fb4a2SCy Schubert } else { 1011780fb4a2SCy Schubert hostapd_logger(hapd, sta->addr, 1012780fb4a2SCy Schubert HOSTAPD_MODULE_IEEE80211, 1013780fb4a2SCy Schubert HOSTAPD_LEVEL_DEBUG, 1014780fb4a2SCy Schubert "missing vlan and wildcard for vlan=%d%s", 1015780fb4a2SCy Schubert vlan_desc->untagged, 1016780fb4a2SCy Schubert vlan_desc->tagged[0] ? "+" : ""); 1017780fb4a2SCy Schubert vlan_id = 0; 1018780fb4a2SCy Schubert ret = -1; 1019780fb4a2SCy Schubert goto done; 1020780fb4a2SCy Schubert } 1021780fb4a2SCy Schubert } 1022780fb4a2SCy Schubert 1023780fb4a2SCy Schubert if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) { 1024780fb4a2SCy Schubert vlan = vlan_add_dynamic(hapd, vlan, vlan_id, vlan_desc); 1025780fb4a2SCy Schubert if (vlan == NULL) { 1026780fb4a2SCy Schubert hostapd_logger(hapd, sta->addr, 1027780fb4a2SCy Schubert HOSTAPD_MODULE_IEEE80211, 1028780fb4a2SCy Schubert HOSTAPD_LEVEL_DEBUG, 1029780fb4a2SCy Schubert "could not add dynamic VLAN interface for vlan=%d%s", 1030780fb4a2SCy Schubert vlan_desc ? vlan_desc->untagged : -1, 1031780fb4a2SCy Schubert (vlan_desc && vlan_desc->tagged[0]) ? 1032780fb4a2SCy Schubert "+" : ""); 1033780fb4a2SCy Schubert vlan_id = 0; 1034780fb4a2SCy Schubert ret = -1; 1035780fb4a2SCy Schubert goto done; 1036780fb4a2SCy Schubert } 1037780fb4a2SCy Schubert 1038780fb4a2SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1039780fb4a2SCy Schubert HOSTAPD_LEVEL_DEBUG, 1040780fb4a2SCy Schubert "added new dynamic VLAN interface '%s'", 1041780fb4a2SCy Schubert vlan->ifname); 1042780fb4a2SCy Schubert } else if (vlan && vlan->dynamic_vlan > 0) { 1043780fb4a2SCy Schubert vlan->dynamic_vlan++; 1044780fb4a2SCy Schubert hostapd_logger(hapd, sta->addr, 1045780fb4a2SCy Schubert HOSTAPD_MODULE_IEEE80211, 1046780fb4a2SCy Schubert HOSTAPD_LEVEL_DEBUG, 1047780fb4a2SCy Schubert "updated existing dynamic VLAN interface '%s'", 1048780fb4a2SCy Schubert vlan->ifname); 1049780fb4a2SCy Schubert } 1050780fb4a2SCy Schubert done: 1051780fb4a2SCy Schubert old_vlan_id = sta->vlan_id; 1052780fb4a2SCy Schubert sta->vlan_id = vlan_id; 1053780fb4a2SCy Schubert sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL; 1054780fb4a2SCy Schubert 1055780fb4a2SCy Schubert if (vlan_id != old_vlan_id && old_vlan_id) 1056780fb4a2SCy Schubert vlan_remove_dynamic(hapd, old_vlan_id); 1057780fb4a2SCy Schubert 1058780fb4a2SCy Schubert return ret; 1059780fb4a2SCy Schubert } 1060780fb4a2SCy Schubert 1061780fb4a2SCy Schubert 1062325151a3SRui Paulo int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta) 1063e28a4053SRui Paulo { 1064e28a4053SRui Paulo #ifndef CONFIG_NO_VLAN 1065e28a4053SRui Paulo const char *iface; 1066e28a4053SRui Paulo struct hostapd_vlan *vlan = NULL; 1067e28a4053SRui Paulo int ret; 1068325151a3SRui Paulo int old_vlanid = sta->vlan_id_bound; 1069e28a4053SRui Paulo 1070*c1d255d3SCy Schubert if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) { 1071*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1072*c1d255d3SCy Schubert "Do not override WDS VLAN assignment for STA " 1073*c1d255d3SCy Schubert MACSTR, MAC2STR(sta->addr)); 1074*c1d255d3SCy Schubert return 0; 1075*c1d255d3SCy Schubert } 1076*c1d255d3SCy Schubert 1077e28a4053SRui Paulo iface = hapd->conf->iface; 1078325151a3SRui Paulo if (hapd->conf->ssid.vlan[0]) 1079325151a3SRui Paulo iface = hapd->conf->ssid.vlan; 1080e28a4053SRui Paulo 1081780fb4a2SCy Schubert if (sta->vlan_id > 0) { 1082780fb4a2SCy Schubert for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) { 10835b9c547cSRui Paulo if (vlan->vlan_id == sta->vlan_id) 1084e28a4053SRui Paulo break; 1085e28a4053SRui Paulo } 10865b9c547cSRui Paulo if (vlan) 10875b9c547cSRui Paulo iface = vlan->ifname; 1088e28a4053SRui Paulo } 1089e28a4053SRui Paulo 1090325151a3SRui Paulo /* 1091325151a3SRui Paulo * Do not increment ref counters if the VLAN ID remains same, but do 1092325151a3SRui Paulo * not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might 1093325151a3SRui Paulo * have been called before. 1094325151a3SRui Paulo */ 1095325151a3SRui Paulo if (sta->vlan_id == old_vlanid) 1096325151a3SRui Paulo goto skip_counting; 1097325151a3SRui Paulo 1098*c1d255d3SCy Schubert if (sta->vlan_id > 0 && !vlan && 1099*c1d255d3SCy Schubert !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) { 1100e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1101e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "could not find VLAN for " 1102e28a4053SRui Paulo "binding station to (vlan_id=%d)", 1103e28a4053SRui Paulo sta->vlan_id); 11045b9c547cSRui Paulo ret = -1; 11055b9c547cSRui Paulo goto done; 1106780fb4a2SCy Schubert } else if (vlan && vlan->dynamic_vlan > 0) { 1107e28a4053SRui Paulo vlan->dynamic_vlan++; 1108e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, 1109e28a4053SRui Paulo HOSTAPD_MODULE_IEEE80211, 1110780fb4a2SCy Schubert HOSTAPD_LEVEL_DEBUG, 1111780fb4a2SCy Schubert "updated existing dynamic VLAN interface '%s'", 1112780fb4a2SCy Schubert iface); 1113e28a4053SRui Paulo } 1114e28a4053SRui Paulo 1115325151a3SRui Paulo /* ref counters have been increased, so mark the station */ 1116325151a3SRui Paulo sta->vlan_id_bound = sta->vlan_id; 1117325151a3SRui Paulo 1118325151a3SRui Paulo skip_counting: 1119e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1120e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "binding station to interface " 1121e28a4053SRui Paulo "'%s'", iface); 1122e28a4053SRui Paulo 1123e28a4053SRui Paulo if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0) 1124e28a4053SRui Paulo wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA"); 1125e28a4053SRui Paulo 1126f05cddf9SRui Paulo ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id); 1127e28a4053SRui Paulo if (ret < 0) { 1128e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1129e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "could not bind the STA " 1130e28a4053SRui Paulo "entry to vlan_id=%d", sta->vlan_id); 1131e28a4053SRui Paulo } 11325b9c547cSRui Paulo 11335b9c547cSRui Paulo /* During 1x reauth, if the vlan id changes, then remove the old id. */ 1134325151a3SRui Paulo if (old_vlanid > 0 && old_vlanid != sta->vlan_id) 11355b9c547cSRui Paulo vlan_remove_dynamic(hapd, old_vlanid); 1136325151a3SRui Paulo done: 11375b9c547cSRui Paulo 1138e28a4053SRui Paulo return ret; 1139e28a4053SRui Paulo #else /* CONFIG_NO_VLAN */ 1140e28a4053SRui Paulo return 0; 1141e28a4053SRui Paulo #endif /* CONFIG_NO_VLAN */ 1142e28a4053SRui Paulo } 1143e28a4053SRui Paulo 1144e28a4053SRui Paulo 1145e28a4053SRui Paulo int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta) 1146e28a4053SRui Paulo { 1147e28a4053SRui Paulo u32 tu; 11485b9c547cSRui Paulo struct os_reltime now, passed; 11495b9c547cSRui Paulo os_get_reltime(&now); 11505b9c547cSRui Paulo os_reltime_sub(&now, &sta->sa_query_start, &passed); 1151e28a4053SRui Paulo tu = (passed.sec * 1000000 + passed.usec) / 1024; 1152e28a4053SRui Paulo if (hapd->conf->assoc_sa_query_max_timeout < tu) { 1153e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, 1154e28a4053SRui Paulo HOSTAPD_MODULE_IEEE80211, 1155e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, 1156e28a4053SRui Paulo "association SA Query timed out"); 1157e28a4053SRui Paulo sta->sa_query_timed_out = 1; 1158e28a4053SRui Paulo os_free(sta->sa_query_trans_id); 1159e28a4053SRui Paulo sta->sa_query_trans_id = NULL; 1160e28a4053SRui Paulo sta->sa_query_count = 0; 1161e28a4053SRui Paulo eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); 1162e28a4053SRui Paulo return 1; 1163e28a4053SRui Paulo } 1164e28a4053SRui Paulo 1165e28a4053SRui Paulo return 0; 1166e28a4053SRui Paulo } 1167e28a4053SRui Paulo 1168e28a4053SRui Paulo 1169e28a4053SRui Paulo static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx) 1170e28a4053SRui Paulo { 1171e28a4053SRui Paulo struct hostapd_data *hapd = eloop_ctx; 1172e28a4053SRui Paulo struct sta_info *sta = timeout_ctx; 1173e28a4053SRui Paulo unsigned int timeout, sec, usec; 1174e28a4053SRui Paulo u8 *trans_id, *nbuf; 1175e28a4053SRui Paulo 1176780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "%s: SA Query timer for STA " MACSTR 1177780fb4a2SCy Schubert " (count=%d)", 1178780fb4a2SCy Schubert hapd->conf->iface, MAC2STR(sta->addr), sta->sa_query_count); 1179780fb4a2SCy Schubert 1180e28a4053SRui Paulo if (sta->sa_query_count > 0 && 1181e28a4053SRui Paulo ap_check_sa_query_timeout(hapd, sta)) 1182e28a4053SRui Paulo return; 1183*c1d255d3SCy Schubert if (sta->sa_query_count >= 1000) 1184*c1d255d3SCy Schubert return; 1185e28a4053SRui Paulo 1186f05cddf9SRui Paulo nbuf = os_realloc_array(sta->sa_query_trans_id, 1187f05cddf9SRui Paulo sta->sa_query_count + 1, 1188f05cddf9SRui Paulo WLAN_SA_QUERY_TR_ID_LEN); 1189e28a4053SRui Paulo if (nbuf == NULL) 1190e28a4053SRui Paulo return; 1191e28a4053SRui Paulo if (sta->sa_query_count == 0) { 1192e28a4053SRui Paulo /* Starting a new SA Query procedure */ 11935b9c547cSRui Paulo os_get_reltime(&sta->sa_query_start); 1194e28a4053SRui Paulo } 1195e28a4053SRui Paulo trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN; 1196e28a4053SRui Paulo sta->sa_query_trans_id = nbuf; 1197e28a4053SRui Paulo sta->sa_query_count++; 1198e28a4053SRui Paulo 11995b9c547cSRui Paulo if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) { 12005b9c547cSRui Paulo /* 12015b9c547cSRui Paulo * We don't really care which ID is used here, so simply 12025b9c547cSRui Paulo * hardcode this if the mostly theoretical os_get_random() 12035b9c547cSRui Paulo * failure happens. 12045b9c547cSRui Paulo */ 12055b9c547cSRui Paulo trans_id[0] = 0x12; 12065b9c547cSRui Paulo trans_id[1] = 0x34; 12075b9c547cSRui Paulo } 1208e28a4053SRui Paulo 1209e28a4053SRui Paulo timeout = hapd->conf->assoc_sa_query_retry_timeout; 1210e28a4053SRui Paulo sec = ((timeout / 1000) * 1024) / 1000; 1211e28a4053SRui Paulo usec = (timeout % 1000) * 1024; 1212e28a4053SRui Paulo eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta); 1213e28a4053SRui Paulo 1214e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1215e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, 1216e28a4053SRui Paulo "association SA Query attempt %d", sta->sa_query_count); 1217e28a4053SRui Paulo 1218e28a4053SRui Paulo ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id); 1219e28a4053SRui Paulo } 1220e28a4053SRui Paulo 1221e28a4053SRui Paulo 1222e28a4053SRui Paulo void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta) 1223e28a4053SRui Paulo { 1224e28a4053SRui Paulo ap_sa_query_timer(hapd, sta); 1225e28a4053SRui Paulo } 1226e28a4053SRui Paulo 1227e28a4053SRui Paulo 1228e28a4053SRui Paulo void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta) 1229e28a4053SRui Paulo { 1230e28a4053SRui Paulo eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); 1231e28a4053SRui Paulo os_free(sta->sa_query_trans_id); 1232e28a4053SRui Paulo sta->sa_query_trans_id = NULL; 1233e28a4053SRui Paulo sta->sa_query_count = 0; 1234e28a4053SRui Paulo } 1235e28a4053SRui Paulo 1236e28a4053SRui Paulo 12374bc52338SCy Schubert const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd, 12384bc52338SCy Schubert struct sta_info *sta) 12394bc52338SCy Schubert { 12404bc52338SCy Schubert struct hostapd_wpa_psk *psk; 12414bc52338SCy Schubert struct hostapd_ssid *ssid; 12424bc52338SCy Schubert const u8 *pmk; 12434bc52338SCy Schubert int pmk_len; 12444bc52338SCy Schubert 12454bc52338SCy Schubert ssid = &hapd->conf->ssid; 12464bc52338SCy Schubert 12474bc52338SCy Schubert pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len); 12484bc52338SCy Schubert if (!pmk || pmk_len != PMK_LEN) 12494bc52338SCy Schubert return NULL; 12504bc52338SCy Schubert 12514bc52338SCy Schubert for (psk = ssid->wpa_psk; psk; psk = psk->next) 12524bc52338SCy Schubert if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0) 12534bc52338SCy Schubert break; 12544bc52338SCy Schubert if (!psk) 12554bc52338SCy Schubert return NULL; 12564bc52338SCy Schubert if (!psk || !psk->keyid[0]) 12574bc52338SCy Schubert return NULL; 12584bc52338SCy Schubert 12594bc52338SCy Schubert return psk->keyid; 12604bc52338SCy Schubert } 12614bc52338SCy Schubert 12624bc52338SCy Schubert 1263f05cddf9SRui Paulo void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, 1264f05cddf9SRui Paulo int authorized) 1265f05cddf9SRui Paulo { 1266f05cddf9SRui Paulo const u8 *dev_addr = NULL; 12675b9c547cSRui Paulo char buf[100]; 1268f05cddf9SRui Paulo #ifdef CONFIG_P2P 1269f05cddf9SRui Paulo u8 addr[ETH_ALEN]; 12705b9c547cSRui Paulo u8 ip_addr_buf[4]; 1271f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 1272f05cddf9SRui Paulo 1273f05cddf9SRui Paulo if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED)) 1274f05cddf9SRui Paulo return; 1275f05cddf9SRui Paulo 12765b9c547cSRui Paulo if (authorized) 12775b9c547cSRui Paulo sta->flags |= WLAN_STA_AUTHORIZED; 12785b9c547cSRui Paulo else 12795b9c547cSRui Paulo sta->flags &= ~WLAN_STA_AUTHORIZED; 12805b9c547cSRui Paulo 1281f05cddf9SRui Paulo #ifdef CONFIG_P2P 1282f05cddf9SRui Paulo if (hapd->p2p_group == NULL) { 1283f05cddf9SRui Paulo if (sta->p2p_ie != NULL && 1284f05cddf9SRui Paulo p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0) 1285f05cddf9SRui Paulo dev_addr = addr; 1286f05cddf9SRui Paulo } else 1287f05cddf9SRui Paulo dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr); 12885b9c547cSRui Paulo 12895b9c547cSRui Paulo if (dev_addr) 12905b9c547cSRui Paulo os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR, 12915b9c547cSRui Paulo MAC2STR(sta->addr), MAC2STR(dev_addr)); 12925b9c547cSRui Paulo else 1293f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 12945b9c547cSRui Paulo os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr)); 1295f05cddf9SRui Paulo 1296f05cddf9SRui Paulo if (hapd->sta_authorized_cb) 1297f05cddf9SRui Paulo hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx, 1298f05cddf9SRui Paulo sta->addr, authorized, dev_addr); 12995b9c547cSRui Paulo 13005b9c547cSRui Paulo if (authorized) { 13014bc52338SCy Schubert const char *keyid; 13024bc52338SCy Schubert char keyid_buf[100]; 13035b9c547cSRui Paulo char ip_addr[100]; 13044bc52338SCy Schubert 13054bc52338SCy Schubert keyid_buf[0] = '\0'; 13065b9c547cSRui Paulo ip_addr[0] = '\0'; 13075b9c547cSRui Paulo #ifdef CONFIG_P2P 13085b9c547cSRui Paulo if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) { 13095b9c547cSRui Paulo os_snprintf(ip_addr, sizeof(ip_addr), 13105b9c547cSRui Paulo " ip_addr=%u.%u.%u.%u", 13115b9c547cSRui Paulo ip_addr_buf[0], ip_addr_buf[1], 13125b9c547cSRui Paulo ip_addr_buf[2], ip_addr_buf[3]); 13135b9c547cSRui Paulo } 13145b9c547cSRui Paulo #endif /* CONFIG_P2P */ 13155b9c547cSRui Paulo 13164bc52338SCy Schubert keyid = ap_sta_wpa_get_keyid(hapd, sta); 13174bc52338SCy Schubert if (keyid) { 13184bc52338SCy Schubert os_snprintf(keyid_buf, sizeof(keyid_buf), 13194bc52338SCy Schubert " keyid=%s", keyid); 13204bc52338SCy Schubert } 13214bc52338SCy Schubert 13224bc52338SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s", 13234bc52338SCy Schubert buf, ip_addr, keyid_buf); 13245b9c547cSRui Paulo 13255b9c547cSRui Paulo if (hapd->msg_ctx_parent && 13265b9c547cSRui Paulo hapd->msg_ctx_parent != hapd->msg_ctx) 13275b9c547cSRui Paulo wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, 13284bc52338SCy Schubert AP_STA_CONNECTED "%s%s%s", 13294bc52338SCy Schubert buf, ip_addr, keyid_buf); 13305b9c547cSRui Paulo } else { 13315b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf); 13325b9c547cSRui Paulo 13335b9c547cSRui Paulo if (hapd->msg_ctx_parent && 13345b9c547cSRui Paulo hapd->msg_ctx_parent != hapd->msg_ctx) 13355b9c547cSRui Paulo wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, 13365b9c547cSRui Paulo AP_STA_DISCONNECTED "%s", buf); 13375b9c547cSRui Paulo } 1338325151a3SRui Paulo 1339325151a3SRui Paulo #ifdef CONFIG_FST 1340325151a3SRui Paulo if (hapd->iface->fst) { 1341325151a3SRui Paulo if (authorized) 1342325151a3SRui Paulo fst_notify_peer_connected(hapd->iface->fst, sta->addr); 1343325151a3SRui Paulo else 1344325151a3SRui Paulo fst_notify_peer_disconnected(hapd->iface->fst, 1345325151a3SRui Paulo sta->addr); 1346325151a3SRui Paulo } 1347325151a3SRui Paulo #endif /* CONFIG_FST */ 1348f05cddf9SRui Paulo } 1349f05cddf9SRui Paulo 1350f05cddf9SRui Paulo 1351e28a4053SRui Paulo void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, 1352e28a4053SRui Paulo const u8 *addr, u16 reason) 1353e28a4053SRui Paulo { 1354780fb4a2SCy Schubert if (sta) 1355780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "%s: %s STA " MACSTR " reason=%u", 1356780fb4a2SCy Schubert hapd->conf->iface, __func__, MAC2STR(sta->addr), 1357780fb4a2SCy Schubert reason); 1358780fb4a2SCy Schubert else if (addr) 1359780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "%s: %s addr " MACSTR " reason=%u", 1360780fb4a2SCy Schubert hapd->conf->iface, __func__, MAC2STR(addr), 1361780fb4a2SCy Schubert reason); 1362e28a4053SRui Paulo 1363e28a4053SRui Paulo if (sta == NULL && addr) 1364e28a4053SRui Paulo sta = ap_get_sta(hapd, addr); 1365e28a4053SRui Paulo 1366e28a4053SRui Paulo if (addr) 1367f05cddf9SRui Paulo hostapd_drv_sta_deauth(hapd, addr, reason); 1368e28a4053SRui Paulo 1369e28a4053SRui Paulo if (sta == NULL) 1370e28a4053SRui Paulo return; 1371f05cddf9SRui Paulo ap_sta_set_authorized(hapd, sta, 0); 1372*c1d255d3SCy Schubert sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); 1373*c1d255d3SCy Schubert hostapd_set_sta_flags(hapd, sta); 1374f05cddf9SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); 1375f05cddf9SRui Paulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 1376780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout " 1377f05cddf9SRui Paulo "for " MACSTR " (%d seconds - " 1378f05cddf9SRui Paulo "AP_MAX_INACTIVITY_AFTER_DEAUTH)", 1379780fb4a2SCy Schubert hapd->conf->iface, __func__, MAC2STR(sta->addr), 1380f05cddf9SRui Paulo AP_MAX_INACTIVITY_AFTER_DEAUTH); 1381e28a4053SRui Paulo eloop_cancel_timeout(ap_handle_timer, hapd, sta); 1382f05cddf9SRui Paulo eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, 1383f05cddf9SRui Paulo ap_handle_timer, hapd, sta); 1384e28a4053SRui Paulo sta->timeout_next = STA_REMOVE; 1385f05cddf9SRui Paulo 138685732ac8SCy Schubert if (hapd->iface->current_mode && 138785732ac8SCy Schubert hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { 138885732ac8SCy Schubert /* Deauthentication is not used in DMG/IEEE 802.11ad; 138985732ac8SCy Schubert * disassociate the STA instead. */ 139085732ac8SCy Schubert sta->disassoc_reason = reason; 139185732ac8SCy Schubert sta->flags |= WLAN_STA_PENDING_DISASSOC_CB; 139285732ac8SCy Schubert eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); 139385732ac8SCy Schubert eloop_register_timeout(hapd->iface->drv_flags & 139485732ac8SCy Schubert WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 139585732ac8SCy Schubert 2 : 0, 0, ap_sta_disassoc_cb_timeout, 139685732ac8SCy Schubert hapd, sta); 139785732ac8SCy Schubert return; 139885732ac8SCy Schubert } 139985732ac8SCy Schubert 1400f05cddf9SRui Paulo sta->deauth_reason = reason; 1401f05cddf9SRui Paulo sta->flags |= WLAN_STA_PENDING_DEAUTH_CB; 1402f05cddf9SRui Paulo eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); 1403f05cddf9SRui Paulo eloop_register_timeout(hapd->iface->drv_flags & 1404f05cddf9SRui Paulo WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, 1405f05cddf9SRui Paulo ap_sta_deauth_cb_timeout, hapd, sta); 1406f05cddf9SRui Paulo } 1407f05cddf9SRui Paulo 1408f05cddf9SRui Paulo 1409f05cddf9SRui Paulo void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta) 1410f05cddf9SRui Paulo { 1411f05cddf9SRui Paulo if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) { 1412f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame"); 1413f05cddf9SRui Paulo return; 1414f05cddf9SRui Paulo } 1415f05cddf9SRui Paulo sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB; 1416f05cddf9SRui Paulo eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); 1417f05cddf9SRui Paulo ap_sta_deauth_cb_timeout(hapd, sta); 1418f05cddf9SRui Paulo } 1419f05cddf9SRui Paulo 1420f05cddf9SRui Paulo 1421f05cddf9SRui Paulo void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta) 1422f05cddf9SRui Paulo { 1423f05cddf9SRui Paulo if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) { 1424f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame"); 1425f05cddf9SRui Paulo return; 1426f05cddf9SRui Paulo } 1427f05cddf9SRui Paulo sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB; 1428f05cddf9SRui Paulo eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); 1429f05cddf9SRui Paulo ap_sta_disassoc_cb_timeout(hapd, sta); 1430e28a4053SRui Paulo } 14315b9c547cSRui Paulo 14325b9c547cSRui Paulo 1433780fb4a2SCy Schubert void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd, 1434780fb4a2SCy Schubert struct sta_info *sta) 1435780fb4a2SCy Schubert { 1436780fb4a2SCy Schubert if (eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta) > 0) 1437780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1438780fb4a2SCy Schubert "%s: Removed ap_sta_deauth_cb_timeout timeout for " 1439780fb4a2SCy Schubert MACSTR, 1440780fb4a2SCy Schubert hapd->conf->iface, MAC2STR(sta->addr)); 1441780fb4a2SCy Schubert if (eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta) > 0) 1442780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1443780fb4a2SCy Schubert "%s: Removed ap_sta_disassoc_cb_timeout timeout for " 1444780fb4a2SCy Schubert MACSTR, 1445780fb4a2SCy Schubert hapd->conf->iface, MAC2STR(sta->addr)); 144685732ac8SCy Schubert if (eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta) > 0) 144785732ac8SCy Schubert { 144885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 144985732ac8SCy Schubert "%s: Removed ap_sta_delayed_1x_auth_fail_cb timeout for " 145085732ac8SCy Schubert MACSTR, 145185732ac8SCy Schubert hapd->conf->iface, MAC2STR(sta->addr)); 145285732ac8SCy Schubert if (sta->flags & WLAN_STA_WPS) 145385732ac8SCy Schubert hostapd_wps_eap_completed(hapd); 145485732ac8SCy Schubert } 1455780fb4a2SCy Schubert } 1456780fb4a2SCy Schubert 1457780fb4a2SCy Schubert 14585b9c547cSRui Paulo int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen) 14595b9c547cSRui Paulo { 14605b9c547cSRui Paulo int res; 14615b9c547cSRui Paulo 14625b9c547cSRui Paulo buf[0] = '\0'; 1463*c1d255d3SCy Schubert res = os_snprintf(buf, buflen, 1464*c1d255d3SCy Schubert "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 14655b9c547cSRui Paulo (flags & WLAN_STA_AUTH ? "[AUTH]" : ""), 14665b9c547cSRui Paulo (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), 14675b9c547cSRui Paulo (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""), 14685b9c547cSRui Paulo (flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" : 14695b9c547cSRui Paulo ""), 14705b9c547cSRui Paulo (flags & WLAN_STA_SHORT_PREAMBLE ? 14715b9c547cSRui Paulo "[SHORT_PREAMBLE]" : ""), 14725b9c547cSRui Paulo (flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""), 14735b9c547cSRui Paulo (flags & WLAN_STA_WMM ? "[WMM]" : ""), 14745b9c547cSRui Paulo (flags & WLAN_STA_MFP ? "[MFP]" : ""), 14755b9c547cSRui Paulo (flags & WLAN_STA_WPS ? "[WPS]" : ""), 14765b9c547cSRui Paulo (flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""), 14775b9c547cSRui Paulo (flags & WLAN_STA_WDS ? "[WDS]" : ""), 14785b9c547cSRui Paulo (flags & WLAN_STA_NONERP ? "[NonERP]" : ""), 14795b9c547cSRui Paulo (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""), 14805b9c547cSRui Paulo (flags & WLAN_STA_GAS ? "[GAS]" : ""), 148185732ac8SCy Schubert (flags & WLAN_STA_HT ? "[HT]" : ""), 14825b9c547cSRui Paulo (flags & WLAN_STA_VHT ? "[VHT]" : ""), 1483*c1d255d3SCy Schubert (flags & WLAN_STA_HE ? "[HE]" : ""), 1484*c1d255d3SCy Schubert (flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""), 14855b9c547cSRui Paulo (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""), 14865b9c547cSRui Paulo (flags & WLAN_STA_WNM_SLEEP_MODE ? 14875b9c547cSRui Paulo "[WNM_SLEEP_MODE]" : "")); 14885b9c547cSRui Paulo if (os_snprintf_error(buflen, res)) 14895b9c547cSRui Paulo res = -1; 14905b9c547cSRui Paulo 14915b9c547cSRui Paulo return res; 14925b9c547cSRui Paulo } 149385732ac8SCy Schubert 149485732ac8SCy Schubert 149585732ac8SCy Schubert static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx) 149685732ac8SCy Schubert { 149785732ac8SCy Schubert struct hostapd_data *hapd = eloop_ctx; 149885732ac8SCy Schubert struct sta_info *sta = timeout_ctx; 149985732ac8SCy Schubert u16 reason; 150085732ac8SCy Schubert 150185732ac8SCy Schubert wpa_dbg(hapd->msg_ctx, MSG_DEBUG, 150285732ac8SCy Schubert "IEEE 802.1X: Scheduled disconnection of " MACSTR 150385732ac8SCy Schubert " after EAP-Failure", MAC2STR(sta->addr)); 150485732ac8SCy Schubert 150585732ac8SCy Schubert reason = sta->disconnect_reason_code; 150685732ac8SCy Schubert if (!reason) 150785732ac8SCy Schubert reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED; 150885732ac8SCy Schubert ap_sta_disconnect(hapd, sta, sta->addr, reason); 150985732ac8SCy Schubert if (sta->flags & WLAN_STA_WPS) 151085732ac8SCy Schubert hostapd_wps_eap_completed(hapd); 151185732ac8SCy Schubert } 151285732ac8SCy Schubert 151385732ac8SCy Schubert 151485732ac8SCy Schubert void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, 151585732ac8SCy Schubert struct sta_info *sta) 151685732ac8SCy Schubert { 151785732ac8SCy Schubert wpa_dbg(hapd->msg_ctx, MSG_DEBUG, 151885732ac8SCy Schubert "IEEE 802.1X: Force disconnection of " MACSTR 151985732ac8SCy Schubert " after EAP-Failure in 10 ms", MAC2STR(sta->addr)); 152085732ac8SCy Schubert 152185732ac8SCy Schubert /* 152285732ac8SCy Schubert * Add a small sleep to increase likelihood of previously requested 152385732ac8SCy Schubert * EAP-Failure TX getting out before this should the driver reorder 152485732ac8SCy Schubert * operations. 152585732ac8SCy Schubert */ 152685732ac8SCy Schubert eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta); 152785732ac8SCy Schubert eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb, 152885732ac8SCy Schubert hapd, sta); 152985732ac8SCy Schubert } 153085732ac8SCy Schubert 153185732ac8SCy Schubert 153285732ac8SCy Schubert int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, 153385732ac8SCy Schubert struct sta_info *sta) 153485732ac8SCy Schubert { 153585732ac8SCy Schubert return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb, 153685732ac8SCy Schubert hapd, sta); 153785732ac8SCy Schubert } 1538*c1d255d3SCy Schubert 1539*c1d255d3SCy Schubert 1540*c1d255d3SCy Schubert int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta) 1541*c1d255d3SCy Schubert { 1542*c1d255d3SCy Schubert /* 1543*c1d255d3SCy Schubert * If a station that is already associated to the AP, is trying to 1544*c1d255d3SCy Schubert * authenticate again, remove the STA entry, in order to make sure the 1545*c1d255d3SCy Schubert * STA PS state gets cleared and configuration gets updated. To handle 1546*c1d255d3SCy Schubert * this, station's added_unassoc flag is cleared once the station has 1547*c1d255d3SCy Schubert * completed association. 1548*c1d255d3SCy Schubert */ 1549*c1d255d3SCy Schubert ap_sta_set_authorized(hapd, sta, 0); 1550*c1d255d3SCy Schubert hostapd_drv_sta_remove(hapd, sta->addr); 1551*c1d255d3SCy Schubert sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED); 1552*c1d255d3SCy Schubert 1553*c1d255d3SCy Schubert if (hostapd_sta_add(hapd, sta->addr, 0, 0, 1554*c1d255d3SCy Schubert sta->supported_rates, 1555*c1d255d3SCy Schubert sta->supported_rates_len, 1556*c1d255d3SCy Schubert 0, NULL, NULL, NULL, 0, NULL, 1557*c1d255d3SCy Schubert sta->flags, 0, 0, 0, 0)) { 1558*c1d255d3SCy Schubert hostapd_logger(hapd, sta->addr, 1559*c1d255d3SCy Schubert HOSTAPD_MODULE_IEEE80211, 1560*c1d255d3SCy Schubert HOSTAPD_LEVEL_NOTICE, 1561*c1d255d3SCy Schubert "Could not add STA to kernel driver"); 1562*c1d255d3SCy Schubert return -1; 1563*c1d255d3SCy Schubert } 1564*c1d255d3SCy Schubert 1565*c1d255d3SCy Schubert sta->added_unassoc = 1; 1566*c1d255d3SCy Schubert return 0; 1567*c1d255d3SCy Schubert } 1568