am a3dc3096: Cumulative patch from commit f43c1ae7989c38fe15756f12a9196a1cf798b4d7

* commit 'a3dc30964aa24aea2b518246f6812663a1103490':
  Cumulative patch from commit f43c1ae7989c38fe15756f12a9196a1cf798b4d7
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 10f50d8..49f43f1 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -892,6 +892,7 @@
 
 OBJS_c = hostapd_cli.c src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
 OBJS_c += src/utils/eloop.c
+OBJS_c += src/utils/common.c
 ifdef CONFIG_WPA_TRACE
 OBJS_c += src/utils/trace.c
 endif
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 3c7bd6f..d4fd36e 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -108,6 +108,7 @@
 endif
 
 OBJS += ../src/utils/common.o
+OBJS_c += ../src/utils/common.o
 OBJS += ../src/utils/wpa_debug.o
 OBJS_c += ../src/utils/wpa_debug.o
 OBJS += ../src/utils/wpabuf.o
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index c3573a4..c14eeda 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -117,9 +117,6 @@
 	int dynamic_vlan;
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 
-#define DVLAN_CLEAN_BR 	0x1
-#define DVLAN_CLEAN_VLAN	0x2
-#define DVLAN_CLEAN_VLAN_PORT	0x4
 #define DVLAN_CLEAN_WLAN_PORT	0x8
 	int clean;
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 60c8f8c..f3f7edd 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -633,7 +633,7 @@
 {
 	if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
 		return 0;
-	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack);
+	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0);
 }
 
 
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 75cc24e..be5c7a8 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -49,6 +49,9 @@
 	struct hostapd_iface **iface;
 
 	size_t terminate_on_error;
+#ifndef CONFIG_NO_VLAN
+	struct dynamic_iface *vlan_priv;
+#endif /* CONFIG_NO_VLAN */
 };
 
 enum hostapd_chan_status {
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index b89a1f4..fd1c8dd 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -35,6 +35,90 @@
 	int s; /* socket on which to listen for new/removed interfaces. */
 };
 
+#define DVLAN_CLEAN_BR         0x1
+#define DVLAN_CLEAN_VLAN       0x2
+#define DVLAN_CLEAN_VLAN_PORT  0x4
+
+struct dynamic_iface {
+	char ifname[IFNAMSIZ + 1];
+	int usage;
+	int clean;
+	struct dynamic_iface *next;
+};
+
+
+/* Increment ref counter for ifname and add clean flag.
+ * If not in list, add it only if some flags are given.
+ */
+static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
+			  int clean)
+{
+	struct dynamic_iface *next, **dynamic_ifaces;
+	struct hapd_interfaces *interfaces;
+
+	interfaces = hapd->iface->interfaces;
+	dynamic_ifaces = &interfaces->vlan_priv;
+
+	for (next = *dynamic_ifaces; next; next = next->next) {
+		if (os_strcmp(ifname, next->ifname) == 0)
+			break;
+	}
+
+	if (next) {
+		next->usage++;
+		next->clean |= clean;
+		return;
+	}
+
+	if (!clean)
+		return;
+
+	next = os_zalloc(sizeof(*next));
+	if (!next)
+		return;
+	os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
+	next->usage = 1;
+	next->clean = clean;
+	next->next = *dynamic_ifaces;
+	*dynamic_ifaces = next;
+}
+
+
+/* Decrement reference counter for given ifname.
+ * Return clean flag iff reference counter was decreased to zero, else zero
+ */
+static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
+{
+	struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
+	struct hapd_interfaces *interfaces;
+	int clean;
+
+	interfaces = hapd->iface->interfaces;
+	dynamic_ifaces = &interfaces->vlan_priv;
+
+	for (next = *dynamic_ifaces; next; next = next->next) {
+		if (os_strcmp(ifname, next->ifname) == 0)
+			break;
+		prev = next;
+	}
+
+	if (!next)
+		return 0;
+
+	next->usage--;
+	if (next->usage)
+		return 0;
+
+	if (prev)
+		prev->next = next->next;
+	else
+		*dynamic_ifaces = next->next;
+	clean = next->clean;
+	os_free(next);
+
+	return clean;
+}
+
 
 static int ifconfig_helper(const char *if_name, int up)
 {
@@ -482,6 +566,7 @@
 	struct hostapd_vlan *vlan = hapd->conf->vlan;
 	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
 	int vlan_naming = hapd->conf->ssid.vlan_naming;
+	int clean;
 
 	wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
 
@@ -502,8 +587,8 @@
 				            "brvlan%d", vlan->vlan_id);
 			}
 
-			if (!br_addbr(br_name))
-				vlan->clean |= DVLAN_CLEAN_BR;
+			dyn_iface_get(hapd, br_name,
+				      br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
 
 			ifconfig_up(br_name);
 
@@ -519,13 +604,16 @@
 						    sizeof(vlan_ifname),
 						    "vlan%d", vlan->vlan_id);
 
+				clean = 0;
 				ifconfig_up(tagged_interface);
 				if (!vlan_add(tagged_interface, vlan->vlan_id,
 					      vlan_ifname))
-					vlan->clean |= DVLAN_CLEAN_VLAN;
+					clean |= DVLAN_CLEAN_VLAN;
 
 				if (!br_addif(br_name, vlan_ifname))
-					vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
+					clean |= DVLAN_CLEAN_VLAN_PORT;
+
+				dyn_iface_get(hapd, vlan_ifname, clean);
 
 				ifconfig_up(vlan_ifname);
 			}
@@ -549,13 +637,15 @@
 	struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
 	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
 	int vlan_naming = hapd->conf->ssid.vlan_naming;
+	int clean;
 
 	wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
 
 	first = prev = vlan;
 
 	while (vlan) {
-		if (os_strcmp(ifname, vlan->ifname) == 0) {
+		if (os_strcmp(ifname, vlan->ifname) == 0 &&
+		    vlan->configured) {
 			if (hapd->conf->vlan_bridge[0]) {
 				os_snprintf(br_name, sizeof(br_name), "%s%d",
 					    hapd->conf->vlan_bridge,
@@ -583,20 +673,27 @@
 					os_snprintf(vlan_ifname,
 						    sizeof(vlan_ifname),
 						    "vlan%d", vlan->vlan_id);
-				if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
-					br_delif(br_name, vlan_ifname);
-				ifconfig_down(vlan_ifname);
 
-				if (vlan->clean & DVLAN_CLEAN_VLAN)
+				clean = dyn_iface_put(hapd, vlan_ifname);
+
+				if (clean & DVLAN_CLEAN_VLAN_PORT)
+					br_delif(br_name, vlan_ifname);
+
+				if (clean & DVLAN_CLEAN_VLAN) {
+					ifconfig_down(vlan_ifname);
 					vlan_rem(vlan_ifname);
+				}
 			}
 
-			if ((vlan->clean & DVLAN_CLEAN_BR) &&
+			clean = dyn_iface_put(hapd, br_name);
+			if ((clean & DVLAN_CLEAN_BR) &&
 			    br_getnumports(br_name) == 0) {
 				ifconfig_down(br_name);
 				br_delbr(br_name);
 			}
+		}
 
+		if (os_strcmp(ifname, vlan->ifname) == 0) {
 			if (vlan == first) {
 				hapd->conf->vlan = vlan->next;
 			} else {
@@ -975,8 +1072,12 @@
 	if (vlan == NULL)
 		return 1;
 
-	if (vlan->dynamic_vlan == 0)
+	if (vlan->dynamic_vlan == 0) {
 		hostapd_vlan_if_remove(hapd, vlan->ifname);
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+		vlan_dellink(vlan->ifname, hapd);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+	}
 
 	return 0;
 }
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 56b1122..d69448b 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -1,6 +1,6 @@
 /*
  * common module tests
- * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,8 @@
 
 #include "utils/common.h"
 #include "ieee802_11_common.h"
+#include "ieee802_11_defs.h"
+#include "gas.h"
 #include "wpa_common.h"
 
 
@@ -46,6 +48,10 @@
 	{ (u8 *) "\x6e\x00", 2, ParseOK, 1 },
 	{ (u8 *) "\xc7\x00", 2, ParseOK, 1 },
 	{ (u8 *) "\xc7\x01\x00", 3, ParseOK, 1 },
+	{ (u8 *) "\x03\x00\x2a\x00\x36\x00\x37\x00\x38\x00\x2d\x00\x3d\x00\xbf\x00\xc0\x00",
+	  18, ParseOK, 9 },
+	{ (u8 *) "\x8b\x00", 2, ParseOK, 1 },
+	{ (u8 *) "\xdd\x04\x00\x90\x4c\x04", 6, ParseUnknown, 1 },
 	{ NULL, 0, ParseOK, 0 }
 };
 
@@ -158,6 +164,34 @@
 }
 
 
+static int gas_tests(void)
+{
+	struct wpabuf *buf;
+
+	wpa_printf(MSG_INFO, "gas tests");
+	gas_anqp_set_len(NULL);
+
+	buf = wpabuf_alloc(1);
+	if (buf == NULL)
+		return -1;
+	gas_anqp_set_len(buf);
+	wpabuf_free(buf);
+
+	buf = wpabuf_alloc(20);
+	if (buf == NULL)
+		return -1;
+	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+	wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ);
+	wpabuf_put_u8(buf, 0);
+	wpabuf_put_be32(buf, 0);
+	wpabuf_put_u8(buf, 0);
+	gas_anqp_set_len(buf);
+	wpabuf_free(buf);
+
+	return 0;
+}
+
+
 int common_module_tests(void)
 {
 	int ret = 0;
@@ -165,6 +199,7 @@
 	wpa_printf(MSG_INFO, "common module tests");
 
 	if (ieee802_11_parse_tests() < 0 ||
+	    gas_tests() < 0 ||
 	    rsn_ie_parse_tests() < 0)
 		ret = -1;
 
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index e23007a..82dd707 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -580,7 +580,7 @@
 };
 
 static const char *const cn_op_class_cc[] = {
-	"CN", "CA", NULL
+	"CN", NULL
 };
 
 
@@ -630,6 +630,10 @@
 		if (chan < 149 || chan > 161)
 			return -1;
 		return 5000 + 5 * chan;
+	case 5: /* channels 149,153,157,161,165 */
+		if (chan < 149 || chan > 165)
+			return -1;
+		return 5000 + 5 * chan;
 	case 34: /* 60 GHz band, channels 1..3 */
 		if (chan < 1 || chan > 3)
 			return -1;
@@ -782,12 +786,15 @@
 			return -1;
 		return 5000 + 5 * chan;
 	case 124: /* channels 149,153,157,161 */
-	case 125: /* channels 149,153,157,161,165,169 */
 	case 126: /* channels 149,157; 40 MHz */
 	case 127: /* channels 153,161; 40 MHz */
 		if (chan < 149 || chan > 161)
 			return -1;
 		return 5000 + 5 * chan;
+	case 125: /* channels 149,153,157,161,165,169 */
+		if (chan < 149 || chan > 169)
+			return -1;
+		return 5000 + 5 * chan;
 	case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
 	case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
 		if (chan < 36 || chan > 161)
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 8f28ca8..37ab000 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -2770,8 +2770,11 @@
 	}
 
 	rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
-	if (rnd == NULL)
+	if (!rnd) {
+		os_free(tmp_out);
 		return -1;
+	}
+
 	if (server_random_first) {
 		os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE);
 		os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random,
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 0324339..d452d8c 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1940,10 +1940,12 @@
 	 * @data: IEEE 802.11 management frame with IEEE 802.11 header
 	 * @data_len: Size of the management frame
 	 * @noack: Do not wait for this frame to be acked (disable retries)
+	 * @freq: Frequency (in MHz) to send the frame on, or 0 to let the
+	 * driver decide
 	 * Returns: 0 on success, -1 on failure
 	 */
 	int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
-			 int noack);
+			 int noack, unsigned int freq);
 
 	/**
 	 * update_ft_ies - Update FT (IEEE 802.11r) IEs
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index b8e7864..aaada0a 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -1840,7 +1840,7 @@
 #ifdef CONFIG_IEEE80211R
 
 static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
-			     int noack)
+			     int noack, unsigned int freq)
 {
 	struct atheros_driver_data *drv = priv;
 	u8 buf[1510];
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 84b98fb..14c52d2 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -266,7 +266,8 @@
 }
 
 
-static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack)
+static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack,
+			    unsigned int freq)
 {
 	struct hostap_driver_data *drv = priv;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 590731d..20f5321 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -87,7 +87,6 @@
 #undef nl_socket_set_nonblocking
 #define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
 
-#define genl_ctrl_resolve android_genl_ctrl_resolve
 #endif /* ANDROID */
 
 
@@ -7245,11 +7244,12 @@
 
 
 static int driver_nl80211_send_mlme(void *priv, const u8 *data,
-				    size_t data_len, int noack)
+				    size_t data_len, int noack,
+				    unsigned int freq)
 {
 	struct i802_bss *bss = priv;
 	return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
-					    0, 0, 0, 0);
+					    freq, 0, 0, 0);
 }
 
 
@@ -7807,7 +7807,7 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
 
-	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WOWLAN)) ||
+	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
 	    !(wowlan_triggers = nla_nest_start(msg,
 					       NL80211_ATTR_WOWLAN_TRIGGERS)) ||
 	    (triggers->any &&
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index b5071b4..acfe959 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -232,7 +232,6 @@
 
 #ifdef ANDROID
 int android_nl_socket_set_nonblocking(struct nl_handle *handle);
-int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name);
 int android_pno_start(struct i802_bss *bss,
 		      struct wpa_driver_scan_params *params);
 int android_pno_stop(struct i802_bss *bss);
diff --git a/src/drivers/driver_nl80211_android.c b/src/drivers/driver_nl80211_android.c
index 3cc9a65..f3a39f6 100644
--- a/src/drivers/driver_nl80211_android.c
+++ b/src/drivers/driver_nl80211_android.c
@@ -188,33 +188,3 @@
 }
 
 
-int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name)
-{
-	/*
-	 * Android ICS has very minimal genl_ctrl_resolve() implementation, so
-	 * need to work around that.
-	 */
-	struct nl_cache *cache = NULL;
-	struct genl_family *nl80211 = NULL;
-	int id = -1;
-
-	if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache");
-		goto fail;
-	}
-
-	nl80211 = genl_ctrl_search_by_name(cache, name);
-	if (nl80211 == NULL)
-		goto fail;
-
-	id = genl_family_get_id(nl80211);
-
-fail:
-	if (nl80211)
-		genl_family_put(nl80211);
-	if (cache)
-		nl_cache_free(cache);
-
-	return id;
-}
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 248b57b..f636e74 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -267,8 +267,8 @@
 }
 
 
-static void eap_fast_derive_key_auth(struct eap_sm *sm,
-				     struct eap_fast_data *data)
+static int eap_fast_derive_key_auth(struct eap_sm *sm,
+				    struct eap_fast_data *data)
 {
 	u8 *sks;
 
@@ -281,7 +281,7 @@
 	if (sks == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
 			   "session_key_seed");
-		return;
+		return -1;
 	}
 
 	/*
@@ -294,11 +294,12 @@
 	data->simck_idx = 0;
 	os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
 	os_free(sks);
+	return 0;
 }
 
 
-static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
-					     struct eap_fast_data *data)
+static int eap_fast_derive_key_provisioning(struct eap_sm *sm,
+					    struct eap_fast_data *data)
 {
 	os_free(data->key_block_p);
 	data->key_block_p = (struct eap_fast_key_block_provisioning *)
@@ -307,7 +308,7 @@
 				    sizeof(*data->key_block_p));
 	if (data->key_block_p == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
-		return;
+		return -1;
 	}
 	/*
 	 * RFC 4851, Section 5.2:
@@ -326,15 +327,19 @@
 	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
 			data->key_block_p->client_challenge,
 			sizeof(data->key_block_p->client_challenge));
+	return 0;
 }
 
 
-static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
+static int eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
 {
+	int res;
+
 	if (data->anon_provisioning)
-		eap_fast_derive_key_provisioning(sm, data);
+		res = eap_fast_derive_key_provisioning(sm, data);
 	else
-		eap_fast_derive_key_auth(sm, data);
+		res = eap_fast_derive_key_auth(sm, data);
+	return res;
 }
 
 
@@ -1586,7 +1591,14 @@
 			} else
 				data->anon_provisioning = 0;
 			data->resuming = 0;
-			eap_fast_derive_keys(sm, data);
+			if (eap_fast_derive_keys(sm, data) < 0) {
+				wpa_printf(MSG_DEBUG,
+					   "EAP-FAST: Could not derive keys");
+				ret->methodState = METHOD_DONE;
+				ret->decision = DECISION_FAIL;
+				wpabuf_free(resp);
+				return NULL;
+			}
 		}
 
 		if (res == 2) {
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index c02044b..16ffac4 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -297,7 +297,7 @@
 		return;
 	}
 
-	ies = p2p_build_probe_resp_ies(p2p);
+	ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
 	if (ies == NULL)
 		return;
 
@@ -346,7 +346,7 @@
 		return 0;
 	}
 
-	ies = p2p_build_probe_resp_ies(p2p);
+	ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
 	if (ies == NULL)
 		return -1;
 
@@ -468,7 +468,8 @@
 
 static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
 				 const u8 *go_interface_addr, int freq,
-				 const u8 *gi, size_t gi_len)
+				 const u8 *gi, size_t gi_len,
+				 struct os_reltime *rx_time)
 {
 	struct p2p_group_info info;
 	size_t c;
@@ -536,10 +537,11 @@
 
 		os_memcpy(dev->interface_addr, cli->p2p_interface_addr,
 			  ETH_ALEN);
-		os_get_reltime(&dev->last_seen);
+		os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_reltime));
 		os_memcpy(dev->member_in_go_dev, go_dev_addr, ETH_ALEN);
 		os_memcpy(dev->member_in_go_iface, go_interface_addr,
 			  ETH_ALEN);
+		dev->flags |= P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT;
 	}
 
 	return 0;
@@ -758,22 +760,30 @@
 
 	/*
 	 * Update the device entry only if the new peer
-	 * entry is newer than the one previously stored.
+	 * entry is newer than the one previously stored, or if
+	 * the device was previously seen as a P2P Client in a group
+	 * and the new entry isn't older than a threshold.
 	 */
 	if (dev->last_seen.sec > 0 &&
-	    os_reltime_before(rx_time, &dev->last_seen)) {
-		p2p_dbg(p2p, "Do not update peer entry based on old frame (rx_time=%u.%06u last_seen=%u.%06u)",
+	    os_reltime_before(rx_time, &dev->last_seen) &&
+	    (!(dev->flags & P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT) ||
+	     os_reltime_expired(&dev->last_seen, rx_time,
+				P2P_DEV_GROUP_CLIENT_RESP_THRESHOLD))) {
+		p2p_dbg(p2p,
+			"Do not update peer entry based on old frame (rx_time=%u.%06u last_seen=%u.%06u flags=0x%x)",
 			(unsigned int) rx_time->sec,
 			(unsigned int) rx_time->usec,
 			(unsigned int) dev->last_seen.sec,
-			(unsigned int) dev->last_seen.usec);
+			(unsigned int) dev->last_seen.usec,
+			dev->flags);
 		p2p_parse_free(&msg);
 		return -1;
 	}
 
 	os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_reltime));
 
-	dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
+	dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY |
+			P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT);
 
 	if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0)
 		os_memcpy(dev->interface_addr, addr, ETH_ALEN);
@@ -844,7 +854,8 @@
 
 	if (scan_res) {
 		p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq,
-				      msg.group_info, msg.group_info_len);
+				      msg.group_info, msg.group_info_len,
+				      rx_time);
 	}
 
 	p2p_parse_free(&msg);
@@ -1128,6 +1139,8 @@
 
 	adv_array = (u8 *) str_buf;
 	adv_len = os_strlen(str);
+	if (adv_len >= sizeof(str_buf))
+		return 0;
 
 	for (i = 0; str[i] && i < adv_len; i++) {
 		if (str[i] >= 'A' && str[i] <= 'Z')
@@ -1183,27 +1196,25 @@
 		 * An empty seek string means no hash values, but still an ASP
 		 * search.
 		 */
+		p2p_dbg(p2p, "ASP search");
 		p2p->p2ps_seek_count = 0;
 		p2p->p2ps_seek = 1;
 	} else if (seek && seek_count <= P2P_MAX_QUERY_HASH) {
 		u8 buf[P2PS_HASH_LEN];
-		int i;
+		int i, count = 0;
 
-		p2p->p2ps_seek_count = seek_count;
 		for (i = 0; i < seek_count; i++) {
 			if (!p2ps_gen_hash(p2p, seek[i], buf))
 				continue;
 
-			/* If asking for wildcard, don't do others */
-			if (os_memcmp(buf, p2p->wild_card_hash,
-				      P2PS_HASH_LEN) == 0) {
-				p2p->p2ps_seek_count = 0;
-				break;
-			}
-
-			os_memcpy(&p2p->query_hash[i * P2PS_HASH_LEN], buf,
-				  P2PS_HASH_LEN);
+			p2p_dbg(p2p, "Seek service %s hash " MACSTR,
+				seek[i], MAC2STR(buf));
+			os_memcpy(&p2p->p2ps_seek_hash[count * P2PS_HASH_LEN],
+				  buf, P2PS_HASH_LEN);
+			count++;
 		}
+
+		p2p->p2ps_seek_count = count;
 		p2p->p2ps_seek = 1;
 	} else {
 		p2p->p2ps_seek_count = 0;
@@ -1213,7 +1224,8 @@
 	/* Special case to perform wildcard search */
 	if (p2p->p2ps_seek_count == 0 && p2p->p2ps_seek) {
 		p2p->p2ps_seek_count = 1;
-		os_memcpy(&p2p->query_hash, p2p->wild_card_hash, P2PS_HASH_LEN);
+		os_memcpy(&p2p->p2ps_seek_hash, p2p->wild_card_hash,
+			  P2PS_HASH_LEN);
 	}
 
 	p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
@@ -1381,7 +1393,7 @@
 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_5ghz[] = { 124, 125, 115, 0 };
 	const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
 	const int op_classes_vht[] = { 128, 0 };
 
@@ -2148,7 +2160,9 @@
 }
 
 
-struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
+struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p,
+					 const u8 *query_hash,
+					 u8 query_count)
 {
 	struct wpabuf *buf;
 	u8 *len;
@@ -2163,7 +2177,7 @@
 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P])
 		extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]);
 
-	if (p2p->query_count)
+	if (query_count)
 		extra += MAX_SVC_ADV_IE_LEN;
 
 	buf = wpabuf_alloc(1000 + extra);
@@ -2200,9 +2214,8 @@
 	p2p_buf_add_device_info(buf, p2p, NULL);
 	p2p_buf_update_ie_hdr(buf, len);
 
-	if (p2p->query_count) {
-		p2p_buf_add_service_instance(buf, p2p, p2p->query_count,
-					     p2p->query_hash,
+	if (query_count) {
+		p2p_buf_add_service_instance(buf, p2p, query_count, query_hash,
 					     p2p->p2ps_adv_list);
 	}
 
@@ -2213,18 +2226,21 @@
 static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
 {
 	struct p2ps_advertisement *adv_data;
+	int any_wfa;
 
 	p2p_dbg(p2p, "ASP find - ASP list: %p", p2p->p2ps_adv_list);
 
-	/* Wildcard always matches if we have actual services */
-	if (os_memcmp(hash, p2p->wild_card_hash, P2PS_HASH_LEN) == 0)
-		return p2p->p2ps_adv_list != NULL;
+	/* Wildcard org.wi-fi.wfds matches any WFA spec defined service */
+	any_wfa = os_memcmp(hash, p2p->wild_card_hash, P2PS_HASH_LEN) == 0;
 
 	adv_data = p2p->p2ps_adv_list;
 	while (adv_data) {
-		p2p_dbg(p2p, "ASP hash: %x =? %x", hash[0], adv_data->hash[0]);
 		if (os_memcmp(hash, adv_data->hash, P2PS_HASH_LEN) == 0)
-			return 1;
+			return 1; /* exact hash match */
+		if (any_wfa &&
+		    os_strncmp(adv_data->svc_name, P2PS_WILD_HASH_STR,
+			       os_strlen(P2PS_WILD_HASH_STR)) == 0)
+			return 1; /* WFA service match */
 		adv_data = adv_data->next;
 	}
 
@@ -2234,13 +2250,15 @@
 
 static enum p2p_probe_req_status
 p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
-		const u8 *bssid, const u8 *ie, size_t ie_len)
+		const u8 *bssid, const u8 *ie, size_t ie_len,
+		unsigned int rx_freq)
 {
 	struct ieee802_11_elems elems;
 	struct wpabuf *buf;
 	struct ieee80211_mgmt *resp;
 	struct p2p_message msg;
 	struct wpabuf *ies;
+	u8 channel, op_class;
 
 	if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
 	    ParseFailed) {
@@ -2292,53 +2310,29 @@
 		return P2P_PREQ_NOT_P2P;
 	}
 
-	p2p->p2ps_svc_found = 0;
-
 	if (msg.service_hash && msg.service_hash_count) {
 		const u8 *hash = msg.service_hash;
-		u8 *dest = p2p->query_hash;
 		u8 i;
+		int p2ps_svc_found = 0;
 
-		p2p->query_count = 0;
 		for (i = 0; i < msg.service_hash_count; i++) {
 			if (p2p_service_find_asp(p2p, hash)) {
-				p2p->p2ps_svc_found = 1;
-
-				if (!os_memcmp(hash, p2p->wild_card_hash,
-					       P2PS_HASH_LEN)) {
-					/* We found match(es) but wildcard
-					 * will return all */
-					p2p->query_count = 1;
-					os_memcpy(p2p->query_hash, hash,
-						  P2PS_HASH_LEN);
-					break;
-				}
-
-				/* Save each matching hash */
-				if (p2p->query_count < P2P_MAX_QUERY_HASH) {
-					os_memcpy(dest, hash, P2PS_HASH_LEN);
-					dest += P2PS_HASH_LEN;
-					p2p->query_count++;
-				} else {
-					/* We found match(es) but too many to
-					 * return all */
-					p2p->query_count = 0;
-					break;
-				}
+				p2p_dbg(p2p, "Service Hash match found: "
+					MACSTR, MAC2STR(hash));
+				p2ps_svc_found = 1;
+				break;
 			}
 			hash += P2PS_HASH_LEN;
 		}
 
-		p2p_dbg(p2p, "ASP adv found: %d", p2p->p2ps_svc_found);
-
 		/* Probed hash unknown */
-		if (!p2p->p2ps_svc_found) {
+		if (!p2ps_svc_found) {
+			p2p_dbg(p2p, "No Service Hash match found");
 			p2p_parse_free(&msg);
 			return P2P_PREQ_NOT_PROCESSED;
 		}
 	} else {
 		/* This is not a P2PS Probe Request */
-		p2p->query_count = 0;
 		p2p_dbg(p2p, "No P2PS Hash in Probe Request");
 
 		if (!p2p->in_listen || !p2p->drv_in_listen) {
@@ -2367,11 +2361,11 @@
 		p2p_parse_free(&msg);
 		return P2P_PREQ_NOT_PROCESSED;
 	}
-	p2p_parse_free(&msg);
 
 	if (!p2p->cfg->send_probe_resp) {
 		/* Response generated elsewhere */
 		p2p_dbg(p2p, "Probe Resp generated elsewhere - do not generate additional response");
+		p2p_parse_free(&msg);
 		return P2P_PREQ_NOT_PROCESSED;
 	}
 
@@ -2383,7 +2377,9 @@
 	 * really only used for discovery purposes, not to learn exact BSS
 	 * parameters.
 	 */
-	ies = p2p_build_probe_resp_ies(p2p);
+	ies = p2p_build_probe_resp_ies(p2p, msg.service_hash,
+				       msg.service_hash_count);
+	p2p_parse_free(&msg);
 	if (ies == NULL)
 		return P2P_PREQ_NOT_PROCESSED;
 
@@ -2423,32 +2419,50 @@
 	wpabuf_put_u8(buf, 480 / 5);
 	wpabuf_put_u8(buf, 540 / 5);
 
+	if (!rx_freq) {
+		channel = p2p->cfg->channel;
+	} else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
+		wpabuf_free(ies);
+		wpabuf_free(buf);
+		return P2P_PREQ_NOT_PROCESSED;
+	}
+
 	wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
 	wpabuf_put_u8(buf, 1);
-	wpabuf_put_u8(buf, p2p->cfg->channel);
+	wpabuf_put_u8(buf, channel);
 
 	wpabuf_put_buf(buf, ies);
 	wpabuf_free(ies);
 
-	p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf);
+	p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf, rx_freq);
 
 	wpabuf_free(buf);
 
-	return P2P_PREQ_NOT_PROCESSED;
+	return P2P_PREQ_PROCESSED;
 }
 
 
 enum p2p_probe_req_status
 p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
-		 const u8 *bssid, const u8 *ie, size_t ie_len)
+		 const u8 *bssid, const u8 *ie, size_t ie_len,
+		 unsigned int rx_freq)
 {
 	enum p2p_probe_req_status res;
 
 	p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
 
-	res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
-	p2p->query_count = 0;
+	res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len, rx_freq);
+	if (res != P2P_PREQ_PROCESSED && res != P2P_PREQ_NOT_PROCESSED)
+		return res;
 
+	/*
+	 * Activate a pending GO Negotiation/Invite flow if a received Probe
+	 * Request frame is from an expected peer. Some devices may share the
+	 * same address for P2P and non-P2P STA running simultaneously. The
+	 * P2P_PREQ_PROCESSED and P2P_PREQ_NOT_PROCESSED p2p_reply_probe()
+	 * return values verified above ensure we are handling a Probe Request
+	 * frame from a P2P peer.
+	 */
 	if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
 	    p2p->go_neg_peer &&
 	    os_memcmp(addr, p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN)
@@ -2458,7 +2472,7 @@
 		p2p_dbg(p2p, "Found GO Negotiation peer - try to start GO negotiation from timeout");
 		eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
 		eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
-		return P2P_PREQ_PROCESSED;
+		return res;
 	}
 
 	if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) &&
@@ -2470,7 +2484,7 @@
 		p2p_dbg(p2p, "Found Invite peer - try to start Invite from timeout");
 		eloop_cancel_timeout(p2p_invite_start, p2p, NULL);
 		eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
-		return P2P_PREQ_PROCESSED;
+		return res;
 	}
 
 	return res;
@@ -2937,7 +2951,7 @@
 	os_free(p2p->cfg->serial_number);
 	os_free(p2p->cfg->pref_chan);
 	os_free(p2p->groups);
-	os_free(p2p->p2ps_prov);
+	p2ps_prov_free(p2p);
 	wpabuf_free(p2p->sd_resp);
 	os_free(p2p->after_scan_tx);
 	p2p_remove_wps_vendor_extensions(p2p);
@@ -4143,7 +4157,7 @@
 			  "country=%c%c\n"
 			  "oper_freq=%d\n"
 			  "req_config_methods=0x%x\n"
-			  "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
+			  "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
 			  "status=%d\n"
 			  "invitation_reqs=%u\n",
 			  (int) (now.sec - dev->last_seen.sec),
@@ -4187,6 +4201,8 @@
 			  "[FORCE_FREQ]" : "",
 			  dev->flags & P2P_DEV_PD_FOR_JOIN ?
 			  "[PD_FOR_JOIN]" : "",
+			  dev->flags & P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT ?
+			  "[LAST_SEEN_AS_GROUP_CLIENT]" : "",
 			  dev->status,
 			  dev->invitation_reqs);
 	if (os_snprintf_error(end - pos, res))
@@ -5238,6 +5254,7 @@
 
 	if (!msg.oob_go_neg_channel) {
 		p2p_dbg(p2p, "OOB GO Negotiation Channel attribute not included");
+		p2p_parse_free(&msg);
 		return -1;
 	}
 
@@ -5249,6 +5266,7 @@
 					   msg.oob_go_neg_channel[4]);
 	if (freq < 0) {
 		p2p_dbg(p2p, "Unknown peer OOB GO Neg channel");
+		p2p_parse_free(&msg);
 		return -1;
 	}
 	role = msg.oob_go_neg_channel[5];
@@ -5269,6 +5287,7 @@
 					   p2p->cfg->channel);
 		if (freq < 0) {
 			p2p_dbg(p2p, "Own listen channel not known");
+			p2p_parse_free(&msg);
 			return -1;
 		}
 		p2p_dbg(p2p, "Use own Listen channel as OOB GO Neg channel: %u MHz", freq);
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 6b0ba80..67b8bdb 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -570,12 +570,14 @@
 	 * send_probe_resp - Transmit a Probe Response frame
 	 * @ctx: Callback context from cb_ctx
 	 * @buf: Probe Response frame (including the header and body)
+	 * @freq: Forced frequency (in MHz) to use or 0.
 	 * Returns: 0 on success, -1 on failure
 	 *
 	 * This function is used to reply to Probe Request frames that were
 	 * indicated with a call to p2p_probe_req_rx(). The response is to be
-	 * sent on the same channel or to be dropped if the driver is not
-	 * anymore listening to Probe Request frames.
+	 * sent on the same channel, unless otherwise specified, or to be
+	 * dropped if the driver is not listening to Probe Request frames
+	 * anymore.
 	 *
 	 * Alternatively, the responsibility for building the Probe Response
 	 * frames in Listen state may be in another system component in which
@@ -586,7 +588,8 @@
 	 * Request frames must be indicated by calling p2p_probe_req_rx() even
 	 * if this send_probe_resp() is not used.
 	 */
-	int (*send_probe_resp)(void *ctx, const struct wpabuf *buf);
+	int (*send_probe_resp)(void *ctx, const struct wpabuf *buf,
+			       unsigned int freq);
 
 	/**
 	 * send_action - Transmit an Action frame
@@ -1463,11 +1466,13 @@
  * @bssid: BSSID if available or %NULL
  * @ie: Information elements from the Probe Request frame body
  * @ie_len: Length of ie buffer in octets
+ * @rx_freq: Probe Request frame RX frequency
  * Returns: value indicating the type and status of the probe request
  */
 enum p2p_probe_req_status
 p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
-		 const u8 *bssid, const u8 *ie, size_t ie_len);
+		 const u8 *bssid, const u8 *ie, size_t ie_len,
+		 unsigned int rx_freq);
 
 /**
  * p2p_rx_action - Report received Action frame
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 92c9206..6b6e770 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -353,10 +353,10 @@
 	/* Service Hash */
 	wpabuf_put_u8(buf, P2P_ATTR_SERVICE_HASH);
 	wpabuf_put_le16(buf, p2p->p2ps_seek_count * P2PS_HASH_LEN);
-	wpabuf_put_data(buf, p2p->query_hash,
+	wpabuf_put_data(buf, p2p->p2ps_seek_hash,
 			p2p->p2ps_seek_count * P2PS_HASH_LEN);
 	wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash",
-		    p2p->query_hash, p2p->p2ps_seek_count * P2PS_HASH_LEN);
+		    p2p->p2ps_seek_hash, p2p->p2ps_seek_count * P2PS_HASH_LEN);
 }
 
 
@@ -404,152 +404,222 @@
 }
 
 
+static int p2ps_wildcard_hash(struct p2p_data *p2p,
+			      const u8 *hash, u8 hash_count)
+{
+	u8 i;
+	const u8 *test = hash;
+
+	for (i = 0; i < hash_count; i++) {
+		if (os_memcmp(test, p2p->wild_card_hash, P2PS_HASH_LEN) == 0)
+			return 1;
+		test += P2PS_HASH_LEN;
+	}
+
+	return 0;
+}
+
+
+static int p2p_wfa_service_adv(struct p2p_data *p2p)
+{
+	struct p2ps_advertisement *adv;
+
+	for (adv = p2p->p2ps_adv_list; adv; adv = adv->next) {
+		if (os_strncmp(adv->svc_name, P2PS_WILD_HASH_STR,
+			       os_strlen(P2PS_WILD_HASH_STR)) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static int p2p_buf_add_service_info(struct wpabuf *buf, struct p2p_data *p2p,
+				    u32 adv_id, u16 config_methods,
+				    const char *svc_name, u8 **ie_len, u8 **pos,
+				    size_t *total_len, u8 *attr_len)
+{
+	size_t svc_len;
+	size_t remaining;
+	size_t info_len;
+
+	p2p_dbg(p2p, "Add service info for %s (adv_id=%u)", svc_name, adv_id);
+	svc_len = os_strlen(svc_name);
+	info_len = sizeof(adv_id) + sizeof(config_methods) + sizeof(u8) +
+		svc_len;
+
+	if (info_len + *total_len > MAX_SVC_ADV_LEN) {
+		p2p_dbg(p2p,
+			"Unsufficient buffer, failed to add advertised service info");
+		return -1;
+	}
+
+	if (svc_len > 255) {
+		p2p_dbg(p2p,
+			"Invalid service name length (%u bytes), failed to add advertised service info",
+			(unsigned int) svc_len);
+		return -1;
+	}
+
+	if (*ie_len) {
+		int ie_data_len = (*pos - *ie_len) - 1;
+
+		if (ie_data_len < 0 || ie_data_len > 255) {
+			p2p_dbg(p2p,
+				"Invalid IE length, failed to add advertised service info");
+			return -1;
+		}
+		remaining = 255 - ie_data_len;
+	} else {
+		/*
+		 * Adding new P2P IE header takes 6 extra bytes:
+		 * - 2 byte IE header (1 byte IE id and 1 byte length)
+		 * - 4 bytes of IE_VENDOR_TYPE are reduced from 255 below
+		 */
+		*ie_len = p2p_buf_add_ie_hdr(buf);
+		remaining = 255 - 4;
+	}
+
+	if (remaining < sizeof(u32) + sizeof(u16) + sizeof(u8)) {
+		/*
+		 * Split adv_id, config_methods, and svc_name_len between two
+		 * IEs.
+		 */
+		size_t front = remaining;
+		size_t back = sizeof(u32) + sizeof(u16) + sizeof(u8) - front;
+		u8 holder[sizeof(u32) + sizeof(u16) + sizeof(u8)];
+
+		WPA_PUT_LE32(holder, adv_id);
+		WPA_PUT_BE16(&holder[sizeof(u32)], config_methods);
+		holder[sizeof(u32) + sizeof(u16)] = svc_len;
+
+		if (front)
+			wpabuf_put_data(buf, holder, front);
+
+		p2p_buf_update_ie_hdr(buf, *ie_len);
+		*ie_len = p2p_buf_add_ie_hdr(buf);
+
+		wpabuf_put_data(buf, &holder[front], back);
+		remaining = 255 - 4 - (sizeof(u32) + sizeof(u16) + sizeof(u8)) -
+			back;
+	} else {
+		wpabuf_put_le32(buf, adv_id);
+		wpabuf_put_be16(buf, config_methods);
+		wpabuf_put_u8(buf, svc_len);
+		remaining -= sizeof(adv_id) + sizeof(config_methods) +
+			sizeof(u8);
+	}
+
+	if (remaining < svc_len) {
+		/* split svc_name between two or three IEs */
+		size_t front = remaining;
+		size_t back = svc_len - front;
+
+		if (front)
+			wpabuf_put_data(buf, svc_name, front);
+
+		p2p_buf_update_ie_hdr(buf, *ie_len);
+		*ie_len = p2p_buf_add_ie_hdr(buf);
+
+		/* In rare cases, we must split across 3 attributes */
+		if (back > 255 - 4) {
+			wpabuf_put_data(buf, &svc_name[front], 255 - 4);
+			back -= 255 - 4;
+			front += 255 - 4;
+			p2p_buf_update_ie_hdr(buf, *ie_len);
+			*ie_len = p2p_buf_add_ie_hdr(buf);
+		}
+
+		wpabuf_put_data(buf, &svc_name[front], back);
+		remaining = 255 - 4 - back;
+	} else {
+		wpabuf_put_data(buf, svc_name, svc_len);
+		remaining -= svc_len;
+	}
+
+	p2p_buf_update_ie_hdr(buf, *ie_len);
+
+	/* set *ie_len to NULL if a new IE has to be added on the next call */
+	if (!remaining)
+		*ie_len = NULL;
+
+	/* set *pos to point to the next byte to update */
+	*pos = wpabuf_put(buf, 0);
+
+	*total_len += info_len;
+	WPA_PUT_LE16(attr_len, (u16) *total_len);
+	return 0;
+}
+
+
 void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p,
 				  u8 hash_count, const u8 *hash,
 				  struct p2ps_advertisement *adv_list)
 {
 	struct p2ps_advertisement *adv;
-	struct wpabuf *tmp_buf;
-	u8 *tag_len = NULL, *ie_len = NULL;
-	size_t svc_len = 0, remaining = 0, total_len = 0;
+	int p2ps_wildcard, found = 0;
+	size_t total_len;
+	struct wpabuf *tmp_buf = NULL;
+	u8 *pos, *attr_len, *ie_len = NULL;
 
-	if (!adv_list || !hash)
+	if (!adv_list || !hash || !hash_count)
 		return;
 
+	wpa_hexdump(MSG_DEBUG, "P2PS: Probe Request service hash values",
+		    hash, hash_count * P2PS_HASH_LEN);
+	p2ps_wildcard = p2ps_wildcard_hash(p2p, hash, hash_count) &&
+		p2p_wfa_service_adv(p2p);
+
 	/* Allocate temp buffer, allowing for overflow of 1 instance */
 	tmp_buf = wpabuf_alloc(MAX_SVC_ADV_IE_LEN + 256 + P2PS_HASH_LEN);
 	if (!tmp_buf)
 		return;
 
+	/*
+	 * Attribute data can be split into a number of IEs. Start with the
+	 * first IE and the attribute headers here.
+	 */
+	ie_len = p2p_buf_add_ie_hdr(tmp_buf);
+
+	total_len = 0;
+
+	wpabuf_put_u8(tmp_buf, P2P_ATTR_ADVERTISED_SERVICE);
+	attr_len = wpabuf_put(tmp_buf, sizeof(u16));
+	WPA_PUT_LE16(attr_len, (u16) total_len);
+	p2p_buf_update_ie_hdr(tmp_buf, ie_len);
+	pos = wpabuf_put(tmp_buf, 0);
+
+	if (p2ps_wildcard) {
+		/* org.wi-fi.wfds match found */
+		p2p_buf_add_service_info(tmp_buf, p2p, 0, 0, P2PS_WILD_HASH_STR,
+					 &ie_len, &pos, &total_len, attr_len);
+		found++;
+	}
+
+	/* add advertised service info of matching services */
 	for (adv = adv_list; adv && total_len <= MAX_SVC_ADV_LEN;
 	     adv = adv->next) {
-		u8 count = hash_count;
 		const u8 *test = hash;
+		u8 i;
 
-		while (count--) {
-			/* Check for wildcard */
-			if (os_memcmp(test, p2p->wild_card_hash,
-				      P2PS_HASH_LEN) == 0) {
-				total_len = MAX_SVC_ADV_LEN + 1;
-				goto wild_hash;
-			}
-
-			if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0)
-				goto hash_match;
-
+		for (i = 0; i < hash_count; i++) {
+			/* exact name hash match */
+			if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0 &&
+			    p2p_buf_add_service_info(tmp_buf, p2p,
+						     adv->id,
+						     adv->config_methods,
+						     adv->svc_name,
+						     &ie_len, &pos,
+						     &total_len,
+						     attr_len))
+				break;
+			found++;
 			test += P2PS_HASH_LEN;
 		}
-
-		/* No matches found - Skip this Adv Instance */
-		continue;
-
-hash_match:
-		if (!tag_len) {
-			tag_len = p2p_buf_add_ie_hdr(tmp_buf);
-			remaining = 255 - 4;
-			if (!ie_len) {
-				wpabuf_put_u8(tmp_buf,
-					      P2P_ATTR_ADVERTISED_SERVICE);
-				ie_len = wpabuf_put(tmp_buf, sizeof(u16));
-				remaining -= (sizeof(u8) + sizeof(u16));
-			}
-		}
-
-		svc_len = os_strlen(adv->svc_name);
-
-		if (7 + svc_len + total_len > MAX_SVC_ADV_LEN) {
-			/* Can't fit... return wildcard */
-			total_len = MAX_SVC_ADV_LEN + 1;
-			break;
-		}
-
-		if (remaining <= (sizeof(adv->id) +
-				  sizeof(adv->config_methods))) {
-			size_t front = remaining;
-			size_t back = (sizeof(adv->id) +
-				       sizeof(adv->config_methods)) - front;
-			u8 holder[sizeof(adv->id) +
-				  sizeof(adv->config_methods)];
-
-			/* This works even if front or back == 0 */
-			WPA_PUT_LE32(holder, adv->id);
-			WPA_PUT_BE16(&holder[sizeof(adv->id)],
-				     adv->config_methods);
-			wpabuf_put_data(tmp_buf, holder, front);
-			p2p_buf_update_ie_hdr(tmp_buf, tag_len);
-			tag_len = p2p_buf_add_ie_hdr(tmp_buf);
-			wpabuf_put_data(tmp_buf, &holder[front], back);
-			remaining = 255 - (sizeof(adv->id) +
-					   sizeof(adv->config_methods)) - back;
-		} else {
-			wpabuf_put_le32(tmp_buf, adv->id);
-			wpabuf_put_be16(tmp_buf, adv->config_methods);
-			remaining -= (sizeof(adv->id) +
-				      sizeof(adv->config_methods));
-		}
-
-		/* We are guaranteed at least one byte for svc_len */
-		wpabuf_put_u8(tmp_buf, svc_len);
-		remaining -= sizeof(u8);
-
-		if (remaining < svc_len) {
-			size_t front = remaining;
-			size_t back = svc_len - front;
-
-			wpabuf_put_data(tmp_buf, adv->svc_name, front);
-			p2p_buf_update_ie_hdr(tmp_buf, tag_len);
-			tag_len = p2p_buf_add_ie_hdr(tmp_buf);
-
-			/* In rare cases, we must split across 3 attributes */
-			if (back > 255 - 4) {
-				wpabuf_put_data(tmp_buf,
-						&adv->svc_name[front], 255 - 4);
-				back -= 255 - 4;
-				front += 255 - 4;
-				p2p_buf_update_ie_hdr(tmp_buf, tag_len);
-				tag_len = p2p_buf_add_ie_hdr(tmp_buf);
-			}
-
-			wpabuf_put_data(tmp_buf, &adv->svc_name[front], back);
-			remaining = 255 - 4 - back;
-		} else {
-			wpabuf_put_data(tmp_buf, adv->svc_name, svc_len);
-			remaining -= svc_len;
-		}
-
-		/*           adv_id      config_methods     svc_string */
-		total_len += sizeof(u32) + sizeof(u16) + sizeof(u8) + svc_len;
 	}
 
-	if (tag_len)
-		p2p_buf_update_ie_hdr(tmp_buf, tag_len);
-
-	if (ie_len)
-		WPA_PUT_LE16(ie_len, (u16) total_len);
-
-wild_hash:
-	/* If all fit, return matching instances, otherwise the wildcard */
-	if (total_len <= MAX_SVC_ADV_LEN) {
+	if (found)
 		wpabuf_put_buf(buf, tmp_buf);
-	} else {
-		char *wild_card = P2PS_WILD_HASH_STR;
-		u8 wild_len;
-
-		/* Insert wildcard instance */
-		tag_len = p2p_buf_add_ie_hdr(buf);
-		wpabuf_put_u8(buf, P2P_ATTR_ADVERTISED_SERVICE);
-		ie_len = wpabuf_put(buf, sizeof(u16));
-
-		wild_len = (u8) os_strlen(wild_card);
-		wpabuf_put_le32(buf, 0);
-		wpabuf_put_be16(buf, 0);
-		wpabuf_put_u8(buf, wild_len);
-		wpabuf_put_data(buf, wild_card, wild_len);
-
-		WPA_PUT_LE16(ie_len, 4 + 2 + 1 + wild_len);
-		p2p_buf_update_ie_hdr(buf, tag_len);
-	}
-
 	wpabuf_free(tmp_buf);
 }
 
diff --git a/src/p2p/p2p_dev_disc.c b/src/p2p/p2p_dev_disc.c
index 86bae1a..98805fe 100644
--- a/src/p2p/p2p_dev_disc.c
+++ b/src/p2p/p2p_dev_disc.c
@@ -314,7 +314,7 @@
 
 	p2p_dbg(p2p, "Received GO Discoverability Request - remain awake for 100 TU");
 
-	ies = p2p_build_probe_resp_ies(p2p);
+	ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
 	if (ies == NULL)
 		return;
 
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 63837eb..19f1daa 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -379,7 +379,7 @@
 	int freq;
 	u8 op_reg_class, op_channel;
 	unsigned int i;
-	const int op_classes_5ghz[] = { 124, 115, 0 };
+	const int op_classes_5ghz[] = { 124, 125, 115, 0 };
 	const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
 	const int op_classes_vht[] = { 128, 0 };
 
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 289a62d..a1042d2 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -14,6 +14,12 @@
 
 #define P2P_GO_NEG_CNF_MAX_RETRY_COUNT 1
 
+/*
+ * A threshold (in seconds) to prefer a direct Probe Response frame from a P2P
+ * Device over the P2P Client Info received from a GO.
+ */
+#define P2P_DEV_GROUP_CLIENT_RESP_THRESHOLD 1
+
 enum p2p_role_indication;
 
 /*
@@ -107,6 +113,8 @@
 #define P2P_DEV_WAIT_INV_REQ_ACK BIT(19)
 #define P2P_DEV_P2PS_REPORTED BIT(20)
 #define P2P_DEV_PD_PEER_P2PS BIT(21)
+#define P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT BIT(22)
+
 	unsigned int flags;
 
 	int status; /* enum p2p_status_code */
@@ -506,11 +514,9 @@
 	struct p2ps_advertisement *p2ps_adv_list;
 	struct p2ps_provision *p2ps_prov;
 	u8 wild_card_hash[P2PS_HASH_LEN];
-	u8 query_hash[P2P_MAX_QUERY_HASH * P2PS_HASH_LEN];
-	u8 query_count;
 	u8 p2ps_seek;
+	u8 p2ps_seek_hash[P2P_MAX_QUERY_HASH * P2PS_HASH_LEN];
 	u8 p2ps_seek_count;
-	u8 p2ps_svc_found;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	struct wpabuf *wfd_ie_beacon;
@@ -795,6 +801,7 @@
 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
 			   int join, int force_freq);
 void p2p_reset_pending_pd(struct p2p_data *p2p);
+void p2ps_prov_free(struct p2p_data *p2p);
 
 /* p2p_invitation.c */
 void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
@@ -840,7 +847,9 @@
 int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps);
 int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[],
 			size_t num_req_dev_type);
-struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p);
+struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p,
+					 const u8 *query_hash,
+					 u8 query_count);
 void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len);
 int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
 		    const u8 *src, const u8 *bssid, const u8 *buf,
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 44a6bbf..f5454f7 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -134,6 +134,9 @@
 		extra = wpabuf_len(wfd_ie);
 #endif /* CONFIG_WIFI_DISPLAY */
 
+	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP])
+		extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP]);
+
 	buf = wpabuf_alloc(1000 + extra);
 	if (buf == NULL)
 		return NULL;
@@ -158,6 +161,9 @@
 		wpabuf_put_buf(buf, wfd_ie);
 #endif /* CONFIG_WIFI_DISPLAY */
 
+	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP])
+		wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP]);
+
 	return buf;
 }
 
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index bc84269..86558f7 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -881,8 +881,7 @@
 						 P2P_PROV_DISC_REJECTED,
 						 adv_id, adv_mac, NULL);
 		p2p_parse_free(&msg);
-		os_free(p2p->p2ps_prov);
-		p2p->p2ps_prov = NULL;
+		p2ps_prov_free(p2p);
 		goto out;
 	}
 
@@ -920,8 +919,7 @@
 				conncap, passwd_id, msg.persistent_ssid,
 				msg.persistent_ssid_len, 1, 0, NULL);
 		}
-		os_free(p2p->p2ps_prov);
-		p2p->p2ps_prov = NULL;
+		p2ps_prov_free(p2p);
 	}
 
 	if (status != P2P_SC_SUCCESS &&
@@ -933,8 +931,7 @@
 				p2p->p2ps_prov->session_mac,
 				group_mac, adv_id, p2p->p2ps_prov->session_id,
 				0, 0, NULL, 0, 1, 0, NULL);
-		os_free(p2p->p2ps_prov);
-		p2p->p2ps_prov = NULL;
+		p2ps_prov_free(p2p);
 	}
 
 	if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
@@ -950,8 +947,7 @@
 
 			if (!deferred_sess_resp) {
 				p2p_parse_free(&msg);
-				os_free(p2p->p2ps_prov);
-				p2p->p2ps_prov = NULL;
+				p2ps_prov_free(p2p);
 				goto out;
 			}
 			utf8_escape((char *) msg.session_info, info_len,
@@ -978,8 +974,7 @@
 						 P2P_PROV_DISC_REJECTED, 0,
 						 NULL, NULL);
 		p2p_parse_free(&msg);
-		os_free(p2p->p2ps_prov);
-		p2p->p2ps_prov = NULL;
+		p2ps_prov_free(p2p);
 		goto out;
 	}
 
@@ -1120,7 +1115,7 @@
 
 	/* Reset provisioning info */
 	dev->wps_prov_info = 0;
-	os_free(p2p->p2ps_prov);
+	p2ps_prov_free(p2p);
 	p2p->p2ps_prov = p2ps_prov;
 
 	dev->req_config_methods = config_methods;
@@ -1176,3 +1171,10 @@
 	p2p->pd_retries = 0;
 	p2p->pd_force_freq = 0;
 }
+
+
+void p2ps_prov_free(struct p2p_data *p2p)
+{
+	os_free(p2p->p2ps_prov);
+	p2p->p2ps_prov = NULL;
+}
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index f32751d..eee3c5a 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -101,6 +101,15 @@
 		return 0;
 	}
 
+	if (freq >= 5745 && freq <= 5845) {
+		if ((freq - 5000) % 5)
+			return -1;
+
+		*op_class = 125; /* 5 GHz, channels 149..169 */
+		*channel = (freq - 5000) / 5;
+		return 0;
+	}
+
 	if (freq >= 58320 && freq <= 64800) {
 		if ((freq - 58320) % 2160)
 			return -1;
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 82a8999..b7a6dba 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -307,7 +307,7 @@
 				    "%s - hexdump(len=%lu):%s%s",
 				    title, (long unsigned int) len, display,
 				    len > slen ? " ..." : "");
-		os_free(strbuf);
+		bin_clear_free(strbuf, 1 + 3 * slen);
 		return;
 	}
 #else /* CONFIG_ANDROID_LOG */
@@ -339,7 +339,7 @@
 
 		syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
 		       title, (unsigned long) len, display);
-		os_free(strbuf);
+		bin_clear_free(strbuf, 1 + 3 * len);
 		return;
 	}
 #endif /* CONFIG_DEBUG_SYSLOG */
@@ -636,7 +636,7 @@
 	wpa_printf(level, "%s%s", prefix, buf);
 	if (wpa_msg_cb)
 		wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
-	os_free(buf);
+	bin_clear_free(buf, buflen);
 }
 
 
@@ -664,7 +664,7 @@
 	len = vsnprintf(buf, buflen, fmt, ap);
 	va_end(ap);
 	wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
-	os_free(buf);
+	bin_clear_free(buf, buflen);
 }
 
 
@@ -691,7 +691,7 @@
 	wpa_printf(level, "%s", buf);
 	if (wpa_msg_cb)
 		wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
-	os_free(buf);
+	bin_clear_free(buf, buflen);
 }
 
 
@@ -719,7 +719,7 @@
 	len = vsnprintf(buf, buflen, fmt, ap);
 	va_end(ap);
 	wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
-	os_free(buf);
+	bin_clear_free(buf, buflen);
 }
 
 
@@ -746,7 +746,7 @@
 	wpa_printf(level, "%s", buf);
 	if (wpa_msg_cb)
 		wpa_msg_cb(ctx, level, WPA_MSG_NO_GLOBAL, buf, len);
-	os_free(buf);
+	bin_clear_free(buf, buflen);
 }
 
 #endif /* CONFIG_NO_WPA_MSG */
@@ -789,6 +789,6 @@
 			   MAC2STR(addr), buf);
 	else
 		wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf);
-	os_free(buf);
+	bin_clear_free(buf, buflen);
 }
 #endif /* CONFIG_NO_HOSTAPD_LOGGER */
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index bfb69fc..f3960c5 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -485,8 +485,13 @@
 			   int ssi_signal)
 {
 	struct wpa_supplicant *wpa_s = ctx;
+	unsigned int freq = 0;
+
+	if (wpa_s->ap_iface)
+		freq = wpa_s->ap_iface->freq;
+
 	return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len,
-				     ssi_signal);
+				     freq, ssi_signal);
 }
 
 
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2fe032d..239c3e8 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -4180,6 +4180,7 @@
 	{ IPV4(ip_addr_mask), 0 },
 	{ IPV4(ip_addr_start), 0 },
 	{ IPV4(ip_addr_end), 0 },
+	{ INT_RANGE(p2p_cli_probe, 0, 1), 0 },
 #endif /* CONFIG_P2P */
 	{ FUNC(country), CFG_CHANGED_COUNTRY },
 	{ INT(bss_max_count), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 545a4bd..d8ca054 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -968,6 +968,18 @@
 	int p2p_no_group_iface;
 
 	/**
+	 * p2p_cli_probe - Enable/disable P2P CLI probe request handling
+	 *
+	 * If this parameter is set to 1, a connected P2P Client will receive
+	 * and handle Probe Request frames. Setting this parameter to 0
+	 * disables this option. Default value: 0.
+	 *
+	 * Note: Setting this property at run time takes effect on the following
+	 * interface state transition to/from the WPA_COMPLETED state.
+	 */
+	int p2p_cli_probe;
+
+	/**
 	 * okc - Whether to enable opportunistic key caching by default
 	 *
 	 * By default, OKC is disabled unless enabled by the per-network
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 2508ca9..e946567 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1131,6 +1131,9 @@
 	if (config->p2p_ignore_shared_freq)
 		fprintf(f, "p2p_ignore_shared_freq=%u\n",
 			config->p2p_ignore_shared_freq);
+	if (config->p2p_cli_probe)
+		fprintf(f, "p2p_cli_probe=%u\n",
+			config->p2p_cli_probe);
 #endif /* CONFIG_P2P */
 	if (config->country[0] && config->country[1]) {
 		fprintf(f, "country=%c%c\n",
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index f32b7c9..0c5ea8f 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -4597,16 +4597,20 @@
 
 	/* Must be searched for last, because it adds nul termination */
 	pos = os_strstr(cmd, " seek=");
+	if (pos)
+		pos += 6;
 	while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) {
 		char *term;
 
-		term = os_strchr(pos + 1, ' ');
-		_seek[seek_count++] = pos + 6;
+		_seek[seek_count++] = pos;
 		seek = _seek;
-		pos = os_strstr(pos + 6, " seek=");
-
-		if (term)
-			*term = '\0';
+		term = os_strchr(pos, ' ');
+		if (!term)
+			break;
+		*term = '\0';
+		pos = os_strstr(term + 1, "seek=");
+		if (pos)
+			pos += 5;
 	}
 	if (seek_count > P2P_MAX_QUERY_HASH) {
 		seek[0] = NULL;
@@ -5501,13 +5505,10 @@
 
 
 static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
-					 char *cmd, int freq, int ht40,
-					 int vht)
+					 int id, int freq, int ht40, int vht)
 {
-	int id;
 	struct wpa_ssid *ssid;
 
-	id = atoi(cmd);
 	ssid = wpa_config_get_network(wpa_s->conf, id);
 	if (ssid == NULL || ssid->disabled != 2) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
@@ -5523,31 +5524,35 @@
 
 static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
 {
-	int freq = 0, ht40, vht;
-	char *pos;
+	int freq = 0, persistent = 0, group_id = -1;
+	int vht = wpa_s->conf->p2p_go_vht;
+	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+	char *token, *context = NULL;
 
-	pos = os_strstr(cmd, "freq=");
-	if (pos)
-		freq = atoi(pos + 5);
+	while ((token = str_token(cmd, " ", &context))) {
+		if (sscanf(token, "freq=%d", &freq) == 1 ||
+		    sscanf(token, "persistent=%d", &group_id) == 1) {
+			continue;
+		} else if (os_strcmp(token, "ht40") == 0) {
+			ht40 = 1;
+		} else if (os_strcmp(token, "vht") == 0) {
+			vht = 1;
+			ht40 = 1;
+		} else if (os_strcmp(token, "persistent") == 0) {
+			persistent = 1;
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "CTRL: Invalid P2P_GROUP_ADD parameter: '%s'",
+				   token);
+			return -1;
+		}
+	}
 
-	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 (group_id >= 0)
+		return p2p_ctrl_group_add_persistent(wpa_s, group_id,
+						     freq, ht40, vht);
 
-	if (os_strncmp(cmd, "persistent=", 11) == 0)
-		return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
-						     ht40, vht);
-	if (os_strcmp(cmd, "persistent") == 0 ||
-	    os_strncmp(cmd, "persistent ", 11) == 0)
-		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, vht);
-	if (ht40)
-		return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
-
-	wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
-		   cmd);
-	return -1;
+	return wpas_p2p_group_add(wpa_s, persistent, freq, ht40, vht);
 }
 
 
@@ -8194,7 +8199,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, 0))
+		if (p2p_ctrl_group_add(wpa_s, ""))
 			reply_len = -1;
 	} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
 		if (p2p_ctrl_group_add(wpa_s, buf + 14))
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 22001cf..f49ba07 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -197,6 +197,13 @@
 		reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
 							      &reply_len);
 		reply = reply_buf;
+
+		/*
+		 * There could be some password/key material in the command, so
+		 * clear the buffer explicitly now that it is not needed
+		 * anymore.
+		 */
+		os_memset(buf, 0, res);
 	}
 
 	if (!reply && reply_len == 1) {
@@ -846,6 +853,13 @@
 		reply_buf = wpa_supplicant_global_ctrl_iface_process(
 			global, buf, &reply_len);
 		reply = reply_buf;
+
+		/*
+		 * There could be some password/key material in the command, so
+		 * clear the buffer explicitly now that it is not needed
+		 * anymore.
+		 */
+		os_memset(buf, 0, res);
 	}
 
 	if (!reply && reply_len == 1) {
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index fb674d4..a3bf1e3 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -603,6 +603,7 @@
 /**
  * wpas_dbus_signal_wps_event_fail - Signals Fail WPS event
  * @wpa_s: %wpa_supplicant network interface data
+ * @fail: WPS failure information
  *
  * Sends Event dbus signal with name "fail" and dictionary containing
  * "msg field with fail message number (int32) as arguments
@@ -644,6 +645,7 @@
 /**
  * wpas_dbus_signal_wps_event_m2d - Signals M2D WPS event
  * @wpa_s: %wpa_supplicant network interface data
+ * @m2d: M2D event data information
  *
  * Sends Event dbus signal with name "m2d" and dictionary containing
  * fields of wps_event_m2d structure.
@@ -709,6 +711,7 @@
 /**
  * wpas_dbus_signal_wps_cred - Signals new credentials
  * @wpa_s: %wpa_supplicant network interface data
+ * @cred: WPS Credential information
  *
  * Sends signal with credentials in directory argument
  */
@@ -1100,6 +1103,16 @@
 }
 
 
+/**
+ * wpas_dbus_signal_p2p_go_neg_req - Signal P2P GO Negotiation Request RX
+ * @wpa_s: %wpa_supplicant network interface data
+ * @src: Source address of the message triggering this notification
+ * @dev_passwd_id: WPS Device Password Id
+ * @go_intent: Peer's GO Intent value
+ *
+ * Sends signal to notify that a peer P2P Device is requesting group owner
+ * negotiation with us.
+ */
 void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
 				     const u8 *src, u16 dev_passwd_id,
 				     u8 go_intent)
@@ -1297,10 +1310,9 @@
 
 
 /**
- *
- * Method to emit GONegotiation Success or Failure signals based
- * on status.
- * @status: Status of the GO neg request. 0 for success, other for errors.
+ * wpas_dbus_signal_p2p_go_neg_resp - Emit GONegotiation Success/Failure signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @res: Result of the GO Neg Request
  */
 void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
 				      struct p2p_go_neg_results *res)
@@ -1801,6 +1813,7 @@
 /**
  * wpas_dbus_signal_p2p_wps_failed - Signals WpsFailed event
  * @wpa_s: %wpa_supplicant network interface data
+ * @fail: WPS failure information
  *
  * Sends Event dbus signal with name "fail" and dictionary containing
  * "msg" field with fail message number (int32) as arguments
@@ -2552,6 +2565,12 @@
 		  END_ARGS
 	  }
 	},
+	{ "Reconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_reconnect,
+	  {
+		  END_ARGS
+	  }
+	},
 	{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
 	  (WPADBusMethodHandler) wpas_dbus_handler_remove_network,
 	  {
@@ -2715,6 +2734,13 @@
 		  END_ARGS
 	  }
 	},
+	{ "RemoveClient", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_remove_client,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
 	{ "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
 	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush,
 	  {
@@ -3502,7 +3528,7 @@
 /**
  * wpas_dbus_register_peer - Register a discovered peer object with dbus
  * @wpa_s: wpa_supplicant interface structure
- * @ssid: network configuration data
+ * @dev_addr: P2P Device Address of the peer
  * Returns: 0 on success, -1 on failure
  *
  * Registers network representing object with dbus
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 97db9a8..2a7e2cf 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1601,6 +1601,30 @@
 
 
 /**
+ * wpas_dbus_handler_reconnect - Reconnect if disconnected
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: InterfaceDisabled DBus error message if disabled
+ * or NULL otherwise.
+ *
+ * Handler function for "Reconnect" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message,
+		struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+		return dbus_message_new_error(message,
+					      WPAS_DBUS_ERROR_IFACE_DISABLED,
+					      "This interface is disabled");
+	}
+
+	if (wpa_s->disconnected)
+		wpas_request_connection(wpa_s);
+	return NULL;
+}
+
+
+/**
  * wpas_dbus_handler_remove_network - Remove a configured network
  * @message: Pointer to incoming dbus message
  * @wpa_s: wpa_supplicant structure for a network interface
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 9afdc05..50f72ec 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -107,6 +107,9 @@
 DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
 					 struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s);
+
 DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
 					       struct wpa_supplicant *wpa_s);
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 56e9033..e9d60df 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -416,6 +416,64 @@
 }
 
 
+DBusMessage * wpas_dbus_handler_p2p_remove_client(DBusMessage *message,
+						  struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	char *peer_object_path = NULL;
+	char *interface_addr = NULL;
+	u8 peer_addr[ETH_ALEN];
+
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
+		return reply;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto err;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto err;
+
+		if (os_strcmp(entry.key, "peer") == 0 &&
+		    entry.type == DBUS_TYPE_OBJECT_PATH) {
+			os_free(peer_object_path);
+			peer_object_path = os_strdup(entry.str_value);
+			wpa_dbus_dict_entry_clear(&entry);
+		} else if (os_strcmp(entry.key, "iface") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
+			os_free(interface_addr);
+			interface_addr = os_strdup(entry.str_value);
+			wpa_dbus_dict_entry_clear(&entry);
+		} else {
+			wpa_dbus_dict_entry_clear(&entry);
+			goto err;
+		}
+	}
+
+	if ((!peer_object_path && !interface_addr) ||
+	    (peer_object_path &&
+	     (parse_peer_object_path(peer_object_path, peer_addr) < 0 ||
+	      !p2p_peer_known(wpa_s->global->p2p, peer_addr))) ||
+	    (interface_addr && hwaddr_aton(interface_addr, peer_addr) < 0))
+		goto err;
+
+	wpas_p2p_remove_client(wpa_s, peer_addr, interface_addr != NULL);
+	reply = NULL;
+out:
+	os_free(peer_object_path);
+	os_free(interface_addr);
+	return reply;
+err:
+	reply = wpas_dbus_error_invalid_args(message, "Invalid address format");
+	goto out;
+}
+
+
 DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
 					  struct wpa_supplicant *wpa_s)
 {
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index d0953f1..2aecbbe 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -56,6 +56,9 @@
 DBusMessage *wpas_dbus_handler_p2p_disconnect(
 	DBusMessage *message, struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_handler_p2p_remove_client(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
 DBusMessage *wpas_dbus_handler_p2p_flush(
 	DBusMessage *message, struct wpa_supplicant *wpa_s);
 
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index ffee1f7..1fcb180 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -286,11 +286,13 @@
 }
 
 static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
-				    const u8 *data, size_t data_len, int noack)
+				    const u8 *data, size_t data_len, int noack,
+				    unsigned int freq)
 {
 	if (wpa_s->driver->send_mlme)
 		return wpa_s->driver->send_mlme(wpa_s->drv_priv,
-						data, data_len, noack);
+						data, data_len, noack,
+						freq);
 	return -1;
 }
 
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 80045e7..7be352d 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2557,6 +2557,21 @@
 			wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the "
 				"driver after interface was added");
 		}
+
+#ifdef CONFIG_P2P
+		if (!wpa_s->global->p2p &&
+		    !wpa_s->global->p2p_disabled &&
+		    !wpa_s->conf->p2p_disabled &&
+		    (wpa_s->drv_flags &
+		     WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+		    wpas_p2p_add_p2pdev_interface(
+			    wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
+			wpa_printf(MSG_INFO,
+				   "P2P: Failed to enable P2P Device interface");
+			/* Try to continue without. P2P will be disabled. */
+		}
+#endif /* CONFIG_P2P */
+
 		break;
 	case EVENT_INTERFACE_REMOVED:
 		wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
@@ -2565,6 +2580,21 @@
 		wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
 		l2_packet_deinit(wpa_s->l2);
 		wpa_s->l2 = NULL;
+
+#ifdef CONFIG_P2P
+		if (wpa_s->global->p2p &&
+		    wpa_s->global->p2p_init_wpa_s->parent == wpa_s &&
+		    (wpa_s->drv_flags &
+		     WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"Removing P2P Device interface");
+			wpa_supplicant_remove_iface(
+				wpa_s->global, wpa_s->global->p2p_init_wpa_s,
+				0);
+			wpa_s->global->p2p_init_wpa_s = NULL;
+		}
+#endif /* CONFIG_P2P */
+
 #ifdef CONFIG_TERMINATE_ONLASTIF
 		/* check if last interface */
 		if (!any_interfaces(wpa_s->global->ifaces))
@@ -3495,6 +3525,7 @@
 				wpas_p2p_probe_req_rx(
 					wpa_s, src, mgmt->da,
 					mgmt->bssid, ie, ie_len,
+					data->rx_mgmt.freq,
 					data->rx_mgmt.ssi_signal);
 				break;
 			}
@@ -3566,6 +3597,7 @@
 				      data->rx_probe_req.bssid,
 				      data->rx_probe_req.ie,
 				      data->rx_probe_req.ie_len,
+				      0,
 				      data->rx_probe_req.ssi_signal);
 		break;
 	case EVENT_REMAIN_ON_CHANNEL:
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 9f5a198..1c93306 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -237,7 +237,7 @@
 			goto out;
 #ifdef CONFIG_P2P
 		case 'm':
-			iface->conf_p2p_dev = optarg;
+			params.conf_p2p_dev = optarg;
 			break;
 #endif /* CONFIG_P2P */
 		case 'o':
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 5c8a3b2..b9ebd38 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -126,6 +126,8 @@
 static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
 static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
 					enum wpa_driver_if_type type);
+static void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s,
+					    int already_deleted);
 
 
 /*
@@ -1231,7 +1233,7 @@
 
 
 static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
-					   int success)
+					   int success, int already_deleted)
 {
 	struct wpa_ssid *ssid;
 	int client;
@@ -1256,6 +1258,8 @@
 	if (!success) {
 		wpa_msg_global(wpa_s->parent, MSG_INFO,
 			       P2P_EVENT_GROUP_FORMATION_FAILURE);
+		if (already_deleted)
+			return;
 		wpas_p2p_group_delete(wpa_s,
 				      P2P_GROUP_REMOVAL_FORMATION_FAILED);
 		return;
@@ -1874,6 +1878,7 @@
 		d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
 		d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
 	}
+	d->p2p_cli_probe = s->p2p_cli_probe;
 }
 
 
@@ -2019,17 +2024,18 @@
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
-	wpas_p2p_group_formation_failed(wpa_s);
+	wpas_p2p_group_formation_failed(wpa_s, 0);
 }
 
 
-void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s,
+					    int already_deleted)
 {
 	eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
 			     wpa_s->parent, NULL);
 	if (wpa_s->global->p2p)
 		p2p_group_formation_failed(wpa_s->global->p2p);
-	wpas_group_formation_completed(wpa_s, 0);
+	wpas_group_formation_completed(wpa_s, 0, already_deleted);
 }
 
 
@@ -2110,7 +2116,7 @@
 			wpas_p2p_remove_pending_group_interface(wpa_s);
 			eloop_cancel_timeout(wpas_p2p_long_listen_timeout,
 					     wpa_s, NULL);
-			wpas_p2p_group_formation_failed(wpa_s);
+			wpas_p2p_group_formation_failed(wpa_s, 1);
 			return;
 		}
 		if (group_wpa_s != wpa_s) {
@@ -2384,15 +2390,24 @@
 		wpa_s->roc_waiting_drv_freq = 0;
 	}
 	wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL);
-	wpa_drv_probe_req_report(wpa_s, 0);
+
+	/*
+	 * Don't cancel Probe Request RX reporting for a connected P2P Client
+	 * handling Probe Request frames.
+	 */
+	if (!wpa_s->p2p_cli_probe)
+		wpa_drv_probe_req_report(wpa_s, 0);
+
 	wpas_p2p_listen_work_done(wpa_s);
 }
 
 
-static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf)
+static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf,
+				unsigned int freq)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-	return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1);
+	return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
+				 freq);
 }
 
 
@@ -3116,6 +3131,7 @@
 #endif
 	{ HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
 	{ HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
+	{ HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20 },
 	{ HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
 	{ HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
 	{ HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
@@ -3305,7 +3321,8 @@
 
 		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
 			if (o->mode != HOSTAPD_MODE_IEEE80211A ||
-			    o->bw == BW20 || ch != channel)
+			    (o->bw != BW40PLUS && o->bw != BW40MINUS) ||
+			    ch != channel)
 				continue;
 			ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
 			if (ret == ALLOWED)
@@ -3455,7 +3472,6 @@
 		iface.confname = wpa_s->confname;
 		iface.ctrl_interface = wpa_s->conf->ctrl_interface;
 	}
-	iface.conf_p2p_dev = NULL;
 
 	p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
 	if (!p2pdev_wpa_s) {
@@ -4410,10 +4426,25 @@
 					       wpa_s->pending_join_iface_addr);
 	}
 	if (bss) {
+		u8 dev_addr[ETH_ALEN];
+
 		freq = bss->freq;
 		wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
 			   "from BSS table: %d MHz (SSID %s)", freq,
 			   wpa_ssid_txt(bss->ssid, bss->ssid_len));
+		if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
+				       dev_addr) == 0 &&
+		    os_memcmp(wpa_s->pending_join_dev_addr,
+			      wpa_s->pending_join_iface_addr, ETH_ALEN) == 0 &&
+		    os_memcmp(dev_addr, wpa_s->pending_join_dev_addr,
+			      ETH_ALEN) != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "P2P: Update target GO device address based on BSS entry: " MACSTR " (was " MACSTR ")",
+				   MAC2STR(dev_addr),
+				   MAC2STR(wpa_s->pending_join_dev_addr));
+			os_memcpy(wpa_s->pending_join_dev_addr, dev_addr,
+				  ETH_ALEN);
+		}
 	}
 	if (freq > 0) {
 		u16 method;
@@ -5226,6 +5257,7 @@
 		    wpa_s->conf->p2p_oper_reg_class == 116 ||
 		    wpa_s->conf->p2p_oper_reg_class == 117 ||
 		    wpa_s->conf->p2p_oper_reg_class == 124 ||
+		    wpa_s->conf->p2p_oper_reg_class == 125 ||
 		    wpa_s->conf->p2p_oper_reg_class == 126 ||
 		    wpa_s->conf->p2p_oper_reg_class == 127) &&
 		   freq_included(channels,
@@ -5721,7 +5753,7 @@
 	}
 	if (wpa_s->global->p2p)
 		p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
-	wpas_group_formation_completed(wpa_s, 1);
+	wpas_group_formation_completed(wpa_s, 1, 0);
 }
 
 
@@ -5997,7 +6029,8 @@
 
 int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
 			  const u8 *dst, const u8 *bssid,
-			  const u8 *ie, size_t ie_len, int ssi_signal)
+			  const u8 *ie, size_t ie_len,
+			  unsigned int rx_freq, int ssi_signal)
 {
 	if (wpa_s->global->p2p_disabled)
 		return 0;
@@ -6005,7 +6038,7 @@
 		return 0;
 
 	switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
-				 ie, ie_len)) {
+				 ie, ie_len, rx_freq)) {
 	case P2P_PREQ_NOT_P2P:
 		wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
 				 ssi_signal);
@@ -6737,7 +6770,7 @@
 		   "session overlap");
 	if (wpa_s != wpa_s->parent)
 		wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
-	wpas_p2p_group_formation_failed(wpa_s);
+	wpas_p2p_group_formation_failed(wpa_s, 0);
 	return 1;
 }
 
@@ -6847,7 +6880,7 @@
 			eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
 					     wpa_s->parent, NULL);
 			if (wpa_s->p2p_in_provisioning) {
-				wpas_group_formation_completed(wpa_s, 0);
+				wpas_group_formation_completed(wpa_s, 0, 0);
 				break;
 			}
 			wpas_p2p_group_delete(wpa_s,
@@ -6857,7 +6890,7 @@
 			wpa_printf(MSG_DEBUG, "P2P: Interface %s in invitation found - cancelling",
 				   wpa_s->ifname);
 			found = 1;
-			wpas_p2p_group_formation_failed(wpa_s);
+			wpas_p2p_group_formation_failed(wpa_s, 0);
 		}
 	}
 
@@ -7053,7 +7086,7 @@
 			 */
 			if (wpa_s->global->p2p)
 				p2p_wps_success_cb(wpa_s->global->p2p, addr);
-			wpas_group_formation_completed(wpa_s, 1);
+			wpas_group_formation_completed(wpa_s, 1, 0);
 		}
 	}
 	if (!wpa_s->p2p_go_group_formation_completed) {
@@ -7078,7 +7111,7 @@
 
 	if (wpa_s->global->p2p_group_formation)
 		group = wpa_s->global->p2p_group_formation;
-	wpa_s = wpa_s->parent;
+	wpa_s = wpa_s->global->p2p_init_wpa_s;
 	offchannel_send_action_done(wpa_s);
 	if (group_added)
 		ret = wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 0b9ebc0..1df34d0 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -66,7 +66,6 @@
 int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 			  u8 *buf, size_t len, int p2p_group);
 void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies);
-void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s);
 u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
 			const struct wpabuf *tlvs);
 u64 wpas_p2p_sd_request_asp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 id,
@@ -158,7 +157,7 @@
 int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
 			  const u8 *dst, const u8 *bssid,
 			  const u8 *ie, size_t ie_len,
-			  int ssi_signal);
+			  unsigned int rx_freq, int ssi_signal);
 void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 			  int registrar);
 void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s);
@@ -212,7 +211,7 @@
 					const u8 *addr,
 					const u8 *dst, const u8 *bssid,
 					const u8 *ie, size_t ie_len,
-					int ssi_signal)
+					unsigned int rx_freq, int ssi_signal)
 {
 	return 0;
 }
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 97e575c..c5d8333 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -4099,45 +4099,49 @@
 }
 
 
+static void wpa_cli_action_ping(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_ctrl *ctrl = eloop_ctx;
+	char buf[256];
+	size_t len;
+
+	/* verify that connection is still working */
+	len = sizeof(buf) - 1;
+	if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
+			     wpa_cli_action_cb) < 0 ||
+	    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
+		printf("wpa_supplicant did not reply to PING command - exiting\n");
+		eloop_terminate();
+		return;
+	}
+	eloop_register_timeout(ping_interval, 0, wpa_cli_action_ping,
+			       ctrl, NULL);
+}
+
+
+static void wpa_cli_action_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_ctrl *ctrl = eloop_ctx;
+
+	wpa_cli_recv_pending(ctrl, 1);
+}
+
+
 static void wpa_cli_action(struct wpa_ctrl *ctrl)
 {
 #ifdef CONFIG_ANSI_C_EXTRA
 	/* TODO: ANSI C version(?) */
 	printf("Action processing not supported in ANSI C build.\n");
 #else /* CONFIG_ANSI_C_EXTRA */
-	fd_set rfds;
-	int fd, res;
-	struct timeval tv;
-	char buf[256]; /* note: large enough to fit in unsolicited messages */
-	size_t len;
+	int fd;
 
 	fd = wpa_ctrl_get_fd(ctrl);
-
-	while (!wpa_cli_quit) {
-		FD_ZERO(&rfds);
-		FD_SET(fd, &rfds);
-		tv.tv_sec = ping_interval;
-		tv.tv_usec = 0;
-		res = select(fd + 1, &rfds, NULL, NULL, &tv);
-		if (res < 0 && errno != EINTR) {
-			perror("select");
-			break;
-		}
-
-		if (FD_ISSET(fd, &rfds))
-			wpa_cli_recv_pending(ctrl, 1);
-		else {
-			/* verify that connection is still working */
-			len = sizeof(buf) - 1;
-			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
-					     wpa_cli_action_cb) < 0 ||
-			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
-				printf("wpa_supplicant did not reply to PING "
-				       "command - exiting\n");
-				break;
-			}
-		}
-	}
+	eloop_register_timeout(ping_interval, 0, wpa_cli_action_ping,
+			       ctrl, NULL);
+	eloop_register_read_sock(fd, wpa_cli_action_receive, ctrl, NULL);
+	eloop_run();
+	eloop_cancel_timeout(wpa_cli_action_ping, ctrl, NULL);
+	eloop_unregister_read_sock(fd);
 #endif /* CONFIG_ANSI_C_EXTRA */
 }
 
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index e833c3a..8fba938 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -728,6 +728,30 @@
 		wpa_s->normal_scans = 0;
 	}
 
+#ifdef CONFIG_P2P
+	/*
+	 * P2PS client has to reply to Probe Request frames received on the
+	 * group operating channel. Enable Probe Request frame reporting for
+	 * P2P connected client in case p2p_cli_probe configuration property is
+	 * set to 1.
+	 */
+	if (wpa_s->conf->p2p_cli_probe && wpa_s->current_ssid &&
+	    wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+	    wpa_s->current_ssid->p2p_group) {
+		if (state == WPA_COMPLETED && !wpa_s->p2p_cli_probe) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"P2P: Enable CLI Probe Request RX reporting");
+			wpa_s->p2p_cli_probe =
+				wpa_drv_probe_req_report(wpa_s, 1) >= 0;
+		} else if (state != WPA_COMPLETED && wpa_s->p2p_cli_probe) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"P2P: Disable CLI Probe Request RX reporting");
+			wpa_s->p2p_cli_probe = 0;
+			wpa_drv_probe_req_report(wpa_s, 0);
+		}
+	}
+#endif /* CONFIG_P2P */
+
 	if (state != WPA_SCANNING)
 		wpa_supplicant_notify_scanning(wpa_s, 0);
 
@@ -4427,7 +4451,8 @@
 	if (wpa_s->global->p2p == NULL &&
 	    !wpa_s->global->p2p_disabled && !wpa_s->conf->p2p_disabled &&
 	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
-	    wpas_p2p_add_p2pdev_interface(wpa_s, iface->conf_p2p_dev) < 0) {
+	    wpas_p2p_add_p2pdev_interface(
+		    wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
 		wpa_printf(MSG_INFO,
 			   "P2P: Failed to enable P2P Device interface");
 		/* Try to continue without. P2P will be disabled. */
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index bc6425d..dd5b245 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -66,17 +66,6 @@
 	 */
 	const char *confanother;
 
-#ifdef CONFIG_P2P
-	/**
-	 * conf_p2p_dev - Configuration file used to hold the
-	 * P2P Device configuration parameters.
-	 *
-	 * This can also be %NULL. In such a case, if a P2P Device dedicated
-	 * interfaces is created, the main configuration file will be used.
-	 */
-	const char *conf_p2p_dev;
-#endif /* CONFIG_P2P */
-
 	/**
 	 * ctrl_interface - Control interface parameter
 	 *
@@ -227,6 +216,18 @@
 	 * its internal entropy store over restarts.
 	 */
 	char *entropy_file;
+
+#ifdef CONFIG_P2P
+	/**
+	 * conf_p2p_dev - Configuration file used to hold the
+	 * P2P Device configuration parameters.
+	 *
+	 * This can also be %NULL. In such a case, if a P2P Device dedicated
+	 * interfaces is created, the main configuration file will be used.
+	 */
+	const char *conf_p2p_dev;
+#endif /* CONFIG_P2P */
+
 };
 
 struct p2p_srv_bonjour {
@@ -366,6 +367,8 @@
 	} type;
 	unsigned int tries;
 	struct os_reltime last_attempt;
+	unsigned int pbc_active;
+	u8 uuid[WPS_UUID_LEN];
 };
 
 struct wpa_ssid_value {
@@ -818,6 +821,7 @@
 	unsigned int p2p_peer_oob_pk_hash_known:1;
 	unsigned int p2p_disable_ip_addr_req:1;
 	unsigned int p2ps_join_addr_valid:1;
+	unsigned int p2p_cli_probe:1;
 	int p2p_persistent_go_freq;
 	int p2p_persistent_id;
 	int p2p_go_intent;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index a97c2a8..2db7914 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1717,10 +1717,10 @@
 int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
 			      struct wpa_bss *selected, struct wpa_ssid *ssid)
 {
-	const u8 *sel_uuid, *uuid;
+	const u8 *sel_uuid;
 	struct wpabuf *wps_ie;
 	int ret = 0;
-	struct wpa_bss *bss;
+	size_t i;
 
 	if (!eap_is_wps_pbc_enrollee(&ssid->eap))
 		return 0;
@@ -1741,40 +1741,28 @@
 		sel_uuid = NULL;
 	}
 
-	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		struct wpabuf *ie;
-		if (bss == selected)
+	for (i = 0; i < wpa_s->num_wps_ap; i++) {
+		struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+
+		if (!ap->pbc_active ||
+		    os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0)
 			continue;
-		ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
-		if (!ie)
-			continue;
-		if (!wps_is_selected_pbc_registrar(ie)) {
-			wpabuf_free(ie);
-			continue;
-		}
+
 		wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
-			   MACSTR, MAC2STR(bss->bssid));
-		uuid = wps_get_uuid_e(ie);
+			   MACSTR, MAC2STR(ap->bssid));
 		wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
-			    uuid, UUID_LEN);
-		if (os_memcmp(selected->bssid, bss->bssid, ETH_ALEN) == 0) {
-			wpabuf_free(ie);
-			continue;
-		}
-		if (sel_uuid == NULL || uuid == NULL ||
-		    os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) {
+			    ap->uuid, UUID_LEN);
+		if (sel_uuid == NULL ||
+		    os_memcmp(sel_uuid, ap->uuid, UUID_LEN) != 0) {
 			ret = 1; /* PBC overlap */
 			wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: "
 				MACSTR " and " MACSTR,
 				MAC2STR(selected->bssid),
-				MAC2STR(bss->bssid));
-			wpabuf_free(ie);
+				MAC2STR(ap->bssid));
 			break;
 		}
 
 		/* TODO: verify that this is reasonable dual-band situation */
-
-		wpabuf_free(ie);
 	}
 
 	wpabuf_free(wps_ie);
@@ -2798,7 +2786,8 @@
 	struct wpabuf *wps;
 	enum wps_ap_info_type type;
 	struct wps_ap_info *ap;
-	int r;
+	int r, pbc_active;
+	const u8 *uuid;
 
 	if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL)
 		return;
@@ -2815,7 +2804,8 @@
 	else
 		type = WPS_AP_NOT_SEL_REG;
 
-	wpabuf_free(wps);
+	uuid = wps_get_uuid_e(wps);
+	pbc_active = wps_is_selected_pbc_registrar(wps);
 
 	ap = wpas_wps_get_ap_info(wpa_s, res->bssid);
 	if (ap) {
@@ -2827,13 +2817,16 @@
 			if (type != WPS_AP_NOT_SEL_REG)
 				wpa_blacklist_del(wpa_s, ap->bssid);
 		}
-		return;
+		ap->pbc_active = pbc_active;
+		if (uuid)
+			os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
+		goto out;
 	}
 
 	ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1,
 			      sizeof(struct wps_ap_info));
 	if (ap == NULL)
-		return;
+		goto out;
 
 	wpa_s->wps_ap = ap;
 	ap = &wpa_s->wps_ap[wpa_s->num_wps_ap];
@@ -2842,8 +2835,14 @@
 	os_memset(ap, 0, sizeof(*ap));
 	os_memcpy(ap->bssid, res->bssid, ETH_ALEN);
 	ap->type = type;
+	ap->pbc_active = pbc_active;
+	if (uuid)
+		os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
 	wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added",
 		   MAC2STR(ap->bssid), ap->type);
+
+out:
+	wpabuf_free(wps);
 }