]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
P2P: Add option to remove channels from GO use
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 22 Oct 2013 16:45:46 +0000 (19:45 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 26 Oct 2013 14:49:10 +0000 (17:49 +0300)
The new p2p_no_go_freq frequency range list (comma-separated list of
min-max frequency ranges in MHz) can now be used to configure channels
on which the local device is not allowed to operate as a GO, but on
which that device can be a P2P Client. These channels are left in the
P2P Channel List in GO Negotiation to allow the peer device to select
one of the channels for the cases where the peer becomes the GO. The
local end will remove these channels from consideration if it becomes
the GO.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

src/p2p/p2p.c
src/p2p/p2p.h
src/p2p/p2p_go_neg.c
src/p2p/p2p_i.h
src/p2p/p2p_utils.c
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/wpa_cli.c

index aa1f29187bec4eb204b6dd29f0e9c89709200008..21d3c7ee0b1ce091e7ff734afb9e2c4f08c41beb 100644 (file)
@@ -1550,8 +1550,15 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
                }
        }
 
+       p2p_channels_dump(p2p, "own channels", &p2p->channels);
+       p2p_channels_dump(p2p, "peer channels", &peer->channels);
        p2p_channels_intersect(&p2p->channels, &peer->channels,
                               &intersection);
+       if (go) {
+               p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq);
+               p2p_channels_dump(p2p, "intersection after no-GO removal",
+                                 &intersection);
+       }
        freqs = 0;
        for (i = 0; i < intersection.reg_classes; i++) {
                struct p2p_reg_class *c = &intersection.reg_class[i];
@@ -2402,6 +2409,7 @@ void p2p_deinit(struct p2p_data *p2p)
        wpabuf_free(p2p->sd_resp);
        os_free(p2p->after_scan_tx);
        p2p_remove_wps_vendor_extensions(p2p);
+       os_free(p2p->no_go_freq.range);
        os_free(p2p);
 }
 
@@ -3933,6 +3941,31 @@ int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
 }
 
 
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+                      const struct wpa_freq_range_list *list)
+{
+       struct wpa_freq_range *tmp;
+
+       if (list == NULL || list->num == 0) {
+               os_free(p2p->no_go_freq.range);
+               p2p->no_go_freq.range = NULL;
+               p2p->no_go_freq.num = 0;
+               return 0;
+       }
+
+       tmp = os_calloc(list->num, sizeof(struct wpa_freq_range));
+       if (tmp == NULL)
+               return -1;
+       os_memcpy(tmp, list->range, list->num * sizeof(struct wpa_freq_range));
+       os_free(p2p->no_go_freq.range);
+       p2p->no_go_freq.range = tmp;
+       p2p->no_go_freq.num = list->num;
+       p2p_dbg(p2p, "Updated no GO chan list");
+
+       return 0;
+}
+
+
 int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
                           u8 *iface_addr)
 {
index 9b6921e556375fd528bb1725a01f8d9b98281aa0..db7ca9d85b08b9d25eb3488dd74dfb87a1120591 100644 (file)
@@ -1648,6 +1648,14 @@ int p2p_channels_includes_freq(const struct p2p_channels *channels,
  */
 int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
 
+/**
+ * p2p_supported_freq_go - Check whether channel is supported for P2P GO operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq);
+
 /**
  * p2p_get_pref_freq - Get channel from preferred channel list
  * @p2p: P2P module context from p2p_init()
@@ -1764,6 +1772,15 @@ int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
 int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
                      const struct p2p_channel *pref_chan);
 
+/**
+ * p2p_set_no_go_freq - Set no GO channel ranges
+ * @p2p: P2P module context from p2p_init()
+ * @list: Channel ranges or %NULL to remove restriction
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+                      const struct wpa_freq_range_list *list);
+
 /**
  * p2p_in_progress - Check whether a P2P operation is progress
  * @p2p: P2P module context from p2p_init()
index 9e9d2eea4709fc5006026ee82b141733d4b161f9..1c0aeb000d4804604833af807c339c901e812213 100644 (file)
@@ -479,6 +479,9 @@ static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
        p2p_channels_dump(p2p, "peer channels", &dev->channels);
        p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection);
        p2p_channels_dump(p2p, "intersection", &intersection);
+       p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq);
+       p2p_channels_dump(p2p, "intersection after no-GO removal",
+                         &intersection);
        if (intersection.reg_classes == 0 ||
            intersection.reg_class[0].channels == 0) {
                *status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
index 3631abd1e14938f43aea94d0209654e44b5e92c2..e5075ae1dc94d1f6a991ee65f2fae2025ee07498 100644 (file)
@@ -316,6 +316,8 @@ struct p2p_data {
         */
        struct p2p_channels channels;
 
+       struct wpa_freq_range_list no_go_freq;
+
        enum p2p_pending_action_state {
                P2P_NO_PENDING_ACTION,
                P2P_PENDING_GO_NEG_REQUEST,
@@ -570,6 +572,8 @@ int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel);
 void p2p_channels_intersect(const struct p2p_channels *a,
                            const struct p2p_channels *b,
                            struct p2p_channels *res);
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+                              const struct wpa_freq_range_list *list);
 int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
                          u8 channel);
 void p2p_channels_dump(struct p2p_data *p2p, const char *title,
index 8489b535c332bc246e955da441ed49aaf66d7bc5..b7bbfcf74989f7d8b85c707b31cb3c2baa8bbdbc 100644 (file)
@@ -204,6 +204,42 @@ void p2p_channels_intersect(const struct p2p_channels *a,
 }
 
 
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+                              const struct wpa_freq_range_list *list)
+{
+       size_t o, c;
+
+       if (list == NULL)
+               return;
+
+       o = 0;
+       while (o < chan->reg_classes) {
+               struct p2p_reg_class *op = &chan->reg_class[o];
+
+               c = 0;
+               while (c < op->channels) {
+                       int freq = p2p_channel_to_freq(op->reg_class,
+                                                      op->channel[c]);
+                       if (freq > 0 && freq_range_list_includes(list, freq)) {
+                               op->channels--;
+                               os_memmove(&op->channel[c],
+                                          &op->channel[c + 1],
+                                          op->channels - c);
+                       } else
+                               c++;
+               }
+
+               if (op->channels == 0) {
+                       chan->reg_classes--;
+                       os_memmove(&chan->reg_class[o], &chan->reg_class[o + 1],
+                                  (chan->reg_classes - o) *
+                                  sizeof(struct p2p_reg_class));
+               } else
+                       o++;
+       }
+}
+
+
 /**
  * p2p_channels_includes - Check whether a channel is included in the list
  * @channels: List of supported channels
@@ -254,6 +290,17 @@ int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
 }
 
 
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq)
+{
+       u8 op_reg_class, op_channel;
+       if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+               return 0;
+       return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+                                    op_channel) &&
+               !freq_range_list_includes(&p2p->no_go_freq, freq);
+}
+
+
 unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
                               const struct p2p_channels *channels)
 {
index 66ee30a3fb9b63d3f0643dc663f48c48e3edd2ef..d9f2bc2688128bd49c7e6455a906ff2b0bfa9376 100644 (file)
@@ -1936,6 +1936,7 @@ void wpa_config_free(struct wpa_config *config)
        os_free(config->p2p_ssid_postfix);
        os_free(config->pssid);
        os_free(config->p2p_pref_chan);
+       os_free(config->p2p_no_go_freq.range);
        os_free(config->autoscan);
        os_free(config->freq_list);
        wpabuf_free(config->wps_nfc_dh_pubkey);
@@ -3079,6 +3080,26 @@ fail:
        wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
        return -1;
 }
+
+
+static int wpa_config_process_p2p_no_go_freq(
+       const struct global_parse_data *data,
+       struct wpa_config *config, int line, const char *pos)
+{
+       int ret;
+
+       ret = freq_range_list_parse(&config->p2p_no_go_freq, pos);
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_no_go_freq", line);
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "P2P: p2p_no_go_freq with %u items",
+                  config->p2p_no_go_freq.num);
+
+       return 0;
+}
+
 #endif /* CONFIG_P2P */
 
 
@@ -3229,6 +3250,7 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
        { INT(p2p_group_idle), 0 },
        { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+       { FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN },
        { INT(p2p_go_ht40), 0 },
        { INT(p2p_disabled), 0 },
        { INT(p2p_no_group_iface), 0 },
index 2e558fdb4bc03fada4dcea2b577589ec54d885bf..de8ba9e0796c6d6e74230de0a709728b03373111 100644 (file)
@@ -605,6 +605,7 @@ struct wpa_config {
        int p2p_intra_bss;
        unsigned int num_p2p_pref_chan;
        struct p2p_channel *p2p_pref_chan;
+       struct wpa_freq_range_list p2p_no_go_freq;
        int p2p_ignore_shared_freq;
 
        struct wpabuf *wps_vendor_ext_m1;
index b8fff70ccddb11fc4be27ee91e54eaaf76064035..75b3022630e800971325413c4f56474f0a42ec64 100644 (file)
@@ -941,6 +941,13 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                }
                fprintf(f, "\n");
        }
+       if (config->p2p_no_go_freq.num) {
+               char *val = freq_range_list_str(&config->p2p_no_go_freq);
+               if (val) {
+                       fprintf(f, "p2p_no_go_freq=%s\n", val);
+                       os_free(val);
+               }
+       }
        if (config->p2p_go_ht40)
                fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
        if (config->p2p_disabled)
index 817232b30425e68ef5769182ed7da1b5d2b42add..8e7a45b2615dcfb6d2b7dddcaee9d943153d2a47 100644 (file)
@@ -3386,6 +3386,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
                        global->p2p, wpa_s->conf->wps_vendor_ext[i]);
        }
 
+       p2p_set_no_go_freq(global->p2p, &wpa_s->conf->p2p_no_go_freq);
+
        return 0;
 }
 
@@ -4313,8 +4315,8 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
                wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
                           "band");
                if (wpa_s->best_24_freq > 0 &&
-                   p2p_supported_freq(wpa_s->global->p2p,
-                                      wpa_s->best_24_freq)) {
+                   p2p_supported_freq_go(wpa_s->global->p2p,
+                                         wpa_s->best_24_freq)) {
                        freq = wpa_s->best_24_freq;
                        wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
                                   "channel: %d MHz", freq);
@@ -4330,7 +4332,7 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
                wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
                           "band");
                if (wpa_s->best_5_freq > 0 &&
-                   p2p_supported_freq(wpa_s->global->p2p,
+                   p2p_supported_freq_go(wpa_s->global->p2p,
                                       wpa_s->best_5_freq)) {
                        freq = wpa_s->best_5_freq;
                        wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
@@ -4338,7 +4340,7 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
                } else {
                        os_get_random((u8 *) &r, sizeof(r));
                        freq = 5180 + (r % 4) * 20;
-                       if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+                       if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
                                wpa_printf(MSG_DEBUG, "P2P: Could not select "
                                           "5 GHz channel for P2P group");
                                return -1;
@@ -4348,7 +4350,7 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
                }
        }
 
-       if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
+       if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
                wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
                           "(%u MHz) is not supported for P2P uses",
                           freq);
@@ -4401,24 +4403,24 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
                           "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) &&
+                  p2p_supported_freq_go(wpa_s->global->p2p,
+                                        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) &&
+                  p2p_supported_freq_go(wpa_s->global->p2p,
+                                        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) &&
+                  p2p_supported_freq_go(wpa_s->global->p2p,
+                                        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 "
@@ -4564,7 +4566,7 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
        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)) {
+           !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) {
                wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
                           "(%u MHz) is not supported for P2P uses",
                           params.freq);
@@ -5605,6 +5607,11 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
                        wpa_printf(MSG_ERROR, "P2P: Preferred channel list "
                                   "update failed");
                }
+
+               if (p2p_set_no_go_freq(p2p, &wpa_s->conf->p2p_no_go_freq) < 0) {
+                       wpa_printf(MSG_ERROR, "P2P: No GO channel list "
+                                  "update failed");
+               }
        }
 }
 
index d793819160569091b59ae0b1c27b95bee304d4ea..9268446faabd43785cf77284ff4c326c3e72fdcb 100644 (file)
@@ -615,6 +615,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
                "p2p_oper_reg_class", "p2p_oper_channel",
                "p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect",
                "p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan",
+               "p2p_no_go_freq",
                "p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface",
                "p2p_ignore_shared_freq", "country", "bss_max_count",
                "bss_expiration_age", "bss_expiration_scan_count",