1214501Srpaulo/* 2214501Srpaulo * hostapd / Station table 3281806Srpaulo * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "utils/includes.h" 10214501Srpaulo 11214501Srpaulo#include "utils/common.h" 12214501Srpaulo#include "utils/eloop.h" 13214501Srpaulo#include "common/ieee802_11_defs.h" 14252726Srpaulo#include "common/wpa_ctrl.h" 15281806Srpaulo#include "common/sae.h" 16214501Srpaulo#include "radius/radius.h" 17214501Srpaulo#include "radius/radius_client.h" 18252726Srpaulo#include "p2p/p2p.h" 19289549Srpaulo#include "fst/fst.h" 20214501Srpaulo#include "hostapd.h" 21214501Srpaulo#include "accounting.h" 22214501Srpaulo#include "ieee802_1x.h" 23214501Srpaulo#include "ieee802_11.h" 24252726Srpaulo#include "ieee802_11_auth.h" 25214501Srpaulo#include "wpa_auth.h" 26214501Srpaulo#include "preauth_auth.h" 27214501Srpaulo#include "ap_config.h" 28214501Srpaulo#include "beacon.h" 29214501Srpaulo#include "ap_mlme.h" 30214501Srpaulo#include "vlan_init.h" 31252726Srpaulo#include "p2p_hostapd.h" 32252726Srpaulo#include "ap_drv_ops.h" 33252726Srpaulo#include "gas_serv.h" 34281806Srpaulo#include "wnm_ap.h" 35281806Srpaulo#include "ndisc_snoop.h" 36214501Srpaulo#include "sta_info.h" 37214501Srpaulo 38214501Srpaulostatic void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, 39214501Srpaulo struct sta_info *sta); 40214501Srpaulostatic void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx); 41281806Srpaulostatic void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx); 42252726Srpaulostatic void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx); 43252726Srpaulostatic void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx); 44214501Srpaulo#ifdef CONFIG_IEEE80211W 45214501Srpaulostatic void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx); 46214501Srpaulo#endif /* CONFIG_IEEE80211W */ 47252726Srpaulostatic int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta); 48214501Srpaulo 49214501Srpauloint ap_for_each_sta(struct hostapd_data *hapd, 50214501Srpaulo int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, 51214501Srpaulo void *ctx), 52214501Srpaulo void *ctx) 53214501Srpaulo{ 54214501Srpaulo struct sta_info *sta; 55214501Srpaulo 56214501Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 57214501Srpaulo if (cb(hapd, sta, ctx)) 58214501Srpaulo return 1; 59214501Srpaulo } 60214501Srpaulo 61214501Srpaulo return 0; 62214501Srpaulo} 63214501Srpaulo 64214501Srpaulo 65214501Srpaulostruct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta) 66214501Srpaulo{ 67214501Srpaulo struct sta_info *s; 68214501Srpaulo 69214501Srpaulo s = hapd->sta_hash[STA_HASH(sta)]; 70214501Srpaulo while (s != NULL && os_memcmp(s->addr, sta, 6) != 0) 71214501Srpaulo s = s->hnext; 72214501Srpaulo return s; 73214501Srpaulo} 74214501Srpaulo 75214501Srpaulo 76281806Srpaulo#ifdef CONFIG_P2P 77281806Srpaulostruct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr) 78281806Srpaulo{ 79281806Srpaulo struct sta_info *sta; 80281806Srpaulo 81281806Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 82281806Srpaulo const u8 *p2p_dev_addr; 83281806Srpaulo 84281806Srpaulo if (sta->p2p_ie == NULL) 85281806Srpaulo continue; 86281806Srpaulo 87281806Srpaulo p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); 88281806Srpaulo if (p2p_dev_addr == NULL) 89281806Srpaulo continue; 90281806Srpaulo 91281806Srpaulo if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0) 92281806Srpaulo return sta; 93281806Srpaulo } 94281806Srpaulo 95281806Srpaulo return NULL; 96281806Srpaulo} 97281806Srpaulo#endif /* CONFIG_P2P */ 98281806Srpaulo 99281806Srpaulo 100214501Srpaulostatic void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta) 101214501Srpaulo{ 102214501Srpaulo struct sta_info *tmp; 103214501Srpaulo 104214501Srpaulo if (hapd->sta_list == sta) { 105214501Srpaulo hapd->sta_list = sta->next; 106214501Srpaulo return; 107214501Srpaulo } 108214501Srpaulo 109214501Srpaulo tmp = hapd->sta_list; 110214501Srpaulo while (tmp != NULL && tmp->next != sta) 111214501Srpaulo tmp = tmp->next; 112214501Srpaulo if (tmp == NULL) { 113214501Srpaulo wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from " 114214501Srpaulo "list.", MAC2STR(sta->addr)); 115214501Srpaulo } else 116214501Srpaulo tmp->next = sta->next; 117214501Srpaulo} 118214501Srpaulo 119214501Srpaulo 120214501Srpaulovoid ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta) 121214501Srpaulo{ 122214501Srpaulo sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)]; 123214501Srpaulo hapd->sta_hash[STA_HASH(sta->addr)] = sta; 124214501Srpaulo} 125214501Srpaulo 126214501Srpaulo 127214501Srpaulostatic void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta) 128214501Srpaulo{ 129214501Srpaulo struct sta_info *s; 130214501Srpaulo 131214501Srpaulo s = hapd->sta_hash[STA_HASH(sta->addr)]; 132214501Srpaulo if (s == NULL) return; 133214501Srpaulo if (os_memcmp(s->addr, sta->addr, 6) == 0) { 134214501Srpaulo hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext; 135214501Srpaulo return; 136214501Srpaulo } 137214501Srpaulo 138214501Srpaulo while (s->hnext != NULL && 139214501Srpaulo os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0) 140214501Srpaulo s = s->hnext; 141214501Srpaulo if (s->hnext != NULL) 142214501Srpaulo s->hnext = s->hnext->hnext; 143214501Srpaulo else 144214501Srpaulo wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR 145214501Srpaulo " from hash table", MAC2STR(sta->addr)); 146214501Srpaulo} 147214501Srpaulo 148214501Srpaulo 149281806Srpaulovoid ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta) 150281806Srpaulo{ 151281806Srpaulo sta_ip6addr_del(hapd, sta); 152281806Srpaulo} 153281806Srpaulo 154281806Srpaulo 155214501Srpaulovoid ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) 156214501Srpaulo{ 157214501Srpaulo int set_beacon = 0; 158214501Srpaulo 159214501Srpaulo accounting_sta_stop(hapd, sta); 160214501Srpaulo 161252726Srpaulo /* just in case */ 162252726Srpaulo ap_sta_set_authorized(hapd, sta, 0); 163252726Srpaulo 164214501Srpaulo if (sta->flags & WLAN_STA_WDS) 165281806Srpaulo hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0); 166214501Srpaulo 167281806Srpaulo if (sta->ipaddr) 168281806Srpaulo hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); 169281806Srpaulo ap_sta_ip6addr_del(hapd, sta); 170281806Srpaulo 171281806Srpaulo if (!hapd->iface->driver_ap_teardown && 172281806Srpaulo !(sta->flags & WLAN_STA_PREAUTH)) 173252726Srpaulo hostapd_drv_sta_remove(hapd, sta->addr); 174214501Srpaulo 175289549Srpaulo#ifndef CONFIG_NO_VLAN 176289549Srpaulo if (sta->vlan_id_bound) { 177289549Srpaulo /* 178289549Srpaulo * Need to remove the STA entry before potentially removing the 179289549Srpaulo * VLAN. 180289549Srpaulo */ 181289549Srpaulo if (hapd->iface->driver_ap_teardown && 182289549Srpaulo !(sta->flags & WLAN_STA_PREAUTH)) 183289549Srpaulo hostapd_drv_sta_remove(hapd, sta->addr); 184289549Srpaulo vlan_remove_dynamic(hapd, sta->vlan_id_bound); 185289549Srpaulo } 186289549Srpaulo#endif /* CONFIG_NO_VLAN */ 187289549Srpaulo 188214501Srpaulo ap_sta_hash_del(hapd, sta); 189214501Srpaulo ap_sta_list_del(hapd, sta); 190214501Srpaulo 191214501Srpaulo if (sta->aid > 0) 192214501Srpaulo hapd->sta_aid[(sta->aid - 1) / 32] &= 193214501Srpaulo ~BIT((sta->aid - 1) % 32); 194214501Srpaulo 195214501Srpaulo hapd->num_sta--; 196214501Srpaulo if (sta->nonerp_set) { 197214501Srpaulo sta->nonerp_set = 0; 198214501Srpaulo hapd->iface->num_sta_non_erp--; 199214501Srpaulo if (hapd->iface->num_sta_non_erp == 0) 200214501Srpaulo set_beacon++; 201214501Srpaulo } 202214501Srpaulo 203214501Srpaulo if (sta->no_short_slot_time_set) { 204214501Srpaulo sta->no_short_slot_time_set = 0; 205214501Srpaulo hapd->iface->num_sta_no_short_slot_time--; 206214501Srpaulo if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G 207214501Srpaulo && hapd->iface->num_sta_no_short_slot_time == 0) 208214501Srpaulo set_beacon++; 209214501Srpaulo } 210214501Srpaulo 211214501Srpaulo if (sta->no_short_preamble_set) { 212214501Srpaulo sta->no_short_preamble_set = 0; 213214501Srpaulo hapd->iface->num_sta_no_short_preamble--; 214214501Srpaulo if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G 215214501Srpaulo && hapd->iface->num_sta_no_short_preamble == 0) 216214501Srpaulo set_beacon++; 217214501Srpaulo } 218214501Srpaulo 219214501Srpaulo if (sta->no_ht_gf_set) { 220214501Srpaulo sta->no_ht_gf_set = 0; 221214501Srpaulo hapd->iface->num_sta_ht_no_gf--; 222214501Srpaulo } 223214501Srpaulo 224214501Srpaulo if (sta->no_ht_set) { 225214501Srpaulo sta->no_ht_set = 0; 226214501Srpaulo hapd->iface->num_sta_no_ht--; 227214501Srpaulo } 228214501Srpaulo 229214501Srpaulo if (sta->ht_20mhz_set) { 230214501Srpaulo sta->ht_20mhz_set = 0; 231214501Srpaulo hapd->iface->num_sta_ht_20mhz--; 232214501Srpaulo } 233214501Srpaulo 234281806Srpaulo#ifdef CONFIG_IEEE80211N 235281806Srpaulo ht40_intolerant_remove(hapd->iface, sta); 236281806Srpaulo#endif /* CONFIG_IEEE80211N */ 237281806Srpaulo 238252726Srpaulo#ifdef CONFIG_P2P 239252726Srpaulo if (sta->no_p2p_set) { 240252726Srpaulo sta->no_p2p_set = 0; 241252726Srpaulo hapd->num_sta_no_p2p--; 242252726Srpaulo if (hapd->num_sta_no_p2p == 0) 243252726Srpaulo hostapd_p2p_non_p2p_sta_disconnected(hapd); 244252726Srpaulo } 245252726Srpaulo#endif /* CONFIG_P2P */ 246252726Srpaulo 247214501Srpaulo#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N) 248214501Srpaulo if (hostapd_ht_operation_update(hapd->iface) > 0) 249214501Srpaulo set_beacon++; 250214501Srpaulo#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */ 251214501Srpaulo 252281806Srpaulo#ifdef CONFIG_MESH 253281806Srpaulo if (hapd->mesh_sta_free_cb) 254281806Srpaulo hapd->mesh_sta_free_cb(sta); 255281806Srpaulo#endif /* CONFIG_MESH */ 256281806Srpaulo 257214501Srpaulo if (set_beacon) 258214501Srpaulo ieee802_11_set_beacons(hapd->iface); 259214501Srpaulo 260252726Srpaulo wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR, 261252726Srpaulo __func__, MAC2STR(sta->addr)); 262214501Srpaulo eloop_cancel_timeout(ap_handle_timer, hapd, sta); 263214501Srpaulo eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); 264281806Srpaulo eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta); 265252726Srpaulo eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); 266252726Srpaulo eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); 267281806Srpaulo sae_clear_retransmit_timer(hapd, sta); 268214501Srpaulo 269214501Srpaulo ieee802_1x_free_station(sta); 270214501Srpaulo wpa_auth_sta_deinit(sta->wpa_sm); 271214501Srpaulo rsn_preauth_free_station(hapd, sta); 272214501Srpaulo#ifndef CONFIG_NO_RADIUS 273281806Srpaulo if (hapd->radius) 274281806Srpaulo radius_client_flush_auth(hapd->radius, sta->addr); 275214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 276214501Srpaulo 277214501Srpaulo os_free(sta->challenge); 278214501Srpaulo 279214501Srpaulo#ifdef CONFIG_IEEE80211W 280214501Srpaulo os_free(sta->sa_query_trans_id); 281214501Srpaulo eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); 282214501Srpaulo#endif /* CONFIG_IEEE80211W */ 283214501Srpaulo 284252726Srpaulo#ifdef CONFIG_P2P 285252726Srpaulo p2p_group_notif_disassoc(hapd->p2p_group, sta->addr); 286252726Srpaulo#endif /* CONFIG_P2P */ 287252726Srpaulo 288252726Srpaulo#ifdef CONFIG_INTERWORKING 289252726Srpaulo if (sta->gas_dialog) { 290252726Srpaulo int i; 291252726Srpaulo for (i = 0; i < GAS_DIALOG_MAX; i++) 292252726Srpaulo gas_serv_dialog_clear(&sta->gas_dialog[i]); 293252726Srpaulo os_free(sta->gas_dialog); 294252726Srpaulo } 295252726Srpaulo#endif /* CONFIG_INTERWORKING */ 296252726Srpaulo 297214501Srpaulo wpabuf_free(sta->wps_ie); 298252726Srpaulo wpabuf_free(sta->p2p_ie); 299252726Srpaulo wpabuf_free(sta->hs20_ie); 300289549Srpaulo#ifdef CONFIG_FST 301289549Srpaulo wpabuf_free(sta->mb_ies); 302289549Srpaulo#endif /* CONFIG_FST */ 303214501Srpaulo 304214501Srpaulo os_free(sta->ht_capabilities); 305281806Srpaulo os_free(sta->vht_capabilities); 306252726Srpaulo hostapd_free_psk_list(sta->psk); 307252726Srpaulo os_free(sta->identity); 308252726Srpaulo os_free(sta->radius_cui); 309281806Srpaulo os_free(sta->remediation_url); 310281806Srpaulo wpabuf_free(sta->hs20_deauth_req); 311281806Srpaulo os_free(sta->hs20_session_info_url); 312214501Srpaulo 313281806Srpaulo#ifdef CONFIG_SAE 314281806Srpaulo sae_clear_data(sta->sae); 315281806Srpaulo os_free(sta->sae); 316281806Srpaulo#endif /* CONFIG_SAE */ 317281806Srpaulo 318214501Srpaulo os_free(sta); 319214501Srpaulo} 320214501Srpaulo 321214501Srpaulo 322214501Srpaulovoid hostapd_free_stas(struct hostapd_data *hapd) 323214501Srpaulo{ 324214501Srpaulo struct sta_info *sta, *prev; 325214501Srpaulo 326214501Srpaulo sta = hapd->sta_list; 327214501Srpaulo 328214501Srpaulo while (sta) { 329214501Srpaulo prev = sta; 330214501Srpaulo if (sta->flags & WLAN_STA_AUTH) { 331214501Srpaulo mlme_deauthenticate_indication( 332214501Srpaulo hapd, sta, WLAN_REASON_UNSPECIFIED); 333214501Srpaulo } 334214501Srpaulo sta = sta->next; 335214501Srpaulo wpa_printf(MSG_DEBUG, "Removing station " MACSTR, 336214501Srpaulo MAC2STR(prev->addr)); 337214501Srpaulo ap_free_sta(hapd, prev); 338214501Srpaulo } 339214501Srpaulo} 340214501Srpaulo 341214501Srpaulo 342214501Srpaulo/** 343214501Srpaulo * ap_handle_timer - Per STA timer handler 344214501Srpaulo * @eloop_ctx: struct hostapd_data * 345214501Srpaulo * @timeout_ctx: struct sta_info * 346214501Srpaulo * 347214501Srpaulo * This function is called to check station activity and to remove inactive 348214501Srpaulo * stations. 349214501Srpaulo */ 350214501Srpaulovoid ap_handle_timer(void *eloop_ctx, void *timeout_ctx) 351214501Srpaulo{ 352214501Srpaulo struct hostapd_data *hapd = eloop_ctx; 353214501Srpaulo struct sta_info *sta = timeout_ctx; 354214501Srpaulo unsigned long next_time = 0; 355281806Srpaulo int reason; 356214501Srpaulo 357252726Srpaulo wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d", 358252726Srpaulo __func__, MAC2STR(sta->addr), sta->flags, 359252726Srpaulo sta->timeout_next); 360214501Srpaulo if (sta->timeout_next == STA_REMOVE) { 361214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 362214501Srpaulo HOSTAPD_LEVEL_INFO, "deauthenticated due to " 363214501Srpaulo "local deauth request"); 364214501Srpaulo ap_free_sta(hapd, sta); 365214501Srpaulo return; 366214501Srpaulo } 367214501Srpaulo 368214501Srpaulo if ((sta->flags & WLAN_STA_ASSOC) && 369214501Srpaulo (sta->timeout_next == STA_NULLFUNC || 370214501Srpaulo sta->timeout_next == STA_DISASSOC)) { 371214501Srpaulo int inactive_sec; 372252726Srpaulo /* 373252726Srpaulo * Add random value to timeout so that we don't end up bouncing 374252726Srpaulo * all stations at the same time if we have lots of associated 375252726Srpaulo * stations that are idle (but keep re-associating). 376252726Srpaulo */ 377252726Srpaulo int fuzz = os_random() % 20; 378252726Srpaulo inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr); 379214501Srpaulo if (inactive_sec == -1) { 380252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, 381252726Srpaulo "Check inactivity: Could not " 382252726Srpaulo "get station info from kernel driver for " 383252726Srpaulo MACSTR, MAC2STR(sta->addr)); 384252726Srpaulo /* 385252726Srpaulo * The driver may not support this functionality. 386252726Srpaulo * Anyway, try again after the next inactivity timeout, 387252726Srpaulo * but do not disconnect the station now. 388252726Srpaulo */ 389252726Srpaulo next_time = hapd->conf->ap_max_inactivity + fuzz; 390281806Srpaulo } else if (inactive_sec == -ENOENT) { 391281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, 392281806Srpaulo "Station " MACSTR " has lost its driver entry", 393281806Srpaulo MAC2STR(sta->addr)); 394281806Srpaulo 395281806Srpaulo /* Avoid sending client probe on removed client */ 396281806Srpaulo sta->timeout_next = STA_DISASSOC; 397281806Srpaulo goto skip_poll; 398281806Srpaulo } else if (inactive_sec < hapd->conf->ap_max_inactivity) { 399214501Srpaulo /* station activity detected; reset timeout state */ 400252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, 401252726Srpaulo "Station " MACSTR " has been active %is ago", 402252726Srpaulo MAC2STR(sta->addr), inactive_sec); 403214501Srpaulo sta->timeout_next = STA_NULLFUNC; 404252726Srpaulo next_time = hapd->conf->ap_max_inactivity + fuzz - 405214501Srpaulo inactive_sec; 406252726Srpaulo } else { 407252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, 408252726Srpaulo "Station " MACSTR " has been " 409252726Srpaulo "inactive too long: %d sec, max allowed: %d", 410252726Srpaulo MAC2STR(sta->addr), inactive_sec, 411252726Srpaulo hapd->conf->ap_max_inactivity); 412252726Srpaulo 413252726Srpaulo if (hapd->conf->skip_inactivity_poll) 414252726Srpaulo sta->timeout_next = STA_DISASSOC; 415214501Srpaulo } 416214501Srpaulo } 417214501Srpaulo 418214501Srpaulo if ((sta->flags & WLAN_STA_ASSOC) && 419214501Srpaulo sta->timeout_next == STA_DISASSOC && 420252726Srpaulo !(sta->flags & WLAN_STA_PENDING_POLL) && 421252726Srpaulo !hapd->conf->skip_inactivity_poll) { 422252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR 423252726Srpaulo " has ACKed data poll", MAC2STR(sta->addr)); 424214501Srpaulo /* data nullfunc frame poll did not produce TX errors; assume 425214501Srpaulo * station ACKed it */ 426214501Srpaulo sta->timeout_next = STA_NULLFUNC; 427214501Srpaulo next_time = hapd->conf->ap_max_inactivity; 428214501Srpaulo } 429214501Srpaulo 430281806Srpauloskip_poll: 431214501Srpaulo if (next_time) { 432252726Srpaulo wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " 433252726Srpaulo "for " MACSTR " (%lu seconds)", 434252726Srpaulo __func__, MAC2STR(sta->addr), next_time); 435214501Srpaulo eloop_register_timeout(next_time, 0, ap_handle_timer, hapd, 436214501Srpaulo sta); 437214501Srpaulo return; 438214501Srpaulo } 439214501Srpaulo 440214501Srpaulo if (sta->timeout_next == STA_NULLFUNC && 441214501Srpaulo (sta->flags & WLAN_STA_ASSOC)) { 442252726Srpaulo wpa_printf(MSG_DEBUG, " Polling STA"); 443214501Srpaulo sta->flags |= WLAN_STA_PENDING_POLL; 444252726Srpaulo hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr, 445252726Srpaulo sta->flags & WLAN_STA_WMM); 446214501Srpaulo } else if (sta->timeout_next != STA_REMOVE) { 447214501Srpaulo int deauth = sta->timeout_next == STA_DEAUTH; 448214501Srpaulo 449252726Srpaulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, 450252726Srpaulo "Timeout, sending %s info to STA " MACSTR, 451252726Srpaulo deauth ? "deauthentication" : "disassociation", 452252726Srpaulo MAC2STR(sta->addr)); 453214501Srpaulo 454214501Srpaulo if (deauth) { 455252726Srpaulo hostapd_drv_sta_deauth( 456252726Srpaulo hapd, sta->addr, 457252726Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 458214501Srpaulo } else { 459281806Srpaulo reason = (sta->timeout_next == STA_DISASSOC) ? 460281806Srpaulo WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : 461281806Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID; 462281806Srpaulo 463281806Srpaulo hostapd_drv_sta_disassoc(hapd, sta->addr, reason); 464214501Srpaulo } 465214501Srpaulo } 466214501Srpaulo 467214501Srpaulo switch (sta->timeout_next) { 468214501Srpaulo case STA_NULLFUNC: 469214501Srpaulo sta->timeout_next = STA_DISASSOC; 470252726Srpaulo wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " 471252726Srpaulo "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)", 472252726Srpaulo __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY); 473214501Srpaulo eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer, 474214501Srpaulo hapd, sta); 475214501Srpaulo break; 476214501Srpaulo case STA_DISASSOC: 477281806Srpaulo case STA_DISASSOC_FROM_CLI: 478252726Srpaulo ap_sta_set_authorized(hapd, sta, 0); 479214501Srpaulo sta->flags &= ~WLAN_STA_ASSOC; 480214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 481214501Srpaulo if (!sta->acct_terminate_cause) 482214501Srpaulo sta->acct_terminate_cause = 483214501Srpaulo RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; 484214501Srpaulo accounting_sta_stop(hapd, sta); 485214501Srpaulo ieee802_1x_free_station(sta); 486214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 487214501Srpaulo HOSTAPD_LEVEL_INFO, "disassociated due to " 488214501Srpaulo "inactivity"); 489281806Srpaulo reason = (sta->timeout_next == STA_DISASSOC) ? 490281806Srpaulo WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : 491281806Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID; 492214501Srpaulo sta->timeout_next = STA_DEAUTH; 493252726Srpaulo wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " 494252726Srpaulo "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)", 495252726Srpaulo __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY); 496214501Srpaulo eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, 497214501Srpaulo hapd, sta); 498281806Srpaulo mlme_disassociate_indication(hapd, sta, reason); 499214501Srpaulo break; 500214501Srpaulo case STA_DEAUTH: 501214501Srpaulo case STA_REMOVE: 502214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 503214501Srpaulo HOSTAPD_LEVEL_INFO, "deauthenticated due to " 504252726Srpaulo "inactivity (timer DEAUTH/REMOVE)"); 505214501Srpaulo if (!sta->acct_terminate_cause) 506214501Srpaulo sta->acct_terminate_cause = 507214501Srpaulo RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; 508214501Srpaulo mlme_deauthenticate_indication( 509214501Srpaulo hapd, sta, 510214501Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 511214501Srpaulo ap_free_sta(hapd, sta); 512214501Srpaulo break; 513214501Srpaulo } 514214501Srpaulo} 515214501Srpaulo 516214501Srpaulo 517214501Srpaulostatic void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx) 518214501Srpaulo{ 519214501Srpaulo struct hostapd_data *hapd = eloop_ctx; 520214501Srpaulo struct sta_info *sta = timeout_ctx; 521214501Srpaulo 522252726Srpaulo if (!(sta->flags & WLAN_STA_AUTH)) { 523252726Srpaulo if (sta->flags & WLAN_STA_GAS) { 524252726Srpaulo wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA " 525252726Srpaulo "entry " MACSTR, MAC2STR(sta->addr)); 526252726Srpaulo ap_free_sta(hapd, sta); 527252726Srpaulo } 528214501Srpaulo return; 529252726Srpaulo } 530214501Srpaulo 531281806Srpaulo hostapd_drv_sta_deauth(hapd, sta->addr, 532281806Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 533214501Srpaulo mlme_deauthenticate_indication(hapd, sta, 534214501Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 535214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 536214501Srpaulo HOSTAPD_LEVEL_INFO, "deauthenticated due to " 537214501Srpaulo "session timeout"); 538214501Srpaulo sta->acct_terminate_cause = 539214501Srpaulo RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT; 540214501Srpaulo ap_free_sta(hapd, sta); 541214501Srpaulo} 542214501Srpaulo 543214501Srpaulo 544281806Srpaulovoid ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta, 545281806Srpaulo u32 session_timeout) 546281806Srpaulo{ 547281806Srpaulo if (eloop_replenish_timeout(session_timeout, 0, 548281806Srpaulo ap_handle_session_timer, hapd, sta) == 1) { 549281806Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 550281806Srpaulo HOSTAPD_LEVEL_DEBUG, "setting session timeout " 551281806Srpaulo "to %d seconds", session_timeout); 552281806Srpaulo } 553281806Srpaulo} 554281806Srpaulo 555281806Srpaulo 556214501Srpaulovoid ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, 557214501Srpaulo u32 session_timeout) 558214501Srpaulo{ 559214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 560214501Srpaulo HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d " 561214501Srpaulo "seconds", session_timeout); 562214501Srpaulo eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); 563214501Srpaulo eloop_register_timeout(session_timeout, 0, ap_handle_session_timer, 564214501Srpaulo hapd, sta); 565214501Srpaulo} 566214501Srpaulo 567214501Srpaulo 568214501Srpaulovoid ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta) 569214501Srpaulo{ 570214501Srpaulo eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); 571214501Srpaulo} 572214501Srpaulo 573214501Srpaulo 574281806Srpaulostatic void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx) 575281806Srpaulo{ 576281806Srpaulo#ifdef CONFIG_WNM 577281806Srpaulo struct hostapd_data *hapd = eloop_ctx; 578281806Srpaulo struct sta_info *sta = timeout_ctx; 579281806Srpaulo 580281806Srpaulo wpa_printf(MSG_DEBUG, "WNM: Session warning time reached for " MACSTR, 581281806Srpaulo MAC2STR(sta->addr)); 582281806Srpaulo if (sta->hs20_session_info_url == NULL) 583281806Srpaulo return; 584281806Srpaulo 585281806Srpaulo wnm_send_ess_disassoc_imminent(hapd, sta, sta->hs20_session_info_url, 586281806Srpaulo sta->hs20_disassoc_timer); 587281806Srpaulo#endif /* CONFIG_WNM */ 588281806Srpaulo} 589281806Srpaulo 590281806Srpaulo 591281806Srpaulovoid ap_sta_session_warning_timeout(struct hostapd_data *hapd, 592281806Srpaulo struct sta_info *sta, int warning_time) 593281806Srpaulo{ 594281806Srpaulo eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta); 595281806Srpaulo eloop_register_timeout(warning_time, 0, ap_handle_session_warning_timer, 596281806Srpaulo hapd, sta); 597281806Srpaulo} 598281806Srpaulo 599281806Srpaulo 600214501Srpaulostruct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) 601214501Srpaulo{ 602214501Srpaulo struct sta_info *sta; 603214501Srpaulo 604214501Srpaulo sta = ap_get_sta(hapd, addr); 605214501Srpaulo if (sta) 606214501Srpaulo return sta; 607214501Srpaulo 608214501Srpaulo wpa_printf(MSG_DEBUG, " New STA"); 609214501Srpaulo if (hapd->num_sta >= hapd->conf->max_num_sta) { 610214501Srpaulo /* FIX: might try to remove some old STAs first? */ 611214501Srpaulo wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)", 612214501Srpaulo hapd->num_sta, hapd->conf->max_num_sta); 613214501Srpaulo return NULL; 614214501Srpaulo } 615214501Srpaulo 616214501Srpaulo sta = os_zalloc(sizeof(struct sta_info)); 617214501Srpaulo if (sta == NULL) { 618214501Srpaulo wpa_printf(MSG_ERROR, "malloc failed"); 619214501Srpaulo return NULL; 620214501Srpaulo } 621214501Srpaulo sta->acct_interim_interval = hapd->conf->acct_interim_interval; 622252726Srpaulo accounting_sta_get_id(hapd, sta); 623214501Srpaulo 624281806Srpaulo if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) { 625281806Srpaulo wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " 626281806Srpaulo "for " MACSTR " (%d seconds - ap_max_inactivity)", 627281806Srpaulo __func__, MAC2STR(addr), 628281806Srpaulo hapd->conf->ap_max_inactivity); 629281806Srpaulo eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, 630281806Srpaulo ap_handle_timer, hapd, sta); 631281806Srpaulo } 632281806Srpaulo 633214501Srpaulo /* initialize STA info data */ 634214501Srpaulo os_memcpy(sta->addr, addr, ETH_ALEN); 635214501Srpaulo sta->next = hapd->sta_list; 636214501Srpaulo hapd->sta_list = sta; 637214501Srpaulo hapd->num_sta++; 638214501Srpaulo ap_sta_hash_add(hapd, sta); 639214501Srpaulo ap_sta_remove_in_other_bss(hapd, sta); 640281806Srpaulo sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; 641281806Srpaulo dl_list_init(&sta->ip6addr); 642214501Srpaulo 643214501Srpaulo return sta; 644214501Srpaulo} 645214501Srpaulo 646214501Srpaulo 647214501Srpaulostatic int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta) 648214501Srpaulo{ 649214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 650214501Srpaulo 651281806Srpaulo if (sta->ipaddr) 652281806Srpaulo hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); 653281806Srpaulo ap_sta_ip6addr_del(hapd, sta); 654281806Srpaulo 655214501Srpaulo wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver", 656214501Srpaulo MAC2STR(sta->addr)); 657252726Srpaulo if (hostapd_drv_sta_remove(hapd, sta->addr) && 658214501Srpaulo sta->flags & WLAN_STA_ASSOC) { 659214501Srpaulo wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR 660214501Srpaulo " from kernel driver.", MAC2STR(sta->addr)); 661214501Srpaulo return -1; 662214501Srpaulo } 663214501Srpaulo return 0; 664214501Srpaulo} 665214501Srpaulo 666214501Srpaulo 667214501Srpaulostatic void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, 668214501Srpaulo struct sta_info *sta) 669214501Srpaulo{ 670214501Srpaulo struct hostapd_iface *iface = hapd->iface; 671214501Srpaulo size_t i; 672214501Srpaulo 673214501Srpaulo for (i = 0; i < iface->num_bss; i++) { 674214501Srpaulo struct hostapd_data *bss = iface->bss[i]; 675214501Srpaulo struct sta_info *sta2; 676214501Srpaulo /* bss should always be set during operation, but it may be 677214501Srpaulo * NULL during reconfiguration. Assume the STA is not 678214501Srpaulo * associated to another BSS in that case to avoid NULL pointer 679214501Srpaulo * dereferences. */ 680214501Srpaulo if (bss == hapd || bss == NULL) 681214501Srpaulo continue; 682214501Srpaulo sta2 = ap_get_sta(bss, sta->addr); 683214501Srpaulo if (!sta2) 684214501Srpaulo continue; 685214501Srpaulo 686214501Srpaulo ap_sta_disconnect(bss, sta2, sta2->addr, 687214501Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 688214501Srpaulo } 689214501Srpaulo} 690214501Srpaulo 691214501Srpaulo 692252726Srpaulostatic void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx) 693252726Srpaulo{ 694252726Srpaulo struct hostapd_data *hapd = eloop_ctx; 695252726Srpaulo struct sta_info *sta = timeout_ctx; 696252726Srpaulo 697252726Srpaulo ap_sta_remove(hapd, sta); 698252726Srpaulo mlme_disassociate_indication(hapd, sta, sta->disassoc_reason); 699252726Srpaulo} 700252726Srpaulo 701252726Srpaulo 702214501Srpaulovoid ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, 703214501Srpaulo u16 reason) 704214501Srpaulo{ 705214501Srpaulo wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR, 706214501Srpaulo hapd->conf->iface, MAC2STR(sta->addr)); 707281806Srpaulo sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; 708281806Srpaulo sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); 709252726Srpaulo ap_sta_set_authorized(hapd, sta, 0); 710214501Srpaulo sta->timeout_next = STA_DEAUTH; 711252726Srpaulo wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " 712252726Srpaulo "for " MACSTR " (%d seconds - " 713252726Srpaulo "AP_MAX_INACTIVITY_AFTER_DISASSOC)", 714252726Srpaulo __func__, MAC2STR(sta->addr), 715252726Srpaulo AP_MAX_INACTIVITY_AFTER_DISASSOC); 716214501Srpaulo eloop_cancel_timeout(ap_handle_timer, hapd, sta); 717214501Srpaulo eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0, 718214501Srpaulo ap_handle_timer, hapd, sta); 719214501Srpaulo accounting_sta_stop(hapd, sta); 720214501Srpaulo ieee802_1x_free_station(sta); 721214501Srpaulo 722252726Srpaulo sta->disassoc_reason = reason; 723252726Srpaulo sta->flags |= WLAN_STA_PENDING_DISASSOC_CB; 724252726Srpaulo eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); 725252726Srpaulo eloop_register_timeout(hapd->iface->drv_flags & 726252726Srpaulo WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, 727252726Srpaulo ap_sta_disassoc_cb_timeout, hapd, sta); 728214501Srpaulo} 729214501Srpaulo 730214501Srpaulo 731252726Srpaulostatic void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx) 732252726Srpaulo{ 733252726Srpaulo struct hostapd_data *hapd = eloop_ctx; 734252726Srpaulo struct sta_info *sta = timeout_ctx; 735252726Srpaulo 736252726Srpaulo ap_sta_remove(hapd, sta); 737252726Srpaulo mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason); 738252726Srpaulo} 739252726Srpaulo 740252726Srpaulo 741214501Srpaulovoid ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, 742214501Srpaulo u16 reason) 743214501Srpaulo{ 744214501Srpaulo wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR, 745214501Srpaulo hapd->conf->iface, MAC2STR(sta->addr)); 746281806Srpaulo sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; 747281806Srpaulo sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); 748252726Srpaulo ap_sta_set_authorized(hapd, sta, 0); 749214501Srpaulo sta->timeout_next = STA_REMOVE; 750252726Srpaulo wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " 751252726Srpaulo "for " MACSTR " (%d seconds - " 752252726Srpaulo "AP_MAX_INACTIVITY_AFTER_DEAUTH)", 753252726Srpaulo __func__, MAC2STR(sta->addr), 754252726Srpaulo AP_MAX_INACTIVITY_AFTER_DEAUTH); 755214501Srpaulo eloop_cancel_timeout(ap_handle_timer, hapd, sta); 756214501Srpaulo eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, 757214501Srpaulo ap_handle_timer, hapd, sta); 758214501Srpaulo accounting_sta_stop(hapd, sta); 759214501Srpaulo ieee802_1x_free_station(sta); 760214501Srpaulo 761252726Srpaulo sta->deauth_reason = reason; 762252726Srpaulo sta->flags |= WLAN_STA_PENDING_DEAUTH_CB; 763252726Srpaulo eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); 764252726Srpaulo eloop_register_timeout(hapd->iface->drv_flags & 765252726Srpaulo WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, 766252726Srpaulo ap_sta_deauth_cb_timeout, hapd, sta); 767214501Srpaulo} 768214501Srpaulo 769214501Srpaulo 770252726Srpaulo#ifdef CONFIG_WPS 771252726Srpauloint ap_sta_wps_cancel(struct hostapd_data *hapd, 772252726Srpaulo struct sta_info *sta, void *ctx) 773252726Srpaulo{ 774252726Srpaulo if (sta && (sta->flags & WLAN_STA_WPS)) { 775252726Srpaulo ap_sta_deauthenticate(hapd, sta, 776252726Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 777252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR, 778252726Srpaulo __func__, MAC2STR(sta->addr)); 779252726Srpaulo return 1; 780252726Srpaulo } 781252726Srpaulo 782252726Srpaulo return 0; 783252726Srpaulo} 784252726Srpaulo#endif /* CONFIG_WPS */ 785252726Srpaulo 786252726Srpaulo 787289549Srpauloint ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta) 788214501Srpaulo{ 789214501Srpaulo#ifndef CONFIG_NO_VLAN 790214501Srpaulo const char *iface; 791214501Srpaulo struct hostapd_vlan *vlan = NULL; 792214501Srpaulo int ret; 793289549Srpaulo int old_vlanid = sta->vlan_id_bound; 794214501Srpaulo 795214501Srpaulo iface = hapd->conf->iface; 796289549Srpaulo if (hapd->conf->ssid.vlan[0]) 797289549Srpaulo iface = hapd->conf->ssid.vlan; 798214501Srpaulo 799289549Srpaulo if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED) 800214501Srpaulo sta->vlan_id = 0; 801214501Srpaulo else if (sta->vlan_id > 0) { 802281806Srpaulo struct hostapd_vlan *wildcard_vlan = NULL; 803214501Srpaulo vlan = hapd->conf->vlan; 804214501Srpaulo while (vlan) { 805281806Srpaulo if (vlan->vlan_id == sta->vlan_id) 806214501Srpaulo break; 807281806Srpaulo if (vlan->vlan_id == VLAN_ID_WILDCARD) 808281806Srpaulo wildcard_vlan = vlan; 809214501Srpaulo vlan = vlan->next; 810214501Srpaulo } 811281806Srpaulo if (!vlan) 812281806Srpaulo vlan = wildcard_vlan; 813281806Srpaulo if (vlan) 814281806Srpaulo iface = vlan->ifname; 815214501Srpaulo } 816214501Srpaulo 817289549Srpaulo /* 818289549Srpaulo * Do not increment ref counters if the VLAN ID remains same, but do 819289549Srpaulo * not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might 820289549Srpaulo * have been called before. 821289549Srpaulo */ 822289549Srpaulo if (sta->vlan_id == old_vlanid) 823289549Srpaulo goto skip_counting; 824289549Srpaulo 825214501Srpaulo if (sta->vlan_id > 0 && vlan == NULL) { 826214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 827214501Srpaulo HOSTAPD_LEVEL_DEBUG, "could not find VLAN for " 828214501Srpaulo "binding station to (vlan_id=%d)", 829214501Srpaulo sta->vlan_id); 830281806Srpaulo ret = -1; 831281806Srpaulo goto done; 832214501Srpaulo } else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) { 833214501Srpaulo vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id); 834214501Srpaulo if (vlan == NULL) { 835214501Srpaulo hostapd_logger(hapd, sta->addr, 836214501Srpaulo HOSTAPD_MODULE_IEEE80211, 837214501Srpaulo HOSTAPD_LEVEL_DEBUG, "could not add " 838214501Srpaulo "dynamic VLAN interface for vlan_id=%d", 839214501Srpaulo sta->vlan_id); 840281806Srpaulo ret = -1; 841281806Srpaulo goto done; 842214501Srpaulo } 843214501Srpaulo 844214501Srpaulo iface = vlan->ifname; 845289549Srpaulo if (vlan_setup_encryption_dyn(hapd, iface) != 0) { 846214501Srpaulo hostapd_logger(hapd, sta->addr, 847214501Srpaulo HOSTAPD_MODULE_IEEE80211, 848214501Srpaulo HOSTAPD_LEVEL_DEBUG, "could not " 849214501Srpaulo "configure encryption for dynamic VLAN " 850214501Srpaulo "interface for vlan_id=%d", 851214501Srpaulo sta->vlan_id); 852214501Srpaulo } 853214501Srpaulo 854214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 855214501Srpaulo HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN " 856214501Srpaulo "interface '%s'", iface); 857214501Srpaulo } else if (vlan && vlan->vlan_id == sta->vlan_id) { 858289549Srpaulo if (vlan->dynamic_vlan > 0) { 859214501Srpaulo vlan->dynamic_vlan++; 860214501Srpaulo hostapd_logger(hapd, sta->addr, 861214501Srpaulo HOSTAPD_MODULE_IEEE80211, 862214501Srpaulo HOSTAPD_LEVEL_DEBUG, "updated existing " 863214501Srpaulo "dynamic VLAN interface '%s'", iface); 864214501Srpaulo } 865214501Srpaulo 866214501Srpaulo /* 867214501Srpaulo * Update encryption configuration for statically generated 868214501Srpaulo * VLAN interface. This is only used for static WEP 869214501Srpaulo * configuration for the case where hostapd did not yet know 870214501Srpaulo * which keys are to be used when the interface was added. 871214501Srpaulo */ 872289549Srpaulo if (vlan_setup_encryption_dyn(hapd, iface) != 0) { 873214501Srpaulo hostapd_logger(hapd, sta->addr, 874214501Srpaulo HOSTAPD_MODULE_IEEE80211, 875214501Srpaulo HOSTAPD_LEVEL_DEBUG, "could not " 876214501Srpaulo "configure encryption for VLAN " 877214501Srpaulo "interface for vlan_id=%d", 878214501Srpaulo sta->vlan_id); 879214501Srpaulo } 880214501Srpaulo } 881214501Srpaulo 882289549Srpaulo /* ref counters have been increased, so mark the station */ 883289549Srpaulo sta->vlan_id_bound = sta->vlan_id; 884289549Srpaulo 885289549Srpauloskip_counting: 886214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 887214501Srpaulo HOSTAPD_LEVEL_DEBUG, "binding station to interface " 888214501Srpaulo "'%s'", iface); 889214501Srpaulo 890214501Srpaulo if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0) 891214501Srpaulo wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA"); 892214501Srpaulo 893252726Srpaulo ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id); 894214501Srpaulo if (ret < 0) { 895214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 896214501Srpaulo HOSTAPD_LEVEL_DEBUG, "could not bind the STA " 897214501Srpaulo "entry to vlan_id=%d", sta->vlan_id); 898214501Srpaulo } 899281806Srpaulo 900281806Srpaulo /* During 1x reauth, if the vlan id changes, then remove the old id. */ 901289549Srpaulo if (old_vlanid > 0 && old_vlanid != sta->vlan_id) 902281806Srpaulo vlan_remove_dynamic(hapd, old_vlanid); 903289549Srpaulodone: 904281806Srpaulo 905214501Srpaulo return ret; 906214501Srpaulo#else /* CONFIG_NO_VLAN */ 907214501Srpaulo return 0; 908214501Srpaulo#endif /* CONFIG_NO_VLAN */ 909214501Srpaulo} 910214501Srpaulo 911214501Srpaulo 912214501Srpaulo#ifdef CONFIG_IEEE80211W 913214501Srpaulo 914214501Srpauloint ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta) 915214501Srpaulo{ 916214501Srpaulo u32 tu; 917281806Srpaulo struct os_reltime now, passed; 918281806Srpaulo os_get_reltime(&now); 919281806Srpaulo os_reltime_sub(&now, &sta->sa_query_start, &passed); 920214501Srpaulo tu = (passed.sec * 1000000 + passed.usec) / 1024; 921214501Srpaulo if (hapd->conf->assoc_sa_query_max_timeout < tu) { 922214501Srpaulo hostapd_logger(hapd, sta->addr, 923214501Srpaulo HOSTAPD_MODULE_IEEE80211, 924214501Srpaulo HOSTAPD_LEVEL_DEBUG, 925214501Srpaulo "association SA Query timed out"); 926214501Srpaulo sta->sa_query_timed_out = 1; 927214501Srpaulo os_free(sta->sa_query_trans_id); 928214501Srpaulo sta->sa_query_trans_id = NULL; 929214501Srpaulo sta->sa_query_count = 0; 930214501Srpaulo eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); 931214501Srpaulo return 1; 932214501Srpaulo } 933214501Srpaulo 934214501Srpaulo return 0; 935214501Srpaulo} 936214501Srpaulo 937214501Srpaulo 938214501Srpaulostatic void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx) 939214501Srpaulo{ 940214501Srpaulo struct hostapd_data *hapd = eloop_ctx; 941214501Srpaulo struct sta_info *sta = timeout_ctx; 942214501Srpaulo unsigned int timeout, sec, usec; 943214501Srpaulo u8 *trans_id, *nbuf; 944214501Srpaulo 945214501Srpaulo if (sta->sa_query_count > 0 && 946214501Srpaulo ap_check_sa_query_timeout(hapd, sta)) 947214501Srpaulo return; 948214501Srpaulo 949252726Srpaulo nbuf = os_realloc_array(sta->sa_query_trans_id, 950252726Srpaulo sta->sa_query_count + 1, 951252726Srpaulo WLAN_SA_QUERY_TR_ID_LEN); 952214501Srpaulo if (nbuf == NULL) 953214501Srpaulo return; 954214501Srpaulo if (sta->sa_query_count == 0) { 955214501Srpaulo /* Starting a new SA Query procedure */ 956281806Srpaulo os_get_reltime(&sta->sa_query_start); 957214501Srpaulo } 958214501Srpaulo trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN; 959214501Srpaulo sta->sa_query_trans_id = nbuf; 960214501Srpaulo sta->sa_query_count++; 961214501Srpaulo 962281806Srpaulo if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) { 963281806Srpaulo /* 964281806Srpaulo * We don't really care which ID is used here, so simply 965281806Srpaulo * hardcode this if the mostly theoretical os_get_random() 966281806Srpaulo * failure happens. 967281806Srpaulo */ 968281806Srpaulo trans_id[0] = 0x12; 969281806Srpaulo trans_id[1] = 0x34; 970281806Srpaulo } 971214501Srpaulo 972214501Srpaulo timeout = hapd->conf->assoc_sa_query_retry_timeout; 973214501Srpaulo sec = ((timeout / 1000) * 1024) / 1000; 974214501Srpaulo usec = (timeout % 1000) * 1024; 975214501Srpaulo eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta); 976214501Srpaulo 977214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 978214501Srpaulo HOSTAPD_LEVEL_DEBUG, 979214501Srpaulo "association SA Query attempt %d", sta->sa_query_count); 980214501Srpaulo 981214501Srpaulo ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id); 982214501Srpaulo} 983214501Srpaulo 984214501Srpaulo 985214501Srpaulovoid ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta) 986214501Srpaulo{ 987214501Srpaulo ap_sa_query_timer(hapd, sta); 988214501Srpaulo} 989214501Srpaulo 990214501Srpaulo 991214501Srpaulovoid ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta) 992214501Srpaulo{ 993214501Srpaulo eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); 994214501Srpaulo os_free(sta->sa_query_trans_id); 995214501Srpaulo sta->sa_query_trans_id = NULL; 996214501Srpaulo sta->sa_query_count = 0; 997214501Srpaulo} 998214501Srpaulo 999214501Srpaulo#endif /* CONFIG_IEEE80211W */ 1000214501Srpaulo 1001214501Srpaulo 1002252726Srpaulovoid ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, 1003252726Srpaulo int authorized) 1004252726Srpaulo{ 1005252726Srpaulo const u8 *dev_addr = NULL; 1006281806Srpaulo char buf[100]; 1007252726Srpaulo#ifdef CONFIG_P2P 1008252726Srpaulo u8 addr[ETH_ALEN]; 1009281806Srpaulo u8 ip_addr_buf[4]; 1010252726Srpaulo#endif /* CONFIG_P2P */ 1011252726Srpaulo 1012252726Srpaulo if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED)) 1013252726Srpaulo return; 1014252726Srpaulo 1015281806Srpaulo if (authorized) 1016281806Srpaulo sta->flags |= WLAN_STA_AUTHORIZED; 1017281806Srpaulo else 1018281806Srpaulo sta->flags &= ~WLAN_STA_AUTHORIZED; 1019281806Srpaulo 1020252726Srpaulo#ifdef CONFIG_P2P 1021252726Srpaulo if (hapd->p2p_group == NULL) { 1022252726Srpaulo if (sta->p2p_ie != NULL && 1023252726Srpaulo p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0) 1024252726Srpaulo dev_addr = addr; 1025252726Srpaulo } else 1026252726Srpaulo dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr); 1027281806Srpaulo 1028281806Srpaulo if (dev_addr) 1029281806Srpaulo os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR, 1030281806Srpaulo MAC2STR(sta->addr), MAC2STR(dev_addr)); 1031281806Srpaulo else 1032252726Srpaulo#endif /* CONFIG_P2P */ 1033281806Srpaulo os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr)); 1034252726Srpaulo 1035281806Srpaulo if (hapd->sta_authorized_cb) 1036281806Srpaulo hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx, 1037281806Srpaulo sta->addr, authorized, dev_addr); 1038281806Srpaulo 1039252726Srpaulo if (authorized) { 1040281806Srpaulo char ip_addr[100]; 1041281806Srpaulo ip_addr[0] = '\0'; 1042281806Srpaulo#ifdef CONFIG_P2P 1043281806Srpaulo if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) { 1044281806Srpaulo os_snprintf(ip_addr, sizeof(ip_addr), 1045281806Srpaulo " ip_addr=%u.%u.%u.%u", 1046281806Srpaulo ip_addr_buf[0], ip_addr_buf[1], 1047281806Srpaulo ip_addr_buf[2], ip_addr_buf[3]); 1048281806Srpaulo } 1049281806Srpaulo#endif /* CONFIG_P2P */ 1050281806Srpaulo 1051281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s", 1052281806Srpaulo buf, ip_addr); 1053281806Srpaulo 1054252726Srpaulo if (hapd->msg_ctx_parent && 1055281806Srpaulo hapd->msg_ctx_parent != hapd->msg_ctx) 1056281806Srpaulo wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, 1057281806Srpaulo AP_STA_CONNECTED "%s%s", 1058281806Srpaulo buf, ip_addr); 1059281806Srpaulo } else { 1060281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf); 1061252726Srpaulo 1062252726Srpaulo if (hapd->msg_ctx_parent && 1063281806Srpaulo hapd->msg_ctx_parent != hapd->msg_ctx) 1064281806Srpaulo wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, 1065281806Srpaulo AP_STA_DISCONNECTED "%s", buf); 1066252726Srpaulo } 1067289549Srpaulo 1068289549Srpaulo#ifdef CONFIG_FST 1069289549Srpaulo if (hapd->iface->fst) { 1070289549Srpaulo if (authorized) 1071289549Srpaulo fst_notify_peer_connected(hapd->iface->fst, sta->addr); 1072289549Srpaulo else 1073289549Srpaulo fst_notify_peer_disconnected(hapd->iface->fst, 1074289549Srpaulo sta->addr); 1075289549Srpaulo } 1076289549Srpaulo#endif /* CONFIG_FST */ 1077252726Srpaulo} 1078252726Srpaulo 1079252726Srpaulo 1080214501Srpaulovoid ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, 1081214501Srpaulo const u8 *addr, u16 reason) 1082214501Srpaulo{ 1083214501Srpaulo 1084214501Srpaulo if (sta == NULL && addr) 1085214501Srpaulo sta = ap_get_sta(hapd, addr); 1086214501Srpaulo 1087214501Srpaulo if (addr) 1088252726Srpaulo hostapd_drv_sta_deauth(hapd, addr, reason); 1089214501Srpaulo 1090214501Srpaulo if (sta == NULL) 1091214501Srpaulo return; 1092252726Srpaulo ap_sta_set_authorized(hapd, sta, 0); 1093252726Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); 1094252726Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 1095252726Srpaulo sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); 1096252726Srpaulo wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " 1097252726Srpaulo "for " MACSTR " (%d seconds - " 1098252726Srpaulo "AP_MAX_INACTIVITY_AFTER_DEAUTH)", 1099252726Srpaulo __func__, MAC2STR(sta->addr), 1100252726Srpaulo AP_MAX_INACTIVITY_AFTER_DEAUTH); 1101214501Srpaulo eloop_cancel_timeout(ap_handle_timer, hapd, sta); 1102252726Srpaulo eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, 1103252726Srpaulo ap_handle_timer, hapd, sta); 1104214501Srpaulo sta->timeout_next = STA_REMOVE; 1105252726Srpaulo 1106252726Srpaulo sta->deauth_reason = reason; 1107252726Srpaulo sta->flags |= WLAN_STA_PENDING_DEAUTH_CB; 1108252726Srpaulo eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); 1109252726Srpaulo eloop_register_timeout(hapd->iface->drv_flags & 1110252726Srpaulo WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, 1111252726Srpaulo ap_sta_deauth_cb_timeout, hapd, sta); 1112214501Srpaulo} 1113252726Srpaulo 1114252726Srpaulo 1115252726Srpaulovoid ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta) 1116252726Srpaulo{ 1117252726Srpaulo if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) { 1118252726Srpaulo wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame"); 1119252726Srpaulo return; 1120252726Srpaulo } 1121252726Srpaulo sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB; 1122252726Srpaulo eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); 1123252726Srpaulo ap_sta_deauth_cb_timeout(hapd, sta); 1124252726Srpaulo} 1125252726Srpaulo 1126252726Srpaulo 1127252726Srpaulovoid ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta) 1128252726Srpaulo{ 1129252726Srpaulo if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) { 1130252726Srpaulo wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame"); 1131252726Srpaulo return; 1132252726Srpaulo } 1133252726Srpaulo sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB; 1134252726Srpaulo eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); 1135252726Srpaulo ap_sta_disassoc_cb_timeout(hapd, sta); 1136252726Srpaulo} 1137281806Srpaulo 1138281806Srpaulo 1139281806Srpauloint ap_sta_flags_txt(u32 flags, char *buf, size_t buflen) 1140281806Srpaulo{ 1141281806Srpaulo int res; 1142281806Srpaulo 1143281806Srpaulo buf[0] = '\0'; 1144281806Srpaulo res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 1145281806Srpaulo (flags & WLAN_STA_AUTH ? "[AUTH]" : ""), 1146281806Srpaulo (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), 1147281806Srpaulo (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""), 1148281806Srpaulo (flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" : 1149281806Srpaulo ""), 1150281806Srpaulo (flags & WLAN_STA_SHORT_PREAMBLE ? 1151281806Srpaulo "[SHORT_PREAMBLE]" : ""), 1152281806Srpaulo (flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""), 1153281806Srpaulo (flags & WLAN_STA_WMM ? "[WMM]" : ""), 1154281806Srpaulo (flags & WLAN_STA_MFP ? "[MFP]" : ""), 1155281806Srpaulo (flags & WLAN_STA_WPS ? "[WPS]" : ""), 1156281806Srpaulo (flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""), 1157281806Srpaulo (flags & WLAN_STA_WDS ? "[WDS]" : ""), 1158281806Srpaulo (flags & WLAN_STA_NONERP ? "[NonERP]" : ""), 1159281806Srpaulo (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""), 1160281806Srpaulo (flags & WLAN_STA_GAS ? "[GAS]" : ""), 1161281806Srpaulo (flags & WLAN_STA_VHT ? "[VHT]" : ""), 1162281806Srpaulo (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""), 1163281806Srpaulo (flags & WLAN_STA_WNM_SLEEP_MODE ? 1164281806Srpaulo "[WNM_SLEEP_MODE]" : "")); 1165281806Srpaulo if (os_snprintf_error(buflen, res)) 1166281806Srpaulo res = -1; 1167281806Srpaulo 1168281806Srpaulo return res; 1169281806Srpaulo} 1170