]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
AP/GO interface teardown optimization
authorMoshe Benji <Moshe.Benji@intel.com>
Wed, 5 Mar 2014 12:55:29 +0000 (14:55 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 5 Mar 2014 21:57:02 +0000 (23:57 +0200)
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>
hostapd/main.c
src/ap/ap_mlme.c
src/ap/hostapd.c
src/ap/hostapd.h
src/ap/sta_info.c
src/drivers/driver.h
src/drivers/driver_nl80211.c
wpa_supplicant/ap.c

index 30269293c5a3984bbe9432d34815b5c6086a7d3d..68bc9b58204294b7496e6ed4a6fadf8476a03105 100644 (file)
@@ -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);
index a9596947fafb2f2bdc400fa791f9168550adddaa..a7129f14b26beea58f4eac56c8988556d04afd29 100644 (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,7 +81,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)
+               mlme_deletekeys_request(hapd, sta);
 }
 
 
index ad1c2d039629767d470c10ecc40d19d6166d5d3a..6ba6f984d8a6b2840cc41b391d292db938d03b76 100644 (file)
@@ -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,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) {
+               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;
index 489ab165278f09d11d894866b06dfb1930700e6d..be7df51b7e236513bcef95131ac3349d81e9a11f 100644 (file)
@@ -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];
index f7af0889ff13fd9759f9d880ef8be43cc7471a4a..0b90e3b23afdda9b60d8950e44a0bc9119686fa6 100644 (file)
@@ -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);
index b6434c294d38f1b24ef80aae69a642ce0ffeea99..6b6c0efe43f3682c152ad55f875a3e35566b7db1 100644 (file)
@@ -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
index 6a2af9511bdca2d117829903553dc3bd679c41ca..87c9661de640195ecfa5477c7ded029347444885 100644 (file)
@@ -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;
 
index f150679e77744514d02d109c7394e5be54712ca1..af273037097609ffa875e895948db370be00b6f6 100644 (file)
@@ -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;