From 5473362458d503bfbbd7137c4bb068df40e32676 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 1 Mar 2013 14:22:29 +0200 Subject: [PATCH] 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 --- src/p2p/p2p.c | 2 +- src/p2p/p2p.h | 7 ++- src/p2p/p2p_invitation.c | 26 +++++++- src/p2p/p2p_utils.c | 17 +++++ wpa_supplicant/ctrl_iface.c | 2 +- wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 3 +- wpa_supplicant/p2p_supplicant.c | 70 +++++++++++++++------ wpa_supplicant/p2p_supplicant.h | 4 +- 8 files changed, 107 insertions(+), 24 deletions(-) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index ec62836ee..1dbdf6d1c 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -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); } diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 3a724bee3..ae96b6e51 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -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() diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index 9cde8bfae..8b160b047 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -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); diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c index bcc690d84..37b9361aa 100644 --- a/src/p2p/p2p_utils.c +++ b/src/p2p/p2p_utils.c @@ -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; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 0804d7184..e376c9549 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -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); } diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index 6279f415f..6ec96dfe3 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -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"); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 004cf74b3..9cb7af2cc 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -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, ¶ms, freq, ht40)) + if (wpas_p2p_init_go_params(wpa_s, ¶ms, 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, ¶ms, freq, ht40)) + if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40, channels)) return -1; params.role_go = 1; diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index caeac7c16..5f0bfd243 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -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,