am 2db4db04: am 243e04f8: Merge "Treat VER_2_1_DEVEL the same as VER_0_8_X"

* commit '2db4db04ec38c53f9189070782f2d1be7832761e':
  Treat VER_2_1_DEVEL the same as VER_0_8_X
  Android: Do not compile wpa_supplicant if not chosen
diff --git a/README b/README
index 805c6cf..bf0bd83 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
 wpa_supplicant and hostapd
 --------------------------
 
-Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 These programs are licensed under the BSD license (the one with
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 695e99c..bc0273e 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -45,9 +45,6 @@
 L_CFLAGS += -mabi=aapcs-linux
 endif
 
-# To allow non-ASCII characters in SSID
-L_CFLAGS += -DWPA_UNICODE_SSID
-
 INCLUDES = $(LOCAL_PATH)
 INCLUDES += $(LOCAL_PATH)/src
 INCLUDES += $(LOCAL_PATH)/src/utils
@@ -108,7 +105,6 @@
 NEED_AES=y
 NEED_MD5=y
 NEED_SHA1=y
-NEED_SHA256=y
 
 OBJS += src/drivers/drivers.c
 L_CFLAGS += -DHOSTAPD
@@ -531,10 +527,6 @@
 ifdef TLS_FUNCS
 OBJS += src/crypto/tls_gnutls.c
 LIBS += -lgnutls -lgpg-error
-ifdef CONFIG_GNUTLS_EXTRA
-L_CFLAGS += -DCONFIG_GNUTLS_EXTRA
-LIBS += -lgnutls-extra
-endif
 endif
 OBJS += src/crypto/crypto_gnutls.c
 HOBJS += src/crypto/crypto_gnutls.c
@@ -831,6 +823,7 @@
 OBJS += src/ap/ap_list.c
 OBJS += src/ap/ieee802_11.c
 OBJS += src/ap/hw_features.c
+OBJS += src/ap/dfs.c
 L_CFLAGS += -DNEED_AP_MLME
 endif
 ifdef CONFIG_IEEE80211N
@@ -860,10 +853,20 @@
 
 OBJS += src/drivers/driver_common.c
 
+ifdef CONFIG_ACS
+L_CFLAGS += -DCONFIG_ACS
+OBJS += src/ap/acs.c
+LIBS += -lm
+endif
+
 ifdef CONFIG_NO_STDOUT_DEBUG
 L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
 endif
 
+ifdef CONFIG_DEBUG_LINUX_TRACING
+L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
 ifdef CONFIG_DEBUG_FILE
 L_CFLAGS += -DCONFIG_DEBUG_FILE
 endif
@@ -884,12 +887,6 @@
 OBJS_c += src/utils/edit_simple.c
 endif
 
-ifdef CONFIG_ACS
-L_CFLAGS += -DCONFIG_ACS
-OBJS += src/ap/acs.c
-LIBS += -lm
-endif
-
 ########################
 
 include $(CLEAR_VARS)
diff --git a/hostapd/Makefile b/hostapd/Makefile
index fda4e4e..b4704ba 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -84,6 +84,14 @@
 endif
 OBJS += ../src/utils/$(CONFIG_ELOOP).o
 OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
+
+ifeq ($(CONFIG_ELOOP), eloop)
+# Using glibc < 2.17 requires -lrt for clock_gettime()
+LIBS += -lrt
+LIBS_c += -lrt
+LIBS_h += -lrt
+endif
+
 OBJS += ../src/utils/common.o
 OBJS += ../src/utils/wpa_debug.o
 OBJS_c += ../src/utils/wpa_debug.o
@@ -782,6 +790,7 @@
 OBJS += ../src/ap/ap_list.o
 OBJS += ../src/ap/ieee802_11.o
 OBJS += ../src/ap/hw_features.o
+OBJS += ../src/ap/dfs.o
 CFLAGS += -DNEED_AP_MLME
 endif
 ifdef CONFIG_IEEE80211N
@@ -827,6 +836,10 @@
 CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
 endif
 
+ifdef CONFIG_DEBUG_LINUX_TRACING
+CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
 ifdef CONFIG_DEBUG_FILE
 CFLAGS += -DCONFIG_DEBUG_FILE
 endif
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 0b4fd77..ae05917 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -748,30 +748,32 @@
 
 static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
 {
-	struct hostapd_bss_config *bss;
+	struct hostapd_bss_config **all, *bss;
 
 	if (*ifname == '\0')
 		return -1;
 
-	bss = os_realloc_array(conf->bss, conf->num_bss + 1,
-			       sizeof(struct hostapd_bss_config));
-	if (bss == NULL) {
+	all = os_realloc_array(conf->bss, conf->num_bss + 1,
+			       sizeof(struct hostapd_bss_config *));
+	if (all == NULL) {
 		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
 			   "multi-BSS entry");
 		return -1;
 	}
-	conf->bss = bss;
+	conf->bss = all;
 
-	bss = &(conf->bss[conf->num_bss]);
-	os_memset(bss, 0, sizeof(*bss));
+	bss = os_zalloc(sizeof(*bss));
+	if (bss == NULL)
+		return -1;
 	bss->radius = os_zalloc(sizeof(*bss->radius));
 	if (bss->radius == NULL) {
 		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
 			   "multi-BSS RADIUS data");
+		os_free(bss);
 		return -1;
 	}
 
-	conf->num_bss++;
+	conf->bss[conf->num_bss++] = bss;
 	conf->last_bss = bss;
 
 	hostapd_config_defaults_bss(bss);
@@ -1060,15 +1062,15 @@
 	if (os_strstr(capab, "[RX-STBC-1234]"))
 		conf->vht_capab |= VHT_CAP_RXSTBC_4;
 	if (os_strstr(capab, "[SU-BEAMFORMER]"))
-		conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+		conf->vht_capab |= VHT_CAP_SU_BEAMFORMER_CAPABLE;
 	if (os_strstr(capab, "[SU-BEAMFORMEE]"))
-		conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+		conf->vht_capab |= VHT_CAP_SU_BEAMFORMEE_CAPABLE;
 	if (os_strstr(capab, "[BF-ANTENNA-2]") &&
-	    (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
-		conf->vht_capab |= VHT_CAP_BEAMFORMER_ANTENNAS_MAX;
+	    (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+		conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
 	if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
-	    (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
-		conf->vht_capab |= VHT_CAP_SOUNDING_DIMENTION_MAX;
+	    (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+		conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
 	if (os_strstr(capab, "[MU-BEAMFORMER]"))
 		conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
 	if (os_strstr(capab, "[MU-BEAMFORMEE]"))
@@ -1094,165 +1096,6 @@
 #endif /* CONFIG_IEEE80211AC */
 
 
-static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
-				    struct hostapd_config *conf)
-{
-	if (bss->ieee802_1x && !bss->eap_server &&
-	    !bss->radius->auth_servers) {
-		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
-			   "EAP authenticator configured).");
-		return -1;
-	}
-
-	if (bss->wpa) {
-		int wep, i;
-
-		wep = bss->default_wep_key_len > 0 ||
-		       bss->individual_wep_key_len > 0;
-		for (i = 0; i < NUM_WEP_KEYS; i++) {
-			if (bss->ssid.wep.keys_set) {
-				wep = 1;
-				break;
-			}
-		}
-
-		if (wep) {
-			wpa_printf(MSG_ERROR, "WEP configuration in a WPA network is not supported");
-			return -1;
-		}
-	}
-
-	if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
-	    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
-		wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
-			   "RADIUS checking (macaddr_acl=2) enabled.");
-		return -1;
-	}
-
-	if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
-	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
-	    bss->ssid.wpa_psk_file == NULL &&
-	    (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
-	     bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
-		wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
-			   "is not configured.");
-		return -1;
-	}
-
-	if (hostapd_mac_comp_empty(bss->bssid) != 0) {
-		size_t i;
-
-		for (i = 0; i < conf->num_bss; i++) {
-			if ((&conf->bss[i] != bss) &&
-			    (hostapd_mac_comp(conf->bss[i].bssid,
-					      bss->bssid) == 0)) {
-				wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
-					   " on interface '%s' and '%s'.",
-					   MAC2STR(bss->bssid),
-					   conf->bss[i].iface, bss->iface);
-				return -1;
-			}
-		}
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
-	    (bss->nas_identifier == NULL ||
-	     os_strlen(bss->nas_identifier) < 1 ||
-	     os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
-		wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
-			   "nas_identifier to be configured as a 1..48 octet "
-			   "string");
-		return -1;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_IEEE80211N
-	if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
-		bss->disable_11n = 1;
-		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
-			   "allowed, disabling HT capabilites");
-	}
-
-	if (conf->ieee80211n &&
-	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
-		bss->disable_11n = 1;
-		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
-			   "allowed, disabling HT capabilities");
-	}
-
-	if (conf->ieee80211n && bss->wpa &&
-	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
-	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) {
-		bss->disable_11n = 1;
-		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
-			   "requires CCMP/GCMP to be enabled, disabling HT "
-			   "capabilities");
-	}
-#endif /* CONFIG_IEEE80211N */
-
-#ifdef CONFIG_WPS2
-	if (bss->wps_state && bss->ignore_broadcast_ssid) {
-		wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
-			   "configuration forced WPS to be disabled");
-		bss->wps_state = 0;
-	}
-
-	if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
-		wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
-			   "disabled");
-		bss->wps_state = 0;
-	}
-
-	if (bss->wps_state && bss->wpa &&
-	    (!(bss->wpa & 2) ||
-	     !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
-		wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
-			   "WPA2/CCMP forced WPS to be disabled");
-		bss->wps_state = 0;
-	}
-#endif /* CONFIG_WPS2 */
-
-#ifdef CONFIG_HS20
-	if (bss->hs20 &&
-	    (!(bss->wpa & 2) ||
-	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
-		wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
-			   "configuration is required for Hotspot 2.0 "
-			   "functionality");
-		return -1;
-	}
-#endif /* CONFIG_HS20 */
-
-	return 0;
-}
-
-
-static int hostapd_config_check(struct hostapd_config *conf)
-{
-	size_t i;
-
-	if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
-		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
-			   "setting the country_code");
-		return -1;
-	}
-
-	if (conf->ieee80211h && !conf->ieee80211d) {
-		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without "
-			   "IEEE 802.11d enabled");
-		return -1;
-	}
-
-	for (i = 0; i < conf->num_bss; i++) {
-		if (hostapd_config_check_bss(&conf->bss[i], conf))
-			return -1;
-	}
-
-	return 0;
-}
-
-
 #ifdef CONFIG_INTERWORKING
 static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
 				    int line)
@@ -1289,26 +1132,34 @@
 static int parse_lang_string(struct hostapd_lang_string **array,
 			     unsigned int *count, char *pos)
 {
-	char *sep;
-	size_t clen, nlen;
+	char *sep, *str = NULL;
+	size_t clen, nlen, slen;
 	struct hostapd_lang_string *ls;
+	int ret = -1;
+
+	if (*pos == '"' || (*pos == 'P' && pos[1] == '"')) {
+		str = wpa_config_parse_string(pos, &slen);
+		if (!str)
+			return -1;
+		pos = str;
+	}
 
 	sep = os_strchr(pos, ':');
 	if (sep == NULL)
-		return -1;
+		goto fail;
 	*sep++ = '\0';
 
 	clen = os_strlen(pos);
-	if (clen < 2)
-		return -1;
+	if (clen < 2 || clen > sizeof(ls->lang))
+		goto fail;
 	nlen = os_strlen(sep);
 	if (nlen > 252)
-		return -1;
+		goto fail;
 
 	ls = os_realloc_array(*array, *count + 1,
 			      sizeof(struct hostapd_lang_string));
 	if (ls == NULL)
-		return -1;
+		goto fail;
 
 	*array = ls;
 	ls = &(*array)[*count];
@@ -1319,7 +1170,10 @@
 	ls->name_len = nlen;
 	os_memcpy(ls->name, sep, nlen);
 
-	return 0;
+	ret = 0;
+fail:
+	os_free(str);
+	return ret;
 }
 
 
@@ -1550,6 +1404,47 @@
 	return -1;
 }
 
+
+static int parse_qos_map_set(struct hostapd_bss_config *bss,
+			     char *buf, int line)
+{
+	u8 qos_map_set[16 + 2 * 21], count = 0;
+	char *pos = buf;
+	int val;
+
+	for (;;) {
+		if (count == sizeof(qos_map_set)) {
+			wpa_printf(MSG_ERROR, "Line %d: Too many qos_map_set "
+				   "parameters '%s'", line, buf);
+			return -1;
+		}
+
+		val = atoi(pos);
+		if (val > 255 || val < 0) {
+			wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set "
+				   "'%s'", line, buf);
+			return -1;
+		}
+
+		qos_map_set[count++] = val;
+		pos = os_strchr(pos, ',');
+		if (!pos)
+			break;
+		pos++;
+	}
+
+	if (count < 16 || count & 1) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set '%s'",
+			   line, buf);
+		return -1;
+	}
+
+	os_memcpy(bss->qos_map_set, qos_map_set, count);
+	bss->qos_map_set_len = count;
+
+	return 0;
+}
+
 #endif /* CONFIG_INTERWORKING */
 
 
@@ -1700,8 +1595,8 @@
 
 	{
 		if (os_strcmp(buf, "interface") == 0) {
-			os_strlcpy(conf->bss[0].iface, pos,
-				   sizeof(conf->bss[0].iface));
+			os_strlcpy(conf->bss[0]->iface, pos,
+				   sizeof(conf->bss[0]->iface));
 		} else if (os_strcmp(buf, "bridge") == 0) {
 			os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
 		} else if (os_strcmp(buf, "vlan_bridge") == 0) {
@@ -2129,8 +2024,11 @@
 			} else {
 				os_free(bss->ssid.wpa_passphrase);
 				bss->ssid.wpa_passphrase = os_strdup(pos);
-				os_free(bss->ssid.wpa_psk);
-				bss->ssid.wpa_psk = NULL;
+				if (bss->ssid.wpa_passphrase) {
+					os_free(bss->ssid.wpa_psk);
+					bss->ssid.wpa_psk = NULL;
+					bss->ssid.wpa_passphrase_set = 1;
+				}
 			}
 		} else if (os_strcmp(buf, "wpa_psk") == 0) {
 			os_free(bss->ssid.wpa_psk);
@@ -2148,6 +2046,7 @@
 				bss->ssid.wpa_psk->group = 1;
 				os_free(bss->ssid.wpa_passphrase);
 				bss->ssid.wpa_passphrase = NULL;
+				bss->ssid.wpa_psk_set = 1;
 			}
 		} else if (os_strcmp(buf, "wpa_psk_file") == 0) {
 			os_free(bss->ssid.wpa_psk_file);
@@ -2523,6 +2422,8 @@
 			}
 		} else if (os_strcmp(buf, "require_ht") == 0) {
 			conf->require_ht = atoi(pos);
+		} else if (os_strcmp(buf, "obss_interval") == 0) {
+			conf->obss_interval = atoi(pos);
 #endif /* CONFIG_IEEE80211N */
 #ifdef CONFIG_IEEE80211AC
 		} else if (os_strcmp(buf, "ieee80211ac") == 0) {
@@ -2875,6 +2776,9 @@
 			bss->gas_frag_limit = atoi(pos);
 		} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
 			bss->gas_comeback_delay = atoi(pos);
+		} else if (os_strcmp(buf, "qos_map_set") == 0) {
+			if (parse_qos_map_set(bss, pos, line) < 0)
+				errors++;
 #endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_RADIUS_TEST
 		} else if (os_strcmp(buf, "dump_msk_file") == 0) {
@@ -2947,6 +2851,25 @@
 		PARSE_TEST_PROBABILITY(ignore_assoc_probability)
 		PARSE_TEST_PROBABILITY(ignore_reassoc_probability)
 		PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
+		} else if (os_strcmp(buf, "bss_load_test") == 0) {
+			WPA_PUT_LE16(bss->bss_load_test, atoi(pos));
+			pos = os_strchr(pos, ':');
+			if (pos == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "bss_load_test", line);
+				return 1;
+			}
+			pos++;
+			bss->bss_load_test[2] = atoi(pos);
+			pos = os_strchr(pos, ':');
+			if (pos == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "bss_load_test", line);
+				return 1;
+			}
+			pos++;
+			WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
+			bss->bss_load_test_set = 1;
 #endif /* CONFIG_TESTING_OPTIONS */
 		} else if (os_strcmp(buf, "vendor_elements") == 0) {
 			struct wpabuf *elems;
@@ -2995,53 +2918,6 @@
 }
 
 
-static void hostapd_set_security_params(struct hostapd_bss_config *bss)
-{
-	if (bss->individual_wep_key_len == 0) {
-		/* individual keys are not use; can use key idx0 for
-		 * broadcast keys */
-		bss->broadcast_key_idx_min = 0;
-	}
-
-	if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
-		bss->rsn_pairwise = bss->wpa_pairwise;
-	bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
-						    bss->rsn_pairwise);
-
-	bss->radius->auth_server = bss->radius->auth_servers;
-	bss->radius->acct_server = bss->radius->acct_servers;
-
-	if (bss->wpa && bss->ieee802_1x) {
-		bss->ssid.security_policy = SECURITY_WPA;
-	} else if (bss->wpa) {
-		bss->ssid.security_policy = SECURITY_WPA_PSK;
-	} else if (bss->ieee802_1x) {
-		int cipher = WPA_CIPHER_NONE;
-		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
-		bss->ssid.wep.default_len = bss->default_wep_key_len;
-		if (bss->default_wep_key_len)
-			cipher = bss->default_wep_key_len >= 13 ?
-				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
-		bss->wpa_group = cipher;
-		bss->wpa_pairwise = cipher;
-		bss->rsn_pairwise = cipher;
-	} else if (bss->ssid.wep.keys_set) {
-		int cipher = WPA_CIPHER_WEP40;
-		if (bss->ssid.wep.len[0] >= 13)
-			cipher = WPA_CIPHER_WEP104;
-		bss->ssid.security_policy = SECURITY_STATIC_WEP;
-		bss->wpa_group = cipher;
-		bss->wpa_pairwise = cipher;
-		bss->rsn_pairwise = cipher;
-	} else {
-		bss->ssid.security_policy = SECURITY_PLAINTEXT;
-		bss->wpa_group = WPA_CIPHER_NONE;
-		bss->wpa_pairwise = WPA_CIPHER_NONE;
-		bss->rsn_pairwise = WPA_CIPHER_NONE;
-	}
-}
-
-
 /**
  * hostapd_config_read - Read and parse a configuration file
  * @fname: Configuration file name (including path, if needed)
@@ -3079,7 +2955,7 @@
 		return NULL;
 	}
 
-	bss = conf->last_bss = conf->bss;
+	bss = conf->last_bss = conf->bss[0];
 
 	while (fgets(buf, sizeof(buf), f)) {
 		bss = conf->last_bss;
@@ -3113,7 +2989,7 @@
 	fclose(f);
 
 	for (i = 0; i < conf->num_bss; i++)
-		hostapd_set_security_params(&conf->bss[i]);
+		hostapd_set_security_params(conf->bss[i]);
 
 	if (hostapd_config_check(conf))
 		errors++;
@@ -3145,7 +3021,7 @@
 	}
 
 	for (i = 0; i < conf->num_bss; i++)
-		hostapd_set_security_params(&conf->bss[i]);
+		hostapd_set_security_params(conf->bss[i]);
 
 	if (hostapd_config_check(conf)) {
 		wpa_printf(MSG_ERROR, "Configuration check failed");
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index be941c4..2d0379f 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -82,15 +82,15 @@
 		    os_memcmp(from->sun_path, dst->addr.sun_path,
 			      fromlen - offsetof(struct sockaddr_un, sun_path))
 		    == 0) {
+			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+				    (u8 *) from->sun_path,
+				    fromlen -
+				    offsetof(struct sockaddr_un, sun_path));
 			if (prev == NULL)
 				hapd->ctrl_dst = dst->next;
 			else
 				prev->next = dst->next;
 			os_free(dst);
-			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
-				    (u8 *) from->sun_path,
-				    fromlen -
-				    offsetof(struct sockaddr_un, sun_path));
 			return 0;
 		}
 		prev = dst;
@@ -559,6 +559,106 @@
 #endif /* CONFIG_WPS */
 
 
+#ifdef CONFIG_INTERWORKING
+
+static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
+					      const char *cmd)
+{
+	u8 qos_map_set[16 + 2 * 21], count = 0;
+	const char *pos = cmd;
+	int val, ret;
+
+	for (;;) {
+		if (count == sizeof(qos_map_set)) {
+			wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
+			return -1;
+		}
+
+		val = atoi(pos);
+		if (val < 0 || val > 255) {
+			wpa_printf(MSG_INFO, "Invalid QoS Map Set");
+			return -1;
+		}
+
+		qos_map_set[count++] = val;
+		pos = os_strchr(pos, ',');
+		if (!pos)
+			break;
+		pos++;
+	}
+
+	if (count < 16 || count & 1) {
+		wpa_printf(MSG_INFO, "Invalid QoS Map Set");
+		return -1;
+	}
+
+	ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
+	if (ret) {
+		wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
+		return -1;
+	}
+
+	os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
+	hapd->conf->qos_map_set_len = count;
+
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
+						const char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	struct sta_info *sta;
+	struct wpabuf *buf;
+	u8 *qos_map_set = hapd->conf->qos_map_set;
+	u8 qos_map_set_len = hapd->conf->qos_map_set_len;
+	int ret;
+
+	if (!qos_map_set_len) {
+		wpa_printf(MSG_INFO, "QoS Map Set is not set");
+		return -1;
+	}
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
+			   "for QoS Map Configuration message",
+			   MAC2STR(addr));
+		return -1;
+	}
+
+	if (!sta->qos_map_enabled) {
+		wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
+			   "support for QoS Map", MAC2STR(addr));
+		return -1;
+	}
+
+	buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
+	if (buf == NULL)
+		return -1;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_QOS);
+	wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
+
+	/* QoS Map Set Element */
+	wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
+	wpabuf_put_u8(buf, qos_map_set_len);
+	wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
+
+	ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+				      wpabuf_head(buf), wpabuf_len(buf));
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+#endif /* CONFIG_INTERWORKING */
+
+
 #ifdef CONFIG_WNM
 
 static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
@@ -643,6 +743,7 @@
 	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
 	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
 	mgmt->u.action.u.bss_tm_req.req_mode =
+		WNM_BSS_TM_REQ_DISASSOC_IMMINENT |
 		WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
 	mgmt->u.action.u.bss_tm_req.disassoc_timer =
 		host_to_le16(disassoc_timer);
@@ -949,6 +1050,83 @@
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
+{
+	union wpa_event_data data;
+	char *pos, *param;
+	enum wpa_event_type event;
+
+	wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
+
+	os_memset(&data, 0, sizeof(data));
+
+	param = os_strchr(cmd, ' ');
+	if (param == NULL)
+		return -1;
+	*param++ = '\0';
+
+	if (os_strcmp(cmd, "DETECTED") == 0)
+		event = EVENT_DFS_RADAR_DETECTED;
+	else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
+		event = EVENT_DFS_CAC_FINISHED;
+	else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
+		event = EVENT_DFS_CAC_ABORTED;
+	else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
+		event = EVENT_DFS_NOP_FINISHED;
+	else {
+		wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
+			   cmd);
+		return -1;
+	}
+
+	pos = os_strstr(param, "freq=");
+	if (pos)
+		data.dfs_event.freq = atoi(pos + 5);
+
+	pos = os_strstr(param, "ht_enabled=1");
+	if (pos)
+		data.dfs_event.ht_enabled = 1;
+
+	pos = os_strstr(param, "chan_offset=");
+	if (pos)
+		data.dfs_event.chan_offset = atoi(pos + 12);
+
+	pos = os_strstr(param, "chan_width=");
+	if (pos)
+		data.dfs_event.chan_width = atoi(pos + 11);
+
+	pos = os_strstr(param, "cf1=");
+	if (pos)
+		data.dfs_event.cf1 = atoi(pos + 4);
+
+	pos = os_strstr(param, "cf2=");
+	if (pos)
+		data.dfs_event.cf2 = atoi(pos + 4);
+
+	wpa_supplicant_event(hapd, event, &data);
+
+	return 0;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static int hostapd_ctrl_iface_chan_switch(struct hostapd_data *hapd, char *pos)
+{
+#ifdef NEED_AP_MLME
+	struct csa_settings settings;
+	int ret = hostapd_parse_csa_settings(pos, &settings);
+
+	if (ret)
+		return ret;
+
+	return hostapd_switch_channel(hapd, &settings);
+#else /* NEED_AP_MLME */
+	return -1;
+#endif /* NEED_AP_MLME */
+}
+
+
 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
 				       void *sock_ctx)
 {
@@ -989,6 +1167,9 @@
 	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
 		if (wpa_debug_reopen_file() < 0)
 			reply_len = -1;
+	} else if (os_strcmp(buf, "STATUS") == 0) {
+		reply_len = hostapd_ctrl_iface_status(hapd, reply,
+						      reply_size);
 	} else if (os_strcmp(buf, "MIB") == 0) {
 		reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
 		if (reply_len >= 0) {
@@ -1093,6 +1274,14 @@
 			reply_len = -1;
 #endif /* CONFIG_WPS_NFC */
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_INTERWORKING
+	} else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
+		if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
+		if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
+			reply_len = -1;
+#endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_WNM
 	} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
 		if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
@@ -1119,6 +1308,14 @@
 	} else if (os_strncmp(buf, "DISABLE", 7) == 0) {
 		if (hostapd_ctrl_iface_disable(hapd->iface))
 			reply_len = -1;
+#ifdef CONFIG_TESTING_OPTIONS
+	} else if (os_strncmp(buf, "RADAR ", 6) == 0) {
+		if (hostapd_ctrl_iface_radar(hapd, buf + 6))
+			reply_len = -1;
+#endif /* CONFIG_TESTING_OPTIONS */
+	} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
+		if (hostapd_ctrl_iface_chan_switch(hapd, buf + 12))
+			reply_len = -1;
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
@@ -1385,6 +1582,7 @@
 		return;
 	}
 	buf[res] = '\0';
+	wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
 
 	os_memcpy(reply, "OK\n", 3);
 	reply_len = 3;
@@ -1392,6 +1590,9 @@
 	if (os_strcmp(buf, "PING") == 0) {
 		os_memcpy(reply, "PONG\n", 5);
 		reply_len = 5;
+	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
+		if (wpa_debug_reopen_file() < 0)
+			reply_len = -1;
 	} else if (os_strncmp(buf, "ADD ", 4) == 0) {
 		if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
 			reply_len = -1;
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 2dd6fc8..3f2924b 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -157,6 +157,12 @@
 # Disabled by default.
 #CONFIG_DEBUG_FILE=y
 
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
 # Remove support for RADIUS accounting
 #CONFIG_NO_ACCOUNTING=y
 
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index e04e2e9..c041887 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -1,6 +1,6 @@
 /*
  * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -18,6 +18,9 @@
  * SIM-REQ-AUTH <IMSI> <max_chal>
  * SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
  * SIM-RESP-AUTH <IMSI> FAILURE
+ * GSM-AUTH-REQ <IMSI> RAND1:RAND2[:RAND3]
+ * GSM-AUTH-RESP <IMSI> Kc1:SRES1:Kc2:SRES2[:Kc3:SRES3]
+ * GSM-AUTH-RESP <IMSI> FAILURE
  *
  * EAP-AKA / UMTS query/response:
  * AKA-REQ-AUTH <IMSI>
@@ -30,12 +33,16 @@
  * IMSI and max_chal are sent as an ASCII string,
  * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
  *
- * The example implementation here reads GSM authentication triplets from a
+ * An example implementation here reads GSM authentication triplets from a
  * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
  * strings. This is used to simulate an HLR/AuC. As such, it is not very useful
  * for real life authentication, but it is useful both as an example
  * implementation and for EAP-SIM/AKA/AKA' testing.
  *
+ * For a stronger example design, Milenage and GSM-Milenage algorithms can be
+ * used to dynamically generate authenticatipn information for EAP-AKA/AKA' and
+ * EAP-SIM, respectively, if Ki is known.
+ *
  * SQN generation follows the not time-based Profile 2 described in
  * 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
  * can be changed with a command line options if needed.
@@ -58,6 +65,7 @@
 static int update_milenage = 0;
 static int sqn_changes = 0;
 static int ind_len = 5;
+static int stdout_debug = 1;
 
 /* GSM triplets */
 struct gsm_triplet {
@@ -214,6 +222,9 @@
 {
 	char cmd[128], val[13], *pos;
 
+	if (sqlite_db == NULL)
+		return 0;
+
 	pos = val;
 	pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
 	*pos = '\0';
@@ -611,31 +622,30 @@
 }
 
 
-static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
-			 char *imsi)
+static int sim_req_auth(char *imsi, char *resp, size_t resp_len)
 {
 	int count, max_chal, ret;
 	char *pos;
-	char reply[1000], *rpos, *rend;
+	char *rpos, *rend;
 	struct milenage_parameters *m;
 	struct gsm_triplet *g;
 
-	reply[0] = '\0';
+	resp[0] = '\0';
 
 	pos = strchr(imsi, ' ');
 	if (pos) {
 		*pos++ = '\0';
 		max_chal = atoi(pos);
-		if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
+		if (max_chal < 1 || max_chal > EAP_SIM_MAX_CHAL)
 			max_chal = EAP_SIM_MAX_CHAL;
 	} else
 		max_chal = EAP_SIM_MAX_CHAL;
 
-	rend = &reply[sizeof(reply)];
-	rpos = reply;
+	rend = resp + resp_len;
+	rpos = resp;
 	ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
 	if (ret < 0 || ret >= rend - rpos)
-		return;
+		return -1;
 	rpos += ret;
 
 	m = get_milenage(imsi);
@@ -643,7 +653,7 @@
 		u8 _rand[16], sres[4], kc[8];
 		for (count = 0; count < max_chal; count++) {
 			if (random_get_bytes(_rand, 16) < 0)
-				return;
+				return -1;
 			gsm_milenage(m->opc, m->ki, _rand, sres, kc);
 			*rpos++ = ' ';
 			rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
@@ -653,7 +663,7 @@
 			rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
 		}
 		*rpos = '\0';
-		goto send;
+		return 0;
 	}
 
 	count = 0;
@@ -677,15 +687,61 @@
 		printf("No GSM triplets found for %s\n", imsi);
 		ret = snprintf(rpos, rend - rpos, " FAILURE");
 		if (ret < 0 || ret >= rend - rpos)
-			return;
+			return -1;
 		rpos += ret;
 	}
 
-send:
-	printf("Send: %s\n", reply);
-	if (sendto(s, reply, rpos - reply, 0,
-		   (struct sockaddr *) from, fromlen) < 0)
-		perror("send");
+	return 0;
+}
+
+
+static int gsm_auth_req(char *imsi, char *resp, size_t resp_len)
+{
+	int count, ret;
+	char *pos, *rpos, *rend;
+	struct milenage_parameters *m;
+
+	resp[0] = '\0';
+
+	pos = os_strchr(imsi, ' ');
+	if (!pos)
+		return -1;
+	*pos++ = '\0';
+
+	rend = resp + resp_len;
+	rpos = resp;
+	ret = os_snprintf(rpos, rend - rpos, "GSM-AUTH-RESP %s", imsi);
+	if (ret < 0 || ret >= rend - rpos)
+		return -1;
+	rpos += ret;
+
+	m = get_milenage(imsi);
+	if (m) {
+		u8 _rand[16], sres[4], kc[8];
+		for (count = 0; count < EAP_SIM_MAX_CHAL; count++) {
+			if (hexstr2bin(pos, _rand, 16) != 0)
+				return -1;
+			gsm_milenage(m->opc, m->ki, _rand, sres, kc);
+			*rpos++ = count == 0 ? ' ' : ':';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
+			*rpos++ = ':';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
+			pos += 16 * 2;
+			if (*pos != ':')
+				break;
+			pos++;
+		}
+		*rpos = '\0';
+		return 0;
+	}
+
+	printf("No GSM triplets found for %s\n", imsi);
+	ret = os_snprintf(rpos, rend - rpos, " FAILURE");
+	if (ret < 0 || ret >= rend - rpos)
+		return -1;
+	rpos += ret;
+
+	return 0;
 }
 
 
@@ -711,11 +767,10 @@
 }
 
 
-static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
-			 char *imsi)
+static int aka_req_auth(char *imsi, char *resp, size_t resp_len)
 {
 	/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
-	char reply[1000], *pos, *end;
+	char *pos, *end;
 	u8 _rand[EAP_AKA_RAND_LEN];
 	u8 autn[EAP_AKA_AUTN_LEN];
 	u8 ik[EAP_AKA_IK_LEN];
@@ -729,16 +784,18 @@
 	m = get_milenage(imsi);
 	if (m) {
 		if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
-			return;
+			return -1;
 		res_len = EAP_AKA_RES_MAX_LEN;
 		inc_sqn(m->sqn);
 #ifdef CONFIG_SQLITE
 		db_update_milenage_sqn(m);
 #endif /* CONFIG_SQLITE */
 		sqn_changes = 1;
-		printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
-		       m->sqn[0], m->sqn[1], m->sqn[2],
-		       m->sqn[3], m->sqn[4], m->sqn[5]);
+		if (stdout_debug) {
+			printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
+			       m->sqn[0], m->sqn[1], m->sqn[2],
+			       m->sqn[3], m->sqn[4], m->sqn[5]);
+		}
 		milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
 				  autn, ik, ck, res, &res_len);
 	} else {
@@ -756,18 +813,18 @@
 #endif /* AKA_USE_FIXED_TEST_VALUES */
 	}
 
-	pos = reply;
-	end = &reply[sizeof(reply)];
+	pos = resp;
+	end = resp + resp_len;
 	ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
 	if (ret < 0 || ret >= end - pos)
-		return;
+		return -1;
 	pos += ret;
 	if (failed) {
 		ret = snprintf(pos, end - pos, "FAILURE");
 		if (ret < 0 || ret >= end - pos)
-			return;
+			return -1;
 		pos += ret;
-		goto done;
+		return 0;
 	}
 	pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
 	*pos++ = ' ';
@@ -779,65 +836,87 @@
 	*pos++ = ' ';
 	pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
 
-done:
-	printf("Send: %s\n", reply);
-
-	if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
-		   fromlen) < 0)
-		perror("send");
+	return 0;
 }
 
 
-static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
-		     char *imsi)
+static int aka_auts(char *imsi, char *resp, size_t resp_len)
 {
 	char *auts, *__rand;
 	u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
 	struct milenage_parameters *m;
 
+	resp[0] = '\0';
+
 	/* AKA-AUTS <IMSI> <AUTS> <RAND> */
 
 	auts = strchr(imsi, ' ');
 	if (auts == NULL)
-		return;
+		return -1;
 	*auts++ = '\0';
 
 	__rand = strchr(auts, ' ');
 	if (__rand == NULL)
-		return;
+		return -1;
 	*__rand++ = '\0';
 
-	printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
+	if (stdout_debug) {
+		printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n",
+		       imsi, auts, __rand);
+	}
 	if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
 	    hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
 		printf("Could not parse AUTS/RAND\n");
-		return;
+		return -1;
 	}
 
 	m = get_milenage(imsi);
 	if (m == NULL) {
 		printf("Unknown IMSI: %s\n", imsi);
-		return;
+		return -1;
 	}
 
 	if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
 		printf("AKA-AUTS: Incorrect MAC-S\n");
 	} else {
 		memcpy(m->sqn, sqn, 6);
-		printf("AKA-AUTS: Re-synchronized: "
-		       "SQN=%02x%02x%02x%02x%02x%02x\n",
-		       sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+		if (stdout_debug) {
+			printf("AKA-AUTS: Re-synchronized: "
+			       "SQN=%02x%02x%02x%02x%02x%02x\n",
+			       sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+		}
 #ifdef CONFIG_SQLITE
 		db_update_milenage_sqn(m);
 #endif /* CONFIG_SQLITE */
 		sqn_changes = 1;
 	}
+
+	return 0;
+}
+
+
+static int process_cmd(char *cmd, char *resp, size_t resp_len)
+{
+	if (os_strncmp(cmd, "SIM-REQ-AUTH ", 13) == 0)
+		return sim_req_auth(cmd + 13, resp, resp_len);
+
+	if (os_strncmp(cmd, "GSM-AUTH-REQ ", 13) == 0)
+		return gsm_auth_req(cmd + 13, resp, resp_len);
+
+	if (os_strncmp(cmd, "AKA-REQ-AUTH ", 13) == 0)
+		return aka_req_auth(cmd + 13, resp, resp_len);
+
+	if (os_strncmp(cmd, "AKA-AUTS ", 9) == 0)
+		return aka_auts(cmd + 9, resp, resp_len);
+
+	printf("Unknown request: %s\n", cmd);
+	return -1;
 }
 
 
 static int process(int s)
 {
-	char buf[1000];
+	char buf[1000], resp[1000];
 	struct sockaddr_un from;
 	socklen_t fromlen;
 	ssize_t res;
@@ -859,14 +938,21 @@
 
 	printf("Received: %s\n", buf);
 
-	if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
-		sim_req_auth(s, &from, fromlen, buf + 13);
-	else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
-		aka_req_auth(s, &from, fromlen, buf + 13);
-	else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
-		aka_auts(s, &from, fromlen, buf + 9);
-	else
-		printf("Unknown request: %s\n", buf);
+	if (process_cmd(buf, resp, sizeof(resp)) < 0) {
+		printf("Failed to process request\n");
+		return -1;
+	}
+
+	if (resp[0] == '\0') {
+		printf("No response\n");
+		return 0;
+	}
+
+	printf("Send: %s\n", resp);
+
+	if (sendto(s, resp, os_strlen(resp), 0, (struct sockaddr *) &from,
+		   fromlen) < 0)
+		perror("send");
 
 	return 0;
 }
@@ -894,8 +980,10 @@
 		os_free(prev);
 	}
 
-	close(serv_sock);
-	unlink(socket_path);
+	if (serv_sock >= 0)
+		close(serv_sock);
+	if (socket_path)
+		unlink(socket_path);
 
 #ifdef CONFIG_SQLITE
 	if (sqlite_db) {
@@ -917,12 +1005,12 @@
 {
 	printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
 	       "database/authenticator\n"
-	       "Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>\n"
+	       "Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n"
 	       "\n"
 	       "usage:\n"
 	       "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
 	       "[-m<milenage file>] \\\n"
-	       "        [-D<DB file>] [-i<IND len in bits>]\n"
+	       "        [-D<DB file>] [-i<IND len in bits>] [command]\n"
 	       "\n"
 	       "options:\n"
 	       "  -h = show this usage help\n"
@@ -932,7 +1020,15 @@
 	       "  -g<triplet file> = path for GSM authentication triplets\n"
 	       "  -m<milenage file> = path for Milenage keys\n"
 	       "  -D<DB file> = path to SQLite database\n"
-	       "  -i<IND len in bits> = IND length for SQN (default: 5)\n",
+	       "  -i<IND len in bits> = IND length for SQN (default: 5)\n"
+	       "\n"
+	       "If the optional command argument, like "
+	       "\"AKA-REQ-AUTH <IMSI>\" is used, a single\n"
+	       "command is processed with response sent to stdout. Otherwise, "
+	       "hlr_auc_gw opens\n"
+	       "a control interface and processes commands sent through it "
+	       "(e.g., by EAP server\n"
+	       "in hostapd).\n",
 	       default_socket_path);
 }
 
@@ -942,6 +1038,7 @@
 	int c;
 	char *gsm_triplet_file = NULL;
 	char *sqlite_db_file = NULL;
+	int ret = 0;
 
 	if (os_program_init())
 		return -1;
@@ -1005,18 +1102,31 @@
 	if (milenage_file && read_milenage(milenage_file) < 0)
 		return -1;
 
-	serv_sock = open_socket(socket_path);
-	if (serv_sock < 0)
-		return -1;
+	if (optind == argc) {
+		serv_sock = open_socket(socket_path);
+		if (serv_sock < 0)
+			return -1;
 
-	printf("Listening for requests on %s\n", socket_path);
+		printf("Listening for requests on %s\n", socket_path);
 
-	atexit(cleanup);
-	signal(SIGTERM, handle_term);
-	signal(SIGINT, handle_term);
+		atexit(cleanup);
+		signal(SIGTERM, handle_term);
+		signal(SIGINT, handle_term);
 
-	for (;;)
-		process(serv_sock);
+		for (;;)
+			process(serv_sock);
+	} else {
+		char buf[1000];
+		socket_path = NULL;
+		stdout_debug = 0;
+		if (process_cmd(argv[optind], buf, sizeof(buf)) < 0) {
+			printf("FAIL\n");
+			ret = -1;
+		} else {
+			printf("%s\n", buf);
+		}
+		cleanup();
+	}
 
 #ifdef CONFIG_SQLITE
 	if (sqlite_db) {
@@ -1027,5 +1137,5 @@
 
 	os_program_deinit();
 
-	return 0;
+	return ret;
 }
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 45897ed..9b70d0f 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -416,6 +416,12 @@
 # associated stations in the BSS. By default, this bridging is allowed.
 #ap_isolate=1
 
+# Fixed BSS Load value for testing purposes
+# This field can be used to configure hostapd to add a fixed BSS Load element
+# into Beacon and Probe Response frames for testing purposes. The format is
+# <station count>:<channel utilization>:<available admission capacity>
+#bss_load_test=12:80:20000
+
 ##### IEEE 802.11n related configuration ######################################
 
 # ieee80211n: Whether IEEE 802.11n (HT) is enabled
@@ -462,6 +468,13 @@
 # Require stations to support HT PHY (reject association if they do not)
 #require_ht=1
 
+# If set non-zero, require stations to perform scans of overlapping
+# channels to test for stations which would be affected by 40 MHz traffic.
+# This parameter sets the interval in seconds between these scans. This
+# is useful only for testing that stations properly set the OBSS interval,
+# since the other parameters in the OBSS scan parameters IE are set to 0.
+#obss_interval=0
+
 ##### IEEE 802.11ac related configuration #####################################
 
 # ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
@@ -1457,6 +1470,9 @@
 # information to be complete.
 #venue_name=eng:Example venue
 #venue_name=fin:Esimerkkipaikka
+# Alternative format for language:value strings:
+# (double quoted string, printf-escaped string)
+#venue_name=P"eng:Example\nvenue"
 
 # Network Authentication Type
 # This parameter indicates what type of network authentication is used in the
@@ -1521,6 +1537,23 @@
 # username/password
 #nai_realm=0,example.org,13[5:6],21[2:4][5:7]
 
+# QoS Map Set configuration
+#
+# Comma delimited QoS Map Set in decimal values
+# (see IEEE Std 802.11-2012, 8.4.2.97)
+#
+# format:
+# [<DSCP Exceptions[DSCP,UP]>,]<UP 0 range[low,high]>,...<UP 7 range[low,high]>
+#
+# There can be up to 21 optional DSCP Exceptions which are pairs of DSCP Value
+# (0..63 or 255) and User Priority (0..7). This is followed by eight DSCP Range
+# descriptions with DSCP Low Value and DSCP High Value pairs (0..63 or 255) for
+# each UP starting from 0. If both low and high value are set to 255, the
+# corresponding UP is not used.
+#
+# default: not set
+#qos_map_set=53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,255,255
+
 ##### Hotspot 2.0 #############################################################
 
 # Enable Hotspot 2.0 support
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 7187abc..b2d3e5b 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1,6 +1,6 @@
 /*
  * hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -216,6 +216,12 @@
 }
 
 
+static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "STATUS");
+}
+
+
 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	return wpa_ctrl_command(ctrl, "MIB");
@@ -688,6 +694,45 @@
 }
 
 
+static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
+					   int argc, char *argv[])
+{
+	char buf[200];
+	int res;
+
+	if (argc != 1) {
+		printf("Invalid 'set_qos_map_set' command - "
+		       "one argument (comma delimited QoS map set) "
+		       "is needed\n");
+		return -1;
+	}
+
+	res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
+	if (res < 0 || res >= (int) sizeof(buf))
+		return -1;
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
+					     int argc, char *argv[])
+{
+	char buf[50];
+	int res;
+
+	if (argc != 1) {
+		printf("Invalid 'send_qos_map_conf' command - "
+		       "one argument (STA addr) is needed\n");
+		return -1;
+	}
+
+	res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
+	if (res < 0 || res >= (int) sizeof(buf))
+		return -1;
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	hostapd_cli_quit = 1;
@@ -801,6 +846,45 @@
 }
 
 
+static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
+				       int argc, char *argv[])
+{
+	char cmd[256];
+	int res;
+	int i;
+	char *tmp;
+	int total;
+
+	if (argc < 2) {
+		printf("Invalid chan_switch command: needs at least two "
+		       "arguments (count and freq)\n"
+		       "usage: <cs_count> <freq> [sec_channel_offset=] "
+		       "[center_freq1=] [center_freq2=] [bandwidth=] "
+		       "[blocktx] [ht|vht]\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
+			  argv[0], argv[1]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long CHAN_SWITCH command.\n");
+		return -1;
+	}
+
+	total = res;
+	for (i = 2; i < argc; i++) {
+		tmp = cmd + total;
+		res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
+		if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
+			printf("Too long CHAN_SWITCH command.\n");
+			return -1;
+		}
+		total += res;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 struct hostapd_cli_cmd {
 	const char *cmd;
 	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -810,6 +894,7 @@
 	{ "ping", hostapd_cli_cmd_ping },
 	{ "mib", hostapd_cli_cmd_mib },
 	{ "relog", hostapd_cli_cmd_relog },
+	{ "status", hostapd_cli_cmd_status },
 	{ "sta", hostapd_cli_cmd_sta },
 	{ "all_sta", hostapd_cli_cmd_all_sta },
 	{ "new_sta", hostapd_cli_cmd_new_sta },
@@ -843,6 +928,9 @@
 	{ "quit", hostapd_cli_cmd_quit },
 	{ "set", hostapd_cli_cmd_set },
 	{ "get", hostapd_cli_cmd_get },
+	{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
+	{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
+	{ "chan_switch", hostapd_cli_cmd_chan_switch },
 	{ NULL, NULL }
 };
 
diff --git a/hostapd/main.c b/hostapd/main.c
index 90e5966..4e9fe40 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -114,7 +114,7 @@
 
 	if ((conf_stdout & module) && level >= conf_stdout_level) {
 		wpa_debug_print_timestamp();
-		printf("%s\n", format);
+		wpa_printf(MSG_INFO, "%s", format);
 	}
 
 #ifndef CONFIG_NATIVE_WINDOWS
@@ -148,65 +148,8 @@
 
 
 /**
- * hostapd_init - Allocate and initialize per-interface data
- * @config_file: Path to the configuration file
- * Returns: Pointer to the allocated interface data or %NULL on failure
- *
- * This function is used to allocate main data structures for per-interface
- * data. The allocated data buffer will be freed by calling
- * hostapd_cleanup_iface().
+ * hostapd_driver_init - Preparate driver interface
  */
-static struct hostapd_iface * hostapd_init(const char *config_file)
-{
-	struct hostapd_iface *hapd_iface = NULL;
-	struct hostapd_config *conf = NULL;
-	struct hostapd_data *hapd;
-	size_t i;
-
-	hapd_iface = os_zalloc(sizeof(*hapd_iface));
-	if (hapd_iface == NULL)
-		goto fail;
-
-	hapd_iface->config_fname = os_strdup(config_file);
-	if (hapd_iface->config_fname == NULL)
-		goto fail;
-
-	conf = hostapd_config_read(hapd_iface->config_fname);
-	if (conf == NULL)
-		goto fail;
-	hapd_iface->conf = conf;
-
-	hapd_iface->num_bss = conf->num_bss;
-	hapd_iface->bss = os_calloc(conf->num_bss,
-				    sizeof(struct hostapd_data *));
-	if (hapd_iface->bss == NULL)
-		goto fail;
-
-	for (i = 0; i < conf->num_bss; i++) {
-		hapd = hapd_iface->bss[i] =
-			hostapd_alloc_bss_data(hapd_iface, conf,
-					       &conf->bss[i]);
-		if (hapd == NULL)
-			goto fail;
-		hapd->msg_ctx = hapd;
-	}
-
-	return hapd_iface;
-
-fail:
-	wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
-		   config_file);
-	if (conf)
-		hostapd_config_free(conf);
-	if (hapd_iface) {
-		os_free(hapd_iface->config_fname);
-		os_free(hapd_iface->bss);
-		os_free(hapd_iface);
-	}
-	return NULL;
-}
-
-
 static int hostapd_driver_init(struct hostapd_iface *iface)
 {
 	struct wpa_init_params params;
@@ -286,6 +229,13 @@
 }
 
 
+/**
+ * hostapd_interface_init - Read configuration file and init BSS data
+ *
+ * This function is used to parse configuration file for a full interface (one
+ * or more BSSes sharing the same radio) and allocate memory for the BSS
+ * interfaces. No actiual driver operations are started.
+ */
 static struct hostapd_iface *
 hostapd_interface_init(struct hapd_interfaces *interfaces,
 		       const char *config_fname, int debug)
@@ -294,7 +244,7 @@
 	int k;
 
 	wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
-	iface = hostapd_init(config_fname);
+	iface = hostapd_init(interfaces, config_fname);
 	if (!iface)
 		return NULL;
 	iface->interfaces = interfaces;
@@ -304,7 +254,7 @@
 			iface->bss[0]->conf->logger_stdout_level--;
 	}
 
-	if (iface->conf->bss[0].iface[0] == '\0' &&
+	if (iface->conf->bss[0]->iface[0] == '\0' &&
 	    !hostapd_drv_none(iface->bss[0])) {
 		wpa_printf(MSG_ERROR, "Interface name not specified in %s",
 			   config_fname);
@@ -312,12 +262,6 @@
 		return NULL;
 	}
 
-	if (hostapd_driver_init(iface) ||
-	    hostapd_setup_interface(iface)) {
-		hostapd_interface_deinit_free(iface);
-		return NULL;
-	}
-
 	return iface;
 }
 
@@ -507,6 +451,10 @@
 #ifdef CONFIG_DEBUG_FILE
 		"   -f   log output to debug file instead of stdout\n"
 #endif /* CONFIG_DEBUG_FILE */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+		"   -T = record to Linux tracing in addition to logging\n"
+		"        (records all messages regardless of debug verbosity)\n"
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 		"   -t   include timestamps in some debug messages\n"
 		"   -v   show hostapd version\n");
 
@@ -517,8 +465,9 @@
 static const char * hostapd_msg_ifname_cb(void *ctx)
 {
 	struct hostapd_data *hapd = ctx;
-	if (hapd && hapd->iconf && hapd->iconf->bss)
-		return hapd->iconf->bss->iface;
+	if (hapd && hapd->iconf && hapd->iconf->bss &&
+	    hapd->iconf->num_bss > 0 && hapd->iconf->bss[0])
+		return hapd->iconf->bss[0]->iface;
 	return NULL;
 }
 
@@ -567,11 +516,16 @@
 {
 	struct hapd_interfaces interfaces;
 	int ret = 1;
-	size_t i;
+	size_t i, j;
 	int c, debug = 0, daemonize = 0;
 	char *pid_file = NULL;
 	const char *log_file = NULL;
 	const char *entropy_file = NULL;
+	char **bss_config = NULL, **tmp_bss;
+	size_t num_bss_configs = 0;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+	int enable_trace_dbg = 0;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 
 	if (os_program_init())
 		return -1;
@@ -588,7 +542,7 @@
 	interfaces.global_ctrl_sock = -1;
 
 	for (;;) {
-		c = getopt(argc, argv, "Bde:f:hKP:tvg:G:");
+		c = getopt(argc, argv, "b:Bde:f:hKP:Ttvg:G:");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -619,6 +573,11 @@
 		case 't':
 			wpa_debug_timestamp++;
 			break;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+		case 'T':
+			enable_trace_dbg = 1;
+			break;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 		case 'v':
 			show_version();
 			exit(1);
@@ -631,23 +590,42 @@
 			if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
 				return -1;
 			break;
+		case 'b':
+			tmp_bss = os_realloc_array(bss_config,
+						   num_bss_configs + 1,
+						   sizeof(char *));
+			if (tmp_bss == NULL)
+				goto out;
+			bss_config = tmp_bss;
+			bss_config[num_bss_configs++] = optarg;
+			break;
 		default:
 			usage();
 			break;
 		}
 	}
 
-	if (optind == argc && interfaces.global_iface_path == NULL)
+	if (optind == argc && interfaces.global_iface_path == NULL &&
+	    num_bss_configs == 0)
 		usage();
 
 	wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
 
 	if (log_file)
 		wpa_debug_open_file(log_file);
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+	if (enable_trace_dbg) {
+		int tret = wpa_debug_open_linux_tracing();
+		if (tret) {
+			wpa_printf(MSG_ERROR, "Failed to enable trace logging");
+			return -1;
+		}
+	}
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 
 	interfaces.count = argc - optind;
-	if (interfaces.count) {
-		interfaces.iface = os_calloc(interfaces.count,
+	if (interfaces.count || num_bss_configs) {
+		interfaces.iface = os_calloc(interfaces.count + num_bss_configs,
 					     sizeof(struct hostapd_iface *));
 		if (interfaces.iface == NULL) {
 			wpa_printf(MSG_ERROR, "malloc failed");
@@ -660,7 +638,7 @@
 		return -1;
 	}
 
-	/* Initialize interfaces */
+	/* Allocate and parse configuration for full interface files */
 	for (i = 0; i < interfaces.count; i++) {
 		interfaces.iface[i] = hostapd_interface_init(&interfaces,
 							     argv[optind + i],
@@ -671,6 +649,57 @@
 		}
 	}
 
+	/* Allocate and parse configuration for per-BSS files */
+	for (i = 0; i < num_bss_configs; i++) {
+		struct hostapd_iface *iface;
+		char *fname;
+
+		wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
+		fname = os_strchr(bss_config[i], ':');
+		if (fname == NULL) {
+			wpa_printf(MSG_ERROR,
+				   "Invalid BSS config identifier '%s'",
+				   bss_config[i]);
+			goto out;
+		}
+		*fname++ = '\0';
+		iface = hostapd_interface_init_bss(&interfaces, bss_config[i],
+						   fname, debug);
+		if (iface == NULL)
+			goto out;
+		for (j = 0; j < interfaces.count; j++) {
+			if (interfaces.iface[j] == iface)
+				break;
+		}
+		if (j == interfaces.count) {
+			struct hostapd_iface **tmp;
+			tmp = os_realloc_array(interfaces.iface,
+					       interfaces.count + 1,
+					       sizeof(struct hostapd_iface *));
+			if (tmp == NULL) {
+				hostapd_interface_deinit_free(iface);
+				goto out;
+			}
+			interfaces.iface = tmp;
+			interfaces.iface[interfaces.count++] = iface;
+		}
+	}
+
+	/*
+	 * Enable configured interfaces. Depending on channel configuration,
+	 * this may complete full initialization before returning or use a
+	 * callback mechanism to complete setup in case of operations like HT
+	 * co-ex scans, ACS, or DFS are needed to determine channel parameters.
+	 * In such case, the interface will be enabled from eloop context within
+	 * hostapd_global_run().
+	 */
+	interfaces.terminate_on_error = interfaces.count;
+	for (i = 0; i < interfaces.count; i++) {
+		if (hostapd_driver_init(interfaces.iface[i]) ||
+		    hostapd_setup_interface(interfaces.iface[i]))
+			goto out;
+	}
+
 	hostapd_global_ctrl_iface_init(&interfaces);
 
 	if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
@@ -692,6 +721,9 @@
 
 	if (log_file)
 		wpa_debug_close_file();
+	wpa_debug_close_linux_tracing();
+
+	os_free(bss_config);
 
 	os_program_deinit();
 
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 9540531..a1f67f0 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -44,7 +44,7 @@
 	msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
 			     radius_client_get_id(hapd->radius));
 	if (msg == NULL) {
-		printf("Could not create net RADIUS packet\n");
+		wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
 		return NULL;
 	}
 
@@ -55,7 +55,7 @@
 			    sta->acct_session_id_hi, sta->acct_session_id_lo);
 		if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
 					 (u8 *) buf, os_strlen(buf))) {
-			printf("Could not add Acct-Session-Id\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Session-Id");
 			goto fail;
 		}
 	} else {
@@ -64,7 +64,7 @@
 
 	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
 				       status_type)) {
-		printf("Could not add Acct-Status-Type\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Status-Type");
 		goto fail;
 	}
 
@@ -74,7 +74,7 @@
 				       hapd->conf->ieee802_1x ?
 				       RADIUS_ACCT_AUTHENTIC_RADIUS :
 				       RADIUS_ACCT_AUTHENTIC_LOCAL)) {
-		printf("Could not add Acct-Authentic\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
 		goto fail;
 	}
 
@@ -99,7 +99,7 @@
 
 		if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
 					 len)) {
-			printf("Could not add User-Name\n");
+			wpa_printf(MSG_INFO, "Could not add User-Name");
 			goto fail;
 		}
 	}
@@ -117,7 +117,7 @@
 
 			if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
 						 val, len)) {
-				printf("Could not add Class\n");
+				wpa_printf(MSG_INFO, "Could not add Class");
 				goto fail;
 			}
 		}
@@ -254,14 +254,14 @@
 			     stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
 			     RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
 	if (!msg) {
-		printf("Could not create RADIUS Accounting message\n");
+		wpa_printf(MSG_INFO, "Could not create RADIUS Accounting message");
 		return;
 	}
 
 	os_get_time(&now);
 	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
 				       now.sec - sta->acct_session_start)) {
-		printf("Could not add Acct-Session-Time\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Session-Time");
 		goto fail;
 	}
 
@@ -269,19 +269,19 @@
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_INPUT_PACKETS,
 					       data.rx_packets)) {
-			printf("Could not add Acct-Input-Packets\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Input-Packets");
 			goto fail;
 		}
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
 					       data.tx_packets)) {
-			printf("Could not add Acct-Output-Packets\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
 			goto fail;
 		}
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_INPUT_OCTETS,
 					       data.rx_bytes)) {
-			printf("Could not add Acct-Input-Octets\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
 			goto fail;
 		}
 		gigawords = sta->acct_input_gigawords;
@@ -292,13 +292,13 @@
 		    !radius_msg_add_attr_int32(
 			    msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
 			    gigawords)) {
-			printf("Could not add Acct-Input-Gigawords\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
 			goto fail;
 		}
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
 					       data.tx_bytes)) {
-			printf("Could not add Acct-Output-Octets\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
 			goto fail;
 		}
 		gigawords = sta->acct_output_gigawords;
@@ -309,14 +309,14 @@
 		    !radius_msg_add_attr_int32(
 			    msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
 			    gigawords)) {
-			printf("Could not add Acct-Output-Gigawords\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords");
 			goto fail;
 		}
 	}
 
 	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
 				       now.sec)) {
-		printf("Could not add Event-Timestamp\n");
+		wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
 		goto fail;
 	}
 
@@ -326,7 +326,7 @@
 	if (stop && cause &&
 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
 				       cause)) {
-		printf("Could not add Acct-Terminate-Cause\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
 		goto fail;
 	}
 
@@ -400,13 +400,12 @@
 		   void *data)
 {
 	if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
-		printf("Unknown RADIUS message code\n");
+		wpa_printf(MSG_INFO, "Unknown RADIUS message code");
 		return RADIUS_RX_UNKNOWN;
 	}
 
 	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
-		printf("Incoming RADIUS packet did not have correct "
-		       "Authenticator - dropped\n");
+		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Authenticator - dropped");
 		return RADIUS_RX_INVALID_AUTHENTICATOR;
 	}
 
@@ -432,7 +431,7 @@
 	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
 				       RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
 	{
-		printf("Could not add Acct-Terminate-Cause\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
 		radius_msg_free(msg);
 		return;
 	}
diff --git a/src/ap/acs.c b/src/ap/acs.c
index d5e3f59..9ef221e 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -13,6 +13,7 @@
 #include "utils/common.h"
 #include "utils/list.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "drivers/driver.h"
 #include "hostapd.h"
 #include "ap_drv_ops.h"
@@ -352,23 +353,13 @@
 }
 
 
-static int acs_usable_chan(struct hostapd_channel_data *chan)
-{
-	if (dl_list_empty(&chan->survey_list))
-		return 0;
-	if (chan->flag & HOSTAPD_CHAN_DISABLED)
-		return 0;
-	return 1;
-}
-
-
 static int acs_usable_ht40_chan(struct hostapd_channel_data *chan)
 {
 	const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149,
 				157, 184, 192 };
 	unsigned int i;
 
-	for (i = 0; i < sizeof(allowed) / sizeof(allowed[0]); i++)
+	for (i = 0; i < ARRAY_SIZE(allowed); i++)
 		if (chan->chan == allowed[i])
 			return 1;
 
@@ -398,28 +389,54 @@
 }
 
 
+static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
+{
+	struct freq_survey *survey;
+
+	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;
+		}
+	}
+
+	return 1;
+
+}
+
+
 static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
 {
 	int i;
 	struct hostapd_channel_data *chan;
-	struct freq_survey *survey;
+	int valid = 0;
 
 	for (i = 0; i < iface->current_mode->num_channels; i++) {
 		chan = &iface->current_mode->channels[i];
 		if (chan->flag & HOSTAPD_CHAN_DISABLED)
 			continue;
 
-		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_list_is_sufficient(chan))
+			continue;
+
+		valid++;
 	}
 
+	/* We need at least survey data for one channel */
+	return !!valid;
+}
+
+
+static int acs_usable_chan(struct hostapd_channel_data *chan)
+{
+	if (dl_list_empty(&chan->survey_list))
+		return 0;
+	if (chan->flag & HOSTAPD_CHAN_DISABLED)
+		return 0;
+	if (!acs_survey_list_is_sufficient(chan))
+		return 0;
 	return 1;
 }
 
@@ -456,7 +473,7 @@
 	for (i = 0; i < iface->current_mode->num_channels; i++) {
 		chan = &iface->current_mode->channels[i];
 
-		if (!acs_usable_chan(chan))
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
 			continue;
 
 		if (chan->freq == freq)
@@ -476,7 +493,8 @@
 static struct hostapd_channel_data *
 acs_find_ideal_chan(struct hostapd_iface *iface)
 {
-	struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL;
+	struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL,
+		*rand_chan = NULL;
 	long double factor, ideal_factor = 0;
 	int i, j;
 	int n_chans = 1;
@@ -508,9 +526,10 @@
 	for (i = 0; i < iface->current_mode->num_channels; i++) {
 		chan = &iface->current_mode->channels[i];
 
-		if (!acs_usable_chan(chan))
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
 			continue;
 
+
 		/* HT40 on 5 GHz has a limited set of primary channels as per
 		 * 11n Annex J */
 		if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
@@ -522,14 +541,17 @@
 			continue;
 		}
 
-		factor = chan->interference_factor;
+		factor = 0;
+		if (acs_usable_chan(chan))
+			factor = chan->interference_factor;
 
 		for (j = 1; j < n_chans; j++) {
 			adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
 			if (!adj_chan)
 				break;
 
-			factor += adj_chan->interference_factor;
+			if (acs_usable_chan(adj_chan))
+				factor += adj_chan->interference_factor;
 		}
 
 		if (j != n_chans) {
@@ -548,22 +570,22 @@
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) - 5);
-				if (adj_chan)
+				if (adj_chan && acs_usable_chan(adj_chan))
 					factor += adj_chan->interference_factor;
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) - 10);
-				if (adj_chan)
+				if (adj_chan && acs_usable_chan(adj_chan))
 					factor += adj_chan->interference_factor;
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) + 5);
-				if (adj_chan)
+				if (adj_chan && acs_usable_chan(adj_chan))
 					factor += adj_chan->interference_factor;
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) + 10);
-				if (adj_chan)
+				if (adj_chan && acs_usable_chan(adj_chan))
 					factor += adj_chan->interference_factor;
 			}
 		}
@@ -571,17 +593,24 @@
 		wpa_printf(MSG_DEBUG, "ACS:  * channel %d: total interference = %Lg",
 			   chan->chan, factor);
 
-		if (!ideal_chan || factor < ideal_factor) {
+		if (acs_usable_chan(chan) &&
+		    (!ideal_chan || factor < ideal_factor)) {
 			ideal_factor = factor;
 			ideal_chan = chan;
 		}
+
+		/* This channel would at least be usable */
+		if (!rand_chan)
+			rand_chan = chan;
 	}
 
-	if (ideal_chan)
+	if (ideal_chan) {
 		wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg",
 			   ideal_chan->chan, ideal_chan->freq, ideal_factor);
+		return ideal_chan;
+	}
 
-	return ideal_chan;
+	return rand_chan;
 }
 
 
@@ -655,6 +684,7 @@
 	ideal_chan = acs_find_ideal_chan(iface);
 	if (!ideal_chan) {
 		wpa_printf(MSG_ERROR, "ACS: Failed to compute ideal channel");
+		err = -1;
 		goto fail;
 	}
 
@@ -663,24 +693,20 @@
 	if (iface->conf->ieee80211ac)
 		acs_adjust_vht_center_freq(iface);
 
+	err = 0;
+fail:
 	/*
 	 * hostapd_setup_interface_complete() will return -1 on failure,
 	 * 0 on success and 0 is HOSTAPD_CHAN_VALID :)
 	 */
-	switch (hostapd_acs_completed(iface)) {
-	case HOSTAPD_CHAN_VALID:
+	if (hostapd_acs_completed(iface, err) == HOSTAPD_CHAN_VALID) {
 		acs_cleanup(iface);
 		return;
-	case HOSTAPD_CHAN_INVALID:
-	case HOSTAPD_CHAN_ACS:
-	default:
-		/* This can possibly happen if channel parameters (secondary
-		 * channel, center frequencies) are misconfigured */
-		wpa_printf(MSG_ERROR, "ACS: Possibly channel configuration is invalid, please report this along with your config file.");
-		goto fail;
 	}
 
-fail:
+	/* This can possibly happen if channel parameters (secondary
+	 * channel, center frequencies) are misconfigured */
+	wpa_printf(MSG_ERROR, "ACS: Possibly channel configuration is invalid, please report this along with your config file.");
 	acs_fail(iface);
 }
 
@@ -704,14 +730,17 @@
 		err = acs_request_scan(iface);
 		if (err) {
 			wpa_printf(MSG_ERROR, "ACS: Failed to request scan");
-			acs_fail(iface);
-			return;
+			goto fail;
 		}
 
 		return;
 	}
 
 	acs_study(iface);
+	return;
+fail:
+	hostapd_acs_completed(iface, 1);
+	acs_fail(iface);
 }
 
 
@@ -766,5 +795,8 @@
 	if (err < 0)
 		return HOSTAPD_CHAN_INVALID;
 
+	hostapd_set_state(iface, HAPD_IFACE_ACS);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_STARTED);
+
 	return HOSTAPD_CHAN_ACS;
 }
diff --git a/src/ap/acs.h b/src/ap/acs.h
index 0d1d0f1..a41f17f 100644
--- a/src/ap/acs.h
+++ b/src/ap/acs.h
@@ -13,7 +13,7 @@
 #ifdef CONFIG_ACS
 
 enum hostapd_chan_status acs_init(struct hostapd_iface *iface);
-int hostapd_acs_completed(struct hostapd_iface *iface);
+int hostapd_acs_completed(struct hostapd_iface *iface, int err);
 
 #else /* CONFIG_ACS */
 
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index caf75c4..65a6f12 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -130,6 +130,13 @@
 		os_free(bss);
 		return NULL;
 	}
+	conf->bss = os_calloc(1, sizeof(struct hostapd_bss_config *));
+	if (conf->bss == NULL) {
+		os_free(conf);
+		os_free(bss);
+		return NULL;
+	}
+	conf->bss[0] = bss;
 
 	bss->radius = os_zalloc(sizeof(*bss->radius));
 	if (bss->radius == NULL) {
@@ -141,7 +148,6 @@
 	hostapd_config_defaults_bss(bss);
 
 	conf->num_bss = 1;
-	conf->bss = bss;
 
 	conf->beacon_int = 100;
 	conf->rts_threshold = -1; /* use driver default: 2347 */
@@ -397,7 +403,7 @@
 }
 
 
-static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
+void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 {
 	struct hostapd_wpa_psk *psk, *prev;
 	struct hostapd_eap_user *user, *prev_user;
@@ -432,10 +438,12 @@
 	os_free(conf->accept_mac);
 	os_free(conf->deny_mac);
 	os_free(conf->nas_identifier);
-	hostapd_config_free_radius(conf->radius->auth_servers,
-				   conf->radius->num_auth_servers);
-	hostapd_config_free_radius(conf->radius->acct_servers,
-				   conf->radius->num_acct_servers);
+	if (conf->radius) {
+		hostapd_config_free_radius(conf->radius->auth_servers,
+					   conf->radius->num_auth_servers);
+		hostapd_config_free_radius(conf->radius->acct_servers,
+					   conf->radius->num_acct_servers);
+	}
 	hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
 	hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
 	os_free(conf->rsn_preauth_interfaces);
@@ -525,6 +533,8 @@
 	os_free(conf->sae_groups);
 
 	os_free(conf->server_id);
+
+	os_free(conf);
 }
 
 
@@ -540,7 +550,7 @@
 		return;
 
 	for (i = 0; i < conf->num_bss; i++)
-		hostapd_config_free_bss(&conf->bss[i]);
+		hostapd_config_free_bss(conf->bss[i]);
 	os_free(conf->bss);
 	os_free(conf->supported_rates);
 	os_free(conf->basic_rates);
@@ -658,3 +668,209 @@
 
 	return NULL;
 }
+
+
+static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+				    struct hostapd_config *conf)
+{
+	if (bss->ieee802_1x && !bss->eap_server &&
+	    !bss->radius->auth_servers) {
+		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
+			   "EAP authenticator configured).");
+		return -1;
+	}
+
+	if (bss->wpa) {
+		int wep, i;
+
+		wep = bss->default_wep_key_len > 0 ||
+		       bss->individual_wep_key_len > 0;
+		for (i = 0; i < NUM_WEP_KEYS; i++) {
+			if (bss->ssid.wep.keys_set) {
+				wep = 1;
+				break;
+			}
+		}
+
+		if (wep) {
+			wpa_printf(MSG_ERROR, "WEP configuration in a WPA network is not supported");
+			return -1;
+		}
+	}
+
+	if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+	    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+		wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
+			   "RADIUS checking (macaddr_acl=2) enabled.");
+		return -1;
+	}
+
+	if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
+	    bss->ssid.wpa_psk_file == NULL &&
+	    (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
+	     bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
+		wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
+			   "is not configured.");
+		return -1;
+	}
+
+	if (hostapd_mac_comp_empty(bss->bssid) != 0) {
+		size_t i;
+
+		for (i = 0; i < conf->num_bss; i++) {
+			if (conf->bss[i] != bss &&
+			    (hostapd_mac_comp(conf->bss[i]->bssid,
+					      bss->bssid) == 0)) {
+				wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
+					   " on interface '%s' and '%s'.",
+					   MAC2STR(bss->bssid),
+					   conf->bss[i]->iface, bss->iface);
+				return -1;
+			}
+		}
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
+	    (bss->nas_identifier == NULL ||
+	     os_strlen(bss->nas_identifier) < 1 ||
+	     os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
+		wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
+			   "nas_identifier to be configured as a 1..48 octet "
+			   "string");
+		return -1;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211N
+	if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
+			   "allowed, disabling HT capabilites");
+	}
+
+	if (conf->ieee80211n &&
+	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
+			   "allowed, disabling HT capabilities");
+	}
+
+	if (conf->ieee80211n && bss->wpa &&
+	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
+			   "requires CCMP/GCMP to be enabled, disabling HT "
+			   "capabilities");
+	}
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_WPS2
+	if (bss->wps_state && bss->ignore_broadcast_ssid) {
+		wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
+			   "configuration forced WPS to be disabled");
+		bss->wps_state = 0;
+	}
+
+	if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
+		wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
+			   "disabled");
+		bss->wps_state = 0;
+	}
+
+	if (bss->wps_state && bss->wpa &&
+	    (!(bss->wpa & 2) ||
+	     !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
+		wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
+			   "WPA2/CCMP forced WPS to be disabled");
+		bss->wps_state = 0;
+	}
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_HS20
+	if (bss->hs20 &&
+	    (!(bss->wpa & 2) ||
+	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
+		wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
+			   "configuration is required for Hotspot 2.0 "
+			   "functionality");
+		return -1;
+	}
+#endif /* CONFIG_HS20 */
+
+	return 0;
+}
+
+
+int hostapd_config_check(struct hostapd_config *conf)
+{
+	size_t i;
+
+	if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
+		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
+			   "setting the country_code");
+		return -1;
+	}
+
+	if (conf->ieee80211h && !conf->ieee80211d) {
+		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without "
+			   "IEEE 802.11d enabled");
+		return -1;
+	}
+
+	for (i = 0; i < conf->num_bss; i++) {
+		if (hostapd_config_check_bss(conf->bss[i], conf))
+			return -1;
+	}
+
+	return 0;
+}
+
+
+void hostapd_set_security_params(struct hostapd_bss_config *bss)
+{
+	if (bss->individual_wep_key_len == 0) {
+		/* individual keys are not use; can use key idx0 for
+		 * broadcast keys */
+		bss->broadcast_key_idx_min = 0;
+	}
+
+	if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
+		bss->rsn_pairwise = bss->wpa_pairwise;
+	bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
+						    bss->rsn_pairwise);
+
+	bss->radius->auth_server = bss->radius->auth_servers;
+	bss->radius->acct_server = bss->radius->acct_servers;
+
+	if (bss->wpa && bss->ieee802_1x) {
+		bss->ssid.security_policy = SECURITY_WPA;
+	} else if (bss->wpa) {
+		bss->ssid.security_policy = SECURITY_WPA_PSK;
+	} else if (bss->ieee802_1x) {
+		int cipher = WPA_CIPHER_NONE;
+		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+		bss->ssid.wep.default_len = bss->default_wep_key_len;
+		if (bss->default_wep_key_len)
+			cipher = bss->default_wep_key_len >= 13 ?
+				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else if (bss->ssid.wep.keys_set) {
+		int cipher = WPA_CIPHER_WEP40;
+		if (bss->ssid.wep.len[0] >= 13)
+			cipher = WPA_CIPHER_WEP104;
+		bss->ssid.security_policy = SECURITY_STATIC_WEP;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else {
+		bss->ssid.security_policy = SECURITY_PLAINTEXT;
+		bss->wpa_group = WPA_CIPHER_NONE;
+		bss->wpa_pairwise = WPA_CIPHER_NONE;
+		bss->rsn_pairwise = WPA_CIPHER_NONE;
+	}
+}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index c5531fa..09b2778 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -53,6 +53,8 @@
 	size_t ssid_len;
 	unsigned int ssid_set:1;
 	unsigned int utf8_ssid:1;
+	unsigned int wpa_passphrase_set:1;
+	unsigned int wpa_psk_set:1;
 
 	char vlan[IFNAMSIZ + 1];
 	secpolicy security_policy;
@@ -442,6 +444,9 @@
 	u16 gas_comeback_delay;
 	int gas_frag_limit;
 
+	u8 qos_map_set[16 + 2 * 21];
+	unsigned int qos_map_set_len;
+
 #ifdef CONFIG_HS20
 	int hs20;
 	int disable_dgaf;
@@ -464,6 +469,11 @@
 
 	unsigned int sae_anti_clogging_threshold;
 	int *sae_groups;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	u8 bss_load_test[5];
+	u8 bss_load_test_set;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 
@@ -471,7 +481,7 @@
  * struct hostapd_config - Per-radio interface configuration
  */
 struct hostapd_config {
-	struct hostapd_bss_config *bss, *last_bss;
+	struct hostapd_bss_config **bss, *last_bss;
 	size_t num_bss;
 
 	u16 beacon_int;
@@ -520,6 +530,7 @@
 	int ieee80211n;
 	int secondary_channel;
 	int require_ht;
+	int obss_interval;
 	u32 vht_capab;
 	int ieee80211ac;
 	int require_vht;
@@ -545,6 +556,7 @@
 int hostapd_mac_comp_empty(const void *a);
 struct hostapd_config * hostapd_config_defaults(void);
 void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
+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,
 			  const u8 *addr, int *vlan_id);
@@ -560,5 +572,7 @@
 					int vlan_id);
 struct hostapd_radius_attr *
 hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
+int hostapd_config_check(struct hostapd_config *conf);
+void hostapd_set_security_params(struct hostapd_bss_config *bss);
 
 #endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 3072562..0dc0600 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -286,7 +286,7 @@
 	char force_ifname[IFNAMSIZ];
 	u8 if_addr[ETH_ALEN];
 	return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
-			      NULL, NULL, force_ifname, if_addr, NULL);
+			      NULL, NULL, force_ifname, if_addr, NULL, 0);
 }
 
 
@@ -417,20 +417,21 @@
 int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		   const char *ifname, const u8 *addr, void *bss_ctx,
 		   void **drv_priv, char *force_ifname, u8 *if_addr,
-		   const char *bridge)
+		   const char *bridge, int use_existing)
 {
 	if (hapd->driver == NULL || hapd->driver->if_add == NULL)
 		return -1;
 	return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
 				    bss_ctx, drv_priv, force_ifname, if_addr,
-				    bridge);
+				    bridge, use_existing);
 }
 
 
 int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		      const char *ifname)
 {
-	if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
+	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+	    hapd->driver->if_remove == NULL)
 		return -1;
 	return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
 }
@@ -463,44 +464,50 @@
 }
 
 
-int hostapd_set_freq(struct hostapd_data *hapd, int 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)
+static int hostapd_set_freq_params(struct hostapd_freq_params *data, int 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)
 {
-	struct hostapd_freq_params data;
 	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;
+	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) {
+	if (data->vht_enabled) switch (vht_oper_chwidth) {
 	case VHT_CHANWIDTH_USE_HT:
 		if (center_segment1)
 			return -1;
-		if (5000 + center_segment0 * 5 != data.center_freq1)
+		if (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;
+		data->center_freq2 = 5000 + center_segment1 * 5;
 		/* fall through */
 	case VHT_CHANWIDTH_80MHZ:
-		data.bandwidth = 80;
+		data->bandwidth = 80;
 		if (vht_oper_chwidth == 1 && center_segment1)
 			return -1;
 		if (vht_oper_chwidth == 3 && !center_segment1)
@@ -510,13 +517,19 @@
 		/* primary 40 part must match the HT configuration */
 		tmp = (30 + freq - 5000 - center_segment0 * 5)/20;
 		tmp /= 2;
-		if (data.center_freq1 != 5000 +
+		if (data->center_freq1 != 5000 +
 					 center_segment0 * 5 - 20 + 40 * tmp)
 			return -1;
-		data.center_freq1 = 5000 + center_segment0 * 5;
+		data->center_freq1 = 5000 + center_segment0 * 5;
 		break;
 	case VHT_CHANWIDTH_160MHZ:
-		data.bandwidth = 160;
+		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)
@@ -524,12 +537,31 @@
 		/* primary 40 part must match the HT configuration */
 		tmp = (70 + freq - 5000 - center_segment0 * 5)/20;
 		tmp /= 2;
-		if (data.center_freq1 != 5000 +
+		if (data->center_freq1 != 5000 +
 					 center_segment0 * 5 - 60 + 40 * tmp)
 			return -1;
-		data.center_freq1 = 5000 + center_segment0 * 5;
+		data->center_freq1 = 5000 + center_segment0 * 5;
 		break;
 	}
+
+	return 0;
+}
+
+
+int hostapd_set_freq(struct hostapd_data *hapd, int 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)
+{
+	struct hostapd_freq_params data;
+
+	if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
+				    vht_enabled, sec_channel_offset,
+				    vht_oper_chwidth,
+				    center_segment0, center_segment1,
+				    hapd->iface->current_mode->vht_capab))
+		return -1;
+
 	if (hapd->driver == NULL)
 		return 0;
 	if (hapd->driver->set_freq == NULL)
@@ -699,3 +731,46 @@
 					 hapd->own_addr, hapd->own_addr, data,
 					 len, 0);
 }
+
+
+int hostapd_start_dfs_cac(struct hostapd_iface *iface, int 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)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	struct hostapd_freq_params data;
+	int res;
+
+	if (!hapd->driver || !hapd->driver->start_dfs_cac)
+		return 0;
+
+	if (!iface->conf->ieee80211h) {
+		wpa_printf(MSG_ERROR, "Can't start DFS CAC, DFS functionality "
+			   "is not enabled");
+		return -1;
+	}
+
+	if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
+				    vht_enabled, sec_channel_offset,
+				    vht_oper_chwidth, center_segment0,
+				    center_segment1,
+				    iface->current_mode->vht_capab))
+		return -1;
+
+	res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
+	if (!res)
+		iface->cac_started = 1;
+
+	return res;
+}
+
+
+int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
+			    const u8 *qos_map_set, u8 qos_map_set_len)
+{
+	if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL)
+		return 0;
+	return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
+					 qos_map_set_len);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 23277b6..1eab939 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -1,6 +1,6 @@
 /*
  * hostapd - Driver operations
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -48,7 +48,7 @@
 int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		   const char *ifname, const u8 *addr, void *bss_ctx,
 		   void **drv_priv, char *force_ifname, u8 *if_addr,
-		   const char *bridge);
+		   const char *bridge, int use_existing);
 int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		      const char *ifname);
 int hostapd_set_ieee8021x(struct hostapd_data *hapd,
@@ -101,6 +101,10 @@
 		      int reassoc, u16 status, const u8 *ie, size_t len);
 int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
 		      u8 *tspec_ie, size_t tspec_ielen);
+int hostapd_start_dfs_cac(struct hostapd_iface *iface, int 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);
 
 
 #include "drivers/driver.h"
@@ -109,6 +113,9 @@
 			 enum wnm_oper oper, const u8 *peer,
 			 u8 *buf, u16 *buf_len);
 
+int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
+			    u8 qos_map_set_len);
+
 static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
 						  int enabled)
 {
@@ -235,4 +242,28 @@
 	return hapd->driver->get_survey(hapd->drv_priv, freq);
 }
 
+static inline int hostapd_get_country(struct hostapd_data *hapd, char *alpha2)
+{
+	if (hapd->driver == NULL || hapd->driver->get_country == NULL)
+		return -1;
+	return hapd->driver->get_country(hapd->drv_priv, alpha2);
+}
+
+static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd)
+{
+	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+	    hapd->driver->get_radio_name == NULL)
+		return NULL;
+	return hapd->driver->get_radio_name(hapd->drv_priv);
+}
+
+static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
+					     struct csa_settings *settings)
+{
+	if (hapd->driver == NULL || hapd->driver->switch_channel == NULL)
+		return -ENOTSUP;
+
+	return hapd->driver->switch_channel(hapd->drv_priv, settings);
+}
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 2f4ba23..0e0dae4 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -38,6 +38,22 @@
 
 #ifdef NEED_AP_MLME
 
+static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->conf->bss_load_test_set) {
+		if (2 + 5 > len)
+			return eid;
+		*eid++ = WLAN_EID_BSS_LOAD;
+		*eid++ = 5;
+		os_memcpy(eid, hapd->conf->bss_load_test, 5);
+		eid += 5;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+	return eid;
+}
+
+
 static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
 {
 	u8 erp = 0;
@@ -187,13 +203,34 @@
 }
 
 
+static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 chan;
+
+	if (!hapd->iface->cs_freq)
+		return eid;
+
+	if (ieee80211_freq_to_chan(hapd->iface->cs_freq, &chan) ==
+	    NUM_HOSTAPD_MODES)
+		return eid;
+
+	*eid++ = WLAN_EID_CHANNEL_SWITCH;
+	*eid++ = 3;
+	*eid++ = hapd->iface->cs_block_tx;
+	*eid++ = chan;
+	*eid++ = hapd->iface->cs_count;
+
+	return eid;
+}
+
+
 static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 				   struct sta_info *sta,
 				   const struct ieee80211_mgmt *req,
 				   int is_p2p, size_t *resp_len)
 {
 	struct ieee80211_mgmt *resp;
-	u8 *pos, *epos;
+	u8 *pos, *epos, *old_pos;
 	size_t buflen;
 
 #define MAX_PROBERESP_LEN 768
@@ -251,6 +288,8 @@
 	/* RSN, MDIE, WPA */
 	pos = hostapd_eid_wpa(hapd, pos, epos - pos);
 
+	pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
+
 #ifdef CONFIG_IEEE80211N
 	pos = hostapd_eid_ht_capabilities(hapd, pos);
 	pos = hostapd_eid_ht_operation(hapd, pos);
@@ -265,6 +304,13 @@
 	pos = hostapd_eid_adv_proto(hapd, pos);
 	pos = hostapd_eid_roaming_consortium(hapd, pos);
 
+	old_pos = pos;
+	pos = hostapd_eid_csa(hapd, pos);
+
+	/* save an offset to the counter - should be last byte */
+	hapd->iface->cs_c_off_proberesp = (pos != old_pos) ?
+		pos - (u8 *) resp - 1 : 0;
+
 #ifdef CONFIG_IEEE80211AC
 	pos = hostapd_eid_vht_capabilities(hapd, pos);
 	pos = hostapd_eid_vht_operation(hapd, pos);
@@ -522,7 +568,7 @@
 		   is_broadcast_ether_addr(mgmt->da));
 
 	if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
-		perror("handle_probe_req: send");
+		wpa_printf(MSG_INFO, "handle_probe_req: send failed");
 
 	os_free(resp);
 
@@ -570,23 +616,17 @@
 #endif /* NEED_AP_MLME */
 
 
-void ieee802_11_set_beacon(struct hostapd_data *hapd)
+int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+			       struct wpa_driver_ap_params *params)
 {
 	struct ieee80211_mgmt *head = NULL;
 	u8 *tail = NULL;
 	size_t head_len = 0, tail_len = 0;
 	u8 *resp = NULL;
 	size_t resp_len = 0;
-	struct wpa_driver_ap_params params;
-	struct wpabuf *beacon, *proberesp, *assocresp;
 #ifdef NEED_AP_MLME
 	u16 capab_info;
-	u8 *pos, *tailpos;
-#endif /* NEED_AP_MLME */
-
-	hapd->beacon_set_done = 1;
-
-#ifdef NEED_AP_MLME
+	u8 *pos, *tailpos, *old_pos;
 
 #define BEACON_HEAD_BUF_SIZE 256
 #define BEACON_TAIL_BUF_SIZE 512
@@ -607,7 +647,7 @@
 		wpa_printf(MSG_ERROR, "Failed to set beacon data");
 		os_free(head);
 		os_free(tail);
-		return;
+		return -1;
 	}
 
 	head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -662,6 +702,9 @@
 	tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
 				  tailpos);
 
+	tailpos = hostapd_eid_bss_load(hapd, tailpos,
+				       tail + BEACON_TAIL_BUF_SIZE - tailpos);
+
 #ifdef CONFIG_IEEE80211N
 	tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
 	tailpos = hostapd_eid_ht_operation(hapd, tailpos);
@@ -678,6 +721,10 @@
 	tailpos = hostapd_eid_interworking(hapd, tailpos);
 	tailpos = hostapd_eid_adv_proto(hapd, tailpos);
 	tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
+	old_pos = tailpos;
+	tailpos = hostapd_eid_csa(hapd, tailpos);
+	hapd->iface->cs_c_off_beacon = (old_pos != tailpos) ?
+		tailpos - tail - 1 : 0;
 
 #ifdef CONFIG_IEEE80211AC
 	tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
@@ -723,84 +770,118 @@
 	resp = hostapd_probe_resp_offloads(hapd, &resp_len);
 #endif /* NEED_AP_MLME */
 
-	os_memset(&params, 0, sizeof(params));
-	params.head = (u8 *) head;
-	params.head_len = head_len;
-	params.tail = tail;
-	params.tail_len = tail_len;
-	params.proberesp = resp;
-	params.proberesp_len = resp_len;
-	params.dtim_period = hapd->conf->dtim_period;
-	params.beacon_int = hapd->iconf->beacon_int;
-	params.basic_rates = hapd->iface->basic_rates;
-	params.ssid = hapd->conf->ssid.ssid;
-	params.ssid_len = hapd->conf->ssid.ssid_len;
-	params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
+	os_memset(params, 0, sizeof(*params));
+	params->head = (u8 *) head;
+	params->head_len = head_len;
+	params->tail = tail;
+	params->tail_len = tail_len;
+	params->proberesp = resp;
+	params->proberesp_len = resp_len;
+	params->dtim_period = hapd->conf->dtim_period;
+	params->beacon_int = hapd->iconf->beacon_int;
+	params->basic_rates = hapd->iface->basic_rates;
+	params->ssid = hapd->conf->ssid.ssid;
+	params->ssid_len = hapd->conf->ssid.ssid_len;
+	params->pairwise_ciphers = hapd->conf->rsn_pairwise ?
 		hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
-	params.group_cipher = hapd->conf->wpa_group;
-	params.key_mgmt_suites = hapd->conf->wpa_key_mgmt;
-	params.auth_algs = hapd->conf->auth_algs;
-	params.wpa_version = hapd->conf->wpa;
-	params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+	params->group_cipher = hapd->conf->wpa_group;
+	params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
+	params->auth_algs = hapd->conf->auth_algs;
+	params->wpa_version = hapd->conf->wpa;
+	params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
 		(hapd->conf->ieee802_1x &&
 		 (hapd->conf->default_wep_key_len ||
 		  hapd->conf->individual_wep_key_len));
 	switch (hapd->conf->ignore_broadcast_ssid) {
 	case 0:
-		params.hide_ssid = NO_SSID_HIDING;
+		params->hide_ssid = NO_SSID_HIDING;
 		break;
 	case 1:
-		params.hide_ssid = HIDDEN_SSID_ZERO_LEN;
+		params->hide_ssid = HIDDEN_SSID_ZERO_LEN;
 		break;
 	case 2:
-		params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
+		params->hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
 		break;
 	}
-	hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp);
-	params.beacon_ies = beacon;
-	params.proberesp_ies = proberesp;
-	params.assocresp_ies = assocresp;
-	params.isolate = hapd->conf->isolate;
+	params->isolate = hapd->conf->isolate;
 #ifdef NEED_AP_MLME
-	params.cts_protect = !!(ieee802_11_erp_info(hapd) &
+	params->cts_protect = !!(ieee802_11_erp_info(hapd) &
 				ERP_INFO_USE_PROTECTION);
-	params.preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
+	params->preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
 		hapd->iconf->preamble == SHORT_PREAMBLE;
 	if (hapd->iface->current_mode &&
 	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
-		params.short_slot_time =
+		params->short_slot_time =
 			hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
 	else
-		params.short_slot_time = -1;
+		params->short_slot_time = -1;
 	if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
-		params.ht_opmode = -1;
+		params->ht_opmode = -1;
 	else
-		params.ht_opmode = hapd->iface->ht_op_mode;
+		params->ht_opmode = hapd->iface->ht_op_mode;
 #endif /* NEED_AP_MLME */
-	params.interworking = hapd->conf->interworking;
+	params->interworking = hapd->conf->interworking;
 	if (hapd->conf->interworking &&
 	    !is_zero_ether_addr(hapd->conf->hessid))
-		params.hessid = hapd->conf->hessid;
-	params.access_network_type = hapd->conf->access_network_type;
-	params.ap_max_inactivity = hapd->conf->ap_max_inactivity;
+		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_HS20
-	params.disable_dgaf = hapd->conf->disable_dgaf;
+	params->disable_dgaf = hapd->conf->disable_dgaf;
 #endif /* CONFIG_HS20 */
+	return 0;
+}
+
+
+void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
+{
+	os_free(params->tail);
+	params->tail = NULL;
+	os_free(params->head);
+	params->head = NULL;
+	os_free(params->proberesp);
+	params->proberesp = NULL;
+}
+
+
+void ieee802_11_set_beacon(struct hostapd_data *hapd)
+{
+	struct wpa_driver_ap_params params;
+	struct wpabuf *beacon, *proberesp, *assocresp;
+
+	if (hapd->iface->csa_in_progress) {
+		wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period");
+		return;
+	}
+
+	hapd->beacon_set_done = 1;
+
+	if (ieee802_11_build_ap_params(hapd, &params) < 0)
+		return;
+
+	if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
+	    0)
+		goto fail;
+
+	params.beacon_ies = beacon;
+	params.proberesp_ies = proberesp;
+	params.assocresp_ies = assocresp;
+
 	if (hostapd_drv_set_ap(hapd, &params))
 		wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
 	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
-
-	os_free(tail);
-	os_free(head);
-	os_free(resp);
+fail:
+	ieee802_11_free_ap_params(&params);
 }
 
 
 void ieee802_11_set_beacons(struct hostapd_iface *iface)
 {
 	size_t i;
-	for (i = 0; i < iface->num_bss; i++)
-		ieee802_11_set_beacon(iface->bss[i]);
+	for (i = 0; i < iface->num_bss; i++) {
+		if (iface->bss[i]->started)
+			ieee802_11_set_beacon(iface->bss[i]);
+	}
 }
 
 
@@ -809,7 +890,7 @@
 {
 	size_t i;
 	for (i = 0; i < iface->num_bss; i++)
-		if (iface->bss[i]->beacon_set_done)
+		if (iface->bss[i]->beacon_set_done && iface->bss[i]->started)
 			ieee802_11_set_beacon(iface->bss[i]);
 }
 
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index 37f10d2..a04a829 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -24,5 +24,8 @@
 void ieee802_11_set_beacon(struct hostapd_data *hapd);
 void ieee802_11_set_beacons(struct hostapd_iface *iface);
 void ieee802_11_update_beacons(struct hostapd_iface *iface);
+int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+			       struct wpa_driver_ap_params *params);
+void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
 
 #endif /* BEACON_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 1cb7e73..ac33068 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1,6 +1,6 @@
 /*
  * Control interface for shared AP commands
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -303,3 +303,123 @@
 
 	return 0;
 }
+
+
+int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
+			      size_t buflen)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	int len = 0, ret;
+	size_t i;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "state=%s\n"
+			  "phy=%s\n"
+			  "freq=%d\n"
+			  "num_sta_non_erp=%d\n"
+			  "num_sta_no_short_slot_time=%d\n"
+			  "num_sta_no_short_preamble=%d\n"
+			  "olbc=%d\n"
+			  "num_sta_ht_no_gf=%d\n"
+			  "num_sta_no_ht=%d\n"
+			  "num_sta_ht_20_mhz=%d\n"
+			  "olbc_ht=%d\n"
+			  "ht_op_mode=0x%x\n",
+			  hostapd_state_text(iface->state),
+			  iface->phy,
+			  iface->freq,
+			  iface->num_sta_non_erp,
+			  iface->num_sta_no_short_slot_time,
+			  iface->num_sta_no_short_preamble,
+			  iface->olbc,
+			  iface->num_sta_ht_no_gf,
+			  iface->num_sta_no_ht,
+			  iface->num_sta_ht_20mhz,
+			  iface->olbc_ht,
+			  iface->ht_op_mode);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "channel=%u\n"
+			  "secondary_channel=%d\n"
+			  "ieee80211n=%d\n"
+			  "ieee80211ac=%d\n"
+			  "vht_oper_chwidth=%d\n"
+			  "vht_oper_centr_freq_seg0_idx=%d\n"
+			  "vht_oper_centr_freq_seg1_idx=%d\n",
+			  iface->conf->channel,
+			  iface->conf->secondary_channel,
+			  iface->conf->ieee80211n,
+			  iface->conf->ieee80211ac,
+			  iface->conf->vht_oper_chwidth,
+			  iface->conf->vht_oper_centr_freq_seg0_idx,
+			  iface->conf->vht_oper_centr_freq_seg1_idx);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		struct hostapd_data *bss = iface->bss[i];
+		ret = os_snprintf(buf + len, buflen - len,
+				  "bss[%d]=%s\n"
+				  "bssid[%d]=" MACSTR "\n"
+				  "ssid[%d]=%s\n"
+				  "num_sta[%d]=%d\n",
+				  (int) i, bss->conf->iface,
+				  (int) i, MAC2STR(bss->own_addr),
+				  (int) i,
+				  wpa_ssid_txt(bss->conf->ssid.ssid,
+					       bss->conf->ssid.ssid_len),
+				  (int) i, bss->num_sta);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+	}
+
+	return len;
+}
+
+
+int hostapd_parse_csa_settings(const char *pos,
+			       struct csa_settings *settings)
+{
+	char *end;
+
+	if (!settings)
+		return -1;
+
+	os_memset(settings, 0, sizeof(*settings));
+	settings->cs_count = strtol(pos, &end, 10);
+	if (pos == end) {
+		wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
+		return -1;
+	}
+
+	settings->freq_params.freq = atoi(end);
+	if (settings->freq_params.freq == 0) {
+		wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
+		return -1;
+	}
+
+#define SET_CSA_SETTING(str) \
+	do { \
+		const char *pos2 = os_strstr(pos, " " #str "="); \
+		if (pos2) { \
+			pos2 += sizeof(" " #str "=") - 1; \
+			settings->freq_params.str = atoi(pos2); \
+		} \
+	} while (0)
+
+	SET_CSA_SETTING(center_freq1);
+	SET_CSA_SETTING(center_freq2);
+	SET_CSA_SETTING(bandwidth);
+	SET_CSA_SETTING(sec_channel_offset);
+	settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
+	settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
+	settings->block_tx = !!os_strstr(pos, " blocktx");
+#undef SET_CSA_SETTING
+
+	return 0;
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index e83f894..ee58b4c 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -1,6 +1,6 @@
 /*
  * Control interface for shared AP commands
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -19,5 +19,10 @@
 				      const char *txtaddr);
 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
 				    const char *txtaddr);
+int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
+			      size_t buflen);
+int hostapd_parse_csa_settings(const char *pos,
+			       struct csa_settings *settings);
+
 
 #endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
new file mode 100644
index 0000000..0a909f4
--- /dev/null
+++ b/src/ap/dfs.c
@@ -0,0 +1,711 @@
+/*
+ * DFS - Dynamic Frequency Selection
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "hostapd.h"
+#include "ap_drv_ops.h"
+#include "drivers/driver.h"
+#include "dfs.h"
+
+
+static int dfs_get_used_n_chans(struct hostapd_iface *iface)
+{
+	int n_chans = 1;
+
+	if (iface->conf->ieee80211n && iface->conf->secondary_channel)
+		n_chans = 2;
+
+	if (iface->conf->ieee80211ac) {
+		switch (iface->conf->vht_oper_chwidth) {
+		case VHT_CHANWIDTH_USE_HT:
+			break;
+		case VHT_CHANWIDTH_80MHZ:
+			n_chans = 4;
+			break;
+		case VHT_CHANWIDTH_160MHZ:
+			n_chans = 8;
+			break;
+		default:
+			break;
+		}
+	}
+
+	return n_chans;
+}
+
+
+static int dfs_channel_available(struct hostapd_channel_data *chan)
+{
+	if (chan->flag & HOSTAPD_CHAN_DISABLED)
+		return 0;
+	if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
+	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
+	     HOSTAPD_CHAN_DFS_UNAVAILABLE))
+		return 0;
+	return 1;
+}
+
+
+static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
+{
+	/*
+	 * The tables contain first valid channel number based on channel width.
+	 * We will also choose this first channel as the control one.
+	 */
+	int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+			     184, 192 };
+	/*
+	 * VHT80, valid channels based on center frequency:
+	 * 42, 58, 106, 122, 138, 155
+	 */
+	int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
+	int *allowed = allowed_40;
+	unsigned int i, allowed_no = 0;
+
+	switch (n_chans) {
+	case 2:
+		allowed = allowed_40;
+		allowed_no = ARRAY_SIZE(allowed_40);
+		break;
+	case 4:
+		allowed = allowed_80;
+		allowed_no = ARRAY_SIZE(allowed_80);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
+		break;
+	}
+
+	for (i = 0; i < allowed_no; i++) {
+		if (chan->chan == allowed[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
+				    int first_chan_idx, int num_chans)
+{
+	struct hostapd_channel_data *first_chan, *chan;
+	int i;
+
+	if (first_chan_idx + num_chans >= mode->num_channels)
+		return 0;
+
+	first_chan = &mode->channels[first_chan_idx];
+
+	for (i = 0; i < num_chans; i++) {
+		chan = &mode->channels[first_chan_idx + i];
+
+		if (first_chan->freq + i * 20 != chan->freq)
+			return 0;
+
+		if (!dfs_channel_available(chan))
+			return 0;
+	}
+
+	return 1;
+}
+
+
+/*
+ * The function assumes HT40+ operation.
+ * Make sure to adjust the following variables after calling this:
+ *  - hapd->secondary_channel
+ *  - hapd->vht_oper_centr_freq_seg0_idx
+ *  - hapd->vht_oper_centr_freq_seg1_idx
+ */
+static int dfs_find_channel(struct hostapd_iface *iface,
+			    struct hostapd_channel_data **ret_chan,
+			    int idx)
+{
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *chan;
+	int i, channel_idx = 0, n_chans;
+
+	mode = iface->current_mode;
+	n_chans = dfs_get_used_n_chans(iface);
+
+	wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
+	for (i = 0; i < mode->num_channels; i++) {
+		chan = &mode->channels[i];
+
+		/* Skip HT40/VHT incompatible channels */
+		if (iface->conf->ieee80211n &&
+		    iface->conf->secondary_channel &&
+		    !dfs_is_chan_allowed(chan, n_chans))
+			continue;
+
+		/* Skip incompatible chandefs */
+		if (!dfs_chan_range_available(mode, i, n_chans))
+			continue;
+
+		if (ret_chan && idx == channel_idx) {
+			wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
+			*ret_chan = chan;
+			return idx;
+		}
+		wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
+		channel_idx++;
+	}
+	return channel_idx;
+}
+
+
+static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
+				       struct hostapd_channel_data *chan,
+				       u8 *vht_oper_centr_freq_seg0_idx,
+				       u8 *vht_oper_centr_freq_seg1_idx)
+{
+	if (!iface->conf->ieee80211ac)
+		return;
+
+	if (!chan)
+		return;
+
+	*vht_oper_centr_freq_seg1_idx = 0;
+
+	switch (iface->conf->vht_oper_chwidth) {
+	case VHT_CHANWIDTH_USE_HT:
+		if (iface->conf->secondary_channel == 1)
+			*vht_oper_centr_freq_seg0_idx = chan->chan + 2;
+		else if (iface->conf->secondary_channel == -1)
+			*vht_oper_centr_freq_seg0_idx = chan->chan - 2;
+		else
+			*vht_oper_centr_freq_seg0_idx = chan->chan;
+		break;
+	case VHT_CHANWIDTH_80MHZ:
+		*vht_oper_centr_freq_seg0_idx = chan->chan + 6;
+		break;
+	case VHT_CHANWIDTH_160MHZ:
+		*vht_oper_centr_freq_seg0_idx = chan->chan + 14;
+		break;
+	default:
+		wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
+		break;
+	}
+
+	wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
+		   *vht_oper_centr_freq_seg0_idx,
+		   *vht_oper_centr_freq_seg1_idx);
+}
+
+
+/* Return start channel idx we will use for mode->channels[idx] */
+static int dfs_get_start_chan_idx(struct hostapd_iface *iface)
+{
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *chan;
+	int channel_no = iface->conf->channel;
+	int res = -1, i;
+
+	/* HT40- */
+	if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
+		channel_no -= 4;
+
+	/* VHT */
+	if (iface->conf->ieee80211ac) {
+		switch (iface->conf->vht_oper_chwidth) {
+		case VHT_CHANWIDTH_USE_HT:
+			break;
+		case VHT_CHANWIDTH_80MHZ:
+			channel_no =
+				iface->conf->vht_oper_centr_freq_seg0_idx - 6;
+			break;
+		case VHT_CHANWIDTH_160MHZ:
+			channel_no =
+				iface->conf->vht_oper_centr_freq_seg0_idx - 14;
+			break;
+		default:
+			wpa_printf(MSG_INFO,
+				   "DFS only VHT20/40/80/160 is supported now");
+			channel_no = -1;
+			break;
+		}
+	}
+
+	/* Get idx */
+	mode = iface->current_mode;
+	for (i = 0; i < mode->num_channels; i++) {
+		chan = &mode->channels[i];
+		if (chan->chan == channel_no) {
+			res = i;
+			break;
+		}
+	}
+
+	if (res == -1)
+		wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong: -1");
+
+	return res;
+}
+
+
+/* At least one channel have radar flag */
+static int dfs_check_chans_radar(struct hostapd_iface *iface,
+				 int start_chan_idx, int n_chans)
+{
+	struct hostapd_channel_data *channel;
+	struct hostapd_hw_modes *mode;
+	int i, res = 0;
+
+	mode = iface->current_mode;
+
+	for (i = 0; i < n_chans; i++) {
+		channel = &mode->channels[start_chan_idx + i];
+		if (channel->flag & HOSTAPD_CHAN_RADAR)
+			res++;
+	}
+
+	return res;
+}
+
+
+/* All channels available */
+static int dfs_check_chans_available(struct hostapd_iface *iface,
+				     int start_chan_idx, int n_chans)
+{
+	struct hostapd_channel_data *channel;
+	struct hostapd_hw_modes *mode;
+	int i;
+
+	mode = iface->current_mode;
+
+	for(i = 0; i < n_chans; i++) {
+		channel = &mode->channels[start_chan_idx + i];
+		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
+		    HOSTAPD_CHAN_DFS_AVAILABLE)
+			break;
+	}
+
+	return i == n_chans;
+}
+
+
+/* At least one channel unavailable */
+static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
+				       int start_chan_idx,
+				       int n_chans)
+{
+	struct hostapd_channel_data *channel;
+	struct hostapd_hw_modes *mode;
+	int i, res = 0;
+
+	mode = iface->current_mode;
+
+	for(i = 0; i < n_chans; i++) {
+		channel = &mode->channels[start_chan_idx + i];
+		if (channel->flag & HOSTAPD_CHAN_DISABLED)
+			res++;
+		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
+		    HOSTAPD_CHAN_DFS_UNAVAILABLE)
+			res++;
+	}
+
+	return res;
+}
+
+
+static struct hostapd_channel_data *
+dfs_get_valid_channel(struct hostapd_iface *iface,
+		      int *secondary_channel,
+		      u8 *vht_oper_centr_freq_seg0_idx,
+		      u8 *vht_oper_centr_freq_seg1_idx)
+{
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *chan = NULL;
+	int num_available_chandefs;
+	int chan_idx;
+	u32 _rand;
+
+	wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
+
+	if (iface->current_mode == NULL)
+		return NULL;
+
+	mode = iface->current_mode;
+	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+		return NULL;
+
+	/* Get the count first */
+	num_available_chandefs = dfs_find_channel(iface, NULL, 0);
+	if (num_available_chandefs == 0)
+		return NULL;
+
+	os_get_random((u8 *) &_rand, sizeof(_rand));
+	chan_idx = _rand % num_available_chandefs;
+	dfs_find_channel(iface, &chan, chan_idx);
+
+	/* dfs_find_channel() calculations assume HT40+ */
+	if (iface->conf->secondary_channel)
+		*secondary_channel = 1;
+	else
+		*secondary_channel = 0;
+
+	dfs_adjust_vht_center_freq(iface, chan,
+				   vht_oper_centr_freq_seg0_idx,
+				   vht_oper_centr_freq_seg1_idx);
+
+	return chan;
+}
+
+
+static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
+{
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *chan = NULL;
+	int i;
+
+	mode = iface->current_mode;
+	if (mode == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
+	for (i = 0; i < iface->current_mode->num_channels; i++) {
+		chan = &iface->current_mode->channels[i];
+		if (chan->freq == freq) {
+			if (chan->flag & HOSTAPD_CHAN_RADAR) {
+				chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
+				chan->flag |= state;
+				return 1; /* Channel found */
+			}
+		}
+	}
+	wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
+	return 0;
+}
+
+
+static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
+			 int chan_offset, int chan_width, int cf1,
+			 int cf2, u32 state)
+{
+	int n_chans = 1, i;
+	struct hostapd_hw_modes *mode;
+	int frequency = freq;
+	int ret = 0;
+
+	mode = iface->current_mode;
+	if (mode == NULL)
+		return 0;
+
+	if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
+		wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
+		return 0;
+	}
+
+	/* Seems cf1 and chan_width is enough here */
+	switch (chan_width) {
+	case CHAN_WIDTH_20_NOHT:
+	case CHAN_WIDTH_20:
+		n_chans = 1;
+		if (frequency == 0)
+			frequency = cf1;
+		break;
+	case CHAN_WIDTH_40:
+		n_chans = 2;
+		frequency = cf1 - 10;
+		break;
+	case CHAN_WIDTH_80:
+		n_chans = 4;
+		frequency = cf1 - 30;
+		break;
+	case CHAN_WIDTH_160:
+		n_chans = 8;
+		frequency = cf1 - 70;
+		break;
+	default:
+		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
+			   chan_width);
+		break;
+	}
+
+	wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
+		   n_chans);
+	for (i = 0; i < n_chans; i++) {
+		ret += set_dfs_state_freq(iface, frequency, state);
+		frequency = frequency + 20;
+	}
+
+	return ret;
+}
+
+
+static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
+				       int chan_width, int cf1, int cf2)
+{
+	int start_chan_idx;
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *chan;
+	int n_chans, i, j, frequency = freq, radar_n_chans = 1;
+	u8 radar_chan;
+	int res = 0;
+
+	/* Our configuration */
+	mode = iface->current_mode;
+	start_chan_idx = dfs_get_start_chan_idx(iface);
+	n_chans = dfs_get_used_n_chans(iface);
+
+	/* Check we are on DFS channel(s) */
+	if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
+		return 0;
+
+	/* Reported via radar event */
+	switch (chan_width) {
+	case CHAN_WIDTH_20_NOHT:
+	case CHAN_WIDTH_20:
+		radar_n_chans = 1;
+		if (frequency == 0)
+			frequency = cf1;
+		break;
+	case CHAN_WIDTH_40:
+		radar_n_chans = 2;
+		frequency = cf1 - 10;
+		break;
+	case CHAN_WIDTH_80:
+		radar_n_chans = 4;
+		frequency = cf1 - 30;
+		break;
+	case CHAN_WIDTH_160:
+		radar_n_chans = 8;
+		frequency = cf1 - 70;
+		break;
+	default:
+		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
+			   chan_width);
+		break;
+	}
+
+	ieee80211_freq_to_chan(frequency, &radar_chan);
+
+	for (i = 0; i < n_chans; i++) {
+		chan = &mode->channels[start_chan_idx + i];
+		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
+			continue;
+		for (j = 0; j < radar_n_chans; j++) {
+			wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
+				   chan->chan, radar_chan + j * 4);
+			if (chan->chan == radar_chan + j * 4)
+				res++;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "overlapped: %d", res);
+
+	return res;
+}
+
+
+/*
+ * Main DFS handler
+ * 1 - continue channel/ap setup
+ * 0 - channel/ap setup will be continued after CAC
+ * -1 - hit critical error
+ */
+int hostapd_handle_dfs(struct hostapd_iface *iface)
+{
+	struct hostapd_channel_data *channel;
+	int res, n_chans, start_chan_idx;
+
+	iface->cac_started = 0;
+
+	do {
+		/* Get start (first) channel for current configuration */
+		start_chan_idx = dfs_get_start_chan_idx(iface);
+		if (start_chan_idx == -1)
+			return -1;
+
+		/* Get number of used channels, depend on width */
+		n_chans = dfs_get_used_n_chans(iface);
+
+		/* Check if any of configured channels require DFS */
+		res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
+		wpa_printf(MSG_DEBUG,
+			   "DFS %d channels required radar detection",
+			   res);
+		if (!res)
+			return 1;
+
+		/* Check if all channels are DFS available */
+		res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
+		wpa_printf(MSG_DEBUG,
+			   "DFS all channels available, (SKIP CAC): %s",
+			   res ? "yes" : "no");
+		if (res)
+			return 1;
+
+		/* Check if any of configured channels is unavailable */
+		res = dfs_check_chans_unavailable(iface, start_chan_idx,
+						  n_chans);
+		wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
+			   res, res ? "yes": "no");
+		if (res) {
+			int sec;
+			u8 cf1, cf2;
+
+			channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2);
+			if (!channel) {
+				wpa_printf(MSG_ERROR, "could not get valid channel");
+				return -1;
+			}
+
+			iface->freq = channel->freq;
+			iface->conf->channel = channel->chan;
+			iface->conf->secondary_channel = sec;
+			iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
+			iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
+		}
+	} while (res);
+
+	/* Finally start CAC */
+	hostapd_set_state(iface, HAPD_IFACE_DFS);
+	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
+		"freq=%d chan=%d sec_chan=%d",
+		iface->freq,
+		iface->conf->channel, iface->conf->secondary_channel);
+	if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+				  iface->freq,
+				  iface->conf->channel,
+				  iface->conf->ieee80211n,
+				  iface->conf->ieee80211ac,
+				  iface->conf->secondary_channel,
+				  iface->conf->vht_oper_chwidth,
+				  iface->conf->vht_oper_centr_freq_seg0_idx,
+				  iface->conf->vht_oper_centr_freq_seg1_idx)) {
+		wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
+			     int ht_enabled, int chan_offset, int chan_width,
+			     int cf1, int cf2)
+{
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
+		"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+		success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
+	if (success) {
+		/* Complete iface/ap configuration */
+		set_dfs_state(iface, freq, ht_enabled, chan_offset,
+			      chan_width, cf1, cf2,
+			      HOSTAPD_CHAN_DFS_AVAILABLE);
+		iface->cac_started = 0;
+		hostapd_setup_interface_complete(iface, 0);
+	}
+
+	return 0;
+}
+
+
+static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
+{
+	struct hostapd_channel_data *channel;
+	int err = 1;
+	int secondary_channel;
+	u8 vht_oper_centr_freq_seg0_idx;
+	u8 vht_oper_centr_freq_seg1_idx;
+
+	wpa_printf(MSG_DEBUG, "%s called", __func__);
+	channel = dfs_get_valid_channel(iface, &secondary_channel,
+					&vht_oper_centr_freq_seg0_idx,
+					&vht_oper_centr_freq_seg1_idx);
+	if (channel) {
+		wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
+			   channel->chan);
+		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+			"freq=%d chan=%d sec_chan=%d", channel->freq,
+			channel->chan, secondary_channel);
+
+		iface->freq = channel->freq;
+		iface->conf->channel = channel->chan;
+		iface->conf->secondary_channel = secondary_channel;
+		iface->conf->vht_oper_centr_freq_seg0_idx =
+			vht_oper_centr_freq_seg0_idx;
+		iface->conf->vht_oper_centr_freq_seg1_idx =
+			vht_oper_centr_freq_seg1_idx;
+		err = 0;
+	} else {
+		wpa_printf(MSG_ERROR, "No valid channel available");
+	}
+
+	if (iface->cac_started) {
+		wpa_printf(MSG_DEBUG, "DFS radar detected during CAC");
+		iface->cac_started = 0;
+		/* FIXME: Wait for channel(s) to become available if no channel
+		 * has been found */
+		hostapd_setup_interface_complete(iface, err);
+		return err;
+	}
+
+	if (err) {
+		/* FIXME: Wait for channel(s) to become available */
+		hostapd_disable_iface(iface);
+		return err;
+	}
+
+	wpa_printf(MSG_DEBUG, "DFS radar detected");
+	hostapd_disable_iface(iface);
+	hostapd_enable_iface(iface);
+	return 0;
+}
+
+
+int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
+			       int ht_enabled, int chan_offset, int chan_width,
+			       int cf1, int cf2)
+{
+	int res;
+
+	if (!iface->conf->ieee80211h)
+		return 0;
+
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
+		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
+	/* mark radar frequency as invalid */
+	res = set_dfs_state(iface, freq, ht_enabled, chan_offset,
+			    chan_width, cf1, cf2,
+			    HOSTAPD_CHAN_DFS_UNAVAILABLE);
+
+	/* Skip if reported radar event not overlapped our channels */
+	res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
+	if (!res)
+		return 0;
+
+	/* radar detected while operating, switch the channel. */
+	res = hostapd_dfs_start_channel_switch(iface);
+
+	return res;
+}
+
+
+int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
+			     int ht_enabled, int chan_offset, int chan_width,
+			     int cf1, int cf2)
+{
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
+		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+	/* TODO add correct implementation here */
+	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
+	return 0;
+}
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
new file mode 100644
index 0000000..859ff79
--- /dev/null
+++ b/src/ap/dfs.h
@@ -0,0 +1,25 @@
+/*
+ * DFS - Dynamic Frequency Selection
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef DFS_H
+#define DFS_H
+
+int hostapd_handle_dfs(struct hostapd_iface *iface);
+
+int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
+			     int ht_enabled, int chan_offset, int chan_width,
+			     int cf1, int cf2);
+int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
+			       int ht_enabled,
+			       int chan_offset, int chan_width,
+			       int cf1, int cf2);
+int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
+			     int ht_enabled,
+			     int chan_offset, int chan_width, int cf1, int cf2);
+
+#endif /* DFS_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index d6bc98d..1b69ba8 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -29,6 +29,7 @@
 #include "ap_drv_ops.h"
 #include "ap_config.h"
 #include "hw_features.h"
+#include "dfs.h"
 
 
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -114,6 +115,13 @@
 	}
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_INTERWORKING
+	if (elems.ext_capab && elems.ext_capab_len > 4) {
+		if (elems.ext_capab[4] & 0x01)
+			sta->qos_map_enabled = 1;
+	}
+#endif /* CONFIG_INTERWORKING */
+
 #ifdef CONFIG_HS20
 	wpabuf_free(sta->hs20_ie);
 	if (elems.hs20 && elems.hs20_len > 4) {
@@ -395,6 +403,13 @@
 	hapd->iconf->channel = channel;
 	hapd->iconf->ieee80211n = ht;
 	hapd->iconf->secondary_channel = offset;
+
+	if (hapd->iface->csa_in_progress && freq == hapd->iface->cs_freq) {
+		hostapd_cleanup_cs_params(hapd);
+
+		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d",
+			freq);
+	}
 #endif /* NEED_AP_MLME */
 }
 
@@ -785,6 +800,50 @@
 }
 
 
+#ifdef NEED_AP_MLME
+
+static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
+					     struct dfs_event *radar)
+{
+	wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
+	hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled,
+				   radar->chan_offset, radar->chan_width,
+				   radar->cf1, radar->cf2);
+}
+
+
+static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd,
+					   struct dfs_event *radar)
+{
+	wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
+	hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled,
+				 radar->chan_offset, radar->chan_width,
+				 radar->cf1, radar->cf2);
+}
+
+
+static void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd,
+					  struct dfs_event *radar)
+{
+	wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
+	hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled,
+				 radar->chan_offset, radar->chan_width,
+				 radar->cf1, radar->cf2);
+}
+
+
+static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd,
+					   struct dfs_event *radar)
+{
+	wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
+	hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled,
+				 radar->chan_offset, radar->chan_width,
+				 radar->cf1, radar->cf2);
+}
+
+#endif /* NEED_AP_MLME */
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
@@ -929,6 +988,36 @@
 	case EVENT_SURVEY:
 		hostapd_event_get_survey(hapd, &data->survey_results);
 		break;
+#ifdef NEED_AP_MLME
+	case EVENT_DFS_RADAR_DETECTED:
+		if (!data)
+			break;
+		hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
+		break;
+	case EVENT_DFS_CAC_FINISHED:
+		if (!data)
+			break;
+		hostapd_event_dfs_cac_finished(hapd, &data->dfs_event);
+		break;
+	case EVENT_DFS_CAC_ABORTED:
+		if (!data)
+			break;
+		hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event);
+		break;
+	case EVENT_DFS_NOP_FINISHED:
+		if (!data)
+			break;
+		hostapd_event_dfs_nop_finished(hapd, &data->dfs_event);
+		break;
+	case EVENT_CHANNEL_LIST_CHANGED:
+		/* channel list changed (regulatory?), update channel list */
+		/* TODO: check this. hostapd_get_hw_features() initializes
+		 * too much stuff. */
+		/* hostapd_get_hw_features(hapd->iface); */
+		hostapd_channel_list_updated(
+			hapd->iface, data->channel_list_changed.initiator);
+		break;
+#endif /* NEED_AP_MLME */
 	default:
 		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
 		break;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index b3574ba..8349c4d 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -46,6 +46,8 @@
 		 * it to be that long.
 		 */
 		ap_sta_session_timeout(hapd, sta, 5);
+	} else {
+		ap_sta_replenish_timeout(hapd, sta, 5);
 	}
 
 	if (sta->gas_dialog == NULL) {
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index fd1ca2b..69e8956 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / Initialization and configuration
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -11,6 +11,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "radius/radius_client.h"
 #include "radius/radius_das.h"
 #include "drivers/driver.h"
@@ -32,11 +33,14 @@
 #include "ap_config.h"
 #include "p2p_hostapd.h"
 #include "gas_serv.h"
+#include "dfs.h"
 
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
 static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
 static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
+static int setup_interface2(struct hostapd_iface *iface);
+static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
 
 extern int wpa_debug_level;
 extern struct wpa_driver_ops *wpa_drivers[];
@@ -61,10 +65,22 @@
 
 static void hostapd_reload_bss(struct hostapd_data *hapd)
 {
+	struct hostapd_ssid *ssid;
+
 #ifndef CONFIG_NO_RADIUS
 	radius_client_reconfig(hapd->radius, hapd->conf->radius);
 #endif /* CONFIG_NO_RADIUS */
 
+	ssid = &hapd->conf->ssid;
+	if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next &&
+	    ssid->wpa_passphrase_set && ssid->wpa_passphrase) {
+		/*
+		 * Force PSK to be derived again since SSID or passphrase may
+		 * have changed.
+		 */
+		os_free(ssid->wpa_psk);
+		ssid->wpa_psk = NULL;
+	}
 	if (hostapd_setup_wpa_psk(hapd->conf)) {
 		wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
 			   "after reloading configuration");
@@ -159,7 +175,7 @@
 	for (j = 0; j < iface->num_bss; j++) {
 		hapd = iface->bss[j];
 		hapd->iconf = newconf;
-		hapd->conf = &newconf->bss[j];
+		hapd->conf = newconf->bss[j];
 		hostapd_reload_bss(hapd);
 	}
 
@@ -227,6 +243,14 @@
 
 static void hostapd_free_hapd_data(struct hostapd_data *hapd)
 {
+	if (!hapd->started) {
+		wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started",
+			   __func__, hapd->conf->iface);
+		return;
+	}
+	hapd->started = 0;
+
+	wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
 	iapp_deinit(hapd->iapp);
 	hapd->iapp = NULL;
 	accounting_deinit(hapd);
@@ -278,13 +302,13 @@
  * @hapd: Pointer to BSS data
  *
  * This function is used to free all per-BSS data structures and resources.
- * This gets called in a loop for each BSS between calls to
- * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
- * is deinitialized. Most of the modules that are initialized in
- * hostapd_setup_bss() are deinitialized here.
+ * Most of the modules that are initialized in hostapd_setup_bss() are
+ * deinitialized here.
  */
 static void hostapd_cleanup(struct hostapd_data *hapd)
 {
+	wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
+		   hapd->conf->iface);
 	if (hapd->iface->interfaces &&
 	    hapd->iface->interfaces->ctrl_iface_deinit)
 		hapd->iface->interfaces->ctrl_iface_deinit(hapd);
@@ -292,20 +316,9 @@
 }
 
 
-/**
- * hostapd_cleanup_iface_pre - Preliminary per-interface cleanup
- * @iface: Pointer to interface data
- *
- * This function is called before per-BSS data structures are deinitialized
- * with hostapd_cleanup().
- */
-static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
-{
-}
-
-
 static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
 {
+	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
 	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
 	iface->hw_features = NULL;
 	os_free(iface->current_rates);
@@ -325,12 +338,16 @@
  */
 static void hostapd_cleanup_iface(struct hostapd_iface *iface)
 {
+	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+
 	hostapd_cleanup_iface_partial(iface);
 	hostapd_config_free(iface->conf);
 	iface->conf = NULL;
 
 	os_free(iface->config_fname);
 	os_free(iface->bss);
+	wpa_printf(MSG_DEBUG, "%s: free iface=%p", __func__, iface);
 	os_free(iface);
 }
 
@@ -429,7 +446,7 @@
 	/* Determine the bits necessary to any configured BSSIDs,
 	   if they are higher than the number of BSSIDs. */
 	for (j = 0; j < iface->conf->num_bss; j++) {
-		if (hostapd_mac_comp_empty(iface->conf->bss[j].bssid) == 0) {
+		if (hostapd_mac_comp_empty(iface->conf->bss[j]->bssid) == 0) {
 			if (j)
 				auto_addr++;
 			continue;
@@ -437,7 +454,7 @@
 
 		for (i = 0; i < ETH_ALEN; i++) {
 			mask[i] |=
-				iface->conf->bss[j].bssid[i] ^
+				iface->conf->bss[j]->bssid[i] ^
 				hapd->own_addr[i];
 		}
 	}
@@ -502,7 +519,7 @@
 	size_t i;
 
 	for (i = 0; i < conf->num_bss; i++) {
-		if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) {
+		if (hostapd_mac_comp(conf->bss[i]->bssid, a) == 0) {
 			return 1;
 		}
 	}
@@ -596,7 +613,8 @@
 /**
  * hostapd_setup_bss - Per-BSS setup (initialization)
  * @hapd: Pointer to BSS data
- * @first: Whether this BSS is the first BSS of an interface
+ * @first: Whether this BSS is the first BSS of an interface; -1 = not first,
+ *	but interface may exist
  *
  * This function is used to initialize all per-BSS data structures and
  * resources. This gets called in a loop for each BSS when an interface is
@@ -611,7 +629,17 @@
 	char force_ifname[IFNAMSIZ];
 	u8 if_addr[ETH_ALEN];
 
-	if (!first) {
+	wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)",
+		   __func__, hapd, hapd->conf->iface, first);
+
+	if (hapd->started) {
+		wpa_printf(MSG_ERROR, "%s: Interface %s was already started",
+			   __func__, hapd->conf->iface);
+		return -1;
+	}
+	hapd->started = 1;
+
+	if (!first || first == -1) {
 		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
 			/* Allocate the next available BSSID. */
 			do {
@@ -636,7 +664,7 @@
 				   hapd->conf->iface, hapd->own_addr, hapd,
 				   &hapd->drv_priv, force_ifname, if_addr,
 				   hapd->conf->bridge[0] ? hapd->conf->bridge :
-				   NULL)) {
+				   NULL, first == -1)) {
 			wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
 				   MACSTR ")", MAC2STR(hapd->own_addr));
 			return -1;
@@ -768,14 +796,14 @@
 		wpa_printf(MSG_ERROR, "GAS server initialization failed");
 		return -1;
 	}
-#endif /* CONFIG_INTERWORKING */
 
-	if (hapd->iface->interfaces &&
-	    hapd->iface->interfaces->ctrl_iface_init &&
-	    hapd->iface->interfaces->ctrl_iface_init(hapd)) {
-		wpa_printf(MSG_ERROR, "Failed to setup control interface");
+	if (conf->qos_map_set_len &&
+	    hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
+				    conf->qos_map_set_len)) {
+		wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
 		return -1;
 	}
+#endif /* CONFIG_INTERWORKING */
 
 	if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
 		wpa_printf(MSG_ERROR, "VLAN initialization failed.");
@@ -849,14 +877,15 @@
 
 	if (hapd->iface->drv_max_acl_mac_addrs == 0)
 		return;
-	if (!(conf->bss->num_accept_mac || conf->bss->num_deny_mac))
+	if (!(conf->bss[0]->num_accept_mac || conf->bss[0]->num_deny_mac))
 		return;
 
-	if (conf->bss->macaddr_acl == DENY_UNLESS_ACCEPTED) {
-		if (conf->bss->num_accept_mac) {
+	if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
+		if (conf->bss[0]->num_accept_mac) {
 			accept_acl = 1;
-			err = hostapd_set_acl_list(hapd, conf->bss->accept_mac,
-						   conf->bss->num_accept_mac,
+			err = hostapd_set_acl_list(hapd,
+						   conf->bss[0]->accept_mac,
+						   conf->bss[0]->num_accept_mac,
 						   accept_acl);
 			if (err) {
 				wpa_printf(MSG_DEBUG, "Failed to set accept acl");
@@ -865,11 +894,11 @@
 		} else {
 			wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
 		}
-	} else if (conf->bss->macaddr_acl == ACCEPT_UNLESS_DENIED) {
-		if (conf->bss->num_deny_mac) {
+	} else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
+		if (conf->bss[0]->num_deny_mac) {
 			accept_acl = 0;
-			err = hostapd_set_acl_list(hapd, conf->bss->deny_mac,
-						   conf->bss->num_deny_mac,
+			err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
+						   conf->bss[0]->num_deny_mac,
 						   accept_acl);
 			if (err) {
 				wpa_printf(MSG_DEBUG, "Failed to set deny acl");
@@ -882,11 +911,85 @@
 }
 
 
+static int start_ctrl_iface_bss(struct hostapd_data *hapd)
+{
+	if (!hapd->iface->interfaces ||
+	    !hapd->iface->interfaces->ctrl_iface_init)
+		return 0;
+
+	if (hapd->iface->interfaces->ctrl_iface_init(hapd)) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to setup control interface for %s",
+			   hapd->conf->iface);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int start_ctrl_iface(struct hostapd_iface *iface)
+{
+	size_t i;
+
+	if (!iface->interfaces || !iface->interfaces->ctrl_iface_init)
+		return 0;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		struct hostapd_data *hapd = iface->bss[i];
+		if (iface->interfaces->ctrl_iface_init(hapd)) {
+			wpa_printf(MSG_ERROR,
+				   "Failed to setup control interface for %s",
+				   hapd->conf->iface);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_iface *iface = eloop_ctx;
+
+	if (!iface->wait_channel_update) {
+		wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it");
+		return;
+	}
+
+	/*
+	 * It is possible that the existing channel list is acceptable, so try
+	 * to proceed.
+	 */
+	wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway");
+	setup_interface2(iface);
+}
+
+
+void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator)
+{
+	if (!iface->wait_channel_update || initiator != REGDOM_SET_BY_USER)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Channel list updated - continue setup");
+	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+	setup_interface2(iface);
+}
+
+
 static int setup_interface(struct hostapd_iface *iface)
 {
 	struct hostapd_data *hapd = iface->bss[0];
 	size_t i;
-	char country[4];
+
+	if (!iface->phy[0]) {
+		const char *phy = hostapd_drv_get_radio_name(hapd);
+		if (phy) {
+			wpa_printf(MSG_DEBUG, "phy: %s", phy);
+			os_strlcpy(iface->phy, phy, sizeof(iface->phy));
+		}
+	}
 
 	/*
 	 * Make sure that all BSSes get configured with a pointer to the same
@@ -900,15 +1003,49 @@
 	if (hostapd_validate_bssid_configuration(iface))
 		return -1;
 
+	/*
+	 * Initialize control interfaces early to allow external monitoring of
+	 * channel setup operations that may take considerable amount of time
+	 * especially for DFS cases.
+	 */
+	if (start_ctrl_iface(iface))
+		return -1;
+
 	if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
+		char country[4], previous_country[4];
+
+		hostapd_set_state(iface, HAPD_IFACE_COUNTRY_UPDATE);
+		if (hostapd_get_country(hapd, previous_country) < 0)
+			previous_country[0] = '\0';
+
 		os_memcpy(country, hapd->iconf->country, 3);
 		country[3] = '\0';
 		if (hostapd_set_country(hapd, country) < 0) {
 			wpa_printf(MSG_ERROR, "Failed to set country code");
 			return -1;
 		}
+
+		wpa_printf(MSG_DEBUG, "Previous country code %s, new country code %s",
+			   previous_country, country);
+
+		if (os_strncmp(previous_country, country, 2) != 0) {
+			wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update");
+			iface->wait_channel_update = 1;
+			eloop_register_timeout(1, 0,
+					       channel_list_update_timeout,
+					       iface, NULL);
+			return 0;
+		}
 	}
 
+	return setup_interface2(iface);
+}
+
+
+static int setup_interface2(struct hostapd_iface *iface)
+{
+	iface->wait_channel_update = 0;
+
 	if (hostapd_get_hw_features(iface)) {
 		/* Not all drivers support this yet, so continue without hw
 		 * feature data. */
@@ -931,11 +1068,22 @@
 				   "be completed in a callback");
 			return 0;
 		}
+
+		if (iface->conf->ieee80211h)
+			wpa_printf(MSG_DEBUG, "DFS support is enabled");
 	}
 	return hostapd_setup_interface_complete(iface, 0);
 }
 
 
+/**
+ * hostapd_setup_interface_complete - Complete interface setup
+ *
+ * This function is called when previous steps in the interface setup has been
+ * completed. This can also start operations, e.g., DFS, that will require
+ * additional processing before interface is ready to be enabled. Such
+ * operations will call this function from eloop callbacks when finished.
+ */
 int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
 {
 	struct hostapd_data *hapd = iface->bss[0];
@@ -944,17 +1092,30 @@
 
 	if (err) {
 		wpa_printf(MSG_ERROR, "Interface initialization failed");
-		eloop_terminate();
+		hostapd_set_state(iface, HAPD_IFACE_DISABLED);
+		if (iface->interfaces && iface->interfaces->terminate_on_error)
+			eloop_terminate();
 		return -1;
 	}
 
 	wpa_printf(MSG_DEBUG, "Completing interface initialization");
-	if (hapd->iconf->channel) {
-		iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
+	if (iface->conf->channel) {
+#ifdef NEED_AP_MLME
+		int res;
+#endif /* NEED_AP_MLME */
+
+		iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
 		wpa_printf(MSG_DEBUG, "Mode: %s  Channel: %d  "
 			   "Frequency: %d MHz",
-			   hostapd_hw_mode_txt(hapd->iconf->hw_mode),
-			   hapd->iconf->channel, iface->freq);
+			   hostapd_hw_mode_txt(iface->conf->hw_mode),
+			   iface->conf->channel, iface->freq);
+
+#ifdef NEED_AP_MLME
+		/* Check DFS */
+		res = hostapd_handle_dfs(iface);
+		if (res <= 0)
+			return res;
+#endif /* NEED_AP_MLME */
 
 		if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
 				     hapd->iconf->channel,
@@ -1006,6 +1167,7 @@
 		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
 			prev_addr = hapd->own_addr;
 	}
+	hapd = iface->bss[0];
 
 	hostapd_tx_queue_params(iface);
 
@@ -1030,11 +1192,15 @@
 			return -1;
 	}
 
+	hostapd_set_state(iface, HAPD_IFACE_ENABLED);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
 	if (hapd->setup_complete_cb)
 		hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
 
 	wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
 		   iface->bss[0]->conf->iface);
+	if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
+		iface->interfaces->terminate_on_error--;
 
 	return 0;
 }
@@ -1049,6 +1215,12 @@
  * and sets driver parameters based on the configuration.
  * Flushes old stations, sets the channel, encryption,
  * beacons, and WDS links based on the configuration.
+ *
+ * If interface setup requires more time, e.g., to perform HT co-ex scans, ACS,
+ * or DFS operations, this function returns 0 before such operations have been
+ * completed. The pending operations are registered into eloop and will be
+ * completed from eloop callbacks. Those callbacks end up calling
+ * hostapd_setup_interface_complete() once setup has been completed.
  */
 int hostapd_setup_interface(struct hostapd_iface *iface)
 {
@@ -1098,44 +1270,259 @@
 }
 
 
+static void hostapd_bss_deinit(struct hostapd_data *hapd)
+{
+	wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
+		   hapd->conf->iface);
+	hostapd_free_stas(hapd);
+	hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+	hostapd_clear_wep(hapd);
+	hostapd_cleanup(hapd);
+}
+
+
 void hostapd_interface_deinit(struct hostapd_iface *iface)
 {
-	size_t j;
+	int j;
 
+	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
 	if (iface == NULL)
 		return;
 
-	hostapd_cleanup_iface_pre(iface);
-	for (j = 0; j < iface->num_bss; j++) {
-		struct hostapd_data *hapd = iface->bss[j];
-		hostapd_free_stas(hapd);
-		hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
-		hostapd_clear_wep(hapd);
-		hostapd_cleanup(hapd);
-	}
+	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+	iface->wait_channel_update = 0;
+
+	for (j = iface->num_bss - 1; j >= 0; j--)
+		hostapd_bss_deinit(iface->bss[j]);
 }
 
 
 void hostapd_interface_free(struct hostapd_iface *iface)
 {
 	size_t j;
-	for (j = 0; j < iface->num_bss; j++)
+	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+	for (j = 0; j < iface->num_bss; j++) {
+		wpa_printf(MSG_DEBUG, "%s: free hapd %p",
+			   __func__, iface->bss[j]);
 		os_free(iface->bss[j]);
+	}
 	hostapd_cleanup_iface(iface);
 }
 
 
-#ifdef HOSTAPD
+/**
+ * hostapd_init - Allocate and initialize per-interface data
+ * @config_file: Path to the configuration file
+ * Returns: Pointer to the allocated interface data or %NULL on failure
+ *
+ * This function is used to allocate main data structures for per-interface
+ * data. The allocated data buffer will be freed by calling
+ * hostapd_cleanup_iface().
+ */
+struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
+				    const char *config_file)
+{
+	struct hostapd_iface *hapd_iface = NULL;
+	struct hostapd_config *conf = NULL;
+	struct hostapd_data *hapd;
+	size_t i;
+
+	hapd_iface = os_zalloc(sizeof(*hapd_iface));
+	if (hapd_iface == NULL)
+		goto fail;
+
+	hapd_iface->config_fname = os_strdup(config_file);
+	if (hapd_iface->config_fname == NULL)
+		goto fail;
+
+	conf = interfaces->config_read_cb(hapd_iface->config_fname);
+	if (conf == NULL)
+		goto fail;
+	hapd_iface->conf = conf;
+
+	hapd_iface->num_bss = conf->num_bss;
+	hapd_iface->bss = os_calloc(conf->num_bss,
+				    sizeof(struct hostapd_data *));
+	if (hapd_iface->bss == NULL)
+		goto fail;
+
+	for (i = 0; i < conf->num_bss; i++) {
+		hapd = hapd_iface->bss[i] =
+			hostapd_alloc_bss_data(hapd_iface, conf,
+					       conf->bss[i]);
+		if (hapd == NULL)
+			goto fail;
+		hapd->msg_ctx = hapd;
+	}
+
+	return hapd_iface;
+
+fail:
+	wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
+		   config_file);
+	if (conf)
+		hostapd_config_free(conf);
+	if (hapd_iface) {
+		os_free(hapd_iface->config_fname);
+		os_free(hapd_iface->bss);
+		wpa_printf(MSG_DEBUG, "%s: free iface %p",
+			   __func__, hapd_iface);
+		os_free(hapd_iface);
+	}
+	return NULL;
+}
+
+
+static int ifname_in_use(struct hapd_interfaces *interfaces, const char *ifname)
+{
+	size_t i, j;
+
+	for (i = 0; i < interfaces->count; i++) {
+		struct hostapd_iface *iface = interfaces->iface[i];
+		for (j = 0; j < iface->num_bss; j++) {
+			struct hostapd_data *hapd = iface->bss[j];
+			if (os_strcmp(ifname, hapd->conf->iface) == 0)
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ * hostapd_interface_init_bss - Read configuration file and init BSS data
+ *
+ * This function is used to parse configuration file for a BSS. This BSS is
+ * added to an existing interface sharing the same radio (if any) or a new
+ * interface is created if this is the first interface on a radio. This
+ * allocate memory for the BSS. No actual driver operations are started.
+ *
+ * This is similar to hostapd_interface_init(), but for a case where the
+ * configuration is used to add a single BSS instead of all BSSes for a radio.
+ */
+struct hostapd_iface *
+hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+			   const char *config_fname, int debug)
+{
+	struct hostapd_iface *new_iface = NULL, *iface = NULL;
+	struct hostapd_data *hapd;
+	int k;
+	size_t i, bss_idx;
+
+	if (!phy || !*phy)
+		return NULL;
+
+	for (i = 0; i < interfaces->count; i++) {
+		if (os_strcmp(interfaces->iface[i]->phy, phy) == 0) {
+			iface = interfaces->iface[i];
+			break;
+		}
+	}
+
+	wpa_printf(MSG_INFO, "Configuration file: %s (phy %s)%s",
+		   config_fname, phy, iface ? "" : " --> new PHY");
+	if (iface) {
+		struct hostapd_config *conf;
+		struct hostapd_bss_config **tmp_conf;
+		struct hostapd_data **tmp_bss;
+		struct hostapd_bss_config *bss;
+		const char *ifname;
+
+		/* Add new BSS to existing iface */
+		conf = interfaces->config_read_cb(config_fname);
+		if (conf == NULL)
+			return NULL;
+		if (conf->num_bss > 1) {
+			wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config");
+			hostapd_config_free(conf);
+			return NULL;
+		}
+
+		ifname = conf->bss[0]->iface;
+		if (ifname[0] != '\0' && ifname_in_use(interfaces, ifname)) {
+			wpa_printf(MSG_ERROR,
+				   "Interface name %s already in use", ifname);
+			hostapd_config_free(conf);
+			return NULL;
+		}
+
+		tmp_conf = os_realloc_array(
+			iface->conf->bss, iface->conf->num_bss + 1,
+			sizeof(struct hostapd_bss_config *));
+		tmp_bss = os_realloc_array(iface->bss, iface->num_bss + 1,
+					   sizeof(struct hostapd_data *));
+		if (tmp_bss)
+			iface->bss = tmp_bss;
+		if (tmp_conf) {
+			iface->conf->bss = tmp_conf;
+			iface->conf->last_bss = tmp_conf[0];
+		}
+		if (tmp_bss == NULL || tmp_conf == NULL) {
+			hostapd_config_free(conf);
+			return NULL;
+		}
+		bss = iface->conf->bss[iface->conf->num_bss] = conf->bss[0];
+		iface->conf->num_bss++;
+
+		hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
+		if (hapd == NULL) {
+			iface->conf->num_bss--;
+			hostapd_config_free(conf);
+			return NULL;
+		}
+		iface->conf->last_bss = bss;
+		iface->bss[iface->num_bss] = hapd;
+		hapd->msg_ctx = hapd;
+
+		bss_idx = iface->num_bss++;
+		conf->num_bss--;
+		conf->bss[0] = NULL;
+		hostapd_config_free(conf);
+	} else {
+		/* Add a new iface with the first BSS */
+		new_iface = iface = hostapd_init(interfaces, config_fname);
+		if (!iface)
+			return NULL;
+		os_strlcpy(iface->phy, phy, sizeof(iface->phy));
+		iface->interfaces = interfaces;
+		bss_idx = 0;
+	}
+
+	for (k = 0; k < debug; k++) {
+		if (iface->bss[bss_idx]->conf->logger_stdout_level > 0)
+			iface->bss[bss_idx]->conf->logger_stdout_level--;
+	}
+
+	if (iface->conf->bss[bss_idx]->iface[0] == '\0' &&
+	    !hostapd_drv_none(iface->bss[bss_idx])) {
+		wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+			   config_fname);
+		if (new_iface)
+			hostapd_interface_deinit_free(new_iface);
+		return NULL;
+	}
+
+	return iface;
+}
+
 
 void hostapd_interface_deinit_free(struct hostapd_iface *iface)
 {
 	const struct wpa_driver_ops *driver;
 	void *drv_priv;
+
+	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
 	if (iface == NULL)
 		return;
+	wpa_printf(MSG_DEBUG, "%s: num_bss=%u conf->num_bss=%u",
+		   __func__, (unsigned int) iface->num_bss,
+		   (unsigned int) iface->conf->num_bss);
 	driver = iface->bss[0]->driver;
 	drv_priv = iface->bss[0]->drv_priv;
 	hostapd_interface_deinit(iface);
+	wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
+		   __func__, driver, drv_priv);
 	if (driver && driver->hapd_deinit && drv_priv)
 		driver->hapd_deinit(drv_priv);
 	hostapd_interface_free(iface);
@@ -1146,20 +1533,33 @@
 {
 	if (hapd_iface->bss[0]->drv_priv != NULL) {
 		wpa_printf(MSG_ERROR, "Interface %s already enabled",
-			   hapd_iface->conf->bss[0].iface);
+			   hapd_iface->conf->bss[0]->iface);
 		return -1;
 	}
 
 	wpa_printf(MSG_DEBUG, "Enable interface %s",
-		   hapd_iface->conf->bss[0].iface);
+		   hapd_iface->conf->bss[0]->iface);
 
 	if (hapd_iface->interfaces == NULL ||
 	    hapd_iface->interfaces->driver_init == NULL ||
-	    hapd_iface->interfaces->driver_init(hapd_iface) ||
-	    hostapd_setup_interface(hapd_iface)) {
-		hostapd_interface_deinit_free(hapd_iface);
+	    hapd_iface->interfaces->driver_init(hapd_iface))
+		return -1;
+
+	if (hostapd_setup_interface(hapd_iface)) {
+		const struct wpa_driver_ops *driver;
+		void *drv_priv;
+
+		driver = hapd_iface->bss[0]->driver;
+		drv_priv = hapd_iface->bss[0]->drv_priv;
+		wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
+			   __func__, driver, drv_priv);
+		if (driver && driver->hapd_deinit && drv_priv) {
+			driver->hapd_deinit(drv_priv);
+			hapd_iface->bss[0]->drv_priv = NULL;
+		}
 		return -1;
 	}
+
 	return 0;
 }
 
@@ -1169,19 +1569,17 @@
 	size_t j;
 
 	wpa_printf(MSG_DEBUG, "Reload interface %s",
-		   hapd_iface->conf->bss[0].iface);
-	for (j = 0; j < hapd_iface->num_bss; j++) {
-		hostapd_flush_old_stations(hapd_iface->bss[j],
-					   WLAN_REASON_PREV_AUTH_NOT_VALID);
-
-#ifndef CONFIG_NO_RADIUS
-		/* TODO: update dynamic data based on changed configuration
-		 * items (e.g., open/close sockets, etc.) */
-		radius_client_flush(hapd_iface->bss[j]->radius, 0);
-#endif  /* CONFIG_NO_RADIUS */
-
-		hostapd_reload_bss(hapd_iface->bss[j]);
+		   hapd_iface->conf->bss[0]->iface);
+	for (j = 0; j < hapd_iface->num_bss; j++)
+		hostapd_set_security_params(hapd_iface->conf->bss[j]);
+	if (hostapd_config_check(hapd_iface->conf) < 0) {
+		wpa_printf(MSG_ERROR, "Updated configuration is invalid");
+		return -1;
 	}
+	hostapd_clear_old(hapd_iface);
+	for (j = 0; j < hapd_iface->num_bss; j++)
+		hostapd_reload_bss(hapd_iface->bss[j]);
+
 	return 0;
 }
 
@@ -1189,13 +1587,12 @@
 int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
 {
 	size_t j;
-	struct hostapd_bss_config *bss;
 	const struct wpa_driver_ops *driver;
 	void *drv_priv;
 
 	if (hapd_iface == NULL)
 		return -1;
-	bss = hapd_iface->bss[0]->conf;
+	wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
 	driver = hapd_iface->bss[0]->driver;
 	drv_priv = hapd_iface->bss[0]->drv_priv;
 
@@ -1208,6 +1605,8 @@
 		hostapd_free_hapd_data(hapd);
 	}
 
+	wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
+		   __func__, driver, drv_priv);
 	if (driver && driver->hapd_deinit && drv_priv) {
 		driver->hapd_deinit(drv_priv);
 		hapd_iface->bss[0]->drv_priv = NULL;
@@ -1217,11 +1616,10 @@
 	 * hostapd_setup_interface and hostapd_setup_interface_complete
 	 */
 	hostapd_cleanup_iface_partial(hapd_iface);
-	bss->wpa = 0;
-	bss->wpa_key_mgmt = -1;
-	bss->wpa_pairwise = -1;
 
-	wpa_printf(MSG_DEBUG, "Interface %s disabled", bss->iface);
+	wpa_printf(MSG_DEBUG, "Interface %s disabled",
+		   hapd_iface->bss[0]->conf->iface);
+	hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED);
 	return 0;
 }
 
@@ -1272,7 +1670,7 @@
 		return NULL;
 	}
 
-	bss = conf->last_bss = conf->bss;
+	bss = conf->last_bss = conf->bss[0];
 
 	os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
 	bss->ctrl_interface = os_strdup(ctrl_iface);
@@ -1307,8 +1705,7 @@
 
 	for (i = 0; i < conf->num_bss; i++) {
 		hapd = hapd_iface->bss[i] =
-			hostapd_alloc_bss_data(hapd_iface, conf,
-					       &conf->bss[i]);
+			hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]);
 		if (hapd == NULL)
 			return NULL;
 		hapd->msg_ctx = hapd;
@@ -1323,17 +1720,83 @@
 int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
 {
 	struct hostapd_config *conf = NULL;
-	struct hostapd_iface *hapd_iface = NULL;
+	struct hostapd_iface *hapd_iface = NULL, *new_iface = NULL;
+	struct hostapd_data *hapd;
 	char *ptr;
-	size_t i;
+	size_t i, j;
+	const char *conf_file = NULL, *phy_name = NULL;
+
+	if (os_strncmp(buf, "bss_config=", 11) == 0) {
+		char *pos;
+		phy_name = buf + 11;
+		pos = os_strchr(phy_name, ':');
+		if (!pos)
+			return -1;
+		*pos++ = '\0';
+		conf_file = pos;
+		if (!os_strlen(conf_file))
+			return -1;
+
+		hapd_iface = hostapd_interface_init_bss(interfaces, phy_name,
+							conf_file, 0);
+		if (!hapd_iface)
+			return -1;
+		for (j = 0; j < interfaces->count; j++) {
+			if (interfaces->iface[j] == hapd_iface)
+				break;
+		}
+		if (j == interfaces->count) {
+			struct hostapd_iface **tmp;
+			tmp = os_realloc_array(interfaces->iface,
+					       interfaces->count + 1,
+					       sizeof(struct hostapd_iface *));
+			if (!tmp) {
+				hostapd_interface_deinit_free(hapd_iface);
+				return -1;
+			}
+			interfaces->iface = tmp;
+			interfaces->iface[interfaces->count++] = hapd_iface;
+			new_iface = hapd_iface;
+		}
+
+		if (new_iface) {
+			if (interfaces->driver_init(hapd_iface) ||
+			    hostapd_setup_interface(hapd_iface)) {
+				interfaces->count--;
+				goto fail;
+			}
+		} else {
+			/* Assign new BSS with bss[0]'s driver info */
+			hapd = hapd_iface->bss[hapd_iface->num_bss - 1];
+			hapd->driver = hapd_iface->bss[0]->driver;
+			hapd->drv_priv = hapd_iface->bss[0]->drv_priv;
+			os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr,
+				  ETH_ALEN);
+
+			if (start_ctrl_iface_bss(hapd) < 0 ||
+			    (hapd_iface->state == HAPD_IFACE_ENABLED &&
+			     hostapd_setup_bss(hapd, -1))) {
+				hapd_iface->conf->num_bss--;
+				hapd_iface->num_bss--;
+				wpa_printf(MSG_DEBUG, "%s: free hapd %p %s",
+					   __func__, hapd, hapd->conf->iface);
+				os_free(hapd);
+				return -1;
+			}
+		}
+		return 0;
+	}
 
 	ptr = os_strchr(buf, ' ');
 	if (ptr == NULL)
 		return -1;
 	*ptr++ = '\0';
 
+	if (os_strncmp(ptr, "config=", 7) == 0)
+		conf_file = ptr + 7;
+
 	for (i = 0; i < interfaces->count; i++) {
-		if (!os_strcmp(interfaces->iface[i]->conf->bss[0].iface,
+		if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface,
 			       buf)) {
 			wpa_printf(MSG_INFO, "Cannot add interface - it "
 				   "already exists");
@@ -1348,8 +1811,14 @@
 		goto fail;
 	}
 
-	conf = hostapd_config_alloc(interfaces, buf, ptr);
-	if (conf == NULL) {
+	if (conf_file && interfaces->config_read_cb) {
+		conf = interfaces->config_read_cb(conf_file);
+		if (conf && conf->bss)
+			os_strlcpy(conf->bss[0]->iface, buf,
+				   sizeof(conf->bss[0]->iface));
+	} else
+		conf = hostapd_config_alloc(interfaces, buf, ptr);
+	if (conf == NULL || conf->bss == NULL) {
 		wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
 			   "for configuration", __func__);
 		goto fail;
@@ -1362,14 +1831,10 @@
 		goto fail;
 	}
 
-	if (hapd_iface->interfaces &&
-	    hapd_iface->interfaces->ctrl_iface_init &&
-	    hapd_iface->interfaces->ctrl_iface_init(hapd_iface->bss[0])) {
-		wpa_printf(MSG_ERROR, "%s: Failed to setup control "
-			   "interface", __func__);
+	if (start_ctrl_iface(hapd_iface) < 0)
 		goto fail;
-	}
-	wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0].iface);
+
+	wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0]->iface);
 
 	return 0;
 
@@ -1377,23 +1842,71 @@
 	if (conf)
 		hostapd_config_free(conf);
 	if (hapd_iface) {
-		os_free(hapd_iface->bss[interfaces->count]);
+		if (hapd_iface->bss) {
+			for (i = 0; i < hapd_iface->num_bss; i++) {
+				hapd = hapd_iface->bss[i];
+				if (hapd && hapd_iface->interfaces &&
+				    hapd_iface->interfaces->ctrl_iface_deinit)
+					hapd_iface->interfaces->
+						ctrl_iface_deinit(hapd);
+				wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
+					   __func__, hapd_iface->bss[i],
+					hapd_iface->bss[i]->conf->iface);
+				os_free(hapd_iface->bss[i]);
+			}
+			os_free(hapd_iface->bss);
+		}
+		wpa_printf(MSG_DEBUG, "%s: free iface %p",
+			   __func__, hapd_iface);
 		os_free(hapd_iface);
 	}
 	return -1;
 }
 
 
+static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx)
+{
+	size_t i;
+
+	wpa_printf(MSG_INFO, "Remove BSS '%s'", iface->conf->bss[idx]->iface);
+
+	/* Remove hostapd_data only if it has already been initialized */
+	if (idx < iface->num_bss) {
+		struct hostapd_data *hapd = iface->bss[idx];
+
+		hostapd_bss_deinit(hapd);
+		wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
+			   __func__, hapd, hapd->conf->iface);
+		hostapd_config_free_bss(hapd->conf);
+		os_free(hapd);
+
+		iface->num_bss--;
+
+		for (i = idx; i < iface->num_bss; i++)
+			iface->bss[i] = iface->bss[i + 1];
+	} else {
+		hostapd_config_free_bss(iface->conf->bss[idx]);
+		iface->conf->bss[idx] = NULL;
+	}
+
+	iface->conf->num_bss--;
+	for (i = idx; i < iface->conf->num_bss; i++)
+		iface->conf->bss[i] = iface->conf->bss[i + 1];
+
+	return 0;
+}
+
+
 int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
 {
 	struct hostapd_iface *hapd_iface;
-	size_t i, k = 0;
+	size_t i, j, k = 0;
 
 	for (i = 0; i < interfaces->count; i++) {
 		hapd_iface = interfaces->iface[i];
 		if (hapd_iface == NULL)
 			return -1;
-		if (!os_strcmp(hapd_iface->conf->bss[0].iface, buf)) {
+		if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
 			wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
 			hostapd_interface_deinit_free(hapd_iface);
 			k = i;
@@ -1405,12 +1918,15 @@
 			interfaces->count--;
 			return 0;
 		}
+
+		for (j = 0; j < hapd_iface->conf->num_bss; j++) {
+			if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf))
+				return hostapd_remove_bss(hapd_iface, j);
+		}
 	}
 	return -1;
 }
 
-#endif /* HOSTAPD */
-
 
 /**
  * hostapd_new_assoc_sta - Notify that a new station associated with the AP
@@ -1472,3 +1988,262 @@
 	eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
 			       ap_handle_timer, hapd, sta);
 }
+
+
+const char * hostapd_state_text(enum hostapd_iface_state s)
+{
+	switch (s) {
+	case HAPD_IFACE_UNINITIALIZED:
+		return "UNINITIALIZED";
+	case HAPD_IFACE_DISABLED:
+		return "DISABLED";
+	case HAPD_IFACE_COUNTRY_UPDATE:
+		return "COUNTRY_UPDATE";
+	case HAPD_IFACE_ACS:
+		return "ACS";
+	case HAPD_IFACE_HT_SCAN:
+		return "HT_SCAN";
+	case HAPD_IFACE_DFS:
+		return "DFS";
+	case HAPD_IFACE_ENABLED:
+		return "ENABLED";
+	}
+
+	return "UNKNOWN";
+}
+
+
+void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
+{
+	wpa_printf(MSG_INFO, "%s: interface state %s->%s",
+		   iface->conf->bss[0]->iface, hostapd_state_text(iface->state),
+		   hostapd_state_text(s));
+	iface->state = s;
+}
+
+
+#ifdef NEED_AP_MLME
+
+static void free_beacon_data(struct beacon_data *beacon)
+{
+	os_free(beacon->head);
+	beacon->head = NULL;
+	os_free(beacon->tail);
+	beacon->tail = NULL;
+	os_free(beacon->probe_resp);
+	beacon->probe_resp = NULL;
+	os_free(beacon->beacon_ies);
+	beacon->beacon_ies = NULL;
+	os_free(beacon->proberesp_ies);
+	beacon->proberesp_ies = NULL;
+	os_free(beacon->assocresp_ies);
+	beacon->assocresp_ies = NULL;
+}
+
+
+static int hostapd_build_beacon_data(struct hostapd_iface *iface,
+				     struct beacon_data *beacon)
+{
+	struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra;
+	struct wpa_driver_ap_params params;
+	int ret;
+	struct hostapd_data *hapd = iface->bss[0];
+
+	ret = ieee802_11_build_ap_params(hapd, &params);
+	if (ret < 0)
+		return ret;
+
+	ret = hostapd_build_ap_extra_ies(hapd, &beacon_extra,
+					 &proberesp_extra,
+					 &assocresp_extra);
+	if (ret)
+		goto free_ap_params;
+
+	ret = -1;
+	beacon->head = os_malloc(params.head_len);
+	if (!beacon->head)
+		goto free_ap_extra_ies;
+
+	os_memcpy(beacon->head, params.head, params.head_len);
+	beacon->head_len = params.head_len;
+
+	beacon->tail = os_malloc(params.tail_len);
+	if (!beacon->tail)
+		goto free_beacon;
+
+	os_memcpy(beacon->tail, params.tail, params.tail_len);
+	beacon->tail_len = params.tail_len;
+
+	if (params.proberesp != NULL) {
+		beacon->probe_resp = os_malloc(params.proberesp_len);
+		if (!beacon->probe_resp)
+			goto free_beacon;
+
+		os_memcpy(beacon->probe_resp, params.proberesp,
+			  params.proberesp_len);
+		beacon->probe_resp_len = params.proberesp_len;
+	}
+
+	/* copy the extra ies */
+	if (beacon_extra) {
+		beacon->beacon_ies = os_malloc(wpabuf_len(beacon_extra));
+		if (!beacon->beacon_ies)
+			goto free_beacon;
+
+		os_memcpy(beacon->beacon_ies,
+			  beacon_extra->buf, wpabuf_len(beacon_extra));
+		beacon->beacon_ies_len = wpabuf_len(beacon_extra);
+	}
+
+	if (proberesp_extra) {
+		beacon->proberesp_ies =
+			os_malloc(wpabuf_len(proberesp_extra));
+		if (!beacon->proberesp_ies)
+			goto free_beacon;
+
+		os_memcpy(beacon->proberesp_ies, proberesp_extra->buf,
+			  wpabuf_len(proberesp_extra));
+		beacon->proberesp_ies_len = wpabuf_len(proberesp_extra);
+	}
+
+	if (assocresp_extra) {
+		beacon->assocresp_ies =
+			os_malloc(wpabuf_len(assocresp_extra));
+		if (!beacon->assocresp_ies)
+			goto free_beacon;
+
+		os_memcpy(beacon->assocresp_ies, assocresp_extra->buf,
+			  wpabuf_len(assocresp_extra));
+		beacon->assocresp_ies_len = wpabuf_len(assocresp_extra);
+	}
+
+	ret = 0;
+free_beacon:
+	/* if the function fails, the caller should not free beacon data */
+	if (ret)
+		free_beacon_data(beacon);
+
+free_ap_extra_ies:
+	hostapd_free_ap_extra_ies(hapd, beacon_extra, proberesp_extra,
+				  assocresp_extra);
+free_ap_params:
+	ieee802_11_free_ap_params(&params);
+	return ret;
+}
+
+
+/*
+ * TODO: This flow currently supports only changing frequency within the
+ * same hw_mode. Any other changes to MAC parameters or provided settings (even
+ * width) are not supported.
+ */
+static int hostapd_change_config_freq(struct hostapd_data *hapd,
+				      struct hostapd_config *conf,
+				      struct hostapd_freq_params *params,
+				      struct hostapd_freq_params *old_params)
+{
+	int channel;
+
+	if (!params->channel) {
+		/* check if the new channel is supported by hw */
+		channel = hostapd_hw_get_channel(hapd, params->freq);
+		if (!channel)
+			return -1;
+	} else {
+		channel = params->channel;
+	}
+
+	/* if a pointer to old_params is provided we save previous state */
+	if (old_params) {
+		old_params->channel = conf->channel;
+		old_params->ht_enabled = conf->ieee80211n;
+		old_params->sec_channel_offset = conf->secondary_channel;
+	}
+
+	conf->channel = channel;
+	conf->ieee80211n = params->ht_enabled;
+	conf->secondary_channel = params->sec_channel_offset;
+
+	/* TODO: maybe call here hostapd_config_check here? */
+
+	return 0;
+}
+
+
+static int hostapd_fill_csa_settings(struct hostapd_iface *iface,
+				     struct csa_settings *settings)
+{
+	struct hostapd_freq_params old_freq;
+	int ret;
+
+	os_memset(&old_freq, 0, sizeof(old_freq));
+	if (!iface || !iface->freq || iface->csa_in_progress)
+		return -1;
+
+	ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
+					 &settings->freq_params,
+					 &old_freq);
+	if (ret)
+		return ret;
+
+	ret = hostapd_build_beacon_data(iface, &settings->beacon_after);
+
+	/* change back the configuration */
+	hostapd_change_config_freq(iface->bss[0], iface->conf,
+				   &old_freq, NULL);
+
+	if (ret)
+		return ret;
+
+	/* set channel switch parameters for csa ie */
+	iface->cs_freq = settings->freq_params.freq;
+	iface->cs_count = settings->cs_count;
+	iface->cs_block_tx = settings->block_tx;
+
+	ret = hostapd_build_beacon_data(iface, &settings->beacon_csa);
+	if (ret) {
+		free_beacon_data(&settings->beacon_after);
+		return ret;
+	}
+
+	settings->counter_offset_beacon = iface->cs_c_off_beacon;
+	settings->counter_offset_presp = iface->cs_c_off_proberesp;
+
+	return 0;
+}
+
+
+void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
+{
+	hapd->iface->cs_freq = 0;
+	hapd->iface->cs_count = 0;
+	hapd->iface->cs_block_tx = 0;
+	hapd->iface->cs_c_off_beacon = 0;
+	hapd->iface->cs_c_off_proberesp = 0;
+	hapd->iface->csa_in_progress = 0;
+}
+
+
+int hostapd_switch_channel(struct hostapd_data *hapd,
+			   struct csa_settings *settings)
+{
+	int ret;
+	ret = hostapd_fill_csa_settings(hapd->iface, settings);
+	if (ret)
+		return ret;
+
+	ret = hostapd_drv_switch_channel(hapd, settings);
+	free_beacon_data(&settings->beacon_csa);
+	free_beacon_data(&settings->beacon_after);
+
+	if (ret) {
+		/* if we failed, clean cs parameters */
+		hostapd_cleanup_cs_params(hapd);
+		return ret;
+	}
+
+	hapd->iface->csa_in_progress = 1;
+	return 0;
+}
+
+#endif /* NEED_AP_MLME */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index dbf1b52..c25917d 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -1,6 +1,6 @@
 /*
  * hostapd / Initialization and configuration
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -27,6 +27,8 @@
 struct hostapd_iface;
 struct hostapd_dynamic_iface;
 
+struct csa_settings;
+
 struct hapd_interfaces {
 	int (*reload_config)(struct hostapd_iface *iface);
 	struct hostapd_config * (*config_read_cb)(const char *config_fname);
@@ -42,9 +44,13 @@
 	int global_ctrl_sock;
 	char *global_iface_path;
 	char *global_iface_name;
+#ifndef CONFIG_NATIVE_WINDOWS
 	gid_t ctrl_iface_group;
+#endif /* CONFIG_NATIVE_WINDOWS */
 	struct hostapd_iface **iface;
 	struct hostapd_dynamic_iface **dynamic_iface;
+
+	size_t terminate_on_error;
 };
 
 enum hostapd_chan_status {
@@ -100,6 +106,7 @@
 	struct hostapd_config *iconf;
 	struct hostapd_bss_config *conf;
 	int interface_added; /* virtual interface added for this BSS */
+	unsigned int started:1;
 
 	u8 own_addr[ETH_ALEN];
 
@@ -247,10 +254,24 @@
 	void *owner;
 	char *config_fname;
 	struct hostapd_config *conf;
+	char phy[16]; /* Name of the PHY (radio) */
+
+	enum hostapd_iface_state {
+		HAPD_IFACE_UNINITIALIZED,
+		HAPD_IFACE_DISABLED,
+		HAPD_IFACE_COUNTRY_UPDATE,
+		HAPD_IFACE_ACS,
+		HAPD_IFACE_HT_SCAN,
+		HAPD_IFACE_DFS,
+		HAPD_IFACE_ENABLED
+	} state;
 
 	size_t num_bss;
 	struct hostapd_data **bss;
 
+	unsigned int wait_channel_update:1;
+	unsigned int cac_started: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];
@@ -315,6 +336,14 @@
 	/* lowest observed noise floor in dBm */
 	s8 lowest_nf;
 
+	/* channel switch parameters */
+	int cs_freq;
+	u8 cs_count;
+	int cs_block_tx;
+	unsigned int cs_c_off_beacon;
+	unsigned int cs_c_off_proberesp;
+	int csa_in_progress;
+
 #ifdef CONFIG_ACS
 	unsigned int acs_num_completed_scans;
 #endif /* CONFIG_ACS */
@@ -345,6 +374,11 @@
 int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
 void hostapd_interface_deinit(struct hostapd_iface *iface);
 void hostapd_interface_free(struct hostapd_iface *iface);
+struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
+				    const char *config_file);
+struct hostapd_iface *
+hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+			   const char *config_fname, int debug);
 void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
 			   int reassoc);
 void hostapd_interface_deinit_free(struct hostapd_iface *iface);
@@ -353,6 +387,12 @@
 int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
 int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
 int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
+void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
+void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
+const char * hostapd_state_text(enum hostapd_iface_state s);
+int hostapd_switch_channel(struct hostapd_data *hapd,
+			   struct csa_settings *settings);
+void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
 
 /* utils.c */
 int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 8a239f4..e95e0e1 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -20,6 +20,7 @@
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
 #include "drivers/driver.h"
 #include "hostapd.h"
 #include "ap_config.h"
@@ -45,6 +46,36 @@
 }
 
 
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static char * dfs_info(struct hostapd_channel_data *chan)
+{
+	static char info[256];
+	char *state;
+
+	switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) {
+	case HOSTAPD_CHAN_DFS_UNKNOWN:
+		state = "unknown";
+		break;
+	case HOSTAPD_CHAN_DFS_USABLE:
+		state = "usable";
+		break;
+	case HOSTAPD_CHAN_DFS_UNAVAILABLE:
+		state = "unavailable";
+		break;
+	case HOSTAPD_CHAN_DFS_AVAILABLE:
+		state = "available";
+		break;
+	default:
+		return "";
+	}
+	os_snprintf(info, sizeof(info), " (DFS state = %s)", state);
+	info[sizeof(info) - 1] = '\0';
+
+	return info;
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
 int hostapd_get_hw_features(struct hostapd_iface *iface)
 {
 	struct hostapd_data *hapd = iface->bss[0];
@@ -71,30 +102,40 @@
 
 	for (i = 0; i < num_modes; i++) {
 		struct hostapd_hw_modes *feature = &modes[i];
+		int dfs_enabled = hapd->iconf->ieee80211h &&
+			(iface->drv_flags & WPA_DRIVER_FLAGS_RADAR);
+
 		/* set flag for channels we can use in current regulatory
 		 * domain */
 		for (j = 0; j < feature->num_channels; j++) {
+			int dfs = 0;
+
 			/*
 			 * Disable all channels that are marked not to allow
-			 * IBSS operation or active scanning. In addition,
-			 * disable all channels that require radar detection,
-			 * since that (in addition to full DFS) is not yet
-			 * supported.
+			 * IBSS operation or active scanning.
+			 * Use radar channels only if the driver supports DFS.
 			 */
-			if (feature->channels[j].flag &
-			    (HOSTAPD_CHAN_NO_IBSS |
-			     HOSTAPD_CHAN_PASSIVE_SCAN |
-			     HOSTAPD_CHAN_RADAR))
+			if ((feature->channels[j].flag &
+			     HOSTAPD_CHAN_RADAR) && dfs_enabled) {
+				dfs = 1;
+			} else if (feature->channels[j].flag &
+				   (HOSTAPD_CHAN_NO_IBSS |
+				    HOSTAPD_CHAN_PASSIVE_SCAN |
+				    HOSTAPD_CHAN_RADAR)) {
 				feature->channels[j].flag |=
 					HOSTAPD_CHAN_DISABLED;
+			}
+
 			if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
 				continue;
+
 			wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
-				   "chan=%d freq=%d MHz max_tx_power=%d dBm",
+				   "chan=%d freq=%d MHz max_tx_power=%d dBm%s",
 				   feature->mode,
 				   feature->channels[j].chan,
 				   feature->channels[j].freq,
-				   feature->channels[j].max_tx_power);
+				   feature->channels[j].max_tx_power,
+				   dfs ? dfs_info(&feature->channels[j]) : "");
 		}
 	}
 
@@ -230,7 +271,7 @@
 		first = sec_chan;
 
 	ok = 0;
-	for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
+	for (k = 0; k < ARRAY_SIZE(allowed); k++) {
 		if (first == allowed[k]) {
 			ok = 1;
 			break;
@@ -491,6 +532,47 @@
 }
 
 
+static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
+					struct wpa_driver_scan_params *params)
+{
+	/* Scan only the affected frequency range */
+	int pri_freq;
+	int affected_start, affected_end;
+	int i, pos;
+	struct hostapd_hw_modes *mode;
+
+	if (iface->current_mode == NULL)
+		return;
+
+	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+	if (iface->conf->secondary_channel > 0) {
+		affected_start = pri_freq - 10;
+		affected_end = pri_freq + 30;
+	} else {
+		affected_start = pri_freq - 30;
+		affected_end = pri_freq + 10;
+	}
+	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+		   affected_start, affected_end);
+
+	mode = iface->current_mode;
+	params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
+	if (params->freqs == NULL)
+		return;
+	pos = 0;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		struct hostapd_channel_data *chan = &mode->channels[i];
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+		if (chan->freq < affected_start ||
+		    chan->freq > affected_end)
+			continue;
+		params->freqs[pos++] = chan->freq;
+	}
+}
+
+
 static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
 {
 	struct wpa_driver_scan_params params;
@@ -498,11 +580,14 @@
 	if (!iface->conf->secondary_channel)
 		return 0; /* HT40 not used */
 
+	hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
 	wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
 		   "40 MHz channel");
 	os_memset(&params, 0, sizeof(params));
 	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
 		ieee80211n_scan_channels_2g4(iface, &params);
+	else
+		ieee80211n_scan_channels_5g(iface, &params);
 	if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
 		wpa_printf(MSG_ERROR, "Failed to request a scan of "
 			   "neighboring BSSes");
@@ -613,6 +698,92 @@
 	return 1;
 }
 
+
+#ifdef CONFIG_IEEE80211AC
+
+static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
+{
+	u32 req_cap = conf & cap;
+
+	/*
+	 * Make sure we support all requested capabilities.
+	 * NOTE: We assume that 'cap' represents a capability mask,
+	 * not a discrete value.
+	 */
+	if ((hw & req_cap) != req_cap) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
+			   name);
+		return 0;
+	}
+	return 1;
+}
+
+
+static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 cap,
+				     const char *name)
+{
+	u32 hw_max = hw & cap;
+	u32 conf_val = conf & cap;
+
+	if (conf_val > hw_max) {
+		int offset = find_first_bit(cap);
+		wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
+			   name, conf_val >> offset, hw_max >> offset);
+		return 0;
+	}
+	return 1;
+}
+
+
+static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
+{
+	u32 hw = iface->current_mode->vht_capab;
+	u32 conf = iface->conf->vht_capab;
+
+	wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
+		   hw, conf);
+
+#define VHT_CAP_CHECK(cap) \
+	do { \
+		if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
+			return 0; \
+	} while (0)
+
+#define VHT_CAP_CHECK_MAX(cap) \
+	do { \
+		if (!ieee80211ac_cap_check_max(hw, conf, cap, #cap)) \
+			return 0; \
+	} while (0)
+
+	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
+	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
+	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
+	VHT_CAP_CHECK(VHT_CAP_RXLDPC);
+	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
+	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
+	VHT_CAP_CHECK(VHT_CAP_TXSTBC);
+	VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
+	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+	VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
+	VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
+	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
+	VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
+	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT);
+	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
+	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
+	VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
+	VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
+
+#undef VHT_CAP_CHECK
+#undef VHT_CAP_CHECK_MAX
+
+	return 1;
+}
+#endif /* CONFIG_IEEE80211AC */
+
 #endif /* CONFIG_IEEE80211N */
 
 
@@ -624,6 +795,10 @@
 		return 0;
 	if (!ieee80211n_supported_ht_capab(iface))
 		return -1;
+#ifdef CONFIG_IEEE80211AC
+	if (!ieee80211ac_supported_vht_capab(iface))
+		return -1;
+#endif /* CONFIG_IEEE80211AC */
 	ret = ieee80211n_check_40mhz(iface);
 	if (ret)
 		return ret;
@@ -718,33 +893,45 @@
 }
 
 
-int hostapd_acs_completed(struct hostapd_iface *iface)
+int hostapd_acs_completed(struct hostapd_iface *iface, int err)
 {
-	int ret;
+	int ret = -1;
+
+	if (err)
+		goto out;
 
 	switch (hostapd_check_chans(iface)) {
 	case HOSTAPD_CHAN_VALID:
+		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
+			ACS_EVENT_COMPLETED "freq=%d channel=%d",
+			hostapd_hw_get_freq(iface->bss[0],
+					    iface->conf->channel),
+			iface->conf->channel);
 		break;
 	case HOSTAPD_CHAN_ACS:
 		wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
+		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
 		hostapd_notify_bad_chans(iface);
-		return -1;
+		goto out;
 	case HOSTAPD_CHAN_INVALID:
 	default:
 		wpa_printf(MSG_ERROR, "ACS picked unusable channels");
+		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
 		hostapd_notify_bad_chans(iface);
-		return -1;
+		goto out;
 	}
 
 	ret = hostapd_check_ht_capab(iface);
 	if (ret < 0)
-		return -1;
+		goto out;
 	if (ret == 1) {
 		wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback");
 		return 0;
 	}
 
-	return hostapd_setup_interface_complete(iface, 0);
+	ret = 0;
+out:
+	return hostapd_setup_interface_complete(iface, ret);
 }
 
 
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
index be55c69..bad080f 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -204,7 +204,7 @@
 	addr.sin_port = htons(IAPP_UDP_PORT);
 	if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
 		   (struct sockaddr *) &addr, sizeof(addr)) < 0)
-		perror("sendto[IAPP-ADD]");
+		wpa_printf(MSG_INFO, "sendto[IAPP-ADD]: %s", strerror(errno));
 }
 
 
@@ -231,7 +231,7 @@
 				   * FIX: what is correct RW with 802.11? */
 
 	if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
-		perror("send[L2 Update]");
+		wpa_printf(MSG_INFO, "send[L2 Update]: %s", strerror(errno));
 }
 
 
@@ -276,8 +276,8 @@
 	struct sta_info *sta;
 
 	if (len != sizeof(*add)) {
-		printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
-		       len, (unsigned long) sizeof(*add));
+		wpa_printf(MSG_INFO, "Invalid IAPP-ADD packet length %d (expected %lu)",
+			   len, (unsigned long) sizeof(*add));
 		return;
 	}
 
@@ -326,7 +326,8 @@
 	len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (len < 0) {
-		perror("recvfrom");
+		wpa_printf(MSG_INFO, "iapp_receive_udp - recvfrom: %s",
+			   strerror(errno));
 		return;
 	}
 
@@ -350,17 +351,18 @@
 		       hdr->version, hdr->command,
 		       be_to_host16(hdr->identifier), hlen);
 	if (hdr->version != IAPP_VERSION) {
-		printf("Dropping IAPP frame with unknown version %d\n",
-		       hdr->version);
+		wpa_printf(MSG_INFO, "Dropping IAPP frame with unknown version %d",
+			   hdr->version);
 		return;
 	}
 	if (hlen > len) {
-		printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
+		wpa_printf(MSG_INFO, "Underflow IAPP frame (hlen=%d len=%d)",
+			   hlen, len);
 		return;
 	}
 	if (hlen < len) {
-		printf("Ignoring %d extra bytes from IAPP frame\n",
-		       len - hlen);
+		wpa_printf(MSG_INFO, "Ignoring %d extra bytes from IAPP frame",
+			   len - hlen);
 		len = hlen;
 	}
 
@@ -376,7 +378,7 @@
 		/* TODO: process */
 		break;
 	default:
-		printf("Unknown IAPP command %d\n", hdr->command);
+		wpa_printf(MSG_INFO, "Unknown IAPP command %d", hdr->command);
 		break;
 	}
 }
@@ -403,7 +405,8 @@
 
 	iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (iapp->udp_sock < 0) {
-		perror("socket[PF_INET,SOCK_DGRAM]");
+		wpa_printf(MSG_INFO, "iapp_init - socket[PF_INET,SOCK_DGRAM]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
@@ -411,35 +414,38 @@
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
 	if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
-		perror("ioctl(SIOCGIFINDEX)");
+		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFINDEX): %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 	ifindex = ifr.ifr_ifindex;
 
 	if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
-		perror("ioctl(SIOCGIFADDR)");
+		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFADDR): %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
 	if (paddr->sin_family != AF_INET) {
-		printf("Invalid address family %i (SIOCGIFADDR)\n",
-		       paddr->sin_family);
+		wpa_printf(MSG_INFO, "IAPP: Invalid address family %i (SIOCGIFADDR)",
+			   paddr->sin_family);
 		iapp_deinit(iapp);
 		return NULL;
 	}
 	iapp->own.s_addr = paddr->sin_addr.s_addr;
 
 	if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
-		perror("ioctl(SIOCGIFBRDADDR)");
+		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFBRDADDR): %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
 	if (paddr->sin_family != AF_INET) {
-		printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
-		       paddr->sin_family);
+		wpa_printf(MSG_INFO, "Invalid address family %i (SIOCGIFBRDADDR)",
+			   paddr->sin_family);
 		iapp_deinit(iapp);
 		return NULL;
 	}
@@ -450,7 +456,8 @@
 	uaddr.sin_port = htons(IAPP_UDP_PORT);
 	if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
 		 sizeof(uaddr)) < 0) {
-		perror("bind[UDP]");
+		wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
@@ -461,14 +468,16 @@
 	mreq.imr_ifindex = 0;
 	if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
 		       sizeof(mreq)) < 0) {
-		perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
+		wpa_printf(MSG_INFO, "iapp_init - setsockopt[UDP,IP_ADD_MEMBERSHIP]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 
 	iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 	if (iapp->packet_sock < 0) {
-		perror("socket[PF_PACKET,SOCK_RAW]");
+		wpa_printf(MSG_INFO, "iapp_init - socket[PF_PACKET,SOCK_RAW]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
@@ -478,19 +487,20 @@
 	addr.sll_ifindex = ifindex;
 	if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
 		 sizeof(addr)) < 0) {
-		perror("bind[PACKET]");
+		wpa_printf(MSG_INFO, "iapp_init - bind[PACKET]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 
 	if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
 				     iapp, NULL)) {
-		printf("Could not register read socket for IAPP.\n");
+		wpa_printf(MSG_INFO, "Could not register read socket for IAPP");
 		iapp_deinit(iapp);
 		return NULL;
 	}
 
-	printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
+	wpa_printf(MSG_INFO, "IEEE 802.11F (IAPP) using interface %s", iface);
 
 	/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
 	 * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
@@ -515,7 +525,8 @@
 		mreq.imr_ifindex = 0;
 		if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
 			       &mreq, sizeof(mreq)) < 0) {
-			perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
+			wpa_printf(MSG_INFO, "iapp_deinit - setsockopt[UDP,IP_DEL_MEMBERSHIP]: %s",
+				   strerror(errno));
 		}
 
 		eloop_unregister_read_sock(iapp->udp_sock);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 781f826..d553caa 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -286,7 +286,7 @@
 		   MAC2STR(dst), auth_alg, auth_transaction,
 		   resp, (unsigned long) ies_len);
 	if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
-		perror("send_auth_reply: send");
+		wpa_printf(MSG_INFO, "send_auth_reply: send");
 
 	os_free(buf);
 }
@@ -552,8 +552,8 @@
 	char *radius_cui = NULL;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
-		printf("handle_auth - too short payload (len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
+			   (unsigned long) len);
 		return;
 	}
 
@@ -601,23 +601,23 @@
 #endif /* CONFIG_SAE */
 	      ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
 	       auth_alg == WLAN_AUTH_SHARED_KEY))) {
-		printf("Unsupported authentication algorithm (%d)\n",
-		       auth_alg);
+		wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
+			   auth_alg);
 		resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
 		goto fail;
 	}
 
 	if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
 	      (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
-		printf("Unknown authentication transaction number (%d)\n",
-		       auth_transaction);
+		wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
+			   auth_transaction);
 		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
 		goto fail;
 	}
 
 	if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
-		printf("Station " MACSTR " not allowed to authenticate.\n",
-		       MAC2STR(mgmt->sa));
+		wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
+			   MAC2STR(mgmt->sa));
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
@@ -628,8 +628,8 @@
 				      &psk, &identity, &radius_cui);
 
 	if (res == HOSTAPD_ACL_REJECT) {
-		printf("Station " MACSTR " not allowed to authenticate.\n",
-		       MAC2STR(mgmt->sa));
+		wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
+			   MAC2STR(mgmt->sa));
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
@@ -859,6 +859,21 @@
 }
 
 
+static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
+			   const u8 *ext_capab_ie, size_t ext_capab_ie_len)
+{
+#ifdef CONFIG_INTERWORKING
+	/* check for QoS Map support */
+	if (ext_capab_ie_len >= 5) {
+		if (ext_capab_ie[4] & 0x01)
+			sta->qos_map_enabled = 1;
+	}
+#endif /* CONFIG_INTERWORKING */
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
 static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
 			   const u8 *ies, size_t ies_len, int reassoc)
 {
@@ -881,6 +896,9 @@
 	resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
 	if (resp != WLAN_STATUS_SUCCESS)
 		return resp;
+	resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
 	resp = copy_supp_rates(hapd, sta, &elems);
 	if (resp != WLAN_STATUS_SUCCESS)
 		return resp;
@@ -1169,6 +1187,8 @@
 
 	p = hostapd_eid_ext_capab(hapd, p);
 	p = hostapd_eid_bss_max_idle_period(hapd, p);
+	if (sta->qos_map_enabled)
+		p = hostapd_eid_qos_map_set(hapd, p);
 
 	if (sta->flags & WLAN_STA_WMM)
 		p = hostapd_eid_wmm(hapd, p);
@@ -1235,8 +1255,8 @@
 
 	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
 				      sizeof(mgmt->u.assoc_req))) {
-		printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
-		       "\n", reassoc, (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
+			   reassoc, (unsigned long) len);
 		return;
 	}
 
@@ -1422,8 +1442,8 @@
 	struct sta_info *sta;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
-		printf("handle_disassoc - too short payload (len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)",
+			   (unsigned long) len);
 		return;
 	}
 
@@ -1433,8 +1453,8 @@
 
 	sta = ap_get_sta(hapd, mgmt->sa);
 	if (sta == NULL) {
-		printf("Station " MACSTR " trying to disassociate, but it "
-		       "is not associated.\n", MAC2STR(mgmt->sa));
+		wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated",
+			   MAC2STR(mgmt->sa));
 		return;
 	}
 
@@ -1508,8 +1528,8 @@
 	struct ieee802_11_elems elems;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
-		printf("handle_beacon - too short payload (len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
+			   (unsigned long) len);
 		return;
 	}
 
@@ -1729,8 +1749,8 @@
 	      stype == WLAN_FC_STYPE_ACTION) &&
 #endif /* CONFIG_P2P */
 	    os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
-		printf("MGMT: BSSID=" MACSTR " not our address\n",
-		       MAC2STR(mgmt->bssid));
+		wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
+			   MAC2STR(mgmt->bssid));
 		return;
 	}
 
@@ -1797,8 +1817,8 @@
 	}
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
-		printf("handle_auth_cb - too short payload (len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
+			   (unsigned long) len);
 		return;
 	}
 
@@ -1808,8 +1828,8 @@
 
 	sta = ap_get_sta(hapd, mgmt->da);
 	if (!sta) {
-		printf("handle_auth_cb: STA " MACSTR " not found\n",
-		       MAC2STR(mgmt->da));
+		wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
+			   MAC2STR(mgmt->da));
 		return;
 	}
 
@@ -1859,15 +1879,15 @@
 
 	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
 				      sizeof(mgmt->u.assoc_resp))) {
-		printf("handle_assoc_cb(reassoc=%d) - too short payload "
-		       "(len=%lu)\n", reassoc, (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
+			   reassoc, (unsigned long) len);
 		return;
 	}
 
 	sta = ap_get_sta(hapd, mgmt->da);
 	if (!sta) {
-		printf("handle_assoc_cb: STA " MACSTR " not found\n",
-		       MAC2STR(mgmt->da));
+		wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
+			   MAC2STR(mgmt->da));
 		return;
 	}
 
@@ -2083,7 +2103,7 @@
 		wpa_printf(MSG_DEBUG, "mgmt::action cb");
 		break;
 	default:
-		printf("unknown mgmt cb frame subtype %d\n", stype);
+		wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
 		break;
 	}
 }
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 2aab56d..61f1316 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -41,6 +41,7 @@
 u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
 			   int probe);
 u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 6483e1c..2d53648 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -50,6 +50,22 @@
 
  	pos += sizeof(*cap);
 
+	if (hapd->iconf->obss_interval) {
+		struct ieee80211_obss_scan_parameters *scan_params;
+
+		*pos++ = WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS;
+		*pos++ = sizeof(*scan_params);
+
+		scan_params = (struct ieee80211_obss_scan_parameters *) pos;
+		os_memset(scan_params, 0, sizeof(*scan_params));
+		scan_params->width_trigger_scan_interval =
+			host_to_le16(hapd->iconf->obss_interval);
+
+		/* TODO: Fill in more parameters (supplicant ignores them) */
+
+		pos += sizeof(*scan_params);
+	}
+
 	return pos;
 }
 
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index c36bbe3..76688b5 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -69,7 +69,7 @@
 		  WLAN_SA_QUERY_TR_ID_LEN);
 	end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
 	if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
-		perror("ieee802_11_send_sa_query_req: send");
+		wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
 }
 
 
@@ -107,7 +107,7 @@
 		  WLAN_SA_QUERY_TR_ID_LEN);
 	end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
 	if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
-		perror("ieee80211_mgmt_sa_query_request: send");
+		wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
 }
 
 
@@ -189,6 +189,8 @@
 			*pos |= 0x80; /* Bit 31 - Interworking */
 		break;
 	case 4: /* Bits 32-39 */
+		if (hapd->conf->qos_map_set_len)
+			*pos |= 0x01; /* Bit 32 - QoS Map */
 		if (hapd->conf->tdls & TDLS_PROHIBIT)
 			*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
 		if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) {
@@ -250,6 +252,23 @@
 }
 
 
+u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	u8 len = hapd->conf->qos_map_set_len;
+
+	if (!len)
+		return eid;
+
+	*pos++ = WLAN_EID_QOS_MAP_SET;
+	*pos++ = len;
+	os_memcpy(pos, hapd->conf->qos_map_set, len);
+	pos += len;
+
+	return pos;
+}
+
+
 u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid)
 {
 	u8 *pos = eid;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 0012c0f..60e6b57 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -35,7 +35,7 @@
 	cap = (struct ieee80211_vht_capabilities *) pos;
 	os_memset(cap, 0, sizeof(*cap));
 	cap->vht_capabilities_info = host_to_le32(
-		hapd->iface->current_mode->vht_capab);
+		hapd->iface->conf->vht_capab);
 
 	/* Supported MCS set comes from hw */
 	os_memcpy(&cap->vht_supported_mcs_set,
@@ -113,9 +113,60 @@
 			   struct ieee80211_vht_capabilities *vht_cap,
 			   struct ieee80211_vht_capabilities *neg_vht_cap)
 {
+	u32 cap, own_cap, sym_caps;
+
 	if (vht_cap == NULL)
 		return;
 	os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
 
-	/* TODO: mask own capabilities, like get_ht_capab() */
+	cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
+	own_cap = hapd->iconf->vht_capab;
+
+	/* mask out symmetric VHT capabilities we don't support */
+	sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
+	cap &= ~sym_caps | (own_cap & sym_caps);
+
+	/* mask out beamformer/beamformee caps if not supported */
+	if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+		cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+			 VHT_CAP_BEAMFORMEE_STS_MAX);
+
+	if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+		cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
+			 VHT_CAP_SOUNDING_DIMENSION_MAX);
+
+	if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+		cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+
+	if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
+		cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
+
+	/* mask channel widths we don't support */
+	switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
+	case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
+		break;
+	case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
+		if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
+			cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+			cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+		}
+		break;
+	default:
+		cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+		break;
+	}
+
+	if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
+		cap &= ~VHT_CAP_SHORT_GI_160;
+
+	/*
+	 * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
+	 * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
+	 */
+	if (!(own_cap & VHT_CAP_RXSTBC_MASK))
+		cap &= ~VHT_CAP_TXSTBC;
+	if (!(own_cap & VHT_CAP_TXSTBC))
+		cap &= ~VHT_CAP_RXSTBC_MASK;
+
+	neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
 }
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 9867581..7874332 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -96,8 +96,9 @@
 	}
 
 	if (res && errno != ENOENT) {
-		printf("Could not set station " MACSTR " flags for kernel "
-		       "driver (errno=%d).\n", MAC2STR(sta->addr), errno);
+		wpa_printf(MSG_DEBUG, "Could not set station " MACSTR
+			   " flags for kernel driver (errno=%d).",
+			   MAC2STR(sta->addr), errno);
 	}
 
 	if (authorized) {
@@ -452,7 +453,7 @@
 	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
 			     sm->radius_identifier);
 	if (msg == NULL) {
-		printf("Could not create net RADIUS packet\n");
+		wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
 		return;
 	}
 
@@ -461,7 +462,7 @@
 	if (sm->identity &&
 	    !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
 				 sm->identity, sm->identity_len)) {
-		printf("Could not add User-Name\n");
+		wpa_printf(MSG_INFO, "Could not add User-Name");
 		goto fail;
 	}
 
@@ -475,12 +476,12 @@
 	if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
 					    RADIUS_ATTR_FRAMED_MTU) &&
 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
-		printf("Could not add Framed-MTU\n");
+		wpa_printf(MSG_INFO, "Could not add Framed-MTU");
 		goto fail;
 	}
 
 	if (eap && !radius_msg_add_eap(msg, eap, len)) {
-		printf("Could not add EAP-Message\n");
+		wpa_printf(MSG_INFO, "Could not add EAP-Message");
 		goto fail;
 	}
 
@@ -492,8 +493,7 @@
 		int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
 					       RADIUS_ATTR_STATE);
 		if (res < 0) {
-			printf("Could not copy State attribute from previous "
-			       "Access-Challenge\n");
+			wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge");
 			goto fail;
 		}
 		if (res > 0) {
@@ -543,7 +543,7 @@
 	data = (u8 *) (eap + 1);
 
 	if (len < sizeof(*eap) + 1) {
-		printf("handle_eap_response: too short response data\n");
+		wpa_printf(MSG_INFO, "handle_eap_response: too short response data");
 		return;
 	}
 
@@ -571,7 +571,7 @@
 	u16 eap_len;
 
 	if (len < sizeof(*eap)) {
-		printf("   too short EAP packet\n");
+		wpa_printf(MSG_INFO, "   too short EAP packet");
 		return;
 	}
 
@@ -664,7 +664,7 @@
 	}
 
 	if (len < sizeof(*hdr)) {
-		printf("   too short IEEE 802.1X packet\n");
+		wpa_printf(MSG_INFO, "   too short IEEE 802.1X packet");
 		return;
 	}
 
@@ -674,7 +674,7 @@
 		   hdr->version, hdr->type, datalen);
 
 	if (len - sizeof(*hdr) < datalen) {
-		printf("   frame too short for this IEEE 802.1X packet\n");
+		wpa_printf(MSG_INFO, "   frame too short for this IEEE 802.1X packet");
 		if (sta->eapol_sm)
 			sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
 		return;
@@ -1276,15 +1276,14 @@
 			   "EAP-Message");
 	} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
 				     req, 1)) {
-		printf("Incoming RADIUS packet did not have correct "
-		       "Message-Authenticator - dropped\n");
+		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
 		return RADIUS_RX_INVALID_AUTHENTICATOR;
 	}
 
 	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
 	    hdr->code != RADIUS_CODE_ACCESS_REJECT &&
 	    hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
-		printf("Unknown RADIUS message code\n");
+		wpa_printf(MSG_INFO, "Unknown RADIUS message code");
 		return RADIUS_RX_UNKNOWN;
 	}
 
@@ -1448,7 +1447,7 @@
 	if (eapol->default_wep_key == NULL ||
 	    random_get_bytes(eapol->default_wep_key,
 			     hapd->conf->default_wep_key_len)) {
-		printf("Could not generate random WEP key.\n");
+		wpa_printf(MSG_INFO, "Could not generate random WEP key");
 		os_free(eapol->default_wep_key);
 		eapol->default_wep_key = NULL;
 		return -1;
@@ -2127,12 +2126,7 @@
 		 * driver reorder operations.
 		 */
 		os_sleep(0, 10000);
-#ifndef ANDROID_P2P
-		/* We need not do this for driver. For AP-SME flags if we send this disassoc,
-		  * the p2p_client is gettig disassoc after it has completed the assoc
-		  */
 		ap_sta_disconnect(hapd, sta, sta->addr,
 				  WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
-#endif
 	}
 }
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 6704c09..9d28d9c 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -232,7 +232,8 @@
 	wpa_auth_sta_deinit(sta->wpa_sm);
 	rsn_preauth_free_station(hapd, sta);
 #ifndef CONFIG_NO_RADIUS
-	radius_client_flush_auth(hapd->radius, sta->addr);
+	if (hapd->radius)
+		radius_client_flush_auth(hapd->radius, sta->addr);
 #endif /* CONFIG_NO_RADIUS */
 
 	os_free(sta->last_assoc_req);
@@ -261,6 +262,7 @@
 	wpabuf_free(sta->hs20_ie);
 
 	os_free(sta->ht_capabilities);
+	os_free(sta->vht_capabilities);
 	hostapd_free_psk_list(sta->psk);
 	os_free(sta->identity);
 	os_free(sta->radius_cui);
@@ -489,6 +491,18 @@
 }
 
 
+void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
+			      u32 session_timeout)
+{
+	if (eloop_replenish_timeout(session_timeout, 0,
+				    ap_handle_session_timer, hapd, sta)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG, "setting session timeout "
+			       "to %d seconds", session_timeout);
+	}
+}
+
+
 void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
 			    u32 session_timeout)
 {
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index e5b5069..dc74219 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -57,6 +57,7 @@
 	unsigned int no_ht_set:1;
 	unsigned int ht_20mhz_set:1;
 	unsigned int no_p2p_set:1;
+	unsigned int qos_map_enabled:1;
 
 	u16 auth_alg;
 	u8 previous_ap[6];
@@ -161,6 +162,8 @@
 void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
 void hostapd_free_stas(struct hostapd_data *hapd);
 void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
+void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
+			      u32 session_timeout);
 void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
 			    u32 session_timeout);
 void ap_sta_no_session_timeout(struct hostapd_data *hapd,
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 746af40..1afbb8e 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -1021,6 +1021,7 @@
 
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 	full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
+	hapd->full_dynamic_vlan = NULL;
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
 }
 
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index d21c82f..2851672 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -157,7 +157,7 @@
 	len = ((u8 *) (t + 1)) - buf;
 
 	if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
-		perror("wmm_send_action: send");
+		wpa_printf(MSG_INFO, "wmm_send_action: send failed");
 }
 
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 0286c5b..03b15c2 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1863,6 +1863,7 @@
 {
 	struct wpa_igtk_kde igtk;
 	struct wpa_group *gsm = sm->group;
+	u8 rsc[WPA_KEY_RSC_LEN];
 
 	if (!sm->mgmt_frame_prot)
 		return pos;
@@ -1870,8 +1871,10 @@
 	igtk.keyid[0] = gsm->GN_igtk;
 	igtk.keyid[1] = 0;
 	if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
-	    wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
+	    wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, rsc) < 0)
 		os_memset(igtk.pn, 0, sizeof(igtk.pn));
+	else
+		os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
 	os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
 	if (sm->wpa_auth->conf.disable_gtk) {
 		/*
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index d977b42..cbaab9f 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -618,5 +618,6 @@
 
 #ifdef CONFIG_IEEE80211R
 	l2_packet_deinit(hapd->l2);
+	hapd->l2 = NULL;
 #endif /* CONFIG_IEEE80211R */
 }
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index eb300f1..294a39d 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1211,6 +1211,7 @@
 static void hostapd_wps_nfc_clear(struct wps_context *wps)
 {
 #ifdef CONFIG_WPS_NFC
+	wpa_printf(MSG_DEBUG, "WPS: Clear NFC Tag context %p", wps);
 	wps->ap_nfc_dev_pw_id = 0;
 	wpabuf_free(wps->ap_nfc_dh_pubkey);
 	wps->ap_nfc_dh_pubkey = NULL;
@@ -1823,6 +1824,9 @@
 		return -1;
 
 	hostapd_wps_nfc_clear(wps);
+	wpa_printf(MSG_DEBUG,
+		   "WPS: Enable NFC Tag (Dev Pw Id %u) for AP interface %s (context %p)",
+		   hapd->conf->wps_nfc_dev_pw_id, hapd->conf->iface, wps);
 	wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
 	wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
 	wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
@@ -1849,6 +1853,8 @@
 
 void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
 {
+	wpa_printf(MSG_DEBUG, "WPS: Disable NFC token for AP interface %s",
+		   hapd->conf->iface);
 	hostapd_wps_nfc_clear(hapd->wps);
 }
 
diff --git a/src/common/defs.h b/src/common/defs.h
index 281dd8a..0c90c24 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -312,6 +312,7 @@
 	WPA_CTRL_REQ_EAP_PIN,
 	WPA_CTRL_REQ_EAP_OTP,
 	WPA_CTRL_REQ_EAP_PASSPHRASE,
+	WPA_CTRL_REQ_SIM,
 	NUM_WPA_CTRL_REQS
 };
 
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index aab8ac6..304dfc6 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -276,6 +276,12 @@
 			elems->interworking = pos;
 			elems->interworking_len = elen;
 			break;
+		case WLAN_EID_QOS_MAP_SET:
+			if (elen < 16)
+				break;
+			elems->qos_map_set = pos;
+			elems->qos_map_set_len = elen;
+			break;
 		case WLAN_EID_EXT_CAPAB:
 			elems->ext_capab = pos;
 			elems->ext_capab_len = elen;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 68c6b96..c4618b2 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -40,6 +40,7 @@
 	const u8 *wfd;
 	const u8 *link_id;
 	const u8 *interworking;
+	const u8 *qos_map_set;
 	const u8 *hs20;
 	const u8 *ext_capab;
 	const u8 *bss_max_idle_period;
@@ -73,6 +74,7 @@
 	u8 p2p_len;
 	u8 wfd_len;
 	u8 interworking_len;
+	u8 qos_map_set_len;
 	u8 hs20_len;
 	u8 ext_capab_len;
 	u8 ssid_list_len;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 137c309..9b2d54f 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -203,6 +203,7 @@
 #define WLAN_EID_TIM 5
 #define WLAN_EID_IBSS_PARAMS 6
 #define WLAN_EID_COUNTRY 7
+#define WLAN_EID_BSS_LOAD 11
 #define WLAN_EID_CHALLENGE 16
 /* EIDs defined by IEEE 802.11h - START */
 #define WLAN_EID_PWR_CONSTRAINT 32
@@ -242,6 +243,7 @@
 #define WLAN_EID_LINK_ID 101
 #define WLAN_EID_INTERWORKING 107
 #define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_QOS_MAP_SET 110
 #define WLAN_EID_ROAMING_CONSORTIUM 111
 #define WLAN_EID_EXT_CAPAB 127
 #define WLAN_EID_CCKM 156
@@ -585,6 +587,17 @@
 } STRUCT_PACKED;
 
 
+struct ieee80211_obss_scan_parameters {
+	le16 scan_passive_dwell;
+	le16 scan_active_dwell;
+	le16 width_trigger_scan_interval;
+	le16 scan_passive_total_per_channel;
+	le16 scan_active_total_per_channel;
+	le16 channel_transition_delay_factor;
+	le16 scan_activity_threshold;
+} STRUCT_PACKED;
+
+
 struct ieee80211_vht_capabilities {
 	le32 vht_capabilities_info;
 	struct {
@@ -702,8 +715,10 @@
 /* VHT Defines */
 #define VHT_CAP_MAX_MPDU_LENGTH_7991                ((u32) BIT(0))
 #define VHT_CAP_MAX_MPDU_LENGTH_11454               ((u32) BIT(1))
+#define VHT_CAP_MAX_MPDU_LENGTH_MASK                ((u32) BIT(0) | BIT(1))
 #define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ              ((u32) BIT(2))
 #define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ     ((u32) BIT(3))
+#define VHT_CAP_SUPP_CHAN_WIDTH_MASK                ((u32) BIT(2) | BIT(3))
 #define VHT_CAP_RXLDPC                              ((u32) BIT(4))
 #define VHT_CAP_SHORT_GI_80                         ((u32) BIT(5))
 #define VHT_CAP_SHORT_GI_160                        ((u32) BIT(6))
@@ -712,15 +727,22 @@
 #define VHT_CAP_RXSTBC_2                            ((u32) BIT(9))
 #define VHT_CAP_RXSTBC_3                            ((u32) BIT(8) | BIT(9))
 #define VHT_CAP_RXSTBC_4                            ((u32) BIT(10))
+#define VHT_CAP_RXSTBC_MASK                         ((u32) BIT(8) | BIT(9) | \
+							   BIT(10))
 #define VHT_CAP_SU_BEAMFORMER_CAPABLE               ((u32) BIT(11))
 #define VHT_CAP_SU_BEAMFORMEE_CAPABLE               ((u32) BIT(12))
-#define VHT_CAP_BEAMFORMER_ANTENNAS_MAX             ((u32) BIT(13) | BIT(14))
-#define VHT_CAP_SOUNDING_DIMENTION_MAX              ((u32) BIT(16) | BIT(17))
+#define VHT_CAP_BEAMFORMEE_STS_MAX                  ((u32) BIT(13) | \
+							   BIT(14) | BIT(15))
+#define VHT_CAP_BEAMFORMEE_STS_OFFSET               13
+#define VHT_CAP_SOUNDING_DIMENSION_MAX              ((u32) BIT(16) | \
+							   BIT(17) | BIT(18))
+#define VHT_CAP_SOUNDING_DIMENSION_OFFSET           16
 #define VHT_CAP_MU_BEAMFORMER_CAPABLE               ((u32) BIT(19))
 #define VHT_CAP_MU_BEAMFORMEE_CAPABLE               ((u32) BIT(20))
 #define VHT_CAP_VHT_TXOP_PS                         ((u32) BIT(21))
 #define VHT_CAP_HTC_VHT                             ((u32) BIT(22))
-#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT          ((u32) BIT(23))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT          ((u32) BIT(23) | \
+							   BIT(24) | BIT(25))
 #define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB   ((u32) BIT(27))
 #define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB     ((u32) BIT(26) | BIT(27))
 #define VHT_CAP_RX_ANTENNA_PATTERN                  ((u32) BIT(28))
@@ -1079,6 +1101,15 @@
 #define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES   70
 #define WNM_NEIGHBOR_MULTIPLE_BSSID             71
 
+/* QoS action */
+enum qos_action {
+	QOS_ADDTS_REQ = 0,
+	QOS_ADDTS_RESP = 1,
+	QOS_DELTS = 2,
+	QOS_SCHEDULE = 3,
+	QOS_QOS_MAP_CONFIG = 4,
+};
+
 /* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */
 #define WLAN_20_40_BSS_COEX_INFO_REQ            BIT(0)
 #define WLAN_20_40_BSS_COEX_40MHZ_INTOL         BIT(1)
@@ -1126,4 +1157,8 @@
 	WNM_SLEEP_SUBELEM_IGTK = 1
 };
 
+/* Channel Switch modes (802.11h) */
+#define CHAN_SWITCH_MODE_ALLOW_TX	0
+#define CHAN_SWITCH_MODE_BLOCK_TX	1
+
 #endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index bce60a3..4e9e461 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -678,7 +678,7 @@
 {
 	if (allowed_groups) {
 		int i;
-		for (i = 0; allowed_groups[i] >= 0; i++) {
+		for (i = 0; allowed_groups[i] > 0; i++) {
 			if (allowed_groups[i] == group)
 				break;
 		}
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index fd7f686..93c0f9d 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -149,6 +149,7 @@
 
 #define INTERWORKING_AP "INTERWORKING-AP "
 #define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
+#define INTERWORKING_ALREADY_CONNECTED "INTERWORKING-ALREADY-CONNECTED "
 
 #define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO "
 
@@ -166,6 +167,21 @@
 #define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
 #define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
 
+#define AP_EVENT_ENABLED "AP-ENABLED "
+#define AP_EVENT_DISABLED "AP-DISABLED "
+
+#define ACS_EVENT_STARTED "ACS-STARTED "
+#define ACS_EVENT_COMPLETED "ACS-COMPLETED "
+#define ACS_EVENT_FAILED "ACS-FAILED "
+
+#define DFS_EVENT_RADAR_DETECTED "DFS-RADAR-DETECTED "
+#define DFS_EVENT_NEW_CHANNEL "DFS-NEW-CHANNEL "
+#define DFS_EVENT_CAC_START "DFS-CAC-START "
+#define DFS_EVENT_CAC_COMPLETED "DFS-CAC-COMPLETED "
+#define DFS_EVENT_NOP_FINISHED "DFS-NOP-FINISHED "
+
+#define AP_CSA_FINISHED "AP-CSA-FINISHED "
+
 /* BSS command information masks */
 
 #define WPA_BSS_MASK_ALL		0xFFFDFFFF
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index 3a675df..58e94c3 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -1169,7 +1169,7 @@
 #endif /* ALL_DH_GROUPS */
 };
 
-#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0]))
+#define NUM_DH_GROUPS ARRAY_SIZE(dh_groups)
 
 
 const struct dh_group * dh_groups_get(int id)
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 2fdaa02..feba13f 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -40,7 +40,8 @@
 	TLS_FAIL_SUBJECT_MISMATCH = 5,
 	TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
 	TLS_FAIL_BAD_CERTIFICATE = 7,
-	TLS_FAIL_SERVER_CHAIN_PROBE = 8
+	TLS_FAIL_SERVER_CHAIN_PROBE = 8,
+	TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9
 };
 
 union tls_event_data {
@@ -96,6 +97,8 @@
  * %NULL to allow all subjects
  * @altsubject_match: String to match in the alternative subject of the peer
  * certificate or %NULL to allow all alternative subjects
+ * @suffix_match: String to suffix match in the dNSName or CN of the peer
+ * certificate or %NULL to allow all domain names
  * @client_cert: File or reference name for client X.509 certificate in PEM or
  * DER format
  * @client_cert_blob: client_cert as inlined data or %NULL if not used
@@ -137,6 +140,7 @@
 	const char *ca_path;
 	const char *subject_match;
 	const char *altsubject_match;
+	const char *suffix_match;
 	const char *client_cert;
 	const u8 *client_cert_blob;
 	size_t client_cert_blob_len;
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index d27af0a..eeaf859 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -48,23 +48,6 @@
 #endif
 #endif
 
-#ifdef ANDROID
-#include <openssl/pem.h>
-#include <keystore/keystore_get.h>
-
-static BIO * BIO_from_keystore(const char *key)
-{
-    BIO *bio = NULL;
-    uint8_t *value = NULL;
-    int length = keystore_get(key, strlen(key), &value);
-    if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL) {
-        BIO_write(bio, value, length);
-    }
-    free(value);
-    return bio;
-}
-#endif /* ANDROID */
-
 #ifdef SSL_set_tlsext_status_type
 #ifndef OPENSSL_NO_TLSEXT
 #define HAVE_OCSP
@@ -72,6 +55,22 @@
 #endif /* OPENSSL_NO_TLSEXT */
 #endif /* SSL_set_tlsext_status_type */
 
+#ifdef ANDROID
+#include <openssl/pem.h>
+#include <keystore/keystore_get.h>
+
+static BIO * BIO_from_keystore(const char *key)
+{
+	BIO *bio = NULL;
+	uint8_t *value = NULL;
+	int length = keystore_get(key, strlen(key), &value);
+	if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
+		BIO_write(bio, value, length);
+	free(value);
+	return bio;
+}
+#endif /* ANDROID */
+
 static int tls_openssl_ref_count = 0;
 
 struct tls_context {
@@ -93,7 +92,7 @@
 	ENGINE *engine;        /* functional reference to the engine */
 	EVP_PKEY *private_key; /* the private key if using engine */
 #endif /* OPENSSL_NO_ENGINE */
-	char *subject_match, *altsubject_match;
+	char *subject_match, *altsubject_match, *suffix_match;
 	int read_alerts, write_alerts, failed;
 
 	tls_session_ticket_cb session_ticket_cb;
@@ -798,11 +797,13 @@
 	ssl = SSL_CTX_new(TLSv1_method());
 	if (ssl == NULL) {
 		tls_openssl_ref_count--;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+		if (context != tls_global)
+			os_free(context);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
 		if (tls_openssl_ref_count == 0) {
 			os_free(tls_global);
 			tls_global = NULL;
-		} else if (context != tls_global) {
-			os_free(context);
 		}
 		return NULL;
 	}
@@ -1049,6 +1050,7 @@
 	tls_engine_deinit(conn);
 	os_free(conn->subject_match);
 	os_free(conn->altsubject_match);
+	os_free(conn->suffix_match);
 	os_free(conn->session_ticket);
 	os_free(conn);
 }
@@ -1139,6 +1141,104 @@
 }
 
 
+#ifndef CONFIG_NATIVE_WINDOWS
+static int domain_suffix_match(const u8 *val, size_t len, const char *match)
+{
+	size_t i, match_len;
+
+	/* Check for embedded nuls that could mess up suffix matching */
+	for (i = 0; i < len; i++) {
+		if (val[i] == '\0') {
+			wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject");
+			return 0;
+		}
+	}
+
+	match_len = os_strlen(match);
+	if (match_len > len)
+		return 0;
+
+	if (os_strncasecmp((const char *) val + len - match_len, match,
+			   match_len) != 0)
+		return 0; /* no match */
+
+	if (match_len == len)
+		return 1; /* exact match */
+
+	if (val[len - match_len - 1] == '.')
+		return 1; /* full label match completes suffix match */
+
+	wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
+	return 0;
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static int tls_match_suffix(X509 *cert, const char *match)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+	/* wincrypt.h has conflicting X509_NAME definition */
+	return -1;
+#else /* CONFIG_NATIVE_WINDOWS */
+	GENERAL_NAME *gen;
+	void *ext;
+	int i;
+	int dns_name = 0;
+	X509_NAME *name;
+
+	wpa_printf(MSG_DEBUG, "TLS: Match domain against suffix %s", match);
+
+	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+
+	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
+		gen = sk_GENERAL_NAME_value(ext, i);
+		if (gen->type != GEN_DNS)
+			continue;
+		dns_name++;
+		wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
+				  gen->d.dNSName->data,
+				  gen->d.dNSName->length);
+		if (domain_suffix_match(gen->d.dNSName->data,
+					gen->d.dNSName->length, match) == 1) {
+			wpa_printf(MSG_DEBUG, "TLS: Suffix match in dNSName found");
+			return 1;
+		}
+	}
+
+	if (dns_name) {
+		wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
+		return 0;
+	}
+
+	name = X509_get_subject_name(cert);
+	i = -1;
+	for (;;) {
+		X509_NAME_ENTRY *e;
+		ASN1_STRING *cn;
+
+		i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
+		if (i == -1)
+			break;
+		e = X509_NAME_get_entry(name, i);
+		if (e == NULL)
+			continue;
+		cn = X509_NAME_ENTRY_get_data(e);
+		if (cn == NULL)
+			continue;
+		wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
+				  cn->data, cn->length);
+		if (domain_suffix_match(cn->data, cn->length, match) == 1) {
+			wpa_printf(MSG_DEBUG, "TLS: Suffix match in commonName found");
+			return 1;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "TLS: No CommonName suffix match found");
+	return 0;
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
 static enum tls_fail_reason openssl_tls_fail_reason(int err)
 {
 	switch (err) {
@@ -1267,7 +1367,7 @@
 	SSL *ssl;
 	struct tls_connection *conn;
 	struct tls_context *context;
-	char *match, *altmatch;
+	char *match, *altmatch, *suffix_match;
 	const char *err_str;
 
 	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
@@ -1289,6 +1389,7 @@
 	context = conn->context;
 	match = conn->subject_match;
 	altmatch = conn->altsubject_match;
+	suffix_match = conn->suffix_match;
 
 	if (!preverify_ok && !conn->ca_cert_verify)
 		preverify_ok = 1;
@@ -1357,6 +1458,14 @@
 		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 				       "AltSubject mismatch",
 				       TLS_FAIL_ALTSUBJECT_MISMATCH);
+	} else if (depth == 0 && suffix_match &&
+		   !tls_match_suffix(err_cert, suffix_match)) {
+		wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
+			   suffix_match);
+		preverify_ok = 0;
+		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "Domain suffix mismatch",
+				       TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
 	} else
 		openssl_tls_cert_event(conn, err_cert, depth, buf);
 
@@ -1619,7 +1728,8 @@
 
 static int tls_connection_set_subject_match(struct tls_connection *conn,
 					    const char *subject_match,
-					    const char *altsubject_match)
+					    const char *altsubject_match,
+					    const char *suffix_match)
 {
 	os_free(conn->subject_match);
 	conn->subject_match = NULL;
@@ -1637,6 +1747,14 @@
 			return -1;
 	}
 
+	os_free(conn->suffix_match);
+	conn->suffix_match = NULL;
+	if (suffix_match) {
+		conn->suffix_match = os_strdup(suffix_match);
+		if (conn->suffix_match == NULL)
+			return -1;
+	}
+
 	return 0;
 }
 
@@ -2855,8 +2973,15 @@
 
 	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
 
-	if (!conn->peer_cert || !conn->peer_issuer) {
-		wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate or issue certificate not available for OCSP status check");
+	if (!conn->peer_cert) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check");
+		OCSP_BASICRESP_free(basic);
+		OCSP_RESPONSE_free(rsp);
+		return 0;
+	}
+
+	if (!conn->peer_issuer) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check");
 		OCSP_BASICRESP_free(basic);
 		OCSP_RESPONSE_free(rsp);
 		return 0;
@@ -2902,7 +3027,7 @@
 		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
 		return 0;
 	}
-		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
+	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
 	return 1;
 }
 
@@ -2947,7 +3072,6 @@
 {
 	int ret;
 	unsigned long err;
-	SSL_CTX *ssl_ctx = tls_ctx;
 
 	if (conn == NULL)
 		return -1;
@@ -2967,7 +3091,8 @@
 	}
 	if (tls_connection_set_subject_match(conn,
 					     params->subject_match,
-					     params->altsubject_match))
+					     params->altsubject_match,
+					     params->suffix_match))
 		return -1;
 
 	if (params->engine && params->ca_cert_id) {
@@ -3019,6 +3144,7 @@
 
 #ifdef HAVE_OCSP
 	if (params->flags & TLS_CONN_REQUEST_OCSP) {
+		SSL_CTX *ssl_ctx = tls_ctx;
 		SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
 		SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
 		SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index b8c9829..3502eb8 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -37,6 +37,18 @@
 #define HOSTAPD_CHAN_DFS_AVAILABLE 0x00000300
 #define HOSTAPD_CHAN_DFS_MASK 0x00000300
 
+#define HOSTAPD_CHAN_VHT_10_70 0x00000800
+#define HOSTAPD_CHAN_VHT_30_50 0x00001000
+#define HOSTAPD_CHAN_VHT_50_30 0x00002000
+#define HOSTAPD_CHAN_VHT_70_10 0x00004000
+
+enum reg_change_initiator {
+	REGDOM_SET_BY_CORE,
+	REGDOM_SET_BY_USER,
+	REGDOM_SET_BY_DRIVER,
+	REGDOM_SET_BY_COUNTRY_IE,
+};
+
 /**
  * struct hostapd_channel_data - Channel information
  */
@@ -57,7 +69,7 @@
 	int flag;
 
 	/**
-	 * max_tx_power - Maximum transmit power in dBm
+	 * max_tx_power - Regulatory transmit power limit in dBm
 	 */
 	u8 max_tx_power;
 
@@ -622,7 +634,7 @@
 	/**
 	 * head - Beacon head from IEEE 802.11 header to IEs before TIM IE
 	 */
-	const u8 *head;
+	u8 *head;
 
 	/**
 	 * head_len - Length of the head buffer in octets
@@ -632,7 +644,7 @@
 	/**
 	 * tail - Beacon tail following TIM IE
 	 */
-	const u8 *tail;
+	u8 *tail;
 
 	/**
 	 * tail_len - Length of the tail buffer in octets
@@ -663,7 +675,7 @@
 	 * This is used by drivers that reply to Probe Requests internally in
 	 * AP mode and require the full Probe Response template.
 	 */
-	const u8 *proberesp;
+	u8 *proberesp;
 
 	/**
 	 * proberesp_len - Length of the proberesp buffer in octets
@@ -1152,6 +1164,59 @@
 };
 
 /**
+ * struct beacon_data - Beacon data
+ * @head: Head portion of Beacon frame (before TIM IE)
+ * @tail: Tail portion of Beacon frame (after TIM IE)
+ * @beacon_ies: Extra information element(s) to add into Beacon frames or %NULL
+ * @proberesp_ies: Extra information element(s) to add into Probe Response
+ *	frames or %NULL
+ * @assocresp_ies: Extra information element(s) to add into (Re)Association
+ *	Response frames or %NULL
+ * @probe_resp: Probe Response frame template
+ * @head_len: Length of @head
+ * @tail_len: Length of @tail
+ * @beacon_ies_len: Length of beacon_ies in octets
+ * @proberesp_ies_len: Length of proberesp_ies in octets
+ * @proberesp_ies_len: Length of proberesp_ies in octets
+ * @probe_resp_len: Length of probe response template (@probe_resp)
+ */
+struct beacon_data {
+	u8 *head, *tail;
+	u8 *beacon_ies;
+	u8 *proberesp_ies;
+	u8 *assocresp_ies;
+	u8 *probe_resp;
+
+	size_t head_len, tail_len;
+	size_t beacon_ies_len;
+	size_t proberesp_ies_len;
+	size_t assocresp_ies_len;
+	size_t probe_resp_len;
+};
+
+/**
+ * struct csa_settings - Settings for channel switch command
+ * @cs_count: Count in Beacon frames (TBTT) to perform the switch
+ * @block_tx: 1 - block transmission for CSA period
+ * @freq_params: Next channel frequency parameter
+ * @beacon_csa: Beacon/probe resp/asooc resp info for CSA period
+ * @beacon_after: Next beacon/probe resp/asooc resp info
+ * @counter_offset_beacon: Offset to the count field in beacon's tail
+ * @counter_offset_presp: Offset to the count field in probe resp.
+ */
+struct csa_settings {
+	u8 cs_count;
+	u8 block_tx;
+
+	struct hostapd_freq_params freq_params;
+	struct beacon_data beacon_csa;
+	struct beacon_data beacon_after;
+
+	u16 counter_offset_beacon;
+	u16 counter_offset_presp;
+};
+
+/**
  * struct wpa_driver_ops - Driver interface API definition
  *
  * This structure defines the API that each driver interface needs to implement
@@ -1565,6 +1630,14 @@
 	int (*set_country)(void *priv, const char *alpha2);
 
 	/**
+	 * get_country - Get country
+	 * @priv: Private driver interface data
+	 * @alpha2: Buffer for returning country code (at least 3 octets)
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*get_country)(void *priv, char *alpha2);
+
+	/**
 	 * global_init - Global driver initialization
 	 * Returns: Pointer to private data (global), %NULL on failure
 	 *
@@ -1950,12 +2023,13 @@
 	 *	(this may differ from the requested addr if the driver cannot
 	 *	change interface address)
 	 * @bridge: Bridge interface to use or %NULL if no bridge configured
+	 * @use_existing: Whether to allow existing interface to be used
 	 * Returns: 0 on success, -1 on failure
 	 */
 	int (*if_add)(void *priv, enum wpa_driver_if_type type,
 		      const char *ifname, const u8 *addr, void *bss_ctx,
 		      void **drv_priv, char *force_ifname, u8 *if_addr,
-		      const char *bridge);
+		      const char *bridge, int use_existing);
 
 	/**
 	 * if_remove - Remove a virtual interface
@@ -2572,6 +2646,15 @@
 			u8 *buf, u16 *buf_len);
 
 	/**
+	 * set_qos_map - Set QoS Map
+	 * @priv: Private driver interface data
+	 * @qos_map_set: QoS Map
+	 * @qos_map_set_len: Length of QoS Map
+	 */
+	int (*set_qos_map)(void *priv, const u8 *qos_map_set,
+			   u8 qos_map_set_len);
+
+	/**
 	 * signal_poll - Get current connection information
 	 * @priv: Private driver interface data
 	 * @signal_info: Connection info structure
@@ -2591,18 +2674,19 @@
 	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*set_authmode)(void *priv, int authmode);
+
 #ifdef ANDROID
 	/**
-	 * driver_cmd - execute driver-specific command
-	 * @priv: private driver interface data
-	 * @cmd: command to execute
-	 * @buf: return buffer
-	 * @buf_len: buffer length
-	 *
+	 * driver_cmd - Execute driver-specific command
+	 * @priv: Private driver interface data
+	 * @cmd: Command to execute
+	 * @buf: Return buffer
+	 * @buf_len: Buffer length
 	 * Returns: 0 on success, -1 on failure
 	 */
-	 int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len);
-#endif
+	int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len);
+#endif /* ANDROID */
+
 	/**
 	 * set_rekey_info - Set rekey information
 	 * @priv: Private driver interface data
@@ -2735,21 +2819,21 @@
 	 * switch_channel - Announce channel switch and migrate the GO to the
 	 * given frequency
 	 * @priv: Private driver interface data
-	 * @freq: Frequency in MHz
+	 * @settings: Settings for CSA period and new channel
 	 * Returns: 0 on success, -1 on failure
 	 *
 	 * This function is used to move the GO to the legacy STA channel to
 	 * avoid frequency conflict in single channel concurrency.
 	 */
-	int (*switch_channel)(void *priv, unsigned int freq);
+	int (*switch_channel)(void *priv, struct csa_settings *settings);
 
 	/**
 	 * start_dfs_cac - Listen for radar interference on the channel
 	 * @priv: Private driver interface data
-	 * @freq: Frequency (in MHz) of the channel
+	 * @freq: Channel parameters
 	 * Returns: 0 on success, -1 on failure
 	 */
-	int (*start_dfs_cac)(void *priv, int freq);
+	int (*start_dfs_cac)(void *priv, struct hostapd_freq_params *freq);
 
 	/**
 	 * stop_ap - Removes beacon from AP
@@ -2786,6 +2870,15 @@
 	 * survey.
 	 */
 	int (*get_survey)(void *priv, unsigned int freq);
+
+	/**
+	 * status - Get driver interface status information
+	 * @priv: Private driver interface data
+	 * @buf: Buffer for printing tou the status information
+	 * @buflen: Maximum length of the buffer
+	 * Returns: Length of written status information or -1 on failure
+	 */
+	int (*status)(void *priv, char *buf, size_t buflen);
 };
 
 
@@ -3961,6 +4054,11 @@
 	 */
 	struct dfs_event {
 		int freq;
+		int ht_enabled;
+		int chan_offset;
+		enum chan_width chan_width;
+		int cf1;
+		int cf2;
 	} dfs_event;
 
 	/**
@@ -3973,6 +4071,14 @@
 		unsigned int freq_filter;
 		struct dl_list survey_list; /* struct freq_survey */
 	} survey_results;
+
+	/**
+	 * channel_list_changed - Data for EVENT_CHANNEL_LIST_CHANGED
+	 * @initiator: Initiator of the regulatory change
+	 */
+	struct channel_list_changed {
+		enum reg_change_initiator initiator;
+	} channel_list_changed;
 };
 
 /**
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index c2f5934..7d301f7 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -354,19 +354,16 @@
 		return atheros_set_privacy(drv, 0);
 	}
 	if (!params->wpa && !params->ieee802_1x) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+		wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!");
 		return -1;
 	}
 	if (params->wpa && atheros_configure_wpa(drv, params) != 0) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+		wpa_printf(MSG_WARNING, "Error configuring WPA state!");
 		return -1;
 	}
 	if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
 		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+		wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!");
 		return -1;
 	}
 
@@ -872,8 +869,59 @@
 	event.rx_mgmt.frame_len = len;
 	wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
 }
+
 #endif /* CONFIG_HS20 */
 
+
+static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set,
+			       u8 qos_map_set_len)
+{
+#ifdef CONFIG_ATHEROS_QOS_MAP
+	struct atheros_driver_data *drv = ctx;
+	struct ieee80211req_athdbg req;
+	struct ieee80211_qos_map *qos_map = &req.data.qos_map;
+	struct iwreq iwr;
+	int i, up_start;
+
+	if (qos_map_set_len < 16 || qos_map_set_len > 58 ||
+	    qos_map_set_len & 1) {
+		wpa_printf(MSG_ERROR, "Invalid QoS Map");
+		return -1;
+	} else {
+		memset(&req, 0, sizeof(struct ieee80211req_athdbg));
+		req.cmd = IEEE80211_DBGREQ_SETQOSMAPCONF;
+		os_memset(&iwr, 0, sizeof(iwr));
+		os_strlcpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name));
+		iwr.u.data.pointer = (void *) &req;
+		iwr.u.data.length = sizeof(struct ieee80211req_athdbg);
+	}
+
+	qos_map->valid = 1;
+	qos_map->num_dscp_except = (qos_map_set_len - 16) / 2;
+	if (qos_map->num_dscp_except) {
+		for (i = 0; i < qos_map->num_dscp_except; i++) {
+			qos_map->dscp_exception[i].dscp	= qos_map_set[i * 2];
+			qos_map->dscp_exception[i].up =	qos_map_set[i * 2 + 1];
+		}
+	}
+
+	up_start = qos_map_set_len - 16;
+	for (i = 0; i < IEEE80211_MAX_QOS_UP_RANGE; i++) {
+		qos_map->up[i].low = qos_map_set[up_start + (i * 2)];
+		qos_map->up[i].high = qos_map_set[up_start + (i * 2) + 1];
+	}
+
+	if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_DBGREQ, &iwr) < 0) {
+		perror("ioctl[IEEE80211_IOCTL_DBGREQ]");
+		wpa_printf(MSG_DEBUG, "%s: %s: Failed to set QoS Map",
+			   __func__, drv->iface);
+		return -1;
+	}
+#endif /* CONFIG_ATHEROS_QOS_MAP */
+
+	return 0;
+}
+
 #if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
 static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf,
 				 size_t len)
@@ -1334,7 +1382,7 @@
 
 	while (1) {
 		os_memset(&iwr, 0, sizeof(iwr));
-		os_strncpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+		os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
 
 		iwr.u.data.pointer = (void *) tbuf;
 		iwr.u.data.length = sizeof(tbuf);
@@ -1963,7 +2011,7 @@
 }
 
 
-#ifdef CONFIG_WNM
+#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM)
 static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer,
 			u8 *ie, u16 *len, enum wnm_oper oper)
 {
@@ -2116,7 +2164,7 @@
 		return -1;
 	}
 }
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */
 
 
 const struct wpa_driver_ops wpa_driver_atheros_ops = {
@@ -2150,7 +2198,8 @@
 	.add_sta_node    	= atheros_add_sta_node,
 #endif /* CONFIG_IEEE80211R */
 	.send_action		= atheros_send_action,
-#ifdef CONFIG_WNM
+#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM)
 	.wnm_oper		= atheros_wnm_oper,
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */
+	.set_qos_map		= atheros_set_qos_map,
 };
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 4acb12b..45d6b19 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -72,7 +72,7 @@
 	struct ifmediareq ifmr;
 
 	(void) memset(&ifmr, 0, sizeof(ifmr));
-	(void) strncpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
+	(void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
 
 	if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
 		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c
index bb48011..0930834 100644
--- a/src/drivers/driver_madwifi.c
+++ b/src/drivers/driver_madwifi.c
@@ -182,7 +182,7 @@
 #endif /* MADWIFI_NG */
 		int idx = op - first;
 		if (first <= op &&
-		    idx < (int) (sizeof(opnames) / sizeof(opnames[0])) &&
+		    idx < (int) ARRAY_SIZE(opnames) &&
 		    opnames[idx])
 			perror(opnames[idx]);
 		else
@@ -322,19 +322,16 @@
 			IEEE80211_AUTH_AUTO);
 	}
 	if (!params->wpa && !params->ieee802_1x) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+		wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!");
 		return -1;
 	}
 	if (params->wpa && madwifi_configure_wpa(drv, params) != 0) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+		wpa_printf(MSG_WARNING, "Error configuring WPA state!");
 		return -1;
 	}
 	if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
 		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+		wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!");
 		return -1;
 	}
 
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index a3ff189..eaca172 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -109,6 +109,17 @@
 #endif /* CONFIG_LIBNL20 */
 
 
+#ifdef ANDROID
+/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
+static int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+{
+	return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
+}
+#undef nl_socket_set_nonblocking
+#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
+#endif /* ANDROID */
+
+
 static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
 {
 	struct nl_handle *handle;
@@ -140,6 +151,31 @@
 }
 
 
+#if __WORDSIZE == 64
+#define ELOOP_SOCKET_INVALID	(intptr_t) 0x8888888888888889ULL
+#else
+#define ELOOP_SOCKET_INVALID	(intptr_t) 0x88888889ULL
+#endif
+
+static void nl80211_register_eloop_read(struct nl_handle **handle,
+					eloop_sock_handler handler,
+					void *eloop_data)
+{
+	nl_socket_set_nonblocking(*handle);
+	eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
+				 eloop_data, *handle);
+	*handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+}
+
+
+static void nl80211_destroy_eloop_handle(struct nl_handle **handle)
+{
+	*handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+	eloop_unregister_read_sock(nl_socket_get_fd(*handle));
+	nl_destroy_handles(handle);
+}
+
+
 #ifndef IFF_LOWER_UP
 #define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
 #endif
@@ -193,6 +229,7 @@
 	unsigned int added_bridge:1;
 	unsigned int in_deinit:1;
 	unsigned int wdev_id_set:1;
+	unsigned int added_if:1;
 
 	u8 addr[ETH_ALEN];
 
@@ -226,6 +263,11 @@
 	int operstate;
 
 	int scan_complete_events;
+	enum scan_states {
+		NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED,
+		SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED,
+		SCHED_SCAN_RESULTS
+	} scan_state;
 
 	struct nl_cb *nl_cb;
 
@@ -255,6 +297,10 @@
 	unsigned int use_monitor:1;
 	unsigned int ignore_next_local_disconnect:1;
 	unsigned int allow_p2p_device:1;
+	unsigned int hostapd:1;
+	unsigned int start_mode_ap:1;
+	unsigned int start_iface_up:1;
+	unsigned int channel_switch_supported:1;
 
 	u64 remain_on_chan_cookie;
 	u64 send_action_cookie;
@@ -264,21 +310,16 @@
 	struct wpa_driver_scan_filter *filter_ssids;
 	size_t num_filter_ssids;
 
-	struct i802_bss first_bss;
+	struct i802_bss *first_bss;
 
 	int eapol_tx_sock;
 
-#ifdef HOSTAPD
 	int eapol_sock; /* socket for EAPOL frames */
 
 	int default_if_indices[16];
 	int *if_indices;
 	int num_if_indices;
 
-	int last_freq;
-	int last_freq_ht;
-#endif /* HOSTAPD */
-
 	/* From failed authentication command */
 	int auth_freq;
 	u8 auth_bssid_[ETH_ALEN];
@@ -301,7 +342,8 @@
 static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
 				       enum nl80211_iftype nlmode);
 static int
-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
+				   const u8 *set_addr, int first);
 static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
 				   const u8 *addr, int cmd, u16 reason_code,
 				   int local_state_change);
@@ -320,41 +362,24 @@
 static int android_pno_start(struct i802_bss *bss,
 			     struct wpa_driver_scan_params *params);
 static int android_pno_stop(struct i802_bss *bss);
+extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+					 size_t buf_len);
 #endif /* ANDROID */
 #ifdef ANDROID_P2P
 int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
 int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
 int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
 int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
-				  const struct wpabuf *proberesp,
-				  const struct wpabuf *assocresp);
+				 const struct wpabuf *proberesp,
+				 const struct wpabuf *assocresp);
+#endif /* ANDROID_P2P */
 
-#endif
-#ifdef HOSTAPD
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
 					enum wpa_driver_if_type type,
 					const char *ifname);
-#else /* HOSTAPD */
-static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-}
-
-static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-}
-
-static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-	return 0;
-}
-#endif /* HOSTAPD */
-#ifdef ANDROID
-extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
-					 size_t buf_len);
-#endif
 
 static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
 				       struct hostapd_freq_params *freq);
@@ -575,8 +600,14 @@
 		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
 			  valid_handler, valid_data);
 
-	while (err > 0)
-		nl_recvmsgs(nl_handle, cb);
+	while (err > 0) {
+		int res = nl_recvmsgs(nl_handle, cb);
+		if (res) {
+			wpa_printf(MSG_INFO,
+				   "nl80211: %s->nl_recvmsgs failed: %d",
+				   __func__, res);
+		}
+	}
  out:
 	nl_cb_put(cb);
 	nlmsg_free(msg);
@@ -594,10 +625,7 @@
 }
 
 
-#ifndef ANDROID
-static
-#endif
-int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
+static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
 			      struct nl_msg *msg,
 			      int (*valid_handler)(struct nl_msg *, void *),
 			      void *valid_data)
@@ -772,7 +800,6 @@
 }
 
 
-#ifndef HOSTAPD
 static int nl80211_get_macaddr(struct i802_bss *bss)
 {
 	struct nl_msg *msg;
@@ -794,7 +821,6 @@
 	nlmsg_free(msg);
 	return NL80211_IFTYPE_UNSPECIFIED;
 }
-#endif /* HOSTAPD */
 
 
 static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
@@ -829,10 +855,15 @@
 static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
 {
 	struct nl80211_wiphy_data *w = eloop_ctx;
+	int res;
 
 	wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
 
-	nl_recvmsgs(handle, w->nl_cb);
+	res = nl_recvmsgs(handle, w->nl_cb);
+	if (res) {
+		wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
+			   __func__, res);
+	}
 }
 
 
@@ -916,8 +947,7 @@
 		return NULL;
 	}
 
-	eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
-				 nl80211_recv_beacons, w, w->nl_beacons);
+	nl80211_register_eloop_read(&w->nl_beacons, nl80211_recv_beacons, w);
 
 	dl_list_add(&nl80211_wiphys, &w->list);
 
@@ -964,10 +994,9 @@
 	if (!dl_list_empty(&w->bsss))
 		return;
 
-	eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
+	nl80211_destroy_eloop_handle(&w->nl_beacons);
 
 	nl_cb_put(w->nl_cb);
-	nl_destroy_handles(&w->nl_beacons);
 	dl_list_del(&w->list);
 	os_free(w);
 }
@@ -1012,7 +1041,8 @@
 		   event.interface_status.ifname,
 		   del ? "removed" : "added");
 
-	if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
+	if (os_strcmp(drv->first_bss->ifname, event.interface_status.ifname) ==
+	    0) {
 		if (del) {
 			if (drv->if_removed) {
 				wpa_printf(MSG_DEBUG, "nl80211: if_removed "
@@ -1021,11 +1051,11 @@
 			}
 			drv->if_removed = 1;
 		} else {
-			if (if_nametoindex(drv->first_bss.ifname) == 0) {
+			if (if_nametoindex(drv->first_bss->ifname) == 0) {
 				wpa_printf(MSG_DEBUG, "nl80211: Interface %s "
 					   "does not exist - ignore "
 					   "RTM_NEWLINK",
-					   drv->first_bss.ifname);
+					   drv->first_bss->ifname);
 				return;
 			}
 			if (!drv->if_removed) {
@@ -1053,8 +1083,8 @@
 	rta_len = RTA_ALIGN(sizeof(struct rtattr));
 	while (RTA_OK(attr, attrlen)) {
 		if (attr->rta_type == IFLA_IFNAME) {
-			if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
-			    == 0)
+			if (os_strcmp(((char *) attr) + rta_len,
+				      drv->first_bss->ifname) == 0)
 				return 1;
 			else
 				break;
@@ -1075,7 +1105,7 @@
 	if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
 			   "interface");
-		wpa_driver_nl80211_finish_drv_init(drv);
+		wpa_driver_nl80211_finish_drv_init(drv, NULL, 0);
 		return 1;
 	}
 
@@ -1126,7 +1156,7 @@
 	if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
 		if (if_indextoname(ifi->ifi_index, namebuf) &&
 		    linux_iface_up(drv->global->ioctl_sock,
-				   drv->first_bss.ifname) > 0) {
+				   drv->first_bss->ifname) > 0) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
 				   "event since interface %s is up", namebuf);
 			return;
@@ -1146,18 +1176,18 @@
 	if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
 		if (if_indextoname(ifi->ifi_index, namebuf) &&
 		    linux_iface_up(drv->global->ioctl_sock,
-				   drv->first_bss.ifname) == 0) {
+				   drv->first_bss->ifname) == 0) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
 				   "event since interface %s is down",
 				   namebuf);
-		} else if (if_nametoindex(drv->first_bss.ifname) == 0) {
+		} else if (if_nametoindex(drv->first_bss->ifname) == 0) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
 				   "event since interface %s does not exist",
-				   drv->first_bss.ifname);
+				   drv->first_bss->ifname);
 		} else if (drv->if_removed) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
 				   "event since interface %s is marked "
-				   "removed", drv->first_bss.ifname);
+				   "removed", drv->first_bss->ifname);
 		} else {
 			wpa_printf(MSG_DEBUG, "nl80211: Interface up");
 			drv->if_disabled = 0;
@@ -1483,6 +1513,8 @@
 	data.ch_switch.ht_enabled = ht_enabled;
 	data.ch_switch.ch_offset = chan_offset;
 
+	drv->first_bss->freq = data.ch_switch.freq;
+
 	wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
 }
 
@@ -1520,6 +1552,7 @@
 	union wpa_event_data event;
 	u16 fc, stype;
 	int ssi_signal = 0;
+	int rx_freq = 0;
 
 	wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
 	mgmt = (const struct ieee80211_mgmt *) frame;
@@ -1537,8 +1570,11 @@
 	os_memset(&event, 0, sizeof(event));
 	if (freq) {
 		event.rx_action.freq = nla_get_u32(freq);
-		drv->last_mgmt_freq = event.rx_action.freq;
+		rx_freq = drv->last_mgmt_freq = event.rx_action.freq;
 	}
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: RX frame freq=%d ssi_signal=%d stype=%u len=%u",
+		   rx_freq, ssi_signal, stype, (unsigned int) len);
 	if (stype == WLAN_FC_STYPE_ACTION) {
 		event.rx_action.da = mgmt->da;
 		event.rx_action.sa = mgmt->sa;
@@ -1653,7 +1689,7 @@
 
 	if (type == EVENT_DISASSOC) {
 		event.disassoc_info.locally_generated =
-			!os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+			!os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
 		event.disassoc_info.addr = bssid;
 		event.disassoc_info.reason_code = reason_code;
 		if (frame + len > mgmt->u.disassoc.variable) {
@@ -1663,7 +1699,7 @@
 		}
 	} else {
 		event.deauth_info.locally_generated =
-			!os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+			!os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
 		event.deauth_info.addr = bssid;
 		event.deauth_info.reason_code = reason_code;
 		if (frame + len > mgmt->u.deauth.variable) {
@@ -1836,8 +1872,6 @@
 static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
 				 struct nlattr *tb[])
 {
-	u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
-
 	if (tb[NL80211_ATTR_MAC] == NULL) {
 		wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
 			   "event");
@@ -1845,10 +1879,6 @@
 	}
 	os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
 
-	/* register for any AUTH message */
-	nl80211_register_frame(&drv->first_bss, drv->first_bss.nl_mgmt,
-			       type, NULL, 0);
-
 	drv->associated = 1;
 	wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
 		   MAC2STR(drv->bssid));
@@ -2504,6 +2534,8 @@
 }
 
 
+static enum chan_width convert2width(int width);
+
 static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
 				struct nlattr **tb)
 {
@@ -2514,11 +2546,43 @@
 		return;
 
 	os_memset(&data, 0, sizeof(data));
-	data.dfs_event.freq = nla_get_u16(tb[NL80211_ATTR_WIPHY_FREQ]);
-	event_type = nla_get_u8(tb[NL80211_ATTR_RADAR_EVENT]);
+	data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+	event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
 
-	wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
-		   data.dfs_event.freq);
+	/* Check HT params */
+	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+		data.dfs_event.ht_enabled = 1;
+		data.dfs_event.chan_offset = 0;
+
+		switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
+		case NL80211_CHAN_NO_HT:
+			data.dfs_event.ht_enabled = 0;
+			break;
+		case NL80211_CHAN_HT20:
+			break;
+		case NL80211_CHAN_HT40PLUS:
+			data.dfs_event.chan_offset = 1;
+			break;
+		case NL80211_CHAN_HT40MINUS:
+			data.dfs_event.chan_offset = -1;
+			break;
+		}
+	}
+
+	/* Get VHT params */
+	if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+		data.dfs_event.chan_width =
+			convert2width(nla_get_u32(
+					      tb[NL80211_ATTR_CHANNEL_WIDTH]));
+	if (tb[NL80211_ATTR_CENTER_FREQ1])
+		data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+	if (tb[NL80211_ATTR_CENTER_FREQ2])
+		data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+	wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
+		   data.dfs_event.freq, data.dfs_event.ht_enabled,
+		   data.dfs_event.chan_offset, data.dfs_event.chan_width,
+		   data.dfs_event.cf1, data.dfs_event.cf2);
 
 	switch (event_type) {
 	case NL80211_RADAR_DETECTED:
@@ -2563,6 +2627,7 @@
 				 struct nlattr **tb)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
+	union wpa_event_data data;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
 		   cmd, nl80211_command_to_string(cmd), bss->ifname);
@@ -2570,7 +2635,7 @@
 	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
 	    (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
 	     cmd == NL80211_CMD_SCAN_ABORTED)) {
-		wpa_driver_nl80211_set_mode(&drv->first_bss,
+		wpa_driver_nl80211_set_mode(drv->first_bss,
 					    drv->ap_scan_as_station);
 		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 	}
@@ -2578,17 +2643,21 @@
 	switch (cmd) {
 	case NL80211_CMD_TRIGGER_SCAN:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
+		drv->scan_state = SCAN_STARTED;
 		break;
 	case NL80211_CMD_START_SCHED_SCAN:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
+		drv->scan_state = SCHED_SCAN_STARTED;
 		break;
 	case NL80211_CMD_SCHED_SCAN_STOPPED:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
+		drv->scan_state = SCHED_SCAN_STOPPED;
 		wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
 		break;
 	case NL80211_CMD_NEW_SCAN_RESULTS:
 		wpa_dbg(drv->ctx, MSG_DEBUG,
 			"nl80211: New scan results available");
+		drv->scan_state = SCAN_COMPLETED;
 		drv->scan_complete_events = 1;
 		eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
 				     drv->ctx);
@@ -2597,10 +2666,12 @@
 	case NL80211_CMD_SCHED_SCAN_RESULTS:
 		wpa_dbg(drv->ctx, MSG_DEBUG,
 			"nl80211: New sched scan results available");
+		drv->scan_state = SCHED_SCAN_RESULTS;
 		send_scan_event(drv, 0, tb);
 		break;
 	case NL80211_CMD_SCAN_ABORTED:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
+		drv->scan_state = SCAN_ABORTED;
 		/*
 		 * Need to indicate that scan results are available in order
 		 * not to make wpa_supplicant stop its scanning.
@@ -2656,8 +2727,33 @@
 		break;
 	case NL80211_CMD_REG_CHANGE:
 		wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+		if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
+			break;
+		os_memset(&data, 0, sizeof(data));
+		switch (nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])) {
+		case NL80211_REGDOM_SET_BY_CORE:
+			data.channel_list_changed.initiator =
+				REGDOM_SET_BY_CORE;
+			break;
+		case NL80211_REGDOM_SET_BY_USER:
+			data.channel_list_changed.initiator =
+				REGDOM_SET_BY_USER;
+			break;
+		case NL80211_REGDOM_SET_BY_DRIVER:
+			data.channel_list_changed.initiator =
+				REGDOM_SET_BY_DRIVER;
+			break;
+		case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+			data.channel_list_changed.initiator =
+				REGDOM_SET_BY_COUNTRY_IE;
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "nl80211: Unknown reg change initiator %d received",
+				   nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]));
+			break;
+		}
 		wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
-				     NULL);
+				     &data);
 		break;
 	case NL80211_CMD_REG_BEACON_HINT:
 		wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
@@ -2716,7 +2812,7 @@
 	if (tb[NL80211_ATTR_IFINDEX]) {
 		ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
-		for (bss = &drv->first_bss; bss; bss = bss->next)
+		for (bss = drv->first_bss; bss; bss = bss->next)
 			if (ifidx == -1 || ifidx == bss->ifindex) {
 				do_process_drv_event(bss, gnlh->cmd, tb);
 				return NL_SKIP;
@@ -2727,7 +2823,7 @@
 	} else if (tb[NL80211_ATTR_WDEV]) {
 		u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
 		wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
-		for (bss = &drv->first_bss; bss; bss = bss->next) {
+		for (bss = drv->first_bss; bss; bss = bss->next) {
 			if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
 				do_process_drv_event(bss, gnlh->cmd, tb);
 				return NL_SKIP;
@@ -2765,7 +2861,7 @@
 
 	dl_list_for_each_safe(drv, tmp, &global->interfaces,
 			      struct wpa_driver_nl80211_data, list) {
-		for (bss = &drv->first_bss; bss; bss = bss->next) {
+		for (bss = drv->first_bss; bss; bss = bss->next) {
 			if ((ifidx == -1 && !wdev_id_set) ||
 			    ifidx == bss->ifindex ||
 			    (wdev_id_set && bss->wdev_id_set &&
@@ -2822,10 +2918,15 @@
 					     void *handle)
 {
 	struct nl_cb *cb = eloop_ctx;
+	int res;
 
 	wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
 
-	nl_recvmsgs(handle, cb);
+	res = nl_recvmsgs(handle, cb);
+	if (res) {
+		wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
+			   __func__, res);
+	}
 }
 
 
@@ -2865,6 +2966,44 @@
 }
 
 
+static int nl80211_get_country(struct nl_msg *msg, void *arg)
+{
+	char *alpha2 = arg;
+	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) {
+		wpa_printf(MSG_DEBUG, "nl80211: No country information available");
+		return NL_SKIP;
+	}
+	os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
+	return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+	alpha2[0] = '\0';
+	ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2);
+	if (!alpha2[0])
+		ret = -1;
+
+	return ret;
+}
+
+
 static int protocol_feature_handler(struct nl_msg *msg, void *arg)
 {
 	u32 *feat = arg;
@@ -2917,6 +3056,7 @@
 	unsigned int p2p_go_supported:1;
 	unsigned int p2p_client_supported:1;
 	unsigned int p2p_concurrent:1;
+	unsigned int channel_switch_supported:1;
 };
 
 
@@ -3074,6 +3214,9 @@
 		case NL80211_CMD_PROBE_CLIENT:
 			info->poll_command_supported = 1;
 			break;
+		case NL80211_CMD_CHANNEL_SWITCH:
+			info->channel_switch_supported = 1;
+			break;
 		}
 	}
 }
@@ -3156,7 +3299,7 @@
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
 	if (tb[NL80211_ATTR_WIPHY_NAME])
-		os_strncpy(drv->phyname,
+		os_strlcpy(drv->phyname,
 			   nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
 			   sizeof(drv->phyname));
 	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
@@ -3255,7 +3398,7 @@
 		nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
 	NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
-	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+	if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
 		goto nla_put_failure;
 
 	if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
@@ -3335,21 +3478,13 @@
 	drv->device_ap_sme = info.device_ap_sme;
 	drv->poll_command_supported = info.poll_command_supported;
 	drv->data_tx_status = info.data_tx_status;
+	drv->channel_switch_supported = info.channel_switch_supported;
 
-#ifdef ANDROID_P2P
-	if(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
-		/* Driver is new enough to support monitorless mode*/
-		wpa_printf(MSG_DEBUG, "nl80211: Driver is new "
-			  "enough to support monitor-less mode");
-		drv->use_monitor = 0;
-	}
-#else
 	/*
 	 * If poll command and tx status are supported, mac80211 is new enough
 	 * to have everything we need to not need monitor interfaces.
 	 */
 	drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
-#endif
 
 	if (drv->device_ap_sme && drv->use_monitor) {
 		/*
@@ -3474,9 +3609,9 @@
 	nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
 		  process_global_event, global);
 
-	eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
-				 wpa_driver_nl80211_event_receive,
-				 global->nl_cb, global->nl_event);
+	nl80211_register_eloop_read(&global->nl_event,
+				    wpa_driver_nl80211_event_receive,
+				    global->nl_cb);
 
 	return 0;
 
@@ -3520,7 +3655,7 @@
 {
 	struct wpa_driver_nl80211_data *drv = ctx;
 	wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
-	if (i802_set_iface_flags(&drv->first_bss, 1)) {
+	if (i802_set_iface_flags(drv->first_bss, 1)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
 			   "after rfkill unblock");
 		return;
@@ -3610,16 +3745,9 @@
 }
 
 
-/**
- * wpa_driver_nl80211_init - Initialize nl80211 driver interface
- * @ctx: context to be used when calling wpa_supplicant functions,
- * e.g., wpa_supplicant_event()
- * @ifname: interface name, e.g., wlan0
- * @global_priv: private driver global data from global_init()
- * Returns: Pointer to private data, %NULL on failure
- */
-static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
-				      void *global_priv)
+static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
+					  void *global_priv, int hostapd,
+					  const u8 *set_addr)
 {
 	struct wpa_driver_nl80211_data *drv;
 	struct rfkill_config *rcfg;
@@ -3632,7 +3760,17 @@
 		return NULL;
 	drv->global = global_priv;
 	drv->ctx = ctx;
-	bss = &drv->first_bss;
+	drv->hostapd = !!hostapd;
+	drv->eapol_sock = -1;
+	drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
+	drv->if_indices = drv->default_if_indices;
+
+	drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
+	if (!drv->first_bss) {
+		os_free(drv);
+		return NULL;
+	}
+	bss = drv->first_bss;
 	bss->drv = drv;
 	bss->ctx = ctx;
 
@@ -3663,7 +3801,10 @@
 		os_free(rcfg);
 	}
 
-	if (wpa_driver_nl80211_finish_drv_init(drv))
+	if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
+		drv->start_iface_up = 1;
+
+	if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1))
 		goto failed;
 
 	drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
@@ -3701,6 +3842,21 @@
 }
 
 
+/**
+ * wpa_driver_nl80211_init - Initialize nl80211 driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * @global_priv: private driver global data from global_init()
+ * Returns: Pointer to private data, %NULL on failure
+ */
+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
+				      void *global_priv)
+{
+	return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL);
+}
+
+
 static int nl80211_register_frame(struct i802_bss *bss,
 				  struct nl_handle *nl_handle,
 				  u16 type, const u8 *match, size_t match_len)
@@ -3757,14 +3913,18 @@
 	if (bss->nl_mgmt == NULL)
 		return -1;
 
-	eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
-				 wpa_driver_nl80211_event_receive, bss->nl_cb,
-				 bss->nl_mgmt);
-
 	return 0;
 }
 
 
+static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
+{
+	nl80211_register_eloop_read(&bss->nl_mgmt,
+				    wpa_driver_nl80211_event_receive,
+				    bss->nl_cb);
+}
+
+
 static int nl80211_register_action_frame(struct i802_bss *bss,
 					 const u8 *match, size_t match_len)
 {
@@ -3783,6 +3943,18 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
 		   "handle %p", bss->nl_mgmt);
 
+	if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
+		u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
+
+		/* register for any AUTH message */
+		nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0);
+	}
+
+#ifdef CONFIG_INTERWORKING
+	/* QoS Map Configure */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
+		return -1;
+#endif /* CONFIG_INTERWORKING */
 #if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
 	/* GAS Initial Request */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
@@ -3837,6 +4009,8 @@
 	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
 		return -1;
 
+	nl80211_mgmt_handle_register_eloop(bss);
+
 	return 0;
 }
 
@@ -3894,7 +4068,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
 		   "handle %p", bss->nl_mgmt);
 
-	for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(stypes); i++) {
 		if (nl80211_register_frame(bss, bss->nl_mgmt,
 					   (WLAN_FC_TYPE_MGMT << 2) |
 					   (stypes[i] << 4),
@@ -3909,10 +4083,10 @@
 	if (nl80211_get_wiphy_data_ap(bss) == NULL)
 		goto out_err;
 
+	nl80211_mgmt_handle_register_eloop(bss);
 	return 0;
 
 out_err:
-	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
 	nl_destroy_handles(&bss->nl_mgmt);
 	return -1;
 }
@@ -3931,10 +4105,10 @@
 				   NULL, 0) < 0)
 		goto out_err;
 
+	nl80211_mgmt_handle_register_eloop(bss);
 	return 0;
 
 out_err:
-	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
 	nl_destroy_handles(&bss->nl_mgmt);
 	return -1;
 }
@@ -3946,8 +4120,7 @@
 		return;
 	wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
 		   "(%s)", bss->nl_mgmt, reason);
-	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
-	nl_destroy_handles(&bss->nl_mgmt);
+	nl80211_destroy_eloop_handle(&bss->nl_mgmt);
 
 	nl80211_put_wiphy_data_ap(bss);
 }
@@ -3977,7 +4150,7 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
 		   bss->ifname, (long long unsigned int) bss->wdev_id,
-		   strerror(ret));
+		   strerror(-ret));
 
 nla_put_failure:
 	nlmsg_free(msg);
@@ -4007,7 +4180,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
 		   start ? "Start" : "Stop",
 		   bss->ifname, (long long unsigned int) bss->wdev_id,
-		   strerror(ret));
+		   strerror(-ret));
 
 nla_put_failure:
 	nlmsg_free(msg);
@@ -4031,13 +4204,12 @@
 
 
 static int
-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
+				   const u8 *set_addr, int first)
 {
-#ifndef HOSTAPD
-	enum nl80211_iftype nlmode = NL80211_IFTYPE_STATION;
-#endif /* HOSTAPD */
-	struct i802_bss *bss = &drv->first_bss;
+	struct i802_bss *bss = drv->first_bss;
 	int send_rfkill_event = 0;
+	enum nl80211_iftype nlmode;
 
 	drv->ifindex = if_nametoindex(bss->ifname);
 	bss->ifindex = drv->ifindex;
@@ -4054,20 +4226,26 @@
 	wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
 		   bss->ifname, drv->phyname);
 
-#ifndef HOSTAPD
-	if (bss->if_dynamic)
-		nlmode = nl80211_get_ifmode(bss);
+	if (set_addr &&
+	    (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) ||
+	     linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+				set_addr)))
+		return -1;
 
-	/*
-	 * Make sure the interface starts up in station mode unless this is a
-	 * dynamically added interface (e.g., P2P) that was already configured
-	 * with proper iftype.
-	 */
+	if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
+		drv->start_mode_ap = 1;
+
+	if (drv->hostapd)
+		nlmode = NL80211_IFTYPE_AP;
+	else if (bss->if_dynamic)
+		nlmode = nl80211_get_ifmode(bss);
+	else
+		nlmode = NL80211_IFTYPE_STATION;
+
 	if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to use managed mode");
+		wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
 		return -1;
 	}
-	drv->nlmode = nlmode;
 
 	if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
 		int ret = nl80211_set_p2pdev(bss, 1);
@@ -4091,9 +4269,9 @@
 		}
 	}
 
-	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
-			       1, IF_OPER_DORMANT);
-#endif /* HOSTAPD */
+	if (!drv->hostapd)
+		netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
+				       1, IF_OPER_DORMANT);
 
 	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
 			       bss->addr))
@@ -4116,6 +4294,8 @@
 	if (!msg)
 		return -ENOMEM;
 
+	wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
+		   drv->ifindex);
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
@@ -4164,15 +4344,6 @@
 	if (is_ap_interface(drv->nlmode))
 		wpa_driver_nl80211_del_beacon(drv);
 
-#ifdef HOSTAPD
-	if (drv->last_freq_ht) {
-		/* Clear HT flags from the driver */
-		struct hostapd_freq_params freq;
-		os_memset(&freq, 0, sizeof(freq));
-		freq.freq = drv->last_freq;
-		wpa_driver_nl80211_set_freq(bss, &freq);
-	}
-
 	if (drv->eapol_sock >= 0) {
 		eloop_unregister_read_sock(drv->eapol_sock);
 		close(drv->eapol_sock);
@@ -4180,7 +4351,6 @@
 
 	if (drv->if_indices != drv->default_if_indices)
 		os_free(drv->if_indices);
-#endif /* HOSTAPD */
 
 	if (drv->disabled_11b_rates)
 		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
@@ -4191,9 +4361,12 @@
 
 	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-	(void) i802_set_iface_flags(bss, 0);
+	if (!drv->start_iface_up)
+		(void) i802_set_iface_flags(bss, 0);
 	if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
-		wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
+		if (!drv->hostapd || !drv->start_mode_ap)
+			wpa_driver_nl80211_set_mode(bss,
+						    NL80211_IFTYPE_STATION);
 		nl80211_mgmt_unsubscribe(bss, "deinit");
 	} else {
 		nl80211_mgmt_unsubscribe(bss, "deinit");
@@ -4201,7 +4374,7 @@
 	}
 	nl_cb_put(drv->nl_cb);
 
-	nl80211_destroy_bss(&drv->first_bss);
+	nl80211_destroy_bss(drv->first_bss);
 
 	os_free(drv->filter_ssids);
 
@@ -4212,6 +4385,7 @@
 
 	os_free(drv->extended_capa);
 	os_free(drv->extended_capa_mask);
+	os_free(drv->first_bss);
 	os_free(drv);
 }
 
@@ -4228,7 +4402,7 @@
 {
 	struct wpa_driver_nl80211_data *drv = eloop_ctx;
 	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
-		wpa_driver_nl80211_set_mode(&drv->first_bss,
+		wpa_driver_nl80211_set_mode(drv->first_bss,
 					    drv->ap_scan_as_station);
 		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 	}
@@ -4356,8 +4530,7 @@
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
-#ifdef HOSTAPD
-		if (is_ap_interface(drv->nlmode)) {
+		if (drv->hostapd && is_ap_interface(drv->nlmode)) {
 			/*
 			 * mac80211 does not allow scan requests in AP mode, so
 			 * try to do this in station mode.
@@ -4376,11 +4549,9 @@
 			ret = 0;
 		} else
 			goto nla_put_failure;
-#else /* HOSTAPD */
-		goto nla_put_failure;
-#endif /* HOSTAPD */
 	}
 
+	drv->scan_state = SCAN_REQUESTED;
 	/* Not all drivers generate "scan completed" wireless event, so try to
 	 * read results after a timeout. */
 	timeout = 10;
@@ -4832,7 +5003,7 @@
 		goto nla_put_failure;
 
 	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
-	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+	if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
 		goto nla_put_failure;
 
 	arg.drv = drv;
@@ -5475,7 +5646,7 @@
 	struct wpa_driver_nl80211_data *drv)
 {
 	struct wpa_driver_auth_params params;
-	struct i802_bss *bss = &drv->first_bss;
+	struct i802_bss *bss = drv->first_bss;
 	int i;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
@@ -5572,10 +5743,6 @@
 	if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
 		chan->flag |= HOSTAPD_CHAN_RADAR;
 
-	if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
-	    !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
-		chan->max_tx_power = nla_get_u32(
-			tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
 	if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
 		enum nl80211_dfs_state state =
 			nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
@@ -5898,6 +6065,38 @@
 }
 
 
+static void nl80211_reg_rule_max_eirp(struct nlattr *tb[],
+				      struct phy_info_arg *results)
+{
+	u32 start, end, max_eirp;
+	u16 m;
+
+	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+	    tb[NL80211_ATTR_POWER_RULE_MAX_EIRP] == NULL)
+		return;
+
+	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+	max_eirp = nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
+
+	wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u mBm",
+		   start, end, max_eirp);
+
+	for (m = 0; m < *results->num_modes; m++) {
+		int c;
+		struct hostapd_hw_modes *mode = &results->modes[m];
+
+		for (c = 0; c < mode->num_channels; c++) {
+			struct hostapd_channel_data *chan = &mode->channels[c];
+			if ((u32) chan->freq - 10 >= start &&
+			    (u32) chan->freq + 10 <= end)
+				chan->max_tx_power = max_eirp;
+		}
+	}
+}
+
+
 static void nl80211_reg_rule_ht40(struct nlattr *tb[],
 				  struct phy_info_arg *results)
 {
@@ -5954,6 +6153,59 @@
 }
 
 
+static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
+				 int end)
+{
+	int c;
+
+	for (c = 0; c < mode->num_channels; c++) {
+		struct hostapd_channel_data *chan = &mode->channels[c];
+		if (chan->freq - 10 >= start && chan->freq + 70 <= end)
+			chan->flag |= HOSTAPD_CHAN_VHT_10_70;
+
+		if (chan->freq - 30 >= start && chan->freq + 50 <= end)
+			chan->flag |= HOSTAPD_CHAN_VHT_30_50;
+
+		if (chan->freq - 50 >= start && chan->freq + 30 <= end)
+			chan->flag |= HOSTAPD_CHAN_VHT_50_30;
+
+		if (chan->freq - 70 >= start && chan->freq + 10 <= end)
+			chan->flag |= HOSTAPD_CHAN_VHT_70_10;
+	}
+}
+
+
+static void nl80211_reg_rule_vht(struct nlattr *tb[],
+				 struct phy_info_arg *results)
+{
+	u32 start, end, max_bw;
+	u16 m;
+
+	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+		return;
+
+	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+	if (max_bw < 80)
+		return;
+
+	for (m = 0; m < *results->num_modes; m++) {
+		if (!(results->modes[m].ht_capab &
+		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+			continue;
+		/* TODO: use a real VHT support indication */
+		if (!results->modes[m].vht_capab)
+			continue;
+
+		nl80211_set_vht_mode(&results->modes[m], start, end);
+	}
+}
+
+
 static int nl80211_get_reg(struct nl_msg *msg, void *arg)
 {
 	struct phy_info_arg *results = arg;
@@ -5988,6 +6240,7 @@
 		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
 			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
 		nl80211_reg_rule_ht40(tb_rule, results);
+		nl80211_reg_rule_max_eirp(tb_rule, results);
 	}
 
 	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
@@ -5997,12 +6250,19 @@
 		nl80211_reg_rule_sec(tb_rule, results);
 	}
 
+	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+	{
+		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+		nl80211_reg_rule_vht(tb_rule, results);
+	}
+
 	return NL_SKIP;
 }
 
 
-static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
-				  struct phy_info_arg *results)
+static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
+					struct phy_info_arg *results)
 {
 	struct nl_msg *msg;
 
@@ -6045,7 +6305,7 @@
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
 	if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
-		nl80211_set_ht40_flags(drv, &result);
+		nl80211_set_regulatory_flags(drv, &result);
 		return wpa_driver_nl80211_postprocess_modes(result.modes,
 							    num_modes);
 	}
@@ -6121,16 +6381,42 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	u64 cookie;
+	int res;
 
-	if (freq == 0)
+	if (freq == 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: send_frame - Use bss->freq=%u",
+			   bss->freq);
 		freq = bss->freq;
+	}
 
-	if (drv->use_monitor)
+	if (drv->use_monitor) {
+		wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_mntr",
+			   freq, bss->freq);
 		return wpa_driver_nl80211_send_mntr(drv, data, len,
 						    encrypt, noack);
+	}
 
-	return nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
-				      &cookie, no_cck, noack, offchanok);
+	wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
+	res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
+				     &cookie, no_cck, noack, offchanok);
+	if (res == 0 && !noack) {
+		const struct ieee80211_mgmt *mgmt;
+		u16 fc;
+
+		mgmt = (const struct ieee80211_mgmt *) data;
+		fc = le_to_host16(mgmt->frame_control);
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
+			wpa_printf(MSG_MSGDUMP,
+				   "nl80211: Update send_action_cookie from 0x%llx to 0x%llx",
+				   (long long unsigned int)
+				   drv->send_action_cookie,
+				   (long long unsigned int) cookie);
+			drv->send_action_cookie = cookie;
+		}
+	}
+
+	return res;
 }
 
 
@@ -6147,6 +6433,8 @@
 
 	mgmt = (struct ieee80211_mgmt *) data;
 	fc = le_to_host16(mgmt->frame_control);
+	wpa_printf(MSG_DEBUG, "nl80211: send_mlme - noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x nlmode=%d",
+		   noack, freq, no_cck, offchanok, wait_time, fc, drv->nlmode);
 
 	if ((is_sta_interface(drv->nlmode) ||
 	     drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
@@ -6157,16 +6445,22 @@
 		 * but it works due to the single-threaded nature
 		 * of wpa_supplicant.
 		 */
-		if (freq == 0)
+		if (freq == 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Use last_mgmt_freq=%d",
+				   drv->last_mgmt_freq);
 			freq = drv->last_mgmt_freq;
+		}
 		return nl80211_send_frame_cmd(bss, freq, 0,
 					      data, data_len, NULL, 1, noack,
 					      1);
 	}
 
 	if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
-		if (freq == 0)
+		if (freq == 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d",
+				   bss->freq);
 			freq = bss->freq;
+		}
 		return nl80211_send_frame_cmd(bss, freq,
 					      (int) freq == bss->freq ? 0 :
 					      wait_time,
@@ -6189,6 +6483,7 @@
 			encrypt = 0;
 	}
 
+	wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame");
 	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
 					     noack, freq, no_cck, offchanok,
 					     wait_time);
@@ -6486,24 +6781,9 @@
 }
 
 
-static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
-				       struct hostapd_freq_params *freq)
+static int nl80211_put_freq_params(struct nl_msg *msg,
+				   struct hostapd_freq_params *freq)
 {
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d,"
-		   " bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
-		   freq->freq, freq->ht_enabled, freq->vht_enabled,
-		   freq->bandwidth, freq->center_freq1, freq->center_freq2);
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
 	if (freq->vht_enabled) {
 		switch (freq->bandwidth) {
@@ -6528,7 +6808,7 @@
 				    NL80211_CHAN_WIDTH_160);
 			break;
 		default:
-			return -1;
+			return -EINVAL;
 		}
 		NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
 		if (freq->center_freq2)
@@ -6550,6 +6830,33 @@
 			break;
 		}
 	}
+	return 0;
+
+nla_put_failure:
+	return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
+				       struct hostapd_freq_params *freq)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+		   freq->freq, freq->ht_enabled, freq->vht_enabled,
+		   freq->bandwidth, freq->center_freq1, freq->center_freq2);
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (nl80211_put_freq_params(msg, freq) < 0)
+		goto nla_put_failure;
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
@@ -6800,7 +7107,7 @@
 		return -1;
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
-	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+	if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
 		goto nla_put_failure;
 	NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
@@ -6856,7 +7163,7 @@
 				const char *ifname, enum nl80211_iftype iftype,
 				const u8 *addr, int wds,
 				int (*handler)(struct nl_msg *, void *),
-				void *arg)
+				void *arg, int use_existing)
 {
 	int ret;
 
@@ -6865,6 +7172,11 @@
 
 	/* if error occurred and interface exists already */
 	if (ret == -ENFILE && if_nametoindex(ifname)) {
+		if (use_existing) {
+			wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
+				   ifname);
+			return -ENFILE;
+		}
 		wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
 
 		/* Try to remove the interface that was already there. */
@@ -6966,12 +7278,13 @@
 
 	len = recv(sock, buf, sizeof(buf), 0);
 	if (len < 0) {
-		perror("recv");
+		wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
+			   strerror(errno));
 		return;
 	}
 
 	if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
-		printf("received invalid radiotap frame\n");
+		wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
 		return;
 	}
 
@@ -6980,7 +7293,8 @@
 		if (ret == -ENOENT)
 			break;
 		if (ret) {
-			printf("received invalid radiotap frame (%d)\n", ret);
+			wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)",
+				   ret);
 			return;
 		}
 		switch (iter.this_arg_index) {
@@ -7130,7 +7444,7 @@
 };
 
 static struct sock_fprog msock_filter = {
-	.len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
+	.len = ARRAY_SIZE(msock_filter_insns),
 	.filter = msock_filter_insns,
 };
 
@@ -7165,7 +7479,8 @@
 
 	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
 		       &msock_filter, sizeof(msock_filter))) {
-		perror("SO_ATTACH_FILTER");
+		wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -7176,7 +7491,10 @@
 static void nl80211_remove_monitor_interface(
 	struct wpa_driver_nl80211_data *drv)
 {
-	drv->monitor_refcount--;
+	if (drv->monitor_refcount > 0)
+		drv->monitor_refcount--;
+	wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
+		   drv->monitor_refcount);
 	if (drv->monitor_refcount > 0)
 		return;
 
@@ -7202,27 +7520,29 @@
 
 	if (drv->monitor_ifidx >= 0) {
 		drv->monitor_refcount++;
+		wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
+			   drv->monitor_refcount);
 		return 0;
 	}
 
-	if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
+	if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
 		/*
 		 * P2P interface name is of the format p2p-%s-%d. For monitor
 		 * interface name corresponding to P2P GO, replace "p2p-" with
 		 * "mon-" to retain the same interface name length and to
 		 * indicate that it is a monitor interface.
 		 */
-		snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
+		snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
 	} else {
 		/* Non-P2P interface with AP functionality. */
-		snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
+		snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
 	}
 
 	buf[IFNAMSIZ - 1] = '\0';
 
 	drv->monitor_ifidx =
 		nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-				     0, NULL, NULL);
+				     0, NULL, NULL, 0);
 
 	if (drv->monitor_ifidx == -EOPNOTSUPP) {
 		/*
@@ -7247,7 +7567,8 @@
 	ll.sll_ifindex = drv->monitor_ifidx;
 	drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 	if (drv->monitor_sock < 0) {
-		perror("socket[PF_PACKET,SOCK_RAW]");
+		wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
+			   strerror(errno));
 		goto error;
 	}
 
@@ -7258,7 +7579,8 @@
 	}
 
 	if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
-		perror("monitor socket bind");
+		wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
+			   strerror(errno));
 		goto error;
 	}
 
@@ -7266,16 +7588,18 @@
 	optval = 20;
 	if (setsockopt
 	    (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
-		perror("Failed to set socket priority");
+		wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
+			   strerror(errno));
 		goto error;
 	}
 
 	if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
 				     drv, NULL)) {
-		printf("Could not register monitor read socket\n");
+		wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
 		goto error;
 	}
 
+	drv->monitor_refcount++;
 	return 0;
  error:
 	nl80211_remove_monitor_interface(drv);
@@ -7287,8 +7611,8 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
-		   "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
+	wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
+		   bss->ifname, drv->device_ap_sme, drv->use_monitor);
 
 	/*
 	 * Disable Probe Request reporting unless we need it in this way for
@@ -7311,16 +7635,6 @@
 	    !drv->device_ap_sme)
 		return -1;
 
-#ifdef ANDROID_P2P
-	if (drv->device_ap_sme && drv->use_monitor)
-		if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
-			return -1;
-
-	if (drv->use_monitor &&
-	    nl80211_create_monitor_interface(drv))
-		return -1;
-#endif
-
 	if (drv->device_ap_sme &&
 	    wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
@@ -7336,6 +7650,8 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
+	wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
+		   bss->ifname, drv->device_ap_sme, drv->use_monitor);
 	if (drv->device_ap_sme) {
 		wpa_driver_nl80211_probe_req_report(bss, 0);
 		if (!drv->use_monitor)
@@ -7390,19 +7706,16 @@
 	u8 *pos;
 	int res;
 	int qos = flags & WPA_STA_WMM;
-#ifndef ANDROID_P2P
+
 	if (drv->device_ap_sme || !drv->use_monitor)
-#else
-	if (drv->device_ap_sme && !drv->use_monitor)
-#endif
 		return nl80211_send_eapol_data(bss, addr, data, data_len);
 
 	len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
 		data_len;
 	hdr = os_zalloc(len);
 	if (hdr == NULL) {
-		printf("malloc() failed for i802_send_data(len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
+			   (unsigned long) len);
 		return -1;
 	}
 
@@ -7519,14 +7832,14 @@
 		nlmode = NL80211_IFTYPE_AP;
 
 	old_mode = drv->nlmode;
-	if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode)) {
+	if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) {
 		nl80211_remove_monitor_interface(drv);
 		return -1;
 	}
 
-	if (wpa_driver_nl80211_set_freq(&drv->first_bss, &freq)) {
+	if (wpa_driver_nl80211_set_freq(drv->first_bss, &freq)) {
 		if (old_mode != nlmode)
-			wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
+			wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
 		nl80211_remove_monitor_interface(drv);
 		return -1;
 	}
@@ -7558,6 +7871,12 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
 
 nla_put_failure:
+	if (wpa_driver_nl80211_set_mode(drv->first_bss,
+					NL80211_IFTYPE_STATION)) {
+		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
+			   "station mode");
+	}
+
 	nlmsg_free(msg);
 	return ret;
 }
@@ -7572,7 +7891,7 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
 
-	if (wpa_driver_nl80211_set_mode(&drv->first_bss,
+	if (wpa_driver_nl80211_set_mode(drv->first_bss,
 					NL80211_IFTYPE_ADHOC)) {
 		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
 			   "IBSS mode");
@@ -8085,7 +8404,7 @@
 		return -ENOMEM;
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
-	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+	if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
 		goto nla_put_failure;
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
 
@@ -8275,8 +8594,6 @@
 }
 
 
-#if defined(HOSTAPD) || defined(CONFIG_AP)
-
 static inline int min_int(int a, int b)
 {
 	if (a < b)
@@ -8431,8 +8748,6 @@
 	return -ENOBUFS;
 }
 
-#endif /* HOSTAPD || CONFIG_AP */
-
 
 static int get_sta_handler(struct nl_msg *msg, void *arg)
 {
@@ -8513,8 +8828,6 @@
 }
 
 
-#if defined(HOSTAPD) || defined(CONFIG_AP)
-
 static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
 				    int cw_min, int cw_max, int burst_time)
 {
@@ -8585,6 +8898,10 @@
 	if (!msg)
 		return -ENOMEM;
 
+	wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
+		   ", ifname=%s[%d], vlan_id=%d)",
+		   bss->ifname, if_nametoindex(bss->ifname),
+		   MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
@@ -8676,9 +8993,6 @@
 					    0);
 }
 
-#endif /* HOSTAPD || CONFIG_AP */
-
-#ifdef HOSTAPD
 
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 {
@@ -8760,7 +9074,8 @@
 		if (!if_nametoindex(name)) {
 			if (nl80211_create_iface(drv, name,
 						 NL80211_IFTYPE_AP_VLAN,
-						 bss->addr, 1, NULL, NULL) < 0)
+						 bss->addr, 1, NULL, NULL, 0) <
+			    0)
 				return -1;
 			if (bridge_ifname &&
 			    linux_br_add_if(drv->global->ioctl_sock,
@@ -8795,7 +9110,8 @@
 	len = recvfrom(sock, buf, sizeof(buf), 0,
 		       (struct sockaddr *)&lladdr, &fromlen);
 	if (len < 0) {
-		perror("recv");
+		wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s",
+			   strerror(errno));
 		return;
 	}
 
@@ -8868,14 +9184,13 @@
 	int ifindex, br_ifindex;
 	int br_added = 0;
 
-	bss = wpa_driver_nl80211_init(hapd, params->ifname,
-				      params->global_priv);
+	bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
+					  params->global_priv, 1,
+					  params->bssid);
 	if (bss == NULL)
 		return NULL;
 
 	drv = bss->drv;
-	drv->nlmode = NL80211_IFTYPE_AP;
-	drv->eapol_sock = -1;
 
 	if (linux_br_get(brname, params->ifname) == 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
@@ -8886,8 +9201,6 @@
 		br_ifindex = 0;
 	}
 
-	drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
-	drv->if_indices = drv->default_if_indices;
 	for (i = 0; i < params->num_bridge; i++) {
 		if (params->bridge[i]) {
 			ifindex = if_nametoindex(params->bridge[i]);
@@ -8904,37 +9217,20 @@
 	/* start listening for EAPOL on the default AP interface */
 	add_ifidx(drv, drv->ifindex);
 
-	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
-		goto failed;
-
-	if (params->bssid) {
-		if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-				       params->bssid))
-			goto failed;
-	}
-
-	if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
-			   "into AP mode", bss->ifname);
-		goto failed;
-	}
-
 	if (params->num_bridge && params->bridge[0] &&
 	    i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
 		goto failed;
 
-	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
-		goto failed;
-
 	drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
 	if (drv->eapol_sock < 0) {
-		perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
+		wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
+			   strerror(errno));
 		goto failed;
 	}
 
 	if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
 	{
-		printf("Could not register read socket for eapol\n");
+		wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
 		goto failed;
 	}
 
@@ -8958,8 +9254,6 @@
 	wpa_driver_nl80211_deinit(bss);
 }
 
-#endif /* HOSTAPD */
-
 
 static enum nl80211_iftype wpa_driver_nl80211_if_type(
 	enum wpa_driver_if_type type)
@@ -8990,7 +9284,7 @@
 	struct wpa_driver_nl80211_data *drv;
 	dl_list_for_each(drv, &global->interfaces,
 			 struct wpa_driver_nl80211_data, list) {
-		if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
+		if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0)
 			return 1;
 	}
 	return 0;
@@ -9005,9 +9299,9 @@
 	if (!drv->global)
 		return -1;
 
-	os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
+	os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN);
 	for (idx = 0; idx < 64; idx++) {
-		new_addr[0] = drv->first_bss.addr[0] | 0x02;
+		new_addr[0] = drv->first_bss->addr[0] | 0x02;
 		new_addr[0] ^= idx << 2;
 		if (!nl80211_addr_in_use(drv->global, new_addr))
 			break;
@@ -9055,21 +9349,13 @@
 				     const char *ifname, const u8 *addr,
 				     void *bss_ctx, void **drv_priv,
 				     char *force_ifname, u8 *if_addr,
-				     const char *bridge)
+				     const char *bridge, int use_existing)
 {
 	enum nl80211_iftype nlmode;
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ifidx;
-#ifdef HOSTAPD
-	struct i802_bss *new_bss = NULL;
-
-	if (type == WPA_IF_AP_BSS) {
-		new_bss = os_zalloc(sizeof(*new_bss));
-		if (new_bss == NULL)
-			return -1;
-	}
-#endif /* HOSTAPD */
+	int added = 1;
 
 	if (addr)
 		os_memcpy(if_addr, addr, ETH_ALEN);
@@ -9080,7 +9366,7 @@
 		os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
 		ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
 					     0, nl80211_wdev_handler,
-					     &p2pdev_info);
+					     &p2pdev_info, use_existing);
 		if (!p2pdev_info.wdev_id_set || ifidx != 0) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
 				   ifname);
@@ -9096,11 +9382,11 @@
 			   (long long unsigned int) p2pdev_info.wdev_id);
 	} else {
 		ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
-					     0, NULL, NULL);
-		if (ifidx < 0) {
-#ifdef HOSTAPD
-			os_free(new_bss);
-#endif /* HOSTAPD */
+					     0, NULL, NULL, use_existing);
+		if (use_existing && ifidx == -ENFILE) {
+			added = 0;
+			ifidx = if_nametoindex(ifname);
+		} else if (ifidx < 0) {
 			return -1;
 		}
 	}
@@ -9110,7 +9396,8 @@
 			os_memcpy(if_addr, bss->addr, ETH_ALEN);
 		else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
 					    bss->ifname, if_addr) < 0) {
-			nl80211_remove_iface(drv, ifidx);
+			if (added)
+				nl80211_remove_iface(drv, ifidx);
 			return -1;
 		}
 	}
@@ -9144,17 +9431,25 @@
 	}
 #endif /* CONFIG_P2P */
 
-#ifdef HOSTAPD
-	if (bridge &&
-	    i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
-			   "interface %s to a bridge %s", ifname, bridge);
-		nl80211_remove_iface(drv, ifidx);
-		os_free(new_bss);
-		return -1;
-	}
-
 	if (type == WPA_IF_AP_BSS) {
+		struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
+		if (new_bss == NULL) {
+			if (added)
+				nl80211_remove_iface(drv, ifidx);
+			return -1;
+		}
+
+		if (bridge &&
+		    i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
+			wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
+				   "interface %s to a bridge %s",
+				   ifname, bridge);
+			if (added)
+				nl80211_remove_iface(drv, ifidx);
+			os_free(new_bss);
+			return -1;
+		}
+
 		if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
 		{
 			nl80211_remove_iface(drv, ifidx);
@@ -9165,10 +9460,11 @@
 		os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
 		new_bss->ifindex = ifidx;
 		new_bss->drv = drv;
-		new_bss->next = drv->first_bss.next;
-		new_bss->freq = drv->first_bss.freq;
+		new_bss->next = drv->first_bss->next;
+		new_bss->freq = drv->first_bss->freq;
 		new_bss->ctx = bss_ctx;
-		drv->first_bss.next = new_bss;
+		new_bss->added_if = added;
+		drv->first_bss->next = new_bss;
 		if (drv_priv)
 			*drv_priv = new_bss;
 		nl80211_init_bss(new_bss);
@@ -9177,7 +9473,6 @@
 		if (nl80211_setup_ap(new_bss))
 			return -1;
 	}
-#endif /* HOSTAPD */
 
 	if (drv->global)
 		drv->global->if_add_ifindex = ifidx;
@@ -9193,14 +9488,11 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ifindex = if_nametoindex(ifname);
 
-	wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
-		   __func__, type, ifname, ifindex);
-	if (ifindex <= 0)
-		return -1;
+	wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
+		   __func__, type, ifname, ifindex, bss->added_if);
+	if (ifindex > 0 && bss->added_if)
+		nl80211_remove_iface(drv, ifindex);
 
-	nl80211_remove_iface(drv, ifindex);
-
-#ifdef HOSTAPD
 	if (type != WPA_IF_AP_BSS)
 		return 0;
 
@@ -9218,10 +9510,11 @@
 				   bss->brname, strerror(errno));
 	}
 
-	if (bss != &drv->first_bss) {
+	if (bss != drv->first_bss) {
 		struct i802_bss *tbss;
 
-		for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
+		wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
+		for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
 			if (tbss->next == bss) {
 				tbss->next = bss->next;
 				/* Unsubscribe management frames */
@@ -9235,8 +9528,22 @@
 		if (bss)
 			wpa_printf(MSG_INFO, "nl80211: %s - could not find "
 				   "BSS %p in the list", __func__, bss);
+	} else {
+		wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
+		nl80211_teardown_ap(bss);
+		if (!bss->added_if && !drv->first_bss->next)
+			wpa_driver_nl80211_del_beacon(drv);
+		nl80211_destroy_bss(bss);
+		if (!bss->added_if)
+			i802_set_iface_flags(bss, 0);
+		if (drv->first_bss->next) {
+			drv->first_bss = drv->first_bss->next;
+			drv->ctx = drv->first_bss->ctx;
+			os_free(bss);
+		} else {
+			wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
+		}
 	}
-#endif /* HOSTAPD */
 
 	return 0;
 }
@@ -9341,7 +9648,10 @@
 	os_memcpy(hdr->addr2, src, ETH_ALEN);
 	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
-	if (is_ap_interface(drv->nlmode))
+	if (is_ap_interface(drv->nlmode) &&
+	    (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
+	     (int) freq == bss->freq || drv->device_ap_sme ||
+	     !drv->use_monitor))
 		ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
 						   0, freq, no_cck, 1,
 						   wait_time);
@@ -9484,9 +9794,7 @@
 		} else if (bss->nl_preq) {
 			wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
 				   "reporting nl_preq=%p", bss->nl_preq);
-			eloop_unregister_read_sock(
-				nl_socket_get_fd(bss->nl_preq));
-			nl_destroy_handles(&bss->nl_preq);
+			nl80211_destroy_eloop_handle(&bss->nl_preq);
 		}
 		return 0;
 	}
@@ -9509,9 +9817,9 @@
 				   NULL, 0) < 0)
 		goto out_err;
 
-	eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
-				 wpa_driver_nl80211_event_receive, bss->nl_cb,
-				 bss->nl_preq);
+	nl80211_register_eloop_read(&bss->nl_preq,
+				    wpa_driver_nl80211_event_receive,
+				    bss->nl_cb);
 
 	return 0;
 
@@ -9818,19 +10126,15 @@
 			 struct wpa_driver_nl80211_data, list) {
 		if (drv == driver ||
 		    os_strcmp(drv->phyname, driver->phyname) != 0 ||
-#ifdef ANDROID_P2P
-		    (!driver->associated && !is_ap_interface(driver->nlmode)))
-#else
 		    !driver->associated)
-#endif
 			continue;
 
 		wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
 			   MACSTR,
-			   driver->phyname, driver->first_bss.ifname,
-			   MAC2STR(driver->first_bss.addr));
+			   driver->phyname, driver->first_bss->ifname,
+			   MAC2STR(driver->first_bss->addr));
 		if (is_ap_interface(driver->nlmode))
-			freq = driver->first_bss.freq;
+			freq = driver->first_bss->freq;
 		else
 			freq = nl80211_get_assoc_freq(driver);
 		wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
@@ -9876,16 +10180,6 @@
 		struct wpa_driver_nl80211_data *drv = bss->drv;
 		drv->allow_p2p_device = 1;
 	}
-
-#ifdef ANDROID_P2P
-	if(os_strstr(param, "use_multi_chan_concurrent=1")) {
-		struct i802_bss *bss = priv;
-		struct wpa_driver_nl80211_data *drv = bss->drv;
-		wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel "
-			   "concurrency");
-		drv->capa.num_multichan_concurrent = 2;
-	}
-#endif
 #endif /* CONFIG_P2P */
 
 	return 0;
@@ -9922,7 +10216,8 @@
 
 	global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (global->ioctl_sock < 0) {
-		perror("socket(PF_INET,SOCK_DGRAM)");
+		wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
+			   strerror(errno));
 		goto err;
 	}
 
@@ -9950,11 +10245,8 @@
 
 	nl_destroy_handles(&global->nl);
 
-	if (global->nl_event) {
-		eloop_unregister_read_sock(
-			nl_socket_get_fd(global->nl_event));
-		nl_destroy_handles(&global->nl_event);
-	}
+	if (global->nl_event)
+		nl80211_destroy_eloop_handle(&global->nl_event);
 
 	nl_cb_put(global->nl_cb);
 
@@ -10328,12 +10620,13 @@
 	wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
 		   "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
 
-	if (opp_ps != -1 || ctwindow != -1)
+	if (opp_ps != -1 || ctwindow != -1) {
 #ifdef ANDROID_P2P
 		wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
-#else
+#else /* ANDROID_P2P */
 		return -1; /* Not yet supported */
-#endif
+#endif /* ANDROID_P2P */
+	}
 
 	if (legacy_ps == -1)
 		return 0;
@@ -10344,14 +10637,18 @@
 }
 
 
-static int nl80211_start_radar_detection(void *priv, int freq)
+static int nl80211_start_radar_detection(void *priv,
+					 struct hostapd_freq_params *freq)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	int ret;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC)");
+	wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC) %d MHz (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+		   freq->freq, freq->ht_enabled, freq->vht_enabled,
+		   freq->bandwidth, freq->center_freq1, freq->center_freq2);
+
 	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
 			   "detection");
@@ -10364,10 +10661,53 @@
 
 	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
 
-	/* only HT20 is supported at this point */
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
+	if (freq->vht_enabled) {
+		switch (freq->bandwidth) {
+		case 20:
+			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+				    NL80211_CHAN_WIDTH_20);
+			break;
+		case 40:
+			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+				    NL80211_CHAN_WIDTH_40);
+			break;
+		case 80:
+			if (freq->center_freq2)
+				NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+					    NL80211_CHAN_WIDTH_80P80);
+			else
+				NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+					    NL80211_CHAN_WIDTH_80);
+			break;
+		case 160:
+			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+				    NL80211_CHAN_WIDTH_160);
+			break;
+		default:
+			return -1;
+		}
+		NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
+		if (freq->center_freq2)
+			NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
+				    freq->center_freq2);
+	} else if (freq->ht_enabled) {
+		switch (freq->sec_channel_offset) {
+		case -1:
+			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				    NL80211_CHAN_HT40MINUS);
+			break;
+		case 1:
+			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				    NL80211_CHAN_HT40PLUS);
+			break;
+		default:
+			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				    NL80211_CHAN_HT20);
+			break;
+		}
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	if (ret == 0)
@@ -10570,7 +10910,7 @@
 
 	memset(&ifr, 0, sizeof(ifr));
 	memset(&priv_cmd, 0, sizeof(priv_cmd));
-	os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
 
 	priv_cmd.buf = buf;
 	priv_cmd.used_len = bp;
@@ -10667,14 +11007,12 @@
 }
 
 
-#if defined(HOSTAPD) || defined(CONFIG_AP)
 static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
 				       const char *ifname, int vlan_id)
 {
 	struct i802_bss *bss = priv;
 	return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
 }
-#endif /* HOSTAPD || CONFIG_AP */
 
 
 static int driver_nl80211_read_sta_data(void *priv,
@@ -10751,6 +11089,285 @@
 }
 
 
+static const char * scan_state_str(enum scan_states scan_state)
+{
+	switch (scan_state) {
+	case NO_SCAN:
+		return "NO_SCAN";
+	case SCAN_REQUESTED:
+		return "SCAN_REQUESTED";
+	case SCAN_STARTED:
+		return "SCAN_STARTED";
+	case SCAN_COMPLETED:
+		return "SCAN_COMPLETED";
+	case SCAN_ABORTED:
+		return "SCAN_ABORTED";
+	case SCHED_SCAN_STARTED:
+		return "SCHED_SCAN_STARTED";
+	case SCHED_SCAN_STOPPED:
+		return "SCHED_SCAN_STOPPED";
+	case SCHED_SCAN_RESULTS:
+		return "SCHED_SCAN_RESULTS";
+	}
+
+	return "??";
+}
+
+
+static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int res;
+	char *pos, *end;
+
+	pos = buf;
+	end = buf + buflen;
+
+	res = os_snprintf(pos, end - pos,
+			  "ifindex=%d\n"
+			  "ifname=%s\n"
+			  "brname=%s\n"
+			  "addr=" MACSTR "\n"
+			  "freq=%d\n"
+			  "%s%s%s%s%s",
+			  bss->ifindex,
+			  bss->ifname,
+			  bss->brname,
+			  MAC2STR(bss->addr),
+			  bss->freq,
+			  bss->beacon_set ? "beacon_set=1\n" : "",
+			  bss->added_if_into_bridge ?
+			  "added_if_into_bridge=1\n" : "",
+			  bss->added_bridge ? "added_bridge=1\n" : "",
+			  bss->in_deinit ? "in_deinit=1\n" : "",
+			  bss->if_dynamic ? "if_dynamic=1\n" : "");
+	if (res < 0 || res >= end - pos)
+		return pos - buf;
+	pos += res;
+
+	if (bss->wdev_id_set) {
+		res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
+				  (unsigned long long) bss->wdev_id);
+		if (res < 0 || res >= end - pos)
+			return pos - buf;
+		pos += res;
+	}
+
+	res = os_snprintf(pos, end - pos,
+			  "phyname=%s\n"
+			  "drv_ifindex=%d\n"
+			  "operstate=%d\n"
+			  "scan_state=%s\n"
+			  "auth_bssid=" MACSTR "\n"
+			  "auth_attempt_bssid=" MACSTR "\n"
+			  "bssid=" MACSTR "\n"
+			  "prev_bssid=" MACSTR "\n"
+			  "associated=%d\n"
+			  "assoc_freq=%u\n"
+			  "monitor_sock=%d\n"
+			  "monitor_ifidx=%d\n"
+			  "monitor_refcount=%d\n"
+			  "last_mgmt_freq=%u\n"
+			  "eapol_tx_sock=%d\n"
+			  "%s%s%s%s%s%s%s%s%s%s%s%s%s",
+			  drv->phyname,
+			  drv->ifindex,
+			  drv->operstate,
+			  scan_state_str(drv->scan_state),
+			  MAC2STR(drv->auth_bssid),
+			  MAC2STR(drv->auth_attempt_bssid),
+			  MAC2STR(drv->bssid),
+			  MAC2STR(drv->prev_bssid),
+			  drv->associated,
+			  drv->assoc_freq,
+			  drv->monitor_sock,
+			  drv->monitor_ifidx,
+			  drv->monitor_refcount,
+			  drv->last_mgmt_freq,
+			  drv->eapol_tx_sock,
+			  drv->ignore_if_down_event ?
+			  "ignore_if_down_event=1\n" : "",
+			  drv->scan_complete_events ?
+			  "scan_complete_events=1\n" : "",
+			  drv->disabled_11b_rates ?
+			  "disabled_11b_rates=1\n" : "",
+			  drv->pending_remain_on_chan ?
+			  "pending_remain_on_chan=1\n" : "",
+			  drv->in_interface_list ? "in_interface_list=1\n" : "",
+			  drv->device_ap_sme ? "device_ap_sme=1\n" : "",
+			  drv->poll_command_supported ?
+			  "poll_command_supported=1\n" : "",
+			  drv->data_tx_status ? "data_tx_status=1\n" : "",
+			  drv->scan_for_auth ? "scan_for_auth=1\n" : "",
+			  drv->retry_auth ? "retry_auth=1\n" : "",
+			  drv->use_monitor ? "use_monitor=1\n" : "",
+			  drv->ignore_next_local_disconnect ?
+			  "ignore_next_local_disconnect=1\n" : "",
+			  drv->allow_p2p_device ? "allow_p2p_device=1\n" : "");
+	if (res < 0 || res >= end - pos)
+		return pos - buf;
+	pos += res;
+
+	if (drv->has_capability) {
+		res = os_snprintf(pos, end - pos,
+				  "capa.key_mgmt=0x%x\n"
+				  "capa.enc=0x%x\n"
+				  "capa.auth=0x%x\n"
+				  "capa.flags=0x%x\n"
+				  "capa.max_scan_ssids=%d\n"
+				  "capa.max_sched_scan_ssids=%d\n"
+				  "capa.sched_scan_supported=%d\n"
+				  "capa.max_match_sets=%d\n"
+				  "capa.max_remain_on_chan=%u\n"
+				  "capa.max_stations=%u\n"
+				  "capa.probe_resp_offloads=0x%x\n"
+				  "capa.max_acl_mac_addrs=%u\n"
+				  "capa.num_multichan_concurrent=%u\n",
+				  drv->capa.key_mgmt,
+				  drv->capa.enc,
+				  drv->capa.auth,
+				  drv->capa.flags,
+				  drv->capa.max_scan_ssids,
+				  drv->capa.max_sched_scan_ssids,
+				  drv->capa.sched_scan_supported,
+				  drv->capa.max_match_sets,
+				  drv->capa.max_remain_on_chan,
+				  drv->capa.max_stations,
+				  drv->capa.probe_resp_offloads,
+				  drv->capa.max_acl_mac_addrs,
+				  drv->capa.num_multichan_concurrent);
+		if (res < 0 || res >= end - pos)
+			return pos - buf;
+		pos += res;
+	}
+
+	return pos - buf;
+}
+
+
+static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
+{
+	if (settings->head)
+		NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD,
+			settings->head_len, settings->head);
+
+	if (settings->tail)
+		NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL,
+			settings->tail_len, settings->tail);
+
+	if (settings->beacon_ies)
+		NLA_PUT(msg, NL80211_ATTR_IE,
+			settings->beacon_ies_len, settings->beacon_ies);
+
+	if (settings->proberesp_ies)
+		NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
+			settings->proberesp_ies_len, settings->proberesp_ies);
+
+	if (settings->assocresp_ies)
+		NLA_PUT(msg,
+			NL80211_ATTR_IE_ASSOC_RESP,
+			settings->assocresp_ies_len, settings->assocresp_ies);
+
+	if (settings->probe_resp)
+		NLA_PUT(msg, NL80211_ATTR_PROBE_RESP,
+			settings->probe_resp_len, settings->probe_resp);
+
+	return 0;
+
+nla_put_failure:
+	return -ENOBUFS;
+}
+
+
+static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
+{
+	struct nl_msg *msg;
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nlattr *beacon_csa;
+	int ret = -ENOBUFS;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d)",
+		   settings->cs_count, settings->block_tx,
+		   settings->freq_params.freq);
+
+	if (!drv->channel_switch_supported) {
+		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
+		return -EOPNOTSUPP;
+	}
+
+	if ((drv->nlmode != NL80211_IFTYPE_AP) &&
+	    (drv->nlmode != NL80211_IFTYPE_P2P_GO))
+		return -EOPNOTSUPP;
+
+	/* check settings validity */
+	if (!settings->beacon_csa.tail ||
+	    ((settings->beacon_csa.tail_len <=
+	      settings->counter_offset_beacon) ||
+	     (settings->beacon_csa.tail[settings->counter_offset_beacon] !=
+	      settings->cs_count)))
+		return -EINVAL;
+
+	if (settings->beacon_csa.probe_resp &&
+	    ((settings->beacon_csa.probe_resp_len <=
+	      settings->counter_offset_presp) ||
+	     (settings->beacon_csa.probe_resp[settings->counter_offset_presp] !=
+	      settings->cs_count)))
+		return -EINVAL;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, settings->cs_count);
+	ret = nl80211_put_freq_params(msg, &settings->freq_params);
+	if (ret)
+		goto error;
+
+	if (settings->block_tx)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX);
+
+	/* beacon_after params */
+	ret = set_beacon_data(msg, &settings->beacon_after);
+	if (ret)
+		goto error;
+
+	/* beacon_csa params */
+	beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
+	if (!beacon_csa)
+		goto nla_put_failure;
+
+	ret = set_beacon_data(msg, &settings->beacon_csa);
+	if (ret)
+		goto error;
+
+	NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
+		    settings->counter_offset_beacon);
+
+	if (settings->beacon_csa.probe_resp)
+		NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
+			    settings->counter_offset_presp);
+
+	nla_nest_end(msg, beacon_csa);
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
+			   ret, strerror(-ret));
+	}
+	return ret;
+
+nla_put_failure:
+	ret = -ENOBUFS;
+error:
+	nlmsg_free(msg);
+	wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request");
+	return ret;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -10772,6 +11389,7 @@
 	.set_operstate = wpa_driver_nl80211_set_operstate,
 	.set_supp_port = wpa_driver_nl80211_set_supp_port,
 	.set_country = wpa_driver_nl80211_set_country,
+	.get_country = wpa_driver_nl80211_get_country,
 	.set_ap = wpa_driver_nl80211_set_ap,
 	.set_acl = wpa_driver_nl80211_set_acl,
 	.if_add = wpa_driver_nl80211_if_add,
@@ -10782,12 +11400,9 @@
 	.sta_remove = driver_nl80211_sta_remove,
 	.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
 	.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
-#ifdef HOSTAPD
 	.hapd_init = i802_init,
 	.hapd_deinit = i802_deinit,
 	.set_wds_sta = i802_set_wds_sta,
-#endif /* HOSTAPD */
-#if defined(HOSTAPD) || defined(CONFIG_AP)
 	.get_seqnum = i802_get_seqnum,
 	.flush = i802_flush,
 	.get_inact_sec = i802_get_inact_sec,
@@ -10798,7 +11413,6 @@
 	.set_sta_vlan = driver_nl80211_set_sta_vlan,
 	.sta_deauth = i802_sta_deauth,
 	.sta_disassoc = i802_sta_disassoc,
-#endif /* HOSTAPD || CONFIG_AP */
 	.read_sta_data = driver_nl80211_read_sta_data,
 	.set_freq = i802_set_freq,
 	.send_action = driver_nl80211_send_action,
@@ -10832,12 +11446,14 @@
 	.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
 	.get_mac_addr = wpa_driver_nl80211_get_macaddr,
 	.get_survey = wpa_driver_nl80211_get_survey,
+	.status = wpa_driver_nl80211_status,
+	.switch_channel = nl80211_switch_channel,
 #ifdef ANDROID_P2P
 	.set_noa = wpa_driver_set_p2p_noa,
 	.get_noa = wpa_driver_get_p2p_noa,
 	.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
-#endif
+#endif /* ANDROID_P2P */
 #ifdef ANDROID
 	.driver_cmd = wpa_driver_nl80211_driver_cmd,
-#endif
+#endif /* ANDROID */
 };
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index 541ebcc..5742b98 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1059,7 +1059,7 @@
 			      const char *ifname, const u8 *addr,
 			      void *bss_ctx, void **drv_priv,
 			      char *force_ifname, u8 *if_addr,
-			      const char *bridge)
+			      const char *bridge, int use_existing)
 {
 	struct test_driver_bss *dbss = priv;
 	struct wpa_driver_test_data *drv = dbss->drv;
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 1401050..6e2e771 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -2427,7 +2427,7 @@
 	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
 
 	os_memset(&iwr, 0, sizeof(iwr));
-	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 	iwr.u.data.pointer = buf;
 	iwr.u.data.length = bp;
 
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index 4380428..837971d 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -204,11 +204,14 @@
 int linux_br_get(char *brname, const char *ifname)
 {
 	char path[128], brlink[128], *pos;
+	ssize_t res;
+
 	os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
 		    ifname);
-	os_memset(brlink, 0, sizeof(brlink));
-	if (readlink(path, brlink, sizeof(brlink) - 1) < 0)
+	res = readlink(path, brlink, sizeof(brlink));
+	if (res < 0 || (size_t) res >= sizeof(brlink))
 		return -1;
+	brlink[res] = '\0';
 	pos = os_strrchr(brlink, '/');
 	if (pos == NULL)
 		return -1;
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 32b060e..f752e98 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -126,6 +126,31 @@
  */
 
 /**
+ * DOC: packet coalesce support
+ *
+ * In most cases, host that receives IPv4 and IPv6 multicast/broadcast
+ * packets does not do anything with these packets. Therefore the
+ * reception of these unwanted packets causes unnecessary processing
+ * and power consumption.
+ *
+ * Packet coalesce feature helps to reduce number of received interrupts
+ * to host by buffering these packets in firmware/hardware for some
+ * predefined time. Received interrupt will be generated when one of the
+ * following events occur.
+ * a) Expiration of hardware timer whose expiration time is set to maximum
+ * coalescing delay of matching coalesce rule.
+ * b) Coalescing buffer in hardware reaches it's limit.
+ * c) Packet doesn't match any of the configured coalesce rules.
+ *
+ * User needs to configure following parameters for creating a coalesce
+ * rule.
+ * a) Maximum coalescing delay
+ * b) List of packet patterns which needs to be matched
+ * c) Condition for coalescence. pattern 'match' or 'no match'
+ * Multiple such rules can be created.
+ */
+
+/**
  * enum nl80211_commands - supported nl80211 commands
  *
  * @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -648,6 +673,19 @@
  * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can
  *	return back to normal.
  *
+ * @NL80211_CMD_GET_COALESCE: Get currently supported coalesce rules.
+ * @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules.
+ *
+ * @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the
+ *	the new channel information (Channel Switch Announcement - CSA)
+ *	in the beacon for some time (as defined in the
+ *	%NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the
+ *	new channel. Userspace provides the new channel information (using
+ *	%NL80211_ATTR_WIPHY_FREQ and the attributes determining channel
+ *	width). %NL80211_ATTR_CH_SWITCH_BLOCK_TX may be supplied to inform
+ *	other station that transmission must be blocked until the channel
+ *	switch is complete.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -810,6 +848,11 @@
 	NL80211_CMD_CRIT_PROTOCOL_START,
 	NL80211_CMD_CRIT_PROTOCOL_STOP,
 
+	NL80211_CMD_GET_COALESCE,
+	NL80211_CMD_SET_COALESCE,
+
+	NL80211_CMD_CHANNEL_SWITCH,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -945,7 +988,7 @@
  * 	to query the CRDA to retrieve one regulatory domain. This attribute can
  * 	also be used by userspace to query the kernel for the currently set
  * 	regulatory domain. We chose an alpha2 as that is also used by the
- * 	IEEE-802.11d country information element to identify a country.
+ * 	IEEE-802.11 country information element to identify a country.
  * 	Users can also simply ask the wireless core to set regulatory domain
  * 	to a specific alpha2.
  * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
@@ -1436,6 +1479,35 @@
  *	allowed to be used with the first @NL80211_CMD_SET_STATION command to
  *	update a TDLS peer STA entry.
  *
+ * @NL80211_ATTR_COALESCE_RULE: Coalesce rule information.
+ *
+ * @NL80211_ATTR_CH_SWITCH_COUNT: u32 attribute specifying the number of TBTT's
+ *	until the channel switch event.
+ * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission
+ *	must be blocked on the current channel (before the channel switch
+ *	operation).
+ * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
+ *	for the time while performing a channel switch.
+ * @NL80211_ATTR_CSA_C_OFF_BEACON: Offset of the channel switch counter
+ *	field in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
+ * @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter
+ *	field in the probe response (%NL80211_ATTR_PROBE_RESP).
+ *
+ * @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32.
+ *	As specified in the &enum nl80211_rxmgmt_flags.
+ *
+ * @NL80211_ATTR_STA_SUPPORTED_CHANNELS: array of supported channels.
+ *
+ * @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported
+ *      supported operating classes.
+ *
+ * @NL80211_ATTR_HANDLE_DFS: A flag indicating whether user space
+ *	controls DFS operation in IBSS mode. If the flag is included in
+ *	%NL80211_CMD_JOIN_IBSS request, the driver will allow use of DFS
+ *	channels and reports radar events to userspace. Userspace is required
+ *	to react to radar events, e.g. initiate a channel switch or leave the
+ *	IBSS network.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1736,6 +1808,22 @@
 
 	NL80211_ATTR_PEER_AID,
 
+	NL80211_ATTR_COALESCE_RULE,
+
+	NL80211_ATTR_CH_SWITCH_COUNT,
+	NL80211_ATTR_CH_SWITCH_BLOCK_TX,
+	NL80211_ATTR_CSA_IES,
+	NL80211_ATTR_CSA_C_OFF_BEACON,
+	NL80211_ATTR_CSA_C_OFF_PRESP,
+
+	NL80211_ATTR_RXMGMT_FLAGS,
+
+	NL80211_ATTR_STA_SUPPORTED_CHANNELS,
+
+	NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
+
+	NL80211_ATTR_HANDLE_DFS,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -2428,6 +2516,8 @@
  * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
  * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
  *	overrides all other flags.
+ * @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address
+ *	and ACK incoming unicast packets.
  *
  * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
  * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
@@ -2439,6 +2529,7 @@
 	NL80211_MNTR_FLAG_CONTROL,
 	NL80211_MNTR_FLAG_OTHER_BSS,
 	NL80211_MNTR_FLAG_COOK_FRAMES,
+	NL80211_MNTR_FLAG_ACTIVE,
 
 	/* keep last */
 	__NL80211_MNTR_FLAG_AFTER_LAST,
@@ -2574,6 +2665,10 @@
  *
  * @NL80211_MESHCONF_AWAKE_WINDOW: awake window duration (in TUs)
  *
+ * @NL80211_MESHCONF_PLINK_TIMEOUT: If no tx activity is seen from a STA we've
+ *	established peering with for longer than this time (in seconds), then
+ *	remove it from the STA's list of peers.  Default is 30 minutes.
+ *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_meshconf_params {
@@ -2605,6 +2700,7 @@
 	NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
 	NL80211_MESHCONF_POWER_MODE,
 	NL80211_MESHCONF_AWAKE_WINDOW,
+	NL80211_MESHCONF_PLINK_TIMEOUT,
 
 	/* keep last */
 	__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2750,6 +2846,8 @@
  *	and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well
  * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
  *	attribute must be provided as well
+ * @NL80211_CHAN_WIDTH_5: 5 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_10: 10 MHz OFDM channel
  */
 enum nl80211_chan_width {
 	NL80211_CHAN_WIDTH_20_NOHT,
@@ -2758,6 +2856,23 @@
 	NL80211_CHAN_WIDTH_80,
 	NL80211_CHAN_WIDTH_80P80,
 	NL80211_CHAN_WIDTH_160,
+	NL80211_CHAN_WIDTH_5,
+	NL80211_CHAN_WIDTH_10,
+};
+
+/**
+ * enum nl80211_bss_scan_width - control channel width for a BSS
+ *
+ * These values are used with the %NL80211_BSS_CHAN_WIDTH attribute.
+ *
+ * @NL80211_BSS_CHAN_WIDTH_20: control channel is 20 MHz wide or compatible
+ * @NL80211_BSS_CHAN_WIDTH_10: control channel is 10 MHz wide
+ * @NL80211_BSS_CHAN_WIDTH_5: control channel is 5 MHz wide
+ */
+enum nl80211_bss_scan_width {
+	NL80211_BSS_CHAN_WIDTH_20,
+	NL80211_BSS_CHAN_WIDTH_10,
+	NL80211_BSS_CHAN_WIDTH_5,
 };
 
 /**
@@ -2784,6 +2899,8 @@
  * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
  *	elements from a Beacon frame (bin); not present if no Beacon frame has
  *	yet been received
+ * @NL80211_BSS_CHAN_WIDTH: channel width of the control channel
+ *	(u32, enum nl80211_bss_scan_width)
  * @__NL80211_BSS_AFTER_LAST: internal
  * @NL80211_BSS_MAX: highest BSS attribute
  */
@@ -2800,6 +2917,7 @@
 	NL80211_BSS_STATUS,
 	NL80211_BSS_SEEN_MS_AGO,
 	NL80211_BSS_BEACON_IES,
+	NL80211_BSS_CHAN_WIDTH,
 
 	/* keep last */
 	__NL80211_BSS_AFTER_LAST,
@@ -3048,11 +3166,11 @@
 };
 
 /**
- * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
- * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
- * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
+ * enum nl80211_packet_pattern_attr - packet pattern attribute
+ * @__NL80211_PKTPAT_INVALID: invalid number for nested attribute
+ * @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has
  *	a zero bit are ignored
- * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have
+ * @NL80211_PKTPAT_MASK: pattern mask, must be long enough to have
  *	a bit for each byte in the pattern. The lowest-order bit corresponds
  *	to the first byte of the pattern, but the bytes of the pattern are
  *	in a little-endian-like format, i.e. the 9th byte of the pattern
@@ -3063,39 +3181,50 @@
  *	Note that the pattern matching is done as though frames were not
  *	802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
  *	first (including SNAP header unpacking) and then matched.
- * @NL80211_WOWLAN_PKTPAT_OFFSET: packet offset, pattern is matched after
+ * @NL80211_PKTPAT_OFFSET: packet offset, pattern is matched after
  *	these fixed number of bytes of received packet
- * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
- * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
+ * @NUM_NL80211_PKTPAT: number of attributes
+ * @MAX_NL80211_PKTPAT: max attribute number
  */
-enum nl80211_wowlan_packet_pattern_attr {
-	__NL80211_WOWLAN_PKTPAT_INVALID,
-	NL80211_WOWLAN_PKTPAT_MASK,
-	NL80211_WOWLAN_PKTPAT_PATTERN,
-	NL80211_WOWLAN_PKTPAT_OFFSET,
+enum nl80211_packet_pattern_attr {
+	__NL80211_PKTPAT_INVALID,
+	NL80211_PKTPAT_MASK,
+	NL80211_PKTPAT_PATTERN,
+	NL80211_PKTPAT_OFFSET,
 
-	NUM_NL80211_WOWLAN_PKTPAT,
-	MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
+	NUM_NL80211_PKTPAT,
+	MAX_NL80211_PKTPAT = NUM_NL80211_PKTPAT - 1,
 };
 
 /**
- * struct nl80211_wowlan_pattern_support - pattern support information
+ * struct nl80211_pattern_support - packet pattern support information
  * @max_patterns: maximum number of patterns supported
  * @min_pattern_len: minimum length of each pattern
  * @max_pattern_len: maximum length of each pattern
  * @max_pkt_offset: maximum Rx packet offset
  *
  * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
- * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
- * capability information given by the kernel to userspace.
+ * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED or in
+ * %NL80211_ATTR_COALESCE_RULE_PKT_PATTERN when that is part of
+ * %NL80211_ATTR_COALESCE_RULE in the capability information given
+ * by the kernel to userspace.
  */
-struct nl80211_wowlan_pattern_support {
+struct nl80211_pattern_support {
 	__u32 max_patterns;
 	__u32 min_pattern_len;
 	__u32 max_pattern_len;
 	__u32 max_pkt_offset;
 } __attribute__((packed));
 
+/* only for backward compatibility */
+#define __NL80211_WOWLAN_PKTPAT_INVALID __NL80211_PKTPAT_INVALID
+#define NL80211_WOWLAN_PKTPAT_MASK NL80211_PKTPAT_MASK
+#define NL80211_WOWLAN_PKTPAT_PATTERN NL80211_PKTPAT_PATTERN
+#define NL80211_WOWLAN_PKTPAT_OFFSET NL80211_PKTPAT_OFFSET
+#define NUM_NL80211_WOWLAN_PKTPAT NUM_NL80211_PKTPAT
+#define MAX_NL80211_WOWLAN_PKTPAT MAX_NL80211_PKTPAT
+#define nl80211_wowlan_pattern_support nl80211_pattern_support
+
 /**
  * enum nl80211_wowlan_triggers - WoWLAN trigger definitions
  * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes
@@ -3115,7 +3244,7 @@
  *	pattern matching is done after the packet is converted to the MSDU.
  *
  *	In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
- *	carrying a &struct nl80211_wowlan_pattern_support.
+ *	carrying a &struct nl80211_pattern_support.
  *
  *	When reporting wakeup. it is a u32 attribute containing the 0-based
  *	index of the pattern that caused the wakeup, in the patterns passed
@@ -3272,7 +3401,7 @@
  * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a
  *	u32 attribute holding the maximum length
  * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for
- *	feature advertising. The mask works like @NL80211_WOWLAN_PKTPAT_MASK
+ *	feature advertising. The mask works like @NL80211_PKTPAT_MASK
  *	but on the TCP payload only.
  * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes
  * @MAX_NL80211_WOWLAN_TCP: highest attribute number
@@ -3297,6 +3426,55 @@
 };
 
 /**
+ * struct nl80211_coalesce_rule_support - coalesce rule support information
+ * @max_rules: maximum number of rules supported
+ * @pat: packet pattern support information
+ * @max_delay: maximum supported coalescing delay in msecs
+ *
+ * This struct is carried in %NL80211_ATTR_COALESCE_RULE in the
+ * capability information given by the kernel to userspace.
+ */
+struct nl80211_coalesce_rule_support {
+	__u32 max_rules;
+	struct nl80211_pattern_support pat;
+	__u32 max_delay;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_attr_coalesce_rule - coalesce rule attribute
+ * @__NL80211_COALESCE_RULE_INVALID: invalid number for nested attribute
+ * @NL80211_ATTR_COALESCE_RULE_DELAY: delay in msecs used for packet coalescing
+ * @NL80211_ATTR_COALESCE_RULE_CONDITION: condition for packet coalescence,
+ *	see &enum nl80211_coalesce_condition.
+ * @NL80211_ATTR_COALESCE_RULE_PKT_PATTERN: packet offset, pattern is matched
+ *	after these fixed number of bytes of received packet
+ * @NUM_NL80211_ATTR_COALESCE_RULE: number of attributes
+ * @NL80211_ATTR_COALESCE_RULE_MAX: max attribute number
+ */
+enum nl80211_attr_coalesce_rule {
+	__NL80211_COALESCE_RULE_INVALID,
+	NL80211_ATTR_COALESCE_RULE_DELAY,
+	NL80211_ATTR_COALESCE_RULE_CONDITION,
+	NL80211_ATTR_COALESCE_RULE_PKT_PATTERN,
+
+	/* keep last */
+	NUM_NL80211_ATTR_COALESCE_RULE,
+	NL80211_ATTR_COALESCE_RULE_MAX = NUM_NL80211_ATTR_COALESCE_RULE - 1
+};
+
+/**
+ * enum nl80211_coalesce_condition - coalesce rule conditions
+ * @NL80211_COALESCE_CONDITION_MATCH: coalaesce Rx packets when patterns
+ *	in a rule are matched.
+ * @NL80211_COALESCE_CONDITION_NO_MATCH: coalesce Rx packets when patterns
+ *	in a rule are not matched.
+ */
+enum nl80211_coalesce_condition {
+	NL80211_COALESCE_CONDITION_MATCH,
+	NL80211_COALESCE_CONDITION_NO_MATCH
+};
+
+/**
  * enum nl80211_iface_limit_attrs - limit attributes
  * @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
  * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that
@@ -3576,6 +3754,10 @@
  *	Peering Management entity which may be implemented by registering for
  *	beacons or NL80211_CMD_NEW_PEER_CANDIDATE events. The mesh beacon is
  *	still generated by the driver.
+ * @NL80211_FEATURE_ACTIVE_MONITOR: This driver supports an active monitor
+ *	interface. An active monitor interface behaves like a normal monitor
+ *	interface, but gets added to the driver. It ensures that incoming
+ *	unicast packets directed at the configured interface address get ACKed.
  */
 enum nl80211_feature_flags {
 	NL80211_FEATURE_SK_TX_STATUS			= 1 << 0,
@@ -3595,6 +3777,7 @@
 	NL80211_FEATURE_ADVERTISE_CHAN_LIMITS		= 1 << 14,
 	NL80211_FEATURE_FULL_AP_CLIENT_STATE		= 1 << 15,
 	NL80211_FEATURE_USERSPACE_MPM			= 1 << 16,
+	NL80211_FEATURE_ACTIVE_MONITOR			= 1 << 17,
 };
 
 /**
@@ -3695,13 +3878,12 @@
  *
  * Channel states used by the DFS code.
  *
- * @IEEE80211_DFS_USABLE: The channel can be used, but channel availability
+ * @NL80211_DFS_USABLE: The channel can be used, but channel availability
  *	check (CAC) must be performed before using it for AP or IBSS.
- * @IEEE80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
+ * @NL80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
  *	is therefore marked as not available.
- * @IEEE80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
+ * @NL80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
  */
-
 enum nl80211_dfs_state {
 	NL80211_DFS_USABLE,
 	NL80211_DFS_UNAVAILABLE,
@@ -3741,4 +3923,15 @@
 /* maximum duration for critical protocol measures */
 #define NL80211_CRIT_PROTO_MAX_DURATION		5000 /* msec */
 
+/**
+ * enum nl80211_rxmgmt_flags - flags for received management frame.
+ *
+ * Used by cfg80211_rx_mgmt()
+ *
+ * @NL80211_RXMGMT_FLAG_ANSWERED: frame was answered by device/driver.
+ */
+enum nl80211_rxmgmt_flags {
+	NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0,
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/ikev2_common.c b/src/eap_common/ikev2_common.c
index 376fcad..f061866 100644
--- a/src/eap_common/ikev2_common.c
+++ b/src/eap_common/ikev2_common.c
@@ -21,7 +21,7 @@
 	{ AUTH_HMAC_MD5_96, 16, 12 }
 };
 
-#define NUM_INTEG_ALGS (sizeof(ikev2_integ_algs) / sizeof(ikev2_integ_algs[0]))
+#define NUM_INTEG_ALGS ARRAY_SIZE(ikev2_integ_algs)
 
 
 static struct ikev2_prf_alg ikev2_prf_algs[] = {
@@ -29,7 +29,7 @@
 	{ PRF_HMAC_MD5, 16, 16 }
 };
 
-#define NUM_PRF_ALGS (sizeof(ikev2_prf_algs) / sizeof(ikev2_prf_algs[0]))
+#define NUM_PRF_ALGS ARRAY_SIZE(ikev2_prf_algs)
 
 
 static struct ikev2_encr_alg ikev2_encr_algs[] = {
@@ -37,7 +37,7 @@
 	{ ENCR_3DES, 24, 8 }
 };
 
-#define NUM_ENCR_ALGS (sizeof(ikev2_encr_algs) / sizeof(ikev2_encr_algs[0]))
+#define NUM_ENCR_ALGS ARRAY_SIZE(ikev2_encr_algs)
 
 
 const struct ikev2_integ_alg * ikev2_get_integ(int id)
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 554e7e9..3439c2d 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1638,7 +1638,8 @@
 			   const char *msg, size_t msglen)
 {
 	struct eap_peer_config *config;
-	char *txt = NULL, *tmp;
+	const char *txt = NULL;
+	char *tmp;
 
 	if (sm == NULL)
 		return;
@@ -1681,6 +1682,9 @@
 	case WPA_CTRL_REQ_EAP_PASSPHRASE:
 		config->pending_req_passphrase++;
 		break;
+	case WPA_CTRL_REQ_SIM:
+		txt = msg;
+		break;
 	default:
 		return;
 	}
@@ -1792,6 +1796,17 @@
 
 
 /**
+ * eap_sm_request_sim - Request external SIM processing
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @req: EAP method specific request
+ */
+void eap_sm_request_sim(struct eap_sm *sm, const char *req)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_SIM, req, os_strlen(req));
+}
+
+
+/**
  * eap_sm_notify_ctrl_attached - Notification of attached monitor
  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
  *
@@ -2304,6 +2319,17 @@
 }
 
 
+/**
+ * eap_set_external_sim - Set external_sim flag
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @external_sim: Whether external SIM/USIM processing is used
+ */
+void eap_set_external_sim(struct eap_sm *sm, int external_sim)
+{
+	sm->external_sim = external_sim;
+}
+
+
  /**
  * eap_notify_pending - Notify that EAP method is ready to re-process a request
  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index f87f9b3..711f41f 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -296,6 +296,7 @@
 void eap_sm_request_pin(struct eap_sm *sm);
 void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len);
 void eap_sm_request_passphrase(struct eap_sm *sm);
+void eap_sm_request_sim(struct eap_sm *sm, const char *req);
 void eap_sm_notify_ctrl_attached(struct eap_sm *sm);
 u32 eap_get_phase2_type(const char *name, int *vendor);
 struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
@@ -303,6 +304,7 @@
 void eap_set_fast_reauth(struct eap_sm *sm, int enabled);
 void eap_set_workaround(struct eap_sm *sm, unsigned int workaround);
 void eap_set_force_disabled(struct eap_sm *sm, int disabled);
+void eap_set_external_sim(struct eap_sm *sm, int external_sim);
 int eap_key_available(struct eap_sm *sm);
 void eap_notify_success(struct eap_sm *sm);
 void eap_notify_lower_layer_success(struct eap_sm *sm);
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index dc424d7..d3cbaca 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -142,6 +142,89 @@
 }
 
 
+static int eap_aka_ext_sim_req(struct eap_sm *sm, struct eap_aka_data *data)
+{
+	char req[200], *pos, *end;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Use external USIM processing");
+	pos = req;
+	end = pos + sizeof(req);
+	pos += os_snprintf(pos, end - pos, "UMTS-AUTH");
+	pos += os_snprintf(pos, end - pos, ":");
+	pos += wpa_snprintf_hex(pos, end - pos, data->rand, EAP_AKA_RAND_LEN);
+	pos += os_snprintf(pos, end - pos, ":");
+	pos += wpa_snprintf_hex(pos, end - pos, data->autn, EAP_AKA_AUTN_LEN);
+
+	eap_sm_request_sim(sm, req);
+	return 1;
+}
+
+
+static int eap_aka_ext_sim_result(struct eap_sm *sm, struct eap_aka_data *data,
+				  struct eap_peer_config *conf)
+{
+	char *resp, *pos;
+
+	wpa_printf(MSG_DEBUG,
+		   "EAP-AKA: Use result from external USIM processing");
+
+	resp = conf->external_sim_resp;
+	conf->external_sim_resp = NULL;
+
+	if (os_strncmp(resp, "UMTS-AUTS:", 10) == 0) {
+		pos = resp + 10;
+		if (hexstr2bin(pos, data->auts, EAP_AKA_AUTS_LEN) < 0)
+			goto invalid;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: AUTS", data->auts,
+				EAP_AKA_AUTS_LEN);
+		os_free(resp);
+		return -2;
+	}
+
+	if (os_strncmp(resp, "UMTS-AUTH:", 10) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized external USIM processing response");
+		os_free(resp);
+		return -1;
+	}
+
+	pos = resp + 10;
+	wpa_hexdump(MSG_DEBUG, "EAP-AKA: RAND", data->rand, EAP_AKA_RAND_LEN);
+
+	if (hexstr2bin(pos, data->ik, EAP_AKA_IK_LEN) < 0)
+		goto invalid;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", data->ik, EAP_AKA_IK_LEN);
+	pos += EAP_AKA_IK_LEN * 2;
+	if (*pos != ':')
+		goto invalid;
+	pos++;
+
+	if (hexstr2bin(pos, data->ck, EAP_AKA_CK_LEN) < 0)
+		goto invalid;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", data->ck, EAP_AKA_CK_LEN);
+	pos += EAP_AKA_CK_LEN * 2;
+	if (*pos != ':')
+		goto invalid;
+	pos++;
+
+	data->res_len = os_strlen(pos) / 2;
+	if (data->res_len > EAP_AKA_RES_MAX_LEN) {
+		data->res_len = 0;
+		goto invalid;
+	}
+	if (hexstr2bin(pos, data->res, data->res_len) < 0)
+		goto invalid;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: RES", data->res, data->res_len);
+
+	os_free(resp);
+	return 0;
+
+invalid:
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Invalid external USIM processing UMTS-AUTH response");
+	os_free(resp);
+	return -1;
+}
+
+
 static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
 {
 	struct eap_peer_config *conf;
@@ -151,6 +234,14 @@
 	conf = eap_get_config(sm);
 	if (conf == NULL)
 		return -1;
+
+	if (sm->external_sim) {
+		if (conf->external_sim_resp)
+			return eap_aka_ext_sim_result(sm, data, conf);
+		else
+			return eap_aka_ext_sim_req(sm, data);
+	}
+
 	if (conf->pcsc) {
 		return scard_umts_auth(sm->scard_ctx, data->rand,
 				       data->autn, data->res, &data->res_len,
@@ -861,6 +952,9 @@
 		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
 			   "failed (AUTN seq# -> AUTS)");
 		return eap_aka_synchronization_failure(data, id);
+	} else if (res > 0) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Wait for external USIM processing");
+		return NULL;
 	} else if (res) {
 		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
 		return eap_aka_client_error(data, id,
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 42f525b..98ec1f7 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -208,6 +208,24 @@
 	u8 *altsubject_match;
 
 	/**
+	 * domain_suffix_match - Constraint for server domain name
+	 *
+	 * If set, this FQDN is used as a suffix match requirement for the
+	 * server certificate in SubjectAltName dNSName element(s). If a
+	 * matching dNSName is found, this constraint is met. If no dNSName
+	 * values are present, this constraint is matched against SubjetName CN
+	 * using same suffix match comparison. Suffix match here means that the
+	 * host/domain name is compared one label at a time starting from the
+	 * top-level domain and all the labels in domain_suffix_match shall be
+	 * included in the certificate. The certificate may include additional
+	 * sub-level labels in addition to the required labels.
+	 *
+	 * For example, domain_suffix_match=example.com would match
+	 * test.example.com but would not match test-example.com.
+	 */
+	char *domain_suffix_match;
+
+	/**
 	 * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
 	 *
 	 * This file can have one or more trusted CA certificates. If ca_cert2
@@ -303,6 +321,14 @@
 	u8 *altsubject_match2;
 
 	/**
+	 * domain_suffix_match2 - Constraint for server domain name
+	 *
+	 * This field is like domain_suffix_match, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication.
+	 */
+	char *domain_suffix_match2;
+
+	/**
 	 * eap_methods - Allowed EAP methods
 	 *
 	 * (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of
@@ -643,6 +669,15 @@
 	 * 2 = require valid OCSP stapling response
 	 */
 	int ocsp;
+
+	/**
+	 * external_sim_resp - Response from external SIM processing
+	 *
+	 * This field should not be set in configuration step. It is only used
+	 * internally when control interface is used to request external
+	 * SIM/USIM processing.
+	 */
+	char *external_sim_resp;
 };
 
 
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 62c867c..9307f3f 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -348,6 +348,8 @@
 
 	struct ext_password_data *ext_pw;
 	struct wpabuf *ext_pw_buf;
+
+	int external_sim;
 };
 
 const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
diff --git a/src/eap_peer/eap_proxy.h b/src/eap_peer/eap_proxy.h
index 3b4dcef..23cdbe6 100644
--- a/src/eap_peer/eap_proxy.h
+++ b/src/eap_peer/eap_proxy.h
@@ -40,7 +40,8 @@
 int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
 			    int verbose);
 
-int eap_proxy_get_imsi(char *imsi_buf, size_t *imsi_len);
+int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf,
+		       size_t *imsi_len);
 
 int eap_proxy_notify_config(struct eap_proxy_sm *sm,
 			    struct eap_peer_config *config);
diff --git a/src/eap_peer/eap_proxy_dummy.c b/src/eap_peer/eap_proxy_dummy.c
index cd97fb6..d84f012 100644
--- a/src/eap_peer/eap_proxy_dummy.c
+++ b/src/eap_peer/eap_proxy_dummy.c
@@ -63,7 +63,8 @@
 }
 
 
-int eap_proxy_get_imsi(char *imsi_buf, size_t *imsi_len)
+int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf,
+		       size_t *imsi_len)
 {
 	return -1;
 }
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index 82ea18d..d856054 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -145,6 +145,80 @@
 }
 
 
+static int eap_sim_ext_sim_req(struct eap_sm *sm, struct eap_sim_data *data)
+{
+	char req[200], *pos, *end;
+	size_t i;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Use external SIM processing");
+	pos = req;
+	end = pos + sizeof(req);
+	pos += os_snprintf(pos, end - pos, "GSM-AUTH");
+	for (i = 0; i < data->num_chal; i++) {
+		pos += os_snprintf(pos, end - pos, ":");
+		pos += wpa_snprintf_hex(pos, end - pos, data->rand[i],
+					GSM_RAND_LEN);
+	}
+
+	eap_sm_request_sim(sm, req);
+	return 1;
+}
+
+
+static int eap_sim_ext_sim_result(struct eap_sm *sm, struct eap_sim_data *data,
+				  struct eap_peer_config *conf)
+{
+	char *resp, *pos;
+	size_t i;
+
+	wpa_printf(MSG_DEBUG,
+		   "EAP-SIM: Use result from external SIM processing");
+
+	resp = conf->external_sim_resp;
+	conf->external_sim_resp = NULL;
+
+	if (os_strncmp(resp, "GSM-AUTH:", 9) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized external SIM processing response");
+		os_free(resp);
+		return -1;
+	}
+
+	pos = resp + 9;
+	for (i = 0; i < data->num_chal; i++) {
+		wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
+			    data->rand[i], GSM_RAND_LEN);
+
+		if (hexstr2bin(pos, data->kc[i], EAP_SIM_KC_LEN) < 0)
+			goto invalid;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
+				data->kc[i], EAP_SIM_KC_LEN);
+		pos += EAP_SIM_KC_LEN * 2;
+		if (*pos != ':')
+			goto invalid;
+		pos++;
+
+		if (hexstr2bin(pos, data->sres[i], EAP_SIM_SRES_LEN) < 0)
+			goto invalid;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
+				data->sres[i], EAP_SIM_SRES_LEN);
+		pos += EAP_SIM_SRES_LEN * 2;
+		if (i + 1 < data->num_chal) {
+			if (*pos != ':')
+				goto invalid;
+			pos++;
+		}
+	}
+
+	os_free(resp);
+	return 0;
+
+invalid:
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Invalid external SIM processing GSM-AUTH response");
+	os_free(resp);
+	return -1;
+}
+
+
 static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
 {
 	struct eap_peer_config *conf;
@@ -154,6 +228,14 @@
 	conf = eap_get_config(sm);
 	if (conf == NULL)
 		return -1;
+
+	if (sm->external_sim) {
+		if (conf->external_sim_resp)
+			return eap_sim_ext_sim_result(sm, data, conf);
+		else
+			return eap_sim_ext_sim_req(sm, data);
+	}
+
 	if (conf->pcsc) {
 		if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
 				   data->sres[0], data->kc[0]) ||
@@ -605,6 +687,7 @@
 	const u8 *identity;
 	size_t identity_len;
 	struct eap_sim_attrs eattr;
+	int res;
 
 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
 	data->reauth = 0;
@@ -648,8 +731,13 @@
 
 	os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
 	data->num_chal = attr->num_chal;
-		
-	if (eap_sim_gsm_auth(sm, data)) {
+
+	res = eap_sim_gsm_auth(sm, data);
+	if (res > 0) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Wait for external SIM processing");
+		return NULL;
+	}
+	if (res) {
 		wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
 		return eap_sim_client_error(data, id,
 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index be8c301..008af37 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -78,6 +78,7 @@
 	params->dh_file = (char *) config->dh_file;
 	params->subject_match = (char *) config->subject_match;
 	params->altsubject_match = (char *) config->altsubject_match;
+	params->suffix_match = config->domain_suffix_match;
 	params->engine = config->engine;
 	params->engine_id = config->engine_id;
 	params->pin = config->pin;
@@ -99,6 +100,7 @@
 	params->dh_file = (char *) config->dh_file2;
 	params->subject_match = (char *) config->subject_match2;
 	params->altsubject_match = (char *) config->altsubject_match2;
+	params->suffix_match = config->domain_suffix_match2;
 	params->engine = config->engine2;
 	params->engine_id = config->engine2_id;
 	params->pin = config->pin2;
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 469b9a0..46fc458 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -1040,6 +1040,7 @@
 	data->auts_reported = 1;
 
 	/* Remain in CHALLENGE state to re-try after resynchronization */
+	eap_aka_fullauth(sm, data);
 }
 
 
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index 1b9d701..345c788 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -630,7 +630,7 @@
 
 	data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (data->sock < 0) {
-		perror("socket(eap_sim_db)");
+		wpa_printf(MSG_INFO, "socket(eap_sim_db): %s", strerror(errno));
 		return -1;
 	}
 
@@ -641,7 +641,7 @@
 	os_free(data->local_sock);
 	data->local_sock = os_strdup(addr.sun_path);
 	if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind(eap_sim_db)");
+		wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno));
 		close(data->sock);
 		data->sock = -1;
 		return -1;
@@ -651,7 +651,8 @@
 	addr.sun_family = AF_UNIX;
 	os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
 	if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("connect(eap_sim_db)");
+		wpa_printf(MSG_INFO, "connect(eap_sim_db): %s",
+			   strerror(errno));
 		wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
 				  (u8 *) addr.sun_path,
 				  os_strlen(addr.sun_path));
@@ -804,7 +805,8 @@
 
 	if (send(data->sock, msg, len, 0) < 0) {
 		_errno = errno;
-		perror("send[EAP-SIM DB UNIX]");
+		wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
+			   strerror(errno));
 	}
 
 	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
@@ -816,7 +818,8 @@
 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
 			   "external server");
 		if (send(data->sock, msg, len, 0) < 0) {
-			perror("send[EAP-SIM DB UNIX]");
+			wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
+				   strerror(errno));
 			return -1;
 		}
 	}
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 013d781..a257781 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -1062,6 +1062,10 @@
 	}
 	if (src->pac_opaque_encr_key) {
 		dst->pac_opaque_encr_key = os_malloc(16);
+		if (dst->pac_opaque_encr_key == NULL) {
+			os_free(dst->eap_req_id_text);
+			return -1;
+		}
 		os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
 			  16);
 	} else
@@ -1070,6 +1074,7 @@
 		dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
 		if (dst->eap_fast_a_id == NULL) {
 			os_free(dst->eap_req_id_text);
+			os_free(dst->pac_opaque_encr_key);
 			return -1;
 		}
 		os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
@@ -1081,6 +1086,7 @@
 		dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
 		if (dst->eap_fast_a_id_info == NULL) {
 			os_free(dst->eap_req_id_text);
+			os_free(dst->pac_opaque_encr_key);
 			os_free(dst->eap_fast_a_id);
 			return -1;
 		}
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 9b054fc..9d7aef0 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1257,6 +1257,24 @@
 
 	switch (hdr->type) {
 	case IEEE802_1X_TYPE_EAP_PACKET:
+		if (sm->conf.workaround) {
+			/*
+			 * An AP has been reported to send out EAP message with
+			 * undocumented code 10 at some point near the
+			 * completion of EAP authentication. This can result in
+			 * issues with the unexpected EAP message triggering
+			 * restart of EAPOL authentication. Avoid this by
+			 * skipping the message without advancing the state
+			 * machine.
+			 */
+			const struct eap_hdr *ehdr =
+				(const struct eap_hdr *) (hdr + 1);
+			if (plen >= sizeof(*ehdr) && ehdr->code == 10) {
+				wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10");
+				break;
+			}
+		}
+
 		if (sm->cached_pmk) {
 			/* Trying to use PMKSA caching, but Authenticator did
 			 * not seem to have a matching entry. Need to restart
@@ -1461,6 +1479,7 @@
 		eap_set_fast_reauth(sm->eap, conf->fast_reauth);
 		eap_set_workaround(sm->eap, conf->workaround);
 		eap_set_force_disabled(sm->eap, conf->eap_disabled);
+		eap_set_external_sim(sm->eap, conf->external_sim);
 	}
 }
 
@@ -2032,3 +2051,15 @@
 		return 0;
 	return !sm->eapSuccess && sm->eapFail;
 }
+
+
+int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
+{
+#ifdef CONFIG_EAP_PROXY
+	if (sm->eap_proxy == NULL)
+		return -1;
+	return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
+#else /* CONFIG_EAP_PROXY */
+	return -1;
+#endif /* CONFIG_EAP_PROXY */
+}
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index c4b87da..54e8a27 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -53,6 +53,11 @@
 	 * eap_disabled - Whether EAP is disabled
 	 */
 	int eap_disabled;
+
+	/**
+	 * external_sim - Use external processing for SIM/USIM operations
+	 */
+	int external_sim;
 };
 
 struct eapol_sm;
@@ -287,6 +292,7 @@
 void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
 			     struct ext_password_data *ext);
 int eapol_sm_failed(struct eapol_sm *sm);
+int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len);
 #else /* IEEE8021X_EAPOL */
 static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
 {
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 738436c..e77563b 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1111,18 +1111,6 @@
 	return res;
 }
 
-#ifdef ANDROID_P2P
-int p2p_search_pending(struct p2p_data *p2p)
-{
-	if(p2p == NULL)
-		return 0;
-
-	if(p2p->state == P2P_SEARCH_WHEN_READY)
-		return 1;
-
-	return 0;
-}
-#endif
 
 int p2p_other_scan_completed(struct p2p_data *p2p)
 {
@@ -1208,19 +1196,21 @@
 
 static int p2p_prepare_channel_pref(struct p2p_data *p2p,
 				    unsigned int force_freq,
-				    unsigned int pref_freq)
+				    unsigned int pref_freq, int go)
 {
 	u8 op_class, op_channel;
 	unsigned int freq = force_freq ? force_freq : pref_freq;
 
-	p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u",
-		force_freq, pref_freq);
+	p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u go=%d",
+		force_freq, pref_freq, go);
 	if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) {
 		p2p_dbg(p2p, "Unsupported frequency %u MHz", freq);
 		return -1;
 	}
 
-	if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel)) {
+	if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel) &&
+	    (go || !p2p_channels_includes(&p2p->cfg->cli_channels, op_class,
+					  op_channel))) {
 		p2p_dbg(p2p, "Frequency %u MHz (oper_class %u channel %u) not allowed for P2P",
 			freq, op_class, op_channel);
 		return -1;
@@ -1246,6 +1236,9 @@
 static void p2p_prepare_channel_best(struct p2p_data *p2p)
 {
 	u8 op_class, op_channel;
+	const int op_classes_5ghz[] = { 124, 115, 0 };
+	const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
+	const int op_classes_vht[] = { 128, 0 };
 
 	p2p_dbg(p2p, "Prepare channel best");
 
@@ -1277,6 +1270,21 @@
 		p2p_dbg(p2p, "Select first pref_chan entry as operating channel preference");
 		p2p->op_reg_class = p2p->cfg->pref_chan[0].op_class;
 		p2p->op_channel = p2p->cfg->pref_chan[0].chan;
+	} else if (p2p_channel_select(&p2p->cfg->channels, op_classes_vht,
+				      &p2p->op_reg_class, &p2p->op_channel) ==
+		   0) {
+		p2p_dbg(p2p, "Select possible VHT channel (op_class %u channel %u) as operating channel preference",
+			p2p->op_reg_class, p2p->op_channel);
+	} else if (p2p_channel_select(&p2p->cfg->channels, op_classes_ht40,
+				      &p2p->op_reg_class, &p2p->op_channel) ==
+		   0) {
+		p2p_dbg(p2p, "Select possible HT40 channel (op_class %u channel %u) as operating channel preference",
+			p2p->op_reg_class, p2p->op_channel);
+	} else if (p2p_channel_select(&p2p->cfg->channels, op_classes_5ghz,
+				      &p2p->op_reg_class, &p2p->op_channel) ==
+		   0) {
+		p2p_dbg(p2p, "Select possible 5 GHz channel (op_class %u channel %u) as operating channel preference",
+			p2p->op_reg_class, p2p->op_channel);
 	} else {
 		p2p_dbg(p2p, "Select pre-configured channel as operating channel preference");
 		p2p->op_reg_class = p2p->cfg->op_reg_class;
@@ -1294,6 +1302,7 @@
  * @dev: Selected peer device
  * @force_freq: Forced frequency in MHz or 0 if not forced
  * @pref_freq: Preferred frequency in MHz or 0 if no preference
+ * @go: Whether the local end will be forced to be GO
  * Returns: 0 on success, -1 on failure (channel not supported for P2P)
  *
  * This function is used to do initial operating channel selection for GO
@@ -1302,16 +1311,25 @@
  * is available.
  */
 int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
-			unsigned int force_freq, unsigned int pref_freq)
+			unsigned int force_freq, unsigned int pref_freq, int go)
 {
-	p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u",
-		force_freq, pref_freq);
+	p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u go=%d",
+		force_freq, pref_freq, go);
 	if (force_freq || pref_freq) {
-		if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
+		if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq, go) <
+		    0)
 			return -1;
 	} else {
 		p2p_prepare_channel_best(p2p);
 	}
+	p2p_channels_dump(p2p, "prepared channels", &p2p->channels);
+	if (go)
+		p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
+	else if (!force_freq)
+		p2p_channels_union(&p2p->channels, &p2p->cfg->cli_channels,
+				   &p2p->channels);
+	p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels);
+
 	p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
 		p2p->op_reg_class, p2p->op_channel,
 		force_freq ? " (forced)" : "");
@@ -1367,7 +1385,8 @@
 		return -1;
 	}
 
-	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+				go_intent == 15) < 0)
 		return -1;
 
 	if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
@@ -1477,7 +1496,8 @@
 		return -1;
 	}
 
-	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, go_intent ==
+				15) < 0)
 		return -1;
 
 	p2p->ssid_set = 0;
@@ -1618,8 +1638,15 @@
 		}
 	}
 
+	p2p_channels_dump(p2p, "own channels", &p2p->channels);
+	p2p_channels_dump(p2p, "peer channels", &peer->channels);
 	p2p_channels_intersect(&p2p->channels, &peer->channels,
 			       &intersection);
+	if (go) {
+		p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq);
+		p2p_channels_dump(p2p, "intersection after no-GO removal",
+				  &intersection);
+	}
 	freqs = 0;
 	for (i = 0; i < intersection.reg_classes; i++) {
 		struct p2p_reg_class *c = &intersection.reg_class[i];
@@ -1672,6 +1699,7 @@
 					   rx_freq);
 		break;
 	case P2P_INVITATION_RESP:
+		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
 		break;
 	case P2P_PROV_DISC_REQ:
@@ -1978,7 +2006,11 @@
 		pw_id = p2p_wps_method_pw_id(p2p->go_neg_peer->wps_method);
 	}
 
-	p2p_build_wps_ie(p2p, buf, pw_id, 1);
+	if (p2p_build_wps_ie(p2p, buf, pw_id, 1) < 0) {
+		p2p_dbg(p2p, "Failed to build WPS IE for Probe Response");
+		wpabuf_free(buf);
+		return NULL;
+	}
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_probe_resp)
@@ -2438,6 +2470,10 @@
 	p2p->go_timeout = 100;
 	p2p->client_timeout = 20;
 
+	p2p_dbg(p2p, "initialized");
+	p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+	p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
+
 	return p2p;
 }
 
@@ -2474,6 +2510,7 @@
 	wpabuf_free(p2p->sd_resp);
 	os_free(p2p->after_scan_tx);
 	p2p_remove_wps_vendor_extensions(p2p);
+	os_free(p2p->no_go_freq.range);
 	os_free(p2p);
 }
 
@@ -2774,7 +2811,8 @@
 			MAC2STR(dev->info.p2p_device_addr),
 			dev->req_config_methods);
 		p2p_send_prov_disc_req(p2p, dev,
-				       dev->flags & P2P_DEV_PD_FOR_JOIN, 0);
+				       dev->flags & P2P_DEV_PD_FOR_JOIN,
+				       p2p->pd_force_freq);
 		return;
 	}
 }
@@ -2808,11 +2846,7 @@
 			p2p_continue_find(p2p);
 		else if (p2p->user_initiated_pd) {
 			p2p->pending_action_state = P2P_PENDING_PD;
-#ifdef ANDROID_P2P
-			p2p_set_timeout(p2p, 0, 350000);
-#else
 			p2p_set_timeout(p2p, 0, 300000);
-#endif
 		}
 		return;
 	}
@@ -2829,11 +2863,7 @@
 	/* Wait for response from the peer */
 	if (p2p->state == P2P_SEARCH)
 		p2p_set_state(p2p, P2P_PD_DURING_FIND);
-#ifdef ANDROID_P2P
-	p2p_set_timeout(p2p, 0, 350000);
-#else
 	p2p_set_timeout(p2p, 0, 200000);
-#endif
 }
 
 
@@ -3361,7 +3391,8 @@
 			if (p2p->cfg->invitation_result)
 				p2p->cfg->invitation_result(
 					p2p->cfg->cb_ctx, -1, NULL, NULL,
-					p2p->invite_peer->info.p2p_device_addr);
+					p2p->invite_peer->info.p2p_device_addr,
+					0);
 		}
 		p2p_set_state(p2p, P2P_IDLE);
 	}
@@ -4045,6 +4076,31 @@
 }
 
 
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+		       const struct wpa_freq_range_list *list)
+{
+	struct wpa_freq_range *tmp;
+
+	if (list == NULL || list->num == 0) {
+		os_free(p2p->no_go_freq.range);
+		p2p->no_go_freq.range = NULL;
+		p2p->no_go_freq.num = 0;
+		return 0;
+	}
+
+	tmp = os_calloc(list->num, sizeof(struct wpa_freq_range));
+	if (tmp == NULL)
+		return -1;
+	os_memcpy(tmp, list->range, list->num * sizeof(struct wpa_freq_range));
+	os_free(p2p->no_go_freq.range);
+	p2p->no_go_freq.range = tmp;
+	p2p->no_go_freq.num = list->num;
+	p2p_dbg(p2p, "Updated no GO chan list");
+
+	return 0;
+}
+
+
 int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
 			   u8 *iface_addr)
 {
@@ -4107,10 +4163,16 @@
 }
 
 
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan)
+void p2p_update_channel_list(struct p2p_data *p2p,
+			     const struct p2p_channels *chan,
+			     const struct p2p_channels *cli_chan)
 {
 	p2p_dbg(p2p, "Update channel list");
 	os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels));
+	p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+	os_memcpy(&p2p->cfg->cli_channels, cli_chan,
+		  sizeof(struct p2p_channels));
+	p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
 }
 
 
@@ -4209,15 +4271,6 @@
 	return &dev->info;
 }
 
-#ifdef ANDROID_P2P
-int p2p_search_in_progress(struct p2p_data *p2p)
-{
-	if (p2p == NULL)
-		return 0;
-
-	return p2p->state == P2P_SEARCH;
-}
-#endif
 
 int p2p_in_progress(struct p2p_data *p2p)
 {
@@ -4256,7 +4309,7 @@
 
 	for (g = 0; g < p2p->num_groups; g++) {
 		group = p2p->groups[g];
-		p2p_group_update_ies(group);
+		p2p_group_force_beacon_update_ies(group);
 	}
 }
 
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 7f845b2..22d0c58 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -77,6 +77,8 @@
 
 	int ht40;
 
+	int vht;
+
 	/**
 	 * ssid - SSID of the group
 	 */
@@ -287,6 +289,20 @@
 	struct p2p_channels channels;
 
 	/**
+	 * cli_channels - Additional client channels
+	 *
+	 * This list of channels (if any) will be used when advertising local
+	 * channels during GO Negotiation or Invitation for the cases where the
+	 * local end may become the client. This may allow the peer to become a
+	 * GO on additional channels if it supports these options. The main use
+	 * case for this is to include passive-scan channels on devices that may
+	 * not know their current location and have configured most channels to
+	 * not allow initiation of radition (i.e., another device needs to take
+	 * master responsibilities).
+	 */
+	struct p2p_channels cli_channels;
+
+	/**
 	 * num_pref_chan - Number of pref_chan entries
 	 */
 	unsigned int num_pref_chan;
@@ -742,6 +758,7 @@
 	 * @bssid: P2P Group BSSID or %NULL if not received
 	 * @channels: Available operating channels for the group
 	 * @addr: Peer address
+	 * @freq: Frequency (in MHz) indicated during invitation or 0
 	 *
 	 * This callback is used to indicate result of an Invitation procedure
 	 * started with a call to p2p_invite(). The indicated status code is
@@ -751,7 +768,7 @@
 	 */
 	void (*invitation_result)(void *ctx, int status, const u8 *bssid,
 				  const struct p2p_channels *channels,
-				  const u8 *addr);
+				  const u8 *addr, int freq);
 
 	/**
 	 * go_connected - Check whether we are connected to a GO
@@ -1649,6 +1666,22 @@
 int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
 
 /**
+ * p2p_supported_freq_go - Check whether channel is supported for P2P GO operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq);
+
+/**
+ * p2p_supported_freq_cli - Check whether channel is supported for P2P client operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq);
+
+/**
  * p2p_get_pref_freq - Get channel from preferred channel list
  * @p2p: P2P module context from p2p_init()
  * @channels: List of channels
@@ -1657,7 +1690,9 @@
 unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
 			       const struct p2p_channels *channels);
 
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
+void p2p_update_channel_list(struct p2p_data *p2p,
+			     const struct p2p_channels *chan,
+			     const struct p2p_channels *cli_chan);
 
 /**
  * p2p_set_best_channels - Update best channel information
@@ -1765,28 +1800,21 @@
 		      const struct p2p_channel *pref_chan);
 
 /**
+ * p2p_set_no_go_freq - Set no GO channel ranges
+ * @p2p: P2P module context from p2p_init()
+ * @list: Channel ranges or %NULL to remove restriction
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+		       const struct wpa_freq_range_list *list);
+
+/**
  * p2p_in_progress - Check whether a P2P operation is progress
  * @p2p: P2P module context from p2p_init()
  * Returns: 0 if P2P module is idle or 1 if an operation is in progress
  */
 int p2p_in_progress(struct p2p_data *p2p);
 
-#ifdef ANDROID_P2P
-/**
- * p2p_search_in_progress - Check whether a P2P SEARCH is in progress
- * @p2p: P2P module context from p2p_init()
- * Returns: 0 if P2P module is idle or 1 if an operation is in progress
- */
-int p2p_search_in_progress(struct p2p_data *p2p);
-
-/**
- * p2p_search_pending - Check whether there is a deferred P2P SEARCH
- * @p2p: P2P module context from p2p_init()
- * Returns: 0 if there is no deferred P2P search or 1 if there is one
- */
-int p2p_search_pending(struct p2p_data *p2p);
-#endif
-
 /**
  * p2p_other_scan_completed - Notify completion of non-P2P scan
  * @p2p: P2P module context from p2p_init()
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 5838d35..42c0232 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -258,6 +258,7 @@
 	wpabuf_put_data(buf, ssid, ssid_len);
 	wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
 		   MAC2STR(dev_addr));
+	wpa_hexdump_ascii(MSG_DEBUG, "P2P: P2P Group ID SSID", ssid, ssid_len);
 }
 
 
@@ -327,13 +328,15 @@
 }
 
 
-static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
-			       const char *val)
+static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
+			      const char *val)
 {
 	size_t len;
 
-	wpabuf_put_be16(buf, attr);
 	len = val ? os_strlen(val) : 0;
+	if (wpabuf_tailroom(buf) < 4 + len)
+		return -1;
+	wpabuf_put_be16(buf, attr);
 #ifndef CONFIG_WPS_STRICT
 	if (len == 0) {
 		/*
@@ -341,36 +344,46 @@
 		 * attributes. As a workaround, send a space character if the
 		 * device attribute string is empty.
 		 */
+		if (wpabuf_tailroom(buf) < 3)
+			return -1;
 		wpabuf_put_be16(buf, 1);
 		wpabuf_put_u8(buf, ' ');
-		return;
+		return 0;
 	}
 #endif /* CONFIG_WPS_STRICT */
 	wpabuf_put_be16(buf, len);
 	if (val)
 		wpabuf_put_data(buf, val, len);
+	return 0;
 }
 
 
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
-		      int all_attr)
+int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
+		     int all_attr)
 {
 	u8 *len;
 	int i;
 
+	if (wpabuf_tailroom(buf) < 6)
+		return -1;
 	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
 	len = wpabuf_put(buf, 1);
 	wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
 
-	wps_build_version(buf);
+	if (wps_build_version(buf) < 0)
+		return -1;
 
 	if (all_attr) {
+		if (wpabuf_tailroom(buf) < 5)
+			return -1;
 		wpabuf_put_be16(buf, ATTR_WPS_STATE);
 		wpabuf_put_be16(buf, 1);
 		wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED);
 	}
 
 	if (pw_id >= 0) {
+		if (wpabuf_tailroom(buf) < 6)
+			return -1;
 		/* Device Password ID */
 		wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
 		wpabuf_put_be16(buf, 2);
@@ -380,33 +393,47 @@
 	}
 
 	if (all_attr) {
+		if (wpabuf_tailroom(buf) < 5)
+			return -1;
 		wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
 		wpabuf_put_be16(buf, 1);
 		wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO);
 
-		wps_build_uuid_e(buf, p2p->cfg->uuid);
-		p2p_add_wps_string(buf, ATTR_MANUFACTURER,
-				   p2p->cfg->manufacturer);
-		p2p_add_wps_string(buf, ATTR_MODEL_NAME, p2p->cfg->model_name);
-		p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
-				   p2p->cfg->model_number);
-		p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
-				   p2p->cfg->serial_number);
+		if (wps_build_uuid_e(buf, p2p->cfg->uuid) < 0 ||
+		    p2p_add_wps_string(buf, ATTR_MANUFACTURER,
+				       p2p->cfg->manufacturer) < 0 ||
+		    p2p_add_wps_string(buf, ATTR_MODEL_NAME,
+				       p2p->cfg->model_name) < 0 ||
+		    p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
+				       p2p->cfg->model_number) < 0 ||
+		    p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
+				       p2p->cfg->serial_number) < 0)
+			return -1;
 
+		if (wpabuf_tailroom(buf) < 4 + WPS_DEV_TYPE_LEN)
+			return -1;
 		wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE);
 		wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN);
 		wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN);
 
-		p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name);
+		if (p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name)
+		    < 0)
+			return -1;
 
+		if (wpabuf_tailroom(buf) < 6)
+			return -1;
 		wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
 		wpabuf_put_be16(buf, 2);
 		wpabuf_put_be16(buf, p2p->cfg->config_methods);
 	}
 
-	wps_build_wfa_ext(buf, 0, NULL, 0);
+	if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0)
+		return -1;
 
 	if (all_attr && p2p->cfg->num_sec_dev_types) {
+		if (wpabuf_tailroom(buf) <
+		    4 + WPS_DEV_TYPE_LEN * p2p->cfg->num_sec_dev_types)
+			return -1;
 		wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST);
 		wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN *
 				p2p->cfg->num_sec_dev_types);
@@ -428,4 +455,6 @@
 	}
 
 	p2p_buf_update_ie_hdr(buf, len);
+
+	return 0;
 }
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index bd583be..008651e 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -172,7 +172,12 @@
 	p2p_buf_update_ie_hdr(buf, len);
 
 	/* WPS IE with Device Password ID attribute */
-	p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0);
+	if (p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method),
+			     0) < 0) {
+		p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Request");
+		wpabuf_free(buf);
+		return NULL;
+	}
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_go_neg)
@@ -307,9 +312,13 @@
 	p2p_buf_update_ie_hdr(buf, len);
 
 	/* WPS IE with Device Password ID attribute */
-	p2p_build_wps_ie(p2p, buf,
-			 p2p_wps_method_pw_id(peer ? peer->wps_method :
-					      WPS_NOT_READY), 0);
+	if (p2p_build_wps_ie(p2p, buf,
+			     p2p_wps_method_pw_id(peer ? peer->wps_method :
+						  WPS_NOT_READY), 0) < 0) {
+		p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Response");
+		wpabuf_free(buf);
+		return NULL;
+	}
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_go_neg)
@@ -339,6 +348,9 @@
 	int freq;
 	u8 op_reg_class, op_channel;
 	unsigned int i;
+	const int op_classes_5ghz[] = { 124, 115, 0 };
+	const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
+	const int op_classes_vht[] = { 128, 0 };
 
 	if (p2p->own_freq_preference > 0 &&
 	    p2p_freq_to_channel(p2p->own_freq_preference,
@@ -403,44 +415,28 @@
 		}
 	}
 
+	/* Try a channel where we might be able to use VHT */
+	if (p2p_channel_select(intersection, op_classes_vht,
+			       &p2p->op_reg_class, &p2p->op_channel) == 0) {
+		p2p_dbg(p2p, "Pick possible VHT channel (op_class %u channel %u) from intersection",
+			p2p->op_reg_class, p2p->op_channel);
+		return;
+	}
+
 	/* Try a channel where we might be able to use HT40 */
-	for (i = 0; i < intersection->reg_classes; i++) {
-		struct p2p_reg_class *c = &intersection->reg_class[i];
-		if (c->reg_class == 116 || c->reg_class == 117 ||
-		    c->reg_class == 126 || c->reg_class == 127) {
-			p2p_dbg(p2p, "Pick possible HT40 channel (reg_class %u channel %u) from intersection",
-				c->reg_class, c->channel[0]);
-			p2p->op_reg_class = c->reg_class;
-			p2p->op_channel = c->channel[0];
-			return;
-		}
+	if (p2p_channel_select(intersection, op_classes_ht40,
+			       &p2p->op_reg_class, &p2p->op_channel) == 0) {
+		p2p_dbg(p2p, "Pick possible HT40 channel (op_class %u channel %u) from intersection",
+			p2p->op_reg_class, p2p->op_channel);
+		return;
 	}
 
 	/* Prefer a 5 GHz channel */
-	for (i = 0; i < intersection->reg_classes; i++) {
-#ifdef ANDROID_P2P
-		struct p2p_reg_class prc;
-		struct p2p_reg_class *c = &prc;
-		p2p_copy_reg_class(c, &intersection->reg_class[i]);
-#else
-		struct p2p_reg_class *c = &intersection->reg_class[i];
-#endif
-		if ((c->reg_class == 115 || c->reg_class == 124) &&
-		    c->channels) {
-			unsigned int r;
-
-			/*
-			 * Pick one of the available channels in the operating
-			 * class at random.
-			 */
-			os_get_random((u8 *) &r, sizeof(r));
-			r %= c->channels;
-			p2p_dbg(p2p, "Pick possible 5 GHz channel (op_class %u channel %u) from intersection",
-				c->reg_class, c->channel[r]);
-			p2p->op_reg_class = c->reg_class;
-			p2p->op_channel = c->channel[r];
-			return;
-		}
+	if (p2p_channel_select(intersection, op_classes_5ghz,
+			       &p2p->op_reg_class, &p2p->op_channel) == 0) {
+		p2p_dbg(p2p, "Pick possible 5 GHz channel (op_class %u channel %u) from intersection",
+			p2p->op_reg_class, p2p->op_channel);
+		return;
 	}
 
 	/*
@@ -470,10 +466,17 @@
 static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
 				 u8 *status)
 {
-	struct p2p_channels intersection;
-	size_t i;
+	struct p2p_channels tmp, intersection;
 
-	p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection);
+	p2p_channels_dump(p2p, "own channels", &p2p->channels);
+	p2p_channels_dump(p2p, "peer channels", &dev->channels);
+	p2p_channels_intersect(&p2p->channels, &dev->channels, &tmp);
+	p2p_channels_dump(p2p, "intersection", &tmp);
+	p2p_channels_remove_freqs(&tmp, &p2p->no_go_freq);
+	p2p_channels_dump(p2p, "intersection after no-GO removal", &tmp);
+	p2p_channels_intersect(&tmp, &p2p->cfg->channels, &intersection);
+	p2p_channels_dump(p2p, "intersection with local channel list",
+			  &intersection);
 	if (intersection.reg_classes == 0 ||
 	    intersection.reg_class[0].channels == 0) {
 		*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
@@ -481,14 +484,6 @@
 		return -1;
 	}
 
-	for (i = 0; i < intersection.reg_classes; i++) {
-		struct p2p_reg_class *c;
-		c = &intersection.reg_class[i];
-		p2p_dbg(p2p, "reg_class %u", c->reg_class);
-		wpa_hexdump(MSG_DEBUG, "P2P: channels",
-			    c->channel, c->channels);
-	}
-
 	if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
 				   p2p->op_channel)) {
 		if (dev->flags & P2P_DEV_FORCE_FREQ) {
@@ -1131,16 +1126,6 @@
 		}
 	}
 
-#ifdef ANDROID_P2P
-	if (msg.operating_channel) {
-		dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
-						     msg.operating_channel[4]);
-		p2p_dbg(p2p, "P2P: Peer operating channel preference: %d MHz",
-			dev->oper_freq);
-	} else
-		dev->oper_freq = 0;
-#endif
-
 	if (!msg.channel_list) {
 		p2p_dbg(p2p, "Mandatory Operating Channel attribute missing from GO Negotiation Confirmation");
 #ifdef CONFIG_P2P_STRICT
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 15e7622..92b5583 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -980,3 +980,10 @@
 	return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid,
 			 group->cfg->ssid_len) == 0;
 }
+
+
+void p2p_group_force_beacon_update_ies(struct p2p_group *group)
+{
+	group->beacon_update = 1;
+	p2p_group_update_ies(group);
+}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 81e521e..e980be6 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -324,6 +324,8 @@
 	 */
 	struct p2p_channels channels;
 
+	struct wpa_freq_range_list no_go_freq;
+
 	enum p2p_pending_action_state {
 		P2P_NO_PENDING_ACTION,
 		P2P_PENDING_GO_NEG_REQUEST,
@@ -450,6 +452,14 @@
 	 */
 	int pd_retries;
 
+	/**
+	 * pd_force_freq - Forced frequency for PD retries or 0 to auto-select
+	 *
+	 * This is is used during PD retries for join-a-group case to use the
+	 * correct operating frequency determined from a BSS entry for the GO.
+	 */
+	int pd_force_freq;
+
 	u8 go_timeout;
 	u8 client_timeout;
 
@@ -570,11 +580,17 @@
 void p2p_channels_intersect(const struct p2p_channels *a,
 			    const struct p2p_channels *b,
 			    struct p2p_channels *res);
+void p2p_channels_union(const struct p2p_channels *a,
+			const struct p2p_channels *b,
+			struct p2p_channels *res);
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+			       const struct wpa_freq_range_list *list);
 int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
 			  u8 channel);
-#ifdef ANDROID_P2P
-size_t p2p_copy_reg_class(struct p2p_reg_class *dc, struct p2p_reg_class *sc);
-#endif
+void p2p_channels_dump(struct p2p_data *p2p, const char *title,
+		       const struct p2p_channels *chan);
+int p2p_channel_select(struct p2p_channels *chans, const int *classes,
+		       u8 *op_class, u8 *op_channel);
 
 /* p2p_parse.c */
 int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg);
@@ -602,6 +618,7 @@
 int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
 				size_t group_id_len);
 void p2p_group_update_ies(struct p2p_group *group);
+void p2p_group_force_beacon_update_ies(struct p2p_group *group);
 struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g);
 
 
@@ -634,8 +651,8 @@
 void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
 				   u16 interval);
 void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p);
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
-		      int all_attr);
+int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
+		     int all_attr);
 
 /* p2p_sd.c */
 struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
@@ -727,7 +744,8 @@
 		    size_t len, unsigned int wait_time);
 void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
 int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
-			unsigned int force_freq, unsigned int pref_freq);
+			unsigned int force_freq, unsigned int pref_freq,
+			int go);
 void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
 PRINTF_FORMAT(2, 3);
 void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 6b3dafb..2734386 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -407,7 +407,7 @@
 		return;
 	}
 
-	if (!msg.channel_list) {
+	if (!msg.channel_list && *msg.status == P2P_SC_SUCCESS) {
 		p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from "
 			MACSTR, MAC2STR(sa));
 #ifdef CONFIG_P2P_STRICT
@@ -416,6 +416,9 @@
 #endif /* CONFIG_P2P_STRICT */
 		/* Try to survive without peer channel list */
 		channels = &p2p->channels;
+	} else if (!msg.channel_list) {
+		/* Non-success cases are not required to include Channel List */
+		channels = &p2p->channels;
 	} else if (p2p_peer_channels_check(p2p, &p2p->channels, dev,
 					   msg.channel_list,
 					   msg.channel_list_len) < 0) {
@@ -428,9 +431,15 @@
 		channels = &intersection;
 	}
 
-	if (p2p->cfg->invitation_result)
+	if (p2p->cfg->invitation_result) {
+		int freq = p2p_channel_to_freq(p2p->op_reg_class,
+					       p2p->op_channel);
+		if (freq < 0)
+			freq = 0;
 		p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
-					    msg.group_bssid, channels, sa);
+					    msg.group_bssid, channels, sa,
+					    freq);
+	}
 
 	p2p_parse_free(&msg);
 
@@ -466,7 +475,7 @@
 	dev->invitation_reqs++;
 	if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
 			    p2p->cfg->dev_addr, dev->info.p2p_device_addr,
-			    wpabuf_head(req), wpabuf_len(req), 200) < 0) {
+			    wpabuf_head(req), wpabuf_len(req), 500) < 0) {
 		p2p_dbg(p2p, "Failed to send Action frame");
 		/* Use P2P find to recover and retry */
 		p2p_set_timeout(p2p, 0, 0);
@@ -492,7 +501,7 @@
 	 * channel.
 	 */
 	p2p_set_state(p2p, P2P_INVITE);
-	p2p_set_timeout(p2p, 0, success ? 350000 : 100000);
+	p2p_set_timeout(p2p, 0, success ? 500000 : 100000);
 }
 
 
@@ -545,7 +554,8 @@
 		return -1;
 	}
 
-	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+				role != P2P_INVITE_ROLE_CLIENT) < 0)
 		return -1;
 
 	if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq &&
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 54aa428..409405f 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -437,6 +437,7 @@
 	}
 
 	p2p->user_initiated_pd = user_initiated_pd;
+	p2p->pd_force_freq = force_freq;
 
 	if (p2p->user_initiated_pd)
 		p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
@@ -472,4 +473,5 @@
 	p2p->user_initiated_pd = 0;
 	os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
 	p2p->pd_retries = 0;
+	p2p->pd_force_freq = 0;
 }
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index a4c48f6..161a402 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -94,6 +94,10 @@
 		if (channel < 149 || channel > 161)
 			return -1;
 		return 5000 + 5 * channel;
+	case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+		if (channel < 36 || channel > 161)
+			return -1;
+		return 5000 + 5 * channel;
 	}
 	return -1;
 }
@@ -204,6 +208,105 @@
 }
 
 
+static void p2p_op_class_union(struct p2p_reg_class *cl,
+			       const struct p2p_reg_class *b_cl)
+{
+	size_t i, j;
+
+	for (i = 0; i < b_cl->channels; i++) {
+		for (j = 0; j < cl->channels; j++) {
+			if (b_cl->channel[i] == cl->channel[j])
+				break;
+		}
+		if (j == cl->channels) {
+			if (cl->channels == P2P_MAX_REG_CLASS_CHANNELS)
+				return;
+			cl->channel[cl->channels++] = b_cl->channel[i];
+		}
+	}
+}
+
+
+/**
+ * p2p_channels_union - Union of channel lists
+ * @a: First set of channels
+ * @b: Second set of channels
+ * @res: Data structure for returning the union of channels
+ */
+void p2p_channels_union(const struct p2p_channels *a,
+			const struct p2p_channels *b,
+			struct p2p_channels *res)
+{
+	size_t i, j;
+
+	if (a != res)
+		os_memcpy(res, a, sizeof(*res));
+
+	for (i = 0; i < res->reg_classes; i++) {
+		struct p2p_reg_class *cl = &res->reg_class[i];
+		for (j = 0; j < b->reg_classes; j++) {
+			const struct p2p_reg_class *b_cl = &b->reg_class[j];
+			if (cl->reg_class != b_cl->reg_class)
+				continue;
+			p2p_op_class_union(cl, b_cl);
+		}
+	}
+
+	for (j = 0; j < b->reg_classes; j++) {
+		const struct p2p_reg_class *b_cl = &b->reg_class[j];
+
+		for (i = 0; i < res->reg_classes; i++) {
+			struct p2p_reg_class *cl = &res->reg_class[i];
+			if (cl->reg_class == b_cl->reg_class)
+				break;
+		}
+
+		if (i == res->reg_classes) {
+			if (res->reg_classes == P2P_MAX_REG_CLASSES)
+				return;
+			os_memcpy(&res->reg_class[res->reg_classes++],
+				  b_cl, sizeof(struct p2p_reg_class));
+		}
+	}
+}
+
+
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+			       const struct wpa_freq_range_list *list)
+{
+	size_t o, c;
+
+	if (list == NULL)
+		return;
+
+	o = 0;
+	while (o < chan->reg_classes) {
+		struct p2p_reg_class *op = &chan->reg_class[o];
+
+		c = 0;
+		while (c < op->channels) {
+			int freq = p2p_channel_to_freq(op->reg_class,
+						       op->channel[c]);
+			if (freq > 0 && freq_range_list_includes(list, freq)) {
+				op->channels--;
+				os_memmove(&op->channel[c],
+					   &op->channel[c + 1],
+					   op->channels - c);
+			} else
+				c++;
+		}
+
+		if (op->channels == 0) {
+			chan->reg_classes--;
+			os_memmove(&chan->reg_class[o], &chan->reg_class[o + 1],
+				   (chan->reg_classes - o) *
+				   sizeof(struct p2p_reg_class));
+		} else
+			o++;
+	}
+}
+
+
 /**
  * p2p_channels_includes - Check whether a channel is included in the list
  * @channels: List of supported channels
@@ -244,39 +347,9 @@
 }
 
 
-#ifdef ANDROID_P2P
-static int p2p_block_op_freq(unsigned int freq)
-{
-	return (freq >= 5170 && freq < 5745);
-}
-
-
-size_t p2p_copy_reg_class(struct p2p_reg_class *dc, struct p2p_reg_class *sc)
-{
-	unsigned int i;
-
-	dc->reg_class = sc->reg_class;
-	dc->channels = 0;
-	for (i=0; i < sc->channels; i++) {
-		if (!p2p_block_op_freq(p2p_channel_to_freq(sc->reg_class,
-							   sc->channel[i]))) {
-			dc->channel[dc->channels] = sc->channel[i];
-			dc->channels++;
-		}
-	}
-	return dc->channels;
-}
-#endif
-
-
 int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
 {
 	u8 op_reg_class, op_channel;
-
-#ifdef ANDROID_P2P
-	if (p2p_block_op_freq(freq))
-		return 0;
-#endif
 	if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
 		return 0;
 	return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
@@ -284,6 +357,29 @@
 }
 
 
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq)
+{
+	u8 op_reg_class, op_channel;
+	if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+		return 0;
+	return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+				     op_channel) &&
+		!freq_range_list_includes(&p2p->no_go_freq, freq);
+}
+
+
+int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq)
+{
+	u8 op_reg_class, op_channel;
+	if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+		return 0;
+	return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+				     op_channel) ||
+		p2p_channels_includes(&p2p->cfg->cli_channels, op_reg_class,
+				      op_channel);
+}
+
+
 unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
 			       const struct p2p_channels *channels)
 {
@@ -310,3 +406,66 @@
 
 	return 0;
 }
+
+
+void p2p_channels_dump(struct p2p_data *p2p, const char *title,
+		       const struct p2p_channels *chan)
+{
+	char buf[500], *pos, *end;
+	size_t i, j;
+	int ret;
+
+	pos = buf;
+	end = pos + sizeof(buf);
+
+	for (i = 0; i < chan->reg_classes; i++) {
+		const struct p2p_reg_class *c;
+		c = &chan->reg_class[i];
+		ret = os_snprintf(pos, end - pos, " %u:", c->reg_class);
+		if (ret < 0 || ret >= end - pos)
+			break;
+		pos += ret;
+
+		for (j = 0; j < c->channels; j++) {
+			ret = os_snprintf(pos, end - pos, "%s%u",
+					  j == 0 ? "" : ",",
+					  c->channel[j]);
+			if (ret < 0 || ret >= end - pos)
+				break;
+			pos += ret;
+		}
+	}
+	*pos = '\0';
+
+	p2p_dbg(p2p, "%s:%s", title, buf);
+}
+
+
+int p2p_channel_select(struct p2p_channels *chans, const int *classes,
+		       u8 *op_class, u8 *op_channel)
+{
+	unsigned int i, j, r;
+
+	for (j = 0; classes[j]; j++) {
+		for (i = 0; i < chans->reg_classes; i++) {
+			struct p2p_reg_class *c = &chans->reg_class[i];
+
+			if (c->channels == 0)
+				continue;
+
+			if (c->reg_class == classes[j]) {
+				/*
+				 * Pick one of the available channels in the
+				 * operating class at random.
+				 */
+				os_get_random((u8 *) &r, sizeof(r));
+				r %= c->channels;
+				*op_class = c->reg_class;
+				*op_channel = c->channel[r];
+				return 0;
+			}
+		}
+	}
+
+	return -1;
+}
diff --git a/src/radius/radius.c b/src/radius/radius.c
index d1feec9..494f92d 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -233,7 +233,7 @@
 	{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
 	{ RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }
 };
-#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
+#define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
 
 
 static struct radius_attr_type *radius_get_attr_type(u8 type)
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 425ad93..290c7c8 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -300,7 +300,7 @@
 {
 #ifndef CONFIG_NATIVE_WINDOWS
 	int _errno = errno;
-	perror("send[RADIUS]");
+	wpa_printf(MSG_INFO, "send[RADIUS]: %s", strerror(errno));
 	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
 	    _errno == EBADF) {
 		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
@@ -361,8 +361,7 @@
 	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
 		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
 	if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
-		printf("Removing un-ACKed RADIUS message due to too many "
-		       "failed retransmit attempts\n");
+		wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
 		return 1;
 	}
 
@@ -526,7 +525,7 @@
 
 	entry = os_zalloc(sizeof(*entry));
 	if (entry == NULL) {
-		printf("Failed to add RADIUS packet into retransmit list\n");
+		wpa_printf(MSG_INFO, "RADIUS: Failed to add packet into retransmit list");
 		radius_msg_free(msg);
 		return;
 	}
@@ -547,8 +546,7 @@
 	radius_client_update_timeout(radius);
 
 	if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
-		printf("Removing the oldest un-ACKed RADIUS packet due to "
-		       "retransmit list limits.\n");
+		wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits");
 		prev = NULL;
 		while (entry->next) {
 			prev = entry;
@@ -710,21 +708,20 @@
 
 	len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
 	if (len < 0) {
-		perror("recv[RADIUS]");
+		wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
 		return;
 	}
 	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 		       HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
 		       "server", len);
 	if (len == sizeof(buf)) {
-		printf("Possibly too long UDP frame for our buffer - "
-		       "dropping it\n");
+		wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
 		return;
 	}
 
 	msg = radius_msg_parse(buf, len);
 	if (msg == NULL) {
-		printf("Parsing incoming RADIUS frame failed\n");
+		wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed");
 		rconf->malformed_responses++;
 		return;
 	}
@@ -1041,13 +1038,14 @@
 		}
 
 		if (bind(sel_sock, cl_addr, claddrlen) < 0) {
-			perror("bind[radius]");
+			wpa_printf(MSG_INFO, "bind[radius]: %s",
+				   strerror(errno));
 			return -1;
 		}
 	}
 
 	if (connect(sel_sock, addr, addrlen) < 0) {
-		perror("connect[radius]");
+		wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
 		return -1;
 	}
 
@@ -1123,8 +1121,8 @@
 	r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
 		       sizeof(action));
 	if (r == -1)
-		wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
-			   "%s", strerror(errno));
+		wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
+			   strerror(errno));
 #endif
 	return r;
 }
@@ -1137,7 +1135,8 @@
 
 	radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (radius->auth_serv_sock < 0)
-		perror("socket[PF_INET,SOCK_DGRAM]");
+		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
+			   strerror(errno));
 	else {
 		radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
 		ok++;
@@ -1146,7 +1145,8 @@
 #ifdef CONFIG_IPV6
 	radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
 	if (radius->auth_serv_sock6 < 0)
-		perror("socket[PF_INET6,SOCK_DGRAM]");
+		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
+			   strerror(errno));
 	else
 		ok++;
 #endif /* CONFIG_IPV6 */
@@ -1162,8 +1162,7 @@
 	    eloop_register_read_sock(radius->auth_serv_sock,
 				     radius_client_receive, radius,
 				     (void *) RADIUS_AUTH)) {
-		printf("Could not register read socket for authentication "
-		       "server\n");
+		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
 		return -1;
 	}
 
@@ -1172,8 +1171,7 @@
 	    eloop_register_read_sock(radius->auth_serv_sock6,
 				     radius_client_receive, radius,
 				     (void *) RADIUS_AUTH)) {
-		printf("Could not register read socket for authentication "
-		       "server\n");
+		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
 		return -1;
 	}
 #endif /* CONFIG_IPV6 */
@@ -1189,7 +1187,8 @@
 
 	radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (radius->acct_serv_sock < 0)
-		perror("socket[PF_INET,SOCK_DGRAM]");
+		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
+			   strerror(errno));
 	else {
 		radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
 		ok++;
@@ -1198,7 +1197,8 @@
 #ifdef CONFIG_IPV6
 	radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
 	if (radius->acct_serv_sock6 < 0)
-		perror("socket[PF_INET6,SOCK_DGRAM]");
+		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
+			   strerror(errno));
 	else
 		ok++;
 #endif /* CONFIG_IPV6 */
@@ -1214,8 +1214,7 @@
 	    eloop_register_read_sock(radius->acct_serv_sock,
 				     radius_client_receive, radius,
 				     (void *) RADIUS_ACCT)) {
-		printf("Could not register read socket for accounting "
-		       "server\n");
+		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
 		return -1;
 	}
 
@@ -1224,8 +1223,7 @@
 	    eloop_register_read_sock(radius->acct_serv_sock6,
 				     radius_client_receive, radius,
 				     (void *) RADIUS_ACCT)) {
-		printf("Could not register read socket for accounting "
-		       "server\n");
+		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
 		return -1;
 	}
 #endif /* CONFIG_IPV6 */
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index bded965..418b160 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -1,6 +1,6 @@
 /*
  * RADIUS Dynamic Authorization Server (DAS) (RFC 5176)
- * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -200,7 +200,8 @@
 				  (u8 *) &val, 4);
 	if (res == 4) {
 		u32 timestamp = ntohl(val);
-		if (abs(now.sec - timestamp) > das->time_window) {
+		if ((unsigned int) abs(now.sec - timestamp) >
+		    das->time_window) {
 			wpa_printf(MSG_DEBUG, "DAS: Unacceptable "
 				   "Event-Timestamp (%u; local time %u) in "
 				   "packet from %s:%d - drop",
@@ -284,7 +285,7 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket");
+		wpa_printf(MSG_INFO, "RADIUS DAS: socket: %s", strerror(errno));
 		return -1;
 	}
 
@@ -292,7 +293,7 @@
 	addr.sin_family = AF_INET;
 	addr.sin_port = htons(port);
 	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind");
+		wpa_printf(MSG_INFO, "RADIUS DAS: bind: %s", strerror(errno));
 		close(s);
 		return -1;
 	}
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 0144c9f..fe19770 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -679,7 +679,7 @@
 	buf = radius_msg_get_buf(msg);
 	if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
 		   (struct sockaddr *) from, sizeof(*from)) < 0) {
-		perror("sendto[RADIUS SRV]");
+		wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", strerror(errno));
 		ret = -1;
 	}
 
@@ -750,7 +750,8 @@
 				     wpabuf_len(buf), 0,
 				     (struct sockaddr *) from, fromlen);
 			if (res < 0) {
-				perror("sendto[RADIUS SRV]");
+				wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
+					   strerror(errno));
 			}
 			return 0;
 		}
@@ -842,7 +843,8 @@
 			     wpabuf_len(buf), 0,
 			     (struct sockaddr *) from, fromlen);
 		if (res < 0) {
-			perror("sendto[RADIUS SRV]");
+			wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
+				   strerror(errno));
 		}
 		radius_msg_free(sess->last_reply);
 		sess->last_reply = reply;
@@ -897,7 +899,8 @@
 	len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
 		       (struct sockaddr *) &from.ss, &fromlen);
 	if (len < 0) {
-		perror("recvfrom[radius_server]");
+		wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s",
+			   strerror(errno));
 		goto fail;
 	}
 
@@ -1001,7 +1004,7 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket");
+		wpa_printf(MSG_INFO, "RADIUS: socket: %s", strerror(errno));
 		return -1;
 	}
 
@@ -1011,7 +1014,7 @@
 	addr.sin_family = AF_INET;
 	addr.sin_port = htons(port);
 	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind");
+		wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -1028,7 +1031,8 @@
 
 	s = socket(PF_INET6, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket[IPv6]");
+		wpa_printf(MSG_INFO, "RADIUS: socket[IPv6]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -1037,7 +1041,7 @@
 	os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
 	addr.sin6_port = htons(port);
 	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind");
+		wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -1248,8 +1252,7 @@
 
 #ifndef CONFIG_IPV6
 	if (conf->ipv6) {
-		fprintf(stderr, "RADIUS server compiled without IPv6 "
-			"support.\n");
+		wpa_printf(MSG_ERROR, "RADIUS server compiled without IPv6 support");
 		return NULL;
 	}
 #endif /* CONFIG_IPV6 */
@@ -1305,7 +1308,7 @@
 	data->clients = radius_server_read_clients(conf->client_file,
 						   conf->ipv6);
 	if (data->clients == NULL) {
-		printf("No RADIUS clients configured.\n");
+		wpa_printf(MSG_ERROR, "No RADIUS clients configured");
 		radius_server_deinit(data);
 		return NULL;
 	}
@@ -1317,8 +1320,7 @@
 #endif /* CONFIG_IPV6 */
 	data->auth_sock = radius_server_open_socket(conf->auth_port);
 	if (data->auth_sock < 0) {
-		printf("Failed to open UDP socket for RADIUS authentication "
-		       "server\n");
+		wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server");
 		radius_server_deinit(data);
 		return NULL;
 	}
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index e911ad0..efc6431 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -797,6 +797,28 @@
 }
 
 
+const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr)
+{
+	struct wpa_tdls_peer *peer;
+
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return "disabled";
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer == NULL)
+		return "peer does not exist";
+
+	if (!peer->tpk_success)
+		return "peer not connected";
+
+	return "connected";
+}
+
+
 static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
 				  const u8 *buf, size_t len)
 {
@@ -1817,7 +1839,7 @@
 	int ielen;
 	u16 status;
 	const u8 *pos;
-	int ret;
+	int ret = 0;
 
 	wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 "
 		   "(Peer " MACSTR ")", MAC2STR(src_addr));
@@ -2034,11 +2056,19 @@
 		return -1;
 	}
 
-	ret = wpa_tdls_enable_link(sm, peer);
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
-		wpa_tdls_do_teardown(sm, peer,
-				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+	if (!peer->tpk_success) {
+		/*
+		 * Enable Link only when tpk_success is 0, signifying that this
+		 * processing of TPK M2 frame is not because of a retransmission
+		 * during TDLS setup handshake.
+		 */
+		ret = wpa_tdls_enable_link(sm, peer);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
+			wpa_tdls_do_teardown(
+				sm, peer,
+				WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+		}
 	}
 	return ret;
 
@@ -2062,7 +2092,7 @@
 	u16 status;
 	const u8 *pos;
 	u32 lifetime;
-	int ret;
+	int ret = 0;
 
 	wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 "
 		   "(Peer " MACSTR ")", MAC2STR(src_addr));
@@ -2179,11 +2209,19 @@
 	}
 
 skip_rsn:
-	ret = wpa_tdls_enable_link(sm, peer);
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
-		wpa_tdls_do_teardown(sm, peer,
-				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+	if (!peer->tpk_success) {
+		/*
+		 * Enable Link only when tpk_success is 0, signifying that this
+		 * processing of TPK M3 frame is not because of a retransmission
+		 * during TDLS setup handshake.
+		 */
+		ret = wpa_tdls_enable_link(sm, peer);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
+			wpa_tdls_do_teardown(
+				sm, peer,
+				WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+		}
 	}
 	return ret;
 error:
@@ -2284,7 +2322,7 @@
 		 * Disable previous link to allow renegotiation to be completed
 		 * on AP path.
 		 */
-		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+		wpa_tdls_disable_peer_link(sm, peer);
 	}
 }
 
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 292255c..d4f86e6 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1126,7 +1126,8 @@
 		goto failed;
 	}
 
-	wpa_sm_set_rekey_offload(sm);
+	if (ie.gtk)
+		wpa_sm_set_rekey_offload(sm);
 
 	return;
 
@@ -1347,13 +1348,14 @@
 			MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
 		wpa_sm_cancel_auth_timeout(sm);
 		wpa_sm_set_state(sm, WPA_COMPLETED);
-
-		wpa_sm_set_rekey_offload(sm);
 	} else {
 		wpa_supplicant_key_neg_complete(sm, sm->bssid,
 						key_info &
 						WPA_KEY_INFO_SECURE);
 	}
+
+	wpa_sm_set_rekey_offload(sm);
+
 	return;
 
 failed:
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 26e9c6c..db7f0db 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -380,6 +380,7 @@
 void wpa_tdls_deinit(struct wpa_sm *sm);
 void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
 void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
+const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr);
 int wpa_tdls_is_external_setup(struct wpa_sm *sm);
 
 int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index d212862..4578b22 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -57,8 +57,7 @@
 	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
 };
 
-#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
-#define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites)
+#define NUM_TLS_CIPHER_SUITES ARRAY_SIZE(tls_cipher_suites)
 
 
 static const struct tls_cipher_data tls_ciphers[] = {
@@ -84,7 +83,7 @@
 	  CRYPTO_CIPHER_ALG_AES }
 };
 
-#define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers)
+#define NUM_TLS_CIPHER_DATA ARRAY_SIZE(tls_ciphers)
 
 
 /**
diff --git a/src/utils/Makefile b/src/utils/Makefile
index 940b4d8..b04a8a3 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -11,6 +11,7 @@
 
 #CFLAGS += -DWPA_TRACE
 CFLAGS += -DCONFIG_IPV6
+CFLAGS += -DCONFIG_DEBUG_FILE
 
 LIB_OBJS= \
 	base64.o \
diff --git a/src/utils/common.c b/src/utils/common.c
index bf326cd..257bb6d 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -400,7 +400,7 @@
 	int val;
 
 	while (*pos) {
-		if (len == maxlen)
+		if (len + 1 >= maxlen)
 			break;
 		switch (*pos) {
 		case '\\':
@@ -468,6 +468,8 @@
 			break;
 		}
 	}
+	if (maxlen > len)
+		buf[len] = '\0';
 
 	return len;
 }
@@ -576,6 +578,21 @@
 }
 
 
+int find_first_bit(u32 value)
+{
+	int pos = 0;
+
+	while (value) {
+		if (value & 0x1)
+			return pos;
+		value >>= 1;
+		pos++;
+	}
+
+	return -1;
+}
+
+
 size_t merge_byte_arrays(u8 *res, size_t res_len,
 			 const u8 *src1, size_t src1_len,
 			 const u8 *src2, size_t src2_len)
@@ -622,3 +639,99 @@
 
 	return res;
 }
+
+
+int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value)
+{
+	struct wpa_freq_range *freq = NULL, *n;
+	unsigned int count = 0;
+	const char *pos, *pos2, *pos3;
+
+	/*
+	 * Comma separated list of frequency ranges.
+	 * For example: 2412-2432,2462,5000-6000
+	 */
+	pos = value;
+	while (pos && pos[0]) {
+		n = os_realloc_array(freq, count + 1,
+				     sizeof(struct wpa_freq_range));
+		if (n == NULL) {
+			os_free(freq);
+			return -1;
+		}
+		freq = n;
+		freq[count].min = atoi(pos);
+		pos2 = os_strchr(pos, '-');
+		pos3 = os_strchr(pos, ',');
+		if (pos2 && (!pos3 || pos2 < pos3)) {
+			pos2++;
+			freq[count].max = atoi(pos2);
+		} else
+			freq[count].max = freq[count].min;
+		pos = pos3;
+		if (pos)
+			pos++;
+		count++;
+	}
+
+	os_free(res->range);
+	res->range = freq;
+	res->num = count;
+
+	return 0;
+}
+
+
+int freq_range_list_includes(const struct wpa_freq_range_list *list,
+			     unsigned int freq)
+{
+	unsigned int i;
+
+	if (list == NULL)
+		return 0;
+
+	for (i = 0; i < list->num; i++) {
+		if (freq >= list->range[i].min && freq <= list->range[i].max)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+char * freq_range_list_str(const struct wpa_freq_range_list *list)
+{
+	char *buf, *pos, *end;
+	size_t maxlen;
+	unsigned int i;
+	int res;
+
+	if (list->num == 0)
+		return NULL;
+
+	maxlen = list->num * 30;
+	buf = os_malloc(maxlen);
+	if (buf == NULL)
+		return NULL;
+	pos = buf;
+	end = buf + maxlen;
+
+	for (i = 0; i < list->num; i++) {
+		struct wpa_freq_range *range = &list->range[i];
+
+		if (range->min == range->max)
+			res = os_snprintf(pos, end - pos, "%s%u",
+					  i == 0 ? "" : ",", range->min);
+		else
+			res = os_snprintf(pos, end - pos, "%s%u-%u",
+					  i == 0 ? "" : ",",
+					  range->min, range->max);
+		if (res < 0 || res > end - pos) {
+			os_free(buf);
+			return NULL;
+		}
+		pos += res;
+	}
+
+	return buf;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 29f0b95..028a5ef 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -485,6 +485,7 @@
 
 char * wpa_config_parse_string(const char *value, size_t *len);
 int is_hex(const u8 *data, size_t len);
+int find_first_bit(u32 value);
 size_t merge_byte_arrays(u8 *res, size_t res_len,
 			 const u8 *src1, size_t src1_len,
 			 const u8 *src2, size_t src2_len);
@@ -505,6 +506,22 @@
 #include "wpa_debug.h"
 
 
+struct wpa_freq_range_list {
+	struct wpa_freq_range {
+		unsigned int min;
+		unsigned int max;
+	} *range;
+	unsigned int num;
+};
+
+int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value);
+int freq_range_list_includes(const struct wpa_freq_range_list *list,
+			     unsigned int freq);
+char * freq_range_list_str(const struct wpa_freq_range_list *list);
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+
 /*
  * gcc 4.4 ends up generating strict-aliasing warnings about some very common
  * networking socket uses that do not really result in a real problem and
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index f62e2b7..e983edc 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -31,7 +31,7 @@
 
 struct eloop_timeout {
 	struct dl_list list;
-	struct os_time time;
+	struct os_reltime time;
 	void *eloop_data;
 	void *user_data;
 	eloop_timeout_handler handler;
@@ -484,7 +484,7 @@
 	timeout = os_zalloc(sizeof(*timeout));
 	if (timeout == NULL)
 		return -1;
-	if (os_get_time(&timeout->time) < 0) {
+	if (os_get_reltime(&timeout->time) < 0) {
 		os_free(timeout);
 		return -1;
 	}
@@ -514,7 +514,7 @@
 
 	/* Maintain timeouts in order of increasing time */
 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
-		if (os_time_before(&timeout->time, &tmp->time)) {
+		if (os_reltime_before(&timeout->time, &tmp->time)) {
 			dl_list_add(tmp->list.prev, &timeout->list);
 			return 0;
 		}
@@ -558,13 +558,13 @@
 
 int eloop_cancel_timeout_one(eloop_timeout_handler handler,
 			     void *eloop_data, void *user_data,
-			     struct os_time *remaining)
+			     struct os_reltime *remaining)
 {
 	struct eloop_timeout *timeout, *prev;
 	int removed = 0;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	remaining->sec = remaining->usec = 0;
 
 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
@@ -573,8 +573,8 @@
 		    (timeout->eloop_data == eloop_data) &&
 		    (timeout->user_data == user_data)) {
 			removed = 1;
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, remaining);
+			if (os_reltime_before(&now, &timeout->time))
+				os_reltime_sub(&timeout->time, &now, remaining);
 			eloop_remove_timeout(timeout);
 			break;
 		}
@@ -599,6 +599,68 @@
 }
 
 
+int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
+			  eloop_timeout_handler handler, void *eloop_data,
+			  void *user_data)
+{
+	struct os_reltime now, requested, remaining;
+	struct eloop_timeout *tmp;
+
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data) {
+			requested.sec = req_secs;
+			requested.usec = req_usecs;
+			os_get_reltime(&now);
+			os_reltime_sub(&tmp->time, &now, &remaining);
+			if (os_reltime_before(&requested, &remaining)) {
+				eloop_cancel_timeout(handler, eloop_data,
+						     user_data);
+				eloop_register_timeout(requested.sec,
+						       requested.usec,
+						       handler, eloop_data,
+						       user_data);
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
+			    eloop_timeout_handler handler, void *eloop_data,
+			    void *user_data)
+{
+	struct os_reltime now, requested, remaining;
+	struct eloop_timeout *tmp;
+
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data) {
+			requested.sec = req_secs;
+			requested.usec = req_usecs;
+			os_get_reltime(&now);
+			os_reltime_sub(&tmp->time, &now, &remaining);
+			if (os_reltime_before(&remaining, &requested)) {
+				eloop_cancel_timeout(handler, eloop_data,
+						     user_data);
+				eloop_register_timeout(requested.sec,
+						       requested.usec,
+						       handler, eloop_data,
+						       user_data);
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+
 #ifndef CONFIG_NATIVE_WINDOWS
 static void eloop_handle_alarm(int sig)
 {
@@ -714,7 +776,7 @@
 	struct timeval _tv;
 #endif /* CONFIG_ELOOP_POLL */
 	int res;
-	struct os_time tv, now;
+	struct os_reltime tv, now;
 
 #ifndef CONFIG_ELOOP_POLL
 	rfds = os_malloc(sizeof(*rfds));
@@ -731,9 +793,9 @@
 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
 					list);
 		if (timeout) {
-			os_get_time(&now);
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, &tv);
+			os_get_reltime(&now);
+			if (os_reltime_before(&now, &timeout->time))
+				os_reltime_sub(&timeout->time, &now, &tv);
 			else
 				tv.sec = tv.usec = 0;
 #ifdef CONFIG_ELOOP_POLL
@@ -753,7 +815,8 @@
 			   timeout ? timeout_ms : -1);
 
 		if (res < 0 && errno != EINTR && errno != 0) {
-			perror("poll");
+			wpa_printf(MSG_INFO, "eloop: poll: %s",
+				   strerror(errno));
 			goto out;
 		}
 #else /* CONFIG_ELOOP_POLL */
@@ -763,7 +826,8 @@
 		res = select(eloop.max_sock + 1, rfds, wfds, efds,
 			     timeout ? &_tv : NULL);
 		if (res < 0 && errno != EINTR && errno != 0) {
-			perror("select");
+			wpa_printf(MSG_INFO, "eloop: select: %s",
+				   strerror(errno));
 			goto out;
 		}
 #endif /* CONFIG_ELOOP_POLL */
@@ -773,8 +837,8 @@
 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
 					list);
 		if (timeout) {
-			os_get_time(&now);
-			if (!os_time_before(&now, &timeout->time)) {
+			os_get_reltime(&now);
+			if (!os_reltime_before(&now, &timeout->time)) {
 				void *eloop_data = timeout->eloop_data;
 				void *user_data = timeout->user_data;
 				eloop_timeout_handler handler =
@@ -819,9 +883,9 @@
 void eloop_destroy(void)
 {
 	struct eloop_timeout *timeout, *prev;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
 			      struct eloop_timeout, list) {
 		int sec, usec;
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
index 0037c63..d3980fa 100644
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -207,7 +207,7 @@
  */
 int eloop_cancel_timeout_one(eloop_timeout_handler handler,
 			     void *eloop_data, void *user_data,
-			     struct os_time *remaining);
+			     struct os_reltime *remaining);
 
 /**
  * eloop_is_timeout_registered - Check if a timeout is already registered
@@ -223,6 +223,38 @@
 				void *eloop_data, void *user_data);
 
 /**
+ * eloop_deplete_timeout - Deplete a timeout that is already registered
+ * @req_secs: Requested number of seconds to the timeout
+ * @req_usecs: Requested number of microseconds to the timeout
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * Returns: 1 if the timeout is depleted, 0 if no change is made
+ *
+ * Find a registered matching <handler,eloop_data,user_data> timeout. If found,
+ * deplete the timeout if remaining time is more than the requested time.
+ */
+int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
+			  eloop_timeout_handler handler, void *eloop_data,
+			  void *user_data);
+
+/**
+ * eloop_replenish_timeout - Replenish a timeout that is already registered
+ * @req_secs: Requested number of seconds to the timeout
+ * @req_usecs: Requested number of microseconds to the timeout
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * Returns: 1 if the timeout is replenished, 0 if no change is made
+ *
+ * Find a registered matching <handler,eloop_data,user_data> timeout. If found,
+ * replenish the timeout if remaining time is less than the requested time.
+ */
+int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
+			    eloop_timeout_handler handler, void *eloop_data,
+			    void *user_data);
+
+/**
  * eloop_register_signal - Register handler for signals
  * @sig: Signal number (e.g., SIGHUP)
  * @handler: Callback function to be called when the signal is received
diff --git a/src/utils/eloop_none.c b/src/utils/eloop_none.c
deleted file mode 100644
index cb5e922..0000000
--- a/src/utils/eloop_none.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Event loop - empty template (basic structure, but no OS specific operations)
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "list.h"
-#include "eloop.h"
-
-
-struct eloop_sock {
-	int sock;
-	void *eloop_data;
-	void *user_data;
-	eloop_sock_handler handler;
-};
-
-struct eloop_timeout {
-	struct dl_list list;
-	struct os_time time;
-	void *eloop_data;
-	void *user_data;
-	eloop_timeout_handler handler;
-};
-
-struct eloop_signal {
-	int sig;
-	void *user_data;
-	eloop_signal_handler handler;
-	int signaled;
-};
-
-struct eloop_data {
-	int max_sock, reader_count;
-	struct eloop_sock *readers;
-
-	struct dl_list timeout;
-
-	int signal_count;
-	struct eloop_signal *signals;
-	int signaled;
-	int pending_terminate;
-
-	int terminate;
-	int reader_table_changed;
-};
-
-static struct eloop_data eloop;
-
-
-int eloop_init(void)
-{
-	os_memset(&eloop, 0, sizeof(eloop));
-	dl_list_init(&eloop.timeout);
-	return 0;
-}
-
-
-int eloop_register_read_sock(int sock, eloop_sock_handler handler,
-			     void *eloop_data, void *user_data)
-{
-	struct eloop_sock *tmp;
-
-	tmp = os_realloc_array(eloop.readers, eloop.reader_count + 1,
-			       sizeof(struct eloop_sock));
-	if (tmp == NULL)
-		return -1;
-
-	tmp[eloop.reader_count].sock = sock;
-	tmp[eloop.reader_count].eloop_data = eloop_data;
-	tmp[eloop.reader_count].user_data = user_data;
-	tmp[eloop.reader_count].handler = handler;
-	eloop.reader_count++;
-	eloop.readers = tmp;
-	if (sock > eloop.max_sock)
-		eloop.max_sock = sock;
-	eloop.reader_table_changed = 1;
-
-	return 0;
-}
-
-
-void eloop_unregister_read_sock(int sock)
-{
-	int i;
-
-	if (eloop.readers == NULL || eloop.reader_count == 0)
-		return;
-
-	for (i = 0; i < eloop.reader_count; i++) {
-		if (eloop.readers[i].sock == sock)
-			break;
-	}
-	if (i == eloop.reader_count)
-		return;
-	if (i != eloop.reader_count - 1) {
-		os_memmove(&eloop.readers[i], &eloop.readers[i + 1],
-			   (eloop.reader_count - i - 1) *
-			   sizeof(struct eloop_sock));
-	}
-	eloop.reader_count--;
-	eloop.reader_table_changed = 1;
-}
-
-
-int eloop_register_timeout(unsigned int secs, unsigned int usecs,
-			   eloop_timeout_handler handler,
-			   void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *timeout, *tmp;
-	os_time_t now_sec;
-
-	timeout = os_zalloc(sizeof(*timeout));
-	if (timeout == NULL)
-		return -1;
-	if (os_get_time(&timeout->time) < 0) {
-		os_free(timeout);
-		return -1;
-	}
-	now_sec = timeout->time.sec;
-	timeout->time.sec += secs;
-	if (timeout->time.sec < now_sec) {
-		/*
-		 * Integer overflow - assume long enough timeout to be assumed
-		 * to be infinite, i.e., the timeout would never happen.
-		 */
-		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
-			   "ever happen - ignore it", secs);
-		os_free(timeout);
-		return 0;
-	}
-	timeout->time.usec += usecs;
-	while (timeout->time.usec >= 1000000) {
-		timeout->time.sec++;
-		timeout->time.usec -= 1000000;
-	}
-	timeout->eloop_data = eloop_data;
-	timeout->user_data = user_data;
-	timeout->handler = handler;
-
-	/* Maintain timeouts in order of increasing time */
-	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
-		if (os_time_before(&timeout->time, &tmp->time)) {
-			dl_list_add(tmp->list.prev, &timeout->list);
-			return 0;
-		}
-	}
-	dl_list_add_tail(&eloop.timeout, &timeout->list);
-
-	return 0;
-}
-
-
-static void eloop_remove_timeout(struct eloop_timeout *timeout)
-{
-	dl_list_del(&timeout->list);
-	os_free(timeout);
-}
-
-
-int eloop_cancel_timeout(eloop_timeout_handler handler,
-			 void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *timeout, *prev;
-	int removed = 0;
-
-	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
-			      struct eloop_timeout, list) {
-		if (timeout->handler == handler &&
-		    (timeout->eloop_data == eloop_data ||
-		     eloop_data == ELOOP_ALL_CTX) &&
-		    (timeout->user_data == user_data ||
-		     user_data == ELOOP_ALL_CTX)) {
-			eloop_remove_timeout(timeout);
-			removed++;
-		}
-	}
-
-	return removed;
-}
-
-
-int eloop_cancel_timeout_one(eloop_timeout_handler handler,
-			     void *eloop_data, void *user_data,
-			     struct os_time *remaining)
-{
-	struct eloop_timeout *timeout, *prev;
-	int removed = 0;
-	struct os_time now;
-
-	os_get_time(&now);
-	remaining->sec = remaining->usec = 0;
-
-	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
-			      struct eloop_timeout, list) {
-		if (timeout->handler == handler &&
-		    (timeout->eloop_data == eloop_data) &&
-		    (timeout->user_data == user_data)) {
-			removed = 1;
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, remaining);
-			eloop_remove_timeout(timeout);
-			break;
-		}
-	}
-	return removed;
-}
-
-
-int eloop_is_timeout_registered(eloop_timeout_handler handler,
-				void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *tmp;
-
-	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
-		if (tmp->handler == handler &&
-		    tmp->eloop_data == eloop_data &&
-		    tmp->user_data == user_data)
-			return 1;
-	}
-
-	return 0;
-}
-
-
-/* TODO: replace with suitable signal handler */
-#if 0
-static void eloop_handle_signal(int sig)
-{
-	int i;
-
-	eloop.signaled++;
-	for (i = 0; i < eloop.signal_count; i++) {
-		if (eloop.signals[i].sig == sig) {
-			eloop.signals[i].signaled++;
-			break;
-		}
-	}
-}
-#endif
-
-
-static void eloop_process_pending_signals(void)
-{
-	int i;
-
-	if (eloop.signaled == 0)
-		return;
-	eloop.signaled = 0;
-
-	if (eloop.pending_terminate) {
-		eloop.pending_terminate = 0;
-	}
-
-	for (i = 0; i < eloop.signal_count; i++) {
-		if (eloop.signals[i].signaled) {
-			eloop.signals[i].signaled = 0;
-			eloop.signals[i].handler(eloop.signals[i].sig,
-						 eloop.signals[i].user_data);
-		}
-	}
-}
-
-
-int eloop_register_signal(int sig, eloop_signal_handler handler,
-			  void *user_data)
-{
-	struct eloop_signal *tmp;
-
-	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
-			       sizeof(struct eloop_signal));
-	if (tmp == NULL)
-		return -1;
-
-	tmp[eloop.signal_count].sig = sig;
-	tmp[eloop.signal_count].user_data = user_data;
-	tmp[eloop.signal_count].handler = handler;
-	tmp[eloop.signal_count].signaled = 0;
-	eloop.signal_count++;
-	eloop.signals = tmp;
-
-	/* TODO: register signal handler */
-
-	return 0;
-}
-
-
-int eloop_register_signal_terminate(eloop_signal_handler handler,
-				    void *user_data)
-{
-#if 0
-	/* TODO: for example */
-	int ret = eloop_register_signal(SIGINT, handler, user_data);
-	if (ret == 0)
-		ret = eloop_register_signal(SIGTERM, handler, user_data);
-	return ret;
-#endif
-	return 0;
-}
-
-
-int eloop_register_signal_reconfig(eloop_signal_handler handler,
-				   void *user_data)
-{
-#if 0
-	/* TODO: for example */
-	return eloop_register_signal(SIGHUP, handler, user_data);
-#endif
-	return 0;
-}
-
-
-void eloop_run(void)
-{
-	int i;
-	struct os_time tv, now;
-
-	while (!eloop.terminate &&
-		(!dl_list_empty(&eloop.timeout) || eloop.reader_count > 0)) {
-		struct eloop_timeout *timeout;
-		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
-					list);
-		if (timeout) {
-			os_get_time(&now);
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, &tv);
-			else
-				tv.sec = tv.usec = 0;
-		}
-
-		/*
-		 * TODO: wait for any event (read socket ready, timeout (tv),
-		 * signal
-		 */
-		os_sleep(1, 0); /* just a dummy wait for testing */
-
-		eloop_process_pending_signals();
-
-		/* check if some registered timeouts have occurred */
-		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
-					list);
-		if (timeout) {
-			os_get_time(&now);
-			if (!os_time_before(&now, &timeout->time)) {
-				void *eloop_data = timeout->eloop_data;
-				void *user_data = timeout->user_data;
-				eloop_timeout_handler handler =
-					timeout->handler;
-				eloop_remove_timeout(timeout);
-				handler(eloop_data, user_data);
-			}
-
-		}
-
-		eloop.reader_table_changed = 0;
-		for (i = 0; i < eloop.reader_count; i++) {
-			/*
-			 * TODO: call each handler that has pending data to
-			 * read
-			 */
-			if (0 /* TODO: eloop.readers[i].sock ready */) {
-				eloop.readers[i].handler(
-					eloop.readers[i].sock,
-					eloop.readers[i].eloop_data,
-					eloop.readers[i].user_data);
-				if (eloop.reader_table_changed)
-					break;
-			}
-		}
-	}
-}
-
-
-void eloop_terminate(void)
-{
-	eloop.terminate = 1;
-}
-
-
-void eloop_destroy(void)
-{
-	struct eloop_timeout *timeout, *prev;
-
-	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
-			      struct eloop_timeout, list) {
-		eloop_remove_timeout(timeout);
-	}
-	os_free(eloop.readers);
-	os_free(eloop.signals);
-}
-
-
-int eloop_terminated(void)
-{
-	return eloop.terminate;
-}
-
-
-void eloop_wait_for_read_sock(int sock)
-{
-	/*
-	 * TODO: wait for the file descriptor to have something available for
-	 * reading
-	 */
-}
diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c
index eda412f..a1f9996 100644
--- a/src/utils/eloop_win.c
+++ b/src/utils/eloop_win.c
@@ -31,7 +31,7 @@
 
 struct eloop_timeout {
 	struct dl_list list;
-	struct os_time time;
+	struct os_reltime time;
 	void *eloop_data;
 	void *user_data;
 	eloop_timeout_handler handler;
@@ -244,7 +244,7 @@
 	timeout = os_zalloc(sizeof(*timeout));
 	if (timeout == NULL)
 		return -1;
-	if (os_get_time(&timeout->time) < 0) {
+	if (os_get_reltime(&timeout->time) < 0) {
 		os_free(timeout);
 		return -1;
 	}
@@ -271,7 +271,7 @@
 
 	/* Maintain timeouts in order of increasing time */
 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
-		if (os_time_before(&timeout->time, &tmp->time)) {
+		if (os_reltime_before(&timeout->time, &tmp->time)) {
 			dl_list_add(tmp->list.prev, &timeout->list);
 			return 0;
 		}
@@ -313,13 +313,13 @@
 
 int eloop_cancel_timeout_one(eloop_timeout_handler handler,
 			     void *eloop_data, void *user_data,
-			     struct os_time *remaining)
+			     struct os_reltime *remaining)
 {
 	struct eloop_timeout *timeout, *prev;
 	int removed = 0;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	remaining->sec = remaining->usec = 0;
 
 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
@@ -328,8 +328,8 @@
 		    (timeout->eloop_data == eloop_data) &&
 		    (timeout->user_data == user_data)) {
 			removed = 1;
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, remaining);
+			if (os_reltime_before(&now, &timeout->time))
+				os_reltime_sub(&timeout->time, &now, remaining);
 			eloop_remove_timeout(timeout);
 			break;
 		}
@@ -354,6 +354,68 @@
 }
 
 
+int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
+			  eloop_timeout_handler handler, void *eloop_data,
+			  void *user_data)
+{
+	struct os_reltime now, requested, remaining;
+	struct eloop_timeout *tmp;
+
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data) {
+			requested.sec = req_secs;
+			requested.usec = req_usecs;
+			os_get_reltime(&now);
+			os_reltime_sub(&tmp->time, &now, &remaining);
+			if (os_reltime_before(&requested, &remaining)) {
+				eloop_cancel_timeout(handler, eloop_data,
+						     user_data);
+				eloop_register_timeout(requested.sec,
+						       requested.usec,
+						       handler, eloop_data,
+						       user_data);
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
+			    eloop_timeout_handler handler, void *eloop_data,
+			    void *user_data)
+{
+	struct os_reltime now, requested, remaining;
+	struct eloop_timeout *tmp;
+
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data) {
+			requested.sec = req_secs;
+			requested.usec = req_usecs;
+			os_get_reltime(&now);
+			os_reltime_sub(&tmp->time, &now, &remaining);
+			if (os_reltime_before(&remaining, &requested)) {
+				eloop_cancel_timeout(handler, eloop_data,
+						     user_data);
+				eloop_register_timeout(requested.sec,
+						       requested.usec,
+						       handler, eloop_data,
+						       user_data);
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+
 /* TODO: replace with suitable signal handler */
 #if 0
 static void eloop_handle_signal(int sig)
@@ -468,7 +530,7 @@
 
 void eloop_run(void)
 {
-	struct os_time tv, now;
+	struct os_reltime tv, now;
 	DWORD count, ret, timeout_val, err;
 	size_t i;
 
@@ -480,9 +542,9 @@
 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
 					list);
 		if (timeout) {
-			os_get_time(&now);
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, &tv);
+			os_get_reltime(&now);
+			if (os_reltime_before(&now, &timeout->time))
+				os_reltime_sub(&timeout->time, &now, &tv);
 		}
 
 		count = 0;
@@ -521,8 +583,8 @@
 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
 					list);
 		if (timeout) {
-			os_get_time(&now);
-			if (!os_time_before(&now, &timeout->time)) {
+			os_get_reltime(&now);
+			if (!os_reltime_before(&now, &timeout->time)) {
 				void *eloop_data = timeout->eloop_data;
 				void *user_data = timeout->user_data;
 				eloop_timeout_handler handler =
diff --git a/src/utils/os.h b/src/utils/os.h
index ad20834..77dc6e3 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -23,6 +23,11 @@
 	os_time_t usec;
 };
 
+struct os_reltime {
+	os_time_t sec;
+	os_time_t usec;
+};
+
 /**
  * os_get_time - Get current time (sec, usec)
  * @t: Pointer to buffer for the time
@@ -30,21 +35,56 @@
  */
 int os_get_time(struct os_time *t);
 
+/**
+ * os_get_reltime - Get relative time (sec, usec)
+ * @t: Pointer to buffer for the time
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_reltime(struct os_reltime *t);
 
-/* Helper macros for handling struct os_time */
 
-#define os_time_before(a, b) \
-	((a)->sec < (b)->sec || \
-	 ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
+/* Helpers for handling struct os_time */
 
-#define os_time_sub(a, b, res) do { \
-	(res)->sec = (a)->sec - (b)->sec; \
-	(res)->usec = (a)->usec - (b)->usec; \
-	if ((res)->usec < 0) { \
-		(res)->sec--; \
-		(res)->usec += 1000000; \
-	} \
-} while (0)
+static inline int os_time_before(struct os_time *a, struct os_time *b)
+{
+	return (a->sec < b->sec) ||
+	       (a->sec == b->sec && a->usec < b->usec);
+}
+
+
+static inline void os_time_sub(struct os_time *a, struct os_time *b,
+			       struct os_time *res)
+{
+	res->sec = a->sec - b->sec;
+	res->usec = a->usec - b->usec;
+	if (res->usec < 0) {
+		res->sec--;
+		res->usec += 1000000;
+	}
+}
+
+
+/* Helpers for handling struct os_reltime */
+
+static inline int os_reltime_before(struct os_reltime *a,
+				    struct os_reltime *b)
+{
+	return (a->sec < b->sec) ||
+	       (a->sec == b->sec && a->usec < b->usec);
+}
+
+
+static inline void os_reltime_sub(struct os_reltime *a, struct os_reltime *b,
+				  struct os_reltime *res)
+{
+	res->sec = a->sec - b->sec;
+	res->usec = a->usec - b->usec;
+	if (res->usec < 0) {
+		res->sec--;
+		res->usec += 1000000;
+	}
+}
+
 
 /**
  * os_mktime - Convert broken-down time into seconds since 1970-01-01
@@ -361,15 +401,6 @@
 int os_strncmp(const char *s1, const char *s2, size_t n);
 
 /**
- * os_strncpy - Copy a string
- * @dest: Destination
- * @src: Source
- * @n: Maximum number of characters to copy
- * Returns: dest
- */
-char * os_strncpy(char *dest, const char *src, size_t n);
-
-/**
  * os_strstr - Locate a substring
  * @haystack: String (haystack) to search from
  * @needle: Needle to search from haystack
@@ -465,9 +496,6 @@
 #ifndef os_strncmp
 #define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
 #endif
-#ifndef os_strncpy
-#define os_strncpy(d, s, n) strncpy((d), (s), (n))
-#endif
 #ifndef os_strrchr
 #define os_strrchr(s, c) strrchr((s), (c))
 #endif
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
index e4b7fdb..2cb0d12 100644
--- a/src/utils/os_internal.c
+++ b/src/utils/os_internal.c
@@ -41,6 +41,17 @@
 }
 
 
+int os_get_reltime(struct os_reltime *t)
+{
+	int res;
+	struct timeval tv;
+	res = gettimeofday(&tv, NULL);
+	t->sec = tv.tv_sec;
+	t->usec = tv.tv_usec;
+	return res;
+}
+
+
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
 	      os_time_t *t)
 {
diff --git a/src/utils/os_none.c b/src/utils/os_none.c
index cabf73b..228c472 100644
--- a/src/utils/os_none.c
+++ b/src/utils/os_none.c
@@ -26,6 +26,12 @@
 }
 
 
+int os_get_reltime(struct os_reltime *t)
+{
+	return -1;
+}
+
+
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
 	      os_time_t *t)
 {
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 10b9e0d..fa67fdf 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -17,10 +17,10 @@
 #endif /* ANDROID */
 
 #include "os.h"
+#include "common.h"
 
 #ifdef WPA_TRACE
 
-#include "common.h"
 #include "wpa_debug.h"
 #include "trace.h"
 #include "list.h"
@@ -60,6 +60,43 @@
 }
 
 
+int os_get_reltime(struct os_reltime *t)
+{
+#if defined(CLOCK_BOOTTIME)
+	static clockid_t clock_id = CLOCK_BOOTTIME;
+#elif defined(CLOCK_MONOTONIC)
+	static clockid_t clock_id = CLOCK_MONOTONIC;
+#else
+	static clockid_t clock_id = CLOCK_REALTIME;
+#endif
+	struct timespec ts;
+	int res;
+
+	while (1) {
+		res = clock_gettime(clock_id, &ts);
+		if (res == 0) {
+			t->sec = ts.tv_sec;
+			t->usec = ts.tv_nsec / 1000;
+			return 0;
+		}
+		switch (clock_id) {
+#ifdef CLOCK_BOOTTIME
+		case CLOCK_BOOTTIME:
+			clock_id = CLOCK_MONOTONIC;
+			break;
+#endif
+#ifdef CLOCK_MONOTONIC
+		case CLOCK_MONOTONIC:
+			clock_id = CLOCK_REALTIME;
+			break;
+#endif
+		case CLOCK_REALTIME:
+			return -1;
+		}
+	}
+}
+
+
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
 	      os_time_t *t)
 {
@@ -268,7 +305,7 @@
 	struct __user_cap_header_struct header;
 	struct __user_cap_data_struct cap;
 
-	setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+	setgroups(ARRAY_SIZE(groups), groups);
 
 	prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
 
diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c
index 163cebe..1cfa7a5 100644
--- a/src/utils/os_win32.c
+++ b/src/utils/os_win32.c
@@ -47,6 +47,17 @@
 }
 
 
+int os_get_reltime(struct os_reltime *t)
+{
+	/* consider using performance counters or so instead */
+	struct os_time now;
+	int res = os_get_time(&now);
+	t->sec = now.sec;
+	t->usec = now.usec;
+	return res;
+}
+
+
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
 	      os_time_t *t)
 {
diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c
index 08510d0..ee90d25 100644
--- a/src/utils/pcsc_funcs.c
+++ b/src/utils/pcsc_funcs.c
@@ -485,17 +485,15 @@
 
 /**
  * scard_init - Initialize SIM/USIM connection using PC/SC
- * @sim_type: Allowed SIM types (SIM, USIM, or both)
  * @reader: Reader name prefix to search for
  * Returns: Pointer to private data structure, or %NULL on failure
  *
  * This function is used to initialize SIM/USIM connection. PC/SC is used to
- * open connection to the SIM/USIM card and the card is verified to support the
- * selected sim_type. In addition, local flag is set if a PIN is needed to
- * access some of the card functions. Once the connection is not needed
- * anymore, scard_deinit() can be used to close it.
+ * open connection to the SIM/USIM card. In addition, local flag is set if a
+ * PIN is needed to access some of the card functions. Once the connection is
+ * not needed anymore, scard_deinit() can be used to close it.
  */
-struct scard_data * scard_init(scard_sim_type sim_type, const char *reader)
+struct scard_data * scard_init(const char *reader)
 {
 	long ret;
 	unsigned long len, pos;
@@ -612,20 +610,14 @@
 
 	blen = sizeof(buf);
 
-	scard->sim_type = SCARD_GSM_SIM;
-	if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) {
-		wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
-		if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
-				       SCARD_USIM, NULL, 0)) {
-			wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported");
-			if (sim_type == SCARD_USIM_ONLY)
-				goto failed;
-			wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM");
-			scard->sim_type = SCARD_GSM_SIM;
-		} else {
-			wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
-			scard->sim_type = SCARD_USIM;
-		}
+	wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
+	if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
+			       SCARD_USIM, NULL, 0)) {
+		wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported. Trying to use GSM SIM");
+		scard->sim_type = SCARD_GSM_SIM;
+	} else {
+		wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
+		scard->sim_type = SCARD_USIM;
 	}
 
 	if (scard->sim_type == SCARD_GSM_SIM) {
diff --git a/src/utils/pcsc_funcs.h b/src/utils/pcsc_funcs.h
index b4ebc99..eacd2a2 100644
--- a/src/utils/pcsc_funcs.h
+++ b/src/utils/pcsc_funcs.h
@@ -9,15 +9,8 @@
 #ifndef PCSC_FUNCS_H
 #define PCSC_FUNCS_H
 
-typedef enum {
-	SCARD_GSM_SIM_ONLY,
-	SCARD_USIM_ONLY,
-	SCARD_TRY_BOTH
-} scard_sim_type;
-
-
 #ifdef PCSC_FUNCS
-struct scard_data * scard_init(scard_sim_type sim_type, const char *reader);
+struct scard_data * scard_init(const char *reader);
 void scard_deinit(struct scard_data *scard);
 
 int scard_set_pin(struct scard_data *scard, const char *pin);
@@ -34,7 +27,7 @@
 
 #else /* PCSC_FUNCS */
 
-#define scard_init(s, r) NULL
+#define scard_init(r) NULL
 #define scard_deinit(s) do { } while (0)
 #define scard_set_pin(s, p) -1
 #define scard_get_imsi(s, i, l) -1
diff --git a/src/wps/http_server.c b/src/wps/http_server.c
index 6ca3214..06c8bee 100644
--- a/src/wps/http_server.c
+++ b/src/wps/http_server.c
@@ -232,6 +232,7 @@
 {
 	struct sockaddr_in sin;
 	struct http_server *srv;
+	int on = 1;
 
 	srv = os_zalloc(sizeof(*srv));
 	if (srv == NULL)
@@ -242,6 +243,9 @@
 	srv->fd = socket(AF_INET, SOCK_STREAM, 0);
 	if (srv->fd < 0)
 		goto fail;
+
+	setsockopt(srv->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
 	if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
 		goto fail;
 	if (port < 0)
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index ac9bb1e..b232754 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -118,6 +118,8 @@
 
 int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
 {
+	if (wpabuf_tailroom(msg) < 4 + WPS_UUID_LEN)
+		return -1;
 	wpa_printf(MSG_DEBUG, "WPS:  * UUID-E");
 	wpabuf_put_be16(msg, ATTR_UUID_E);
 	wpabuf_put_be16(msg, WPS_UUID_LEN);
@@ -183,6 +185,8 @@
 	 * backwards compatibility reasons. The real version negotiation is
 	 * done with Version2.
 	 */
+	if (wpabuf_tailroom(msg) < 5)
+		return -1;
 	wpa_printf(MSG_DEBUG, "WPS:  * Version (hardcoded 0x10)");
 	wpabuf_put_be16(msg, ATTR_VERSION);
 	wpabuf_put_be16(msg, 1);
@@ -197,6 +201,10 @@
 #ifdef CONFIG_WPS2
 	u8 *len;
 
+	if (wpabuf_tailroom(msg) <
+	    7 + 3 + (req_to_enroll ? 3 : 0) +
+	    (auth_macs ? 2 + auth_macs_count * ETH_ALEN : 0))
+		return -1;
 	wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
 	len = wpabuf_put(msg, 2); /* to be filled */
 	wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
@@ -230,6 +238,8 @@
 
 #ifdef CONFIG_WPS_TESTING
 	if (WPS_VERSION > 0x20) {
+		if (wpabuf_tailroom(msg) < 5)
+			return -1;
 		wpa_printf(MSG_DEBUG, "WPS:  * Extensibility Testing - extra "
 			   "attribute");
 		wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST);
@@ -372,14 +382,20 @@
 	const u8 *addr[1];
 	u8 pubkey_hash[WPS_HASH_LEN];
 
+	wpa_printf(MSG_DEBUG, "WPS:  * OOB Device Password (dev_pw_id=%u)",
+		   dev_pw_id);
 	addr[0] = wpabuf_head(pubkey);
 	hash_len = wpabuf_len(pubkey);
 	sha256_vector(1, addr, &hash_len, pubkey_hash);
 
 	wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
 	wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len);
+	wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash",
+		    pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
 	wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
 	wpabuf_put_be16(msg, dev_pw_id);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: OOB Device Password",
+			dev_pw, dev_pw_len);
 	wpabuf_put_data(msg, dev_pw, dev_pw_len);
 
 	return 0;
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index d02ba30..7b86ff7 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -864,6 +864,12 @@
 	wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password "
 		   "ID from %u to %u", wps->dev_pw_id, id);
 
+	if (wps->dev_pw_id == DEV_PW_PUSHBUTTON && id == DEV_PW_DEFAULT) {
+		wpa_printf(MSG_DEBUG,
+			   "WPS: Workaround - ignore PBC-to-PIN change");
+		return 0;
+	}
+
 	if (wps->alt_dev_password && wps->alt_dev_pw_id == id) {
 		wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password");
 		os_free(wps->dev_password);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index b7fcd9c..ef17617 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -367,13 +367,8 @@
 	pbc = reg->pbc_sessions;
 	while (pbc) {
 		if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 ||
-#ifdef ANDROID_P2P
-		    (p2p_dev_addr && !is_zero_ether_addr(pbc->addr) &&
-		     os_memcmp(pbc->addr, p2p_dev_addr, ETH_ALEN) ==
-#else
 		    (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) &&
 		     os_memcmp(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
-#endif
 		     0)) {
 			if (prev)
 				prev->next = pbc->next;
@@ -1379,7 +1374,8 @@
 	}
 	if (pin == NULL) {
 		wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "
-			   "the Enrollee");
+			   "the Enrollee (context %p registrar %p)",
+			   wps->wps, wps->wps->registrar);
 		wps_cb_pin_needed(wps->wps->registrar, wps->uuid_e,
 				  &wps->peer_dev);
 		return -1;
@@ -2541,6 +2537,8 @@
 		const u8 *addr[1];
 		u8 hash[WPS_HASH_LEN];
 
+		wpa_printf(MSG_DEBUG, "WPS: Searching for NFC token match for id=%d (ctx %p registrar %p)",
+			   wps->dev_pw_id, wps->wps, wps->wps->registrar);
 		token = wps_get_nfc_pw_token(
 			&wps->wps->registrar->nfc_pw_tokens, wps->dev_pw_id);
 		if (token) {
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 8515b5a..373a344 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -51,9 +51,6 @@
 L_CFLAGS += -mabi=aapcs-linux
 endif
 
-# To allow non-ASCII characters in SSID
-L_CFLAGS += -DWPA_UNICODE_SSID
-
 INCLUDES = $(LOCAL_PATH)
 INCLUDES += $(LOCAL_PATH)/src
 INCLUDES += $(LOCAL_PATH)/src/common
@@ -71,7 +68,7 @@
 INCLUDES += $(LOCAL_PATH)/src/utils
 INCLUDES += $(LOCAL_PATH)/src/wps
 INCLUDES += external/openssl/include
-INCLUDES += system/security/keystore
+INCLUDES += system/security/keystore/include
 ifdef CONFIG_DRIVER_NL80211
 INCLUDES += external/libnl-headers
 endif
@@ -772,6 +769,9 @@
 OBJS += src/ap/eap_user_db.c
 ifdef CONFIG_IEEE80211N
 OBJS += src/ap/ieee802_11_ht.c
+ifdef CONFIG_IEEE80211AC
+OBJS += src/ap/ieee802_11_vht.c
+endif
 endif
 ifdef CONFIG_WNM
 OBJS += src/ap/wnm_ap.c
@@ -787,6 +787,9 @@
 
 ifdef CONFIG_IEEE80211N
 L_CFLAGS += -DCONFIG_IEEE80211N
+ifdef CONFIG_IEEE80211AC
+L_CFLAGS += -DCONFIG_IEEE80211AC
+endif
 endif
 
 ifdef NEED_AP_MLME
@@ -794,6 +797,7 @@
 OBJS += src/ap/ap_list.c
 OBJS += src/ap/ieee802_11.c
 OBJS += src/ap/hw_features.c
+OBJS += src/ap/dfs.c
 L_CFLAGS += -DNEED_AP_MLME
 endif
 ifdef CONFIG_WPS
@@ -1122,7 +1126,7 @@
 ifdef NEED_AES_OMAC1
 NEED_AES_ENC=y
 ifdef CONFIG_OPENSSL_CMAC
-CFLAGS += -DCONFIG_OPENSSL_CMAC
+L_CFLAGS += -DCONFIG_OPENSSL_CMAC
 else
 AESOBJS += src/crypto/aes-omac1.c
 endif
@@ -1171,7 +1175,10 @@
 endif
 endif
 
-MD5OBJS = src/crypto/md5.c
+MD5OBJS =
+ifndef CONFIG_FIPS
+MD5OBJS += src/crypto/md5.c
+endif
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
 MD5OBJS += src/crypto/md5-internal.c
@@ -1425,7 +1432,7 @@
 endif
 
 ifdef CONFIG_AUTOSCAN_PERIODIC
-CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
+L_CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
 OBJS += autoscan_periodic.c
 NEED_AUTOSCAN=y
 endif
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 5698619..f6a46d2 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -113,6 +113,13 @@
 OBJS += ../src/utils/$(CONFIG_ELOOP).o
 OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
 
+ifeq ($(CONFIG_ELOOP), eloop)
+# Using glibc < 2.17 requires -lrt for clock_gettime()
+LIBS += -lrt
+LIBS_c += -lrt
+LIBS_p += -lrt
+endif
+
 ifdef CONFIG_ELOOP_POLL
 CFLAGS += -DCONFIG_ELOOP_POLL
 endif
@@ -750,6 +757,9 @@
 OBJS += ../src/ap/eap_user_db.o
 ifdef CONFIG_IEEE80211N
 OBJS += ../src/ap/ieee802_11_ht.o
+ifdef CONFIG_IEEE80211AC
+OBJS += ../src/ap/ieee802_11_vht.o
+endif
 endif
 ifdef CONFIG_WNM
 OBJS += ../src/ap/wnm_ap.o
@@ -765,6 +775,9 @@
 
 ifdef CONFIG_IEEE80211N
 CFLAGS += -DCONFIG_IEEE80211N
+ifdef CONFIG_IEEE80211AC
+CFLAGS += -DCONFIG_IEEE80211AC
+endif
 endif
 
 ifdef NEED_AP_MLME
@@ -772,6 +785,7 @@
 OBJS += ../src/ap/ap_list.o
 OBJS += ../src/ap/ieee802_11.o
 OBJS += ../src/ap/hw_features.o
+OBJS += ../src/ap/dfs.o
 CFLAGS += -DNEED_AP_MLME
 endif
 ifdef CONFIG_WPS
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 78df89e..8e9cc45 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -949,3 +949,37 @@
 wpa_priv can control multiple interface with one process, but it is
 also possible to run multiple wpa_priv processes at the same time, if
 desired.
+
+
+Linux capabilities instead of privileged process
+------------------------------------------------
+
+wpa_supplicant performs operations that need special permissions, e.g.,
+to control the network connection. Traditionally this has been achieved
+by running wpa_supplicant as a privileged process with effective user id
+0 (root). Linux capabilities can be used to provide restricted set of
+capabilities to match the functions needed by wpa_supplicant. The
+minimum set of capabilities needed for the operations is CAP_NET_ADMIN
+and CAP_NET_RAW.
+
+setcap(8) can be used to set file capabilities. For example:
+
+sudo setcap cap_net_raw,cap_net_admin+ep wpa_supplicant
+
+Please note that this would give anyone being able to run that
+wpa_supplicant binary access to the additional capabilities. This can
+further be limited by file owner/group and mode bits. For example:
+
+sudo chown wpas wpa_supplicant
+sudo chmod 0100 wpa_supplicant
+
+This combination of setcap, chown, and chmod commands would allow wpas
+user to execute wpa_supplicant with additional network admin/raw
+capabilities.
+
+Common way style of creating a control interface socket in
+/var/run/wpa_supplicant could not be done by this user, but this
+directory could be created before starting the wpa_supplicant and set to
+suitable mode to allow wpa_supplicant to create sockets
+there. Alternatively, other directory or abstract socket namespace could
+be used for the control interface.
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index 5669c55..61e4a4d 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -166,9 +166,25 @@
 # milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
 #	format
 #
-# domain: Home service provider FQDN
+# domain_suffix_match: Constraint for server domain name
+#	If set, this FQDN is used as a suffix match requirement for the AAA
+#	server certificate in SubjectAltName dNSName element(s). If a
+#	matching dNSName is found, this constraint is met. If no dNSName
+#	values are present, this constraint is matched against SubjetName CN
+#	using same suffix match comparison. Suffix match here means that the
+#	host/domain name is compared one label at a time starting from the
+#	top-level domain and all the labels in @domain_suffix_match shall be
+#	included in the certificate. The certificate may include additional
+#	sub-level labels in addition to the required labels.
+#
+#	For example, domain_suffix_match=example.com would match
+#	test.example.com but would not match test-example.com.
+#
+# domain: Home service provider FQDN(s)
 #	This is used to compare against the Domain Name List to figure out
-#	whether the AP is operated by the Home SP.
+#	whether the AP is operated by the Home SP. Multiple domain entries can
+#	be used to configure alternative FQDNs that will be considered home
+#	networks.
 #
 # roaming_consortium: Roaming Consortium OI
 #	If roaming_consortium_len is non-zero, this field contains the
@@ -203,6 +219,7 @@
 #	password="password"
 #	ca_cert="/etc/wpa_supplicant/ca.pem"
 #	domain="example.com"
+#	domain_suffix_match="example.com"
 #}
 #
 #cred={
@@ -267,6 +284,17 @@
 Note: the return value of add_cred is used as the first argument to
 the following set_cred commands.
 
+Add a SIM credential using a external SIM/USIM processing:
+
+> set external_sim 1
+OK
+> add_cred
+1
+> set_cred 1 imsi "23456-0000000000"
+OK
+> set_cred 1 eap SIM
+OK
+
 
 Add a WPA2-Enterprise network:
 
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index 76f8219..ffc2baf 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -125,7 +125,7 @@
 
 p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad]
 	[persistent|persistent=<network id>] [join|auth]
-	[go_intent=<0..15>] [freq=<in MHz>] [ht40] [provdisc]
+	[go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc]
 
 Start P2P group formation with a discovered P2P peer. This includes
 optional group owner negotiation, group interface setup, provisioning,
@@ -166,7 +166,8 @@
 P2P implementations that require this to allow the user to accept the
 connection.
 
-p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>] [ht40]
+p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
+	[ht40] [vht]
 
 Set up a P2P group owner manually (i.e., without group owner
 negotiation with a specific peer). This is also known as autonomous
@@ -373,7 +374,8 @@
 Invitation
 
 p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
-	[go_dev_addr=address] [freq=<freq in MHz>] [ht40] [pref=<MHz>]
+	[go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht]
+	[pref=<MHz>]
 
 Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
 persistent group (e.g., persistent=4). If the peer device is the GO of
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 8b3d6b4..501137c 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -305,7 +305,6 @@
 # Select event loop implementation
 # eloop = select() loop (default)
 # eloop_win = Windows events and WaitForMultipleObject() loop
-# eloop_none = Empty template
 CONFIG_ELOOP=eloop
 
 # Should we use poll instead of select? Select is used by default.
@@ -490,10 +489,10 @@
 # This can be used to enable functionality to improve interworking with
 # external networks (GAS/ANQP to learn more about the networks and network
 # selection based on available credentials).
-#CONFIG_INTERWORKING=y
+CONFIG_INTERWORKING=y
 
 # Hotspot 2.0
-#CONFIG_HS20=y
+CONFIG_HS20=y
 
 # Disable roaming in wpa_supplicant
 CONFIG_NO_ROAMING=y
@@ -510,14 +509,17 @@
 # more information on P2P operations.
 CONFIG_P2P=y
 
+# Enable TDLS support
 CONFIG_TDLS=y
 
-#Enable Wifi Display
+# Wi-Fi Direct
+# This can be used to enable Wi-Fi Direct extensions for P2P using an external
+# program to control the additional information exchanges in the messages.
 CONFIG_WIFI_DISPLAY=y
 
 # Autoscan
 # This can be used to enable automatic scan support in wpa_supplicant.
-# See wpa_supplicant.conf for more information on autoscan usage.
+# See wpa_supplicant.conf for more information on autoscan usage.
 #
 # Enabling directly a module will enable autoscan support.
 # For exponential module:
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index fdbe248..cbe67a4 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -42,11 +42,38 @@
 #endif /* CONFIG_WPS */
 
 
+#ifdef CONFIG_IEEE80211N
+static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
+			     struct hostapd_config *conf,
+			     struct hostapd_hw_modes *mode)
+{
+	u8 center_chan = 0;
+	u8 channel = conf->channel;
+
+	if (!conf->secondary_channel)
+		goto no_vht;
+
+	center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+	if (!center_chan)
+		goto no_vht;
+
+	/* Use 80 MHz channel */
+	conf->vht_oper_chwidth = 1;
+	conf->vht_oper_centr_freq_seg0_idx = center_chan;
+	return;
+
+no_vht:
+	conf->vht_oper_centr_freq_seg0_idx =
+		channel + conf->secondary_channel * 2;
+}
+#endif /* CONFIG_IEEE80211N */
+
+
 static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid,
 				  struct hostapd_config *conf)
 {
-	struct hostapd_bss_config *bss = &conf->bss[0];
+	struct hostapd_bss_config *bss = conf->bss[0];
 
 	conf->driver = wpa_s->driver;
 
@@ -114,6 +141,11 @@
 				 HT_CAP_INFO_SHORT_GI40MHZ |
 				 HT_CAP_INFO_RX_STBC_MASK |
 				 HT_CAP_INFO_MAX_AMSDU_SIZE);
+
+			if (mode->vht_capab && ssid->vht) {
+				conf->ieee80211ac = 1;
+				wpas_conf_ap_vht(wpa_s, conf, mode);
+			}
 		}
 	}
 #endif /* CONFIG_IEEE80211N */
@@ -529,8 +561,8 @@
 		  sizeof(wpa_s->conf->wmm_ac_params));
 
 	if (params.uapsd > 0) {
-		conf->bss->wmm_enabled = 1;
-		conf->bss->wmm_uapsd = 1;
+		conf->bss[0]->wmm_enabled = 1;
+		conf->bss[0]->wmm_uapsd = 1;
 	}
 
 	if (wpa_supplicant_conf_ap(wpa_s, ssid, conf)) {
@@ -541,9 +573,9 @@
 
 #ifdef CONFIG_P2P
 	if (ssid->mode == WPAS_MODE_P2P_GO)
-		conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+		conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER;
 	else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
-		conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+		conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER |
 			P2P_GROUP_FORMATION;
 #endif /* CONFIG_P2P */
 
@@ -558,7 +590,7 @@
 	for (i = 0; i < conf->num_bss; i++) {
 		hapd_iface->bss[i] =
 			hostapd_alloc_bss_data(hapd_iface, conf,
-					       &conf->bss[i]);
+					       conf->bss[i]);
 		if (hapd_iface->bss[i] == NULL) {
 			wpa_supplicant_ap_deinit(wpa_s);
 			return -1;
@@ -1010,9 +1042,9 @@
 
 #ifdef CONFIG_P2P
 	if (ssid->mode == WPAS_MODE_P2P_GO)
-		iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+		iface->conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER;
 	else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
-		iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+		iface->conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER |
 			P2P_GROUP_FORMATION;
 #endif /* CONFIG_P2P */
 
@@ -1026,6 +1058,32 @@
 }
 
 
+int ap_switch_channel(struct wpa_supplicant *wpa_s,
+		      struct csa_settings *settings)
+{
+#ifdef NEED_AP_MLME
+	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+		return -1;
+
+	return hostapd_switch_channel(wpa_s->ap_iface->bss[0], settings);
+#else /* NEED_AP_MLME */
+	return -1;
+#endif /* NEED_AP_MLME */
+}
+
+
+int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos)
+{
+	struct csa_settings settings;
+	int ret = hostapd_parse_csa_settings(pos, &settings);
+
+	if (ret)
+		return ret;
+
+	return ap_switch_channel(wpa_s, &settings);
+}
+
+
 void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
 		       int offset)
 {
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 74a0b18..33a3d0f 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -50,6 +50,9 @@
 int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
 				      const u8 *addr);
 void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
+int ap_switch_channel(struct wpa_supplicant *wpa_s,
+		      struct csa_settings *settings);
+int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr);
 void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
 		       int offset);
 struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/bgscan.c b/wpa_supplicant/bgscan.c
index 9a9bd52..f74cdbf 100644
--- a/wpa_supplicant/bgscan.c
+++ b/wpa_supplicant/bgscan.c
@@ -31,9 +31,9 @@
 };
 
 
-int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+		const char *name)
 {
-	const char *name = ssid->bgscan;
 	const char *params;
 	size_t nlen;
 	int i;
@@ -41,7 +41,7 @@
 
 	bgscan_deinit(wpa_s);
 	if (name == NULL)
-		return 0;
+		return -1;
 
 	params = os_strchr(name, ':');
 	if (params == NULL) {
diff --git a/wpa_supplicant/bgscan.h b/wpa_supplicant/bgscan.h
index e9d15fc..9131e4e 100644
--- a/wpa_supplicant/bgscan.h
+++ b/wpa_supplicant/bgscan.h
@@ -29,7 +29,8 @@
 
 #ifdef CONFIG_BGSCAN
 
-int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+		const char *name);
 void bgscan_deinit(struct wpa_supplicant *wpa_s);
 int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
 		       struct wpa_scan_results *scan_res);
@@ -41,7 +42,7 @@
 #else /* CONFIG_BGSCAN */
 
 static inline int bgscan_init(struct wpa_supplicant *wpa_s,
-			      struct wpa_ssid *ssid)
+			      struct wpa_ssid *ssid, const char name)
 {
 	return 0;
 }
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 67a9f97..df1a0c8 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -502,6 +502,22 @@
 	wpa_bss_copy_res(bss, res, fetch_time);
 	/* Move the entry to the end of the list */
 	dl_list_del(&bss->list);
+#ifdef CONFIG_P2P
+	if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+	    !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) {
+		/*
+		 * This can happen when non-P2P station interface runs a scan
+		 * without P2P IE in the Probe Request frame. P2P GO would reply
+		 * to that with a Probe Response that does not include P2P IE.
+		 * Do not update the IEs in this BSS entry to avoid such loss of
+		 * information that may be needed for P2P operations to
+		 * determine group information.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
+			MACSTR " since that would remove P2P IE information",
+			MAC2STR(bss->bssid));
+	} else
+#endif /* CONFIG_P2P */
 	if (bss->ie_len + bss->beacon_ie_len >=
 	    res->ie_len + res->beacon_ie_len) {
 		os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
@@ -625,8 +641,18 @@
 	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
 	if (bss == NULL)
 		bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
-	else
+	else {
 		bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
+		if (wpa_s->last_scan_res) {
+			unsigned int i;
+			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+				if (bss == wpa_s->last_scan_res[i]) {
+					/* Already in the list */
+					return;
+				}
+			}
+		}
+	}
 
 	if (bss == NULL)
 		return;
@@ -1002,6 +1028,43 @@
 
 
 /**
+ * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ *
+ * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
+					u32 vendor_type)
+{
+	const u8 *end, *pos;
+
+	if (bss->beacon_ie_len == 0)
+		return NULL;
+
+	pos = (const u8 *) (bss + 1);
+	pos += bss->ie_len;
+	end = pos + bss->beacon_ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+
+/**
  * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
  * @bss: BSS table entry
  * @vendor_type: Vendor type (four octets starting the IE payload)
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 2b41948..0d2693f 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -118,6 +118,8 @@
 				      unsigned int idf, unsigned int idl);
 const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
 const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
+const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
+					u32 vendor_type);
 struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
 					    u32 vendor_type);
 struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 69f920d..9ceaaf8 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -546,10 +546,10 @@
 	char *buf, *pos, *end;
 	int ret;
 
-	pos = buf = os_zalloc(50);
+	pos = buf = os_zalloc(100);
 	if (buf == NULL)
 		return NULL;
-	end = buf + 50;
+	end = buf + 100;
 
 	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
 		ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
@@ -602,29 +602,59 @@
 	}
 
 #ifdef CONFIG_IEEE80211R
-	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK)
-		pos += os_snprintf(pos, end - pos, "%sFT-PSK",
-				   pos == buf ? "" : " ");
+	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+		ret = os_snprintf(pos, end - pos, "%sFT-PSK",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
 
-	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
-		pos += os_snprintf(pos, end - pos, "%sFT-EAP",
-				   pos == buf ? "" : " ");
+	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+		ret = os_snprintf(pos, end - pos, "%sFT-EAP",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
 #endif /* CONFIG_IEEE80211R */
 
 #ifdef CONFIG_IEEE80211W
-	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
-		pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
-				   pos == buf ? "" : " ");
+	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+		ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
 
-	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
-		pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
-				   pos == buf ? "" : " ");
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
 #endif /* CONFIG_IEEE80211W */
 
 #ifdef CONFIG_WPS
-	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
-		pos += os_snprintf(pos, end - pos, "%sWPS",
-				   pos == buf ? "" : " ");
+	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+		ret = os_snprintf(pos, end - pos, "%sWPS",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
 #endif /* CONFIG_WPS */
 
 	return buf;
@@ -873,6 +903,10 @@
 	freqs = wpa_config_parse_int_array(value);
 	if (freqs == NULL)
 		return -1;
+	if (freqs[0] == 0) {
+		os_free(freqs);
+		freqs = NULL;
+	}
 	os_free(ssid->scan_freq);
 	ssid->scan_freq = freqs;
 
@@ -889,6 +923,10 @@
 	freqs = wpa_config_parse_int_array(value);
 	if (freqs == NULL)
 		return -1;
+	if (freqs[0] == 0) {
+		os_free(freqs);
+		freqs = NULL;
+	}
 	os_free(ssid->freq_list);
 	ssid->freq_list = freqs;
 
@@ -1283,6 +1321,52 @@
 
 #ifdef CONFIG_P2P
 
+static int wpa_config_parse_go_p2p_dev_addr(const struct parse_data *data,
+					    struct wpa_ssid *ssid, int line,
+					    const char *value)
+{
+	if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
+	    os_strcmp(value, "any") == 0) {
+		os_memset(ssid->go_p2p_dev_addr, 0, ETH_ALEN);
+		wpa_printf(MSG_MSGDUMP, "GO P2P Device Address any");
+		return 0;
+	}
+	if (hwaddr_aton(value, ssid->go_p2p_dev_addr)) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid GO P2P Device Address '%s'.",
+			   line, value);
+		return -1;
+	}
+	ssid->bssid_set = 1;
+	wpa_printf(MSG_MSGDUMP, "GO P2P Device Address " MACSTR,
+		   MAC2STR(ssid->go_p2p_dev_addr));
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_go_p2p_dev_addr(const struct parse_data *data,
+					       struct wpa_ssid *ssid)
+{
+	char *value;
+	int res;
+
+	if (is_zero_ether_addr(ssid->go_p2p_dev_addr))
+		return NULL;
+
+	value = os_malloc(20);
+	if (value == NULL)
+		return NULL;
+	res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->go_p2p_dev_addr));
+	if (res < 0 || res >= 20) {
+		os_free(value);
+		return NULL;
+	}
+	value[20 - 1] = '\0';
+	return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
 static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
 					    struct wpa_ssid *ssid, int line,
 					    const char *value)
@@ -1541,6 +1625,7 @@
 	{ STRe(dh_file) },
 	{ STRe(subject_match) },
 	{ STRe(altsubject_match) },
+	{ STRe(domain_suffix_match) },
 	{ STRe(ca_cert2) },
 	{ STRe(ca_path2) },
 	{ STRe(client_cert2) },
@@ -1549,6 +1634,7 @@
 	{ STRe(dh_file2) },
 	{ STRe(subject_match2) },
 	{ STRe(altsubject_match2) },
+	{ STRe(domain_suffix_match2) },
 	{ STRe(phase1) },
 	{ STRe(phase2) },
 	{ STRe(pcsc) },
@@ -1592,6 +1678,7 @@
 	{ STR(bgscan) },
 	{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
 #ifdef CONFIG_P2P
+	{ FUNC(go_p2p_dev_addr) },
 	{ FUNC(p2p_client_list) },
 	{ FUNC(psk_list) },
 #endif /* CONFIG_P2P */
@@ -1646,7 +1733,7 @@
 #undef _FUNC
 #undef FUNC
 #undef FUNC_KEY
-#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
+#define NUM_SSID_FIELDS ARRAY_SIZE(ssid_fields)
 
 
 /**
@@ -1748,6 +1835,7 @@
 	os_free(eap->dh_file);
 	os_free(eap->subject_match);
 	os_free(eap->altsubject_match);
+	os_free(eap->domain_suffix_match);
 	os_free(eap->ca_cert2);
 	os_free(eap->ca_path2);
 	os_free(eap->client_cert2);
@@ -1756,6 +1844,7 @@
 	os_free(eap->dh_file2);
 	os_free(eap->subject_match2);
 	os_free(eap->altsubject_match2);
+	os_free(eap->domain_suffix_match2);
 	os_free(eap->phase1);
 	os_free(eap->phase2);
 	os_free(eap->pcsc);
@@ -1773,6 +1862,7 @@
 	os_free(eap->pending_req_otp);
 	os_free(eap->pac_file);
 	os_free(eap->new_password);
+	os_free(eap->external_sim_resp);
 }
 #endif /* IEEE8021X_EAPOL */
 
@@ -1813,6 +1903,8 @@
 
 void wpa_config_free_cred(struct wpa_cred *cred)
 {
+	size_t i;
+
 	os_free(cred->realm);
 	os_free(cred->username);
 	os_free(cred->password);
@@ -1822,7 +1914,10 @@
 	os_free(cred->private_key_passwd);
 	os_free(cred->imsi);
 	os_free(cred->milenage);
+	for (i = 0; i < cred->num_domain; i++)
+		os_free(cred->domain[i]);
 	os_free(cred->domain);
+	os_free(cred->domain_suffix_match);
 	os_free(cred->eap_method);
 	os_free(cred->phase1);
 	os_free(cred->phase2);
@@ -1888,6 +1983,7 @@
 	os_free(config->p2p_ssid_postfix);
 	os_free(config->pssid);
 	os_free(config->p2p_pref_chan);
+	os_free(config->p2p_no_go_freq.range);
 	os_free(config->autoscan);
 	os_free(config->freq_list);
 	wpabuf_free(config->wps_nfc_dh_pubkey);
@@ -2394,9 +2490,23 @@
 		return 0;
 	}
 
+	if (os_strcmp(var, "domain_suffix_match") == 0) {
+		os_free(cred->domain_suffix_match);
+		cred->domain_suffix_match = val;
+		return 0;
+	}
+
 	if (os_strcmp(var, "domain") == 0) {
-		os_free(cred->domain);
-		cred->domain = val;
+		char **new_domain;
+		new_domain = os_realloc_array(cred->domain,
+					      cred->num_domain + 1,
+					      sizeof(char *));
+		if (new_domain == NULL) {
+			os_free(val);
+			return -1;
+		}
+		new_domain[cred->num_domain++] = val;
+		cred->domain = new_domain;
 		return 0;
 	}
 
@@ -2426,6 +2536,21 @@
 		return 0;
 	}
 
+	if (os_strcmp(var, "required_roaming_consortium") == 0) {
+		if (len < 3 || len > sizeof(cred->required_roaming_consortium))
+		{
+			wpa_printf(MSG_ERROR, "Line %d: invalid "
+				   "required_roaming_consortium length %d "
+				   "(3..15 expected)", line, (int) len);
+			os_free(val);
+			return -1;
+		}
+		os_memcpy(cred->required_roaming_consortium, val, len);
+		cred->required_roaming_consortium_len = len;
+		os_free(val);
+		return 0;
+	}
+
 	if (os_strcmp(var, "excluded_ssid") == 0) {
 		struct excluded_ssid *e;
 
@@ -2770,6 +2895,24 @@
 }
 
 
+static int wpa_config_process_bgscan(const struct global_parse_data *data,
+				     struct wpa_config *config, int line,
+				     const char *pos)
+{
+	size_t len;
+	char *tmp;
+
+	tmp = wpa_config_parse_string(pos, &len);
+	if (tmp == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: failed to parse %s",
+			   line, data->name);
+		return -1;
+	}
+
+	return wpa_global_config_parse_str(data, config, line, tmp);
+}
+
+
 static int wpa_global_config_parse_bin(const struct global_parse_data *data,
 				       struct wpa_config *config, int line,
 				       const char *pos)
@@ -2808,6 +2951,10 @@
 	freqs = wpa_config_parse_int_array(value);
 	if (freqs == NULL)
 		return -1;
+	if (freqs[0] == 0) {
+		os_free(freqs);
+		freqs = NULL;
+	}
 	os_free(config->freq_list);
 	config->freq_list = freqs;
 	return 0;
@@ -2998,6 +3145,26 @@
 	wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
 	return -1;
 }
+
+
+static int wpa_config_process_p2p_no_go_freq(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	int ret;
+
+	ret = freq_range_list_parse(&config->p2p_no_go_freq, pos);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_no_go_freq", line);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: p2p_no_go_freq with %u items",
+		   config->p2p_no_go_freq.num);
+
+	return 0;
+}
+
 #endif /* CONFIG_P2P */
 
 
@@ -3070,6 +3237,19 @@
 }
 
 
+#ifdef CONFIG_CTRL_IFACE
+static int wpa_config_process_no_ctrl_interface(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	wpa_printf(MSG_DEBUG, "no_ctrl_interface -> ctrl_interface=NULL");
+	os_free(config->ctrl_interface);
+	config->ctrl_interface = NULL;
+	return 0;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
 #ifdef OFFSET
 #undef OFFSET
 #endif /* OFFSET */
@@ -3089,10 +3269,12 @@
 static const struct global_parse_data global_fields[] = {
 #ifdef CONFIG_CTRL_IFACE
 	{ STR(ctrl_interface), 0 },
+	{ FUNC_NO_VAR(no_ctrl_interface), 0 },
 	{ STR(ctrl_interface_group), 0 } /* deprecated */,
 #endif /* CONFIG_CTRL_IFACE */
 	{ INT_RANGE(eapol_version, 1, 2), 0 },
 	{ INT(ap_scan), 0 },
+	{ FUNC(bgscan), 0 },
 	{ INT(disable_scan_offload), 0 },
 	{ INT(fast_reauth), 0 },
 	{ STR(opensc_engine_path), 0 },
@@ -3100,6 +3282,7 @@
 	{ STR(pkcs11_module_path), 0 },
 	{ STR(pcsc_reader), 0 },
 	{ STR(pcsc_pin), 0 },
+	{ INT(external_sim), 0 },
 	{ STR(driver_param), 0 },
 	{ INT(dot11RSNAConfigPMKLifetime), 0 },
 	{ INT(dot11RSNAConfigPMKReauthThreshold), 0 },
@@ -3125,15 +3308,18 @@
 	{ FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
 	{ INT(p2p_listen_reg_class), 0 },
 	{ INT(p2p_listen_channel), 0 },
-	{ INT(p2p_oper_reg_class), 0 },
-	{ INT(p2p_oper_channel), 0 },
+	{ INT(p2p_oper_reg_class), CFG_CHANGED_P2P_OPER_CHANNEL },
+	{ INT(p2p_oper_channel), CFG_CHANGED_P2P_OPER_CHANNEL },
 	{ INT_RANGE(p2p_go_intent, 0, 15), 0 },
 	{ STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
 	{ INT_RANGE(persistent_reconnect, 0, 1), 0 },
 	{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
 	{ INT(p2p_group_idle), 0 },
 	{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+	{ FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN },
+	{ INT_RANGE(p2p_add_cli_chan, 0, 1), 0 },
 	{ INT(p2p_go_ht40), 0 },
+	{ INT(p2p_go_vht), 0 },
 	{ INT(p2p_disabled), 0 },
 	{ INT(p2p_no_group_iface), 0 },
 	{ INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 },
@@ -3183,7 +3369,7 @@
 #undef STR
 #undef STR_RANGE
 #undef BIN
-#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
+#define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields)
 
 
 int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 3fe46e3..068679e 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -150,12 +150,37 @@
 	char *milenage;
 
 	/**
-	 * domain - Home service provider FQDN
+	 * domain_suffix_match - Constraint for server domain name
+	 *
+	 * If set, this FQDN is used as a suffix match requirement for the AAA
+	 * server certificate in SubjectAltName dNSName element(s). If a
+	 * matching dNSName is found, this constraint is met. If no dNSName
+	 * values are present, this constraint is matched against SubjetName CN
+	 * using same suffix match comparison. Suffix match here means that the
+	 * host/domain name is compared one label at a time starting from the
+	 * top-level domain and all the labels in @domain_suffix_match shall be
+	 * included in the certificate. The certificate may include additional
+	 * sub-level labels in addition to the required labels.
+	 *
+	 * For example, domain_suffix_match=example.com would match
+	 * test.example.com but would not match test-example.com.
+	 */
+	char *domain_suffix_match;
+
+	/**
+	 * domain - Home service provider FQDN(s)
 	 *
 	 * This is used to compare against the Domain Name List to figure out
-	 * whether the AP is operated by the Home SP.
+	 * whether the AP is operated by the Home SP. Multiple domain entries
+	 * can be used to configure alternative FQDNs that will be considered
+	 * home networks.
 	 */
-	char *domain;
+	char **domain;
+
+	/**
+	 * num_domain - Number of FQDNs in the domain array
+	 */
+	size_t num_domain;
 
 	/**
 	 * roaming_consortium - Roaming Consortium OI
@@ -175,6 +200,9 @@
 	 */
 	size_t roaming_consortium_len;
 
+	u8 required_roaming_consortium[15];
+	size_t required_roaming_consortium_len;
+
 	/**
 	 * eap_method - EAP method to use
 	 *
@@ -301,6 +329,18 @@
 	int ap_scan;
 
 	/**
+	 * bgscan - Background scan and roaming parameters or %NULL if none
+	 *
+	 * This is an optional set of parameters for background scanning and
+	 * roaming within a network (ESS). For more detailed information see
+	 * ssid block documentation.
+	 *
+	 * The variable defines default bgscan behavior for all BSS station
+	 * networks except for those which have their own bgscan configuration.
+	 */
+	 char *bgscan;
+
+	/**
 	 * disable_scan_offload - Disable automatic offloading of scan requests
 	 *
 	 * By default, %wpa_supplicant tries to offload scanning if the driver
@@ -425,6 +465,11 @@
 	char *pcsc_pin;
 
 	/**
+	 * external_sim - Use external processing for SIM/USIM operations
+	 */
+	int external_sim;
+
+	/**
 	 * driver_param - Driver interface parameters
 	 *
 	 * This text string is passed to the selected driver interface with the
@@ -572,6 +617,8 @@
 	int p2p_intra_bss;
 	unsigned int num_p2p_pref_chan;
 	struct p2p_channel *p2p_pref_chan;
+	struct wpa_freq_range_list p2p_no_go_freq;
+	int p2p_add_cli_chan;
 	int p2p_ignore_shared_freq;
 
 	struct wpabuf *wps_vendor_ext_m1;
@@ -793,6 +840,16 @@
 	int p2p_go_ht40;
 
 	/**
+	 * p2p_go_vht - Default mode for VHT enable when operating as GO
+	 *
+	 * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+	 * Note that regulatory constraints and driver capabilities are
+	 * consulted anyway, so setting it to 1 can't do real harm.
+	 * By default: 0 (disabled)
+	 */
+	int p2p_go_vht;
+
+	/**
 	 * p2p_disabled - Whether P2P operations are disabled for this interface
 	 */
 	int p2p_disabled;
@@ -884,7 +941,6 @@
 	 * to specify the TDLS link to get established to the driver. The
 	 * driver requests the TDLS setup to the supplicant only for the
 	 * specified TDLS peers.
-	 *
 	 */
 	int tdls_external_control;
 };
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index bb0e536..7d32867 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -606,6 +606,15 @@
 
 #ifdef CONFIG_P2P
 
+static void write_go_p2p_dev_addr(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value = wpa_config_get(ssid, "go_p2p_dev_addr");
+	if (value == NULL)
+		return;
+	fprintf(f, "\tgo_p2p_dev_addr=%s\n", value);
+	os_free(value);
+}
+
 static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid)
 {
 	char *value = wpa_config_get(ssid, "p2p_client_list");
@@ -653,6 +662,7 @@
 	write_auth_alg(f, ssid);
 	STR(bgscan);
 	STR(autoscan);
+	STR(scan_freq);
 #ifdef IEEE8021X_EAPOL
 	write_eap(f, ssid);
 	STR(identity);
@@ -666,6 +676,7 @@
 	STR(dh_file);
 	STR(subject_match);
 	STR(altsubject_match);
+	STR(domain_suffix_match);
 	STR(ca_cert2);
 	STR(ca_path2);
 	STR(client_cert2);
@@ -674,6 +685,7 @@
 	STR(dh_file2);
 	STR(subject_match2);
 	STR(altsubject_match2);
+	STR(domain_suffix_match2);
 	STR(phase1);
 	STR(phase2);
 	STR(pcsc);
@@ -711,6 +723,7 @@
 #endif /* CONFIG_IEEE80211W */
 	STR(id_str);
 #ifdef CONFIG_P2P
+	write_go_p2p_dev_addr(f, ssid);
 	write_p2p_client_list(f, ssid);
 	write_psk_list(f, ssid);
 #endif /* CONFIG_P2P */
@@ -725,6 +738,8 @@
 
 static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
 {
+	size_t i;
+
 	if (cred->priority)
 		fprintf(f, "\tpriority=%d\n", cred->priority);
 	if (cred->pcsc)
@@ -750,10 +765,12 @@
 		fprintf(f, "\timsi=\"%s\"\n", cred->imsi);
 	if (cred->milenage)
 		fprintf(f, "\tmilenage=\"%s\"\n", cred->milenage);
-	if (cred->domain)
-		fprintf(f, "\tdomain=\"%s\"\n", cred->domain);
+	for (i = 0; i < cred->num_domain; i++)
+		fprintf(f, "\tdomain=\"%s\"\n", cred->domain[i]);
+	if (cred->domain_suffix_match)
+		fprintf(f, "\tdomain_suffix_match=\"%s\"",
+			cred->domain_suffix_match);
 	if (cred->roaming_consortium_len) {
-		size_t i;
 		fprintf(f, "\troaming_consortium=");
 		for (i = 0; i < cred->roaming_consortium_len; i++)
 			fprintf(f, "%02x", cred->roaming_consortium[i]);
@@ -770,7 +787,7 @@
 	if (cred->phase2)
 		fprintf(f, "\tphase2=\"%s\"\n", cred->phase2);
 	if (cred->excluded_ssid) {
-		size_t i, j;
+		size_t j;
 		for (i = 0; i < cred->num_excluded_ssid; i++) {
 			struct excluded_ssid *e = &cred->excluded_ssid[i];
 			fprintf(f, "\texcluded_ssid=");
@@ -934,8 +951,19 @@
 		}
 		fprintf(f, "\n");
 	}
+	if (config->p2p_no_go_freq.num) {
+		char *val = freq_range_list_str(&config->p2p_no_go_freq);
+		if (val) {
+			fprintf(f, "p2p_no_go_freq=%s\n", val);
+			os_free(val);
+		}
+	}
+	if (config->p2p_add_cli_chan)
+		fprintf(f, "p2p_add_cli_chan=%d\n", config->p2p_add_cli_chan);
 	if (config->p2p_go_ht40)
 		fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
+	if (config->p2p_go_vht)
+		fprintf(f, "p2p_go_vht=%u\n", config->p2p_go_vht);
 	if (config->p2p_disabled)
 		fprintf(f, "p2p_disabled=%u\n", config->p2p_disabled);
 	if (config->p2p_no_group_iface)
@@ -1049,8 +1077,11 @@
 		fprintf(f, "sched_scan_interval=%u\n",
 			config->sched_scan_interval);
 
+	if (config->external_sim)
+		fprintf(f, "external_sim=%d\n", config->external_sim);
+
 	if (config->tdls_external_control)
-		fprintf(f, "tdls_external_control=%u\n",
+		fprintf(f, "tdls_external_control=%d\n",
 			config->tdls_external_control);
 }
 
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index c6ea963..0102da9 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -131,6 +131,11 @@
 	int bssid_set;
 
 	/**
+	 * go_p2p_dev_addr - GO's P2P Device Address or all zeros if not set
+	 */
+	u8 go_p2p_dev_addr[ETH_ALEN];
+
+	/**
 	 * psk - WPA pre-shared key (256 bits)
 	 */
 	u8 psk[32];
@@ -394,6 +399,8 @@
 
 	int ht40;
 
+	int vht;
+
 	/**
 	 * wpa_ptk_rekey - Maximum lifetime for PTK in seconds
 	 *
@@ -491,13 +498,6 @@
 	 */
 	int export_keys;
 
-#ifdef ANDROID_P2P
-	/**
-	 * assoc_retry - Number of times association should be retried.
-	 */
-	int assoc_retry;
-#endif
-
 #ifdef CONFIG_HT_OVERRIDES
 	/**
 	 * disable_ht - Disable HT (IEEE 802.11n) for this network
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 1b5e237..00a1004 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -623,6 +623,9 @@
 	wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0);
 	wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0);
 
+	wpa_config_write_reg_dword(hk, TEXT("external_sim"),
+				   config->external_sim, 0);
+
 	return 0;
 }
 
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 6335605..4e344b8 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -50,7 +50,7 @@
 
 static int pno_start(struct wpa_supplicant *wpa_s)
 {
-	int ret;
+	int ret, interval;
 	size_t i, num_ssid;
 	struct wpa_ssid *ssid;
 	struct wpa_driver_scan_params params;
@@ -114,7 +114,10 @@
 	if (wpa_s->conf->filter_rssi)
 		params.filter_rssi = wpa_s->conf->filter_rssi;
 
-	ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
+	interval = wpa_s->conf->sched_scan_interval ?
+		wpa_s->conf->sched_scan_interval : 10;
+
+	ret = wpa_supplicant_start_sched_scan(wpa_s, &params, interval);
 	os_free(params.filter_ssids);
 	if (ret == 0)
 		wpa_s->pno = 1;
@@ -128,7 +131,7 @@
 
 	if (wpa_s->pno) {
 		wpa_s->pno = 0;
-		ret = wpa_drv_stop_sched_scan(wpa_s);
+		ret = wpa_supplicant_stop_sched_scan(wpa_s);
 	}
 
 	if (wpa_s->wpa_state == WPA_SCANNING)
@@ -184,7 +187,7 @@
 	struct wpa_ssid *c;
 
 	/*
-	 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | “”
+	 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | ""
 	 * SSID_SPEC ::= ssid <SSID_HEX>
 	 * BSSID_SPEC ::= bssid <BSSID_HEX>
 	 */
@@ -569,9 +572,8 @@
 		   MAC2STR(peer));
 
 	if ((wpa_s->conf->tdls_external_control) &&
-	     wpa_tdls_is_external_setup(wpa_s->wpa)) {
+	    wpa_tdls_is_external_setup(wpa_s->wpa))
 		return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
-	}
 
 	wpa_tdls_remove(wpa_s->wpa, peer);
 
@@ -600,9 +602,8 @@
 		   MAC2STR(peer));
 
 	if ((wpa_s->conf->tdls_external_control) &&
-	     wpa_tdls_is_external_setup(wpa_s->wpa)) {
+	    wpa_tdls_is_external_setup(wpa_s->wpa))
 		return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
-	}
 
 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
 		ret = wpa_tdls_teardown_link(
@@ -656,7 +657,7 @@
 	u8 *_p2p_dev_addr = NULL;
 #endif /* CONFIG_AP */
 
-	if (cmd == NULL || os_strcmp(cmd, "any") == 0 || cmd[0] == '\0') {
+	if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
 		_bssid = NULL;
 #ifdef CONFIG_P2P
 	} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
@@ -1427,6 +1428,8 @@
 	char *pos, *end, tmp[30];
 	int res, verbose, wps, ret;
 
+	if (os_strcmp(params, "-DRIVER") == 0)
+		return wpa_drv_status(wpa_s, buf, buflen);
 	verbose = os_strcmp(params, "-VERBOSE") == 0;
 	wps = os_strcmp(params, "-WPS") == 0;
 	pos = buf;
@@ -1576,16 +1579,19 @@
 		char *type;
 
 		for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+			size_t i;
+
 			if (wpa_s->current_ssid->parent_cred != cred)
 				continue;
-			if (!cred->domain)
-				continue;
 
-			ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
-					  cred->domain);
-			if (ret < 0 || ret >= end - pos)
-				return pos - buf;
-			pos += ret;
+			for (i = 0; cred->domain && i < cred->num_domain; i++) {
+				ret = os_snprintf(pos, end - pos,
+						  "home_sp=%s\n",
+						  cred->domain[i]);
+				if (ret < 0 || ret >= end - pos)
+					return pos - buf;
+				pos += ret;
+			}
 
 			if (wpa_s->current_bss == NULL ||
 			    wpa_s->current_bss->anqp == NULL)
@@ -1631,14 +1637,15 @@
 		     MAC2STR(wpa_s->bssid),
 		     wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
 		     wpa_ssid_txt(wpa_s->current_ssid->ssid,
-		     wpa_s->current_ssid->ssid_len) : "");
+				  wpa_s->current_ssid->ssid_len) : "");
 	if (wpa_s->wpa_state == WPA_COMPLETED) {
 		struct wpa_ssid *ssid = wpa_s->current_ssid;
-		wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- connection to "
-			MACSTR " completed %s [id=%d id_str=%s]",
-			MAC2STR(wpa_s->bssid), "(auth)",
-			ssid ? ssid->id : -1,
-			ssid && ssid->id_str ? ssid->id_str : "");
+		wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED
+			     "- connection to " MACSTR
+			     " completed %s [id=%d id_str=%s]",
+			     MAC2STR(wpa_s->bssid), "(auth)",
+			     ssid ? ssid->id : -1,
+			     ssid && ssid->id_str ? ssid->id_str : "");
 	}
 #endif /* ANDROID */
 
@@ -2046,6 +2053,8 @@
 	const u8 *ie, *ie2, *p2p;
 
 	p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+	if (!p2p)
+		p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
 	if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
 	    os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
 	    0)
@@ -2476,7 +2485,7 @@
 		ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
 				  cred->id, cred->realm ? cred->realm : "",
 				  cred->username ? cred->username : "",
-				  cred->domain ? cred->domain : "",
+				  cred->domain ? cred->domain[0] : "",
 				  cred->imsi ? cred->imsi : "");
 		if (ret < 0 || ret >= end - pos)
 			return pos - buf;
@@ -2561,9 +2570,16 @@
 		while (cred) {
 			prev = cred;
 			cred = cred->next;
-			if (prev->domain &&
-			    os_strcmp(prev->domain, cmd + 8) == 0)
-				wpas_ctrl_remove_cred(wpa_s, prev);
+			if (prev->domain) {
+				size_t i;
+				for (i = 0; i < prev->num_domain; i++) {
+					if (os_strcmp(prev->domain[i], cmd + 8)
+					    != 0)
+						continue;
+					wpas_ctrl_remove_cred(wpa_s, prev);
+					break;
+				}
+			}
 		}
 		return 0;
 	}
@@ -3295,7 +3311,8 @@
 				return 0;
 			pos += ret;
 		}
-		if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
+		if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
+		    wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
 			ret = os_snprintf(pos, end - pos, "[P2P]");
 			if (ret < 0 || ret >= end - pos)
 				return 0;
@@ -3703,12 +3720,12 @@
 	int go_intent = -1;
 	int freq = 0;
 	int pd;
-	int ht40;
+	int ht40, vht;
 
 	/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
 	 * [persistent|persistent=<network id>]
 	 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
-	 * [ht40] */
+	 * [ht40] [vht] */
 
 	if (hwaddr_aton(cmd, addr))
 		return -1;
@@ -3736,7 +3753,9 @@
 	auth = os_strstr(pos, " auth") != NULL;
 	automatic = os_strstr(pos, " auto") != NULL;
 	pd = os_strstr(pos, " provdisc") != NULL;
-	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+	vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
+	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
+		vht;
 
 	pos2 = os_strstr(pos, " go_intent=");
 	if (pos2) {
@@ -3777,7 +3796,7 @@
 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
 				   persistent_group, automatic, join,
 				   auth, go_intent, freq, persistent_id, pd,
-				   ht40);
+				   ht40, vht);
 	if (new_pin == -2) {
 		os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
 		return 25;
@@ -4141,7 +4160,7 @@
 	struct wpa_ssid *ssid;
 	u8 *_peer = NULL, peer[ETH_ALEN];
 	int freq = 0, pref_freq = 0;
-	int ht40;
+	int ht40, vht;
 
 	id = atoi(cmd);
 	pos = os_strstr(cmd, " peer=");
@@ -4175,9 +4194,12 @@
 			return -1;
 	}
 
-	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+	vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
+	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
+		vht;
 
-	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, pref_freq);
+	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
+			       pref_freq);
 }
 
 
@@ -4224,7 +4246,8 @@
 
 
 static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
-					 char *cmd, int freq, int ht40)
+					 char *cmd, int freq, int ht40,
+					 int vht)
 {
 	int id;
 	struct wpa_ssid *ssid;
@@ -4238,31 +4261,34 @@
 		return -1;
 	}
 
-	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL);
+	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, vht,
+					     NULL, 0);
 }
 
 
 static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
 {
-	int freq = 0, ht40;
+	int freq = 0, ht40, vht;
 	char *pos;
 
 	pos = os_strstr(cmd, "freq=");
 	if (pos)
 		freq = atoi(pos + 5);
 
-	ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+	vht = (os_strstr(cmd, "vht") != NULL) || wpa_s->conf->p2p_go_vht;
+	ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
+		vht;
 
 	if (os_strncmp(cmd, "persistent=", 11) == 0)
 		return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
-						     ht40);
+						     ht40, vht);
 	if (os_strcmp(cmd, "persistent") == 0 ||
 	    os_strncmp(cmd, "persistent ", 11) == 0)
-		return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
+		return wpas_p2p_group_add(wpa_s, 1, freq, ht40, vht);
 	if (os_strncmp(cmd, "freq=", 5) == 0)
-		return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+		return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
 	if (ht40)
-		return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+		return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
 
 	wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
 		   cmd);
@@ -4365,48 +4391,21 @@
 static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
 				  const char *param)
 {
-	struct wpa_freq_range *freq = NULL, *n;
-	unsigned int count = 0, i;
-	const char *pos, *pos2, *pos3;
+	unsigned int i;
 
 	if (wpa_s->global->p2p == NULL)
 		return -1;
 
-	/*
-	 * param includes comma separated frequency range.
-	 * For example: 2412-2432,2462,5000-6000
-	 */
-	pos = param;
-	while (pos && pos[0]) {
-		n = os_realloc_array(freq, count + 1,
-				     sizeof(struct wpa_freq_range));
-		if (n == NULL) {
-			os_free(freq);
-			return -1;
-		}
-		freq = n;
-		freq[count].min = atoi(pos);
-		pos2 = os_strchr(pos, '-');
-		pos3 = os_strchr(pos, ',');
-		if (pos2 && (!pos3 || pos2 < pos3)) {
-			pos2++;
-			freq[count].max = atoi(pos2);
-		} else
-			freq[count].max = freq[count].min;
-		pos = pos3;
-		if (pos)
-			pos++;
-		count++;
-	}
+	if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0)
+		return -1;
 
-	for (i = 0; i < count; i++) {
+	for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) {
+		struct wpa_freq_range *freq;
+		freq = &wpa_s->global->p2p_disallow_freq.range[i];
 		wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
-			   freq[i].min, freq[i].max);
+			   freq->min, freq->max);
 	}
 
-	os_free(wpa_s->global->p2p_disallow_freq);
-	wpa_s->global->p2p_disallow_freq = freq;
-	wpa_s->global->num_p2p_disallow_freq = count;
 	wpas_p2p_update_channel_list(wpa_s);
 	return 0;
 }
@@ -5177,11 +5176,11 @@
 				p2p_set_country(p2p, country);
 			}
 		}
-		ret = sprintf(buf, "%s\n", "OK");
+		ret = os_snprintf(buf, buflen, "%s\n", "OK");
 	}
 	return ret;
 }
-#endif
+#endif /* ANDROID */
 
 
 static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
@@ -5201,6 +5200,8 @@
 #ifdef CONFIG_WPS
 	wpas_wps_cancel(wpa_s);
 #endif /* CONFIG_WPS */
+	wpa_s->after_wps = 0;
+	wpa_s->known_wps_freq = 0;
 
 #ifdef CONFIG_TDLS_TESTING
 	extern unsigned int tdls_testing;
@@ -5236,12 +5237,18 @@
 }
 
 
+static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	eapol_sm_notify_ctrl_response(wpa_s->eapol);
+}
+
+
 char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 					 char *buf, size_t *resp_len)
 {
 	char *reply;
 	const int reply_size = 4096;
-	int ctrl_rsp = 0;
 	int reply_len;
 
 	if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
@@ -5468,7 +5475,7 @@
 		if (wpas_p2p_group_remove(wpa_s, buf + 17))
 			reply_len = -1;
 	} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
-		if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
+		if (wpas_p2p_group_add(wpa_s, 0, 0, 0, 0))
 			reply_len = -1;
 	} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
 		if (p2p_ctrl_group_add(wpa_s, buf + 14))
@@ -5580,8 +5587,14 @@
 		if (wpa_supplicant_ctrl_iface_ctrl_rsp(
 			    wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
 			reply_len = -1;
-		else
-			ctrl_rsp = 1;
+		else {
+			/*
+			 * Notify response from timeout to allow the control
+			 * interface response to be sent first.
+			 */
+			eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
+					       wpa_s, NULL);
+		}
 	} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
 		if (wpa_supplicant_reload_configuration(wpa_s))
 			reply_len = -1;
@@ -5622,6 +5635,8 @@
 			     (wpa_s->wpa_state == WPA_COMPLETED))) {
 				wpa_s->normal_scans = 0;
 				wpa_s->scan_req = MANUAL_SCAN_REQ;
+				wpa_s->after_wps = 0;
+				wpa_s->known_wps_freq = 0;
 				wpa_supplicant_req_scan(wpa_s, 0, 0);
 			} else if (wpa_s->sched_scanning) {
 				wpa_printf(MSG_DEBUG, "Stop ongoing "
@@ -5711,6 +5726,9 @@
 	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
 		if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
+		if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
+			reply_len = -1;
 #endif /* CONFIG_AP */
 	} else if (os_strcmp(buf, "SUSPEND") == 0) {
 		wpas_notify_suspend(wpa_s->global);
@@ -5760,7 +5778,7 @@
 	} else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
 		reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
 						      reply_size);
-#endif
+#endif /* ANDROID */
 	} else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
 		pmksa_cache_clear_current(wpa_s->wpa);
 		eapol_sm_request_reauth(wpa_s->eapol);
@@ -5784,9 +5802,6 @@
 		reply_len = 5;
 	}
 
-	if (ctrl_rsp)
-		eapol_sm_notify_ctrl_response(wpa_s->eapol);
-
 	*resp_len = reply_len;
 	return reply;
 }
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index e35d2c3..7135d06 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -57,10 +57,17 @@
 };
 
 
-static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+					   const char *ifname, int sock,
 					   struct dl_list *ctrl_dst,
 					   int level, const char *buf,
-					   size_t len);
+					   size_t len,
+					   struct ctrl_iface_priv *priv,
+					   struct ctrl_iface_global_priv *gp);
+static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
+				  struct ctrl_iface_priv *priv);
+static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
+					 struct ctrl_iface_global_priv *priv);
 
 
 static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
@@ -143,7 +150,7 @@
 	int res;
 	struct sockaddr_un from;
 	socklen_t fromlen = sizeof(from);
-	char *reply = NULL;
+	char *reply = NULL, *reply_buf = NULL;
 	size_t reply_len = 0;
 	int new_attached = 0;
 
@@ -177,21 +184,49 @@
 		else
 			reply_len = 2;
 	} else {
-		reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
-							  &reply_len);
+		reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
+							      &reply_len);
+		reply = reply_buf;
+	}
+
+	if (!reply && reply_len == 1) {
+		reply = "FAIL\n";
+		reply_len = 5;
+	} else if (!reply && reply_len == 2) {
+		reply = "OK\n";
+		reply_len = 3;
 	}
 
 	if (reply) {
-		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
-		       fromlen);
-		os_free(reply);
-	} else if (reply_len == 1) {
-		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
-		       fromlen);
-	} else if (reply_len == 2) {
-		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
-		       fromlen);
+		if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+			   fromlen) < 0) {
+			int _errno = errno;
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"ctrl_iface sendto failed: %d - %s",
+				_errno, strerror(_errno));
+			if (_errno == ENOBUFS || _errno == EAGAIN) {
+				/*
+				 * The socket send buffer could be full. This
+				 * may happen if client programs are not
+				 * receiving their pending messages. Close and
+				 * reopen the socket as a workaround to avoid
+				 * getting stuck being unable to send any new
+				 * responses.
+				 */
+				sock = wpas_ctrl_iface_reinit(wpa_s, priv);
+				if (sock < 0) {
+					wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket");
+				}
+			}
+			if (new_attached) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching");
+				new_attached = 0;
+				wpa_supplicant_ctrl_iface_detach(
+					&priv->ctrl_dst, &from, fromlen);
+			}
+		}
 	}
+	os_free(reply_buf);
 
 	if (new_attached)
 		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
@@ -262,26 +297,27 @@
 	if (global != 2 && wpa_s->global->ctrl_iface) {
 		struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
 		if (!dl_list_empty(&priv->ctrl_dst)) {
-			wpa_supplicant_ctrl_iface_send(global ? NULL :
+			wpa_supplicant_ctrl_iface_send(wpa_s, global ? NULL :
 						       wpa_s->ifname,
 						       priv->sock,
 						       &priv->ctrl_dst,
-						       level, txt, len);
+						       level, txt, len, NULL,
+						       priv);
 		}
 	}
 
 	if (wpa_s->ctrl_iface == NULL)
 		return;
-	wpa_supplicant_ctrl_iface_send(NULL, wpa_s->ctrl_iface->sock,
+	wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
 				       &wpa_s->ctrl_iface->ctrl_dst,
-				       level, txt, len);
+				       level, txt, len, wpa_s->ctrl_iface,
+				       NULL);
 }
 
 
-struct ctrl_iface_priv *
-wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s,
+				     struct ctrl_iface_priv *priv)
 {
-	struct ctrl_iface_priv *priv;
 	struct sockaddr_un addr;
 	char *fname = NULL;
 	gid_t gid = 0;
@@ -291,16 +327,6 @@
 	char *endp;
 	int flags;
 
-	priv = os_zalloc(sizeof(*priv));
-	if (priv == NULL)
-		return NULL;
-	dl_list_init(&priv->ctrl_dst);
-	priv->wpa_s = wpa_s;
-	priv->sock = -1;
-
-	if (wpa_s->conf->ctrl_interface == NULL)
-		return priv;
-
 	buf = os_strdup(wpa_s->conf->ctrl_interface);
 	if (buf == NULL)
 		goto fail;
@@ -476,18 +502,61 @@
 	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
 
 	os_free(buf);
-	return priv;
+	return 0;
 
 fail:
-	if (priv->sock >= 0)
+	if (priv->sock >= 0) {
 		close(priv->sock);
-	os_free(priv);
+		priv->sock = -1;
+	}
 	if (fname) {
 		unlink(fname);
 		os_free(fname);
 	}
 	os_free(buf);
-	return NULL;
+	return -1;
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+	struct ctrl_iface_priv *priv;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	dl_list_init(&priv->ctrl_dst);
+	priv->wpa_s = wpa_s;
+	priv->sock = -1;
+
+	if (wpa_s->conf->ctrl_interface == NULL)
+		return priv;
+
+	if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0) {
+		os_free(priv);
+		return NULL;
+	}
+
+	return priv;
+}
+
+
+static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
+				  struct ctrl_iface_priv *priv)
+{
+	int res;
+
+	if (priv->sock <= 0)
+		return -1;
+
+	eloop_unregister_read_sock(priv->sock);
+	close(priv->sock);
+	priv->sock = -1;
+	res = wpas_ctrl_iface_open_sock(wpa_s, priv);
+	if (res < 0)
+		return -1;
+	return priv->sock;
 }
 
 
@@ -517,6 +586,8 @@
 			os_free(fname);
 		}
 
+		if (priv->wpa_s->conf->ctrl_interface == NULL)
+			goto free_dst;
 		buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
 		if (buf == NULL)
 			goto free_dst;
@@ -563,10 +634,13 @@
  *
  * Send a packet to all monitor programs attached to the control interface.
  */
-static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+					   const char *ifname, int sock,
 					   struct dl_list *ctrl_dst,
 					   int level, const char *buf,
-					   size_t len)
+					   size_t len,
+					   struct ctrl_iface_priv *priv,
+					   struct ctrl_iface_global_priv *gp)
 {
 	struct wpa_ctrl_dst *dst, *next;
 	char levelstr[10];
@@ -602,31 +676,57 @@
 	msg.msg_iov = io;
 	msg.msg_iovlen = idx;
 
-	idx = 0;
+	idx = -1;
 	dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
-		if (level >= dst->debug_level) {
-			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
-				    (u8 *) dst->addr.sun_path, dst->addrlen -
-				    offsetof(struct sockaddr_un, sun_path));
-			msg.msg_name = (void *) &dst->addr;
-			msg.msg_namelen = dst->addrlen;
-			if (sendmsg(sock, &msg, MSG_DONTWAIT) < 0) {
-				int _errno = errno;
-				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
-					   "%d - %s",
-					   idx, errno, strerror(errno));
-				dst->errors++;
-				if (dst->errors > 1000 ||
-				    (_errno != ENOBUFS && dst->errors > 10) ||
-				    _errno == ENOENT) {
-					wpa_supplicant_ctrl_iface_detach(
-						ctrl_dst, &dst->addr,
-						dst->addrlen);
-				}
-			} else
-				dst->errors = 0;
-		}
+		int _errno;
+
 		idx++;
+		if (level < dst->debug_level)
+			continue;
+
+		wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
+			    (u8 *) dst->addr.sun_path, dst->addrlen -
+			    offsetof(struct sockaddr_un, sun_path));
+		msg.msg_name = (void *) &dst->addr;
+		msg.msg_namelen = dst->addrlen;
+		if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) {
+			dst->errors = 0;
+			idx++;
+			continue;
+		}
+
+		_errno = errno;
+		wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: %d - %s",
+			   idx, errno, strerror(errno));
+		dst->errors++;
+
+		if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) {
+			wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages");
+			wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr,
+							 dst->addrlen);
+		}
+
+		if (_errno == ENOBUFS || _errno == EAGAIN) {
+			/*
+			 * The socket send buffer could be full. This may happen
+			 * if client programs are not receiving their pending
+			 * messages. Close and reopen the socket as a workaround
+			 * to avoid getting stuck being unable to send any new
+			 * responses.
+			 */
+			if (priv)
+				sock = wpas_ctrl_iface_reinit(wpa_s, priv);
+			else if (gp)
+				sock = wpas_ctrl_iface_global_reinit(
+					wpa_s->global, gp);
+			else
+				break;
+			if (sock < 0) {
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"Failed to reinitialize ctrl_iface socket");
+				break;
+			}
+		}
 	}
 }
 
@@ -656,18 +756,30 @@
 			/* handle ATTACH signal of first monitor interface */
 			if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
 							      &from, fromlen)) {
-				sendto(priv->sock, "OK\n", 3, 0,
-				       (struct sockaddr *) &from, fromlen);
+				if (sendto(priv->sock, "OK\n", 3, 0,
+					   (struct sockaddr *) &from, fromlen) <
+				    0) {
+					wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+						   strerror(errno));
+				}
 				/* OK to continue */
 				return;
 			} else {
-				sendto(priv->sock, "FAIL\n", 5, 0,
-				       (struct sockaddr *) &from, fromlen);
+				if (sendto(priv->sock, "FAIL\n", 5, 0,
+					   (struct sockaddr *) &from, fromlen) <
+				    0) {
+					wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+						   strerror(errno));
+				}
 			}
 		} else {
 			/* return FAIL for all other signals */
-			sendto(priv->sock, "FAIL\n", 5, 0,
-			       (struct sockaddr *) &from, fromlen);
+			if (sendto(priv->sock, "FAIL\n", 5, 0,
+				   (struct sockaddr *) &from, fromlen) < 0) {
+				wpa_printf(MSG_DEBUG,
+					   "ctrl_iface sendto failed: %s",
+					   strerror(errno));
+			}
 		}
 	}
 }
@@ -684,7 +796,7 @@
 	int res;
 	struct sockaddr_un from;
 	socklen_t fromlen = sizeof(from);
-	char *reply = NULL;
+	char *reply = NULL, *reply_buf = NULL;
 	size_t reply_len;
 
 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
@@ -709,41 +821,37 @@
 		else
 			reply_len = 2;
 	} else {
-		reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
-								 &reply_len);
+		reply_buf = wpa_supplicant_global_ctrl_iface_process(
+			global, buf, &reply_len);
+		reply = reply_buf;
+	}
+
+	if (!reply && reply_len == 1) {
+		reply = "FAIL\n";
+		reply_len = 5;
+	} else if (!reply && reply_len == 2) {
+		reply = "OK\n";
+		reply_len = 3;
 	}
 
 	if (reply) {
-		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
-		       fromlen);
-		os_free(reply);
-	} else if (reply_len == 1) {
-		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
-		       fromlen);
-	} else if (reply_len == 2) {
-		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, fromlen);
+		if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+			   fromlen) < 0) {
+			wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+				strerror(errno));
+		}
 	}
+	os_free(reply_buf);
 }
 
 
-struct ctrl_iface_global_priv *
-wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global,
+					    struct ctrl_iface_global_priv *priv)
 {
-	struct ctrl_iface_global_priv *priv;
 	struct sockaddr_un addr;
 	const char *ctrl = global->params.ctrl_interface;
 	int flags;
 
-	priv = os_zalloc(sizeof(*priv));
-	if (priv == NULL)
-		return NULL;
-	dl_list_init(&priv->ctrl_dst);
-	priv->global = global;
-	priv->sock = -1;
-
-	if (ctrl == NULL)
-		return priv;
-
 	wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl);
 
 #ifdef ANDROID
@@ -899,13 +1007,58 @@
 				 wpa_supplicant_global_ctrl_iface_receive,
 				 global, priv);
 
-	return priv;
+	return 0;
 
 fail:
-	if (priv->sock >= 0)
+	if (priv->sock >= 0) {
 		close(priv->sock);
-	os_free(priv);
-	return NULL;
+		priv->sock = -1;
+	}
+	return -1;
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+	struct ctrl_iface_global_priv *priv;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	dl_list_init(&priv->ctrl_dst);
+	priv->global = global;
+	priv->sock = -1;
+
+	if (global->params.ctrl_interface == NULL)
+		return priv;
+
+	if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) {
+		os_free(priv);
+		return NULL;
+	}
+
+	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+	return priv;
+}
+
+
+static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
+					 struct ctrl_iface_global_priv *priv)
+{
+	int res;
+
+	if (priv->sock <= 0)
+		return -1;
+
+	eloop_unregister_read_sock(priv->sock);
+	close(priv->sock);
+	priv->sock = -1;
+	res = wpas_global_ctrl_iface_open_sock(global, priv);
+	if (res < 0)
+		return -1;
+	return priv->sock;
 }
 
 
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index ddd2c82..9736e8f 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1362,7 +1362,7 @@
 	DBusMessageIter iter, dict_iter;
 	struct wpas_dbus_priv *iface;
 
-	wpa_printf(MSG_INFO, "%s\n", __func__);
+	wpa_printf(MSG_DEBUG, "%s", __func__);
 
 	iface = wpa_s->global->dbus;
 	/* Do nothing if the control interface is not turned on */
@@ -2736,6 +2736,37 @@
 	  }
 	},
 #endif /* CONFIG_AUTOSCAN */
+#ifdef CONFIG_TDLS
+	{ "TDLSDiscover", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_discover,
+	  {
+		  { "peer_address", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "TDLSSetup", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_setup,
+	  {
+		  { "peer_address", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "TDLSStatus", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_status,
+	  {
+		  { "peer_address", "s", ARG_IN },
+		  { "status", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "TDLSTeardown", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_teardown,
+	  {
+		  { "peer_address", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_TDLS */
 	{ NULL, NULL, NULL, { END_ARGS } }
 };
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 478d02f..0a80521 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1236,6 +1236,23 @@
 }
 
 
+static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
+					 DBusMessageIter *var,
+					 dbus_bool_t *allow,
+					 DBusMessage **reply)
+{
+	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+			   "Type must be a boolean");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "Wrong Type value type. Boolean required");
+		return -1;
+	}
+	dbus_message_iter_get_basic(var, allow);
+	return 0;
+}
+
+
 /**
  * wpas_dbus_handler_scan - Request a wireless scan on an interface
  * @message: Pointer to incoming dbus message
@@ -1254,6 +1271,7 @@
 	char *key = NULL, *type = NULL;
 	struct wpa_driver_scan_params params;
 	size_t i;
+	dbus_bool_t allow_roam = 1;
 
 	os_memset(&params, 0, sizeof(params));
 
@@ -1284,6 +1302,12 @@
 			if (wpas_dbus_get_scan_channels(message, &variant_iter,
 							&params, &reply) < 0)
 				goto out;
+		} else if (os_strcmp(key, "AllowRoam") == 0) {
+			if (wpas_dbus_get_scan_allow_roam(message,
+							  &variant_iter,
+							  &allow_roam,
+							  &reply) < 0)
+				goto out;
 		} else {
 			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
 				   "Unknown argument %s", key);
@@ -1332,6 +1356,9 @@
 		goto out;
 	}
 
+	if (!allow_roam)
+		wpa_s->scan_res_handler = scan_only_handler;
+
 out:
 	for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
 		os_free((u8 *) params.ssids[i].ssid);
@@ -1970,6 +1997,170 @@
 }
 
 
+#ifdef CONFIG_TDLS
+
+static DBusMessage * get_peer_hwaddr_helper(DBusMessage *message,
+					    const char *func_name,
+					    u8 *peer_address)
+{
+	const char *peer_string;
+
+	if (!dbus_message_get_args(message, NULL,
+				   DBUS_TYPE_STRING, &peer_string,
+				   DBUS_TYPE_INVALID))
+		return wpas_dbus_error_invalid_args(message, NULL);
+
+	if (hwaddr_aton(peer_string, peer_address)) {
+		wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
+			   func_name, peer_string);
+		return wpas_dbus_error_invalid_args(
+			message, "Invalid hardware address format");
+	}
+
+	return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_discover - Discover TDLS peer
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSDiscover" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s)
+{
+	u8 peer[ETH_ALEN];
+	DBusMessage *error_reply;
+	int ret;
+
+	error_reply = get_peer_hwaddr_helper(message, __func__, peer);
+	if (error_reply)
+		return error_reply;
+
+	wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
+
+	if (wpa_tdls_is_external_setup(wpa_s->wpa))
+		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
+	else
+		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
+
+	if (ret) {
+		return wpas_dbus_error_unknown_error(
+			message, "error performing TDLS discovery");
+	}
+
+	return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_setup - Setup TDLS session
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSSetup" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s)
+{
+	u8 peer[ETH_ALEN];
+	DBusMessage *error_reply;
+	int ret;
+
+	error_reply = get_peer_hwaddr_helper(message, __func__, peer);
+	if (error_reply)
+		return error_reply;
+
+	wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
+
+	wpa_tdls_remove(wpa_s->wpa, peer);
+	if (wpa_tdls_is_external_setup(wpa_s->wpa))
+		ret = wpa_tdls_start(wpa_s->wpa, peer);
+	else
+		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+
+	if (ret) {
+		return wpas_dbus_error_unknown_error(
+			message, "error performing TDLS setup");
+	}
+
+	return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_status - Return TDLS session status
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A string representing the state of the link to this TDLS peer
+ *
+ * Handler function for "TDLSStatus" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s)
+{
+	u8 peer[ETH_ALEN];
+	DBusMessage *reply;
+	const char *tdls_status;
+
+	reply = get_peer_hwaddr_helper(message, __func__, peer);
+	if (reply)
+		return reply;
+
+	wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
+
+	tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
+
+	reply = dbus_message_new_method_return(message);
+	dbus_message_append_args(reply, DBUS_TYPE_STRING,
+				 &tdls_status, DBUS_TYPE_INVALID);
+	return reply;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSTeardown" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s)
+{
+	u8 peer[ETH_ALEN];
+	DBusMessage *error_reply;
+	int ret;
+
+	error_reply = get_peer_hwaddr_helper(message, __func__, peer);
+	if (error_reply)
+		return error_reply;
+
+	wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
+
+	if (wpa_tdls_is_external_setup(wpa_s->wpa))
+		ret = wpa_tdls_teardown_link(
+			wpa_s->wpa, peer,
+			WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+	else
+		ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+	if (ret) {
+		return wpas_dbus_error_unknown_error(
+			message, "error performing TDLS teardown");
+	}
+
+	return NULL;
+}
+
+#endif /* CONFIG_TDLS */
+
+
 /**
  * wpas_dbus_getter_capabilities - Return interface capabilities
  * @iter: Pointer to incoming dbus message iter
@@ -2003,7 +2194,7 @@
 		const char *args[] = {"ccmp", "tkip", "none"};
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "Pairwise", args,
-			    sizeof(args) / sizeof(char*)))
+			    ARRAY_SIZE(args)))
 			goto nomem;
 	} else {
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
@@ -2050,7 +2241,7 @@
 		};
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "Group", args,
-			    sizeof(args) / sizeof(char*)))
+			    ARRAY_SIZE(args)))
 			goto nomem;
 	} else {
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
@@ -2107,7 +2298,7 @@
 		};
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "KeyMgmt", args,
-			    sizeof(args) / sizeof(char*)))
+			    ARRAY_SIZE(args)))
 			goto nomem;
 	} else {
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
@@ -2187,7 +2378,7 @@
 		const char *args[] = { "rsn", "wpa" };
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "Protocol", args,
-			    sizeof(args) / sizeof(char*)))
+			    ARRAY_SIZE(args)))
 			goto nomem;
 	} else {
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
@@ -2222,7 +2413,7 @@
 		const char *args[] = { "open", "shared", "leap" };
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "AuthAlg", args,
-			    sizeof(args) / sizeof(char*)))
+			    ARRAY_SIZE(args)))
 			goto nomem;
 	} else {
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
@@ -2258,7 +2449,7 @@
 
 	/***** Scan */
 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
-					       sizeof(scans) / sizeof(char *)))
+					       ARRAY_SIZE(scans)))
 		goto nomem;
 
 	/***** Modes */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index fbc8358..aa3316b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -278,6 +278,15 @@
 						 DBusError *error,
 						 void *user_data);
 
+DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s);
+
 DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
 					   const char *arg);
 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 6ec96df..5150a76 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -346,14 +346,14 @@
 		if (ssid == NULL || ssid->disabled != 2)
 			goto inv_args;
 
-		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0,
-						  NULL)) {
+		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0,
+						  NULL, 0)) {
 			reply = wpas_dbus_error_unknown_error(
 				message,
 				"Failed to reinvoke a persistent group");
 			goto out;
 		}
-	} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0))
+	} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0))
 		goto inv_args;
 
 out:
@@ -505,7 +505,7 @@
 
 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
 				   persistent_group, 0, join, authorize_only,
-				   go_intent, freq, -1, 0, 0);
+				   go_intent, freq, -1, 0, 0, 0);
 
 	if (new_pin >= 0) {
 		char npin[9];
@@ -631,8 +631,8 @@
 		if (ssid == NULL || ssid->disabled != 2)
 			goto err;
 
-		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0) < 0)
-		{
+		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0) <
+		    0) {
 			reply = wpas_dbus_error_unknown_error(
 				message,
 				"Failed to reinvoke a persistent group");
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index e565de9..6d178f4 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -539,7 +539,7 @@
 			const char *args[] = {"CCMP", "TKIP", "NONE"};
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "pairwise", args,
-				    sizeof(args) / sizeof(char*)))
+				    ARRAY_SIZE(args)))
 				goto error;
 		}
 	} else {
@@ -582,7 +582,7 @@
 			};
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "group", args,
-				    sizeof(args) / sizeof(char*)))
+				    ARRAY_SIZE(args)))
 				goto error;
 		}
 	} else {
@@ -632,7 +632,7 @@
 			};
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "key_mgmt", args,
-				    sizeof(args) / sizeof(char*)))
+				    ARRAY_SIZE(args)))
 				goto error;
 		}
 	} else {
@@ -683,7 +683,7 @@
 			const char *args[] = { "RSN", "WPA" };
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "proto", args,
-				    sizeof(args) / sizeof(char*)))
+				    ARRAY_SIZE(args)))
 				goto error;
 		}
 	} else {
@@ -720,7 +720,7 @@
 			const char *args[] = { "OPEN", "SHARED", "LEAP" };
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "auth_alg", args,
-				    sizeof(args) / sizeof(char*)))
+				    ARRAY_SIZE(args)))
 				goto error;
 		}
 	} else {
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index aa6005f..ea0db04 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -307,7 +307,6 @@
 # Select event loop implementation
 # eloop = select() loop (default)
 # eloop_win = Windows events and WaitForMultipleObject() loop
-# eloop_none = Empty template
 #CONFIG_ELOOP=eloop
 
 # Should we use poll instead of select? Select is used by default.
@@ -484,6 +483,10 @@
 # IEEE 802.11n (High Throughput) support (mainly for AP mode)
 #CONFIG_IEEE80211N=y
 
+# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
+# (depends on CONFIG_IEEE80211N)
+#CONFIG_IEEE80211AC=y
+
 # Wireless Network Management (IEEE Std 802.11v-2011)
 # Note: This is experimental and not complete implementation.
 #CONFIG_WNM=y
@@ -515,9 +518,14 @@
 # Enable TDLS support
 #CONFIG_TDLS=y
 
+# Wi-Fi Direct
+# This can be used to enable Wi-Fi Direct extensions for P2P using an external
+# program to control the additional information exchanges in the messages.
+#CONFIG_WIFI_DISPLAY=y
+
 # Autoscan
 # This can be used to enable automatic scan support in wpa_supplicant.
-# See wpa_supplicant.conf for more information on autoscan usage.
+# See wpa_supplicant.conf for more information on autoscan usage.
 #
 # Enabling directly a module will enable autoscan support.
 # For exponential module:
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 5e7dbf7..7f196de 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -380,7 +380,7 @@
 	if (wpa_s->driver->if_add)
 		return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname,
 					     addr, bss_ctx, NULL, force_ifname,
-					     if_addr, bridge);
+					     if_addr, bridge, 0);
 	return -1;
 }
 
@@ -673,7 +673,7 @@
 		return -1;
 	return wpa_s->driver->driver_cmd(wpa_s->drv_priv, cmd, buf, buf_len);
 }
-#endif
+#endif /* ANDROID */
 
 static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
 					  const u8 *kek, const u8 *kck,
@@ -693,11 +693,11 @@
 }
 
 static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s,
-					 unsigned int freq)
+					 struct csa_settings *settings)
 {
 	if (!wpa_s->driver->switch_channel)
 		return -1;
-	return wpa_s->driver->switch_channel(wpa_s->drv_priv, freq);
+	return wpa_s->driver->switch_channel(wpa_s->drv_priv, settings);
 }
 
 static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s,
@@ -710,4 +710,21 @@
 				       buf_len);
 }
 
+static inline int wpa_drv_status(struct wpa_supplicant *wpa_s,
+				 char *buf, size_t buflen)
+{
+	if (!wpa_s->driver->status)
+		return -1;
+	return wpa_s->driver->status(wpa_s->drv_priv, buf, buflen);
+}
+
+static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s,
+				      const u8 *qos_map_set, u8 qos_map_set_len)
+{
+	if (!wpa_s->driver->set_qos_map)
+		return -1;
+	return wpa_s->driver->set_qos_map(wpa_s->drv_priv, qos_map_set,
+					  qos_map_set_len);
+}
+
 #endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index dad2765..2b25b69 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - test code
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -27,6 +27,7 @@
 #include "common/wpa_ctrl.h"
 #include "ctrl_iface.h"
 #include "pcsc_funcs.h"
+#include "wpas_glue.h"
 
 
 extern int wpa_debug_level;
@@ -395,6 +396,54 @@
 }
 
 
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static void eapol_test_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
+					const char *default_txt)
+{
+	struct eapol_test_data *e = ctx;
+	struct wpa_supplicant *wpa_s = e->wpa_s;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	const char *field_name, *txt = NULL;
+	char *buf;
+	size_t buflen;
+	int len;
+
+	if (ssid == NULL)
+		return;
+
+	field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
+						       &txt);
+	if (field_name == NULL) {
+		wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed",
+			   field);
+		return;
+	}
+
+	buflen = 100 + os_strlen(txt) + ssid->ssid_len;
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return;
+	len = os_snprintf(buf, buflen,
+			  WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
+			  field_name, ssid->id, txt);
+	if (len < 0 || (size_t) len >= buflen) {
+		os_free(buf);
+		return;
+	}
+	if (ssid->ssid && buflen > len + ssid->ssid_len) {
+		os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
+		len += ssid->ssid_len;
+		buf[len] = '\0';
+	}
+	buf[buflen - 1] = '\0';
+	wpa_msg(wpa_s, MSG_INFO, "%s", buf);
+	os_free(buf);
+}
+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#define eapol_test_eap_param_needed NULL
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
 static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
 			       const char *cert_hash,
 			       const struct wpabuf *cert)
@@ -484,6 +533,7 @@
 	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
 	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
 	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+	ctx->eap_param_needed = eapol_test_eap_param_needed;
 	ctx->cert_cb = eapol_test_cert_cb;
 	ctx->cert_in_cb = 1;
 	ctx->set_anon_id = eapol_test_set_anon_id;
@@ -501,6 +551,7 @@
 	eapol_conf.required_keys = 0;
 	eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
 	eapol_conf.workaround = ssid->eap_workaround;
+	eapol_conf.external_sim = wpa_s->conf->external_sim;
 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 	eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
 
@@ -892,7 +943,7 @@
 	unsigned char aka_ik[IK_LEN];
 	unsigned char aka_ck[CK_LEN];
 
-	scard = scard_init(SCARD_TRY_BOTH, NULL);
+	scard = scard_init(NULL);
 	if (scard == NULL)
 		return -1;
 	if (scard_set_pin(scard, "1234")) {
@@ -992,7 +1043,7 @@
 		wpa_debug_level = 99;
 	}
 
-	scard = scard_init(SCARD_GSM_SIM_ONLY, NULL);
+	scard = scard_init(NULL);
 	if (scard == NULL) {
 		printf("Failed to open smartcard connection\n");
 		return -1;
@@ -1094,6 +1145,7 @@
 
 int main(int argc, char *argv[])
 {
+	struct wpa_global global;
 	struct wpa_supplicant wpa_s;
 	int c, ret = 1, wait_for_monitor = 0, save_config = 0;
 	char *as_addr = "127.0.0.1";
@@ -1230,8 +1282,12 @@
 		return -1;
 	}
 
+	os_memset(&global, 0, sizeof(global));
 	os_memset(&wpa_s, 0, sizeof(wpa_s));
+	wpa_s.global = &global;
 	eapol_test.wpa_s = &wpa_s;
+	dl_list_init(&wpa_s.bss);
+	dl_list_init(&wpa_s.bss_id);
 	wpa_s.conf = wpa_config_read(conf, NULL);
 	if (wpa_s.conf == NULL) {
 		printf("Failed to parse configuration file '%s'.\n", conf);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 9de8d7f..b9481f6 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -46,7 +46,7 @@
 
 #ifndef CONFIG_NO_SCAN_PROCESSING
 static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
-					      int new_scan);
+					      int new_scan, int own_request);
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 
 
@@ -160,9 +160,6 @@
 		return;
 
 	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-#ifdef ANDROID
-	wpa_s->conf->ap_scan = DEFAULT_AP_SCAN;
-#endif
 	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
 	os_memset(wpa_s->bssid, 0, ETH_ALEN);
 	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
@@ -278,7 +275,8 @@
 #ifdef PCSC_FUNCS
 	int aka = 0, sim = 0;
 
-	if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL)
+	if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL ||
+	    wpa_s->conf->external_sim)
 		return 0;
 
 	if (ssid->eap.eap_methods == NULL) {
@@ -316,8 +314,7 @@
 	wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to use SIM "
 		"(sim=%d aka=%d) - initialize PCSC", sim, aka);
 
-	wpa_s->scard = scard_init((!sim && aka) ? SCARD_USIM_ONLY :
-				  SCARD_TRY_BOTH, NULL);
+	wpa_s->scard = scard_init(NULL);
 	if (wpa_s->scard == NULL) {
 		wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM "
 			"(pcsc-lite)");
@@ -718,10 +715,13 @@
 	rsn_ie_len = ie ? ie[1] : 0;
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
-		"wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s",
+		"wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s%s",
 		i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len),
 		wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
-		wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "");
+		wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "",
+		(wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
+		 wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) ?
+		" p2p" : "");
 
 	e = wpa_blacklist_get(wpa_s, bss->bssid);
 	if (e) {
@@ -858,6 +858,39 @@
 		}
 
 #ifdef CONFIG_P2P
+		if (ssid->p2p_group &&
+		    !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+		    !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no P2P IE seen");
+			continue;
+		}
+
+		if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
+			struct wpabuf *p2p_ie;
+			u8 dev_addr[ETH_ALEN];
+
+			ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+			if (ie == NULL) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no P2P element");
+				continue;
+			}
+			p2p_ie = wpa_bss_get_vendor_ie_multi(
+				bss, P2P_IE_VENDOR_TYPE);
+			if (p2p_ie == NULL) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "   skip - could not fetch P2P element");
+				continue;
+			}
+
+			if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0
+			    || os_memcmp(dev_addr, ssid->go_p2p_dev_addr,
+					 ETH_ALEN) != 0) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no matching GO P2P Device Address in P2P element");
+				wpabuf_free(p2p_ie);
+				continue;
+			}
+			wpabuf_free(p2p_ie);
+		}
+
 		/*
 		 * TODO: skip the AP if its P2P IE has Group Formation
 		 * bit set in the P2P Group Capability Bitmap and we
@@ -1268,12 +1301,12 @@
 
 	wpa_scan_results_free(scan_res);
 
-	return wpas_select_network_from_last_scan(wpa_s, 1);
+	return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
 }
 
 
 static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
-					      int new_scan)
+					      int new_scan, int own_request)
 {
 	struct wpa_bss *selected;
 	struct wpa_ssid *ssid = NULL;
@@ -1308,17 +1341,24 @@
 			wpa_supplicant_associate(wpa_s, NULL, ssid);
 			if (new_scan)
 				wpa_supplicant_rsn_preauth_scan_results(wpa_s);
-		} else {
+		} else if (own_request) {
+			/*
+			 * No SSID found. If SCAN results are as a result of
+			 * own scan request and not due to a scan request on
+			 * another shared interface, try another scan.
+			 */
 			int timeout_sec = wpa_s->scan_interval;
 			int timeout_usec = 0;
 #ifdef CONFIG_P2P
 			if (wpas_p2p_scan_no_go_seen(wpa_s) == 1)
 				return 0;
 
-			if (wpa_s->p2p_in_provisioning) {
+			if (wpa_s->p2p_in_provisioning ||
+			    wpa_s->show_group_started) {
 				/*
 				 * Use shorter wait during P2P Provisioning
-				 * state to speed up group formation.
+				 * state and during P2P join-a-group operation
+				 * to speed up group formation.
 				 */
 				timeout_sec = 0;
 				timeout_usec = 250000;
@@ -1412,7 +1452,7 @@
 		return -1;
 	}
 
-	return wpas_select_network_from_last_scan(wpa_s, 0);
+	return wpas_select_network_from_last_scan(wpa_s, 0, 1);
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 }
 
@@ -1496,6 +1536,43 @@
 }
 
 
+#ifdef CONFIG_INTERWORKING
+
+static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map,
+			    size_t len)
+{
+	int res;
+
+	wpa_hexdump(MSG_DEBUG, "Interworking: QoS Map Set", qos_map, len);
+	res = wpa_drv_set_qos_map(wpa_s, qos_map, len);
+	if (res) {
+		wpa_printf(MSG_DEBUG, "Interworking: Failed to configure QoS Map Set to the driver");
+	}
+
+	return res;
+}
+
+
+static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
+					    const u8 *ies, size_t ies_len)
+{
+	struct ieee802_11_elems elems;
+
+	if (ies == NULL)
+		return;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+		return;
+
+	if (elems.qos_map_set) {
+		wpas_qos_map_set(wpa_s, elems.qos_map_set,
+				 elems.qos_map_set_len);
+	}
+}
+
+#endif /* CONFIG_INTERWORKING */
+
+
 static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
 					  union wpa_event_data *data)
 {
@@ -1520,6 +1597,10 @@
 		wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
 				       data->assoc_info.resp_ies_len);
 #endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+		interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+						data->assoc_info.resp_ies_len);
+#endif /* CONFIG_INTERWORKING */
 	}
 	if (data->assoc_info.beacon_ies)
 		wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -2051,11 +2132,7 @@
 			fast_reconnect_ssid = wpa_s->current_ssid;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 		} else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
-#ifdef ANDROID
-			wpa_supplicant_req_scan(wpa_s, 0, 500000);
-#else
 			wpa_supplicant_req_scan(wpa_s, 0, 100000);
-#endif
 		else
 			wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new "
 				"immediate scan");
@@ -2591,6 +2668,52 @@
 }
 
 
+static void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s)
+{
+	const char *rn, *rn2;
+	struct wpa_supplicant *ifs;
+
+	if (wpa_s->drv_priv == NULL)
+		return; /* Ignore event during drv initialization */
+
+	free_hw_features(wpa_s);
+	wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
+		wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
+
+#ifdef CONFIG_P2P
+	wpas_p2p_update_channel_list(wpa_s);
+#endif /* CONFIG_P2P */
+
+	/*
+	 * Check other interfaces to see if they have the same radio-name. If
+	 * so, they get updated with this same hw mode info.
+	 */
+	if (!wpa_s->driver->get_radio_name)
+		return;
+
+	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+	if (rn == NULL || rn[0] == '\0')
+		return;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Checking for other virtual interfaces "
+		"sharing same radio (%s) in event_channel_list_change", rn);
+
+	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+		if (ifs == wpa_s || !ifs->driver->get_radio_name)
+			continue;
+
+		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+		if (rn2 && os_strcmp(rn, rn2) == 0) {
+			wpa_printf(MSG_DEBUG, "%s: Updating hw mode",
+				   ifs->ifname);
+			free_hw_features(ifs);
+			ifs->hw.modes = wpa_drv_get_hw_feature_data(
+				ifs, &ifs->hw.num_modes, &ifs->hw.flags);
+		}
+	}
+}
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
@@ -2698,52 +2821,11 @@
 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
 			sme_event_assoc_reject(wpa_s, data);
 		else {
-#ifdef ANDROID_P2P
-			if(!wpa_s->current_ssid) {
-				wpa_printf(MSG_ERROR, "current_ssid == NULL");
-				break;
-			}
-			/* If assoc reject is reported by the driver, then avoid
-			 * waiting for  the authentication timeout. Cancel the
-			 * authentication timeout and retry the assoc.
-			 */
-			if(wpa_s->current_ssid->assoc_retry++ < 10) {
-				wpa_printf(MSG_ERROR, "Retrying assoc: %d ",
-								wpa_s->current_ssid->assoc_retry);
-
-				wpa_supplicant_cancel_auth_timeout(wpa_s);
-
-				/* Clear the states */
-				wpa_sm_notify_disassoc(wpa_s->wpa);
-				wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-
-				wpa_s->reassociate = 1;
-				if (wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE) {
-					const u8 *bl_bssid = data->assoc_reject.bssid;
-					if (!bl_bssid || is_zero_ether_addr(bl_bssid))
-						bl_bssid = wpa_s->pending_bssid;
-					wpa_blacklist_add(wpa_s, bl_bssid);
-					wpa_supplicant_req_scan(wpa_s, 0, 0);
-				} else {
-					wpa_supplicant_req_scan(wpa_s, 1, 0);
-				}
-			} else if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
-				/* If we ASSOC_REJECT's hits threshold, disable the 
-			 	 * network
-			 	 */
-				wpa_printf(MSG_ERROR, "Assoc retry threshold reached. "
-				"Disabling the network");
-				wpa_s->current_ssid->assoc_retry = 0;
-				wpa_supplicant_disable_network(wpa_s, wpa_s->current_ssid);
-				wpas_p2p_group_remove(wpa_s, wpa_s->ifname);
-			}
-#else
 			const u8 *bssid = data->assoc_reject.bssid;
 			if (bssid == NULL || is_zero_ether_addr(bssid))
 				bssid = wpa_s->pending_bssid;
 			wpas_connection_failed(wpa_s, bssid);
 			wpa_supplicant_mark_disassoc(wpa_s);
-#endif /* ANDROID_P2P */
 		}
 		break;
 	case EVENT_AUTH_TIMED_OUT:
@@ -2948,6 +3030,22 @@
 			break;
 		}
 #endif /* CONFIG_TDLS */
+#ifdef CONFIG_INTERWORKING
+		if (data->rx_action.category == WLAN_ACTION_QOS &&
+		    data->rx_action.len >= 1 &&
+		    data->rx_action.data[0] == QOS_QOS_MAP_CONFIG) {
+			const u8 *pos = data->rx_action.data + 1;
+			size_t len = data->rx_action.len - 1;
+			wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: Received QoS Map Configure frame from "
+				MACSTR, MAC2STR(data->rx_action.sa));
+			if (os_memcmp(data->rx_action.sa, wpa_s->bssid,
+				      ETH_ALEN) == 0 &&
+			    len > 2 && pos[0] == WLAN_EID_QOS_MAP_SET &&
+			    pos[1] <= len - 2 && pos[1] >= 16)
+				wpas_qos_map_set(wpa_s, pos + 2, pos[1]);
+			break;
+		}
+#endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_P2P
 		wpas_p2p_rx_action(wpa_s, data->rx_action.da,
 				   data->rx_action.sa,
@@ -3105,16 +3203,7 @@
 		wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
 		break;
 	case EVENT_CHANNEL_LIST_CHANGED:
-		if (wpa_s->drv_priv == NULL)
-			break; /* Ignore event during drv initialization */
-
-		free_hw_features(wpa_s);
-		wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
-			wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
-
-#ifdef CONFIG_P2P
-		wpas_p2p_update_channel_list(wpa_s);
-#endif /* CONFIG_P2P */
+		wpa_supplicant_update_channel_list(wpa_s);
 		break;
 	case EVENT_INTERFACE_UNAVAILABLE:
 #ifdef CONFIG_P2P
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 06a97d3..f9885e3 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -1,7 +1,7 @@
 /*
  * Generic advertisement service (GAS) query
  * Copyright (c) 2009, Atheros Communications
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -21,6 +21,8 @@
 
 /** GAS query timeout in seconds */
 #define GAS_QUERY_TIMEOUT_PERIOD 2
+/** Retry period for GAS query requests in milliseconds */
+#define GAS_SERVICE_RETRY_PERIOD_MS 500
 
 
 /**
@@ -35,6 +37,7 @@
 	unsigned int offchannel_tx_started:1;
 	int freq;
 	u16 status_code;
+	struct wpabuf *req;
 	struct wpabuf *adv_proto;
 	struct wpabuf *resp;
 	void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
@@ -50,11 +53,13 @@
 struct gas_query {
 	struct wpa_supplicant *wpa_s;
 	struct dl_list pending; /* struct gas_query_pending */
+	struct gas_query_pending *current;
 };
 
 
 static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
 static void gas_query_timeout(void *eloop_data, void *user_ctx);
+static void gas_service_timeout(void *eloop_data, void *user_ctx);
 
 
 /**
@@ -81,13 +86,17 @@
 			   struct gas_query_pending *query,
 			   enum gas_query_result result)
 {
+	if (gas->current == query)
+		gas->current = NULL;
 	if (query->offchannel_tx_started)
 		offchannel_send_action_done(gas->wpa_s);
 	eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
 	eloop_cancel_timeout(gas_query_timeout, gas, query);
+	eloop_cancel_timeout(gas_service_timeout, gas, query);
 	dl_list_del(&query->list);
 	query->cb(query->ctx, query->addr, query->dialog_token, result,
 		  query->adv_proto, query->resp, query->status_code);
+	wpabuf_free(query->req);
 	wpabuf_free(query->adv_proto);
 	wpabuf_free(query->resp);
 	os_free(query);
@@ -138,6 +147,44 @@
 }
 
 
+static void gas_query_tx_status(struct wpa_supplicant *wpa_s,
+				unsigned int freq, const u8 *dst,
+				const u8 *src, const u8 *bssid,
+				const u8 *data, size_t data_len,
+				enum offchannel_send_action_result result)
+{
+	struct gas_query_pending *query;
+	struct gas_query *gas = wpa_s->gas;
+
+	if (gas->current == NULL) {
+		wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: freq=%u dst="
+			   MACSTR " result=%d - no query in progress",
+			   freq, MAC2STR(dst), result);
+		return;
+	}
+
+	query = gas->current;
+
+	wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
+		   " result=%d query=%p dialog_token=%u",
+		   freq, MAC2STR(dst), result, query, query->dialog_token);
+	if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination");
+		return;
+	}
+
+	if (result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
+		eloop_cancel_timeout(gas_query_timeout, gas, query);
+		eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+				       gas_query_timeout, gas, query);
+	}
+	if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+		eloop_cancel_timeout(gas_query_timeout, gas, query);
+		eloop_register_timeout(0, 0, gas_query_timeout, gas, query);
+	}
+}
+
+
 static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
 			struct wpabuf *req)
 {
@@ -148,7 +195,7 @@
 	res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
 				     gas->wpa_s->own_addr, query->addr,
 				     wpabuf_head(req), wpabuf_len(req), 1000,
-				     NULL, 0);
+				     gas_query_tx_status, 0);
 	if (res == 0)
 		query->offchannel_tx_started = 1;
 	return res;
@@ -426,12 +473,50 @@
 	struct gas_query *gas = eloop_data;
 	struct gas_query_pending *query = user_ctx;
 
-	wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR,
-		   MAC2STR(query->addr));
+	wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR
+		   " dialog token %u",
+		   MAC2STR(query->addr), query->dialog_token);
 	gas_query_done(gas, query, GAS_QUERY_TIMEOUT);
 }
 
 
+static void gas_service_timeout(void *eloop_data, void *user_ctx)
+{
+	struct gas_query *gas = eloop_data;
+	struct wpa_supplicant *wpa_s = gas->wpa_s;
+	struct gas_query_pending *query = user_ctx;
+	int conn;
+
+	conn = wpas_wpa_is_in_progress(wpa_s, 1);
+	if (conn || wpa_s->scanning || gas->current) {
+		wpa_printf(MSG_DEBUG, "GAS: Delaying GAS query Tx while another operation is in progress:%s%s%s",
+			   conn ? " connection" : "",
+			   wpa_s->scanning ? " scanning" : "",
+			   gas->current ? " gas_query" : "");
+		eloop_register_timeout(
+			GAS_SERVICE_RETRY_PERIOD_MS / 1000,
+			(GAS_SERVICE_RETRY_PERIOD_MS % 1000) * 1000,
+			gas_service_timeout, gas, query);
+		return;
+	}
+
+	if (gas_query_tx(gas, query, query->req) < 0) {
+		wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+			   MACSTR, MAC2STR(query->addr));
+		dl_list_del(&query->list);
+		wpabuf_free(query->req);
+		os_free(query);
+		return;
+	}
+	gas->current = query;
+
+	wpa_printf(MSG_DEBUG, "GAS: Starting query timeout for dialog token %u",
+		   query->dialog_token);
+	eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+			       gas_query_timeout, gas, query);
+}
+
+
 static int gas_query_dialog_token_available(struct gas_query *gas,
 					    const u8 *dst, u8 dialog_token)
 {
@@ -451,7 +536,8 @@
  * @gas: GAS query data from gas_query_init()
  * @dst: Destination MAC address for the query
  * @freq: Frequency (in MHz) for the channel on which to send the query
- * @req: GAS query payload
+ * @req: GAS query payload (to be freed by gas_query module in case of success
+ *	return)
  * @cb: Callback function for reporting GAS query result and response
  * @ctx: Context pointer to use with the @cb call
  * Returns: dialog token (>= 0) on success or -1 on failure
@@ -490,22 +576,15 @@
 	query->freq = freq;
 	query->cb = cb;
 	query->ctx = ctx;
+	query->req = req;
 	dl_list_add(&gas->pending, &query->list);
 
 	*(wpabuf_mhead_u8(req) + 2) = dialog_token;
 
 	wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR
 		   " dialog_token %u", MAC2STR(dst), dialog_token);
-	if (gas_query_tx(gas, query, req) < 0) {
-		wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
-			   MACSTR, MAC2STR(query->addr));
-		dl_list_del(&query->list);
-		os_free(query);
-		return -1;
-	}
 
-	eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout,
-			       gas, query);
+	eloop_register_timeout(0, 0, gas_service_timeout, gas, query);
 
 	return dialog_token;
 }
@@ -526,3 +605,9 @@
 		gas_query_done(gas, query, GAS_QUERY_CANCELLED);
 
 }
+
+
+int gas_query_in_progress(struct gas_query *gas)
+{
+	return gas->current != NULL;
+}
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index 5c3d161..6b6c77c 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -18,6 +18,7 @@
 void gas_query_deinit(struct gas_query *gas);
 int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
 		 const u8 *bssid, const u8 *data, size_t len, int freq);
+int gas_query_in_progress(struct gas_query *gas);
 
 /**
  * enum gas_query_result - GAS query result
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 4048cf7..5f30313 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -125,12 +125,12 @@
 	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		wpabuf_free(buf);
 		ret = -1;
 	} else
 		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
 			   "%u", res);
 
-	wpabuf_free(buf);
 	return ret;
 }
 
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 36f75a1..93652d8 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1,6 +1,6 @@
 /*
  * Interworking (IEEE 802.11u)
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -18,6 +18,8 @@
 #include "eap_common/eap_defs.h"
 #include "eap_peer/eap.h"
 #include "eap_peer/eap_methods.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
 #include "wpa_supplicant_i.h"
 #include "config.h"
 #include "config_ssid.h"
@@ -112,6 +114,8 @@
 	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
 		if (cred->roaming_consortium_len)
 			return 1;
+		if (cred->required_roaming_consortium_len)
+			return 1;
 	}
 	return 0;
 }
@@ -242,6 +246,7 @@
 			    interworking_anqp_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		wpabuf_free(buf);
 		ret = -1;
 		eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
 				       NULL);
@@ -249,7 +254,6 @@
 		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
 			   "%u", res);
 
-	wpabuf_free(buf);
 	return ret;
 }
 
@@ -747,6 +751,59 @@
 #endif /* INTERWORKING_3GPP */
 
 
+static int already_connected(struct wpa_supplicant *wpa_s,
+			     struct wpa_cred *cred, struct wpa_bss *bss)
+{
+	struct wpa_ssid *ssid;
+
+	if (wpa_s->wpa_state < WPA_ASSOCIATED || wpa_s->current_ssid == NULL)
+		return 0;
+
+	ssid = wpa_s->current_ssid;
+	if (ssid->parent_cred != cred)
+		return 0;
+
+	if (ssid->ssid_len != bss->ssid_len ||
+	    os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
+		return 0;
+
+	return 1;
+}
+
+
+static void remove_duplicate_network(struct wpa_supplicant *wpa_s,
+				     struct wpa_cred *cred,
+				     struct wpa_bss *bss)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (ssid->parent_cred != cred)
+			continue;
+		if (ssid->ssid_len != bss->ssid_len ||
+		    os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
+			continue;
+
+		break;
+	}
+
+	if (ssid == NULL)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Interworking: Remove duplicate network entry for the same credential");
+
+	if (ssid == wpa_s->current_ssid) {
+		wpa_sm_set_config(wpa_s->wpa, NULL);
+		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+	}
+
+	wpas_notify_network_removed(wpa_s, ssid);
+	wpa_config_remove_network(wpa_s->conf, ssid->id);
+}
+
+
 static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
 					struct wpa_ssid *ssid)
 {
@@ -768,7 +825,6 @@
 {
 #ifdef INTERWORKING_3GPP
 	struct wpa_ssid *ssid;
-	const u8 *ie;
 	int eap_type;
 	int res;
 	char prefix;
@@ -776,12 +832,17 @@
 	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
 		return -1;
 
-	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
-	if (ie == NULL)
-		return -1;
 	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
 		   MAC2STR(bss->bssid));
 
+	if (already_connected(wpa_s, cred, bss)) {
+		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+			MAC2STR(bss->bssid));
+		return 0;
+	}
+
+	remove_duplicate_network(wpa_s, cred, bss);
+
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL)
 		return -1;
@@ -791,11 +852,11 @@
 	wpa_config_set_network_defaults(ssid);
 	ssid->priority = cred->priority;
 	ssid->temporary = 1;
-	ssid->ssid = os_zalloc(ie[1] + 1);
+	ssid->ssid = os_zalloc(bss->ssid_len + 1);
 	if (ssid->ssid == NULL)
 		goto fail;
-	os_memcpy(ssid->ssid, ie + 2, ie[1]);
-	ssid->ssid_len = ie[1];
+	os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+	ssid->ssid_len = bss->ssid_len;
 
 	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
 		goto fail;
@@ -944,6 +1005,27 @@
 }
 
 
+static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
+{
+	const u8 *ie;
+
+	if (cred->required_roaming_consortium_len == 0)
+		return 0;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+
+	if (ie == NULL &&
+	    (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
+		return 1;
+
+	return !roaming_consortium_match(ie,
+					 bss->anqp ?
+					 bss->anqp->roaming_consortium : NULL,
+					 cred->required_roaming_consortium,
+					 cred->required_roaming_consortium_len);
+}
+
+
 static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
 {
 	size_t i;
@@ -991,6 +1073,8 @@
 
 		if (cred_excluded_ssid(cred, bss))
 			continue;
+		if (cred_no_required_oi_match(cred, bss))
+			continue;
 
 		if (selected == NULL ||
 		    selected->priority < cred->priority)
@@ -1100,19 +1184,32 @@
 	    wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
 		return -1;
 
+	if (cred->domain_suffix_match && cred->domain_suffix_match[0] &&
+	    wpa_config_set_quoted(ssid, "domain_suffix_match",
+				  cred->domain_suffix_match) < 0)
+		return -1;
+
 	return 0;
 }
 
 
 static int interworking_connect_roaming_consortium(
 	struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
-	struct wpa_bss *bss, const u8 *ssid_ie)
+	struct wpa_bss *bss)
 {
 	struct wpa_ssid *ssid;
 
 	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
 		   "roaming consortium match", MAC2STR(bss->bssid));
 
+	if (already_connected(wpa_s, cred, bss)) {
+		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+			MAC2STR(bss->bssid));
+		return 0;
+	}
+
+	remove_duplicate_network(wpa_s, cred, bss);
+
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL)
 		return -1;
@@ -1121,11 +1218,11 @@
 	wpa_config_set_network_defaults(ssid);
 	ssid->priority = cred->priority;
 	ssid->temporary = 1;
-	ssid->ssid = os_zalloc(ssid_ie[1] + 1);
+	ssid->ssid = os_zalloc(bss->ssid_len + 1);
 	if (ssid->ssid == NULL)
 		goto fail;
-	os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]);
-	ssid->ssid_len = ssid_ie[1];
+	os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+	ssid->ssid_len = bss->ssid_len;
 
 	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
 		goto fail;
@@ -1162,13 +1259,12 @@
 	struct nai_realm_eap *eap = NULL;
 	u16 count, i;
 	char buf[100];
-	const u8 *ie;
 
 	if (wpa_s->conf->cred == NULL || bss == NULL)
 		return -1;
-	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
-	if (ie == NULL || ie[1] == 0) {
-		wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
+	if (disallowed_bssid(wpa_s, bss->bssid) ||
+	    disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+		wpa_printf(MSG_DEBUG, "Interworking: Reject connection to disallowed BSS "
 			   MACSTR, MAC2STR(bss->bssid));
 		return -1;
 	}
@@ -1208,7 +1304,7 @@
 	    (cred == NULL || cred_rc->priority >= cred->priority) &&
 	    (cred_3gpp == NULL || cred_rc->priority >= cred_3gpp->priority))
 		return interworking_connect_roaming_consortium(wpa_s, cred_rc,
-							       bss, ie);
+							       bss);
 
 	if (cred_3gpp &&
 	    (cred == NULL || cred_3gpp->priority >= cred->priority)) {
@@ -1248,6 +1344,15 @@
 	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
 		   MAC2STR(bss->bssid));
 
+	if (already_connected(wpa_s, cred, bss)) {
+		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+			MAC2STR(bss->bssid));
+		nai_realm_free(realm, count);
+		return 0;
+	}
+
+	remove_duplicate_network(wpa_s, cred, bss);
+
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL) {
 		nai_realm_free(realm, count);
@@ -1258,11 +1363,11 @@
 	wpa_config_set_network_defaults(ssid);
 	ssid->priority = cred->priority;
 	ssid->temporary = 1;
-	ssid->ssid = os_zalloc(ie[1] + 1);
+	ssid->ssid = os_zalloc(bss->ssid_len + 1);
 	if (ssid->ssid == NULL)
 		goto fail;
-	os_memcpy(ssid->ssid, ie + 2, ie[1]);
-	ssid->ssid_len = ie[1];
+	os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+	ssid->ssid_len = bss->ssid_len;
 
 	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
 		goto fail;
@@ -1353,6 +1458,23 @@
 	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
 		return NULL;
 
+#ifdef CONFIG_EAP_PROXY
+	if (!wpa_s->imsi[0]) {
+		size_t len;
+		wpa_printf(MSG_DEBUG, "Interworking: IMSI not available - try to read again through eap_proxy");
+		wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol,
+							     wpa_s->imsi,
+							     &len);
+		if (wpa_s->mnc_len > 0) {
+			wpa_s->imsi[len] = '\0';
+			wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
+				   wpa_s->imsi, wpa_s->mnc_len);
+		} else {
+			wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+		}
+	}
+#endif /* CONFIG_EAP_PROXY */
+
 	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
 		char *sep;
 		const char *imsi;
@@ -1377,7 +1499,8 @@
 #endif /* CONFIG_EAP_PROXY */
 
 		if (cred->imsi == NULL || !cred->imsi[0] ||
-		    cred->milenage == NULL || !cred->milenage[0])
+		    (!wpa_s->conf->external_sim &&
+		     (cred->milenage == NULL || !cred->milenage[0])))
 			continue;
 
 		sep = os_strchr(cred->imsi, '-');
@@ -1404,6 +1527,8 @@
 		if (ret) {
 			if (cred_excluded_ssid(cred, bss))
 				continue;
+			if (cred_no_required_oi_match(cred, bss))
+				continue;
 			if (selected == NULL ||
 			    selected->priority < cred->priority)
 				selected = cred;
@@ -1446,6 +1571,8 @@
 			if (nai_realm_find_eap(cred, &realm[i])) {
 				if (cred_excluded_ssid(cred, bss))
 					continue;
+				if (cred_no_required_oi_match(cred, bss))
+					continue;
 				if (selected == NULL ||
 				    selected->priority < cred->priority)
 					selected = cred;
@@ -1465,6 +1592,13 @@
 {
 	struct wpa_cred *cred, *cred2;
 
+	if (disallowed_bssid(wpa_s, bss->bssid) ||
+	    disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+		wpa_printf(MSG_DEBUG, "Interworking: Ignore disallowed BSS "
+			   MACSTR, MAC2STR(bss->bssid));
+		return NULL;
+	}
+
 	cred = interworking_credentials_available_realm(wpa_s, bss);
 	cred2 = interworking_credentials_available_3gpp(wpa_s, bss);
 	if (cred && cred2 && cred2->priority >= cred->priority)
@@ -1514,6 +1648,8 @@
 			      struct wpa_cred *cred,
 			      struct wpabuf *domain_names)
 {
+	size_t i;
+	int ret = -1;
 #ifdef INTERWORKING_3GPP
 	char nai[100], *realm;
 
@@ -1528,6 +1664,12 @@
 		mnc_len = wpa_s->mnc_len;
 	}
 #endif /* CONFIG_PCSC */
+#ifdef CONFIG_EAP_PROXY
+	else if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
+		imsi = wpa_s->imsi;
+		mnc_len = wpa_s->mnc_len;
+	}
+#endif /* CONFIG_EAP_PROXY */
 	if (domain_names &&
 	    imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
 		realm = os_strchr(nai, '@');
@@ -1538,16 +1680,20 @@
 		if (realm &&
 		    domain_name_list_contains(domain_names, realm))
 			return 1;
+		if (realm)
+			ret = 0;
 	}
 #endif /* INTERWORKING_3GPP */
 
 	if (domain_names == NULL || cred->domain == NULL)
-		return 0;
+		return ret;
 
-	wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
-		   "home SP FQDN %s", cred->domain);
-	if (domain_name_list_contains(domain_names, cred->domain))
-		return 1;
+	for (i = 0; i < cred->num_domain; i++) {
+		wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
+			   "home SP FQDN %s", cred->domain[i]);
+		if (domain_name_list_contains(domain_names, cred->domain[i]))
+			return 1;
+	}
 
 	return 0;
 }
@@ -1739,6 +1885,9 @@
 		ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
 		if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
 			continue; /* AP does not support Interworking */
+		if (disallowed_bssid(wpa_s, bss->bssid) ||
+		    disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len))
+			continue; /* Disallowed BSS */
 
 		if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
 			if (bss->anqp == NULL) {
@@ -1833,12 +1982,12 @@
 	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		wpabuf_free(buf);
 		ret = -1;
 	} else
 		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
 			   "%u", res);
 
-	wpabuf_free(buf);
 	return ret;
 }
 
@@ -2055,7 +2204,10 @@
 	wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
 		   "selection");
 	wpa_s->scan_res_handler = interworking_scan_res_handler;
+	wpa_s->normal_scans = 0;
 	wpa_s->scan_req = MANUAL_SCAN_REQ;
+	wpa_s->after_wps = 0;
+	wpa_s->known_wps_freq = 0;
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
 
 	return 0;
@@ -2133,11 +2285,11 @@
 	res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
+		wpabuf_free(buf);
 		ret = -1;
 	} else
 		wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
 			   "%u", res);
 
-	wpabuf_free(buf);
 	return ret;
 }
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index ab62bea..a82fbf3 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -96,7 +96,7 @@
 		     MAC2STR(wpa_s->bssid),
 		     wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
 		     wpa_ssid_txt(wpa_s->current_ssid->ssid,
-		     wpa_s->current_ssid->ssid_len): "");
+				  wpa_s->current_ssid->ssid_len) : "");
 #endif /* ANDROID */
 }
 
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index d94407c..40cbea1 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -159,6 +159,21 @@
 		return;
 	}
 
+	/* Accept report only if the contents of the frame matches */
+	if (data_len - wpabuf_len(wpa_s->pending_action_tx) != 24 ||
+	    os_memcmp(data + 24, wpabuf_head(wpa_s->pending_action_tx),
+		      wpabuf_len(wpa_s->pending_action_tx)) != 0) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
+				   "mismatching contents with pending frame");
+		wpa_hexdump(MSG_MSGDUMP, "TX status frame data",
+			    data, data_len);
+		wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+				wpa_s->pending_action_tx);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "Off-channel: Delete matching pending action frame");
+
 	wpabuf_free(wpa_s->pending_action_tx);
 	wpa_s->pending_action_tx = NULL;
 
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index d7b3189..40fbffb 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -48,11 +48,7 @@
  * How many seconds to try to reconnect to the GO when connection in P2P client
  * role has been lost.
  */
-#ifdef ANDROID_P2P
-#define P2P_MAX_CLIENT_IDLE 20
-#else
 #define P2P_MAX_CLIENT_IDLE 10
-#endif /* ANDROID_P2P */
 #endif /* P2P_MAX_CLIENT_IDLE */
 
 #ifndef P2P_MAX_INITIAL_CONN_WAIT
@@ -73,6 +69,15 @@
 #define P2P_MAX_INITIAL_CONN_WAIT_GO 10
 #endif /* P2P_MAX_INITIAL_CONN_WAIT_GO */
 
+#ifndef P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * re-invocation of a persistent group on the GO when the client is expected
+ * to connect automatically (no user interaction).
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE 15
+#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE */
+
 #ifndef P2P_CONCURRENT_SEARCH_DELAY
 #define P2P_CONCURRENT_SEARCH_DELAY 500
 #endif /* P2P_CONCURRENT_SEARCH_DELAY */
@@ -125,7 +130,7 @@
 static int wpas_p2p_num_unused_channels(struct wpa_supplicant *wpa_s)
 {
 	int *freqs;
-	int num;
+	int num, unused;
 
 	freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
 	if (!freqs)
@@ -135,7 +140,9 @@
 				     wpa_s->num_multichan_concurrent);
 	os_free(freqs);
 
-	return wpa_s->num_multichan_concurrent - num;
+	unused = wpa_s->num_multichan_concurrent - num;
+	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: num_unused_channels: %d", unused);
+	return unused;
 }
 
 
@@ -165,6 +172,8 @@
 
 	os_free(freqs);
 
+	dump_freq_array(wpa_s, "valid for P2P", p2p_freqs, j);
+
 	return j;
 }
 
@@ -174,10 +183,13 @@
 {
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
-	if (freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
-	    wpas_p2p_num_unused_channels(wpa_s) > 0 &&
-	    wpa_s->parent->conf->p2p_ignore_shared_freq)
+	if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
+	    freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
+	    wpas_p2p_num_unused_channels(wpa_s) > 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz due to p2p_ignore_shared_freq=1 configuration",
+			   freq);
 		freq = 0;
+	}
 	p2p_set_own_freq_preference(wpa_s->global->p2p, freq);
 }
 
@@ -196,13 +208,28 @@
 	for (i = 0; i < scan_res->num; i++) {
 		struct wpa_scan_res *bss = scan_res->res[i];
 		struct os_time time_tmp_age, entry_ts;
+		const u8 *ies;
+		size_t ies_len;
+
 		time_tmp_age.sec = bss->age / 1000;
 		time_tmp_age.usec = (bss->age % 1000) * 1000;
 		os_time_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts);
+
+		ies = (const u8 *) (bss + 1);
+		ies_len = bss->ie_len;
+		if (bss->beacon_ie_len > 0 &&
+		    !wpa_scan_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+		    wpa_scan_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+			wpa_printf(MSG_DEBUG, "P2P: Use P2P IE(s) from Beacon frame since no P2P IE(s) in Probe Response frames received for "
+				   MACSTR, MAC2STR(bss->bssid));
+			ies = ies + ies_len;
+			ies_len = bss->beacon_ie_len;
+		}
+
+
 		if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
 					 bss->freq, &entry_ts, bss->level,
-					 (const u8 *) (bss + 1),
-					 bss->ie_len) > 0)
+					 ies, ies_len) > 0)
 			break;
 	}
 
@@ -432,6 +459,12 @@
 		wpa_s->p2p_in_provisioning = 0;
 	}
 
+	/*
+	 * Make sure wait for the first client does not remain active after the
+	 * group has been removed.
+	 */
+	wpa_s->global->p2p_go_wait_client.sec = 0;
+
 	if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
 		wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
 
@@ -452,6 +485,15 @@
 		return 1;
 	}
 
+	if (!wpa_s->p2p_go_group_formation_completed) {
+		wpa_s->global->p2p_group_formation = NULL;
+		wpa_s->p2p_in_provisioning = 0;
+	}
+
+	wpa_s->show_group_started = 0;
+	os_free(wpa_s->go_params);
+	wpa_s->go_params = NULL;
+
 	wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
 	if (ssid && (ssid->p2p_group ||
 		     ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
@@ -518,6 +560,9 @@
 	}
 
 	p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+	if (p2p == NULL)
+		p2p = wpa_bss_get_vendor_ie_multi_beacon(bss,
+							 P2P_IE_VENDOR_TYPE);
 	if (p2p == NULL) {
 		wpa_printf(MSG_DEBUG, "P2P: Could not figure out whether "
 			   "group is persistent - BSS " MACSTR
@@ -728,8 +773,10 @@
 	 */
 	if (wpa_s->global->p2p_group_formation)
 		wpa_s = wpa_s->global->p2p_group_formation;
-	wpa_s->global->p2p_group_formation = NULL;
-	wpa_s->p2p_in_provisioning = 0;
+	if (wpa_s->p2p_go_group_formation_completed) {
+		wpa_s->global->p2p_group_formation = NULL;
+		wpa_s->p2p_in_provisioning = 0;
+	}
 
 	if (!success) {
 		wpa_msg_global(wpa_s->parent, MSG_INFO,
@@ -777,13 +824,6 @@
 		 * packets.
 		 */
 		wpa_s->show_group_started = 1;
-#ifdef ANDROID_P2P
-		/* For client Second phase of Group formation (4-way handshake) can be still pending
-		 * So we need to restore wpa_s->global->p2p_group_formation */
-		wpa_printf(MSG_INFO, "Restoring back wpa_s->global->p2p_group_formation to wpa_s %p\n", wpa_s);
-		wpa_s->global->p2p_group_formation = wpa_s;
-#endif
-
 	} else if (ssid && ssid->passphrase == NULL && ssid->psk_set) {
 		char psk[65];
 		wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
@@ -996,6 +1036,7 @@
 				       " [PERSISTENT]" : "");
 		}
 
+		os_get_time(&wpa_s->global->p2p_go_wait_client);
 		if (params->persistent_group) {
 			network_id = wpas_p2p_store_persistent_group(
 				wpa_s->parent, ssid,
@@ -1007,6 +1048,21 @@
 		wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
 		wpas_p2p_cross_connect_setup(wpa_s);
 		wpas_p2p_set_group_idle_timeout(wpa_s);
+
+		if (wpa_s->p2p_first_connection_timeout) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"P2P: Start group formation timeout of %d seconds until first data connection on GO",
+				wpa_s->p2p_first_connection_timeout);
+			wpa_s->p2p_go_group_formation_completed = 0;
+			wpa_s->global->p2p_group_formation = wpa_s;
+			eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+					     wpa_s->parent, NULL);
+			eloop_register_timeout(
+				wpa_s->p2p_first_connection_timeout, 0,
+				wpas_p2p_group_formation_timeout,
+				wpa_s->parent, NULL);
+		}
+
 		return;
 	}
 
@@ -1057,6 +1113,7 @@
 		WPAS_MODE_P2P_GO;
 	ssid->frequency = params->freq;
 	ssid->ht40 = params->ht40;
+	ssid->vht = params->vht;
 	ssid->ssid = os_zalloc(params->ssid_len + 1);
 	if (ssid->ssid) {
 		os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -1126,6 +1183,7 @@
 	d->ignore_old_scan_res = s->ignore_old_scan_res;
 	d->beacon_int = s->beacon_int;
 	d->disassoc_low_ack = s->disassoc_low_ack;
+	d->disable_scan_offload = s->disable_scan_offload;
 }
 
 
@@ -1143,8 +1201,7 @@
 	if (os_strlen(ifname) >= IFNAMSIZ &&
 	    os_strlen(wpa_s->ifname) < IFNAMSIZ) {
 		/* Try to avoid going over the IFNAMSIZ length limit */
-		os_snprintf(ifname, sizeof(ifname), "p2p-%d",
-			    wpa_s->p2p_group_idx);
+		os_snprintf(ifname, len, "p2p-%d", wpa_s->p2p_group_idx);
 	}
 }
 
@@ -1316,6 +1373,8 @@
 
 	if (wpa_s->p2p_go_ht40)
 		res->ht40 = 1;
+	if (wpa_s->p2p_go_vht)
+		res->vht = 1;
 
 	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s "
 		       "freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR
@@ -2656,9 +2715,14 @@
 
 	/* Get one of the frequencies currently in use */
 	if (wpas_p2p_valid_oper_freqs(wpa_s, &res, 1) > 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match a channel already used by one of the interfaces");
-		*force_freq = res;
+		wpa_printf(MSG_DEBUG, "P2P: Trying to prefer a channel already used by one of the interfaces");
 		wpas_p2p_set_own_freq_preference(wpa_s, res);
+
+		if (wpa_s->num_multichan_concurrent < 2 ||
+		    wpas_p2p_num_unused_channels(wpa_s) < 1) {
+			wpa_printf(MSG_DEBUG, "P2P: No extra channels available - trying to force channel to match a channel already used by one of the interfaces");
+			*force_freq = res;
+		}
 	}
 
 	if (*force_freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
@@ -2706,7 +2770,8 @@
 		if (s) {
 			int go = s->mode == WPAS_MODE_P2P_GO;
 			wpas_p2p_group_add_persistent(
-				wpa_s, s, go, go ? op_freq : 0, 0, NULL);
+				wpa_s, s, go, go ? op_freq : 0, 0, 0, NULL,
+				go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0);
 		} else if (bssid) {
 			wpa_s->user_initiated_pd = 0;
 			wpas_p2p_join(wpa_s, bssid, go_dev_addr,
@@ -2813,10 +2878,11 @@
 
 static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
 				   const struct p2p_channels *channels,
-				   const u8 *peer)
+				   const u8 *peer, int neg_freq)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *ssid;
+	int freq;
 
 	if (bssid) {
 		wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
@@ -2878,28 +2944,29 @@
 	os_sleep(0, 100000);
 #endif
 
+	freq = wpa_s->p2p_persistent_go_freq;
+	if (neg_freq > 0 && ssid->mode == WPAS_MODE_P2P_GO &&
+	    freq_included(channels, neg_freq)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use frequence %d MHz from invitation for GO mode",
+			neg_freq);
+		freq = neg_freq;
+	}
+
 	wpas_p2p_group_add_persistent(wpa_s, ssid,
 				      ssid->mode == WPAS_MODE_P2P_GO,
-				      wpa_s->p2p_persistent_go_freq,
-				      wpa_s->p2p_go_ht40, channels);
+				      freq,
+				      wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
+				      channels,
+				      ssid->mode == WPAS_MODE_P2P_GO ?
+				      P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
+				      0);
 }
 
 
 static int wpas_p2p_disallowed_freq(struct wpa_global *global,
 				    unsigned int freq)
 {
-	unsigned int i;
-
-	if (global->p2p_disallow_freq == NULL)
-		return 0;
-
-	for (i = 0; i < global->num_p2p_disallow_freq; i++) {
-		if (freq >= global->p2p_disallow_freq[i].min &&
-		    freq <= global->p2p_disallow_freq[i].max)
-			return 1;
-	}
-
-	return 0;
+	return freq_range_list_includes(&global->p2p_disallow_freq, freq);
 }
 
 
@@ -2911,10 +2978,13 @@
 
 
 static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
-				     struct p2p_channels *chan)
+				     struct p2p_channels *chan,
+				     struct p2p_channels *cli_chan)
 {
 	int i, cla = 0;
 
+	os_memset(cli_chan, 0, sizeof(*cli_chan));
+
 	wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
 		   "band");
 
@@ -2982,6 +3052,10 @@
 }
 
 
+enum chan_allowed {
+	NOT_ALLOWED, PASSIVE_ONLY, ALLOWED
+};
+
 static int has_channel(struct wpa_global *global,
 		       struct hostapd_hw_modes *mode, u8 chan, int *flags)
 {
@@ -2991,21 +3065,25 @@
 	freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
 		chan * 5;
 	if (wpas_p2p_disallowed_freq(global, freq))
-		return 0;
+		return NOT_ALLOWED;
 
 	for (i = 0; i < mode->num_channels; i++) {
 		if (mode->channels[i].chan == chan) {
 			if (flags)
 				*flags = mode->channels[i].flag;
-			return !(mode->channels[i].flag &
-				 (HOSTAPD_CHAN_DISABLED |
-				  HOSTAPD_CHAN_PASSIVE_SCAN |
-				  HOSTAPD_CHAN_NO_IBSS |
-				  HOSTAPD_CHAN_RADAR));
+			if (mode->channels[i].flag &
+			    (HOSTAPD_CHAN_DISABLED |
+			     HOSTAPD_CHAN_RADAR))
+				return NOT_ALLOWED;
+			if (mode->channels[i].flag &
+			    (HOSTAPD_CHAN_PASSIVE_SCAN |
+			     HOSTAPD_CHAN_NO_IBSS))
+				return PASSIVE_ONLY;
+			return ALLOWED;
 		}
 	}
 
-	return 0;
+	return NOT_ALLOWED;
 }
 
 
@@ -3015,7 +3093,7 @@
 	u8 min_chan;
 	u8 max_chan;
 	u8 inc;
-	enum { BW20, BW40PLUS, BW40MINUS } bw;
+	enum { BW20, BW40PLUS, BW40MINUS, BW80 } bw;
 };
 
 static struct p2p_oper_class_map op_class[] = {
@@ -3030,73 +3108,171 @@
 	{ HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
 	{ HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
 	{ HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
+
+	/*
+	 * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center
+	 * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of
+	 * 80 MHz, but currently use the following definition for simplicity
+	 * (these center frequencies are not actual channels, which makes
+	 * has_channel() fail). wpas_p2p_verify_80mhz() should take care of
+	 * removing invalid channels.
+	 */
+	{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 },
 	{ -1, 0, 0, 0, 0, BW20 }
 };
 
 
-static int wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
-				   struct hostapd_hw_modes *mode,
-				   u8 channel, u8 bw)
+static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
+				     struct hostapd_hw_modes *mode,
+				     u8 channel)
+{
+	u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
+	unsigned int i;
+
+	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(center_channels); i++)
+		/*
+		 * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
+		 * so the center channel is 6 channels away from the start/end.
+		 */
+		if (channel >= center_channels[i] - 6 &&
+		    channel <= center_channels[i] + 6)
+			return center_channels[i];
+
+	return 0;
+}
+
+
+static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
+					       struct hostapd_hw_modes *mode,
+					       u8 channel, u8 bw)
+{
+	u8 center_chan;
+	int i, flags;
+	enum chan_allowed res, ret = ALLOWED;
+
+	center_chan = wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+	if (!center_chan)
+		return NOT_ALLOWED;
+	if (center_chan >= 58 && center_chan <= 138)
+		return NOT_ALLOWED; /* Do not allow DFS channels for P2P */
+
+	/* check all the channels are available */
+	for (i = 0; i < 4; i++) {
+		int adj_chan = center_chan - 6 + i * 4;
+
+		res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+		if (res == NOT_ALLOWED)
+			return NOT_ALLOWED;
+		if (res == PASSIVE_ONLY)
+			ret = PASSIVE_ONLY;
+
+		if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70))
+			return NOT_ALLOWED;
+		if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50))
+			return NOT_ALLOWED;
+		if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30))
+			return NOT_ALLOWED;
+		if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10))
+			return NOT_ALLOWED;
+	}
+
+	return ret;
+}
+
+
+static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
+						 struct hostapd_hw_modes *mode,
+						 u8 channel, u8 bw)
 {
 	int flag;
+	enum chan_allowed res, res2;
 
-	if (!has_channel(wpa_s->global, mode, channel, &flag))
-		return -1;
-	if (bw == BW40MINUS &&
-	    (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
-	     !has_channel(wpa_s->global, mode, channel - 4, NULL)))
-		return 0;
-	if (bw == BW40PLUS &&
-	    (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
-	     !has_channel(wpa_s->global, mode, channel + 4, NULL)))
-		return 0;
-	return 1;
+	res2 = res = has_channel(wpa_s->global, mode, channel, &flag);
+	if (bw == BW40MINUS) {
+		if (!(flag & HOSTAPD_CHAN_HT40MINUS))
+			return NOT_ALLOWED;
+		res2 = has_channel(wpa_s->global, mode, channel - 4, NULL);
+	} else if (bw == BW40PLUS) {
+		if (!(flag & HOSTAPD_CHAN_HT40PLUS))
+			return NOT_ALLOWED;
+		res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
+	} else if (bw == BW80) {
+		res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
+	}
+
+	if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
+		return NOT_ALLOWED;
+	if (res == PASSIVE_ONLY || res2 == PASSIVE_ONLY)
+		return PASSIVE_ONLY;
+	return res;
 }
 
 
 static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
-				   struct p2p_channels *chan)
+				   struct p2p_channels *chan,
+				   struct p2p_channels *cli_chan)
 {
 	struct hostapd_hw_modes *mode;
-	int cla, op;
+	int cla, op, cli_cla;
 
 	if (wpa_s->hw.modes == NULL) {
 		wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
 			   "of all supported channels; assume dualband "
 			   "support");
-		return wpas_p2p_default_channels(wpa_s, chan);
+		return wpas_p2p_default_channels(wpa_s, chan, cli_chan);
 	}
 
-	cla = 0;
+	cla = cli_cla = 0;
 
 	for (op = 0; op_class[op].op_class; op++) {
 		struct p2p_oper_class_map *o = &op_class[op];
 		u8 ch;
-		struct p2p_reg_class *reg = NULL;
+		struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
 
 		mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
 		if (mode == NULL)
 			continue;
 		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
-			if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1)
-				continue;
-			if (reg == NULL) {
-				wpa_printf(MSG_DEBUG, "P2P: Add operating "
-					   "class %u", o->op_class);
-				reg = &chan->reg_class[cla];
-				cla++;
-				reg->reg_class = o->op_class;
+			enum chan_allowed res;
+			res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+			if (res == ALLOWED) {
+				if (reg == NULL) {
+					wpa_printf(MSG_DEBUG, "P2P: Add operating class %u",
+						   o->op_class);
+					reg = &chan->reg_class[cla];
+					cla++;
+					reg->reg_class = o->op_class;
+				}
+				reg->channel[reg->channels] = ch;
+				reg->channels++;
+			} else if (res == PASSIVE_ONLY &&
+				   wpa_s->conf->p2p_add_cli_chan) {
+				if (cli_reg == NULL) {
+					wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
+						   o->op_class);
+					cli_reg = &cli_chan->reg_class[cli_cla];
+					cli_cla++;
+					cli_reg->reg_class = o->op_class;
+				}
+				cli_reg->channel[cli_reg->channels] = ch;
+				cli_reg->channels++;
 			}
-			reg->channel[reg->channels] = ch;
-			reg->channels++;
 		}
 		if (reg) {
 			wpa_hexdump(MSG_DEBUG, "P2P: Channels",
 				    reg->channel, reg->channels);
 		}
+		if (cli_reg) {
+			wpa_hexdump(MSG_DEBUG, "P2P: Channels (client only)",
+				    cli_reg->channel, cli_reg->channels);
+		}
 	}
 
 	chan->reg_classes = cla;
+	cli_chan->reg_classes = cli_cla;
 
 	return 0;
 }
@@ -3105,7 +3281,8 @@
 int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
 			   struct hostapd_hw_modes *mode, u8 channel)
 {
-	int op, ret;
+	int op;
+	enum chan_allowed ret;
 
 	for (op = 0; op_class[op].op_class; op++) {
 		struct p2p_oper_class_map *o = &op_class[op];
@@ -3116,18 +3293,24 @@
 			    o->bw == BW20 || ch != channel)
 				continue;
 			ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
-			if (ret < 0)
-				continue;
-			else if (ret > 0)
+			if (ret == ALLOWED)
 				return (o->bw == BW40MINUS) ? -1 : 1;
-			else
-				return 0;
 		}
 	}
 	return 0;
 }
 
 
+int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
+			      struct hostapd_hw_modes *mode, u8 channel)
+{
+	if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW80))
+		return 0;
+
+	return wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+}
+
+
 static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
 			size_t buf_len)
 {
@@ -3335,7 +3518,7 @@
 	} else
 		os_memcpy(p2p.country, "XX\x04", 3);
 
-	if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)) {
+	if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
 		wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
 			   "channel list");
 		return -1;
@@ -3378,6 +3561,8 @@
 			global->p2p, wpa_s->conf->wps_vendor_ext[i]);
 	}
 
+	p2p_set_no_go_freq(global->p2p, &wpa_s->conf->p2p_no_go_freq);
+
 	return 0;
 }
 
@@ -3695,7 +3880,8 @@
 					 wpa_s->p2p_connect_freq,
 					 wpa_s->p2p_persistent_id,
 					 wpa_s->p2p_pd_before_go_neg,
-					 wpa_s->p2p_go_ht40);
+					 wpa_s->p2p_go_ht40,
+					 wpa_s->p2p_go_vht);
 			return;
 		}
 
@@ -3733,7 +3919,8 @@
 	if (bss) {
 		freq = bss->freq;
 		wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
-			   "from BSS table: %d MHz", freq);
+			   "from BSS table: %d MHz (SSID %s)", freq,
+			   wpa_ssid_txt(bss->ssid, bss->ssid_len));
 	}
 	if (freq > 0) {
 		u16 method;
@@ -3948,6 +4135,9 @@
 		res.freq = bss->freq;
 		res.ssid_len = bss->ssid_len;
 		os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+		wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency "
+			   "from BSS table: %d MHz (SSID %s)", bss->freq,
+			   wpa_ssid_txt(bss->ssid, bss->ssid_len));
 	}
 
 	if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
@@ -3973,7 +4163,7 @@
 
 
 static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
-				int *force_freq, int *pref_freq)
+				int *force_freq, int *pref_freq, int go)
 {
 	int *freqs, res;
 	unsigned int freq_in_use = 0, num, i;
@@ -3989,7 +4179,12 @@
 		   freq, wpa_s->num_multichan_concurrent, num);
 
 	if (freq > 0) {
-		if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+		int ret;
+		if (go)
+			ret = p2p_supported_freq(wpa_s->global->p2p, freq);
+		else
+			ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq);
+		if (!ret) {
 			wpa_printf(MSG_DEBUG, "P2P: The forced channel "
 				   "(%u MHz) is not supported for P2P uses",
 				   freq);
@@ -4018,29 +4213,25 @@
 		if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
 			continue;
 
-#ifndef ANDROID_P2P
-		wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use",
-			   *force_freq);
-		*force_freq = freqs[i];
-#endif
-
 		if (*pref_freq == 0 && num < wpa_s->num_multichan_concurrent) {
-			wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency we are already using");
+			wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency (%u MHz) we are already using",
+				   freqs[i]);
 			*pref_freq = freqs[i];
-#ifdef ANDROID_P2P
 		} else {
 			wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use",
-				   *force_freq);
+				   freqs[i]);
 			*force_freq = freqs[i];
-#endif
 		}
 		break;
 	}
 
 	if (i == num) {
-		if (num < wpa_s->num_multichan_concurrent) {
+		if (num < wpa_s->num_multichan_concurrent && num > 0) {
 			wpa_printf(MSG_DEBUG, "P2P: Current operating channels are not available for P2P. Try to use another channel");
 			*force_freq = 0;
+		} else if (num < wpa_s->num_multichan_concurrent) {
+			wpa_printf(MSG_DEBUG, "P2P: No current operating channels - try to use a new channel");
+			*force_freq = 0;
 		} else {
 			wpa_printf(MSG_DEBUG, "P2P: All channels are in use and none of them are P2P enabled. Cannot start P2P group");
 			res = -2;
@@ -4074,6 +4265,7 @@
  * @pd: Whether to send Provision Discovery prior to GO Negotiation as an
  *	interoperability workaround when initiating group formation
  * @ht40: Start GO with 40 MHz channel width
+ * @vht:  Start GO with VHT support
  * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
  *	failure, -2 on failure due to channel not currently available,
  *	-3 if forced channel is not supported
@@ -4082,7 +4274,7 @@
 		     const char *pin, enum p2p_wps_method wps_method,
 		     int persistent_group, int auto_join, int join, int auth,
 		     int go_intent, int freq, int persistent_id, int pd,
-		     int ht40)
+		     int ht40, int vht)
 {
 	int force_freq = 0, pref_freq = 0;
 	int ret = 0, res;
@@ -4117,6 +4309,7 @@
 	wpa_s->p2p_fallback_to_go_neg = 0;
 	wpa_s->p2p_pd_before_go_neg = !!pd;
 	wpa_s->p2p_go_ht40 = !!ht40;
+	wpa_s->p2p_go_vht = !!vht;
 
 	if (pin)
 		os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -4159,10 +4352,12 @@
 		return ret;
 	}
 
-	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
+	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+				   go_intent == 15);
 	if (res)
 		return res;
-	wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
+	wpas_p2p_set_own_freq_preference(wpa_s,
+					 force_freq ? force_freq : pref_freq);
 
 	wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
 
@@ -4322,8 +4517,8 @@
 		wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
 			   "band");
 		if (wpa_s->best_24_freq > 0 &&
-		    p2p_supported_freq(wpa_s->global->p2p,
-				       wpa_s->best_24_freq)) {
+		    p2p_supported_freq_go(wpa_s->global->p2p,
+					  wpa_s->best_24_freq)) {
 			freq = wpa_s->best_24_freq;
 			wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
 				   "channel: %d MHz", freq);
@@ -4339,7 +4534,7 @@
 		wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
 			   "band");
 		if (wpa_s->best_5_freq > 0 &&
-		    p2p_supported_freq(wpa_s->global->p2p,
+		    p2p_supported_freq_go(wpa_s->global->p2p,
 				       wpa_s->best_5_freq)) {
 			freq = wpa_s->best_5_freq;
 			wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
@@ -4347,7 +4542,7 @@
 		} else {
 			os_get_random((u8 *) &r, sizeof(r));
 			freq = 5180 + (r % 4) * 20;
-			if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+			if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
 				wpa_printf(MSG_DEBUG, "P2P: Could not select "
 					   "5 GHz channel for P2P group");
 				return -1;
@@ -4357,7 +4552,7 @@
 		}
 	}
 
-	if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
+	if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
 		wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
 			   "(%u MHz) is not supported for P2P uses",
 			   freq);
@@ -4370,7 +4565,7 @@
 
 static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
 				   struct p2p_go_neg_results *params,
-				   int freq, int ht40,
+				   int freq, int ht40, int vht,
 				   const struct p2p_channels *channels)
 {
 	int res, *freqs;
@@ -4380,6 +4575,7 @@
 	os_memset(params, 0, sizeof(*params));
 	params->role_go = 1;
 	params->ht40 = ht40;
+	params->vht = vht;
 	if (freq) {
 		if (!freq_included(channels, freq)) {
 			wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
@@ -4410,24 +4606,24 @@
 			   "frequency %d MHz", params->freq);
 	} else if (wpa_s->conf->p2p_oper_channel == 0 &&
 		   wpa_s->best_overall_freq > 0 &&
-		   p2p_supported_freq(wpa_s->global->p2p,
-				      wpa_s->best_overall_freq) &&
+		   p2p_supported_freq_go(wpa_s->global->p2p,
+					 wpa_s->best_overall_freq) &&
 		   freq_included(channels, wpa_s->best_overall_freq)) {
 		params->freq = wpa_s->best_overall_freq;
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
 			   "channel %d MHz", params->freq);
 	} else if (wpa_s->conf->p2p_oper_channel == 0 &&
 		   wpa_s->best_24_freq > 0 &&
-		   p2p_supported_freq(wpa_s->global->p2p,
-				      wpa_s->best_24_freq) &&
+		   p2p_supported_freq_go(wpa_s->global->p2p,
+					 wpa_s->best_24_freq) &&
 		   freq_included(channels, wpa_s->best_24_freq)) {
 		params->freq = wpa_s->best_24_freq;
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
 			   "channel %d MHz", params->freq);
 	} else if (wpa_s->conf->p2p_oper_channel == 0 &&
 		   wpa_s->best_5_freq > 0 &&
-		   p2p_supported_freq(wpa_s->global->p2p,
-				      wpa_s->best_5_freq) &&
+		   p2p_supported_freq_go(wpa_s->global->p2p,
+					 wpa_s->best_5_freq) &&
 		   freq_included(channels, wpa_s->best_5_freq)) {
 		params->freq = wpa_s->best_5_freq;
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
@@ -4467,41 +4663,32 @@
 	}
 	num = res;
 
-	if (!freq) {
-		for (i = 0; i < num; i++) {
-			if (freq_included(channels, freqs[i])) {
-				wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
-					   freqs[i]);
-				params->freq = freqs[i];
-				break;
-			}
-		}
-
-		if (i == num) {
-			if (num == wpa_s->num_multichan_concurrent) {
-				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
-				os_free(freqs);
-				return -1;
-			} else {
-				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
-			}
-		}
-	} else {
-		for (i = 0; i < num; i++) {
-			if (freqs[i] == freq)
-				break;
-		}
-
-		if (i == num) {
-			if (num == wpa_s->num_multichan_concurrent) {
-				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
-				os_free(freqs);
-				return -1;
-			} else {
-				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
-			}
+	for (i = 0; i < num; i++) {
+		if (freq && freqs[i] == freq)
+			break;
+		if (!freq && freq_included(channels, freqs[i])) {
+			wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
+				   freqs[i]);
+			params->freq = freqs[i];
+			break;
 		}
 	}
+
+	if (i == num) {
+		if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+			if (freq)
+				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
+			else
+				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
+			os_free(freqs);
+			return -1;
+		} else if (num == 0) {
+			wpa_printf(MSG_DEBUG, "P2P: Use one of the free channels");
+		} else {
+			wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
+		}
+	}
+
 	os_free(freqs);
 	return 0;
 }
@@ -4516,6 +4703,7 @@
 	if (!wpas_p2p_create_iface(wpa_s)) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
 			"operations");
+		wpa_s->p2p_first_connection_timeout = 0;
 		return wpa_s;
 	}
 
@@ -4535,6 +4723,7 @@
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
 		group_wpa_s->ifname);
+	group_wpa_s->p2p_first_connection_timeout = 0;
 	return group_wpa_s;
 }
 
@@ -4544,13 +4733,15 @@
  * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
  * @persistent_group: Whether to create a persistent group
  * @freq: Frequency for the group or 0 to indicate no hardcoding
+ * @ht40: Start GO with 40 MHz channel width
+ * @vht:  Start GO with VHT support
  * Returns: 0 on success, -1 on failure
  *
  * This function creates a new P2P group with the local end as the Group Owner,
  * i.e., without using Group Owner Negotiation.
  */
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
-		       int freq, int ht40)
+		       int freq, int ht40, int vht)
 {
 	struct p2p_go_neg_results params;
 
@@ -4568,10 +4759,10 @@
 	if (freq < 0)
 		return -1;
 
-	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, NULL))
+	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, NULL))
 		return -1;
 	if (params.freq &&
-	    !p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
+	    !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) {
 		wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
 			   "(%u MHz) is not supported for P2P uses",
 			   params.freq);
@@ -4626,18 +4817,19 @@
 	if (params->passphrase)
 		ssid->passphrase = os_strdup(params->passphrase);
 
-	wpa_supplicant_select_network(wpa_s, ssid);
-
 	wpa_s->show_group_started = 1;
 
+	wpa_supplicant_select_network(wpa_s, ssid);
+
 	return 0;
 }
 
 
 int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid, int addr_allocated,
-				  int freq, int ht40,
-				  const struct p2p_channels *channels)
+				  int freq, int ht40, int vht,
+				  const struct p2p_channels *channels,
+				  int connection_timeout)
 {
 	struct p2p_go_neg_results params;
 	int go = 0;
@@ -4670,7 +4862,7 @@
 	if (freq < 0)
 		return -1;
 
-	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, channels))
+	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, channels))
 		return -1;
 
 	params.role_go = 1;
@@ -4694,6 +4886,7 @@
 	if (wpa_s == NULL)
 		return -1;
 
+	wpa_s->p2p_first_connection_timeout = connection_timeout;
 	wpas_start_wps_go(wpa_s, &params, 0);
 
 	return 0;
@@ -4801,6 +4994,7 @@
 
 	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
 			     NULL);
+	wpa_s->p2p_go_group_formation_completed = 1;
 	if (ssid && ssid->mode == WPAS_MODE_INFRA) {
 		/*
 		 * Use a separate timeout for initial data connection to
@@ -4808,9 +5002,28 @@
 		 * something goes wrong in this step before the P2P group idle
 		 * timeout mechanism is taken into use.
 		 */
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"P2P: Re-start group formation timeout (%d seconds) as client for initial connection",
+			P2P_MAX_INITIAL_CONN_WAIT);
 		eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
 				       wpas_p2p_group_formation_timeout,
 				       wpa_s->parent, NULL);
+	} else if (ssid) {
+		/*
+		 * Use a separate timeout for initial data connection to
+		 * complete to allow the group to be removed automatically if
+		 * the client does not complete data connection successfully.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"P2P: Re-start group formation timeout (%d seconds) as GO for initial connection",
+			P2P_MAX_INITIAL_CONN_WAIT_GO);
+		eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT_GO, 0,
+				       wpas_p2p_group_formation_timeout,
+				       wpa_s->parent, NULL);
+		/*
+		 * Complete group formation on first successful data connection
+		 */
+		wpa_s->p2p_go_group_formation_completed = 0;
 	}
 	if (wpa_s->global->p2p)
 		p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
@@ -5110,12 +5323,13 @@
 /* Invite to reinvoke a persistent group */
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
-		    int ht40, int pref_freq)
+		    int ht40, int vht, int pref_freq)
 {
 	enum p2p_invite_role role;
 	u8 *bssid = NULL;
 	int force_freq = 0;
 	int res;
+	int no_pref_freq_given = pref_freq == 0;
 
 	wpa_s->global->p2p_invite_group = NULL;
 	if (peer_addr)
@@ -5149,7 +5363,8 @@
 	}
 	wpa_s->pending_invite_ssid_id = ssid->id;
 
-	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
+	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+				   role == P2P_INVITE_ROLE_GO);
 	if (res)
 		return res;
 
@@ -5161,6 +5376,15 @@
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
+	if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
+	    no_pref_freq_given && pref_freq > 0 &&
+	    wpa_s->num_multichan_concurrent > 1 &&
+	    wpas_p2p_num_unused_channels(wpa_s) > 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz for invitation due to p2p_ignore_shared_freq=1 configuration",
+			   pref_freq);
+		pref_freq = 0;
+	}
+
 	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
 			  ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
 			  1, pref_freq);
@@ -5176,11 +5400,12 @@
 	u8 *bssid = NULL;
 	struct wpa_ssid *ssid;
 	int persistent;
-	int force_freq = 0, pref_freq = 0;
+	int freq = 0, force_freq = 0, pref_freq = 0;
 	int res;
 
 	wpa_s->p2p_persistent_go_freq = 0;
 	wpa_s->p2p_go_ht40 = 0;
+	wpa_s->p2p_go_vht = 0;
 
 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
 		if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -5208,6 +5433,7 @@
 		bssid = wpa_s->own_addr;
 		if (go_dev_addr == NULL)
 			go_dev_addr = wpa_s->global->p2p_dev_addr;
+		freq = ssid->frequency;
 	} else {
 		role = P2P_INVITE_ROLE_CLIENT;
 		if (wpa_s->wpa_state < WPA_ASSOCIATED) {
@@ -5219,6 +5445,8 @@
 		if (go_dev_addr == NULL &&
 		    !is_zero_ether_addr(wpa_s->go_dev_addr))
 			go_dev_addr = wpa_s->go_dev_addr;
+		freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
+			(int) wpa_s->assoc_freq;
 	}
 	wpa_s->parent->pending_invite_ssid_id = -1;
 
@@ -5230,7 +5458,8 @@
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
-	res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq);
+	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+				   role == P2P_INVITE_ROLE_ACTIVE_GO);
 	if (res)
 		return res;
 	wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
@@ -5587,6 +5816,11 @@
 			wpa_printf(MSG_ERROR, "P2P: Preferred channel list "
 				   "update failed");
 		}
+
+		if (p2p_set_no_go_freq(p2p, &wpa_s->conf->p2p_no_go_freq) < 0) {
+			wpa_printf(MSG_ERROR, "P2P: No GO channel list "
+				   "update failed");
+		}
 	}
 }
 
@@ -5758,19 +5992,20 @@
 
 void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
 {
-	struct p2p_channels chan;
+	struct p2p_channels chan, cli_chan;
 
 	if (wpa_s->global == NULL || wpa_s->global->p2p == NULL)
 		return;
 
 	os_memset(&chan, 0, sizeof(chan));
-	if (wpas_p2p_setup_channels(wpa_s, &chan)) {
+	os_memset(&cli_chan, 0, sizeof(cli_chan));
+	if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan)) {
 		wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
 			   "channel list");
 		return;
 	}
 
-	p2p_update_channel_list(wpa_s->global->p2p, &chan);
+	p2p_update_channel_list(wpa_s->global->p2p, &chan, &cli_chan);
 }
 
 
@@ -6007,6 +6242,25 @@
 void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
 				       const u8 *addr)
 {
+	if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+				 wpa_s->parent, NULL) > 0) {
+		/*
+		 * This can happen if WPS provisioning step is not terminated
+		 * cleanly (e.g., P2P Client does not send WSC_Done). Since the
+		 * peer was able to connect, there is no need to time out group
+		 * formation after this, though. In addition, this is used with
+		 * the initial connection wait on the GO as a separate formation
+		 * timeout and as such, expected to be hit after the initial WPS
+		 * provisioning step.
+		 */
+		wpa_printf(MSG_DEBUG, "P2P: Canceled P2P group formation timeout on data connection");
+	}
+	if (!wpa_s->p2p_go_group_formation_completed) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Marking group formation completed on GO on first data connection");
+		wpa_s->p2p_go_group_formation_completed = 1;
+		wpa_s->global->p2p_group_formation = NULL;
+		wpa_s->p2p_in_provisioning = 0;
+	}
 	wpa_s->global->p2p_go_wait_client.sec = 0;
 	if (addr == NULL)
 		return;
@@ -6030,7 +6284,8 @@
 			 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
 			 wpa_s->p2p_persistent_id,
 			 wpa_s->p2p_pd_before_go_neg,
-			 wpa_s->p2p_go_ht40);
+			 wpa_s->p2p_go_ht40,
+			 wpa_s->p2p_go_vht);
 }
 
 
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 65ccbf9..b462d1b 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -24,7 +24,7 @@
 		     const char *pin, enum p2p_wps_method wps_method,
 		     int persistent_group, int auto_join, int join,
 		     int auth, int go_intent, int freq, int persistent_id,
-		     int pd, int ht40);
+		     int pd, int ht40, int vht);
 void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 				   unsigned int freq, unsigned int duration);
 void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
@@ -35,11 +35,12 @@
 #endif
 int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
-		       int freq, int ht40);
+		       int freq, int ht40, int vht);
 int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid, int addr_allocated,
-				  int freq, int ht40,
-				  const struct p2p_channels *channels);
+				  int freq, int ht40, int vht,
+				  const struct p2p_channels *channels,
+				  int connection_timeout);
 struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
 				       struct wpa_ssid *ssid);
 void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
@@ -114,7 +115,7 @@
 int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
-		    int ht40, int pref_freq);
+		    int ht40, int vht, int pref_freq);
 int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
 			  const u8 *peer_addr, const u8 *go_dev_addr);
 void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
@@ -155,6 +156,8 @@
 int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
 int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
 			   struct hostapd_hw_modes *mode, u8 channel);
+int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
+			      struct hostapd_hw_modes *mode, u8 channel);
 unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
 void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
 			 const u8 *p2p_dev_addr,
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index a0f51d0..625ff28 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -21,6 +21,7 @@
 #include "hs20_supplicant.h"
 #include "notify.h"
 #include "bss.h"
+#include "gas_query.h"
 #include "scan.h"
 
 
@@ -260,10 +261,9 @@
 }
 
 
-static int
-wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
-				struct wpa_driver_scan_params *params,
-				int interval)
+int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+				    struct wpa_driver_scan_params *params,
+				    int interval)
 {
 	int ret;
 
@@ -271,15 +271,14 @@
 	ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000);
 	if (ret)
 		wpa_supplicant_notify_scanning(wpa_s, 0);
-	else {
+	else
 		wpa_s->sched_scanning = 1;
-	}
 
 	return ret;
 }
 
 
-static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
 {
 	int ret;
 
@@ -566,13 +565,17 @@
 		wpas_p2p_continue_after_scan(wpa_s);
 		return;
 	}
-#ifdef ANDROID
+
 	if (wpa_s->scanning) {
-		/* If we are already in scanning state, we shall ignore this new scan request*/
-		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - already scanning");
+		/*
+		 * If we are already in scanning state, we shall reschedule the
+		 * the incoming scan request.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Reschedule the incoming scan req");
+		wpa_supplicant_req_scan(wpa_s, 1, 0);
 		return;
 	}
-#endif
+
 	if (!wpa_supplicant_enabled_networks(wpa_s) &&
 	    wpa_s->scan_req == NORMAL_SCAN_REQ) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
@@ -595,7 +598,7 @@
 	}
 
 #ifdef CONFIG_P2P
-	if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s)) {
+	if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s, 0)) {
 		if (wpa_s->sta_scan_pending &&
 		    wpas_p2p_in_progress(wpa_s) == 2 &&
 		    wpa_s->global->p2p_cb_on_scan_complete) {
@@ -611,6 +614,14 @@
 	}
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_GAS
+	if (gas_query_in_progress(wpa_s->gas)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Delay scan while GAS query is in progress");
+		wpa_supplicant_req_scan(wpa_s, 1, 0);
+		return;
+	}
+#endif /* CONFIG_GAS */
+
 	if (wpa_s->conf->ap_scan == 2)
 		max_ssids = 1;
 	else {
@@ -654,8 +665,9 @@
 #ifdef CONFIG_P2P
 	if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
 	    wpa_s->go_params) {
-		wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during "
-			   "P2P group formation");
+		wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)",
+			   wpa_s->p2p_in_provisioning,
+			   wpa_s->show_group_started);
 		params.ssids[0].ssid = wpa_s->go_params->ssid;
 		params.ssids[0].ssid_len = wpa_s->go_params->ssid_len;
 		params.num_ssids = 1;
@@ -680,14 +692,12 @@
 		wpa_s->prev_scan_wildcard = 0;
 		wpa_supplicant_assoc_try(wpa_s, ssid);
 		return;
-#ifndef ANDROID
 	} else if (wpa_s->conf->ap_scan == 2) {
 		/*
 		 * User-initiated scan request in ap_scan == 2; scan with
 		 * wildcard SSID.
 		 */
 		ssid = NULL;
-#endif
 	} else {
 		struct wpa_ssid *start = ssid, *tssid;
 		int freqs_set = 0;
@@ -874,7 +884,7 @@
 
 void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec)
 {
-	struct os_time remaining, new_int;
+	struct os_reltime remaining, new_int;
 	int cancelled;
 
 	cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL,
@@ -882,13 +892,15 @@
 
 	new_int.sec = sec;
 	new_int.usec = 0;
-	if (cancelled && os_time_before(&remaining, &new_int)) {
+	if (cancelled && os_reltime_before(&remaining, &new_int)) {
 		new_int.sec = remaining.sec;
 		new_int.usec = remaining.usec;
 	}
 
-	eloop_register_timeout(new_int.sec, new_int.usec, wpa_supplicant_scan,
-			       wpa_s, NULL);
+	if (cancelled) {
+		eloop_register_timeout(new_int.sec, new_int.usec,
+				       wpa_supplicant_scan, wpa_s, NULL);
+	}
 	wpa_s->scan_interval = sec;
 }
 
@@ -904,30 +916,13 @@
  */
 void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
 {
-#ifndef ANDROID
-	/* If there's at least one network that should be specifically scanned
-	 * then don't cancel the scan and reschedule.  Some drivers do
-	 * background scanning which generates frequent scan results, and that
-	 * causes the specific SSID scan to get continually pushed back and
-	 * never happen, which causes hidden APs to never get probe-scanned.
-	 */
-	if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
-	    wpa_s->conf->ap_scan == 1) {
-		struct wpa_ssid *ssid = wpa_s->conf->ssid;
-
-		while (ssid) {
-			if (!wpas_network_disabled(wpa_s, ssid) &&
-			    ssid->scan_ssid)
-				break;
-			ssid = ssid->next;
-		}
-		if (ssid) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
-			        "ensure that specific SSID scans occur");
-			return;
-		}
+	if (eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL))
+	{
+		wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d sec %d usec",
+			sec, usec);
+		return;
 	}
-#endif
+
 	wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
 		sec, usec);
 	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
@@ -1204,9 +1199,6 @@
 	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request");
 	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
 	wpas_p2p_continue_after_scan(wpa_s);
-#ifdef ANDROID
-	wpa_supplicant_notify_scanning(wpa_s, 0);
-#endif
 }
 
 
@@ -1345,6 +1337,43 @@
 
 
 /**
+ * wpa_scan_get_vendor_ie_beacon - Fetch vendor information from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ *
+ * This function is like wpa_scan_get_vendor_ie(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
+					 u32 vendor_type)
+{
+	const u8 *end, *pos;
+
+	if (res->beacon_ie_len == 0)
+		return NULL;
+
+	pos = (const u8 *) (res + 1);
+	pos += res->ie_len;
+	end = pos + res->beacon_ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+
+/**
  * wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result
  * @res: Scan result entry
  * @vendor_type: Vendor type (four octets starting the IE payload)
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 2144787..b6fe070 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -29,6 +29,8 @@
 const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie);
 const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
 				  u32 vendor_type);
+const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
+					 u32 vendor_type);
 struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
 					     u32 vendor_type);
 int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
@@ -37,5 +39,9 @@
 void scan_only_handler(struct wpa_supplicant *wpa_s,
 		       struct wpa_scan_results *scan_res);
 int wpas_scan_scheduled(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+				    struct wpa_driver_scan_params *params,
+				    int interval);
+int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s);
 
 #endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 925d132..87c14ae 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -46,7 +46,7 @@
 {
 	int i;
 	for (i = 0; i < idx; i++) {
-		if (array[i] == -1)
+		if (array[i] <= 0)
 			return 0;
 	}
 	return 1;
@@ -56,9 +56,9 @@
 static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
 {
 	int *groups = wpa_s->conf->sae_groups;
-	int default_groups[] = { 19, 20, 21, 25, 26 };
+	int default_groups[] = { 19, 20, 21, 25, 26, 0 };
 
-	if (!groups)
+	if (!groups || groups[0] <= 0)
 		groups = default_groups;
 
 	/* Configuration may have changed, so validate current index */
@@ -438,6 +438,7 @@
 #ifdef CONFIG_SAE
 	wpa_s->sme.sae.state = SAE_NOTHING;
 	wpa_s->sme.sae.send_confirm = 0;
+	wpa_s->sme.sae_group_index = 0;
 #endif /* CONFIG_SAE */
 	sme_send_authentication(wpa_s, bss, ssid, 1);
 }
@@ -482,15 +483,18 @@
 		return -1;
 
 	if (auth_transaction == 1) {
+		int *groups = wpa_s->conf->sae_groups;
+
 		wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
 		if (wpa_s->current_bss == NULL ||
 		    wpa_s->current_ssid == NULL)
 			return -1;
 		if (wpa_s->sme.sae.state != SAE_COMMITTED)
 			return -1;
+		if (groups && groups[0] <= 0)
+			groups = NULL;
 		if (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
-				     wpa_s->conf->sae_groups) !=
-		    WLAN_STATUS_SUCCESS)
+				     groups) != WLAN_STATUS_SUCCESS)
 			return -1;
 
 		if (sae_process_commit(&wpa_s->sme.sae) < 0) {
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index a379d65..aabaa3c 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -496,6 +496,8 @@
 		return wpa_ctrl_command(ctrl, "STATUS-VERBOSE");
 	if (argc > 0 && os_strcmp(argv[0], "wps") == 0)
 		return wpa_ctrl_command(ctrl, "STATUS-WPS");
+	if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
+		return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
 	return wpa_ctrl_command(ctrl, "STATUS");
 }
 
@@ -613,7 +615,9 @@
 		"p2p_oper_reg_class", "p2p_oper_channel",
 		"p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect",
 		"p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan",
+		"p2p_no_go_freq",
 		"p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface",
+		"p2p_go_vht",
 		"p2p_ignore_shared_freq", "country", "bss_max_count",
 		"bss_expiration_age", "bss_expiration_scan_count",
 		"filter_ssids", "filter_rssi", "max_num_sta",
@@ -623,9 +627,9 @@
 		"wps_nfc_dev_pw", "ext_password_backend",
 		"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
 		"sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements",
-		"ignore_old_scan_res", "freq_list"
+		"ignore_old_scan_res", "freq_list", "external_sim"
 	};
-	int i, num_fields = sizeof(fields) / sizeof(fields[0]);
+	int i, num_fields = ARRAY_SIZE(fields);
 
 	if (arg == 1) {
 		char **res = os_calloc(num_fields + 1, sizeof(char *));
@@ -1268,6 +1272,38 @@
 }
 
 
+static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256], *pos, *end;
+	int i, ret;
+
+	if (argc < 2) {
+		printf("Invalid SIM command: needs two arguments "
+		       "(network id and SIM operation response)\n");
+		return -1;
+	}
+
+	end = cmd + sizeof(cmd);
+	pos = cmd;
+	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s",
+			  argv[0], argv[1]);
+	if (ret < 0 || ret >= end - pos) {
+		printf("Too long SIM command.\n");
+		return -1;
+	}
+	pos += ret;
+	for (i = 2; i < argc; i++) {
+		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+		if (ret < 0 || ret >= end - pos) {
+			printf("Too long SIM command.\n");
+			return -1;
+		}
+		pos += ret;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
 				  char *argv[])
 {
@@ -1687,6 +1723,13 @@
 {
 	return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
 }
+
+static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv);
+}
+
 #endif /* CONFIG_AP */
 
 
@@ -2078,7 +2121,7 @@
 		"disc_int",
 		"per_sta_psk",
 	};
-	int i, num_fields = sizeof(fields) / sizeof(fields[0]);
+	int i, num_fields = ARRAY_SIZE(fields);
 
 	if (arg == 1) {
 		char **res = os_calloc(num_fields + 1, sizeof(char *));
@@ -2372,23 +2415,9 @@
 #ifdef ANDROID
 static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-	char cmd[256];
-	int i;
-	int len;
-
-	if (argc < 1) {
-		printf("Invalid DRIVER command: needs one argument (cmd)\n");
-		return -1;
-	}
-
-	len = os_snprintf(cmd, sizeof(cmd), "DRIVER %s", argv[0]);
-	for (i=1; i < argc; i++)
-		len += os_snprintf(cmd + len, sizeof(cmd) - len, " %s", argv[i]);
-	cmd[sizeof(cmd) - 1] = '\0';
-	printf("%s: %s\n", __func__, cmd);
-	return wpa_ctrl_command(ctrl, cmd);
+	return wpa_cli_cmd(ctrl, "DRIVER", 1, argc, argv);
 }
-#endif
+#endif /* ANDROID */
 
 
 static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -2486,6 +2515,9 @@
 	  cli_cmd_flag_sensitive,
 	  "<network id> <passphrase> = configure private key passphrase\n"
 	  "  for an SSID" },
+	{ "sim", wpa_cli_cmd_sim, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <pin> = report SIM operation result" },
 	{ "bssid", wpa_cli_cmd_bssid, NULL,
 	  cli_cmd_flag_none,
 	  "<network id> <BSSID> = set preferred BSSID for an SSID" },
@@ -2687,6 +2719,11 @@
 	{ "disassociate", wpa_cli_cmd_disassociate, NULL,
 	  cli_cmd_flag_none,
 	  "<addr> = disassociate a station" },
+	{ "chan_switch", wpa_cli_cmd_chanswitch, NULL,
+	  cli_cmd_flag_none,
+	  "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]"
+	  " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]"
+	  " = CSA parameters" },
 #endif /* CONFIG_AP */
 	{ "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
 	  "= notification of suspend/hibernate" },
@@ -2853,10 +2890,9 @@
 	{ "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none,
 	  "= flush wpa_supplicant state" },
 #ifdef ANDROID
-	{ "driver", wpa_cli_cmd_driver, NULL,
-	  cli_cmd_flag_none,
+	{ "driver", wpa_cli_cmd_driver, NULL, cli_cmd_flag_none,
 	  "<command> = driver private commands" },
-#endif
+#endif /* ANDROID */
 	{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
 };
 
@@ -2917,7 +2953,7 @@
 	int i, count;
 	struct cli_txt_entry *e;
 
-	count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
+	count = ARRAY_SIZE(wpa_cli_commands);
 	count += dl_list_len(&p2p_groups);
 	count += dl_list_len(&ifnames);
 	res = os_calloc(count + 1, sizeof(char *));
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index b431662..4e8d016 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -217,7 +217,7 @@
 void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
 				     int sec, int usec)
 {
-	if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
+	if (wpa_s->conf->ap_scan == 0 &&
 	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
 		return;
 
@@ -293,16 +293,16 @@
 				EAPOL_REQUIRE_KEY_BROADCAST;
 		}
 
-		if (wpa_s->conf && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)
 			eapol_conf.required_keys = 0;
 	}
-	if (wpa_s->conf)
-		eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
+	eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
 	eapol_conf.workaround = ssid->eap_workaround;
 	eapol_conf.eap_disabled =
 		!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
 		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
 		wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
+	eapol_conf.external_sim = wpa_s->conf->external_sim;
 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 #endif /* IEEE8021X_EAPOL */
 }
@@ -570,14 +570,22 @@
 
 static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
 {
+	const char *name;
+
+	if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan)
+		name = wpa_s->current_ssid->bgscan;
+	else
+		name = wpa_s->conf->bgscan;
+	if (name == NULL)
+		return;
 	if (wpas_driver_bss_selection(wpa_s))
 		return;
 	if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
 		return;
 
 	bgscan_deinit(wpa_s);
-	if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
-		if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
+	if (wpa_s->current_ssid) {
+		if (bgscan_init(wpa_s, wpa_s->current_ssid, name)) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
 				"bgscan");
 			/*
@@ -651,12 +659,6 @@
 		wpa_supplicant_state_txt(wpa_s->wpa_state),
 		wpa_supplicant_state_txt(state));
 
-#ifdef ANDROID_P2P
-	if(state == WPA_ASSOCIATED && wpa_s->current_ssid) {
-		wpa_s->current_ssid->assoc_retry = 0;
-	}
-#endif /* ANDROID_P2P */
-
 	if (state != WPA_SCANNING)
 		wpa_supplicant_notify_scanning(wpa_s, 0);
 
@@ -664,7 +666,7 @@
 		struct wpa_ssid *ssid = wpa_s->current_ssid;
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
-			MACSTR " completed (auth) [id=%d id_str=%s]",
+			MACSTR " completed [id=%d id_str=%s]",
 			MAC2STR(wpa_s->bssid),
 			ssid ? ssid->id : -1,
 			ssid && ssid->id_str ? ssid->id_str : "");
@@ -677,6 +679,7 @@
 		wpa_drv_set_supp_port(wpa_s, 1);
 #endif /* IEEE8021X_EAPOL */
 		wpa_s->after_wps = 0;
+		wpa_s->known_wps_freq = 0;
 #ifdef CONFIG_P2P
 		wpas_p2p_completed(wpa_s);
 #endif /* CONFIG_P2P */
@@ -722,6 +725,11 @@
 #ifdef CONFIG_WPS
 	struct wpa_supplicant *wpa_s = global->ifaces;
 	while (wpa_s) {
+#ifdef CONFIG_P2P
+		if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE ||
+		    (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group))
+			wpas_p2p_disconnect(wpa_s);
+#endif /* CONFIG_P2P */
 		if (wpas_wps_terminate_pending(wpa_s) == 1)
 			pending = 1;
 		wpa_s = wpa_s->next;
@@ -1220,6 +1228,9 @@
 #endif /* CONFIG_INTERWORKING */
 		break;
 	case 4: /* Bits 32-39 */
+#ifdef CONFIG_INTERWORKING
+		*pos |= 0x01; /* Bit 32 - QoS Map */
+#endif /* CONFIG_INTERWORKING */
 		break;
 	case 5: /* Bits 40-47 */
 		break;
@@ -1279,8 +1290,6 @@
 	int wep_keys_set = 0;
 	int assoc_failed = 0;
 	struct wpa_ssid *old_ssid;
-	u8 ext_capab[10];
-	int ext_capab_len;
 #ifdef CONFIG_HT_OVERRIDES
 	struct ieee80211_ht_capabilities htcaps;
 	struct ieee80211_ht_capabilities htcaps_mask;
@@ -1495,15 +1504,27 @@
 	}
 #endif /* CONFIG_HS20 */
 
-	ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
-	if (ext_capab_len > 0) {
-		u8 *pos = wpa_ie;
-		if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
-			pos += 2 + pos[1];
-		os_memmove(pos + ext_capab_len, pos,
-			   wpa_ie_len - (pos - wpa_ie));
-		wpa_ie_len += ext_capab_len;
-		os_memcpy(pos, ext_capab, ext_capab_len);
+	/*
+	 * Workaround: Add Extended Capabilities element only if the AP
+	 * included this element in Beacon/Probe Response frames. Some older
+	 * APs seem to have interoperability issues if this element is
+	 * included, so while the standard may require us to include the
+	 * element in all cases, it is justifiable to skip it to avoid
+	 * interoperability issues.
+	 */
+	if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
+		u8 ext_capab[10];
+		int ext_capab_len;
+		ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+		if (ext_capab_len > 0) {
+			u8 *pos = wpa_ie;
+			if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+				pos += 2 + pos[1];
+			os_memmove(pos + ext_capab_len, pos,
+				   wpa_ie_len - (pos - wpa_ie));
+			wpa_ie_len += ext_capab_len;
+			os_memcpy(pos, ext_capab, ext_capab_len);
+		}
 	}
 
 	wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
@@ -2747,7 +2768,7 @@
 	if (!wpa_s->conf->pcsc_reader)
 		return 0;
 
-	wpa_s->scard = scard_init(SCARD_TRY_BOTH, wpa_s->conf->pcsc_reader);
+	wpa_s->scard = scard_init(wpa_s->conf->pcsc_reader);
 	if (!wpa_s->scard)
 		return 1;
 
@@ -3066,7 +3087,8 @@
 #ifdef CONFIG_EAP_PROXY
 {
 	size_t len;
-	wpa_s->mnc_len = eap_proxy_get_imsi(wpa_s->imsi, &len);
+	wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, wpa_s->imsi,
+						     &len);
 	if (wpa_s->mnc_len > 0) {
 		wpa_s->imsi[len] = '\0';
 		wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
@@ -3502,7 +3524,7 @@
 	os_free(global->params.override_driver);
 	os_free(global->params.override_ctrl_interface);
 
-	os_free(global->p2p_disallow_freq);
+	os_free(global->p2p_disallow_freq.range);
 	os_free(global->add_psk);
 
 	os_free(global);
@@ -3753,6 +3775,10 @@
 		if (ssid == wpa_s->current_ssid)
 			wpa_s->reassociate = 1;
 		break;
+	case WPA_CTRL_REQ_SIM:
+		os_free(eap->external_sim_resp);
+		eap->external_sim_resp = os_strdup(value);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
 		return -1;
@@ -3943,37 +3969,53 @@
 }
 
 
+static int wpas_conn_in_progress(struct wpa_supplicant *wpa_s)
+{
+	return wpa_s->wpa_state >= WPA_AUTHENTICATING &&
+		wpa_s->wpa_state != WPA_COMPLETED;
+}
+
+
 /**
  * wpas_wpa_is_in_progress - Check whether a connection is in progress
  * @wpa_s: Pointer to wpa_supplicant data
+ * @include_current: Whether to consider specified interface
  *
  * This function is to check if the wpa state is in beginning of the connection
  * during 4-way handshake or group key handshake with WPA on any shared
  * interface.
  */
-int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s)
+int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s, int include_current)
 {
 	const char *rn, *rn2;
 	struct wpa_supplicant *ifs;
 
-	if (!wpa_s->driver->get_radio_name)
+	if (!wpa_s->driver->get_radio_name) {
+		if (include_current && wpas_conn_in_progress(wpa_s)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Connection is in progress on interface %s - defer",
+				wpa_s->ifname);
+			return 1;
+		}
+
                 return 0;
+	}
 
 	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
 	if (rn == NULL || rn[0] == '\0')
 		return 0;
 
 	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
-		if (ifs == wpa_s || !ifs->driver->get_radio_name)
+		if (!include_current && ifs == wpa_s)
+			continue;
+		if (!ifs->driver->get_radio_name)
 			continue;
 
 		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
 		if (!rn2 || os_strcmp(rn, rn2) != 0)
 			continue;
-		if (ifs->wpa_state >= WPA_AUTHENTICATING &&
-		    ifs->wpa_state != WPA_COMPLETED) {
+		if (wpas_conn_in_progress(ifs)) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "Connection is in progress "
-				"on interface %s - defer scan", ifs->ifname);
+				"on interface %s - defer", ifs->ifname);
 			return 1;
 		}
 	}
@@ -3982,6 +4024,18 @@
 }
 
 
+void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title,
+		     int *freq_array, unsigned int len)
+{
+	unsigned int i;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Shared frequencies (len=%u): %s",
+		len, title);
+	for (i = 0; i < len; i++)
+		wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d", i, freq_array[i]);
+}
+
+
 /*
  * Find the operating frequencies of any of the virtual interfaces that
  * are using the same radio as the current interface.
@@ -3995,6 +4049,8 @@
 	int freq;
 	unsigned int idx = 0, i;
 
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"Determining shared radio frequencies (max len %u)", len);
 	os_memset(freq_array, 0, sizeof(int) * len);
 
 	/* First add the frequency of the local interface */
@@ -4012,14 +4068,18 @@
 		if (freq > 0 && idx < len &&
 		    (idx == 0 || freq_array[0] != freq))
 			freq_array[idx++] = freq;
+		dump_freq_array(wpa_s, "No get_radio_name", freq_array, idx);
 		return idx;
 	}
 
 	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
-	if (rn == NULL || rn[0] == '\0')
+	if (rn == NULL || rn[0] == '\0') {
+		dump_freq_array(wpa_s, "get_radio_name failed",
+				freq_array, idx);
 		return idx;
+	}
 
-	for (ifs = wpa_s->global->ifaces, idx = 0; ifs && idx < len;
+	for (ifs = wpa_s->global->ifaces; ifs && idx < len;
 	     ifs = ifs->next) {
 		if (wpa_s == ifs || !ifs->driver->get_radio_name)
 			continue;
@@ -4047,5 +4107,7 @@
 		if (i == idx)
 			freq_array[idx++] = freq;
 	}
+
+	dump_freq_array(wpa_s, "completed iteration", freq_array, idx);
 	return idx;
 }
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index d73d371..0ecfaa6 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -241,14 +241,14 @@
 # This is an optional set of parameters for automatic scanning
 # within an interface in following format:
 #autoscan=<autoscan module name>:<module parameters>
-# autoscan is like bgscan but on disconnected or inactive state.
-# For instance, on exponential module parameters would be <base>:<limit>
+# autoscan is like bgscan but on disconnected or inactive state.
+# For instance, on exponential module parameters would be <base>:<limit>
 #autoscan=exponential:3:300
 # Which means a delay between scans on a base exponential of 3,
-# up to the limit of 300 seconds (3, 9, 27 ... 300)
-# For periodic module, parameters would be <fixed interval>
+# up to the limit of 300 seconds (3, 9, 27 ... 300)
+# For periodic module, parameters would be <fixed interval>
 #autoscan=periodic:30
-# So a delay of 30 seconds will be applied between each scan
+# So a delay of 30 seconds will be applied between each scan
 
 # filter_ssids - SSID-based scan result filtering
 # 0 = do not filter scan results (default)
@@ -399,9 +399,11 @@
 # milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
 #	format
 #
-# domain: Home service provider FQDN
+# domain: Home service provider FQDN(s)
 #	This is used to compare against the Domain Name List to figure out
-#	whether the AP is operated by the Home SP.
+#	whether the AP is operated by the Home SP. Multiple domain entries can
+#	be used to configure alternative FQDNs that will be considered home
+#	networks.
 #
 # roaming_consortium: Roaming Consortium OI
 #	If roaming_consortium_len is non-zero, this field contains the
@@ -548,6 +550,10 @@
 # <long interval>[:<database file name>]"
 # bgscan="learn:30:-45:300:/etc/wpa_supplicant/network1.bgscan"
 #
+# This option can also be set outside of all network blocks for the bgscan
+# parameter to apply for all the networks that have no specific bgscan
+# parameter.
+#
 # proto: list of accepted protocols
 # WPA = WPA/IEEE 802.11i/D3.0
 # RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index d69cd61..eed1053 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -227,12 +227,6 @@
 	char *service;
 };
 
-struct wpa_freq_range {
-	unsigned int min;
-	unsigned int max;
-};
-
-
 /**
  * struct wpa_global - Internal, global data for all %wpa_supplicant interfaces
  *
@@ -257,8 +251,7 @@
 	struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
 	int p2p_disabled;
 	int cross_connection;
-	struct wpa_freq_range *p2p_disallow_freq;
-	unsigned int num_p2p_disallow_freq;
+	struct wpa_freq_range_list p2p_disallow_freq;
 	enum wpa_conc_pref {
 		WPA_CONC_PREF_NOT_SET,
 		WPA_CONC_PREF_STA,
@@ -646,7 +639,10 @@
 	unsigned int p2p_fallback_to_go_neg:1;
 	unsigned int p2p_pd_before_go_neg:1;
 	unsigned int p2p_go_ht40:1;
+	unsigned int p2p_go_vht:1;
 	unsigned int user_initiated_pd:1;
+	unsigned int p2p_go_group_formation_completed:1;
+	int p2p_first_connection_timeout;
 	int p2p_persistent_go_freq;
 	int p2p_persistent_id;
 	int p2p_go_intent;
@@ -821,7 +817,7 @@
 		    size_t ssid_len);
 void wpas_request_connection(struct wpa_supplicant *wpa_s);
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf);
-int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s);
+int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s, int include_current);
 
 /**
  * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -867,6 +863,8 @@
 
 int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
 
+void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title,
+		     int *freq_array, unsigned int len);
 int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
 			   int *freq_array, unsigned int len);
 
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 61a42bd..ab6cdca 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -611,6 +611,8 @@
 		return WPA_CTRL_REQ_EAP_OTP;
 	else if (os_strcmp(field, "PASSPHRASE") == 0)
 		return WPA_CTRL_REQ_EAP_PASSPHRASE;
+	else if (os_strcmp(field, "SIM") == 0)
+		return WPA_CTRL_REQ_SIM;
 	return WPA_CTRL_REQ_UNKNOWN;
 }
 
@@ -647,6 +649,9 @@
 		*txt = "Private key passphrase";
 		ret = "PASSPHRASE";
 		break;
+	case WPA_CTRL_REQ_SIM:
+		ret = "SIM";
+		break;
 	default:
 		break;
 	}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index f6c2fcb..0b3c892 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -882,6 +882,9 @@
 	int id;
 	struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
 
+	wpa_s->after_wps = 0;
+	wpa_s->known_wps_freq = 0;
+
 	prev_current = wpa_s->current_ssid;
 
 	/* Enable the networks disabled during wpas_wps_reassoc */
@@ -1049,6 +1052,8 @@
 	wpa_s->normal_scans = 0;
 	wpa_s->wps_success = 0;
 	wpa_s->blacklist_cleared = 0;
+
+	wpa_supplicant_cancel_sched_scan(wpa_s);
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
 }
 
@@ -1157,6 +1162,8 @@
 		wpas_wps_clear_ap_info(wpa_s);
 	}
 
+	wpa_s->after_wps = 0;
+
 	return 0;
 }
 
@@ -2174,6 +2181,8 @@
 	}
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
+
+	wpa_supplicant_cancel_sched_scan(wpa_s);
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
 
 	return 0;
@@ -2463,6 +2472,9 @@
 void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
 {
 	struct wps_ap_info *ap;
+
+	wpa_s->after_wps = 0;
+
 	if (!wpa_s->wps_ap_iter)
 		return;
 	ap = wpas_wps_get_ap_info(wpa_s, bssid);