/*
* hostapd / Station table
* Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2007-2008, Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include "includes.h"
+#include "common.h"
#include "hostapd.h"
#include "sta_info.h"
#include "eloop.h"
#include "wpa.h"
#include "preauth.h"
#include "radius/radius_client.h"
-#include "driver.h"
+#include "driver_i.h"
#include "beacon.h"
#include "hw_features.h"
#include "mlme.h"
accounting_sta_stop(hapd, sta);
+ hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0);
if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC) &&
!(sta->flags & WLAN_STA_PREAUTH))
hostapd_sta_remove(hapd, sta->addr);
ap_sta_list_del(hapd, sta);
if (sta->aid > 0)
- hapd->sta_aid[sta->aid - 1] = NULL;
+ hapd->sta_aid[(sta->aid - 1) / 32] &=
+ ~BIT((sta->aid - 1) % 32);
hapd->num_sta--;
if (sta->nonerp_set) {
set_beacon++;
}
-#ifdef CONFIG_IEEE80211N
if (sta->no_ht_gf_set) {
sta->no_ht_gf_set = 0;
hapd->iface->num_sta_ht_no_gf--;
hapd->iface->num_sta_ht_20mhz--;
}
+#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
if (hostapd_ht_operation_update(hapd->iface) > 0)
set_beacon++;
-#endif /* CONFIG_IEEE80211N */
+#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
if (set_beacon)
ieee802_11_set_beacons(hapd->iface);
ieee802_1x_free_station(sta);
wpa_auth_sta_deinit(sta->wpa_sm);
rsn_preauth_free_station(hapd, sta);
+#ifndef CONFIG_NO_RADIUS
radius_client_flush_auth(hapd->radius, sta->addr);
+#endif /* CONFIG_NO_RADIUS */
os_free(sta->last_assoc_req);
os_free(sta->challenge);
wpabuf_free(sta->wps_ie);
+ os_free(sta->ht_capabilities);
+
os_free(sta);
}
}
+/**
+ * ap_handle_timer - Per STA timer handler
+ * @eloop_ctx: struct hostapd_data *
+ * @timeout_ctx: struct sta_info *
+ *
+ * This function is called to check station activity and to remove inactive
+ * stations.
+ */
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
sta->flags |= WLAN_STA_PENDING_POLL;
#ifndef CONFIG_NATIVE_WINDOWS
- /* FIX: WLAN_FC_STYPE_NULLFUNC would be more appropriate, but
- * it is apparently not retried so TX Exc events are not
- * received for it */
os_memset(&hdr, 0, sizeof(hdr));
- hdr.frame_control =
- IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
+ if (hapd->driver &&
+ os_strcmp(hapd->driver->name, "hostap") == 0) {
+ /*
+ * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
+ * but it is apparently not retried so TX Exc events
+ * are not received for it.
+ */
+ hdr.frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA,
+ WLAN_FC_STYPE_DATA);
+ } else {
+ hdr.frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA,
+ WLAN_FC_STYPE_NULLFUNC);
+ }
+
hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
ETH_ALEN);
os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
- if (hostapd_send_mgmt_frame(hapd, &hdr, sizeof(hdr), 0) < 0)
+ if (hapd->drv.send_mgmt_frame(hapd, &hdr, sizeof(hdr)) < 0)
perror("ap_handle_timer: send");
#endif /* CONFIG_NATIVE_WINDOWS */
} else if (sta->timeout_next != STA_REMOVE) {
wpa_printf(MSG_ERROR, "malloc failed");
return NULL;
}
- sta->acct_interim_interval = hapd->conf->radius->acct_interim_interval;
+ sta->acct_interim_interval = hapd->conf->acct_interim_interval;
/* initialize STA info data */
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int old_vlanid)
{
+#ifndef CONFIG_NO_VLAN
const char *iface;
struct hostapd_vlan *vlan = NULL;
wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
return hostapd_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
+#else /* CONFIG_NO_VLAN */
+ return 0;
+#endif /* CONFIG_NO_VLAN */
}
#ifdef CONFIG_IEEE80211W
-/* MLME-SAQuery.request */
-static void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
- const u8 *addr, const u8 *trans_id)
+int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
- struct ieee80211_mgmt mgmt;
- u8 *end;
-
- os_memset(&mgmt, 0, sizeof(mgmt));
- mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- os_memcpy(mgmt.da, addr, ETH_ALEN);
- os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
- mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
- mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
- os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
- WLAN_SA_QUERY_TR_ID_LEN);
- end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
- if (hostapd_send_mgmt_frame(hapd, &mgmt, IEEE80211_HDRLEN +
- end - (u8 *) &mgmt, 0) < 0)
- perror("ieee802_11_send_sa_query_req: send");
+ u32 tu;
+ struct os_time now, passed;
+ os_get_time(&now);
+ os_time_sub(&now, &sta->sa_query_start, &passed);
+ tu = (passed.sec * 1000000 + passed.usec) / 1024;
+ if (hapd->conf->assoc_sa_query_max_timeout < tu) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "association SA Query timed out");
+ sta->sa_query_timed_out = 1;
+ os_free(sta->sa_query_trans_id);
+ sta->sa_query_trans_id = NULL;
+ sta->sa_query_count = 0;
+ eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+ return 1;
+ }
+
+ return 0;
}
unsigned int timeout, sec, usec;
u8 *trans_id, *nbuf;
- if (sta->sa_query_count >= hapd->conf->assoc_ping_attempts) {
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG,
- "association SA Query timed out");
- sta->sa_query_timed_out = 1;
- os_free(sta->sa_query_trans_id);
- sta->sa_query_trans_id = NULL;
- sta->sa_query_count = 0;
+ if (sta->sa_query_count > 0 &&
+ ap_check_sa_query_timeout(hapd, sta))
return;
- }
nbuf = os_realloc(sta->sa_query_trans_id,
(sta->sa_query_count + 1) * WLAN_SA_QUERY_TR_ID_LEN);
if (nbuf == NULL)
return;
+ if (sta->sa_query_count == 0) {
+ /* Starting a new SA Query procedure */
+ os_get_time(&sta->sa_query_start);
+ }
trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
sta->sa_query_trans_id = nbuf;
sta->sa_query_count++;
os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+ timeout = hapd->conf->assoc_sa_query_retry_timeout;
+ sec = ((timeout / 1000) * 1024) / 1000;
+ usec = (timeout % 1000) * 1024;
+ eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
+
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"association SA Query attempt %d", sta->sa_query_count);
+#ifdef NEED_AP_MLME
ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
-
- timeout = hapd->conf->assoc_ping_timeout;
- sec = ((timeout / 1000) * 1024) / 1000;
- usec = (timeout % 1000) * 1024;
- eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
+#endif /* NEED_AP_MLME */
}
}
#endif /* CONFIG_IEEE80211W */
+
+
+void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *addr, u16 reason)
+{
+
+ if (sta == NULL && addr)
+ sta = ap_get_sta(hapd, addr);
+
+ if (addr)
+ hostapd_sta_deauth(hapd, addr, reason);
+
+ if (sta == NULL)
+ return;
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED);
+ eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+ eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
+ sta->timeout_next = STA_REMOVE;
+}