[RFC v2] ap: AP/GO interface teardown optimization

Ilan Peer ilan.peer at intel.com
Wed Mar 5 07:55:29 EST 2014


From: Moshe Benji <Moshe.Benji at intel.com>

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 at intel.com>
---
 hostapd/main.c               |    6 +++++-
 src/ap/ap_mlme.c             |    5 +++--
 src/ap/hostapd.c             |   41 +++++++++++++++++++++++++++++++++--------
 src/ap/hostapd.h             |    6 ++++++
 src/ap/sta_info.c            |    3 ++-
 src/drivers/driver.h         |    3 ++-
 src/drivers/driver_nl80211.c |    9 +++++++++
 wpa_supplicant/ap.c          |    3 +++
 8 files changed, 63 insertions(+), 13 deletions(-)

diff --git a/hostapd/main.c b/hostapd/main.c
index 3026929..68bc9b5 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -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);
diff --git a/src/ap/ap_mlme.c b/src/ap/ap_mlme.c
index a959694..b7b1900 100644
--- a/src/ap/ap_mlme.c
+++ b/src/ap/ap_mlme.c
@@ -16,7 +16,7 @@
 #include "wpa_auth.h"
 #include "sta_info.h"
 #include "ap_mlme.h"
-
+#include "hostapd.h"
 
 #ifndef CONFIG_NO_HOSTAPD_LOGGER
 static const char * mlme_auth_alg_str(int alg)
@@ -80,7 +80,8 @@ void mlme_deauthenticate_indication(struct hostapd_data *hapd,
 		       HOSTAPD_LEVEL_DEBUG,
 		       "MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
 		       MAC2STR(sta->addr), reason_code);
-	mlme_deletekeys_request(hapd, sta);
+	if (hapd->iface->driver_ap_teardown == 0)
+		mlme_deletekeys_request(hapd, sta);
 }
 
 
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ad1c2d0..d7379d3 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -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 == 0) {
 		hostapd_set_privacy(hapd, 0);
 		hostapd_broadcast_wep_clear(hapd);
 	}
@@ -401,11 +401,15 @@ 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 (hostapd_flush(hapd)) {
-		wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to "
-			"kernel driver");
-		ret = -1;
+	if (hapd->iface->driver_ap_teardown == 0) {
+		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");
+			ret = -1;
+		}
 	}
 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
 	os_memset(addr, 0xff, ETH_ALEN);
@@ -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,8 +1976,12 @@ 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;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 489ab16..f03c6e9 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -345,6 +345,12 @@ struct hostapd_iface {
 	unsigned int cs_c_off_proberesp;
 	int csa_in_progress;
 
+	/*
+	 * when set, indicates that the driver will handle the AP
+	 * teardown: delete global keys, station keys and stations
+	 */
+	unsigned int driver_ap_teardown:1;
+
 #ifdef CONFIG_ACS
 	unsigned int acs_num_completed_scans;
 #endif /* CONFIG_ACS */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index f7af088..dd64b01 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -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 == 0 &&
+	    !(sta->flags & WLAN_STA_PREAUTH))
 		hostapd_drv_sta_remove(hapd, sta->addr);
 
 	ap_sta_hash_del(hapd, sta);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index d2aad24..07796e8 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -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 stations and keys 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
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c509170..d88c6ab 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -3808,6 +3808,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;
 
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index f150679..740934a 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -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 =
+		!!(iface->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;
-- 
1.7.10.4



More information about the HostAP mailing list