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,