Accumulative patch from commit 77e4e85321a0a1255901914d5de916aba050f9e1

P2P: Mark peer authorized for persistent group invitation
P2P: Indicate frequency for upper layer invitation processing
Allow wpa_supplicant AP mode to configure Beacon interval
P2P: Use peer's channel list to limit GO freq on invitation
P2P: Allow P2P client to specify preferred group channel
P2P: Use shared function for setting up frequencies
P2P: Allow all channels in case of multi channel concurrency
hostapd: Make VHT IE struct more expressive

Change-Id: I6d86d98a10a1a699bb464c5b916ebf21f626558b
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index f6cc5d6..0012c0f 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -38,7 +38,7 @@
 		hapd->iface->current_mode->vht_capab);
 
 	/* Supported MCS set comes from hw */
-	os_memcpy(cap->vht_supported_mcs_set,
+	os_memcpy(&cap->vht_supported_mcs_set,
 	          hapd->iface->current_mode->vht_mcs_set, 8);
 
 	pos += sizeof(*cap);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 6a7fff6..652476f 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -579,7 +579,12 @@
 
 struct ieee80211_vht_capabilities {
 	le32 vht_capabilities_info;
-	u8 vht_supported_mcs_set[8];
+	struct {
+		le16 rx_map;
+		le16 rx_highest;
+		le16 tx_map;
+		le16 tx_highest;
+	} vht_supported_mcs_set;
 } STRUCT_PACKED;
 
 struct ieee80211_vht_operation {
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index ab917dc..704e531 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1326,8 +1326,8 @@
  * may be further optimized in p2p_reselect_channel() once the peer information
  * is available.
  */
-static int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
-			       unsigned int force_freq, unsigned int pref_freq)
+int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
+			unsigned int force_freq, unsigned int pref_freq)
 {
 	if (force_freq || pref_freq) {
 		if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
@@ -3490,7 +3490,7 @@
 				"P2P: Invitation Request retry limit reached");
 			if (p2p->cfg->invitation_result)
 				p2p->cfg->invitation_result(
-					p2p->cfg->cb_ctx, -1, NULL);
+					p2p->cfg->cb_ctx, -1, NULL, NULL);
 		}
 		p2p_set_state(p2p, P2P_IDLE);
 	}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 0663fbb..4f9b75d 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -742,6 +742,7 @@
 	 * @ctx: Callback context from cb_ctx
 	 * @status: Negotiation result (Status Code)
 	 * @bssid: P2P Group BSSID or %NULL if not received
+	 * @channels: Available operating channels for the group
 	 *
 	 * This callback is used to indicate result of an Invitation procedure
 	 * started with a call to p2p_invite(). The indicated status code is
@@ -749,7 +750,8 @@
 	 * (P2P_SC_SUCCESS) indicating success or -1 to indicate a timeout or a
 	 * local failure in transmitting the Invitation Request.
 	 */
-	void (*invitation_result)(void *ctx, int status, const u8 *bssid);
+	void (*invitation_result)(void *ctx, int status, const u8 *bssid,
+				  const struct p2p_channels *channels);
 
 	/**
 	 * go_connected - Check whether we are connected to a GO
@@ -1059,12 +1061,14 @@
  * @force_freq: The only allowed channel frequency in MHz or 0
  * @go_dev_addr: Forced GO Device Address or %NULL if none
  * @persistent_group: Whether this is to reinvoke a persistent group
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ *	force_freq == 0)
  * Returns: 0 on success, -1 on failure
  */
 int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
 	       const u8 *bssid, const u8 *ssid, size_t ssid_len,
 	       unsigned int force_freq, const u8 *go_dev_addr,
-	       int persistent_group);
+	       int persistent_group, unsigned int pref_freq);
 
 /**
  * p2p_presence_req - Request GO presence
@@ -1631,6 +1635,9 @@
  */
 void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled);
 
+int p2p_channels_includes_freq(const struct p2p_channels *channels,
+			       unsigned int freq);
+
 /**
  * p2p_supported_freq - Check whether channel is supported for P2P
  * @p2p: P2P module context from p2p_init()
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index d59a8ac..5286b02 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -92,6 +92,7 @@
 #define P2P_DEV_REPORTED_ONCE BIT(15)
 #define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
 #define P2P_DEV_PD_BEFORE_GO_NEG BIT(17)
+#define P2P_DEV_NO_PREF_CHAN BIT(18)
 	unsigned int flags;
 
 	int status; /* enum p2p_status_code */
@@ -726,5 +727,7 @@
 		    const u8 *src, const u8 *bssid, const u8 *buf,
 		    size_t len, unsigned int wait_time);
 void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
+int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
+			unsigned int force_freq, unsigned int pref_freq);
 
 #endif /* P2P_I_H */
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 9283113..43d9475 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -62,8 +62,11 @@
 					   p2p->client_timeout);
 	p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ?
 				     P2P_INVITATION_FLAGS_TYPE : 0);
-	p2p_buf_add_operating_channel(buf, p2p->cfg->country,
-				      p2p->op_reg_class, p2p->op_channel);
+	if (p2p->inv_role != P2P_INVITE_ROLE_CLIENT ||
+	    !(peer->flags & P2P_DEV_NO_PREF_CHAN))
+		p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+					      p2p->op_reg_class,
+					      p2p->op_channel);
 	if (p2p->inv_bssid_set)
 		p2p_buf_add_group_bssid(buf, p2p->inv_bssid);
 	p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
@@ -406,6 +409,7 @@
 {
 	struct p2p_device *dev;
 	struct p2p_message msg;
+	struct p2p_channels intersection, *channels = NULL;
 
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 		"P2P: Received Invitation Response from " MACSTR,
@@ -437,9 +441,32 @@
 		return;
 	}
 
+	if (!msg.channel_list) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+			"P2P: Mandatory Channel List attribute missing in "
+			"Invitation Response from " MACSTR, MAC2STR(sa));
+#ifdef CONFIG_P2P_STRICT
+		p2p_parse_free(&msg);
+		return;
+#endif /* CONFIG_P2P_STRICT */
+		/* Try to survive without peer channel list */
+		channels = &p2p->channels;
+	} else if (p2p_peer_channels_check(p2p, &p2p->channels, dev,
+					   msg.channel_list,
+					   msg.channel_list_len) < 0) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+			"P2P: No common channels found");
+		p2p_parse_free(&msg);
+		return;
+	} else {
+		p2p_channels_intersect(&p2p->channels, &dev->channels,
+				       &intersection);
+		channels = &intersection;
+	}
+
 	if (p2p->cfg->invitation_result)
 		p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
-					    msg.group_bssid);
+					    msg.group_bssid, channels);
 
 	p2p_parse_free(&msg);
 
@@ -535,7 +562,7 @@
 int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
 	       const u8 *bssid, const u8 *ssid, size_t ssid_len,
 	       unsigned int force_freq, const u8 *go_dev_addr,
-	       int persistent_group)
+	       int persistent_group, unsigned int pref_freq)
 {
 	struct p2p_device *dev;
 
@@ -565,6 +592,15 @@
 		return -1;
 	}
 
+	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+		return -1;
+
+	if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq &&
+	    !pref_freq)
+		dev->flags |= P2P_DEV_NO_PREF_CHAN;
+	else
+		dev->flags &= ~P2P_DEV_NO_PREF_CHAN;
+
 	if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
 		if (!(dev->info.dev_capab &
 		      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
@@ -578,32 +614,6 @@
 
 	dev->invitation_reqs = 0;
 
-	if (force_freq) {
-		if (p2p_freq_to_channel(p2p->cfg->country, force_freq,
-					&p2p->op_reg_class, &p2p->op_channel) <
-		    0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Unsupported frequency %u MHz",
-				force_freq);
-			return -1;
-		}
-#ifdef ANDROID_P2P
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "Single channel list %d", p2p->op_channel);
-#endif
-		p2p->channels.reg_classes = 1;
-		p2p->channels.reg_class[0].channels = 1;
-		p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
-		p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
-	} else {
-#ifdef ANDROID_P2P
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "Full channel list");
-#endif
-		p2p->op_reg_class = p2p->cfg->op_reg_class;
-		p2p->op_channel = p2p->cfg->op_channel;
-		os_memcpy(&p2p->channels, &p2p->cfg->channels,
-			  sizeof(struct p2p_channels));
-	}
-
 	if (p2p->state != P2P_IDLE)
 		p2p_stop_find(p2p);
 
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index bcc690d..37b9361 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -254,6 +254,23 @@
 }
 
 
+int p2p_channels_includes_freq(const struct p2p_channels *channels,
+			       unsigned int freq)
+{
+	size_t i, j;
+	for (i = 0; i < channels->reg_classes; i++) {
+		const struct p2p_reg_class *reg = &channels->reg_class[i];
+		for (j = 0; j < reg->channels; j++) {
+			if (p2p_channel_to_freq_j4(reg->reg_class,
+						   reg->channel[j]) ==
+			    (int) freq)
+				return 1;
+		}
+	}
+	return 0;
+}
+
+
 int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
 {
 	u8 op_reg_class, op_channel;
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index fb99c7b..8447a90 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -365,7 +365,7 @@
 Invitation
 
 p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
-	[go_dev_addr=address] [freq=<freq in MHz>] [ht40]
+	[go_dev_addr=address] [freq=<freq in MHz>] [ht40] [pref=<MHz>]
 
 Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
 persistent group (e.g., persistent=4). If the peer device is the GO of
@@ -374,7 +374,11 @@
 used to override the GO device address for Invitation Request should
 it be not known for some reason (this should not be needed in most
 cases). When reinvoking a persistent group, the GO device can specify
-the frequency for the group with the freq parameter.
+the frequency for the group with the freq parameter. When reinvoking a
+persistent group, the P2P client device can use freq parameter to force
+a specific operating channel (or invitation failure if GO rejects that)
+or pref parameter to request a specific channel (while allowing GO to
+select to use another channel, if needed).
 
 Group Operations
 
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 82b7e19..720ff7b 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -209,6 +209,13 @@
 
 	if (ssid->dtim_period)
 		bss->dtim_period = ssid->dtim_period;
+	else if (wpa_s->conf->dtim_period)
+		bss->dtim_period = wpa_s->conf->dtim_period;
+
+	if (ssid->beacon_int)
+		conf->beacon_int = ssid->beacon_int;
+	else if (wpa_s->conf->beacon_int)
+		conf->beacon_int = wpa_s->conf->beacon_int;
 
 	if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
 		bss->rsn_pairwise = bss->wpa_pairwise;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index ee634a5..91d82ae 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1545,6 +1545,7 @@
 #endif /* CONFIG_HT_OVERRIDES */
 	{ INT(ap_max_inactivity) },
 	{ INT(dtim_period) },
+	{ INT(beacon_int) },
 };
 
 #undef OFFSET
@@ -2991,6 +2992,8 @@
 	{ INT(okc), 0 },
 	{ INT(pmf), 0 },
 	{ FUNC(sae_groups), 0 },
+	{ INT(dtim_period), 0 },
+	{ INT(beacon_int), 0 },
 };
 
 #undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 2b88bb5..2e3e76b 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -817,6 +817,22 @@
 	 * groups will be tried in the indicated order.
 	 */
 	int *sae_groups;
+
+	/**
+	 * dtim_period - Default DTIM period in Beacon intervals
+	 *
+	 * This parameter can be used to set the default value for network
+	 * blocks that do not specify dtim_period.
+	 */
+	int dtim_period;
+
+	/**
+	 * beacon_int - Default Beacon interval in TU
+	 *
+	 * This parameter can be used to set the default value for network
+	 * blocks that do not specify beacon_int.
+	 */
+	int beacon_int;
 };
 
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index f29f7a6..ff99cd7 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -690,6 +690,8 @@
 #ifdef CONFIG_P2P
 	write_p2p_client_list(f, ssid);
 #endif /* CONFIG_P2P */
+	INT(dtim_period);
+	INT(beacon_int);
 
 #undef STR
 #undef INT
@@ -974,6 +976,10 @@
 		fprintf(f, "okc=%d\n", config->okc);
 	if (config->pmf)
 		fprintf(f, "pmf=%d\n", config->pmf);
+	if (config->dtim_period)
+		fprintf(f, "dtim_period=%d\n", config->dtim_period);
+	if (config->beacon_int)
+		fprintf(f, "beacon_int=%d\n", config->beacon_int);
 
 	if (config->sae_groups) {
 		int i;
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index d079863..e225d3f 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -556,6 +556,11 @@
 	int dtim_period;
 
 	/**
+	 * beacon_int - Beacon interval (default: 100 TU)
+	 */
+	int beacon_int;
+
+	/**
 	 * auth_failures - Number of consecutive authentication failures
 	 */
 	unsigned int auth_failures;
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index ea6395e..dec002f 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -3988,7 +3988,7 @@
 	int id;
 	struct wpa_ssid *ssid;
 	u8 *_peer = NULL, peer[ETH_ALEN];
-	int freq = 0;
+	int freq = 0, pref_freq = 0;
 	int ht40;
 
 	id = atoi(cmd);
@@ -4015,9 +4015,17 @@
 			return -1;
 	}
 
+	pos = os_strstr(cmd, " pref=");
+	if (pos) {
+		pos += 6;
+		pref_freq = atoi(pos);
+		if (pref_freq <= 0)
+			return -1;
+	}
+
 	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
 
-	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40);
+	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, pref_freq);
 }
 
 
@@ -4078,7 +4086,7 @@
 		return -1;
 	}
 
-	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40);
+	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL);
 }
 
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 30e0eb3..6ec96df 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -346,7 +346,8 @@
 		if (ssid == NULL || ssid->disabled != 2)
 			goto inv_args;
 
-		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0)) {
+		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0,
+						  NULL)) {
 			reply = wpas_dbus_error_unknown_error(
 				message,
 				"Failed to reinvoke a persistent group");
@@ -630,7 +631,8 @@
 		if (ssid == NULL || ssid->disabled != 2)
 			goto err;
 
-		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0) < 0) {
+		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0) < 0)
+		{
 			reply = wpas_dbus_error_unknown_error(
 				message,
 				"Failed to reinvoke a persistent group");
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 6cff577..0b21700 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -2425,7 +2425,11 @@
 		goto accept_inv;
 	}
 
-	if (!wpa_s->conf->persistent_reconnect)
+	if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
+	    os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Accept previously initiated "
+			   "invitation to re-invoke a persistent group");
+	} else if (!wpa_s->conf->persistent_reconnect)
 		return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
 
 	for (s = wpa_s->conf->ssid; s; s = s->next) {
@@ -2506,7 +2510,7 @@
 		if (s) {
 			int go = s->mode == WPAS_MODE_P2P_GO;
 			wpas_p2p_group_add_persistent(
-				wpa_s, s, go, go ? op_freq : 0, 0);
+				wpa_s, s, go, go ? op_freq : 0, 0, NULL);
 		} else if (bssid) {
 			wpa_s->user_initiated_pd = 0;
 			wpas_p2p_join(wpa_s, bssid, go_dev_addr,
@@ -2537,12 +2541,19 @@
 		return;
 	}
 
-	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa=" MACSTR
-		" persistent=%d", MAC2STR(sa), s->id);
+	if (s->mode == WPAS_MODE_P2P_GO && op_freq) {
+		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa="
+			MACSTR " persistent=%d freq=%d",
+			MAC2STR(sa), s->id, op_freq);
+	} else {
+		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa="
+			MACSTR " persistent=%d", MAC2STR(sa), s->id);
+	}
 }
 
 
-static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
+static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
+				   const struct p2p_channels *channels)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *ssid;
@@ -2560,6 +2571,12 @@
 	if (wpa_s->pending_invite_ssid_id == -1)
 		return; /* Invitation to active group */
 
+	if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
+		wpa_printf(MSG_DEBUG, "P2P: Waiting for peer to start another "
+			   "invitation exchange to indicate readiness for "
+			   "re-invocation");
+	}
+
 	if (status != P2P_SC_SUCCESS) {
 		wpas_p2p_remove_pending_group_interface(wpa_s);
 		return;
@@ -2594,7 +2611,7 @@
 	wpas_p2p_group_add_persistent(wpa_s, ssid,
 				      ssid->mode == WPAS_MODE_P2P_GO,
 				      wpa_s->p2p_persistent_go_freq,
-				      wpa_s->p2p_go_ht40);
+				      wpa_s->p2p_go_ht40, channels);
 }
 
 
@@ -3637,6 +3654,60 @@
 }
 
 
+static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
+				int *force_freq, int *pref_freq,
+				int *oper_freq)
+{
+	if (freq > 0) {
+		if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+			wpa_printf(MSG_DEBUG, "P2P: The forced channel "
+				   "(%u MHz) is not supported for P2P uses",
+				   freq);
+			return -3;
+		}
+
+		if (*oper_freq > 0 && freq != *oper_freq &&
+		    !(wpa_s->drv_flags &
+		      WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+				   "on %u MHz while connected on another "
+				   "channel (%u MHz)", freq, *oper_freq);
+			return -2;
+		}
+		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+			   "requested channel (%u MHz)", freq);
+		*force_freq = freq;
+	} else if (*oper_freq > 0 &&
+		   !p2p_supported_freq(wpa_s->global->p2p, *oper_freq)) {
+		if (!(wpa_s->drv_flags &
+		      WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+				   "while connected on non-P2P supported "
+				   "channel (%u MHz)", *oper_freq);
+			return -2;
+		}
+		wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
+			   "(%u MHz) not available for P2P - try to use "
+			   "another channel", *oper_freq);
+		*force_freq = 0;
+	} else if (*oper_freq > 0 && *pref_freq == 0 &&
+		   (wpa_s->drv_flags &
+		    WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+		wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we "
+			   "are already using (%u MHz) on another interface",
+			   *oper_freq);
+		*pref_freq = *oper_freq;
+	} else if (*oper_freq > 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+			   "channel we are already using (%u MHz) on another "
+			   "interface", *oper_freq);
+		*force_freq = *oper_freq;
+	}
+
+	return 0;
+}
+
+
 /**
  * wpas_p2p_connect - Request P2P Group Formation to be started
  * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
@@ -3667,7 +3738,7 @@
 {
 	int force_freq = 0, pref_freq = 0, oper_freq = 0;
 	u8 bssid[ETH_ALEN];
-	int ret = 0;
+	int ret = 0, res;
 	enum wpa_driver_if_type iftype;
 	const u8 *if_addr;
 	struct wpa_ssid *ssid = NULL;
@@ -3739,59 +3810,18 @@
 	}
 
 	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
-	    wpa_s->assoc_freq)
+	    wpa_s->assoc_freq) {
 		oper_freq = wpa_s->assoc_freq;
-	else {
+	} else {
 		oper_freq = wpa_drv_shared_freq(wpa_s);
 		if (oper_freq < 0)
 			oper_freq = 0;
 	}
 
-	if (freq > 0) {
-		if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
-			wpa_printf(MSG_DEBUG, "P2P: The forced channel "
-				   "(%u MHz) is not supported for P2P uses",
-				   freq);
-			return -3;
-		}
-
-		if (oper_freq > 0 && freq != oper_freq &&
-		    !(wpa_s->drv_flags &
-		      WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
-			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
-				   "on %u MHz while connected on another "
-				   "channel (%u MHz)", freq, oper_freq);
-			return -2;
-		}
-		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
-			   "requested channel (%u MHz)", freq);
-		force_freq = freq;
-	} else if (oper_freq > 0 &&
-		   !p2p_supported_freq(wpa_s->global->p2p, oper_freq)) {
-		if (!(wpa_s->drv_flags &
-		      WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
-			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
-				   "while connected on non-P2P supported "
-				   "channel (%u MHz)", oper_freq);
-			return -2;
-		}
-		wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
-			   "(%u MHz) not available for P2P - try to use "
-			   "another channel", oper_freq);
-		force_freq = 0;
-	} else if (oper_freq > 0 &&
-		   (wpa_s->drv_flags &
-		    WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
-		wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we "
-			   "are already using (%u MHz) on another interface",
-			   oper_freq);
-		pref_freq = oper_freq;
-	} else if (oper_freq > 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
-			   "channel we are already using (%u MHz) on another "
-			   "interface", oper_freq);
-		force_freq = oper_freq;
-	}
+	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+				   &oper_freq);
+	if (res)
+		return res;
 
 	wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
 
@@ -3933,9 +3963,18 @@
 }
 
 
+static int freq_included(const struct p2p_channels *channels, unsigned int freq)
+{
+	if (channels == NULL)
+		return 1; /* Assume no restrictions */
+	return p2p_channels_includes_freq(channels, freq);
+}
+
+
 static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
 				   struct p2p_go_neg_results *params,
-				   int freq, int ht40)
+				   int freq, int ht40,
+				   const struct p2p_channels *channels)
 {
 	u8 bssid[ETH_ALEN];
 	int res;
@@ -3944,42 +3983,54 @@
 	params->role_go = 1;
 	params->ht40 = ht40;
 	if (freq) {
+		if (!freq_included(channels, freq)) {
+			wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+				   "accepted", freq);
+			return -1;
+		}
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
 			   "frequency %d MHz", freq);
 		params->freq = freq;
 	} else if (wpa_s->conf->p2p_oper_reg_class == 81 &&
 		   wpa_s->conf->p2p_oper_channel >= 1 &&
-		   wpa_s->conf->p2p_oper_channel <= 11) {
+		   wpa_s->conf->p2p_oper_channel <= 11 &&
+		   freq_included(channels,
+				 2407 + 5 * wpa_s->conf->p2p_oper_channel)) {
 		params->freq = 2407 + 5 * wpa_s->conf->p2p_oper_channel;
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
 			   "frequency %d MHz", params->freq);
-	} else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
-		   wpa_s->conf->p2p_oper_reg_class == 116 ||
-		   wpa_s->conf->p2p_oper_reg_class == 117 ||
-		   wpa_s->conf->p2p_oper_reg_class == 124 ||
-		   wpa_s->conf->p2p_oper_reg_class == 126 ||
-		   wpa_s->conf->p2p_oper_reg_class == 127) {
+	} else if ((wpa_s->conf->p2p_oper_reg_class == 115 ||
+		    wpa_s->conf->p2p_oper_reg_class == 116 ||
+		    wpa_s->conf->p2p_oper_reg_class == 117 ||
+		    wpa_s->conf->p2p_oper_reg_class == 124 ||
+		    wpa_s->conf->p2p_oper_reg_class == 126 ||
+		    wpa_s->conf->p2p_oper_reg_class == 127) &&
+		   freq_included(channels,
+				 5000 + 5 * wpa_s->conf->p2p_oper_channel)) {
 		params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel;
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
 			   "frequency %d MHz", params->freq);
 	} else if (wpa_s->conf->p2p_oper_channel == 0 &&
 		   wpa_s->best_overall_freq > 0 &&
 		   p2p_supported_freq(wpa_s->global->p2p,
-				      wpa_s->best_overall_freq)) {
+				      wpa_s->best_overall_freq) &&
+		   freq_included(channels, wpa_s->best_overall_freq)) {
 		params->freq = wpa_s->best_overall_freq;
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
 			   "channel %d MHz", params->freq);
 	} else if (wpa_s->conf->p2p_oper_channel == 0 &&
 		   wpa_s->best_24_freq > 0 &&
 		   p2p_supported_freq(wpa_s->global->p2p,
-				      wpa_s->best_24_freq)) {
+				      wpa_s->best_24_freq) &&
+		   freq_included(channels, wpa_s->best_24_freq)) {
 		params->freq = wpa_s->best_24_freq;
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
 			   "channel %d MHz", params->freq);
 	} else if (wpa_s->conf->p2p_oper_channel == 0 &&
 		   wpa_s->best_5_freq > 0 &&
 		   p2p_supported_freq(wpa_s->global->p2p,
-				      wpa_s->best_5_freq)) {
+				      wpa_s->best_5_freq) &&
+		   freq_included(channels, wpa_s->best_5_freq)) {
 		params->freq = wpa_s->best_5_freq;
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
 			   "channel %d MHz", params->freq);
@@ -3988,7 +4039,8 @@
 		for (chan = 0; chan < 11; chan++) {
 			params->freq = 2412 + chan * 5;
 			if (!wpas_p2p_disallowed_freq(wpa_s->global,
-						      params->freq))
+						      params->freq) &&
+			    freq_included(channels, params->freq))
 				break;
 		}
 		if (chan == 11) {
@@ -4005,6 +4057,11 @@
 		wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
 			   "already using");
 		params->freq = wpa_s->assoc_freq;
+		if (!freq_included(channels, params->freq)) {
+			wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+				   "accepted", params->freq);
+			return -1;
+		}
 	}
 
 	res = wpa_drv_shared_freq(wpa_s);
@@ -4012,6 +4069,11 @@
 		wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
 			   "already using on a shared interface");
 		params->freq = res;
+		if (!freq_included(channels, params->freq)) {
+			wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+				   "accepted", params->freq);
+			return -1;
+		}
 	} else if (res > 0 && freq != res &&
 		   !(wpa_s->drv_flags &
 		     WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
@@ -4125,7 +4187,7 @@
 		return -1;
 	}
 
-	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40))
+	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, NULL))
 		return -1;
 	if (params.freq &&
 	    !p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
@@ -4192,7 +4254,8 @@
 
 int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid, int addr_allocated,
-				  int freq, int ht40)
+				  int freq, int ht40,
+				  const struct p2p_channels *channels)
 {
 	struct p2p_go_neg_results params;
 	int go = 0;
@@ -4218,7 +4281,7 @@
 	if (ssid->mode != WPAS_MODE_P2P_GO)
 		return -1;
 
-	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40))
+	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, channels))
 		return -1;
 
 	params.role_go = 1;
@@ -4658,13 +4721,17 @@
 /* Invite to reinvoke a persistent group */
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
-		    int ht40)
+		    int ht40, int pref_freq)
 {
 	enum p2p_invite_role role;
-	u8 *bssid = NULL;
-#ifdef ANDROID_P2P
+	u8 *bssid = NULL, bssid_buf[ETH_ALEN];
 	int force_freq = 0, oper_freq = 0;
-#endif
+	int res;
+
+	if (peer_addr)
+		os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
+	else
+		os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
 
 	wpa_s->p2p_persistent_go_freq = freq;
 	wpa_s->p2p_go_ht40 = !!ht40;
@@ -4692,55 +4759,22 @@
 	}
 	wpa_s->pending_invite_ssid_id = ssid->id;
 
-#ifdef ANDROID_P2P
-	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
-	    wpa_s->assoc_freq)
+	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid_buf) == 0 &&
+	    wpa_s->assoc_freq) {
 		oper_freq = wpa_s->assoc_freq;
-	else {
+		if (bssid == NULL)
+			bssid = bssid_buf;
+	} else {
 		oper_freq = wpa_drv_shared_freq(wpa_s);
 		if (oper_freq < 0)
 			oper_freq = 0;
 	}
 
-	if (freq > 0) {
-		if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
-			wpa_printf(MSG_DEBUG, "P2P: The forced channel "
-				   "(%u MHz) is not supported for P2P uses",
-				   freq);
-			return -3;
-		}
+	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+				   &oper_freq);
+	if (res)
+		return res;
 
-		if (oper_freq > 0 && freq != oper_freq &&
-		    !(wpa_s->drv_flags &
-		      WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
-			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
-				   "on %u MHz while connected on another "
-				   "channel (%u MHz)", freq, oper_freq);
-			return -2;
-		}
-		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
-			   "requested channel (%u MHz)", freq);
-		force_freq = freq;
-	} else if (oper_freq > 0 &&
-		   !p2p_supported_freq(wpa_s->global->p2p, oper_freq)) {
-		if (!(wpa_s->drv_flags &
-		      WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
-			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
-				   "while connected on non-P2P supported "
-				   "channel (%u MHz)", oper_freq);
-			return -2;
-		}
-		wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
-			   "(%u MHz) not available for P2P - try to use "
-			   "another channel", oper_freq);
-		force_freq = 0;
-	} else if (oper_freq > 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
-			   "channel we are already using (%u MHz) on another "
-			   "interface", oper_freq);
-		force_freq = oper_freq;
-	}
-#endif
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
 		return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
 					  ssid->ssid, ssid->ssid_len,
@@ -4749,13 +4783,9 @@
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
-#ifdef ANDROID_P2P
 	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
-			  ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr, 1);
-#else
-	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
-			  ssid->ssid, ssid->ssid_len, freq, go_dev_addr, 1);
-#endif
+			  ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
+			  1, pref_freq);
 }
 
 
@@ -4765,9 +4795,11 @@
 {
 	struct wpa_global *global = wpa_s->global;
 	enum p2p_invite_role role;
-	u8 *bssid = NULL;
+	u8 *bssid = NULL, bssid_buf[ETH_ALEN];
 	struct wpa_ssid *ssid;
 	int persistent;
+	int force_freq = 0, oper_freq = 0, pref_freq = 0;
+	int res;
 
 	wpa_s->p2p_persistent_go_freq = 0;
 	wpa_s->p2p_go_ht40 = 0;
@@ -4819,9 +4851,25 @@
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
+	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid_buf) == 0 &&
+	    wpa_s->assoc_freq) {
+		oper_freq = wpa_s->assoc_freq;
+		if (bssid == NULL)
+			bssid = bssid_buf;
+	} else {
+		oper_freq = wpa_drv_shared_freq(wpa_s);
+		if (oper_freq < 0)
+			oper_freq = 0;
+	}
+
+	res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq,
+				   &oper_freq);
+	if (res)
+		return res;
+
 	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
-			  ssid->ssid, ssid->ssid_len, wpa_s->assoc_freq,
-			  go_dev_addr, persistent);
+			  ssid->ssid, ssid->ssid_len, force_freq,
+			  go_dev_addr, persistent, pref_freq);
 }
 
 
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index a27c1b6..7690e56 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -13,6 +13,7 @@
 struct p2p_go_neg_results;
 enum p2p_send_action_result;
 struct p2p_peer_info;
+struct p2p_channels;
 
 int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
 void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
@@ -35,7 +36,8 @@
 		       int freq, int ht40);
 int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid, int addr_allocated,
-				  int freq, int ht40);
+				  int freq, int ht40,
+				  const struct p2p_channels *channels);
 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,
@@ -113,7 +115,7 @@
 int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
-		    int ht40);
+		    int ht40, 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);
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 18460b8..c9deb4b 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -289,6 +289,12 @@
 # http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
 #sae_groups=21 20 19 26 25
 
+# Default value for DTIM period (if not overridden in network block)
+#dtim_period=2
+
+# Default value for Beacon interval (if not overridden in network block)
+#beacon_int=100
+
 # Interworking (IEEE 802.11u)
 
 # Enable Interworking
@@ -832,6 +838,9 @@
 # DTIM period in Beacon intervals for AP mode (default: 2)
 #dtim_period=2
 
+# Beacon interval (default: 100 TU)
+#beacon_int=100
+
 # disable_ht: Whether HT (802.11n) should be disabled.
 # 0 = HT enabled (if AP supports it)
 # 1 = HT disabled