P2P: Verify local driver preferred frequencies for P2P use cases

Previously the peer operating channel preference was accepted if the
indicated frequency was listed in the local preference list from the
driver. This was assuming that the driver included only channels that
are currently enabled for GO operation. Since that might not be the
case, filter the local preference list by doing an explicit validation
of the indicated channels for P2P support.

This moves the similar validation steps from two other code paths in
p2p_check_pref_chan_recv() and p2p_check_pref_chan_no_recv() into a
common filtering step in p2p_check_pref_chan() for all three cases.

This avoids issues to start the GO in cases where the preferred
frequency list from the driver may include channels that are not
currently enabled for P2P GO use (e.g., 5 GHz band in world roaming
configuration).

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2017-02-16 11:42:47 +02:00 committed by Jouni Malinen
parent 3a7819f0ad
commit 79329ae0aa

View file

@ -567,26 +567,11 @@ static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go,
* also supported by the peer device. * also supported by the peer device.
*/ */
for (i = 0; i < size && !found; i++) { for (i = 0; i < size && !found; i++) {
/* /* Make sure that the common frequency is supported by peer. */
* Make sure that the common frequency is:
* 1. Supported by peer
* 2. Allowed for P2P use.
*/
oper_freq = freq_list[i]; oper_freq = freq_list[i];
if (p2p_freq_to_channel(oper_freq, &op_class, if (p2p_freq_to_channel(oper_freq, &op_class,
&op_channel) < 0) { &op_channel) < 0)
p2p_dbg(p2p, "Unsupported frequency %u MHz", oper_freq); continue; /* cannot happen due to earlier check */
continue;
}
if (!p2p_channels_includes(&p2p->cfg->channels,
op_class, op_channel) &&
(go || !p2p_channels_includes(&p2p->cfg->cli_channels,
op_class, op_channel))) {
p2p_dbg(p2p,
"Freq %u MHz (oper_class %u channel %u) not allowed for P2P",
oper_freq, op_class, op_channel);
break;
}
for (j = 0; j < msg->channel_list_len; j++) { for (j = 0; j < msg->channel_list_len; j++) {
if (op_channel != msg->channel_list[j]) if (op_channel != msg->channel_list[j])
@ -607,8 +592,7 @@ static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go,
oper_freq); oper_freq);
} else { } else {
p2p_dbg(p2p, p2p_dbg(p2p,
"None of our preferred channels are supported by peer!. Use: %d MHz for oper_channel", "None of our preferred channels are supported by peer!");
dev->oper_freq);
} }
} }
@ -634,29 +618,9 @@ static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go,
msg->pref_freq_list[2 * j + 1]); msg->pref_freq_list[2 * j + 1]);
if (freq_list[i] != oper_freq) if (freq_list[i] != oper_freq)
continue; continue;
/*
* Make sure that the found frequency is:
* 1. Supported
* 2. Allowed for P2P use.
*/
if (p2p_freq_to_channel(oper_freq, &op_class, if (p2p_freq_to_channel(oper_freq, &op_class,
&op_channel) < 0) { &op_channel) < 0)
p2p_dbg(p2p, "Unsupported frequency %u MHz", continue; /* cannot happen */
oper_freq);
continue;
}
if (!p2p_channels_includes(&p2p->cfg->channels,
op_class, op_channel) &&
(go ||
!p2p_channels_includes(&p2p->cfg->cli_channels,
op_class, op_channel))) {
p2p_dbg(p2p,
"Freq %u MHz (oper_class %u channel %u) not allowed for P2P",
oper_freq, op_class, op_channel);
break;
}
p2p->op_reg_class = op_class; p2p->op_reg_class = op_class;
p2p->op_channel = op_channel; p2p->op_channel = op_channel;
os_memcpy(&p2p->channels, &p2p->cfg->channels, os_memcpy(&p2p->channels, &p2p->cfg->channels,
@ -671,9 +635,7 @@ static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go,
"Freq %d MHz is a common preferred channel for both peer and local, use it as operating channel", "Freq %d MHz is a common preferred channel for both peer and local, use it as operating channel",
oper_freq); oper_freq);
} else { } else {
p2p_dbg(p2p, p2p_dbg(p2p, "No common preferred channels found!");
"No common preferred channels found! Use: %d MHz for oper_channel",
dev->oper_freq);
} }
} }
@ -684,6 +646,8 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
unsigned int freq_list[P2P_MAX_PREF_CHANNELS], size; unsigned int freq_list[P2P_MAX_PREF_CHANNELS], size;
unsigned int i; unsigned int i;
u8 op_class, op_channel; u8 op_class, op_channel;
char txt[100], *pos, *end;
int res;
/* /*
* Use the preferred channel list from the driver only if there is no * Use the preferred channel list from the driver only if there is no
@ -699,6 +663,39 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, &size, if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, &size,
freq_list)) freq_list))
return; return;
/* Filter out frequencies that are not acceptable for P2P use */
i = 0;
while (i < size) {
if (p2p_freq_to_channel(freq_list[i], &op_class,
&op_channel) < 0 ||
(!p2p_channels_includes(&p2p->cfg->channels,
op_class, op_channel) &&
(go || !p2p_channels_includes(&p2p->cfg->cli_channels,
op_class, op_channel)))) {
p2p_dbg(p2p,
"Ignore local driver frequency preference %u MHz since it is not acceptable for P2P use (go=%d)",
freq_list[i], go);
if (size - i - 1 > 0)
os_memmove(&freq_list[i], &freq_list[i + 1], size - i - 1);
size--;
continue;
}
/* Preferred frequency is acceptable for P2P use */
i++;
}
pos = txt;
end = pos + sizeof(txt);
for (i = 0; i < size; i++) {
res = os_snprintf(pos, end - pos, " %u", freq_list[i]);
if (os_snprintf_error(end - pos, res))
break;
pos += res;
}
*pos = '\0';
p2p_dbg(p2p, "Local driver frequency preference (size=%u):%s",
size, txt);
/* /*
* Check if peer's preference of operating channel is in * Check if peer's preference of operating channel is in
@ -708,20 +705,14 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
if (freq_list[i] == (unsigned int) dev->oper_freq) if (freq_list[i] == (unsigned int) dev->oper_freq)
break; break;
} }
if (i != size) { if (i != size &&
p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) == 0) {
/* Peer operating channel preference matches our preference */ /* Peer operating channel preference matches our preference */
if (p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) < p2p->op_reg_class = op_class;
0) { p2p->op_channel = op_channel;
p2p_dbg(p2p, os_memcpy(&p2p->channels, &p2p->cfg->channels,
"Peer operating channel preference is unsupported frequency %u MHz", sizeof(struct p2p_channels));
freq_list[i]); return;
} else {
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
os_memcpy(&p2p->channels, &p2p->cfg->channels,
sizeof(struct p2p_channels));
return;
}
} }
p2p_dbg(p2p, p2p_dbg(p2p,