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/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 37f5ad3..08ae9e5 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -105,13 +105,64 @@
static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
+/*
+ * Get the number of concurrent channels that the HW can operate, but that are
+ * currently not in use by any of the wpa_supplicant interfaces.
+ */
+static int wpas_p2p_num_unused_channels(struct wpa_supplicant *wpa_s)
+{
+ int *freqs;
+ int num;
+
+ freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ if (!freqs)
+ return -1;
+
+ num = get_shared_radio_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+ os_free(freqs);
+
+ return wpa_s->num_multichan_concurrent - num;
+}
+
+
+/*
+ * 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)
+{
+ int *freqs;
+ unsigned int num, i, j;
+
+ freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ if (!freqs)
+ return -1;
+
+ num = get_shared_radio_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+
+ os_memset(p2p_freqs, 0, sizeof(int) * len);
+
+ for (i = 0, j = 0; i < num && j < len; i++) {
+ if (p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
+ p2p_freqs[j++] = freqs[i];
+ }
+
+ os_free(freqs);
+
+ return j;
+}
+
+
static void wpas_p2p_set_own_freq_preference(struct wpa_supplicant *wpa_s,
int freq)
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- if (freq > 0 &&
- (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+ if (freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
+ wpas_p2p_num_unused_channels(wpa_s) > 0 &&
wpa_s->parent->conf->p2p_ignore_shared_freq)
freq = 0;
p2p_set_own_freq_preference(wpa_s->global->p2p, freq);
@@ -2473,7 +2524,6 @@
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *s;
- u8 cur_bssid[ETH_ALEN];
int res;
struct wpa_supplicant *grp;
@@ -2550,25 +2600,15 @@
accept_inv:
wpas_p2p_set_own_freq_preference(wpa_s, 0);
- if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, cur_bssid) == 0 &&
- wpa_s->assoc_freq) {
- wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
- "the channel we are already using");
- *force_freq = wpa_s->assoc_freq;
- wpas_p2p_set_own_freq_preference(wpa_s, wpa_s->assoc_freq);
- }
-
- res = wpa_drv_shared_freq(wpa_s);
- if (res > 0) {
- wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
- "with the channel we are already using on a "
- "shared interface");
+ /* Get one of the frequencies currently in use */
+ if (wpas_p2p_valid_oper_freqs(wpa_s, &res, 1) > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match a channel already used by one of the interfaces");
*force_freq = res;
wpas_p2p_set_own_freq_preference(wpa_s, res);
}
- if (*force_freq > 0 &&
- (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+ if (*force_freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
+ wpas_p2p_num_unused_channels(wpa_s) > 0) {
if (*go == 0) {
/* We are the client */
wpa_printf(MSG_DEBUG, "P2P: Peer was found to be "
@@ -3268,17 +3308,6 @@
p2p.max_listen = wpa_s->max_remain_on_chan;
-#ifdef ANDROID_P2P
- if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
- p2p.p2p_concurrency = P2P_MULTI_CHANNEL_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);
if (global->p2p == NULL)
return -1;
@@ -3475,43 +3504,38 @@
static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
{
- struct wpa_supplicant *iface;
- int shared_freq;
- u8 bssid[ETH_ALEN];
+ int *freqs, res, num, i;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)
+ if (wpas_p2p_num_unused_channels(wpa_s) > 0) {
+ /* Multiple channels are supported and not all are in use */
return 0;
+ }
- for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
- if (!wpas_p2p_create_iface(wpa_s) && iface == wpa_s)
- continue;
- if (iface->current_ssid == NULL || iface->assoc_freq == 0)
- continue;
- if (iface->current_ssid->mode == WPAS_MODE_AP ||
- iface->current_ssid->mode == WPAS_MODE_P2P_GO)
- shared_freq = iface->current_ssid->frequency;
- else if (wpa_drv_get_bssid(iface, bssid) == 0)
- shared_freq = iface->assoc_freq;
- else
- shared_freq = 0;
+ freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ if (!freqs)
+ return 1;
- if (shared_freq && freq != shared_freq) {
- wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - %s "
- "connected on %d MHz - new connection on "
- "%d MHz", iface->ifname, shared_freq, freq);
- 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) {
+ wpa_printf(MSG_DEBUG, "P2P: Frequency %d MHz in use by another virtual interface and can be used",
+ freq);
+ res = 0;
+ goto exit_free;
}
}
- shared_freq = wpa_drv_shared_freq(wpa_s);
- if (shared_freq > 0 && shared_freq != freq) {
- wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - shared "
- "virtual interface connected on %d MHz - new "
- "connection on %d MHz", shared_freq, freq);
- return 1;
- }
+ res = 1;
- return 0;
+exit_free:
+ os_free(freqs);
+ return res;
}
@@ -3891,56 +3915,75 @@
static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
- int *force_freq, int *pref_freq,
- int *oper_freq)
+ int *force_freq, int *pref_freq)
{
+ int *freqs, res;
+ unsigned int freq_in_use = 0, num, i;
+
+ freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ if (!freqs)
+ return -1;
+
+ num = get_shared_radio_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+
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 = -3;
+ goto exit_free;
}
- 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;
+ for (i = 0; i < num; i++) {
+ if (freqs[i] == freq)
+ freq_in_use = 1;
+ }
+
+ if (num == wpa_s->num_multichan_concurrent && !freq_in_use) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz as there are no available channels",
+ freq);
+ res = -2;
+ goto exit_free;
}
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;
+ goto exit_ok;
}
- return 0;
+ for (i = 0; i < num; i++) {
+ if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
+ continue;
+
+ wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use",
+ *force_freq);
+ *force_freq = freqs[i];
+
+ if (*pref_freq == 0 && num < wpa_s->num_multichan_concurrent) {
+ wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency we are already using");
+ *pref_freq = *force_freq;
+ }
+ break;
+ }
+
+ if (i == num) {
+ if (num < wpa_s->num_multichan_concurrent) {
+ 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:
+ res = 0;
+exit_free:
+ os_free(freqs);
+ return res;
}
@@ -3972,8 +4015,7 @@
int go_intent, int freq, int persistent_id, int pd,
int ht40)
{
- int force_freq = 0, pref_freq = 0, oper_freq = 0;
- u8 bssid[ETH_ALEN];
+ int force_freq = 0, pref_freq = 0;
int ret = 0, res;
enum wpa_driver_if_type iftype;
const u8 *if_addr;
@@ -4045,20 +4087,10 @@
return ret;
}
- 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;
- }
-
- res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
- &oper_freq);
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
if (res)
return res;
- wpas_p2p_set_own_freq_preference(wpa_s, oper_freq);
+ wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
@@ -4259,9 +4291,9 @@
int freq, int ht40,
const struct p2p_channels *channels)
{
- u8 bssid[ETH_ALEN];
- int res;
+ int res, *freqs;
unsigned int pref_freq;
+ unsigned int num, i;
os_memset(params, 0, sizeof(*params));
params->role_go = 1;
@@ -4341,64 +4373,54 @@
"known)", params->freq);
}
- if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
- wpa_s->assoc_freq && !freq) {
- if (!p2p_supported_freq(wpa_s->global->p2p, wpa_s->assoc_freq)
- || !freq_included(channels, wpa_s->assoc_freq)) {
- if (wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on "
- "the channel we are already using "
- "(%u MHz) - allow multi-channel "
- "concurrency", wpa_s->assoc_freq);
- } else {
- wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on "
- "the channel we are already using "
- "(%u MHz)", wpa_s->assoc_freq);
- return -1;
- }
- } else {
- wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we "
- "are already using (%u MHz)",
- wpa_s->assoc_freq);
- params->freq = wpa_s->assoc_freq;
- }
- }
+ freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ if (!freqs)
+ return -1;
- res = wpa_drv_shared_freq(wpa_s);
- if (res > 0 && !freq &&
- (!p2p_supported_freq(wpa_s->global->p2p, res) ||
- !freq_included(channels, res))) {
- if (wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on the "
- "channel we are already using on a shared "
- "interface (%u MHz) - allow multi-channel "
- "concurrency", res);
- } else {
- wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on the "
- "channel we are already using on a shared "
- "interface (%u MHz)", res);
- return -1;
- }
- } else if (res > 0 && !freq) {
- 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)) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz "
- "while connected on another channel (%u MHz)",
- freq, res);
+ res = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+ if (res < 0) {
+ os_free(freqs);
return -1;
}
+ num = res;
+ if (!freq) {
+ for (i = 0; i < num; i++) {
+ if (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;
+ }
+ }
+
+ if (i == num) {
+ if (num == wpa_s->num_multichan_concurrent) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
+ 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)
+ break;
+ }
+
+ if (i == num) {
+ if (num == wpa_s->num_multichan_concurrent) {
+ 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: Cannot force GO on any of the channels we are already using. Use one of the free channels");
+ }
+ }
+ }
+ os_free(freqs);
return 0;
}
@@ -5002,8 +5024,8 @@
int ht40, int pref_freq)
{
enum p2p_invite_role role;
- u8 *bssid = NULL, bssid_buf[ETH_ALEN];
- int force_freq = 0, oper_freq = 0;
+ u8 *bssid = NULL;
+ int force_freq = 0;
int res;
wpa_s->global->p2p_invite_group = NULL;
@@ -5038,19 +5060,7 @@
}
wpa_s->pending_invite_ssid_id = ssid->id;
- 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, freq, &force_freq, &pref_freq,
- &oper_freq);
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
if (res)
return res;
@@ -5074,10 +5084,10 @@
{
struct wpa_global *global = wpa_s->global;
enum p2p_invite_role role;
- u8 *bssid = NULL, bssid_buf[ETH_ALEN];
+ u8 *bssid = NULL;
struct wpa_ssid *ssid;
int persistent;
- int force_freq = 0, oper_freq = 0, pref_freq = 0;
+ int force_freq = 0, pref_freq = 0;
int res;
wpa_s->p2p_persistent_go_freq = 0;
@@ -5131,22 +5141,10 @@
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);
+ res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq);
if (res)
return res;
- wpas_p2p_set_own_freq_preference(wpa_s, oper_freq);
+ wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
ssid->ssid, ssid->ssid_len, force_freq,