diff mbox

[13/19] P2PS: add p2ps_supported_cpt configuration property

Message ID 1433925829-8019-14-git-send-email-ilan.peer@intel.com
State Changes Requested
Headers show

Commit Message

Peer, Ilan June 10, 2015, 8:43 a.m. UTC
From: Max Stepanov <Max.Stepanov@intel.com>

The p2ps_supported_cpt configuration property allows ASP to
specify supported Coordination Protocol Transports (CPT) and their
priorities. The property value is a list of supported ASP trasport
names ordred by their priority. Currently only two transports are
supported: UDP and MAC. The property can be set with ctrl-iface P2P_SET
command: (e.g. P2P_SET p2ps_supported_cpt UDP MAC). By default only UDP
transport is enabled.

The configuration parameter defines two internal p2p properties used
to verify CPT bitmask field of received provision discovery request's
feature capability as well as to select the best matching CPT option
for a provision discovery response.

The supported CPT bitwise mask value is used to verify a feature_cap=<hex>
parameter of P2P_ASP_PROVISION and P2P_ASP_PROVISION_RESP commands.
An error is returned if the parameter value doesn't match a supported
CPT bitwise mask. If this parameter is not specified, the supplicant
uses a supported CPT bitwise mask as CPT value of feature capability
attribute sent in PD request.

Signed-off-by: Max Stepanov <Max.Stepanov@intel.com>
Reviewed-by: Ilan Peer <ilan.peer@intel.com>
---
 src/common/ieee802_11_defs.h    |  1 +
 src/p2p/p2p.c                   | 34 ++++++++++++++++++++
 src/p2p/p2p.h                   | 21 +++++++++++++
 src/p2p/p2p_pd.c                | 56 +++++++++++++++++++++++++++++++--
 wpa_supplicant/ctrl_iface.c     | 69 ++++++++++++++++++++++++++++++++++++++---
 wpa_supplicant/p2p_supplicant.c |  2 ++
 6 files changed, 177 insertions(+), 6 deletions(-)

Comments

Jouni Malinen June 16, 2015, 2:10 p.m. UTC | #1
On Wed, Jun 10, 2015 at 11:43:43AM +0300, Ilan Peer wrote:
> The p2ps_supported_cpt configuration property allows ASP to
> specify supported Coordination Protocol Transports (CPT) and their
> priorities. The property value is a list of supported ASP trasport
> names ordred by their priority. Currently only two transports are
> supported: UDP and MAC. The property can be set with ctrl-iface P2P_SET
> command: (e.g. P2P_SET p2ps_supported_cpt UDP MAC). By default only UDP
> transport is enabled.

This would make the priority list global to the P2P Device, i.e., this
would apply to all services. Would that really cover the cases where
multiple services are available? I would expect that different services
could have different preferences for CPT especially since the current
designs would likely only support the UDP option while some newer
services may end up expecting the MAC option to be used.

Should this be done as a per-service (P2P_SERVICE_ADD,
P2P_ASP_PROVISION_RESP, P2P_ASP_PROVISION) parameter instead of an
extension to the global P2P_SET?
Stepanov, Max June 16, 2015, 4:15 p.m. UTC | #2
On Tue, June 16, 2015 at 17:10, Jouni Malinen wrote:
>This would make the priority list global to the P2P Device, i.e., this would apply
>to all services. Would that really cover the cases where multiple services are
>available? I would expect that different services could have different
>preferences for CPT especially since the current designs would likely only
>support the UDP option while some newer services may end up expecting the
>MAC option to be used.
>
>Should this be done as a per-service (P2P_SERVICE_ADD,
>P2P_ASP_PROVISION_RESP, P2P_ASP_PROVISION) parameter instead of an
>extension to the global P2P_SET?
>

Good question. According to WFDS spec: " The ASP on a device communicates with the ASP on a peer device to manage ASP sessions between the two devices".
E.g. in general the supported session coordination protocol relates to a single ASP service, not to services.

By default only UDP transport is enabled, and setting of p2ps_supported_cpt is needed only for new services that may require MAC. Also ASP service may decide which ASP coordination protocol transport to use for a specific service. Both P2P_ASP_PROVISION and P2P_ASP_PROVISION_RESP commands allow ASP to specify 'feature_cap' parameter and explicitly set CPT value of a provision discovery request frame. On the other hand the CPT values of p2ps_supported_cpt are used mainly for provision discovery request verification and CPT value selection returned in a provision discovery response frame.

So, it looks like reasonable to have a set of the supported CPTs as a global ASP related P2P property.

Max
Vamsi, Krishna June 17, 2015, 10:30 a.m. UTC | #3
> -----Original Message-----
> From: hostap-bounces@lists.shmoo.com [mailto:hostap-
> bounces@lists.shmoo.com] On Behalf Of Stepanov, Max
> 
> Good question. According to WFDS spec: " The ASP on a device communicates
> with the ASP on a peer device to manage ASP sessions between the two
> devices".

The above snippet mostly applies to the value that should be sent in PD request. The value in PD request indicates all the modes supported by an ASP in general. But PD response is supposed to have a single transport bit set and that mode should be used for that service, which means the responder should/can select the preferred transport mode for that service. 

Now coming to your patch, it talks about setting supported features as well as the priority between them. The overall supported features can be global while the priority between them can be specific to each service. As the spec is providing flexibility to choose different transports let us not limit this in supplicant. I suggest giving the configuration flexibility as much as possible to the ASP, which is supposed to be implemented on top of supplicant.

Another thing, looking at the way p2p_match_feat_cap() is implemented, I would like to bring to your notice the point that "feature capability" is not only meant for transport modes but for any kind of ASP features. Writing the below logic so generic may not good hold for future. In general its good practice/mandate to set all the reserved fields to zero.

+	for (i = 0; p2p->cfg->p2ps_asp_cpt_priority[i]; i++) {
+		if (p2p->cfg->p2ps_asp_cpt_priority[i] & req_cap[0]) {
+			resp_cap[0] = p2p->cfg->p2ps_asp_cpt_priority[i];
+			break;
+		}
+	}

Thanks,
Vamsi
Stepanov, Max June 18, 2015, 8:50 a.m. UTC | #4
>The above snippet mostly applies to the value that should be sent in PD
>request. The value in PD request indicates all the modes supported by an ASP
>in general. But PD response is supposed to have a single transport bit set and
>that mode should be used for that service, which means the responder
>should/can select the preferred transport mode for that service.

Agree. Please notice that this flow supposes to work on a seeker side handling a follow on PD request and not having per service CPT preferences. 


>Now coming to your patch, it talks about setting supported features as well as
>the priority between them. The overall supported features can be global
>while the priority between them can be specific to each service. As the spec is
>providing flexibility to choose different transports let us not limit this in
>supplicant. I suggest giving the configuration flexibility as much as possible to
>the ASP, which is supposed to be implemented on top of supplicant.

Assume we have per service CPT preference on an advertiser side. How should a seeker (making a final decision) select CPT bit for a follow on PD response if a follow on PD request contains a number of CPT bit options in a feature capability field? Definitely the seeker selection may not match an advertiser per service preference. My point is that perhaps we may need both per service CPT and a global CPT preference lists to cover your requirement. Per service CPT preference list is supposed to be used by an advertiser handling a direct PD request. (To be precise a per service CPT preference usage is restricted only for service advertisements having auto_accept == true and config_methods != KEYPAD.) A global CPT preference list supposed to be used in other cases, e.g. by advertisers when per service preference list is not defined or by seekers on follow-on PD request.

What do you think?


>Another thing, looking at the way p2p_match_feat_cap() is implemented, I
>would like to bring to your notice the point that "feature capability" is not only
>meant for transport modes but for any kind of ASP features. Writing the
>below logic so generic may not good hold for future. In general its good
>practice/mandate to set all the reserved fields to zero.
>
>+	for (i = 0; p2p->cfg->p2ps_asp_cpt_priority[i]; i++) {
>+		if (p2p->cfg->p2ps_asp_cpt_priority[i] & req_cap[0]) {
>+			resp_cap[0] = p2p->cfg->p2ps_asp_cpt_priority[i];
>+			break;
>+		}
>+	}

The first byte is defined as Coordination Protocol Transport Bitmask field, so, PD responder sets only one single bit selecting the transport.
The rest of the feature capability fields are explicitly set to zero a line before this loop:

	os_memset(resp_cap, 0, P2PS_FEATURE_CAPAB_LEN);

I think this function and P2PS_FEATURE_CAPAB_LEN has to be updated when new fields in feature capability to be added.

Thanks,
Max
Vamsi, Krishna June 18, 2015, 9:33 a.m. UTC | #5
> -----Original Message-----
> From: Stepanov, Max [mailto:Max.Stepanov@intel.com]


> Assume we have per service CPT preference on an advertiser side. How should
> a seeker (making a final decision) select CPT bit for a follow on PD response if a
> follow on PD request contains a number of CPT bit options in a feature
> capability field? Definitely the seeker selection may not match an advertiser
> per service preference. My point is that perhaps we may need both per service
> CPT and a global CPT preference lists to cover your requirement. Per service
> CPT preference list is supposed to be used by an advertiser handling a direct PD
> request. (To be precise a per service CPT preference usage is restricted only for
> service advertisements having auto_accept == true and config_methods !=
> KEYPAD.) A global CPT preference list supposed to be used in other cases, e.g.
> by advertisers when per service preference list is not defined or by seekers on
> follow-on PD request.
> 
> What do you think?


I think P2P_ASP_PROVISIONING command can be used to provide the cpt to be used for responding to a follow-on PD req by seeker.

Let me write down my proposal on this.There are two cases:
1. auto_accept == true
     Seeker sends "cpt configured through P2P_ASP_PROVISIOING command" in PD request. Advertiser uses "cpt configured through P2P_SERVICE_ADD command" to choose (based on intersection with whatever received in PD req) a transport mode and sends it in PD response.

2. auto_acceot==false
     Seeker sends "cpt configured through P2P_ASP_PROVISIOING command" in PD request. Advertiser uses "cpt configured through P2P_SERVICE_ADD command" to choose (based on intersection with whatever received in PD req) a transport mode and sends it in PD response(though this will not be used for service establishment). Advertiser reports the received feat_capa to the ASP sitting on top of it.
    The Advertiser's ASP will configure the preferred cpt through P2P_ASP_PROVISIONING_RESP command which should be sent in follow-on PD req. The seeker can choose one transport mode to be used with that service instance based on the intersection of cpt received in follow-on PD request and the cpt configured earlier through P2P_ASP_PROVISIONING command (this can be saved in p2ps_prov structure until then).

Let me know if you see some problem with the above.

Thanks,
Vamsi
Stepanov, Max June 18, 2015, 11:27 a.m. UTC | #6
>-----Original Message-----
>From: Vamsi, Krishna [mailto:vamsin@qti.qualcomm.com]
>1. auto_accept == true
>     Seeker sends "cpt configured through P2P_ASP_PROVISIOING command"
>in PD request. Advertiser uses "cpt configured through P2P_SERVICE_ADD
>command" to choose (based on intersection with whatever received in PD
>req) a transport mode and sends it in PD response.
>
>2. auto_acceot==false
>     Seeker sends "cpt configured through P2P_ASP_PROVISIOING command"
>in PD request. Advertiser uses "cpt configured through P2P_SERVICE_ADD
>command" to choose (based on intersection with whatever received in PD
>req) a transport mode and sends it in PD response(though this will not be
>used for service establishment). Advertiser reports the received feat_capa to
>the ASP sitting on top of it.
>    The Advertiser's ASP will configure the preferred cpt through
>P2P_ASP_PROVISIONING_RESP command which should be sent in follow-on
>PD req. The seeker can choose one transport mode to be used with that
>service instance based on the intersection of cpt received in follow-on PD
>request and the cpt configured earlier through P2P_ASP_PROVISIONING
>command (this can be saved in p2ps_prov structure until then).
>
>Let me know if you see some problem with the above.

It looks reasonable to me. I'll change my implementation and let you know.

Thanks,
Max
diff mbox

Patch

diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 1727fa7..734ac5c 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1069,6 +1069,7 @@  enum p2p_attr_id {
 
 /* P2PS Feature Capability bitmap */
 #define P2PS_FEATURE_CAPAB_UDP_TRANSPORT BIT(0)
+#define P2PS_FEATURE_CAPAB_MAC_TRANSPORT BIT(1)
 
 /* Invitation Flags */
 #define P2P_INVITATION_FLAGS_TYPE BIT(0)
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index bfc656b..12a8b96 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -20,6 +20,11 @@ 
 #include "p2p.h"
 
 
+static const u8 p2ps_supported_cpt_default[P2PS_FEATURE_CAPAB_CPT_MAX] = {
+	P2PS_FEATURE_CAPAB_UDP_TRANSPORT,
+	0
+};
+
 static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx);
 static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev);
 static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da,
@@ -5384,3 +5389,32 @@  void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx)
 		"Timeout on waiting peer to become ready for GO Negotiation");
 	p2p_go_neg_failed(p2p, -1);
 }
+
+
+void p2p_set_asp_supported_cpt(struct p2p_data *p2p, const u8 *cpt_priority)
+{
+	int cnt;
+
+	if (!cpt_priority)
+		cpt_priority = p2ps_supported_cpt_default;
+
+	for (p2p->cfg->p2ps_asp_cpt_mask = 0, cnt = 0;
+	     cpt_priority[cnt]; cnt++)
+		p2p->cfg->p2ps_asp_cpt_mask |= cpt_priority[cnt];
+
+	os_memcpy(p2p->cfg->p2ps_asp_cpt_priority, cpt_priority, cnt);
+
+	p2p_dbg(p2p, "P2PS set supported ASP CPT mask: 0x%X",
+		p2p->cfg->p2ps_asp_cpt_mask);
+	wpa_hexdump(MSG_DEBUG, "P2PS set supported ASP CPT piorities: ",
+		    cpt_priority, cnt);
+}
+
+
+u8 p2p_get_asp_supported_cpt(struct p2p_data *p2p, const u8 **cpt_priority)
+{
+	if (cpt_priority)
+		*cpt_priority = p2p->cfg->p2ps_asp_cpt_priority;
+
+	return p2p->cfg->p2ps_asp_cpt_mask;
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 82c8454..acf62cc 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -22,6 +22,7 @@ 
 #define P2PS_HASH_LEN 6
 #define P2P_MAX_QUERY_HASH 6
 #define P2PS_FEATURE_CAPAB_LEN 2
+#define P2PS_FEATURE_CAPAB_CPT_MAX 2
 
 /**
  * P2P_MAX_REG_CLASSES - Maximum number of regulatory classes
@@ -523,6 +524,24 @@  struct p2p_config {
 	unsigned int passphrase_len;
 
 	/**
+	 * p2ps_asp_cpt_mask - supported ASP CPT mask
+	 *
+	 * A bitwise mask of supported ASP Coordination Protocol Transports.
+	 * This property is set together and corresponds with
+	 * p2ps_asp_cpt_priority.
+	 */
+	u8 p2ps_asp_cpt_mask;
+
+	/**
+	 * p2ps_asp_cpt_priority - priorities of ASP CPT
+	 *
+	 * Priorities of supported ASP Coordinatin Protocol Transports.
+	 * This property is set together and corresponds with p2ps_asp_cpt.
+	 * The last byte of the array has to be 0.
+	 */
+	u8 p2ps_asp_cpt_priority[P2PS_FEATURE_CAPAB_CPT_MAX + 1];
+
+	/**
 	 * cb_ctx - Context to use with callback functions
 	 */
 	void *cb_ctx;
@@ -2257,5 +2276,7 @@  int p2p_service_add_asp(struct p2p_data *p2p, int auto_accept, u32 adv_id,
 int p2p_service_del_asp(struct p2p_data *p2p, u32 adv_id);
 void p2p_service_flush_asp(struct p2p_data *p2p);
 struct p2ps_advertisement * p2p_get_p2ps_adv_list(struct p2p_data *p2p);
+void p2p_set_asp_supported_cpt(struct p2p_data *p2p, const u8 *cpt_priority);
+u8 p2p_get_asp_supported_cpt(struct p2p_data *p2p, const u8 **cpt_priority);
 
 #endif /* P2P_H */
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index f9e2911..cb8df59 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -401,6 +401,43 @@  static int p2ps_setup_p2ps_prov(struct p2p_data *p2p, u32 adv_id,
 }
 
 
+static int p2p_match_feat_cap(struct p2p_data *p2p,
+			      const u8 *req_cap, u16 req_cap_len,
+			      u8 resp_cap[P2PS_FEATURE_CAPAB_LEN])
+{
+	int i;
+
+	/*
+	 * P2PS feature capability structure:
+	 * u8 - ASP Coordination Protocol Transport Bitmask
+	 * u8 - Reserved
+	 */
+	if (req_cap_len < P2PS_FEATURE_CAPAB_LEN) {
+		p2p_dbg(p2p,
+			"Invalid length of P2PS feature capability attribute");
+		return -1;
+	}
+
+	if (req_cap[0] & ~(p2p->cfg->p2ps_asp_cpt_mask)) {
+		p2p_dbg(p2p,
+			"Unsupported CPT in  P2PS feature capability attribute");
+		return -1;
+	}
+
+	os_memset(resp_cap, 0, P2PS_FEATURE_CAPAB_LEN);
+
+	/* CPT Bitmask: use the best matching CPT option */
+	for (i = 0; p2p->cfg->p2ps_asp_cpt_priority[i]; i++) {
+		if (p2p->cfg->p2ps_asp_cpt_priority[i] & req_cap[0]) {
+			resp_cap[0] = p2p->cfg->p2ps_asp_cpt_priority[i];
+			break;
+		}
+	}
+
+	return 0;
+}
+
+
 void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
 			       const u8 *data, size_t len, int rx_freq)
 {
@@ -419,6 +456,7 @@  void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
 	u8 group_mac[ETH_ALEN];
 	int passwd_id = DEV_PW_DEFAULT;
 	u16 config_methods;
+	u8 feature_cap[P2PS_FEATURE_CAPAB_LEN] = {0};
 
 	if (p2p_parse(data, len, &msg))
 		return;
@@ -552,6 +590,12 @@  void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
 				p2p_dbg(p2p,
 					"Missing feature capability in Provision Discovery Request");
 				reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+			} else if (p2p_match_feat_cap(p2p, msg.feature_cap,
+						      msg.feature_cap_len,
+						      feature_cap)) {
+				p2p_dbg(p2p,
+					"Invalid feature capability in Provision Discovery Request");
+				reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
 			}
 
 			if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
@@ -657,6 +701,14 @@  void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
 						"Missing feature capability in Follow-On Provision Discovery Request");
 					reject =
 						P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+				} else if (p2p_match_feat_cap(
+							p2p, msg.feature_cap,
+							msg.feature_cap_len,
+							feature_cap)) {
+					p2p_dbg(p2p,
+						"Invalid feature capability in Follow-On Provision Discovery Request");
+					reject =
+						P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
 				} else {
 					reject = P2P_SC_SUCCESS;
 				}
@@ -679,8 +731,8 @@  out:
 					msg.group_id, msg.group_id_len,
 					msg.persistent_ssid,
 					msg.persistent_ssid_len,
-					msg.feature_cap,
-					msg.feature_cap_len);
+					feature_cap,
+					sizeof(feature_cap));
 	if (resp == NULL) {
 		p2p_parse_free(&msg);
 		return;
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index ce5a155..be641c7 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -4624,7 +4624,8 @@  static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
 }
 
 
-static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
+static struct p2ps_provision *
+p2p_parse_asp_provision_cmd(struct wpa_supplicant *wpa_s, const char *cmd)
 {
 	struct p2ps_provision *p2ps_prov;
 	char *pos;
@@ -4632,6 +4633,7 @@  static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
 	char *info = NULL;
 	u8 role = P2PS_SETUP_NONE;
 	long long unsigned val;
+	u8 cpt_mask;
 
 	pos = os_strstr(cmd, "info=");
 	if (pos) {
@@ -4705,14 +4707,24 @@  static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
 	}
 	p2ps_prov->role = role;
 
+	cpt_mask = p2p_get_asp_supported_cpt(wpa_s->global->p2p, NULL);
+
 	pos = os_strstr(cmd, "feature_cap=");
 	if (pos) {
 		/* read a hexadecimal string of all feature capability bytes */
 		if (hexstr2bin(pos + 12, p2ps_prov->feature_cap,
 			       sizeof(p2ps_prov->feature_cap)) < 0)
 			goto invalid_args;
+
+		if (~cpt_mask & p2ps_prov->feature_cap[0]) {
+			wpa_printf(MSG_ERROR,
+				   "Command CPT %02X of feature_cap conflicts with supported CPT mask %02X",
+				   p2ps_prov->feature_cap[0], cpt_mask);
+		        goto invalid_args;
+		}
 	} else {
-		p2ps_prov->feature_cap[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
+		/* set CPT field (byte 0) of feature capability */
+		p2ps_prov->feature_cap[0] = cpt_mask;
 	}
 
 	return p2ps_prov;
@@ -4740,7 +4752,7 @@  static int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd)
 	if (*pos != ' ')
 		return -1;
 
-	p2ps_prov = p2p_parse_asp_provision_cmd(pos);
+	p2ps_prov = p2p_parse_asp_provision_cmd(wpa_s, pos);
 	if (!p2ps_prov)
 		return -1;
 
@@ -4772,7 +4784,7 @@  static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
 	if (*pos != ' ')
 		return -1;
 
-	p2ps_prov = p2p_parse_asp_provision_cmd(pos);
+	p2ps_prov = p2p_parse_asp_provision_cmd(wpa_s, pos);
 	if (!p2ps_prov)
 		return -1;
 
@@ -5690,6 +5702,46 @@  static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
 }
 
 
+static int p2ps_ctrl_parse_supported_cpt(const char *str, u8 *cpt)
+{
+	char *token, *context = NULL, *buf;
+	int i;
+
+	buf = os_strdup(str);
+	if (!buf)
+		return -1;
+
+	for (i = 0; /* empty */; i++) {
+		token = str_token(buf, " \t", &context);
+		if (!token)
+			break;
+
+		if (i >= P2PS_FEATURE_CAPAB_CPT_MAX) {
+			wpa_printf(MSG_ERROR,
+				   "P2PS: CPT name list is too long, expected up to %d names",
+				   P2PS_FEATURE_CAPAB_CPT_MAX);
+			os_free(buf);
+			return -1;
+		}
+
+		if (os_strcmp(token, "UDP") == 0) {
+			cpt[i] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
+		} else if (os_strcmp(token, "MAC") == 0) {
+			cpt[i] = P2PS_FEATURE_CAPAB_MAC_TRANSPORT;
+		} else {
+			wpa_printf(MSG_ERROR,
+				   "P2PS: Unsupported CPT name %s", token);
+			os_free(buf);
+			return -1;
+		}
+	}
+	cpt[i] = 0;
+
+	os_free(buf);
+	return 0;
+}
+
+
 static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
 {
 	char *param;
@@ -5890,6 +5942,15 @@  static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
 		return 0;
 	}
 
+	if (os_strcmp(cmd, "p2ps_supported_cpt") == 0) {
+		u8 cpt[P2PS_FEATURE_CAPAB_CPT_MAX + 1];
+
+		if (p2ps_ctrl_parse_supported_cpt(param, cpt) == 0) {
+			p2p_set_asp_supported_cpt(wpa_s->global->p2p, cpt);
+			return 0;
+		}
+	}
+
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
 		   cmd);
 
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 694915a..6c795c4 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -4039,6 +4039,8 @@  int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
 
 	p2p_set_no_go_freq(global->p2p, &wpa_s->conf->p2p_no_go_freq);
 
+	p2p_set_asp_supported_cpt(global->p2p, NULL);
+
 	return 0;
 }