Delay STA entry removal until Deauth/Disassoc TX status in AP mode
This allows the driver to use PS buffering of Deauthentication and Disassociation frames when the STA is in power save sleep. The STA entry (and PTK) will be removed from the kernel only after the Deauth/Disassoc has been transmitted (e.g., when the STA wakes up). A hardcoded two second timeout is used to limit the length of this window should the driver fail to deliver the frame (e.g., the STA is out of range and does not wake up). The kernel STA entry is marked unauthorized during the wait to avoid accepting Data frames from the STA that we have decided to disconnect. This behavior is available only with drivers that provide TX status events for Deauth/Disassoc frames (nl80211 at this point). Other drivers continue to use the previous behavior where the STA entry is removed immediately.
This commit is contained in:
parent
49a191a142
commit
4dc03726de
5 changed files with 123 additions and 9 deletions
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* hostapd / IEEE 802.11 Management
|
* hostapd / IEEE 802.11 Management
|
||||||
* Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -1752,6 +1752,54 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void handle_deauth_cb(struct hostapd_data *hapd,
|
||||||
|
const struct ieee80211_mgmt *mgmt,
|
||||||
|
size_t len, int ok)
|
||||||
|
{
|
||||||
|
struct sta_info *sta;
|
||||||
|
if (mgmt->da[0] & 0x01)
|
||||||
|
return;
|
||||||
|
sta = ap_get_sta(hapd, mgmt->da);
|
||||||
|
if (!sta) {
|
||||||
|
wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
|
||||||
|
" not found", MAC2STR(mgmt->da));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ok)
|
||||||
|
wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
else
|
||||||
|
wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
|
||||||
|
"deauth", MAC2STR(sta->addr));
|
||||||
|
|
||||||
|
ap_sta_deauth_cb(hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void handle_disassoc_cb(struct hostapd_data *hapd,
|
||||||
|
const struct ieee80211_mgmt *mgmt,
|
||||||
|
size_t len, int ok)
|
||||||
|
{
|
||||||
|
struct sta_info *sta;
|
||||||
|
if (mgmt->da[0] & 0x01)
|
||||||
|
return;
|
||||||
|
sta = ap_get_sta(hapd, mgmt->da);
|
||||||
|
if (!sta) {
|
||||||
|
wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
|
||||||
|
" not found", MAC2STR(mgmt->da));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ok)
|
||||||
|
wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
else
|
||||||
|
wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
|
||||||
|
"disassoc", MAC2STR(sta->addr));
|
||||||
|
|
||||||
|
ap_sta_disassoc_cb(hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee802_11_mgmt_cb - Process management frame TX status callback
|
* ieee802_11_mgmt_cb - Process management frame TX status callback
|
||||||
* @hapd: hostapd BSS data structure (the BSS from which the management frame
|
* @hapd: hostapd BSS data structure (the BSS from which the management frame
|
||||||
|
@ -1784,7 +1832,12 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
|
||||||
wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
|
wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
|
||||||
break;
|
break;
|
||||||
case WLAN_FC_STYPE_DEAUTH:
|
case WLAN_FC_STYPE_DEAUTH:
|
||||||
/* ignore */
|
wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
|
||||||
|
handle_deauth_cb(hapd, mgmt, len, ok);
|
||||||
|
break;
|
||||||
|
case WLAN_FC_STYPE_DISASSOC:
|
||||||
|
wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
|
||||||
|
handle_disassoc_cb(hapd, mgmt, len, ok);
|
||||||
break;
|
break;
|
||||||
case WLAN_FC_STYPE_ACTION:
|
case WLAN_FC_STYPE_ACTION:
|
||||||
wpa_printf(MSG_DEBUG, "mgmt::action cb");
|
wpa_printf(MSG_DEBUG, "mgmt::action cb");
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* hostapd / Station table
|
* hostapd / Station table
|
||||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -38,9 +38,12 @@
|
||||||
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
|
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
|
||||||
struct sta_info *sta);
|
struct sta_info *sta);
|
||||||
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
|
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
|
||||||
|
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||||
|
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||||
#ifdef CONFIG_IEEE80211W
|
#ifdef CONFIG_IEEE80211W
|
||||||
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
|
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
|
||||||
#endif /* CONFIG_IEEE80211W */
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
|
||||||
int ap_for_each_sta(struct hostapd_data *hapd,
|
int ap_for_each_sta(struct hostapd_data *hapd,
|
||||||
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
|
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
@ -198,6 +201,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
|
||||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||||
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
|
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
|
||||||
|
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
|
||||||
|
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
|
||||||
|
|
||||||
ieee802_1x_free_station(sta);
|
ieee802_1x_free_station(sta);
|
||||||
wpa_auth_sta_deinit(sta->wpa_sm);
|
wpa_auth_sta_deinit(sta->wpa_sm);
|
||||||
|
@ -525,13 +530,23 @@ static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = eloop_ctx;
|
||||||
|
struct sta_info *sta = timeout_ctx;
|
||||||
|
|
||||||
|
ap_sta_remove(hapd, sta);
|
||||||
|
mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
u16 reason)
|
u16 reason)
|
||||||
{
|
{
|
||||||
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
|
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
|
||||||
hapd->conf->iface, MAC2STR(sta->addr));
|
hapd->conf->iface, MAC2STR(sta->addr));
|
||||||
sta->flags &= ~WLAN_STA_ASSOC;
|
sta->flags &= ~WLAN_STA_ASSOC;
|
||||||
ap_sta_remove(hapd, sta);
|
ap_sta_set_authorized(hapd, sta, 0);
|
||||||
sta->timeout_next = STA_DEAUTH;
|
sta->timeout_next = STA_DEAUTH;
|
||||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||||
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
|
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
|
||||||
|
@ -539,7 +554,21 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
accounting_sta_stop(hapd, sta);
|
accounting_sta_stop(hapd, sta);
|
||||||
ieee802_1x_free_station(sta);
|
ieee802_1x_free_station(sta);
|
||||||
|
|
||||||
mlme_disassociate_indication(hapd, sta, reason);
|
sta->disassoc_reason = reason;
|
||||||
|
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
|
||||||
|
eloop_register_timeout(hapd->iface->drv_flags &
|
||||||
|
WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
|
||||||
|
ap_sta_disassoc_cb_timeout, hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = eloop_ctx;
|
||||||
|
struct sta_info *sta = timeout_ctx;
|
||||||
|
|
||||||
|
ap_sta_remove(hapd, sta);
|
||||||
|
mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -549,7 +578,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
|
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
|
||||||
hapd->conf->iface, MAC2STR(sta->addr));
|
hapd->conf->iface, MAC2STR(sta->addr));
|
||||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
||||||
ap_sta_remove(hapd, sta);
|
ap_sta_set_authorized(hapd, sta, 0);
|
||||||
sta->timeout_next = STA_REMOVE;
|
sta->timeout_next = STA_REMOVE;
|
||||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||||
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
|
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
|
||||||
|
@ -557,7 +586,11 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
accounting_sta_stop(hapd, sta);
|
accounting_sta_stop(hapd, sta);
|
||||||
ieee802_1x_free_station(sta);
|
ieee802_1x_free_station(sta);
|
||||||
|
|
||||||
mlme_deauthenticate_indication(hapd, sta, reason);
|
sta->deauth_reason = reason;
|
||||||
|
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
|
||||||
|
eloop_register_timeout(hapd->iface->drv_flags &
|
||||||
|
WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
|
||||||
|
ap_sta_deauth_cb_timeout, hapd, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -791,6 +824,25 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
ap_sta_set_authorized(hapd, sta, 0);
|
ap_sta_set_authorized(hapd, sta, 0);
|
||||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
||||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||||
eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
|
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
|
||||||
|
ap_handle_timer, hapd, sta);
|
||||||
sta->timeout_next = STA_REMOVE;
|
sta->timeout_next = STA_REMOVE;
|
||||||
|
|
||||||
|
sta->deauth_reason = reason;
|
||||||
|
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
|
||||||
|
eloop_register_timeout(hapd->iface->drv_flags &
|
||||||
|
WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
|
||||||
|
ap_sta_deauth_cb_timeout, hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
|
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
|
||||||
|
ap_sta_deauth_cb_timeout(hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* hostapd / Station table
|
* hostapd / Station table
|
||||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -66,6 +66,9 @@ struct sta_info {
|
||||||
STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
|
STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
|
||||||
} timeout_next;
|
} timeout_next;
|
||||||
|
|
||||||
|
u16 deauth_reason;
|
||||||
|
u16 disassoc_reason;
|
||||||
|
|
||||||
/* IEEE 802.1X related data */
|
/* IEEE 802.1X related data */
|
||||||
struct eapol_state_machine *eapol_sm;
|
struct eapol_state_machine *eapol_sm;
|
||||||
|
|
||||||
|
@ -163,4 +166,7 @@ static inline int ap_sta_is_authorized(struct sta_info *sta)
|
||||||
return sta->flags & WLAN_STA_AUTHORIZED;
|
return sta->flags & WLAN_STA_AUTHORIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
|
||||||
#endif /* STA_INFO_H */
|
#endif /* STA_INFO_H */
|
||||||
|
|
|
@ -673,6 +673,8 @@ struct wpa_driver_capa {
|
||||||
#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000
|
#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000
|
||||||
/* Driver indicates TX status events for EAPOL Data frames */
|
/* Driver indicates TX status events for EAPOL Data frames */
|
||||||
#define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS 0x00010000
|
#define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS 0x00010000
|
||||||
|
/* Driver indicates TX status events for Deauth/Disassoc frames */
|
||||||
|
#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS 0x00020000
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
|
||||||
int max_scan_ssids;
|
int max_scan_ssids;
|
||||||
|
|
|
@ -1773,6 +1773,7 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
|
||||||
if (info.p2p_supported)
|
if (info.p2p_supported)
|
||||||
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
|
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
|
||||||
drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
|
drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
|
||||||
|
drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
|
||||||
drv->capa.max_remain_on_chan = info.max_remain_on_chan;
|
drv->capa.max_remain_on_chan = info.max_remain_on_chan;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue