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/src/p2p/p2p.c b/src/p2p/p2p.c
index 1875ca4..104f77b 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -183,6 +183,14 @@
 	p2p_dbg(p2p, "State %s -> %s",
 		p2p_state_txt(p2p->state), p2p_state_txt(new_state));
 	p2p->state = new_state;
+
+	if (new_state == P2P_IDLE && p2p->pending_channel) {
+		p2p_dbg(p2p, "Apply change in listen channel");
+		p2p->cfg->reg_class = p2p->pending_reg_class;
+		p2p->cfg->channel = p2p->pending_channel;
+		p2p->pending_reg_class = 0;
+		p2p->pending_channel = 0;
+	}
 }
 
 
@@ -3991,20 +3999,43 @@
 }
 
 
-int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel)
+int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
+			   u8 forced)
 {
 	if (p2p_channel_to_freq(reg_class, channel) < 0)
 		return -1;
 
 	p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
 		reg_class, channel);
-	p2p->cfg->reg_class = reg_class;
-	p2p->cfg->channel = channel;
+
+	/*
+	 * Listen channel was set in configuration or set by control interface;
+	 * cannot override it.
+	 */
+	if (p2p->cfg->channel_forced && forced == 0)
+		return -1;
+
+	if (p2p->state == P2P_IDLE) {
+		p2p->cfg->reg_class = reg_class;
+		p2p->cfg->channel = channel;
+		p2p->cfg->channel_forced = forced;
+	} else {
+		p2p_dbg(p2p, "Defer setting listen channel");
+		p2p->pending_reg_class = reg_class;
+		p2p->pending_channel = channel;
+		p2p->pending_channel_forced = forced;
+	}
 
 	return 0;
 }
 
 
+u8 p2p_get_listen_channel(struct p2p_data *p2p)
+{
+	return p2p->cfg->channel;
+}
+
+
 int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
 {
 	p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len));
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index fa8031d..9cf100f 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -267,6 +267,12 @@
 	u8 channel;
 
 	/**
+	 * channel_forced - the listen channel was forced by configuration
+	 *                  or by control interface and cannot be overridden
+	 */
+	u8 channel_forced;
+
+	/**
 	 * Regulatory class for own operational channel
 	 */
 	u8 op_reg_class;
@@ -1669,7 +1675,10 @@
  */
 void p2p_set_managed_oper(struct p2p_data *p2p, int enabled);
 
-int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel);
+int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
+			   u8 forced);
+
+u8 p2p_get_listen_channel(struct p2p_data *p2p);
 
 int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len);
 
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 65ff9ef..39a927a 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -480,6 +480,10 @@
 	unsigned int search_delay;
 	int in_search_delay;
 
+	u8 pending_reg_class;
+	u8 pending_channel;
+	u8 pending_channel_forced;
+
 #ifdef CONFIG_WIFI_DISPLAY
 	struct wpabuf *wfd_ie_beacon;
 	struct wpabuf *wfd_ie_probe_req;
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index ac19064..189300a 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -388,17 +388,19 @@
 			       const struct p2p_channels *channels)
 {
 	unsigned int i;
-	int freq;
+	int freq = 0;
+	const struct p2p_channels *tmpc = channels ?
+		channels : &p2p->cfg->channels;
+
+	if (tmpc == NULL)
+		return 0;
 
 	for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
 		freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class,
 					   p2p->cfg->pref_chan[i].chan);
-		if (freq <= 0)
-			continue;
-		if (!channels || p2p_channels_includes_freq(channels, freq))
+		if (p2p_channels_includes_freq(tmpc, freq))
 			return freq;
 	}
-
 	return 0;
 }