Accumulative patch from commit 20a0b03debef66cc57b0c34a05f8be5229be907c

atheros: Fix auth_alg configuration for static WEP
nl80211: Implement set_rate_sets for non-hostapd AP case
nl80211: Enable more AP callbacks for non-hostapd AP mode
nl80211: Re-order functions to group AP/hostapd specific code
Remove compiler warning for non-P2P builds
random: Add support for maintaining internal entropy store over restarts
Fix a compiler warning on WPS-AP-without-UPnP builds
P2P: Retry provision discovery requests in IDLE state
P2P: Add callback for provision discovery failure
P2P: Add wpas_notify_p2p_provision_discovery()
P2P: Add group started notification
DBus: Move wpas_dbus_new_decompose_object_path()
DBus: Refactor array adding, add binary arrays
DBus: Add support for P2P primitives
DBus: Fix some typos on comments
Fix CONFIG_AP=y build without CONFIG_P2P=y
Fix non-P2P D-Bus build
nl80211: Add support for driver-based PMKSA cache
P2P: Start GO without extra scan step
Remove a compiler warning on uninitialized variable
Add EVENT_RX_ACTION handler for hostapd
Fix hostapd build without NEED_AP_MLME=y
Fix AP selection to check privacy mismatch and IBSS with WPA/RSN IE
bsd: Fix set_key() sequence number endian issue
Add a copyright and license statement for a radiotap header file
Use nl80211 as an example instead of WEXT
Add notes for CONFIG_WPS_ER build configuration option
Fix CONFIG_NO_WPA_PASSPHRASE=y build
hostapd: Don't mask out non-symmetric STA HT caps
P2P: Enable P2P capability advertisement on D-Bus
P2P: Update D-Bus network object semantics during group formation
P2P: Show P2P peer signal level in D-Bus P2P device properties
P2P: Fix P2P device signal level type in D-Bus
P2P: Add dissasoc_low_ack in P2P device properties
P2P: More complete persistent group management over D-Bus
P2P: Add WpsFailed signal in P2P D-Bus
P2P: Update listen and operating channel from P2P D-Bus
P2P: Fix WpsFailed signal in P2P D-Bus
atheros: Fix glibc 'invalid pointer' error when WPA_TRACE is enabled
Clear WPA and EAPOL state machine config pointer on network removal
	20a0b03debef66cc57b0c34a05f8be5229be907c

Change-Id: I2b83bf86ba9c7a9a218638be7b4de31d209cdde1
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 38d3284..26be2a8 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -193,9 +193,15 @@
 # it may help in cases where the system pool is not initialized properly.
 # However, it is very strongly recommended that the system pool is initialized
 # with enough entropy either by using hardware assisted random number
-# generatior or by storing state over device reboots.
+# generator or by storing state over device reboots.
 #
-# If the os_get_random() is known to provide strong ramdom data (e.g., on
+# hostapd can be configured to maintain its own entropy store over restarts to
+# enhance random number generation. This is not perfect, but it is much more
+# secure than using the same sequence of random numbers after every reboot.
+# This can be enabled with -e<entropy file> command line option. The specified
+# file needs to be readable and writable by hostapd.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
 # Linux/BSD, the board in question is known to have reliable source of random
 # data from /dev/urandom), the internal hostapd random pool can be disabled.
 # This will save some in binary size and CPU use. However, this should only be
diff --git a/hostapd/main.c b/hostapd/main.c
index 7a4cfb0..01ad826 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -369,7 +369,8 @@
 #endif /* CONFIG_NATIVE_WINDOWS */
 
 
-static int hostapd_global_init(struct hapd_interfaces *interfaces)
+static int hostapd_global_init(struct hapd_interfaces *interfaces,
+			       const char *entropy_file)
 {
 	hostapd_logger_register_cb(hostapd_logger_cb);
 
@@ -383,7 +384,7 @@
 		return -1;
 	}
 
-	random_init();
+	random_init(entropy_file);
 
 #ifndef CONFIG_NATIVE_WINDOWS
 	eloop_register_signal(SIGHUP, handle_reload, interfaces);
@@ -468,13 +469,14 @@
 	show_version();
 	fprintf(stderr,
 		"\n"
-		"usage: hostapd [-hdBKtv] [-P <PID file>] "
+		"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
 		"<configuration file(s)>\n"
 		"\n"
 		"options:\n"
 		"   -h   show this usage\n"
 		"   -d   show more debug messages (-dd for even more)\n"
 		"   -B   run daemon in the background\n"
+		"   -e   entropy file\n"
 		"   -P   PID file\n"
 		"   -K   include key data in debug messages\n"
 #ifdef CONFIG_DEBUG_FILE
@@ -504,12 +506,13 @@
 	int c, debug = 0, daemonize = 0;
 	char *pid_file = NULL;
 	const char *log_file = NULL;
+	const char *entropy_file = NULL;
 
 	if (os_program_init())
 		return -1;
 
 	for (;;) {
-		c = getopt(argc, argv, "Bdf:hKP:tv");
+		c = getopt(argc, argv, "Bde:f:hKP:tv");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -524,6 +527,9 @@
 		case 'B':
 			daemonize++;
 			break;
+		case 'e':
+			entropy_file = optarg;
+			break;
 		case 'f':
 			log_file = optarg;
 			break;
@@ -564,7 +570,7 @@
 		return -1;
 	}
 
-	if (hostapd_global_init(&interfaces))
+	if (hostapd_global_init(&interfaces, entropy_file))
 		return -1;
 
 	/* Initialize interfaces */
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 36bb826..f6076af 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -194,4 +194,12 @@
 	return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
 }
 
+static inline int hostapd_drv_set_authmode(struct hostapd_data *hapd,
+					   int auth_algs)
+{
+	if (hapd->driver == NULL || hapd->driver->set_authmode == NULL)
+		return 0;
+	return hapd->driver->set_authmode(hapd->drv_priv, auth_algs);
+}
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 02b7ecf..fc4bc31 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -396,6 +396,46 @@
 }
 
 
+static void hostapd_rx_action(struct hostapd_data *hapd,
+			      struct rx_action *rx_action)
+{
+	struct rx_mgmt rx_mgmt;
+	u8 *buf;
+	struct ieee80211_hdr *hdr;
+
+	wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR
+		   " BSSID=" MACSTR " category=%u",
+		   MAC2STR(rx_action->da), MAC2STR(rx_action->sa),
+		   MAC2STR(rx_action->bssid), rx_action->category);
+	wpa_hexdump(MSG_MSGDUMP, "Received action frame contents",
+		    rx_action->data, rx_action->len);
+
+	buf = os_zalloc(24 + 1 + rx_action->len);
+	if (buf == NULL)
+		return;
+	hdr = (struct ieee80211_hdr *) buf;
+	hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_ACTION);
+	if (rx_action->category == WLAN_ACTION_SA_QUERY) {
+		/*
+		 * Assume frame was protected; it would have been dropped if
+		 * not.
+		 */
+		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+	}
+	os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN);
+	os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN);
+	os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN);
+	buf[24] = rx_action->category;
+	os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len);
+	os_memset(&rx_mgmt, 0, sizeof(rx_mgmt));
+	rx_mgmt.frame = buf;
+	rx_mgmt.frame_len = 24 + 1 + rx_action->len;
+	hostapd_mgmt_rx(hapd, &rx_mgmt);
+	os_free(buf);
+}
+
+
 static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
 			       size_t len, u16 stype, int ok)
 {
@@ -530,6 +570,14 @@
 			break;
 		hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
 		break;
+#ifdef NEED_AP_MLME
+	case EVENT_RX_ACTION:
+		if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
+		    data->rx_action.bssid == NULL)
+			break;
+		hostapd_rx_action(hapd, &data->rx_action);
+		break;
+#endif /* NEED_AP_MLME */
 	default:
 		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
 		break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 32db668..d8af571 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -306,6 +306,12 @@
 		return 0;
 	}
 
+	/*
+	 * When IEEE 802.1X is not enabled, the driver may need to know how to
+	 * set authentication algorithms for static WEP.
+	 */
+	hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs);
+
 	for (i = 0; i < 4; i++) {
 		if (hapd->conf->ssid.wep.key[i] &&
 		    hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 3dce5cb..6c3696f 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -250,8 +250,14 @@
 		return;
 	os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap));
 	cap = le_to_host16(neg_ht_cap->ht_capabilities_info);
-	cap &= hapd->iconf->ht_capab;
-	cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED);
+
+	/*
+	 * Mask out HT features we don't support, but don't overwrite
+	 * non-symmetric features like STBC and SMPS. Just because
+	 * we're not in dynamic SMPS mode the STA might still be.
+	 */
+	cap &= (hapd->iconf->ht_capab | HT_CAP_INFO_RX_STBC_MASK |
+		HT_CAP_INFO_TX_STBC | HT_CAP_INFO_SMPS_MASK);
 
 	/*
 	 * STBC needs to be handled specially
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 217f9f9..6b6fd4b 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1852,6 +1852,7 @@
 
 const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
 {
+	*len = 0;
 	if (sm == NULL)
 		return NULL;
 
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index fc927f9..640e8cd 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -890,7 +890,7 @@
 {
 	struct wps_context *wps = hapd->wps;
 
-	if (hapd->wps == NULL)
+	if (wps == NULL)
 		return 0;
 
 #ifdef CONFIG_WPS_UPNP
diff --git a/src/crypto/random.c b/src/crypto/random.c
index a30afde..f545917 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -57,12 +57,18 @@
 static int random_fd = -1;
 #endif /* __linux__ */
 static unsigned int own_pool_ready = 0;
+#define RANDOM_ENTROPY_SIZE 20
+static char *random_entropy_file = NULL;
+static int random_entropy_file_read = 0;
 
 #define MIN_COLLECT_ENTROPY 1000
 static unsigned int entropy = 0;
 static unsigned int total_collected = 0;
 
 
+static void random_write_entropy(void);
+
+
 static u32 __ROL32(u32 x, u32 y)
 {
 	return (x << (y & 31)) | (x >> (32 - (y & 31)));
@@ -232,8 +238,12 @@
 	dummy_key_avail += res;
 	close(fd);
 
-	if (dummy_key_avail == sizeof(dummy_key))
+	if (dummy_key_avail == sizeof(dummy_key)) {
+		if (own_pool_ready < MIN_READY_MARK)
+			own_pool_ready = MIN_READY_MARK;
+		random_write_entropy();
 		return 1;
+	}
 
 	wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
 		   "random data available from /dev/random",
@@ -261,6 +271,7 @@
 	own_pool_ready++;
 	wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be "
 		   "ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK);
+	random_write_entropy();
 }
 
 
@@ -298,15 +309,84 @@
 		   (unsigned) (sizeof(dummy_key) - dummy_key_avail));
 	dummy_key_avail += res;
 
-	if (dummy_key_avail == sizeof(dummy_key))
+	if (dummy_key_avail == sizeof(dummy_key)) {
 		random_close_fd();
+		if (own_pool_ready < MIN_READY_MARK)
+			own_pool_ready = MIN_READY_MARK;
+		random_write_entropy();
+	}
 }
 
 #endif /* __linux__ */
 
 
-void random_init(void)
+static void random_read_entropy(void)
 {
+	char *buf;
+	size_t len;
+
+	if (!random_entropy_file)
+		return;
+
+	buf = os_readfile(random_entropy_file, &len);
+	if (buf == NULL)
+		return; /* entropy file not yet available */
+
+	if (len != 1 + RANDOM_ENTROPY_SIZE) {
+		wpa_printf(MSG_DEBUG, "random: Invalid entropy file %s",
+			   random_entropy_file);
+		os_free(buf);
+		return;
+	}
+
+	own_pool_ready = (u8) buf[0];
+	random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
+	random_entropy_file_read = 1;
+	os_free(buf);
+	wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
+		   "(own_pool_ready=%u)",
+		   random_entropy_file, own_pool_ready);
+}
+
+
+static void random_write_entropy(void)
+{
+	char buf[RANDOM_ENTROPY_SIZE];
+	FILE *f;
+	u8 opr;
+
+	if (!random_entropy_file)
+		return;
+
+	random_get_bytes(buf, RANDOM_ENTROPY_SIZE);
+
+	f = fopen(random_entropy_file, "wb");
+	if (f == NULL) {
+		wpa_printf(MSG_ERROR, "random: Could not write %s",
+			   random_entropy_file);
+		return;
+	}
+
+	opr = own_pool_ready > 0xff ? 0xff : own_pool_ready;
+	fwrite(&opr, 1, 1, f);
+	fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f);
+	fclose(f);
+
+	wpa_printf(MSG_DEBUG, "random: Updated entropy file %s "
+		   "(own_pool_ready=%u)",
+		   random_entropy_file, own_pool_ready);
+}
+
+
+void random_init(const char *entropy_file)
+{
+	os_free(random_entropy_file);
+	if (entropy_file)
+		random_entropy_file = os_strdup(entropy_file);
+	else
+		random_entropy_file = NULL;
+	random_read_entropy();
+
 #ifdef __linux__
 	if (random_fd >= 0)
 		return;
@@ -326,6 +406,8 @@
 
 	eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL);
 #endif /* __linux__ */
+
+	random_write_entropy();
 }
 
 
@@ -334,4 +416,7 @@
 #ifdef __linux__
 	random_close_fd();
 #endif /* __linux__ */
+	random_write_entropy();
+	os_free(random_entropy_file);
+	random_entropy_file = NULL;
 }
diff --git a/src/crypto/random.h b/src/crypto/random.h
index 5dabd2b..1048bb4 100644
--- a/src/crypto/random.h
+++ b/src/crypto/random.h
@@ -16,14 +16,14 @@
 #define RANDOM_H
 
 #ifdef CONFIG_NO_RANDOM_POOL
-#define random_init() do { } while (0)
+#define random_init(e) do { } while (0)
 #define random_deinit() do { } while (0)
 #define random_add_randomness(b, l) do { } while (0)
 #define random_get_bytes(b, l) os_get_random((b), (l))
 #define random_pool_ready() 1
 #define random_mark_pool_ready() do { } while (0)
 #else /* CONFIG_NO_RANDOM_POOL */
-void random_init(void);
+void random_init(const char *entropy_file);
 void random_deinit(void);
 void random_add_randomness(const void *buf, size_t len);
 int random_get_bytes(void *buf, size_t len);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 2a3efa4..c7dbdc1 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2243,6 +2243,18 @@
 	int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
 
 	/**
+	 * set_authmode - Set authentication algorithm(s) for static WEP
+	 * @priv: Private driver interface data
+	 * @authmode: 1=Open System, 2=Shared Key, 3=both
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function can be used to set authentication algorithms for AP
+	 * mode when static WEP is used. If the driver uses user space MLME/SME
+	 * implementation, there is no need to implement this function.
+	 */
+	int (*set_authmode)(void *priv, int authmode);
+
+	/**
 	 * driver_cmd - execute driver-specific command
 	 * @priv: private driver interface data
 	 * @cmd: command to execute
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 6ac1cea..1e78f6e 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -1116,7 +1116,7 @@
 		drv->we_version = range->we_version_compiled;
 	}
 
-	free(range);
+	os_free(range);
 	return 0;
 }
 
@@ -1357,6 +1357,23 @@
 	return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
 }
 
+static int atheros_set_authmode(void *priv, int auth_algs)
+{
+	int authmode;
+
+	if ((auth_algs & WPA_AUTH_ALG_OPEN) &&
+	    (auth_algs & WPA_AUTH_ALG_SHARED))
+		authmode = IEEE80211_AUTH_AUTO;
+	else if (auth_algs & WPA_AUTH_ALG_OPEN)
+		authmode = IEEE80211_AUTH_OPEN;
+	else if (auth_algs & WPA_AUTH_ALG_SHARED)
+		authmode = IEEE80211_AUTH_SHARED;
+	else
+		return -1;
+
+	return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode);
+}
+
 const struct wpa_driver_ops wpa_driver_atheros_ops = {
 	.name			= "atheros",
 	.hapd_init		= atheros_init,
@@ -1378,4 +1395,5 @@
 	.sta_clear_stats	= atheros_sta_clear_stats,
 	.commit			= atheros_commit,
 	.set_ap_wps_ie		= atheros_set_ap_wps_ie,
+	.set_authmode		= atheros_set_authmode,
 };
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 1b52865..4596a51 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -345,8 +345,20 @@
 	if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
 		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
 	wk.ik_keylen = key_len;
-	if (seq)
+	if (seq) {
+#ifdef WORDS_BIGENDIAN
+		/*
+		 * wk.ik_keyrsc is in host byte order (big endian), need to
+		 * swap it to match with the byte order used in WPA.
+		 */
+		int i;
+		u8 *keyrsc = (u8 *) &wk.ik_keyrsc;
+		for (i = 0; i < seq_len; i++)
+			keyrsc[WPA_KEY_RSC_LEN - i - 1] = seq[i];
+#else /* WORDS_BIGENDIAN */
 		os_memcpy(&wk.ik_keyrsc, seq, seq_len);
+#endif /* WORDS_BIGENDIAN */
+	}
 	os_memcpy(wk.ik_keydata, key, key_len);
 
 	return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index b4f01fa..cfc9372 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5043,70 +5043,17 @@
 }
 
 
-#ifdef HOSTAPD
-
-static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+/* Set kernel driver on given frequency (MHz) */
+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
 {
-	int i;
-	int *old;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
-		   ifidx);
-	for (i = 0; i < drv->num_if_indices; i++) {
-		if (drv->if_indices[i] == 0) {
-			drv->if_indices[i] = ifidx;
-			return;
-		}
-	}
-
-	if (drv->if_indices != drv->default_if_indices)
-		old = drv->if_indices;
-	else
-		old = NULL;
-
-	drv->if_indices = os_realloc(old,
-				     sizeof(int) * (drv->num_if_indices + 1));
-	if (!drv->if_indices) {
-		if (!old)
-			drv->if_indices = drv->default_if_indices;
-		else
-			drv->if_indices = old;
-		wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
-			   "interfaces");
-		wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
-		return;
-	} else if (!old)
-		os_memcpy(drv->if_indices, drv->default_if_indices,
-			  sizeof(drv->default_if_indices));
-	drv->if_indices[drv->num_if_indices] = ifidx;
-	drv->num_if_indices++;
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
+					   freq->sec_channel_offset);
 }
 
 
-static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-	int i;
-
-	for (i = 0; i < drv->num_if_indices; i++) {
-		if (drv->if_indices[i] == ifidx) {
-			drv->if_indices[i] = 0;
-			break;
-		}
-	}
-}
-
-
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-	int i;
-
-	for (i = 0; i < drv->num_if_indices; i++)
-		if (drv->if_indices[i] == ifidx)
-			return 1;
-
-	return 0;
-}
-
+#if defined(HOSTAPD) || defined(CONFIG_AP)
 
 static inline int min_int(int a, int b)
 {
@@ -5193,20 +5140,6 @@
 	return -ENOBUFS;
 }
 
-#endif /* HOSTAPD */
-
-
-/* Set kernel driver on given frequency (MHz) */
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
-					   freq->sec_channel_offset);
-}
-
-
-#ifdef HOSTAPD
 
 static int i802_set_rts(void *priv, int rts)
 {
@@ -5511,37 +5444,6 @@
 }
 
 
-static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
-                            const char *bridge_ifname)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	char name[IFNAMSIZ + 1];
-
-	os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
-	wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
-		   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
-	if (val) {
-		if (!if_nametoindex(name)) {
-			if (nl80211_create_iface(drv, name,
-						 NL80211_IFTYPE_AP_VLAN,
-						 NULL, 1) < 0)
-				return -1;
-			if (bridge_ifname &&
-			    linux_br_add_if(drv->ioctl_sock, bridge_ifname,
-					    name) < 0)
-				return -1;
-		}
-		linux_set_iface_flags(drv->ioctl_sock, name, 1);
-		return i802_set_sta_vlan(priv, addr, name, 0);
-	} else {
-		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
-		return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
-						    name);
-	}
-}
-
-
 static int i802_set_ht_params(void *priv, const u8 *ht_capab,
 			      size_t ht_capab_len, const u8 *ht_oper,
 			      size_t ht_oper_len)
@@ -5555,26 +5457,6 @@
 }
 
 
-static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct wpa_driver_nl80211_data *drv = eloop_ctx;
-	struct sockaddr_ll lladdr;
-	unsigned char buf[3000];
-	int len;
-	socklen_t fromlen = sizeof(lladdr);
-
-	len = recvfrom(sock, buf, sizeof(buf), 0,
-		       (struct sockaddr *)&lladdr, &fromlen);
-	if (len < 0) {
-		perror("recv");
-		return;
-	}
-
-	if (have_ifidx(drv, lladdr.sll_ifindex))
-		drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
-}
-
-
 static int i802_get_inact_sec(void *priv, const u8 *addr)
 {
 	struct hostap_sta_driver_data data;
@@ -5596,9 +5478,6 @@
 	return 0;
 }
 
-#endif /* HOSTAPD */
-
-#if defined(HOSTAPD) || defined(CONFIG_AP)
 
 static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
 			   int reason)
@@ -5641,6 +5520,120 @@
 
 #ifdef HOSTAPD
 
+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+	int i;
+	int *old;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
+		   ifidx);
+	for (i = 0; i < drv->num_if_indices; i++) {
+		if (drv->if_indices[i] == 0) {
+			drv->if_indices[i] = ifidx;
+			return;
+		}
+	}
+
+	if (drv->if_indices != drv->default_if_indices)
+		old = drv->if_indices;
+	else
+		old = NULL;
+
+	drv->if_indices = os_realloc(old,
+				     sizeof(int) * (drv->num_if_indices + 1));
+	if (!drv->if_indices) {
+		if (!old)
+			drv->if_indices = drv->default_if_indices;
+		else
+			drv->if_indices = old;
+		wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
+			   "interfaces");
+		wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
+		return;
+	} else if (!old)
+		os_memcpy(drv->if_indices, drv->default_if_indices,
+			  sizeof(drv->default_if_indices));
+	drv->if_indices[drv->num_if_indices] = ifidx;
+	drv->num_if_indices++;
+}
+
+
+static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+	int i;
+
+	for (i = 0; i < drv->num_if_indices; i++) {
+		if (drv->if_indices[i] == ifidx) {
+			drv->if_indices[i] = 0;
+			break;
+		}
+	}
+}
+
+
+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+	int i;
+
+	for (i = 0; i < drv->num_if_indices; i++)
+		if (drv->if_indices[i] == ifidx)
+			return 1;
+
+	return 0;
+}
+
+
+static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
+                            const char *bridge_ifname)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	char name[IFNAMSIZ + 1];
+
+	os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+	wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
+		   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
+	if (val) {
+		if (!if_nametoindex(name)) {
+			if (nl80211_create_iface(drv, name,
+						 NL80211_IFTYPE_AP_VLAN,
+						 NULL, 1) < 0)
+				return -1;
+			if (bridge_ifname &&
+			    linux_br_add_if(drv->ioctl_sock, bridge_ifname,
+					    name) < 0)
+				return -1;
+		}
+		linux_set_iface_flags(drv->ioctl_sock, name, 1);
+		return i802_set_sta_vlan(priv, addr, name, 0);
+	} else {
+		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
+		return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
+						    name);
+	}
+}
+
+
+static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	struct sockaddr_ll lladdr;
+	unsigned char buf[3000];
+	int len;
+	socklen_t fromlen = sizeof(lladdr);
+
+	len = recvfrom(sock, buf, sizeof(buf), 0,
+		       (struct sockaddr *)&lladdr, &fromlen);
+	if (len < 0) {
+		perror("recv");
+		return;
+	}
+
+	if (have_ifidx(drv, lladdr.sll_ifindex))
+		drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
+}
+
+
 static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
 			     struct i802_bss *bss,
 			     const char *brname, const char *ifname)
@@ -6562,6 +6555,55 @@
 }
 
 
+static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
+			 const u8 *pmkid)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	genlmsg_put(msg, 0, 0, genl_family_get_id(bss->drv->nl80211), 0, 0,
+		    cmd, 0);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+	if (pmkid)
+		NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
+	if (bssid)
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+
+	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ nla_put_failure:
+	return -ENOBUFS;
+}
+
+
+static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+{
+	struct i802_bss *bss = priv;
+	wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
+	return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
+}
+
+
+static int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+{
+	struct i802_bss *bss = priv;
+	wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
+		   MAC2STR(bssid));
+	return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
+}
+
+
+static int nl80211_flush_pmkid(void *priv)
+{
+	struct i802_bss *bss = priv;
+	wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
+	return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -6594,6 +6636,9 @@
 #ifdef HOSTAPD
 	.hapd_init = i802_init,
 	.hapd_deinit = i802_deinit,
+	.set_wds_sta = i802_set_wds_sta,
+#endif /* HOSTAPD */
+#if defined(HOSTAPD) || defined(CONFIG_AP)
 	.get_seqnum = i802_get_seqnum,
 	.flush = i802_flush,
 	.read_sta_data = i802_read_sta_data,
@@ -6601,16 +6646,13 @@
 	.sta_clear_stats = i802_sta_clear_stats,
 	.set_rts = i802_set_rts,
 	.set_frag = i802_set_frag,
-	.set_rate_sets = i802_set_rate_sets,
 	.set_cts_protect = i802_set_cts_protect,
 	.set_preamble = i802_set_preamble,
 	.set_short_slot_time = i802_set_short_slot_time,
 	.set_tx_queue_params = i802_set_tx_queue_params,
 	.set_sta_vlan = i802_set_sta_vlan,
-	.set_wds_sta = i802_set_wds_sta,
 	.set_ht_params = i802_set_ht_params,
-#endif /* HOSTAPD */
-#if defined(HOSTAPD) || defined(CONFIG_AP)
+	.set_rate_sets = i802_set_rate_sets,
 	.sta_deauth = i802_sta_deauth,
 	.sta_disassoc = i802_sta_disassoc,
 #endif /* HOSTAPD || CONFIG_AP */
@@ -6631,4 +6673,7 @@
 	.set_intra_bss = nl80211_set_intra_bss,
 	.set_param = nl80211_set_param,
 	.get_radio_name = nl80211_get_radio_name,
+	.add_pmkid = nl80211_add_pmkid,
+	.remove_pmkid = nl80211_remove_pmkid,
+	.flush_pmkid = nl80211_flush_pmkid,
 };
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 653609e..191099a 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -576,7 +576,7 @@
 	dev->listen_freq = freq;
 	if (msg.group_info)
 		dev->oper_freq = freq;
-	dev->level = level;
+	dev->info.level = level;
 
 	p2p_copy_wps_info(dev, 0, &msg);
 
@@ -2250,19 +2250,81 @@
 	p2p_set_timeout(p2p, 0, 200000);
 }
 
+
+/**
+ * p2p_retry_pd - Retry any pending provision disc requests in IDLE state
+ * @p2p: P2P module context from p2p_init()
+ */
+void p2p_retry_pd(struct p2p_data *p2p)
+{
+	struct p2p_device *dev;
+
+	if (p2p->state != P2P_IDLE)
+		return;
+
+	/*
+	 * Retry the prov disc req attempt only for the peer that the user had
+	 * requested for and provided a join has not been initiated on it
+	 * in the meantime.
+	 */
+
+	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+		if (os_memcmp(p2p->pending_pd_devaddr,
+			      dev->info.p2p_device_addr, ETH_ALEN) != 0)
+			continue;
+		if (!dev->req_config_methods)
+			continue;
+		if (dev->flags & P2P_DEV_PD_FOR_JOIN)
+			continue;
+
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
+			"pending Provisioning Discovery Request to "
+			MACSTR " (config methods 0x%x)",
+			MAC2STR(dev->info.p2p_device_addr),
+			dev->req_config_methods);
+		p2p_send_prov_disc_req(p2p, dev, 0);
+		return;
+	}
+}
+
+
 static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
 {
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 		"P2P: Provision Discovery Request TX callback: success=%d",
 		success);
-	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+	/*
+	 * Postpone resetting the pending action state till after we actually
+	 * time out. This allows us to take some action like notifying any
+	 * interested parties about no response to the request.
+	 *
+	 * When the timer (below) goes off we check in IDLE, SEARCH, or
+	 * LISTEN_ONLY state, which are the only allowed states to issue a PD
+	 * requests in, if this was still pending and then raise notification.
+	 */
 
 	if (!success) {
+		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
 		if (p2p->state != P2P_IDLE)
 			p2p_continue_find(p2p);
+		else if (p2p->user_initiated_pd) {
+			p2p->pending_action_state = P2P_PENDING_PD;
+			p2p_set_timeout(p2p, 0, 300000);
+		}
 		return;
 	}
 
+	/*
+	 * This postponing, of resetting pending_action_state, needs to be
+	 * done only for user initiated PD requests and not internal ones.
+	 */
+	if (p2p->user_initiated_pd)
+		p2p->pending_action_state = P2P_PENDING_PD;
+	else
+		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
 	/* Wait for response from the peer */
 	if (p2p->state == P2P_SEARCH)
 		p2p_set_state(p2p, P2P_PD_DURING_FIND);
@@ -2653,6 +2715,34 @@
 }
 
 
+static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
+{
+	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+	/*
+	 * For user initiated PD requests that we have not gotten any responses
+	 * for while in IDLE state, we retry them a couple of times before
+	 * giving up.
+	 */
+	if (!p2p->user_initiated_pd)
+		return;
+
+	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+		"P2P: User initiated Provision Discovery Request timeout");
+
+	if (p2p->pd_retries) {
+		p2p->pd_retries--;
+		p2p_retry_pd(p2p);
+	} else {
+		if (p2p->cfg->prov_disc_fail)
+			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
+						 p2p->pending_pd_devaddr,
+						 P2P_PROV_DISC_TIMEOUT);
+		p2p_reset_pending_pd(p2p);
+	}
+}
+
+
 static void p2p_timeout_invite(struct p2p_data *p2p)
 {
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
@@ -2701,8 +2791,14 @@
 
 	switch (p2p->state) {
 	case P2P_IDLE:
+		/* Check if we timed out waiting for PD req */
+		if (p2p->pending_action_state == P2P_PENDING_PD)
+			p2p_timeout_prov_disc_req(p2p);
 		break;
 	case P2P_SEARCH:
+		/* Check if we timed out waiting for PD req */
+		if (p2p->pending_action_state == P2P_PENDING_PD)
+			p2p_timeout_prov_disc_req(p2p);
 		p2p_search(p2p);
 		break;
 	case P2P_CONNECT:
@@ -2714,6 +2810,10 @@
 	case P2P_GO_NEG:
 		break;
 	case P2P_LISTEN_ONLY:
+		/* Check if we timed out waiting for PD req */
+		if (p2p->pending_action_state == P2P_PENDING_PD)
+			p2p_timeout_prov_disc_req(p2p);
+
 		if (p2p->ext_listen_only) {
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: Extended Listen Timing - Listen State "
@@ -2861,7 +2961,7 @@
 			  "invitation_reqs=%u\n",
 			  (int) (now.sec - dev->last_seen.sec),
 			  dev->listen_freq,
-			  dev->level,
+			  dev->info.level,
 			  p2p_wps_method_text(dev->wps_method),
 			  MAC2STR(dev->interface_addr),
 			  MAC2STR(dev->member_in_go_dev),
@@ -3328,6 +3428,22 @@
 }
 
 
+int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
+			 int cfg_op_channel)
+{
+	if (p2p_channel_to_freq(p2p->cfg->country, op_reg_class, op_channel)
+	    < 0)
+		return -1;
+
+	wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, "P2P: Set Operating channel: "
+		"reg_class %u channel %u", op_reg_class, op_channel);
+	p2p->cfg->op_reg_class = op_reg_class;
+	p2p->cfg->op_channel = op_channel;
+	p2p->cfg->cfg_op_channel = cfg_op_channel;
+	return 0;
+}
+
+
 int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
 			   u8 *iface_addr)
 {
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 954f562..db816a6 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -180,6 +180,11 @@
 	char serial_number[33];
 
 	/**
+	 * level - Signal level
+	 */
+	int level;
+
+	/**
 	 * config_methods - WPS Configuration Methods
 	 */
 	u16 config_methods;
@@ -210,6 +215,12 @@
 	struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
 };
 
+enum p2p_prov_disc_status {
+	P2P_PROV_DISC_SUCCESS,
+	P2P_PROV_DISC_TIMEOUT,
+	P2P_PROV_DISC_REJECTED,
+};
+
 /**
  * struct p2p_config - P2P configuration
  *
@@ -603,6 +614,21 @@
 	void (*prov_disc_resp)(void *ctx, const u8 *peer, u16 config_methods);
 
 	/**
+	 * prov_disc_fail - Callback on Provision Discovery failure
+	 * @ctx: Callback context from cb_ctx
+	 * @peer: Source address of the response
+	 * @status: Cause of failure, will not be %P2P_PROV_DISC_SUCCESS
+	 *
+	 * This callback is used to indicate either a failure or no response
+	 * to an earlier provision discovery request.
+	 *
+	 * This callback handler can be set to %NULL if provision discovery
+	 * is not used or failures do not need to be indicated.
+	 */
+	void (*prov_disc_fail)(void *ctx, const u8 *peer,
+			       enum p2p_prov_disc_status status);
+
+	/**
 	 * invitation_process - Optional callback for processing Invitations
 	 * @ctx: Callback context from cb_ctx
 	 * @sa: Source address of the Invitation Request
@@ -1470,4 +1496,15 @@
 int p2p_add_wps_vendor_extension(struct p2p_data *p2p,
 				 const struct wpabuf *vendor_ext);
 
+/**
+ * p2p_set_oper_channel - Set the P2P operating channel
+ * @p2p: P2P module context from p2p_init()
+ * @op_reg_class: Operating regulatory class to set
+ * @op_channel: operating channel to set
+ * @cfg_op_channel : Whether op_channel is hardcoded in configuration
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
+			 int cfg_op_channel);
+
 #endif /* P2P_H */
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 68b1194..52d9311 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -33,7 +33,6 @@
 	struct dl_list list;
 	struct os_time last_seen;
 	int listen_freq;
-	int level;
 	enum p2p_wps_method wps_method;
 
 	struct p2p_peer_info info;
@@ -393,6 +392,23 @@
 	 * wps_vendor_ext - WPS Vendor Extensions to add
 	 */
 	struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+
+	/*
+	 * user_initiated_pd - Whether a PD request is user initiated or not.
+	 */
+	u8 user_initiated_pd;
+
+	/*
+	 * Keep track of which peer a given PD request was sent to.
+	 * Used to raise a timeout alert in case there is no response.
+	 */
+	u8 pending_pd_devaddr[ETH_ALEN];
+
+	/*
+	 * Retry counter for provision discovery requests when issued
+	 * in IDLE state.
+	 */
+	int pd_retries;
 };
 
 /**
@@ -586,6 +602,7 @@
 				const u8 *data, size_t len);
 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
 			   int join);
+void p2p_reset_pending_pd(struct p2p_data *p2p);
 
 /* p2p_invitation.c */
 void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index e064216..f7ff06c 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -21,6 +21,13 @@
 #include "p2p.h"
 
 
+/*
+ * Number of retries to attempt for provision discovery requests during IDLE
+ * state in case the peer is not listening.
+ */
+#define MAX_PROV_DISC_REQ_RETRIES 10
+
+
 static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
 					    u16 config_methods)
 {
@@ -215,6 +222,11 @@
 		return;
 	}
 
+	if (p2p->pending_action_state == P2P_PENDING_PD) {
+		os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
+		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+	}
+
 	if (dev->dialog_token != msg.dialog_token) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Ignore Provisioning Discovery Response with "
@@ -224,9 +236,20 @@
 		return;
 	}
 
+	/*
+	 * If the response is from the peer to whom a user initiated request
+	 * was sent earlier, we reset that state info here.
+	 */
+	if (p2p->user_initiated_pd &&
+	    os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
+		p2p_reset_pending_pd(p2p);
+
 	if (msg.wps_config_methods != dev->req_config_methods) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
 			"our Provisioning Discovery Request");
+		if (p2p->cfg->prov_disc_fail)
+			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
+						 P2P_PROV_DISC_REJECTED);
 		p2p_parse_free(&msg);
 		goto out;
 	}
@@ -301,6 +324,8 @@
 		return -1;
 	}
 
+	os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
+
 	wpabuf_free(req);
 	return 0;
 }
@@ -343,5 +368,23 @@
 		return 0;
 	}
 
+	/*
+	 * We use the join param as a cue to differentiate between user
+	 * initiated PD request and one issued during finds (internal).
+	 */
+	p2p->user_initiated_pd = !join;
+
+	/* Also set some retries to attempt in case of IDLE state */
+	if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
+		p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
+
 	return p2p_send_prov_disc_req(p2p, dev, join);
 }
+
+
+void p2p_reset_pending_pd(struct p2p_data *p2p)
+{
+	p2p->user_initiated_pd = 0;
+	os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
+	p2p->pd_retries = 0;
+}
diff --git a/src/utils/radiotap_iter.h b/src/utils/radiotap_iter.h
index 92a798a..2e0e872 100644
--- a/src/utils/radiotap_iter.h
+++ b/src/utils/radiotap_iter.h
@@ -1,3 +1,18 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007		Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
 #ifndef __RADIOTAP_ITER_H
 #define __RADIOTAP_ITER_H
 
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index aeb9ab9..767e995 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -12,7 +12,13 @@
 CFLAGS += -I../src
 CFLAGS += -I../src/utils
 
-ALL=wpa_supplicant wpa_passphrase wpa_cli
+-include .config
+
+ALL=wpa_supplicant wpa_cli
+
+ifndef CONFIG_NO_WPA_PASSPHRASE
+ALL += wpa_passphrase
+endif
 
 all: verify_config $(ALL) dynamic_eap_methods
 
@@ -52,8 +58,6 @@
 OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
 OBJS_c += ../src/utils/wpa_debug.o
 
--include .config
-
 ifndef CONFIG_OS
 ifdef CONFIG_NATIVE_WINDOWS
 CONFIG_OS=win32
@@ -1012,7 +1016,9 @@
 SHA1OBJS += ../src/crypto/fips_prf_internal.o
 endif
 endif
-ifndef CONFIG_NO_WPA_PASSPHRASE
+ifdef CONFIG_NO_WPA_PASSPHRASE
+CFLAGS += -DCONFIG_NO_PBKDF2
+else
 SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
 endif
 ifdef NEED_T_PRF
@@ -1140,6 +1146,9 @@
 ifdef CONFIG_WPS
 DBUS_OBJS += dbus/dbus_new_handlers_wps.o
 endif
+ifdef CONFIG_P2P
+DBUS_OBJS += dbus/dbus_new_handlers_p2p.o
+endif
 ifndef DBUS_LIBS
 DBUS_LIBS := $(shell pkg-config --libs dbus-1)
 endif
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index 93184e4..313e873 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -55,13 +55,18 @@
 
 WPS is an optional component that needs to be enabled in
 wpa_supplicant build configuration (.config). Here is an example
-configuration that includes WPS support and Linux wireless extensions
--based driver interface:
+configuration that includes WPS support and Linux nl80211 -based
+driver interface:
 
-CONFIG_DRIVER_WEXT=y
+CONFIG_DRIVER_NL80211=y
 CONFIG_WPS=y
 CONFIG_WPS2=y
 
+If you want to enable WPS external registrar (ER) functionality, you
+will also need to add following line:
+
+CONFIG_WPS_ER=y
+
 
 WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for
 the device. This is configured in the runtime configuration for
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 95279d3..dddac44 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -227,18 +227,21 @@
 #ifdef CONFIG_P2P
 	struct wpa_supplicant *wpa_s = ctx;
 
-	if (event == WPS_EV_FAIL && wpa_s->parent && wpa_s->parent != wpa_s &&
-	    wpa_s == wpa_s->global->p2p_group_formation) {
+	if (event == WPS_EV_FAIL) {
 		struct wps_event_fail *fail = &data->fail;
 
-		/*
-		 * src/ap/wps_hostapd.c has already sent this on the main
-		 * interface, so only send on the parent interface here if
-		 * needed.
-		 */
-		wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
-			"msg=%d config_error=%d",
-			fail->msg, fail->config_error);
+		if (wpa_s->parent && wpa_s->parent != wpa_s &&
+		    wpa_s == wpa_s->global->p2p_group_formation) {
+			/*
+			 * src/ap/wps_hostapd.c has already sent this on the
+			 * main interface, so only send on the parent interface
+			 * here if needed.
+			 */
+			wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+				"msg=%d config_error=%d",
+				fail->msg, fail->config_error);
+		}
+		wpas_p2p_wps_failed(wpa_s, fail);
 	}
 #endif /* CONFIG_P2P */
 }
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index c370362..10abdad 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -44,6 +44,8 @@
 #define CFG_CHANGED_WPS_STRING BIT(8)
 #define CFG_CHANGED_P2P_INTRA_BSS BIT(9)
 #define CFG_CHANGED_VENDOR_EXTENSION BIT(10)
+#define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11)
+#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
 
 /**
  * struct wpa_config - wpa_supplicant configuration data
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index ecf2e08..b071f76 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -297,7 +297,12 @@
 					     char *cmd)
 {
 	u8 bssid[ETH_ALEN], *_bssid = bssid;
-	u8 p2p_dev_addr[ETH_ALEN], *_p2p_dev_addr = NULL;
+#ifdef CONFIG_P2P
+	u8 p2p_dev_addr[ETH_ALEN];
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_AP
+	u8 *_p2p_dev_addr = NULL;
+#endif /* CONFIG_AP */
 
 	if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
 		_bssid = NULL;
@@ -1484,6 +1489,8 @@
 		}
 		if (wpa_s->current_ssid) {
 			eapol_sm_invalidate_cached_session(wpa_s->eapol);
+			wpa_sm_set_config(wpa_s->wpa, NULL);
+			eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 			wpa_supplicant_disassociate(wpa_s,
 				                    WLAN_REASON_DEAUTH_LEAVING);
 		}
@@ -1507,6 +1514,8 @@
 		 * removed.
 		 */
 		eapol_sm_invalidate_cached_session(wpa_s->eapol);
+		wpa_sm_set_config(wpa_s->wpa, NULL);
+		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 
 		wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 	}
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index d900487..788f736 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -16,6 +16,7 @@
 #include <dbus/dbus.h>
 
 #include "common.h"
+#include "wpabuf.h"
 #include "dbus_dict_helpers.h"
 
 
@@ -443,11 +444,12 @@
 
 
 /**
- * Begin a string array entry in the dict
+ * Begin an array entry in the dict
  *
  * @param iter_dict A valid DBusMessageIter returned from
  *                  wpa_dbus_dict_open_write()
  * @param key The key of the dict item
+ * @param type The type of the contained data
  * @param iter_dict_entry A private DBusMessageIter provided by the caller to
  *                        be passed to wpa_dbus_dict_end_string_array()
  * @param iter_dict_val A private DBusMessageIter provided by the caller to
@@ -457,12 +459,21 @@
  * @return TRUE on success, FALSE on failure
  *
  */
-dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
-					     const char *key,
-					     DBusMessageIter *iter_dict_entry,
-					     DBusMessageIter *iter_dict_val,
-					     DBusMessageIter *iter_array)
+dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
+				      const char *key, const char *type,
+				      DBusMessageIter *iter_dict_entry,
+				      DBusMessageIter *iter_dict_val,
+				      DBusMessageIter *iter_array)
 {
+	char array_type[10];
+	int err;
+
+	err = os_snprintf(array_type, sizeof(array_type),
+			  DBUS_TYPE_ARRAY_AS_STRING "%s",
+			  type);
+	if (err < 0 || err > (int) sizeof(array_type))
+		return FALSE;
+
 	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
 		return FALSE;
 
@@ -472,20 +483,31 @@
 
 	if (!dbus_message_iter_open_container(iter_dict_entry,
 					      DBUS_TYPE_VARIANT,
-					      DBUS_TYPE_ARRAY_AS_STRING
-					      DBUS_TYPE_STRING_AS_STRING,
+					      array_type,
 					      iter_dict_val))
 		return FALSE;
 
 	if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
-					      DBUS_TYPE_STRING_AS_STRING,
-					      iter_array))
+					      type, iter_array))
 		return FALSE;
 
 	return TRUE;
 }
 
 
+dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
+					     const char *key,
+					     DBusMessageIter *iter_dict_entry,
+					     DBusMessageIter *iter_dict_val,
+					     DBusMessageIter *iter_array)
+{
+	return wpa_dbus_dict_begin_array(
+		iter_dict, key,
+		DBUS_TYPE_STRING_AS_STRING,
+		iter_dict_entry, iter_dict_val, iter_array);
+}
+
+
 /**
  * Add a single string element to a string array dict entry
  *
@@ -508,23 +530,67 @@
 
 
 /**
- * End a string array dict entry
+ * Add a single byte array element to a string array dict entry
+ *
+ * @param iter_array A valid DBusMessageIter returned from
+ *                   wpa_dbus_dict_begin_array()'s iter_array
+ *                   parameter -- note that wpa_dbus_dict_begin_array()
+ *                   must have been called with "ay" as the type
+ * @param value The data to be added to the dict entry's array
+ * @param value_len The length of the data
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
+						const u8 *value,
+						size_t value_len)
+{
+	DBusMessageIter iter_bytes;
+	size_t i;
+
+	if (!iter_array || !value)
+		return FALSE;
+
+	if (!dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
+					      DBUS_TYPE_BYTE_AS_STRING,
+					      &iter_bytes))
+		return FALSE;
+
+	for (i = 0; i < value_len; i++) {
+		if (!dbus_message_iter_append_basic(&iter_bytes,
+						    DBUS_TYPE_BYTE,
+						    &(value[i])))
+			return FALSE;
+	}
+
+	if (!dbus_message_iter_close_container(iter_array, &iter_bytes))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+/**
+ * End an array dict entry
  *
  * @param iter_dict A valid DBusMessageIter returned from
  *                  wpa_dbus_dict_open_write()
  * @param iter_dict_entry A private DBusMessageIter returned from
- *                        wpa_dbus_dict_end_string_array()
+ *                        wpa_dbus_dict_begin_string_array() or
+ *			  wpa_dbus_dict_begin_array()
  * @param iter_dict_val A private DBusMessageIter returned from
- *                      wpa_dbus_dict_end_string_array()
+ *                      wpa_dbus_dict_begin_string_array() or
+ *			wpa_dbus_dict_begin_array()
  * @param iter_array A DBusMessageIter returned from
- *                   wpa_dbus_dict_end_string_array()
+ *                   wpa_dbus_dict_begin_string_array() or
+ *		     wpa_dbus_dict_begin_array()
  * @return TRUE on success, FALSE on failure
  *
  */
-dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
-					   DBusMessageIter *iter_dict_entry,
-					   DBusMessageIter *iter_dict_val,
-					   DBusMessageIter *iter_array)
+dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
+				    DBusMessageIter *iter_dict_entry,
+				    DBusMessageIter *iter_dict_val,
+				    DBusMessageIter *iter_array)
 {
 	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
 		return FALSE;
@@ -583,6 +649,52 @@
 }
 
 
+/**
+ * Convenience function to add an wpabuf binary array to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ *                  wpa_dbus_dict_open_write()
+ * @param key The key of the dict item
+ * @param items The array of wpabuf structures
+ * @param num_items The number of strings in the array
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
+					      const char *key,
+					      const struct wpabuf **items,
+					      const dbus_uint32_t num_items)
+{
+	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
+	dbus_uint32_t i;
+
+	if (!key)
+		return FALSE;
+	if (!items && (num_items != 0))
+		return FALSE;
+
+	if (!wpa_dbus_dict_begin_array(iter_dict, key,
+				       DBUS_TYPE_ARRAY_AS_STRING
+				       DBUS_TYPE_BYTE_AS_STRING,
+				       &iter_dict_entry, &iter_dict_val,
+				       &iter_array))
+		return FALSE;
+
+	for (i = 0; i < num_items; i++) {
+		if (!wpa_dbus_dict_bin_array_add_element(&iter_array,
+							 wpabuf_head(items[i]),
+							 wpabuf_len(items[i])))
+			return FALSE;
+	}
+
+	if (!wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
+				     &iter_dict_val, &iter_array))
+		return FALSE;
+
+	return TRUE;
+}
+
+
 /*****************************************************/
 /* Stuff for reading dicts                           */
 /*****************************************************/
@@ -615,8 +727,7 @@
 #define BYTE_ARRAY_ITEM_SIZE (sizeof(char))
 
 static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
-	DBusMessageIter *iter, int array_type,
-	struct wpa_dbus_dict_entry *entry)
+	DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
 {
 	dbus_uint32_t count = 0;
 	dbus_bool_t success = FALSE;
@@ -733,6 +844,66 @@
 }
 
 
+#define BIN_ARRAY_CHUNK_SIZE 10
+#define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *))
+
+static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
+	DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
+{
+	struct wpa_dbus_dict_entry tmpentry;
+	size_t buflen = 0;
+	int i;
+
+	if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
+		return FALSE;
+
+	entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
+	entry->array_len = 0;
+	entry->binarray_value = NULL;
+
+	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
+		DBusMessageIter iter_array;
+
+		if (entry->array_len == buflen) {
+			struct wpabuf **newbuf;
+
+			buflen += BIN_ARRAY_CHUNK_SIZE;
+
+			newbuf = os_realloc(entry->binarray_value,
+					    buflen * BIN_ARRAY_ITEM_SIZE);
+			if (!newbuf)
+				goto cleanup;
+			entry->binarray_value = newbuf;
+		}
+
+		dbus_message_iter_recurse(iter, &iter_array);
+		if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
+					== FALSE)
+			goto cleanup;
+
+		entry->binarray_value[entry->array_len] =
+			wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value,
+					      tmpentry.array_len);
+		if (entry->binarray_value[entry->array_len] == NULL) {
+			wpa_dbus_dict_entry_clear(&tmpentry);
+			goto cleanup;
+		}
+		entry->array_len++;
+		dbus_message_iter_next(iter);
+	}
+
+	return TRUE;
+
+ cleanup:
+	for (i = 0; i < (int) entry->array_len; i++)
+		wpabuf_free(entry->binarray_value[i]);
+	os_free(entry->binarray_value);
+	entry->array_len = 0;
+	entry->binarray_value = NULL;
+	return FALSE;
+}
+
+
 static dbus_bool_t _wpa_dbus_dict_entry_get_array(
 	DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
 {
@@ -748,7 +919,6 @@
  	switch (array_type) {
 	case DBUS_TYPE_BYTE:
 		success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
-							      array_type,
 							      entry);
 		break;
 	case DBUS_TYPE_STRING:
@@ -756,6 +926,8 @@
 								array_type,
 								entry);
 		break;
+	case DBUS_TYPE_ARRAY:
+		success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
 	default:
 		break;
 	}
@@ -917,6 +1089,11 @@
 			break;
 		}
 		break;
+	case WPAS_DBUS_TYPE_BINARRAY:
+		for (i = 0; i < entry->array_len; i++)
+			wpabuf_free(entry->binarray_value[i]);
+		os_free(entry->binarray_value);
+		break;
 	}
 
 	memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index eb31575..9e90c50 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -15,6 +15,8 @@
 #ifndef DBUS_DICT_HELPERS_H
 #define DBUS_DICT_HELPERS_H
 
+#include "wpabuf.h"
+
 /*
  * Adding a dict to a DBusMessage
  */
@@ -74,7 +76,13 @@
 					    const char *value,
 					    const dbus_uint32_t value_len);
 
-/* Manual construction and addition of string array elements */
+/* Manual construction and addition of array elements */
+dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
+                                      const char *key, const char *type,
+                                      DBusMessageIter *iter_dict_entry,
+                                      DBusMessageIter *iter_dict_val,
+                                      DBusMessageIter *iter_array);
+
 dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
                                              const char *key,
                                              DBusMessageIter *iter_dict_entry,
@@ -84,10 +92,24 @@
 dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
                                              const char *elem);
 
-dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
-                                           DBusMessageIter *iter_dict_entry,
-                                           DBusMessageIter *iter_dict_val,
-                                           DBusMessageIter *iter_array);
+dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
+						const u8 *value,
+						size_t value_len);
+
+dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
+                                    DBusMessageIter *iter_dict_entry,
+                                    DBusMessageIter *iter_dict_val,
+                                    DBusMessageIter *iter_array);
+
+static inline dbus_bool_t
+wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
+			       DBusMessageIter *iter_dict_entry,
+			       DBusMessageIter *iter_dict_val,
+			       DBusMessageIter *iter_array)
+{
+	return wpa_dbus_dict_end_array(iter_dict, iter_dict_entry,
+				       iter_dict_val, iter_array);
+}
 
 /* Convenience function to add a whole string list */
 dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
@@ -95,14 +117,22 @@
 					      const char **items,
 					      const dbus_uint32_t num_items);
 
+dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
+					      const char *key,
+					      const struct wpabuf **items,
+					      const dbus_uint32_t num_items);
+
 /*
  * Reading a dict from a DBusMessage
  */
 
+#define WPAS_DBUS_TYPE_BINARRAY (DBUS_NUMBER_OF_TYPES + 100)
+
 struct wpa_dbus_dict_entry {
 	int type;         /** the dbus type of the dict entry's value */
 	int array_type;   /** the dbus type of the array elements if the dict
-			      entry value contains an array */
+			      entry value contains an array, or the special
+			      WPAS_DBUS_TYPE_BINARRAY */
 	const char *key;  /** key of the dict entry */
 
 	/** Possible values of the property */
@@ -119,6 +149,7 @@
 		double double_value;
 		char *bytearray_value;
 		char **strarray_value;
+		struct wpabuf **binarray_value;
 	};
 	dbus_uint32_t array_len; /** length of the array if the dict entry's
 				     value contains an array */
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 49a0895..c75fbdf 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -17,6 +17,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "common/ieee802_11_defs.h"
 #include "wps/wps.h"
 #include "../config.h"
 #include "../wpa_supplicant_i.h"
@@ -27,6 +28,8 @@
 #include "dbus_new_handlers.h"
 #include "dbus_common.h"
 #include "dbus_common_i.h"
+#include "dbus_new_handlers_p2p.h"
+#include "p2p/p2p.h"
 
 
 /**
@@ -650,13 +653,783 @@
 
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_P2P
+
+/**
+ * wpas_dbus_signal_p2p_group_removed - Signals P2P group was removed
+ * @wpa_s: %wpa_supplicant network interface data
+ * @role: role of this device (client or GO)
+ * Sends signal with i/f name and role as string arguments
+ */
+void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+					const char *role)
+{
+
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
+	char *ifname = wpa_s->ifname;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "GroupFinished");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &ifname)) {
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished"
+				      "signal -not enough memory for ifname ");
+		goto err;
+	}
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &role))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished"
+				      "signal -not enough memory for role ");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
+
+err:
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_provision_discovery - Signals various PD events
+ *
+ * @dev_addr - who sent the request or responded to our request.
+ * @request - Will be 1 if request, 0 for response.
+ * @status - valid only in case of response
+ * @config_methods - wps config methods
+ * @generated_pin - pin to be displayed in case of WPS_CONFIG_DISPLAY method
+ *
+ * Sends following provision discovery related events:
+ *	ProvisionDiscoveryRequestDisplayPin
+ *	ProvisionDiscoveryResponseDisplayPin
+ *	ProvisionDiscoveryRequestEnterPin
+ *	ProvisionDiscoveryResponseEnterPin
+ *	ProvisionDiscoveryPBCRequest
+ *	ProvisionDiscoveryPBCResponse
+ *
+ *	TODO::
+ *	ProvisionDiscoveryFailure (timeout case)
+ */
+void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					      const u8 *dev_addr, int request,
+					      enum p2p_prov_disc_status status,
+					      u16 config_methods,
+					      unsigned int generated_pin)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	struct wpas_dbus_priv *iface;
+	char *_signal;
+	int add_pin = 0;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+	int error_ret = 1;
+	char pin[9], *p_pin = NULL;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	if (request || !status) {
+		if (config_methods & WPS_CONFIG_DISPLAY)
+			_signal = request ?
+				 "ProvisionDiscoveryRequestDisplayPin" :
+				 "ProvisionDiscoveryResponseEnterPin";
+		else if (config_methods & WPS_CONFIG_KEYPAD)
+			_signal = request ?
+				 "ProvisionDiscoveryRequestEnterPin" :
+				 "ProvisionDiscoveryResponseDisplayPin";
+		else if (config_methods & WPS_CONFIG_PUSHBUTTON)
+			_signal = request ? "ProvisionDiscoveryPBCRequest" :
+				   "ProvisionDiscoveryPBCResponse";
+		else
+			return; /* Unknown or un-supported method */
+	} else if (!request && status)
+		/* Explicit check for failure response */
+		_signal = "ProvisionDiscoveryFailure";
+
+	add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) ||
+		   (!request && !status &&
+			(config_methods & WPS_CONFIG_KEYPAD)));
+
+	if (add_pin) {
+		os_snprintf(pin, sizeof(pin), "%08d", generated_pin);
+		p_pin = pin;
+	}
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE, _signal);
+	if (msg == NULL)
+		return;
+
+	/* Check if this is a known peer */
+	if (p2p_get_peer_info(wpa_s->global->p2p, dev_addr, 0, NULL, 0) < 0)
+		goto error;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+			"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+			COMPACT_MACSTR,
+			wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+	path = peer_obj_path;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!dbus_message_iter_append_basic(&iter,
+					    DBUS_TYPE_OBJECT_PATH,
+					    &path))
+			goto error;
+
+	if (!request && status)
+		/* Attach status to ProvisionDiscoveryFailure */
+		error_ret = !dbus_message_iter_append_basic(&iter,
+						    DBUS_TYPE_INT32,
+						    &status);
+	else
+		error_ret = (add_pin &&
+				 !dbus_message_iter_append_basic(&iter,
+							DBUS_TYPE_STRING,
+							&p_pin));
+
+error:
+	if (!error_ret)
+		dbus_connection_send(iface->con, msg, NULL);
+	else
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+
+	dbus_message_unref(msg);
+}
+
+
+void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+				     const u8 *src, u16 dev_passwd_id)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	struct wpas_dbus_priv *iface;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+		    wpa_s->dbus_new_path, MAC2STR(src));
+	path = peer_obj_path;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "GONegotiationRequest");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &path) ||
+	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16,
+					    &dev_passwd_id))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+}
+
+
+static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s,
+					const struct wpa_ssid *ssid,
+					char *group_obj_path)
+{
+	char group_name[3];
+
+	if (os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN))
+		return -1;
+
+	memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
+	group_name[2] = '\0';
+
+	os_snprintf(group_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_GROUPS_PART "/%s",
+		    wpa_s->dbus_new_path, group_name);
+
+	return 0;
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_group_started - Signals P2P group has
+ * started.Emitted when a group is succesfully started
+ * irrespective of the role (client/GO) of the current device
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @ssid: SSID object
+ * @client: this device is P2P client
+ * @network_id: network id of the group started, use instead of ssid->id
+ *	to account for persistent groups
+ */
+void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+					const struct wpa_ssid *ssid,
+					int client, int network_id)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+	char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	iface = wpa_s->parent->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
+		return;
+
+	/* New interface has been created for this group */
+	msg = dbus_message_new_signal(wpa_s->parent->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "GroupStarted");
+
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto nomem;
+
+	/*
+	 * In case the device supports creating a separate interface the
+	 * DBus client will need to know the object path for the interface
+	 * object this group was created on, so include it here.
+	 */
+	if (!wpa_dbus_dict_append_object_path(&dict_iter,
+					"interface_object",
+					wpa_s->dbus_new_path))
+		goto nomem;
+
+	if (!wpa_dbus_dict_append_string(&dict_iter, "role",
+					 client ? "client" : "GO"))
+		goto nomem;
+
+	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
+		    wpa_s->parent->dbus_new_path, network_id);
+
+	if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
+					     group_obj_path) ||
+	   !wpa_dbus_dict_append_object_path(&dict_iter, "network_object",
+					     net_obj_path) ||
+	   !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto nomem;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+	dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit GONeogtiation Success or Failure signals based
+ * on status.
+ * @status: Status of the GO neg request. 0 for success, other for errors.
+ */
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, int status)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	struct wpas_dbus_priv *iface;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      status ? "GONegotiationFailure" :
+					       "GONegotiationSuccess");
+	if (msg == NULL)
+		return;
+
+	if (status) {
+		dbus_message_iter_init_append(msg, &iter);
+		if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32,
+						    &status)) {
+			wpa_printf(MSG_ERROR,
+				   "dbus: Failed to construct signal");
+			goto err;
+		}
+	}
+
+	dbus_connection_send(iface->con, msg, NULL);
+err:
+	dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit Invitation Result signal based on status and
+ * bssid
+ * @status: Status of the Invite request. 0 for success, other
+ * for errors
+ * @bssid : Basic Service Set Identifier
+ */
+void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+					    int status, const u8 *bssid)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+
+	wpa_printf(MSG_INFO, "%s\n", __func__);
+
+	iface = wpa_s->global->dbus;
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "InvitationResult");
+
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto nomem;
+
+	if (!wpa_dbus_dict_append_int32(&dict_iter, "status", status))
+		goto nomem;
+	if (bssid) {
+		if (!wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
+						     (const char *) bssid,
+						     ETH_ALEN))
+			goto nomem;
+	}
+	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto nomem;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+	dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a peer joining the group.
+ * The signal will carry path to the group member object
+ * constructed using p2p i/f addr used for connecting.
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @member_addr: addr (p2p i/f) of the peer joining the group
+ */
+void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+				      const u8 *member)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	if (!wpa_s->dbus_groupobj_path)
+		return;
+
+	os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+			"%s/"  WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/"
+			COMPACT_MACSTR,
+			wpa_s->dbus_groupobj_path, MAC2STR(member));
+
+	msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
+				      WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+				      "PeerJoined");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	path = groupmember_obj_path;
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &path))
+		goto err;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a peer disconnecting the group.
+ * The signal will carry path to the group member object
+ * constructed using p2p i/f addr used for connecting.
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @member_addr: addr (p2p i/f) of the peer joining the group
+ */
+void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+				      const u8 *member)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	if (!wpa_s->dbus_groupobj_path)
+		return;
+
+	os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+			"%s/"  WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/"
+			COMPACT_MACSTR,
+			wpa_s->dbus_groupobj_path, MAC2STR(member));
+
+	msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
+				      WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+				      "PeerDisconnected");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	path = groupmember_obj_path;
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &path))
+		goto err;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct PeerDisconnected "
+			      "signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a service discovery request.
+ * The signal will carry station address, frequency, dialog token,
+ * update indicator and it tlvs
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sa: station addr (p2p i/f) of the peer
+ * @dialog_token: service discovery request dialog token
+ * @update_indic: service discovery request update indicator
+ * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs_len: service discovery request tlvs length
+ */
+void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
+				     int freq, const u8 *sa, u8 dialog_token,
+				     u16 update_indic, const u8 *tlvs,
+				     size_t tlvs_len)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "ServiceDiscoveryRequest");
+	if (msg == NULL)
+		return;
+
+	/* Check if this is a known peer */
+	if (p2p_get_peer_info(wpa_s->global->p2p, sa, 0, NULL, 0) < 0)
+		goto error;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+		    COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
+
+	path = peer_obj_path;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto error;
+
+
+	if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+					      path) ||
+	    !wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) ||
+	    !wpa_dbus_dict_append_int32(&dict_iter, "dialog_token",
+					dialog_token) ||
+	    !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
+					 update_indic) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
+					     (const char *) tlvs,
+					     tlvs_len) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto error;
+
+	dbus_connection_send(iface->con, msg, NULL);
+	dbus_message_unref(msg);
+	return;
+error:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a service discovery response.
+ * The signal will carry station address, update indicator and it
+ * tlvs
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sa: station addr (p2p i/f) of the peer
+ * @update_indic: service discovery request update indicator
+ * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs_len: service discovery request tlvs length
+ */
+void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+				      const u8 *sa, u16 update_indic,
+				      const u8 *tlvs, size_t tlvs_len)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				"ServiceDiscoveryResponse");
+	if (msg == NULL)
+		return;
+
+	/* Check if this is a known peer */
+	if (p2p_get_peer_info(wpa_s->global->p2p, sa, 0, NULL, 0) < 0)
+		goto error;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+		    COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
+
+	path = peer_obj_path;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto error;
+
+	if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+					      path) ||
+	    !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
+					 update_indic) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
+					     (const char *) tlvs,
+					     tlvs_len) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto error;
+
+
+	dbus_connection_send(iface->con, msg, NULL);
+	dbus_message_unref(msg);
+	return;
+error:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+/**
+ * wpas_dbus_signal_persistent_group - Send a persistent group related
+ *	event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: new persistent group id
+ * @sig_name: signal name - PersistentGroupAdded, PersistentGroupRemoved
+ * @properties: determines if add second argument with object properties
+ *
+ * Notify listeners about an event related to persistent groups.
+ */
+static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
+					      int id, const char *sig_name,
+					      int properties)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter, iter_dict;
+	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+		    wpa_s->dbus_new_path, id);
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      sig_name);
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	path = pgrp_obj_path;
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &path))
+		goto err;
+
+	if (properties) {
+		if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
+			goto err;
+
+		wpa_dbus_get_object_properties(
+			iface, pgrp_obj_path,
+			WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP,
+			&iter_dict);
+
+		if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+			goto err;
+	}
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_persistent_group_added - Send a persistent_group
+ *	added signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: new persistent group id
+ *
+ * Notify listeners about addition of a new persistent group.
+ */
+static void wpas_dbus_signal_persistent_group_added(
+	struct wpa_supplicant *wpa_s, int id)
+{
+	wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupAdded",
+					  TRUE);
+}
+
+
+/**
+ * wpas_dbus_signal_persistent_group_removed - Send a persistent_group
+ *	removed signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: persistent group id
+ *
+ * Notify listeners about removal of a persistent group.
+ */
+static void wpas_dbus_signal_persistent_group_removed(
+	struct wpa_supplicant *wpa_s, int id)
+{
+	wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupRemoved",
+					  FALSE);
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_wps_failed - Signals WpsFailed event
+ * @wpa_s: %wpa_supplicant network interface data
+ *
+ * Sends Event dbus signal with name "fail" and dictionary containing
+ * "msg" field with fail message number (int32) as arguments
+ */
+void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				     struct wps_event_fail *fail)
+{
+
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+	char *key = "fail";
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "WpsFailed");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
+	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) ||
+	    !wpa_dbus_dict_append_int16(&dict_iter, "config_error",
+					fail->config_error) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+}
+
+#endif /*CONFIG_P2P*/
+
 
 /**
  * wpas_dbus_signal_prop_changed - Signals change of property
  * @wpa_s: %wpa_supplicant network interface data
  * @property: indicates which property has changed
  *
- * Sends ProertyChanged signals with path, interface and arguments
+ * Sends PropertyChanged signals with path, interface and arguments
  * depending on which property has changed.
  */
 void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
@@ -772,7 +1545,7 @@
  * wpas_dbus_signal_debug_level_changed - Signals change of debug param
  * @global: wpa_global structure
  *
- * Sends ProertyChanged signals informing that debug level has changed.
+ * Sends PropertyChanged signals informing that debug level has changed.
  */
 void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
 {
@@ -786,7 +1559,7 @@
  * wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param
  * @global: wpa_global structure
  *
- * Sends ProertyChanged signals informing that debug timestamp has changed.
+ * Sends PropertyChanged signals informing that debug timestamp has changed.
  */
 void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
 {
@@ -800,7 +1573,7 @@
  * wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param
  * @global: wpa_global structure
  *
- * Sends ProertyChanged signals informing that debug show_keys has changed.
+ * Sends PropertyChanged signals informing that debug show_keys has changed.
  */
 void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global)
 {
@@ -1021,6 +1794,14 @@
 	struct network_handler_args *arg;
 	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
 
+	/*
+	 * If it is a persistent group register it as such.
+	 * This is to handle cases where an interface is being initialized
+	 * with a list of networks read from config.
+	 */
+	if (network_is_persistent_group(ssid))
+		return wpas_dbus_register_persistent_group(wpa_s, ssid);
+
 	/* Do nothing if the control interface is not turned on */
 	if (wpa_s == NULL || wpa_s->global == NULL)
 		return 0;
@@ -1083,6 +1864,13 @@
 	struct wpas_dbus_priv *ctrl_iface;
 	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
 	int ret;
+	struct wpa_ssid *ssid;
+
+	ssid = wpa_config_get_network(wpa_s->conf, nid);
+
+	/* If it is a persistent group unregister it as such */
+	if (ssid && network_is_persistent_group(ssid))
+		return wpas_dbus_unregister_persistent_group(wpa_s, nid);
 
 	/* Do nothing if the control interface is not turned on */
 	if (wpa_s == NULL || wpa_s->global == NULL ||
@@ -1358,6 +2146,174 @@
 	  }
 	},
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	{ "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_find,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_stop_find,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_listen,
+	  {
+		  { "timeout", "i", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_extendedlisten,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_presence_request,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_prov_disc_req,
+	  {
+		  { "peer", "o", ARG_IN },
+		  { "config_method", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  { "generated_pin", "i", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_group_add,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_invite,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_disconnect,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_rejectpeer,
+	  {
+		  { "peer", "o", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_add_service,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_delete_service,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush_service,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_req,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_res,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_cancel_req,
+	  {
+		  { "args", "t", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_update,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+	  {
+		  { "arg", "i", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+	  {
+		  { "arg", "i", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "AddPersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_add_persistent_group,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  { "path", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "RemovePersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_remove_persistent_group,
+	  {
+		  { "path", "o", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "RemoveAllPersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)
+	  wpas_dbus_handler_remove_all_persistent_groups,
+	  {
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_P2P */
 	{ "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE,
 	  (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss,
 	  {
@@ -1444,6 +2400,33 @@
 	  RW
 	},
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	{ "P2PDeviceProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
+	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_device_properties,
+	  (WPADBusPropertyAccessor) wpas_dbus_setter_p2p_device_properties,
+	  RW
+	},
+	{ "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
+	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peers,
+	  NULL, R
+	},
+	{ "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s",
+	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_role,
+	  NULL, R
+	},
+	{ "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
+	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_group,
+	  NULL, R
+	},
+	{ "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
+	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peergo,
+	  NULL, R
+	},
+	{ "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
+	  (WPADBusPropertyAccessor) wpas_dbus_getter_persistent_groups,
+	  NULL, R
+	},
+#endif /* CONFIG_P2P */
 	{ NULL, NULL, NULL, NULL, NULL, 0 }
 };
 
@@ -1525,6 +2508,135 @@
 	  }
 	},
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	{ "P2PStateChanged", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "states", "a{ss}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryRequestDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  { "pin", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryResponseDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  { "pin", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryRequestEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryResponseEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryPBCRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryPBCResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  { "status", "i", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "GroupStarted", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "GONegotiationSuccess", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "GONegotiationFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "status", "i", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "GONegotiationRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  { "dev_passwd_id", "i", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "InvitationResult", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "invite_result", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "GroupFinished", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "ifname", "s", ARG_OUT },
+		  { "role", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "sd_request", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "sd_response", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "PersistentGroupAdded", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "WpsFailed", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "name", "s", ARG_OUT },
+		  { "args", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_P2P */
 	{ NULL, NULL, { END_ARGS } }
 };
 
@@ -1603,3 +2715,577 @@
 
 	return 0;
 }
+
+#ifdef CONFIG_P2P
+
+static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
+	{ "Properties", WPAS_DBUS_NEW_IFACE_P2P_PEER, "a{sv}",
+	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peer_properties,
+	  NULL, R
+	},
+	{ "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peer_ies,
+	  NULL, R
+	},
+	{ NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
+
+	{ NULL, NULL, { END_ARGS } }
+};
+
+/**
+ * wpas_dbus_signal_peer - Send a peer related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ * @interface: name of the interface emitting this signal.
+ *	In case of peer objects, it would be emitted by either
+ *	the "interface object" or by "peer objects"
+ * @sig_name: signal name - DeviceFound
+ *
+ * Notify listeners about event related with newly found p2p peer device
+ */
+static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr, const char *interface,
+				  const char *sig_name)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path, interface,
+				      sig_name);
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	path = peer_obj_path;
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &path))
+		goto err;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_peer_found - Send a peer found signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ *
+ * Notify listeners about find a p2p peer device found
+ */
+void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+					const u8 *dev_addr)
+{
+	wpas_dbus_signal_peer(wpa_s, dev_addr,
+			      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+			      "DeviceFound");
+}
+
+/**
+ * wpas_dbus_signal_peer_lost - Send a peer lost signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ *
+ * Notify listeners about lost a p2p peer device
+ */
+void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+				       const u8 *dev_addr)
+{
+	wpas_dbus_signal_peer(wpa_s, dev_addr,
+			      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+			      "DeviceLost");
+}
+
+/**
+ * wpas_dbus_register_peer - Register a discovered peer object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: network configuration data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers network representing object with dbus
+ */
+int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	struct wpa_dbus_object_desc *obj_desc;
+	struct peer_handler_args *arg;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return 0;
+
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+	wpa_printf(MSG_INFO, "dbus: Register peer object '%s'",
+		   peer_obj_path);
+	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create object description");
+		goto err;
+	}
+
+	/* allocate memory for handlers arguments */
+	arg = os_zalloc(sizeof(struct peer_handler_args));
+	if (!arg) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create arguments for method");
+		goto err;
+	}
+
+	arg->wpa_s = wpa_s;
+	os_memcpy(arg->p2p_device_addr, dev_addr, ETH_ALEN);
+
+	wpas_dbus_register(obj_desc, arg, wpa_dbus_free,
+			   NULL,
+			   wpas_dbus_p2p_peer_properties,
+			   wpas_dbus_p2p_peer_signals);
+
+	if (wpa_dbus_register_object_per_iface(ctrl_iface, peer_obj_path,
+					       wpa_s->ifname, obj_desc))
+		goto err;
+
+	return 0;
+
+err:
+	free_dbus_object_desc(obj_desc);
+	return -1;
+}
+
+/**
+ * wpas_dbus_unregister_peer - Unregister a peer object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @dev_addr: p2p device addr
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers network representing object with dbus
+ */
+int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+	int ret;
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL ||
+	    wpa_s->dbus_new_path == NULL)
+		return 0;
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+	wpa_printf(MSG_INFO, "dbus: Unregister peer object '%s'",
+		   peer_obj_path);
+	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, peer_obj_path);
+
+	return ret;
+}
+
+
+static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
+	{ "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao",
+	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_group_members,
+	  NULL, R
+	},
+	{ "Properties",
+	  WPAS_DBUS_NEW_IFACE_P2P_GROUP, "a{sv}",
+	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_group_properties,
+	  (WPADBusPropertyAccessor) wpas_dbus_setter_p2p_group_properties,
+	  RW
+	},
+	{ NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = {
+	{ "PeerJoined", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+	  {
+		  { "peer", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "PeerDisconnected", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+	  {
+		  { "peer", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ NULL, NULL, { END_ARGS } }
+};
+
+/**
+ * wpas_dbus_register_p2p_group - Register a p2p group object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: SSID struct
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers p2p group representing object with dbus
+ */
+void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	struct wpa_dbus_object_desc *obj_desc;
+	char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return;
+
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return;
+
+	if (wpa_s->dbus_groupobj_path) {
+		wpa_printf(MSG_INFO, "%s: Group object '%s' already exists",
+			   __func__, wpa_s->dbus_groupobj_path);
+		return;
+	}
+
+	if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
+		return;
+
+	wpa_s->dbus_groupobj_path = os_strdup(group_obj_path);
+	if (wpa_s->dbus_groupobj_path == NULL)
+		return;
+
+	wpa_printf(MSG_INFO, "dbus: Register group object '%s'",
+		   group_obj_path);
+	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create object description");
+		goto err;
+	}
+
+	wpas_dbus_register(obj_desc, wpa_s, NULL, NULL,
+			   wpas_dbus_p2p_group_properties,
+			   wpas_dbus_p2p_group_signals);
+
+	if (wpa_dbus_register_object_per_iface(ctrl_iface, group_obj_path,
+					       wpa_s->ifname, obj_desc))
+		goto err;
+
+	return;
+
+err:
+	if (wpa_s->dbus_groupobj_path) {
+		os_free(wpa_s->dbus_groupobj_path);
+		wpa_s->dbus_groupobj_path = NULL;
+	}
+
+	free_dbus_object_desc(obj_desc);
+}
+
+/**
+ * wpas_dbus_unregister_p2p_group - Unregister a p2p group object from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: network name of the p2p group started
+ */
+void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+				    const struct wpa_ssid *ssid)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return;
+
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return;
+
+	if (!wpa_s->dbus_groupobj_path) {
+		wpa_printf(MSG_DEBUG,
+			   "%s: Group object '%s' already unregistered",
+			   __func__, wpa_s->dbus_groupobj_path);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "dbus: Unregister group object '%s'",
+		   wpa_s->dbus_groupobj_path);
+
+	wpa_dbus_unregister_object_per_iface(ctrl_iface,
+					     wpa_s->dbus_groupobj_path);
+
+	os_free(wpa_s->dbus_groupobj_path);
+	wpa_s->dbus_groupobj_path = NULL;
+}
+
+static const struct wpa_dbus_property_desc
+wpas_dbus_p2p_groupmember_properties[] = {
+	{ "Properties", WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER, "a{sv}",
+	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_group_properties,
+	  NULL, R
+	},
+	{ NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
+/**
+ * wpas_dbus_register_p2p_groupmember - Register a p2p groupmember
+ * object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @p2p_if_addr: i/f addr of the device joining this group
+ *
+ * Registers p2p groupmember representing object with dbus
+ */
+void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+					const u8 *p2p_if_addr)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	struct wpa_dbus_object_desc *obj_desc = NULL;
+	struct groupmember_handler_args *arg;
+	char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return;
+
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return;
+
+	if (!wpa_s->dbus_groupobj_path)
+		return;
+
+	os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		"%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
+		wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
+
+	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create object description");
+		goto err;
+	}
+
+	/* allocate memory for handlers arguments */
+	arg = os_zalloc(sizeof(struct groupmember_handler_args));
+	if (!arg) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create arguments for method");
+		goto err;
+	}
+
+	arg->wpa_s = wpa_s;
+	os_memcpy(arg->member_addr, p2p_if_addr, ETH_ALEN);
+
+	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+			   wpas_dbus_p2p_groupmember_properties, NULL);
+
+	if (wpa_dbus_register_object_per_iface(ctrl_iface, groupmember_obj_path,
+					       wpa_s->ifname, obj_desc))
+		goto err;
+
+	wpa_printf(MSG_INFO,
+		   "dbus: Registered group member object '%s' successfully",
+		   groupmember_obj_path);
+	return;
+
+err:
+	free_dbus_object_desc(obj_desc);
+}
+
+/**
+ * wpas_dbus_unregister_p2p_groupmember - Unregister a p2p groupmember
+ * object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @p2p_if_addr: i/f addr of the device joining this group
+ *
+ * Unregisters p2p groupmember representing object with dbus
+ */
+void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+					  const u8 *p2p_if_addr)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return;
+
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return;
+
+	if (!wpa_s->dbus_groupobj_path)
+		return;
+
+	os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		"%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
+		wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
+
+	wpa_dbus_unregister_object_per_iface(ctrl_iface, groupmember_obj_path);
+}
+
+
+static const struct wpa_dbus_property_desc
+	wpas_dbus_persistent_group_properties[] = {
+	{ "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
+	  (WPADBusPropertyAccessor)
+	  wpas_dbus_getter_persistent_group_properties,
+	  (WPADBusPropertyAccessor)
+	  wpas_dbus_setter_persistent_group_properties,
+	  RW
+	},
+	{ NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
+/* No signals intended for persistent group objects */
+
+/**
+ * wpas_dbus_register_persistent_group - Register a configured(saved)
+ *	persistent group with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: persistent group (still represented as a network within wpa)
+ *	  configuration data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers a persistent group representing object with dbus.
+ */
+int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	struct wpa_dbus_object_desc *obj_desc;
+	struct network_handler_args *arg;
+	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return 0;
+
+	/* Make sure ssid is a persistent group */
+	if (ssid->disabled != 2 && !ssid->p2p_persistent_group)
+		return -1; /* should we return w/o complaining? */
+
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	/*
+	 * Intentionally not coming up with different numbering scheme
+	 * for persistent groups.
+	 */
+	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+		    wpa_s->dbus_new_path, ssid->id);
+
+	wpa_printf(MSG_DEBUG, "dbus: Register persistent group object '%s'",
+		   pgrp_obj_path);
+	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
+			   "object description");
+		goto err;
+	}
+
+	/*
+	 * Reusing the same context structure as that for networks
+	 * since these are represented using same data structure.
+	 */
+	/* allocate memory for handlers arguments */
+	arg = os_zalloc(sizeof(struct network_handler_args));
+	if (!arg) {
+		wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
+			   "arguments for method");
+		goto err;
+	}
+
+	arg->wpa_s = wpa_s;
+	arg->ssid = ssid;
+
+	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+			   wpas_dbus_persistent_group_properties,
+			   NULL);
+
+	if (wpa_dbus_register_object_per_iface(ctrl_iface, pgrp_obj_path,
+					       wpa_s->ifname, obj_desc))
+		goto err;
+
+	wpas_dbus_signal_persistent_group_added(wpa_s, ssid->id);
+
+	return 0;
+
+err:
+	free_dbus_object_desc(obj_desc);
+	return -1;
+}
+
+
+/**
+ * wpas_dbus_unregister_persistent_group - Unregister a persistent_group
+ *	from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @nid: network id
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters persistent group representing object from dbus
+ *
+ * NOTE: There is a slight issue with the semantics here. While the
+ * implementation simply means the persistent group is unloaded from memory,
+ * it should not get interpreted as the group is actually being erased/removed
+ * from persistent storage as well.
+ */
+int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
+					  int nid)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+	int ret;
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL ||
+	    wpa_s->dbus_new_path == NULL)
+		return 0;
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+		    wpa_s->dbus_new_path, nid);
+
+	wpa_printf(MSG_DEBUG, "dbus: Unregister persistent group object '%s'",
+		   pgrp_obj_path);
+	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, pgrp_obj_path);
+
+	if (!ret)
+		wpas_dbus_signal_persistent_group_removed(wpa_s, nid);
+
+	return ret;
+}
+
+#endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 377e381..3b0d50c 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -16,6 +16,8 @@
 #ifndef CTRL_IFACE_DBUS_NEW_H
 #define CTRL_IFACE_DBUS_NEW_H
 
+#include "p2p/p2p.h"
+
 struct wpa_global;
 struct wpa_supplicant;
 struct wpa_ssid;
@@ -61,6 +63,29 @@
 #define WPAS_DBUS_NEW_BSSIDS_PART "BSSs"
 #define WPAS_DBUS_NEW_IFACE_BSS	WPAS_DBUS_NEW_INTERFACE ".BSS"
 
+#define WPAS_DBUS_NEW_IFACE_P2PDEVICE	\
+		WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice"
+
+/*
+ * Groups correspond to P2P groups where this device is a GO (owner)
+ */
+#define WPAS_DBUS_NEW_P2P_GROUPS_PART	"Groups"
+#define	WPAS_DBUS_NEW_IFACE_P2P_GROUP WPAS_DBUS_NEW_INTERFACE ".Group"
+
+/*
+ * Different dbus object for persistent groups so they do not get confused
+ * with regular (configured) network objects.
+ */
+#define WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "PersistentGroups"
+#define WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP \
+	WPAS_DBUS_NEW_INTERFACE ".PersistentGroup"
+
+#define WPAS_DBUS_NEW_P2P_PEERS_PART	"Peers"
+#define	WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer"
+
+#define WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART	"Members"
+#define	WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER \
+	WPAS_DBUS_NEW_INTERFACE ".GroupMember"
 
 /* Errors */
 #define WPAS_DBUS_ERROR_UNKNOWN_ERROR \
@@ -78,6 +103,13 @@
 #define WPAS_DBUS_ERROR_NETWORK_UNKNOWN \
 	WPAS_DBUS_NEW_INTERFACE ".NetworkUnknown"
 
+#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE \
+	WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnavailable"
+#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED \
+	WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnsupported"
+#define WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR \
+	WPAS_DBUS_NEW_INTERFACE ".ConnectUnspecifiedError"
+
 #define WPAS_DBUS_ERROR_BLOB_EXISTS \
 	WPAS_DBUS_NEW_INTERFACE ".BlobExists"
 #define WPAS_DBUS_ERROR_BLOB_UNKNOWN \
@@ -122,6 +154,54 @@
 void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global);
 void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global);
 
+int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr);
+void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+					   const u8 *dev_addr);
+int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr);
+void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+					   const u8 *dev_addr);
+void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+					const char *role);
+void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					      const u8 *dev_addr, int request,
+					      enum p2p_prov_disc_status status,
+					      u16 config_methods,
+					      unsigned int generated_pin);
+void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+				     const u8 *src, u16 dev_passwd_id);
+void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+					const struct wpa_ssid *ssid,
+					int client, int network_id);
+void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid);
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, int status);
+void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+				    const struct wpa_ssid *ssid);
+int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid);
+int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
+					  int nid);
+void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+					    int status, const u8 *bssid);
+void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+					const u8 *p2p_if_addr);
+void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+					  const u8 *p2p_if_addr);
+void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+					    const u8 *member);
+void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
+				     int freq, const u8 *sa, u8 dialog_token,
+				     u16 update_indic, const u8 *tlvs,
+				     size_t tlvs_len);
+void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+				      const u8 *sa, u16 update_indic,
+				      const u8 *tlvs, size_t tlvs_len);
+void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+				const u8 *member);
+void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				     struct wps_event_fail *fail);
+
 #else /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
 static inline int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
@@ -231,6 +311,138 @@
 {
 }
 
+static inline int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s,
+					  const u8 *dev_addr)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+					    const u8 *dev_addr)
+{
+	return 0;
+}
+
+static inline void
+wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+				   const char *role)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					 const u8 *dev_addr, int request,
+					 enum p2p_prov_disc_status status,
+					 u16 config_methods,
+					 unsigned int generated_pin)
+{
+}
+
+static inline void wpas_dbus_signal_p2p_go_neg_req(
+				struct wpa_supplicant *wpa_s,
+				const u8 *src,
+				u16 dev_passwd_id)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+				   const struct wpa_ssid *ssid,
+				   int client, int network_id)
+{
+}
+
+static inline void
+wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+			     struct wpa_ssid *ssid)
+{
+}
+
+static inline int wpas_dbus_register_persistent_group(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_unregister_persistent_group(
+	struct wpa_supplicant *wpa_s, int nid)
+{
+	return 0;
+}
+
+static inline void
+wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, int status)
+{
+}
+
+static inline void
+wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+			       const struct wpa_ssid *ssid)
+{
+}
+
+static inline void wpas_dbus_signal_p2p_invitation_result(
+				struct wpa_supplicant *wpa_s, int status,
+				const u8 *bssid)
+{
+}
+
+static inline void
+wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+				   const u8 *p2p_if_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s, int freq,
+				const u8 *sa, u8 dialog_token, u16 update_indic,
+				const u8 *tlvs, size_t tlvs_len)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+				 const u8 *sa, u16 update_indic,
+				 const u8 *tlvs, size_t tlvs_len)
+{
+}
+
+static inline void
+wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+				     const u8 *p2p_if_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+				 const u8 *member)
+{
+}
+
+static inline void
+wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+				   const u8 *dev_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+				       const u8 *member)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail)
+{
+}
+
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
 #endif /* CTRL_IFACE_DBUS_H_NEW */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 68e5465..7c4218b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -43,70 +43,6 @@
 
 
 /**
- * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
- * @path: The dbus object path
- * @network: (out) the configured network this object path refers to, if any
- * @bssid: (out) the scanned bssid this object path refers to, if any
- * Returns: The object path of the network interface this path refers to
- *
- * For a given object path, decomposes the object path into object id, network,
- * and BSSID parts, if those parts exist.
- */
-static char * wpas_dbus_new_decompose_object_path(const char *path,
-						  char **network,
-						  char **bssid)
-{
-	const unsigned int dev_path_prefix_len =
-		strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
-	char *obj_path_only;
-	char *next_sep;
-
-	/* Be a bit paranoid about path */
-	if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
-				dev_path_prefix_len))
-		return NULL;
-
-	/* Ensure there's something at the end of the path */
-	if ((path + dev_path_prefix_len)[0] == '\0')
-		return NULL;
-
-	obj_path_only = os_strdup(path);
-	if (obj_path_only == NULL)
-		return NULL;
-
-	next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
-	if (next_sep != NULL) {
-		const char *net_part = os_strstr(
-			next_sep, WPAS_DBUS_NEW_NETWORKS_PART "/");
-		const char *bssid_part = os_strstr(
-			next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
-
-		if (network && net_part) {
-			/* Deal with a request for a configured network */
-			const char *net_name = net_part +
-				os_strlen(WPAS_DBUS_NEW_NETWORKS_PART "/");
-			*network = NULL;
-			if (os_strlen(net_name))
-				*network = os_strdup(net_name);
-		} else if (bssid && bssid_part) {
-			/* Deal with a request for a scanned BSSID */
-			const char *bssid_name = bssid_part +
-				os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
-			if (strlen(bssid_name))
-				*bssid = os_strdup(bssid_name);
-			else
-				*bssid = NULL;
-		}
-
-		/* Cut off interface object path before "/" */
-		*next_sep = '\0';
-	}
-
-	return obj_path_only;
-}
-
-
-/**
  * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
  * @message: Pointer to incoming dbus message this error refers to
  * @arg: Optional string appended to error message
@@ -236,10 +172,10 @@
  *
  * Sets network configuration with parameters given id DBus dictionary
  */
-static DBusMessage * set_network_properties(DBusMessage *message,
-					    struct wpa_supplicant *wpa_s,
-					    struct wpa_ssid *ssid,
-					    DBusMessageIter *iter)
+DBusMessage * set_network_properties(DBusMessage *message,
+				     struct wpa_supplicant *wpa_s,
+				     struct wpa_ssid *ssid,
+				     DBusMessageIter *iter)
 {
 
 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
@@ -1429,7 +1365,7 @@
 
 	/* Extract the network ID and ensure the network */
 	/* is actually a child of this interface */
-	iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL);
+	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
 	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
 		goto out;
@@ -1528,7 +1464,7 @@
 
 	/* Extract the network ID and ensure the network */
 	/* is actually a child of this interface */
-	iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL);
+	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
 	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
 		goto out;
@@ -1763,8 +1699,6 @@
 	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array,
 		variant_iter;
 	const char *scans[] = { "active", "passive", "ssid" };
-	const char *modes[] = { "infrastructure", "ad-hoc", "ap" };
-	int n = sizeof(modes) / sizeof(char *);
 
 	if (message == NULL)
 		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
@@ -2035,11 +1969,41 @@
 		goto nomem;
 
 	/***** Modes */
-	if (res < 0 || !(capa.flags & WPA_DRIVER_FLAGS_AP))
-		n--; /* exclude ap mode if it is not supported by the driver */
-	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Modes", modes, n))
+	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
+					      &iter_dict_entry,
+					      &iter_dict_val,
+					      &iter_array))
 		goto nomem;
 
+	if (!wpa_dbus_dict_string_array_add_element(
+			    &iter_array, "infrastructure"))
+		goto nomem;
+
+	if (!wpa_dbus_dict_string_array_add_element(
+			    &iter_array, "ad-hoc"))
+		goto nomem;
+
+	if (res >= 0) {
+		if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "ap"))
+				goto nomem;
+		}
+
+		if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "p2p"))
+				goto nomem;
+		}
+	}
+
+	if (!wpa_dbus_dict_end_string_array(&iter_dict,
+					    &iter_dict_entry,
+					    &iter_dict_val,
+					    &iter_array))
+		goto nomem;
+	/***** Modes end */
+
 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
 		goto nomem;
 	if (!dbus_message_iter_close_container(&iter, &variant_iter))
@@ -2544,7 +2508,8 @@
 	}
 
 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
-		num++;
+		if (!network_is_persistent_group(ssid))
+			num++;
 
 	paths = os_zalloc(num * sizeof(char *));
 	if (!paths) {
@@ -2554,6 +2519,8 @@
 
 	/* Loop through configured networks and append object path of each */
 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (network_is_persistent_group(ssid))
+			continue;
 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
 		if (paths[i] == NULL) {
 			reply = dbus_message_new_error(message,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 742d33c..978ee4c 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -77,6 +77,11 @@
 DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
 					   struct wpa_supplicant *wpa_s);
 
+DBusMessage * set_network_properties(DBusMessage *message,
+				     struct wpa_supplicant *wpa_s,
+				     struct wpa_ssid *ssid,
+				     DBusMessageIter *iter);
+
 DBusMessage * wpas_dbus_handler_add_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
new file mode 100644
index 0000000..3fec308
--- /dev/null
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -0,0 +1,2113 @@
+/*
+ * WPA Supplicant / dbus-based control interface (P2P)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/includes.h"
+#include "common.h"
+#include "../config.h"
+#include "../wpa_supplicant_i.h"
+#include "../wps_supplicant.h"
+#include "../notify.h"
+#include "dbus_new_helpers.h"
+#include "dbus_new.h"
+#include "dbus_new_handlers.h"
+#include "dbus_new_handlers_p2p.h"
+#include "dbus_dict_helpers.h"
+#include "p2p/p2p.h"
+#include "common/ieee802_11_defs.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/wps_hostapd.h"
+
+#include "../p2p_supplicant.h"
+
+/**
+ * Parses out the mac address from the peer object path.
+ * @peer_path - object path of the form
+ *	/fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons)
+ * @addr - out param must be of ETH_ALEN size
+ * Returns 0 if valid (including MAC), -1 otherwise
+ */
+static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
+{
+	char *p;
+
+	if (!peer_path)
+		return -1;
+	p = strrchr(peer_path, '/');
+	if (!p)
+		return -1;
+	p++;
+	return hwaddr_compact_aton(p, addr);
+}
+
+
+/**
+ * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown
+ * error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an invalid persistent group error.
+ */
+static DBusMessage * wpas_dbus_error_persistent_group_unknown(
+	DBusMessage *message)
+{
+	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+				      "There is no such persistent group in "
+				      "this P2P device.");
+}
+
+
+DBusMessage *wpas_dbus_handler_p2p_find(DBusMessage * message,
+					struct wpa_supplicant * wpa_s)
+{
+	struct wpa_dbus_dict_entry entry;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	DBusMessageIter iter_dict;
+	unsigned int timeout = 0;
+	unsigned int searchonly = 0;
+	enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
+	int num_req_dev_types = 0;
+	unsigned int i;
+	u8 *req_dev_types = NULL;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		if (!os_strcmp(entry.key, "Timeout") &&
+		    (entry.type == DBUS_TYPE_INT32)) {
+			timeout = entry.uint32_value;
+		} else if (!os_strcmp(entry.key, "SearchOnly") &&
+			   (entry.type == DBUS_TYPE_BOOLEAN)) {
+			searchonly = (entry.bool_value == TRUE) ? 1 : 0;
+		} else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
+			if ((entry.type != DBUS_TYPE_ARRAY) ||
+			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
+				goto error_clear;
+
+			req_dev_types =
+				os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
+			if (!req_dev_types)
+				goto error_clear;
+
+			for (i = 0; i < entry.array_len; i++) {
+				if (wpabuf_len(entry.binarray_value[i]) !=
+							WPS_DEV_TYPE_LEN)
+					goto error_clear;
+				os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
+					  wpabuf_head(entry.binarray_value[i]),
+					  WPS_DEV_TYPE_LEN);
+			}
+
+			num_req_dev_types = entry.array_len;
+		} else
+			goto error_clear;
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types);
+	return reply;
+
+error_clear:
+	os_free(req_dev_types);
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	reply = wpas_dbus_error_invalid_args(message, entry.key);
+	return reply;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_stop_find(DBusMessage * message,
+					     struct wpa_supplicant * wpa_s)
+{
+	wpas_p2p_stop_find(wpa_s);
+	return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_rejectpeer(DBusMessage * message,
+					      struct wpa_supplicant * wpa_s)
+{
+	DBusMessageIter iter;
+	char *peer_object_path = NULL;
+	u8 peer_addr[ETH_ALEN];
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_get_basic(&iter, &peer_object_path);
+
+	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
+		return wpas_dbus_error_invalid_args(message, NULL);
+
+	if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
+		return wpas_dbus_error_unknown_error(message,
+				"Failed to call wpas_p2p_reject method.");
+
+	return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_listen(DBusMessage * message,
+					  struct wpa_supplicant * wpa_s)
+{
+	dbus_int32_t timeout = 0;
+
+	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
+				   DBUS_TYPE_INVALID))
+		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					      NULL);
+
+	if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
+		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					      NULL);
+
+	return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_extendedlisten(DBusMessage * message,
+						  struct wpa_supplicant * wpa_s)
+{
+	unsigned int period = 0, interval = 0;
+	struct wpa_dbus_dict_entry entry;
+	DBusMessageIter iter;
+	DBusMessageIter iter_dict;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		if (!strcmp(entry.key, "period") &&
+		    (entry.type == DBUS_TYPE_INT32))
+			period = entry.uint32_value;
+		else if (!strcmp(entry.key, "interval") &&
+			 (entry.type == DBUS_TYPE_INT32))
+			interval = entry.uint32_value;
+		else
+			goto error_clear;
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	if (wpas_p2p_ext_listen(wpa_s, period, interval))
+		return wpas_dbus_error_unknown_error(message,
+					"failed to initiate a p2p_ext_listen.");
+
+	return NULL;
+
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	return wpas_dbus_error_invalid_args(message, entry.key);
+}
+
+DBusMessage *wpas_dbus_handler_p2p_presence_request(DBusMessage * message,
+						    struct wpa_supplicant *
+						    wpa_s)
+{
+	unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
+	struct wpa_dbus_dict_entry entry;
+	DBusMessageIter iter;
+	DBusMessageIter iter_dict;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		if (!strcmp(entry.key, "duration1") &&
+		    (entry.type == DBUS_TYPE_INT32))
+			dur1 = entry.uint32_value;
+		else if (!strcmp(entry.key, "interval1") &&
+			 entry.type == DBUS_TYPE_INT32)
+			int1 = entry.uint32_value;
+		else if (!strcmp(entry.key, "duration2") &&
+			 entry.type == DBUS_TYPE_INT32)
+			dur2 = entry.uint32_value;
+		else if (!strcmp(entry.key, "interval2") &&
+			 entry.type == DBUS_TYPE_INT32)
+			int2 = entry.uint32_value;
+		else
+			goto error_clear;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+	if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
+		return wpas_dbus_error_unknown_error(message,
+				"Failed to invoke presence request.");
+
+	return NULL;
+
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	return wpas_dbus_error_invalid_args(message, entry.key);
+}
+
+DBusMessage *wpas_dbus_handler_p2p_group_add(DBusMessage * message,
+					     struct wpa_supplicant * wpa_s)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	char *pg_object_path = NULL;
+	int persistent_group = 0;
+	int freq = 0;
+	char *iface = NULL;
+	char *net_id_str = NULL;
+	unsigned int group_id = 0;
+	struct wpa_ssid *ssid;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+		goto inv_args;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto inv_args;
+
+		if (!strcmp(entry.key, "persistent") &&
+		    (entry.type == DBUS_TYPE_BOOLEAN)) {
+			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
+		} else if (!strcmp(entry.key, "frequency") &&
+			   (entry.type == DBUS_TYPE_INT32)) {
+			freq = entry.int32_value;
+			if (freq <= 0)
+				goto inv_args_clear;
+		} else if (!strcmp(entry.key, "persistent_group_object") &&
+			   entry.type == DBUS_TYPE_OBJECT_PATH)
+			pg_object_path = os_strdup(entry.str_value);
+		else
+			goto inv_args_clear;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	if (pg_object_path != NULL) {
+		/*
+		 * A persistent group Object Path is defined meaning we want
+		 * to re-invoke a persistent group.
+		 */
+
+		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
+							    &net_id_str, NULL);
+		if (iface == NULL ||
+		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+			reply =
+			    wpas_dbus_error_invalid_args(message,
+							 pg_object_path);
+			goto out;
+		}
+
+		group_id = strtoul(net_id_str, NULL, 10);
+		if (errno == EINVAL) {
+			reply = wpas_dbus_error_invalid_args(
+						message, pg_object_path);
+			goto out;
+		}
+
+		/* Get the SSID structure form the persistant group id */
+		ssid = wpa_config_get_network(wpa_s->conf, group_id);
+		if (ssid == NULL || ssid->disabled != 2)
+			goto inv_args;
+
+		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
+			reply = wpas_dbus_error_unknown_error(message,
+							      "Failed to reinvoke a persistent group");
+			goto out;
+		}
+	} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
+		goto inv_args;
+
+out:
+	os_free(pg_object_path);
+	os_free(net_id_str);
+	os_free(iface);
+	return reply;
+inv_args_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+inv_args:
+	reply = wpas_dbus_error_invalid_args(message, NULL);
+	goto out;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s)
+{
+	if (wpas_p2p_disconnect(wpa_s))
+		return wpas_dbus_error_unknown_error(message,
+						"failed to disconnect");
+
+	return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_flush(DBusMessage * message,
+					 struct wpa_supplicant * wpa_s)
+{
+	os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+	wpa_s->force_long_sd = 0;
+	p2p_flush(wpa_s->global->p2p);
+
+	return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_connect(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;
+	int persistent_group = 0;
+	int join = 0;
+	int authorize_only = 0;
+	int go_intent = -1;
+	int freq = 0;
+	u8 addr[ETH_ALEN];
+	char *pin = NULL;
+	enum p2p_wps_method wps_method = WPS_NOT_READY;
+	int new_pin;
+	char *err_msg = NULL;
+	char *iface = NULL;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+		goto inv_args;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto inv_args;
+
+		if (!strcmp(entry.key, "peer") &&
+		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+			peer_object_path = os_strdup(entry.str_value);
+		} else if (!strcmp(entry.key, "persistent") &&
+			   (entry.type == DBUS_TYPE_BOOLEAN)) {
+			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
+		} else if (!strcmp(entry.key, "join") &&
+			   (entry.type == DBUS_TYPE_BOOLEAN)) {
+			join = (entry.bool_value == TRUE) ? 1 : 0;
+		} else if (!strcmp(entry.key, "authorize_only") &&
+			   (entry.type == DBUS_TYPE_BOOLEAN)) {
+			authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
+		} else if (!strcmp(entry.key, "frequency") &&
+			   (entry.type == DBUS_TYPE_INT32)) {
+			freq = entry.int32_value;
+			if (freq <= 0)
+				goto inv_args_clear;
+		} else if (!strcmp(entry.key, "go_intent") &&
+			   (entry.type == DBUS_TYPE_INT32)) {
+			go_intent = entry.int32_value;
+			if ((go_intent < 0) || (go_intent > 15))
+				goto inv_args_clear;
+		} else if (!strcmp(entry.key, "wps_method") &&
+			   (entry.type == DBUS_TYPE_STRING)) {
+			if (!strcmp(entry.str_value, "pbc"))
+				wps_method = WPS_PBC;
+			else if (!strcmp(entry.str_value, "pin"))
+				wps_method = WPS_PIN_DISPLAY;
+			else if (!strcmp(entry.str_value, "label"))
+				wps_method = WPS_PIN_LABEL;
+			else if (!strcmp(entry.str_value, "display"))
+				wps_method = WPS_PIN_DISPLAY;
+			else if (!strcmp(entry.str_value, "keypad"))
+				wps_method = WPS_PIN_KEYPAD;
+			else
+				goto inv_args_clear;
+		} else if (!strcmp(entry.key, "pin") &&
+			   (entry.type == DBUS_TYPE_STRING)) {
+			pin = os_strdup(entry.str_value);
+		} else
+			goto inv_args_clear;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
+	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
+	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0)) {
+		reply = wpas_dbus_error_invalid_args(message, NULL);
+		goto inv_args;
+	}
+
+	/*
+	 * Validate the wps_method specified and the pin value.
+	 */
+	if ((!pin || !pin[0]) &&
+	    ((wps_method == WPS_PIN_LABEL) || (wps_method == WPS_PIN_KEYPAD)))
+		goto inv_args;
+
+	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
+				   persistent_group, join, authorize_only,
+				   go_intent, freq);
+
+	if (new_pin >= 0) {
+		reply = dbus_message_new_method_return(message);
+		dbus_message_append_args(reply, DBUS_TYPE_INT32,
+					 &new_pin, DBUS_TYPE_INVALID);
+	} else {
+		switch (new_pin) {
+		case -2:
+			err_msg = "connect failed due to"
+					" channel unavailability.";
+			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
+			break;
+
+		case -3:
+			err_msg = "connect failed due to"
+					" unsupported channel.";
+			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
+			break;
+
+		default:
+			err_msg = "connect failed due to"
+					" unspecified error.";
+			iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
+			break;
+		}
+		/*
+		 * TODO::
+		 * Do we need specialized errors corresponding to above
+		 * error conditions as against just returning a different
+		 * error message?
+		 */
+		reply = dbus_message_new_error(message, iface, err_msg);
+	}
+
+out:
+	os_free(peer_object_path);
+	os_free(pin);
+	return reply;
+inv_args_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+inv_args:
+	reply = wpas_dbus_error_invalid_args(message, NULL);
+	goto out;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_invite(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 *pg_object_path = NULL;
+	char *iface = NULL;
+	char *net_id_str = NULL;
+	u8 peer_addr[ETH_ALEN];
+	unsigned int group_id = 0;
+	int persistent = 0;
+	struct wpa_ssid *ssid;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+		goto err;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto err;
+
+		if (!strcmp(entry.key, "peer") &&
+		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+			peer_object_path = os_strdup(entry.str_value);
+			wpa_dbus_dict_entry_clear(&entry);
+		} else if (!strcmp(entry.key, "persistent_group_object") &&
+			   (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+			pg_object_path = os_strdup(entry.str_value);
+			persistent = 1;
+			wpa_dbus_dict_entry_clear(&entry);
+		} else {
+			wpa_dbus_dict_entry_clear(&entry);
+			goto err;
+		}
+	}
+
+	if (!peer_object_path ||
+	    (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
+	    (p2p_get_peer_info(wpa_s->global->p2p,
+			       peer_addr, 0, NULL, 0) < 0)) {
+		goto err;
+	}
+
+	if (persistent) {
+		/*
+		 * A group ID is defined meaning we want to re-invoke a
+		 * persisatnt group
+		 */
+
+		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
+							    &net_id_str, NULL);
+		if (iface == NULL ||
+		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+			reply =
+			    wpas_dbus_error_invalid_args(message,
+							 pg_object_path);
+			goto out;
+		}
+
+		group_id = strtoul(net_id_str, NULL, 10);
+		if (errno == EINVAL) {
+			reply = wpas_dbus_error_invalid_args(
+						message, pg_object_path);
+			goto out;
+		}
+
+		/* Get the SSID structure form the persistant group id */
+		ssid = wpa_config_get_network(wpa_s->conf, group_id);
+		if (ssid == NULL || ssid->disabled != 2)
+			goto err;
+
+		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
+			reply = wpas_dbus_error_unknown_error(
+					message,
+					"Failed to reinvoke a persistent group");
+			goto out;
+		}
+	} else {
+		/*
+		 * No group ID means propose to a peer to join my active group
+		 */
+		if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
+					 peer_addr, NULL)) {
+			reply = wpas_dbus_error_unknown_error(
+					message,
+					"Failed to join to an active group");
+			goto out;
+		}
+	}
+
+out:
+	os_free(pg_object_path);
+	os_free(peer_object_path);
+	return reply;
+
+err:
+	reply = wpas_dbus_error_invalid_args(message, NULL);
+	goto out;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_prov_disc_req(DBusMessage * message,
+						 struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter;
+	char *peer_object_path = NULL;
+	char *config_method = NULL;
+	u8 peer_addr[ETH_ALEN];
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_get_basic(&iter, &peer_object_path);
+
+	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
+		return wpas_dbus_error_invalid_args(message, NULL);
+
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_get_basic(&iter, &config_method);
+
+	/*
+	 * Validation checks on config_method are being duplicated here
+	 * to be able to return invalid args reply since the error code
+	 * from p2p module are not granular enough (yet).
+	 */
+	if (os_strcmp(config_method, "display") &&
+	    os_strcmp(config_method, "keypad") &&
+	    os_strcmp(config_method, "pbc") &&
+	    os_strcmp(config_method, "pushbutton"))
+		return wpas_dbus_error_invalid_args(message, NULL);
+
+	if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method) < 0)
+		return wpas_dbus_error_unknown_error(message,
+				"Failed to send provision discovery request");
+
+	return NULL;
+}
+
+/*
+ * P2P Device property accessor methods.
+ */
+
+DBusMessage *wpas_dbus_getter_p2p_device_properties(DBusMessage * message,
+						    struct wpa_supplicant *
+						    wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter, variant_iter, dict_iter;
+	const char *dev_name;
+	int num_sec_dev_types = 0;
+	int num_vendor_extensions = 0;
+	int i;
+	const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+
+	if (message == NULL)
+		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
+	else
+		reply = dbus_message_new_method_return(message);
+
+	if (!reply)
+		goto err_no_mem;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+					      "a{sv}", &variant_iter) ||
+	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
+		goto err_no_mem;
+
+	/* DeviceName */
+	dev_name = wpa_s->conf->device_name;
+	if (dev_name &&
+	    !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
+		goto err_no_mem;
+
+	/* Primary device type */
+	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
+	    				     (char *)wpa_s->conf->device_type,
+	    				     WPS_DEV_TYPE_LEN))
+		goto err_no_mem;
+
+	/* Secondary device types */
+	for (i = 0; i < MAX_SEC_DEVICE_TYPES; i++) {
+		if (wpa_s->conf->sec_device_type[i] == NULL)
+			break;
+		num_sec_dev_types++;
+	}
+
+	if (!wpa_dbus_dict_append_string_array(
+			&dict_iter, "SecondaryDeviceTypes",
+			(const char **)wpa_s->conf->sec_device_type,
+			num_sec_dev_types))
+		goto err_no_mem;
+
+	/* Vendor Extensions */
+	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+		if (wpa_s->conf->wps_vendor_ext[i] == NULL)
+			continue;
+		vendor_ext[num_vendor_extensions++] =
+			wpa_s->conf->wps_vendor_ext[i];
+	}
+
+	if (num_vendor_extensions &&
+	    !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
+					       "VendorExtension",
+					       vendor_ext,
+					       num_vendor_extensions))
+		goto err_no_mem;
+
+	/* GO Intent */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
+					 wpa_s->conf->p2p_go_intent))
+		goto err_no_mem;
+
+	/* Persistant Reconnect */
+	if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
+				       wpa_s->conf->persistent_reconnect))
+		goto err_no_mem;
+
+	/* Listen Reg Class */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
+					 wpa_s->conf->p2p_listen_reg_class))
+		goto err_no_mem;
+
+	/* Listen Channel */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
+					 wpa_s->conf->p2p_listen_channel))
+		goto err_no_mem;
+
+	/* Oper Reg Class */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
+					 wpa_s->conf->p2p_oper_reg_class))
+		goto err_no_mem;
+
+	/* Oper Channel */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
+					 wpa_s->conf->p2p_oper_channel))
+		goto err_no_mem;
+
+	/* SSID Postfix */
+	if (wpa_s->conf->p2p_ssid_postfix &&
+	    !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
+					 wpa_s->conf->p2p_ssid_postfix))
+		goto err_no_mem;
+
+	/* Intra Bss */
+	if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
+				       wpa_s->conf->p2p_intra_bss))
+		goto err_no_mem;
+
+	/* Group Idle */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
+					 wpa_s->conf->p2p_group_idle))
+		goto err_no_mem;
+
+	/* Dissasociation low ack */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
+					 wpa_s->conf->disassoc_low_ack))
+		goto err_no_mem;
+
+	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+	    !dbus_message_iter_close_container(&iter, &variant_iter))
+		goto err_no_mem;
+
+	return reply;
+err_no_mem:
+	dbus_message_unref(reply);
+	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+DBusMessage *wpas_dbus_setter_p2p_device_properties(DBusMessage * message,
+						    struct wpa_supplicant *
+						    wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter, variant_iter;
+	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
+	DBusMessageIter iter_dict;
+	unsigned int i;
+
+	dbus_message_iter_init(message, &iter);
+
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_next(&iter);
+
+	dbus_message_iter_recurse(&iter, &variant_iter);
+
+	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
+		return wpas_dbus_error_invalid_args(message, NULL);
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			return wpas_dbus_error_invalid_args(message, NULL);
+
+		if (os_strcmp(entry.key, "DeviceName") == 0) {
+			char *devname;
+
+			if (entry.type != DBUS_TYPE_STRING)
+				goto error_clear;
+
+			devname = os_strdup(entry.str_value);
+			if (devname == NULL)
+				goto err_no_mem_clear;
+
+			os_free(wpa_s->conf->device_name);
+			wpa_s->conf->device_name = devname;
+
+			wpa_s->conf->changed_parameters |=
+							CFG_CHANGED_DEVICE_NAME;
+		} else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != DBUS_TYPE_BYTE ||
+			    entry.array_len != WPS_DEV_TYPE_LEN)
+				goto error_clear;
+
+			os_memcpy(wpa_s->conf->device_type,
+				  entry.bytearray_value,
+				  WPS_DEV_TYPE_LEN);
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_DEVICE_TYPE;
+		} else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
+			    entry.array_len > MAX_SEC_DEVICE_TYPES)
+				goto error;
+
+			for (i = 0; i < entry.array_len; i++)
+				if (wpabuf_len(entry.binarray_value[i]) != WPS_DEV_TYPE_LEN)
+					goto err_no_mem_clear;
+			for (i = 0; i < entry.array_len; i++)
+				os_memcpy(wpa_s->conf->sec_device_type[i],
+					  wpabuf_head(entry.binarray_value[i]),
+					  WPS_DEV_TYPE_LEN);
+			wpa_s->conf->num_sec_device_types = entry.array_len;
+			wpa_s->conf->changed_parameters |=
+					CFG_CHANGED_SEC_DEVICE_TYPE;
+		} else if (os_strcmp(entry.key, "VendorExtension") == 0) {
+			if ((entry.type != DBUS_TYPE_ARRAY) ||
+			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
+			    (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
+				goto error_clear;
+
+			wpa_s->conf->changed_parameters |=
+					CFG_CHANGED_VENDOR_EXTENSION;
+
+			for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+				wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
+				if (i < entry.array_len) {
+					wpa_s->conf->wps_vendor_ext[i] =
+						entry.binarray_value[i];
+					entry.binarray_value[i] = NULL;
+				} else
+					wpa_s->conf->wps_vendor_ext[i] = NULL;
+			}
+		} else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
+			   (entry.type == DBUS_TYPE_UINT32) &&
+			   (entry.uint32_value <= 15))
+			wpa_s->conf->p2p_go_intent = entry.uint32_value;
+
+		else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
+			 (entry.type == DBUS_TYPE_BOOLEAN))
+			wpa_s->conf->persistent_reconnect = entry.bool_value;
+
+		else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
+			 (entry.type == DBUS_TYPE_UINT32)) {
+			wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_P2P_LISTEN_CHANNEL;
+		} else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
+			   (entry.type == DBUS_TYPE_UINT32)) {
+			wpa_s->conf->p2p_listen_channel = entry.uint32_value;
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_P2P_LISTEN_CHANNEL;
+		} else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
+			   (entry.type == DBUS_TYPE_UINT32)) {
+			wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_P2P_OPER_CHANNEL;
+		} else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
+			   (entry.type == DBUS_TYPE_UINT32)) {
+			wpa_s->conf->p2p_oper_channel = entry.uint32_value;
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_P2P_OPER_CHANNEL;
+		} else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
+			char *postfix;
+
+			if (entry.type != DBUS_TYPE_STRING)
+				goto error_clear;
+
+			postfix = os_strdup(entry.str_value);
+			if (!postfix)
+				goto err_no_mem_clear;
+
+			os_free(wpa_s->conf->p2p_ssid_postfix);
+			wpa_s->conf->p2p_ssid_postfix = postfix;
+
+			wpa_s->conf->changed_parameters |=
+					CFG_CHANGED_P2P_SSID_POSTFIX;
+		} else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
+			   (entry.type == DBUS_TYPE_BOOLEAN)) {
+			wpa_s->conf->p2p_intra_bss = entry.bool_value;
+			wpa_s->conf->changed_parameters |=
+						      CFG_CHANGED_P2P_INTRA_BSS;
+		} else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
+			   (entry.type == DBUS_TYPE_UINT32))
+			wpa_s->conf->p2p_group_idle = entry.uint32_value;
+		else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
+			 entry.type == DBUS_TYPE_UINT32)
+			wpa_s->conf->disassoc_low_ack = entry.uint32_value;
+		else
+			goto error_clear;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	if (wpa_s->conf->changed_parameters) {
+		/* Some changed parameters requires to update config*/
+		wpa_supplicant_update_config(wpa_s);
+	}
+
+	return reply;
+
+ error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+ error:
+	reply = wpas_dbus_error_invalid_args(message, entry.key);
+	wpa_dbus_dict_entry_clear(&entry);
+
+	return reply;
+ err_no_mem_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+DBusMessage *wpas_dbus_getter_p2p_peers(DBusMessage * message,
+					struct wpa_supplicant * wpa_s)
+{
+	DBusMessage *reply = NULL;
+	struct p2p_data *p2p = wpa_s->global->p2p;
+	int next = 0, i = 0;
+	int num = 0, out_of_mem = 0;
+	const u8 *addr;
+	const struct p2p_peer_info *peer_info = NULL;
+
+	struct dl_list peer_objpath_list;
+	struct peer_objpath_node {
+		struct dl_list list;
+		char path[WPAS_DBUS_OBJECT_PATH_MAX];
+	} *node, *tmp;
+
+	char **peer_obj_paths = NULL;
+
+	dl_list_init(&peer_objpath_list);
+
+	/* Get the first peer info */
+	peer_info = p2p_get_peer_found(p2p, NULL, next);
+
+	/* Get next and accumulate them */
+	next = 1;
+	while (peer_info != NULL) {
+		node = os_zalloc(sizeof(struct peer_objpath_node));
+		if (!node) {
+			out_of_mem = 1;
+			goto error;
+		}
+
+		addr = peer_info->p2p_device_addr;
+		os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
+			    "/" COMPACT_MACSTR,
+			    wpa_s->dbus_new_path, MAC2STR(addr));
+		dl_list_add_tail(&peer_objpath_list, &node->list);
+		num++;
+
+		peer_info = p2p_get_peer_found(p2p, addr, next);
+	}
+
+	/*
+	 * Now construct the peer object paths in a form suitable for
+	 * array_property_getter helper below.
+	 */
+	peer_obj_paths = os_zalloc(num * sizeof(char *));
+
+	if (!peer_obj_paths) {
+		out_of_mem = 1;
+		goto error;
+	}
+
+	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
+			      struct peer_objpath_node, list)
+		peer_obj_paths[i++] = node->path;
+
+	reply = wpas_dbus_simple_array_property_getter(message,
+						       DBUS_TYPE_OBJECT_PATH,
+						       peer_obj_paths, num);
+
+error:
+	if (peer_obj_paths)
+		os_free(peer_obj_paths);
+
+	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
+			      struct peer_objpath_node, list) {
+		dl_list_del(&node->list);
+		os_free(node);
+	}
+	if (out_of_mem)
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+
+	return reply;
+}
+
+enum wpas_p2p_role {
+	WPAS_P2P_ROLE_DEVICE,
+	WPAS_P2P_ROLE_GO,
+	WPAS_P2P_ROLE_CLIENT,
+};
+
+static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (!ssid)
+		return WPAS_P2P_ROLE_DEVICE;
+	if (wpa_s->wpa_state != WPA_COMPLETED)
+		return WPAS_P2P_ROLE_DEVICE;
+
+	switch (ssid->mode) {
+	case WPAS_MODE_P2P_GO:
+	case WPAS_MODE_P2P_GROUP_FORMATION:
+		return WPAS_P2P_ROLE_GO;
+	case WPAS_MODE_INFRA:
+		if (ssid->p2p_group)
+			return WPAS_P2P_ROLE_CLIENT;
+		return WPAS_P2P_ROLE_DEVICE;
+	default:
+		return WPAS_P2P_ROLE_DEVICE;
+	}
+}
+
+DBusMessage *wpas_dbus_getter_p2p_role(DBusMessage * message,
+				       struct wpa_supplicant * wpa_s)
+{
+	char *str;
+
+	switch (wpas_get_p2p_role(wpa_s)) {
+	case WPAS_P2P_ROLE_GO:
+		str = "GO";
+		break;
+	case WPAS_P2P_ROLE_CLIENT:
+		str = "client";
+		break;
+	default:
+		str = "device";
+	}
+
+	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
+						&str);
+}
+
+DBusMessage *wpas_dbus_getter_p2p_group(DBusMessage * message,
+					struct wpa_supplicant * wpa_s)
+{
+	if (wpa_s->dbus_groupobj_path == NULL)
+		return NULL;
+
+	return wpas_dbus_simple_property_getter(message,
+						DBUS_TYPE_OBJECT_PATH,
+						&wpa_s->dbus_groupobj_path);
+}
+
+DBusMessage *wpas_dbus_getter_p2p_peergo(DBusMessage * message,
+					 struct wpa_supplicant * wpa_s)
+{
+	char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+	if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
+		return NULL;
+
+	os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+		    wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
+	path = go_peer_obj_path;
+	return wpas_dbus_simple_property_getter(message,
+						DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+/*
+ * Peer object properties accessor methods
+ */
+
+DBusMessage *wpas_dbus_getter_p2p_peer_properties(DBusMessage * message,
+						  struct peer_handler_args *
+						  peer_args)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter, variant_iter, dict_iter;
+	const struct p2p_peer_info *info = NULL;
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+
+	/* get the peer info */
+	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+				  peer_args->p2p_device_addr, 0);
+	if (info == NULL)
+		return NULL;
+
+	if (message == NULL)
+		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
+	else
+		reply = dbus_message_new_method_return(message);
+
+	if (!reply)
+		goto err_no_mem;
+
+	dbus_message_iter_init_append(reply, &iter);
+	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+					      "a{sv}", &variant_iter) ||
+	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
+		goto err_no_mem;
+
+	/* Fill out the dictionary */
+	wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype));
+	if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
+					 info->device_name))
+		goto err_no_mem;
+	if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType",
+					 devtype))
+		goto err_no_mem;
+	if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
+					 info->config_methods))
+		goto err_no_mem;
+	if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
+					 info->level))
+		goto err_no_mem;
+	if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
+				       info->dev_capab))
+		goto err_no_mem;
+	if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
+				       info->group_capab))
+		goto err_no_mem;
+
+	if (info->wps_sec_dev_type_list_len) {
+		char *sec_dev_types[MAX_SEC_DEVICE_TYPES];
+		u8 *sec_dev_type_list = NULL;
+		char secdevtype[WPS_DEV_TYPE_BUFSIZE];
+		int num_sec_dev_types = 0;
+		int i;
+
+		sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len);
+
+		if (sec_dev_type_list == NULL)
+			goto err_no_mem;
+
+		os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list,
+			  info->wps_sec_dev_type_list_len);
+
+		for (i = 0; i < MAX_SEC_DEVICE_TYPES &&
+		       i < (int) (info->wps_sec_dev_type_list_len /
+				  WPS_DEV_TYPE_LEN);
+		     i++) {
+			sec_dev_types[i] = os_zalloc(sizeof(secdevtype));
+
+			if (!sec_dev_types[i] ||
+			    wps_dev_type_bin2str(
+					&sec_dev_type_list[i *
+							   WPS_DEV_TYPE_LEN],
+					sec_dev_types[i],
+					sizeof(secdevtype)) == NULL) {
+				while (--i >= 0)
+					os_free(sec_dev_types[i]);
+				os_free(sec_dev_type_list);
+				goto err_no_mem;
+			}
+
+			num_sec_dev_types++;
+		}
+
+		os_free(sec_dev_type_list);
+
+		if (num_sec_dev_types) {
+			if (!wpa_dbus_dict_append_string_array(&dict_iter,
+						"SecondaryDeviceTypes",
+						(const char **)sec_dev_types,
+						num_sec_dev_types)) {
+				for (i = 0; i < num_sec_dev_types; i++)
+					os_free(sec_dev_types[i]);
+				goto err_no_mem;
+			}
+
+			for (i = 0; i < num_sec_dev_types; i++)
+				os_free(sec_dev_types[i]);
+		}
+	}
+
+	{
+		/* Add WPS vendor extensions attribute */
+		const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
+		int i, num = 0;
+
+		for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+			if (info->wps_vendor_ext[i] == NULL)
+				continue;
+			vendor_extension[num] = info->wps_vendor_ext[i];
+			num++;
+		}
+
+		if (!wpa_dbus_dict_append_wpabuf_array(
+					&dict_iter, "VendorExtension",
+					vendor_extension, num))
+			goto err_no_mem;
+	}
+
+	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+	    !dbus_message_iter_close_container(&iter, &variant_iter))
+		goto err_no_mem;
+
+	return reply;
+err_no_mem:
+	dbus_message_unref(reply);
+	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+DBusMessage *wpas_dbus_getter_p2p_peer_ies(DBusMessage * message,
+					   struct peer_handler_args * peer_args)
+{
+	return NULL;
+}
+
+
+/**
+ * wpas_dbus_getter_persistent_groups - Get array of peristent group objects
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: a dbus message containing an array of all persistent group
+ * dbus object paths.
+ *
+ * Getter for "Networks" property.
+ */
+DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
+						 struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	struct wpa_ssid *ssid;
+	char **paths;
+	unsigned int i = 0, num = 0;
+
+	if (wpa_s->conf == NULL) {
+		wpa_printf(MSG_ERROR, "dbus: %s: "
+			   "An error occurred getting persistent groups list",
+			   __func__);
+		return wpas_dbus_error_unknown_error(message, NULL);
+	}
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+		if (network_is_persistent_group(ssid))
+			num++;
+
+	paths = os_zalloc(num * sizeof(char *));
+	if (!paths) {
+		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					      NULL);
+	}
+
+	/* Loop through configured networks and append object path of each */
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (!network_is_persistent_group(ssid))
+			continue;
+		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+		if (paths[i] == NULL) {
+			reply = dbus_message_new_error(message,
+						       DBUS_ERROR_NO_MEMORY,
+						       NULL);
+			goto out;
+		}
+		/* Construct the object path for this network. */
+		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
+			    wpa_s->dbus_new_path, ssid->id);
+	}
+
+	reply = wpas_dbus_simple_array_property_getter(message,
+						       DBUS_TYPE_OBJECT_PATH,
+						       paths, num);
+
+out:
+	while (i)
+		os_free(paths[--i]);
+	os_free(paths);
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
+ *	group
+ * @message: Pointer to incoming dbus message
+ * @net: wpa_supplicant structure for a network interface and
+ * wpa_ssid structure for a configured persistent group (internally network)
+ * Returns: DBus message with network properties or DBus error on failure
+ *
+ * Getter for "Properties" property of a persistent group.
+ */
+DBusMessage * wpas_dbus_getter_persistent_group_properties(
+	DBusMessage *message, struct network_handler_args *net)
+{
+	/*
+	 * Leveraging the fact that persistent group object is still
+	 * represented in same manner as network within.
+	 */
+	return wpas_dbus_getter_network_properties(message, net);
+}
+
+
+/**
+ * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
+ *	group
+ * @message: Pointer to incoming dbus message
+ * @net: wpa_supplicant structure for a network interface and
+ * wpa_ssid structure for a configured persistent group (internally network)
+ * Returns: DBus message with network properties or DBus error on failure
+ *
+ * Setter for "Properties" property of a persistent group.
+ */
+DBusMessage * wpas_dbus_setter_persistent_group_properties(
+	DBusMessage *message, struct network_handler_args *net)
+{
+	struct wpa_ssid *ssid = net->ssid;
+	DBusMessage *reply = NULL;
+	DBusMessageIter	iter, variant_iter;
+
+	dbus_message_iter_init(message, &iter);
+
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_next(&iter);
+
+	dbus_message_iter_recurse(&iter, &variant_iter);
+
+	/*
+	 * Leveraging the fact that persistent group object is still
+	 * represented in same manner as network within.
+	 */
+	reply = set_network_properties(message, net->wpa_s, ssid,
+				       &variant_iter);
+	if (reply)
+		wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
+			   "persistent group properties");
+
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_new_iface_add_persistent_group - Add a new configured
+ *	persistent_group
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing the object path of the new
+ * persistent group
+ *
+ * Handler function for "AddPersistentGroup" method call of a P2P Device
+ * interface.
+ */
+DBusMessage * wpas_dbus_handler_add_persistent_group(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter	iter;
+	struct wpa_ssid *ssid = NULL;
+	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
+
+	dbus_message_iter_init(message, &iter);
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL) {
+		wpa_printf(MSG_ERROR, "dbus: %s: "
+			   "Cannot add new persistent group", __func__);
+		reply = wpas_dbus_error_unknown_error(
+			message,
+			"wpa_supplicant could not add "
+			"a persistent group on this interface.");
+		goto err;
+	}
+
+	/* Mark the ssid as being a persistent group before the notification */
+	ssid->disabled = 2;
+	ssid->p2p_persistent_group = 1;
+	wpas_notify_persistent_group_added(wpa_s, ssid);
+
+	wpa_config_set_network_defaults(ssid);
+
+	reply = set_network_properties(message, wpa_s, ssid, &iter);
+	if (reply) {
+		wpa_printf(MSG_DEBUG, "dbus: %s: "
+			   "Control interface could not set persistent group "
+			   "properties", __func__);
+		goto err;
+	}
+
+	/* Construct the object path for this network. */
+	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
+		    wpa_s->dbus_new_path, ssid->id);
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL) {
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto err;
+	}
+	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
+				      DBUS_TYPE_INVALID)) {
+		dbus_message_unref(reply);
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto err;
+	}
+
+	return reply;
+
+err:
+	if (ssid) {
+		wpas_notify_persistent_group_removed(wpa_s, ssid);
+		wpa_config_remove_network(wpa_s->conf, ssid->id);
+	}
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
+ *	group
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemovePersistentGroup" method call of a P2P Device
+ * interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_persistent_group(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	const char *op;
+	char *iface = NULL, *persistent_group_id = NULL;
+	int id;
+	struct wpa_ssid *ssid;
+
+	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
+			      DBUS_TYPE_INVALID);
+
+	/*
+	 * Extract the network ID and ensure the network is actually a child of
+	 * this interface.
+	 */
+	iface = wpas_dbus_new_decompose_object_path(op, 1,
+						    &persistent_group_id,
+						    NULL);
+	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+		reply = wpas_dbus_error_invalid_args(message, op);
+		goto out;
+	}
+
+	id = strtoul(persistent_group_id, NULL, 10);
+	if (errno == EINVAL) {
+		reply = wpas_dbus_error_invalid_args(message, op);
+		goto out;
+	}
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		reply = wpas_dbus_error_persistent_group_unknown(message);
+		goto out;
+	}
+
+	wpas_notify_persistent_group_removed(wpa_s, ssid);
+
+	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+		wpa_printf(MSG_ERROR, "dbus: %s: "
+			   "error occurred when removing persistent group %d",
+			   __func__, id);
+		reply = wpas_dbus_error_unknown_error(
+			message,
+			"error removing the specified persistent group on "
+			"this interface.");
+		goto out;
+	}
+
+out:
+	os_free(iface);
+	os_free(persistent_group_id);
+	return reply;
+}
+
+
+static void remove_persistent_group(struct wpa_supplicant *wpa_s,
+				    struct wpa_ssid *ssid)
+{
+	wpas_notify_persistent_group_removed(wpa_s, ssid);
+
+	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
+		wpa_printf(MSG_ERROR, "dbus: %s: "
+			   "error occurred when removing persistent group %d",
+			   __func__, ssid->id);
+		return;
+	}
+}
+
+
+/**
+ * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
+ * persistent groups
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemoveAllPersistentGroups" method call of a
+ * P2P Device interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid, *next;
+	struct wpa_config *config;
+
+	config = wpa_s->conf;
+	ssid = config->ssid;
+	while (ssid) {
+		next = ssid->next;
+		if (network_is_persistent_group(ssid))
+			remove_persistent_group(wpa_s, ssid);
+		ssid = next;
+	}
+	return NULL;
+}
+
+
+/*
+ * Group object properties accessor methods
+ */
+
+DBusMessage *wpas_dbus_getter_p2p_group_members(DBusMessage * message,
+						struct wpa_supplicant * wpa_s)
+{
+	DBusMessage *reply = NULL;
+	struct wpa_ssid *ssid;
+	unsigned int num_members;
+	char **paths;
+	unsigned int i;
+	void *next = NULL;
+	const u8 *addr;
+
+	/* Ensure we are a GO */
+	if (wpa_s->wpa_state != WPA_COMPLETED)
+		goto out;
+
+	ssid = wpa_s->conf->ssid;
+	/* At present WPAS P2P_GO mode only applicable for p2p_go */
+	if (ssid->mode != WPAS_MODE_P2P_GO &&
+	    ssid->mode != WPAS_MODE_AP &&
+	    ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
+		goto out;
+
+	num_members = p2p_get_group_num_members(wpa_s->p2p_group);
+
+	paths = os_zalloc(num_members * sizeof(char *));
+	if (!paths)
+		goto out_of_memory;
+
+	i = 0;
+	while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
+		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+		if (!paths[i])
+			goto out_of_memory;
+		os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
+			    "/" COMPACT_MACSTR,
+			    wpa_s->dbus_groupobj_path, MAC2STR(addr));
+		i++;
+	}
+
+	reply = wpas_dbus_simple_array_property_getter(message,
+						       DBUS_TYPE_OBJECT_PATH,
+						       paths, num_members);
+
+out_free:
+	for (i = 0; i < num_members; i++)
+		os_free(paths[i]);
+	os_free(paths);
+out:
+	return reply;
+out_of_memory:
+	reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+	goto out_free;
+}
+
+
+DBusMessage *wpas_dbus_getter_p2p_group_properties(
+	DBusMessage *message,
+	struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter, variant_iter, dict_iter;
+	struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
+	const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+	int num_vendor_ext = 0;
+	int i;
+
+	if (!hapd) {
+		reply = dbus_message_new_error(message, DBUS_ERROR_FAILED,
+					       NULL);
+		return reply;
+	}
+
+	if (message == NULL)
+		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
+	else
+		reply = dbus_message_new_method_return(message);
+
+	if (!reply)
+		goto err_no_mem;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+					      "a{sv}", &variant_iter) ||
+	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
+		goto err_no_mem;
+
+	/* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
+	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+		if (hapd->conf->wps_vendor_ext[i] == NULL)
+			continue;
+		vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i];
+	}
+
+	if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
+					       "WPSVendorExtensions",
+					       vendor_ext, num_vendor_ext))
+		goto err_no_mem;
+
+	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+	    !dbus_message_iter_close_container(&iter, &variant_iter))
+		goto err_no_mem;
+
+	return reply;
+
+err_no_mem:
+	dbus_message_unref(reply);
+	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+DBusMessage *wpas_dbus_setter_p2p_group_properties(
+	DBusMessage *message,
+	struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter, variant_iter;
+	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
+	DBusMessageIter iter_dict;
+	unsigned int i;
+
+	struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
+
+	if (!hapd)
+		goto error;
+
+	dbus_message_iter_init(message, &iter);
+
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_next(&iter);
+
+	dbus_message_iter_recurse(&iter, &variant_iter);
+
+	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
+		return wpas_dbus_error_invalid_args(message, NULL);
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
+			reply = wpas_dbus_error_invalid_args(message, NULL);
+			break;
+		}
+
+		if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
+			    entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
+				goto error;
+
+			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+				if (i < entry.array_len) {
+					hapd->conf->wps_vendor_ext[i] =
+						entry.binarray_value[i];
+					entry.binarray_value[i] = NULL;
+				} else
+					hapd->conf->wps_vendor_ext[i] = NULL;
+			}
+
+			hostapd_update_wps(hapd);
+		} else
+			goto error;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	return reply;
+
+error:
+	reply = wpas_dbus_error_invalid_args(message, entry.key);
+	wpa_dbus_dict_entry_clear(&entry);
+
+	return reply;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_add_service(DBusMessage * message,
+					       struct wpa_supplicant * wpa_s)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	int upnp = 0;
+	int bonjour = 0;
+	char *service = NULL;
+	struct wpabuf *query = NULL;
+	struct wpabuf *resp = NULL;
+	u8 version = 0;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+		goto error;
+
+	if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		if (!strcmp(entry.key, "service_type") &&
+		    (entry.type == DBUS_TYPE_STRING)) {
+			if (!strcmp(entry.str_value, "upnp"))
+				upnp = 1;
+			else if (!strcmp(entry.str_value, "bonjour"))
+				bonjour = 1;
+			else
+				goto error_clear;
+			wpa_dbus_dict_entry_clear(&entry);
+		}
+	}
+
+	if (upnp == 1) {
+		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+				goto error;
+
+			if (!strcmp(entry.key, "version") &&
+			    entry.type == DBUS_TYPE_INT32)
+				version = entry.uint32_value;
+			else if (!strcmp(entry.key, "service") &&
+				 entry.type == DBUS_TYPE_STRING)
+				service = os_strdup(entry.str_value);
+			wpa_dbus_dict_entry_clear(&entry);
+		}
+		if (version <= 0 || service == NULL)
+			goto error;
+
+		if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
+			goto error;
+
+		os_free(service);
+	} else if (bonjour == 1) {
+		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+				goto error;
+
+			if (!strcmp(entry.key, "query")) {
+				if ((entry.type != DBUS_TYPE_ARRAY) ||
+				    (entry.array_type != DBUS_TYPE_BYTE))
+					goto error_clear;
+				query = wpabuf_alloc_copy(entry.bytearray_value,
+							  entry.array_len);
+			} else if (!strcmp(entry.key, "response")) {
+				if ((entry.type != DBUS_TYPE_ARRAY) ||
+				    (entry.array_type != DBUS_TYPE_BYTE))
+					goto error_clear;
+				resp = wpabuf_alloc_copy(entry.bytearray_value,
+							 entry.array_len);
+			}
+
+			wpa_dbus_dict_entry_clear(&entry);
+		}
+
+		if (query == NULL || resp == NULL)
+			goto error;
+
+		if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
+			wpabuf_free(query);
+			wpabuf_free(resp);
+			goto error;
+		}
+	} else
+		goto error;
+
+	return reply;
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	return wpas_dbus_error_invalid_args(message, NULL);
+}
+
+DBusMessage *wpas_dbus_handler_p2p_delete_service(DBusMessage * message,
+						  struct wpa_supplicant * wpa_s)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	int upnp = 0;
+	int bonjour = 0;
+	int ret = 0;
+	char *service = NULL;
+	struct wpabuf *query = NULL;
+	u8 version = 0;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+		goto error;
+
+	if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		if (!strcmp(entry.key, "service_type") &&
+		    (entry.type == DBUS_TYPE_STRING)) {
+			if (!strcmp(entry.str_value, "upnp"))
+				upnp = 1;
+			else if (!strcmp(entry.str_value, "bonjour"))
+				bonjour = 1;
+			else
+				goto error_clear;
+			wpa_dbus_dict_entry_clear(&entry);
+		}
+	}
+	if (upnp == 1) {
+		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+				goto error;
+			if (!strcmp(entry.key, "version") &&
+			    entry.type == DBUS_TYPE_INT32)
+				version = entry.uint32_value;
+			else if (!strcmp(entry.key, "service") &&
+				 entry.type == DBUS_TYPE_STRING)
+				service = os_strdup(entry.str_value);
+			else
+				goto error_clear;
+
+			wpa_dbus_dict_entry_clear(&entry);
+		}
+
+		if (version <= 0 || service == NULL)
+			goto error;
+
+		ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
+		os_free(service);
+		if (ret != 0)
+			goto error;
+	} else if (bonjour == 1) {
+		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+				goto error;
+
+			if (!strcmp(entry.key, "query")) {
+				if ((entry.type != DBUS_TYPE_ARRAY) ||
+				    (entry.array_type != DBUS_TYPE_BYTE))
+					goto error_clear;
+				query = wpabuf_alloc_copy(entry.bytearray_value,
+							  entry.array_len);
+			} else
+				goto error_clear;
+
+			wpa_dbus_dict_entry_clear(&entry);
+		}
+
+		if (query == NULL)
+			goto error;
+
+		ret = wpas_p2p_service_del_bonjour(wpa_s, query);
+		if (ret != 0)
+			goto error;
+		wpabuf_free(query);
+	} else
+		goto error;
+
+	return reply;
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	return wpas_dbus_error_invalid_args(message, NULL);
+}
+
+DBusMessage *wpas_dbus_handler_p2p_flush_service(DBusMessage * message,
+						 struct wpa_supplicant * wpa_s)
+{
+	wpas_p2p_service_flush(wpa_s);
+	return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_req(DBusMessage * message,
+						  struct wpa_supplicant * wpa_s)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	int upnp = 0;
+	char *service = NULL;
+	char *peer_object_path = NULL;
+	struct wpabuf *tlv = NULL;
+	u8 version = 0;
+	u64 ref = 0;
+	u8 addr[ETH_ALEN];
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+		if (!strcmp(entry.key, "peer_object") &&
+		    entry.type == DBUS_TYPE_OBJECT_PATH) {
+			peer_object_path = os_strdup(entry.str_value);
+		} else if (!strcmp(entry.key, "service_type") &&
+			   entry.type == DBUS_TYPE_STRING) {
+			if (!strcmp(entry.str_value, "upnp"))
+				upnp = 1;
+			else
+				goto error_clear;
+		} else if (!strcmp(entry.key, "version") &&
+			   entry.type == DBUS_TYPE_INT32) {
+			version = entry.uint32_value;
+		} else if (!strcmp(entry.key, "service") &&
+			   entry.type == DBUS_TYPE_STRING) {
+			service = os_strdup(entry.str_value);
+		} else if (!strcmp(entry.key, "tlv")) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != DBUS_TYPE_BYTE)
+				goto error_clear;
+			tlv = wpabuf_alloc_copy(entry.bytearray_value,
+						entry.array_len);
+		} else
+			goto error_clear;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	if (!peer_object_path ||
+	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
+	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
+		goto error;
+
+	if (upnp == 1) {
+		if (version <= 0 || service == NULL)
+			goto error;
+
+		ref = (unsigned long)wpas_p2p_sd_request_upnp(wpa_s, addr,
+							      version, service);
+	} else {
+		if (tlv == NULL)
+			goto error;
+		ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
+		wpabuf_free(tlv);
+	}
+
+	if (ref != 0) {
+		reply = dbus_message_new_method_return(message);
+		dbus_message_append_args(reply, DBUS_TYPE_UINT64,
+					 &ref, DBUS_TYPE_INVALID);
+	} else {
+		reply = wpas_dbus_error_unknown_error(message,
+				"Unable to send SD request");
+	}
+out:
+	os_free(service);
+	os_free(peer_object_path);
+	return reply;
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	if (tlv)
+		wpabuf_free(tlv);
+	reply = wpas_dbus_error_invalid_args(message, NULL);
+	goto out;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_res(
+	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;
+	struct wpabuf *tlv = NULL;
+	int freq = 0;
+	int dlg_tok = 0;
+	u8 addr[ETH_ALEN];
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		if (!strcmp(entry.key, "peer_object") &&
+		    entry.type == DBUS_TYPE_OBJECT_PATH) {
+			peer_object_path = os_strdup(entry.str_value);
+		} else if (!strcmp(entry.key, "frequency") &&
+			   entry.type == DBUS_TYPE_INT32) {
+			freq = entry.uint32_value;
+		} else if (!strcmp(entry.key, "dialog_token") &&
+			   entry.type == DBUS_TYPE_UINT32) {
+			dlg_tok = entry.uint32_value;
+		} else if (!strcmp(entry.key, "tlvs")) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != DBUS_TYPE_BYTE)
+				goto error_clear;
+			tlv = wpabuf_alloc_copy(entry.bytearray_value,
+						entry.array_len);
+		} else
+			goto error_clear;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+	if (!peer_object_path ||
+	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
+	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
+		goto error;
+
+	if (tlv == NULL)
+		goto error;
+
+	wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
+	wpabuf_free(tlv);
+out:
+	os_free(peer_object_path);
+	return reply;
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	reply = wpas_dbus_error_invalid_args(message, NULL);
+	goto out;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(DBusMessage * message, struct wpa_supplicant
+							 *wpa_s)
+{
+	DBusMessageIter iter;
+	u64 req = 0;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_get_basic(&iter, &req);
+
+	if (req == 0)
+		goto error;
+
+	if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long)req))
+		goto error;
+
+	return NULL;
+error:
+	return wpas_dbus_error_invalid_args(message, NULL);
+}
+
+DBusMessage *wpas_dbus_handler_p2p_service_update(DBusMessage * message,
+						  struct wpa_supplicant * wpa_s)
+{
+	wpas_p2p_sd_service_update(wpa_s);
+	return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(DBusMessage * message,
+						      struct wpa_supplicant *
+						      wpa_s)
+{
+	DBusMessageIter iter;
+	int ext = 0;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_get_basic(&iter, &ext);
+
+	wpa_s->p2p_sd_over_ctrl_iface = ext;
+
+	return NULL;
+
+}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
new file mode 100644
index 0000000..ed9a345
--- /dev/null
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -0,0 +1,162 @@
+
+/*
+ * WPA Supplicant / dbus-based control interface for p2p
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef DBUS_NEW_HANDLERS_P2P_H
+#define DBUS_NEW_HANDLERS_P2P_H
+
+struct peer_handler_args {
+	struct wpa_supplicant *wpa_s;
+	u8 p2p_device_addr[ETH_ALEN];
+};
+
+struct groupmember_handler_args {
+	struct wpa_supplicant *wpa_s;
+	u8 member_addr[ETH_ALEN];
+};
+
+/*
+ * P2P Device methods
+ */
+
+DBusMessage *wpas_dbus_handler_p2p_find(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_stop_find(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_rejectpeer(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_listen(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_extendedlisten(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_presence_request(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_prov_disc_req(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_group_add(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_connect(
+		DBusMessage *message,
+		struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_invite(
+		DBusMessage *message,
+		struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_disconnect(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_flush(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_add_service(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_delete_service(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_flush_service(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_req(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_res(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_update(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+/*
+ * P2P Device property accessor methods.
+ */
+DBusMessage *wpas_dbus_setter_p2p_device_properties(DBusMessage *message,
+				      struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_getter_p2p_device_properties(DBusMessage *message,
+				      struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_getter_p2p_peers(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_getter_p2p_role(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_getter_p2p_group(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_getter_p2p_peergo(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s);
+
+/*
+ * P2P Peer properties.
+ */
+DBusMessage *wpas_dbus_getter_p2p_peer_properties(
+		DBusMessage *message,
+		struct peer_handler_args *peer);
+
+DBusMessage *wpas_dbus_getter_p2p_peer_ies(
+		DBusMessage *message,
+		struct peer_handler_args *peer);
+
+/*
+ * P2P Group properties
+ */
+
+DBusMessage *wpas_dbus_getter_p2p_group_members(
+		DBusMessage *message,
+		struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_getter_p2p_group_properties(
+		DBusMessage *message,
+		struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_setter_p2p_group_properties(
+		DBusMessage *message,
+		struct wpa_supplicant *wpa_s);
+
+/*
+ * P2P Persistent Groups and properties
+ */
+
+DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
+						 struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_getter_persistent_group_properties(
+	DBusMessage *message, struct network_handler_args *net);
+DBusMessage * wpas_dbus_setter_persistent_group_properties(
+	DBusMessage *message, struct network_handler_args *net);
+DBusMessage * wpas_dbus_handler_add_persistent_group(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_persistent_group(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+
+#endif /* DBUS_NEW_HANDLERS_P2P_H */
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index 6e6e842..78611d4 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -884,3 +884,74 @@
 	fill_dict_with_properties(dict_iter, obj_desc->properties,
 				  interface, obj_desc->user_data);
 }
+
+/**
+ * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
+ * @path: The dbus object path
+ * @p2p_persistent_group: indicates whether to parse the path as a P2P
+ *                        persistent group object
+ * @network: (out) the configured network this object path refers to, if any
+ * @bssid: (out) the scanned bssid this object path refers to, if any
+ * Returns: The object path of the network interface this path refers to
+ *
+ * For a given object path, decomposes the object path into object id, network,
+ * and BSSID parts, if those parts exist.
+ */
+char *wpas_dbus_new_decompose_object_path(const char *path,
+					   int p2p_persistent_group,
+					   char **network,
+					   char **bssid)
+{
+	const unsigned int dev_path_prefix_len =
+		os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
+	char *obj_path_only;
+	char *next_sep;
+
+	/* Be a bit paranoid about path */
+	if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
+				dev_path_prefix_len))
+		return NULL;
+
+	/* Ensure there's something at the end of the path */
+	if ((path + dev_path_prefix_len)[0] == '\0')
+		return NULL;
+
+	obj_path_only = os_strdup(path);
+	if (obj_path_only == NULL)
+		return NULL;
+
+	next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
+	if (next_sep != NULL) {
+		const char *net_part = os_strstr(
+			next_sep, p2p_persistent_group ?
+			WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" :
+			WPAS_DBUS_NEW_NETWORKS_PART "/");
+		const char *bssid_part = os_strstr(
+			next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
+
+		if (network && net_part) {
+			/* Deal with a request for a configured network */
+			const char *net_name = net_part +
+				os_strlen(p2p_persistent_group ?
+					  WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
+					  "/" :
+					  WPAS_DBUS_NEW_NETWORKS_PART "/");
+			*network = NULL;
+			if (os_strlen(net_name))
+				*network = os_strdup(net_name);
+		} else if (bssid && bssid_part) {
+			/* Deal with a request for a scanned BSSID */
+			const char *bssid_name = bssid_part +
+				os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
+			if (os_strlen(bssid_name))
+				*bssid = os_strdup(bssid_name);
+			else
+				*bssid = NULL;
+		}
+
+		/* Cut off interface object path before "/" */
+		*next_sep = '\0';
+	}
+
+	return obj_path_only;
+}
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h
index 7038b63..fd21c22 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.h
+++ b/wpa_supplicant/dbus/dbus_new_helpers.h
@@ -145,4 +145,9 @@
 DBusMessage * wpa_dbus_introspect(DBusMessage *message,
 				  struct wpa_dbus_object_desc *obj_dsc);
 
+char *wpas_dbus_new_decompose_object_path(const char *path,
+					   int p2p_persistent_group,
+					   char **network,
+					   char **bssid);
+
 #endif /* WPA_DBUS_CTRL_H */
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 0c8e5f2..429ff3b 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -201,6 +201,8 @@
 #CONFIG_WPS=y
 # Enable WSC 2.0 support
 #CONFIG_WPS2=y
+# Enable WPS external registrar functionality
+#CONFIG_WPS_ER=y
 
 # EAP-IKEv2
 #CONFIG_EAP_IKEV2=y
@@ -437,10 +439,16 @@
 # from the OS. This by itself is not considered to be very strong, but it may
 # help in cases where the system pool is not initialized properly. However, it
 # is very strongly recommended that the system pool is initialized with enough
-# entropy either by using hardware assisted random number generatior or by
+# entropy either by using hardware assisted random number generator or by
 # storing state over device reboots.
 #
-# If the os_get_random() is known to provide strong ramdom data (e.g., on
+# wpa_supplicant can be configured to maintain its own entropy store over
+# restarts to enhance random number generation. This is not perfect, but it is
+# much more secure than using the same sequence of random numbers after every
+# reboot. This can be enabled with -e<entropy file> command line option. The
+# specified file needs to be readable and writable by wpa_supplicant.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
 # Linux/BSD, the board in question is known to have reliable source of random
 # data from /dev/urandom), the internal wpa_supplicant random pool can be
 # disabled. This will save some in binary size and CPU use. However, this
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 495f81d..eb6c964 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -303,6 +303,9 @@
 		privacy = 1;
 #endif /* IEEE8021X_EAPOL */
 
+	if (wpa_key_mgmt_wpa(ssid->key_mgmt))
+		privacy = 1;
+
 	if (bss->caps & IEEE80211_CAP_PRIVACY)
 		return privacy;
 	return !privacy;
@@ -572,13 +575,13 @@
 			continue;
 		}
 
-		if (!wpa && !wpa_supplicant_match_privacy(bss, ssid)) {
+		if (!wpa_supplicant_match_privacy(bss, ssid)) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - privacy "
 				"mismatch");
 			continue;
 		}
 
-		if (!wpa && (bss->caps & IEEE80211_CAP_IBSS)) {
+		if (bss->caps & IEEE80211_CAP_IBSS) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - IBSS (adhoc) "
 				"network");
 			continue;
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index c0aa59c..e196f3c 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -33,7 +33,8 @@
 	       "[-g<global ctrl>] \\\n"
 	       "        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
 	       "[-p<driver_param>] \\\n"
-	       "        [-b<br_ifname>] [-f<debug file>] \\\n"
+	       "        [-b<br_ifname>] [-f<debug file>] [-e<entropy file>] "
+	       "\\\n"
 	       "        [-o<override driver>] [-O<override ctrl>] \\\n"
 	       "        [-N -i<ifname> -c<conf> [-C<ctrl>] "
 	       "[-D<driver>] \\\n"
@@ -56,7 +57,8 @@
 	       "  -C = ctrl_interface parameter (only used if -c is not)\n"
 	       "  -i = interface name\n"
 	       "  -d = increase debugging verbosity (-dd even more)\n"
-	       "  -D = driver name (can be multiple drivers: nl80211,wext)\n");
+	       "  -D = driver name (can be multiple drivers: nl80211,wext)\n"
+	       "  -e = entropy file\n");
 #ifdef CONFIG_DEBUG_FILE
 	printf("  -f = log output to debug file instead of stdout\n");
 #endif /* CONFIG_DEBUG_FILE */
@@ -143,7 +145,7 @@
 	wpa_supplicant_fd_workaround();
 
 	for (;;) {
-		c = getopt(argc, argv, "b:Bc:C:D:df:g:hi:KLNo:O:p:P:qstuvW");
+		c = getopt(argc, argv, "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qstuvW");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -172,6 +174,9 @@
 			params.wpa_debug_level--;
 			break;
 #endif /* CONFIG_NO_STDOUT_DEBUG */
+		case 'e':
+			params.entropy_file = optarg;
+			break;
 #ifdef CONFIG_DEBUG_FILE
 		case 'f':
 			params.wpa_debug_file_path = optarg;
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 2053c3d..6595fec 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -206,14 +206,36 @@
 void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
 			       struct wpa_ssid *ssid)
 {
-	wpas_dbus_register_network(wpa_s, ssid);
+	/*
+	 * Networks objects created during any P2P activities should not be
+	 * exposed out. They might/will confuse certain non-P2P aware
+	 * applications since these network objects won't behave like
+	 * regular ones.
+	 */
+	if (wpa_s->global->p2p_group_formation != wpa_s)
+		wpas_dbus_register_network(wpa_s, ssid);
+}
+
+
+void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid)
+{
+	wpas_dbus_register_persistent_group(wpa_s, ssid);
+}
+
+
+void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s,
+					  struct wpa_ssid *ssid)
+{
+	wpas_dbus_unregister_persistent_group(wpa_s, ssid->id);
 }
 
 
 void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
 				 struct wpa_ssid *ssid)
 {
-	wpas_dbus_unregister_network(wpa_s, ssid->id);
+	if (wpa_s->global->p2p_group_formation != wpa_s)
+		wpas_dbus_unregister_network(wpa_s, ssid->id);
 }
 
 
@@ -368,12 +390,23 @@
 void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
 				  const u8 *dev_addr, int new_device)
 {
+	if (new_device) {
+		/* Create the new peer object */
+		wpas_dbus_register_peer(wpa_s, dev_addr);
+	}
+
+	/* Notify a new peer has been detected*/
+	wpas_dbus_signal_peer_device_found(wpa_s, dev_addr);
 }
 
 
 void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s,
 				 const u8 *dev_addr)
 {
+	wpas_dbus_unregister_peer(wpa_s, dev_addr);
+
+	/* Create signal on interface object*/
+	wpas_dbus_signal_peer_device_lost(wpa_s, dev_addr);
 }
 
 
@@ -381,23 +414,29 @@
 				   const struct wpa_ssid *ssid,
 				   const char *role)
 {
+	wpas_dbus_unregister_p2p_group(wpa_s, ssid);
+
+	wpas_dbus_signal_p2p_group_removed(wpa_s, role);
 }
 
 
 void wpas_notify_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
 				const u8 *src, u16 dev_passwd_id)
 {
+	wpas_dbus_signal_p2p_go_neg_req(wpa_s, src, dev_passwd_id);
 }
 
 
 void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s, int status)
 {
+	wpas_dbus_signal_p2p_go_neg_resp(wpa_s, status);
 }
 
 
 void wpas_notify_p2p_invitation_result(struct wpa_supplicant *wpa_s,
 				       int status, const u8 *bssid)
 {
+	wpas_dbus_signal_p2p_invitation_result(wpa_s, status, bssid);
 }
 
 
@@ -406,6 +445,8 @@
 				u16 update_indic, const u8 *tlvs,
 				size_t tlvs_len)
 {
+	wpas_dbus_signal_p2p_sd_request(wpa_s, freq, sa, dialog_token,
+					update_indic, tlvs, tlvs_len);
 }
 
 
@@ -413,6 +454,51 @@
 				 const u8 *sa, u16 update_indic,
 				 const u8 *tlvs, size_t tlvs_len)
 {
+	wpas_dbus_signal_p2p_sd_response(wpa_s, sa, update_indic,
+					 tlvs, tlvs_len);
+}
+
+
+/**
+ * wpas_notify_p2p_provision_discovery - Notification of provision discovery
+ * @dev_addr: Who sent the request or responded to our request.
+ * @request: Will be 1 if request, 0 for response.
+ * @status: Valid only in case of response (0 in case of success)
+ * @config_methods: WPS config methods
+ * @generated_pin: PIN to be displayed in case of WPS_CONFIG_DISPLAY method
+ *
+ * This can be used to notify:
+ * - Requests or responses
+ * - Various config methods
+ * - Failure condition in case of response
+ */
+void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					 const u8 *dev_addr, int request,
+					 enum p2p_prov_disc_status status,
+					 u16 config_methods,
+					 unsigned int generated_pin)
+{
+	wpas_dbus_signal_p2p_provision_discovery(wpa_s, dev_addr, request,
+						 status, config_methods,
+						 generated_pin);
+}
+
+
+void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid, int network_id,
+				   int client)
+{
+	/* Notify a group has been started */
+	wpas_dbus_register_p2p_group(wpa_s, ssid);
+
+	wpas_dbus_signal_p2p_group_started(wpa_s, ssid, client, network_id);
+}
+
+
+void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail)
+{
+	wpas_dbus_signal_p2p_wps_failed(wpa_s, fail);
 }
 
 #endif /* CONFIG_P2P */
@@ -421,12 +507,39 @@
 static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
 					  const u8 *sta)
 {
+#ifdef CONFIG_P2P
+	/*
+	 * Register a group member object corresponding to this peer and
+	 * emit a PeerJoined signal. This will check if it really is a
+	 * P2P group.
+	 */
+	wpas_dbus_register_p2p_groupmember(wpa_s, sta);
+
+	/*
+	 * Create 'peer-joined' signal on group object -- will also
+	 * check P2P itself.
+	 */
+	wpas_dbus_signal_p2p_peer_joined(wpa_s, sta);
+#endif /* CONFIG_P2P */
 }
 
 
 static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s,
 					    const u8 *sta)
 {
+#ifdef CONFIG_P2P
+	/*
+	 * Unregister a group member object corresponding to this peer
+	 * if this is a P2P group.
+	 */
+	wpas_dbus_unregister_p2p_groupmember(wpa_s, sta);
+
+	/*
+	 * Create 'peer-disconnected' signal on group object if this
+	 * is a P2P group.
+	 */
+	wpas_dbus_signal_p2p_peer_disconnected(wpa_s, sta);
+#endif /* CONFIG_P2P */
 }
 
 
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 6c8fdf7..766668f 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -15,6 +15,8 @@
 #ifndef NOTIFY_H
 #define NOTIFY_H
 
+#include "p2p/p2p.h"
+
 struct wps_credential;
 struct wps_event_m2d;
 struct wps_event_fail;
@@ -101,5 +103,20 @@
 void wpas_notify_p2p_sd_response(struct wpa_supplicant *wpa_s,
 				 const u8 *sa, u16 update_indic,
 				 const u8 *tlvs, size_t tlvs_len);
+void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					 const u8 *dev_addr, int request,
+					 enum p2p_prov_disc_status status,
+					 u16 config_methods,
+					 unsigned int generated_pin);
+void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid, int network_id,
+				   int client);
+void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid);
+void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s,
+					  struct wpa_ssid *ssid);
+
+void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail);
 
 #endif /* NOTIFY_H */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 03d1672..c34a28c 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -23,6 +23,8 @@
 #include "p2p/p2p.h"
 #include "ap/hostapd.h"
 #include "ap/p2p_hostapd.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "ap.h"
@@ -293,9 +295,20 @@
 		     ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
 		     (ssid->key_mgmt & WPA_KEY_MGMT_WPS))) {
 		int id = ssid->id;
-		if (ssid == wpa_s->current_ssid)
+		if (ssid == wpa_s->current_ssid) {
+			wpa_sm_set_config(wpa_s->wpa, NULL);
+			eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 			wpa_s->current_ssid = NULL;
-		wpas_notify_network_removed(wpa_s, ssid);
+		}
+		/*
+		 * Networks objects created during any P2P activities are not
+		 * exposed out as they might/will confuse certain non-P2P aware
+		 * applications since these network objects won't behave like
+		 * regular ones.
+		 *
+		 * Likewise, we don't send out network removed signals for such
+		 * network objects.
+		 */
 		wpa_config_remove_network(wpa_s->conf, id);
 		wpa_supplicant_clear_status(wpa_s);
 	} else {
@@ -368,9 +381,9 @@
 }
 
 
-static void wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
-					    struct wpa_ssid *ssid,
-					    const u8 *go_dev_addr)
+static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
+					   struct wpa_ssid *ssid,
+					   const u8 *go_dev_addr)
 {
 	struct wpa_ssid *s;
 	int changed = 0;
@@ -399,7 +412,17 @@
 		changed = 1;
 		s = wpa_config_add_network(wpa_s->conf);
 		if (s == NULL)
-			return;
+			return -1;
+
+		/*
+		 * Instead of network_added we emit persistent_group_added
+		 * notification. Also to keep the defense checks in
+		 * persistent_group obj registration method, we set the
+		 * relevant flags in s to designate it as a persistent group.
+		 */
+		s->p2p_group = 1;
+		s->p2p_persistent_group = 1;
+		wpas_notify_persistent_group_added(wpa_s, s);
 		wpa_config_set_network_defaults(s);
 	}
 
@@ -439,6 +462,8 @@
 		wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
 	}
 #endif /* CONFIG_NO_CONFIG_WRITE */
+
+	return s->id;
 }
 
 
@@ -450,6 +475,7 @@
 	int client;
 	int persistent;
 	u8 go_dev_addr[ETH_ALEN];
+	int network_id = -1;
 
 	/*
 	 * This callback is likely called for the main interface. Update wpa_s
@@ -529,8 +555,12 @@
 	}
 
 	if (persistent)
-		wpas_p2p_store_persistent_group(wpa_s->parent, ssid,
-						go_dev_addr);
+		network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
+							     ssid, go_dev_addr);
+	if (network_id < 0)
+		network_id = ssid->id;
+	if (!client)
+		wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
 }
 
 
@@ -836,6 +866,7 @@
 	struct wpa_supplicant *wpa_s = ctx;
 	struct p2p_go_neg_results *params = data;
 	struct wpa_ssid *ssid;
+	int network_id = -1;
 
 	ssid = wpa_s->current_ssid;
 	if (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
@@ -851,10 +882,14 @@
 			params->passphrase ? params->passphrase : "",
 			MAC2STR(wpa_s->parent->own_addr),
 			params->persistent_group ? " [PERSISTENT]" : "");
+
 		if (params->persistent_group)
-			wpas_p2p_store_persistent_group(
+			network_id = wpas_p2p_store_persistent_group(
 				wpa_s->parent, ssid,
 				wpa_s->parent->own_addr);
+		if (network_id < 0)
+			network_id = ssid->id;
+		wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
 		wpas_p2p_cross_connect_setup(wpa_s);
 		wpas_p2p_set_group_idle_timeout(wpa_s);
 		return;
@@ -891,7 +926,6 @@
 	if (ssid == NULL)
 		return;
 
-	wpas_notify_network_added(wpa_s, ssid);
 	wpa_config_set_network_defaults(ssid);
 	ssid->temporary = 1;
 	ssid->p2p_group = 1;
@@ -913,7 +947,7 @@
 	wpa_s->ap_configured_cb = p2p_go_configured;
 	wpa_s->ap_configured_cb_ctx = wpa_s;
 	wpa_s->ap_configured_cb_data = wpa_s->go_params;
-	wpa_s->connect_without_scan = 1;
+	wpa_s->connect_without_scan = ssid;
 	wpa_s->reassociate = 1;
 	wpa_s->disconnected = 0;
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -1893,6 +1927,10 @@
 	else if (config_methods & WPS_CONFIG_PUSHBUTTON)
 		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ MACSTR
 			"%s", MAC2STR(peer), params);
+
+	wpas_notify_p2p_provision_discovery(wpa_s, peer, 1 /* request */,
+					    P2P_PROV_DISC_SUCCESS,
+					    config_methods, generated_pin);
 }
 
 
@@ -1910,6 +1948,10 @@
 		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR,
 			MAC2STR(peer));
 
+	wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
+					    P2P_PROV_DISC_SUCCESS,
+					    config_methods, generated_pin);
+
 	if (wpa_s->pending_pd_before_join &&
 	    (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
 	     os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
@@ -1921,6 +1963,16 @@
 }
 
 
+void wpas_prov_disc_fail(void *ctx, const u8 *peer,
+			 enum p2p_prov_disc_status status)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
+					    status, 0, 0);
+}
+
+
 static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
 				  const u8 *go_dev_addr, const u8 *ssid,
 				  size_t ssid_len, int *go, u8 *group_bssid,
@@ -2356,6 +2408,7 @@
 	p2p.sd_response = wpas_sd_response;
 	p2p.prov_disc_req = wpas_prov_disc_req;
 	p2p.prov_disc_resp = wpas_prov_disc_resp;
+	p2p.prov_disc_fail = wpas_prov_disc_fail;
 	p2p.invitation_process = wpas_invitation_process;
 	p2p.invitation_received = wpas_invitation_received;
 	p2p.invitation_result = wpas_invitation_result;
@@ -3271,7 +3324,6 @@
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL)
 		return -1;
-	wpas_notify_network_added(wpa_s, ssid);
 	wpa_config_set_network_defaults(ssid);
 	ssid->temporary = 1;
 	ssid->proto = WPA_PROTO_RSN;
@@ -3280,7 +3332,6 @@
 	ssid->key_mgmt = WPA_KEY_MGMT_PSK;
 	ssid->ssid = os_malloc(params->ssid_len);
 	if (ssid->ssid == NULL) {
-		wpas_notify_network_removed(wpa_s, ssid);
 		wpa_config_remove_network(wpa_s->conf, ssid->id);
 		return -1;
 	}
@@ -3443,6 +3494,18 @@
 }
 
 
+void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+			 struct wps_event_fail *fail)
+{
+	if (!wpa_s->p2p_in_provisioning) {
+		wpa_printf(MSG_DEBUG, "P2P: Ignore WPS fail event - P2P "
+			   "provisioning not in progress");
+		return;
+	}
+	wpas_notify_p2p_wps_failed(wpa_s, fail);
+}
+
+
 int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		       const char *config_method)
 {
@@ -3753,6 +3816,7 @@
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 	const char *ssid_txt;
 	u8 go_dev_addr[ETH_ALEN];
+	int network_id = -1;
 	int persistent;
 
 	if (!wpa_s->show_group_started || !ssid)
@@ -3791,8 +3855,11 @@
 	}
 
 	if (persistent)
-		wpas_p2p_store_persistent_group(wpa_s->parent, ssid,
-						go_dev_addr);
+		network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
+							     ssid, go_dev_addr);
+	if (network_id < 0)
+		network_id = ssid->id;
+	wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
 }
 
 
@@ -3949,6 +4016,54 @@
 
 	if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_INTRA_BSS)
 		p2p_set_intra_bss_dist(p2p, wpa_s->conf->p2p_intra_bss);
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_LISTEN_CHANNEL) {
+		u8 reg_class, channel;
+		int ret;
+		unsigned int r;
+		if (wpa_s->conf->p2p_listen_reg_class &&
+		    wpa_s->conf->p2p_listen_channel) {
+			reg_class = wpa_s->conf->p2p_listen_reg_class;
+			channel = wpa_s->conf->p2p_listen_channel;
+		} else {
+			reg_class = 81;
+			/*
+			 * Pick one of the social channels randomly as the
+			 * listen channel.
+			 */
+			os_get_random((u8 *) &r, sizeof(r));
+			channel = 1 + (r % 3) * 5;
+		}
+		ret = p2p_set_listen_channel(p2p, reg_class, channel);
+		if (ret)
+			wpa_printf(MSG_ERROR, "P2P: Own listen channel update "
+				   "failed: %d", ret);
+	}
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_OPER_CHANNEL) {
+		u8 op_reg_class, op_channel, cfg_op_channel;
+		int ret = 0;
+		unsigned int r;
+		if (wpa_s->conf->p2p_oper_reg_class &&
+		    wpa_s->conf->p2p_oper_channel) {
+			op_reg_class = wpa_s->conf->p2p_oper_reg_class;
+			op_channel = wpa_s->conf->p2p_oper_channel;
+			cfg_op_channel = 1;
+		} else {
+			op_reg_class = 81;
+			/*
+			 * Use random operation channel from (1, 6, 11)
+			 *if no other preference is indicated.
+			 */
+			os_get_random((u8 *) &r, sizeof(r));
+			op_channel = 1 + (r % 3) * 5;
+			cfg_op_channel = 0;
+		}
+		ret = p2p_set_oper_channel(p2p, op_reg_class, op_channel,
+					   cfg_op_channel);
+		if (ret)
+			wpa_printf(MSG_ERROR, "P2P: Own oper channel update "
+				   "failed: %d", ret);
+	}
 }
 
 
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 69df475..b1080a5 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -124,5 +124,7 @@
 				   int freq_24, int freq_5, int freq_overall);
 int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr);
 int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s);
+void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+			 struct wps_event_fail *fail);
 
 #endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 805ff80..f2f7227 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -307,6 +307,20 @@
 	    wpa_s->wpa_state == WPA_INACTIVE)
 		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
 
+	if (scan_req != 2 && wpa_s->connect_without_scan) {
+		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+			if (ssid == wpa_s->connect_without_scan)
+				break;
+		}
+		wpa_s->connect_without_scan = NULL;
+		if (ssid) {
+			wpa_printf(MSG_DEBUG, "Start a pre-selected network "
+				   "without scan step");
+			wpa_supplicant_associate(wpa_s, NULL, ssid);
+			return;
+		}
+	}
+
 	/* Find the starting point from which to continue scanning */
 	ssid = wpa_s->conf->ssid;
 	if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
@@ -319,9 +333,8 @@
 		}
 	}
 
-	if (scan_req != 2 && (wpa_s->conf->ap_scan == 2 ||
-			      wpa_s->connect_without_scan)) {
-		wpa_s->connect_without_scan = 0;
+	if (scan_req != 2 && wpa_s->conf->ap_scan == 2) {
+		wpa_s->connect_without_scan = NULL;
 		wpa_supplicant_assoc_try(wpa_s, ssid);
 		return;
 	} else if (wpa_s->conf->ap_scan == 2) {
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 4261be4..74a2286 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1634,6 +1634,7 @@
 		if (was_disabled != other_ssid->disabled)
 			wpas_notify_network_enabled_changed(wpa_s, other_ssid);
 	}
+	wpa_s->connect_without_scan = NULL;
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -2544,7 +2545,7 @@
 		return NULL;
 	}
 
-	random_init();
+	random_init(params->entropy_file);
 
 	global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
 	if (global->ctrl_iface == NULL) {
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 8498666..c1a8808 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -17,6 +17,7 @@
 
 #include "utils/list.h"
 #include "common/defs.h"
+#include "config_ssid.h"
 
 extern const char *wpa_supplicant_version;
 extern const char *wpa_supplicant_license;
@@ -181,6 +182,14 @@
 	 * created.
 	 */
 	char *override_ctrl_interface;
+
+	/**
+	 * entropy_file - Optional entropy file
+	 *
+	 * This parameter can be used to configure wpa_supplicant to maintain
+	 * its internal entropy store over restarts.
+	 */
+	char *entropy_file;
 };
 
 struct p2p_srv_bonjour {
@@ -334,6 +343,7 @@
 #endif /* CONFIG_CTRL_IFACE_DBUS */
 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
 	char *dbus_new_path;
+	char *dbus_groupobj_path;
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
 	char bridge_ifname[16];
 
@@ -540,7 +550,7 @@
 	const struct bgscan_ops *bgscan;
 	void *bgscan_priv;
 
-	int connect_without_scan;
+	struct wpa_ssid *connect_without_scan;
 
 	int after_wps;
 	unsigned int wps_freq;
@@ -633,4 +643,14 @@
 /* eap_register.c */
 int eap_register_methods(void);
 
+/**
+ * Utility method to tell if a given network is a persistent group
+ * @ssid: Network object
+ * Returns: 1 if network is a persistent group, 0 otherwise
+ */
+static inline int network_is_persistent_group(struct wpa_ssid *ssid)
+{
+	return ((ssid->disabled == 2) || ssid->p2p_persistent_group);
+}
+
 #endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 778ccaf..e3388bd 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -24,6 +24,7 @@
 #include "common/wpa_ctrl.h"
 #include "eap_common/eap_wsc_common.h"
 #include "eap_peer/eap.h"
+#include "eapol_supp/eapol_supp_sm.h"
 #include "rsn_supp/wpa.h"
 #include "config.h"
 #include "wpa_supplicant_i.h"
@@ -470,6 +471,9 @@
 	}
 	wpas_clear_wps(wpa_s);
 	wpas_notify_wps_event_fail(wpa_s, fail);
+#ifdef CONFIG_P2P
+	wpas_p2p_wps_failed(wpa_s, fail);
+#endif /* CONFIG_P2P */
 }
 
 
@@ -670,7 +674,9 @@
 static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
 {
 	int id;
-	struct wpa_ssid *ssid, *remove_ssid = NULL;
+	struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
+
+	prev_current = wpa_s->current_ssid;
 
 	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
 
@@ -689,6 +695,11 @@
 			id = -1;
 		ssid = ssid->next;
 		if (id >= 0) {
+			if (prev_current == remove_ssid) {
+				wpa_sm_set_config(wpa_s->wpa, NULL);
+				eapol_sm_notify_config(wpa_s->eapol, NULL,
+						       NULL);
+			}
 			wpas_notify_network_removed(wpa_s, remove_ssid);
 			wpa_config_remove_network(wpa_s->conf, id);
 		}
@@ -780,9 +791,18 @@
 	ssid = wpa_s->conf->ssid;
 	while (ssid) {
 		int was_disabled = ssid->disabled;
-		ssid->disabled = ssid != selected;
-		if (was_disabled != ssid->disabled)
-			wpas_notify_network_enabled_changed(wpa_s, ssid);
+		/*
+		 * In case the network object corresponds to a persistent group
+		 * then do not send out network disabled signal. In addition,
+		 * do not change disabled status of persistent network objects
+		 * from 2 to 1 should we connect to another network.
+		 */
+		if (was_disabled != 2) {
+			ssid->disabled = ssid != selected;
+			if (was_disabled != ssid->disabled)
+				wpas_notify_network_enabled_changed(wpa_s,
+								    ssid);
+		}
 		ssid = ssid->next;
 	}
 	wpa_s->disconnected = 0;