WFD: Add support for sending Wi-Fi Display service discovery requests

wpa_cli p2p_serv_disc_req command can now be used to request WSD
request to be sent to specified or all peers who support WSD.

format: wifi-display <list of roles> <list of subelements>
examples:
p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source] 2,3,4,5
p2p_serv_disc_req 02:01:02:03:04:05 wifi-display [pri-sink] 3
p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [sec-source] 2
p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source+sink] 2,3,4,5
p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source][pri-sink] 2,3,4,5

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2012-03-02 21:48:57 +02:00 committed by Jouni Malinen
parent 337c781f9c
commit 347d6a5b76
8 changed files with 156 additions and 0 deletions

View file

@ -925,6 +925,7 @@ enum p2p_service_protocol_type {
P2P_SERV_BONJOUR = 1, P2P_SERV_BONJOUR = 1,
P2P_SERV_UPNP = 2, P2P_SERV_UPNP = 2,
P2P_SERV_WS_DISCOVERY = 3, P2P_SERV_WS_DISCOVERY = 3,
P2P_SERV_WIFI_DISPLAY = 4,
P2P_SERV_VENDOR_SPECIFIC = 255 P2P_SERV_VENDOR_SPECIFIC = 255
}; };

View file

@ -964,6 +964,11 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst, void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
const struct wpabuf *tlvs); const struct wpabuf *tlvs);
#ifdef CONFIG_WIFI_DISPLAY
void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst,
const struct wpabuf *tlvs);
#endif /* CONFIG_WIFI_DISPLAY */
/** /**
* p2p_sd_cancel_request - Cancel a pending service discovery query * p2p_sd_cancel_request - Cancel a pending service discovery query
* @p2p: P2P module context from p2p_init() * @p2p: P2P module context from p2p_init()

View file

@ -109,6 +109,7 @@ struct p2p_sd_query {
struct p2p_sd_query *next; struct p2p_sd_query *next;
u8 peer[ETH_ALEN]; u8 peer[ETH_ALEN];
int for_all_peers; int for_all_peers;
int wsd; /* Wi-Fi Display Service Discovery Request */
struct wpabuf *tlvs; struct wpabuf *tlvs;
}; };

View file

@ -15,15 +15,55 @@
#include "p2p.h" #include "p2p.h"
#ifdef CONFIG_WIFI_DISPLAY
static int wfd_wsd_supported(struct wpabuf *wfd)
{
const u8 *pos, *end;
u8 subelem;
u16 len;
if (wfd == NULL)
return 0;
pos = wpabuf_head(wfd);
end = pos + wpabuf_len(wfd);
while (pos + 3 <= end) {
subelem = *pos++;
len = WPA_GET_BE16(pos);
pos += 2;
if (pos + len > end)
break;
if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) {
u16 info = WPA_GET_BE16(pos);
return !!(info & 0x0040);
}
pos += len;
}
return 0;
}
#endif /* CONFIG_WIFI_DISPLAY */
struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p, struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
struct p2p_device *dev) struct p2p_device *dev)
{ {
struct p2p_sd_query *q; struct p2p_sd_query *q;
int wsd = 0;
if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY)) if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
return NULL; /* peer does not support SD */ return NULL; /* peer does not support SD */
#ifdef CONFIG_WIFI_DISPLAY
if (wfd_wsd_supported(dev->info.wfd_subelems))
wsd = 1;
#endif /* CONFIG_WIFI_DISPLAY */
for (q = p2p->sd_queries; q; q = q->next) { for (q = p2p->sd_queries; q; q = q->next) {
/* Use WSD only if the peer indicates support or it */
if (q->wsd && !wsd)
continue;
if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO)) if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO))
return q; return q;
if (!q->for_all_peers && if (!q->for_all_peers &&
@ -876,6 +916,19 @@ void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
} }
#ifdef CONFIG_WIFI_DISPLAY
void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst,
const struct wpabuf *tlvs)
{
struct p2p_sd_query *q;
q = p2p_sd_request(p2p, dst, tlvs);
if (q)
q->wsd = 1;
return q;
}
#endif /* CONFIG_WIFI_DISPLAY */
void p2p_sd_service_update(struct p2p_data *p2p) void p2p_sd_service_update(struct p2p_data *p2p)
{ {
p2p->srv_update_indic++; p2p->srv_update_indic++;

View file

@ -256,6 +256,14 @@ p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:service:Content
p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 uuid:6859dede-8574-59ab-9332-123456789012 p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 uuid:6859dede-8574-59ab-9332-123456789012
p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1 p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1
# Wi-Fi Display examples
# format: wifi-display <list of roles> <list of subelements>
p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source] 2,3,4,5
p2p_serv_disc_req 02:01:02:03:04:05 wifi-display [pri-sink] 3
p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [sec-source] 2
p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source+sink] 2,3,4,5
p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source][pri-sink] 2,3,4,5
p2p_serv_disc_cancel_req <query identifier> p2p_serv_disc_cancel_req <query identifier>
Cancel a pending P2P service discovery request. This command takes a Cancel a pending P2P service discovery request. This command takes a

View file

@ -3252,6 +3252,10 @@ static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
return -1; return -1;
pos++; pos++;
ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos); ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
#ifdef CONFIG_WIFI_DISPLAY
} else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
#endif /* CONFIG_WIFI_DISPLAY */
} else { } else {
len = os_strlen(pos); len = os_strlen(pos);
if (len & 1) if (len & 1)

View file

@ -1687,6 +1687,88 @@ u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
} }
#ifdef CONFIG_WIFI_DISPLAY
static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
const struct wpabuf *tlvs)
{
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
return 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return 0;
return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
}
#define MAX_WFD_SD_SUBELEMS 20
static void wfd_add_sd_req_role(struct wpabuf *tlvs, u8 id, u8 role,
const char *subelems)
{
u8 *len;
const char *pos;
int val;
int count = 0;
len = wpabuf_put(tlvs, 2);
wpabuf_put_u8(tlvs, P2P_SERV_WIFI_DISPLAY); /* Service Protocol Type */
wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
wpabuf_put_u8(tlvs, role);
pos = subelems;
while (*pos) {
val = atoi(pos);
if (val >= 0 && val < 256) {
wpabuf_put_u8(tlvs, val);
count++;
if (count == MAX_WFD_SD_SUBELEMS)
break;
}
pos = os_strchr(pos + 1, ',');
if (pos == NULL)
break;
pos++;
}
WPA_PUT_LE16(len, (u8 *) wpabuf_put(tlvs, 0) - len - 2);
}
u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
const u8 *dst, const char *role)
{
struct wpabuf *tlvs;
u64 ret;
const char *subelems;
u8 id = 1;
subelems = os_strchr(role, ' ');
if (subelems == NULL)
return 0;
subelems++;
tlvs = wpabuf_alloc(4 * (2 + 1 + 1 + 1 + MAX_WFD_SD_SUBELEMS));
if (tlvs == NULL)
return 0;
if (os_strstr(role, "[source]"))
wfd_add_sd_req_role(tlvs, id++, 0x00, subelems);
if (os_strstr(role, "[pri-sink]"))
wfd_add_sd_req_role(tlvs, id++, 0x01, subelems);
if (os_strstr(role, "[sec-sink]"))
wfd_add_sd_req_role(tlvs, id++, 0x02, subelems);
if (os_strstr(role, "[source+sink]"))
wfd_add_sd_req_role(tlvs, id++, 0x03, subelems);
ret = wpas_p2p_sd_request_wfd(wpa_s, dst, tlvs);
wpabuf_free(tlvs);
return ret;
}
#endif /* CONFIG_WIFI_DISPLAY */
int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req) int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
{ {
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)

View file

@ -86,6 +86,8 @@ u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
const struct wpabuf *tlvs); const struct wpabuf *tlvs);
u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst, u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
u8 version, const char *query); u8 version, const char *query);
u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
const u8 *dst, const char *role);
int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req); int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req);
void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq, void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
const u8 *dst, u8 dialog_token, const u8 *dst, u8 dialog_token,