Cumulative patch from commit 7efc7f66b1d63b3bbb99d9176f6f68c4d1fc6327

7efc7f6 TDLS: Fix TPK M1 error case (CID 68214)
d1bb7ae nl80211: Fix non-hostapd interface addition to not call add_ifidx()
38ddcca TDLS: Add ctrl_iface option for flushing all TDLS peers
342bce6 TDLS: Bail on STA add failure in tpk_m1 processing
947f900 TDLS: Handle unreachable link teardown for external setup
cf1600a hostapd: Configure driver ACL even if MAC address list is empty
fa21e6c Fix CONFIG_MODULE_TESTS=y build without CONFIG_P2P=y
bd10d93 P2P: Clean up by moving ifdef CONFIG_P2P to p2p_suppplicant.h
e3bd6e9 P2P: Use another interface operating channel as listen channel
28812a8 P2P: Try using one of the social channels for GO
751b00b P2P: Modify p2p_get_pref_freq
0a816e8 P2P: Remove duplicated code from get_shared_radio_freqs_data()
504df28 Remove unused dump_freq_array()
a0c90bb P2P: Collect and use extended data on used frequencies
b278f32 P2P: Remove unused code from get_shared_radio_freqs_data()
e627012 Clean up EAPOL-Key Key Data processing
d56d7e5 Clean up EAPOL-Key processing
8605eab EAP-EKE: Fix typos in debug message
25be28a dbus: Check return value more consistently (CID 62841)
ac79fcf wext: Verify set_ssid results consistently (CID 62842)
f62415d Note chmod() failure in debug log even in ignore case (CID 62843)
305000e WPS: Check wps_build_wfa_ext() return value consistently (CID 68104)
2485835 EAP-MSCHAPv2: Check hash function results more consistently (CID 68105)
b7c61c9 Fix validation of EAPOL-Key length with AES key wrap (CID 62859)

Change-Id: I4da11c59a54467301c38c3bec52629b9db19647d
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 817a69d..8f7c23f 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1499,6 +1499,9 @@
 ifdef CONFIG_WPS
 OBJS += ../src/wps/wps_module_tests.o
 endif
+ifndef CONFIG_P2P
+OBJS += ../src/utils/bitfield.o
+endif
 endif
 
 OBJS += ../src/drivers/driver_common.o
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index d10583b..f9aa807 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -455,23 +455,17 @@
 			   const u8 *bssid, const u8 *ie, size_t ie_len,
 			   int ssi_signal)
 {
-#ifdef CONFIG_P2P
 	struct wpa_supplicant *wpa_s = ctx;
 	return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len,
 				     ssi_signal);
-#else /* CONFIG_P2P */
-	return 0;
-#endif /* CONFIG_P2P */
 }
 
 
 static void ap_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
 				  const u8 *uuid_e)
 {
-#ifdef CONFIG_P2P
 	struct wpa_supplicant *wpa_s = ctx;
 	wpas_p2p_wps_success(wpa_s, mac_addr, 1);
-#endif /* CONFIG_P2P */
 }
 
 
@@ -668,11 +662,7 @@
 	wpa_s->current_ssid = NULL;
 	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 	wpa_s->assoc_freq = 0;
-#ifdef CONFIG_P2P
-	if (wpa_s->ap_iface->bss)
-		wpa_s->ap_iface->bss[0]->p2p_group = NULL;
-	wpas_p2p_group_deinit(wpa_s);
-#endif /* CONFIG_P2P */
+	wpas_p2p_ap_deinit(wpa_s);
 	wpa_s->ap_iface->driver_ap_teardown =
 		!!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
 
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 278ec9b..4cea2ef 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -3256,6 +3256,7 @@
 	config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
 	config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
 	config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
+	config->p2p_optimize_listen_chan = DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN;
 	config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
 	config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
 	config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
@@ -3838,6 +3839,7 @@
 	{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
 	{ FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN },
 	{ INT_RANGE(p2p_add_cli_chan, 0, 1), 0 },
+	{ INT_RANGE(p2p_optimize_listen_chan, 0, 1), 0 },
 	{ INT(p2p_go_ht40), 0 },
 	{ INT(p2p_go_vht), 0 },
 	{ INT(p2p_disabled), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 9b7e21d..3c2fc4a 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -19,6 +19,7 @@
 #define DEFAULT_P2P_GO_INTENT 7
 #define DEFAULT_P2P_INTRA_BSS 1
 #define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60)
+#define DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN 0
 #define DEFAULT_BSS_MAX_COUNT 200
 #define DEFAULT_BSS_EXPIRATION_AGE 180
 #define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
@@ -686,6 +687,7 @@
 	struct wpa_freq_range_list p2p_no_go_freq;
 	int p2p_add_cli_chan;
 	int p2p_ignore_shared_freq;
+	int p2p_optimize_listen_chan;
 
 	struct wpabuf *wps_vendor_ext_m1;
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index d09b942..58e7111 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1035,6 +1035,10 @@
 	}
 	if (config->p2p_add_cli_chan)
 		fprintf(f, "p2p_add_cli_chan=%d\n", config->p2p_add_cli_chan);
+	if (config->p2p_optimize_listen_chan !=
+	    DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN)
+		fprintf(f, "p2p_optimize_listen_chan=%d\n",
+			config->p2p_optimize_listen_chan);
 	if (config->p2p_go_ht40)
 		fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
 	if (config->p2p_go_vht)
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 4311208..a509bfb 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -584,6 +584,13 @@
 	u8 peer[ETH_ALEN];
 	int ret;
 
+	if (os_strcmp(addr, "*") == 0) {
+		/* remove everyone */
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN *");
+		wpa_tdls_teardown_peers(wpa_s->wpa);
+		return 0;
+	}
+
 	if (hwaddr_aton(addr, peer)) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
 			   "address '%s'", addr);
@@ -4760,7 +4767,7 @@
 
 	if (os_strcmp(cmd, "listen_channel") == 0) {
 		return p2p_set_listen_channel(wpa_s->global->p2p, 81,
-					      atoi(param));
+					      atoi(param), 1);
 	}
 
 	if (os_strcmp(cmd, "ssid_postfix") == 0) {
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index d4e45de..40082e2 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -990,7 +990,13 @@
 			goto fail;
 		}
 	} else {
-		chmod(ctrl, S_IRWXU);
+		if (chmod(ctrl, S_IRWXU) < 0) {
+			wpa_printf(MSG_DEBUG,
+				   "chmod[global_ctrl_interface=%s](S_IRWXU): %s",
+				   ctrl, strerror(errno));
+			/* continue anyway since group change was not required
+			 */
+		}
 	}
 
 havesock:
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index a89a87d..f5efd8b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -440,8 +440,13 @@
 	}
 
 	for (i = 0; i < array_len; i++) {
-		dbus_message_iter_append_basic(&array_iter, type,
-					       array + i * element_size);
+		if (!dbus_message_iter_append_basic(&array_iter, type,
+						    array + i * element_size)) {
+			dbus_set_error(error, DBUS_ERROR_FAILED,
+				       "%s: failed to construct message 2.5",
+				       __func__);
+			return FALSE;
+		}
 	}
 
 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index 712bffc..750522d 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -38,27 +38,25 @@
 
 		if (!dbus_message_iter_open_container(dict_iter,
 						      DBUS_TYPE_DICT_ENTRY,
-						      NULL, &entry_iter)) {
-			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
-			                     "no memory");
-			return FALSE;
-		}
-		if (!dbus_message_iter_append_basic(&entry_iter,
+						      NULL, &entry_iter) ||
+		    !dbus_message_iter_append_basic(&entry_iter,
 						    DBUS_TYPE_STRING,
-						    &dsc->dbus_property)) {
-			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
-			                     "no memory");
-			return FALSE;
-		}
+						    &dsc->dbus_property))
+			goto error;
 
 		/* An error getting a property fails the request entirely */
 		if (!dsc->getter(&entry_iter, error, user_data))
 			return FALSE;
 
-		dbus_message_iter_close_container(dict_iter, &entry_iter);
+		if (!dbus_message_iter_close_container(dict_iter, &entry_iter))
+			goto error;
 	}
 
 	return TRUE;
+
+error:
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	return FALSE;
 }
 
 
@@ -111,7 +109,12 @@
 		return reply;
 	}
 
-	wpa_dbus_dict_close_write(&iter, &dict_iter);
+	if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
+		dbus_message_unref(reply);
+		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					      "out of memory");
+	}
+
 	return reply;
 }
 
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index c0cb1c2..88e5254 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -350,7 +350,7 @@
 DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
 					   struct wpa_supplicant *wpa_s)
 {
-	DBusMessage *reply = NULL;
+	DBusMessage *reply;
 	DBusMessageIter iter;
 	DBusMessageIter sub_iter;
 	struct wpa_bss *bss;
@@ -358,9 +358,10 @@
 	/* Create and initialize the return message */
 	reply = dbus_message_new_method_return(message);
 	dbus_message_iter_init_append(reply, &iter);
-	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-					 DBUS_TYPE_OBJECT_PATH_AS_STRING,
-					 &sub_iter);
+	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+					      DBUS_TYPE_OBJECT_PATH_AS_STRING,
+					      &sub_iter))
+		goto error;
 
 	/* Loop through scan results and append each result's object path */
 	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
@@ -374,13 +375,21 @@
 			    "%s/" WPAS_DBUS_BSSIDS_PART "/"
 			    WPAS_DBUS_BSSID_FORMAT,
 			    wpa_s->dbus_path, MAC2STR(bss->bssid));
-		dbus_message_iter_append_basic(&sub_iter,
-					       DBUS_TYPE_OBJECT_PATH, &path);
+		if (!dbus_message_iter_append_basic(&sub_iter,
+						    DBUS_TYPE_OBJECT_PATH,
+						    &path))
+			goto error;
 	}
 
-	dbus_message_iter_close_container(&iter, &sub_iter);
+	if (!dbus_message_iter_close_container(&iter, &sub_iter))
+		goto error;
 
 	return reply;
+
+error:
+	dbus_message_unref(reply);
+	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
+				      "an internal error occurred returning scan results");
 }
 
 
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index a9291a4..60da3bf 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2770,9 +2770,7 @@
 	wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
 		wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
 
-#ifdef CONFIG_P2P
 	wpas_p2p_update_channel_list(wpa_s);
-#endif /* CONFIG_P2P */
 
 	/*
 	 * Check other interfaces to see if they share the same radio. If
@@ -2868,10 +2866,8 @@
 	}
 #endif /* CONFIG_INTERWORKING */
 
-#ifdef CONFIG_P2P
 	wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
 			   category, payload, plen, freq);
-#endif /* CONFIG_P2P */
 }
 
 
@@ -3272,14 +3268,12 @@
 			break;
 		}
 #endif /* CONFIG_AP */
-#ifdef CONFIG_P2P
 		wpas_p2p_probe_req_rx(wpa_s, data->rx_probe_req.sa,
 				      data->rx_probe_req.da,
 				      data->rx_probe_req.bssid,
 				      data->rx_probe_req.ie,
 				      data->rx_probe_req.ie_len,
 				      data->rx_probe_req.ssi_signal);
-#endif /* CONFIG_P2P */
 		break;
 	case EVENT_REMAIN_ON_CHANNEL:
 #ifdef CONFIG_OFFCHANNEL
@@ -3287,21 +3281,17 @@
 			wpa_s, data->remain_on_channel.freq,
 			data->remain_on_channel.duration);
 #endif /* CONFIG_OFFCHANNEL */
-#ifdef CONFIG_P2P
 		wpas_p2p_remain_on_channel_cb(
 			wpa_s, data->remain_on_channel.freq,
 			data->remain_on_channel.duration);
-#endif /* CONFIG_P2P */
 		break;
 	case EVENT_CANCEL_REMAIN_ON_CHANNEL:
 #ifdef CONFIG_OFFCHANNEL
 		offchannel_cancel_remain_on_channel_cb(
 			wpa_s, data->remain_on_channel.freq);
 #endif /* CONFIG_OFFCHANNEL */
-#ifdef CONFIG_P2P
 		wpas_p2p_cancel_remain_on_channel_cb(
 			wpa_s, data->remain_on_channel.freq);
-#endif /* CONFIG_P2P */
 		break;
 	case EVENT_EAPOL_RX:
 		wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
@@ -3386,9 +3376,7 @@
 			wpa_s, &data->channel_list_changed);
 		break;
 	case EVENT_INTERFACE_UNAVAILABLE:
-#ifdef CONFIG_P2P
 		wpas_p2p_interface_unavailable(wpa_s);
-#endif /* CONFIG_P2P */
 		break;
 	case EVENT_BEST_CHANNEL:
 		wpa_dbg(wpa_s, MSG_DEBUG, "Best channel event received "
@@ -3398,11 +3386,9 @@
 		wpa_s->best_24_freq = data->best_chan.freq_24;
 		wpa_s->best_5_freq = data->best_chan.freq_5;
 		wpa_s->best_overall_freq = data->best_chan.freq_overall;
-#ifdef CONFIG_P2P
 		wpas_p2p_update_best_channels(wpa_s, data->best_chan.freq_24,
 					      data->best_chan.freq_5,
 					      data->best_chan.freq_overall);
-#endif /* CONFIG_P2P */
 		break;
 	case EVENT_UNPROT_DEAUTH:
 		wpa_supplicant_event_unprot_deauth(wpa_s,
@@ -3420,7 +3406,8 @@
 #endif /* CONFIG_AP */
 #ifdef CONFIG_TDLS
 		if (data)
-			wpa_tdls_disable_link(wpa_s->wpa, data->low_ack.addr);
+			wpa_tdls_disable_unreachable_link(wpa_s->wpa,
+							  data->low_ack.addr);
 #endif /* CONFIG_TDLS */
 		break;
 	case EVENT_IBSS_PEER_LOST:
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 2db1d54..d096357 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -79,12 +79,10 @@
 	/* notify the new DBus API */
 	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE);
 
-#ifdef CONFIG_P2P
 	if (new_state == WPA_COMPLETED)
 		wpas_p2p_notif_connected(wpa_s);
 	else if (old_state >= WPA_ASSOCIATED && new_state < WPA_ASSOCIATED)
 		wpas_p2p_notif_disconnected(wpa_s);
-#endif /* CONFIG_P2P */
 
 	sme_state_changed(wpa_s);
 
@@ -258,9 +256,7 @@
 		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
 	if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s)
 		wpas_dbus_unregister_network(wpa_s, ssid->id);
-#ifdef CONFIG_P2P
 	wpas_p2p_network_removed(wpa_s, ssid);
-#endif /* CONFIG_P2P */
 }
 
 
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 50ee1e0..6b85efe 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -122,6 +122,7 @@
 static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
 static void wpas_stop_listen(void *ctx);
 static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx);
+static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
 
 
 /*
@@ -151,29 +152,32 @@
  * Get the frequencies that are currently in use by one or more of the virtual
  * interfaces, and that are also valid for P2P operation.
  */
-static int wpas_p2p_valid_oper_freqs(struct wpa_supplicant *wpa_s,
-				     int *p2p_freqs, unsigned int len)
+static unsigned int
+wpas_p2p_valid_oper_freqs(struct wpa_supplicant *wpa_s,
+			  struct wpa_used_freq_data *p2p_freqs,
+			  unsigned int len)
 {
-	int *freqs;
+	struct wpa_used_freq_data *freqs;
 	unsigned int num, i, j;
 
-	freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+	freqs = os_calloc(wpa_s->num_multichan_concurrent,
+			  sizeof(struct wpa_used_freq_data));
 	if (!freqs)
-		return -1;
+		return 0;
 
-	num = get_shared_radio_freqs(wpa_s, freqs,
-				     wpa_s->num_multichan_concurrent);
+	num = get_shared_radio_freqs_data(wpa_s, freqs,
+					  wpa_s->num_multichan_concurrent);
 
-	os_memset(p2p_freqs, 0, sizeof(int) * len);
+	os_memset(p2p_freqs, 0, sizeof(struct wpa_used_freq_data) * len);
 
 	for (i = 0, j = 0; i < num && j < len; i++) {
-		if (p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
+		if (p2p_supported_freq(wpa_s->global->p2p, freqs[i].freq))
 			p2p_freqs[j++] = freqs[i];
 	}
 
 	os_free(freqs);
 
-	dump_freq_array(wpa_s, "valid for P2P", p2p_freqs, j);
+	dump_freq_data(wpa_s, "valid for P2P", p2p_freqs, j);
 
 	return j;
 }
@@ -2914,6 +2918,45 @@
 }
 
 
+/**
+ * Pick the best frequency to use from all the currently used frequencies.
+ */
+static int wpas_p2p_pick_best_used_freq(struct wpa_supplicant *wpa_s,
+					struct wpa_used_freq_data *freqs,
+					unsigned int num)
+{
+	unsigned int i, c;
+
+	/* find a candidate freq that is supported by P2P */
+	for (c = 0; c < num; c++)
+		if (p2p_supported_freq(wpa_s->global->p2p, freqs[c].freq))
+			break;
+
+	if (c == num)
+		return 0;
+
+	/* once we have a candidate, try to find a 'better' one */
+	for (i = c + 1; i < num; i++) {
+		if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i].freq))
+			continue;
+
+		/*
+		 * 1. Infrastructure station interfaces have higher preference.
+		 * 2. P2P Clients have higher preference.
+		 * 3. All others.
+		 */
+		if (freqs[i].flags & WPA_FREQ_USED_BY_INFRA_STATION) {
+			c = i;
+			break;
+		}
+
+		if ((freqs[i].flags & WPA_FREQ_USED_BY_P2P_CLIENT))
+			c = i;
+	}
+	return freqs[c].freq;
+}
+
+
 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,
@@ -2923,8 +2966,9 @@
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *s;
-	int res;
+	struct wpa_used_freq_data *freqs;
 	struct wpa_supplicant *grp;
+	int best_freq;
 
 	if (!persistent_group) {
 		wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
@@ -3016,15 +3060,25 @@
 accept_inv:
 	wpas_p2p_set_own_freq_preference(wpa_s, 0);
 
+	best_freq = 0;
+	freqs = os_calloc(wpa_s->num_multichan_concurrent,
+			  sizeof(struct wpa_used_freq_data));
+	if (freqs) {
+		int num_channels = wpa_s->num_multichan_concurrent;
+		int num = wpas_p2p_valid_oper_freqs(wpa_s, freqs, num_channels);
+		best_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
+		os_free(freqs);
+	}
+
 	/* Get one of the frequencies currently in use */
-	if (wpas_p2p_valid_oper_freqs(wpa_s, &res, 1) > 0) {
+	if (best_freq > 0) {
 		wpa_printf(MSG_DEBUG, "P2P: Trying to prefer a channel already used by one of the interfaces");
-		wpas_p2p_set_own_freq_preference(wpa_s, res);
+		wpas_p2p_set_own_freq_preference(wpa_s, best_freq);
 
 		if (wpa_s->num_multichan_concurrent < 2 ||
 		    wpas_p2p_num_unused_channels(wpa_s) < 1) {
 			wpa_printf(MSG_DEBUG, "P2P: No extra channels available - trying to force channel to match a channel already used by one of the interfaces");
-			*force_freq = res;
+			*force_freq = best_freq;
 		}
 	}
 
@@ -3819,6 +3873,7 @@
 	    wpa_s->conf->p2p_listen_channel) {
 		p2p.reg_class = wpa_s->conf->p2p_listen_reg_class;
 		p2p.channel = wpa_s->conf->p2p_listen_channel;
+		p2p.channel_forced = 1;
 	} else {
 		p2p.reg_class = 81;
 		/*
@@ -3827,6 +3882,7 @@
 		 */
 		os_get_random((u8 *) &r, sizeof(r));
 		p2p.channel = 1 + (r % 3) * 5;
+		p2p.channel_forced = 0;
 	}
 	wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel);
 
@@ -3961,7 +4017,7 @@
  *
  * This function deinitializes the global (per device) P2P module.
  */
-void wpas_p2p_deinit_global(struct wpa_global *global)
+static void wpas_p2p_deinit_global(struct wpa_global *global)
 {
 	struct wpa_supplicant *wpa_s, *tmp;
 
@@ -4095,26 +4151,25 @@
 
 static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
 {
-	int *freqs, res, num, i;
+	int res;
+	unsigned int num, i;
+	struct wpa_used_freq_data *freqs;
 
 	if (wpas_p2p_num_unused_channels(wpa_s) > 0) {
 		/* Multiple channels are supported and not all are in use */
 		return 0;
 	}
 
-	freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+	freqs = os_calloc(wpa_s->num_multichan_concurrent,
+			  sizeof(struct wpa_used_freq_data));
 	if (!freqs)
 		return 1;
 
 	num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
 					wpa_s->num_multichan_concurrent);
-	if (num < 0) {
-		res = 1;
-		goto exit_free;
-	}
 
 	for (i = 0; i < num; i++) {
-		if (freqs[i] == freq) {
+		if (freqs[i].freq == freq) {
 			wpa_printf(MSG_DEBUG, "P2P: Frequency %d MHz in use by another virtual interface and can be used",
 				   freq);
 			res = 0;
@@ -4122,6 +4177,7 @@
 		}
 	}
 
+	wpa_printf(MSG_DEBUG, "P2P: No valid operating frequencies");
 	res = 1;
 
 exit_free:
@@ -4555,18 +4611,28 @@
 static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
 				int *force_freq, int *pref_freq, int go)
 {
-	int *freqs, res;
+	struct wpa_used_freq_data *freqs;
+	int res, best_freq, num_unused;
 	unsigned int freq_in_use = 0, num, i;
 
-	freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+	freqs = os_calloc(wpa_s->num_multichan_concurrent,
+			  sizeof(struct wpa_used_freq_data));
 	if (!freqs)
 		return -1;
 
-	num = get_shared_radio_freqs(wpa_s, freqs,
-				     wpa_s->num_multichan_concurrent);
+	num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
+					wpa_s->num_multichan_concurrent);
+
+	/*
+	 * It is possible that the total number of used frequencies is bigger
+	 * than the number of frequencies used for P2P, so get the system wide
+	 * number of unused frequencies.
+	 */
+	num_unused = wpas_p2p_num_unused_channels(wpa_s);
+
 	wpa_printf(MSG_DEBUG,
-		   "P2P: Setup freqs: freq=%d num_MCC=%d shared_freqs=%u",
-		   freq, wpa_s->num_multichan_concurrent, num);
+		   "P2P: Setup freqs: freq=%d num_MCC=%d shared_freqs=%u num_unused=%d",
+		   freq, wpa_s->num_multichan_concurrent, num, num_unused);
 
 	if (freq > 0) {
 		int ret;
@@ -4583,11 +4649,11 @@
 		}
 
 		for (i = 0; i < num; i++) {
-			if (freqs[i] == freq)
+			if (freqs[i].freq == freq)
 				freq_in_use = 1;
 		}
 
-		if (num == wpa_s->num_multichan_concurrent && !freq_in_use) {
+		if (num_unused <= 0 && !freq_in_use) {
 			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz as there are no available channels",
 				   freq);
 			res = -2;
@@ -4599,34 +4665,28 @@
 		goto exit_ok;
 	}
 
-	for (i = 0; i < num; i++) {
-		if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
-			continue;
+	best_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
 
-		if (*pref_freq == 0 && num < wpa_s->num_multichan_concurrent) {
+	/* We have a candidate frequency to use */
+	if (best_freq > 0) {
+		if (*pref_freq == 0 && num_unused > 0) {
 			wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency (%u MHz) we are already using",
-				   freqs[i]);
-			*pref_freq = freqs[i];
+				   best_freq);
+			*pref_freq = best_freq;
 		} else {
 			wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use",
-				   freqs[i]);
-			*force_freq = freqs[i];
+				   best_freq);
+			*force_freq = best_freq;
 		}
-		break;
-	}
-
-	if (i == num) {
-		if (num < wpa_s->num_multichan_concurrent && num > 0) {
-			wpa_printf(MSG_DEBUG, "P2P: Current operating channels are not available for P2P. Try to use another channel");
-			*force_freq = 0;
-		} else if (num < wpa_s->num_multichan_concurrent) {
-			wpa_printf(MSG_DEBUG, "P2P: No current operating channels - try to use a new channel");
-			*force_freq = 0;
-		} else {
-			wpa_printf(MSG_DEBUG, "P2P: All channels are in use and none of them are P2P enabled. Cannot start P2P group");
-			res = -2;
-			goto exit_free;
-		}
+	} else if (num_unused > 0) {
+		wpa_printf(MSG_DEBUG,
+			   "P2P: Current operating channels are not available for P2P. Try to use another channel");
+		*force_freq = 0;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "P2P: All channels are in use and none of them are P2P enabled. Cannot start P2P group");
+		res = -2;
+		goto exit_free;
 	}
 
 exit_ok:
@@ -4957,13 +5017,46 @@
 }
 
 
+static int wpas_p2p_select_freq_no_pref(struct wpa_supplicant *wpa_s,
+					struct p2p_go_neg_results *params,
+					const struct p2p_channels *channels)
+{
+	unsigned int i, r;
+
+	/* first try some random selection of the social channels */
+	os_get_random((u8 *) &r, sizeof(r));
+
+	for (i = 0; i < 3; i++) {
+		params->freq = 2412 + ((r + i) % 3) * 25;
+		if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+		    freq_included(channels, params->freq))
+			goto out;
+	}
+
+	/* try all channels in reg. class 81 */
+	for (i = 0; i < 11; i++) {
+		params->freq = 2412 + i * 5;
+		if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+		    freq_included(channels, params->freq))
+			goto out;
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel allowed");
+	return -1;
+out:
+	wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference known)",
+		   params->freq);
+	return 0;
+}
+
+
 static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
 				   struct p2p_go_neg_results *params,
 				   int freq, int ht40, int vht,
 				   const struct p2p_channels *channels)
 {
-	int res, *freqs;
-	unsigned int pref_freq;
+	struct wpa_used_freq_data *freqs;
+	unsigned int pref_freq, cand_freq;
 	unsigned int num, i;
 
 	os_memset(params, 0, sizeof(*params));
@@ -5028,58 +5121,59 @@
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz from preferred "
 			   "channels", params->freq);
 	} else {
-		int chan;
-		for (chan = 0; chan < 11; chan++) {
-			params->freq = 2412 + chan * 5;
-			if (!wpas_p2p_disallowed_freq(wpa_s->global,
-						      params->freq) &&
-			    freq_included(channels, params->freq))
-				break;
-		}
-		if (chan == 11) {
-			wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel "
-				   "allowed");
+		/* no preference, select some channel */
+		if (wpas_p2p_select_freq_no_pref(wpa_s, params, channels) < 0)
 			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference "
-			   "known)", params->freq);
 	}
 
-	freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+	freqs = os_calloc(wpa_s->num_multichan_concurrent,
+			  sizeof(struct wpa_used_freq_data));
 	if (!freqs)
 		return -1;
 
-	res = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
+	num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
 					wpa_s->num_multichan_concurrent);
-	if (res < 0) {
-		os_free(freqs);
-		return -1;
-	}
-	num = res;
 
-	for (i = 0; i < num; i++) {
-		if (freq && freqs[i] == freq)
-			break;
-		if (!freq && freq_included(channels, freqs[i])) {
-			wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
-				   freqs[i]);
-			params->freq = freqs[i];
-			break;
+	cand_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
+
+	/* First try the best used frequency if possible */
+	if (!freq && cand_freq > 0 && freq_included(channels, cand_freq)) {
+		params->freq = cand_freq;
+	} else if (!freq) {
+		/* Try any of the used frequencies */
+		for (i = 0; i < num; i++) {
+			if (freq_included(channels, freqs[i].freq)) {
+				wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
+					   freqs[i].freq);
+				params->freq = freqs[i].freq;
+				break;
+			}
 		}
-	}
 
-	if (i == num) {
-		if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
-			if (freq)
-				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
-			else
+		if (i == num) {
+			if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
 				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
-			os_free(freqs);
-			return -1;
-		} else if (num == 0) {
-			wpa_printf(MSG_DEBUG, "P2P: Use one of the free channels");
-		} else {
-			wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
+				os_free(freqs);
+				return -1;
+			} else {
+				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
+			}
+		}
+	} else {
+		for (i = 0; i < num; i++) {
+			if (freqs[i].freq == freq)
+				break;
+		}
+
+		if (i == num) {
+			if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+				if (freq)
+					wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
+				os_free(freqs);
+				return -1;
+			} else {
+				wpa_printf(MSG_DEBUG, "P2P: Use one of the free channels");
+			}
 		}
 	}
 
@@ -5714,7 +5808,7 @@
 }
 
 
-void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s)
 {
 	p2p_group_deinit(wpa_s->p2p_group);
 	wpa_s->p2p_group = NULL;
@@ -6179,10 +6273,13 @@
 		u8 reg_class, channel;
 		int ret;
 		unsigned int r;
+		u8 channel_forced;
+
 		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;
+			channel_forced = 1;
 		} else {
 			reg_class = 81;
 			/*
@@ -6191,8 +6288,10 @@
 			 */
 			os_get_random((u8 *) &r, sizeof(r));
 			channel = 1 + (r % 3) * 5;
+			channel_forced = 0;
 		}
-		ret = p2p_set_listen_channel(p2p, reg_class, channel);
+		ret = p2p_set_listen_channel(p2p, reg_class, channel,
+					     channel_forced);
 		if (ret)
 			wpa_printf(MSG_ERROR, "P2P: Own listen channel update "
 				   "failed: %d", ret);
@@ -7675,3 +7774,80 @@
 }
 
 #endif /* CONFIG_WPS_NFC */
+
+
+static void wpas_p2p_optimize_listen_channel(struct wpa_supplicant *wpa_s,
+					     struct wpa_used_freq_data *freqs,
+					     unsigned int num)
+{
+	u8 curr_chan, cand, chan;
+	unsigned int i;
+
+	curr_chan = p2p_get_listen_channel(wpa_s->global->p2p);
+	for (i = 0, cand = 0; i < num; i++) {
+		ieee80211_freq_to_chan(freqs[i].freq, &chan);
+		if (curr_chan == chan) {
+			cand = 0;
+			break;
+		}
+
+		if (chan == 1 || chan == 6 || chan == 11)
+			cand = chan;
+	}
+
+	if (cand) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"P2P: Update Listen channel to %u baased on operating channel",
+			cand);
+		p2p_set_listen_channel(wpa_s->global->p2p, 81, cand, 0);
+	}
+}
+
+
+void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_used_freq_data *freqs;
+	unsigned int num = wpa_s->num_multichan_concurrent;
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return;
+
+	/*
+	 * If possible, optimize the Listen channel to be a channel that is
+	 * already used by one of the other interfaces.
+	 */
+	if (!wpa_s->conf->p2p_optimize_listen_chan)
+		return;
+
+	if (!wpa_s->current_ssid || wpa_s->wpa_state != WPA_COMPLETED)
+		return;
+
+	freqs = os_calloc(num, sizeof(struct wpa_used_freq_data));
+	if (!freqs)
+		return;
+
+	num = get_shared_radio_freqs_data(wpa_s, freqs, num);
+
+	wpas_p2p_optimize_listen_channel(wpa_s, freqs, num);
+	os_free(freqs);
+}
+
+
+void wpas_p2p_deinit_iface(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s == wpa_s->parent)
+		wpas_p2p_group_remove(wpa_s, "*");
+	if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
+			"the management interface is being removed");
+		wpas_p2p_deinit_global(wpa_s->global);
+	}
+}
+
+
+void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->ap_iface->bss)
+		wpa_s->ap_iface->bss[0]->p2p_group = NULL;
+	wpas_p2p_group_deinit(wpa_s);
+}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 0bf3ca9..cb4bf25 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -16,19 +16,12 @@
 struct p2p_channels;
 struct wps_event_fail;
 
-int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
-void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
-void wpas_p2p_deinit_global(struct wpa_global *global);
 int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s);
 int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		     const char *pin, enum p2p_wps_method wps_method,
 		     int persistent_group, int auto_join, int join,
 		     int auth, int go_intent, int freq, int persistent_id,
 		     int pd, int ht40, int vht);
-void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
-				   unsigned int freq, unsigned int duration);
-void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
-					  unsigned int freq);
 int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
                                           int freq, struct wpa_ssid *ssid);
 int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
@@ -41,8 +34,6 @@
 				  int connection_timeout);
 struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
 				       struct wpa_ssid *ssid);
-void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
-			  int registrar);
 enum wpas_p2p_prov_disc_use {
 	WPAS_P2P_PD_FOR_GO_NEG,
 	WPAS_P2P_PD_FOR_JOIN,
@@ -65,15 +56,7 @@
 int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout);
 int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 			  u8 *buf, size_t len, int p2p_group);
-int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
-			  const u8 *dst, const u8 *bssid,
-			  const u8 *ie, size_t ie_len,
-			  int ssi_signal);
-void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
-			const u8 *sa, const u8 *bssid,
-			u8 category, const u8 *data, size_t len, int freq);
 void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies);
-void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
 void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s);
 u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
 			const struct wpabuf *tlvs);
@@ -101,7 +84,6 @@
 		    int ht40, int vht, int pref_freq);
 int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
 			  const u8 *peer_addr, const u8 *go_dev_addr);
-void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
 int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
 			  u32 interval1, u32 duration2, u32 interval2);
 int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
@@ -112,26 +94,12 @@
 void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
 			     u16 reason_code, const u8 *ie, size_t ie_len,
 			     int locally_generated);
-void wpas_p2p_update_config(struct wpa_supplicant *wpa_s);
 int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
 		     int duration);
 int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled);
-void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s);
-void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s);
-int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s);
-void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s);
 int wpas_p2p_cancel(struct wpa_supplicant *wpa_s);
-void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s);
-void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
-				   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);
-int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s);
-int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s);
-void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
-			      struct wpa_ssid *ssid);
 struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
 					  const u8 *addr, const u8 *ssid,
 					  size_t ssid_len);
@@ -161,9 +129,124 @@
 void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx);
 
 #ifdef CONFIG_P2P
+
+int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
+void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
+void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
+void wpas_p2p_update_config(struct wpa_supplicant *wpa_s);
+int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
+			  const u8 *dst, const u8 *bssid,
+			  const u8 *ie, size_t ie_len,
+			  int ssi_signal);
+void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+			  int registrar);
+void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s);
+void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
+				   int freq_24, int freq_5, int freq_overall);
+void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+			const u8 *sa, const u8 *bssid,
+			u8 category, const u8 *data, size_t len, int freq);
+void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+				   unsigned int freq, unsigned int duration);
+void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+					  unsigned int freq);
+void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s);
+void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s);
+void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s);
+int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s);
 int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s);
 void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s);
+void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s);
+void wpas_p2p_deinit_iface(struct wpa_supplicant *wpa_s);
+void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s);
+void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid);
+int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s);
+int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s);
+void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+			 struct wps_event_fail *fail);
+
 #else /* CONFIG_P2P */
+
+static inline int
+wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s,
+					const u8 *addr,
+					const u8 *dst, const u8 *bssid,
+					const u8 *ie, size_t ie_len,
+					int ssi_signal)
+{
+	return 0;
+}
+
+static inline void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s,
+					const u8 *peer_addr, int registrar)
+{
+}
+
+static inline void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
+						 int freq_24, int freq_5,
+						 int freq_overall)
+{
+}
+
+static inline void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s,
+				      const u8 *da,
+				      const u8 *sa, const u8 *bssid,
+				      u8 category, const u8 *data, size_t len,
+				      int freq)
+{
+}
+
+static inline void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+						 unsigned int freq,
+						 unsigned int duration)
+{
+}
+
+static inline void
+wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+				     unsigned int freq)
+{
+}
+
+static inline void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
 static inline int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
 {
 	return 0;
@@ -172,6 +255,39 @@
 static inline void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s)
 {
 }
+
+static inline void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_deinit_iface(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
+					    struct wpa_ssid *ssid)
+{
+}
+
+static inline int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				       struct wps_event_fail *fail)
+{
+}
+
 #endif /* CONFIG_P2P */
 
 #endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 4d96e82..aaef3c3 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -605,13 +605,11 @@
 		return;
 	}
 
-#ifdef CONFIG_P2P
 	if (wpas_p2p_in_progress(wpa_s)) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
 		wpa_supplicant_req_scan(wpa_s, 5, 0);
 		return;
 	}
-#endif /* CONFIG_P2P */
 
 	if (wpa_s->conf->ap_scan == 2)
 		max_ssids = 1;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index c4d5cb2..28d763c 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -447,9 +447,7 @@
 	wpa_supplicant_ap_deinit(wpa_s);
 #endif /* CONFIG_AP */
 
-#ifdef CONFIG_P2P
 	wpas_p2p_deinit(wpa_s);
-#endif /* CONFIG_P2P */
 
 #ifdef CONFIG_OFFCHANNEL
 	offchannel_deinit(wpa_s);
@@ -705,9 +703,7 @@
 #endif /* IEEE8021X_EAPOL */
 		wpa_s->after_wps = 0;
 		wpa_s->known_wps_freq = 0;
-#ifdef CONFIG_P2P
 		wpas_p2p_completed(wpa_s);
-#endif /* CONFIG_P2P */
 
 		sme_sched_obss_scan(wpa_s, 1);
 	} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
@@ -737,6 +733,12 @@
 	if (wpa_s->wpa_state != old_state) {
 		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
 
+		/*
+		 * Notify the P2P Device interface about a state change in one
+		 * of the interfaces.
+		 */
+		wpas_p2p_indicate_state_change(wpa_s);
+
 		if (wpa_s->wpa_state == WPA_COMPLETED ||
 		    old_state == WPA_COMPLETED)
 			wpas_notify_auth_changed(wpa_s);
@@ -3725,12 +3727,10 @@
 		return -1;
 	}
 
-#ifdef CONFIG_P2P
 	if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
 		wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
 		return -1;
 	}
-#endif /* CONFIG_P2P */
 
 	if (wpa_bss_init(wpa_s) < 0)
 		return -1;
@@ -3781,16 +3781,7 @@
 	}
 
 	wpa_supplicant_cleanup(wpa_s);
-
-#ifdef CONFIG_P2P
-	if (wpa_s == wpa_s->parent)
-		wpas_p2p_group_remove(wpa_s, "*");
-	if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
-			"the management interface is being removed");
-		wpas_p2p_deinit_global(wpa_s->global);
-	}
-#endif /* CONFIG_P2P */
+	wpas_p2p_deinit_iface(wpa_s);
 
 	wpas_ctrl_radio_work_flush(wpa_s);
 	radio_remove_interface(wpa_s);
@@ -4219,11 +4210,7 @@
 #ifdef CONFIG_WPS
 	wpas_wps_update_config(wpa_s);
 #endif /* CONFIG_WPS */
-
-#ifdef CONFIG_P2P
 	wpas_p2p_update_config(wpa_s);
-#endif /* CONFIG_P2P */
-
 	wpa_s->conf->changed_parameters = 0;
 }
 
@@ -4640,24 +4627,30 @@
 }
 
 
-void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title,
-		     int *freq_array, unsigned int len)
+void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
+		    struct wpa_used_freq_data *freqs_data,
+		    unsigned int len)
 {
 	unsigned int i;
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "Shared frequencies (len=%u): %s",
 		len, title);
-	for (i = 0; i < len; i++)
-		wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d", i, freq_array[i]);
+	for (i = 0; i < len; i++) {
+		struct wpa_used_freq_data *cur = &freqs_data[i];
+		wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d, flags=0x%X",
+			i, cur->freq, cur->flags);
+	}
 }
 
 
 /*
  * Find the operating frequencies of any of the virtual interfaces that
- * are using the same radio as the current interface.
+ * are using the same radio as the current interface, and in addition, get
+ * information about the interface types that are using the frequency.
  */
-int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
-			   int *freq_array, unsigned int len)
+int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
+				struct wpa_used_freq_data *freqs_data,
+				unsigned int len)
 {
 	struct wpa_supplicant *ifs;
 	u8 bssid[ETH_ALEN];
@@ -4666,31 +4659,12 @@
 
 	wpa_dbg(wpa_s, MSG_DEBUG,
 		"Determining shared radio frequencies (max len %u)", len);
-	os_memset(freq_array, 0, sizeof(int) * len);
-
-	/* First add the frequency of the local interface */
-	if (wpa_s->current_ssid != NULL && wpa_s->assoc_freq != 0) {
-		if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
-		    wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO)
-			freq_array[idx++] = wpa_s->current_ssid->frequency;
-		else if (wpa_drv_get_bssid(wpa_s, bssid) == 0)
-			freq_array[idx++] = wpa_s->assoc_freq;
-	}
-
-	/* If get_radio_name is not supported, use only the local freq */
-	if (!wpa_driver_get_radio_name(wpa_s)) {
-		freq = wpa_drv_shared_freq(wpa_s);
-		if (freq > 0 && idx < len &&
-		    (idx == 0 || freq_array[0] != freq))
-			freq_array[idx++] = freq;
-		dump_freq_array(wpa_s, "No get_radio_name", freq_array, idx);
-		return idx;
-	}
+	os_memset(freqs_data, 0, sizeof(struct wpa_used_freq_data) * len);
 
 	dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
 			 radio_list) {
-		if (wpa_s == ifs)
-			continue;
+		if (idx == len)
+			break;
 
 		if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
 			continue;
@@ -4705,13 +4679,45 @@
 
 		/* Hold only distinct freqs */
 		for (i = 0; i < idx; i++)
-			if (freq_array[i] == freq)
+			if (freqs_data[i].freq == freq)
 				break;
 
 		if (i == idx)
-			freq_array[idx++] = freq;
+			freqs_data[idx++].freq = freq;
+
+		if (ifs->current_ssid->mode == WPAS_MODE_INFRA) {
+			freqs_data[i].flags = ifs->current_ssid->p2p_group ?
+				WPA_FREQ_USED_BY_P2P_CLIENT :
+				WPA_FREQ_USED_BY_INFRA_STATION;
+		}
 	}
 
-	dump_freq_array(wpa_s, "completed iteration", freq_array, idx);
+	dump_freq_data(wpa_s, "completed iteration", freqs_data, idx);
 	return idx;
 }
+
+
+/*
+ * Find the operating frequencies of any of the virtual interfaces that
+ * are using the same radio as the current interface.
+ */
+int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
+			   int *freq_array, unsigned int len)
+{
+	struct wpa_used_freq_data *freqs_data;
+	int num, i;
+
+	os_memset(freq_array, 0, sizeof(int) * len);
+
+	freqs_data = os_calloc(len, sizeof(struct wpa_used_freq_data));
+	if (!freqs_data)
+		return -1;
+
+	num = get_shared_radio_freqs_data(wpa_s, freqs_data, len);
+	for (i = 0; i < num; i++)
+		freq_array[i] = freqs_data[i].freq;
+
+	os_free(freqs_data);
+
+	return num;
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 56434c4..c51a703 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -365,6 +365,14 @@
 	size_t ssid_len;
 };
 
+#define WPA_FREQ_USED_BY_INFRA_STATION BIT(0)
+#define WPA_FREQ_USED_BY_P2P_CLIENT BIT(1)
+
+struct wpa_used_freq_data {
+	int freq;
+	unsigned int flags;
+};
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -987,8 +995,13 @@
 
 int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
 
-void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title,
-		     int *freq_array, unsigned int len);
+void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
+		    struct wpa_used_freq_data *freqs_data,
+		    unsigned int len);
+
+int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
+				struct wpa_used_freq_data *freqs_data,
+				unsigned int len);
 int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
 			   int *freq_array, unsigned int len);
 
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index de015ee..fd0d14a 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -73,10 +73,8 @@
 
 int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
 {
-#ifdef CONFIG_P2P
 	if (wpas_p2p_wps_eapol_cb(wpa_s) > 0)
 		return 1;
-#endif /* CONFIG_P2P */
 
 	if (!wpa_s->wps_success &&
 	    wpa_s->current_ssid &&
@@ -576,9 +574,7 @@
 	eloop_register_timeout(0, 100000, wpas_wps_clear_timeout, wpa_s, NULL);
 
 	wpas_notify_wps_event_fail(wpa_s, fail);
-#ifdef CONFIG_P2P
 	wpas_p2p_wps_failed(wpa_s, fail);
-#endif /* CONFIG_P2P */
 }
 
 
@@ -637,9 +633,7 @@
 	eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
 			       NULL);
 
-#ifdef CONFIG_P2P
 	wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0);
-#endif /* CONFIG_P2P */
 }