P2PS: Add CPT handling on PD request and response
authorMax Stepanov <Max.Stepanov@intel.com>
Thu, 2 Jul 2015 13:21:22 +0000 (16:21 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 26 Jul 2015 21:47:19 +0000 (00:47 +0300)
On PD Request/follow-on PD Request preparation set a feature capability
CPT value of PD context.

On PD Request processing use a request CPT and service advertisement
CPT priority list to select a feature capability CPT of PD Response.

On follow-on PD Request processing use a request CPT and a CPT priority
list in PD context to select a CPT value of follow on PD Response.

Signed-off-by: Max Stepanov <Max.Stepanov@intel.com>
Reviewed-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Reviewed-by: Ilan Peer <ilan.peer@intel.com>
src/common/ieee802_11_defs.h
src/p2p/p2p_pd.c

index 92a2f8b..5ac69e6 100644 (file)
@@ -1080,6 +1080,11 @@ enum p2p_attr_id {
 #define P2PS_FEATURE_CAPAB_UDP_TRANSPORT BIT(0)
 #define P2PS_FEATURE_CAPAB_MAC_TRANSPORT BIT(1)
 
+struct p2ps_feature_capab {
+       u8 cpt;
+       u8 reserved;
+} STRUCT_PACKED;
+
 /* Invitation Flags */
 #define P2P_INVITATION_FLAGS_TYPE BIT(0)
 
index 5366d8d..7e83e2f 100644 (file)
@@ -86,7 +86,7 @@ static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev,
                                  struct wpabuf *buf, u16 config_methods)
 {
        struct p2ps_provision *prov = p2p->p2ps_prov;
-       u8 feat_cap_mask[] = { 1, 0 };
+       struct p2ps_feature_capab fcap = { prov->cpt_mask, 0 };
        int shared_group = 0;
        u8 ssid[SSID_MAX_LEN];
        size_t ssid_len;
@@ -151,8 +151,7 @@ static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev,
 
        p2p_buf_add_session_id(buf, prov->session_id, prov->session_mac);
 
-       p2p_buf_add_feature_capability(buf, sizeof(feat_cap_mask),
-                                      feat_cap_mask);
+       p2p_buf_add_feature_capability(buf, sizeof(fcap), (const u8 *) &fcap);
 
        if (shared_group) {
                p2p_buf_add_persistent_group_info(buf, go_dev_addr,
@@ -243,7 +242,9 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
                                                const u8 *group_id,
                                                size_t group_id_len,
                                                const u8 *persist_ssid,
-                                               size_t persist_ssid_len)
+                                               size_t persist_ssid_len,
+                                               const u8 *fcap,
+                                               u16 fcap_len)
 {
        struct wpabuf *buf;
        size_t extra = 0;
@@ -281,7 +282,6 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
 
        /* Add P2P IE for P2PS */
        if (p2p->p2ps_prov && p2p->p2ps_prov->adv_id == adv_id) {
-               u8 feat_cap_mask[] = { 1, 0 };
                u8 *len = p2p_buf_add_ie_hdr(buf);
                struct p2ps_provision *prov = p2p->p2ps_prov;
                u8 group_capab;
@@ -360,8 +360,7 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
                p2p_buf_add_session_id(buf, prov->session_id,
                                       prov->session_mac);
 
-               p2p_buf_add_feature_capability(buf, sizeof(feat_cap_mask),
-                                              feat_cap_mask);
+               p2p_buf_add_feature_capability(buf, fcap_len, fcap);
                p2p_buf_update_ie_hdr(buf, len);
        } else if (status != P2P_SC_SUCCESS || adv_id) {
                u8 *len = p2p_buf_add_ie_hdr(buf);
@@ -416,6 +415,18 @@ static int p2ps_setup_p2ps_prov(struct p2p_data *p2p, u32 adv_id,
 }
 
 
+static u8 p2ps_own_preferred_cpt(const u8 *cpt_priority, u8 req_cpt_mask)
+{
+       int i;
+
+       for (i = 0; cpt_priority[i]; i++)
+               if (req_cpt_mask & cpt_priority[i])
+                       return cpt_priority[i];
+
+       return 0;
+}
+
+
 void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                               const u8 *data, size_t len, int rx_freq)
 {
@@ -435,6 +446,8 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
        int passwd_id = DEV_PW_DEFAULT;
        u16 config_methods;
        u16 allowed_config_methods = WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+       struct p2ps_feature_capab resp_fcap = { 0, 0 };
+       struct p2ps_feature_capab *req_fcap;
 
        if (p2p_parse(data, len, &msg))
                return;
@@ -523,10 +536,23 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
        os_memset(adv_mac, 0, ETH_ALEN);
        os_memset(group_mac, 0, ETH_ALEN);
 
+       /* Note 1: A feature capability attribute structure can be changed
+        * in the future. The assumption is that such modifications are
+        * backwards compatible, therefore we allow processing of
+        * msg.feature_cap exceeding the size of the p2ps_feature_capab
+        * structure.
+        * Note 2: Vverification of msg.feature_cap_len below has to be changed
+        * to allow 2 byte feature capability processing if struct
+        * p2ps_feature_capab is extended to include additional fields and it
+        * affects the structure size.
+        */
        if (msg.adv_id && msg.session_id && msg.session_mac && msg.adv_mac &&
+           msg.feature_cap && msg.feature_cap_len >= sizeof(*req_fcap) &&
            (msg.status || msg.conn_cap)) {
                u8 remote_conncap;
 
+               req_fcap = (struct p2ps_feature_capab *) msg.feature_cap;
+
                if (msg.intended_addr)
                        os_memcpy(group_mac, msg.intended_addr, ETH_ALEN);
 
@@ -553,9 +579,22 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                        p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d",
                                auto_accept, remote_conncap, conncap);
 
-                       if (p2ps_adv->config_methods &&
-                           !(msg.wps_config_methods &
-                             p2ps_adv->config_methods)) {
+                       resp_fcap.cpt =
+                               p2ps_own_preferred_cpt(p2ps_adv->cpt_priority,
+                                                      req_fcap->cpt);
+
+                       p2p_dbg(p2p,
+                               "cpt: service:0x%x remote:0x%x result:0x%x",
+                               p2ps_adv->cpt_mask, req_fcap->cpt,
+                               resp_fcap.cpt);
+
+                       if (!resp_fcap.cpt) {
+                               p2p_dbg(p2p,
+                                       "Incompatible P2PS feature capability CPT bitmask");
+                               reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+                       } else if (p2ps_adv->config_methods &&
+                                  !(msg.wps_config_methods &
+                                  p2ps_adv->config_methods)) {
                                p2p_dbg(p2p,
                                        "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
                                        p2ps_adv->config_methods,
@@ -644,6 +683,15 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                                        p2p->p2ps_prov->conncap,
                                        remote_conncap, conncap);
 
+                               resp_fcap.cpt = p2ps_own_preferred_cpt(
+                                       p2p->p2ps_prov->cpt_priority,
+                                       req_fcap->cpt);
+
+                               p2p_dbg(p2p,
+                                       "cpt: local:0x%x remote:0x%x result:0x%x",
+                                       p2p->p2ps_prov->cpt_mask,
+                                       req_fcap->cpt, resp_fcap.cpt);
+
                                /*
                                 * Ensure that if we asked for PIN originally,
                                 * our method is consistent with original
@@ -654,14 +702,22 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                                else if (method & WPS_CONFIG_KEYPAD)
                                        method = WPS_CONFIG_DISPLAY;
 
-                               /* Reject this "Deferred Accept* if incompatible
-                                * conncap or method */
                                if (!conncap ||
-                                   !(msg.wps_config_methods & method))
+                                   !(msg.wps_config_methods & method)) {
+                                       /*
+                                        * Reject this "Deferred Accept*
+                                        * if incompatible conncap or method
+                                        */
+                                       reject =
+                                               P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+                               } else if (!resp_fcap.cpt) {
+                                       p2p_dbg(p2p,
+                                               "Incompatible P2PS feature capability CPT bitmask");
                                        reject =
                                                P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
-                               else
+                               } else {
                                        reject = P2P_SC_SUCCESS;
+                               }
 
                                p2p->p2ps_prov->status = reject;
                                p2p->p2ps_prov->conncap = conncap;
@@ -679,7 +735,9 @@ out:
                                        config_methods, adv_id,
                                        msg.group_id, msg.group_id_len,
                                        msg.persistent_ssid,
-                                       msg.persistent_ssid_len);
+                                       msg.persistent_ssid_len,
+                                       (const u8 *) &resp_fcap,
+                                       sizeof(resp_fcap));
        if (resp == NULL) {
                p2p_parse_free(&msg);
                return;