Cumulative patch from commit 905828fea4b95a6d48ce86e1b5272c25a618b3d8

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

Change-Id: I6d49f445692b71a4cd324f517eba651518ee14bb
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index fa7d14a..bd66474 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1096,8 +1096,20 @@
 		conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
 	if (os_strstr(capab, "[HTC-VHT]"))
 		conf->vht_capab |= VHT_CAP_HTC_VHT;
-	if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP0]"))
-		conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT;
+	if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP7]"))
+		conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX;
+	else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP6]"))
+		conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_6;
+	else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP5]"))
+		conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_5;
+	else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP4]"))
+		conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_4;
+	else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP3]"))
+		conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_3;
+	else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP2]"))
+		conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_2;
+	else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP1]"))
+		conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_1;
 	if (os_strstr(capab, "[VHT-LINK-ADAPT2]") &&
 	    (conf->vht_capab & VHT_CAP_HTC_VHT))
 		conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB;
diff --git a/hostapd/main.c b/hostapd/main.c
index 3026929..68bc9b5 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -728,8 +728,12 @@
  out:
 	hostapd_global_ctrl_iface_deinit(&interfaces);
 	/* Deinitialize all interfaces */
-	for (i = 0; i < interfaces.count; i++)
+	for (i = 0; i < interfaces.count; i++) {
+		interfaces.iface[i]->driver_ap_teardown =
+			!!(interfaces.iface[i]->drv_flags &
+			   WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
 		hostapd_interface_deinit_free(interfaces.iface[i]);
+	}
 	os_free(interfaces.iface);
 
 	hostapd_global_deinit(pid_file);
diff --git a/src/ap/acs.c b/src/ap/acs.c
index f58b091..60b7580 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -367,6 +367,19 @@
 }
 
 
+static int acs_usable_vht80_chan(struct hostapd_channel_data *chan)
+{
+	const int allowed[] = { 36, 52, 100, 116, 132, 149 };
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(allowed); i++)
+		if (chan->chan == allowed[i])
+			return 1;
+
+	return 0;
+}
+
+
 static int acs_survey_is_sufficient(struct freq_survey *survey)
 {
 	if (!(survey->filled & SURVEY_HAS_NF)) {
@@ -541,6 +554,15 @@
 			continue;
 		}
 
+		if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+		    iface->conf->ieee80211ac &&
+		    iface->conf->vht_oper_chwidth == 1 &&
+		    !acs_usable_vht80_chan(chan)) {
+			wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for VHT80",
+				   chan->chan);
+			continue;
+		}
+
 		factor = 0;
 		if (acs_usable_chan(chan))
 			factor = chan->interference_factor;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index b8b260a..5ba48c9 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -767,8 +767,10 @@
 				    vht_enabled, sec_channel_offset,
 				    vht_oper_chwidth, center_segment0,
 				    center_segment1,
-				    iface->current_mode->vht_capab))
+				    iface->current_mode->vht_capab)) {
+		wpa_printf(MSG_ERROR, "Can't set freq params");
 		return -1;
+	}
 
 	res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
 	if (!res)
diff --git a/src/ap/ap_mlme.c b/src/ap/ap_mlme.c
index a959694..a7129f1 100644
--- a/src/ap/ap_mlme.c
+++ b/src/ap/ap_mlme.c
@@ -16,6 +16,7 @@
 #include "wpa_auth.h"
 #include "sta_info.h"
 #include "ap_mlme.h"
+#include "hostapd.h"
 
 
 #ifndef CONFIG_NO_HOSTAPD_LOGGER
@@ -80,7 +81,8 @@
 		       HOSTAPD_LEVEL_DEBUG,
 		       "MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
 		       MAC2STR(sta->addr), reason_code);
-	mlme_deletekeys_request(hapd, sta);
+	if (!hapd->iface->driver_ap_teardown)
+		mlme_deletekeys_request(hapd, sta);
 }
 
 
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 8c0cbab..c27cf3b 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -250,9 +250,8 @@
 
 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
 	*pos++ = 4 + 3 + 1;
-	WPA_PUT_BE24(pos, OUI_WFA);
-	pos += 3;
-	*pos++ = P2P_OUI_TYPE;
+	WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
+	pos += 4;
 
 	*pos++ = P2P_ATTR_MINOR_REASON_CODE;
 	WPA_PUT_LE16(pos, 1);
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 2b8b90f..92eda21 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -608,19 +608,25 @@
 	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",
+		"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%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");
+		iface->conf->channel, 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);
+
+	res = 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);
+
+	if (res) {
+		wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
 		return -1;
 	}
 
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ad1c2d0..6ba6f98 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -350,7 +350,7 @@
 
 static void hostapd_clear_wep(struct hostapd_data *hapd)
 {
-	if (hapd->drv_priv) {
+	if (hapd->drv_priv && !hapd->iface->driver_ap_teardown) {
 		hostapd_set_privacy(hapd, 0);
 		hostapd_broadcast_wep_clear(hapd);
 	}
@@ -401,11 +401,15 @@
 	if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
 		return 0;
 
-	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries");
-	if (hostapd_flush(hapd)) {
-		wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to "
-			"kernel driver");
-		ret = -1;
+	if (!hapd->iface->driver_ap_teardown) {
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+			"Flushing old station entries");
+
+		if (hostapd_flush(hapd)) {
+			wpa_msg(hapd->msg_ctx, MSG_WARNING,
+				"Could not connect to kernel driver");
+			ret = -1;
+		}
 	}
 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
 	os_memset(addr, 0xff, ETH_ALEN);
@@ -1009,6 +1013,15 @@
 	struct hostapd_data *hapd = iface->bss[0];
 	size_t i;
 
+	/*
+	 * It is possible that setup_interface() is called after the interface
+	 * was disabled etc., in which case driver_ap_teardown is possibly set
+	 * to 1. Clear it here so any other key/station deletion, which is not
+	 * part of a teardown flow, would also call the relevant driver
+	 * callbacks.
+	 */
+	iface->driver_ap_teardown = 0;
+
 	if (!iface->phy[0]) {
 		const char *phy = hostapd_drv_get_radio_name(hapd);
 		if (phy) {
@@ -1627,7 +1640,11 @@
 	driver = hapd_iface->bss[0]->driver;
 	drv_priv = hapd_iface->bss[0]->drv_priv;
 
-	/* whatever hostapd_interface_deinit does */
+	hapd_iface->driver_ap_teardown =
+		!!(hapd_iface->drv_flags &
+		   WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+
+	/* same as hostapd_interface_deinit without deinitializing ctrl-iface */
 	for (j = 0; j < hapd_iface->num_bss; j++) {
 		struct hostapd_data *hapd = hapd_iface->bss[j];
 		hostapd_free_stas(hapd);
@@ -1943,6 +1960,10 @@
 			return -1;
 		if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
 			wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
+			hapd_iface->driver_ap_teardown =
+				!!(hapd_iface->drv_flags &
+				   WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+
 			hostapd_interface_deinit_free(hapd_iface);
 			k = i;
 			while (k < (interfaces->count - 1)) {
@@ -1955,8 +1976,12 @@
 		}
 
 		for (j = 0; j < hapd_iface->conf->num_bss; j++) {
-			if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf))
+			if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf)) {
+				hapd_iface->driver_ap_teardown =
+					!(hapd_iface->drv_flags &
+					  WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
 				return hostapd_remove_bss(hapd_iface, j);
+			}
 		}
 	}
 	return -1;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 489ab16..be7df51 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -273,6 +273,12 @@
 	unsigned int wait_channel_update:1;
 	unsigned int cac_started:1;
 
+	/*
+	 * When set, indicates that the driver will handle the AP
+	 * teardown: delete global keys, station keys, and stations.
+	 */
+	unsigned int driver_ap_teardown:1;
+
 	int num_ap; /* number of entries in ap_list */
 	struct ap_info *ap_list; /* AP info list head */
 	struct ap_info *ap_hash[STA_HASH_SIZE];
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index af1bc9b..28e92fd 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -764,7 +764,7 @@
 	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_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
 	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);
diff --git a/src/ap/p2p_hostapd.c b/src/ap/p2p_hostapd.c
index 795d313..9be640c 100644
--- a/src/ap/p2p_hostapd.c
+++ b/src/ap/p2p_hostapd.c
@@ -96,9 +96,8 @@
 	u8 bitmap;
 	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
 	*eid++ = 4 + 3 + 1;
-	WPA_PUT_BE24(eid, OUI_WFA);
-	eid += 3;
-	*eid++ = P2P_OUI_TYPE;
+	WPA_PUT_BE32(eid, P2P_IE_VENDOR_TYPE);
+	eid += 4;
 
 	*eid++ = P2P_ATTR_MANAGEABILITY;
 	WPA_PUT_LE16(eid, 1);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index f7af088..0b90e3b 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -156,7 +156,8 @@
 	if (sta->flags & WLAN_STA_WDS)
 		hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
 
-	if (!(sta->flags & WLAN_STA_PREAUTH))
+	if (!hapd->iface->driver_ap_teardown &&
+	    !(sta->flags & WLAN_STA_PREAUTH))
 		hostapd_drv_sta_remove(hapd, sta->addr);
 
 	ap_sta_hash_del(hapd, sta);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index cf4664f..dcee679 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -758,7 +758,14 @@
 #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_1        ((u32) BIT(23))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_2        ((u32) BIT(24))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_3        ((u32) BIT(23) | BIT(24))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_4        ((u32) BIT(25))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_5        ((u32) BIT(23) | BIT(25))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_6        ((u32) BIT(24) | BIT(25))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX      ((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))
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index d2aad24..6b6c0ef 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -914,7 +914,8 @@
 #define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE	0x00000400
 /* This interface is P2P capable (P2P GO or P2P Client) */
 #define WPA_DRIVER_FLAGS_P2P_CAPABLE	0x00000800
-/* unused: 0x00001000 */
+/* Driver supports station and key removal when stopping an AP */
+#define WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT		0x00001000
 /*
  * Driver uses the initial interface for P2P management interface and non-P2P
  * purposes (e.g., connect to infra AP), but this interface cannot be used for
@@ -2520,6 +2521,30 @@
 #endif /* ANDROID */
 
 	/**
+	 * vendor_cmd - Execute vendor specific command
+	 * @priv: Private driver interface data
+	 * @vendor_id: Vendor id
+	 * @subcmd: Vendor command id
+	 * @data: Vendor command parameters (%NULL if no parameters)
+	 * @data_len: Data length
+	 * @buf: Return buffer (%NULL to ignore reply)
+	 * Returns: 0 on success, negative (<0) on failure
+	 *
+	 * This function handles vendor specific commands that are passed to
+	 * the driver/device. The command is identified by vendor id and
+	 * command id. Parameters can be passed as argument to the command
+	 * in the data buffer. Reply (if any) will be filled in the supplied
+	 * return buffer.
+	 *
+	 * The exact driver behavior is driver interface and vendor specific. As
+	 * an example, this will be converted to a vendor specific cfg80211
+	 * command in case of the nl80211 driver interface.
+	 */
+	int (*vendor_cmd)(void *priv, unsigned int vendor_id,
+			  unsigned int subcmd, const u8 *data, size_t data_len,
+			  struct wpabuf *buf);
+
+	/**
 	 * set_rekey_info - Set rekey information
 	 * @priv: Private driver interface data
 	 * @kek: Current KEK
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c509170..87c9661 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1239,6 +1239,16 @@
 			drv->if_disabled = 1;
 			wpa_supplicant_event(drv->ctx,
 					     EVENT_INTERFACE_DISABLED, NULL);
+
+			/*
+			 * Try to get drv again, since it may be removed as
+			 * part of the EVENT_INTERFACE_DISABLED handling for
+			 * dynamic interfaces
+			 */
+			drv = nl80211_find_drv(global, ifi->ifi_index,
+					       buf, len);
+			if (!drv)
+				return;
 		}
 	}
 
@@ -3808,6 +3818,15 @@
 	drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
 	drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
 
+	/*
+	 * As all cfg80211 drivers must support cases where the AP interface is
+	 * removed without the knowledge of wpa_supplicant/hostapd, e.g., in
+	 * case that the user space daemon has crashed, they must be able to
+	 * cleanup all stations and key entries in the AP tear down flow. Thus,
+	 * this flag can/should always be set for cfg80211 drivers.
+	 */
+	drv->capa.flags |= WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT;
+
 	if (!info.device_ap_sme) {
 		drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
 
@@ -9431,8 +9450,8 @@
 					name);
 
 		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
-		return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
-						    name);
+		nl80211_remove_iface(drv, if_nametoindex(name));
+		return 0;
 	}
 }
 
@@ -11710,6 +11729,106 @@
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+static int cmd_reply_handler(struct nl_msg *msg, void *arg)
+{
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct wpabuf *buf = arg;
+
+	if (!buf)
+		return NL_SKIP;
+
+	if ((size_t) genlmsg_attrlen(gnlh, 0) > wpabuf_tailroom(buf)) {
+		wpa_printf(MSG_INFO, "nl80211: insufficient buffer space for reply");
+		return NL_SKIP;
+	}
+
+	wpabuf_put_data(buf, genlmsg_attrdata(gnlh, 0),
+			genlmsg_attrlen(gnlh, 0));
+
+	return NL_SKIP;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static int vendor_reply_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct nlattr *nl_vendor_reply, *nl;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct wpabuf *buf = arg;
+	int rem;
+
+	if (!buf)
+		return NL_SKIP;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	nl_vendor_reply = tb[NL80211_ATTR_VENDOR_DATA];
+
+	if (!nl_vendor_reply)
+		return NL_SKIP;
+
+	if ((size_t) nla_len(nl_vendor_reply) > wpabuf_tailroom(buf)) {
+		wpa_printf(MSG_INFO, "nl80211: Vendor command: insufficient buffer space for reply");
+		return NL_SKIP;
+	}
+
+	nla_for_each_nested(nl, nl_vendor_reply, rem) {
+		wpabuf_put_data(buf, nla_data(nl), nla_len(nl));
+	}
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
+			      unsigned int subcmd, const u8 *data,
+			      size_t data_len, struct wpabuf *buf)
+{
+	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;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (vendor_id == 0xffffffff) {
+		nl80211_cmd(drv, msg, 0, subcmd);
+		if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
+		    0)
+			goto nla_put_failure;
+		ret = send_and_recv_msgs(drv, msg, cmd_reply_handler, buf);
+		if (ret)
+			wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
+				   ret);
+		return ret;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+	NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, vendor_id);
+	NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd);
+	if (data)
+		NLA_PUT(msg, NL80211_ATTR_VENDOR_DATA, data_len, data);
+
+	ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf);
+	if (ret)
+		wpa_printf(MSG_DEBUG, "nl80211: vendor command failed err=%d",
+			   ret);
+	return ret;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
 static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
 			       u8 qos_map_set_len)
 {
@@ -11829,5 +11948,6 @@
 #ifdef ANDROID
 	.driver_cmd = wpa_driver_nl80211_driver_cmd,
 #endif /* ANDROID */
+	.vendor_cmd = nl80211_vendor_cmd,
 	.set_qos_map = nl80211_set_qos_map,
 };
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 4b90989..c5bf41f 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1660,20 +1660,15 @@
 	case WLAN_PA_VENDOR_SPECIFIC:
 		data++;
 		len--;
-		if (len < 3)
+		if (len < 4)
 			return;
-		if (WPA_GET_BE24(data) != OUI_WFA)
+		if (WPA_GET_BE32(data) != P2P_IE_VENDOR_TYPE)
 			return;
 
-		data += 3;
-		len -= 3;
-		if (len < 1)
-			return;
+		data += 4;
+		len -= 4;
 
-		if (*data != P2P_OUI_TYPE)
-			return;
-
-		p2p_rx_p2p_action(p2p, sa, data + 1, len - 1, freq);
+		p2p_rx_p2p_action(p2p, sa, data, len, freq);
 		break;
 	case WLAN_PA_GAS_INITIAL_REQ:
 		p2p_rx_gas_initial_req(p2p, sa, data + 1, len - 1, freq);
@@ -1706,15 +1701,10 @@
 	if (len < 4)
 		return;
 
-	if (WPA_GET_BE24(data) != OUI_WFA)
+	if (WPA_GET_BE32(data) != P2P_IE_VENDOR_TYPE)
 		return;
-	data += 3;
-	len -= 3;
-
-	if (*data != P2P_OUI_TYPE)
-		return;
-	data++;
-	len--;
+	data += 4;
+	len -= 4;
 
 	/* P2P action frame */
 	p2p_dbg(p2p, "RX P2P Action from " MACSTR, MAC2STR(sa));
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 664fade..e9b683d 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -17,8 +17,7 @@
 void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token)
 {
 	wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC);
-	wpabuf_put_be24(buf, OUI_WFA);
-	wpabuf_put_u8(buf, P2P_OUI_TYPE);
+	wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
 
 	wpabuf_put_u8(buf, subtype); /* OUI Subtype */
 	wpabuf_put_u8(buf, dialog_token);
@@ -31,8 +30,7 @@
 {
 	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
 	wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC);
-	wpabuf_put_be24(buf, OUI_WFA);
-	wpabuf_put_u8(buf, P2P_OUI_TYPE);
+	wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
 
 	wpabuf_put_u8(buf, subtype); /* OUI Subtype */
 	wpabuf_put_u8(buf, dialog_token);
@@ -47,8 +45,7 @@
 	/* P2P IE header */
 	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
 	len = wpabuf_put(buf, 1); /* IE length to be filled */
-	wpabuf_put_be24(buf, OUI_WFA);
-	wpabuf_put_u8(buf, P2P_OUI_TYPE);
+	wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
 	wpa_printf(MSG_DEBUG, "P2P: * P2P IE header");
 	return len;
 }
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 26b9c2d..9df834c 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -171,8 +171,7 @@
 
 	/* ANQP Query Request Frame */
 	len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
-	wpabuf_put_be24(buf, OUI_WFA);
-	wpabuf_put_u8(buf, P2P_OUI_TYPE);
+	wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
 	wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
 	wpabuf_put_buf(buf, tlvs);
 	gas_anqp_set_element_len(buf, len_pos);
@@ -218,8 +217,7 @@
 	if (tlvs) {
 		/* ANQP Query Response Frame */
 		len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
-		wpabuf_put_be24(buf, OUI_WFA);
-		wpabuf_put_u8(buf, P2P_OUI_TYPE);
+		wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
 		 /* Service Update Indicator */
 		wpabuf_put_le16(buf, update_indic);
 		wpabuf_put_buf(buf, tlvs);
@@ -250,8 +248,7 @@
 		/* ANQP Query Response Frame */
 		wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
 		wpabuf_put_le16(buf, 3 + 1 + 2 + total_len);
-		wpabuf_put_be24(buf, OUI_WFA);
-		wpabuf_put_u8(buf, P2P_OUI_TYPE);
+		wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
 		/* Service Update Indicator */
 		wpabuf_put_le16(buf, update_indic);
 	}
@@ -393,17 +390,12 @@
 		return;
 	}
 
-	if (WPA_GET_BE24(pos) != OUI_WFA) {
-		p2p_dbg(p2p, "Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+	if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
+		p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
+			WPA_GET_BE32(pos));
 		return;
 	}
-	pos += 3;
-
-	if (*pos != P2P_OUI_TYPE) {
-		p2p_dbg(p2p, "Unsupported ANQP vendor type %u", *pos);
-		return;
-	}
-	pos++;
+	pos += 4;
 
 	if (pos + 2 > end)
 		return;
@@ -571,17 +563,12 @@
 		return;
 	}
 
-	if (WPA_GET_BE24(pos) != OUI_WFA) {
-		p2p_dbg(p2p, "Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+	if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
+		p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
+			WPA_GET_BE32(pos));
 		return;
 	}
-	pos += 3;
-
-	if (*pos != P2P_OUI_TYPE) {
-		p2p_dbg(p2p, "Unsupported ANQP vendor type %u", *pos);
-		return;
-	}
-	pos++;
+	pos += 4;
 
 	if (pos + 2 > end)
 		return;
@@ -795,17 +782,12 @@
 	if (pos + 4 > end)
 		return;
 
-	if (WPA_GET_BE24(pos) != OUI_WFA) {
-		p2p_dbg(p2p, "Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+	if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
+		p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
+			WPA_GET_BE32(pos));
 		return;
 	}
-	pos += 3;
-
-	if (*pos != P2P_OUI_TYPE) {
-		p2p_dbg(p2p, "Unsupported ANQP vendor type %u", *pos);
-		return;
-	}
-	pos++;
+	pos += 4;
 
 	if (pos + 2 > end)
 		return;
diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c
index 1ebcfe9..40bc1ad 100644
--- a/src/wps/wps_attr_parse.c
+++ b/src/wps/wps_attr_parse.c
@@ -59,6 +59,14 @@
 		}
 		attr->settings_delay_time = pos;
 		break;
+	case WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Configuration Methods length %u",
+				   len);
+			return -1;
+		}
+		attr->registrar_configuration_methods = pos;
+		break;
 	default:
 		wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
 			   "Extension subelement %u", id);
diff --git a/src/wps/wps_attr_parse.h b/src/wps/wps_attr_parse.h
index eeb08d1..82c4739 100644
--- a/src/wps/wps_attr_parse.h
+++ b/src/wps/wps_attr_parse.h
@@ -55,6 +55,7 @@
 	const u8 *network_key_shareable; /* 1 octet (Bool) */
 	const u8 *request_to_enroll; /* 1 octet (Bool) */
 	const u8 *ap_channel; /* 2 octets */
+	const u8 *registrar_configuration_methods; /* 2 octets */
 
 	/* variable length fields */
 	const u8 *manufacturer;
diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h
index 6f8a49f..e125048 100644
--- a/src/wps/wps_defs.h
+++ b/src/wps/wps_defs.h
@@ -146,7 +146,8 @@
 	WFA_ELEM_AUTHORIZEDMACS = 0x01,
 	WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02,
 	WFA_ELEM_REQUEST_TO_ENROLL = 0x03,
-	WFA_ELEM_SETTINGS_DELAY_TIME = 0x04
+	WFA_ELEM_SETTINGS_DELAY_TIME = 0x04,
+	WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS = 0x05
 };
 
 /* Device Password ID */
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index f150679..af27303 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -669,6 +669,9 @@
 		wpa_s->ap_iface->bss[0]->p2p_group = NULL;
 	wpas_p2p_group_deinit(wpa_s);
 #endif /* CONFIG_P2P */
+	wpa_s->ap_iface->driver_ap_teardown =
+		!!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+
 	hostapd_interface_deinit(wpa_s->ap_iface);
 	hostapd_interface_free(wpa_s->ap_iface);
 	wpa_s->ap_iface = NULL;
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 850a6cf..4f58130 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1118,6 +1118,9 @@
 	if (config->tdls_external_control)
 		fprintf(f, "tdls_external_control=%d\n",
 			config->tdls_external_control);
+
+	if (config->bgscan)
+		fprintf(f, "bgscan=\"%s\"\n", config->bgscan);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 793faec..2935ce7 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -5460,6 +5460,63 @@
 #endif /* ANDROID */
 
 
+static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
+				     char *buf, size_t buflen)
+{
+	int ret;
+	char *pos;
+	u8 *data = NULL;
+	unsigned int vendor_id, subcmd;
+	struct wpabuf *reply;
+	size_t data_len = 0;
+
+	/* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
+	vendor_id = strtoul(cmd, &pos, 16);
+	if (!isblank(*pos))
+		return -EINVAL;
+
+	subcmd = strtoul(pos, &pos, 10);
+
+	if (*pos != '\0') {
+		if (!isblank(*pos++))
+			return -EINVAL;
+		data_len = os_strlen(pos);
+	}
+
+	if (data_len) {
+		data_len /= 2;
+		data = os_malloc(data_len);
+		if (!data)
+			return -ENOBUFS;
+
+		if (hexstr2bin(pos, data, data_len)) {
+			wpa_printf(MSG_DEBUG,
+				   "Vendor command: wrong parameter format");
+			os_free(data);
+			return -EINVAL;
+		}
+	}
+
+	reply = wpabuf_alloc((buflen - 1) / 2);
+	if (!reply) {
+		os_free(data);
+		return -ENOBUFS;
+	}
+
+	ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len,
+				 reply);
+
+	if (ret == 0)
+		ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
+				       wpabuf_len(reply));
+
+	wpabuf_free(reply);
+	os_free(data);
+
+	return ret;
+}
+
+
 static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
 {
 	wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
@@ -6345,6 +6402,9 @@
 		reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
 						      reply_size);
 #endif /* ANDROID */
+	} else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
+		reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply,
+						      reply_size);
 	} else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
 		pmksa_cache_clear_current(wpa_s->wpa);
 		eapol_sm_request_reauth(wpa_s->eapol);
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 0691b6c..b336afb 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -604,4 +604,14 @@
 					  qos_map_set_len);
 }
 
+static inline int wpa_drv_vendor_cmd(struct wpa_supplicant *wpa_s,
+				     int vendor_id, int subcmd, const u8 *data,
+				     size_t data_len, struct wpabuf *buf)
+{
+	if (!wpa_s->driver->vendor_cmd)
+		return -1;
+	return wpa_s->driver->vendor_cmd(wpa_s->drv_priv, vendor_id, subcmd,
+					 data, data_len, buf);
+}
+
 #endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 0691183..63ea1df 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2426,6 +2426,12 @@
 #endif /* ANDROID */
 
 
+static int wpa_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "VENDOR", 1, argc, argv);
+}
+
+
 static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	return wpa_ctrl_command(ctrl, "FLUSH");
@@ -2912,6 +2918,9 @@
 #endif /* ANDROID */
 	{ "radio_work", wpa_cli_cmd_radio_work, NULL, cli_cmd_flag_none,
 	  "= radio_work <show/add/done>" },
+	{ "vendor", wpa_cli_cmd_vendor, NULL, cli_cmd_flag_none,
+	  "<vendor id> <command id> [<hex formatted command argument>] = Send vendor command"
+	},
 	{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
 };
 
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index ad1a03e..46195b1 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -573,12 +573,16 @@
 		name = wpa_s->current_ssid->bgscan;
 	else
 		name = wpa_s->conf->bgscan;
-	if (name == NULL)
+	if (name == NULL || name[0] == '\0')
 		return;
 	if (wpas_driver_bss_selection(wpa_s))
 		return;
 	if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
 		return;
+#ifdef CONFIG_P2P
+	if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
+		return;
+#endif /* CONFIG_P2P */
 
 	bgscan_deinit(wpa_s);
 	if (wpa_s->current_ssid) {
@@ -2669,7 +2673,8 @@
 			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 			interface_count = 0;
 		}
-		if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
+		if (!wpa_s->p2p_mgmt &&
+		    wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
 						      100000))
 			wpa_supplicant_req_scan(wpa_s, interface_count,
 						100000);
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 442b44c..03c6f5f 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -603,6 +603,8 @@
 # bgscan="learn:<short bgscan interval in seconds>:<signal strength threshold>:
 # <long interval>[:<database file name>]"
 # bgscan="learn:30:-45:300:/etc/wpa_supplicant/network1.bgscan"
+# Explicitly disable bgscan by setting
+# 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