AP/GO interface teardown optimization
This commit adds an option to optimize AP teardown by leaving the deletion of keys (including group keys) and stations to the driver. This optimization option should be used if the driver supports stations and keys removal when stopping an AP. For example, the optimization option will always be used for cfg80211 drivers since cfg80211 shall always remove stations and keys when stopping an AP (in order to support cases where the AP is disabled without the knowledge of wpa_supplicant/hostapd). Signed-off-by: Moshe Benji <moshe.benji@intel.com>
This commit is contained in:
parent
8bc4372f37
commit
354c903f8e
8 changed files with 63 additions and 12 deletions
|
@ -728,8 +728,12 @@ int main(int argc, char *argv[])
|
|||
out:
|
||||
hostapd_global_ctrl_iface_deinit(&interfaces);
|
||||
/* Deinitialize all interfaces */
|
||||
for (i = 0; i < interfaces.count; i++)
|
||||
for (i = 0; i < interfaces.count; i++) {
|
||||
interfaces.iface[i]->driver_ap_teardown =
|
||||
!!(interfaces.iface[i]->drv_flags &
|
||||
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
|
||||
hostapd_interface_deinit_free(interfaces.iface[i]);
|
||||
}
|
||||
os_free(interfaces.iface);
|
||||
|
||||
hostapd_global_deinit(pid_file);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "wpa_auth.h"
|
||||
#include "sta_info.h"
|
||||
#include "ap_mlme.h"
|
||||
#include "hostapd.h"
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_HOSTAPD_LOGGER
|
||||
|
@ -80,6 +81,7 @@ void mlme_deauthenticate_indication(struct hostapd_data *hapd,
|
|||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
|
||||
MAC2STR(sta->addr), reason_code);
|
||||
if (!hapd->iface->driver_ap_teardown)
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
}
|
||||
|
||||
|
|
|
@ -350,7 +350,7 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
|
|||
|
||||
static void hostapd_clear_wep(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->drv_priv) {
|
||||
if (hapd->drv_priv && !hapd->iface->driver_ap_teardown) {
|
||||
hostapd_set_privacy(hapd, 0);
|
||||
hostapd_broadcast_wep_clear(hapd);
|
||||
}
|
||||
|
@ -401,12 +401,16 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
|
|||
if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
|
||||
return 0;
|
||||
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries");
|
||||
if (!hapd->iface->driver_ap_teardown) {
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"Flushing old station entries");
|
||||
|
||||
if (hostapd_flush(hapd)) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to "
|
||||
"kernel driver");
|
||||
wpa_msg(hapd->msg_ctx, MSG_WARNING,
|
||||
"Could not connect to kernel driver");
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
|
||||
os_memset(addr, 0xff, ETH_ALEN);
|
||||
hostapd_drv_sta_deauth(hapd, addr, reason);
|
||||
|
@ -1009,6 +1013,15 @@ static int setup_interface(struct hostapd_iface *iface)
|
|||
struct hostapd_data *hapd = iface->bss[0];
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* It is possible that setup_interface() is called after the interface
|
||||
* was disabled etc., in which case driver_ap_teardown is possibly set
|
||||
* to 1. Clear it here so any other key/station deletion, which is not
|
||||
* part of a teardown flow, would also call the relevant driver
|
||||
* callbacks.
|
||||
*/
|
||||
iface->driver_ap_teardown = 0;
|
||||
|
||||
if (!iface->phy[0]) {
|
||||
const char *phy = hostapd_drv_get_radio_name(hapd);
|
||||
if (phy) {
|
||||
|
@ -1627,7 +1640,11 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
|
|||
driver = hapd_iface->bss[0]->driver;
|
||||
drv_priv = hapd_iface->bss[0]->drv_priv;
|
||||
|
||||
/* whatever hostapd_interface_deinit does */
|
||||
hapd_iface->driver_ap_teardown =
|
||||
!!(hapd_iface->drv_flags &
|
||||
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
|
||||
|
||||
/* same as hostapd_interface_deinit without deinitializing ctrl-iface */
|
||||
for (j = 0; j < hapd_iface->num_bss; j++) {
|
||||
struct hostapd_data *hapd = hapd_iface->bss[j];
|
||||
hostapd_free_stas(hapd);
|
||||
|
@ -1943,6 +1960,10 @@ int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
|
|||
return -1;
|
||||
if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
|
||||
wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
|
||||
hapd_iface->driver_ap_teardown =
|
||||
!!(hapd_iface->drv_flags &
|
||||
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
|
||||
|
||||
hostapd_interface_deinit_free(hapd_iface);
|
||||
k = i;
|
||||
while (k < (interfaces->count - 1)) {
|
||||
|
@ -1955,10 +1976,14 @@ int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
|
|||
}
|
||||
|
||||
for (j = 0; j < hapd_iface->conf->num_bss; j++) {
|
||||
if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf))
|
||||
if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf)) {
|
||||
hapd_iface->driver_ap_teardown =
|
||||
!(hapd_iface->drv_flags &
|
||||
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
|
||||
return hostapd_remove_bss(hapd_iface, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -273,6 +273,12 @@ struct hostapd_iface {
|
|||
unsigned int wait_channel_update:1;
|
||||
unsigned int cac_started:1;
|
||||
|
||||
/*
|
||||
* When set, indicates that the driver will handle the AP
|
||||
* teardown: delete global keys, station keys, and stations.
|
||||
*/
|
||||
unsigned int driver_ap_teardown:1;
|
||||
|
||||
int num_ap; /* number of entries in ap_list */
|
||||
struct ap_info *ap_list; /* AP info list head */
|
||||
struct ap_info *ap_hash[STA_HASH_SIZE];
|
||||
|
|
|
@ -156,7 +156,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
|||
if (sta->flags & WLAN_STA_WDS)
|
||||
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
|
||||
|
||||
if (!(sta->flags & WLAN_STA_PREAUTH))
|
||||
if (!hapd->iface->driver_ap_teardown &&
|
||||
!(sta->flags & WLAN_STA_PREAUTH))
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
|
||||
ap_sta_hash_del(hapd, sta);
|
||||
|
|
|
@ -914,7 +914,8 @@ struct wpa_driver_capa {
|
|||
#define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE 0x00000400
|
||||
/* This interface is P2P capable (P2P GO or P2P Client) */
|
||||
#define WPA_DRIVER_FLAGS_P2P_CAPABLE 0x00000800
|
||||
/* unused: 0x00001000 */
|
||||
/* Driver supports station and key removal when stopping an AP */
|
||||
#define WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT 0x00001000
|
||||
/*
|
||||
* Driver uses the initial interface for P2P management interface and non-P2P
|
||||
* purposes (e.g., connect to infra AP), but this interface cannot be used for
|
||||
|
|
|
@ -3818,6 +3818,15 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
|
|||
drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
|
||||
drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
|
||||
|
||||
/*
|
||||
* As all cfg80211 drivers must support cases where the AP interface is
|
||||
* removed without the knowledge of wpa_supplicant/hostapd, e.g., in
|
||||
* case that the user space daemon has crashed, they must be able to
|
||||
* cleanup all stations and key entries in the AP tear down flow. Thus,
|
||||
* this flag can/should always be set for cfg80211 drivers.
|
||||
*/
|
||||
drv->capa.flags |= WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT;
|
||||
|
||||
if (!info.device_ap_sme) {
|
||||
drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
|
||||
|
||||
|
|
|
@ -669,6 +669,9 @@ void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
|
|||
wpa_s->ap_iface->bss[0]->p2p_group = NULL;
|
||||
wpas_p2p_group_deinit(wpa_s);
|
||||
#endif /* CONFIG_P2P */
|
||||
wpa_s->ap_iface->driver_ap_teardown =
|
||||
!!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
|
||||
|
||||
hostapd_interface_deinit(wpa_s->ap_iface);
|
||||
hostapd_interface_free(wpa_s->ap_iface);
|
||||
wpa_s->ap_iface = NULL;
|
||||
|
|
Loading…
Reference in a new issue