P2P: Use peer's channel list to limit GO freq on invitation

Peer device includes its list of allowed operating channels in the
Invitation Response frame. When we are becoming the GO, use that list
from the peer to filter out acceptable channels to avoid selecting a
channel that the peer is unable to use.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2013-03-01 14:22:29 +02:00 committed by Jouni Malinen
parent f5877af01e
commit 5473362458
8 changed files with 107 additions and 24 deletions

View File

@ -3373,7 +3373,7 @@ static void p2p_timeout_invite_listen(struct p2p_data *p2p)
"P2P: Invitation Request retry limit reached");
if (p2p->cfg->invitation_result)
p2p->cfg->invitation_result(
p2p->cfg->cb_ctx, -1, NULL);
p2p->cfg->cb_ctx, -1, NULL, NULL);
}
p2p_set_state(p2p, P2P_IDLE);
}

View File

@ -729,6 +729,7 @@ struct p2p_config {
* @ctx: Callback context from cb_ctx
* @status: Negotiation result (Status Code)
* @bssid: P2P Group BSSID or %NULL if not received
* @channels: Available operating channels for the group
*
* This callback is used to indicate result of an Invitation procedure
* started with a call to p2p_invite(). The indicated status code is
@ -736,7 +737,8 @@ struct p2p_config {
* (P2P_SC_SUCCESS) indicating success or -1 to indicate a timeout or a
* local failure in transmitting the Invitation Request.
*/
void (*invitation_result)(void *ctx, int status, const u8 *bssid);
void (*invitation_result)(void *ctx, int status, const u8 *bssid,
const struct p2p_channels *channels);
/**
* go_connected - Check whether we are connected to a GO
@ -1616,6 +1618,9 @@ int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr);
*/
void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled);
int p2p_channels_includes_freq(const struct p2p_channels *channels,
unsigned int freq);
/**
* p2p_supported_freq - Check whether channel is supported for P2P
* @p2p: P2P module context from p2p_init()

View File

@ -409,6 +409,7 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
{
struct p2p_device *dev;
struct p2p_message msg;
struct p2p_channels intersection, *channels = NULL;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Received Invitation Response from " MACSTR,
@ -440,9 +441,32 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
return;
}
if (!msg.channel_list) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Mandatory Channel List attribute missing in "
"Invitation Response from " MACSTR, MAC2STR(sa));
#ifdef CONFIG_P2P_STRICT
p2p_parse_free(&msg);
return;
#endif /* CONFIG_P2P_STRICT */
/* Try to survive without peer channel list */
channels = &p2p->channels;
} else if (p2p_peer_channels_check(p2p, &p2p->channels, dev,
msg.channel_list,
msg.channel_list_len) < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: No common channels found");
p2p_parse_free(&msg);
return;
} else {
p2p_channels_intersect(&p2p->channels, &dev->channels,
&intersection);
channels = &intersection;
}
if (p2p->cfg->invitation_result)
p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
msg.group_bssid);
msg.group_bssid, channels);
p2p_parse_free(&msg);

View File

@ -254,6 +254,23 @@ int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
}
int p2p_channels_includes_freq(const struct p2p_channels *channels,
unsigned int freq)
{
size_t i, j;
for (i = 0; i < channels->reg_classes; i++) {
const struct p2p_reg_class *reg = &channels->reg_class[i];
for (j = 0; j < reg->channels; j++) {
if (p2p_channel_to_freq_j4(reg->reg_class,
reg->channel[j]) ==
(int) freq)
return 1;
}
}
return 0;
}
int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
{
u8 op_reg_class, op_channel;

View File

@ -4067,7 +4067,7 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
return -1;
}
return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40);
return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL);
}

View File

@ -346,7 +346,8 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
if (ssid == NULL || ssid->disabled != 2)
goto inv_args;
if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0)) {
if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0,
NULL)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");

View File

@ -2445,7 +2445,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
if (s) {
int go = s->mode == WPAS_MODE_P2P_GO;
wpas_p2p_group_add_persistent(
wpa_s, s, go, go ? op_freq : 0, 0);
wpa_s, s, go, go ? op_freq : 0, 0, NULL);
} else if (bssid) {
wpa_s->user_initiated_pd = 0;
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
@ -2481,7 +2481,8 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
}
static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
const struct p2p_channels *channels)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid;
@ -2527,7 +2528,7 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
wpas_p2p_group_add_persistent(wpa_s, ssid,
ssid->mode == WPAS_MODE_P2P_GO,
wpa_s->p2p_persistent_go_freq,
wpa_s->p2p_go_ht40);
wpa_s->p2p_go_ht40, channels);
}
@ -3858,9 +3859,18 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
}
static int freq_included(const struct p2p_channels *channels, unsigned int freq)
{
if (channels == NULL)
return 1; /* Assume no restrictions */
return p2p_channels_includes_freq(channels, freq);
}
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int freq, int ht40)
int freq, int ht40,
const struct p2p_channels *channels)
{
u8 bssid[ETH_ALEN];
int res;
@ -3869,42 +3879,54 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
params->role_go = 1;
params->ht40 = ht40;
if (freq) {
if (!freq_included(channels, freq)) {
wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
"accepted", freq);
return -1;
}
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
"frequency %d MHz", freq);
params->freq = freq;
} else if (wpa_s->conf->p2p_oper_reg_class == 81 &&
wpa_s->conf->p2p_oper_channel >= 1 &&
wpa_s->conf->p2p_oper_channel <= 11) {
wpa_s->conf->p2p_oper_channel <= 11 &&
freq_included(channels,
2407 + 5 * wpa_s->conf->p2p_oper_channel)) {
params->freq = 2407 + 5 * wpa_s->conf->p2p_oper_channel;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
"frequency %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
wpa_s->conf->p2p_oper_reg_class == 116 ||
wpa_s->conf->p2p_oper_reg_class == 117 ||
wpa_s->conf->p2p_oper_reg_class == 124 ||
wpa_s->conf->p2p_oper_reg_class == 126 ||
wpa_s->conf->p2p_oper_reg_class == 127) {
} else if ((wpa_s->conf->p2p_oper_reg_class == 115 ||
wpa_s->conf->p2p_oper_reg_class == 116 ||
wpa_s->conf->p2p_oper_reg_class == 117 ||
wpa_s->conf->p2p_oper_reg_class == 124 ||
wpa_s->conf->p2p_oper_reg_class == 126 ||
wpa_s->conf->p2p_oper_reg_class == 127) &&
freq_included(channels,
5000 + 5 * wpa_s->conf->p2p_oper_channel)) {
params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
"frequency %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_overall_freq > 0 &&
p2p_supported_freq(wpa_s->global->p2p,
wpa_s->best_overall_freq)) {
wpa_s->best_overall_freq) &&
freq_included(channels, wpa_s->best_overall_freq)) {
params->freq = wpa_s->best_overall_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
"channel %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_24_freq > 0 &&
p2p_supported_freq(wpa_s->global->p2p,
wpa_s->best_24_freq)) {
wpa_s->best_24_freq) &&
freq_included(channels, wpa_s->best_24_freq)) {
params->freq = wpa_s->best_24_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
"channel %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_5_freq > 0 &&
p2p_supported_freq(wpa_s->global->p2p,
wpa_s->best_5_freq)) {
wpa_s->best_5_freq) &&
freq_included(channels, wpa_s->best_5_freq)) {
params->freq = wpa_s->best_5_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
"channel %d MHz", params->freq);
@ -3913,7 +3935,8 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
for (chan = 0; chan < 11; chan++) {
params->freq = 2412 + chan * 5;
if (!wpas_p2p_disallowed_freq(wpa_s->global,
params->freq))
params->freq) &&
freq_included(channels, params->freq))
break;
}
if (chan == 11) {
@ -3930,6 +3953,11 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
"already using");
params->freq = wpa_s->assoc_freq;
if (!freq_included(channels, params->freq)) {
wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
"accepted", params->freq);
return -1;
}
}
res = wpa_drv_shared_freq(wpa_s);
@ -3937,6 +3965,11 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
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)) {
@ -4050,7 +4083,7 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
return -1;
}
if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40))
if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, NULL))
return -1;
if (params.freq &&
!p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
@ -4117,7 +4150,8 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
int freq, int ht40)
int freq, int ht40,
const struct p2p_channels *channels)
{
struct p2p_go_neg_results params;
int go = 0;
@ -4143,7 +4177,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
if (ssid->mode != WPAS_MODE_P2P_GO)
return -1;
if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40))
if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, channels))
return -1;
params.role_go = 1;

View File

@ -13,6 +13,7 @@ enum p2p_wps_method;
struct p2p_go_neg_results;
enum p2p_send_action_result;
struct p2p_peer_info;
struct p2p_channels;
int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
@ -31,7 +32,8 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int ht40);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
int freq, int ht40);
int freq, int ht40,
const struct p2p_channels *channels);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,