P2P: Add option to allow additional client channels
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 22 Oct 2013 18:00:49 +0000 (21:00 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 26 Oct 2013 14:49:10 +0000 (17:49 +0300)
The new p2p_add_cli_chan=1 configuration parameter can be used to
request passive-scan channels to be included in P2P channel lists for
cases where the local end may become the P2P client in a group. This
allows more options for the peer to use channels, e.g., if the local
device is not aware of its current location and has marked most channels
to require passive scanning.

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_invitation.c
src/p2p/p2p_utils.c
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c
wpa_supplicant/p2p_supplicant.c

index 21d3c7e..84de7af 100644 (file)
@@ -1140,19 +1140,21 @@ void p2p_stop_find(struct p2p_data *p2p)
 
 static int p2p_prepare_channel_pref(struct p2p_data *p2p,
                                    unsigned int force_freq,
-                                   unsigned int pref_freq)
+                                   unsigned int pref_freq, int go)
 {
        u8 op_class, op_channel;
        unsigned int freq = force_freq ? force_freq : pref_freq;
 
-       p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u",
-               force_freq, pref_freq);
+       p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u go=%d",
+               force_freq, pref_freq, go);
        if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) {
                p2p_dbg(p2p, "Unsupported frequency %u MHz", freq);
                return -1;
        }
 
-       if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel)) {
+       if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel) &&
+           (go || !p2p_channels_includes(&p2p->cfg->cli_channels, op_class,
+                                         op_channel))) {
                p2p_dbg(p2p, "Frequency %u MHz (oper_class %u channel %u) not allowed for P2P",
                        freq, op_class, op_channel);
                return -1;
@@ -1226,6 +1228,7 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
  * @dev: Selected peer device
  * @force_freq: Forced frequency in MHz or 0 if not forced
  * @pref_freq: Preferred frequency in MHz or 0 if no preference
+ * @go: Whether the local end will be forced to be GO
  * Returns: 0 on success, -1 on failure (channel not supported for P2P)
  *
  * This function is used to do initial operating channel selection for GO
@@ -1234,16 +1237,25 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
  * is available.
  */
 int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
-                       unsigned int force_freq, unsigned int pref_freq)
+                       unsigned int force_freq, unsigned int pref_freq, int go)
 {
-       p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u",
-               force_freq, pref_freq);
+       p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u go=%d",
+               force_freq, pref_freq, go);
        if (force_freq || pref_freq) {
-               if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
+               if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq, go) <
+                   0)
                        return -1;
        } else {
                p2p_prepare_channel_best(p2p);
        }
+       p2p_channels_dump(p2p, "prepared channels", &p2p->channels);
+       if (go)
+               p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
+       else if (!force_freq)
+               p2p_channels_union(&p2p->channels, &p2p->cfg->cli_channels,
+                                  &p2p->channels);
+       p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels);
+
        p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
                p2p->op_reg_class, p2p->op_channel,
                force_freq ? " (forced)" : "");
@@ -1299,7 +1311,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
                return -1;
        }
 
-       if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+       if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+                               go_intent == 15) < 0)
                return -1;
 
        if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
@@ -1409,7 +1422,8 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
                return -1;
        }
 
-       if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+       if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, go_intent ==
+                               15) < 0)
                return -1;
 
        p2p->ssid_set = 0;
@@ -2373,6 +2387,10 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
        p2p->go_timeout = 100;
        p2p->client_timeout = 20;
 
+       p2p_dbg(p2p, "initialized");
+       p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+       p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
+
        return p2p;
 }
 
@@ -4028,10 +4046,16 @@ void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled)
 }
 
 
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan)
+void p2p_update_channel_list(struct p2p_data *p2p,
+                            const struct p2p_channels *chan,
+                            const struct p2p_channels *cli_chan)
 {
        p2p_dbg(p2p, "Update channel list");
        os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels));
+       p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+       os_memcpy(&p2p->cfg->cli_channels, cli_chan,
+                 sizeof(struct p2p_channels));
+       p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
 }
 
 
index db7ca9d..b9ca5bd 100644 (file)
@@ -287,6 +287,20 @@ struct p2p_config {
        struct p2p_channels channels;
 
        /**
+        * cli_channels - Additional client channels
+        *
+        * This list of channels (if any) will be used when advertising local
+        * channels during GO Negotiation or Invitation for the cases where the
+        * local end may become the client. This may allow the peer to become a
+        * GO on additional channels if it supports these options. The main use
+        * case for this is to include passive-scan channels on devices that may
+        * not know their current location and have configured most channels to
+        * not allow initiation of radition (i.e., another device needs to take
+        * master responsibilities).
+        */
+       struct p2p_channels cli_channels;
+
+       /**
         * num_pref_chan - Number of pref_chan entries
         */
        unsigned int num_pref_chan;
@@ -1657,6 +1671,14 @@ int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
 int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq);
 
 /**
+ * p2p_supported_freq_cli - Check whether channel is supported for P2P client 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_cli(struct p2p_data *p2p, unsigned int freq);
+
+/**
  * p2p_get_pref_freq - Get channel from preferred channel list
  * @p2p: P2P module context from p2p_init()
  * @channels: List of channels
@@ -1665,7 +1687,9 @@ int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq);
 unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
                               const struct p2p_channels *channels);
 
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
+void p2p_update_channel_list(struct p2p_data *p2p,
+                            const struct p2p_channels *chan,
+                            const struct p2p_channels *cli_chan);
 
 /**
  * p2p_set_best_channels - Update best channel information
index 1c0aeb0..55b1ed3 100644 (file)
@@ -473,14 +473,16 @@ void p2p_reselect_channel(struct p2p_data *p2p,
 static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
                                 u8 *status)
 {
-       struct p2p_channels intersection;
+       struct p2p_channels tmp, intersection;
 
        p2p_channels_dump(p2p, "own channels", &p2p->channels);
        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",
+       p2p_channels_intersect(&p2p->channels, &dev->channels, &tmp);
+       p2p_channels_dump(p2p, "intersection", &tmp);
+       p2p_channels_remove_freqs(&tmp, &p2p->no_go_freq);
+       p2p_channels_dump(p2p, "intersection after no-GO removal", &tmp);
+       p2p_channels_intersect(&tmp, &p2p->cfg->channels, &intersection);
+       p2p_channels_dump(p2p, "intersection with local channel list",
                          &intersection);
        if (intersection.reg_classes == 0 ||
            intersection.reg_class[0].channels == 0) {
index e5075ae..bb5dd39 100644 (file)
@@ -572,6 +572,9 @@ 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_union(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,
@@ -730,7 +733,8 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
                    size_t len, unsigned int wait_time);
 void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
 int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
-                       unsigned int force_freq, unsigned int pref_freq);
+                       unsigned int force_freq, unsigned int pref_freq,
+                       int go);
 void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
 PRINTF_FORMAT(2, 3);
 void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
index 4e4593e..203445b 100644 (file)
@@ -548,7 +548,8 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
                return -1;
        }
 
-       if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+       if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+                               role != P2P_INVITE_ROLE_CLIENT) < 0)
                return -1;
 
        if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq &&
index b7bbfcf..94b5d0b 100644 (file)
@@ -204,6 +204,69 @@ void p2p_channels_intersect(const struct p2p_channels *a,
 }
 
 
+static void p2p_op_class_union(struct p2p_reg_class *cl,
+                              const struct p2p_reg_class *b_cl)
+{
+       size_t i, j;
+
+       for (i = 0; i < b_cl->channels; i++) {
+               for (j = 0; j < cl->channels; j++) {
+                       if (b_cl->channel[i] == cl->channel[j])
+                               break;
+               }
+               if (j == cl->channels) {
+                       if (cl->channels == P2P_MAX_REG_CLASS_CHANNELS)
+                               return;
+                       cl->channel[cl->channels++] = b_cl->channel[i];
+               }
+       }
+}
+
+
+/**
+ * p2p_channels_union - Union of channel lists
+ * @a: First set of channels
+ * @b: Second set of channels
+ * @res: Data structure for returning the union of channels
+ */
+void p2p_channels_union(const struct p2p_channels *a,
+                       const struct p2p_channels *b,
+                       struct p2p_channels *res)
+{
+       size_t i, j;
+
+       if (a != res)
+               os_memcpy(res, a, sizeof(*res));
+
+       for (i = 0; i < res->reg_classes; i++) {
+               struct p2p_reg_class *cl = &res->reg_class[i];
+               for (j = 0; j < b->reg_classes; j++) {
+                       const struct p2p_reg_class *b_cl = &b->reg_class[j];
+                       if (cl->reg_class != b_cl->reg_class)
+                               continue;
+                       p2p_op_class_union(cl, b_cl);
+               }
+       }
+
+       for (j = 0; j < b->reg_classes; j++) {
+               const struct p2p_reg_class *b_cl = &b->reg_class[j];
+
+               for (i = 0; i < res->reg_classes; i++) {
+                       struct p2p_reg_class *cl = &res->reg_class[i];
+                       if (cl->reg_class == b_cl->reg_class)
+                               break;
+               }
+
+               if (i == res->reg_classes) {
+                       if (res->reg_classes == P2P_MAX_REG_CLASSES)
+                               return;
+                       os_memcpy(&res->reg_class[res->reg_classes++],
+                                 b_cl, sizeof(struct p2p_reg_class));
+               }
+       }
+}
+
+
 void p2p_channels_remove_freqs(struct p2p_channels *chan,
                               const struct wpa_freq_range_list *list)
 {
@@ -301,6 +364,18 @@ int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq)
 }
 
 
+int p2p_supported_freq_cli(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) ||
+               p2p_channels_includes(&p2p->cfg->cli_channels, op_reg_class,
+                                     op_channel);
+}
+
+
 unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
                               const struct p2p_channels *channels)
 {
index d9f2bc2..0c9e8f0 100644 (file)
@@ -3251,6 +3251,7 @@ static const struct global_parse_data global_fields[] = {
        { 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_RANGE(p2p_add_cli_chan, 0, 1), 0 },
        { INT(p2p_go_ht40), 0 },
        { INT(p2p_disabled), 0 },
        { INT(p2p_no_group_iface), 0 },
index de8ba9e..3400888 100644 (file)
@@ -606,6 +606,7 @@ struct wpa_config {
        unsigned int num_p2p_pref_chan;
        struct p2p_channel *p2p_pref_chan;
        struct wpa_freq_range_list p2p_no_go_freq;
+       int p2p_add_cli_chan;
        int p2p_ignore_shared_freq;
 
        struct wpabuf *wps_vendor_ext_m1;
index 75b3022..27d4846 100644 (file)
@@ -948,6 +948,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                        os_free(val);
                }
        }
+       if (config->p2p_add_cli_chan)
+               fprintf(f, "p2p_add_cli_chan=%d\n", config->p2p_add_cli_chan);
        if (config->p2p_go_ht40)
                fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
        if (config->p2p_disabled)
index 8e7a45b..422de4d 100644 (file)
@@ -2919,10 +2919,13 @@ static void wpas_p2p_add_chan(struct p2p_reg_class *reg, u8 chan)
 
 
 static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
-                                    struct p2p_channels *chan)
+                                    struct p2p_channels *chan,
+                                    struct p2p_channels *cli_chan)
 {
        int i, cla = 0;
 
+       os_memset(cli_chan, 0, sizeof(*cli_chan));
+
        wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
                   "band");
 
@@ -2990,6 +2993,10 @@ static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
 }
 
 
+enum chan_allowed {
+       NOT_ALLOWED, PASSIVE_ONLY, ALLOWED
+};
+
 static int has_channel(struct wpa_global *global,
                       struct hostapd_hw_modes *mode, u8 chan, int *flags)
 {
@@ -2999,21 +3006,25 @@ static int has_channel(struct wpa_global *global,
        freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
                chan * 5;
        if (wpas_p2p_disallowed_freq(global, freq))
-               return 0;
+               return NOT_ALLOWED;
 
        for (i = 0; i < mode->num_channels; i++) {
                if (mode->channels[i].chan == chan) {
                        if (flags)
                                *flags = mode->channels[i].flag;
-                       return !(mode->channels[i].flag &
-                                (HOSTAPD_CHAN_DISABLED |
-                                 HOSTAPD_CHAN_PASSIVE_SCAN |
-                                 HOSTAPD_CHAN_NO_IBSS |
-                                 HOSTAPD_CHAN_RADAR));
+                       if (mode->channels[i].flag &
+                           (HOSTAPD_CHAN_DISABLED |
+                            HOSTAPD_CHAN_RADAR))
+                               return NOT_ALLOWED;
+                       if (mode->channels[i].flag &
+                           (HOSTAPD_CHAN_PASSIVE_SCAN |
+                            HOSTAPD_CHAN_NO_IBSS))
+                               return PASSIVE_ONLY;
+                       return ALLOWED;
                }
        }
 
-       return 0;
+       return NOT_ALLOWED;
 }
 
 
@@ -3042,69 +3053,94 @@ static struct p2p_oper_class_map op_class[] = {
 };
 
 
-static int wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
-                                  struct hostapd_hw_modes *mode,
-                                  u8 channel, u8 bw)
+static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
+                                                struct hostapd_hw_modes *mode,
+                                                u8 channel, u8 bw)
 {
        int flag;
-
-       if (!has_channel(wpa_s->global, mode, channel, &flag))
-               return -1;
-       if (bw == BW40MINUS &&
-           (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
-            !has_channel(wpa_s->global, mode, channel - 4, NULL)))
-               return 0;
-       if (bw == BW40PLUS &&
-           (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
-            !has_channel(wpa_s->global, mode, channel + 4, NULL)))
-               return 0;
-       return 1;
+       enum chan_allowed res, res2;
+
+       res2 = res = has_channel(wpa_s->global, mode, channel, &flag);
+       if (bw == BW40MINUS) {
+               if (!(flag & HOSTAPD_CHAN_HT40MINUS))
+                       return NOT_ALLOWED;
+               res2 = has_channel(wpa_s->global, mode, channel - 4, NULL);
+       } else if (bw == BW40PLUS) {
+               if (!(flag & HOSTAPD_CHAN_HT40PLUS))
+                       return NOT_ALLOWED;
+               res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
+       }
+
+       if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
+               return NOT_ALLOWED;
+       if (res == PASSIVE_ONLY || res2 == PASSIVE_ONLY)
+               return PASSIVE_ONLY;
+       return res;
 }
 
 
 static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
-                                  struct p2p_channels *chan)
+                                  struct p2p_channels *chan,
+                                  struct p2p_channels *cli_chan)
 {
        struct hostapd_hw_modes *mode;
-       int cla, op;
+       int cla, op, cli_cla;
 
        if (wpa_s->hw.modes == NULL) {
                wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
                           "of all supported channels; assume dualband "
                           "support");
-               return wpas_p2p_default_channels(wpa_s, chan);
+               return wpas_p2p_default_channels(wpa_s, chan, cli_chan);
        }
 
-       cla = 0;
+       cla = cli_cla = 0;
 
        for (op = 0; op_class[op].op_class; op++) {
                struct p2p_oper_class_map *o = &op_class[op];
                u8 ch;
-               struct p2p_reg_class *reg = NULL;
+               struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
 
                mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
                if (mode == NULL)
                        continue;
                for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
-                       if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1)
-                               continue;
-                       if (reg == NULL) {
-                               wpa_printf(MSG_DEBUG, "P2P: Add operating "
-                                          "class %u", o->op_class);
-                               reg = &chan->reg_class[cla];
-                               cla++;
-                               reg->reg_class = o->op_class;
+                       enum chan_allowed res;
+                       res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+                       if (res == ALLOWED) {
+                               if (reg == NULL) {
+                                       wpa_printf(MSG_DEBUG, "P2P: Add operating class %u",
+                                                  o->op_class);
+                                       reg = &chan->reg_class[cla];
+                                       cla++;
+                                       reg->reg_class = o->op_class;
+                               }
+                               reg->channel[reg->channels] = ch;
+                               reg->channels++;
+                       } else if (res == PASSIVE_ONLY &&
+                                  wpa_s->conf->p2p_add_cli_chan) {
+                               if (cli_reg == NULL) {
+                                       wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
+                                                  o->op_class);
+                                       cli_reg = &cli_chan->reg_class[cli_cla];
+                                       cli_cla++;
+                                       cli_reg->reg_class = o->op_class;
+                               }
+                               cli_reg->channel[cli_reg->channels] = ch;
+                               cli_reg->channels++;
                        }
-                       reg->channel[reg->channels] = ch;
-                       reg->channels++;
                }
                if (reg) {
                        wpa_hexdump(MSG_DEBUG, "P2P: Channels",
                                    reg->channel, reg->channels);
                }
+               if (cli_reg) {
+                       wpa_hexdump(MSG_DEBUG, "P2P: Channels (client only)",
+                                   cli_reg->channel, cli_reg->channels);
+               }
        }
 
        chan->reg_classes = cla;
+       cli_chan->reg_classes = cli_cla;
 
        return 0;
 }
@@ -3113,7 +3149,8 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
                           struct hostapd_hw_modes *mode, u8 channel)
 {
-       int op, ret;
+       int op;
+       enum chan_allowed ret;
 
        for (op = 0; op_class[op].op_class; op++) {
                struct p2p_oper_class_map *o = &op_class[op];
@@ -3124,12 +3161,8 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
                            o->bw == BW20 || ch != channel)
                                continue;
                        ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
-                       if (ret < 0)
-                               continue;
-                       else if (ret > 0)
+                       if (ret == ALLOWED)
                                return (o->bw == BW40MINUS) ? -1 : 1;
-                       else
-                               return 0;
                }
        }
        return 0;
@@ -3343,7 +3376,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
        } else
                os_memcpy(p2p.country, "XX\x04", 3);
 
-       if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)) {
+       if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
                wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
                           "channel list");
                return -1;
@@ -3974,7 +4007,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
 
 
 static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
-                               int *force_freq, int *pref_freq)
+                               int *force_freq, int *pref_freq, int go)
 {
        int *freqs, res;
        unsigned int freq_in_use = 0, num, i;
@@ -3990,7 +4023,12 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
                   freq, wpa_s->num_multichan_concurrent, num);
 
        if (freq > 0) {
-               if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+               int ret;
+               if (go)
+                       ret = p2p_supported_freq(wpa_s->global->p2p, freq);
+               else
+                       ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq);
+               if (!ret) {
                        wpa_printf(MSG_DEBUG, "P2P: The forced channel "
                                   "(%u MHz) is not supported for P2P uses",
                                   freq);
@@ -4152,7 +4190,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                return ret;
        }
 
-       res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
+       res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+                                  go_intent == 15);
        if (res)
                return res;
        wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
@@ -5166,7 +5205,8 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        }
        wpa_s->pending_invite_ssid_id = ssid->id;
 
-       res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
+       res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+                                  role == P2P_INVITE_ROLE_GO);
        if (res)
                return res;
 
@@ -5250,7 +5290,8 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
 
-       res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
+       res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+                                  role == P2P_INVITE_ROLE_ACTIVE_GO);
        if (res)
                return res;
        wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
@@ -5783,19 +5824,20 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
 
 void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
 {
-       struct p2p_channels chan;
+       struct p2p_channels chan, cli_chan;
 
        if (wpa_s->global == NULL || wpa_s->global->p2p == NULL)
                return;
 
        os_memset(&chan, 0, sizeof(chan));
-       if (wpas_p2p_setup_channels(wpa_s, &chan)) {
+       os_memset(&cli_chan, 0, sizeof(cli_chan));
+       if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan)) {
                wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
                           "channel list");
                return;
        }
 
-       p2p_update_channel_list(wpa_s->global->p2p, &chan);
+       p2p_update_channel_list(wpa_s->global->p2p, &chan, &cli_chan);
 }