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/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;