Cumulative patch from commit f51f54a007e0de1d413dee3523472d3bbeed2ecc

f51f54a nl80211: Resubscribe to nl80211 events on global nl_event socket
48ec694 Fix Linux packet socket workaround to not close the socket too easily
0d2030e Use estimated throughput to improve roaming selection
1d747e2 Add snr and est_throughput to the BSS entries
a1b790e Select AP based on estimated maximum throughput
ab647ff Add wpa_supplicant Makefile target libwpa_ctrl.a
abae2d1 trace: Initialize alloc_list even without os_program_init() call
891dfb3 Add helper function to clear and free wpa_psk list
71d77ad Update current BSS level when signal change event occurs
f1609f1 wpa_supplicant: Cancel sched_scan when stopping countermeasures
abb8d08 nl80211: Add support for configuring P2P GO CTWindow
0b8bcaa P2P: Allow configuring CTWindow when working as GO
c77ffc6 TDLS: Ignore extra padding in all packets
5ce6ac1 Inteworking: Add support to update the ANQP Capability List into the BSS
185ada4 HS 2.0: Add support to update the HS20 Capability List into the BSS
7fe7a3a wpa_gui: Debug enhancement
2b892d4 Add forgotten network profile parameters to config file writing
563ee18 IBSS: Add support for VHT80 configuration
ada157f Make hostapd_set_freq_params() common
98479dc IBSS: Update operating frequency if joining an existing IBSS
4d9e6fb IBSS: Add fixed_freq network parameter
6f5e1b0 Use priority list instead of global for PNO
97fc2dc Allow libnl-3.0 include path be specified
f92446f P2PS: Add P2PS interface info
59b416c Add optional reassoc-to-same-BSS optimization
c4da67d Fix passive_scan config parameter writing
715d5c4 hs20-osu-client: Ensure NULL checks are done before dereferencing
58d405f Fix OCSP debug messages
710dfb4 OpenSSL: Fix OCSP error path
bd7bb43 HTTP: Fix OCSP error path
946572c Android: Remove commented out non-Android build parameters
15ada7f Android: Remove libxml2 config defines
ebe8d3f Android: Silence unused function parameter warnings
dbd10da Android: Fix hs20-osu-client build on Android 5.0
a926295 HS 2.0R2: Fix permissions for SP/<fqdn> directory on Android
480994d nl80211: Allocate QCA vendor subcmds for DFS radar detected and CAC events
c165cb4 Drop all hostapd STA entries on interface disabled event
106fa1e nl80211: Indicate interface-down event only for the main netdev
eeb1cb2 VLAN: Clean up RTM_NEW/DELLINK processing
47e5fbd hostapd: Avoid sending client probe on removed client
3478273 Re-configure WPA2 group keys on hostapd interface re-enable
f33c860 Re-enable beaconing on interface disable+enable
fc99fab nl80211: Print a debug log entry on NL80211_CMD_PROBE_CLIENT failures
0d2f324 P2P: Fix send_action_in_progress clearing in corner cases
9ff8dda Add hostapd UPDATE_BEACON ctrl_iface command
e0761c5 nl80211: Allocate QCA vendor subcmd for DFS CAC Start event
1db718b nl80211: Test vendor command and event
10263dc Add control interface commands for fetching wpa_config values
f91a512 Add INTERWORKING_ADD_NETWORK command
c612ae9 AP: Do not reply to Probe Request frames with DS Params mismatch
5b74e08 P2P: Document P2P_CONNECT-auto
99650ca Add STOP_AP control interface command
6b00512 P2P: Add event messages for P2P_CONNECT-fallback-to-GO-Neg
b0e669b P2P: Fix P2P_CONNECT-auto fallback to GO Neg with group interface
bf51f4f mesh: Fix remaining BLOCKED state after SAE auth failure
79ddb20 mesh: Add a monitor event on SAE authentication getting blocked
dd2cbaf mesh: Add a monitor event for SAE authentication failure
0cb5f8d mesh: Fix inactivity timer for 32 bit system
11e2ddb mesh: Remove duplicated no_auto_peer update
1e52983 D-Bus: Fix network block type change
4fada12 Fix HT40 co-ex scanning issue on hostapd error path
23ed011 Fix Linux packat socket regression work around
663ae2f Don't write to wpa_supplicant.conf directly
d9a9bc0 IBSS: Do not enable HT with WEP or TKIP
0d7eb43 ACS: Accept channel if any (rather than all) survey results are valid
68fa00c ACS: Allow specific channels to be preferred
6f41a25 ACS: Use weighted average for 2.4 GHz adjacent channel interference

Change-Id: Ie1cabd28dcfdefafa02e81477e34badae6f7e629
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/acs.c b/src/ap/acs.c
index e4c834c..ae7f6c3 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -242,6 +242,7 @@
 
 
 static int acs_request_scan(struct hostapd_iface *iface);
+static int acs_survey_is_sufficient(struct freq_survey *survey);
 
 
 static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
@@ -328,6 +329,7 @@
 	struct freq_survey *survey;
 	unsigned int i = 0;
 	long double int_factor = 0;
+	unsigned count = 0;
 
 	if (dl_list_empty(&chan->survey_list))
 		return;
@@ -339,18 +341,27 @@
 
 	dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list)
 	{
+		i++;
+
+		if (!acs_survey_is_sufficient(survey)) {
+			wpa_printf(MSG_DEBUG, "ACS: %d: insufficient data", i);
+			continue;
+		}
+
+		count++;
 		int_factor = acs_survey_interference_factor(survey,
 							    iface->lowest_nf);
 		chan->interference_factor += int_factor;
 		wpa_printf(MSG_DEBUG, "ACS: %d: min_nf=%d interference_factor=%Lg nf=%d time=%lu busy=%lu rx=%lu",
-			   ++i, chan->min_nf, int_factor,
+			   i, chan->min_nf, int_factor,
 			   survey->nf, (unsigned long) survey->channel_time,
 			   (unsigned long) survey->channel_time_busy,
 			   (unsigned long) survey->channel_time_rx);
 	}
 
-	chan->interference_factor = chan->interference_factor /
-		dl_list_len(&chan->survey_list);
+	if (!count)
+		return;
+	chan->interference_factor /= count;
 }
 
 
@@ -384,18 +395,19 @@
 static int acs_survey_is_sufficient(struct freq_survey *survey)
 {
 	if (!(survey->filled & SURVEY_HAS_NF)) {
-		wpa_printf(MSG_ERROR, "ACS: Survey is missing noise floor");
+		wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor");
 		return 0;
 	}
 
 	if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) {
-		wpa_printf(MSG_ERROR, "ACS: Survey is missing channel time");
+		wpa_printf(MSG_INFO, "ACS: Survey is missing channel time");
 		return 0;
 	}
 
 	if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) &&
 	    !(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) {
-		wpa_printf(MSG_ERROR, "ACS: Survey is missing RX and busy time (at least one is required)");
+		wpa_printf(MSG_INFO,
+			   "ACS: Survey is missing RX and busy time (at least one is required)");
 		return 0;
 	}
 
@@ -406,18 +418,27 @@
 static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
 {
 	struct freq_survey *survey;
+	int ret = -1;
 
 	dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list)
 	{
-		if (!acs_survey_is_sufficient(survey)) {
-			wpa_printf(MSG_ERROR, "ACS: Channel %d has insufficient survey data",
-				   chan->chan);
-			return 0;
+		if (acs_survey_is_sufficient(survey)) {
+			ret = 1;
+			break;
 		}
+		ret = 0;
 	}
 
-	return 1;
+	if (ret == -1)
+		ret = 1; /* no survey list entries */
 
+	if (!ret) {
+		wpa_printf(MSG_INFO,
+			   "ACS: Channel %d has insufficient survey data",
+			   chan->chan);
+	}
+
+	return ret;
 }
 
 
@@ -517,6 +538,36 @@
 }
 
 
+static int is_24ghz_mode(enum hostapd_hw_mode mode)
+{
+	return mode == HOSTAPD_MODE_IEEE80211B ||
+		mode == HOSTAPD_MODE_IEEE80211G;
+}
+
+
+static int is_common_24ghz_chan(int chan)
+{
+	return chan == 1 || chan == 6 || chan == 11;
+}
+
+
+#ifndef ACS_ADJ_WEIGHT
+#define ACS_ADJ_WEIGHT 0.85
+#endif /* ACS_ADJ_WEIGHT */
+
+#ifndef ACS_NEXT_ADJ_WEIGHT
+#define ACS_NEXT_ADJ_WEIGHT 0.55
+#endif /* ACS_NEXT_ADJ_WEIGHT */
+
+#ifndef ACS_24GHZ_PREFER_1_6_11
+/*
+ * Select commonly used channels 1, 6, 11 by default even if a neighboring
+ * channel has a smaller interference factor as long as it is not better by more
+ * than this multiplier.
+ */
+#define ACS_24GHZ_PREFER_1_6_11 0.8
+#endif /* ACS_24GHZ_PREFER_1_6_11 */
+
 /*
  * At this point it's assumed chan->interface_factor has been computed.
  * This function should be reusable regardless of interference computation
@@ -531,6 +582,7 @@
 	long double factor, ideal_factor = 0;
 	int i, j;
 	int n_chans = 1;
+	unsigned int k;
 
 	/* TODO: HT40- support */
 
@@ -557,6 +609,9 @@
 		   -1);
 
 	for (i = 0; i < iface->current_mode->num_channels; i++) {
+		double total_weight;
+		struct acs_bias *bias, tmp_bias;
+
 		chan = &iface->current_mode->channels[i];
 
 		if (chan->flag & HOSTAPD_CHAN_DISABLED)
@@ -588,14 +643,17 @@
 		factor = 0;
 		if (acs_usable_chan(chan))
 			factor = chan->interference_factor;
+		total_weight = 1;
 
 		for (j = 1; j < n_chans; j++) {
 			adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
 			if (!adj_chan)
 				break;
 
-			if (acs_usable_chan(adj_chan))
+			if (acs_usable_chan(adj_chan)) {
 				factor += adj_chan->interference_factor;
+				total_weight += 1;
+			}
 		}
 
 		if (j != n_chans) {
@@ -606,36 +664,69 @@
 
 		/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
 		 * channel interference factor. */
-		if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B ||
-		    iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) {
+		if (is_24ghz_mode(iface->current_mode->mode)) {
 			for (j = 0; j < n_chans; j++) {
-				/* TODO: perhaps a multiplier should be used
-				 * here? */
-
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) - 5);
-				if (adj_chan && acs_usable_chan(adj_chan))
-					factor += adj_chan->interference_factor;
+				if (adj_chan && acs_usable_chan(adj_chan)) {
+					factor += ACS_ADJ_WEIGHT *
+						adj_chan->interference_factor;
+					total_weight += ACS_ADJ_WEIGHT;
+				}
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) - 10);
-				if (adj_chan && acs_usable_chan(adj_chan))
-					factor += adj_chan->interference_factor;
+				if (adj_chan && acs_usable_chan(adj_chan)) {
+					factor += ACS_NEXT_ADJ_WEIGHT *
+						adj_chan->interference_factor;
+					total_weight += ACS_NEXT_ADJ_WEIGHT;
+				}
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) + 5);
-				if (adj_chan && acs_usable_chan(adj_chan))
-					factor += adj_chan->interference_factor;
+				if (adj_chan && acs_usable_chan(adj_chan)) {
+					factor += ACS_ADJ_WEIGHT *
+						adj_chan->interference_factor;
+					total_weight += ACS_ADJ_WEIGHT;
+				}
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) + 10);
-				if (adj_chan && acs_usable_chan(adj_chan))
-					factor += adj_chan->interference_factor;
+				if (adj_chan && acs_usable_chan(adj_chan)) {
+					factor += ACS_NEXT_ADJ_WEIGHT *
+						adj_chan->interference_factor;
+					total_weight += ACS_NEXT_ADJ_WEIGHT;
+				}
 			}
 		}
 
-		wpa_printf(MSG_DEBUG, "ACS:  * channel %d: total interference = %Lg",
-			   chan->chan, factor);
+		factor /= total_weight;
+
+		bias = NULL;
+		if (iface->conf->acs_chan_bias) {
+			for (k = 0; k < iface->conf->num_acs_chan_bias; k++) {
+				bias = &iface->conf->acs_chan_bias[k];
+				if (bias->channel == chan->chan)
+					break;
+				bias = NULL;
+			}
+		} else if (is_24ghz_mode(iface->current_mode->mode) &&
+			   is_common_24ghz_chan(chan->chan)) {
+			tmp_bias.channel = chan->chan;
+			tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11;
+			bias = &tmp_bias;
+		}
+
+		if (bias) {
+			factor *= bias->bias;
+			wpa_printf(MSG_DEBUG,
+				   "ACS:  * channel %d: total interference = %Lg (%f bias)",
+				   chan->chan, factor, bias->bias);
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "ACS:  * channel %d: total interference = %Lg",
+				   chan->chan, factor);
+		}
 
 		if (acs_usable_chan(chan) &&
 		    (!ideal_chan || factor < ideal_factor)) {
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 1c0ed7a..76011dc 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -394,20 +394,27 @@
 }
 
 
+void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
+{
+	struct hostapd_wpa_psk *psk, *tmp;
+
+	for (psk = *l; psk;) {
+		tmp = psk;
+		psk = psk->next;
+		bin_clear_free(tmp, sizeof(*tmp));
+	}
+	*l = NULL;
+}
+
+
 void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 {
-	struct hostapd_wpa_psk *psk, *prev;
 	struct hostapd_eap_user *user, *prev_user;
 
 	if (conf == NULL)
 		return;
 
-	psk = conf->ssid.wpa_psk;
-	while (psk) {
-		prev = psk;
-		psk = psk->next;
-		bin_clear_free(prev, sizeof(*prev));
-	}
+	hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
 
 	str_clear_free(conf->ssid.wpa_passphrase);
 	os_free(conf->ssid.wpa_psk_file);
@@ -574,6 +581,9 @@
 	os_free(conf->basic_rates);
 	os_free(conf->chanlist);
 	os_free(conf->driver_params);
+#ifdef CONFIG_ACS
+	os_free(conf->acs_chan_bias);
+#endif /* CONFIG_ACS */
 
 	os_free(conf);
 }
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index e5215c5..961d2dd 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -629,6 +629,10 @@
 	u8 vht_oper_centr_freq_seg0_idx;
 	u8 vht_oper_centr_freq_seg1_idx;
 
+#ifdef CONFIG_P2P
+	u8 p2p_go_ctwindow;
+#endif /* CONFIG_P2P */
+
 #ifdef CONFIG_TESTING_OPTIONS
 	double ignore_probe_probability;
 	double ignore_auth_probability;
@@ -639,6 +643,11 @@
 
 #ifdef CONFIG_ACS
 	unsigned int acs_num_scans;
+	struct acs_bias {
+		int channel;
+		double bias;
+	} *acs_chan_bias;
+	unsigned int num_acs_chan_bias;
 #endif /* CONFIG_ACS */
 };
 
@@ -648,6 +657,7 @@
 struct hostapd_config * hostapd_config_defaults(void);
 void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
 void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
+void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
 void hostapd_config_free_bss(struct hostapd_bss_config *conf);
 void hostapd_config_free(struct hostapd_config *conf);
 int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 8514cbe..e16306c 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
 #include "wps/wps.h"
 #include "p2p/p2p.h"
 #include "hostapd.h"
@@ -477,92 +478,6 @@
 }
 
 
-int hostapd_set_freq_params(struct hostapd_freq_params *data,
-			    enum hostapd_hw_mode mode,
-			    int freq, int channel, int ht_enabled,
-			    int vht_enabled, int sec_channel_offset,
-			    int vht_oper_chwidth, int center_segment0,
-			    int center_segment1, u32 vht_caps)
-{
-	int tmp;
-
-	os_memset(data, 0, sizeof(*data));
-	data->mode = mode;
-	data->freq = freq;
-	data->channel = channel;
-	data->ht_enabled = ht_enabled;
-	data->vht_enabled = vht_enabled;
-	data->sec_channel_offset = sec_channel_offset;
-	data->center_freq1 = freq + sec_channel_offset * 10;
-	data->center_freq2 = 0;
-	data->bandwidth = sec_channel_offset ? 40 : 20;
-
-	/*
-	 * This validation code is probably misplaced, maybe it should be
-	 * in src/ap/hw_features.c and check the hardware support as well.
-	 */
-	if (data->vht_enabled) switch (vht_oper_chwidth) {
-	case VHT_CHANWIDTH_USE_HT:
-		if (center_segment1)
-			return -1;
-		if (center_segment0 != 0 &&
-		    5000 + center_segment0 * 5 != data->center_freq1 &&
-		    2407 + center_segment0 * 5 != data->center_freq1)
-			return -1;
-		break;
-	case VHT_CHANWIDTH_80P80MHZ:
-		if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
-			wpa_printf(MSG_ERROR,
-				   "80+80 channel width is not supported!");
-			return -1;
-		}
-		if (center_segment1 == center_segment0 + 4 ||
-		    center_segment1 == center_segment0 - 4)
-			return -1;
-		data->center_freq2 = 5000 + center_segment1 * 5;
-		/* fall through */
-	case VHT_CHANWIDTH_80MHZ:
-		data->bandwidth = 80;
-		if (vht_oper_chwidth == 1 && center_segment1)
-			return -1;
-		if (vht_oper_chwidth == 3 && !center_segment1)
-			return -1;
-		if (!sec_channel_offset)
-			return -1;
-		/* primary 40 part must match the HT configuration */
-		tmp = (30 + freq - 5000 - center_segment0 * 5)/20;
-		tmp /= 2;
-		if (data->center_freq1 != 5000 +
-					 center_segment0 * 5 - 20 + 40 * tmp)
-			return -1;
-		data->center_freq1 = 5000 + center_segment0 * 5;
-		break;
-	case VHT_CHANWIDTH_160MHZ:
-		data->bandwidth = 160;
-		if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
-				  VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
-			wpa_printf(MSG_ERROR,
-				   "160MHZ channel width is not supported!");
-			return -1;
-		}
-		if (center_segment1)
-			return -1;
-		if (!sec_channel_offset)
-			return -1;
-		/* primary 40 part must match the HT configuration */
-		tmp = (70 + freq - 5000 - center_segment0 * 5)/20;
-		tmp /= 2;
-		if (data->center_freq1 != 5000 +
-					 center_segment0 * 5 - 60 + 40 * tmp)
-			return -1;
-		data->center_freq1 = 5000 + center_segment0 * 5;
-		break;
-	}
-
-	return 0;
-}
-
-
 int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
 		     int freq, int channel, int ht_enabled, int vht_enabled,
 		     int sec_channel_offset, int vht_oper_chwidth,
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index c133be7..5d07e71 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -107,12 +107,6 @@
 			  int channel, int ht_enabled, int vht_enabled,
 			  int sec_channel_offset, int vht_oper_chwidth,
 			  int center_segment0, int center_segment1);
-int hostapd_set_freq_params(struct hostapd_freq_params *data,
-			    enum hostapd_hw_mode mode,
-			    int freq, int channel, int ht_enabled,
-			    int vht_enabled, int sec_channel_offset,
-			    int vht_oper_chwidth, int center_segment0,
-			    int center_segment1, u32 vht_caps);
 int hostapd_drv_do_acs(struct hostapd_data *hapd);
 
 
@@ -335,4 +329,11 @@
 					data_len, buf);
 }
 
+static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
+{
+	if (hapd->driver == NULL || hapd->driver->stop_ap == NULL)
+		return 0;
+	return hapd->driver->stop_ap(hapd->drv_priv);
+}
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index b0a74e0..e575b65 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -15,6 +15,7 @@
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
+#include "common/hw_features_common.h"
 #include "wps/wps_defs.h"
 #include "p2p/p2p.h"
 #include "hostapd.h"
@@ -579,6 +580,27 @@
 		return;
 	}
 
+	/*
+	 * No need to reply if the Probe Request frame was sent on an adjacent
+	 * channel. IEEE Std 802.11-2012 describes this as a requirement for an
+	 * AP with dot11RadioMeasurementActivated set to true, but strictly
+	 * speaking does not allow such ignoring of Probe Request frames if
+	 * dot11RadioMeasurementActivated is false. Anyway, this can help reduce
+	 * number of unnecessary Probe Response frames for cases where the STA
+	 * is less likely to see them (Probe Request frame sent on a
+	 * neighboring, but partially overlapping, channel).
+	 */
+	if (elems.ds_params && elems.ds_params_len == 1 &&
+	    hapd->iface->current_mode &&
+	    (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G ||
+	     hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) &&
+	    hapd->iconf->channel != elems.ds_params[0]) {
+		wpa_printf(MSG_DEBUG,
+			   "Ignore Probe Request due to DS Params mismatch: chan=%u != ds.chan=%u",
+			   hapd->iconf->channel, elems.ds_params[0]);
+		return;
+	}
+
 #ifdef CONFIG_P2P
 	if (hapd->p2p && elems.wps_ie) {
 		struct wpabuf *wps;
@@ -986,6 +1008,9 @@
 		params->hessid = hapd->conf->hessid;
 	params->access_network_type = hapd->conf->access_network_type;
 	params->ap_max_inactivity = hapd->conf->ap_max_inactivity;
+#ifdef CONFIG_P2P
+	params->p2p_go_ctwindow = hapd->iconf->p2p_go_ctwindow;
+#endif /* CONFIG_P2P */
 #ifdef CONFIG_HS20
 	params->disable_dgaf = hapd->conf->disable_dgaf;
 	if (hapd->conf->osen) {
@@ -1034,6 +1059,8 @@
 	params.beacon_ies = beacon;
 	params.proberesp_ies = proberesp;
 	params.assocresp_ies = assocresp;
+	params.reenable = hapd->reenable_beacon;
+	hapd->reenable_beacon = 0;
 
 	if (iface->current_mode &&
 	    hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 8c84e3e..41ab988 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -537,3 +537,9 @@
 
 	return 0;
 }
+
+
+int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
+{
+	return hostapd_drv_stop_ap(hapd);
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index ee58b4c..e5297d0 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -23,6 +23,6 @@
 			      size_t buflen);
 int hostapd_parse_csa_settings(const char *pos,
 			       struct csa_settings *settings);
-
+int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
 
 #endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 0db5ef6..fc8d7ad 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -11,6 +11,7 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
 #include "common/wpa_ctrl.h"
 #include "hostapd.h"
 #include "ap_drv_ops.h"
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 40a2a9c..c39989c 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -1210,9 +1210,21 @@
 #endif /* NEED_AP_MLME */
 	case EVENT_INTERFACE_ENABLED:
 		wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
+		if (hapd->disabled && hapd->started) {
+			hapd->disabled = 0;
+			/*
+			 * Try to re-enable interface if the driver stopped it
+			 * when the interface got disabled.
+			 */
+			wpa_auth_reconfig_group_keys(hapd->wpa_auth);
+			hapd->reenable_beacon = 1;
+			ieee802_11_set_beacon(hapd);
+		}
 		break;
 	case EVENT_INTERFACE_DISABLED:
+		hostapd_free_stas(hapd);
 		wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
+		hapd->disabled = 1;
 		break;
 #ifdef CONFIG_ACS
 	case EVENT_ACS_CHANNEL_SELECTED:
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index b641503..e641b12 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -82,8 +82,7 @@
 		 * Force PSK to be derived again since SSID or passphrase may
 		 * have changed.
 		 */
-		os_free(ssid->wpa_psk);
-		ssid->wpa_psk = NULL;
+		hostapd_config_clear_wpa_psk(&hapd->conf->ssid.wpa_psk);
 	}
 	if (hostapd_setup_wpa_psk(hapd->conf)) {
 		wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
@@ -357,6 +356,11 @@
 static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
 {
 	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+	hostapd_stop_setup_timers(iface);
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
 	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
 	iface->hw_features = NULL;
 	os_free(iface->current_rates);
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 8e2c70e..75cc24e 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -105,6 +105,8 @@
 	struct hostapd_bss_config *conf;
 	int interface_added; /* virtual interface added for this BSS */
 	unsigned int started:1;
+	unsigned int disabled:1;
+	unsigned int reenable_beacon:1;
 
 	u8 own_addr[ETH_ALEN];
 
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index eebaa3c..7e75e1a 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -375,8 +375,9 @@
 				"Station " MACSTR " has lost its driver entry",
 				MAC2STR(sta->addr));
 
-			if (hapd->conf->skip_inactivity_poll)
-				sta->timeout_next = STA_DISASSOC;
+			/* Avoid sending client probe on removed client */
+			sta->timeout_next = STA_DISASSOC;
+			goto skip_poll;
 		} else if (inactive_sec < hapd->conf->ap_max_inactivity) {
 			/* station activity detected; reset timeout state */
 			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
@@ -409,6 +410,7 @@
 		next_time = hapd->conf->ap_max_inactivity;
 	}
 
+skip_poll:
 	if (next_time) {
 		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
 			   "for " MACSTR " (%lu seconds)",
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 2af2cbc..dc65019 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -617,6 +617,7 @@
 	struct ifinfomsg *ifi;
 	int attrlen, nlmsg_len, rta_len;
 	struct rtattr *attr;
+	char ifname[IFNAMSIZ + 1];
 
 	if (len < sizeof(*ifi))
 		return;
@@ -631,29 +632,39 @@
 
 	attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
 
+	os_memset(ifname, 0, sizeof(ifname));
 	rta_len = RTA_ALIGN(sizeof(struct rtattr));
 	while (RTA_OK(attr, attrlen)) {
-		char ifname[IFNAMSIZ + 1];
-
 		if (attr->rta_type == IFLA_IFNAME) {
 			int n = attr->rta_len - rta_len;
 			if (n < 0)
 				break;
 
-			os_memset(ifname, 0, sizeof(ifname));
-
-			if ((size_t) n > sizeof(ifname))
-				n = sizeof(ifname);
+			if ((size_t) n >= sizeof(ifname))
+				n = sizeof(ifname) - 1;
 			os_memcpy(ifname, ((char *) attr) + rta_len, n);
 
-			if (del)
-				vlan_dellink(ifname, hapd);
-			else
-				vlan_newlink(ifname, hapd);
 		}
 
 		attr = RTA_NEXT(attr, attrlen);
 	}
+
+	if (!ifname[0])
+		return;
+
+	wpa_printf(MSG_DEBUG,
+		   "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+		   del ? "DEL" : "NEW",
+		   ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
+		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+	if (del)
+		vlan_dellink(ifname, hapd);
+	else
+		vlan_newlink(ifname, hapd);
 }
 
 
@@ -677,7 +688,7 @@
 	}
 
 	h = (struct nlmsghdr *) buf;
-	while (left >= (int) sizeof(*h)) {
+	while (NLMSG_OK(h, left)) {
 		int len, plen;
 
 		len = h->nlmsg_len;
@@ -698,9 +709,7 @@
 			break;
 		}
 
-		len = NLMSG_ALIGN(len);
-		left -= len;
-		h = (struct nlmsghdr *) ((char *) h + len);
+		h = NLMSG_NEXT(h, left);
 	}
 
 	if (left > 0) {
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 668cb42..9c5f609 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -3387,3 +3387,14 @@
 {
 	return pmksa_cache_auth_radius_das_disconnect(wpa_auth->pmksa, attr);
 }
+
+
+void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth)
+{
+	struct wpa_group *group;
+
+	if (!wpa_auth)
+		return;
+	for (group = wpa_auth->group; group; group = group->next)
+		wpa_group_config_group_keys(wpa_auth, group);
+}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index b34b84d..2788e65 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -318,5 +318,6 @@
 struct radius_das_attrs;
 int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
 					 struct radius_das_attrs *attr);
+void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth);
 
 #endif /* WPA_AUTH_H */
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 9ba7aba..b0e8b0b 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -362,10 +362,9 @@
 			if (bss->ssid.wpa_passphrase)
 				os_memcpy(bss->ssid.wpa_passphrase, cred->key,
 					  cred->key_len);
-			os_free(bss->ssid.wpa_psk);
-			bss->ssid.wpa_psk = NULL;
+			hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
 		} else if (cred->key_len == 64) {
-			os_free(bss->ssid.wpa_psk);
+			hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
 			bss->ssid.wpa_psk =
 				os_zalloc(sizeof(struct hostapd_wpa_psk));
 			if (bss->ssid.wpa_psk &&