am af84a575: GC channel fixes for better interop with SCC

* commit 'af84a575044f6556994fcc124a955fc0ac0a6736':
  GC channel fixes for better interop with SCC
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index def422d..66e8456 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -135,6 +135,27 @@
 	wpa_printf(MSG_DEBUG, "P2P: * Channel List");
 }
 
+/* Adds a given channel as the only channel in channel list attribute */
+void p2p_buf_add_oper_as_channel_list(struct wpabuf *buf, const char *country,
+		      u8 reg_class, u8 channel)
+{
+	u8 *len;
+	u8 channel_list[1];
+	channel_list[0] = channel;
+
+	/* Channel List */
+	wpabuf_put_u8(buf, P2P_ATTR_CHANNEL_LIST);
+	len = wpabuf_put(buf, 2); /* IE length to be filled */
+	wpabuf_put_data(buf, country, 3); /* Country String */
+
+	wpabuf_put_u8(buf, reg_class);
+	wpabuf_put_u8(buf, 1);
+	wpabuf_put_data(buf, channel_list, 1);
+
+	/* Update attribute length */
+	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+	wpa_printf(MSG_DEBUG, "P2P: * Oper as Channel List %u", channel);
+}
 
 void p2p_buf_add_status(struct wpabuf *buf, u8 status)
 {
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 031b3a1..0324fe5 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -174,7 +174,13 @@
 		p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period,
 					      p2p->ext_listen_interval);
 	p2p_buf_add_intended_addr(buf, p2p->intended_addr);
-	p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
+	if (p2p->cfg->p2p_concurrency == P2P_SINGLE_CHANNEL_CONCURRENT && p2p->op_channel) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Force channel list %d", p2p->op_channel);
+		p2p_buf_add_oper_as_channel_list(buf, p2p->cfg->country, p2p->op_reg_class,
+				p2p->op_channel);
+	} else {
+		p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
+	}
 	p2p_buf_add_device_info(buf, p2p, peer);
 	p2p_buf_add_operating_channel(buf, p2p->cfg->country,
 				      p2p->op_reg_class, p2p->op_channel);
@@ -294,26 +300,40 @@
 	p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
 	p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
 	if (peer && peer->go_state == REMOTE_GO) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Omit Operating "
-			"Channel attribute");
+		if (p2p->cfg->p2p_concurrency == P2P_SINGLE_CHANNEL_CONCURRENT && p2p->op_channel) {
+			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Forcing a channel ");
+			p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+				p2p->op_reg_class, p2p->op_channel);
+		} else {
+			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Omit Operating "
+				"Channel attribute");
+		}
 	} else {
 		p2p_buf_add_operating_channel(buf, p2p->cfg->country,
 					      p2p->op_reg_class,
 					      p2p->op_channel);
 	}
 	p2p_buf_add_intended_addr(buf, p2p->intended_addr);
-	if (status || peer == NULL) {
-		p2p_buf_add_channel_list(buf, p2p->cfg->country,
-					 &p2p->channels);
-	} else if (peer->go_state == REMOTE_GO) {
-		p2p_buf_add_channel_list(buf, p2p->cfg->country,
-					 &p2p->channels);
+
+	if (p2p->cfg->p2p_concurrency == P2P_SINGLE_CHANNEL_CONCURRENT && p2p->op_channel) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Force channel list %d", p2p->op_channel);
+		p2p_buf_add_oper_as_channel_list(buf, p2p->cfg->country, p2p->op_reg_class,
+				p2p->op_channel);
 	} else {
-		struct p2p_channels res;
-		p2p_channels_intersect(&p2p->channels, &peer->channels,
-				       &res);
-		p2p_buf_add_channel_list(buf, p2p->cfg->country, &res);
+		if (status || peer == NULL) {
+			p2p_buf_add_channel_list(buf, p2p->cfg->country,
+						 &p2p->channels);
+		} else if (peer->go_state == REMOTE_GO) {
+			p2p_buf_add_channel_list(buf, p2p->cfg->country,
+						 &p2p->channels);
+		} else {
+			struct p2p_channels res;
+			p2p_channels_intersect(&p2p->channels, &peer->channels,
+					       &res);
+			p2p_buf_add_channel_list(buf, p2p->cfg->country, &res);
+		}
 	}
+
 	p2p_buf_add_device_info(buf, p2p, peer);
 	if (peer && peer->go_state == LOCAL_GO) {
 		p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
@@ -1168,6 +1188,16 @@
 #endif /* CONFIG_P2P_STRICT */
 	}
 
+	if (msg.operating_channel) {
+		dev->oper_freq = p2p_channel_to_freq((const char *)
+						     msg.operating_channel,
+						     msg.operating_channel[3],
+						     msg.operating_channel[4]);
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
+			"channel preference: %d MHz", dev->oper_freq);
+	} else
+		dev->oper_freq = 0;
+
 	if (!msg.channel_list) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Mandatory Operating Channel attribute missing "
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index d26654b..b237cf8 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -66,7 +66,13 @@
 				      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);
+	if (p2p->cfg->p2p_concurrency == P2P_SINGLE_CHANNEL_CONCURRENT && p2p->op_channel) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "Forcing channel list %d", p2p->op_channel);
+		p2p_buf_add_oper_as_channel_list(buf, p2p->cfg->country, p2p->op_reg_class,
+			p2p->op_channel);
+	} else {
+		p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
+	}
 	if (go_dev_addr)
 		dev_addr = go_dev_addr;
 	else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT)
@@ -133,8 +139,14 @@
 					      reg_class, channel);
 	if (group_bssid)
 		p2p_buf_add_group_bssid(buf, group_bssid);
-	if (channels)
-		p2p_buf_add_channel_list(buf, p2p->cfg->country, channels);
+	if (p2p->cfg->p2p_concurrency == P2P_SINGLE_CHANNEL_CONCURRENT && channel) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "Forcing channel list %d", channel);
+		p2p_buf_add_oper_as_channel_list(buf, p2p->cfg->country,
+			reg_class, channel);
+	} else {
+		if (channels)
+			p2p_buf_add_channel_list(buf, p2p->cfg->country, channels);
+	}
 	p2p_buf_update_ie_hdr(buf, len);
 
 #ifdef CONFIG_WIFI_DISPLAY
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index f8db14e..53b2d5d 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -2807,10 +2807,14 @@
 	p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
 
 #ifdef ANDROID_P2P
-	if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)
+	if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
 		p2p.p2p_concurrency = P2P_MULTI_CHANNEL_CONCURRENT;
-	else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CONCURRENT)
+		wpa_printf(MSG_DEBUG, "P2P: Multi channel concurrency support");
+	} else {
+	// Add support for WPA_DRIVER_FLAGS_P2P_CONCURRENT
 		p2p.p2p_concurrency = P2P_SINGLE_CHANNEL_CONCURRENT;
+		wpa_printf(MSG_DEBUG, "P2P: Single channel concurrency support");
+	}
 #endif
 
 	global->p2p = p2p_init(&p2p);
@@ -4427,6 +4431,7 @@
 {
 	enum p2p_invite_role role;
 	u8 *bssid = NULL;
+	int force_freq = 0, oper_freq = 0;
 
 	wpa_s->p2p_persistent_go_freq = freq;
 	wpa_s->p2p_go_ht40 = !!ht40;
@@ -4454,6 +4459,54 @@
 	}
 	wpa_s->pending_invite_ssid_id = ssid->id;
 
+	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
+	    wpa_s->assoc_freq)
+		oper_freq = wpa_s->assoc_freq;
+	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_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;
+	}
+
 	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,
@@ -4463,7 +4516,7 @@
 		return -1;
 
 	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
-			  ssid->ssid, ssid->ssid_len, freq, go_dev_addr, 1);
+			  ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr, 1);
 }