* 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)
+static unsigned int
+wpas_p2p_valid_oper_freqs(struct wpa_supplicant *wpa_s,
+ struct wpa_used_freq_data *p2p_freqs,
+ unsigned int len)
{
- int *freqs;
+ struct wpa_used_freq_data *freqs;
unsigned int num, i, j;
- freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
if (!freqs)
- return -1;
+ return 0;
- num = get_shared_radio_freqs(wpa_s, freqs,
- wpa_s->num_multichan_concurrent);
+ num = get_shared_radio_freqs_data(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
- os_memset(p2p_freqs, 0, sizeof(int) * len);
+ os_memset(p2p_freqs, 0, sizeof(struct wpa_used_freq_data) * len);
for (i = 0, j = 0; i < num && j < len; i++) {
- if (p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
+ if (p2p_supported_freq(wpa_s->global->p2p, freqs[i].freq))
p2p_freqs[j++] = freqs[i];
}
os_free(freqs);
- dump_freq_array(wpa_s, "valid for P2P", p2p_freqs, j);
+ dump_freq_data(wpa_s, "valid for P2P", p2p_freqs, j);
return j;
}
}
+/**
+ * Pick the best frequency to use from all the currently used frequencies.
+ */
+static int wpas_p2p_pick_best_used_freq(struct wpa_supplicant *wpa_s,
+ struct wpa_used_freq_data *freqs,
+ unsigned int num)
+{
+ unsigned int i, c;
+
+ /* find a candidate freq that is supported by P2P */
+ for (c = 0; c < num; c++)
+ if (p2p_supported_freq(wpa_s->global->p2p, freqs[c].freq))
+ break;
+
+ if (c == num)
+ return 0;
+
+ /* once we have a candidate, try to find a 'better' one */
+ for (i = c + 1; i < num; i++) {
+ if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i].freq))
+ continue;
+
+ /*
+ * 1. Infrastructure station interfaces have higher preference.
+ * 2. P2P Clients have higher preference.
+ * 3. All others.
+ */
+ if (freqs[i].flags & WPA_FREQ_USED_BY_INFRA_STATION) {
+ c = i;
+ break;
+ }
+
+ if ((freqs[i].flags & WPA_FREQ_USED_BY_P2P_CLIENT))
+ c = i;
+ }
+ return freqs[c].freq;
+}
+
+
static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
const u8 *go_dev_addr, const u8 *ssid,
size_t ssid_len, int *go, u8 *group_bssid,
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *s;
- int res;
+ struct wpa_used_freq_data *freqs;
struct wpa_supplicant *grp;
+ int best_freq;
if (!persistent_group) {
wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
accept_inv:
wpas_p2p_set_own_freq_preference(wpa_s, 0);
+ best_freq = 0;
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
+ if (freqs) {
+ int num_channels = wpa_s->num_multichan_concurrent;
+ int num = wpas_p2p_valid_oper_freqs(wpa_s, freqs, num_channels);
+ best_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
+ os_free(freqs);
+ }
+
/* Get one of the frequencies currently in use */
- if (wpas_p2p_valid_oper_freqs(wpa_s, &res, 1) > 0) {
+ if (best_freq > 0) {
wpa_printf(MSG_DEBUG, "P2P: Trying to prefer a channel already used by one of the interfaces");
- wpas_p2p_set_own_freq_preference(wpa_s, res);
+ wpas_p2p_set_own_freq_preference(wpa_s, best_freq);
if (wpa_s->num_multichan_concurrent < 2 ||
wpas_p2p_num_unused_channels(wpa_s) < 1) {
wpa_printf(MSG_DEBUG, "P2P: No extra channels available - trying to force channel to match a channel already used by one of the interfaces");
- *force_freq = res;
+ *force_freq = best_freq;
}
}
static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
{
- int *freqs, res, num, i;
+ int res;
+ unsigned int num, i;
+ struct wpa_used_freq_data *freqs;
if (wpas_p2p_num_unused_channels(wpa_s) > 0) {
/* Multiple channels are supported and not all are in use */
return 0;
}
- freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
if (!freqs)
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) {
+ if (freqs[i].freq == freq) {
wpa_printf(MSG_DEBUG, "P2P: Frequency %d MHz in use by another virtual interface and can be used",
freq);
res = 0;
}
}
+ wpa_printf(MSG_DEBUG, "P2P: No valid operating frequencies");
res = 1;
exit_free:
static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
int *force_freq, int *pref_freq, int go)
{
- int *freqs, res;
+ struct wpa_used_freq_data *freqs;
+ int res, best_freq, num_unused;
unsigned int freq_in_use = 0, num, i;
- freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
if (!freqs)
return -1;
- num = get_shared_radio_freqs(wpa_s, freqs,
- wpa_s->num_multichan_concurrent);
+ num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+
+ /*
+ * It is possible that the total number of used frequencies is bigger
+ * than the number of frequencies used for P2P, so get the system wide
+ * number of unused frequencies.
+ */
+ num_unused = wpas_p2p_num_unused_channels(wpa_s);
+
wpa_printf(MSG_DEBUG,
- "P2P: Setup freqs: freq=%d num_MCC=%d shared_freqs=%u",
- freq, wpa_s->num_multichan_concurrent, num);
+ "P2P: Setup freqs: freq=%d num_MCC=%d shared_freqs=%u num_unused=%d",
+ freq, wpa_s->num_multichan_concurrent, num, num_unused);
if (freq > 0) {
int ret;
}
for (i = 0; i < num; i++) {
- if (freqs[i] == freq)
+ if (freqs[i].freq == freq)
freq_in_use = 1;
}
- if (num == wpa_s->num_multichan_concurrent && !freq_in_use) {
+ if (num_unused <= 0 && !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_ok;
}
- for (i = 0; i < num; i++) {
- if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
- continue;
+ best_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
- if (*pref_freq == 0 && num < wpa_s->num_multichan_concurrent) {
+ /* We have a candidate frequency to use */
+ if (best_freq > 0) {
+ if (*pref_freq == 0 && num_unused > 0) {
wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency (%u MHz) we are already using",
- freqs[i]);
- *pref_freq = freqs[i];
+ best_freq);
+ *pref_freq = best_freq;
} else {
wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use",
- freqs[i]);
- *force_freq = freqs[i];
- }
- break;
- }
-
- if (i == num) {
- if (num < wpa_s->num_multichan_concurrent && num > 0) {
- wpa_printf(MSG_DEBUG, "P2P: Current operating channels are not available for P2P. Try to use another channel");
- *force_freq = 0;
- } else if (num < wpa_s->num_multichan_concurrent) {
- wpa_printf(MSG_DEBUG, "P2P: No current operating channels - try to use a new 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;
+ best_freq);
+ *force_freq = best_freq;
}
+ } else if (num_unused > 0) {
+ 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:
int freq, int ht40, int vht,
const struct p2p_channels *channels)
{
- int res, *freqs;
- unsigned int pref_freq;
+ struct wpa_used_freq_data *freqs;
+ unsigned int pref_freq, cand_freq;
unsigned int num, i;
os_memset(params, 0, sizeof(*params));
"known)", params->freq);
}
- freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
if (!freqs)
return -1;
- res = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
+ num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
wpa_s->num_multichan_concurrent);
- if (res < 0) {
- os_free(freqs);
- return -1;
- }
- num = res;
- for (i = 0; i < num; i++) {
- if (freq && freqs[i] == freq)
- break;
- if (!freq && 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;
+ cand_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
+
+ /* First try the best used frequency if possible */
+ if (!freq && cand_freq > 0 && freq_included(channels, cand_freq)) {
+ params->freq = cand_freq;
+ } else if (!freq) {
+ /* Try any of the used frequencies */
+ for (i = 0; i < num; i++) {
+ if (freq_included(channels, freqs[i].freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
+ freqs[i].freq);
+ params->freq = freqs[i].freq;
+ break;
+ }
}
- }
- if (i == num) {
- if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
- if (freq)
- wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
- else
+ if (i == num) {
+ if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
- os_free(freqs);
- return -1;
- } else if (num == 0) {
- wpa_printf(MSG_DEBUG, "P2P: Use one of the free channels");
- } 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 -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 == freq)
+ break;
+ }
+
+ if (i == num) {
+ if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+ if (freq)
+ 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: Use one of the free channels");
+ }
}
}