diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index 5f9354ff1..2aecef53f 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -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; diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 5563f6cf6..fa56d6203 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -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); diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 3d75965ce..eb70dcfb1 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -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) diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 237abbf06..f913e005f 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -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; diff --git a/src/wps/wps.c b/src/wps/wps.c index 72f603b33..7564d60a5 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -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); diff --git a/src/wps/wps.h b/src/wps/wps.h index fc706d9df..918273dd6 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -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); /** diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c index 7253d21ec..f2fb03a5f 100644 --- a/src/wps/wps_dev_attr.c +++ b/src/wps/wps_dev_attr.c @@ -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; diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h index f17f62d64..f26a05bd4 100644 --- a/src/wps/wps_dev_attr.h +++ b/src/wps/wps_dev_attr.h @@ -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 */ diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 9f0611580..0fe31a1a4 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -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); } diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index a0aa55850..9d4b23db8 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -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); } diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 5b3b1d296..69df47526 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -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, diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 5982ed4e5..4fb9befcc 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -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);