Accumulative patch from commit 932659696e2755bb1ecd6a27e1968fd27eef4948

9326596 nl80211: Remove unused WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT
0d08efa P2P: Use the number of concurrent channels in P2P flows
a21816a Use wpa_drv_shared_freq() if get_radio_name() is not supported
53c5dfc Change share_vif_oper_freq() to handle multiple freqs
4752147 nl80211: Report the number of concurrent support channels
d7df0fa Clean up wpa_supplicant_event() with deauth/disassoc helper functions
fd9f170 Remove unnecessary nested ifdef CONFIG_AP
13adc57 IBSS RSN: Add peer restart detection
b21990b nl80211: Register for AUTH frames when joining an IBSS network
c91f796 nl80211: Support not specifying the frame frequency
ec384c5 IBSS RSN: Fix disconnect() with internal SME
ed07764 nl80211: Remove redundant assignment of ifindex
4ed8d95 TDLS: Tear down TDLS using wpas_drv_tlds_oper() if not external
831770b Cancel delayed scheduled scan when wpa_supplicant cleans up
69dd296 WDS: Fix WEP usage with nl80211 wds_sta=1
c8ebeda wpa_supplicant: Add support for VHT BSS membership selector
3f9a813 hostapd: Add a config option to control beaconing
182b2e5 Add missing host_to_le32() for big endian hosts
3f53c00 nl80211: Ignore disconnect event in case of locally generated request

Change-Id: Ia7368e71ae40966a92970ac82b002c09a7971d41
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index f6b881b..a6bd935 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -421,6 +421,7 @@
 
 	wpa_bss_deinit(wpa_s);
 
+	wpa_supplicant_cancel_delayed_sched_scan(wpa_s);
 	wpa_supplicant_cancel_scan(wpa_s);
 	wpa_supplicant_cancel_auth_timeout(wpa_s);
 	eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
@@ -1630,7 +1631,7 @@
 	/* If multichannel concurrency is not supported, check for any frequency
 	 * conflict and take appropriate action.
 	 */
-	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+	if ((wpa_s->num_multichan_concurrent < 2) &&
 		((freq = wpa_drv_shared_freq(wpa_s)) > 0) && (freq != params.freq)) {
 		wpa_printf(MSG_DEBUG, "Shared interface with conflicting frequency found (%d != %d)"
 																, freq, params.freq);
@@ -2985,6 +2986,8 @@
 		wpa_s->extended_capa = capa.extended_capa;
 		wpa_s->extended_capa_mask = capa.extended_capa_mask;
 		wpa_s->extended_capa_len = capa.extended_capa_len;
+		wpa_s->num_multichan_concurrent =
+			capa.num_multichan_concurrent;
 	}
 	if (wpa_s->max_remain_on_chan == 0)
 		wpa_s->max_remain_on_chan = 1000;
@@ -2999,6 +3002,9 @@
 	else
 		iface->p2p_mgmt = 1;
 
+	if (wpa_s->num_multichan_concurrent == 0)
+		wpa_s->num_multichan_concurrent = 1;
+
 	if (wpa_supplicant_driver_init(wpa_s) < 0)
 		return -1;
 
@@ -3957,3 +3963,72 @@
 
 	return 0;
 }
+
+
+/*
+ * 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)
+{
+	const char *rn, *rn2;
+	struct wpa_supplicant *ifs;
+	u8 bssid[ETH_ALEN];
+	int freq;
+	unsigned int idx = 0, i;
+
+	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_s->driver->get_radio_name) {
+		freq = wpa_drv_shared_freq(wpa_s);
+		if (freq > 0 && idx < len &&
+		    (idx == 0 || freq_array[0] != freq))
+			freq_array[idx++] = freq;
+		return idx;
+	}
+
+	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+	if (rn == NULL || rn[0] == '\0')
+		return idx;
+
+	for (ifs = wpa_s->global->ifaces, idx = 0; ifs && idx < len;
+	     ifs = ifs->next) {
+		if (wpa_s == ifs || !ifs->driver->get_radio_name)
+			continue;
+
+		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+		if (!rn2 || os_strcmp(rn, rn2) != 0)
+			continue;
+
+		if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
+			continue;
+
+		if (ifs->current_ssid->mode == WPAS_MODE_AP ||
+		    ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
+			freq = ifs->current_ssid->frequency;
+		else if (wpa_drv_get_bssid(ifs, bssid) == 0)
+			freq = ifs->assoc_freq;
+		else
+			continue;
+
+		/* Hold only distinct freqs */
+		for (i = 0; i < idx; i++)
+			if (freq_array[i] == freq)
+				break;
+
+		if (i == idx)
+			freq_array[idx++] = freq;
+	}
+	return idx;
+}