Patchwork [v3,1/2] P2P: Enable 40MHz support for p2p group addition

login
register
mail settings
Submitter Rajkumar Manoharan
Date July 17, 2012, 10:09 a.m.
Message ID <1342519754-8041-1-git-send-email-rmanohar@qca.qualcomm.com>
Download mbox | patch
Permalink /patch/171370/
State Accepted
Commit 7aeac98509092116085150d76de55c08465ef681
Headers show

Comments

Rajkumar Manoharan - July 17, 2012, 10:09 a.m.
Add optional "ht40" argument for p2p_group_add command to enable 40MHz
in 5GHz band. This could configure secondary channel, when 11n support
was enabled and if the HW supports 40MHz channel width.

Signed-hostap: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
---
 wpa_supplicant/ap.c                         |  12 ++++
 wpa_supplicant/config.h                     |   1 +
 wpa_supplicant/ctrl_iface.c                 |  19 ++++--
 wpa_supplicant/dbus/dbus_new_handlers_p2p.c |   2 +-
 wpa_supplicant/p2p_supplicant.c             | 101 +++++++++++++++++++---------
 wpa_supplicant/p2p_supplicant.h             |   6 +-
 wpa_supplicant/wpa_cli.c                    |  19 +++---
 7 files changed, 107 insertions(+), 53 deletions(-)
Arik Nemtsov - July 18, 2012, 7:37 p.m.
On Tue, Jul 17, 2012 at 1:09 PM, Rajkumar Manoharan
<rmanohar@qca.qualcomm.com> wrote:
> Add optional "ht40" argument for p2p_group_add command to enable 40MHz
> in 5GHz band. This could configure secondary channel, when 11n support
> was enabled and if the HW supports 40MHz channel width.
>
> Signed-hostap: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
> ---
>  wpa_supplicant/ap.c                         |  12 ++++
>  wpa_supplicant/config.h                     |   1 +
>  wpa_supplicant/ctrl_iface.c                 |  19 ++++--
>  wpa_supplicant/dbus/dbus_new_handlers_p2p.c |   2 +-
>  wpa_supplicant/p2p_supplicant.c             | 101 +++++++++++++++++++---------
>  wpa_supplicant/p2p_supplicant.h             |   6 +-
>  wpa_supplicant/wpa_cli.c                    |  19 +++---
>  7 files changed, 107 insertions(+), 53 deletions(-)
>
> diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
> index f9e0045..87765da 100644
> --- a/wpa_supplicant/ap.c
> +++ b/wpa_supplicant/ap.c
> @@ -99,6 +99,18 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
>
>                 if (!no_ht && mode && mode->ht_capab) {
>                         conf->ieee80211n = 1;
> +#ifdef CONFIG_P2P
> +                       if ((conf->hw_mode == HOSTAPD_MODE_IEEE80211A) &&
> +                           (mode->ht_capab &
> +                            HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
> +                           wpa_s->conf->p2p_go_ht40)
> +                               conf->secondary_channel =
> +                                       wpas_p2p_get_ht40_mode(wpa_s, mode,
> +                                                              conf->channel);
> +                       if (conf->secondary_channel)
> +                               conf->ht_capab |=
> +                                       HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
> +#endif
>
>                         /*
>                          * white-list capabilities that won't cause issues
> diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
> index 46c4da2..b9317e4 100644
> --- a/wpa_supplicant/config.h
> +++ b/wpa_supplicant/config.h
> @@ -510,6 +510,7 @@ struct wpa_config {
>         int p2p_oper_reg_class;
>         int p2p_oper_channel;
>         int p2p_go_intent;
> +       int p2p_go_ht40;
>         char *p2p_ssid_postfix;
>         int persistent_reconnect;
>         int p2p_intra_bss;
> diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
> index cb3e523..1a63902 100644
> --- a/wpa_supplicant/ctrl_iface.c
> +++ b/wpa_supplicant/ctrl_iface.c
> @@ -3429,7 +3429,7 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
>
>
>  static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
> -                                        char *cmd, int freq)
> +                                        char *cmd, int freq, int ht40)
>  {
>         int id;
>         struct wpa_ssid *ssid;
> @@ -3443,26 +3443,31 @@ 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);
> +       return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40);
>  }
>
>
>  static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
>  {
> -       int freq = 0;
> +       int freq = 0, ht40 = 0;
>         char *pos;
>
>         pos = os_strstr(cmd, "freq=");
>         if (pos)
>                 freq = atoi(pos + 5);
>
> +       ht40 = os_strstr(cmd, "ht40") != NULL;
> +
>         if (os_strncmp(cmd, "persistent=", 11) == 0)
> -               return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq);
> +               return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11,
> +                                                    freq, ht40);
>         if (os_strcmp(cmd, "persistent") == 0 ||
>             os_strncmp(cmd, "persistent ", 11) == 0)
> -               return wpas_p2p_group_add(wpa_s, 1, freq);
> +               return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
>         if (os_strncmp(cmd, "freq=", 5) == 0)
> -               return wpas_p2p_group_add(wpa_s, 0, freq);
> +               return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
> +       if (ht40)
> +               return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
>
>         wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
>                    cmd);
> @@ -4257,7 +4262,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
>                 if (wpas_p2p_group_remove(wpa_s, buf + 17))
>                         reply_len = -1;
>         } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
> -               if (wpas_p2p_group_add(wpa_s, 0, 0))
> +               if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
>                         reply_len = -1;
>         } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
>                 if (p2p_ctrl_group_add(wpa_s, buf + 14))
> diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
> index f4541f7..f784e85 100644
> --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
> +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
> @@ -346,7 +346,7 @@ 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)) {
> +               if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0)) {
>                         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 218ed2f..1539f76 100644
> --- a/wpa_supplicant/p2p_supplicant.c
> +++ b/wpa_supplicant/p2p_supplicant.c
> @@ -841,6 +841,7 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
>                   sizeof(d->sec_device_type));
>         d->num_sec_device_types = s->num_sec_device_types;
>
> +       d->p2p_go_ht40 = s->p2p_go_ht40;
>         d->p2p_group_idle = s->p2p_group_idle;
>         d->p2p_intra_bss = s->p2p_intra_bss;
>         d->persistent_reconnect = s->persistent_reconnect;
> @@ -2019,7 +2020,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
>                            MAC2STR(sa), op_freq);
>                 if (s) {
>                         wpas_p2p_group_add_persistent(
> -                               wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
> +                               wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0, 0);
>                 } else if (bssid) {
>                         wpas_p2p_join(wpa_s, bssid, go_dev_addr,
>                                       wpa_s->p2p_wps_method, 0);
> @@ -2086,7 +2087,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, 0);
> +                                     ssid->mode == WPAS_MODE_P2P_GO, 0, 0);
>  }
>
>
> @@ -2223,26 +2224,46 @@ struct p2p_oper_class_map {
>         enum { BW20, BW40PLUS, BW40MINUS } bw;
>  };
>
> +static struct p2p_oper_class_map op_class[] = {
> +       { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
> +       { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20 },
> +#if 0 /* Do not enable HT40 on 2 GHz for now */
> +       { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
> +       { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
> +#endif
> +       { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
> +       { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
> +       { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
> +       { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
> +       { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
> +       { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
> +       { -1, 0, 0, 0, 0, BW20 }
> +};
> +
> +static int 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;
> +}
> +
>  static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
>                                    struct p2p_channels *chan)
>  {
>         struct hostapd_hw_modes *mode;
>         int cla, op;
> -       struct p2p_oper_class_map op_class[] = {
> -               { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
> -               { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20 },
> -#if 0 /* Do not enable HT40 on 2 GHz for now */
> -               { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
> -               { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
> -#endif
> -               { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
> -               { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
> -               { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
> -               { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
> -               { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
> -               { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
> -               { -1, 0, 0, 0, 0, BW20 }
> -       };
>
>         if (wpa_s->hw.modes == NULL) {
>                 wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
> @@ -2262,16 +2283,7 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
>                 if (mode == NULL)
>                         continue;
>                 for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
> -                       int flag;
> -                       if (!has_channel(wpa_s->global, mode, ch, &flag))
> -                               continue;
> -                       if (o->bw == BW40MINUS &&
> -                           (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
> -                            !has_channel(wpa_s->global, mode, ch - 4, NULL)))
> -                               continue;
> -                       if (o->bw == BW40PLUS &&
> -                           (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
> -                            !has_channel(wpa_s->global, mode, ch + 4, NULL)))
> +                       if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1)
>                                 continue;
>                         if (reg == NULL) {
>                                 wpa_printf(MSG_DEBUG, "P2P: Add operating "
> @@ -2331,6 +2343,30 @@ static int wpas_go_connected(void *ctx, const u8 *dev_addr)
>         return 0;
>  }
>
> +int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
> +                          struct hostapd_hw_modes *mode, u8 channel)
> +{
> +       int op, ret;
> +
> +       for (op = 0; op_class[op].op_class; op++) {
> +               struct p2p_oper_class_map *o = &op_class[op];
> +               u8 ch;
> +
> +               for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
> +                       if ((o->mode != HOSTAPD_MODE_IEEE80211A) ||

The HOSTAPD_MODE_IEEE80211A checks seem a bit redundant, but the
patches look good overall.

Arik
Rajkumar Manoharan - July 19, 2012, 3:13 a.m.
On Wed, Jul 18, 2012 at 10:37:14PM +0300, Arik Nemtsov wrote:
> On Tue, Jul 17, 2012 at 1:09 PM, Rajkumar Manoharan
> <rmanohar@qca.qualcomm.com> wrote:
> > Add optional "ht40" argument for p2p_group_add command to enable 40MHz
> > in 5GHz band. This could configure secondary channel, when 11n support
> > was enabled and if the HW supports 40MHz channel width.
> >
> > Signed-hostap: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
> > ---
> >
[...]
> > +int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
> > +                          struct hostapd_hw_modes *mode, u8 channel)
> > +{
> > +       int op, ret;
> > +
> > +       for (op = 0; op_class[op].op_class; op++) {
> > +               struct p2p_oper_class_map *o = &op_class[op];
> > +               u8 ch;
> > +
> > +               for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
> > +                       if ((o->mode != HOSTAPD_MODE_IEEE80211A) ||
> 
> The HOSTAPD_MODE_IEEE80211A checks seem a bit redundant, but the
> patches look good overall.
>
As discussed earlier, 40MHz wont be supported for 2.4GHz band. Thats why
11G band op_class is ignored.

-Rajkumar
Jouni Malinen - Aug. 15, 2012, 8:23 p.m.
On Tue, Jul 17, 2012 at 03:39:13PM +0530, Rajkumar Manoharan wrote:
> Add optional "ht40" argument for p2p_group_add command to enable 40MHz
> in 5GHz band. This could configure secondary channel, when 11n support
> was enabled and if the HW supports 40MHz channel width.

Thanks, applied. Though, this version did not build
(wpa_supplicant/dbus/dbus_new_handlers_p2p.c missed a change) and in
addition to fixing that, I moved the HT40 flag into a bit different
place.

Patch

diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index f9e0045..87765da 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -99,6 +99,18 @@  static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 
 		if (!no_ht && mode && mode->ht_capab) {
 			conf->ieee80211n = 1;
+#ifdef CONFIG_P2P
+			if ((conf->hw_mode == HOSTAPD_MODE_IEEE80211A) &&
+			    (mode->ht_capab &
+			     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+			    wpa_s->conf->p2p_go_ht40)
+				conf->secondary_channel =
+					wpas_p2p_get_ht40_mode(wpa_s, mode,
+							       conf->channel);
+			if (conf->secondary_channel)
+				conf->ht_capab |=
+					HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+#endif
 
 			/*
 			 * white-list capabilities that won't cause issues
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 46c4da2..b9317e4 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -510,6 +510,7 @@  struct wpa_config {
 	int p2p_oper_reg_class;
 	int p2p_oper_channel;
 	int p2p_go_intent;
+	int p2p_go_ht40;
 	char *p2p_ssid_postfix;
 	int persistent_reconnect;
 	int p2p_intra_bss;
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index cb3e523..1a63902 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -3429,7 +3429,7 @@  static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
 
 
 static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
-					 char *cmd, int freq)
+					 char *cmd, int freq, int ht40)
 {
 	int id;
 	struct wpa_ssid *ssid;
@@ -3443,26 +3443,31 @@  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);
+	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40);
 }
 
 
 static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
 {
-	int freq = 0;
+	int freq = 0, ht40 = 0;
 	char *pos;
 
 	pos = os_strstr(cmd, "freq=");
 	if (pos)
 		freq = atoi(pos + 5);
 
+	ht40 = os_strstr(cmd, "ht40") != NULL;
+
 	if (os_strncmp(cmd, "persistent=", 11) == 0)
-		return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq);
+		return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11,
+						     freq, ht40);
 	if (os_strcmp(cmd, "persistent") == 0 ||
 	    os_strncmp(cmd, "persistent ", 11) == 0)
-		return wpas_p2p_group_add(wpa_s, 1, freq);
+		return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
 	if (os_strncmp(cmd, "freq=", 5) == 0)
-		return wpas_p2p_group_add(wpa_s, 0, freq);
+		return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+	if (ht40)
+		return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
 
 	wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
 		   cmd);
@@ -4257,7 +4262,7 @@  char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 		if (wpas_p2p_group_remove(wpa_s, buf + 17))
 			reply_len = -1;
 	} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
-		if (wpas_p2p_group_add(wpa_s, 0, 0))
+		if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
 			reply_len = -1;
 	} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
 		if (p2p_ctrl_group_add(wpa_s, buf + 14))
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index f4541f7..f784e85 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -346,7 +346,7 @@  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)) {
+		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0)) {
 			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 218ed2f..1539f76 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -841,6 +841,7 @@  static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
 		  sizeof(d->sec_device_type));
 	d->num_sec_device_types = s->num_sec_device_types;
 
+	d->p2p_go_ht40 = s->p2p_go_ht40;
 	d->p2p_group_idle = s->p2p_group_idle;
 	d->p2p_intra_bss = s->p2p_intra_bss;
 	d->persistent_reconnect = s->persistent_reconnect;
@@ -2019,7 +2020,7 @@  static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
 			   MAC2STR(sa), op_freq);
 		if (s) {
 			wpas_p2p_group_add_persistent(
-				wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
+				wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0, 0);
 		} else if (bssid) {
 			wpas_p2p_join(wpa_s, bssid, go_dev_addr,
 				      wpa_s->p2p_wps_method, 0);
@@ -2086,7 +2087,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, 0);
+				      ssid->mode == WPAS_MODE_P2P_GO, 0, 0);
 }
 
 
@@ -2223,26 +2224,46 @@  struct p2p_oper_class_map {
 	enum { BW20, BW40PLUS, BW40MINUS } bw;
 };
 
+static struct p2p_oper_class_map op_class[] = {
+	{ HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
+	{ HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20 },
+#if 0 /* Do not enable HT40 on 2 GHz for now */
+	{ HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
+	{ HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
+#endif
+	{ HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
+	{ HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
+	{ HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
+	{ HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
+	{ HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
+	{ HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
+	{ -1, 0, 0, 0, 0, BW20 }
+};
+
+static int 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;
+}
+
 static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 				   struct p2p_channels *chan)
 {
 	struct hostapd_hw_modes *mode;
 	int cla, op;
-	struct p2p_oper_class_map op_class[] = {
-		{ HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
-		{ HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20 },
-#if 0 /* Do not enable HT40 on 2 GHz for now */
-		{ HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
-		{ HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
-#endif
-		{ HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
-		{ HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
-		{ HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
-		{ HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
-		{ HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
-		{ HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
-		{ -1, 0, 0, 0, 0, BW20 }
-	};
 
 	if (wpa_s->hw.modes == NULL) {
 		wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
@@ -2262,16 +2283,7 @@  static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 		if (mode == NULL)
 			continue;
 		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
-			int flag;
-			if (!has_channel(wpa_s->global, mode, ch, &flag))
-				continue;
-			if (o->bw == BW40MINUS &&
-			    (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
-			     !has_channel(wpa_s->global, mode, ch - 4, NULL)))
-				continue;
-			if (o->bw == BW40PLUS &&
-			    (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
-			     !has_channel(wpa_s->global, mode, ch + 4, NULL)))
+			if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1)
 				continue;
 			if (reg == NULL) {
 				wpa_printf(MSG_DEBUG, "P2P: Add operating "
@@ -2331,6 +2343,30 @@  static int wpas_go_connected(void *ctx, const u8 *dev_addr)
 	return 0;
 }
 
+int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
+			   struct hostapd_hw_modes *mode, u8 channel)
+{
+	int op, ret;
+
+	for (op = 0; op_class[op].op_class; op++) {
+		struct p2p_oper_class_map *o = &op_class[op];
+		u8 ch;
+
+		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+			if ((o->mode != HOSTAPD_MODE_IEEE80211A) ||
+			    (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)
+				return (o->bw == BW40MINUS) ? -1 : 1;
+			else
+				return 0;
+		}
+	}
+	return 0;
+}
 
 /**
  * wpas_p2p_init - Initialize P2P module for %wpa_supplicant
@@ -3364,13 +3400,14 @@  int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
 
 static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
 				   struct p2p_go_neg_results *params,
-				   int freq)
+				   int freq, int ht40)
 {
 	u8 bssid[ETH_ALEN];
 	int res;
 
 	os_memset(params, 0, sizeof(*params));
 	params->role_go = 1;
+	wpa_s->conf->p2p_go_ht40 = ht40;
 	if (freq) {
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
 			   "frequency %d MHz", freq);
@@ -3482,7 +3519,7 @@  wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
  * i.e., without using Group Owner Negotiation.
  */
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
-		       int freq)
+		       int freq, int ht40)
 {
 	struct p2p_go_neg_results params;
 	unsigned int r;
@@ -3540,7 +3577,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))
+	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40))
 		return -1;
 	if (params.freq &&
 	    !p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
@@ -3607,7 +3644,7 @@  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 freq, int ht40)
 {
 	struct p2p_go_neg_results params;
 	int go = 0;
@@ -3633,7 +3670,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))
+	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40))
 		return -1;
 
 	params.role_go = 1;
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index e2fe259..5573caf 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -28,14 +28,16 @@  void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 					  unsigned int freq);
 int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
-		       int freq);
+		       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 freq, int ht40);
 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,
 			  int registrar);
+int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
+			   struct hostapd_hw_modes *mode, u8 channel);
 enum wpas_p2p_prov_disc_use {
 	WPAS_P2P_PD_FOR_GO_NEG,
 	WPAS_P2P_PD_FOR_JOIN,
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index b159ad3..cbfe742 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2231,17 +2231,14 @@  static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
 					char *argv[])
 {
 	char cmd[128];
-	int res;
-
-	if (argc == 0)
-		return wpa_ctrl_command(ctrl, "P2P_GROUP_ADD");
+	int res = 0, i = 0;
 
-	if (argc > 1)
-		res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD %s %s",
-				  argv[0], argv[1]);
-	else
-		res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD %s",
-				  argv[0]);
+	res = os_snprintf(cmd + res, sizeof(cmd) - res, "P2P_GROUP_ADD");
+	while (i < argc) {
+		res += os_snprintf(cmd + res, sizeof(cmd) - res, " %s",
+				   argv[i]);
+		i++;
+	}
 	if (res < 0 || (size_t) res >= sizeof(cmd))
 		return -1;
 	cmd[sizeof(cmd) - 1] = '\0';
@@ -3221,7 +3218,7 @@  static struct wpa_cli_cmd wpa_cli_commands[] = {
 	{ "p2p_group_remove", wpa_cli_cmd_p2p_group_remove, cli_cmd_flag_none,
 	  "<ifname> = remove P2P group interface (terminate group if GO)" },
 	{ "p2p_group_add", wpa_cli_cmd_p2p_group_add, cli_cmd_flag_none,
-	  "= add a new P2P group (local end as GO)" },
+	  "[ht40] = add a new P2P group (local end as GO)" },
 	{ "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, cli_cmd_flag_none,
 	  "<addr> <method> = request provisioning discovery" },
 	{ "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase,