P2P: Add option for requested device type in P2P search/scan
authorJean-Michel Bachot <jean-michelx.bachot@linux.intel.com>
Sat, 19 Mar 2011 10:57:46 +0000 (12:57 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 19 Mar 2011 10:57:46 +0000 (12:57 +0200)
With this, p2p_find can be extended to find certain requested device
types.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
12 files changed:
src/drivers/driver_test.c
src/p2p/p2p.c
src/p2p/p2p.h
src/p2p/p2p_i.h
src/wps/wps.c
src/wps/wps.h
src/wps/wps_dev_attr.c
src/wps/wps_dev_attr.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h
wpa_supplicant/scan.c

index 5f9354f..2aecef5 100644 (file)
@@ -2885,7 +2885,7 @@ static int wpa_driver_test_p2p_find(void *priv, unsigned int timeout, int type)
        wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
        if (!drv->p2p)
                return -1;
-       return p2p_find(drv->p2p, timeout, type);
+       return p2p_find(drv->p2p, timeout, type, 0, NULL);
 }
 
 
@@ -2969,7 +2969,9 @@ static int wpa_driver_test_p2p_set_params(void *priv,
 }
 
 
-static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq)
+static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
+                        unsigned int num_req_dev_types,
+                        const u8 *req_dev_types)
 {
        struct wpa_driver_test_data *drv = ctx;
        struct wpa_driver_scan_params params;
index 5563f6c..fa56d62 100644 (file)
@@ -699,7 +699,9 @@ static void p2p_search(struct p2p_data *p2p)
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search");
        }
 
-       if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq) < 0) {
+       if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
+                              p2p->num_req_dev_types, p2p->req_dev_types) < 0)
+       {
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                        "P2P: Scan request failed");
                p2p_continue_find(p2p);
@@ -789,8 +791,17 @@ static void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+static void p2p_free_req_dev_types(struct p2p_data *p2p)
+{
+       p2p->num_req_dev_types = 0;
+       os_free(p2p->req_dev_types);
+       p2p->req_dev_types = NULL;
+}
+
+
 int p2p_find(struct p2p_data *p2p, unsigned int timeout,
-            enum p2p_discovery_type type)
+            enum p2p_discovery_type type,
+            unsigned int num_req_dev_types, const u8 *req_dev_types)
 {
        int res;
 
@@ -800,6 +811,18 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan is "
                        "already running");
        }
+
+       p2p_free_req_dev_types(p2p);
+       if (req_dev_types && num_req_dev_types) {
+               p2p->req_dev_types = os_malloc(num_req_dev_types *
+                                              WPS_DEV_TYPE_LEN);
+               if (p2p->req_dev_types == NULL)
+                       return -1;
+               os_memcpy(p2p->req_dev_types, req_dev_types,
+                         num_req_dev_types * WPS_DEV_TYPE_LEN);
+               p2p->num_req_dev_types = num_req_dev_types;
+       }
+
        p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
        p2p_clear_timeout(p2p);
        p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
@@ -813,10 +836,14 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
        switch (type) {
        case P2P_FIND_START_WITH_FULL:
        case P2P_FIND_PROGRESSIVE:
-               res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0);
+               res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,
+                                        p2p->num_req_dev_types,
+                                        p2p->req_dev_types);
                break;
        case P2P_FIND_ONLY_SOCIAL:
-               res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0);
+               res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0,
+                                        p2p->num_req_dev_types,
+                                        p2p->req_dev_types);
                break;
        default:
                return -1;
@@ -843,6 +870,7 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
        eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
        p2p_clear_timeout(p2p);
        p2p_set_state(p2p, P2P_IDLE);
+       p2p_free_req_dev_types(p2p);
        p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
        p2p->go_neg_peer = NULL;
        p2p->sd_peer = NULL;
@@ -1954,6 +1982,7 @@ void p2p_deinit(struct p2p_data *p2p)
        eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
        eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
        p2p_flush(p2p);
+       p2p_free_req_dev_types(p2p);
        os_free(p2p->cfg->dev_name);
        os_free(p2p->groups);
        wpabuf_free(p2p->sd_resp);
index 3d75965..eb70dcf 100644 (file)
@@ -315,6 +315,8 @@ struct p2p_config {
         * @ctx: Callback context from cb_ctx
         * @type: Scan type
         * @freq: Specific frequency (MHz) to scan or 0 for no restriction
+        * @num_req_dev_types: Number of requested device types
+        * @req_dev_types: Array containing requested device types
         * Returns: 0 on success, -1 on failure
         *
         * This callback function is used to request a P2P scan or search
@@ -336,7 +338,9 @@ struct p2p_config {
         * then calling p2p_scan_res_handled() to indicate that all scan
         * results have been indicated.
         */
-       int (*p2p_scan)(void *ctx, enum p2p_scan_type type, int freq);
+       int (*p2p_scan)(void *ctx, enum p2p_scan_type type, int freq,
+                       unsigned int num_req_dev_types,
+                       const u8 *req_dev_types);
 
        /**
         * send_probe_resp - Transmit a Probe Response frame
@@ -733,10 +737,15 @@ enum p2p_discovery_type {
  * @p2p: P2P module context from p2p_init()
  * @timeout: Timeout for find operation in seconds or 0 for no timeout
  * @type: Device Discovery type
+ * @num_req_dev_types: Number of requested device types
+ * @req_dev_types: Requested device types array, must be an array
+ *     containing num_req_dev_types * WPS_DEV_TYPE_LEN bytes; %NULL if no
+ *     requested device types.
  * Returns: 0 on success, -1 on failure
  */
 int p2p_find(struct p2p_data *p2p, unsigned int timeout,
-            enum p2p_discovery_type type);
+            enum p2p_discovery_type type,
+            unsigned int num_req_dev_types, const u8 *req_dev_types);
 
 /**
  * p2p_stop_find - Stop P2P Find (Device Discovery)
index 237abbf..f913e00 100644 (file)
@@ -361,6 +361,10 @@ struct p2p_data {
        u8 after_scan_peer[ETH_ALEN];
        struct p2p_pending_action_tx *after_scan_tx;
 
+       /* Requested device types for find/search */
+       unsigned int num_req_dev_types;
+       u8 *req_dev_types;
+
        struct p2p_group **groups;
        size_t num_groups;
 
index 72f603b..7564d60 100644 (file)
@@ -428,13 +428,18 @@ struct wpabuf * wps_build_assoc_resp_ie(void)
  * @dev: Device attributes
  * @uuid: Own UUID
  * @req_type: Value for Request Type attribute
+ * @num_req_dev_types: Number of requested device types
+ * @req_dev_types: Requested device types (8 * num_req_dev_types octets) or
+ *     %NULL if none
  * Returns: WPS IE or %NULL on failure
  *
  * The caller is responsible for freeing the buffer.
  */
 struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
                                       const u8 *uuid,
-                                      enum wps_request_type req_type)
+                                      enum wps_request_type req_type,
+                                      unsigned int num_req_dev_types,
+                                      const u8 *req_dev_types)
 {
        struct wpabuf *ie;
        u16 methods = 0;
@@ -488,6 +493,8 @@ struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
            wps_build_dev_name(dev, ie) ||
            wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) ||
 #endif /* CONFIG_WPS2 */
+           wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types)
+           ||
            wps_build_secondary_dev_type(dev, ie)
                ) {
                wpabuf_free(ie);
index fc706d9..918273d 100644 (file)
@@ -236,7 +236,9 @@ struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
 struct wpabuf * wps_build_assoc_resp_ie(void);
 struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
                                       const u8 *uuid,
-                                      enum wps_request_type req_type);
+                                      enum wps_request_type req_type,
+                                      unsigned int num_req_dev_types,
+                                      const u8 *req_dev_types);
 
 
 /**
index 7253d21..f2fb03a 100644 (file)
@@ -142,6 +142,26 @@ int wps_build_secondary_dev_type(struct wps_device_data *dev,
 }
 
 
+int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
+                          unsigned int num_req_dev_types,
+                          const u8 *req_dev_types)
+{
+       unsigned int i;
+
+       for (i = 0; i < num_req_dev_types; i++) {
+               wpa_hexdump(MSG_DEBUG, "WPS: * Requested Device Type",
+                           req_dev_types + i * WPS_DEV_TYPE_LEN,
+                           WPS_DEV_TYPE_LEN);
+               wpabuf_put_be16(msg, ATTR_REQUESTED_DEV_TYPE);
+               wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN);
+               wpabuf_put_data(msg, req_dev_types + i * WPS_DEV_TYPE_LEN,
+                               WPS_DEV_TYPE_LEN);
+       }
+
+       return 0;
+}
+
+
 int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg)
 {
        size_t len;
index f17f62d..f26a05b 100644 (file)
@@ -37,5 +37,8 @@ void wps_device_data_dup(struct wps_device_data *dst,
                         const struct wps_device_data *src);
 void wps_device_data_free(struct wps_device_data *dev);
 int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
+                          unsigned int num_req_dev_types,
+                          const u8 *req_dev_types);
 
 #endif /* WPS_DEV_ATTR_H */
index 9f06115..0fe31a1 100644 (file)
@@ -2068,7 +2068,7 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
        else if (os_strstr(cmd, "type=progressive"))
                type = P2P_FIND_PROGRESSIVE;
 
-       return wpas_p2p_find(wpa_s, timeout, type);
+       return wpas_p2p_find(wpa_s, timeout, type, 0, NULL);
 }
 
 
index a0aa558..9d4b23d 100644 (file)
@@ -81,7 +81,9 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
 }
 
 
-static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq)
+static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
+                        unsigned int num_req_dev_types,
+                        const u8 *req_dev_types)
 {
        struct wpa_supplicant *wpa_s = ctx;
        struct wpa_driver_scan_params params;
@@ -101,7 +103,8 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq)
 
        wpa_s->wps->dev.p2p = 1;
        wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
-                                       WPS_REQ_ENROLLEE);
+                                       WPS_REQ_ENROLLEE,
+                                       num_req_dev_types, req_dev_types);
        if (wps_ie == NULL)
                return -1;
 
@@ -2707,7 +2710,7 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
 
        wpa_s->wps->dev.p2p = 1;
        wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
-                                       WPS_REQ_ENROLLEE);
+                                       WPS_REQ_ENROLLEE, 0, NULL);
        if (wps_ie == NULL) {
                wpas_p2p_scan_res_join(wpa_s, NULL);
                return;
@@ -3478,7 +3481,8 @@ static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
 
 
 int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
-                 enum p2p_discovery_type type)
+                 enum p2p_discovery_type type,
+                 unsigned int num_req_dev_types, const u8 *req_dev_types)
 {
        wpas_p2p_clear_pending_action_tx(wpa_s);
        wpa_s->p2p_long_listen = 0;
@@ -3489,7 +3493,8 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
 
-       return p2p_find(wpa_s->global->p2p, timeout, type);
+       return p2p_find(wpa_s->global->p2p, timeout, type,
+                       num_req_dev_types, req_dev_types);
 }
 
 
index 5b3b1d2..69df475 100644 (file)
@@ -51,7 +51,8 @@ int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
                              char *end);
 enum p2p_discovery_type;
 int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
-                 enum p2p_discovery_type type);
+                 enum p2p_discovery_type type,
+                 unsigned int num_req_dev_types, const u8 *req_dev_types);
 void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s);
 int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout);
 int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
index 5982ed4..4fb9bef 100644 (file)
@@ -433,7 +433,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
 
        if (wps) {
                wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
-                                               wpa_s->wps->uuid, req_type);
+                                               wpa_s->wps->uuid, req_type,
+                                               0, NULL);
                if (wps_ie) {
                        params.extra_ies = wpabuf_head(wps_ie);
                        params.extra_ies_len = wpabuf_len(wps_ie);