Cumulative patch from commit 905828fea4b95a6d48ce86e1b5272c25a618b3d8

905828f hostapd: Fix vht_capab 'Maximum A-MPDU Length Exponent' handling
89de64c ACS: Fix VHT80 segment picking
1f37483 DFS: Print error in case CAC fails
354c903 AP/GO interface teardown optimization
8bc4372 Use P2P_IE_VENDOR_TYPE more consistently
8714caa WPS: Parse Registrar Configuration Methods
6b9f7af nl80211: Extend the new vendor command for testing nl80211
3a94adb P2P: Do not start scan for P2P Device interfaces at driver init
aa10983 P2P: Do not initialize bgscan on P2P interfaces
819f096 nl80211: Fix RTM event handling for dynamic interfaces
54ac5aa config: Add bgscan option when saving global configuration
268043d bgscan: Do not initialize bgscan if disabled by user
adef894 nl80211: Add vendor command support
d0595b2 nl80211: Fix tearing down WDS STA interfaces

Change-Id: I6d49f445692b71a4cd324f517eba651518ee14bb
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ad1c2d0..6ba6f98 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -350,7 +350,7 @@
 
 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 @@
 	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 @@
 	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 @@
 	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 @@
 			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 @@
 		}
 
 		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;