]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
P2P: Use peer's channel list to limit GO freq on invitation
authorJouni Malinen <jouni@qca.qualcomm.com>
Fri, 1 Mar 2013 12:22:29 +0000 (14:22 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 1 Mar 2013 18:01:01 +0000 (20:01 +0200)
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>

src/p2p/p2p.c
src/p2p/p2p.h
src/p2p/p2p_invitation.c
src/p2p/p2p_utils.c
wpa_supplicant/ctrl_iface.c
wpa_supplicant/dbus/dbus_new_handlers_p2p.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h

index ec62836eea037fde8c6030f81a18dc72d54a2881..1dbdf6d1c6e7f9d66042849772900aea532e6283 100644 (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);
        }
index 3a724bee3c13c8dc76ed398efc188c11c9c1e873..ae96b6e51d2e15050b060a8a607775516605e680 100644 (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()
index 9cde8bfae3ad54ecf13522b623a901987f1678a3..8b160b04761304cfb85f4c0845268dca6a4d6c6e 100644 (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);
 
index bcc690d8469bbc6ea7708c17b8fddb9d47e5bef0..37b9361aa0af2b4806b42575c40593d61e58f941 100644 (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;
index 0804d7184baad65240760561010e20dcf8f25d1a..e376c9549aaafbffb6408c5d15682b7ce856b57f 100644 (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);
 }
 
 
index 6279f415fab49ec6d230fc237f4d615391bd3aac..6ec96dfe322962c5eb7b022c8109217cfd679148 100644 (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");
index 004cf74b30b7bae8dbbf3be1e71170bc9fd0bc8b..9cb7af2cc45149a605f8e6a3926cde9c0706ae6d 100644 (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;
index caeac7c1614f939a74f7eb02fedf7f62cc87f865..5f0bfd243f457c54813d09a3d5e24e4877b2d6e7 100644 (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,